Merge pull request #2244 from code-yeongyu/fix/pr-2021-issues
fix(dispatch): resolve 3 bugs from PR #2021 plugin command wiring
This commit is contained in:
commit
d4033da41a
19
src/hooks/auto-slash-command/constants.test.ts
Normal file
19
src/hooks/auto-slash-command/constants.test.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { describe, expect, it } from "bun:test"
|
||||||
|
import { parseSlashCommand } from "./detector"
|
||||||
|
|
||||||
|
describe("slash command parsing pattern", () => {
|
||||||
|
describe("#given plugin namespace includes dot", () => {
|
||||||
|
it("#then parses command name with dot and colon", () => {
|
||||||
|
// given
|
||||||
|
const text = "/my.plugin:run ship"
|
||||||
|
|
||||||
|
// when
|
||||||
|
const parsed = parseSlashCommand(text)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(parsed).not.toBeNull()
|
||||||
|
expect(parsed?.command).toBe("my.plugin:run")
|
||||||
|
expect(parsed?.args).toBe("ship")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -3,7 +3,7 @@ export const HOOK_NAME = "auto-slash-command" as const
|
|||||||
export const AUTO_SLASH_COMMAND_TAG_OPEN = "<auto-slash-command>"
|
export const AUTO_SLASH_COMMAND_TAG_OPEN = "<auto-slash-command>"
|
||||||
export const AUTO_SLASH_COMMAND_TAG_CLOSE = "</auto-slash-command>"
|
export const AUTO_SLASH_COMMAND_TAG_CLOSE = "</auto-slash-command>"
|
||||||
|
|
||||||
export const SLASH_COMMAND_PATTERN = /^\/([a-zA-Z@][\w:@/-]*)\s*(.*)/
|
export const SLASH_COMMAND_PATTERN = /^\/([a-zA-Z@][\w.:@/-]*)\s*(.*)/
|
||||||
|
|
||||||
export const EXCLUDED_COMMANDS = new Set([
|
export const EXCLUDED_COMMANDS = new Set([
|
||||||
"ralph-loop",
|
"ralph-loop",
|
||||||
|
|||||||
@ -35,6 +35,14 @@ function writePluginFixture(baseDir: string): void {
|
|||||||
description: Run prompt from daplug
|
description: Run prompt from daplug
|
||||||
---
|
---
|
||||||
Execute daplug prompt flow.
|
Execute daplug prompt flow.
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
writeFileSync(
|
||||||
|
join(pluginInstallPath, "commands", "templated.md"),
|
||||||
|
`---
|
||||||
|
description: Templated prompt from daplug
|
||||||
|
---
|
||||||
|
Echo $ARGUMENTS and \${user_message}.
|
||||||
`,
|
`,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -165,4 +173,23 @@ describe("auto-slash command executor plugin dispatch", () => {
|
|||||||
)
|
)
|
||||||
expect(result.error).not.toContain("Marketplace plugin commands")
|
expect(result.error).not.toContain("Marketplace plugin commands")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("replaces $ARGUMENTS placeholders in plugin command templates", async () => {
|
||||||
|
const result = await executeSlashCommand(
|
||||||
|
{
|
||||||
|
command: "daplug:templated",
|
||||||
|
args: "ship it",
|
||||||
|
raw: "/daplug:templated ship it",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skills: [],
|
||||||
|
pluginsEnabled: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
expect(result.replacementText).toContain("Echo ship it and ship it.")
|
||||||
|
expect(result.replacementText).not.toContain("$ARGUMENTS")
|
||||||
|
expect(result.replacementText).not.toContain("${user_message}")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -7,16 +7,12 @@ import {
|
|||||||
sanitizeModelField,
|
sanitizeModelField,
|
||||||
getClaudeConfigDir,
|
getClaudeConfigDir,
|
||||||
getOpenCodeConfigDir,
|
getOpenCodeConfigDir,
|
||||||
|
discoverPluginCommandDefinitions,
|
||||||
} from "../../shared"
|
} from "../../shared"
|
||||||
import { loadBuiltinCommands } from "../../features/builtin-commands"
|
import { loadBuiltinCommands } from "../../features/builtin-commands"
|
||||||
import type { CommandFrontmatter } from "../../features/claude-code-command-loader/types"
|
import type { CommandFrontmatter } from "../../features/claude-code-command-loader/types"
|
||||||
import { isMarkdownFile } from "../../shared/file-utils"
|
import { isMarkdownFile } from "../../shared/file-utils"
|
||||||
import { discoverAllSkills, type LoadedSkill, type LazyContentLoader } from "../../features/opencode-skill-loader"
|
import { discoverAllSkills, type LoadedSkill, type LazyContentLoader } from "../../features/opencode-skill-loader"
|
||||||
import {
|
|
||||||
discoverInstalledPlugins,
|
|
||||||
loadPluginCommands,
|
|
||||||
loadPluginSkillsAsCommands,
|
|
||||||
} from "../../features/claude-code-plugin-loader"
|
|
||||||
import type { ParsedSlashCommand } from "./types"
|
import type { ParsedSlashCommand } from "./types"
|
||||||
|
|
||||||
interface CommandScope {
|
interface CommandScope {
|
||||||
@ -109,18 +105,7 @@ export interface ExecutorOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function discoverPluginCommands(options?: ExecutorOptions): CommandInfo[] {
|
function discoverPluginCommands(options?: ExecutorOptions): CommandInfo[] {
|
||||||
if (options?.pluginsEnabled === false) {
|
const pluginDefinitions = discoverPluginCommandDefinitions(options)
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const { plugins } = discoverInstalledPlugins({
|
|
||||||
enabledPluginsOverride: options?.enabledPluginsOverride,
|
|
||||||
})
|
|
||||||
|
|
||||||
const pluginDefinitions = {
|
|
||||||
...loadPluginCommands(plugins),
|
|
||||||
...loadPluginSkillsAsCommands(plugins),
|
|
||||||
}
|
|
||||||
|
|
||||||
return Object.entries(pluginDefinitions).map(([name, definition]) => ({
|
return Object.entries(pluginDefinitions).map(([name, definition]) => ({
|
||||||
name,
|
name,
|
||||||
@ -216,7 +201,11 @@ async function formatCommandTemplate(cmd: CommandInfo, args: string): Promise<st
|
|||||||
const commandDir = cmd.path ? dirname(cmd.path) : process.cwd()
|
const commandDir = cmd.path ? dirname(cmd.path) : process.cwd()
|
||||||
const withFileRefs = await resolveFileReferencesInText(content, commandDir)
|
const withFileRefs = await resolveFileReferencesInText(content, commandDir)
|
||||||
const resolvedContent = await resolveCommandsInText(withFileRefs)
|
const resolvedContent = await resolveCommandsInText(withFileRefs)
|
||||||
sections.push(resolvedContent.trim())
|
const resolvedArguments = args
|
||||||
|
const substitutedContent = resolvedContent
|
||||||
|
.replace(/\$\{user_message\}/g, resolvedArguments)
|
||||||
|
.replace(/\$ARGUMENTS/g, resolvedArguments)
|
||||||
|
sections.push(substitutedContent.trim())
|
||||||
|
|
||||||
if (args) {
|
if (args) {
|
||||||
sections.push("\n\n---\n")
|
sections.push("\n\n---\n")
|
||||||
|
|||||||
@ -50,28 +50,34 @@ describe("collectGitDiffStats", () => {
|
|||||||
|
|
||||||
//#then
|
//#then
|
||||||
expect(execSyncSpy).not.toHaveBeenCalled()
|
expect(execSyncSpy).not.toHaveBeenCalled()
|
||||||
expect(execFileSyncSpy).toHaveBeenCalledTimes(3)
|
expect(execFileSyncSpy.mock.calls.length).toBeGreaterThanOrEqual(3)
|
||||||
|
|
||||||
const [firstCallFile, firstCallArgs, firstCallOpts] = execFileSyncSpy.mock
|
const calls = execFileSyncSpy.mock.calls as unknown as Array<[string, string[], { cwd?: string }]>
|
||||||
.calls[0]! as unknown as [string, string[], { cwd?: string }]
|
const diffCall = calls.find(([, args]) => args[0] === "diff")
|
||||||
expect(firstCallFile).toBe("git")
|
const statusCall = calls.find(([, args]) => args[0] === "status")
|
||||||
expect(firstCallArgs).toEqual(["diff", "--numstat", "HEAD"])
|
const untrackedCall = calls.find(([, args]) => args[0] === "ls-files")
|
||||||
expect(firstCallOpts.cwd).toBe(directory)
|
|
||||||
expect(firstCallArgs.join(" ")).not.toContain(directory)
|
|
||||||
|
|
||||||
const [secondCallFile, secondCallArgs, secondCallOpts] = execFileSyncSpy.mock
|
expect(diffCall).toBeDefined()
|
||||||
.calls[1]! as unknown as [string, string[], { cwd?: string }]
|
expect(statusCall).toBeDefined()
|
||||||
expect(secondCallFile).toBe("git")
|
expect(untrackedCall).toBeDefined()
|
||||||
expect(secondCallArgs).toEqual(["status", "--porcelain"])
|
|
||||||
expect(secondCallOpts.cwd).toBe(directory)
|
|
||||||
expect(secondCallArgs.join(" ")).not.toContain(directory)
|
|
||||||
|
|
||||||
const [thirdCallFile, thirdCallArgs, thirdCallOpts] = execFileSyncSpy.mock
|
const [diffCallFile, diffCallArgs, diffCallOpts] = diffCall!
|
||||||
.calls[2]! as unknown as [string, string[], { cwd?: string }]
|
expect(diffCallFile).toBe("git")
|
||||||
expect(thirdCallFile).toBe("git")
|
expect(diffCallArgs).toEqual(["diff", "--numstat", "HEAD"])
|
||||||
expect(thirdCallArgs).toEqual(["ls-files", "--others", "--exclude-standard"])
|
expect(diffCallOpts.cwd).toBe(directory)
|
||||||
expect(thirdCallOpts.cwd).toBe(directory)
|
expect(diffCallArgs.join(" ")).not.toContain(directory)
|
||||||
expect(thirdCallArgs.join(" ")).not.toContain(directory)
|
|
||||||
|
const [statusCallFile, statusCallArgs, statusCallOpts] = statusCall!
|
||||||
|
expect(statusCallFile).toBe("git")
|
||||||
|
expect(statusCallArgs).toEqual(["status", "--porcelain"])
|
||||||
|
expect(statusCallOpts.cwd).toBe(directory)
|
||||||
|
expect(statusCallArgs.join(" ")).not.toContain(directory)
|
||||||
|
|
||||||
|
const [untrackedCallFile, untrackedCallArgs, untrackedCallOpts] = untrackedCall!
|
||||||
|
expect(untrackedCallFile).toBe("git")
|
||||||
|
expect(untrackedCallArgs).toEqual(["ls-files", "--others", "--exclude-standard"])
|
||||||
|
expect(untrackedCallOpts.cwd).toBe(directory)
|
||||||
|
expect(untrackedCallArgs.join(" ")).not.toContain(directory)
|
||||||
|
|
||||||
expect(readFileSyncSpy).toHaveBeenCalled()
|
expect(readFileSyncSpy).toHaveBeenCalled()
|
||||||
|
|
||||||
|
|||||||
@ -60,4 +60,5 @@ export * from "./normalize-sdk-response"
|
|||||||
export * from "./session-directory-resolver"
|
export * from "./session-directory-resolver"
|
||||||
export * from "./prompt-tools"
|
export * from "./prompt-tools"
|
||||||
export * from "./internal-initiator-marker"
|
export * from "./internal-initiator-marker"
|
||||||
|
export * from "./plugin-command-discovery"
|
||||||
export { SessionCategoryRegistry } from "./session-category-registry"
|
export { SessionCategoryRegistry } from "./session-category-registry"
|
||||||
|
|||||||
135
src/shared/plugin-command-discovery.test.ts
Normal file
135
src/shared/plugin-command-discovery.test.ts
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
import { afterEach, beforeEach, describe, expect, it } from "bun:test"
|
||||||
|
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||||
|
import { tmpdir } from "node:os"
|
||||||
|
import { join } from "node:path"
|
||||||
|
import { discoverPluginCommandDefinitions } from "./plugin-command-discovery"
|
||||||
|
|
||||||
|
const ENV_KEYS = [
|
||||||
|
"CLAUDE_CONFIG_DIR",
|
||||||
|
"CLAUDE_PLUGINS_HOME",
|
||||||
|
"CLAUDE_SETTINGS_PATH",
|
||||||
|
"OPENCODE_CONFIG_DIR",
|
||||||
|
] as const
|
||||||
|
|
||||||
|
type EnvKey = (typeof ENV_KEYS)[number]
|
||||||
|
type EnvSnapshot = Record<EnvKey, string | undefined>
|
||||||
|
|
||||||
|
function writePluginFixture(baseDir: string): void {
|
||||||
|
const claudeConfigDir = join(baseDir, "claude-config")
|
||||||
|
const pluginsHome = join(claudeConfigDir, "plugins")
|
||||||
|
const settingsPath = join(claudeConfigDir, "settings.json")
|
||||||
|
const opencodeConfigDir = join(baseDir, "opencode-config")
|
||||||
|
const pluginInstallPath = join(baseDir, "installed-plugins", "daplug")
|
||||||
|
const pluginKey = "daplug@1.0.0"
|
||||||
|
|
||||||
|
mkdirSync(join(pluginInstallPath, ".claude-plugin"), { recursive: true })
|
||||||
|
mkdirSync(join(pluginInstallPath, "commands"), { recursive: true })
|
||||||
|
mkdirSync(join(pluginInstallPath, "skills", "plugin-plan"), { recursive: true })
|
||||||
|
|
||||||
|
writeFileSync(
|
||||||
|
join(pluginInstallPath, ".claude-plugin", "plugin.json"),
|
||||||
|
JSON.stringify({ name: "daplug", version: "1.0.0" }, null, 2),
|
||||||
|
)
|
||||||
|
writeFileSync(
|
||||||
|
join(pluginInstallPath, "commands", "run-prompt.md"),
|
||||||
|
`---
|
||||||
|
description: Run prompt from daplug
|
||||||
|
---
|
||||||
|
Execute daplug prompt flow.
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
writeFileSync(
|
||||||
|
join(pluginInstallPath, "skills", "plugin-plan", "SKILL.md"),
|
||||||
|
`---
|
||||||
|
name: plugin-plan
|
||||||
|
description: Plan work from daplug skill
|
||||||
|
---
|
||||||
|
Build a plan from plugin skill context.
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
|
||||||
|
mkdirSync(pluginsHome, { recursive: true })
|
||||||
|
writeFileSync(
|
||||||
|
join(pluginsHome, "installed_plugins.json"),
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
version: 2,
|
||||||
|
plugins: {
|
||||||
|
[pluginKey]: [
|
||||||
|
{
|
||||||
|
scope: "user",
|
||||||
|
installPath: pluginInstallPath,
|
||||||
|
version: "1.0.0",
|
||||||
|
installedAt: "2026-01-01T00:00:00.000Z",
|
||||||
|
lastUpdated: "2026-01-01T00:00:00.000Z",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
mkdirSync(claudeConfigDir, { recursive: true })
|
||||||
|
writeFileSync(
|
||||||
|
settingsPath,
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
enabledPlugins: {
|
||||||
|
[pluginKey]: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
mkdirSync(opencodeConfigDir, { recursive: true })
|
||||||
|
|
||||||
|
process.env.CLAUDE_CONFIG_DIR = claudeConfigDir
|
||||||
|
process.env.CLAUDE_PLUGINS_HOME = pluginsHome
|
||||||
|
process.env.CLAUDE_SETTINGS_PATH = settingsPath
|
||||||
|
process.env.OPENCODE_CONFIG_DIR = opencodeConfigDir
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("plugin command discovery utility", () => {
|
||||||
|
let tempDir = ""
|
||||||
|
let envSnapshot: EnvSnapshot
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tempDir = mkdtempSync(join(tmpdir(), "omo-shared-plugin-discovery-test-"))
|
||||||
|
envSnapshot = {
|
||||||
|
CLAUDE_CONFIG_DIR: process.env.CLAUDE_CONFIG_DIR,
|
||||||
|
CLAUDE_PLUGINS_HOME: process.env.CLAUDE_PLUGINS_HOME,
|
||||||
|
CLAUDE_SETTINGS_PATH: process.env.CLAUDE_SETTINGS_PATH,
|
||||||
|
OPENCODE_CONFIG_DIR: process.env.OPENCODE_CONFIG_DIR,
|
||||||
|
}
|
||||||
|
writePluginFixture(tempDir)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
for (const key of ENV_KEYS) {
|
||||||
|
const previousValue = envSnapshot[key]
|
||||||
|
if (previousValue === undefined) {
|
||||||
|
delete process.env[key]
|
||||||
|
} else {
|
||||||
|
process.env[key] = previousValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rmSync(tempDir, { recursive: true, force: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given plugin loading is enabled", () => {
|
||||||
|
it("#then returns plugin command and skill definitions", () => {
|
||||||
|
// given
|
||||||
|
const options = { pluginsEnabled: true }
|
||||||
|
|
||||||
|
// when
|
||||||
|
const definitions = discoverPluginCommandDefinitions(options)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(Object.keys(definitions)).toContain("daplug:run-prompt")
|
||||||
|
expect(Object.keys(definitions)).toContain("daplug:plugin-plan")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
28
src/shared/plugin-command-discovery.ts
Normal file
28
src/shared/plugin-command-discovery.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import {
|
||||||
|
discoverInstalledPlugins,
|
||||||
|
loadPluginCommands,
|
||||||
|
loadPluginSkillsAsCommands,
|
||||||
|
} from "../features/claude-code-plugin-loader"
|
||||||
|
import type { CommandDefinition } from "../features/claude-code-command-loader/types"
|
||||||
|
|
||||||
|
export interface PluginCommandDiscoveryOptions {
|
||||||
|
pluginsEnabled?: boolean
|
||||||
|
enabledPluginsOverride?: Record<string, boolean>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function discoverPluginCommandDefinitions(
|
||||||
|
options?: PluginCommandDiscoveryOptions,
|
||||||
|
): Record<string, CommandDefinition> {
|
||||||
|
if (options?.pluginsEnabled === false) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { plugins } = discoverInstalledPlugins({
|
||||||
|
enabledPluginsOverride: options?.enabledPluginsOverride,
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...loadPluginCommands(plugins),
|
||||||
|
...loadPluginSkillsAsCommands(plugins),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,15 +1,15 @@
|
|||||||
import { existsSync, readdirSync, readFileSync } from "fs"
|
import { existsSync, readdirSync, readFileSync } from "fs"
|
||||||
import { basename, join } from "path"
|
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 type { CommandFrontmatter } from "../../features/claude-code-command-loader/types"
|
||||||
import { isMarkdownFile } from "../../shared/file-utils"
|
import { isMarkdownFile } from "../../shared/file-utils"
|
||||||
import { getClaudeConfigDir } from "../../shared"
|
import { getClaudeConfigDir } from "../../shared"
|
||||||
import { loadBuiltinCommands } from "../../features/builtin-commands"
|
import { loadBuiltinCommands } from "../../features/builtin-commands"
|
||||||
import {
|
|
||||||
discoverInstalledPlugins,
|
|
||||||
loadPluginCommands,
|
|
||||||
loadPluginSkillsAsCommands,
|
|
||||||
} from "../../features/claude-code-plugin-loader"
|
|
||||||
import type { CommandInfo, CommandMetadata, CommandScope } from "./types"
|
import type { CommandInfo, CommandMetadata, CommandScope } from "./types"
|
||||||
|
|
||||||
export interface CommandDiscoveryOptions {
|
export interface CommandDiscoveryOptions {
|
||||||
@ -59,18 +59,7 @@ function discoverCommandsFromDir(commandsDir: string, scope: CommandScope): Comm
|
|||||||
}
|
}
|
||||||
|
|
||||||
function discoverPluginCommands(options?: CommandDiscoveryOptions): CommandInfo[] {
|
function discoverPluginCommands(options?: CommandDiscoveryOptions): CommandInfo[] {
|
||||||
if (options?.pluginsEnabled === false) {
|
const pluginDefinitions = discoverPluginCommandDefinitions(options)
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const { plugins } = discoverInstalledPlugins({
|
|
||||||
enabledPluginsOverride: options?.enabledPluginsOverride,
|
|
||||||
})
|
|
||||||
|
|
||||||
const pluginDefinitions = {
|
|
||||||
...loadPluginCommands(plugins),
|
|
||||||
...loadPluginSkillsAsCommands(plugins),
|
|
||||||
}
|
|
||||||
|
|
||||||
return Object.entries(pluginDefinitions).map(([name, definition]) => ({
|
return Object.entries(pluginDefinitions).map(([name, definition]) => ({
|
||||||
name,
|
name,
|
||||||
|
|||||||
28
src/tools/slashcommand/command-output-formatter.test.ts
Normal file
28
src/tools/slashcommand/command-output-formatter.test.ts
Normal file
@ -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()
|
let finalContent = resolvedContent.trim()
|
||||||
if (userMessage) {
|
if (userMessage) {
|
||||||
finalContent = finalContent.replace(/\$\{user_message\}/g, userMessage)
|
finalContent = finalContent
|
||||||
|
.replace(/\$\{user_message\}/g, userMessage)
|
||||||
|
.replace(/\$ARGUMENTS/g, userMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
sections.push(finalContent)
|
sections.push(finalContent)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user