@fission-ai/openspec 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -94,9 +94,11 @@ These tools have built-in OpenSpec commands. Select the OpenSpec integration whe
94
94
  | **CodeBuddy Code (CLI)** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.codebuddy/commands/`) — see [docs](https://www.codebuddy.ai/cli) |
95
95
  | **CoStrict** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.cospec/openspec/commands/`) — see [docs](https://costrict.ai)|
96
96
  | **Cursor** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` |
97
- | **Cline** | Rules in `.clinerules/` directory (`.clinerules/openspec-*.md`) |
97
+ | **Cline** | Workflows in `.clinerules/workflows/` directory (`.clinerules/workflows/openspec-*.md`) |
98
98
  | **Crush** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.crush/commands/openspec/`) |
99
+ | **RooCode** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.roo/commands/`) |
99
100
  | **Factory Droid** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.factory/commands/`) |
101
+ | **Gemini CLI** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.gemini/commands/openspec/`) |
100
102
  | **OpenCode** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` |
101
103
  | **Kilo Code** | `/openspec-proposal.md`, `/openspec-apply.md`, `/openspec-archive.md` (`.kilocode/workflows/`) |
102
104
  | **Qoder (CLI)** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.qoder/commands/openspec/`) — see [docs](https://qoder.com/cli) |
@@ -115,7 +117,7 @@ These tools automatically read workflow instructions from `openspec/AGENTS.md`.
115
117
 
116
118
  | Tools |
117
119
  |-------|
118
- | Amp • Jules • Gemini CLI • Others |
120
+ | Amp • Jules • Others |
119
121
 
120
122
  ### Install & Initialize
121
123
 
@@ -232,7 +234,7 @@ Or run the command yourself in terminal:
232
234
  $ openspec archive add-profile-filters --yes # Archive the completed change without prompts
233
235
  ```
234
236
 
235
- **Note:** Tools with native slash commands (Claude Code, CodeBuddy, Cursor, Codex, Qoder) can use the shortcuts shown. All other tools work with natural language requests to "create an OpenSpec proposal", "apply the OpenSpec change", or "archive the change".
237
+ **Note:** Tools with native slash commands (Claude Code, CodeBuddy, Cursor, Codex, Qoder, RooCode) can use the shortcuts shown. All other tools work with natural language requests to "create an OpenSpec proposal", "apply the OpenSpec change", or "archive the change".
236
238
 
237
239
  ## Command Reference
238
240
 
@@ -7,11 +7,13 @@ export const AI_TOOLS = [
7
7
  { name: 'Auggie (Augment CLI)', value: 'auggie', available: true, successLabel: 'Auggie' },
8
8
  { name: 'Claude Code', value: 'claude', available: true, successLabel: 'Claude Code' },
9
9
  { name: 'Cline', value: 'cline', available: true, successLabel: 'Cline' },
10
+ { name: 'RooCode', value: 'roocode', available: true, successLabel: 'RooCode' },
10
11
  { name: 'CodeBuddy Code (CLI)', value: 'codebuddy', available: true, successLabel: 'CodeBuddy Code' },
11
12
  { name: 'CoStrict', value: 'costrict', available: true, successLabel: 'CoStrict' },
12
13
  { name: 'Crush', value: 'crush', available: true, successLabel: 'Crush' },
13
14
  { name: 'Cursor', value: 'cursor', available: true, successLabel: 'Cursor' },
14
15
  { name: 'Factory Droid', value: 'factory', available: true, successLabel: 'Factory Droid' },
16
+ { name: 'Gemini CLI', value: 'gemini', available: true, successLabel: 'Gemini CLI' },
15
17
  { name: 'OpenCode', value: 'opencode', available: true, successLabel: 'OpenCode' },
16
18
  { name: 'Kilo Code', value: 'kilocode', available: true, successLabel: 'Kilo Code' },
17
19
  { name: 'Qoder (CLI)', value: 'qoder', available: true, successLabel: 'Qoder' },
@@ -1,8 +1,8 @@
1
1
  import { SlashCommandConfigurator } from './base.js';
2
2
  const FILE_PATHS = {
3
- proposal: '.clinerules/openspec-proposal.md',
4
- apply: '.clinerules/openspec-apply.md',
5
- archive: '.clinerules/openspec-archive.md'
3
+ proposal: '.clinerules/workflows/openspec-proposal.md',
4
+ apply: '.clinerules/workflows/openspec-apply.md',
5
+ archive: '.clinerules/workflows/openspec-archive.md'
6
6
  };
7
7
  export class ClineSlashCommandConfigurator extends SlashCommandConfigurator {
8
8
  toolId = 'cline';
@@ -0,0 +1,12 @@
1
+ import { SlashCommandConfigurator } from './base.js';
2
+ import { SlashCommandId } from '../../templates/index.js';
3
+ export declare class GeminiSlashCommandConfigurator extends SlashCommandConfigurator {
4
+ readonly toolId = "gemini";
5
+ readonly isAvailable = true;
6
+ protected getRelativePath(id: SlashCommandId): string;
7
+ protected getFrontmatter(_id: SlashCommandId): string | undefined;
8
+ generateAll(projectPath: string, _openspecDir: string): Promise<string[]>;
9
+ private generateTOML;
10
+ protected updateBody(filePath: string, body: string): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=gemini.d.ts.map
@@ -0,0 +1,68 @@
1
+ import { FileSystemUtils } from '../../../utils/file-system.js';
2
+ import { SlashCommandConfigurator } from './base.js';
3
+ import { OPENSPEC_MARKERS } from '../../config.js';
4
+ const FILE_PATHS = {
5
+ proposal: '.gemini/commands/openspec/proposal.toml',
6
+ apply: '.gemini/commands/openspec/apply.toml',
7
+ archive: '.gemini/commands/openspec/archive.toml'
8
+ };
9
+ const DESCRIPTIONS = {
10
+ proposal: 'Scaffold a new OpenSpec change and validate strictly.',
11
+ apply: 'Implement an approved OpenSpec change and keep tasks in sync.',
12
+ archive: 'Archive a deployed OpenSpec change and update specs.'
13
+ };
14
+ export class GeminiSlashCommandConfigurator extends SlashCommandConfigurator {
15
+ toolId = 'gemini';
16
+ isAvailable = true;
17
+ getRelativePath(id) {
18
+ return FILE_PATHS[id];
19
+ }
20
+ getFrontmatter(_id) {
21
+ // TOML doesn't use separate frontmatter - it's all in one structure
22
+ return undefined;
23
+ }
24
+ // Override to generate TOML format with markers inside the prompt field
25
+ async generateAll(projectPath, _openspecDir) {
26
+ const createdOrUpdated = [];
27
+ for (const target of this.getTargets()) {
28
+ const body = this.getBody(target.id);
29
+ const filePath = FileSystemUtils.joinPath(projectPath, target.path);
30
+ if (await FileSystemUtils.fileExists(filePath)) {
31
+ await this.updateBody(filePath, body);
32
+ }
33
+ else {
34
+ const tomlContent = this.generateTOML(target.id, body);
35
+ await FileSystemUtils.writeFile(filePath, tomlContent);
36
+ }
37
+ createdOrUpdated.push(target.path);
38
+ }
39
+ return createdOrUpdated;
40
+ }
41
+ generateTOML(id, body) {
42
+ const description = DESCRIPTIONS[id];
43
+ // TOML format with triple-quoted string for multi-line prompt
44
+ // Markers are inside the prompt value
45
+ return `description = "${description}"
46
+
47
+ prompt = """
48
+ ${OPENSPEC_MARKERS.start}
49
+ ${body}
50
+ ${OPENSPEC_MARKERS.end}
51
+ """
52
+ `;
53
+ }
54
+ // Override updateBody to handle TOML format
55
+ async updateBody(filePath, body) {
56
+ const content = await FileSystemUtils.readFile(filePath);
57
+ const startIndex = content.indexOf(OPENSPEC_MARKERS.start);
58
+ const endIndex = content.indexOf(OPENSPEC_MARKERS.end);
59
+ if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) {
60
+ throw new Error(`Missing OpenSpec markers in ${filePath}`);
61
+ }
62
+ const before = content.slice(0, startIndex + OPENSPEC_MARKERS.start.length);
63
+ const after = content.slice(endIndex);
64
+ const updatedContent = `${before}\n${body}\n${after}`;
65
+ await FileSystemUtils.writeFile(filePath, updatedContent);
66
+ }
67
+ }
68
+ //# sourceMappingURL=gemini.js.map
@@ -9,11 +9,13 @@ import { CodexSlashCommandConfigurator } from './codex.js';
9
9
  import { GitHubCopilotSlashCommandConfigurator } from './github-copilot.js';
10
10
  import { AmazonQSlashCommandConfigurator } from './amazon-q.js';
11
11
  import { FactorySlashCommandConfigurator } from './factory.js';
12
+ import { GeminiSlashCommandConfigurator } from './gemini.js';
12
13
  import { AuggieSlashCommandConfigurator } from './auggie.js';
13
14
  import { ClineSlashCommandConfigurator } from './cline.js';
14
15
  import { CrushSlashCommandConfigurator } from './crush.js';
15
16
  import { CostrictSlashCommandConfigurator } from './costrict.js';
16
17
  import { QwenSlashCommandConfigurator } from './qwen.js';
18
+ import { RooCodeSlashCommandConfigurator } from './roocode.js';
17
19
  export class SlashCommandRegistry {
18
20
  static configurators = new Map();
19
21
  static {
@@ -28,11 +30,13 @@ export class SlashCommandRegistry {
28
30
  const githubCopilot = new GitHubCopilotSlashCommandConfigurator();
29
31
  const amazonQ = new AmazonQSlashCommandConfigurator();
30
32
  const factory = new FactorySlashCommandConfigurator();
33
+ const gemini = new GeminiSlashCommandConfigurator();
31
34
  const auggie = new AuggieSlashCommandConfigurator();
32
35
  const cline = new ClineSlashCommandConfigurator();
33
36
  const crush = new CrushSlashCommandConfigurator();
34
37
  const costrict = new CostrictSlashCommandConfigurator();
35
38
  const qwen = new QwenSlashCommandConfigurator();
39
+ const roocode = new RooCodeSlashCommandConfigurator();
36
40
  this.configurators.set(claude.toolId, claude);
37
41
  this.configurators.set(codeBuddy.toolId, codeBuddy);
38
42
  this.configurators.set(qoder.toolId, qoder);
@@ -44,11 +48,13 @@ export class SlashCommandRegistry {
44
48
  this.configurators.set(githubCopilot.toolId, githubCopilot);
45
49
  this.configurators.set(amazonQ.toolId, amazonQ);
46
50
  this.configurators.set(factory.toolId, factory);
51
+ this.configurators.set(gemini.toolId, gemini);
47
52
  this.configurators.set(auggie.toolId, auggie);
48
53
  this.configurators.set(cline.toolId, cline);
49
54
  this.configurators.set(crush.toolId, crush);
50
55
  this.configurators.set(costrict.toolId, costrict);
51
56
  this.configurators.set(qwen.toolId, qwen);
57
+ this.configurators.set(roocode.toolId, roocode);
52
58
  }
53
59
  static register(configurator) {
54
60
  this.configurators.set(configurator.toolId, configurator);
@@ -0,0 +1,9 @@
1
+ import { SlashCommandConfigurator } from './base.js';
2
+ import { SlashCommandId } from '../../templates/index.js';
3
+ export declare class RooCodeSlashCommandConfigurator extends SlashCommandConfigurator {
4
+ readonly toolId = "roocode";
5
+ readonly isAvailable = true;
6
+ protected getRelativePath(id: SlashCommandId): string;
7
+ protected getFrontmatter(id: SlashCommandId): string | undefined;
8
+ }
9
+ //# sourceMappingURL=roocode.d.ts.map
@@ -0,0 +1,23 @@
1
+ import { SlashCommandConfigurator } from './base.js';
2
+ const NEW_FILE_PATHS = {
3
+ proposal: '.roo/commands/openspec-proposal.md',
4
+ apply: '.roo/commands/openspec-apply.md',
5
+ archive: '.roo/commands/openspec-archive.md'
6
+ };
7
+ export class RooCodeSlashCommandConfigurator extends SlashCommandConfigurator {
8
+ toolId = 'roocode';
9
+ isAvailable = true;
10
+ getRelativePath(id) {
11
+ return NEW_FILE_PATHS[id];
12
+ }
13
+ getFrontmatter(id) {
14
+ const descriptions = {
15
+ proposal: 'Scaffold a new OpenSpec change and validate strictly.',
16
+ apply: 'Implement an approved OpenSpec change and keep tasks in sync.',
17
+ archive: 'Archive a deployed OpenSpec change and update specs.'
18
+ };
19
+ const description = descriptions[id];
20
+ return `# OpenSpec: ${id.charAt(0).toUpperCase() + id.slice(1)}\n\n${description}`;
21
+ }
22
+ }
23
+ //# sourceMappingURL=roocode.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fission-ai/openspec",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "AI-native system for spec-driven development",
5
5
  "keywords": [
6
6
  "openspec",