MCPcopy
hub / github.com/claude-code-best/claude-code / createPluginFromPath

Function createPluginFromPath

src/utils/plugins/pluginLoader.ts:1349–1771  ·  view source on GitHub ↗
(
  pluginPath: string,
  source: string,
  enabled: boolean,
  fallbackName: string,
  strict = true,
)

Source from the content-addressed store, hash-verified

1347 * @returns Object containing the LoadedPlugin and any errors encountered
1348 */
1349export async function createPluginFromPath(
1350 pluginPath: string,
1351 source: string,
1352 enabled: boolean,
1353 fallbackName: string,
1354 strict = true,
1355): Promise<{ plugin: LoadedPlugin; errors: PluginError[] }> {
1356 const errors: PluginError[] = []
1357
1358 // Step 1: Load or create the plugin manifest
1359 // This provides metadata about the plugin (name, version, etc.)
1360 const manifestPath = join(pluginPath, '.claude-plugin', 'plugin.json')
1361 const manifest = await loadPluginManifest(manifestPath, fallbackName, source)
1362
1363 // Step 2: Create the base plugin object
1364 // Start with required fields from manifest and parameters
1365 const plugin: LoadedPlugin = {
1366 name: manifest.name, // Use name from manifest (or fallback)
1367 manifest, // Store full manifest for later use
1368 path: pluginPath, // Absolute path to plugin directory
1369 source, // Source identifier (e.g., "git:repo" or ".claude-plugin/name")
1370 repository: source, // For backward compatibility with Plugin Repository
1371 enabled, // Current enabled state
1372 }
1373
1374 // Step 3: Auto-detect optional directories in parallel
1375 const [
1376 commandsDirExists,
1377 agentsDirExists,
1378 skillsDirExists,
1379 outputStylesDirExists,
1380 ] = await Promise.all([
1381 !manifest.commands ? pathExists(join(pluginPath, 'commands')) : false,
1382 !manifest.agents ? pathExists(join(pluginPath, 'agents')) : false,
1383 !manifest.skills ? pathExists(join(pluginPath, 'skills')) : false,
1384 !manifest.outputStyles
1385 ? pathExists(join(pluginPath, 'output-styles'))
1386 : false,
1387 ])
1388
1389 const commandsPath = join(pluginPath, 'commands')
1390 if (commandsDirExists) {
1391 plugin.commandsPath = commandsPath
1392 }
1393
1394 // Step 3a: Process additional command paths from manifest
1395 if (manifest.commands) {
1396 // Check if it's an object mapping (record of command name → metadata)
1397 const firstValue = Object.values(manifest.commands)[0]
1398 if (
1399 typeof manifest.commands === 'object' &&
1400 !Array.isArray(manifest.commands) &&
1401 firstValue &&
1402 typeof firstValue === 'object' &&
1403 ('source' in firstValue || 'content' in firstValue)
1404 ) {
1405 // Object mapping format: { "about": { "source": "./README.md", ... } }
1406 const commandsMetadata: Record<string, CommandMetadata> = {}

Callers 2

loadSessionOnlyPluginsFunction · 0.85

Calls 15

loadPluginManifestFunction · 0.85
pathExistsFunction · 0.85
validatePluginPathsFunction · 0.85
loadPluginHooksFunction · 0.85
toErrorFunction · 0.85
mergeHooksSettingsFunction · 0.85
loadPluginSettingsFunction · 0.85
entriesMethod · 0.80
keysMethod · 0.65
logForDebuggingFunction · 0.50
logErrorFunction · 0.50
errorMessageFunction · 0.50

Tested by

no test coverage detected