@dynamicworks/br-openspec 1.3.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 (291) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +210 -0
  3. package/README.pt-BR.md +212 -0
  4. package/bin/openspec.js +3 -0
  5. package/dist/cli/index.d.ts +2 -0
  6. package/dist/cli/index.js +484 -0
  7. package/dist/commands/change.d.ts +35 -0
  8. package/dist/commands/change.js +278 -0
  9. package/dist/commands/completion.d.ts +72 -0
  10. package/dist/commands/completion.js +258 -0
  11. package/dist/commands/config.d.ts +36 -0
  12. package/dist/commands/config.js +553 -0
  13. package/dist/commands/feedback.d.ts +9 -0
  14. package/dist/commands/feedback.js +184 -0
  15. package/dist/commands/schema.d.ts +6 -0
  16. package/dist/commands/schema.js +869 -0
  17. package/dist/commands/show.d.ts +14 -0
  18. package/dist/commands/show.js +133 -0
  19. package/dist/commands/spec.d.ts +15 -0
  20. package/dist/commands/spec.js +226 -0
  21. package/dist/commands/tools.d.ts +11 -0
  22. package/dist/commands/tools.js +252 -0
  23. package/dist/commands/validate.d.ts +24 -0
  24. package/dist/commands/validate.js +295 -0
  25. package/dist/commands/workflow/index.d.ts +17 -0
  26. package/dist/commands/workflow/index.js +12 -0
  27. package/dist/commands/workflow/instructions.d.ts +29 -0
  28. package/dist/commands/workflow/instructions.js +328 -0
  29. package/dist/commands/workflow/new-change.d.ts +11 -0
  30. package/dist/commands/workflow/new-change.js +44 -0
  31. package/dist/commands/workflow/schemas.d.ts +10 -0
  32. package/dist/commands/workflow/schemas.js +35 -0
  33. package/dist/commands/workflow/shared.d.ts +57 -0
  34. package/dist/commands/workflow/shared.js +117 -0
  35. package/dist/commands/workflow/status.d.ts +14 -0
  36. package/dist/commands/workflow/status.js +76 -0
  37. package/dist/commands/workflow/templates.d.ts +16 -0
  38. package/dist/commands/workflow/templates.js +70 -0
  39. package/dist/core/archive.d.ts +11 -0
  40. package/dist/core/archive.js +322 -0
  41. package/dist/core/artifact-graph/graph.d.ts +56 -0
  42. package/dist/core/artifact-graph/graph.js +141 -0
  43. package/dist/core/artifact-graph/index.d.ts +8 -0
  44. package/dist/core/artifact-graph/index.js +14 -0
  45. package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
  46. package/dist/core/artifact-graph/instruction-loader.js +217 -0
  47. package/dist/core/artifact-graph/outputs.d.ts +14 -0
  48. package/dist/core/artifact-graph/outputs.js +39 -0
  49. package/dist/core/artifact-graph/resolver.d.ts +81 -0
  50. package/dist/core/artifact-graph/resolver.js +258 -0
  51. package/dist/core/artifact-graph/schema.d.ts +13 -0
  52. package/dist/core/artifact-graph/schema.js +108 -0
  53. package/dist/core/artifact-graph/state.d.ts +12 -0
  54. package/dist/core/artifact-graph/state.js +31 -0
  55. package/dist/core/artifact-graph/types.d.ts +45 -0
  56. package/dist/core/artifact-graph/types.js +43 -0
  57. package/dist/core/available-tools.d.ts +17 -0
  58. package/dist/core/available-tools.js +43 -0
  59. package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
  60. package/dist/core/command-generation/adapters/amazon-q.js +26 -0
  61. package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
  62. package/dist/core/command-generation/adapters/antigravity.js +26 -0
  63. package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
  64. package/dist/core/command-generation/adapters/auggie.js +27 -0
  65. package/dist/core/command-generation/adapters/bob.d.ts +14 -0
  66. package/dist/core/command-generation/adapters/bob.js +45 -0
  67. package/dist/core/command-generation/adapters/claude.d.ts +13 -0
  68. package/dist/core/command-generation/adapters/claude.js +50 -0
  69. package/dist/core/command-generation/adapters/cline.d.ts +14 -0
  70. package/dist/core/command-generation/adapters/cline.js +27 -0
  71. package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
  72. package/dist/core/command-generation/adapters/codebuddy.js +28 -0
  73. package/dist/core/command-generation/adapters/codex.d.ts +16 -0
  74. package/dist/core/command-generation/adapters/codex.js +39 -0
  75. package/dist/core/command-generation/adapters/continue.d.ts +13 -0
  76. package/dist/core/command-generation/adapters/continue.js +28 -0
  77. package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
  78. package/dist/core/command-generation/adapters/costrict.js +27 -0
  79. package/dist/core/command-generation/adapters/crush.d.ts +13 -0
  80. package/dist/core/command-generation/adapters/crush.js +30 -0
  81. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  82. package/dist/core/command-generation/adapters/cursor.js +44 -0
  83. package/dist/core/command-generation/adapters/factory.d.ts +13 -0
  84. package/dist/core/command-generation/adapters/factory.js +27 -0
  85. package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
  86. package/dist/core/command-generation/adapters/gemini.js +26 -0
  87. package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
  88. package/dist/core/command-generation/adapters/github-copilot.js +26 -0
  89. package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
  90. package/dist/core/command-generation/adapters/iflow.js +29 -0
  91. package/dist/core/command-generation/adapters/index.d.ts +32 -0
  92. package/dist/core/command-generation/adapters/index.js +32 -0
  93. package/dist/core/command-generation/adapters/junie.d.ts +13 -0
  94. package/dist/core/command-generation/adapters/junie.js +26 -0
  95. package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
  96. package/dist/core/command-generation/adapters/kilocode.js +23 -0
  97. package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
  98. package/dist/core/command-generation/adapters/kiro.js +26 -0
  99. package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
  100. package/dist/core/command-generation/adapters/lingma.js +30 -0
  101. package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
  102. package/dist/core/command-generation/adapters/opencode.js +29 -0
  103. package/dist/core/command-generation/adapters/pi.d.ts +18 -0
  104. package/dist/core/command-generation/adapters/pi.js +55 -0
  105. package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
  106. package/dist/core/command-generation/adapters/qoder.js +30 -0
  107. package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
  108. package/dist/core/command-generation/adapters/qwen.js +26 -0
  109. package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
  110. package/dist/core/command-generation/adapters/roocode.js +27 -0
  111. package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
  112. package/dist/core/command-generation/adapters/windsurf.js +51 -0
  113. package/dist/core/command-generation/generator.d.ts +21 -0
  114. package/dist/core/command-generation/generator.js +27 -0
  115. package/dist/core/command-generation/index.d.ts +22 -0
  116. package/dist/core/command-generation/index.js +24 -0
  117. package/dist/core/command-generation/registry.d.ts +36 -0
  118. package/dist/core/command-generation/registry.js +98 -0
  119. package/dist/core/command-generation/types.d.ts +56 -0
  120. package/dist/core/command-generation/types.js +8 -0
  121. package/dist/core/completions/command-registry.d.ts +7 -0
  122. package/dist/core/completions/command-registry.js +462 -0
  123. package/dist/core/completions/completion-provider.d.ts +60 -0
  124. package/dist/core/completions/completion-provider.js +102 -0
  125. package/dist/core/completions/factory.d.ts +64 -0
  126. package/dist/core/completions/factory.js +75 -0
  127. package/dist/core/completions/generators/bash-generator.d.ts +32 -0
  128. package/dist/core/completions/generators/bash-generator.js +174 -0
  129. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  130. package/dist/core/completions/generators/fish-generator.js +157 -0
  131. package/dist/core/completions/generators/powershell-generator.d.ts +33 -0
  132. package/dist/core/completions/generators/powershell-generator.js +208 -0
  133. package/dist/core/completions/generators/zsh-generator.d.ts +44 -0
  134. package/dist/core/completions/generators/zsh-generator.js +250 -0
  135. package/dist/core/completions/installers/bash-installer.d.ts +87 -0
  136. package/dist/core/completions/installers/bash-installer.js +319 -0
  137. package/dist/core/completions/installers/fish-installer.d.ts +43 -0
  138. package/dist/core/completions/installers/fish-installer.js +143 -0
  139. package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
  140. package/dist/core/completions/installers/powershell-installer.js +400 -0
  141. package/dist/core/completions/installers/zsh-installer.d.ts +125 -0
  142. package/dist/core/completions/installers/zsh-installer.js +450 -0
  143. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  144. package/dist/core/completions/templates/bash-templates.js +24 -0
  145. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  146. package/dist/core/completions/templates/fish-templates.js +39 -0
  147. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  148. package/dist/core/completions/templates/powershell-templates.js +25 -0
  149. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  150. package/dist/core/completions/templates/zsh-templates.js +36 -0
  151. package/dist/core/completions/types.d.ts +79 -0
  152. package/dist/core/completions/types.js +2 -0
  153. package/dist/core/config-prompts.d.ts +9 -0
  154. package/dist/core/config-prompts.js +34 -0
  155. package/dist/core/config-schema.d.ts +86 -0
  156. package/dist/core/config-schema.js +213 -0
  157. package/dist/core/config.d.ts +18 -0
  158. package/dist/core/config.js +38 -0
  159. package/dist/core/converters/json-converter.d.ts +6 -0
  160. package/dist/core/converters/json-converter.js +51 -0
  161. package/dist/core/global-config.d.ts +44 -0
  162. package/dist/core/global-config.js +125 -0
  163. package/dist/core/index.d.ts +2 -0
  164. package/dist/core/index.js +3 -0
  165. package/dist/core/init.d.ts +37 -0
  166. package/dist/core/init.js +549 -0
  167. package/dist/core/is-project-initialized.d.ts +12 -0
  168. package/dist/core/is-project-initialized.js +18 -0
  169. package/dist/core/legacy-cleanup.d.ts +162 -0
  170. package/dist/core/legacy-cleanup.js +515 -0
  171. package/dist/core/list.d.ts +9 -0
  172. package/dist/core/list.js +172 -0
  173. package/dist/core/migration.d.ts +23 -0
  174. package/dist/core/migration.js +109 -0
  175. package/dist/core/parsers/change-parser.d.ts +13 -0
  176. package/dist/core/parsers/change-parser.js +197 -0
  177. package/dist/core/parsers/markdown-parser.d.ts +26 -0
  178. package/dist/core/parsers/markdown-parser.js +228 -0
  179. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  180. package/dist/core/parsers/requirement-blocks.js +201 -0
  181. package/dist/core/parsers/spec-structure.d.ts +9 -0
  182. package/dist/core/parsers/spec-structure.js +88 -0
  183. package/dist/core/profile-sync-drift.d.ts +38 -0
  184. package/dist/core/profile-sync-drift.js +200 -0
  185. package/dist/core/profiles.d.ts +26 -0
  186. package/dist/core/profiles.js +40 -0
  187. package/dist/core/project-config.d.ts +64 -0
  188. package/dist/core/project-config.js +224 -0
  189. package/dist/core/schemas/base.schema.d.ts +13 -0
  190. package/dist/core/schemas/base.schema.js +13 -0
  191. package/dist/core/schemas/change.schema.d.ts +73 -0
  192. package/dist/core/schemas/change.schema.js +31 -0
  193. package/dist/core/schemas/index.d.ts +4 -0
  194. package/dist/core/schemas/index.js +4 -0
  195. package/dist/core/schemas/spec.schema.d.ts +18 -0
  196. package/dist/core/schemas/spec.schema.js +15 -0
  197. package/dist/core/shared/index.d.ts +8 -0
  198. package/dist/core/shared/index.js +8 -0
  199. package/dist/core/shared/skill-generation.d.ts +49 -0
  200. package/dist/core/shared/skill-generation.js +96 -0
  201. package/dist/core/shared/tool-detection.d.ts +71 -0
  202. package/dist/core/shared/tool-detection.js +158 -0
  203. package/dist/core/specs-apply.d.ts +73 -0
  204. package/dist/core/specs-apply.js +393 -0
  205. package/dist/core/styles/palette.d.ts +7 -0
  206. package/dist/core/styles/palette.js +8 -0
  207. package/dist/core/templates/index.d.ts +8 -0
  208. package/dist/core/templates/index.js +9 -0
  209. package/dist/core/templates/skill-templates.d.ts +20 -0
  210. package/dist/core/templates/skill-templates.js +19 -0
  211. package/dist/core/templates/types.d.ts +19 -0
  212. package/dist/core/templates/types.js +5 -0
  213. package/dist/core/templates/workflows/apply-change.d.ts +10 -0
  214. package/dist/core/templates/workflows/apply-change.js +308 -0
  215. package/dist/core/templates/workflows/archive-change.d.ts +10 -0
  216. package/dist/core/templates/workflows/archive-change.js +271 -0
  217. package/dist/core/templates/workflows/bulk-archive-change.d.ts +10 -0
  218. package/dist/core/templates/workflows/bulk-archive-change.js +492 -0
  219. package/dist/core/templates/workflows/continue-change.d.ts +10 -0
  220. package/dist/core/templates/workflows/continue-change.js +232 -0
  221. package/dist/core/templates/workflows/explore.d.ts +10 -0
  222. package/dist/core/templates/workflows/explore.js +463 -0
  223. package/dist/core/templates/workflows/feedback.d.ts +9 -0
  224. package/dist/core/templates/workflows/feedback.js +108 -0
  225. package/dist/core/templates/workflows/ff-change.d.ts +10 -0
  226. package/dist/core/templates/workflows/ff-change.js +198 -0
  227. package/dist/core/templates/workflows/new-change.d.ts +10 -0
  228. package/dist/core/templates/workflows/new-change.js +21 -0
  229. package/dist/core/templates/workflows/onboard.d.ts +10 -0
  230. package/dist/core/templates/workflows/onboard.js +21 -0
  231. package/dist/core/templates/workflows/propose.d.ts +10 -0
  232. package/dist/core/templates/workflows/propose.js +216 -0
  233. package/dist/core/templates/workflows/sync-specs.d.ts +10 -0
  234. package/dist/core/templates/workflows/sync-specs.js +272 -0
  235. package/dist/core/templates/workflows/upstream-sync.d.ts +10 -0
  236. package/dist/core/templates/workflows/upstream-sync.js +116 -0
  237. package/dist/core/templates/workflows/verify-change.d.ts +10 -0
  238. package/dist/core/templates/workflows/verify-change.js +21 -0
  239. package/dist/core/tools-manager.d.ts +56 -0
  240. package/dist/core/tools-manager.js +215 -0
  241. package/dist/core/update.d.ts +77 -0
  242. package/dist/core/update.js +538 -0
  243. package/dist/core/validation/constants.d.ts +34 -0
  244. package/dist/core/validation/constants.js +40 -0
  245. package/dist/core/validation/types.d.ts +18 -0
  246. package/dist/core/validation/types.js +2 -0
  247. package/dist/core/validation/validator.d.ts +33 -0
  248. package/dist/core/validation/validator.js +419 -0
  249. package/dist/core/view.d.ts +8 -0
  250. package/dist/core/view.js +169 -0
  251. package/dist/index.d.ts +3 -0
  252. package/dist/index.js +3 -0
  253. package/dist/messages/index.d.ts +867 -0
  254. package/dist/messages/index.js +1960 -0
  255. package/dist/prompts/searchable-multi-select.d.ts +28 -0
  256. package/dist/prompts/searchable-multi-select.js +160 -0
  257. package/dist/telemetry/config.d.ts +38 -0
  258. package/dist/telemetry/config.js +136 -0
  259. package/dist/telemetry/index.d.ts +31 -0
  260. package/dist/telemetry/index.js +165 -0
  261. package/dist/ui/ascii-patterns.d.ts +16 -0
  262. package/dist/ui/ascii-patterns.js +133 -0
  263. package/dist/ui/welcome-screen.d.ts +10 -0
  264. package/dist/ui/welcome-screen.js +147 -0
  265. package/dist/utils/change-metadata.d.ts +51 -0
  266. package/dist/utils/change-metadata.js +147 -0
  267. package/dist/utils/change-utils.d.ts +62 -0
  268. package/dist/utils/change-utils.js +121 -0
  269. package/dist/utils/command-references.d.ts +18 -0
  270. package/dist/utils/command-references.js +20 -0
  271. package/dist/utils/file-system.d.ts +41 -0
  272. package/dist/utils/file-system.js +302 -0
  273. package/dist/utils/index.d.ts +6 -0
  274. package/dist/utils/index.js +9 -0
  275. package/dist/utils/interactive.d.ts +18 -0
  276. package/dist/utils/interactive.js +21 -0
  277. package/dist/utils/item-discovery.d.ts +4 -0
  278. package/dist/utils/item-discovery.js +72 -0
  279. package/dist/utils/match.d.ts +3 -0
  280. package/dist/utils/match.js +22 -0
  281. package/dist/utils/shell-detection.d.ts +20 -0
  282. package/dist/utils/shell-detection.js +41 -0
  283. package/dist/utils/task-progress.d.ts +8 -0
  284. package/dist/utils/task-progress.js +37 -0
  285. package/package.json +84 -0
  286. package/schemas/spec-driven/schema.yaml +153 -0
  287. package/schemas/spec-driven/templates/design.md +19 -0
  288. package/schemas/spec-driven/templates/proposal.md +23 -0
  289. package/schemas/spec-driven/templates/spec.md +8 -0
  290. package/schemas/spec-driven/templates/tasks.md +9 -0
  291. package/scripts/postinstall.js +83 -0
@@ -0,0 +1,14 @@
1
+ export declare class ShowCommand {
2
+ execute(itemName?: string, options?: {
3
+ json?: boolean;
4
+ type?: string;
5
+ noInteractive?: boolean;
6
+ [k: string]: any;
7
+ }): Promise<void>;
8
+ private normalizeType;
9
+ private runInteractiveByType;
10
+ private showDirect;
11
+ private printNonInteractiveHint;
12
+ private warnIrrelevantFlags;
13
+ }
14
+ //# sourceMappingURL=show.d.ts.map
@@ -0,0 +1,133 @@
1
+ import { isInteractive } from '../utils/interactive.js';
2
+ import { getActiveChangeIds, getSpecIds } from '../utils/item-discovery.js';
3
+ import { ChangeCommand } from './change.js';
4
+ import { SpecCommand } from './spec.js';
5
+ import { nearestMatches } from '../utils/match.js';
6
+ import { SHOW_MESSAGES } from '../messages/index.js';
7
+ const CHANGE_FLAG_KEYS = new Set(['deltasOnly', 'requirementsOnly']);
8
+ const SPEC_FLAG_KEYS = new Set(['requirements', 'scenarios', 'requirement']);
9
+ export class ShowCommand {
10
+ async execute(itemName, options = {}) {
11
+ const interactive = isInteractive(options);
12
+ const typeOverride = this.normalizeType(options.type);
13
+ if (!itemName) {
14
+ if (interactive) {
15
+ const { select } = await import('@inquirer/prompts');
16
+ const type = await select({
17
+ message: SHOW_MESSAGES.whatToShow,
18
+ choices: [
19
+ { name: SHOW_MESSAGES.optionChange, value: 'change' },
20
+ { name: SHOW_MESSAGES.optionSpec, value: 'spec' },
21
+ ],
22
+ });
23
+ await this.runInteractiveByType(type, options);
24
+ return;
25
+ }
26
+ this.printNonInteractiveHint();
27
+ process.exitCode = 1;
28
+ return;
29
+ }
30
+ await this.showDirect(itemName, { typeOverride, options });
31
+ }
32
+ normalizeType(value) {
33
+ if (!value)
34
+ return undefined;
35
+ const v = value.toLowerCase();
36
+ if (v === 'change' || v === 'spec')
37
+ return v;
38
+ return undefined;
39
+ }
40
+ async runInteractiveByType(type, options) {
41
+ const { select } = await import('@inquirer/prompts');
42
+ if (type === 'change') {
43
+ const changes = await getActiveChangeIds();
44
+ if (changes.length === 0) {
45
+ console.error(SHOW_MESSAGES.noChangesFound);
46
+ process.exitCode = 1;
47
+ return;
48
+ }
49
+ const picked = await select({ message: SHOW_MESSAGES.pickChange, choices: changes.map(id => ({ name: id, value: id })) });
50
+ const cmd = new ChangeCommand();
51
+ await cmd.show(picked, options);
52
+ return;
53
+ }
54
+ const specs = await getSpecIds();
55
+ if (specs.length === 0) {
56
+ console.error(SHOW_MESSAGES.noSpecsFound);
57
+ process.exitCode = 1;
58
+ return;
59
+ }
60
+ const picked = await select({ message: SHOW_MESSAGES.pickSpec, choices: specs.map(id => ({ name: id, value: id })) });
61
+ const cmd = new SpecCommand();
62
+ await cmd.show(picked, options);
63
+ }
64
+ async showDirect(itemName, params) {
65
+ // Optimize lookups when type is pre-specified
66
+ let isChange = false;
67
+ let isSpec = false;
68
+ let changes = [];
69
+ let specs = [];
70
+ if (params.typeOverride === 'change') {
71
+ changes = await getActiveChangeIds();
72
+ isChange = changes.includes(itemName);
73
+ }
74
+ else if (params.typeOverride === 'spec') {
75
+ specs = await getSpecIds();
76
+ isSpec = specs.includes(itemName);
77
+ }
78
+ else {
79
+ [changes, specs] = await Promise.all([getActiveChangeIds(), getSpecIds()]);
80
+ isChange = changes.includes(itemName);
81
+ isSpec = specs.includes(itemName);
82
+ }
83
+ const resolvedType = params.typeOverride ?? (isChange ? 'change' : isSpec ? 'spec' : undefined);
84
+ if (!resolvedType) {
85
+ console.error(SHOW_MESSAGES.unknownItem(itemName));
86
+ const suggestions = nearestMatches(itemName, [...changes, ...specs]);
87
+ if (suggestions.length)
88
+ console.error(SHOW_MESSAGES.didYouMean(suggestions.join(', ')));
89
+ process.exitCode = 1;
90
+ return;
91
+ }
92
+ if (!params.typeOverride && isChange && isSpec) {
93
+ console.error(SHOW_MESSAGES.ambiguousItem(itemName));
94
+ console.error(SHOW_MESSAGES.passTypeHint);
95
+ process.exitCode = 1;
96
+ return;
97
+ }
98
+ this.warnIrrelevantFlags(resolvedType, params.options);
99
+ if (resolvedType === 'change') {
100
+ const cmd = new ChangeCommand();
101
+ await cmd.show(itemName, params.options);
102
+ return;
103
+ }
104
+ const cmd = new SpecCommand();
105
+ await cmd.show(itemName, params.options);
106
+ }
107
+ printNonInteractiveHint() {
108
+ console.error(SHOW_MESSAGES.nothingToShow);
109
+ console.error(SHOW_MESSAGES.showItemHint);
110
+ console.error(SHOW_MESSAGES.showChangeHint);
111
+ console.error(SHOW_MESSAGES.showSpecHint);
112
+ console.error(SHOW_MESSAGES.runInteractiveHint);
113
+ }
114
+ warnIrrelevantFlags(type, options) {
115
+ const irrelevant = [];
116
+ if (type === 'change') {
117
+ for (const k of SPEC_FLAG_KEYS)
118
+ if (k in options)
119
+ irrelevant.push(k);
120
+ }
121
+ else {
122
+ for (const k of CHANGE_FLAG_KEYS)
123
+ if (k in options)
124
+ irrelevant.push(k);
125
+ }
126
+ if (irrelevant.length > 0) {
127
+ console.error(SHOW_MESSAGES.ignoringFlags(type, irrelevant.join(', ')));
128
+ return true;
129
+ }
130
+ return false;
131
+ }
132
+ }
133
+ //# sourceMappingURL=show.js.map
@@ -0,0 +1,15 @@
1
+ import { program } from 'commander';
2
+ interface ShowOptions {
3
+ json?: boolean;
4
+ requirements?: boolean;
5
+ scenarios?: boolean;
6
+ requirement?: string;
7
+ noInteractive?: boolean;
8
+ }
9
+ export declare class SpecCommand {
10
+ private SPECS_DIR;
11
+ show(specId?: string, options?: ShowOptions): Promise<void>;
12
+ }
13
+ export declare function registerSpecCommand(rootProgram: typeof program): import("commander").Command;
14
+ export {};
15
+ //# sourceMappingURL=spec.d.ts.map
@@ -0,0 +1,226 @@
1
+ import { existsSync, readdirSync, readFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { MarkdownParser } from '../core/parsers/markdown-parser.js';
4
+ import { Validator } from '../core/validation/validator.js';
5
+ import { isInteractive } from '../utils/interactive.js';
6
+ import { getSpecIds } from '../utils/item-discovery.js';
7
+ import { CLI_DESCRIPTIONS, CLI_MESSAGES, SPEC_MESSAGES } from '../messages/index.js';
8
+ const SPECS_DIR = 'openspec/specs';
9
+ function parseSpecFromFile(specPath, specId) {
10
+ const content = readFileSync(specPath, 'utf-8');
11
+ const parser = new MarkdownParser(content);
12
+ return parser.parseSpec(specId);
13
+ }
14
+ function validateRequirementIndex(spec, requirementOpt) {
15
+ if (!requirementOpt)
16
+ return undefined;
17
+ const index = Number.parseInt(requirementOpt, 10);
18
+ if (!Number.isInteger(index) || index < 1 || index > spec.requirements.length) {
19
+ throw new Error(SPEC_MESSAGES.requirementNotFound(requirementOpt));
20
+ }
21
+ return index - 1; // convert to 0-based
22
+ }
23
+ function filterSpec(spec, options) {
24
+ const requirementIndex = validateRequirementIndex(spec, options.requirement);
25
+ const includeScenarios = options.scenarios !== false && !options.requirements;
26
+ const filteredRequirements = (requirementIndex !== undefined
27
+ ? [spec.requirements[requirementIndex]]
28
+ : spec.requirements).map(req => ({
29
+ text: req.text,
30
+ scenarios: includeScenarios ? req.scenarios : [],
31
+ }));
32
+ const metadata = spec.metadata ?? { version: '1.0.0', format: 'openspec' };
33
+ return {
34
+ name: spec.name,
35
+ overview: spec.overview,
36
+ requirements: filteredRequirements,
37
+ metadata,
38
+ };
39
+ }
40
+ /**
41
+ * Print the raw markdown content for a spec file without any formatting.
42
+ * Raw-first behavior ensures text mode is a passthrough for deterministic output.
43
+ */
44
+ function printSpecTextRaw(specPath) {
45
+ const content = readFileSync(specPath, 'utf-8');
46
+ console.log(content);
47
+ }
48
+ export class SpecCommand {
49
+ SPECS_DIR = 'openspec/specs';
50
+ async show(specId, options = {}) {
51
+ if (!specId) {
52
+ const canPrompt = isInteractive(options);
53
+ const specIds = await getSpecIds();
54
+ if (canPrompt && specIds.length > 0) {
55
+ const { select } = await import('@inquirer/prompts');
56
+ specId = await select({
57
+ message: SPEC_MESSAGES.selectSpecToShow,
58
+ choices: specIds.map(id => ({ name: id, value: id })),
59
+ });
60
+ }
61
+ else {
62
+ throw new Error(SPEC_MESSAGES.missingSpecId);
63
+ }
64
+ }
65
+ const specPath = join(this.SPECS_DIR, specId, 'spec.md');
66
+ if (!existsSync(specPath)) {
67
+ throw new Error(SPEC_MESSAGES.specNotFound(specId));
68
+ }
69
+ if (options.json) {
70
+ if (options.requirements && options.requirement) {
71
+ throw new Error(SPEC_MESSAGES.requirementsAndRequirementConflict);
72
+ }
73
+ const parsed = parseSpecFromFile(specPath, specId);
74
+ const filtered = filterSpec(parsed, options);
75
+ const output = {
76
+ id: specId,
77
+ title: parsed.name,
78
+ overview: parsed.overview,
79
+ requirementCount: filtered.requirements.length,
80
+ requirements: filtered.requirements,
81
+ metadata: parsed.metadata ?? { version: '1.0.0', format: 'openspec' },
82
+ };
83
+ console.log(JSON.stringify(output, null, 2));
84
+ return;
85
+ }
86
+ printSpecTextRaw(specPath);
87
+ }
88
+ }
89
+ export function registerSpecCommand(rootProgram) {
90
+ const specCommand = rootProgram
91
+ .command('spec')
92
+ .description(CLI_DESCRIPTIONS.spec);
93
+ // Deprecation notice for noun-based commands
94
+ specCommand.hook('preAction', () => {
95
+ console.error(CLI_MESSAGES.specCommandsDeprecated);
96
+ });
97
+ specCommand
98
+ .command('show [spec-id]')
99
+ .description(CLI_DESCRIPTIONS.specShow)
100
+ .option('--json', CLI_DESCRIPTIONS.specShowJson)
101
+ .option('--requirements', CLI_DESCRIPTIONS.specShowRequirements)
102
+ .option('--no-scenarios', CLI_DESCRIPTIONS.specShowNoScenarios)
103
+ .option('-r, --requirement <id>', CLI_DESCRIPTIONS.specShowRequirement)
104
+ .option('--no-interactive', CLI_DESCRIPTIONS.specShowNoInteractive)
105
+ .action(async (specId, options) => {
106
+ try {
107
+ const cmd = new SpecCommand();
108
+ await cmd.show(specId, options);
109
+ }
110
+ catch (error) {
111
+ console.error(CLI_MESSAGES.error(error instanceof Error ? error.message : CLI_MESSAGES.unknownError));
112
+ process.exitCode = 1;
113
+ }
114
+ });
115
+ specCommand
116
+ .command('list')
117
+ .description(CLI_DESCRIPTIONS.specList)
118
+ .option('--json', CLI_DESCRIPTIONS.specListJson)
119
+ .option('--long', CLI_DESCRIPTIONS.specListLong)
120
+ .action((options) => {
121
+ try {
122
+ if (!existsSync(SPECS_DIR)) {
123
+ console.log(SPEC_MESSAGES.noItemsFound);
124
+ return;
125
+ }
126
+ const specs = readdirSync(SPECS_DIR, { withFileTypes: true })
127
+ .filter(dirent => dirent.isDirectory())
128
+ .map(dirent => {
129
+ const specPath = join(SPECS_DIR, dirent.name, 'spec.md');
130
+ if (existsSync(specPath)) {
131
+ try {
132
+ const spec = parseSpecFromFile(specPath, dirent.name);
133
+ return {
134
+ id: dirent.name,
135
+ title: spec.name,
136
+ requirementCount: spec.requirements.length
137
+ };
138
+ }
139
+ catch {
140
+ return {
141
+ id: dirent.name,
142
+ title: dirent.name,
143
+ requirementCount: 0
144
+ };
145
+ }
146
+ }
147
+ return null;
148
+ })
149
+ .filter((spec) => spec !== null)
150
+ .sort((a, b) => a.id.localeCompare(b.id));
151
+ if (options.json) {
152
+ console.log(JSON.stringify(specs, null, 2));
153
+ }
154
+ else {
155
+ if (specs.length === 0) {
156
+ console.log(SPEC_MESSAGES.noItemsFound);
157
+ return;
158
+ }
159
+ if (!options.long) {
160
+ specs.forEach(spec => console.log(spec.id));
161
+ return;
162
+ }
163
+ specs.forEach(spec => {
164
+ console.log(`${spec.id}: ${spec.title} ${SPEC_MESSAGES.requirementCount(spec.requirementCount)}`);
165
+ });
166
+ }
167
+ }
168
+ catch (error) {
169
+ console.error(CLI_MESSAGES.error(error instanceof Error ? error.message : CLI_MESSAGES.unknownError));
170
+ process.exitCode = 1;
171
+ }
172
+ });
173
+ specCommand
174
+ .command('validate [spec-id]')
175
+ .description(CLI_DESCRIPTIONS.specValidate)
176
+ .option('--strict', CLI_DESCRIPTIONS.specValidateStrict)
177
+ .option('--json', CLI_DESCRIPTIONS.specValidateJson)
178
+ .option('--no-interactive', CLI_DESCRIPTIONS.specValidateNoInteractive)
179
+ .action(async (specId, options) => {
180
+ try {
181
+ if (!specId) {
182
+ const canPrompt = isInteractive(options);
183
+ const specIds = await getSpecIds();
184
+ if (canPrompt && specIds.length > 0) {
185
+ const { select } = await import('@inquirer/prompts');
186
+ specId = await select({
187
+ message: SPEC_MESSAGES.selectSpecToValidate,
188
+ choices: specIds.map(id => ({ name: id, value: id })),
189
+ });
190
+ }
191
+ else {
192
+ throw new Error(SPEC_MESSAGES.missingSpecId);
193
+ }
194
+ }
195
+ const specPath = join(SPECS_DIR, specId, 'spec.md');
196
+ if (!existsSync(specPath)) {
197
+ throw new Error(SPEC_MESSAGES.specNotFound(specId));
198
+ }
199
+ const validator = new Validator(options.strict);
200
+ const report = await validator.validateSpec(specPath);
201
+ if (options.json) {
202
+ console.log(JSON.stringify(report, null, 2));
203
+ }
204
+ else {
205
+ if (report.valid) {
206
+ console.log(SPEC_MESSAGES.specIsValid(specId));
207
+ }
208
+ else {
209
+ console.error(SPEC_MESSAGES.specHasIssues(specId));
210
+ report.issues.forEach(issue => {
211
+ const label = issue.level === 'ERROR' ? 'ERROR' : issue.level;
212
+ const prefix = issue.level === 'ERROR' ? '✗' : issue.level === 'WARNING' ? '⚠' : 'ℹ';
213
+ console.error(`${prefix} [${label}] ${issue.path}: ${issue.message}`);
214
+ });
215
+ }
216
+ }
217
+ process.exitCode = report.valid ? 0 : 1;
218
+ }
219
+ catch (error) {
220
+ console.error(CLI_MESSAGES.error(error instanceof Error ? error.message : CLI_MESSAGES.unknownError));
221
+ process.exitCode = 1;
222
+ }
223
+ });
224
+ return specCommand;
225
+ }
226
+ //# sourceMappingURL=spec.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Tools Command
3
+ *
4
+ * `openspec tools [path]`
5
+ *
6
+ * Add or remove IDE/Code Agent BR-OpenSpec configuration files interactively.
7
+ * Requires the project to already be initialized with `openspec init`.
8
+ */
9
+ import { Command } from 'commander';
10
+ export declare function registerToolsCommand(program: Command): void;
11
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Tools Command
3
+ *
4
+ * `openspec tools [path]`
5
+ *
6
+ * Add or remove IDE/Code Agent BR-OpenSpec configuration files interactively.
7
+ * Requires the project to already be initialized with `openspec init`.
8
+ */
9
+ import path from 'path';
10
+ import chalk from 'chalk';
11
+ import ora from 'ora';
12
+ import { isProjectInitialized } from '../core/is-project-initialized.js';
13
+ import { addTool, removeTool, getCurrentToolIds, getEligibleTools, resolveToolsArg, } from '../core/tools-manager.js';
14
+ import { AI_TOOLS } from '../core/config.js';
15
+ import { getToolStates } from '../core/shared/index.js';
16
+ import { isInteractive } from '../utils/interactive.js';
17
+ import { TOOLS_MESSAGES, CLI_MESSAGES } from '../messages/index.js';
18
+ // ─────────────────────────────────────────────────────────────────────────────
19
+ // Helpers
20
+ // ─────────────────────────────────────────────────────────────────────────────
21
+ function requireInitialized(projectPath) {
22
+ if (!isProjectInitialized(projectPath)) {
23
+ ora().fail(TOOLS_MESSAGES.notInitialized);
24
+ process.exit(1);
25
+ }
26
+ }
27
+ // ─────────────────────────────────────────────────────────────────────────────
28
+ // Non-interactive add
29
+ // ─────────────────────────────────────────────────────────────────────────────
30
+ async function runAdd(projectPath, toolsArg) {
31
+ const toolIds = resolveToolsArg(toolsArg);
32
+ if (toolIds.length === 0) {
33
+ console.log(chalk.dim(TOOLS_MESSAGES.noToolsToAdd));
34
+ return;
35
+ }
36
+ const added = [];
37
+ const failed = [];
38
+ for (const toolId of toolIds) {
39
+ const tool = AI_TOOLS.find((t) => t.value === toolId);
40
+ if (!tool)
41
+ continue;
42
+ const spinner = ora(TOOLS_MESSAGES.adding(tool.name)).start();
43
+ try {
44
+ await addTool(projectPath, tool);
45
+ spinner.succeed(TOOLS_MESSAGES.added(tool.name));
46
+ added.push(tool.name);
47
+ }
48
+ catch (err) {
49
+ spinner.fail(TOOLS_MESSAGES.failedToAdd(tool.name));
50
+ failed.push({ name: tool.name, error: err });
51
+ }
52
+ }
53
+ console.log();
54
+ if (added.length > 0) {
55
+ console.log(TOOLS_MESSAGES.addedList(added.join(', ')));
56
+ }
57
+ if (failed.length > 0) {
58
+ console.log(chalk.red(TOOLS_MESSAGES.failedList(failed.map((f) => `${f.name} (${f.error.message})`).join(', '))));
59
+ }
60
+ if (added.length > 0) {
61
+ console.log();
62
+ console.log(chalk.white(TOOLS_MESSAGES.restartIDE));
63
+ }
64
+ }
65
+ // ─────────────────────────────────────────────────────────────────────────────
66
+ // Non-interactive remove
67
+ // ─────────────────────────────────────────────────────────────────────────────
68
+ async function runRemove(projectPath, toolsArg) {
69
+ const toolIds = resolveToolsArg(toolsArg);
70
+ if (toolIds.length === 0) {
71
+ console.log(chalk.dim(TOOLS_MESSAGES.noToolsToRemove));
72
+ return;
73
+ }
74
+ const removed = [];
75
+ const failed = [];
76
+ for (const toolId of toolIds) {
77
+ const tool = AI_TOOLS.find((t) => t.value === toolId);
78
+ if (!tool)
79
+ continue;
80
+ const spinner = ora(TOOLS_MESSAGES.removing(tool.name)).start();
81
+ try {
82
+ const counts = await removeTool(projectPath, tool);
83
+ spinner.succeed(TOOLS_MESSAGES.removed(tool.name));
84
+ removed.push(tool.name);
85
+ if (counts.removedSkillCount > 0 || counts.removedCommandCount > 0) {
86
+ console.log(chalk.dim(TOOLS_MESSAGES.removedCounts(counts.removedSkillCount, counts.removedCommandCount)));
87
+ }
88
+ }
89
+ catch (err) {
90
+ spinner.fail(TOOLS_MESSAGES.failedToRemove(tool.name));
91
+ failed.push({ name: tool.name, error: err });
92
+ }
93
+ }
94
+ console.log();
95
+ if (removed.length > 0) {
96
+ console.log(TOOLS_MESSAGES.removedList(removed.join(', ')));
97
+ }
98
+ if (failed.length > 0) {
99
+ console.log(chalk.red(TOOLS_MESSAGES.failedList(failed.map((f) => `${f.name} (${f.error.message})`).join(', '))));
100
+ }
101
+ }
102
+ // ─────────────────────────────────────────────────────────────────────────────
103
+ // Interactive mode
104
+ // ─────────────────────────────────────────────────────────────────────────────
105
+ async function runInteractive(projectPath) {
106
+ const eligibleTools = getEligibleTools();
107
+ const toolStates = getToolStates(projectPath);
108
+ const currentlyConfigured = getCurrentToolIds(projectPath);
109
+ // Build choices for the multi-select, sorted: configured first, then the rest
110
+ const choices = eligibleTools
111
+ .map((tool) => {
112
+ const status = toolStates.get(tool.value);
113
+ const configured = status?.configured ?? false;
114
+ return {
115
+ name: tool.name,
116
+ value: tool.value,
117
+ configured,
118
+ preSelected: configured,
119
+ };
120
+ })
121
+ .sort((a, b) => {
122
+ if (a.configured && !b.configured)
123
+ return -1;
124
+ if (!a.configured && b.configured)
125
+ return 1;
126
+ return 0;
127
+ });
128
+ if (currentlyConfigured.size > 0) {
129
+ const names = [...currentlyConfigured]
130
+ .map((id) => AI_TOOLS.find((t) => t.value === id)?.name ?? id)
131
+ .join(', ');
132
+ console.log(TOOLS_MESSAGES.currentlyConfigured(names));
133
+ }
134
+ else {
135
+ console.log(chalk.dim(TOOLS_MESSAGES.noToolsConfigured));
136
+ }
137
+ console.log();
138
+ const { searchableMultiSelect } = await import('../prompts/searchable-multi-select.js');
139
+ const newSelection = await searchableMultiSelect({
140
+ message: TOOLS_MESSAGES.selectToolsToConfigure(eligibleTools.length),
141
+ pageSize: 15,
142
+ choices,
143
+ });
144
+ const newSet = new Set(newSelection);
145
+ // Compute diffs
146
+ const toAdd = newSelection.filter((id) => !currentlyConfigured.has(id));
147
+ const toRemove = [...currentlyConfigured].filter((id) => !newSet.has(id));
148
+ if (toAdd.length === 0 && toRemove.length === 0) {
149
+ console.log(chalk.dim('\n' + TOOLS_MESSAGES.noChanges));
150
+ return;
151
+ }
152
+ console.log();
153
+ const addedNames = [];
154
+ const removedNames = [];
155
+ const failed = [];
156
+ for (const toolId of toAdd) {
157
+ const tool = AI_TOOLS.find((t) => t.value === toolId);
158
+ if (!tool)
159
+ continue;
160
+ const spinner = ora(TOOLS_MESSAGES.adding(tool.name)).start();
161
+ try {
162
+ await addTool(projectPath, tool);
163
+ spinner.succeed(TOOLS_MESSAGES.added(tool.name));
164
+ addedNames.push(tool.name);
165
+ }
166
+ catch (err) {
167
+ spinner.fail(TOOLS_MESSAGES.failedToAdd(tool.name));
168
+ failed.push({ name: tool.name, error: err });
169
+ }
170
+ }
171
+ for (const toolId of toRemove) {
172
+ const tool = AI_TOOLS.find((t) => t.value === toolId);
173
+ if (!tool)
174
+ continue;
175
+ const spinner = ora(TOOLS_MESSAGES.removing(tool.name)).start();
176
+ try {
177
+ await removeTool(projectPath, tool);
178
+ spinner.succeed(TOOLS_MESSAGES.removed(tool.name));
179
+ removedNames.push(tool.name);
180
+ }
181
+ catch (err) {
182
+ spinner.fail(TOOLS_MESSAGES.failedToRemove(tool.name));
183
+ failed.push({ name: tool.name, error: err });
184
+ }
185
+ }
186
+ console.log();
187
+ if (addedNames.length > 0) {
188
+ console.log(TOOLS_MESSAGES.addedList(addedNames.join(', ')));
189
+ }
190
+ if (removedNames.length > 0) {
191
+ console.log(TOOLS_MESSAGES.removedList(removedNames.join(', ')));
192
+ }
193
+ if (failed.length > 0) {
194
+ console.log(chalk.red(TOOLS_MESSAGES.failedList(failed.map((f) => `${f.name} (${f.error.message})`).join(', '))));
195
+ }
196
+ if (addedNames.length > 0) {
197
+ console.log();
198
+ console.log(chalk.white(TOOLS_MESSAGES.restartIDE));
199
+ }
200
+ }
201
+ // ─────────────────────────────────────────────────────────────────────────────
202
+ // Command registration
203
+ // ─────────────────────────────────────────────────────────────────────────────
204
+ export function registerToolsCommand(program) {
205
+ program
206
+ .command('tools [path]')
207
+ .description(TOOLS_MESSAGES.description)
208
+ .option('--add <tools>', TOOLS_MESSAGES.addOption)
209
+ .option('--remove <tools>', TOOLS_MESSAGES.removeOption)
210
+ .action(async (targetPath = '.', options) => {
211
+ try {
212
+ const projectPath = path.resolve(targetPath);
213
+ requireInitialized(projectPath);
214
+ const hasAdd = typeof options?.add === 'string';
215
+ const hasRemove = typeof options?.remove === 'string';
216
+ if (hasAdd && hasRemove) {
217
+ // Check for overlap
218
+ const addIds = resolveToolsArg(options.add);
219
+ const removeIds = resolveToolsArg(options.remove);
220
+ const overlap = addIds.filter((id) => removeIds.includes(id));
221
+ if (overlap.length > 0) {
222
+ throw new Error(TOOLS_MESSAGES.cannotAddAndRemoveSame(overlap.join(', ')));
223
+ }
224
+ // Run both sequentially
225
+ if (addIds.length > 0)
226
+ await runAdd(projectPath, options.add);
227
+ if (removeIds.length > 0)
228
+ await runRemove(projectPath, options.remove);
229
+ return;
230
+ }
231
+ if (hasAdd) {
232
+ await runAdd(projectPath, options.add);
233
+ return;
234
+ }
235
+ if (hasRemove) {
236
+ await runRemove(projectPath, options.remove);
237
+ return;
238
+ }
239
+ // Interactive mode
240
+ if (!isInteractive()) {
241
+ throw new Error(TOOLS_MESSAGES.noFlagNonInteractive);
242
+ }
243
+ await runInteractive(projectPath);
244
+ }
245
+ catch (error) {
246
+ console.log();
247
+ ora().fail(CLI_MESSAGES.error(error.message));
248
+ process.exit(1);
249
+ }
250
+ });
251
+ }
252
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1,24 @@
1
+ interface ExecuteOptions {
2
+ all?: boolean;
3
+ changes?: boolean;
4
+ specs?: boolean;
5
+ type?: string;
6
+ strict?: boolean;
7
+ json?: boolean;
8
+ noInteractive?: boolean;
9
+ interactive?: boolean;
10
+ concurrency?: string;
11
+ }
12
+ export declare class ValidateCommand {
13
+ execute(itemName: string | undefined, options?: ExecuteOptions): Promise<void>;
14
+ private normalizeType;
15
+ private runInteractiveSelector;
16
+ private printNonInteractiveHint;
17
+ private validateDirectItem;
18
+ private validateByType;
19
+ private printReport;
20
+ private printNextSteps;
21
+ private runBulkValidation;
22
+ }
23
+ export {};
24
+ //# sourceMappingURL=validate.d.ts.map