@fission-ai/openspec 1.4.1 → 1.6.0-beta.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 (241) hide show
  1. package/README.md +37 -4
  2. package/dist/cli/index.d.ts +5 -0
  3. package/dist/cli/index.js +95 -95
  4. package/dist/commands/change.d.ts +5 -2
  5. package/dist/commands/change.js +23 -55
  6. package/dist/commands/config.js +6 -65
  7. package/dist/commands/context.d.ts +3 -0
  8. package/dist/commands/context.js +155 -0
  9. package/dist/commands/doctor.d.ts +8 -0
  10. package/dist/commands/doctor.js +163 -0
  11. package/dist/commands/shared-gather.d.ts +14 -0
  12. package/dist/commands/shared-gather.js +31 -0
  13. package/dist/commands/shared-output.d.ts +18 -0
  14. package/dist/commands/shared-output.js +61 -0
  15. package/dist/commands/show.d.ts +11 -6
  16. package/dist/commands/show.js +70 -25
  17. package/dist/commands/spec.d.ts +5 -1
  18. package/dist/commands/spec.js +15 -4
  19. package/dist/commands/store.d.ts +3 -0
  20. package/dist/commands/store.js +547 -0
  21. package/dist/commands/validate.d.ts +10 -0
  22. package/dist/commands/validate.js +88 -40
  23. package/dist/commands/workflow/index.d.ts +0 -2
  24. package/dist/commands/workflow/index.js +0 -1
  25. package/dist/commands/workflow/instructions.d.ts +11 -1
  26. package/dist/commands/workflow/instructions.js +71 -22
  27. package/dist/commands/workflow/new-change.d.ts +6 -3
  28. package/dist/commands/workflow/new-change.js +42 -77
  29. package/dist/commands/workflow/shared.d.ts +15 -3
  30. package/dist/commands/workflow/shared.js +20 -3
  31. package/dist/commands/workflow/status.d.ts +2 -0
  32. package/dist/commands/workflow/status.js +19 -17
  33. package/dist/commands/workset-input.d.ts +19 -0
  34. package/dist/commands/workset-input.js +112 -0
  35. package/dist/commands/workset-prompts.d.ts +12 -0
  36. package/dist/commands/workset-prompts.js +143 -0
  37. package/dist/commands/workset.d.ts +25 -0
  38. package/dist/commands/workset.js +446 -0
  39. package/dist/core/archive.d.ts +17 -6
  40. package/dist/core/archive.js +220 -68
  41. package/dist/core/artifact-graph/index.d.ts +1 -1
  42. package/dist/core/artifact-graph/instruction-loader.d.ts +18 -13
  43. package/dist/core/artifact-graph/instruction-loader.js +8 -31
  44. package/dist/core/change-metadata/schema.d.ts +1 -0
  45. package/dist/core/change-metadata/schema.js +4 -2
  46. package/dist/core/change-status-policy.d.ts +5 -18
  47. package/dist/core/change-status-policy.js +2 -37
  48. package/dist/core/command-generation/adapters/bob.js +1 -14
  49. package/dist/core/command-generation/adapters/claude.d.ts +1 -1
  50. package/dist/core/command-generation/adapters/claude.js +4 -15
  51. package/dist/core/command-generation/adapters/cursor.js +1 -14
  52. package/dist/core/command-generation/adapters/index.d.ts +2 -0
  53. package/dist/core/command-generation/adapters/index.js +2 -0
  54. package/dist/core/command-generation/adapters/oh-my-pi.d.ts +21 -0
  55. package/dist/core/command-generation/adapters/oh-my-pi.js +44 -0
  56. package/dist/core/command-generation/adapters/pi.js +1 -14
  57. package/dist/core/command-generation/adapters/trae.d.ts +13 -0
  58. package/dist/core/command-generation/adapters/trae.js +48 -0
  59. package/dist/core/command-generation/adapters/windsurf.js +1 -14
  60. package/dist/core/command-generation/registry.js +4 -0
  61. package/dist/core/command-generation/yaml.d.ts +22 -0
  62. package/dist/core/command-generation/yaml.js +38 -0
  63. package/dist/core/completions/command-registry.js +87 -289
  64. package/dist/core/completions/generators/zsh-generator.js +3 -1
  65. package/dist/core/completions/installers/bash-installer.js +3 -0
  66. package/dist/core/completions/installers/fish-installer.js +8 -0
  67. package/dist/core/completions/installers/powershell-installer.js +30 -2
  68. package/dist/core/completions/installers/zsh-installer.js +3 -0
  69. package/dist/core/completions/shared-flags.d.ts +1 -0
  70. package/dist/core/completions/shared-flags.js +5 -0
  71. package/dist/core/config-schema.d.ts +2 -1
  72. package/dist/core/config-schema.js +26 -0
  73. package/dist/core/config.js +1 -0
  74. package/dist/core/file-state.d.ts +36 -0
  75. package/dist/core/file-state.js +112 -0
  76. package/dist/core/global-config.d.ts +2 -0
  77. package/dist/core/id.d.ts +17 -0
  78. package/dist/core/id.js +30 -0
  79. package/dist/core/index.d.ts +3 -3
  80. package/dist/core/index.js +3 -3
  81. package/dist/core/init.js +27 -6
  82. package/dist/core/list.d.ts +2 -0
  83. package/dist/core/list.js +37 -14
  84. package/dist/core/openers.d.ts +77 -0
  85. package/dist/core/openers.js +251 -0
  86. package/dist/core/openspec-root.d.ts +45 -0
  87. package/dist/core/openspec-root.js +195 -0
  88. package/dist/core/parsers/change-parser.js +2 -1
  89. package/dist/core/parsers/markdown-parser.d.ts +0 -3
  90. package/dist/core/parsers/markdown-parser.js +5 -59
  91. package/dist/core/parsers/requirement-blocks.d.ts +11 -0
  92. package/dist/core/parsers/requirement-blocks.js +42 -8
  93. package/dist/core/parsers/requirement-text.d.ts +55 -0
  94. package/dist/core/parsers/requirement-text.js +136 -0
  95. package/dist/core/planning-home.d.ts +1 -6
  96. package/dist/core/planning-home.js +2 -43
  97. package/dist/core/profile-sync-drift.js +1 -0
  98. package/dist/core/profiles.d.ts +2 -2
  99. package/dist/core/profiles.js +2 -1
  100. package/dist/core/project-config.d.ts +44 -1
  101. package/dist/core/project-config.js +160 -10
  102. package/dist/core/references.d.ts +63 -0
  103. package/dist/core/references.js +310 -0
  104. package/dist/core/relationship-health.d.ts +65 -0
  105. package/dist/core/relationship-health.js +64 -0
  106. package/dist/core/root-selection.d.ts +122 -0
  107. package/dist/core/root-selection.js +337 -0
  108. package/dist/core/schemas/base.schema.js +7 -2
  109. package/dist/core/shared/allowed-tools.d.ts +12 -0
  110. package/dist/core/shared/allowed-tools.js +12 -0
  111. package/dist/core/shared/skill-generation.js +5 -1
  112. package/dist/core/shared/tool-detection.d.ts +2 -2
  113. package/dist/core/shared/tool-detection.js +2 -0
  114. package/dist/core/specs-apply.d.ts +6 -1
  115. package/dist/core/specs-apply.js +41 -5
  116. package/dist/core/store/errors.d.ts +20 -0
  117. package/dist/core/{context-store → store}/errors.js +3 -3
  118. package/dist/core/store/foundation.d.ts +56 -0
  119. package/dist/core/store/foundation.js +251 -0
  120. package/dist/core/store/git.d.ts +23 -0
  121. package/dist/core/store/git.js +137 -0
  122. package/dist/core/{context-store → store}/index.d.ts +0 -1
  123. package/dist/core/{context-store → store}/index.js +0 -1
  124. package/dist/core/store/operations.d.ts +114 -0
  125. package/dist/core/store/operations.js +803 -0
  126. package/dist/core/store/registry.d.ts +58 -0
  127. package/dist/core/store/registry.js +275 -0
  128. package/dist/core/templates/skill-templates.d.ts +1 -0
  129. package/dist/core/templates/skill-templates.js +1 -0
  130. package/dist/core/templates/workflows/apply-change.js +5 -4
  131. package/dist/core/templates/workflows/archive-change.js +5 -4
  132. package/dist/core/templates/workflows/bulk-archive-change.js +5 -4
  133. package/dist/core/templates/workflows/continue-change.js +7 -2
  134. package/dist/core/templates/workflows/explore.js +5 -0
  135. package/dist/core/templates/workflows/ff-change.js +5 -0
  136. package/dist/core/templates/workflows/new-change.js +5 -0
  137. package/dist/core/templates/workflows/onboard.js +4 -1
  138. package/dist/core/templates/workflows/propose.js +5 -0
  139. package/dist/core/templates/workflows/store-selection.d.ts +8 -0
  140. package/dist/core/templates/workflows/store-selection.js +8 -0
  141. package/dist/core/templates/workflows/sync-specs.js +5 -4
  142. package/dist/core/templates/workflows/update-change.d.ts +10 -0
  143. package/dist/core/templates/workflows/update-change.js +167 -0
  144. package/dist/core/templates/workflows/verify-change.js +5 -4
  145. package/dist/core/update.js +4 -4
  146. package/dist/core/validation/validator.d.ts +7 -0
  147. package/dist/core/validation/validator.js +101 -38
  148. package/dist/core/view.js +1 -1
  149. package/dist/core/working-set.d.ts +47 -0
  150. package/dist/core/working-set.js +43 -0
  151. package/dist/core/worksets.d.ts +75 -0
  152. package/dist/core/worksets.js +245 -0
  153. package/dist/core/zod-issues.d.ts +4 -0
  154. package/dist/core/zod-issues.js +10 -0
  155. package/dist/utils/change-metadata.d.ts +1 -0
  156. package/dist/utils/change-metadata.js +1 -1
  157. package/dist/utils/change-utils.js +15 -0
  158. package/dist/utils/file-system.js +36 -17
  159. package/dist/utils/task-progress.d.ts +10 -1
  160. package/dist/utils/task-progress.js +66 -2
  161. package/package.json +26 -23
  162. package/dist/commands/context-store.d.ts +0 -3
  163. package/dist/commands/context-store.js +0 -475
  164. package/dist/commands/initiative.d.ts +0 -13
  165. package/dist/commands/initiative.js +0 -318
  166. package/dist/commands/workflow/initiative-link.d.ts +0 -24
  167. package/dist/commands/workflow/initiative-link.js +0 -47
  168. package/dist/commands/workflow/set-change.d.ts +0 -13
  169. package/dist/commands/workflow/set-change.js +0 -87
  170. package/dist/commands/workspace/context-status.d.ts +0 -4
  171. package/dist/commands/workspace/context-status.js +0 -59
  172. package/dist/commands/workspace/open-target-selection.d.ts +0 -13
  173. package/dist/commands/workspace/open-target-selection.js +0 -146
  174. package/dist/commands/workspace/open-view.d.ts +0 -62
  175. package/dist/commands/workspace/open-view.js +0 -249
  176. package/dist/commands/workspace/open.d.ts +0 -37
  177. package/dist/commands/workspace/open.js +0 -110
  178. package/dist/commands/workspace/opener-selection.d.ts +0 -11
  179. package/dist/commands/workspace/opener-selection.js +0 -98
  180. package/dist/commands/workspace/operations.d.ts +0 -29
  181. package/dist/commands/workspace/operations.js +0 -543
  182. package/dist/commands/workspace/prompt-theme.d.ts +0 -29
  183. package/dist/commands/workspace/prompt-theme.js +0 -24
  184. package/dist/commands/workspace/registration.d.ts +0 -13
  185. package/dist/commands/workspace/registration.js +0 -84
  186. package/dist/commands/workspace/selection.d.ts +0 -8
  187. package/dist/commands/workspace/selection.js +0 -104
  188. package/dist/commands/workspace/setup-prompts.d.ts +0 -13
  189. package/dist/commands/workspace/setup-prompts.js +0 -121
  190. package/dist/commands/workspace/types.d.ts +0 -103
  191. package/dist/commands/workspace/types.js +0 -36
  192. package/dist/commands/workspace.d.ts +0 -5
  193. package/dist/commands/workspace.js +0 -574
  194. package/dist/core/collections/index.d.ts +0 -3
  195. package/dist/core/collections/index.js +0 -3
  196. package/dist/core/collections/initiatives/collection.d.ts +0 -4
  197. package/dist/core/collections/initiatives/collection.js +0 -17
  198. package/dist/core/collections/initiatives/index.d.ts +0 -6
  199. package/dist/core/collections/initiatives/index.js +0 -6
  200. package/dist/core/collections/initiatives/operations.d.ts +0 -49
  201. package/dist/core/collections/initiatives/operations.js +0 -175
  202. package/dist/core/collections/initiatives/resolution.d.ts +0 -87
  203. package/dist/core/collections/initiatives/resolution.js +0 -374
  204. package/dist/core/collections/initiatives/schema.d.ts +0 -41
  205. package/dist/core/collections/initiatives/schema.js +0 -134
  206. package/dist/core/collections/initiatives/templates.d.ts +0 -12
  207. package/dist/core/collections/initiatives/templates.js +0 -90
  208. package/dist/core/collections/runtime.d.ts +0 -46
  209. package/dist/core/collections/runtime.js +0 -194
  210. package/dist/core/context-store/binding.d.ts +0 -53
  211. package/dist/core/context-store/binding.js +0 -197
  212. package/dist/core/context-store/errors.d.ts +0 -20
  213. package/dist/core/context-store/foundation.d.ts +0 -55
  214. package/dist/core/context-store/foundation.js +0 -321
  215. package/dist/core/context-store/operations.d.ts +0 -85
  216. package/dist/core/context-store/operations.js +0 -528
  217. package/dist/core/context-store/registry.d.ts +0 -45
  218. package/dist/core/context-store/registry.js +0 -229
  219. package/dist/core/workspace/foundation.d.ts +0 -67
  220. package/dist/core/workspace/foundation.js +0 -295
  221. package/dist/core/workspace/index.d.ts +0 -8
  222. package/dist/core/workspace/index.js +0 -8
  223. package/dist/core/workspace/legacy-state.d.ts +0 -28
  224. package/dist/core/workspace/legacy-state.js +0 -200
  225. package/dist/core/workspace/link-input.d.ts +0 -9
  226. package/dist/core/workspace/link-input.js +0 -32
  227. package/dist/core/workspace/open-surface.d.ts +0 -45
  228. package/dist/core/workspace/open-surface.js +0 -215
  229. package/dist/core/workspace/openers.d.ts +0 -21
  230. package/dist/core/workspace/openers.js +0 -124
  231. package/dist/core/workspace/registry.d.ts +0 -24
  232. package/dist/core/workspace/registry.js +0 -146
  233. package/dist/core/workspace/skills.d.ts +0 -57
  234. package/dist/core/workspace/skills.js +0 -334
  235. package/dist/core/workspace/state-io.d.ts +0 -10
  236. package/dist/core/workspace/state-io.js +0 -121
  237. package/schemas/workspace-planning/schema.yaml +0 -72
  238. package/schemas/workspace-planning/templates/design.md +0 -33
  239. package/schemas/workspace-planning/templates/proposal.md +0 -28
  240. package/schemas/workspace-planning/templates/spec.md +0 -9
  241. package/schemas/workspace-planning/templates/tasks.md +0 -15
@@ -1,5 +1,6 @@
1
1
  import { isInteractive } from '../utils/interactive.js';
2
2
  import { getActiveChangeIds, getSpecIds } from '../utils/item-discovery.js';
3
+ import { resolveRootForCommand, toRootOutput, withStoreFlag, isStoreSelectedRoot, } from '../core/root-selection.js';
3
4
  import { ChangeCommand } from './change.js';
4
5
  import { SpecCommand } from './spec.js';
5
6
  import { nearestMatches } from '../utils/match.js';
@@ -7,6 +8,10 @@ const CHANGE_FLAG_KEYS = new Set(['deltasOnly', 'requirementsOnly']);
7
8
  const SPEC_FLAG_KEYS = new Set(['requirements', 'scenarios', 'requirement']);
8
9
  export class ShowCommand {
9
10
  async execute(itemName, options = {}) {
11
+ const root = await resolveRootForCommand(options, { json: options.json });
12
+ if (!root) {
13
+ return;
14
+ }
10
15
  const interactive = isInteractive(options);
11
16
  const typeOverride = this.normalizeType(options.type);
12
17
  if (!itemName) {
@@ -19,14 +24,14 @@ export class ShowCommand {
19
24
  { name: 'Spec', value: 'spec' },
20
25
  ],
21
26
  });
22
- await this.runInteractiveByType(type, options);
27
+ await this.runInteractiveByType(type, options, root);
23
28
  return;
24
29
  }
25
- this.printNonInteractiveHint();
30
+ this.printNonInteractiveHint(root);
26
31
  process.exitCode = 1;
27
32
  return;
28
33
  }
29
- await this.showDirect(itemName, { typeOverride, options });
34
+ await this.showDirect(itemName, { typeOverride, options, root });
30
35
  }
31
36
  normalizeType(value) {
32
37
  if (!value)
@@ -36,78 +41,118 @@ export class ShowCommand {
36
41
  return v;
37
42
  return undefined;
38
43
  }
39
- async runInteractiveByType(type, options) {
44
+ delegateOptions(root, options) {
45
+ return {
46
+ ...options,
47
+ ...(options.json ? { rootOutput: toRootOutput(root) } : {}),
48
+ };
49
+ }
50
+ async runInteractiveByType(type, options, root) {
40
51
  const { select } = await import('@inquirer/prompts');
41
52
  if (type === 'change') {
42
- const changes = await getActiveChangeIds();
53
+ const changes = await getActiveChangeIds(root.path);
43
54
  if (changes.length === 0) {
44
55
  console.error('No changes found.');
45
56
  process.exitCode = 1;
46
57
  return;
47
58
  }
48
59
  const picked = await select({ message: 'Pick a change', choices: changes.map(id => ({ name: id, value: id })) });
49
- const cmd = new ChangeCommand();
50
- await cmd.show(picked, options);
60
+ const cmd = new ChangeCommand(root.path);
61
+ await cmd.show(picked, this.delegateOptions(root, options));
51
62
  return;
52
63
  }
53
- const specs = await getSpecIds();
64
+ const specs = await getSpecIds(root.path);
54
65
  if (specs.length === 0) {
55
66
  console.error('No specs found.');
56
67
  process.exitCode = 1;
57
68
  return;
58
69
  }
59
70
  const picked = await select({ message: 'Pick a spec', choices: specs.map(id => ({ name: id, value: id })) });
60
- const cmd = new SpecCommand();
61
- await cmd.show(picked, options);
71
+ const cmd = new SpecCommand(root.path);
72
+ await cmd.show(picked, this.delegateOptions(root, options));
62
73
  }
63
74
  async showDirect(itemName, params) {
75
+ const root = params.root;
64
76
  // Optimize lookups when type is pre-specified
65
77
  let isChange = false;
66
78
  let isSpec = false;
67
79
  let changes = [];
68
80
  let specs = [];
69
81
  if (params.typeOverride === 'change') {
70
- changes = await getActiveChangeIds();
82
+ changes = await getActiveChangeIds(root.path);
71
83
  isChange = changes.includes(itemName);
72
84
  }
73
85
  else if (params.typeOverride === 'spec') {
74
- specs = await getSpecIds();
86
+ specs = await getSpecIds(root.path);
75
87
  isSpec = specs.includes(itemName);
76
88
  }
77
89
  else {
78
- [changes, specs] = await Promise.all([getActiveChangeIds(), getSpecIds()]);
90
+ [changes, specs] = await Promise.all([getActiveChangeIds(root.path), getSpecIds(root.path)]);
79
91
  isChange = changes.includes(itemName);
80
92
  isSpec = specs.includes(itemName);
81
93
  }
82
94
  const resolvedType = params.typeOverride ?? (isChange ? 'change' : isSpec ? 'spec' : undefined);
83
95
  if (!resolvedType) {
84
- console.error(`Unknown item '${itemName}'`);
85
96
  const suggestions = nearestMatches(itemName, [...changes, ...specs]);
86
- if (suggestions.length)
87
- console.error(`Did you mean: ${suggestions.join(', ')}?`);
97
+ const message = suggestions.length
98
+ ? `Unknown item '${itemName}'. Did you mean: ${suggestions.join(', ')}?`
99
+ : `Unknown item '${itemName}'.`;
100
+ if (params.options.json) {
101
+ console.log(JSON.stringify({ status: [{ severity: 'error', code: 'unknown_item', message }] }, null, 2));
102
+ }
103
+ else {
104
+ console.error(message);
105
+ }
88
106
  process.exitCode = 1;
89
107
  return;
90
108
  }
91
109
  if (!params.typeOverride && isChange && isSpec) {
110
+ if (params.options.json) {
111
+ console.log(JSON.stringify({
112
+ status: [
113
+ {
114
+ severity: 'error',
115
+ code: 'ambiguous_item',
116
+ message: `Ambiguous item '${itemName}' matches both a change and a spec.`,
117
+ fix: 'Pass --type change|spec.',
118
+ },
119
+ ],
120
+ }, null, 2));
121
+ process.exitCode = 1;
122
+ return;
123
+ }
92
124
  console.error(`Ambiguous item '${itemName}' matches both a change and a spec.`);
93
- console.error('Pass --type change|spec, or use: openspec change show / openspec spec show');
125
+ // The noun-form commands are cwd-based and cannot reach a selected store.
126
+ if (isStoreSelectedRoot(root)) {
127
+ console.error('Pass --type change|spec.');
128
+ }
129
+ else {
130
+ console.error('Pass --type change|spec, or use: openspec change show / openspec spec show');
131
+ }
94
132
  process.exitCode = 1;
95
133
  return;
96
134
  }
97
135
  this.warnIrrelevantFlags(resolvedType, params.options);
98
136
  if (resolvedType === 'change') {
99
- const cmd = new ChangeCommand();
100
- await cmd.show(itemName, params.options);
137
+ const cmd = new ChangeCommand(root.path);
138
+ await cmd.show(itemName, this.delegateOptions(root, params.options));
101
139
  return;
102
140
  }
103
- const cmd = new SpecCommand();
104
- await cmd.show(itemName, params.options);
141
+ const cmd = new SpecCommand(root.path);
142
+ await cmd.show(itemName, this.delegateOptions(root, params.options));
105
143
  }
106
- printNonInteractiveHint() {
144
+ printNonInteractiveHint(root) {
107
145
  console.error('Nothing to show. Try one of:');
108
- console.error(' openspec show <item>');
109
- console.error(' openspec change show');
110
- console.error(' openspec spec show');
146
+ console.error(` ${withStoreFlag(root, 'openspec show <item>')}`);
147
+ if (isStoreSelectedRoot(root)) {
148
+ // The noun-form commands are cwd-based and cannot reach a selected store.
149
+ console.error(` ${withStoreFlag(root, 'openspec show <item> --type change')}`);
150
+ console.error(` ${withStoreFlag(root, 'openspec show <item> --type spec')}`);
151
+ }
152
+ else {
153
+ console.error(' openspec change show');
154
+ console.error(' openspec spec show');
155
+ }
111
156
  console.error('Or run in an interactive terminal.');
112
157
  }
113
158
  warnIrrelevantFlags(type, options) {
@@ -1,13 +1,17 @@
1
1
  import { program } from 'commander';
2
+ import type { RootOutput } from '../core/root-selection.js';
2
3
  interface ShowOptions {
3
4
  json?: boolean;
4
5
  requirements?: boolean;
5
6
  scenarios?: boolean;
6
7
  requirement?: string;
7
8
  noInteractive?: boolean;
9
+ rootOutput?: RootOutput;
8
10
  }
9
11
  export declare class SpecCommand {
10
- private SPECS_DIR;
12
+ private specsDir;
13
+ private rootPath?;
14
+ constructor(rootPath?: string);
11
15
  show(specId?: string, options?: ShowOptions): Promise<void>;
12
16
  }
13
17
  export declare function registerSpecCommand(rootProgram: typeof program): import("commander").Command;
@@ -45,11 +45,18 @@ function printSpecTextRaw(specPath) {
45
45
  console.log(content);
46
46
  }
47
47
  export class SpecCommand {
48
- SPECS_DIR = 'openspec/specs';
48
+ specsDir;
49
+ rootPath;
50
+ // rootPath is set only by root-aware callers (top-level `show`); the
51
+ // deprecated noun-form commands stay cwd-based.
52
+ constructor(rootPath) {
53
+ this.rootPath = rootPath;
54
+ this.specsDir = rootPath ? join(rootPath, 'openspec', 'specs') : SPECS_DIR;
55
+ }
49
56
  async show(specId, options = {}) {
50
57
  if (!specId) {
51
58
  const canPrompt = isInteractive(options);
52
- const specIds = await getSpecIds();
59
+ const specIds = await getSpecIds(this.rootPath ?? process.cwd());
53
60
  if (canPrompt && specIds.length > 0) {
54
61
  const { select } = await import('@inquirer/prompts');
55
62
  specId = await select({
@@ -61,9 +68,12 @@ export class SpecCommand {
61
68
  throw new Error('Missing required argument <spec-id>');
62
69
  }
63
70
  }
64
- const specPath = join(this.SPECS_DIR, specId, 'spec.md');
71
+ const specPath = join(this.specsDir, specId, 'spec.md');
65
72
  if (!existsSync(specPath)) {
66
- throw new Error(`Spec '${specId}' not found at openspec/specs/${specId}/spec.md`);
73
+ // Root-aware callers get the absolute path; the cwd-based noun form
74
+ // keeps its historical forward-slash relative message on all platforms.
75
+ const displayPath = this.rootPath ? specPath : `openspec/specs/${specId}/spec.md`;
76
+ throw new Error(`Spec '${specId}' not found at ${displayPath}`);
67
77
  }
68
78
  if (options.json) {
69
79
  if (options.requirements && options.requirement) {
@@ -78,6 +88,7 @@ export class SpecCommand {
78
88
  requirementCount: filtered.requirements.length,
79
89
  requirements: filtered.requirements,
80
90
  metadata: parsed.metadata ?? { version: '1.0.0', format: 'openspec' },
91
+ ...(options.rootOutput ? { root: options.rootOutput } : {}),
81
92
  };
82
93
  console.log(JSON.stringify(output, null, 2));
83
94
  return;
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerStoreCommand(program: Command): void;
3
+ //# sourceMappingURL=store.d.ts.map