@fission-ai/openspec 1.3.1 → 1.4.1

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 (165) hide show
  1. package/README.md +9 -2
  2. package/bin/openspec.js +3 -1
  3. package/dist/cli/index.d.ts +4 -1
  4. package/dist/cli/index.js +65 -3
  5. package/dist/commands/completion.js +7 -0
  6. package/dist/commands/config.js +64 -5
  7. package/dist/commands/context-store.d.ts +3 -0
  8. package/dist/commands/context-store.js +475 -0
  9. package/dist/commands/initiative.d.ts +13 -0
  10. package/dist/commands/initiative.js +318 -0
  11. package/dist/commands/workflow/index.d.ts +2 -0
  12. package/dist/commands/workflow/index.js +1 -0
  13. package/dist/commands/workflow/initiative-link.d.ts +24 -0
  14. package/dist/commands/workflow/initiative-link.js +47 -0
  15. package/dist/commands/workflow/instructions.d.ts +1 -1
  16. package/dist/commands/workflow/instructions.js +28 -11
  17. package/dist/commands/workflow/new-change.d.ts +6 -0
  18. package/dist/commands/workflow/new-change.js +114 -17
  19. package/dist/commands/workflow/set-change.d.ts +13 -0
  20. package/dist/commands/workflow/set-change.js +87 -0
  21. package/dist/commands/workflow/shared.d.ts +4 -2
  22. package/dist/commands/workflow/shared.js +6 -6
  23. package/dist/commands/workflow/status.js +19 -4
  24. package/dist/commands/workspace/context-status.d.ts +4 -0
  25. package/dist/commands/workspace/context-status.js +59 -0
  26. package/dist/commands/workspace/open-target-selection.d.ts +13 -0
  27. package/dist/commands/workspace/open-target-selection.js +146 -0
  28. package/dist/commands/workspace/open-view.d.ts +62 -0
  29. package/dist/commands/workspace/open-view.js +249 -0
  30. package/dist/commands/workspace/open.d.ts +37 -0
  31. package/dist/commands/workspace/open.js +110 -0
  32. package/dist/commands/workspace/opener-selection.d.ts +11 -0
  33. package/dist/commands/workspace/opener-selection.js +98 -0
  34. package/dist/commands/workspace/operations.d.ts +29 -0
  35. package/dist/commands/workspace/operations.js +543 -0
  36. package/dist/commands/workspace/prompt-theme.d.ts +29 -0
  37. package/dist/commands/workspace/prompt-theme.js +24 -0
  38. package/dist/commands/workspace/registration.d.ts +13 -0
  39. package/dist/commands/workspace/registration.js +84 -0
  40. package/dist/commands/workspace/selection.d.ts +8 -0
  41. package/dist/commands/workspace/selection.js +104 -0
  42. package/dist/commands/workspace/setup-prompts.d.ts +13 -0
  43. package/dist/commands/workspace/setup-prompts.js +121 -0
  44. package/dist/commands/workspace/types.d.ts +103 -0
  45. package/dist/commands/workspace/types.js +36 -0
  46. package/dist/commands/workspace.d.ts +5 -0
  47. package/dist/commands/workspace.js +574 -0
  48. package/dist/core/artifact-graph/index.d.ts +2 -1
  49. package/dist/core/artifact-graph/instruction-loader.d.ts +41 -1
  50. package/dist/core/artifact-graph/instruction-loader.js +46 -6
  51. package/dist/core/artifact-graph/types.d.ts +0 -5
  52. package/dist/core/artifact-graph/types.js +0 -14
  53. package/dist/core/change-metadata/index.d.ts +2 -0
  54. package/dist/core/change-metadata/index.js +2 -0
  55. package/dist/core/change-metadata/schema.d.ts +18 -0
  56. package/dist/core/change-metadata/schema.js +28 -0
  57. package/dist/core/change-status-policy.d.ts +50 -0
  58. package/dist/core/change-status-policy.js +70 -0
  59. package/dist/core/collections/index.d.ts +3 -0
  60. package/dist/core/collections/index.js +3 -0
  61. package/dist/core/collections/initiatives/collection.d.ts +4 -0
  62. package/dist/core/collections/initiatives/collection.js +17 -0
  63. package/dist/core/collections/initiatives/index.d.ts +6 -0
  64. package/dist/core/collections/initiatives/index.js +6 -0
  65. package/dist/core/collections/initiatives/operations.d.ts +49 -0
  66. package/dist/core/collections/initiatives/operations.js +175 -0
  67. package/dist/core/collections/initiatives/resolution.d.ts +87 -0
  68. package/dist/core/collections/initiatives/resolution.js +374 -0
  69. package/dist/core/collections/initiatives/schema.d.ts +41 -0
  70. package/dist/core/collections/initiatives/schema.js +134 -0
  71. package/dist/core/collections/initiatives/templates.d.ts +12 -0
  72. package/dist/core/collections/initiatives/templates.js +90 -0
  73. package/dist/core/collections/runtime.d.ts +46 -0
  74. package/dist/core/collections/runtime.js +194 -0
  75. package/dist/core/completions/command-registry.d.ts +1 -5
  76. package/dist/core/completions/command-registry.js +532 -32
  77. package/dist/core/completions/completion-provider.d.ts +11 -0
  78. package/dist/core/completions/completion-provider.js +27 -0
  79. package/dist/core/completions/generators/bash-generator.d.ts +3 -0
  80. package/dist/core/completions/generators/bash-generator.js +60 -4
  81. package/dist/core/completions/generators/fish-generator.js +3 -0
  82. package/dist/core/completions/generators/powershell-generator.d.ts +3 -0
  83. package/dist/core/completions/generators/powershell-generator.js +63 -4
  84. package/dist/core/completions/generators/zsh-generator.d.ts +3 -0
  85. package/dist/core/completions/generators/zsh-generator.js +46 -22
  86. package/dist/core/completions/installers/zsh-installer.d.ts +0 -8
  87. package/dist/core/completions/installers/zsh-installer.js +3 -31
  88. package/dist/core/completions/shared-flags.d.ts +12 -0
  89. package/dist/core/completions/shared-flags.js +28 -0
  90. package/dist/core/completions/templates/bash-templates.d.ts +1 -1
  91. package/dist/core/completions/templates/bash-templates.js +6 -0
  92. package/dist/core/completions/templates/fish-templates.d.ts +1 -1
  93. package/dist/core/completions/templates/fish-templates.js +6 -0
  94. package/dist/core/completions/templates/powershell-templates.d.ts +1 -1
  95. package/dist/core/completions/templates/powershell-templates.js +9 -0
  96. package/dist/core/completions/templates/zsh-templates.d.ts +1 -1
  97. package/dist/core/completions/templates/zsh-templates.js +9 -0
  98. package/dist/core/completions/types.d.ts +23 -1
  99. package/dist/core/config.js +3 -1
  100. package/dist/core/context-store/binding.d.ts +53 -0
  101. package/dist/core/context-store/binding.js +197 -0
  102. package/dist/core/context-store/errors.d.ts +20 -0
  103. package/dist/core/context-store/errors.js +22 -0
  104. package/dist/core/context-store/foundation.d.ts +55 -0
  105. package/dist/core/context-store/foundation.js +321 -0
  106. package/dist/core/context-store/index.d.ts +6 -0
  107. package/dist/core/context-store/index.js +6 -0
  108. package/dist/core/context-store/operations.d.ts +85 -0
  109. package/dist/core/context-store/operations.js +528 -0
  110. package/dist/core/context-store/registry.d.ts +45 -0
  111. package/dist/core/context-store/registry.js +229 -0
  112. package/dist/core/global-config.d.ts +6 -1
  113. package/dist/core/global-config.js +15 -16
  114. package/dist/core/index.d.ts +5 -1
  115. package/dist/core/index.js +4 -0
  116. package/dist/core/parsers/requirement-blocks.js +5 -5
  117. package/dist/core/parsers/spec-structure.js +1 -1
  118. package/dist/core/planning-home.d.ts +21 -0
  119. package/dist/core/planning-home.js +108 -0
  120. package/dist/core/profiles.d.ts +1 -1
  121. package/dist/core/profiles.js +1 -1
  122. package/dist/core/specs-apply.js +1 -1
  123. package/dist/core/templates/workflows/apply-change.js +6 -0
  124. package/dist/core/templates/workflows/archive-change.js +21 -15
  125. package/dist/core/templates/workflows/bulk-archive-change.js +14 -10
  126. package/dist/core/templates/workflows/continue-change.js +6 -4
  127. package/dist/core/templates/workflows/explore.js +8 -10
  128. package/dist/core/templates/workflows/ff-change.js +8 -6
  129. package/dist/core/templates/workflows/new-change.js +6 -6
  130. package/dist/core/templates/workflows/onboard.js +13 -15
  131. package/dist/core/templates/workflows/propose.js +8 -6
  132. package/dist/core/templates/workflows/sync-specs.js +28 -10
  133. package/dist/core/templates/workflows/verify-change.js +10 -4
  134. package/dist/core/update.d.ts +5 -0
  135. package/dist/core/update.js +20 -0
  136. package/dist/core/validation/validator.d.ts +11 -0
  137. package/dist/core/validation/validator.js +19 -2
  138. package/dist/core/workspace/foundation.d.ts +67 -0
  139. package/dist/core/workspace/foundation.js +295 -0
  140. package/dist/core/workspace/index.d.ts +8 -0
  141. package/dist/core/workspace/index.js +8 -0
  142. package/dist/core/workspace/legacy-state.d.ts +28 -0
  143. package/dist/core/workspace/legacy-state.js +200 -0
  144. package/dist/core/workspace/link-input.d.ts +9 -0
  145. package/dist/core/workspace/link-input.js +32 -0
  146. package/dist/core/workspace/open-surface.d.ts +45 -0
  147. package/dist/core/workspace/open-surface.js +215 -0
  148. package/dist/core/workspace/openers.d.ts +21 -0
  149. package/dist/core/workspace/openers.js +124 -0
  150. package/dist/core/workspace/registry.d.ts +24 -0
  151. package/dist/core/workspace/registry.js +146 -0
  152. package/dist/core/workspace/skills.d.ts +57 -0
  153. package/dist/core/workspace/skills.js +334 -0
  154. package/dist/core/workspace/state-io.d.ts +10 -0
  155. package/dist/core/workspace/state-io.js +121 -0
  156. package/dist/utils/change-metadata.d.ts +5 -2
  157. package/dist/utils/change-metadata.js +7 -13
  158. package/dist/utils/change-utils.d.ts +9 -0
  159. package/dist/utils/change-utils.js +7 -5
  160. package/package.json +2 -1
  161. package/schemas/workspace-planning/schema.yaml +72 -0
  162. package/schemas/workspace-planning/templates/design.md +33 -0
  163. package/schemas/workspace-planning/templates/proposal.md +28 -0
  164. package/schemas/workspace-planning/templates/spec.md +9 -0
  165. package/schemas/workspace-planning/templates/tasks.md +15 -0
@@ -9,6 +9,7 @@ export declare class CompletionProvider {
9
9
  private readonly cacheTTL;
10
10
  private changeCache;
11
11
  private specCache;
12
+ private schemaCache;
12
13
  /**
13
14
  * Creates a new completion provider
14
15
  *
@@ -28,6 +29,12 @@ export declare class CompletionProvider {
28
29
  * @returns Array of spec IDs
29
30
  */
30
31
  getSpecIds(): Promise<string[]>;
32
+ /**
33
+ * Get all schema names for completion
34
+ *
35
+ * @returns Array of schema names
36
+ */
37
+ getSchemaNames(): Promise<string[]>;
31
38
  /**
32
39
  * Get both change and spec IDs for completion
33
40
  *
@@ -55,6 +62,10 @@ export declare class CompletionProvider {
55
62
  valid: boolean;
56
63
  age?: number;
57
64
  };
65
+ schemaCache: {
66
+ valid: boolean;
67
+ age?: number;
68
+ };
58
69
  };
59
70
  }
60
71
  //# sourceMappingURL=completion-provider.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import { getActiveChangeIds, getSpecIds } from '../../utils/item-discovery.js';
2
+ import { listSchemas } from '../artifact-graph/index.js';
2
3
  /**
3
4
  * Provides dynamic completion suggestions for OpenSpec items (changes and specs).
4
5
  * Implements a 2-second cache to avoid excessive file system operations during
@@ -10,6 +11,7 @@ export class CompletionProvider {
10
11
  cacheTTL;
11
12
  changeCache = null;
12
13
  specCache = null;
14
+ schemaCache = null;
13
15
  /**
14
16
  * Creates a new completion provider
15
17
  *
@@ -61,6 +63,26 @@ export class CompletionProvider {
61
63
  };
62
64
  return specIds;
63
65
  }
66
+ /**
67
+ * Get all schema names for completion
68
+ *
69
+ * @returns Array of schema names
70
+ */
71
+ async getSchemaNames() {
72
+ const now = Date.now();
73
+ // Check if cache is valid
74
+ if (this.schemaCache && now - this.schemaCache.timestamp < this.cacheTTL) {
75
+ return this.schemaCache.data;
76
+ }
77
+ // Fetch fresh data
78
+ const schemaNames = listSchemas(this.projectRoot);
79
+ // Update cache
80
+ this.schemaCache = {
81
+ data: schemaNames,
82
+ timestamp: now,
83
+ };
84
+ return schemaNames;
85
+ }
64
86
  /**
65
87
  * Get both change and spec IDs for completion
66
88
  *
@@ -79,6 +101,7 @@ export class CompletionProvider {
79
101
  clearCache() {
80
102
  this.changeCache = null;
81
103
  this.specCache = null;
104
+ this.schemaCache = null;
82
105
  }
83
106
  /**
84
107
  * Get cache statistics for debugging
@@ -96,6 +119,10 @@ export class CompletionProvider {
96
119
  valid: this.specCache !== null && now - this.specCache.timestamp < this.cacheTTL,
97
120
  age: this.specCache ? now - this.specCache.timestamp : undefined,
98
121
  },
122
+ schemaCache: {
123
+ valid: this.schemaCache !== null && now - this.schemaCache.timestamp < this.cacheTTL,
124
+ age: this.schemaCache ? now - this.schemaCache.timestamp : undefined,
125
+ },
99
126
  };
100
127
  }
101
128
  }
@@ -24,6 +24,9 @@ export declare class BashGenerator implements CompletionGenerator {
24
24
  * Generate positional argument completion based on type
25
25
  */
26
26
  private generatePositionalCompletion;
27
+ private generateIndexedPositionalCompletion;
28
+ private generateValueFlagCases;
29
+ private generateIndexedPositionalCase;
27
30
  /**
28
31
  * Escape command/subcommand names for safe use in Bash scripts
29
32
  */
@@ -100,21 +100,21 @@ complete -F _openspec_completion openspec
100
100
  lines.push(`${indent}case "$subcmd" in`);
101
101
  for (const subcmd of cmd.subcommands) {
102
102
  lines.push(`${indent} ${subcmd.name})`);
103
- lines.push(...this.generateArgumentCompletion(subcmd, indent + ' '));
103
+ lines.push(...this.generateArgumentCompletion(subcmd, indent + ' ', 3));
104
104
  lines.push(`${indent} ;;`);
105
105
  }
106
106
  lines.push(`${indent}esac`);
107
107
  }
108
108
  else {
109
109
  // No subcommands, just complete arguments
110
- lines.push(...this.generateArgumentCompletion(cmd, indent));
110
+ lines.push(...this.generateArgumentCompletion(cmd, indent, 2));
111
111
  }
112
112
  return lines;
113
113
  }
114
114
  /**
115
115
  * Generate argument completion (flags and positional arguments)
116
116
  */
117
- generateArgumentCompletion(cmd, indent) {
117
+ generateArgumentCompletion(cmd, indent, firstPositionalWordIndex) {
118
118
  const lines = [];
119
119
  // Check for flag completion
120
120
  if (cmd.flags.length > 0) {
@@ -133,7 +133,10 @@ complete -F _openspec_completion openspec
133
133
  lines.push('');
134
134
  }
135
135
  // Handle positional completions
136
- if (cmd.acceptsPositional) {
136
+ if (cmd.positionals && cmd.positionals.length > 0) {
137
+ lines.push(...this.generateIndexedPositionalCompletion(cmd.positionals, cmd.flags, firstPositionalWordIndex, indent));
138
+ }
139
+ else if (cmd.acceptsPositional) {
137
140
  lines.push(...this.generatePositionalCompletion(cmd.positionalType, indent));
138
141
  }
139
142
  return lines;
@@ -153,6 +156,9 @@ complete -F _openspec_completion openspec
153
156
  case 'change-or-spec-id':
154
157
  lines.push(`${indent}_openspec_complete_items`);
155
158
  break;
159
+ case 'schema-name':
160
+ lines.push(`${indent}_openspec_complete_schemas`);
161
+ break;
156
162
  case 'shell':
157
163
  lines.push(`${indent}local shells="zsh bash fish powershell"`);
158
164
  lines.push(`${indent}COMPREPLY=($(compgen -W "$shells" -- "$cur"))`);
@@ -163,6 +169,56 @@ complete -F _openspec_completion openspec
163
169
  }
164
170
  return lines;
165
171
  }
172
+ generateIndexedPositionalCompletion(positionals, flags, firstPositionalWordIndex, indent) {
173
+ const lines = [];
174
+ const valueFlagCases = this.generateValueFlagCases(flags);
175
+ if (valueFlagCases.length > 0) {
176
+ lines.push(`${indent}case "$prev" in`);
177
+ lines.push(`${indent} ${valueFlagCases.join('|')}) return 0 ;;`);
178
+ lines.push(`${indent}esac`);
179
+ lines.push('');
180
+ }
181
+ lines.push(`${indent}local positional_index=0`);
182
+ lines.push(`${indent}local skip_next=0`);
183
+ lines.push(`${indent}local i`);
184
+ lines.push(`${indent}for ((i = ${firstPositionalWordIndex}; i < cword; i++)); do`);
185
+ lines.push(`${indent} if [[ $skip_next -eq 1 ]]; then`);
186
+ lines.push(`${indent} skip_next=0`);
187
+ lines.push(`${indent} continue`);
188
+ lines.push(`${indent} fi`);
189
+ lines.push(`${indent} case "\${words[i]}" in`);
190
+ if (valueFlagCases.length > 0) {
191
+ lines.push(`${indent} ${valueFlagCases.join('|')}) skip_next=1 ;;`);
192
+ lines.push(`${indent} ${valueFlagCases.map((flag) => `${flag}=*`).join('|')}) ;;`);
193
+ }
194
+ lines.push(`${indent} -*) ;;`);
195
+ lines.push(`${indent} *) ((positional_index++)) ;;`);
196
+ lines.push(`${indent} esac`);
197
+ lines.push(`${indent}done`);
198
+ lines.push('');
199
+ lines.push(`${indent}case "$positional_index" in`);
200
+ for (const [index, positional] of positionals.entries()) {
201
+ const completion = this.generateIndexedPositionalCase(positional, indent + ' ');
202
+ if (completion.length === 0)
203
+ continue;
204
+ lines.push(`${indent} ${index})`);
205
+ lines.push(...completion);
206
+ lines.push(`${indent} ;;`);
207
+ }
208
+ lines.push(`${indent}esac`);
209
+ return lines;
210
+ }
211
+ generateValueFlagCases(flags) {
212
+ return flags
213
+ .filter((flag) => flag.takesValue)
214
+ .flatMap((flag) => [
215
+ `--${flag.name}`,
216
+ ...(flag.short ? [`-${flag.short}`] : []),
217
+ ]);
218
+ }
219
+ generateIndexedPositionalCase(positional, indent) {
220
+ return this.generatePositionalCompletion(positional.type, indent);
221
+ }
166
222
  /**
167
223
  * Escape command/subcommand names for safe use in Bash scripts
168
224
  */
@@ -134,6 +134,9 @@ ${commandCompletions}`;
134
134
  case 'change-or-spec-id':
135
135
  lines.push(`complete -c openspec -n '${condition}' -a '(__fish_openspec_items)' -f`);
136
136
  break;
137
+ case 'schema-name':
138
+ lines.push(`complete -c openspec -n '${condition}' -a '(__fish_openspec_schemas)' -f`);
139
+ break;
137
140
  case 'shell':
138
141
  lines.push(`complete -c openspec -n '${condition}' -a 'zsh bash fish powershell' -f`);
139
142
  break;
@@ -21,6 +21,9 @@ export declare class PowerShellGenerator implements CompletionGenerator {
21
21
  * Generate argument completion (flags and positional)
22
22
  */
23
23
  private generateArgumentCompletion;
24
+ private generateIndexedPositionalCompletion;
25
+ private generateValueFlags;
26
+ private escapeRegex;
24
27
  /**
25
28
  * Generate positional argument completion
26
29
  */
@@ -114,21 +114,21 @@ Register-ArgumentCompleter -CommandName openspec -ScriptBlock $openspecCompleter
114
114
  lines.push(`${indent}switch ($subcommand) {`);
115
115
  for (const subcmd of cmd.subcommands) {
116
116
  lines.push(`${indent} "${subcmd.name}" {`);
117
- lines.push(...this.generateArgumentCompletion(subcmd, indent + ' '));
117
+ lines.push(...this.generateArgumentCompletion(subcmd, indent + ' ', 3));
118
118
  lines.push(`${indent} }`);
119
119
  }
120
120
  lines.push(`${indent}}`);
121
121
  }
122
122
  else {
123
123
  // No subcommands
124
- lines.push(...this.generateArgumentCompletion(cmd, indent));
124
+ lines.push(...this.generateArgumentCompletion(cmd, indent, 2));
125
125
  }
126
126
  return lines;
127
127
  }
128
128
  /**
129
129
  * Generate argument completion (flags and positional)
130
130
  */
131
- generateArgumentCompletion(cmd, indent) {
131
+ generateArgumentCompletion(cmd, indent, firstPositionalTokenIndex) {
132
132
  const lines = [];
133
133
  // Flag completion
134
134
  if (cmd.flags.length > 0) {
@@ -155,11 +155,65 @@ Register-ArgumentCompleter -CommandName openspec -ScriptBlock $openspecCompleter
155
155
  lines.push('');
156
156
  }
157
157
  // Positional completion
158
- if (cmd.acceptsPositional) {
158
+ if (cmd.positionals && cmd.positionals.length > 0) {
159
+ lines.push(...this.generateIndexedPositionalCompletion(cmd.positionals, cmd.flags, firstPositionalTokenIndex, indent));
160
+ }
161
+ else if (cmd.acceptsPositional) {
159
162
  lines.push(...this.generatePositionalCompletion(cmd.positionalType, indent));
160
163
  }
161
164
  return lines;
162
165
  }
166
+ generateIndexedPositionalCompletion(positionals, flags, firstPositionalTokenIndex, indent) {
167
+ const lines = [];
168
+ const valueFlags = this.generateValueFlags(flags);
169
+ if (valueFlags.length > 0) {
170
+ const flagList = valueFlags.map((flag) => `"${flag}"`).join(', ');
171
+ lines.push(`${indent}if (@(${flagList}) -contains $tokens[$commandCount - 2]) { return }`);
172
+ lines.push('');
173
+ }
174
+ lines.push(`${indent}$positionalIndex = 0`);
175
+ lines.push(`${indent}$skipNext = $false`);
176
+ lines.push(`${indent}for ($i = ${firstPositionalTokenIndex}; $i -lt ($commandCount - 1); $i++) {`);
177
+ lines.push(`${indent} if ($skipNext) {`);
178
+ lines.push(`${indent} $skipNext = $false`);
179
+ lines.push(`${indent} continue`);
180
+ lines.push(`${indent} }`);
181
+ lines.push(`${indent} $token = $tokens[$i]`);
182
+ if (valueFlags.length > 0) {
183
+ const flagList = valueFlags.map((flag) => `"${flag}"`).join(', ');
184
+ lines.push(`${indent} if (@(${flagList}) -contains $token) {`);
185
+ lines.push(`${indent} $skipNext = $true`);
186
+ lines.push(`${indent} continue`);
187
+ lines.push(`${indent} }`);
188
+ lines.push(`${indent} if ($token -match "^(${valueFlags.map((flag) => this.escapeRegex(flag)).join('|')})=.*") { continue }`);
189
+ }
190
+ lines.push(`${indent} if ($token -like "-*") { continue }`);
191
+ lines.push(`${indent} $positionalIndex++`);
192
+ lines.push(`${indent}}`);
193
+ lines.push('');
194
+ lines.push(`${indent}switch ($positionalIndex) {`);
195
+ for (const [index, positional] of positionals.entries()) {
196
+ const completion = this.generatePositionalCompletion(positional.type, indent + ' ');
197
+ if (completion.length === 0)
198
+ continue;
199
+ lines.push(`${indent} ${index} {`);
200
+ lines.push(...completion);
201
+ lines.push(`${indent} }`);
202
+ }
203
+ lines.push(`${indent}}`);
204
+ return lines;
205
+ }
206
+ generateValueFlags(flags) {
207
+ return flags
208
+ .filter((flag) => flag.takesValue)
209
+ .flatMap((flag) => [
210
+ `--${flag.name}`,
211
+ ...(flag.short ? [`-${flag.short}`] : []),
212
+ ]);
213
+ }
214
+ escapeRegex(value) {
215
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
216
+ }
163
217
  /**
164
218
  * Generate positional argument completion
165
219
  */
@@ -182,6 +236,11 @@ Register-ArgumentCompleter -CommandName openspec -ScriptBlock $openspecCompleter
182
236
  lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_)`);
183
237
  lines.push(`${indent}}`);
184
238
  break;
239
+ case 'schema-name':
240
+ lines.push(`${indent}Get-OpenSpecSchemas | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {`);
241
+ lines.push(`${indent} [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", "Schema: $_")`);
242
+ lines.push(`${indent}}`);
243
+ break;
185
244
  case 'shell':
186
245
  lines.push(`${indent}$shells = @("zsh", "bash", "fish", "powershell")`);
187
246
  lines.push(`${indent}$shells | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {`);
@@ -28,6 +28,9 @@ export declare class ZshGenerator implements CompletionGenerator {
28
28
  * Generate positional argument specification
29
29
  */
30
30
  private generatePositionalSpec;
31
+ private appendPositionalSpecs;
32
+ private generatePositionalSpecs;
33
+ private generateIndexedPositionalSpec;
31
34
  /**
32
35
  * Escape special characters in descriptions
33
36
  */
@@ -122,17 +122,7 @@ compdef _openspec openspec
122
122
  for (const flag of cmd.flags) {
123
123
  lines.push(' ' + this.generateFlagSpec(flag) + ' \\');
124
124
  }
125
- // Add positional argument completion
126
- if (cmd.acceptsPositional) {
127
- const positionalSpec = this.generatePositionalSpec(cmd.positionalType);
128
- lines.push(' ' + positionalSpec);
129
- }
130
- else {
131
- // Remove trailing backslash from last flag
132
- if (lines[lines.length - 1].endsWith(' \\')) {
133
- lines[lines.length - 1] = lines[lines.length - 1].slice(0, -2);
134
- }
135
- }
125
+ this.appendPositionalSpecs(lines, cmd);
136
126
  }
137
127
  lines.push('}');
138
128
  // Generate subcommand functions if they exist
@@ -156,17 +146,7 @@ compdef _openspec openspec
156
146
  for (const flag of subcmd.flags) {
157
147
  lines.push(' ' + this.generateFlagSpec(flag) + ' \\');
158
148
  }
159
- // Add positional argument completion
160
- if (subcmd.acceptsPositional) {
161
- const positionalSpec = this.generatePositionalSpec(subcmd.positionalType);
162
- lines.push(' ' + positionalSpec);
163
- }
164
- else {
165
- // Remove trailing backslash from last flag
166
- if (lines[lines.length - 1].endsWith(' \\')) {
167
- lines[lines.length - 1] = lines[lines.length - 1].slice(0, -2);
168
- }
169
- }
149
+ this.appendPositionalSpecs(lines, subcmd);
170
150
  lines.push('}');
171
151
  return lines;
172
152
  }
@@ -212,6 +192,8 @@ compdef _openspec openspec
212
192
  return "'*: :_openspec_complete_specs'";
213
193
  case 'change-or-spec-id':
214
194
  return "'*: :_openspec_complete_items'";
195
+ case 'schema-name':
196
+ return "'*: :_openspec_complete_schemas'";
215
197
  case 'path':
216
198
  return "'*:path:_files'";
217
199
  case 'shell':
@@ -220,6 +202,48 @@ compdef _openspec openspec
220
202
  return "'*: :_default'";
221
203
  }
222
204
  }
205
+ appendPositionalSpecs(lines, cmd) {
206
+ const positionalSpecs = this.generatePositionalSpecs(cmd);
207
+ if (positionalSpecs.length === 0) {
208
+ if (lines[lines.length - 1].endsWith(' \\')) {
209
+ lines[lines.length - 1] = lines[lines.length - 1].slice(0, -2);
210
+ }
211
+ return;
212
+ }
213
+ for (const [index, spec] of positionalSpecs.entries()) {
214
+ const suffix = index === positionalSpecs.length - 1 ? '' : ' \\';
215
+ lines.push(' ' + spec + suffix);
216
+ }
217
+ }
218
+ generatePositionalSpecs(cmd) {
219
+ if (cmd.positionals && cmd.positionals.length > 0) {
220
+ return cmd.positionals.map((positional, index) => this.generateIndexedPositionalSpec(positional, index + 1));
221
+ }
222
+ if (cmd.acceptsPositional) {
223
+ return [this.generatePositionalSpec(cmd.positionalType)];
224
+ }
225
+ return [];
226
+ }
227
+ generateIndexedPositionalSpec(positional, index) {
228
+ const name = this.escapeDescription(positional.name);
229
+ const separator = positional.optional ? '::' : ':';
230
+ switch (positional.type) {
231
+ case 'change-id':
232
+ return `'${index}${separator}${name}:_openspec_complete_changes'`;
233
+ case 'spec-id':
234
+ return `'${index}${separator}${name}:_openspec_complete_specs'`;
235
+ case 'change-or-spec-id':
236
+ return `'${index}${separator}${name}:_openspec_complete_items'`;
237
+ case 'schema-name':
238
+ return `'${index}${separator}${name}:_openspec_complete_schemas'`;
239
+ case 'path':
240
+ return `'${index}${separator}${name}:_files'`;
241
+ case 'shell':
242
+ return `'${index}${separator}${name}:(zsh bash fish powershell)'`;
243
+ default:
244
+ return `'${index}${separator}${name}:'`;
245
+ }
246
+ }
223
247
  /**
224
248
  * Escape special characters in descriptions
225
249
  */
@@ -59,14 +59,6 @@ export declare class ZshInstaller {
59
59
  * @returns true if .zshrc exists and has markers
60
60
  */
61
61
  private hasZshrcConfig;
62
- /**
63
- * Check if fpath configuration is needed for a given directory
64
- * Used to verify if Oh My Zsh (or other) completions directory is already in fpath
65
- *
66
- * @param completionsDir - Directory to check for in fpath
67
- * @returns true if configuration is needed, false if directory is already referenced
68
- */
69
- private needsFpathConfig;
70
62
  /**
71
63
  * Remove .zshrc configuration
72
64
  * Used during uninstallation
@@ -147,26 +147,6 @@ export class ZshInstaller {
147
147
  return false;
148
148
  }
149
149
  }
150
- /**
151
- * Check if fpath configuration is needed for a given directory
152
- * Used to verify if Oh My Zsh (or other) completions directory is already in fpath
153
- *
154
- * @param completionsDir - Directory to check for in fpath
155
- * @returns true if configuration is needed, false if directory is already referenced
156
- */
157
- async needsFpathConfig(completionsDir) {
158
- try {
159
- const zshrcPath = this.getZshrcPath();
160
- const content = await fs.readFile(zshrcPath, 'utf-8');
161
- // Check if fpath already includes this directory
162
- return !content.includes(completionsDir);
163
- }
164
- catch (error) {
165
- // If we can't read .zshrc, assume config is needed
166
- console.debug(`Unable to read .zshrc to check fpath config: ${error instanceof Error ? error.message : String(error)}`);
167
- return true;
168
- }
169
- }
170
150
  /**
171
151
  * Remove .zshrc configuration
172
152
  * Used during uninstallation
@@ -255,18 +235,10 @@ export class ZshInstaller {
255
235
  const backupPath = isUpdate ? await this.backupExistingFile(targetPath) : undefined;
256
236
  // Write the completion script
257
237
  await fs.writeFile(targetPath, completionScript, 'utf-8');
258
- // Auto-configure .zshrc
238
+ // Auto-configure .zshrc for standard Zsh only.
239
+ // Oh My Zsh loads custom/completions and runs compinit itself.
259
240
  let zshrcConfigured = false;
260
- if (isOhMyZsh) {
261
- // For Oh My Zsh, verify that custom/completions is in fpath
262
- // If not, add it to .zshrc
263
- const needsConfig = await this.needsFpathConfig(targetDir);
264
- if (needsConfig) {
265
- zshrcConfigured = await this.configureZshrc(targetDir);
266
- }
267
- }
268
- else {
269
- // Standard Zsh always needs .zshrc configuration
241
+ if (!isOhMyZsh) {
270
242
  zshrcConfigured = await this.configureZshrc(targetDir);
271
243
  }
272
244
  // Generate instructions (only if .zshrc wasn't auto-configured)
@@ -0,0 +1,12 @@
1
+ import type { FlagDefinition } from './types.js';
2
+ /**
3
+ * Common flags used across multiple commands.
4
+ */
5
+ export declare const COMMON_FLAGS: {
6
+ readonly json: FlagDefinition;
7
+ readonly jsonValidation: FlagDefinition;
8
+ readonly strict: FlagDefinition;
9
+ readonly noInteractive: FlagDefinition;
10
+ readonly type: FlagDefinition;
11
+ };
12
+ //# sourceMappingURL=shared-flags.d.ts.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Common flags used across multiple commands.
3
+ */
4
+ export const COMMON_FLAGS = {
5
+ json: {
6
+ name: 'json',
7
+ description: 'Output as JSON',
8
+ },
9
+ jsonValidation: {
10
+ name: 'json',
11
+ description: 'Output validation results as JSON',
12
+ },
13
+ strict: {
14
+ name: 'strict',
15
+ description: 'Enable strict validation mode',
16
+ },
17
+ noInteractive: {
18
+ name: 'no-interactive',
19
+ description: 'Disable interactive prompts',
20
+ },
21
+ type: {
22
+ name: 'type',
23
+ description: 'Specify item type when ambiguous',
24
+ takesValue: true,
25
+ values: ['change', 'spec'],
26
+ },
27
+ };
28
+ //# sourceMappingURL=shared-flags.js.map
@@ -2,5 +2,5 @@
2
2
  * Static template strings for Bash completion scripts.
3
3
  * These are Bash-specific helper functions that never change.
4
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}";
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}\n\n_openspec_complete_schemas() {\n local schemas\n schemas=$(openspec __complete schemas 2>/dev/null | cut -f1)\n COMPREPLY=($(compgen -W \"$schemas\" -- \"$cur\"))\n}";
6
6
  //# sourceMappingURL=bash-templates.d.ts.map
@@ -20,5 +20,11 @@ _openspec_complete_items() {
20
20
  local items
21
21
  items=$(openspec __complete changes 2>/dev/null | cut -f1; openspec __complete specs 2>/dev/null | cut -f1)
22
22
  COMPREPLY=($(compgen -W "$items" -- "$cur"))
23
+ }
24
+
25
+ _openspec_complete_schemas() {
26
+ local schemas
27
+ schemas=$(openspec __complete schemas 2>/dev/null | cut -f1)
28
+ COMPREPLY=($(compgen -W "$schemas" -- "$cur"))
23
29
  }`;
24
30
  //# sourceMappingURL=bash-templates.js.map
@@ -3,5 +3,5 @@
3
3
  * These are Fish-specific helper functions that never change.
4
4
  */
5
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";
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\n\nfunction __fish_openspec_schemas\n openspec __complete schemas 2>/dev/null | while read -l id desc\n printf '%s\\t%s\\n' \"$id\" \"$desc\"\n end\nend";
7
7
  //# sourceMappingURL=fish-templates.d.ts.map
@@ -35,5 +35,11 @@ end
35
35
  function __fish_openspec_items
36
36
  __fish_openspec_changes
37
37
  __fish_openspec_specs
38
+ end
39
+
40
+ function __fish_openspec_schemas
41
+ openspec __complete schemas 2>/dev/null | while read -l id desc
42
+ printf '%s\\t%s\\n' "$id" "$desc"
43
+ end
38
44
  end`;
39
45
  //# sourceMappingURL=fish-templates.js.map
@@ -2,5 +2,5 @@
2
2
  * Static template strings for PowerShell completion scripts.
3
3
  * These are PowerShell-specific helper functions that never change.
4
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";
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\nfunction Get-OpenSpecSchemas {\n $output = openspec __complete schemas 2>$null\n if ($output) {\n $output | ForEach-Object {\n ($_ -split \"\\t\")[0]\n }\n }\n}\n";
6
6
  //# sourceMappingURL=powershell-templates.d.ts.map
@@ -21,5 +21,14 @@ function Get-OpenSpecSpecs {
21
21
  }
22
22
  }
23
23
  }
24
+
25
+ function Get-OpenSpecSchemas {
26
+ $output = openspec __complete schemas 2>$null
27
+ if ($output) {
28
+ $output | ForEach-Object {
29
+ ($_ -split "\\t")[0]
30
+ }
31
+ }
32
+ }
24
33
  `;
25
34
  //# sourceMappingURL=powershell-templates.js.map
@@ -2,5 +2,5 @@
2
2
  * Static template strings for Zsh completion scripts.
3
3
  * These are Zsh-specific helper functions that never change.
4
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}";
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}\n\n# Use openspec __complete to get available schemas\n_openspec_complete_schemas() {\n local -a schemas\n while IFS=$'\\t' read -r id desc; do\n schemas+=(\"$id:$desc\")\n done < <(openspec __complete schemas 2>/dev/null)\n _describe \"schema\" schemas\n}";
6
6
  //# sourceMappingURL=zsh-templates.d.ts.map
@@ -32,5 +32,14 @@ _openspec_complete_items() {
32
32
  items+=("$id:$desc")
33
33
  done < <(openspec __complete specs 2>/dev/null)
34
34
  _describe "item" items
35
+ }
36
+
37
+ # Use openspec __complete to get available schemas
38
+ _openspec_complete_schemas() {
39
+ local -a schemas
40
+ while IFS=$'\\t' read -r id desc; do
41
+ schemas+=("$id:$desc")
42
+ done < <(openspec __complete schemas 2>/dev/null)
43
+ _describe "schema" schemas
35
44
  }`;
36
45
  //# sourceMappingURL=zsh-templates.js.map