{"record":{"id":"20b61c163ea8ba4b","repo":"can1357/oh-my-pi","slug":"npm-plugin-sources-are-not-yet-supported-use-git","errorCode":null,"errorMessage":"npm plugin sources are not yet supported. Use git-based sources instead.","messagePattern":"npm plugin sources are not yet supported\\. Use git-based sources instead\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/extensibility/plugins/marketplace/source-resolver.ts","lineNumber":139,"sourceCode":"\t\t\t\ttimeoutMs: GIT_CLONE_TIMEOUT_MS,\n\t\t\t});\n\n\t\t\tconst subdirPath = path.resolve(cloneDir, source.path);\n\t\t\tif (!pathIsWithin(cloneDir, subdirPath)) {\n\t\t\t\tawait fs.rm(cloneDir, { recursive: true, force: true });\n\t\t\t\tthrow new Error(`git-subdir path \"${source.path}\" escapes the cloned repository`);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait verifyDirExists(subdirPath, `git-subdir path \"${source.path}\" does not exist in cloned repository`);\n\t\t\t} catch (err) {\n\t\t\t\tawait fs.rm(cloneDir, { recursive: true, force: true });\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\treturn { dir: subdirPath, tempCloneRoot: cloneDir };\n\t\t}\n\n\t\tcase \"npm\":\n\t\t\tthrow new Error(\"npm plugin sources are not yet supported. Use git-based sources instead.\");\n\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown plugin source type: \"${(source as { source: string }).source}\"`);\n\t}\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────\n\nasync function verifyDirExists(dirPath: string, errorMessage: string): Promise<void> {\n\ttry {\n\t\tconst stat = await fs.stat(dirPath);\n\t\tif (!stat.isDirectory()) {\n\t\t\tthrow new Error(errorMessage);\n\t\t}\n\t} catch (err) {\n\t\tif (isEnoent(err)) {\n\t\t\tthrow new Error(errorMessage);\n\t\t}","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/extensibility/plugins/marketplace/source-resolver.ts#L121-L157","documentation":"resolveObjectSource has an explicit case for npm plugin sources that is a hard rejection: npm registry packages are not implemented as a plugin source type in this marketplace resolver yet, so any entry declaring { source: \"npm\", ... } is refused immediately with a directive to use git-based sources. Unlike the unknown-type case this is a known but unimplemented source, so the error is deterministic and not a typo indicator.","triggerScenarios":"resolvePluginSource receives a MarketplacePluginEntry whose source object has source: \"npm\" — e.g. a marketplace.json copied from another tool's catalog (such as Claude Code marketplaces that support npm sources) and loaded by this resolver; or a user hand-writes an npm-based plugin entry expecting registry installation support.","commonSituations":"Migrating a marketplace catalog from Claude Code or another ecosystem where npm plugin sources are valid; following upstream plugin documentation that mentions npm distribution; a plugin author publishing to npm and writing { \"source\": \"npm\", \"package\": \"my-plugin\" } without checking this resolver's supported types.","solutions":["Replace the npm source with a git-based equivalent: { \"source\": \"github\", \"repo\": \"owner/repo\" } or { \"source\": \"url\", \"url\": \"https://host/repo.git\" }, optionally with ref/sha pinning.","If the package exists only on npm, find or create its git repository (many npm packages link one) and reference that instead.","Use source \"git-subdir\" with url + path if the plugin lives in a subdirectory of a monorepo.","Track/watch upstream support for npm sources if you truly need registry-based plugins; until then no configuration change makes npm sources work."],"exampleFix":"// before\n{ \"name\": \"my-plugin\", \"source\": \"npm\", \"package\": \"my-plugin\" }\n\n// after\n{ \"name\": \"my-plugin\", \"source\": \"github\", \"repo\": \"owner/my-plugin\" }","handlingStrategy":"validation","validationCode":"function usesUnsupportedNpmSource(entry: { source: unknown }): boolean {\n  return typeof entry.source === \"object\" && entry.source !== null\n    && (entry.source as { source?: unknown }).source === \"npm\";\n}\n// filter or rewrite these entries before invoking the resolver","typeGuard":"function isNpmPluginSource(source: unknown): source is { source: \"npm\" } {\n  return typeof source === \"object\" && source !== null\n    && (source as { source?: unknown }).source === \"npm\";\n}","tryCatchPattern":"try {\n  const { dir } = await resolvePluginSource(entry, context);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"npm plugin sources are not yet supported\")) {\n    // surface a user-facing message pointing at git-based alternatives; skip the entry\n  } else throw err;\n}","preventionTips":["Audit catalogs from other ecosystems (e.g. Claude Code) for npm entries before loading them here","Always express plugins as git sources: github repo, full URL, or git-subdir","Pin a ref/sha on git sources for reproducible installs","Check the resolver's supported source types in source-resolver.ts docs before authoring entries"],"tags":["unsupported-feature","npm","plugin-marketplace","configuration"],"backgroundTag":"unsupported-source-type","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}