@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 +5 -3
- package/dist/core/config.js +2 -0
- package/dist/core/configurators/slash/cline.js +3 -3
- package/dist/core/configurators/slash/gemini.d.ts +12 -0
- package/dist/core/configurators/slash/gemini.js +68 -0
- package/dist/core/configurators/slash/registry.js +6 -0
- package/dist/core/configurators/slash/roocode.d.ts +9 -0
- package/dist/core/configurators/slash/roocode.js +23 -0
- package/package.json +1 -1
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** |
|
|
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 •
|
|
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
|
|
package/dist/core/config.js
CHANGED
|
@@ -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
|