{"record":{"id":"a7edf2394b5f8a73","repo":"can1357/oh-my-pi","slug":"capability-def-id-is-already-defined","errorCode":null,"errorMessage":"Capability \"${def.id}\" is already defined","messagePattern":"Capability \"(.+?)\" is already defined","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/capability/index.ts","lineNumber":54,"sourceCode":"/** Provider display metadata (shared across capabilities) */\nconst providerMeta = new Map<string, { displayName: string; description: string }>();\n\n/** Disabled providers (by ID) */\nconst disabledProviders = new Set<string>();\n\n/** Settings manager for persistence (if set) */\nlet settings: Settings | null = null;\n\n// =============================================================================\n// Registration API\n// =============================================================================\n\n/**\n * Define a new capability.\n */\nexport function defineCapability<T>(def: Omit<Capability<T>, \"providers\">): Capability<T> {\n\tif (capabilities.has(def.id)) {\n\t\tthrow new Error(`Capability \"${def.id}\" is already defined`);\n\t}\n\tconst capability: Capability<T> = { ...def, providers: [] };\n\tcapabilities.set(def.id, capability as Capability<unknown>);\n\treturn capability;\n}\n\n/**\n * Register a provider for a capability.\n */\nexport function registerProvider<T>(capabilityId: string, provider: Provider<T>): void {\n\tconst capability = capabilities.get(capabilityId);\n\tif (!capability) {\n\t\tthrow new Error(`Unknown capability: \"${capabilityId}\". Define it first with defineCapability().`);\n\t}\n\n\t// Store provider metadata (for cross-capability display)\n\tif (!providerMeta.has(provider.id)) {\n\t\tproviderMeta.set(provider.id, {","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/capability/index.ts#L36-L72","documentation":"defineCapability() stores capability definitions in a module-level registry keyed by id. Calling it twice with the same id would silently overwrite the first definition, so the registry throws. This protects the unique-id invariant that registerProvider and loadCapability rely on.","triggerScenarios":"Calling defineCapability({ id: \"existing-id\", ... }) when a capability with that id was already defined — typically module-level definitions evaluated twice, two modules defining the same id, or module re-import/duplicate-bundle evaluation.","commonSituations":"A bundler duplicates a module so its top-level defineCapability call runs twice; a plugin copies another capability's definition without changing the id; an extension is loaded twice under different names.","solutions":["Rename your capability id to a unique namespaced value (e.g. 'myplugin.myCapability')","Check whether the module containing the defineCapability call is loaded twice (duplicate bundling, double registration) and fix the loading path","If re-defining is intentional, wrap the call in try/catch or look up the existing capability first"],"exampleFix":"// before\ndefineCapability({ id: \"hooks\", ... });\n// after\ndefineCapability({ id: \"myplugin.hooks\", ... });","handlingStrategy":"try-catch","validationCode":"// idempotent define\nconst CAPABILITY_ID = \"myplugin.hooks\";\nif (!isCapabilityDefined(CAPABILITY_ID)) {\n  defineCapability({ id: CAPABILITY_ID, displayName: \"My Hooks\" /* ... */ });\n}","typeGuard":null,"tryCatchPattern":"let capability: Capability<Hooks>;\ntry {\n  capability = defineCapability({ id: \"myplugin.hooks\", displayName: \"My Hooks\" });\n} catch (err) {\n  if (err instanceof Error && err.message.includes('already defined')) {\n    capability = getCapability<Hooks>(\"myplugin.hooks\");\n  } else throw err;\n}","preventionTips":["Namespace capability ids with your plugin/package name","Define capabilities once in a dedicated module imported for side effects only once","Watch for duplicate module evaluation in bundling","Never copy another definition's id without renaming"],"tags":["capability","duplicate-registration","typescript"],"backgroundTag":"duplicate-key-registration","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}