@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,869 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import ora from 'ora';
4
+ import { stringify as stringifyYaml } from 'yaml';
5
+ import { getSchemaDir, getProjectSchemasDir, getUserSchemasDir, getPackageSchemasDir, listSchemas, } from '../core/artifact-graph/resolver.js';
6
+ import { parseSchema, SchemaValidationError } from '../core/artifact-graph/schema.js';
7
+ import { SCHEMA_MESSAGES, CLI_MESSAGES, CONFIG_MESSAGES } from '../messages/index.js';
8
+ /**
9
+ * Check all three locations for a schema and return which ones exist.
10
+ */
11
+ function checkAllLocations(name, projectRoot) {
12
+ const locations = [];
13
+ // Project location
14
+ const projectDir = path.join(getProjectSchemasDir(projectRoot), name);
15
+ const projectSchemaPath = path.join(projectDir, 'schema.yaml');
16
+ locations.push({
17
+ source: 'project',
18
+ path: projectDir,
19
+ exists: fs.existsSync(projectSchemaPath),
20
+ });
21
+ // User location
22
+ const userDir = path.join(getUserSchemasDir(), name);
23
+ const userSchemaPath = path.join(userDir, 'schema.yaml');
24
+ locations.push({
25
+ source: 'user',
26
+ path: userDir,
27
+ exists: fs.existsSync(userSchemaPath),
28
+ });
29
+ // Package location
30
+ const packageDir = path.join(getPackageSchemasDir(), name);
31
+ const packageSchemaPath = path.join(packageDir, 'schema.yaml');
32
+ locations.push({
33
+ source: 'package',
34
+ path: packageDir,
35
+ exists: fs.existsSync(packageSchemaPath),
36
+ });
37
+ return locations;
38
+ }
39
+ /**
40
+ * Get resolution info for a schema including shadow detection.
41
+ */
42
+ function getSchemaResolution(name, projectRoot) {
43
+ const locations = checkAllLocations(name, projectRoot);
44
+ const existingLocations = locations.filter((loc) => loc.exists);
45
+ if (existingLocations.length === 0) {
46
+ return null;
47
+ }
48
+ const active = existingLocations[0];
49
+ const shadows = existingLocations.slice(1).map((loc) => ({
50
+ source: loc.source,
51
+ path: loc.path,
52
+ }));
53
+ return {
54
+ name,
55
+ source: active.source,
56
+ path: active.path,
57
+ shadows,
58
+ };
59
+ }
60
+ /**
61
+ * Get all schemas with resolution info.
62
+ */
63
+ function getAllSchemasWithResolution(projectRoot) {
64
+ const schemaNames = listSchemas(projectRoot);
65
+ const results = [];
66
+ for (const name of schemaNames) {
67
+ const resolution = getSchemaResolution(name, projectRoot);
68
+ if (resolution) {
69
+ results.push(resolution);
70
+ }
71
+ }
72
+ return results;
73
+ }
74
+ /**
75
+ * Validate a schema and return issues.
76
+ */
77
+ function validateSchema(schemaDir, verbose = false) {
78
+ const issues = [];
79
+ const schemaPath = path.join(schemaDir, 'schema.yaml');
80
+ // Check schema.yaml exists
81
+ if (verbose) {
82
+ console.log(SCHEMA_MESSAGES.checkingSchemaExists);
83
+ }
84
+ if (!fs.existsSync(schemaPath)) {
85
+ issues.push({
86
+ level: 'error',
87
+ path: 'schema.yaml',
88
+ message: SCHEMA_MESSAGES.schemaNotFound,
89
+ });
90
+ return { valid: false, issues };
91
+ }
92
+ // Parse YAML
93
+ if (verbose) {
94
+ console.log(SCHEMA_MESSAGES.parsingYaml);
95
+ }
96
+ let content;
97
+ try {
98
+ content = fs.readFileSync(schemaPath, 'utf-8');
99
+ }
100
+ catch (err) {
101
+ issues.push({
102
+ level: 'error',
103
+ path: 'schema.yaml',
104
+ message: SCHEMA_MESSAGES.failedToReadFile(err.message),
105
+ });
106
+ return { valid: false, issues };
107
+ }
108
+ // Validate against Zod schema
109
+ if (verbose) {
110
+ console.log(SCHEMA_MESSAGES.validatingSchemaStructure);
111
+ }
112
+ let schema;
113
+ try {
114
+ schema = parseSchema(content);
115
+ }
116
+ catch (err) {
117
+ if (err instanceof SchemaValidationError) {
118
+ issues.push({
119
+ level: 'error',
120
+ path: 'schema.yaml',
121
+ message: err.message,
122
+ });
123
+ }
124
+ else {
125
+ issues.push({
126
+ level: 'error',
127
+ path: 'schema.yaml',
128
+ message: SCHEMA_MESSAGES.parseError(err.message),
129
+ });
130
+ }
131
+ return { valid: false, issues };
132
+ }
133
+ // Check template files exist
134
+ // Templates can be in schemaDir directly or in a templates/ subdirectory
135
+ if (verbose) {
136
+ console.log(SCHEMA_MESSAGES.checkingTemplateFiles);
137
+ }
138
+ for (const artifact of schema.artifacts) {
139
+ // Try templates subdirectory first (standard location), then root
140
+ const templatePathInTemplates = path.join(schemaDir, 'templates', artifact.template);
141
+ const templatePathInRoot = path.join(schemaDir, artifact.template);
142
+ if (!fs.existsSync(templatePathInTemplates) && !fs.existsSync(templatePathInRoot)) {
143
+ issues.push({
144
+ level: 'error',
145
+ path: `artifacts.${artifact.id}.template`,
146
+ message: SCHEMA_MESSAGES.templateNotFound(artifact.template, artifact.id),
147
+ });
148
+ }
149
+ }
150
+ // Dependency graph validation is already done by parseSchema
151
+ // (it throws on cycles and invalid references)
152
+ if (verbose) {
153
+ console.log(SCHEMA_MESSAGES.dependencyGraphPassed);
154
+ }
155
+ return { valid: issues.length === 0, issues };
156
+ }
157
+ /**
158
+ * Validate schema name format (kebab-case).
159
+ */
160
+ function isValidSchemaName(name) {
161
+ return /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(name);
162
+ }
163
+ /**
164
+ * Copy a directory recursively.
165
+ */
166
+ function copyDirRecursive(src, dest) {
167
+ fs.mkdirSync(dest, { recursive: true });
168
+ const entries = fs.readdirSync(src, { withFileTypes: true });
169
+ for (const entry of entries) {
170
+ const srcPath = path.join(src, entry.name);
171
+ const destPath = path.join(dest, entry.name);
172
+ if (entry.isDirectory()) {
173
+ copyDirRecursive(srcPath, destPath);
174
+ }
175
+ else {
176
+ fs.copyFileSync(srcPath, destPath);
177
+ }
178
+ }
179
+ }
180
+ /**
181
+ * Default artifacts with descriptions for schema init.
182
+ */
183
+ const DEFAULT_ARTIFACTS = [
184
+ {
185
+ id: 'proposal',
186
+ description: 'High-level description of the change, its motivation, and scope',
187
+ generates: 'proposal.md',
188
+ template: 'proposal.md',
189
+ },
190
+ {
191
+ id: 'specs',
192
+ description: 'Detailed specifications with requirements and scenarios',
193
+ generates: 'specs/**/*.md',
194
+ template: 'specs/spec.md',
195
+ },
196
+ {
197
+ id: 'design',
198
+ description: 'Technical design decisions and implementation approach',
199
+ generates: 'design.md',
200
+ template: 'design.md',
201
+ },
202
+ {
203
+ id: 'tasks',
204
+ description: 'Implementation checklist with trackable tasks',
205
+ generates: 'tasks.md',
206
+ template: 'tasks.md',
207
+ },
208
+ ];
209
+ /**
210
+ * Register the schema command and all its subcommands.
211
+ */
212
+ export function registerSchemaCommand(program) {
213
+ const schemaCmd = program
214
+ .command('schema')
215
+ .description(SCHEMA_MESSAGES.manageWorkflows);
216
+ // Experimental warning
217
+ schemaCmd.hook('preAction', () => {
218
+ console.error(SCHEMA_MESSAGES.experimentalWarning);
219
+ });
220
+ // schema which
221
+ schemaCmd
222
+ .command('which [name]')
223
+ .description(SCHEMA_MESSAGES.showResolve)
224
+ .option('--json', SCHEMA_MESSAGES.outputAsJson)
225
+ .option('--all', SCHEMA_MESSAGES.listAllSchemasOption)
226
+ .action(async (name, options) => {
227
+ try {
228
+ const projectRoot = process.cwd();
229
+ if (options?.all) {
230
+ // List all schemas
231
+ const schemas = getAllSchemasWithResolution(projectRoot);
232
+ if (options?.json) {
233
+ console.log(JSON.stringify(schemas, null, 2));
234
+ }
235
+ else {
236
+ if (schemas.length === 0) {
237
+ console.log(SCHEMA_MESSAGES.noSchemasFound);
238
+ return;
239
+ }
240
+ // Group by source
241
+ const bySource = {
242
+ project: schemas.filter((s) => s.source === 'project'),
243
+ user: schemas.filter((s) => s.source === 'user'),
244
+ package: schemas.filter((s) => s.source === 'package'),
245
+ };
246
+ if (bySource.project.length > 0) {
247
+ console.log('\n' + SCHEMA_MESSAGES.projectSchemasHeader);
248
+ for (const schema of bySource.project) {
249
+ const shadowInfo = schema.shadows.length > 0
250
+ ? SCHEMA_MESSAGES.shadowsLabel(schema.shadows.map((s) => s.source).join(', '))
251
+ : '';
252
+ console.log(` ${schema.name}${shadowInfo}`);
253
+ }
254
+ }
255
+ if (bySource.user.length > 0) {
256
+ console.log('\n' + SCHEMA_MESSAGES.userSchemasHeader);
257
+ for (const schema of bySource.user) {
258
+ const shadowInfo = schema.shadows.length > 0
259
+ ? SCHEMA_MESSAGES.shadowsLabel(schema.shadows.map((s) => s.source).join(', '))
260
+ : '';
261
+ console.log(` ${schema.name}${shadowInfo}`);
262
+ }
263
+ }
264
+ if (bySource.package.length > 0) {
265
+ console.log('\n' + SCHEMA_MESSAGES.packageSchemasHeader);
266
+ for (const schema of bySource.package) {
267
+ console.log(` ${schema.name}`);
268
+ }
269
+ }
270
+ }
271
+ return;
272
+ }
273
+ if (!name) {
274
+ console.error(SCHEMA_MESSAGES.schemaNameRequired);
275
+ process.exitCode = 1;
276
+ return;
277
+ }
278
+ const resolution = getSchemaResolution(name, projectRoot);
279
+ if (!resolution) {
280
+ const available = listSchemas(projectRoot);
281
+ if (options?.json) {
282
+ console.log(JSON.stringify({
283
+ error: SCHEMA_MESSAGES.schemaNotFoundError(name),
284
+ available,
285
+ }, null, 2));
286
+ }
287
+ else {
288
+ console.error(SCHEMA_MESSAGES.schemaNotFoundError(name));
289
+ console.error(SCHEMA_MESSAGES.availableSchemas(available.join(', ')));
290
+ }
291
+ process.exitCode = 1;
292
+ return;
293
+ }
294
+ if (options?.json) {
295
+ console.log(JSON.stringify(resolution, null, 2));
296
+ }
297
+ else {
298
+ console.log(SCHEMA_MESSAGES.schemaLabel(resolution.name));
299
+ console.log(SCHEMA_MESSAGES.sourceLabel(resolution.source));
300
+ console.log(SCHEMA_MESSAGES.pathLabel(resolution.path));
301
+ if (resolution.shadows.length > 0) {
302
+ console.log('\n' + SCHEMA_MESSAGES.shadowsHeader);
303
+ for (const shadow of resolution.shadows) {
304
+ console.log(SCHEMA_MESSAGES.shadowEntry(shadow.source, shadow.path));
305
+ }
306
+ }
307
+ }
308
+ }
309
+ catch (error) {
310
+ console.error(CLI_MESSAGES.error(error.message));
311
+ process.exitCode = 1;
312
+ }
313
+ });
314
+ // schema validate
315
+ schemaCmd
316
+ .command('validate [name]')
317
+ .description(SCHEMA_MESSAGES.validateStructure)
318
+ .option('--json', SCHEMA_MESSAGES.outputAsJson)
319
+ .option('--verbose', SCHEMA_MESSAGES.verboseOption)
320
+ .action(async (name, options) => {
321
+ try {
322
+ const projectRoot = process.cwd();
323
+ if (!name) {
324
+ // Validate all project schemas
325
+ const projectSchemasDir = getProjectSchemasDir(projectRoot);
326
+ if (!fs.existsSync(projectSchemasDir)) {
327
+ if (options?.json) {
328
+ console.log(JSON.stringify({
329
+ valid: true,
330
+ message: SCHEMA_MESSAGES.noProjectSchemasDir,
331
+ schemas: [],
332
+ }, null, 2));
333
+ }
334
+ else {
335
+ console.log(SCHEMA_MESSAGES.noProjectSchemasDir + '.');
336
+ }
337
+ return;
338
+ }
339
+ const entries = fs.readdirSync(projectSchemasDir, { withFileTypes: true });
340
+ const schemaResults = [];
341
+ let anyInvalid = false;
342
+ for (const entry of entries) {
343
+ if (!entry.isDirectory())
344
+ continue;
345
+ const schemaDir = path.join(projectSchemasDir, entry.name);
346
+ const schemaPath = path.join(schemaDir, 'schema.yaml');
347
+ if (!fs.existsSync(schemaPath))
348
+ continue;
349
+ if (options?.verbose && !options?.json) {
350
+ console.log('\n' + SCHEMA_MESSAGES.validatingEntry(entry.name));
351
+ }
352
+ const result = validateSchema(schemaDir, options?.verbose && !options?.json);
353
+ schemaResults.push({
354
+ name: entry.name,
355
+ path: schemaDir,
356
+ valid: result.valid,
357
+ issues: result.issues,
358
+ });
359
+ if (!result.valid) {
360
+ anyInvalid = true;
361
+ }
362
+ }
363
+ if (options?.json) {
364
+ console.log(JSON.stringify({
365
+ valid: !anyInvalid,
366
+ schemas: schemaResults,
367
+ }, null, 2));
368
+ }
369
+ else {
370
+ if (schemaResults.length === 0) {
371
+ console.log(SCHEMA_MESSAGES.noSchemasInProject);
372
+ return;
373
+ }
374
+ console.log('\n' + SCHEMA_MESSAGES.validationResultsHeader);
375
+ for (const result of schemaResults) {
376
+ console.log(SCHEMA_MESSAGES.validationStatus(result.valid, result.name));
377
+ for (const issue of result.issues) {
378
+ console.log(SCHEMA_MESSAGES.issueLine(issue.level, issue.message));
379
+ }
380
+ }
381
+ if (anyInvalid) {
382
+ process.exitCode = 1;
383
+ }
384
+ }
385
+ return;
386
+ }
387
+ // Validate specific schema
388
+ const schemaDir = getSchemaDir(name, projectRoot);
389
+ if (!schemaDir) {
390
+ const available = listSchemas(projectRoot);
391
+ if (options?.json) {
392
+ console.log(JSON.stringify({
393
+ valid: false,
394
+ error: SCHEMA_MESSAGES.schemaNotFoundError(name),
395
+ available,
396
+ }, null, 2));
397
+ }
398
+ else {
399
+ console.error(SCHEMA_MESSAGES.schemaNotFoundError(name));
400
+ console.error(SCHEMA_MESSAGES.availableSchemas(available.join(', ')));
401
+ }
402
+ process.exitCode = 1;
403
+ return;
404
+ }
405
+ if (options?.verbose && !options?.json) {
406
+ console.log(SCHEMA_MESSAGES.validatingEntry(name));
407
+ }
408
+ const result = validateSchema(schemaDir, options?.verbose && !options?.json);
409
+ if (options?.json) {
410
+ console.log(JSON.stringify({
411
+ name,
412
+ path: schemaDir,
413
+ valid: result.valid,
414
+ issues: result.issues,
415
+ }, null, 2));
416
+ }
417
+ else {
418
+ if (result.valid) {
419
+ console.log(SCHEMA_MESSAGES.schemaIsValid(name));
420
+ }
421
+ else {
422
+ console.log(SCHEMA_MESSAGES.schemaHasErrors(name));
423
+ for (const issue of result.issues) {
424
+ console.log(SCHEMA_MESSAGES.issueLine(issue.level, issue.message));
425
+ }
426
+ process.exitCode = 1;
427
+ }
428
+ }
429
+ }
430
+ catch (error) {
431
+ if (options?.json) {
432
+ console.log(JSON.stringify({
433
+ valid: false,
434
+ error: error.message,
435
+ }, null, 2));
436
+ }
437
+ else {
438
+ console.error(CLI_MESSAGES.error(error.message));
439
+ }
440
+ process.exitCode = 1;
441
+ }
442
+ });
443
+ // schema fork
444
+ schemaCmd
445
+ .command('fork <source> [name]')
446
+ .description(SCHEMA_MESSAGES.copySchema)
447
+ .option('--json', SCHEMA_MESSAGES.outputAsJson)
448
+ .option('--force', SCHEMA_MESSAGES.forceOption)
449
+ .action(async (source, name, options) => {
450
+ const spinner = options?.json ? null : ora();
451
+ try {
452
+ const projectRoot = process.cwd();
453
+ const destinationName = name || `${source}-custom`;
454
+ // Validate destination name
455
+ if (!isValidSchemaName(destinationName)) {
456
+ if (options?.json) {
457
+ console.log(JSON.stringify({
458
+ forked: false,
459
+ error: SCHEMA_MESSAGES.invalidSchemaName(destinationName),
460
+ }, null, 2));
461
+ }
462
+ else {
463
+ console.error(SCHEMA_MESSAGES.invalidSchemaName(destinationName).replace(/^Nome/, 'Erro: Nome'));
464
+ console.error(SCHEMA_MESSAGES.schemaNamesKebabCase);
465
+ }
466
+ process.exitCode = 1;
467
+ return;
468
+ }
469
+ // Find source schema
470
+ const sourceDir = getSchemaDir(source, projectRoot);
471
+ if (!sourceDir) {
472
+ const available = listSchemas(projectRoot);
473
+ if (options?.json) {
474
+ console.log(JSON.stringify({
475
+ forked: false,
476
+ error: SCHEMA_MESSAGES.schemaSourceNotFound(source),
477
+ available,
478
+ }, null, 2));
479
+ }
480
+ else {
481
+ console.error(SCHEMA_MESSAGES.schemaNotFoundError(source).replace(/^Esquema/, 'Erro: Esquema'));
482
+ console.error(SCHEMA_MESSAGES.availableSchemas(available.join(', ')));
483
+ }
484
+ process.exitCode = 1;
485
+ return;
486
+ }
487
+ // Determine source location
488
+ const sourceResolution = getSchemaResolution(source, projectRoot);
489
+ const sourceLocation = sourceResolution?.source || 'package';
490
+ // Check destination
491
+ const destinationDir = path.join(getProjectSchemasDir(projectRoot), destinationName);
492
+ if (fs.existsSync(destinationDir)) {
493
+ if (!options?.force) {
494
+ if (options?.json) {
495
+ console.log(JSON.stringify({
496
+ forked: false,
497
+ error: SCHEMA_MESSAGES.schemaAlreadyExists(destinationName),
498
+ suggestion: SCHEMA_MESSAGES.suggestionForceOverwrite,
499
+ }, null, 2));
500
+ }
501
+ else {
502
+ console.error(SCHEMA_MESSAGES.schemaAlreadyExistsAt(destinationName, destinationDir));
503
+ console.error(SCHEMA_MESSAGES.suggestionForceOverwrite);
504
+ }
505
+ process.exitCode = 1;
506
+ return;
507
+ }
508
+ // Remove existing
509
+ if (spinner)
510
+ spinner.start(SCHEMA_MESSAGES.removingExistingSchema(destinationName));
511
+ fs.rmSync(destinationDir, { recursive: true });
512
+ }
513
+ // Copy schema
514
+ if (spinner)
515
+ spinner.start(SCHEMA_MESSAGES.forkingSchema(source, destinationName));
516
+ copyDirRecursive(sourceDir, destinationDir);
517
+ // Update name in schema.yaml
518
+ const destSchemaPath = path.join(destinationDir, 'schema.yaml');
519
+ const schemaContent = fs.readFileSync(destSchemaPath, 'utf-8');
520
+ const schema = parseSchema(schemaContent);
521
+ schema.name = destinationName;
522
+ fs.writeFileSync(destSchemaPath, stringifyYaml(schema));
523
+ if (spinner)
524
+ spinner.succeed(SCHEMA_MESSAGES.forkedSchema(source, destinationName));
525
+ if (options?.json) {
526
+ console.log(JSON.stringify({
527
+ forked: true,
528
+ source,
529
+ sourcePath: sourceDir,
530
+ sourceLocation,
531
+ destination: destinationName,
532
+ destinationPath: destinationDir,
533
+ }, null, 2));
534
+ }
535
+ else {
536
+ console.log('\n' + SCHEMA_MESSAGES.sourceLabel2(sourceDir, sourceLocation));
537
+ console.log(SCHEMA_MESSAGES.destinationLabel(destinationDir));
538
+ console.log('\n' + SCHEMA_MESSAGES.customizeSchemaAt);
539
+ console.log(` ${path.join(destinationDir, 'schema.yaml')}`);
540
+ }
541
+ }
542
+ catch (error) {
543
+ if (spinner)
544
+ spinner.fail(SCHEMA_MESSAGES.forkFailed);
545
+ if (options?.json) {
546
+ console.log(JSON.stringify({
547
+ forked: false,
548
+ error: error.message,
549
+ }, null, 2));
550
+ }
551
+ else {
552
+ console.error(CLI_MESSAGES.error(error.message));
553
+ }
554
+ process.exitCode = 1;
555
+ }
556
+ });
557
+ // schema init
558
+ schemaCmd
559
+ .command('init <name>')
560
+ .description(SCHEMA_MESSAGES.createSchema)
561
+ .option('--json', SCHEMA_MESSAGES.outputAsJson)
562
+ .option('--description <text>', SCHEMA_MESSAGES.descriptionOption)
563
+ .option('--artifacts <list>', SCHEMA_MESSAGES.artifactsOption)
564
+ .option('--default', SCHEMA_MESSAGES.defaultOption)
565
+ .option('--no-default', SCHEMA_MESSAGES.noDefaultOption)
566
+ .option('--force', SCHEMA_MESSAGES.forceOption2)
567
+ .action(async (name, options) => {
568
+ const spinner = options?.json ? null : ora();
569
+ try {
570
+ const projectRoot = process.cwd();
571
+ // Validate name
572
+ if (!isValidSchemaName(name)) {
573
+ if (options?.json) {
574
+ console.log(JSON.stringify({
575
+ created: false,
576
+ error: SCHEMA_MESSAGES.invalidSchemaName(name),
577
+ }, null, 2));
578
+ }
579
+ else {
580
+ console.error(SCHEMA_MESSAGES.invalidSchemaName(name).replace(/^Nome/, 'Erro: Nome'));
581
+ console.error(SCHEMA_MESSAGES.schemaNamesKebabCase);
582
+ }
583
+ process.exitCode = 1;
584
+ return;
585
+ }
586
+ const schemaDir = path.join(getProjectSchemasDir(projectRoot), name);
587
+ // Check if exists
588
+ if (fs.existsSync(schemaDir)) {
589
+ if (!options?.force) {
590
+ if (options?.json) {
591
+ console.log(JSON.stringify({
592
+ created: false,
593
+ error: SCHEMA_MESSAGES.schemaAlreadyExists(name),
594
+ suggestion: SCHEMA_MESSAGES.suggestionForkOrForce,
595
+ }, null, 2));
596
+ }
597
+ else {
598
+ console.error(SCHEMA_MESSAGES.schemaAlreadyExistsAt(name, schemaDir));
599
+ console.error(SCHEMA_MESSAGES.suggestionForkOrForce);
600
+ }
601
+ process.exitCode = 1;
602
+ return;
603
+ }
604
+ if (spinner)
605
+ spinner.start(SCHEMA_MESSAGES.removingExistingSchema(name));
606
+ fs.rmSync(schemaDir, { recursive: true });
607
+ }
608
+ // Determine artifacts and description
609
+ let description;
610
+ let selectedArtifactIds;
611
+ // Check if we have explicit flags (non-interactive mode)
612
+ const hasExplicitOptions = options?.description !== undefined || options?.artifacts !== undefined;
613
+ const isInteractive = !options?.json && !hasExplicitOptions && process.stdout.isTTY;
614
+ if (isInteractive) {
615
+ // Interactive mode
616
+ const { input, checkbox, confirm } = await import('@inquirer/prompts');
617
+ description = await input({
618
+ message: CONFIG_MESSAGES.schemaDescription,
619
+ default: SCHEMA_MESSAGES.defaultSchemaDescription(name),
620
+ });
621
+ const artifactChoices = DEFAULT_ARTIFACTS.map((a) => ({
622
+ name: a.id,
623
+ value: a.id,
624
+ checked: true,
625
+ }));
626
+ selectedArtifactIds = await checkbox({
627
+ message: CONFIG_MESSAGES.selectArtifacts,
628
+ choices: artifactChoices,
629
+ });
630
+ if (selectedArtifactIds.length === 0) {
631
+ console.error(SCHEMA_MESSAGES.atLeastOneArtifact);
632
+ process.exitCode = 1;
633
+ return;
634
+ }
635
+ // Ask about setting as default (unless --no-default was passed)
636
+ if (options?.default === undefined) {
637
+ const setAsDefault = await confirm({
638
+ message: CONFIG_MESSAGES.setAsDefaultSchema,
639
+ default: false,
640
+ });
641
+ if (setAsDefault) {
642
+ options = { ...options, default: true };
643
+ }
644
+ }
645
+ }
646
+ else {
647
+ // Non-interactive mode
648
+ description = options?.description || SCHEMA_MESSAGES.defaultSchemaDescription(name);
649
+ if (options?.artifacts) {
650
+ selectedArtifactIds = options.artifacts.split(',').map((a) => a.trim());
651
+ // Validate artifact IDs
652
+ const validIds = DEFAULT_ARTIFACTS.map((a) => a.id);
653
+ for (const id of selectedArtifactIds) {
654
+ if (!validIds.includes(id)) {
655
+ if (options?.json) {
656
+ console.log(JSON.stringify({
657
+ created: false,
658
+ error: SCHEMA_MESSAGES.unknownArtifact(id),
659
+ valid: validIds,
660
+ }, null, 2));
661
+ }
662
+ else {
663
+ console.error(SCHEMA_MESSAGES.unknownArtifact(id).replace(/^Artefato/, 'Erro: Artefato'));
664
+ console.error(SCHEMA_MESSAGES.validArtifacts(validIds.join(', ')));
665
+ }
666
+ process.exitCode = 1;
667
+ return;
668
+ }
669
+ }
670
+ }
671
+ else {
672
+ // Default to all artifacts
673
+ selectedArtifactIds = DEFAULT_ARTIFACTS.map((a) => a.id);
674
+ }
675
+ }
676
+ // Create schema directory
677
+ if (spinner)
678
+ spinner.start(SCHEMA_MESSAGES.creatingSchema(name));
679
+ fs.mkdirSync(schemaDir, { recursive: true });
680
+ // Build artifacts array with proper dependencies
681
+ const selectedArtifacts = selectedArtifactIds.map((id) => {
682
+ const template = DEFAULT_ARTIFACTS.find((a) => a.id === id);
683
+ const artifact = {
684
+ id: template.id,
685
+ generates: template.generates,
686
+ description: template.description,
687
+ template: template.template,
688
+ requires: [],
689
+ };
690
+ // Set up dependencies based on typical workflow
691
+ if (id === 'specs' && selectedArtifactIds.includes('proposal')) {
692
+ artifact.requires = ['proposal'];
693
+ }
694
+ else if (id === 'design' && selectedArtifactIds.includes('specs')) {
695
+ artifact.requires = ['specs'];
696
+ }
697
+ else if (id === 'tasks') {
698
+ const requires = [];
699
+ if (selectedArtifactIds.includes('design'))
700
+ requires.push('design');
701
+ else if (selectedArtifactIds.includes('specs'))
702
+ requires.push('specs');
703
+ artifact.requires = requires;
704
+ }
705
+ return artifact;
706
+ });
707
+ // Create schema.yaml
708
+ const schema = {
709
+ name,
710
+ version: 1,
711
+ description,
712
+ artifacts: selectedArtifacts,
713
+ };
714
+ // Add apply phase if tasks is included
715
+ if (selectedArtifactIds.includes('tasks')) {
716
+ schema.apply = {
717
+ requires: ['tasks'],
718
+ tracks: 'tasks.md',
719
+ };
720
+ }
721
+ fs.writeFileSync(path.join(schemaDir, 'schema.yaml'), stringifyYaml(schema));
722
+ // Create template files in templates/ subdirectory (standard location)
723
+ const templatesDir = path.join(schemaDir, 'templates');
724
+ for (const artifact of selectedArtifacts) {
725
+ const templatePath = path.join(templatesDir, artifact.template);
726
+ const templateDir = path.dirname(templatePath);
727
+ if (!fs.existsSync(templateDir)) {
728
+ fs.mkdirSync(templateDir, { recursive: true });
729
+ }
730
+ // Create default template content
731
+ const templateContent = createDefaultTemplate(artifact.id);
732
+ fs.writeFileSync(templatePath, templateContent);
733
+ }
734
+ // Update config if --default
735
+ if (options?.default) {
736
+ const configPath = path.join(projectRoot, 'openspec', 'config.yaml');
737
+ if (fs.existsSync(configPath)) {
738
+ const { parse: parseYaml, stringify: stringifyYaml2 } = await import('yaml');
739
+ const configContent = fs.readFileSync(configPath, 'utf-8');
740
+ const config = parseYaml(configContent) || {};
741
+ config.defaultSchema = name;
742
+ fs.writeFileSync(configPath, stringifyYaml2(config));
743
+ }
744
+ else {
745
+ // Create config file
746
+ const configDir = path.dirname(configPath);
747
+ if (!fs.existsSync(configDir)) {
748
+ fs.mkdirSync(configDir, { recursive: true });
749
+ }
750
+ fs.writeFileSync(configPath, stringifyYaml({ defaultSchema: name }));
751
+ }
752
+ }
753
+ if (spinner)
754
+ spinner.succeed(SCHEMA_MESSAGES.schemaCreated(name));
755
+ if (options?.json) {
756
+ console.log(JSON.stringify({
757
+ created: true,
758
+ path: schemaDir,
759
+ schema: name,
760
+ artifacts: selectedArtifactIds,
761
+ setAsDefault: options?.default || false,
762
+ }, null, 2));
763
+ }
764
+ else {
765
+ console.log('\n' + SCHEMA_MESSAGES.schemaCreatedAt(schemaDir));
766
+ console.log('\n' + SCHEMA_MESSAGES.artifactsLabel(selectedArtifactIds.join(', ')));
767
+ if (options?.default) {
768
+ console.log('\n' + SCHEMA_MESSAGES.setAsDefaultSchemaLabel);
769
+ }
770
+ console.log('\n' + SCHEMA_MESSAGES.nextStepsHeader);
771
+ console.log(SCHEMA_MESSAGES.editSchemaYaml(schemaDir));
772
+ console.log(SCHEMA_MESSAGES.modifyTemplates);
773
+ console.log(SCHEMA_MESSAGES.useWithSchema(name));
774
+ }
775
+ }
776
+ catch (error) {
777
+ if (spinner)
778
+ spinner.fail(SCHEMA_MESSAGES.creationFailed);
779
+ if (options?.json) {
780
+ console.log(JSON.stringify({
781
+ created: false,
782
+ error: error.message,
783
+ }, null, 2));
784
+ }
785
+ else {
786
+ console.error(CLI_MESSAGES.error(error.message));
787
+ }
788
+ process.exitCode = 1;
789
+ }
790
+ });
791
+ }
792
+ /**
793
+ * Create default template content for an artifact.
794
+ */
795
+ function createDefaultTemplate(artifactId) {
796
+ switch (artifactId) {
797
+ case 'proposal':
798
+ return `## Why
799
+
800
+ <!-- Describe the motivation for this change -->
801
+
802
+ ## What Changes
803
+
804
+ <!-- Describe what will change -->
805
+
806
+ ## Capabilities
807
+
808
+ ### New Capabilities
809
+ <!-- List new capabilities -->
810
+
811
+ ### Modified Capabilities
812
+ <!-- List modified capabilities -->
813
+
814
+ ## Impact
815
+
816
+ <!-- Describe the impact on existing functionality -->
817
+ `;
818
+ case 'specs':
819
+ return `## ADDED Requirements
820
+
821
+ ### Requirement: Example requirement
822
+
823
+ Description of the requirement.
824
+
825
+ #### Scenario: Example scenario
826
+ - **WHEN** some condition
827
+ - **THEN** some outcome
828
+ `;
829
+ case 'design':
830
+ return `## Context
831
+
832
+ <!-- Background and context -->
833
+
834
+ ## Goals / Non-Goals
835
+
836
+ **Goals:**
837
+ <!-- List goals -->
838
+
839
+ **Non-Goals:**
840
+ <!-- List non-goals -->
841
+
842
+ ## Decisions
843
+
844
+ ### 1. Decision Name
845
+
846
+ Description and rationale.
847
+
848
+ **Alternatives considered:**
849
+ - Alternative 1: Rejected because...
850
+
851
+ ## Risks / Trade-offs
852
+
853
+ <!-- List risks and trade-offs -->
854
+ `;
855
+ case 'tasks':
856
+ return `## Implementation Tasks
857
+
858
+ - [ ] Task 1
859
+ - [ ] Task 2
860
+ - [ ] Task 3
861
+ `;
862
+ default:
863
+ return `## ${artifactId}
864
+
865
+ <!-- Add content here -->
866
+ `;
867
+ }
868
+ }
869
+ //# sourceMappingURL=schema.js.map