@devtrack-solution/codesdd 1.2.2

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 (433) hide show
  1. package/.sdd/skills/curated/api-clean-flask-langgraph/SKILL.md +2751 -0
  2. package/.sdd/skills/curated/devtrack-api/SKILL.md +137 -0
  3. package/.sdd/skills/curated/devtrack-api/agents/openai.yaml +4 -0
  4. package/.sdd/skills/curated/devtrack-api/references/application-presentation.md +381 -0
  5. package/.sdd/skills/curated/devtrack-api/references/architecture-governance.md +219 -0
  6. package/.sdd/skills/curated/devtrack-api/references/domain-modeling.md +359 -0
  7. package/.sdd/skills/curated/devtrack-api/references/implementation-checklist.md +127 -0
  8. package/.sdd/skills/curated/devtrack-api/references/imports-lint.md +207 -0
  9. package/.sdd/skills/curated/devtrack-api/references/testing-validation.md +167 -0
  10. package/.sdd/skills/curated/devtrack-api/references/typeorm-infrastructure.md +334 -0
  11. package/LICENSE +21 -0
  12. package/README.md +842 -0
  13. package/bin/codesdd.js +10 -0
  14. package/dist/cli/index.d.ts +3 -0
  15. package/dist/cli/index.js +560 -0
  16. package/dist/commands/change.d.ts +35 -0
  17. package/dist/commands/change.js +296 -0
  18. package/dist/commands/completion.d.ts +72 -0
  19. package/dist/commands/completion.js +258 -0
  20. package/dist/commands/config.d.ts +36 -0
  21. package/dist/commands/config.js +552 -0
  22. package/dist/commands/feedback.d.ts +9 -0
  23. package/dist/commands/feedback.js +184 -0
  24. package/dist/commands/schema.d.ts +6 -0
  25. package/dist/commands/schema.js +870 -0
  26. package/dist/commands/sdd/execution.d.ts +3 -0
  27. package/dist/commands/sdd/execution.js +409 -0
  28. package/dist/commands/sdd/shared.d.ts +9 -0
  29. package/dist/commands/sdd/shared.js +84 -0
  30. package/dist/commands/sdd/skills.d.ts +3 -0
  31. package/dist/commands/sdd/skills.js +154 -0
  32. package/dist/commands/sdd.d.ts +3 -0
  33. package/dist/commands/sdd.js +769 -0
  34. package/dist/commands/show.d.ts +14 -0
  35. package/dist/commands/show.js +133 -0
  36. package/dist/commands/spec.d.ts +15 -0
  37. package/dist/commands/spec.js +228 -0
  38. package/dist/commands/validate.d.ts +24 -0
  39. package/dist/commands/validate.js +295 -0
  40. package/dist/commands/workflow/index.d.ts +17 -0
  41. package/dist/commands/workflow/index.js +12 -0
  42. package/dist/commands/workflow/instructions.d.ts +29 -0
  43. package/dist/commands/workflow/instructions.js +383 -0
  44. package/dist/commands/workflow/new-change.d.ts +11 -0
  45. package/dist/commands/workflow/new-change.js +45 -0
  46. package/dist/commands/workflow/schemas.d.ts +10 -0
  47. package/dist/commands/workflow/schemas.js +34 -0
  48. package/dist/commands/workflow/shared.d.ts +57 -0
  49. package/dist/commands/workflow/shared.js +117 -0
  50. package/dist/commands/workflow/status.d.ts +14 -0
  51. package/dist/commands/workflow/status.js +76 -0
  52. package/dist/commands/workflow/templates.d.ts +16 -0
  53. package/dist/commands/workflow/templates.js +68 -0
  54. package/dist/core/archive.d.ts +16 -0
  55. package/dist/core/archive.js +487 -0
  56. package/dist/core/artifact-graph/graph.d.ts +56 -0
  57. package/dist/core/artifact-graph/graph.js +141 -0
  58. package/dist/core/artifact-graph/index.d.ts +7 -0
  59. package/dist/core/artifact-graph/index.js +13 -0
  60. package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
  61. package/dist/core/artifact-graph/instruction-loader.js +215 -0
  62. package/dist/core/artifact-graph/resolver.d.ts +81 -0
  63. package/dist/core/artifact-graph/resolver.js +258 -0
  64. package/dist/core/artifact-graph/schema.d.ts +13 -0
  65. package/dist/core/artifact-graph/schema.js +108 -0
  66. package/dist/core/artifact-graph/state.d.ts +12 -0
  67. package/dist/core/artifact-graph/state.js +54 -0
  68. package/dist/core/artifact-graph/types.d.ts +45 -0
  69. package/dist/core/artifact-graph/types.js +43 -0
  70. package/dist/core/available-tools.d.ts +16 -0
  71. package/dist/core/available-tools.js +30 -0
  72. package/dist/core/branding.d.ts +8 -0
  73. package/dist/core/branding.js +12 -0
  74. package/dist/core/cli/command-matrix.d.ts +23 -0
  75. package/dist/core/cli/command-matrix.js +123 -0
  76. package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
  77. package/dist/core/command-generation/adapters/amazon-q.js +26 -0
  78. package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
  79. package/dist/core/command-generation/adapters/antigravity.js +26 -0
  80. package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
  81. package/dist/core/command-generation/adapters/auggie.js +27 -0
  82. package/dist/core/command-generation/adapters/claude.d.ts +13 -0
  83. package/dist/core/command-generation/adapters/claude.js +50 -0
  84. package/dist/core/command-generation/adapters/cline.d.ts +14 -0
  85. package/dist/core/command-generation/adapters/cline.js +27 -0
  86. package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
  87. package/dist/core/command-generation/adapters/codebuddy.js +28 -0
  88. package/dist/core/command-generation/adapters/codex.d.ts +16 -0
  89. package/dist/core/command-generation/adapters/codex.js +39 -0
  90. package/dist/core/command-generation/adapters/continue.d.ts +13 -0
  91. package/dist/core/command-generation/adapters/continue.js +28 -0
  92. package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
  93. package/dist/core/command-generation/adapters/costrict.js +27 -0
  94. package/dist/core/command-generation/adapters/crush.d.ts +13 -0
  95. package/dist/core/command-generation/adapters/crush.js +30 -0
  96. package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
  97. package/dist/core/command-generation/adapters/cursor.js +44 -0
  98. package/dist/core/command-generation/adapters/factory.d.ts +13 -0
  99. package/dist/core/command-generation/adapters/factory.js +27 -0
  100. package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
  101. package/dist/core/command-generation/adapters/gemini.js +26 -0
  102. package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
  103. package/dist/core/command-generation/adapters/github-copilot.js +26 -0
  104. package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
  105. package/dist/core/command-generation/adapters/iflow.js +29 -0
  106. package/dist/core/command-generation/adapters/index.d.ts +29 -0
  107. package/dist/core/command-generation/adapters/index.js +29 -0
  108. package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
  109. package/dist/core/command-generation/adapters/kilocode.js +23 -0
  110. package/dist/core/command-generation/adapters/kiro.d.ts +13 -0
  111. package/dist/core/command-generation/adapters/kiro.js +26 -0
  112. package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
  113. package/dist/core/command-generation/adapters/opencode.js +29 -0
  114. package/dist/core/command-generation/adapters/pi.d.ts +14 -0
  115. package/dist/core/command-generation/adapters/pi.js +41 -0
  116. package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
  117. package/dist/core/command-generation/adapters/qoder.js +30 -0
  118. package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
  119. package/dist/core/command-generation/adapters/qwen.js +26 -0
  120. package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
  121. package/dist/core/command-generation/adapters/roocode.js +27 -0
  122. package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
  123. package/dist/core/command-generation/adapters/windsurf.js +51 -0
  124. package/dist/core/command-generation/generator.d.ts +21 -0
  125. package/dist/core/command-generation/generator.js +27 -0
  126. package/dist/core/command-generation/index.d.ts +22 -0
  127. package/dist/core/command-generation/index.js +24 -0
  128. package/dist/core/command-generation/registry.d.ts +36 -0
  129. package/dist/core/command-generation/registry.js +92 -0
  130. package/dist/core/command-generation/types.d.ts +56 -0
  131. package/dist/core/command-generation/types.js +8 -0
  132. package/dist/core/completions/command-registry.d.ts +7 -0
  133. package/dist/core/completions/command-registry.js +461 -0
  134. package/dist/core/completions/completion-provider.d.ts +60 -0
  135. package/dist/core/completions/completion-provider.js +102 -0
  136. package/dist/core/completions/factory.d.ts +64 -0
  137. package/dist/core/completions/factory.js +75 -0
  138. package/dist/core/completions/generators/bash-generator.d.ts +32 -0
  139. package/dist/core/completions/generators/bash-generator.js +174 -0
  140. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  141. package/dist/core/completions/generators/fish-generator.js +157 -0
  142. package/dist/core/completions/generators/powershell-generator.d.ts +33 -0
  143. package/dist/core/completions/generators/powershell-generator.js +207 -0
  144. package/dist/core/completions/generators/zsh-generator.d.ts +44 -0
  145. package/dist/core/completions/generators/zsh-generator.js +250 -0
  146. package/dist/core/completions/installers/bash-installer.d.ts +87 -0
  147. package/dist/core/completions/installers/bash-installer.js +318 -0
  148. package/dist/core/completions/installers/fish-installer.d.ts +43 -0
  149. package/dist/core/completions/installers/fish-installer.js +143 -0
  150. package/dist/core/completions/installers/powershell-installer.d.ts +88 -0
  151. package/dist/core/completions/installers/powershell-installer.js +327 -0
  152. package/dist/core/completions/installers/zsh-installer.d.ts +125 -0
  153. package/dist/core/completions/installers/zsh-installer.js +452 -0
  154. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  155. package/dist/core/completions/templates/bash-templates.js +24 -0
  156. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  157. package/dist/core/completions/templates/fish-templates.js +39 -0
  158. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  159. package/dist/core/completions/templates/powershell-templates.js +25 -0
  160. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  161. package/dist/core/completions/templates/zsh-templates.js +36 -0
  162. package/dist/core/completions/types.d.ts +79 -0
  163. package/dist/core/completions/types.js +2 -0
  164. package/dist/core/config-prompts.d.ts +9 -0
  165. package/dist/core/config-prompts.js +34 -0
  166. package/dist/core/config-schema.d.ts +86 -0
  167. package/dist/core/config-schema.js +213 -0
  168. package/dist/core/config.d.ts +17 -0
  169. package/dist/core/config.js +33 -0
  170. package/dist/core/converters/json-converter.d.ts +6 -0
  171. package/dist/core/converters/json-converter.js +51 -0
  172. package/dist/core/global-config.d.ts +44 -0
  173. package/dist/core/global-config.js +125 -0
  174. package/dist/core/index.d.ts +2 -0
  175. package/dist/core/index.js +3 -0
  176. package/dist/core/init.d.ts +36 -0
  177. package/dist/core/init.js +576 -0
  178. package/dist/core/legacy-cleanup.d.ts +162 -0
  179. package/dist/core/legacy-cleanup.js +512 -0
  180. package/dist/core/list.d.ts +9 -0
  181. package/dist/core/list.js +173 -0
  182. package/dist/core/migration.d.ts +23 -0
  183. package/dist/core/migration.js +108 -0
  184. package/dist/core/parsers/change-parser.d.ts +13 -0
  185. package/dist/core/parsers/change-parser.js +193 -0
  186. package/dist/core/parsers/markdown-parser.d.ts +22 -0
  187. package/dist/core/parsers/markdown-parser.js +187 -0
  188. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  189. package/dist/core/parsers/requirement-blocks.js +201 -0
  190. package/dist/core/profile-sync-drift.d.ts +38 -0
  191. package/dist/core/profile-sync-drift.js +201 -0
  192. package/dist/core/profiles.d.ts +26 -0
  193. package/dist/core/profiles.js +41 -0
  194. package/dist/core/project-config.d.ts +64 -0
  195. package/dist/core/project-config.js +223 -0
  196. package/dist/core/schemas/base.schema.d.ts +13 -0
  197. package/dist/core/schemas/base.schema.js +13 -0
  198. package/dist/core/schemas/change.schema.d.ts +73 -0
  199. package/dist/core/schemas/change.schema.js +31 -0
  200. package/dist/core/schemas/index.d.ts +4 -0
  201. package/dist/core/schemas/index.js +4 -0
  202. package/dist/core/schemas/spec.schema.d.ts +18 -0
  203. package/dist/core/schemas/spec.schema.js +15 -0
  204. package/dist/core/sdd/adr-policy.d.ts +7 -0
  205. package/dist/core/sdd/adr-policy.js +47 -0
  206. package/dist/core/sdd/adr.d.ts +4 -0
  207. package/dist/core/sdd/adr.js +27 -0
  208. package/dist/core/sdd/bootstrap.d.ts +28 -0
  209. package/dist/core/sdd/bootstrap.js +353 -0
  210. package/dist/core/sdd/check.d.ts +51 -0
  211. package/dist/core/sdd/check.js +831 -0
  212. package/dist/core/sdd/coordination/coordination-adapters.d.ts +73 -0
  213. package/dist/core/sdd/coordination/coordination-adapters.js +87 -0
  214. package/dist/core/sdd/coordination/index.d.ts +2 -0
  215. package/dist/core/sdd/coordination/index.js +2 -0
  216. package/dist/core/sdd/dedup.d.ts +23 -0
  217. package/dist/core/sdd/dedup.js +62 -0
  218. package/dist/core/sdd/default-bootstrap-files.d.ts +23 -0
  219. package/dist/core/sdd/default-bootstrap-files.js +385 -0
  220. package/dist/core/sdd/default-skills.d.ts +16 -0
  221. package/dist/core/sdd/default-skills.js +427 -0
  222. package/dist/core/sdd/diagnose.d.ts +25 -0
  223. package/dist/core/sdd/diagnose.js +1312 -0
  224. package/dist/core/sdd/docs-sync.d.ts +21 -0
  225. package/dist/core/sdd/docs-sync.js +231 -0
  226. package/dist/core/sdd/domain/helpers.d.ts +6 -0
  227. package/dist/core/sdd/domain/helpers.js +37 -0
  228. package/dist/core/sdd/domain/lifecycle-guardrails.d.ts +22 -0
  229. package/dist/core/sdd/domain/lifecycle-guardrails.js +31 -0
  230. package/dist/core/sdd/domain/lifecycle-hooks.d.ts +16 -0
  231. package/dist/core/sdd/domain/lifecycle-hooks.js +27 -0
  232. package/dist/core/sdd/domain/post-active-validation.d.ts +15 -0
  233. package/dist/core/sdd/domain/post-active-validation.js +71 -0
  234. package/dist/core/sdd/domain/traceability.d.ts +8 -0
  235. package/dist/core/sdd/domain/traceability.js +83 -0
  236. package/dist/core/sdd/domain/transition-engine.d.ts +49 -0
  237. package/dist/core/sdd/domain/transition-engine.js +120 -0
  238. package/dist/core/sdd/fingerprint.d.ts +23 -0
  239. package/dist/core/sdd/fingerprint.js +146 -0
  240. package/dist/core/sdd/import-openspec.d.ts +31 -0
  241. package/dist/core/sdd/import-openspec.js +232 -0
  242. package/dist/core/sdd/init.d.ts +36 -0
  243. package/dist/core/sdd/init.js +65 -0
  244. package/dist/core/sdd/json-schema.d.ts +6 -0
  245. package/dist/core/sdd/json-schema.js +59 -0
  246. package/dist/core/sdd/legacy-operations.d.ts +286 -0
  247. package/dist/core/sdd/legacy-operations.js +2175 -0
  248. package/dist/core/sdd/lenses.d.ts +14 -0
  249. package/dist/core/sdd/lenses.js +97 -0
  250. package/dist/core/sdd/merge-catalog.d.ts +9 -0
  251. package/dist/core/sdd/merge-catalog.js +70 -0
  252. package/dist/core/sdd/migrate-workspace.d.ts +36 -0
  253. package/dist/core/sdd/migrate-workspace.js +344 -0
  254. package/dist/core/sdd/migrate.d.ts +24 -0
  255. package/dist/core/sdd/migrate.js +385 -0
  256. package/dist/core/sdd/resolve-project-root.d.ts +15 -0
  257. package/dist/core/sdd/resolve-project-root.js +46 -0
  258. package/dist/core/sdd/root-resolver.d.ts +16 -0
  259. package/dist/core/sdd/root-resolver.js +62 -0
  260. package/dist/core/sdd/sanitize.d.ts +35 -0
  261. package/dist/core/sdd/sanitize.js +750 -0
  262. package/dist/core/sdd/services/approve.service.d.ts +20 -0
  263. package/dist/core/sdd/services/approve.service.js +82 -0
  264. package/dist/core/sdd/services/audit.service.d.ts +53 -0
  265. package/dist/core/sdd/services/audit.service.js +136 -0
  266. package/dist/core/sdd/services/breakdown.service.d.ts +35 -0
  267. package/dist/core/sdd/services/breakdown.service.js +185 -0
  268. package/dist/core/sdd/services/context.service.d.ts +346 -0
  269. package/dist/core/sdd/services/context.service.js +278 -0
  270. package/dist/core/sdd/services/debate.service.d.ts +16 -0
  271. package/dist/core/sdd/services/debate.service.js +73 -0
  272. package/dist/core/sdd/services/decide.service.d.ts +23 -0
  273. package/dist/core/sdd/services/decide.service.js +81 -0
  274. package/dist/core/sdd/services/dedup-apply.service.d.ts +39 -0
  275. package/dist/core/sdd/services/dedup-apply.service.js +259 -0
  276. package/dist/core/sdd/services/feature-lint.service.d.ts +29 -0
  277. package/dist/core/sdd/services/feature-lint.service.js +146 -0
  278. package/dist/core/sdd/services/finalize.service.d.ts +33 -0
  279. package/dist/core/sdd/services/finalize.service.js +707 -0
  280. package/dist/core/sdd/services/frontend-gap.service.d.ts +23 -0
  281. package/dist/core/sdd/services/frontend-gap.service.js +117 -0
  282. package/dist/core/sdd/services/frontend-impact.service.d.ts +19 -0
  283. package/dist/core/sdd/services/frontend-impact.service.js +46 -0
  284. package/dist/core/sdd/services/ingest-deposito.service.d.ts +32 -0
  285. package/dist/core/sdd/services/ingest-deposito.service.js +231 -0
  286. package/dist/core/sdd/services/insight.service.d.ts +21 -0
  287. package/dist/core/sdd/services/insight.service.js +81 -0
  288. package/dist/core/sdd/services/legacy-capability.service.d.ts +24 -0
  289. package/dist/core/sdd/services/legacy-capability.service.js +59 -0
  290. package/dist/core/sdd/services/mcp-runtime.service.d.ts +42 -0
  291. package/dist/core/sdd/services/mcp-runtime.service.js +144 -0
  292. package/dist/core/sdd/services/metrics.service.d.ts +49 -0
  293. package/dist/core/sdd/services/metrics.service.js +181 -0
  294. package/dist/core/sdd/services/next.service.d.ts +35 -0
  295. package/dist/core/sdd/services/next.service.js +54 -0
  296. package/dist/core/sdd/services/onboard.service.d.ts +9 -0
  297. package/dist/core/sdd/services/onboard.service.js +165 -0
  298. package/dist/core/sdd/services/rebuild.service.d.ts +31 -0
  299. package/dist/core/sdd/services/rebuild.service.js +482 -0
  300. package/dist/core/sdd/services/scan-naming.service.d.ts +43 -0
  301. package/dist/core/sdd/services/scan-naming.service.js +246 -0
  302. package/dist/core/sdd/services/skills-invoke.service.d.ts +24 -0
  303. package/dist/core/sdd/services/skills-invoke.service.js +63 -0
  304. package/dist/core/sdd/services/skills-sync.service.d.ts +15 -0
  305. package/dist/core/sdd/services/skills-sync.service.js +117 -0
  306. package/dist/core/sdd/services/start.service.d.ts +26 -0
  307. package/dist/core/sdd/services/start.service.js +237 -0
  308. package/dist/core/sdd/skills.d.ts +15 -0
  309. package/dist/core/sdd/skills.js +46 -0
  310. package/dist/core/sdd/state-lock.d.ts +19 -0
  311. package/dist/core/sdd/state-lock.js +144 -0
  312. package/dist/core/sdd/state.d.ts +155 -0
  313. package/dist/core/sdd/state.js +1000 -0
  314. package/dist/core/sdd/store/in-memory-adapter.d.ts +12 -0
  315. package/dist/core/sdd/store/in-memory-adapter.js +27 -0
  316. package/dist/core/sdd/store/index.d.ts +5 -0
  317. package/dist/core/sdd/store/index.js +5 -0
  318. package/dist/core/sdd/store/sdd-stores.d.ts +25 -0
  319. package/dist/core/sdd/store/sdd-stores.js +59 -0
  320. package/dist/core/sdd/store/state-store.d.ts +32 -0
  321. package/dist/core/sdd/store/state-store.js +2 -0
  322. package/dist/core/sdd/store/yaml-file-adapter.d.ts +12 -0
  323. package/dist/core/sdd/store/yaml-file-adapter.js +43 -0
  324. package/dist/core/sdd/structural-health.d.ts +557 -0
  325. package/dist/core/sdd/structural-health.js +187 -0
  326. package/dist/core/sdd/transaction.d.ts +14 -0
  327. package/dist/core/sdd/transaction.js +100 -0
  328. package/dist/core/sdd/types.d.ts +1570 -0
  329. package/dist/core/sdd/types.js +617 -0
  330. package/dist/core/sdd/views.d.ts +3 -0
  331. package/dist/core/sdd/views.js +560 -0
  332. package/dist/core/sdd/workspace-schemas.d.ts +620 -0
  333. package/dist/core/sdd/workspace-schemas.js +254 -0
  334. package/dist/core/sdd/write-manifest.d.ts +25 -0
  335. package/dist/core/sdd/write-manifest.js +353 -0
  336. package/dist/core/shared/index.d.ts +8 -0
  337. package/dist/core/shared/index.js +8 -0
  338. package/dist/core/shared/skill-generation.d.ts +49 -0
  339. package/dist/core/shared/skill-generation.js +106 -0
  340. package/dist/core/shared/tool-detection.d.ts +71 -0
  341. package/dist/core/shared/tool-detection.js +158 -0
  342. package/dist/core/specs-apply.d.ts +73 -0
  343. package/dist/core/specs-apply.js +385 -0
  344. package/dist/core/styles/palette.d.ts +7 -0
  345. package/dist/core/styles/palette.js +8 -0
  346. package/dist/core/templates/index.d.ts +8 -0
  347. package/dist/core/templates/index.js +9 -0
  348. package/dist/core/templates/skill-templates.d.ts +20 -0
  349. package/dist/core/templates/skill-templates.js +19 -0
  350. package/dist/core/templates/types.d.ts +19 -0
  351. package/dist/core/templates/types.js +5 -0
  352. package/dist/core/templates/workflows/apply-change.d.ts +10 -0
  353. package/dist/core/templates/workflows/apply-change.js +308 -0
  354. package/dist/core/templates/workflows/archive-change.d.ts +10 -0
  355. package/dist/core/templates/workflows/archive-change.js +277 -0
  356. package/dist/core/templates/workflows/bulk-archive-change.d.ts +10 -0
  357. package/dist/core/templates/workflows/bulk-archive-change.js +502 -0
  358. package/dist/core/templates/workflows/continue-change.d.ts +10 -0
  359. package/dist/core/templates/workflows/continue-change.js +232 -0
  360. package/dist/core/templates/workflows/explore.d.ts +10 -0
  361. package/dist/core/templates/workflows/explore.js +475 -0
  362. package/dist/core/templates/workflows/feedback.d.ts +9 -0
  363. package/dist/core/templates/workflows/feedback.js +108 -0
  364. package/dist/core/templates/workflows/ff-change.d.ts +10 -0
  365. package/dist/core/templates/workflows/ff-change.js +206 -0
  366. package/dist/core/templates/workflows/new-change.d.ts +10 -0
  367. package/dist/core/templates/workflows/new-change.js +151 -0
  368. package/dist/core/templates/workflows/onboard.d.ts +10 -0
  369. package/dist/core/templates/workflows/onboard.js +573 -0
  370. package/dist/core/templates/workflows/propose.d.ts +10 -0
  371. package/dist/core/templates/workflows/propose.js +224 -0
  372. package/dist/core/templates/workflows/sdd.d.ts +10 -0
  373. package/dist/core/templates/workflows/sdd.js +107 -0
  374. package/dist/core/templates/workflows/sync-specs.d.ts +10 -0
  375. package/dist/core/templates/workflows/sync-specs.js +286 -0
  376. package/dist/core/templates/workflows/verify-change.d.ts +10 -0
  377. package/dist/core/templates/workflows/verify-change.js +346 -0
  378. package/dist/core/update.d.ts +77 -0
  379. package/dist/core/update.js +538 -0
  380. package/dist/core/validation/constants.d.ts +34 -0
  381. package/dist/core/validation/constants.js +40 -0
  382. package/dist/core/validation/types.d.ts +18 -0
  383. package/dist/core/validation/types.js +2 -0
  384. package/dist/core/validation/validator.d.ts +33 -0
  385. package/dist/core/validation/validator.js +409 -0
  386. package/dist/core/view.d.ts +8 -0
  387. package/dist/core/view.js +170 -0
  388. package/dist/index.d.ts +3 -0
  389. package/dist/index.js +3 -0
  390. package/dist/prompts/searchable-multi-select.d.ts +28 -0
  391. package/dist/prompts/searchable-multi-select.js +159 -0
  392. package/dist/telemetry/config.d.ts +32 -0
  393. package/dist/telemetry/config.js +68 -0
  394. package/dist/telemetry/index.d.ts +44 -0
  395. package/dist/telemetry/index.js +207 -0
  396. package/dist/ui/ascii-patterns.d.ts +16 -0
  397. package/dist/ui/ascii-patterns.js +133 -0
  398. package/dist/ui/welcome-screen.d.ts +10 -0
  399. package/dist/ui/welcome-screen.js +146 -0
  400. package/dist/utils/change-metadata.d.ts +51 -0
  401. package/dist/utils/change-metadata.js +147 -0
  402. package/dist/utils/change-utils.d.ts +62 -0
  403. package/dist/utils/change-utils.js +121 -0
  404. package/dist/utils/command-references.d.ts +18 -0
  405. package/dist/utils/command-references.js +20 -0
  406. package/dist/utils/file-system.d.ts +36 -0
  407. package/dist/utils/file-system.js +281 -0
  408. package/dist/utils/index.d.ts +6 -0
  409. package/dist/utils/index.js +9 -0
  410. package/dist/utils/interactive.d.ts +18 -0
  411. package/dist/utils/interactive.js +21 -0
  412. package/dist/utils/item-discovery.d.ts +4 -0
  413. package/dist/utils/item-discovery.js +73 -0
  414. package/dist/utils/match.d.ts +3 -0
  415. package/dist/utils/match.js +22 -0
  416. package/dist/utils/openspec-compat.d.ts +2 -0
  417. package/dist/utils/openspec-compat.js +2 -0
  418. package/dist/utils/shell-detection.d.ts +20 -0
  419. package/dist/utils/shell-detection.js +41 -0
  420. package/dist/utils/task-progress.d.ts +8 -0
  421. package/dist/utils/task-progress.js +36 -0
  422. package/package.json +111 -0
  423. package/schemas/sdd/1-spec.schema.json +221 -0
  424. package/schemas/sdd/2-plan.schema.json +199 -0
  425. package/schemas/sdd/3-tasks.schema.json +102 -0
  426. package/schemas/sdd/4-changelog.schema.json +55 -0
  427. package/schemas/sdd/5-quality.schema.json +427 -0
  428. package/schemas/sdd/workspace-catalog.schema.json +1012 -0
  429. package/schemas/spec-driven/schema.yaml +153 -0
  430. package/schemas/spec-driven/templates/design.md +19 -0
  431. package/schemas/spec-driven/templates/proposal.md +23 -0
  432. package/schemas/spec-driven/templates/spec.md +8 -0
  433. package/schemas/spec-driven/templates/tasks.md +9 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Status Command
3
+ *
4
+ * Displays artifact completion status for a change.
5
+ */
6
+ import ora from 'ora';
7
+ import chalk from 'chalk';
8
+ import { loadChangeContext, formatChangeStatus, } from '../../core/artifact-graph/index.js';
9
+ import { validateChangeExists, validateSchemaExists, getAvailableChanges, getStatusIndicator, getStatusColor, } from './shared.js';
10
+ import { CLI_NAME } from '../../core/branding.js';
11
+ // -----------------------------------------------------------------------------
12
+ // Command Implementation
13
+ // -----------------------------------------------------------------------------
14
+ export async function statusCommand(options) {
15
+ const spinner = ora('Loading change status...').start();
16
+ try {
17
+ const projectRoot = process.cwd();
18
+ // Handle no-changes case gracefully — status is informational,
19
+ // so "no changes" is a valid state, not an error.
20
+ if (!options.change) {
21
+ const available = await getAvailableChanges(projectRoot);
22
+ if (available.length === 0) {
23
+ spinner.stop();
24
+ if (options.json) {
25
+ console.log(JSON.stringify({ changes: [], message: 'No active changes.' }, null, 2));
26
+ return;
27
+ }
28
+ console.log(`No active changes. Create one with: ${CLI_NAME} new change <name>`);
29
+ return;
30
+ }
31
+ // Changes exist but --change not provided
32
+ spinner.stop();
33
+ throw new Error(`Missing required option --change. Available changes:\n ${available.join('\n ')}`);
34
+ }
35
+ const changeName = await validateChangeExists(options.change, projectRoot);
36
+ // Validate schema if explicitly provided
37
+ if (options.schema) {
38
+ validateSchemaExists(options.schema, projectRoot);
39
+ }
40
+ // loadChangeContext will auto-detect schema from metadata if not provided
41
+ const context = loadChangeContext(projectRoot, changeName, options.schema);
42
+ const status = formatChangeStatus(context);
43
+ spinner.stop();
44
+ if (options.json) {
45
+ console.log(JSON.stringify(status, null, 2));
46
+ return;
47
+ }
48
+ printStatusText(status);
49
+ }
50
+ catch (error) {
51
+ spinner.stop();
52
+ throw error;
53
+ }
54
+ }
55
+ export function printStatusText(status) {
56
+ const doneCount = status.artifacts.filter((a) => a.status === 'done').length;
57
+ const total = status.artifacts.length;
58
+ console.log(`Change: ${status.changeName}`);
59
+ console.log(`Schema: ${status.schemaName}`);
60
+ console.log(`Progress: ${doneCount}/${total} artifacts complete`);
61
+ console.log();
62
+ for (const artifact of status.artifacts) {
63
+ const indicator = getStatusIndicator(artifact.status);
64
+ const color = getStatusColor(artifact.status);
65
+ let line = `${indicator} ${artifact.id}`;
66
+ if (artifact.status === 'blocked' && artifact.missingDeps && artifact.missingDeps.length > 0) {
67
+ line += color(` (blocked by: ${artifact.missingDeps.join(', ')})`);
68
+ }
69
+ console.log(line);
70
+ }
71
+ if (status.isComplete) {
72
+ console.log();
73
+ console.log(chalk.green('All artifacts complete!'));
74
+ }
75
+ }
76
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Templates Command
3
+ *
4
+ * Shows resolved template paths for all artifacts in a schema.
5
+ */
6
+ export interface TemplatesOptions {
7
+ schema?: string;
8
+ json?: boolean;
9
+ }
10
+ export interface TemplateInfo {
11
+ artifactId: string;
12
+ templatePath: string;
13
+ source: 'project' | 'user' | 'package';
14
+ }
15
+ export declare function templatesCommand(options: TemplatesOptions): Promise<void>;
16
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Templates Command
3
+ *
4
+ * Shows resolved template paths for all artifacts in a schema.
5
+ */
6
+ import ora from 'ora';
7
+ import path from 'path';
8
+ import { resolveSchema, getSchemaDir, ArtifactGraph, } from '../../core/artifact-graph/index.js';
9
+ import { validateSchemaExists, DEFAULT_SCHEMA } from './shared.js';
10
+ // -----------------------------------------------------------------------------
11
+ // Command Implementation
12
+ // -----------------------------------------------------------------------------
13
+ export async function templatesCommand(options) {
14
+ const spinner = ora('Loading templates...').start();
15
+ try {
16
+ const projectRoot = process.cwd();
17
+ const schemaName = validateSchemaExists(options.schema ?? DEFAULT_SCHEMA, projectRoot);
18
+ const schema = resolveSchema(schemaName, projectRoot);
19
+ const graph = ArtifactGraph.fromSchema(schema);
20
+ const schemaDir = getSchemaDir(schemaName, projectRoot);
21
+ // Determine the source (project, user, or package)
22
+ const { getUserSchemasDir, getProjectSchemasDir, } = await import('../../core/artifact-graph/resolver.js');
23
+ const projectSchemasDir = getProjectSchemasDir(projectRoot);
24
+ const userSchemasDir = getUserSchemasDir();
25
+ // Determine source by checking if schemaDir is inside each base directory
26
+ // Using path.relative is more robust than startsWith for path comparisons
27
+ const isInsideDir = (child, parent) => {
28
+ const relative = path.relative(parent, child);
29
+ return !relative.startsWith('..') && !path.isAbsolute(relative);
30
+ };
31
+ let source;
32
+ if (isInsideDir(schemaDir, projectSchemasDir)) {
33
+ source = 'project';
34
+ }
35
+ else if (isInsideDir(schemaDir, userSchemasDir)) {
36
+ source = 'user';
37
+ }
38
+ else {
39
+ source = 'package';
40
+ }
41
+ const templates = graph.getAllArtifacts().map((artifact) => ({
42
+ artifactId: artifact.id,
43
+ templatePath: path.join(schemaDir, 'templates', artifact.template),
44
+ source,
45
+ }));
46
+ spinner.stop();
47
+ if (options.json) {
48
+ const output = {};
49
+ for (const t of templates) {
50
+ output[t.artifactId] = { path: t.templatePath, source: t.source };
51
+ }
52
+ console.log(JSON.stringify(output, null, 2));
53
+ return;
54
+ }
55
+ console.log(`Schema: ${schemaName}`);
56
+ console.log(`Source: ${source}`);
57
+ console.log();
58
+ for (const t of templates) {
59
+ console.log(`${t.artifactId}:`);
60
+ console.log(` ${t.templatePath}`);
61
+ }
62
+ }
63
+ catch (error) {
64
+ spinner.stop();
65
+ throw error;
66
+ }
67
+ }
68
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1,16 @@
1
+ export declare class ArchiveCommand {
2
+ execute(changeName?: string, options?: {
3
+ yes?: boolean;
4
+ skipSpecs?: boolean;
5
+ noValidate?: boolean;
6
+ validate?: boolean;
7
+ }): Promise<void>;
8
+ private selectChange;
9
+ private getArchiveDate;
10
+ private validateFingerprintsAgainstLiveSpec;
11
+ private buildFingerprintLookup;
12
+ private collectTouchedRequirements;
13
+ private mapRequirementBlocks;
14
+ private inferLastEditorForRequirement;
15
+ }
16
+ //# sourceMappingURL=archive.d.ts.map
@@ -0,0 +1,487 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ import { execFile } from 'node:child_process';
4
+ import { promisify } from 'node:util';
5
+ import { getTaskProgressForChange, formatTaskStatus } from '../utils/task-progress.js';
6
+ import { Validator } from './validation/validator.js';
7
+ import chalk from 'chalk';
8
+ import { findSpecUpdates, buildUpdatedSpec, writeUpdatedSpec, } from './specs-apply.js';
9
+ import { computeRequirementHash, readMeta, captureFingerprintsForChange, writeMeta, } from './sdd/fingerprint.js';
10
+ import { extractRequirementsSection, normalizeRequirementName, parseDeltaSpec, } from './parsers/requirement-blocks.js';
11
+ import { CLI_NAME } from './branding.js';
12
+ import { trackFingerprintMismatch } from '../telemetry/index.js';
13
+ import { resolveOpenSpecLiveSubpath } from './sdd/services/legacy-capability.service.js';
14
+ const execFileAsync = promisify(execFile);
15
+ function buildRequirementKey(capability, name) {
16
+ return `${capability}::${normalizeRequirementName(name)}`;
17
+ }
18
+ /**
19
+ * Recursively copy a directory. Used when fs.rename fails (e.g. EPERM on Windows).
20
+ */
21
+ async function copyDirRecursive(src, dest) {
22
+ await fs.mkdir(dest, { recursive: true });
23
+ const entries = await fs.readdir(src, { withFileTypes: true });
24
+ for (const entry of entries) {
25
+ const srcPath = path.join(src, entry.name);
26
+ const destPath = path.join(dest, entry.name);
27
+ if (entry.isDirectory()) {
28
+ await copyDirRecursive(srcPath, destPath);
29
+ }
30
+ else {
31
+ await fs.copyFile(srcPath, destPath);
32
+ }
33
+ }
34
+ }
35
+ /**
36
+ * Move a directory from src to dest. On Windows, fs.rename() often fails with
37
+ * EPERM when the directory is non-empty or another process has it open (IDE,
38
+ * file watcher, antivirus). Fall back to copy-then-remove when rename fails
39
+ * with EPERM or EXDEV.
40
+ */
41
+ async function moveDirectory(src, dest) {
42
+ try {
43
+ await fs.rename(src, dest);
44
+ }
45
+ catch (err) {
46
+ const code = err?.code;
47
+ if (code === 'EPERM' || code === 'EXDEV') {
48
+ await copyDirRecursive(src, dest);
49
+ await fs.rm(src, { recursive: true, force: true });
50
+ }
51
+ else {
52
+ throw err;
53
+ }
54
+ }
55
+ }
56
+ export class ArchiveCommand {
57
+ async execute(changeName, options = {}) {
58
+ const targetPath = '.';
59
+ const changesDir = resolveOpenSpecLiveSubpath(targetPath, 'changes');
60
+ const archiveDir = path.join(changesDir, 'archive');
61
+ const mainSpecsDir = resolveOpenSpecLiveSubpath(targetPath, 'specs');
62
+ // Check if changes directory exists
63
+ try {
64
+ await fs.access(changesDir);
65
+ }
66
+ catch {
67
+ throw new Error(`No OpenSpec changes directory found. Run '${CLI_NAME} init' first.`);
68
+ }
69
+ // Get change name interactively if not provided
70
+ if (!changeName) {
71
+ const selectedChange = await this.selectChange(changesDir);
72
+ if (!selectedChange) {
73
+ console.log('No change selected. Aborting.');
74
+ return;
75
+ }
76
+ changeName = selectedChange;
77
+ }
78
+ const changeDir = path.join(changesDir, changeName);
79
+ // Verify change exists
80
+ try {
81
+ const stat = await fs.stat(changeDir);
82
+ if (!stat.isDirectory()) {
83
+ throw new Error(`Change '${changeName}' not found.`);
84
+ }
85
+ }
86
+ catch {
87
+ throw new Error(`Change '${changeName}' not found.`);
88
+ }
89
+ const skipValidation = options.validate === false || options.noValidate === true;
90
+ // Validate specs and change before archiving
91
+ if (!skipValidation) {
92
+ const validator = new Validator();
93
+ let hasValidationErrors = false;
94
+ // Validate proposal.md (non-blocking unless strict mode desired in future)
95
+ const changeFile = path.join(changeDir, 'proposal.md');
96
+ try {
97
+ await fs.access(changeFile);
98
+ const changeReport = await validator.validateChange(changeFile);
99
+ // Proposal validation is informative only (do not block archive)
100
+ if (!changeReport.valid) {
101
+ console.log(chalk.yellow(`\nProposal warnings in proposal.md (non-blocking):`));
102
+ for (const issue of changeReport.issues) {
103
+ const symbol = issue.level === 'ERROR' ? '⚠' : (issue.level === 'WARNING' ? '⚠' : 'ℹ');
104
+ console.log(chalk.yellow(` ${symbol} ${issue.message}`));
105
+ }
106
+ }
107
+ }
108
+ catch {
109
+ // Change file doesn't exist, skip validation
110
+ }
111
+ // Validate delta-formatted spec files under the change directory if present
112
+ const changeSpecsDir = path.join(changeDir, 'specs');
113
+ let hasDeltaSpecs = false;
114
+ try {
115
+ const candidates = await fs.readdir(changeSpecsDir, { withFileTypes: true });
116
+ for (const c of candidates) {
117
+ if (c.isDirectory()) {
118
+ try {
119
+ const candidatePath = path.join(changeSpecsDir, c.name, 'spec.md');
120
+ await fs.access(candidatePath);
121
+ const content = await fs.readFile(candidatePath, 'utf-8');
122
+ if (/^##\s+(ADDED|MODIFIED|REMOVED|RENAMED)\s+Requirements/m.test(content)) {
123
+ hasDeltaSpecs = true;
124
+ break;
125
+ }
126
+ }
127
+ catch { }
128
+ }
129
+ }
130
+ }
131
+ catch { }
132
+ if (hasDeltaSpecs) {
133
+ const deltaReport = await validator.validateChangeDeltaSpecs(changeDir);
134
+ if (!deltaReport.valid) {
135
+ hasValidationErrors = true;
136
+ console.log(chalk.red(`\nValidation errors in change delta specs:`));
137
+ for (const issue of deltaReport.issues) {
138
+ if (issue.level === 'ERROR') {
139
+ console.log(chalk.red(` ✗ ${issue.message}`));
140
+ }
141
+ else if (issue.level === 'WARNING') {
142
+ console.log(chalk.yellow(` ⚠ ${issue.message}`));
143
+ }
144
+ }
145
+ }
146
+ }
147
+ if (hasValidationErrors) {
148
+ console.log(chalk.red('\nValidation failed. Please fix the errors before archiving.'));
149
+ console.log(chalk.yellow('To skip validation (not recommended), use --no-validate flag.'));
150
+ return;
151
+ }
152
+ }
153
+ else {
154
+ // Log warning when validation is skipped
155
+ const timestamp = new Date().toISOString();
156
+ if (!options.yes) {
157
+ const { confirm } = await import('@inquirer/prompts');
158
+ const proceed = await confirm({
159
+ message: chalk.yellow('⚠️ WARNING: Skipping validation may archive invalid specs. Continue? (y/N)'),
160
+ default: false
161
+ });
162
+ if (!proceed) {
163
+ console.log('Archive cancelled.');
164
+ return;
165
+ }
166
+ }
167
+ else {
168
+ console.log(chalk.yellow(`\n⚠️ WARNING: Skipping validation may archive invalid specs.`));
169
+ }
170
+ console.log(chalk.yellow(`[${timestamp}] Validation skipped for change: ${changeName}`));
171
+ console.log(chalk.yellow(`Affected files: ${changeDir}`));
172
+ }
173
+ // Show progress and check for incomplete tasks
174
+ const progress = await getTaskProgressForChange(changesDir, changeName);
175
+ const status = formatTaskStatus(progress);
176
+ console.log(`Task status: ${status}`);
177
+ const incompleteTasks = Math.max(progress.total - progress.completed, 0);
178
+ if (incompleteTasks > 0) {
179
+ if (!options.yes) {
180
+ const { confirm } = await import('@inquirer/prompts');
181
+ const proceed = await confirm({
182
+ message: `Warning: ${incompleteTasks} incomplete task(s) found. Continue?`,
183
+ default: false
184
+ });
185
+ if (!proceed) {
186
+ console.log('Archive cancelled.');
187
+ return;
188
+ }
189
+ }
190
+ else {
191
+ console.log(`Warning: ${incompleteTasks} incomplete task(s) found. Continuing due to --yes flag.`);
192
+ }
193
+ }
194
+ // Handle spec updates unless skipSpecs flag is set
195
+ if (options.skipSpecs) {
196
+ console.log('Skipping spec updates (--skip-specs flag provided).');
197
+ }
198
+ else {
199
+ // Find specs to update
200
+ const specUpdates = await findSpecUpdates(changeDir, mainSpecsDir);
201
+ if (specUpdates.length > 0) {
202
+ console.log('\nSpecs to update:');
203
+ for (const update of specUpdates) {
204
+ const status = update.exists ? 'update' : 'create';
205
+ const capability = path.basename(path.dirname(update.target));
206
+ console.log(` ${capability}: ${status}`);
207
+ }
208
+ let shouldUpdateSpecs = true;
209
+ if (!options.yes) {
210
+ const { confirm } = await import('@inquirer/prompts');
211
+ shouldUpdateSpecs = await confirm({
212
+ message: 'Proceed with spec updates?',
213
+ default: true
214
+ });
215
+ if (!shouldUpdateSpecs) {
216
+ console.log('Skipping spec updates. Proceeding with archive.');
217
+ }
218
+ }
219
+ if (shouldUpdateSpecs) {
220
+ if (!skipValidation) {
221
+ try {
222
+ await this.validateFingerprintsAgainstLiveSpec(changeName, changeDir, specUpdates);
223
+ }
224
+ catch (err) {
225
+ console.log(String(err.message || err));
226
+ console.log('Aborted. No files were changed.');
227
+ return;
228
+ }
229
+ }
230
+ // Prepare all updates first (validation pass, no writes)
231
+ const prepared = [];
232
+ try {
233
+ for (const update of specUpdates) {
234
+ const built = await buildUpdatedSpec(update, changeName);
235
+ prepared.push({ update, rebuilt: built.rebuilt, counts: built.counts });
236
+ }
237
+ }
238
+ catch (err) {
239
+ console.log(String(err.message || err));
240
+ console.log('Aborted. No files were changed.');
241
+ return;
242
+ }
243
+ // All validations passed; pre-validate rebuilt full spec and then write files and display counts
244
+ let totals = { added: 0, modified: 0, removed: 0, renamed: 0 };
245
+ for (const p of prepared) {
246
+ const specName = path.basename(path.dirname(p.update.target));
247
+ if (!skipValidation) {
248
+ const report = await new Validator().validateSpecContent(specName, p.rebuilt);
249
+ if (!report.valid) {
250
+ console.log(chalk.red(`\nValidation errors in rebuilt spec for ${specName} (will not write changes):`));
251
+ for (const issue of report.issues) {
252
+ if (issue.level === 'ERROR')
253
+ console.log(chalk.red(` ✗ ${issue.message}`));
254
+ else if (issue.level === 'WARNING')
255
+ console.log(chalk.yellow(` ⚠ ${issue.message}`));
256
+ }
257
+ console.log('Aborted. No files were changed.');
258
+ return;
259
+ }
260
+ }
261
+ await writeUpdatedSpec(p.update, p.rebuilt, p.counts);
262
+ totals.added += p.counts.added;
263
+ totals.modified += p.counts.modified;
264
+ totals.removed += p.counts.removed;
265
+ totals.renamed += p.counts.renamed;
266
+ }
267
+ console.log(`Totals: + ${totals.added}, ~ ${totals.modified}, - ${totals.removed}, → ${totals.renamed}`);
268
+ console.log('Specs updated successfully.');
269
+ }
270
+ }
271
+ }
272
+ // Create archive directory with date prefix
273
+ const archiveName = `${this.getArchiveDate()}-${changeName}`;
274
+ const archivePath = path.join(archiveDir, archiveName);
275
+ // Check if archive already exists
276
+ try {
277
+ await fs.access(archivePath);
278
+ throw new Error(`Archive '${archiveName}' already exists.`);
279
+ }
280
+ catch (error) {
281
+ if (error.code !== 'ENOENT') {
282
+ throw error;
283
+ }
284
+ }
285
+ // Create archive directory if needed
286
+ await fs.mkdir(archiveDir, { recursive: true });
287
+ // Move change to archive (uses copy+remove on EPERM/EXDEV, e.g. Windows)
288
+ await moveDirectory(changeDir, archivePath);
289
+ console.log(`Change '${changeName}' archived as '${archiveName}'.`);
290
+ }
291
+ async selectChange(changesDir) {
292
+ const { select } = await import('@inquirer/prompts');
293
+ // Get all directories in changes (excluding archive)
294
+ const entries = await fs.readdir(changesDir, { withFileTypes: true });
295
+ const changeDirs = entries
296
+ .filter(entry => entry.isDirectory() && entry.name !== 'archive')
297
+ .map(entry => entry.name)
298
+ .sort();
299
+ if (changeDirs.length === 0) {
300
+ console.log('No active changes found.');
301
+ return null;
302
+ }
303
+ // Build choices with progress inline to avoid duplicate lists
304
+ let choices = changeDirs.map(name => ({ name, value: name }));
305
+ try {
306
+ const progressList = [];
307
+ for (const id of changeDirs) {
308
+ const progress = await getTaskProgressForChange(changesDir, id);
309
+ const status = formatTaskStatus(progress);
310
+ progressList.push({ id, status });
311
+ }
312
+ const nameWidth = Math.max(...progressList.map(p => p.id.length));
313
+ choices = progressList.map(p => ({
314
+ name: `${p.id.padEnd(nameWidth)} ${p.status}`,
315
+ value: p.id
316
+ }));
317
+ }
318
+ catch {
319
+ // If anything fails, fall back to simple names
320
+ choices = changeDirs.map(name => ({ name, value: name }));
321
+ }
322
+ try {
323
+ const answer = await select({
324
+ message: 'Select a change to archive',
325
+ choices
326
+ });
327
+ return answer;
328
+ }
329
+ catch (error) {
330
+ // User cancelled (Ctrl+C)
331
+ return null;
332
+ }
333
+ }
334
+ getArchiveDate() {
335
+ // Returns date in YYYY-MM-DD format
336
+ return new Date().toISOString().split('T')[0];
337
+ }
338
+ async validateFingerprintsAgainstLiveSpec(changeName, changeDir, specUpdates) {
339
+ const mainSpecsDir = resolveOpenSpecLiveSubpath('.', 'specs');
340
+ let meta = await readMeta(changeDir);
341
+ if (!meta) {
342
+ meta = await captureFingerprintsForChange(changeDir, mainSpecsDir, {
343
+ sourceChangeId: changeName,
344
+ reconstructed: true,
345
+ });
346
+ await writeMeta(changeDir, meta);
347
+ console.log(chalk.yellow('Fingerprint metadata regenerated (reconstructed=true).'));
348
+ }
349
+ const fingerprintByRequirement = this.buildFingerprintLookup(meta);
350
+ for (const update of specUpdates) {
351
+ const capability = path.basename(path.dirname(update.target));
352
+ const sourceContent = await fs.readFile(update.source, 'utf-8');
353
+ const touched = this.collectTouchedRequirements(sourceContent, capability);
354
+ if (touched.length === 0) {
355
+ continue;
356
+ }
357
+ let liveSpecContent;
358
+ try {
359
+ liveSpecContent = await fs.readFile(update.target, 'utf-8');
360
+ }
361
+ catch {
362
+ throw new Error(`Unable to verify fingerprint for ${capability}: spec file not found. Re-run with --no-validate not recommended.`);
363
+ }
364
+ const currentBlocks = this.mapRequirementBlocks(liveSpecContent);
365
+ for (const touchedRequirement of touched) {
366
+ const fingerprintName = normalizeRequirementName(touchedRequirement.fingerprintRequirementId);
367
+ const key = buildRequirementKey(capability, fingerprintName);
368
+ const entry = fingerprintByRequirement.get(key);
369
+ const observedName = normalizeRequirementName(touchedRequirement.requirementId);
370
+ const blockRaw = currentBlocks.get(observedName) ?? currentBlocks.get(fingerprintName);
371
+ if (!blockRaw) {
372
+ throw new Error(`Archive blocked for ${capability}: requirement "${touchedRequirement.requirementId}" is not present in current spec. Rebase this change against current specs.`);
373
+ }
374
+ if (!entry) {
375
+ throw new Error(`Archive blocked for ${capability}: missing fingerprint for requirement "${touchedRequirement.requirementId}". Re-run "change validate" to recreate change metadata.`);
376
+ }
377
+ const currentHash = computeRequirementHash(blockRaw);
378
+ if (currentHash !== entry.base_hash) {
379
+ const lastEditor = await this.inferLastEditorForRequirement(update.target, touchedRequirement.requirementId);
380
+ await trackFingerprintMismatch({
381
+ change_id: changeName,
382
+ requirement_name: `${capability}::${touchedRequirement.requirementId}`,
383
+ last_editor_change_id: lastEditor,
384
+ });
385
+ throw new Error(`Fingerprint mismatch for ${capability} "${touchedRequirement.requirementId}". ` +
386
+ `Last editor: ${lastEditor}. Rebase this change onto current specs before archiving.`);
387
+ }
388
+ }
389
+ }
390
+ }
391
+ buildFingerprintLookup(meta) {
392
+ const map = new Map();
393
+ for (const entry of meta.requirements) {
394
+ map.set(buildRequirementKey(entry.capability, entry.requirement_id), entry);
395
+ }
396
+ return map;
397
+ }
398
+ collectTouchedRequirements(sourceContent, capability) {
399
+ const plan = parseDeltaSpec(sourceContent);
400
+ const renameToByFrom = new Map();
401
+ const renameFromByTo = new Map();
402
+ for (const rename of plan.renamed) {
403
+ const from = normalizeRequirementName(rename.from);
404
+ const to = normalizeRequirementName(rename.to);
405
+ renameToByFrom.set(from, to);
406
+ renameFromByTo.set(to, from);
407
+ }
408
+ const touched = [];
409
+ for (const modified of plan.modified) {
410
+ const fingerprintRequirementId = normalizeRequirementName(renameFromByTo.get(modified.name) ?? modified.name);
411
+ touched.push({
412
+ capability,
413
+ requirementId: normalizeRequirementName(modified.name),
414
+ fingerprintRequirementId,
415
+ });
416
+ }
417
+ for (const removed of plan.removed) {
418
+ touched.push({
419
+ capability,
420
+ requirementId: normalizeRequirementName(removed),
421
+ fingerprintRequirementId: normalizeRequirementName(removed),
422
+ });
423
+ }
424
+ for (const renamed of plan.renamed) {
425
+ const to = normalizeRequirementName(renameToByFrom.get(renamed.from) ?? renamed.to);
426
+ touched.push({
427
+ capability,
428
+ requirementId: normalizeRequirementName(renamed.from),
429
+ fingerprintRequirementId: normalizeRequirementName(renamed.from),
430
+ });
431
+ touched.push({
432
+ capability,
433
+ requirementId: to,
434
+ fingerprintRequirementId: normalizeRequirementName(renamed.from),
435
+ });
436
+ }
437
+ return touched;
438
+ }
439
+ mapRequirementBlocks(content) {
440
+ const map = new Map();
441
+ const parts = extractRequirementsSection(content);
442
+ for (const block of parts.bodyBlocks) {
443
+ map.set(normalizeRequirementName(block.name), block.raw);
444
+ }
445
+ return map;
446
+ }
447
+ async inferLastEditorForRequirement(specPath, requirementName) {
448
+ const specContent = await fs.readFile(specPath, 'utf-8');
449
+ const lines = specContent.split('\n');
450
+ const target = normalizeRequirementName(requirementName);
451
+ const line = lines.findIndex((candidate) => {
452
+ const match = candidate.match(/^###\s+Requirement:\s*(.+)\s*$/);
453
+ if (!match)
454
+ return false;
455
+ return normalizeRequirementName(match[1]) === target;
456
+ });
457
+ if (line === -1) {
458
+ return 'unknown';
459
+ }
460
+ const lineNumber = line + 1;
461
+ try {
462
+ const blameResult = await execFileAsync('git', [
463
+ 'blame',
464
+ '-L',
465
+ `${lineNumber},${lineNumber}`,
466
+ '--line-porcelain',
467
+ '--',
468
+ specPath,
469
+ ], { cwd: path.dirname(specPath) });
470
+ const firstLine = `${blameResult.stdout}`.split('\n')[0];
471
+ const hashMatch = firstLine.match(/^([0-9a-f]{40})\s/);
472
+ if (!hashMatch) {
473
+ return 'unknown';
474
+ }
475
+ const logResult = await execFileAsync('git', ['log', '-1', '--format=%s', hashMatch[1]], {
476
+ cwd: path.dirname(specPath),
477
+ });
478
+ const message = `${logResult.stdout}`.trim();
479
+ const changeMatch = message.match(/FEAT-\d+/i);
480
+ return changeMatch ? changeMatch[0].toUpperCase() : 'unknown';
481
+ }
482
+ catch {
483
+ return 'unknown';
484
+ }
485
+ }
486
+ }
487
+ //# sourceMappingURL=archive.js.map