@dedesfr/prompter 0.6.14 → 0.7.0

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 (379) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cli/index.js +144 -12
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/archive.d.ts +11 -0
  5. package/dist/commands/archive.d.ts.map +1 -0
  6. package/dist/commands/archive.js +280 -0
  7. package/dist/commands/archive.js.map +1 -0
  8. package/dist/commands/change.d.ts +35 -0
  9. package/dist/commands/change.d.ts.map +1 -0
  10. package/dist/commands/change.js +277 -0
  11. package/dist/commands/change.js.map +1 -0
  12. package/dist/commands/config.d.ts +8 -0
  13. package/dist/commands/config.d.ts.map +1 -0
  14. package/dist/commands/config.js +198 -0
  15. package/dist/commands/config.js.map +1 -0
  16. package/dist/commands/guide.d.ts.map +1 -1
  17. package/dist/commands/guide.js +4 -0
  18. package/dist/commands/guide.js.map +1 -1
  19. package/dist/commands/list.d.ts +2 -2
  20. package/dist/commands/list.d.ts.map +1 -1
  21. package/dist/commands/list.js +153 -47
  22. package/dist/commands/list.js.map +1 -1
  23. package/dist/commands/show.d.ts +14 -0
  24. package/dist/commands/show.d.ts.map +1 -0
  25. package/dist/commands/show.js +132 -0
  26. package/dist/commands/show.js.map +1 -0
  27. package/dist/commands/spec.d.ts +15 -0
  28. package/dist/commands/spec.d.ts.map +1 -0
  29. package/dist/commands/spec.js +225 -0
  30. package/dist/commands/spec.js.map +1 -0
  31. package/dist/commands/validate.d.ts +24 -0
  32. package/dist/commands/validate.d.ts.map +1 -0
  33. package/dist/commands/validate.js +294 -0
  34. package/dist/commands/validate.js.map +1 -0
  35. package/dist/core/artifact-graph/graph.d.ts +56 -0
  36. package/dist/core/artifact-graph/graph.d.ts.map +1 -0
  37. package/dist/core/artifact-graph/graph.js +141 -0
  38. package/dist/core/artifact-graph/graph.js.map +1 -0
  39. package/dist/core/artifact-graph/index.d.ts +7 -0
  40. package/dist/core/artifact-graph/index.d.ts.map +1 -0
  41. package/dist/core/artifact-graph/index.js +13 -0
  42. package/dist/core/artifact-graph/index.js.map +1 -0
  43. package/dist/core/artifact-graph/instruction-loader.d.ts +130 -0
  44. package/dist/core/artifact-graph/instruction-loader.d.ts.map +1 -0
  45. package/dist/core/artifact-graph/instruction-loader.js +173 -0
  46. package/dist/core/artifact-graph/instruction-loader.js.map +1 -0
  47. package/dist/core/artifact-graph/resolver.d.ts +61 -0
  48. package/dist/core/artifact-graph/resolver.d.ts.map +1 -0
  49. package/dist/core/artifact-graph/resolver.js +187 -0
  50. package/dist/core/artifact-graph/resolver.js.map +1 -0
  51. package/dist/core/artifact-graph/schema.d.ts +13 -0
  52. package/dist/core/artifact-graph/schema.d.ts.map +1 -0
  53. package/dist/core/artifact-graph/schema.js +108 -0
  54. package/dist/core/artifact-graph/schema.js.map +1 -0
  55. package/dist/core/artifact-graph/state.d.ts +12 -0
  56. package/dist/core/artifact-graph/state.d.ts.map +1 -0
  57. package/dist/core/artifact-graph/state.js +54 -0
  58. package/dist/core/artifact-graph/state.js.map +1 -0
  59. package/dist/core/artifact-graph/types.d.ts +45 -0
  60. package/dist/core/artifact-graph/types.d.ts.map +1 -0
  61. package/dist/core/artifact-graph/types.js +43 -0
  62. package/dist/core/artifact-graph/types.js.map +1 -0
  63. package/dist/core/completions/command-registry.d.ts +7 -0
  64. package/dist/core/completions/command-registry.d.ts.map +1 -0
  65. package/dist/core/completions/command-registry.js +380 -0
  66. package/dist/core/completions/command-registry.js.map +1 -0
  67. package/dist/core/completions/completion-provider.d.ts +60 -0
  68. package/dist/core/completions/completion-provider.d.ts.map +1 -0
  69. package/dist/core/completions/completion-provider.js +102 -0
  70. package/dist/core/completions/completion-provider.js.map +1 -0
  71. package/dist/core/completions/generators/bash-generator.d.ts +32 -0
  72. package/dist/core/completions/generators/bash-generator.d.ts.map +1 -0
  73. package/dist/core/completions/generators/bash-generator.js +174 -0
  74. package/dist/core/completions/generators/bash-generator.js.map +1 -0
  75. package/dist/core/completions/generators/fish-generator.d.ts +32 -0
  76. package/dist/core/completions/generators/fish-generator.d.ts.map +1 -0
  77. package/dist/core/completions/generators/fish-generator.js +157 -0
  78. package/dist/core/completions/generators/fish-generator.js.map +1 -0
  79. package/dist/core/completions/generators/powershell-generator.d.ts +33 -0
  80. package/dist/core/completions/generators/powershell-generator.d.ts.map +1 -0
  81. package/dist/core/completions/generators/powershell-generator.js +207 -0
  82. package/dist/core/completions/generators/powershell-generator.js.map +1 -0
  83. package/dist/core/completions/generators/zsh-generator.d.ts +44 -0
  84. package/dist/core/completions/generators/zsh-generator.d.ts.map +1 -0
  85. package/dist/core/completions/generators/zsh-generator.js +250 -0
  86. package/dist/core/completions/generators/zsh-generator.js.map +1 -0
  87. package/dist/core/completions/templates/bash-templates.d.ts +6 -0
  88. package/dist/core/completions/templates/bash-templates.d.ts.map +1 -0
  89. package/dist/core/completions/templates/bash-templates.js +24 -0
  90. package/dist/core/completions/templates/bash-templates.js.map +1 -0
  91. package/dist/core/completions/templates/fish-templates.d.ts +7 -0
  92. package/dist/core/completions/templates/fish-templates.d.ts.map +1 -0
  93. package/dist/core/completions/templates/fish-templates.js +39 -0
  94. package/dist/core/completions/templates/fish-templates.js.map +1 -0
  95. package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
  96. package/dist/core/completions/templates/powershell-templates.d.ts.map +1 -0
  97. package/dist/core/completions/templates/powershell-templates.js +25 -0
  98. package/dist/core/completions/templates/powershell-templates.js.map +1 -0
  99. package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
  100. package/dist/core/completions/templates/zsh-templates.d.ts.map +1 -0
  101. package/dist/core/completions/templates/zsh-templates.js +36 -0
  102. package/dist/core/completions/templates/zsh-templates.js.map +1 -0
  103. package/dist/core/completions/types.d.ts +78 -0
  104. package/dist/core/completions/types.d.ts.map +1 -0
  105. package/dist/core/completions/types.js +2 -0
  106. package/dist/core/completions/types.js.map +1 -0
  107. package/dist/core/config-schema.d.ts +76 -0
  108. package/dist/core/config-schema.d.ts.map +1 -0
  109. package/dist/core/config-schema.js +200 -0
  110. package/dist/core/config-schema.js.map +1 -0
  111. package/dist/core/config.d.ts.map +1 -1
  112. package/dist/core/config.js +18 -0
  113. package/dist/core/config.js.map +1 -1
  114. package/dist/core/configurators/slash/antigravity.d.ts.map +1 -1
  115. package/dist/core/configurators/slash/antigravity.js +6 -0
  116. package/dist/core/configurators/slash/antigravity.js.map +1 -1
  117. package/dist/core/configurators/slash/base.js +1 -1
  118. package/dist/core/configurators/slash/base.js.map +1 -1
  119. package/dist/core/configurators/slash/claude.d.ts.map +1 -1
  120. package/dist/core/configurators/slash/claude.js +6 -0
  121. package/dist/core/configurators/slash/claude.js.map +1 -1
  122. package/dist/core/configurators/slash/codex.d.ts.map +1 -1
  123. package/dist/core/configurators/slash/codex.js +6 -0
  124. package/dist/core/configurators/slash/codex.js.map +1 -1
  125. package/dist/core/configurators/slash/github-copilot.d.ts.map +1 -1
  126. package/dist/core/configurators/slash/github-copilot.js +6 -0
  127. package/dist/core/configurators/slash/github-copilot.js.map +1 -1
  128. package/dist/core/configurators/slash/kilocode.d.ts.map +1 -1
  129. package/dist/core/configurators/slash/kilocode.js +6 -0
  130. package/dist/core/configurators/slash/kilocode.js.map +1 -1
  131. package/dist/core/configurators/slash/opencode.d.ts.map +1 -1
  132. package/dist/core/configurators/slash/opencode.js +6 -0
  133. package/dist/core/configurators/slash/opencode.js.map +1 -1
  134. package/dist/core/converters/json-converter.d.ts +6 -0
  135. package/dist/core/converters/json-converter.d.ts.map +1 -0
  136. package/dist/core/converters/json-converter.js +51 -0
  137. package/dist/core/converters/json-converter.js.map +1 -0
  138. package/dist/core/global-config.d.ts +39 -0
  139. package/dist/core/global-config.d.ts.map +1 -0
  140. package/dist/core/global-config.js +115 -0
  141. package/dist/core/global-config.js.map +1 -0
  142. package/dist/core/parsers/change-parser.d.ts +13 -0
  143. package/dist/core/parsers/change-parser.d.ts.map +1 -0
  144. package/dist/core/parsers/change-parser.js +193 -0
  145. package/dist/core/parsers/change-parser.js.map +1 -0
  146. package/dist/core/parsers/markdown-parser.d.ts +22 -0
  147. package/dist/core/parsers/markdown-parser.d.ts.map +1 -0
  148. package/dist/core/parsers/markdown-parser.js +187 -0
  149. package/dist/core/parsers/markdown-parser.js.map +1 -0
  150. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  151. package/dist/core/parsers/requirement-blocks.d.ts.map +1 -0
  152. package/dist/core/parsers/requirement-blocks.js +201 -0
  153. package/dist/core/parsers/requirement-blocks.js.map +1 -0
  154. package/dist/core/prompt-templates.d.ts +3 -0
  155. package/dist/core/prompt-templates.d.ts.map +1 -1
  156. package/dist/core/prompt-templates.js +66 -0
  157. package/dist/core/prompt-templates.js.map +1 -1
  158. package/dist/core/schemas/base.schema.d.ts +13 -0
  159. package/dist/core/schemas/base.schema.d.ts.map +1 -0
  160. package/dist/core/schemas/base.schema.js +13 -0
  161. package/dist/core/schemas/base.schema.js.map +1 -0
  162. package/dist/core/schemas/change.schema.d.ts +73 -0
  163. package/dist/core/schemas/change.schema.d.ts.map +1 -0
  164. package/dist/core/schemas/change.schema.js +31 -0
  165. package/dist/core/schemas/change.schema.js.map +1 -0
  166. package/dist/core/schemas/index.d.ts +4 -0
  167. package/dist/core/schemas/index.d.ts.map +1 -0
  168. package/dist/core/schemas/index.js +4 -0
  169. package/dist/core/schemas/index.js.map +1 -0
  170. package/dist/core/schemas/spec.schema.d.ts +18 -0
  171. package/dist/core/schemas/spec.schema.d.ts.map +1 -0
  172. package/dist/core/schemas/spec.schema.js +15 -0
  173. package/dist/core/schemas/spec.schema.js.map +1 -0
  174. package/dist/core/specs-apply.d.ts +73 -0
  175. package/dist/core/specs-apply.d.ts.map +1 -0
  176. package/dist/core/specs-apply.js +384 -0
  177. package/dist/core/specs-apply.js.map +1 -0
  178. package/dist/core/styles/palette.d.ts +7 -0
  179. package/dist/core/styles/palette.d.ts.map +1 -0
  180. package/dist/core/styles/palette.js +8 -0
  181. package/dist/core/styles/palette.js.map +1 -0
  182. package/dist/core/templates/slash-command-templates.d.ts +1 -1
  183. package/dist/core/templates/slash-command-templates.d.ts.map +1 -1
  184. package/dist/core/templates/slash-command-templates.js +4 -1
  185. package/dist/core/templates/slash-command-templates.js.map +1 -1
  186. package/dist/core/validation/constants.d.ts +34 -0
  187. package/dist/core/validation/constants.d.ts.map +1 -0
  188. package/dist/core/validation/constants.js +40 -0
  189. package/dist/core/validation/constants.js.map +1 -0
  190. package/dist/core/validation/types.d.ts +18 -0
  191. package/dist/core/validation/types.d.ts.map +1 -0
  192. package/dist/core/validation/types.js +2 -0
  193. package/dist/core/validation/types.js.map +1 -0
  194. package/dist/core/validation/validator.d.ts +33 -0
  195. package/dist/core/validation/validator.d.ts.map +1 -0
  196. package/dist/core/validation/validator.js +409 -0
  197. package/dist/core/validation/validator.js.map +1 -0
  198. package/dist/core/view.d.ts +8 -0
  199. package/dist/core/view.d.ts.map +1 -0
  200. package/dist/core/view.js +168 -0
  201. package/dist/core/view.js.map +1 -0
  202. package/dist/utils/change-metadata.d.ts +47 -0
  203. package/dist/utils/change-metadata.d.ts.map +1 -0
  204. package/dist/utils/change-metadata.js +130 -0
  205. package/dist/utils/change-metadata.js.map +1 -0
  206. package/dist/utils/change-utils.d.ts +51 -0
  207. package/dist/utils/change-utils.d.ts.map +1 -0
  208. package/dist/utils/change-utils.js +100 -0
  209. package/dist/utils/change-utils.js.map +1 -0
  210. package/dist/utils/file-system.d.ts +25 -0
  211. package/dist/utils/file-system.d.ts.map +1 -0
  212. package/dist/utils/file-system.js +218 -0
  213. package/dist/utils/file-system.js.map +1 -0
  214. package/dist/utils/index.d.ts +4 -0
  215. package/dist/utils/index.d.ts.map +1 -0
  216. package/dist/utils/index.js +5 -0
  217. package/dist/utils/index.js.map +1 -0
  218. package/dist/utils/interactive.d.ts +18 -0
  219. package/dist/utils/interactive.d.ts.map +1 -0
  220. package/dist/utils/interactive.js +21 -0
  221. package/dist/utils/interactive.js.map +1 -0
  222. package/dist/utils/item-discovery.d.ts +4 -0
  223. package/dist/utils/item-discovery.d.ts.map +1 -0
  224. package/dist/utils/item-discovery.js +72 -0
  225. package/dist/utils/item-discovery.js.map +1 -0
  226. package/dist/utils/match.d.ts +3 -0
  227. package/dist/utils/match.d.ts.map +1 -0
  228. package/dist/utils/match.js +22 -0
  229. package/dist/utils/match.js.map +1 -0
  230. package/dist/utils/shell-detection.d.ts +20 -0
  231. package/dist/utils/shell-detection.d.ts.map +1 -0
  232. package/dist/utils/shell-detection.js +41 -0
  233. package/dist/utils/shell-detection.js.map +1 -0
  234. package/dist/utils/task-progress.d.ts +8 -0
  235. package/dist/utils/task-progress.d.ts.map +1 -0
  236. package/dist/utils/task-progress.js +36 -0
  237. package/dist/utils/task-progress.js.map +1 -0
  238. package/docs/tasks.md +1 -1
  239. package/package.json +6 -2
  240. package/prompt/apply.md +17 -0
  241. package/prompt/archive.md +21 -0
  242. package/prompt/proposal.md +22 -0
  243. package/src/cli/index.ts +151 -16
  244. package/src/commands/archive.ts +302 -0
  245. package/src/commands/change.ts +292 -0
  246. package/src/commands/config.ts +233 -0
  247. package/src/commands/guide.ts +5 -0
  248. package/src/commands/list.ts +176 -66
  249. package/src/commands/show.ts +138 -0
  250. package/src/commands/spec.ts +251 -0
  251. package/src/commands/validate.ts +326 -0
  252. package/src/core/artifact-graph/graph.ts +167 -0
  253. package/src/core/artifact-graph/index.ts +44 -0
  254. package/src/core/artifact-graph/instruction-loader.ts +302 -0
  255. package/src/core/artifact-graph/resolver.ts +226 -0
  256. package/src/core/artifact-graph/schema.ts +124 -0
  257. package/src/core/artifact-graph/state.ts +64 -0
  258. package/src/core/artifact-graph/types.ts +65 -0
  259. package/src/core/completions/command-registry.ts +382 -0
  260. package/src/core/completions/completion-provider.ts +128 -0
  261. package/src/core/completions/generators/bash-generator.ts +191 -0
  262. package/src/core/completions/generators/fish-generator.ts +188 -0
  263. package/src/core/completions/generators/powershell-generator.ts +223 -0
  264. package/src/core/completions/generators/zsh-generator.ts +281 -0
  265. package/src/core/completions/templates/bash-templates.ts +24 -0
  266. package/src/core/completions/templates/fish-templates.ts +40 -0
  267. package/src/core/completions/templates/powershell-templates.ts +25 -0
  268. package/src/core/completions/templates/zsh-templates.ts +36 -0
  269. package/src/core/completions/types.ts +90 -0
  270. package/src/core/config-schema.ts +230 -0
  271. package/src/core/config.ts +18 -0
  272. package/src/core/configurators/slash/antigravity.ts +6 -0
  273. package/src/core/configurators/slash/base.ts +1 -1
  274. package/src/core/configurators/slash/claude.ts +6 -0
  275. package/src/core/configurators/slash/codex.ts +6 -0
  276. package/src/core/configurators/slash/github-copilot.ts +6 -0
  277. package/src/core/configurators/slash/kilocode.ts +6 -0
  278. package/src/core/configurators/slash/opencode.ts +6 -0
  279. package/src/core/converters/json-converter.ts +62 -0
  280. package/src/core/global-config.ts +136 -0
  281. package/src/core/parsers/change-parser.ts +234 -0
  282. package/src/core/parsers/markdown-parser.ts +237 -0
  283. package/src/core/parsers/requirement-blocks.ts +234 -0
  284. package/src/core/prompt-templates.ts +69 -0
  285. package/src/core/schemas/base.schema.ts +20 -0
  286. package/src/core/schemas/change.schema.ts +42 -0
  287. package/src/core/schemas/index.ts +20 -0
  288. package/src/core/schemas/spec.schema.ts +17 -0
  289. package/src/core/specs-apply.ts +483 -0
  290. package/src/core/styles/palette.ts +8 -0
  291. package/src/core/templates/slash-command-templates.ts +7 -1
  292. package/src/core/validation/constants.ts +48 -0
  293. package/src/core/validation/types.ts +19 -0
  294. package/src/core/validation/validator.ts +449 -0
  295. package/src/core/view.ts +219 -0
  296. package/src/utils/change-metadata.ts +171 -0
  297. package/src/utils/change-utils.ts +131 -0
  298. package/src/utils/file-system.ts +252 -0
  299. package/src/utils/index.ts +12 -0
  300. package/src/utils/interactive.ts +29 -0
  301. package/src/utils/item-discovery.ts +66 -0
  302. package/src/utils/match.ts +26 -0
  303. package/src/utils/shell-detection.ts +62 -0
  304. package/src/utils/task-progress.ts +43 -0
  305. package/dist/commands/ai-humanizer.d.ts +0 -11
  306. package/dist/commands/ai-humanizer.d.ts.map +0 -1
  307. package/dist/commands/ai-humanizer.js +0 -97
  308. package/dist/commands/ai-humanizer.js.map +0 -1
  309. package/dist/commands/api-contract-generator.d.ts +0 -11
  310. package/dist/commands/api-contract-generator.d.ts.map +0 -1
  311. package/dist/commands/api-contract-generator.js +0 -97
  312. package/dist/commands/api-contract-generator.js.map +0 -1
  313. package/dist/commands/design-system.d.ts +0 -11
  314. package/dist/commands/design-system.d.ts.map +0 -1
  315. package/dist/commands/design-system.js +0 -97
  316. package/dist/commands/design-system.js.map +0 -1
  317. package/dist/commands/document-explainer.d.ts +0 -11
  318. package/dist/commands/document-explainer.d.ts.map +0 -1
  319. package/dist/commands/document-explainer.js +0 -97
  320. package/dist/commands/document-explainer.js.map +0 -1
  321. package/dist/commands/epic-generator.d.ts +0 -11
  322. package/dist/commands/epic-generator.d.ts.map +0 -1
  323. package/dist/commands/epic-generator.js +0 -97
  324. package/dist/commands/epic-generator.js.map +0 -1
  325. package/dist/commands/erd-generator.d.ts +0 -11
  326. package/dist/commands/erd-generator.d.ts.map +0 -1
  327. package/dist/commands/erd-generator.js +0 -97
  328. package/dist/commands/erd-generator.js.map +0 -1
  329. package/dist/commands/fsd-generator.d.ts +0 -11
  330. package/dist/commands/fsd-generator.d.ts.map +0 -1
  331. package/dist/commands/fsd-generator.js +0 -97
  332. package/dist/commands/fsd-generator.js.map +0 -1
  333. package/dist/commands/prd-agent-generator.d.ts +0 -11
  334. package/dist/commands/prd-agent-generator.d.ts.map +0 -1
  335. package/dist/commands/prd-agent-generator.js +0 -95
  336. package/dist/commands/prd-agent-generator.js.map +0 -1
  337. package/dist/commands/prd-generator.d.ts +0 -11
  338. package/dist/commands/prd-generator.d.ts.map +0 -1
  339. package/dist/commands/prd-generator.js +0 -97
  340. package/dist/commands/prd-generator.js.map +0 -1
  341. package/dist/commands/product-brief.d.ts +0 -11
  342. package/dist/commands/product-brief.d.ts.map +0 -1
  343. package/dist/commands/product-brief.js +0 -97
  344. package/dist/commands/product-brief.js.map +0 -1
  345. package/dist/commands/skill-creator.d.ts +0 -11
  346. package/dist/commands/skill-creator.d.ts.map +0 -1
  347. package/dist/commands/skill-creator.js +0 -101
  348. package/dist/commands/skill-creator.js.map +0 -1
  349. package/dist/commands/story-generator.d.ts +0 -11
  350. package/dist/commands/story-generator.d.ts.map +0 -1
  351. package/dist/commands/story-generator.js +0 -97
  352. package/dist/commands/story-generator.js.map +0 -1
  353. package/dist/commands/tdd-generator.d.ts +0 -11
  354. package/dist/commands/tdd-generator.d.ts.map +0 -1
  355. package/dist/commands/tdd-generator.js +0 -97
  356. package/dist/commands/tdd-generator.js.map +0 -1
  357. package/dist/commands/tdd-lite-generator.d.ts +0 -11
  358. package/dist/commands/tdd-lite-generator.d.ts.map +0 -1
  359. package/dist/commands/tdd-lite-generator.js +0 -97
  360. package/dist/commands/tdd-lite-generator.js.map +0 -1
  361. package/dist/commands/wireframe-generator.d.ts +0 -11
  362. package/dist/commands/wireframe-generator.d.ts.map +0 -1
  363. package/dist/commands/wireframe-generator.js +0 -97
  364. package/dist/commands/wireframe-generator.js.map +0 -1
  365. package/src/commands/ai-humanizer.ts +0 -118
  366. package/src/commands/api-contract-generator.ts +0 -118
  367. package/src/commands/design-system.ts +0 -118
  368. package/src/commands/document-explainer.ts +0 -118
  369. package/src/commands/epic-generator.ts +0 -118
  370. package/src/commands/erd-generator.ts +0 -118
  371. package/src/commands/fsd-generator.ts +0 -118
  372. package/src/commands/prd-agent-generator.ts +0 -115
  373. package/src/commands/prd-generator.ts +0 -118
  374. package/src/commands/product-brief.ts +0 -118
  375. package/src/commands/skill-creator.ts +0 -123
  376. package/src/commands/story-generator.ts +0 -118
  377. package/src/commands/tdd-generator.ts +0 -118
  378. package/src/commands/tdd-lite-generator.ts +0 -118
  379. package/src/commands/wireframe-generator.ts +0 -118
@@ -0,0 +1,483 @@
1
+ /**
2
+ * Spec Application Logic
3
+ *
4
+ * Extracted from ArchiveCommand to enable standalone spec application.
5
+ * Applies delta specs from a change to main specs without archiving.
6
+ */
7
+
8
+ import { promises as fs } from 'fs';
9
+ import path from 'path';
10
+ import chalk from 'chalk';
11
+ import {
12
+ extractRequirementsSection,
13
+ parseDeltaSpec,
14
+ normalizeRequirementName,
15
+ type RequirementBlock,
16
+ } from './parsers/requirement-blocks.js';
17
+ import { Validator } from './validation/validator.js';
18
+
19
+ // -----------------------------------------------------------------------------
20
+ // Types
21
+ // -----------------------------------------------------------------------------
22
+
23
+ export interface SpecUpdate {
24
+ source: string;
25
+ target: string;
26
+ exists: boolean;
27
+ }
28
+
29
+ export interface ApplyResult {
30
+ capability: string;
31
+ added: number;
32
+ modified: number;
33
+ removed: number;
34
+ renamed: number;
35
+ }
36
+
37
+ export interface SpecsApplyOutput {
38
+ changeName: string;
39
+ capabilities: ApplyResult[];
40
+ totals: {
41
+ added: number;
42
+ modified: number;
43
+ removed: number;
44
+ renamed: number;
45
+ };
46
+ noChanges: boolean;
47
+ }
48
+
49
+ // -----------------------------------------------------------------------------
50
+ // Public API
51
+ // -----------------------------------------------------------------------------
52
+
53
+ /**
54
+ * Find all delta spec files that need to be applied from a change.
55
+ */
56
+ export async function findSpecUpdates(changeDir: string, mainSpecsDir: string): Promise<SpecUpdate[]> {
57
+ const updates: SpecUpdate[] = [];
58
+ const changeSpecsDir = path.join(changeDir, 'specs');
59
+
60
+ try {
61
+ const entries = await fs.readdir(changeSpecsDir, { withFileTypes: true });
62
+
63
+ for (const entry of entries) {
64
+ if (entry.isDirectory()) {
65
+ const specFile = path.join(changeSpecsDir, entry.name, 'spec.md');
66
+ const targetFile = path.join(mainSpecsDir, entry.name, 'spec.md');
67
+
68
+ try {
69
+ await fs.access(specFile);
70
+
71
+ // Check if target exists
72
+ let exists = false;
73
+ try {
74
+ await fs.access(targetFile);
75
+ exists = true;
76
+ } catch {
77
+ exists = false;
78
+ }
79
+
80
+ updates.push({
81
+ source: specFile,
82
+ target: targetFile,
83
+ exists,
84
+ });
85
+ } catch {
86
+ // Source spec doesn't exist, skip
87
+ }
88
+ }
89
+ }
90
+ } catch {
91
+ // No specs directory in change
92
+ }
93
+
94
+ return updates;
95
+ }
96
+
97
+ /**
98
+ * Build an updated spec by applying delta operations.
99
+ * Returns the rebuilt content and counts of operations.
100
+ */
101
+ export async function buildUpdatedSpec(
102
+ update: SpecUpdate,
103
+ changeName: string
104
+ ): Promise<{ rebuilt: string; counts: { added: number; modified: number; removed: number; renamed: number } }> {
105
+ // Read change spec content (delta-format expected)
106
+ const changeContent = await fs.readFile(update.source, 'utf-8');
107
+
108
+ // Parse deltas from the change spec file
109
+ const plan = parseDeltaSpec(changeContent);
110
+ const specName = path.basename(path.dirname(update.target));
111
+
112
+ // Pre-validate duplicates within sections
113
+ const addedNames = new Set<string>();
114
+ for (const add of plan.added) {
115
+ const name = normalizeRequirementName(add.name);
116
+ if (addedNames.has(name)) {
117
+ throw new Error(
118
+ `${specName} validation failed - duplicate requirement in ADDED for header "### Requirement: ${add.name}"`
119
+ );
120
+ }
121
+ addedNames.add(name);
122
+ }
123
+ const modifiedNames = new Set<string>();
124
+ for (const mod of plan.modified) {
125
+ const name = normalizeRequirementName(mod.name);
126
+ if (modifiedNames.has(name)) {
127
+ throw new Error(
128
+ `${specName} validation failed - duplicate requirement in MODIFIED for header "### Requirement: ${mod.name}"`
129
+ );
130
+ }
131
+ modifiedNames.add(name);
132
+ }
133
+ const removedNamesSet = new Set<string>();
134
+ for (const rem of plan.removed) {
135
+ const name = normalizeRequirementName(rem);
136
+ if (removedNamesSet.has(name)) {
137
+ throw new Error(
138
+ `${specName} validation failed - duplicate requirement in REMOVED for header "### Requirement: ${rem}"`
139
+ );
140
+ }
141
+ removedNamesSet.add(name);
142
+ }
143
+ const renamedFromSet = new Set<string>();
144
+ const renamedToSet = new Set<string>();
145
+ for (const { from, to } of plan.renamed) {
146
+ const fromNorm = normalizeRequirementName(from);
147
+ const toNorm = normalizeRequirementName(to);
148
+ if (renamedFromSet.has(fromNorm)) {
149
+ throw new Error(
150
+ `${specName} validation failed - duplicate FROM in RENAMED for header "### Requirement: ${from}"`
151
+ );
152
+ }
153
+ if (renamedToSet.has(toNorm)) {
154
+ throw new Error(
155
+ `${specName} validation failed - duplicate TO in RENAMED for header "### Requirement: ${to}"`
156
+ );
157
+ }
158
+ renamedFromSet.add(fromNorm);
159
+ renamedToSet.add(toNorm);
160
+ }
161
+
162
+ // Pre-validate cross-section conflicts
163
+ const conflicts: Array<{ name: string; a: string; b: string }> = [];
164
+ for (const n of modifiedNames) {
165
+ if (removedNamesSet.has(n)) conflicts.push({ name: n, a: 'MODIFIED', b: 'REMOVED' });
166
+ if (addedNames.has(n)) conflicts.push({ name: n, a: 'MODIFIED', b: 'ADDED' });
167
+ }
168
+ for (const n of addedNames) {
169
+ if (removedNamesSet.has(n)) conflicts.push({ name: n, a: 'ADDED', b: 'REMOVED' });
170
+ }
171
+ // Renamed interplay: MODIFIED must reference the NEW header, not FROM
172
+ for (const { from, to } of plan.renamed) {
173
+ const fromNorm = normalizeRequirementName(from);
174
+ const toNorm = normalizeRequirementName(to);
175
+ if (modifiedNames.has(fromNorm)) {
176
+ throw new Error(
177
+ `${specName} validation failed - when a rename exists, MODIFIED must reference the NEW header "### Requirement: ${to}"`
178
+ );
179
+ }
180
+ // Detect ADDED colliding with a RENAMED TO
181
+ if (addedNames.has(toNorm)) {
182
+ throw new Error(
183
+ `${specName} validation failed - RENAMED TO header collides with ADDED for "### Requirement: ${to}"`
184
+ );
185
+ }
186
+ }
187
+ if (conflicts.length > 0) {
188
+ const c = conflicts[0];
189
+ throw new Error(
190
+ `${specName} validation failed - requirement present in multiple sections (${c.a} and ${c.b}) for header "### Requirement: ${c.name}"`
191
+ );
192
+ }
193
+ const hasAnyDelta = plan.added.length + plan.modified.length + plan.removed.length + plan.renamed.length > 0;
194
+ if (!hasAnyDelta) {
195
+ throw new Error(
196
+ `Delta parsing found no operations for ${path.basename(path.dirname(update.source))}. ` +
197
+ `Provide ADDED/MODIFIED/REMOVED/RENAMED sections in change spec.`
198
+ );
199
+ }
200
+
201
+ // Load or create base target content
202
+ let targetContent: string;
203
+ let isNewSpec = false;
204
+ try {
205
+ targetContent = await fs.readFile(update.target, 'utf-8');
206
+ } catch {
207
+ // Target spec does not exist; MODIFIED and RENAMED are not allowed for new specs
208
+ // REMOVED will be ignored with a warning since there's nothing to remove
209
+ if (plan.modified.length > 0 || plan.renamed.length > 0) {
210
+ throw new Error(
211
+ `${specName}: target spec does not exist; only ADDED requirements are allowed for new specs. MODIFIED and RENAMED operations require an existing spec.`
212
+ );
213
+ }
214
+ // Warn about REMOVED requirements being ignored for new specs
215
+ if (plan.removed.length > 0) {
216
+ console.log(
217
+ chalk.yellow(
218
+ `⚠️ Warning: ${specName} - ${plan.removed.length} REMOVED requirement(s) ignored for new spec (nothing to remove).`
219
+ )
220
+ );
221
+ }
222
+ isNewSpec = true;
223
+ targetContent = buildSpecSkeleton(specName, changeName);
224
+ }
225
+
226
+ // Extract requirements section and build name->block map
227
+ const parts = extractRequirementsSection(targetContent);
228
+ const nameToBlock = new Map<string, RequirementBlock>();
229
+ for (const block of parts.bodyBlocks) {
230
+ nameToBlock.set(normalizeRequirementName(block.name), block);
231
+ }
232
+
233
+ // Apply operations in order: RENAMED → REMOVED → MODIFIED → ADDED
234
+ // RENAMED
235
+ for (const r of plan.renamed) {
236
+ const from = normalizeRequirementName(r.from);
237
+ const to = normalizeRequirementName(r.to);
238
+ if (!nameToBlock.has(from)) {
239
+ throw new Error(`${specName} RENAMED failed for header "### Requirement: ${r.from}" - source not found`);
240
+ }
241
+ if (nameToBlock.has(to)) {
242
+ throw new Error(`${specName} RENAMED failed for header "### Requirement: ${r.to}" - target already exists`);
243
+ }
244
+ const block = nameToBlock.get(from)!;
245
+ const newHeader = `### Requirement: ${to}`;
246
+ const rawLines = block.raw.split('\n');
247
+ rawLines[0] = newHeader;
248
+ const renamedBlock: RequirementBlock = {
249
+ headerLine: newHeader,
250
+ name: to,
251
+ raw: rawLines.join('\n'),
252
+ };
253
+ nameToBlock.delete(from);
254
+ nameToBlock.set(to, renamedBlock);
255
+ }
256
+
257
+ // REMOVED
258
+ for (const name of plan.removed) {
259
+ const key = normalizeRequirementName(name);
260
+ if (!nameToBlock.has(key)) {
261
+ // For new specs, REMOVED requirements are already warned about and ignored
262
+ // For existing specs, missing requirements are an error
263
+ if (!isNewSpec) {
264
+ throw new Error(`${specName} REMOVED failed for header "### Requirement: ${name}" - not found`);
265
+ }
266
+ // Skip removal for new specs (already warned above)
267
+ continue;
268
+ }
269
+ nameToBlock.delete(key);
270
+ }
271
+
272
+ // MODIFIED
273
+ for (const mod of plan.modified) {
274
+ const key = normalizeRequirementName(mod.name);
275
+ if (!nameToBlock.has(key)) {
276
+ throw new Error(`${specName} MODIFIED failed for header "### Requirement: ${mod.name}" - not found`);
277
+ }
278
+ // Replace block with provided raw (ensure header line matches key)
279
+ const modHeaderMatch = mod.raw.split('\n')[0].match(/^###\s*Requirement:\s*(.+)\s*$/);
280
+ if (!modHeaderMatch || normalizeRequirementName(modHeaderMatch[1]) !== key) {
281
+ throw new Error(
282
+ `${specName} MODIFIED failed for header "### Requirement: ${mod.name}" - header mismatch in content`
283
+ );
284
+ }
285
+ nameToBlock.set(key, mod);
286
+ }
287
+
288
+ // ADDED
289
+ for (const add of plan.added) {
290
+ const key = normalizeRequirementName(add.name);
291
+ if (nameToBlock.has(key)) {
292
+ throw new Error(`${specName} ADDED failed for header "### Requirement: ${add.name}" - already exists`);
293
+ }
294
+ nameToBlock.set(key, add);
295
+ }
296
+
297
+ // Duplicates within resulting map are implicitly prevented by key uniqueness.
298
+
299
+ // Recompose requirements section preserving original ordering where possible
300
+ const keptOrder: RequirementBlock[] = [];
301
+ const seen = new Set<string>();
302
+ for (const block of parts.bodyBlocks) {
303
+ const key = normalizeRequirementName(block.name);
304
+ const replacement = nameToBlock.get(key);
305
+ if (replacement) {
306
+ keptOrder.push(replacement);
307
+ seen.add(key);
308
+ }
309
+ }
310
+ // Append any newly added that were not in original order
311
+ for (const [key, block] of nameToBlock.entries()) {
312
+ if (!seen.has(key)) {
313
+ keptOrder.push(block);
314
+ }
315
+ }
316
+
317
+ const reqBody = [parts.preamble && parts.preamble.trim() ? parts.preamble.trimEnd() : '']
318
+ .filter(Boolean)
319
+ .concat(keptOrder.map((b) => b.raw))
320
+ .join('\n\n')
321
+ .trimEnd();
322
+
323
+ const rebuilt = [parts.before.trimEnd(), parts.headerLine, reqBody, parts.after]
324
+ .filter((s, idx) => !(idx === 0 && s === ''))
325
+ .join('\n')
326
+ .replace(/\n{3,}/g, '\n\n');
327
+
328
+ return {
329
+ rebuilt,
330
+ counts: {
331
+ added: plan.added.length,
332
+ modified: plan.modified.length,
333
+ removed: plan.removed.length,
334
+ renamed: plan.renamed.length,
335
+ },
336
+ };
337
+ }
338
+
339
+ /**
340
+ * Write an updated spec to disk.
341
+ */
342
+ export async function writeUpdatedSpec(
343
+ update: SpecUpdate,
344
+ rebuilt: string,
345
+ counts: { added: number; modified: number; removed: number; renamed: number }
346
+ ): Promise<void> {
347
+ // Create target directory if needed
348
+ const targetDir = path.dirname(update.target);
349
+ await fs.mkdir(targetDir, { recursive: true });
350
+ await fs.writeFile(update.target, rebuilt);
351
+
352
+ const specName = path.basename(path.dirname(update.target));
353
+ console.log(`Applying changes to prompter/specs/${specName}/spec.md:`);
354
+ if (counts.added) console.log(` + ${counts.added} added`);
355
+ if (counts.modified) console.log(` ~ ${counts.modified} modified`);
356
+ if (counts.removed) console.log(` - ${counts.removed} removed`);
357
+ if (counts.renamed) console.log(` → ${counts.renamed} renamed`);
358
+ }
359
+
360
+ /**
361
+ * Build a skeleton spec for new capabilities.
362
+ */
363
+ export function buildSpecSkeleton(specFolderName: string, changeName: string): string {
364
+ const titleBase = specFolderName;
365
+ return `# ${titleBase} Specification\n\n## Purpose\nTBD - created by archiving change ${changeName}. Update Purpose after archive.\n\n## Requirements\n`;
366
+ }
367
+
368
+ /**
369
+ * Apply all delta specs from a change to main specs.
370
+ *
371
+ * @param projectRoot - The project root directory
372
+ * @param changeName - The name of the change to apply
373
+ * @param options - Options for the operation
374
+ * @returns Result of the operation with counts
375
+ */
376
+ export async function applySpecs(
377
+ projectRoot: string,
378
+ changeName: string,
379
+ options: {
380
+ dryRun?: boolean;
381
+ skipValidation?: boolean;
382
+ silent?: boolean;
383
+ } = {}
384
+ ): Promise<SpecsApplyOutput> {
385
+ const changeDir = path.join(projectRoot, 'prompter', 'changes', changeName);
386
+ const mainSpecsDir = path.join(projectRoot, 'prompter', 'specs');
387
+
388
+ // Verify change exists
389
+ try {
390
+ const stat = await fs.stat(changeDir);
391
+ if (!stat.isDirectory()) {
392
+ throw new Error(`Change '${changeName}' not found.`);
393
+ }
394
+ } catch {
395
+ throw new Error(`Change '${changeName}' not found.`);
396
+ }
397
+
398
+ // Find specs to update
399
+ const specUpdates = await findSpecUpdates(changeDir, mainSpecsDir);
400
+
401
+ if (specUpdates.length === 0) {
402
+ return {
403
+ changeName,
404
+ capabilities: [],
405
+ totals: { added: 0, modified: 0, removed: 0, renamed: 0 },
406
+ noChanges: true,
407
+ };
408
+ }
409
+
410
+ // Prepare all updates first (validation pass, no writes)
411
+ const prepared: Array<{
412
+ update: SpecUpdate;
413
+ rebuilt: string;
414
+ counts: { added: number; modified: number; removed: number; renamed: number };
415
+ }> = [];
416
+
417
+ for (const update of specUpdates) {
418
+ const built = await buildUpdatedSpec(update, changeName);
419
+ prepared.push({ update, rebuilt: built.rebuilt, counts: built.counts });
420
+ }
421
+
422
+ // Validate rebuilt specs unless validation is skipped
423
+ if (!options.skipValidation) {
424
+ const validator = new Validator();
425
+ for (const p of prepared) {
426
+ const specName = path.basename(path.dirname(p.update.target));
427
+ const report = await validator.validateSpecContent(specName, p.rebuilt);
428
+ if (!report.valid) {
429
+ const errors = report.issues
430
+ .filter((i) => i.level === 'ERROR')
431
+ .map((i) => ` ✗ ${i.message}`)
432
+ .join('\n');
433
+ throw new Error(`Validation errors in rebuilt spec for ${specName}:\n${errors}`);
434
+ }
435
+ }
436
+ }
437
+
438
+ // Build results
439
+ const capabilities: ApplyResult[] = [];
440
+ const totals = { added: 0, modified: 0, removed: 0, renamed: 0 };
441
+
442
+ for (const p of prepared) {
443
+ const capability = path.basename(path.dirname(p.update.target));
444
+
445
+ if (!options.dryRun) {
446
+ // Write the updated spec
447
+ const targetDir = path.dirname(p.update.target);
448
+ await fs.mkdir(targetDir, { recursive: true });
449
+ await fs.writeFile(p.update.target, p.rebuilt);
450
+
451
+ if (!options.silent) {
452
+ console.log(`Applying changes to prompter/specs/${capability}/spec.md:`);
453
+ if (p.counts.added) console.log(` + ${p.counts.added} added`);
454
+ if (p.counts.modified) console.log(` ~ ${p.counts.modified} modified`);
455
+ if (p.counts.removed) console.log(` - ${p.counts.removed} removed`);
456
+ if (p.counts.renamed) console.log(` → ${p.counts.renamed} renamed`);
457
+ }
458
+ } else if (!options.silent) {
459
+ console.log(`Would apply changes to prompter/specs/${capability}/spec.md:`);
460
+ if (p.counts.added) console.log(` + ${p.counts.added} added`);
461
+ if (p.counts.modified) console.log(` ~ ${p.counts.modified} modified`);
462
+ if (p.counts.removed) console.log(` - ${p.counts.removed} removed`);
463
+ if (p.counts.renamed) console.log(` → ${p.counts.renamed} renamed`);
464
+ }
465
+
466
+ capabilities.push({
467
+ capability,
468
+ ...p.counts,
469
+ });
470
+
471
+ totals.added += p.counts.added;
472
+ totals.modified += p.counts.modified;
473
+ totals.removed += p.counts.removed;
474
+ totals.renamed += p.counts.renamed;
475
+ }
476
+
477
+ return {
478
+ changeName,
479
+ capabilities,
480
+ totals,
481
+ noChanges: false,
482
+ };
483
+ }
@@ -0,0 +1,8 @@
1
+ import chalk from 'chalk';
2
+
3
+ export const PALETTE = {
4
+ white: chalk.hex('#f4f4f4'),
5
+ lightGray: chalk.hex('#c8c8c8'),
6
+ midGray: chalk.hex('#8a8a8a'),
7
+ darkGray: chalk.hex('#4a4a4a')
8
+ };
@@ -1,9 +1,12 @@
1
1
  import {
2
2
  API_CONTRACT_GENERATOR_TEMPLATE,
3
+ APPLY_TEMPLATE,
4
+ ARCHIVE_TEMPLATE,
3
5
  DESIGN_SYSTEM_TEMPLATE,
4
6
  EPIC_GENERATOR_TEMPLATE,
5
7
  ERD_GENERATOR_TEMPLATE,
6
8
  FSD_GENERATOR_TEMPLATE,
9
+ PROPOSAL_TEMPLATE,
7
10
  STORY_GENERATOR_TEMPLATE,
8
11
  TDD_GENERATOR_TEMPLATE,
9
12
  TDD_LITE_GENERATOR_TEMPLATE,
@@ -11,7 +14,7 @@ import {
11
14
  DOCUMENT_EXPLAINER_TEMPLATE
12
15
  } from '../prompt-templates.js';
13
16
 
14
- export type SlashCommandId = 'enhance' | 'prd-generator' | 'prd-agent-generator' | 'product-brief' | 'epic-single' | 'epic-generator' | 'story-single' | 'story-generator' | 'qa-test-scenario' | 'skill-creator' | 'ai-humanizer' | 'api-contract-generator' | 'design-system' | 'erd-generator' | 'fsd-generator' | 'tdd-generator' | 'tdd-lite-generator' | 'wireframe-generator' | 'document-explainer';
17
+ export type SlashCommandId = 'enhance' | 'prd-generator' | 'prd-agent-generator' | 'product-brief' | 'epic-single' | 'epic-generator' | 'story-single' | 'story-generator' | 'qa-test-scenario' | 'skill-creator' | 'ai-humanizer' | 'api-contract-generator' | 'apply' | 'archive' | 'design-system' | 'erd-generator' | 'fsd-generator' | 'proposal' | 'tdd-generator' | 'tdd-lite-generator' | 'wireframe-generator' | 'document-explainer';
15
18
 
16
19
  const enhanceWorkflow = `## MUST FOLLOW
17
20
  - Response Language: {User Request Language}
@@ -1042,9 +1045,12 @@ export const slashCommandBodies: Record<SlashCommandId, string> = {
1042
1045
  'skill-creator': skillCreatorWorkflow,
1043
1046
  'ai-humanizer': aiHumanizerWorkflow,
1044
1047
  'api-contract-generator': API_CONTRACT_GENERATOR_TEMPLATE,
1048
+ 'apply': APPLY_TEMPLATE,
1049
+ 'archive': ARCHIVE_TEMPLATE,
1045
1050
  'design-system': DESIGN_SYSTEM_TEMPLATE,
1046
1051
  'erd-generator': ERD_GENERATOR_TEMPLATE,
1047
1052
  'fsd-generator': FSD_GENERATOR_TEMPLATE,
1053
+ 'proposal': PROPOSAL_TEMPLATE,
1048
1054
  'tdd-generator': TDD_GENERATOR_TEMPLATE,
1049
1055
  'tdd-lite-generator': TDD_LITE_GENERATOR_TEMPLATE,
1050
1056
  'wireframe-generator': WIREFRAME_GENERATOR_TEMPLATE,
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Validation threshold constants
3
+ */
4
+
5
+ // Minimum character lengths
6
+ export const MIN_WHY_SECTION_LENGTH = 50;
7
+ export const MIN_PURPOSE_LENGTH = 50;
8
+
9
+ // Maximum character/item limits
10
+ export const MAX_WHY_SECTION_LENGTH = 1000;
11
+ export const MAX_REQUIREMENT_TEXT_LENGTH = 500;
12
+ export const MAX_DELTAS_PER_CHANGE = 10;
13
+
14
+ // Validation messages
15
+ export const VALIDATION_MESSAGES = {
16
+ // Required content
17
+ SCENARIO_EMPTY: 'Scenario text cannot be empty',
18
+ REQUIREMENT_EMPTY: 'Requirement text cannot be empty',
19
+ REQUIREMENT_NO_SHALL: 'Requirement must contain SHALL or MUST keyword',
20
+ REQUIREMENT_NO_SCENARIOS: 'Requirement must have at least one scenario',
21
+ SPEC_NAME_EMPTY: 'Spec name cannot be empty',
22
+ SPEC_PURPOSE_EMPTY: 'Purpose section cannot be empty',
23
+ SPEC_NO_REQUIREMENTS: 'Spec must have at least one requirement',
24
+ CHANGE_NAME_EMPTY: 'Change name cannot be empty',
25
+ CHANGE_WHY_TOO_SHORT: `Why section must be at least ${MIN_WHY_SECTION_LENGTH} characters`,
26
+ CHANGE_WHY_TOO_LONG: `Why section should not exceed ${MAX_WHY_SECTION_LENGTH} characters`,
27
+ CHANGE_WHAT_EMPTY: 'What Changes section cannot be empty',
28
+ CHANGE_NO_DELTAS: 'Change must have at least one delta',
29
+ CHANGE_TOO_MANY_DELTAS: `Consider splitting changes with more than ${MAX_DELTAS_PER_CHANGE} deltas`,
30
+ DELTA_SPEC_EMPTY: 'Spec name cannot be empty',
31
+ DELTA_DESCRIPTION_EMPTY: 'Delta description cannot be empty',
32
+
33
+ // Warnings
34
+ PURPOSE_TOO_BRIEF: `Purpose section is too brief (less than ${MIN_PURPOSE_LENGTH} characters)`,
35
+ REQUIREMENT_TOO_LONG: `Requirement text is very long (>${MAX_REQUIREMENT_TEXT_LENGTH} characters). Consider breaking it down.`,
36
+ DELTA_DESCRIPTION_TOO_BRIEF: 'Delta description is too brief',
37
+ DELTA_MISSING_REQUIREMENTS: 'Delta should include requirements',
38
+
39
+ // Guidance snippets (appended to primary messages for remediation)
40
+ GUIDE_NO_DELTAS:
41
+ 'No deltas found. Ensure your change has a specs/ directory with capability folders (e.g. specs/http-server/spec.md) containing .md files that use delta headers (## ADDED/MODIFIED/REMOVED/RENAMED Requirements) and that each requirement includes at least one "#### Scenario:" block. Tip: run "prompter change show <change-id> --json --deltas-only" to inspect parsed deltas.',
42
+ GUIDE_MISSING_SPEC_SECTIONS:
43
+ 'Missing required sections. Expected headers: "## Purpose" and "## Requirements". Example:\n## Purpose\n[brief purpose]\n\n## Requirements\n### Requirement: Clear requirement statement\nUsers SHALL ...\n\n#### Scenario: Descriptive name\n- **WHEN** ...\n- **THEN** ...',
44
+ GUIDE_MISSING_CHANGE_SECTIONS:
45
+ 'Missing required sections. Expected headers: "## Why" and "## What Changes". Ensure deltas are documented in specs/ using delta headers.',
46
+ GUIDE_SCENARIO_FORMAT:
47
+ 'Scenarios must use level-4 headers. Convert bullet lists into:\n#### Scenario: Short name\n- **WHEN** ...\n- **THEN** ...\n- **AND** ...',
48
+ } as const;
@@ -0,0 +1,19 @@
1
+ export type ValidationLevel = 'ERROR' | 'WARNING' | 'INFO';
2
+
3
+ export interface ValidationIssue {
4
+ level: ValidationLevel;
5
+ path: string;
6
+ message: string;
7
+ line?: number;
8
+ column?: number;
9
+ }
10
+
11
+ export interface ValidationReport {
12
+ valid: boolean;
13
+ issues: ValidationIssue[];
14
+ summary: {
15
+ errors: number;
16
+ warnings: number;
17
+ info: number;
18
+ };
19
+ }