feat(dispatch): wire marketplace plugin commands into slash command dispatch

Connect the existing plugin loader infrastructure to both slash command
dispatch paths (executor and slashcommand tool), enabling namespaced
commands like /daplug:run-prompt to resolve and execute.

- Add plugin discovery to executor.ts discoverAllCommands()
- Add plugin discovery to command-discovery.ts discoverCommandsSync()
- Add "plugin" to CommandScope type
- Remove blanket colon-rejection error (replaced with standard not-found)
- Update slash command regex to accept namespaced commands
- Thread claude_code.plugins config toggle through dispatch chain
- Add unit tests for plugin command discovery and dispatch

Closes #2019

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
Gershom Rogers
2026-02-21 10:05:50 -05:00
parent 111ae5ea5a
commit 6dd8d60d49
14 changed files with 461 additions and 14 deletions
+1 -1
View File
@@ -464,7 +464,7 @@ describe("skill tool - ordering and priority", () => {
const tool = createSkillTool({ skills, commands })
//#then: should include priority info
expect(tool.description).toContain("Priority: project > user > opencode > builtin")
expect(tool.description).toContain("Priority: project > user > opencode > builtin/plugin")
expect(tool.description).toContain("Skills listed before commands")
})
+6 -2
View File
@@ -16,6 +16,7 @@ const scopePriority: Record<string, number> = {
user: 3,
opencode: 2,
"opencode-project": 2,
plugin: 1,
config: 1,
builtin: 1,
}
@@ -89,7 +90,7 @@ function formatCombinedDescription(skills: SkillInfo[], commands: CommandInfo[])
}
if (allItems.length > 0) {
lines.push(`\n<available_items>\nPriority: project > user > opencode > builtin | Skills listed before commands\nInvoke via: skill(name="item-name") — omit leading slash for commands.\n${allItems.join("\n")}\n</available_items>`)
lines.push(`\n<available_items>\nPriority: project > user > opencode > builtin/plugin | Skills listed before commands\nInvoke via: skill(name="item-name") — omit leading slash for commands.\n${allItems.join("\n")}\n</available_items>`)
}
return TOOL_DESCRIPTION_PREFIX + lines.join("")
@@ -195,7 +196,10 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition
const getCommands = (): CommandInfo[] => {
if (cachedCommands) return cachedCommands
cachedCommands = discoverCommandsSync()
cachedCommands = discoverCommandsSync(undefined, {
pluginsEnabled: options.pluginsEnabled,
enabledPluginsOverride: options.enabledPluginsOverride,
})
return cachedCommands
}
+4
View File
@@ -33,4 +33,8 @@ export interface SkillLoadOptions {
/** Git master configuration for watermark/co-author settings */
gitMasterConfig?: GitMasterConfig
disabledSkills?: Set<string>
/** Include Claude marketplace plugin commands in discovery (default: true) */
pluginsEnabled?: boolean
/** Override plugin enablement from Claude settings by plugin key */
enabledPluginsOverride?: Record<string, boolean>
}