-
Notifications
You must be signed in to change notification settings - Fork 4.6k
feat(tools): add Command Code command adapter for /opsx-* commands #1622
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| "@fission-ai/openspec": minor | ||
| --- | ||
|
|
||
| ### New Features | ||
|
|
||
| - **Command Code command adapter** — Command Code is now a first-class, adapter-backed tool. `openspec init` generates OpenSpec commands under `.commandcode/commands/opsx-<id>.md` (invoked as `/opsx-<id>`) alongside the skills under `.commandcode/skills/`, matching Command Code's documented custom-slash-command surface. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /** | ||
| * Command Code Command Adapter | ||
| * | ||
| * Command Code reads custom slash commands from `.commandcode/commands/`. The | ||
| * command name is the markdown filename without its `.md` extension, so | ||
| * `opsx-<id>.md` registers `/opsx-<id>` — the same flat naming Cursor and | ||
| * OpenCode use. See https://commandcode.ai/docs/reference/slash-commands. | ||
| */ | ||
|
|
||
| import path from 'path'; | ||
| import type { CommandContent, ToolCommandAdapter } from '../types.js'; | ||
|
|
||
| const COMMAND_CODE_INPUT_HEADING = /^\*\*Input\*\*:[^\n]*$/m; | ||
|
|
||
| function injectCommandCodeArgs(body: string): string { | ||
| if (/^\*\*Provided arguments\*\*:\s*(?:\$(?:ARGUMENTS|@)|\$\{(?:ARGUMENTS|@)\})\s*$/m.test(body)) { | ||
| return body; | ||
| } | ||
|
|
||
| return body.replace( | ||
| COMMAND_CODE_INPUT_HEADING, | ||
| (heading) => `${heading}\n**Provided arguments**: $ARGUMENTS` | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Command Code adapter for command generation. | ||
| * File path: .commandcode/commands/opsx-<id>.md | ||
| * Format: plain Markdown with $ARGUMENTS injected after the input contract | ||
| * | ||
| * Command Code executes the full trimmed file body and substitutes invocation | ||
| * arguments only where the body includes one of its argument placeholders. | ||
| */ | ||
| export const commandCodeAdapter: ToolCommandAdapter = { | ||
| toolId: 'command-code', | ||
|
|
||
| getFilePath(commandId: string): string { | ||
| return path.join('.commandcode', 'commands', `opsx-${commandId}.md`); | ||
| }, | ||
|
|
||
| formatFile(content: CommandContent): string { | ||
| return `${injectCommandCodeArgs(content.body)}\n`; | ||
| }, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -130,7 +130,7 @@ describe('command-generation/registry', () => { | |
| }; | ||
|
|
||
| // Tools that don't use YAML frontmatter (markdown headers or TOML or plain) | ||
| const noYamlFrontmatter = ['cline', 'kilocode', 'roocode', 'gemini']; | ||
| const noYamlFrontmatter = ['cline', 'command-code', 'kilocode', 'roocode', 'gemini']; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Add an explicit Command Code registry assertion. The 🤖 Prompt for AI Agents |
||
|
|
||
| const adapters = CommandAdapterRegistry.getAll(); | ||
| for (const adapter of adapters) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Detect supported placeholders throughout the command body.
Line 16 only recognizes a placeholder when it is the complete value of a
**Provided arguments**line. A body that already uses$ARGUMENTS,$@,${ARGUMENTS}, or${@}elsewhere receives a second injected$ARGUMENTSline. This duplicates the invocation text.src/core/command-generation/adapters/command-code.ts#L16-L17: Detect the supported placeholders anywhere inbodybefore injection.test/core/command-generation/adapters.test.ts#L146-L155: Add cases with each supported placeholder outside**Provided arguments**and assert that injection does not add a second placeholder.📍 Affects 2 files
src/core/command-generation/adapters/command-code.ts#L16-L17(this comment)test/core/command-generation/adapters.test.ts#L146-L155🤖 Prompt for AI Agents