fix(dispatch): resolve plugin namespace parsing, template substitution, and discovery duplication

This commit is contained in:
YeonGyu-Kim
2026-03-03 00:14:01 +09:00
parent f383d7abb5
commit c084cc3f26
10 changed files with 256 additions and 38 deletions
+7 -18
View File
@@ -1,15 +1,15 @@
import { existsSync, readdirSync, readFileSync } from "fs"
import { basename, join } from "path"
import { parseFrontmatter, sanitizeModelField, getOpenCodeConfigDir } from "../../shared"
import {
parseFrontmatter,
sanitizeModelField,
getOpenCodeConfigDir,
discoverPluginCommandDefinitions,
} from "../../shared"
import type { CommandFrontmatter } from "../../features/claude-code-command-loader/types"
import { isMarkdownFile } from "../../shared/file-utils"
import { getClaudeConfigDir } from "../../shared"
import { loadBuiltinCommands } from "../../features/builtin-commands"
import {
discoverInstalledPlugins,
loadPluginCommands,
loadPluginSkillsAsCommands,
} from "../../features/claude-code-plugin-loader"
import type { CommandInfo, CommandMetadata, CommandScope } from "./types"
export interface CommandDiscoveryOptions {
@@ -59,18 +59,7 @@ function discoverCommandsFromDir(commandsDir: string, scope: CommandScope): Comm
}
function discoverPluginCommands(options?: CommandDiscoveryOptions): CommandInfo[] {
if (options?.pluginsEnabled === false) {
return []
}
const { plugins } = discoverInstalledPlugins({
enabledPluginsOverride: options?.enabledPluginsOverride,
})
const pluginDefinitions = {
...loadPluginCommands(plugins),
...loadPluginSkillsAsCommands(plugins),
}
const pluginDefinitions = discoverPluginCommandDefinitions(options)
return Object.entries(pluginDefinitions).map(([name, definition]) => ({
name,
@@ -0,0 +1,28 @@
import { describe, expect, it } from "bun:test"
import { formatLoadedCommand } from "./command-output-formatter"
import type { CommandInfo } from "./types"
describe("command output formatter", () => {
describe("#given command template includes argument placeholders", () => {
it("#then replaces both placeholder forms", async () => {
// given
const command: CommandInfo = {
name: "daplug:templated",
metadata: {
name: "daplug:templated",
description: "Templated plugin command",
},
content: "Echo $ARGUMENTS and ${user_message}.",
scope: "plugin",
}
// when
const output = await formatLoadedCommand(command, "ship it")
// then
expect(output).toContain("Echo ship it and ship it.")
expect(output).not.toContain("$ARGUMENTS")
expect(output).not.toContain("${user_message}")
})
})
})
@@ -49,7 +49,9 @@ export async function formatLoadedCommand(
let finalContent = resolvedContent.trim()
if (userMessage) {
finalContent = finalContent.replace(/\$\{user_message\}/g, userMessage)
finalContent = finalContent
.replace(/\$\{user_message\}/g, userMessage)
.replace(/\$ARGUMENTS/g, userMessage)
}
sections.push(finalContent)