diff --git a/docs/supported-tools.md b/docs/supported-tools.md index 524e597f2..5239ff90d 100644 --- a/docs/supported-tools.md +++ b/docs/supported-tools.md @@ -27,6 +27,7 @@ You can enable expanded workflows (`new`, `continue`, `ff`, `verify`, `sync`, `b | Claude Code (`claude`) | `.claude/skills/openspec-*/SKILL.md` | `.claude/commands/opsx/.md` | | Cline (`cline`) | `.cline/skills/openspec-*/SKILL.md` | `.clinerules/workflows/opsx-.md` | | CodeBuddy (`codebuddy`) | `.codebuddy/skills/openspec-*/SKILL.md` | `.codebuddy/commands/opsx/.md` | +| Code Studio (`codestudio`) | `.codestudio/skills/openspec-*/SKILL.md` | `.codestudio/prompts/opsx-.prompt.md` | | Codex (`codex`) | `.codex/skills/openspec-*/SKILL.md` | `$CODEX_HOME/prompts/opsx-.md`\* | | Continue (`continue`) | `.continue/skills/openspec-*/SKILL.md` | `.continue/prompts/opsx-.prompt` | | CoStrict (`costrict`) | `.cospec/skills/openspec-*/SKILL.md` | `.cospec/openspec/commands/opsx-.md` | @@ -68,7 +69,7 @@ openspec init --tools none openspec init --profile core ``` -**Available tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `claude`, `cline`, `codex`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `kilocode`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf` +**Available tool IDs (`--tools`):** `amazon-q`, `antigravity`, `auggie`, `claude`, `cline`, `codex`, `codebuddy`, `codestudio`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `iflow`, `kilocode`, `kiro`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `trae`, `windsurf` ## Workflow-Dependent Installation diff --git a/src/core/command-generation/adapters/codestudio.ts b/src/core/command-generation/adapters/codestudio.ts new file mode 100644 index 000000000..c233d30ac --- /dev/null +++ b/src/core/command-generation/adapters/codestudio.ts @@ -0,0 +1,30 @@ +/** + * Code Studio Command Adapter + * + * Formats commands for Syncfusion Code Studio following its .prompt.md specification. + */ + +import path from 'path'; +import type { CommandContent, ToolCommandAdapter } from '../types.js'; + +/** + * Code Studio adapter for command generation. + * File path: .codestudio/prompts/opsx-.prompt.md + * Frontmatter: description + */ +export const codeStudioAdapter: ToolCommandAdapter = { + toolId: 'codestudio', + + getFilePath(commandId: string): string { + return path.join('.codestudio', 'prompts', `opsx-${commandId}.prompt.md`); + }, + + formatFile(content: CommandContent): string { + return `--- +description: ${content.description} +--- + +${content.body} +`; + }, +}; diff --git a/src/core/command-generation/adapters/index.ts b/src/core/command-generation/adapters/index.ts index 06f7a7ae7..d3ee978a1 100644 --- a/src/core/command-generation/adapters/index.ts +++ b/src/core/command-generation/adapters/index.ts @@ -11,6 +11,7 @@ export { claudeAdapter } from './claude.js'; export { clineAdapter } from './cline.js'; export { codexAdapter } from './codex.js'; export { codebuddyAdapter } from './codebuddy.js'; +export { codeStudioAdapter } from './codestudio.js'; export { continueAdapter } from './continue.js'; export { costrictAdapter } from './costrict.js'; export { crushAdapter } from './crush.js'; diff --git a/src/core/command-generation/registry.ts b/src/core/command-generation/registry.ts index a69a98adc..c334a29ef 100644 --- a/src/core/command-generation/registry.ts +++ b/src/core/command-generation/registry.ts @@ -13,6 +13,7 @@ import { claudeAdapter } from './adapters/claude.js'; import { clineAdapter } from './adapters/cline.js'; import { codexAdapter } from './adapters/codex.js'; import { codebuddyAdapter } from './adapters/codebuddy.js'; +import { codeStudioAdapter } from './adapters/codestudio.js'; import { continueAdapter } from './adapters/continue.js'; import { costrictAdapter } from './adapters/costrict.js'; import { crushAdapter } from './adapters/crush.js'; @@ -45,6 +46,7 @@ export class CommandAdapterRegistry { CommandAdapterRegistry.register(clineAdapter); CommandAdapterRegistry.register(codexAdapter); CommandAdapterRegistry.register(codebuddyAdapter); + CommandAdapterRegistry.register(codeStudioAdapter); CommandAdapterRegistry.register(continueAdapter); CommandAdapterRegistry.register(costrictAdapter); CommandAdapterRegistry.register(crushAdapter); diff --git a/src/core/config.ts b/src/core/config.ts index f35f92861..1a9d73b95 100644 --- a/src/core/config.ts +++ b/src/core/config.ts @@ -25,6 +25,7 @@ export const AI_TOOLS: AIToolOption[] = [ { name: 'Cline', value: 'cline', available: true, successLabel: 'Cline', skillsDir: '.cline' }, { name: 'Codex', value: 'codex', available: true, successLabel: 'Codex', skillsDir: '.codex' }, { name: 'CodeBuddy Code (CLI)', value: 'codebuddy', available: true, successLabel: 'CodeBuddy Code', skillsDir: '.codebuddy' }, + { name: 'Code Studio', value: 'codestudio', available: true, successLabel: 'Code Studio', skillsDir: '.codestudio' }, { name: 'Continue', value: 'continue', available: true, successLabel: 'Continue (VS Code / JetBrains / Cli)', skillsDir: '.continue' }, { name: 'CoStrict', value: 'costrict', available: true, successLabel: 'CoStrict', skillsDir: '.cospec' }, { name: 'Crush', value: 'crush', available: true, successLabel: 'Crush', skillsDir: '.crush' }, diff --git a/test/core/command-generation/adapters.test.ts b/test/core/command-generation/adapters.test.ts index dab19bf3d..9e4aa869e 100644 --- a/test/core/command-generation/adapters.test.ts +++ b/test/core/command-generation/adapters.test.ts @@ -8,6 +8,7 @@ import { claudeAdapter } from '../../../src/core/command-generation/adapters/cla import { clineAdapter } from '../../../src/core/command-generation/adapters/cline.js'; import { codexAdapter } from '../../../src/core/command-generation/adapters/codex.js'; import { codebuddyAdapter } from '../../../src/core/command-generation/adapters/codebuddy.js'; +import { codeStudioAdapter } from '../../../src/core/command-generation/adapters/codestudio.js'; import { continueAdapter } from '../../../src/core/command-generation/adapters/continue.js'; import { costrictAdapter } from '../../../src/core/command-generation/adapters/costrict.js'; import { crushAdapter } from '../../../src/core/command-generation/adapters/crush.js'; @@ -277,6 +278,25 @@ describe('command-generation/adapters', () => { }); }); + describe('codeStudioAdapter', () => { + it('should have correct toolId', () => { + expect(codeStudioAdapter.toolId).toBe('codestudio'); + }); + + it('should generate correct file path with .prompt.md extension', () => { + const filePath = codeStudioAdapter.getFilePath('explore'); + expect(filePath).toBe(path.join('.codestudio', 'prompts', 'opsx-explore.prompt.md')); + }); + + it('should format file with description frontmatter', () => { + const output = codeStudioAdapter.formatFile(sampleContent); + expect(output).toContain('---\n'); + expect(output).toContain('description: Enter explore mode for thinking'); + expect(output).toContain('---\n\n'); + expect(output).toContain('This is the command body.'); + }); + }); + describe('continueAdapter', () => { it('should have correct toolId', () => { expect(continueAdapter.toolId).toBe('continue'); @@ -607,7 +627,7 @@ describe('command-generation/adapters', () => { // Verify all adapters produce valid paths const adapters = [ amazonQAdapter, antigravityAdapter, auggieAdapter, clineAdapter, - codexAdapter, codebuddyAdapter, continueAdapter, costrictAdapter, + codexAdapter, codebuddyAdapter, codeStudioAdapter, continueAdapter, costrictAdapter, crushAdapter, factoryAdapter, geminiAdapter, githubCopilotAdapter, iflowAdapter, kilocodeAdapter, opencodeAdapter, piAdapter, qoderAdapter, qwenAdapter, roocodeAdapter