@superkou/openspec 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +213 -0
  3. package/bin/openspec.js +5 -0
  4. package/dist/cli/index.d.ts +5 -0
  5. package/dist/cli/index.js +544 -0
  6. package/dist/commands/change.d.ts +35 -0
  7. package/dist/commands/change.js +277 -0
  8. package/dist/commands/completion.d.ts +72 -0
  9. package/dist/commands/completion.js +264 -0
  10. package/dist/commands/config.d.ts +36 -0
  11. package/dist/commands/config.js +611 -0
  12. package/dist/commands/context-store.d.ts +3 -0
  13. package/dist/commands/context-store.js +475 -0
  14. package/dist/commands/feedback.d.ts +9 -0
  15. package/dist/commands/feedback.js +183 -0
  16. package/dist/commands/initiative.d.ts +13 -0
  17. package/dist/commands/initiative.js +318 -0
  18. package/dist/commands/schema.d.ts +6 -0
  19. package/dist/commands/schema.js +869 -0
  20. package/dist/commands/show.d.ts +14 -0
  21. package/dist/commands/show.js +132 -0
  22. package/dist/commands/spec.d.ts +15 -0
  23. package/dist/commands/spec.js +225 -0
  24. package/dist/commands/validate.d.ts +24 -0
  25. package/dist/commands/validate.js +294 -0
  26. package/dist/commands/workflow/index.d.ts +19 -0
  27. package/dist/commands/workflow/index.js +13 -0
  28. package/dist/commands/workflow/initiative-link.d.ts +24 -0
  29. package/dist/commands/workflow/initiative-link.js +47 -0
  30. package/dist/commands/workflow/instructions.d.ts +29 -0
  31. package/dist/commands/workflow/instructions.js +344 -0
  32. package/dist/commands/workflow/new-change.d.ts +17 -0
  33. package/dist/commands/workflow/new-change.js +141 -0
  34. package/dist/commands/workflow/schemas.d.ts +10 -0
  35. package/dist/commands/workflow/schemas.js +34 -0
  36. package/dist/commands/workflow/set-change.d.ts +13 -0
  37. package/dist/commands/workflow/set-change.js +87 -0
  38. package/dist/commands/workflow/shared.d.ts +59 -0
  39. package/dist/commands/workflow/shared.js +116 -0
  40. package/dist/commands/workflow/status.d.ts +14 -0
  41. package/dist/commands/workflow/status.js +90 -0
  42. package/dist/commands/workflow/templates.d.ts +16 -0
  43. package/dist/commands/workflow/templates.js +69 -0
  44. package/dist/commands/workspace/context-status.d.ts +4 -0
  45. package/dist/commands/workspace/context-status.js +59 -0
  46. package/dist/commands/workspace/open-target-selection.d.ts +13 -0
  47. package/dist/commands/workspace/open-target-selection.js +146 -0
  48. package/dist/commands/workspace/open-view.d.ts +62 -0
  49. package/dist/commands/workspace/open-view.js +249 -0
  50. package/dist/commands/workspace/open.d.ts +37 -0
  51. package/dist/commands/workspace/open.js +110 -0
  52. package/dist/commands/workspace/opener-selection.d.ts +11 -0
  53. package/dist/commands/workspace/opener-selection.js +98 -0
  54. package/dist/commands/workspace/operations.d.ts +29 -0
  55. package/dist/commands/workspace/operations.js +543 -0
  56. package/dist/commands/workspace/prompt-theme.d.ts +29 -0
  57. package/dist/commands/workspace/prompt-theme.js +24 -0
  58. package/dist/commands/workspace/registration.d.ts +13 -0
  59. package/dist/commands/workspace/registration.js +84 -0
  60. package/dist/commands/workspace/selection.d.ts +8 -0
  61. package/dist/commands/workspace/selection.js +104 -0
  62. package/dist/commands/workspace/setup-prompts.d.ts +13 -0
  63. package/dist/commands/workspace/setup-prompts.js +121 -0
  64. package/dist/commands/workspace/types.d.ts +103 -0
  65. package/dist/commands/workspace/types.js +36 -0
  66. package/dist/commands/workspace.d.ts +5 -0
  67. package/dist/commands/workspace.js +577 -0
  68. package/dist/core/archive.d.ts +11 -0
  69. package/dist/core/archive.js +318 -0
  70. package/dist/core/artifact-graph/graph.d.ts +56 -0
  71. package/dist/core/artifact-graph/graph.js +141 -0
  72. package/dist/core/artifact-graph/index.d.ts +9 -0
  73. package/dist/core/artifact-graph/index.js +14 -0
  74. package/dist/core/artifact-graph/instruction-loader.d.ts +183 -0
  75. package/dist/core/artifact-graph/instruction-loader.js +256 -0
  76. package/dist/core/artifact-graph/outputs.d.ts +14 -0
  77. package/dist/core/artifact-graph/outputs.js +39 -0
  78. package/dist/core/artifact-graph/resolver.d.ts +81 -0
  79. package/dist/core/artifact-graph/resolver.js +257 -0
  80. package/dist/core/artifact-graph/schema.d.ts +13 -0
  81. package/dist/core/artifact-graph/schema.js +108 -0
  82. package/dist/core/artifact-graph/state.d.ts +12 -0
  83. package/dist/core/artifact-graph/state.js +31 -0
  84. package/dist/core/artifact-graph/types.d.ts +40 -0
  85. package/dist/core/artifact-graph/types.js +29 -0
  86. package/dist/core/available-tools.d.ts +17 -0
  87. package/dist/core/available-tools.js +43 -0
  88. package/dist/core/change-metadata/index.d.ts +2 -0
  89. package/dist/core/change-metadata/index.js +2 -0
  90. package/dist/core/change-metadata/schema.d.ts +18 -0
  91. package/dist/core/change-metadata/schema.js +28 -0
  92. package/dist/core/change-status-policy.d.ts +50 -0
  93. package/dist/core/change-status-policy.js +70 -0
  94. package/dist/core/collections/index.d.ts +3 -0
  95. package/dist/core/collections/index.js +3 -0
  96. package/dist/core/collections/initiatives/collection.d.ts +4 -0
  97. package/dist/core/collections/initiatives/collection.js +17 -0
  98. package/dist/core/collections/initiatives/index.d.ts +6 -0
  99. package/dist/core/collections/initiatives/index.js +6 -0
  100. package/dist/core/collections/initiatives/operations.d.ts +49 -0
  101. package/dist/core/collections/initiatives/operations.js +175 -0
  102. package/dist/core/collections/initiatives/resolution.d.ts +87 -0
  103. package/dist/core/collections/initiatives/resolution.js +374 -0
  104. package/dist/core/collections/initiatives/schema.d.ts +41 -0
  105. package/dist/core/collections/initiatives/schema.js +134 -0
  106. package/dist/core/collections/initiatives/templates.d.ts +12 -0
  107. package/dist/core/collections/initiatives/templates.js +90 -0
  108. package/dist/core/collections/runtime.d.ts +46 -0
  109. package/dist/core/collections/runtime.js +194 -0
  110. package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
  111. package/dist/core/command-generation/adapters/amazon-q.js +26 -0
  112. package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
  113. package/dist/core/command-generation/adapters/antigravity.js +26 -0
  114. package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
  115. package/dist/core/command-generation/adapters/auggie.js +27 -0
  116. package/dist/core/command-generation/adapters/bob.d.ts +14 -0
  117. package/dist/core/command-generation/adapters/bob.js +45 -0
  118. package/dist/core/command-generation/adapters/claude.d.ts +13 -0
  119. package/dist/core/command-generation/adapters/claude.js +50 -0
  120. package/dist/core/command-generation/adapters/cline.d.ts +14 -0
  121. package/dist/core/command-generation/adapters/cline.js +27 -0
  122. package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
  123. package/dist/core/command-generation/adapters/codebuddy.js +28 -0
  124. package/dist/core/command-generation/adapters/codex.d.ts +16 -0
  125. package/dist/core/command-generation/adapters/codex.js +39 -0
  126. package/dist/core/command-generation/adapters/continue.d.ts +13 -0
  127. package/dist/core/command-generation/adapters/continue.js +28 -0
  128. package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
  129. package/dist/core/command-generation/adapters/costrict.js +27 -0
  130. package/dist/core/command-generation/adapters/crush.d.ts +13 -0
  131. package/dist/core/command-generation/adapters/crush.js +30 -0
  132. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  133. package/dist/core/command-generation/adapters/cursor.js +44 -0
  134. package/dist/core/command-generation/adapters/factory.d.ts +13 -0
  135. package/dist/core/command-generation/adapters/factory.js +27 -0
  136. package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
  137. package/dist/core/command-generation/adapters/gemini.js +26 -0
  138. package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
  139. package/dist/core/command-generation/adapters/github-copilot.js +26 -0
  140. package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
  141. package/dist/core/command-generation/adapters/iflow.js +29 -0
  142. package/dist/core/command-generation/adapters/index.d.ts +32 -0
  143. package/dist/core/command-generation/adapters/index.js +32 -0
  144. package/dist/core/command-generation/adapters/junie.d.ts +13 -0
  145. package/dist/core/command-generation/adapters/junie.js +26 -0
  146. package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
  147. package/dist/core/command-generation/adapters/kilocode.js +23 -0
  148. package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
  149. package/dist/core/command-generation/adapters/kiro.js +26 -0
  150. package/dist/core/command-generation/adapters/lingma.d.ts +13 -0
  151. package/dist/core/command-generation/adapters/lingma.js +30 -0
  152. package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
  153. package/dist/core/command-generation/adapters/opencode.js +29 -0
  154. package/dist/core/command-generation/adapters/pi.d.ts +18 -0
  155. package/dist/core/command-generation/adapters/pi.js +55 -0
  156. package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
  157. package/dist/core/command-generation/adapters/qoder.js +30 -0
  158. package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
  159. package/dist/core/command-generation/adapters/qwen.js +26 -0
  160. package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
  161. package/dist/core/command-generation/adapters/roocode.js +27 -0
  162. package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
  163. package/dist/core/command-generation/adapters/windsurf.js +51 -0
  164. package/dist/core/command-generation/generator.d.ts +21 -0
  165. package/dist/core/command-generation/generator.js +27 -0
  166. package/dist/core/command-generation/index.d.ts +22 -0
  167. package/dist/core/command-generation/index.js +24 -0
  168. package/dist/core/command-generation/registry.d.ts +36 -0
  169. package/dist/core/command-generation/registry.js +98 -0
  170. package/dist/core/command-generation/types.d.ts +56 -0
  171. package/dist/core/command-generation/types.js +8 -0
  172. package/dist/core/completions/command-registry.d.ts +3 -0
  173. package/dist/core/completions/command-registry.js +961 -0
  174. package/dist/core/completions/completion-provider.d.ts +71 -0
  175. package/dist/core/completions/completion-provider.js +129 -0
  176. package/dist/core/completions/factory.d.ts +64 -0
  177. package/dist/core/completions/factory.js +75 -0
  178. package/dist/core/completions/generators/bash-generator.d.ts +35 -0
  179. package/dist/core/completions/generators/bash-generator.js +230 -0
  180. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  181. package/dist/core/completions/generators/fish-generator.js +160 -0
  182. package/dist/core/completions/generators/powershell-generator.d.ts +36 -0
  183. package/dist/core/completions/generators/powershell-generator.js +266 -0
  184. package/dist/core/completions/generators/zsh-generator.d.ts +47 -0
  185. package/dist/core/completions/generators/zsh-generator.js +274 -0
  186. package/dist/core/completions/installers/bash-installer.d.ts +87 -0
  187. package/dist/core/completions/installers/bash-installer.js +318 -0
  188. package/dist/core/completions/installers/fish-installer.d.ts +43 -0
  189. package/dist/core/completions/installers/fish-installer.js +143 -0
  190. package/dist/core/completions/installers/powershell-installer.d.ts +102 -0
  191. package/dist/core/completions/installers/powershell-installer.js +387 -0
  192. package/dist/core/completions/installers/zsh-installer.d.ts +117 -0
  193. package/dist/core/completions/installers/zsh-installer.js +421 -0
  194. package/dist/core/completions/shared-flags.d.ts +12 -0
  195. package/dist/core/completions/shared-flags.js +28 -0
  196. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  197. package/dist/core/completions/templates/bash-templates.js +30 -0
  198. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  199. package/dist/core/completions/templates/fish-templates.js +45 -0
  200. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  201. package/dist/core/completions/templates/powershell-templates.js +34 -0
  202. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  203. package/dist/core/completions/templates/zsh-templates.js +45 -0
  204. package/dist/core/completions/types.d.ts +101 -0
  205. package/dist/core/completions/types.js +2 -0
  206. package/dist/core/config-prompts.d.ts +9 -0
  207. package/dist/core/config-prompts.js +34 -0
  208. package/dist/core/config-schema.d.ts +86 -0
  209. package/dist/core/config-schema.js +213 -0
  210. package/dist/core/config.d.ts +18 -0
  211. package/dist/core/config.js +39 -0
  212. package/dist/core/context-store/binding.d.ts +53 -0
  213. package/dist/core/context-store/binding.js +197 -0
  214. package/dist/core/context-store/errors.d.ts +20 -0
  215. package/dist/core/context-store/errors.js +22 -0
  216. package/dist/core/context-store/foundation.d.ts +55 -0
  217. package/dist/core/context-store/foundation.js +321 -0
  218. package/dist/core/context-store/index.d.ts +6 -0
  219. package/dist/core/context-store/index.js +6 -0
  220. package/dist/core/context-store/operations.d.ts +85 -0
  221. package/dist/core/context-store/operations.js +528 -0
  222. package/dist/core/context-store/registry.d.ts +45 -0
  223. package/dist/core/context-store/registry.js +229 -0
  224. package/dist/core/converters/json-converter.d.ts +6 -0
  225. package/dist/core/converters/json-converter.js +51 -0
  226. package/dist/core/global-config.d.ts +49 -0
  227. package/dist/core/global-config.js +124 -0
  228. package/dist/core/index.d.ts +6 -0
  229. package/dist/core/index.js +7 -0
  230. package/dist/core/init.d.ts +37 -0
  231. package/dist/core/init.js +593 -0
  232. package/dist/core/legacy-cleanup.d.ts +162 -0
  233. package/dist/core/legacy-cleanup.js +514 -0
  234. package/dist/core/list.d.ts +9 -0
  235. package/dist/core/list.js +171 -0
  236. package/dist/core/migration.d.ts +23 -0
  237. package/dist/core/migration.js +108 -0
  238. package/dist/core/parsers/change-parser.d.ts +13 -0
  239. package/dist/core/parsers/change-parser.js +197 -0
  240. package/dist/core/parsers/markdown-parser.d.ts +26 -0
  241. package/dist/core/parsers/markdown-parser.js +227 -0
  242. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  243. package/dist/core/parsers/requirement-blocks.js +201 -0
  244. package/dist/core/parsers/spec-structure.d.ts +9 -0
  245. package/dist/core/parsers/spec-structure.js +88 -0
  246. package/dist/core/planning-home.d.ts +21 -0
  247. package/dist/core/planning-home.js +108 -0
  248. package/dist/core/profile-sync-drift.d.ts +38 -0
  249. package/dist/core/profile-sync-drift.js +200 -0
  250. package/dist/core/profiles.d.ts +26 -0
  251. package/dist/core/profiles.js +40 -0
  252. package/dist/core/project-config.d.ts +64 -0
  253. package/dist/core/project-config.js +223 -0
  254. package/dist/core/schemas/base.schema.d.ts +13 -0
  255. package/dist/core/schemas/base.schema.js +13 -0
  256. package/dist/core/schemas/change.schema.d.ts +73 -0
  257. package/dist/core/schemas/change.schema.js +31 -0
  258. package/dist/core/schemas/index.d.ts +4 -0
  259. package/dist/core/schemas/index.js +4 -0
  260. package/dist/core/schemas/spec.schema.d.ts +18 -0
  261. package/dist/core/schemas/spec.schema.js +15 -0
  262. package/dist/core/shared/index.d.ts +8 -0
  263. package/dist/core/shared/index.js +8 -0
  264. package/dist/core/shared/skill-generation.d.ts +49 -0
  265. package/dist/core/shared/skill-generation.js +96 -0
  266. package/dist/core/shared/tool-detection.d.ts +71 -0
  267. package/dist/core/shared/tool-detection.js +158 -0
  268. package/dist/core/specs-apply.d.ts +73 -0
  269. package/dist/core/specs-apply.js +392 -0
  270. package/dist/core/styles/palette.d.ts +7 -0
  271. package/dist/core/styles/palette.js +8 -0
  272. package/dist/core/templates/index.d.ts +8 -0
  273. package/dist/core/templates/index.js +9 -0
  274. package/dist/core/templates/skill-templates.d.ts +19 -0
  275. package/dist/core/templates/skill-templates.js +18 -0
  276. package/dist/core/templates/types.d.ts +19 -0
  277. package/dist/core/templates/types.js +5 -0
  278. package/dist/core/templates/workflows/apply-change.d.ts +10 -0
  279. package/dist/core/templates/workflows/apply-change.js +314 -0
  280. package/dist/core/templates/workflows/archive-change.d.ts +10 -0
  281. package/dist/core/templates/workflows/archive-change.js +277 -0
  282. package/dist/core/templates/workflows/bulk-archive-change.d.ts +10 -0
  283. package/dist/core/templates/workflows/bulk-archive-change.js +492 -0
  284. package/dist/core/templates/workflows/continue-change.d.ts +10 -0
  285. package/dist/core/templates/workflows/continue-change.js +234 -0
  286. package/dist/core/templates/workflows/explore.d.ts +10 -0
  287. package/dist/core/templates/workflows/explore.js +459 -0
  288. package/dist/core/templates/workflows/feedback.d.ts +9 -0
  289. package/dist/core/templates/workflows/feedback.js +108 -0
  290. package/dist/core/templates/workflows/ff-change.d.ts +10 -0
  291. package/dist/core/templates/workflows/ff-change.js +200 -0
  292. package/dist/core/templates/workflows/new-change.d.ts +10 -0
  293. package/dist/core/templates/workflows/new-change.js +143 -0
  294. package/dist/core/templates/workflows/onboard.d.ts +10 -0
  295. package/dist/core/templates/workflows/onboard.js +563 -0
  296. package/dist/core/templates/workflows/propose.d.ts +10 -0
  297. package/dist/core/templates/workflows/propose.js +218 -0
  298. package/dist/core/templates/workflows/sync-specs.d.ts +10 -0
  299. package/dist/core/templates/workflows/sync-specs.js +290 -0
  300. package/dist/core/templates/workflows/verify-change.d.ts +10 -0
  301. package/dist/core/templates/workflows/verify-change.js +338 -0
  302. package/dist/core/update.d.ts +82 -0
  303. package/dist/core/update.js +557 -0
  304. package/dist/core/validation/constants.d.ts +34 -0
  305. package/dist/core/validation/constants.js +40 -0
  306. package/dist/core/validation/types.d.ts +18 -0
  307. package/dist/core/validation/types.js +2 -0
  308. package/dist/core/validation/validator.d.ts +43 -0
  309. package/dist/core/validation/validator.js +435 -0
  310. package/dist/core/view.d.ts +8 -0
  311. package/dist/core/view.js +168 -0
  312. package/dist/core/workspace/foundation.d.ts +67 -0
  313. package/dist/core/workspace/foundation.js +295 -0
  314. package/dist/core/workspace/index.d.ts +8 -0
  315. package/dist/core/workspace/index.js +8 -0
  316. package/dist/core/workspace/legacy-state.d.ts +28 -0
  317. package/dist/core/workspace/legacy-state.js +200 -0
  318. package/dist/core/workspace/link-input.d.ts +9 -0
  319. package/dist/core/workspace/link-input.js +32 -0
  320. package/dist/core/workspace/open-surface.d.ts +45 -0
  321. package/dist/core/workspace/open-surface.js +215 -0
  322. package/dist/core/workspace/openers.d.ts +21 -0
  323. package/dist/core/workspace/openers.js +124 -0
  324. package/dist/core/workspace/registry.d.ts +24 -0
  325. package/dist/core/workspace/registry.js +146 -0
  326. package/dist/core/workspace/skills.d.ts +57 -0
  327. package/dist/core/workspace/skills.js +334 -0
  328. package/dist/core/workspace/state-io.d.ts +10 -0
  329. package/dist/core/workspace/state-io.js +121 -0
  330. package/dist/index.d.ts +3 -0
  331. package/dist/index.js +3 -0
  332. package/dist/prompts/searchable-multi-select.d.ts +28 -0
  333. package/dist/prompts/searchable-multi-select.js +159 -0
  334. package/dist/telemetry/config.d.ts +38 -0
  335. package/dist/telemetry/config.js +136 -0
  336. package/dist/telemetry/index.d.ts +31 -0
  337. package/dist/telemetry/index.js +164 -0
  338. package/dist/ui/ascii-patterns.d.ts +16 -0
  339. package/dist/ui/ascii-patterns.js +133 -0
  340. package/dist/ui/welcome-screen.d.ts +10 -0
  341. package/dist/ui/welcome-screen.js +146 -0
  342. package/dist/utils/change-metadata.d.ts +54 -0
  343. package/dist/utils/change-metadata.js +141 -0
  344. package/dist/utils/change-utils.d.ts +71 -0
  345. package/dist/utils/change-utils.js +123 -0
  346. package/dist/utils/command-references.d.ts +18 -0
  347. package/dist/utils/command-references.js +20 -0
  348. package/dist/utils/file-system.d.ts +41 -0
  349. package/dist/utils/file-system.js +301 -0
  350. package/dist/utils/index.d.ts +6 -0
  351. package/dist/utils/index.js +9 -0
  352. package/dist/utils/interactive.d.ts +18 -0
  353. package/dist/utils/interactive.js +21 -0
  354. package/dist/utils/item-discovery.d.ts +4 -0
  355. package/dist/utils/item-discovery.js +72 -0
  356. package/dist/utils/match.d.ts +3 -0
  357. package/dist/utils/match.js +22 -0
  358. package/dist/utils/shell-detection.d.ts +20 -0
  359. package/dist/utils/shell-detection.js +41 -0
  360. package/dist/utils/task-progress.d.ts +8 -0
  361. package/dist/utils/task-progress.js +36 -0
  362. package/package.json +85 -0
  363. package/schemas/spec-driven/schema.yaml +151 -0
  364. package/schemas/spec-driven/templates/design.md +19 -0
  365. package/schemas/spec-driven/templates/proposal.md +23 -0
  366. package/schemas/spec-driven/templates/spec.md +8 -0
  367. package/schemas/spec-driven/templates/tasks.md +9 -0
  368. package/schemas/workspace-planning/schema.yaml +72 -0
  369. package/schemas/workspace-planning/templates/design.md +33 -0
  370. package/schemas/workspace-planning/templates/proposal.md +28 -0
  371. package/schemas/workspace-planning/templates/spec.md +9 -0
  372. package/schemas/workspace-planning/templates/tasks.md +15 -0
  373. 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
+ /**
8
+ * Check all three locations for a schema and return which ones exist.
9
+ */
10
+ function checkAllLocations(name, projectRoot) {
11
+ const locations = [];
12
+ // Project location
13
+ const projectDir = path.join(getProjectSchemasDir(projectRoot), name);
14
+ const projectSchemaPath = path.join(projectDir, 'schema.yaml');
15
+ locations.push({
16
+ source: 'project',
17
+ path: projectDir,
18
+ exists: fs.existsSync(projectSchemaPath),
19
+ });
20
+ // User location
21
+ const userDir = path.join(getUserSchemasDir(), name);
22
+ const userSchemaPath = path.join(userDir, 'schema.yaml');
23
+ locations.push({
24
+ source: 'user',
25
+ path: userDir,
26
+ exists: fs.existsSync(userSchemaPath),
27
+ });
28
+ // Package location
29
+ const packageDir = path.join(getPackageSchemasDir(), name);
30
+ const packageSchemaPath = path.join(packageDir, 'schema.yaml');
31
+ locations.push({
32
+ source: 'package',
33
+ path: packageDir,
34
+ exists: fs.existsSync(packageSchemaPath),
35
+ });
36
+ return locations;
37
+ }
38
+ /**
39
+ * Get resolution info for a schema including shadow detection.
40
+ */
41
+ function getSchemaResolution(name, projectRoot) {
42
+ const locations = checkAllLocations(name, projectRoot);
43
+ const existingLocations = locations.filter((loc) => loc.exists);
44
+ if (existingLocations.length === 0) {
45
+ return null;
46
+ }
47
+ const active = existingLocations[0];
48
+ const shadows = existingLocations.slice(1).map((loc) => ({
49
+ source: loc.source,
50
+ path: loc.path,
51
+ }));
52
+ return {
53
+ name,
54
+ source: active.source,
55
+ path: active.path,
56
+ shadows,
57
+ };
58
+ }
59
+ /**
60
+ * Get all schemas with resolution info.
61
+ */
62
+ function getAllSchemasWithResolution(projectRoot) {
63
+ const schemaNames = listSchemas(projectRoot);
64
+ const results = [];
65
+ for (const name of schemaNames) {
66
+ const resolution = getSchemaResolution(name, projectRoot);
67
+ if (resolution) {
68
+ results.push(resolution);
69
+ }
70
+ }
71
+ return results;
72
+ }
73
+ /**
74
+ * Validate a schema and return issues.
75
+ */
76
+ function validateSchema(schemaDir, verbose = false) {
77
+ const issues = [];
78
+ const schemaPath = path.join(schemaDir, 'schema.yaml');
79
+ // Check schema.yaml exists
80
+ if (verbose) {
81
+ console.log(' 检查 schema.yaml 是否存在...');
82
+ }
83
+ if (!fs.existsSync(schemaPath)) {
84
+ issues.push({
85
+ level: 'error',
86
+ path: 'schema.yaml',
87
+ message: '未找到 schema.yaml',
88
+ });
89
+ return { valid: false, issues };
90
+ }
91
+ // Parse YAML
92
+ if (verbose) {
93
+ console.log(' 正在解析 YAML...');
94
+ }
95
+ let content;
96
+ try {
97
+ content = fs.readFileSync(schemaPath, 'utf-8');
98
+ }
99
+ catch (err) {
100
+ issues.push({
101
+ level: 'error',
102
+ path: 'schema.yaml',
103
+ message: `读取文件失败:${err.message}`,
104
+ });
105
+ return { valid: false, issues };
106
+ }
107
+ // Validate against Zod schema
108
+ if (verbose) {
109
+ console.log(' 正在验证架构结构...');
110
+ }
111
+ let schema;
112
+ try {
113
+ schema = parseSchema(content);
114
+ }
115
+ catch (err) {
116
+ if (err instanceof SchemaValidationError) {
117
+ issues.push({
118
+ level: 'error',
119
+ path: 'schema.yaml',
120
+ message: err.message,
121
+ });
122
+ }
123
+ else {
124
+ issues.push({
125
+ level: 'error',
126
+ path: 'schema.yaml',
127
+ message: `解析错误:${err.message}`,
128
+ });
129
+ }
130
+ return { valid: false, issues };
131
+ }
132
+ // Check template files exist
133
+ // Templates can be in schemaDir directly or in a templates/ subdirectory
134
+ if (verbose) {
135
+ console.log(' 正在检查模板文件...');
136
+ }
137
+ for (const artifact of schema.artifacts) {
138
+ // Try templates subdirectory first (standard location), then root
139
+ const templatePathInTemplates = path.join(schemaDir, 'templates', artifact.template);
140
+ const templatePathInRoot = path.join(schemaDir, artifact.template);
141
+ if (!fs.existsSync(templatePathInTemplates) && !fs.existsSync(templatePathInRoot)) {
142
+ issues.push({
143
+ level: 'error',
144
+ path: `artifacts.${artifact.id}.template`,
145
+ message: `制品 '${artifact.id}' 的模板文件 '${artifact.template}' 未找到`,
146
+ });
147
+ }
148
+ }
149
+ // Dependency graph validation is already done by parseSchema
150
+ // (it throws on cycles and invalid references)
151
+ if (verbose) {
152
+ console.log(' 依赖图验证已通过(通过 parseSchema)');
153
+ }
154
+ return { valid: issues.length === 0, issues };
155
+ }
156
+ /**
157
+ * Validate schema name format (kebab-case).
158
+ */
159
+ function isValidSchemaName(name) {
160
+ return /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(name);
161
+ }
162
+ /**
163
+ * Copy a directory recursively.
164
+ */
165
+ function copyDirRecursive(src, dest) {
166
+ fs.mkdirSync(dest, { recursive: true });
167
+ const entries = fs.readdirSync(src, { withFileTypes: true });
168
+ for (const entry of entries) {
169
+ const srcPath = path.join(src, entry.name);
170
+ const destPath = path.join(dest, entry.name);
171
+ if (entry.isDirectory()) {
172
+ copyDirRecursive(srcPath, destPath);
173
+ }
174
+ else {
175
+ fs.copyFileSync(srcPath, destPath);
176
+ }
177
+ }
178
+ }
179
+ /**
180
+ * Default artifacts with descriptions for schema init.
181
+ */
182
+ const DEFAULT_ARTIFACTS = [
183
+ {
184
+ id: 'proposal',
185
+ description: '变更的高层描述、动机和范围',
186
+ generates: 'proposal.md',
187
+ template: 'proposal.md',
188
+ },
189
+ {
190
+ id: 'specs',
191
+ description: '包含需求和场景的详细规格说明',
192
+ generates: 'specs/**/*.md',
193
+ template: 'specs/spec.md',
194
+ },
195
+ {
196
+ id: 'design',
197
+ description: '技术设计决策和实现方案',
198
+ generates: 'design.md',
199
+ template: 'design.md',
200
+ },
201
+ {
202
+ id: 'tasks',
203
+ description: '包含可追踪任务的任务清单',
204
+ generates: 'tasks.md',
205
+ template: 'tasks.md',
206
+ },
207
+ ];
208
+ /**
209
+ * Register the schema command and all its subcommands.
210
+ */
211
+ export function registerSchemaCommand(program) {
212
+ const schemaCmd = program
213
+ .command('schema')
214
+ .description('管理工作流架构 [实验性]');
215
+ // Experimental warning
216
+ schemaCmd.hook('preAction', () => {
217
+ console.error('注意:架构命令为实验性功能,可能发生变化。');
218
+ });
219
+ // schema which
220
+ schemaCmd
221
+ .command('which [name]')
222
+ .description('查看架构的来源解析位置')
223
+ .option('--json', '以 JSON 格式输出')
224
+ .option('--all', '列出所有架构及其解析来源')
225
+ .action(async (name, options) => {
226
+ try {
227
+ const projectRoot = process.cwd();
228
+ if (options?.all) {
229
+ // List all schemas
230
+ const schemas = getAllSchemasWithResolution(projectRoot);
231
+ if (options?.json) {
232
+ console.log(JSON.stringify(schemas, null, 2));
233
+ }
234
+ else {
235
+ if (schemas.length === 0) {
236
+ console.log('未找到架构。');
237
+ return;
238
+ }
239
+ // Group by source
240
+ const bySource = {
241
+ project: schemas.filter((s) => s.source === 'project'),
242
+ user: schemas.filter((s) => s.source === 'user'),
243
+ package: schemas.filter((s) => s.source === 'package'),
244
+ };
245
+ if (bySource.project.length > 0) {
246
+ console.log('\n项目架构:');
247
+ for (const schema of bySource.project) {
248
+ const shadowInfo = schema.shadows.length > 0
249
+ ? ` (遮蔽:${schema.shadows.map((s) => s.source).join(', ')})`
250
+ : '';
251
+ console.log(` ${schema.name}${shadowInfo}`);
252
+ }
253
+ }
254
+ if (bySource.user.length > 0) {
255
+ console.log('\n用户架构:');
256
+ for (const schema of bySource.user) {
257
+ const shadowInfo = schema.shadows.length > 0
258
+ ? ` (遮蔽:${schema.shadows.map((s) => s.source).join(', ')})`
259
+ : '';
260
+ console.log(` ${schema.name}${shadowInfo}`);
261
+ }
262
+ }
263
+ if (bySource.package.length > 0) {
264
+ console.log('\n包架构:');
265
+ for (const schema of bySource.package) {
266
+ console.log(` ${schema.name}`);
267
+ }
268
+ }
269
+ }
270
+ return;
271
+ }
272
+ if (!name) {
273
+ console.error('错误:需要指定架构名称(或使用 --all 列出所有架构)');
274
+ process.exitCode = 1;
275
+ return;
276
+ }
277
+ const resolution = getSchemaResolution(name, projectRoot);
278
+ if (!resolution) {
279
+ const available = listSchemas(projectRoot);
280
+ if (options?.json) {
281
+ console.log(JSON.stringify({
282
+ error: `架构 '${name}' 未找到`,
283
+ available,
284
+ }, null, 2));
285
+ }
286
+ else {
287
+ console.error(`错误:架构 '${name}' 未找到`);
288
+ console.error(`可用架构:${available.join(', ')}`);
289
+ }
290
+ process.exitCode = 1;
291
+ return;
292
+ }
293
+ if (options?.json) {
294
+ console.log(JSON.stringify(resolution, null, 2));
295
+ }
296
+ else {
297
+ console.log(`架构:${resolution.name}`);
298
+ console.log(`来源:${resolution.source}`);
299
+ console.log(`路径:${resolution.path}`);
300
+ if (resolution.shadows.length > 0) {
301
+ console.log('\n遮蔽来源:');
302
+ for (const shadow of resolution.shadows) {
303
+ console.log(` ${shadow.source}: ${shadow.path}`);
304
+ }
305
+ }
306
+ }
307
+ }
308
+ catch (error) {
309
+ console.error(`错误:${error.message}`);
310
+ process.exitCode = 1;
311
+ }
312
+ });
313
+ // schema validate
314
+ schemaCmd
315
+ .command('validate [name]')
316
+ .description('验证架构结构和模板')
317
+ .option('--json', '以 JSON 格式输出')
318
+ .option('--verbose', '显示详细的验证步骤')
319
+ .action(async (name, options) => {
320
+ try {
321
+ const projectRoot = process.cwd();
322
+ if (!name) {
323
+ // Validate all project schemas
324
+ const projectSchemasDir = getProjectSchemasDir(projectRoot);
325
+ if (!fs.existsSync(projectSchemasDir)) {
326
+ if (options?.json) {
327
+ console.log(JSON.stringify({
328
+ valid: true,
329
+ message: 'No project schemas directory found',
330
+ schemas: [],
331
+ }, null, 2));
332
+ }
333
+ else {
334
+ console.log('未找到项目架构目录。');
335
+ }
336
+ return;
337
+ }
338
+ const entries = fs.readdirSync(projectSchemasDir, { withFileTypes: true });
339
+ const schemaResults = [];
340
+ let anyInvalid = false;
341
+ for (const entry of entries) {
342
+ if (!entry.isDirectory())
343
+ continue;
344
+ const schemaDir = path.join(projectSchemasDir, entry.name);
345
+ const schemaPath = path.join(schemaDir, 'schema.yaml');
346
+ if (!fs.existsSync(schemaPath))
347
+ continue;
348
+ if (options?.verbose && !options?.json) {
349
+ console.log(`\n正在验证 ${entry.name}...`);
350
+ }
351
+ const result = validateSchema(schemaDir, options?.verbose && !options?.json);
352
+ schemaResults.push({
353
+ name: entry.name,
354
+ path: schemaDir,
355
+ valid: result.valid,
356
+ issues: result.issues,
357
+ });
358
+ if (!result.valid) {
359
+ anyInvalid = true;
360
+ }
361
+ }
362
+ if (options?.json) {
363
+ console.log(JSON.stringify({
364
+ valid: !anyInvalid,
365
+ schemas: schemaResults,
366
+ }, null, 2));
367
+ }
368
+ else {
369
+ if (schemaResults.length === 0) {
370
+ console.log('项目中未找到架构。');
371
+ return;
372
+ }
373
+ console.log('\n验证结果:');
374
+ for (const result of schemaResults) {
375
+ const status = result.valid ? '✓' : '✗';
376
+ console.log(` ${status} ${result.name}`);
377
+ for (const issue of result.issues) {
378
+ console.log(` ${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: `架构 '${name}' 未找到`,
395
+ available,
396
+ }, null, 2));
397
+ }
398
+ else {
399
+ console.error(`错误:架构 '${name}' 未找到`);
400
+ console.error(`可用架构:${available.join(', ')}`);
401
+ }
402
+ process.exitCode = 1;
403
+ return;
404
+ }
405
+ if (options?.verbose && !options?.json) {
406
+ console.log(`正在验证 ${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(`✓ 架构 '${name}' 有效`);
420
+ }
421
+ else {
422
+ console.log(`✗ 架构 '${name}' 存在错误:`);
423
+ for (const issue of result.issues) {
424
+ console.log(` ${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(`错误:${error.message}`);
439
+ }
440
+ process.exitCode = 1;
441
+ }
442
+ });
443
+ // schema fork
444
+ schemaCmd
445
+ .command('fork <source> [name]')
446
+ .description('复制现有架构到项目进行自定义')
447
+ .option('--json', '以 JSON 格式输出')
448
+ .option('--force', '覆盖已存在的目标')
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: `无效的架构名称 '${destinationName}'。请使用 kebab-case(如 my-workflow)`,
460
+ }, null, 2));
461
+ }
462
+ else {
463
+ console.error(`错误:无效的架构名称 '${destinationName}'`);
464
+ console.error('架构名称必须使用 kebab-case 格式(如 my-workflow)');
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: `架构 '${source}' 未找到`,
477
+ available,
478
+ }, null, 2));
479
+ }
480
+ else {
481
+ console.error(`错误:架构 '${source}' 未找到`);
482
+ console.error(`可用架构:${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: `架构 '${destinationName}' 已存在`,
498
+ suggestion: '使用 --force 覆盖',
499
+ }, null, 2));
500
+ }
501
+ else {
502
+ console.error(`错误:架构 '${destinationName}' 已存在于 ${destinationDir}`);
503
+ console.error('使用 --force 覆盖');
504
+ }
505
+ process.exitCode = 1;
506
+ return;
507
+ }
508
+ // Remove existing
509
+ if (spinner)
510
+ spinner.start(`正在移除现有架构 '${destinationName}'...`);
511
+ fs.rmSync(destinationDir, { recursive: true });
512
+ }
513
+ // Copy schema
514
+ if (spinner)
515
+ spinner.start(`正在派生 '${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(`已派生 '${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来源:${sourceDir}(${sourceLocation})`);
537
+ console.log(`目标:${destinationDir}`);
538
+ console.log(`\n你现在可以自定义架构:`);
539
+ console.log(` ${destinationDir}/schema.yaml`);
540
+ }
541
+ }
542
+ catch (error) {
543
+ if (spinner)
544
+ spinner.fail(`派生失败`);
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(`错误:${error.message}`);
553
+ }
554
+ process.exitCode = 1;
555
+ }
556
+ });
557
+ // schema init
558
+ schemaCmd
559
+ .command('init <name>')
560
+ .description('创建新的项目本地架构')
561
+ .option('--json', '以 JSON 格式输出')
562
+ .option('--description <text>', '架构描述')
563
+ .option('--artifacts <list>', '逗号分隔的制品 ID 列表(proposal,specs,design,tasks)')
564
+ .option('--default', '设置为项目默认架构')
565
+ .option('--no-default', '不提示设置为默认')
566
+ .option('--force', '覆盖已有架构')
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: `无效的架构名称 '${name}'。请使用 kebab-case(如 my-workflow)`,
577
+ }, null, 2));
578
+ }
579
+ else {
580
+ console.error(`错误:无效的架构名称 '${name}'`);
581
+ console.error('架构名称必须使用 kebab-case 格式(如 my-workflow)');
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: `架构 '${name}' 已存在`,
594
+ suggestion: '使用 --force 覆盖或使用 "openspec schema fork" 复制',
595
+ }, null, 2));
596
+ }
597
+ else {
598
+ console.error(`错误:架构 '${name}' 已存在于 ${schemaDir}`);
599
+ console.error('使用 --force 覆盖或使用 "openspec schema fork" 复制');
600
+ }
601
+ process.exitCode = 1;
602
+ return;
603
+ }
604
+ if (spinner)
605
+ spinner.start(`正在移除现有架构 '${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: '架构描述:',
619
+ default: `用于 ${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: '选择要包含的制品:',
628
+ choices: artifactChoices,
629
+ });
630
+ if (selectedArtifactIds.length === 0) {
631
+ console.error('错误:至少需要选择一个制品');
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: '设置为项目默认架构?',
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 || `用于 ${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: `未知的制品 '${id}'`,
659
+ valid: validIds,
660
+ }, null, 2));
661
+ }
662
+ else {
663
+ console.error(`错误:未知的制品 '${id}'`);
664
+ console.error(`有效制品:${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(`正在创建架构 '${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(`已创建架构 '${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架构已创建于:${schemaDir}`);
766
+ console.log(`\n制品:${selectedArtifactIds.join(', ')}`);
767
+ if (options?.default) {
768
+ console.log(`\n已设置为项目默认架构。`);
769
+ }
770
+ console.log(`\n下一步操作:`);
771
+ console.log(` 1. 编辑 ${schemaDir}/schema.yaml 自定义制品`);
772
+ console.log(` 2. 修改架构目录中的模板`);
773
+ console.log(` 3. 使用命令:openspec new --schema ${name}`);
774
+ }
775
+ }
776
+ catch (error) {
777
+ if (spinner)
778
+ spinner.fail(`创建失败`);
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(`错误:${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
+ <!-- 描述此变更的动机 -->
801
+
802
+ ## What Changes
803
+
804
+ <!-- 描述将要变更的内容 -->
805
+
806
+ ## Capabilities
807
+
808
+ ### New Capabilities
809
+ <!-- 列出新能力 -->
810
+
811
+ ### Modified Capabilities
812
+ <!-- 列出已修改的能力 -->
813
+
814
+ ## Impact
815
+
816
+ <!-- 描述对现有功能的影响 -->
817
+ `;
818
+ case 'specs':
819
+ return `## ADDED Requirements
820
+
821
+ ### Requirement: Example requirement
822
+
823
+ 描述该需求。
824
+
825
+ #### Scenario: Example scenario
826
+ - **WHEN** 某个条件
827
+ - **THEN** 某个结果
828
+ `;
829
+ case 'design':
830
+ return `## Context
831
+
832
+ <!-- 背景和上下文 -->
833
+
834
+ ## Goals / Non-Goals
835
+
836
+ **目标:**
837
+ <!-- 列出目标 -->
838
+
839
+ **非目标:**
840
+ <!-- 列出非目标 -->
841
+
842
+ ## Decisions
843
+
844
+ ### 1. 决策名称
845
+
846
+ 描述和理由。
847
+
848
+ **考虑过的替代方案:**
849
+ - 方案 1:因...被拒绝
850
+
851
+ ## Risks / Trade-offs
852
+
853
+ <!-- 列出风险与权衡 -->
854
+ `;
855
+ case 'tasks':
856
+ return `## Implementation Tasks
857
+
858
+ - [ ] 任务 1
859
+ - [ ] 任务 2
860
+ - [ ] 任务 3
861
+ `;
862
+ default:
863
+ return `## ${artifactId}
864
+
865
+ <!-- 在此添加内容 -->
866
+ `;
867
+ }
868
+ }
869
+ //# sourceMappingURL=schema.js.map