@fission-ai/openspec 0.18.0 → 0.20.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.
Files changed (47) hide show
  1. package/README.md +59 -0
  2. package/dist/cli/index.js +32 -2
  3. package/dist/commands/artifact-workflow.js +11 -1
  4. package/dist/commands/completion.js +42 -6
  5. package/dist/core/completions/command-registry.js +7 -1
  6. package/dist/core/completions/factory.d.ts +15 -2
  7. package/dist/core/completions/factory.js +19 -1
  8. package/dist/core/completions/generators/bash-generator.d.ts +32 -0
  9. package/dist/core/completions/generators/bash-generator.js +174 -0
  10. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  11. package/dist/core/completions/generators/fish-generator.js +157 -0
  12. package/dist/core/completions/generators/powershell-generator.d.ts +33 -0
  13. package/dist/core/completions/generators/powershell-generator.js +207 -0
  14. package/dist/core/completions/generators/zsh-generator.d.ts +0 -14
  15. package/dist/core/completions/generators/zsh-generator.js +55 -124
  16. package/dist/core/completions/installers/bash-installer.d.ts +87 -0
  17. package/dist/core/completions/installers/bash-installer.js +318 -0
  18. package/dist/core/completions/installers/fish-installer.d.ts +43 -0
  19. package/dist/core/completions/installers/fish-installer.js +143 -0
  20. package/dist/core/completions/installers/powershell-installer.d.ts +88 -0
  21. package/dist/core/completions/installers/powershell-installer.js +327 -0
  22. package/dist/core/completions/installers/zsh-installer.d.ts +1 -12
  23. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  24. package/dist/core/completions/templates/bash-templates.js +24 -0
  25. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  26. package/dist/core/completions/templates/fish-templates.js +39 -0
  27. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  28. package/dist/core/completions/templates/powershell-templates.js +25 -0
  29. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  30. package/dist/core/completions/templates/zsh-templates.js +36 -0
  31. package/dist/core/config.js +1 -0
  32. package/dist/core/configurators/slash/codebuddy.js +6 -9
  33. package/dist/core/configurators/slash/continue.d.ts +9 -0
  34. package/dist/core/configurators/slash/continue.js +46 -0
  35. package/dist/core/configurators/slash/registry.js +3 -0
  36. package/dist/core/templates/agents-template.d.ts +1 -1
  37. package/dist/core/templates/agents-template.js +7 -7
  38. package/dist/core/templates/skill-templates.d.ts +19 -0
  39. package/dist/core/templates/skill-templates.js +817 -20
  40. package/dist/core/templates/slash-command-templates.js +2 -2
  41. package/dist/telemetry/config.d.ts +32 -0
  42. package/dist/telemetry/config.js +68 -0
  43. package/dist/telemetry/index.d.ts +31 -0
  44. package/dist/telemetry/index.js +145 -0
  45. package/dist/utils/file-system.d.ts +6 -0
  46. package/dist/utils/file-system.js +43 -2
  47. package/package.json +3 -2
@@ -0,0 +1,327 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ /**
5
+ * Installer for PowerShell completion scripts.
6
+ * Works with both Windows PowerShell 5.1 and PowerShell Core 7+
7
+ */
8
+ export class PowerShellInstaller {
9
+ homeDir;
10
+ /**
11
+ * Markers for PowerShell profile configuration management
12
+ */
13
+ PROFILE_MARKERS = {
14
+ start: '# OPENSPEC:START',
15
+ end: '# OPENSPEC:END',
16
+ };
17
+ constructor(homeDir = os.homedir()) {
18
+ this.homeDir = homeDir;
19
+ }
20
+ /**
21
+ * Get PowerShell profile path
22
+ * Prefers $PROFILE environment variable, falls back to platform defaults
23
+ *
24
+ * @returns Profile path
25
+ */
26
+ getProfilePath() {
27
+ // Check $PROFILE environment variable (set when running in PowerShell)
28
+ if (process.env.PROFILE) {
29
+ return process.env.PROFILE;
30
+ }
31
+ // Fall back to platform-specific defaults
32
+ if (process.platform === 'win32') {
33
+ // Windows: Documents/PowerShell/Microsoft.PowerShell_profile.ps1
34
+ return path.join(this.homeDir, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1');
35
+ }
36
+ else {
37
+ // macOS/Linux: .config/powershell/Microsoft.PowerShell_profile.ps1
38
+ return path.join(this.homeDir, '.config', 'powershell', 'Microsoft.PowerShell_profile.ps1');
39
+ }
40
+ }
41
+ /**
42
+ * Get all PowerShell profile paths to configure.
43
+ * On Windows, returns both PowerShell Core and Windows PowerShell 5.1 paths.
44
+ * On Unix, returns PowerShell Core path only.
45
+ */
46
+ getAllProfilePaths() {
47
+ // If PROFILE env var is set, use only that path
48
+ if (process.env.PROFILE) {
49
+ return [process.env.PROFILE];
50
+ }
51
+ if (process.platform === 'win32') {
52
+ return [
53
+ // PowerShell Core 6+ (cross-platform)
54
+ path.join(this.homeDir, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1'),
55
+ // Windows PowerShell 5.1 (Windows-only)
56
+ path.join(this.homeDir, 'Documents', 'WindowsPowerShell', 'Microsoft.PowerShell_profile.ps1'),
57
+ ];
58
+ }
59
+ else {
60
+ // Unix systems: PowerShell Core only
61
+ return [path.join(this.homeDir, '.config', 'powershell', 'Microsoft.PowerShell_profile.ps1')];
62
+ }
63
+ }
64
+ /**
65
+ * Get the installation path for the completion script
66
+ *
67
+ * @returns Installation path
68
+ */
69
+ getInstallationPath() {
70
+ const profilePath = this.getProfilePath();
71
+ const profileDir = path.dirname(profilePath);
72
+ return path.join(profileDir, 'OpenSpecCompletion.ps1');
73
+ }
74
+ /**
75
+ * Backup an existing completion file if it exists
76
+ *
77
+ * @param targetPath - Path to the file to backup
78
+ * @returns Path to the backup file, or undefined if no backup was needed
79
+ */
80
+ async backupExistingFile(targetPath) {
81
+ try {
82
+ await fs.access(targetPath);
83
+ // File exists, create a backup
84
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
85
+ const backupPath = `${targetPath}.backup-${timestamp}`;
86
+ await fs.copyFile(targetPath, backupPath);
87
+ return backupPath;
88
+ }
89
+ catch {
90
+ // File doesn't exist, no backup needed
91
+ return undefined;
92
+ }
93
+ }
94
+ /**
95
+ * Generate PowerShell profile configuration content
96
+ *
97
+ * @param scriptPath - Path to the completion script
98
+ * @returns Configuration content
99
+ */
100
+ generateProfileConfig(scriptPath) {
101
+ return [
102
+ '# OpenSpec shell completions configuration',
103
+ `if (Test-Path "${scriptPath}") {`,
104
+ ` . "${scriptPath}"`,
105
+ '}',
106
+ ].join('\n');
107
+ }
108
+ /**
109
+ * Configure PowerShell profile to source the completion script
110
+ *
111
+ * @param scriptPath - Path to the completion script
112
+ * @returns true if configured successfully, false otherwise
113
+ */
114
+ async configureProfile(scriptPath) {
115
+ const profilePaths = this.getAllProfilePaths();
116
+ let anyConfigured = false;
117
+ for (const profilePath of profilePaths) {
118
+ try {
119
+ // Create profile file if it doesn't exist
120
+ const profileDir = path.dirname(profilePath);
121
+ await fs.mkdir(profileDir, { recursive: true });
122
+ let profileContent = '';
123
+ try {
124
+ profileContent = await fs.readFile(profilePath, 'utf-8');
125
+ }
126
+ catch {
127
+ // Profile doesn't exist yet, that's fine
128
+ }
129
+ // Check if already configured
130
+ const scriptLine = `. "${scriptPath}"`;
131
+ if (profileContent.includes(scriptLine)) {
132
+ continue; // Already configured, skip
133
+ }
134
+ // Add OpenSpec completion configuration with markers
135
+ const openspecBlock = [
136
+ '',
137
+ '# OPENSPEC:START - OpenSpec completion (managed block, do not edit manually)',
138
+ scriptLine,
139
+ '# OPENSPEC:END',
140
+ '',
141
+ ].join('\n');
142
+ const newContent = profileContent + openspecBlock;
143
+ await fs.writeFile(profilePath, newContent, 'utf-8');
144
+ anyConfigured = true;
145
+ }
146
+ catch (error) {
147
+ // Continue to next profile if this one fails
148
+ console.warn(`Warning: Could not configure ${profilePath}: ${error}`);
149
+ }
150
+ }
151
+ return anyConfigured;
152
+ }
153
+ /**
154
+ * Remove PowerShell profile configuration
155
+ * Used during uninstallation
156
+ *
157
+ * @returns true if removed successfully, false otherwise
158
+ */
159
+ async removeProfileConfig() {
160
+ const profilePaths = this.getAllProfilePaths();
161
+ let anyRemoved = false;
162
+ for (const profilePath of profilePaths) {
163
+ try {
164
+ // Read profile content
165
+ let profileContent;
166
+ try {
167
+ profileContent = await fs.readFile(profilePath, 'utf-8');
168
+ }
169
+ catch {
170
+ continue; // Profile doesn't exist, nothing to remove
171
+ }
172
+ // Remove OPENSPEC:START -> OPENSPEC:END block
173
+ const startMarker = '# OPENSPEC:START';
174
+ const endMarker = '# OPENSPEC:END';
175
+ const startIndex = profileContent.indexOf(startMarker);
176
+ if (startIndex === -1) {
177
+ continue; // No OpenSpec block found
178
+ }
179
+ const endIndex = profileContent.indexOf(endMarker, startIndex);
180
+ if (endIndex === -1) {
181
+ console.warn(`Warning: Found start marker but no end marker in ${profilePath}`);
182
+ continue;
183
+ }
184
+ // Remove the block (including markers and surrounding newlines)
185
+ const beforeBlock = profileContent.substring(0, startIndex);
186
+ const afterBlock = profileContent.substring(endIndex + endMarker.length);
187
+ // Clean up extra newlines
188
+ const newContent = (beforeBlock.trimEnd() + '\n' + afterBlock.trimStart()).trim() + '\n';
189
+ await fs.writeFile(profilePath, newContent, 'utf-8');
190
+ anyRemoved = true;
191
+ }
192
+ catch (error) {
193
+ console.warn(`Warning: Could not clean ${profilePath}: ${error}`);
194
+ }
195
+ }
196
+ return anyRemoved;
197
+ }
198
+ /**
199
+ * Install the completion script
200
+ *
201
+ * @param completionScript - The completion script content to install
202
+ * @returns Installation result with status and instructions
203
+ */
204
+ async install(completionScript) {
205
+ try {
206
+ const targetPath = this.getInstallationPath();
207
+ // Check if already installed with same content
208
+ let isUpdate = false;
209
+ try {
210
+ const existingContent = await fs.readFile(targetPath, 'utf-8');
211
+ if (existingContent === completionScript) {
212
+ // Already installed and up to date
213
+ return {
214
+ success: true,
215
+ installedPath: targetPath,
216
+ message: 'Completion script is already installed (up to date)',
217
+ instructions: [
218
+ 'The completion script is already installed and up to date.',
219
+ 'If completions are not working, try restarting PowerShell or run: . $PROFILE',
220
+ ],
221
+ };
222
+ }
223
+ // File exists but content is different - this is an update
224
+ isUpdate = true;
225
+ }
226
+ catch (error) {
227
+ // File doesn't exist or can't be read, proceed with installation
228
+ console.debug(`Unable to read existing completion file at ${targetPath}: ${error.message}`);
229
+ }
230
+ // Ensure the directory exists
231
+ const targetDir = path.dirname(targetPath);
232
+ await fs.mkdir(targetDir, { recursive: true });
233
+ // Backup existing file if updating
234
+ const backupPath = isUpdate ? await this.backupExistingFile(targetPath) : undefined;
235
+ // Write the completion script
236
+ await fs.writeFile(targetPath, completionScript, 'utf-8');
237
+ // Auto-configure PowerShell profile
238
+ const profileConfigured = await this.configureProfile(targetPath);
239
+ // Generate instructions if profile wasn't auto-configured
240
+ const instructions = profileConfigured ? undefined : this.generateInstructions(targetPath);
241
+ // Determine appropriate message
242
+ let message;
243
+ if (isUpdate) {
244
+ message = backupPath
245
+ ? 'Completion script updated successfully (previous version backed up)'
246
+ : 'Completion script updated successfully';
247
+ }
248
+ else {
249
+ message = profileConfigured
250
+ ? 'Completion script installed and PowerShell profile configured successfully'
251
+ : 'Completion script installed successfully for PowerShell';
252
+ }
253
+ return {
254
+ success: true,
255
+ installedPath: targetPath,
256
+ backupPath,
257
+ profileConfigured,
258
+ message,
259
+ instructions,
260
+ };
261
+ }
262
+ catch (error) {
263
+ return {
264
+ success: false,
265
+ message: `Failed to install completion script: ${error instanceof Error ? error.message : String(error)}`,
266
+ };
267
+ }
268
+ }
269
+ /**
270
+ * Generate user instructions for enabling completions
271
+ *
272
+ * @param installedPath - Path where the script was installed
273
+ * @returns Array of instruction strings
274
+ */
275
+ generateInstructions(installedPath) {
276
+ const profilePath = this.getProfilePath();
277
+ return [
278
+ 'Completion script installed successfully.',
279
+ '',
280
+ `To enable completions, add the following to your PowerShell profile (${profilePath}):`,
281
+ '',
282
+ ' # Source OpenSpec completions',
283
+ ` if (Test-Path "${installedPath}") {`,
284
+ ` . "${installedPath}"`,
285
+ ' }',
286
+ '',
287
+ 'Then restart PowerShell or run: . $PROFILE',
288
+ ];
289
+ }
290
+ /**
291
+ * Uninstall the completion script
292
+ *
293
+ * @param options - Optional uninstall options
294
+ * @param options.yes - Skip confirmation prompt (handled by command layer)
295
+ * @returns Uninstallation result
296
+ */
297
+ async uninstall(options) {
298
+ try {
299
+ const targetPath = this.getInstallationPath();
300
+ // Check if installed
301
+ try {
302
+ await fs.access(targetPath);
303
+ }
304
+ catch {
305
+ return {
306
+ success: false,
307
+ message: 'Completion script is not installed',
308
+ };
309
+ }
310
+ // Remove the completion script
311
+ await fs.unlink(targetPath);
312
+ // Remove profile configuration
313
+ await this.removeProfileConfig();
314
+ return {
315
+ success: true,
316
+ message: 'Completion script uninstalled successfully',
317
+ };
318
+ }
319
+ catch (error) {
320
+ return {
321
+ success: false,
322
+ message: `Failed to uninstall completion script: ${error instanceof Error ? error.message : String(error)}`,
323
+ };
324
+ }
325
+ }
326
+ }
327
+ //# sourceMappingURL=powershell-installer.js.map
@@ -1,15 +1,4 @@
1
- /**
2
- * Installation result information
3
- */
4
- export interface InstallationResult {
5
- success: boolean;
6
- installedPath?: string;
7
- backupPath?: string;
8
- isOhMyZsh: boolean;
9
- zshrcConfigured?: boolean;
10
- message: string;
11
- instructions?: string[];
12
- }
1
+ import { InstallationResult } from '../factory.js';
13
2
  /**
14
3
  * Installer for Zsh completion scripts.
15
4
  * Supports both Oh My Zsh and standard Zsh configurations.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Static template strings for Bash completion scripts.
3
+ * These are Bash-specific helper functions that never change.
4
+ */
5
+ export declare const BASH_DYNAMIC_HELPERS = "# Dynamic completion helpers\n\n_openspec_complete_changes() {\n local changes\n changes=$(openspec __complete changes 2>/dev/null | cut -f1)\n COMPREPLY=($(compgen -W \"$changes\" -- \"$cur\"))\n}\n\n_openspec_complete_specs() {\n local specs\n specs=$(openspec __complete specs 2>/dev/null | cut -f1)\n COMPREPLY=($(compgen -W \"$specs\" -- \"$cur\"))\n}\n\n_openspec_complete_items() {\n local items\n items=$(openspec __complete changes 2>/dev/null | cut -f1; openspec __complete specs 2>/dev/null | cut -f1)\n COMPREPLY=($(compgen -W \"$items\" -- \"$cur\"))\n}";
6
+ //# sourceMappingURL=bash-templates.d.ts.map
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Static template strings for Bash completion scripts.
3
+ * These are Bash-specific helper functions that never change.
4
+ */
5
+ export const BASH_DYNAMIC_HELPERS = `# Dynamic completion helpers
6
+
7
+ _openspec_complete_changes() {
8
+ local changes
9
+ changes=$(openspec __complete changes 2>/dev/null | cut -f1)
10
+ COMPREPLY=($(compgen -W "$changes" -- "$cur"))
11
+ }
12
+
13
+ _openspec_complete_specs() {
14
+ local specs
15
+ specs=$(openspec __complete specs 2>/dev/null | cut -f1)
16
+ COMPREPLY=($(compgen -W "$specs" -- "$cur"))
17
+ }
18
+
19
+ _openspec_complete_items() {
20
+ local items
21
+ items=$(openspec __complete changes 2>/dev/null | cut -f1; openspec __complete specs 2>/dev/null | cut -f1)
22
+ COMPREPLY=($(compgen -W "$items" -- "$cur"))
23
+ }`;
24
+ //# sourceMappingURL=bash-templates.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Static template strings for Fish completion scripts.
3
+ * These are Fish-specific helper functions that never change.
4
+ */
5
+ export declare const FISH_STATIC_HELPERS = "# Helper function to check if a subcommand is present\nfunction __fish_openspec_using_subcommand\n set -l cmd (commandline -opc)\n set -e cmd[1]\n for i in $argv\n if contains -- $i $cmd\n return 0\n end\n end\n return 1\nend\n\nfunction __fish_openspec_no_subcommand\n set -l cmd (commandline -opc)\n test (count $cmd) -eq 1\nend";
6
+ export declare const FISH_DYNAMIC_HELPERS = "# Dynamic completion helpers\n\nfunction __fish_openspec_changes\n openspec __complete changes 2>/dev/null | while read -l id desc\n printf '%s\\t%s\\n' \"$id\" \"$desc\"\n end\nend\n\nfunction __fish_openspec_specs\n openspec __complete specs 2>/dev/null | while read -l id desc\n printf '%s\\t%s\\n' \"$id\" \"$desc\"\n end\nend\n\nfunction __fish_openspec_items\n __fish_openspec_changes\n __fish_openspec_specs\nend";
7
+ //# sourceMappingURL=fish-templates.d.ts.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Static template strings for Fish completion scripts.
3
+ * These are Fish-specific helper functions that never change.
4
+ */
5
+ export const FISH_STATIC_HELPERS = `# Helper function to check if a subcommand is present
6
+ function __fish_openspec_using_subcommand
7
+ set -l cmd (commandline -opc)
8
+ set -e cmd[1]
9
+ for i in $argv
10
+ if contains -- $i $cmd
11
+ return 0
12
+ end
13
+ end
14
+ return 1
15
+ end
16
+
17
+ function __fish_openspec_no_subcommand
18
+ set -l cmd (commandline -opc)
19
+ test (count $cmd) -eq 1
20
+ end`;
21
+ export const FISH_DYNAMIC_HELPERS = `# Dynamic completion helpers
22
+
23
+ function __fish_openspec_changes
24
+ openspec __complete changes 2>/dev/null | while read -l id desc
25
+ printf '%s\\t%s\\n' "$id" "$desc"
26
+ end
27
+ end
28
+
29
+ function __fish_openspec_specs
30
+ openspec __complete specs 2>/dev/null | while read -l id desc
31
+ printf '%s\\t%s\\n' "$id" "$desc"
32
+ end
33
+ end
34
+
35
+ function __fish_openspec_items
36
+ __fish_openspec_changes
37
+ __fish_openspec_specs
38
+ end`;
39
+ //# sourceMappingURL=fish-templates.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Static template strings for PowerShell completion scripts.
3
+ * These are PowerShell-specific helper functions that never change.
4
+ */
5
+ export declare const POWERSHELL_DYNAMIC_HELPERS = "# Dynamic completion helpers\n\nfunction Get-OpenSpecChanges {\n $output = openspec __complete changes 2>$null\n if ($output) {\n $output | ForEach-Object {\n ($_ -split \"\\t\")[0]\n }\n }\n}\n\nfunction Get-OpenSpecSpecs {\n $output = openspec __complete specs 2>$null\n if ($output) {\n $output | ForEach-Object {\n ($_ -split \"\\t\")[0]\n }\n }\n}\n";
6
+ //# sourceMappingURL=powershell-templates.d.ts.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Static template strings for PowerShell completion scripts.
3
+ * These are PowerShell-specific helper functions that never change.
4
+ */
5
+ export const POWERSHELL_DYNAMIC_HELPERS = `# Dynamic completion helpers
6
+
7
+ function Get-OpenSpecChanges {
8
+ $output = openspec __complete changes 2>$null
9
+ if ($output) {
10
+ $output | ForEach-Object {
11
+ ($_ -split "\\t")[0]
12
+ }
13
+ }
14
+ }
15
+
16
+ function Get-OpenSpecSpecs {
17
+ $output = openspec __complete specs 2>$null
18
+ if ($output) {
19
+ $output | ForEach-Object {
20
+ ($_ -split "\\t")[0]
21
+ }
22
+ }
23
+ }
24
+ `;
25
+ //# sourceMappingURL=powershell-templates.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Static template strings for Zsh completion scripts.
3
+ * These are Zsh-specific helper functions that never change.
4
+ */
5
+ export declare const ZSH_DYNAMIC_HELPERS = "# Dynamic completion helpers\n\n# Use openspec __complete to get available changes\n_openspec_complete_changes() {\n local -a changes\n while IFS=$'\\t' read -r id desc; do\n changes+=(\"$id:$desc\")\n done < <(openspec __complete changes 2>/dev/null)\n _describe \"change\" changes\n}\n\n# Use openspec __complete to get available specs\n_openspec_complete_specs() {\n local -a specs\n while IFS=$'\\t' read -r id desc; do\n specs+=(\"$id:$desc\")\n done < <(openspec __complete specs 2>/dev/null)\n _describe \"spec\" specs\n}\n\n# Get both changes and specs\n_openspec_complete_items() {\n local -a items\n while IFS=$'\\t' read -r id desc; do\n items+=(\"$id:$desc\")\n done < <(openspec __complete changes 2>/dev/null)\n while IFS=$'\\t' read -r id desc; do\n items+=(\"$id:$desc\")\n done < <(openspec __complete specs 2>/dev/null)\n _describe \"item\" items\n}";
6
+ //# sourceMappingURL=zsh-templates.d.ts.map
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Static template strings for Zsh completion scripts.
3
+ * These are Zsh-specific helper functions that never change.
4
+ */
5
+ export const ZSH_DYNAMIC_HELPERS = `# Dynamic completion helpers
6
+
7
+ # Use openspec __complete to get available changes
8
+ _openspec_complete_changes() {
9
+ local -a changes
10
+ while IFS=$'\\t' read -r id desc; do
11
+ changes+=("$id:$desc")
12
+ done < <(openspec __complete changes 2>/dev/null)
13
+ _describe "change" changes
14
+ }
15
+
16
+ # Use openspec __complete to get available specs
17
+ _openspec_complete_specs() {
18
+ local -a specs
19
+ while IFS=$'\\t' read -r id desc; do
20
+ specs+=("$id:$desc")
21
+ done < <(openspec __complete specs 2>/dev/null)
22
+ _describe "spec" specs
23
+ }
24
+
25
+ # Get both changes and specs
26
+ _openspec_complete_items() {
27
+ local -a items
28
+ while IFS=$'\\t' read -r id desc; do
29
+ items+=("$id:$desc")
30
+ done < <(openspec __complete changes 2>/dev/null)
31
+ while IFS=$'\\t' read -r id desc; do
32
+ items+=("$id:$desc")
33
+ done < <(openspec __complete specs 2>/dev/null)
34
+ _describe "item" items
35
+ }`;
36
+ //# sourceMappingURL=zsh-templates.js.map
@@ -11,6 +11,7 @@ export const AI_TOOLS = [
11
11
  { name: 'Cline', value: 'cline', available: true, successLabel: 'Cline' },
12
12
  { name: 'Codex', value: 'codex', available: true, successLabel: 'Codex' },
13
13
  { name: 'CodeBuddy Code (CLI)', value: 'codebuddy', available: true, successLabel: 'CodeBuddy Code' },
14
+ { name: 'Continue', value: 'continue', available: true, successLabel: 'Continue (VS Code / JetBrains / Cli)' },
14
15
  { name: 'CoStrict', value: 'costrict', available: true, successLabel: 'CoStrict' },
15
16
  { name: 'Crush', value: 'crush', available: true, successLabel: 'Crush' },
16
17
  { name: 'Cursor', value: 'cursor', available: true, successLabel: 'Cursor' },
@@ -7,21 +7,18 @@ const FILE_PATHS = {
7
7
  const FRONTMATTER = {
8
8
  proposal: `---
9
9
  name: OpenSpec: Proposal
10
- description: Scaffold a new OpenSpec change and validate strictly.
11
- category: OpenSpec
12
- tags: [openspec, change]
10
+ description: "Scaffold a new OpenSpec change and validate strictly."
11
+ argument-hint: "[feature description or request]"
13
12
  ---`,
14
13
  apply: `---
15
14
  name: OpenSpec: Apply
16
- description: Implement an approved OpenSpec change and keep tasks in sync.
17
- category: OpenSpec
18
- tags: [openspec, apply]
15
+ description: "Implement an approved OpenSpec change and keep tasks in sync."
16
+ argument-hint: "[change-id]"
19
17
  ---`,
20
18
  archive: `---
21
19
  name: OpenSpec: Archive
22
- description: Archive a deployed OpenSpec change and update specs.
23
- category: OpenSpec
24
- tags: [openspec, archive]
20
+ description: "Archive a deployed OpenSpec change and update specs."
21
+ argument-hint: "[change-id]"
25
22
  ---`
26
23
  };
27
24
  export class CodeBuddySlashCommandConfigurator extends SlashCommandConfigurator {
@@ -0,0 +1,9 @@
1
+ import { SlashCommandConfigurator } from './base.js';
2
+ import { SlashCommandId } from '../../templates/index.js';
3
+ export declare class ContinueSlashCommandConfigurator extends SlashCommandConfigurator {
4
+ readonly toolId = "continue";
5
+ readonly isAvailable = true;
6
+ protected getRelativePath(id: SlashCommandId): string;
7
+ protected getFrontmatter(id: SlashCommandId): string;
8
+ }
9
+ //# sourceMappingURL=continue.d.ts.map
@@ -0,0 +1,46 @@
1
+ import { SlashCommandConfigurator } from './base.js';
2
+ const FILE_PATHS = {
3
+ proposal: '.continue/prompts/openspec-proposal.prompt',
4
+ apply: '.continue/prompts/openspec-apply.prompt',
5
+ archive: '.continue/prompts/openspec-archive.prompt'
6
+ };
7
+ /*
8
+ * Continue .prompt format requires YAML frontmatter:
9
+ * ---
10
+ * name: commandName
11
+ * description: description
12
+ * invokable: true
13
+ * ---
14
+ * Body...
15
+ *
16
+ * The 'invokable: true' field is required to make the prompt available as a slash command.
17
+ * We use 'openspec-proposal' as the name so the command becomes /openspec-proposal.
18
+ */
19
+ const FRONTMATTER = {
20
+ proposal: `---
21
+ name: openspec-proposal
22
+ description: Scaffold a new OpenSpec change and validate strictly.
23
+ invokable: true
24
+ ---`,
25
+ apply: `---
26
+ name: openspec-apply
27
+ description: Implement an approved OpenSpec change and keep tasks in sync.
28
+ invokable: true
29
+ ---`,
30
+ archive: `---
31
+ name: openspec-archive
32
+ description: Archive a deployed OpenSpec change and update specs.
33
+ invokable: true
34
+ ---`
35
+ };
36
+ export class ContinueSlashCommandConfigurator extends SlashCommandConfigurator {
37
+ toolId = 'continue';
38
+ isAvailable = true;
39
+ getRelativePath(id) {
40
+ return FILE_PATHS[id];
41
+ }
42
+ getFrontmatter(id) {
43
+ return FRONTMATTER[id];
44
+ }
45
+ }
46
+ //# sourceMappingURL=continue.js.map
@@ -18,6 +18,7 @@ import { QwenSlashCommandConfigurator } from './qwen.js';
18
18
  import { RooCodeSlashCommandConfigurator } from './roocode.js';
19
19
  import { AntigravitySlashCommandConfigurator } from './antigravity.js';
20
20
  import { IflowSlashCommandConfigurator } from './iflow.js';
21
+ import { ContinueSlashCommandConfigurator } from './continue.js';
21
22
  export class SlashCommandRegistry {
22
23
  static configurators = new Map();
23
24
  static {
@@ -41,6 +42,7 @@ export class SlashCommandRegistry {
41
42
  const roocode = new RooCodeSlashCommandConfigurator();
42
43
  const antigravity = new AntigravitySlashCommandConfigurator();
43
44
  const iflow = new IflowSlashCommandConfigurator();
45
+ const continueTool = new ContinueSlashCommandConfigurator();
44
46
  this.configurators.set(claude.toolId, claude);
45
47
  this.configurators.set(codeBuddy.toolId, codeBuddy);
46
48
  this.configurators.set(qoder.toolId, qoder);
@@ -61,6 +63,7 @@ export class SlashCommandRegistry {
61
63
  this.configurators.set(roocode.toolId, roocode);
62
64
  this.configurators.set(antigravity.toolId, antigravity);
63
65
  this.configurators.set(iflow.toolId, iflow);
66
+ this.configurators.set(continueTool.toolId, continueTool);
64
67
  }
65
68
  static register(configurator) {
66
69
  this.configurators.set(configurator.toolId, configurator);