@educa-corp/sdd-framework 0.1.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 (382) hide show
  1. package/bin/build.js +230 -0
  2. package/bin/index.js +609 -0
  3. package/commands/debug.md +835 -0
  4. package/commands/debug.tmpl +257 -0
  5. package/commands/define-product.md +746 -0
  6. package/commands/define-product.tmpl +191 -0
  7. package/commands/dev-gen-test.md +1015 -0
  8. package/commands/dev-gen-test.tmpl +490 -0
  9. package/commands/dev-run-test.md +749 -0
  10. package/commands/dev-run-test.tmpl +224 -0
  11. package/commands/dev-smoke-test.md +716 -0
  12. package/commands/dev-smoke-test.tmpl +217 -0
  13. package/commands/fix-bug.md +749 -0
  14. package/commands/fix-bug.tmpl +171 -0
  15. package/commands/generate-bdd.md +1144 -0
  16. package/commands/generate-bdd.tmpl +499 -0
  17. package/commands/generate-code.md +1038 -0
  18. package/commands/generate-code.tmpl +513 -0
  19. package/commands/generate-design-spec.md +1079 -0
  20. package/commands/generate-design-spec.tmpl +524 -0
  21. package/commands/generate-prd.md +945 -0
  22. package/commands/generate-prd.tmpl +166 -0
  23. package/commands/generate-spec-manifest.md +663 -0
  24. package/commands/generate-spec-manifest.tmpl +164 -0
  25. package/commands/generate-tech-docs.md +1249 -0
  26. package/commands/generate-tech-docs.tmpl +252 -0
  27. package/commands/learn.md +641 -0
  28. package/commands/learn.tmpl +63 -0
  29. package/commands/map-testids.md +580 -0
  30. package/commands/map-testids.tmpl +81 -0
  31. package/commands/propose-scenario.md +632 -0
  32. package/commands/propose-scenario.tmpl +133 -0
  33. package/commands/qc-analyze.md +611 -0
  34. package/commands/qc-analyze.tmpl +112 -0
  35. package/commands/qc-design-test.md +567 -0
  36. package/commands/qc-design-test.tmpl +68 -0
  37. package/commands/qc-plan.md +548 -0
  38. package/commands/qc-plan.tmpl +49 -0
  39. package/commands/qc-report.md +559 -0
  40. package/commands/qc-report.tmpl +60 -0
  41. package/commands/qc-review.md +552 -0
  42. package/commands/qc-review.tmpl +53 -0
  43. package/commands/qc-run-test.md +609 -0
  44. package/commands/qc-run-test.tmpl +84 -0
  45. package/commands/refine-prd.md +992 -0
  46. package/commands/refine-prd.tmpl +278 -0
  47. package/commands/report-bug.md +647 -0
  48. package/commands/report-bug.tmpl +148 -0
  49. package/commands/review-code.md +682 -0
  50. package/commands/review-code.tmpl +104 -0
  51. package/commands/review-context.md +1202 -0
  52. package/commands/review-context.tmpl +488 -0
  53. package/commands/review-tech-docs.md +871 -0
  54. package/commands/review-tech-docs.tmpl +372 -0
  55. package/commands/setup-ai-first.md +546 -0
  56. package/commands/setup-ai-first.tmpl +358 -0
  57. package/commands/sync.md +451 -0
  58. package/commands/sync.tmpl +351 -0
  59. package/commands/update-framework.md +251 -0
  60. package/commands/update-framework.tmpl +151 -0
  61. package/commands/validate-traces.md +928 -0
  62. package/commands/validate-traces.tmpl +429 -0
  63. package/core/FRAMEWORK_VERSION +1 -0
  64. package/core/commands/debug.md +835 -0
  65. package/core/commands/define-product.md +746 -0
  66. package/core/commands/dev-gen-test.md +1015 -0
  67. package/core/commands/dev-run-test.md +749 -0
  68. package/core/commands/dev-smoke-test.md +716 -0
  69. package/core/commands/fix-bug.md +749 -0
  70. package/core/commands/generate-bdd.md +1144 -0
  71. package/core/commands/generate-code.md +1038 -0
  72. package/core/commands/generate-design-spec.md +1079 -0
  73. package/core/commands/generate-prd.md +945 -0
  74. package/core/commands/generate-spec-manifest.md +663 -0
  75. package/core/commands/generate-tech-docs.md +1249 -0
  76. package/core/commands/learn.md +641 -0
  77. package/core/commands/map-testids.md +580 -0
  78. package/core/commands/propose-scenario.md +632 -0
  79. package/core/commands/qc-analyze.md +611 -0
  80. package/core/commands/qc-design-test.md +567 -0
  81. package/core/commands/qc-plan.md +548 -0
  82. package/core/commands/qc-report.md +559 -0
  83. package/core/commands/qc-review.md +552 -0
  84. package/core/commands/qc-run-test.md +609 -0
  85. package/core/commands/refine-prd.md +992 -0
  86. package/core/commands/report-bug.md +647 -0
  87. package/core/commands/review-code.md +682 -0
  88. package/core/commands/review-context.md +1202 -0
  89. package/core/commands/review-tech-docs.md +871 -0
  90. package/core/commands/setup-ai-first.md +546 -0
  91. package/core/commands/sync.md +451 -0
  92. package/core/commands/update-framework.md +251 -0
  93. package/core/commands/validate-traces.md +928 -0
  94. package/core/hooks/data-guard.js +141 -0
  95. package/core/hooks/settings.json +18 -0
  96. package/core/modules/android-compose/module.yaml +13 -0
  97. package/core/modules/android-compose/stack-profile.yaml +57 -0
  98. package/core/modules/angular/architecture-snippets/component-patterns.md +187 -0
  99. package/core/modules/angular/module.yaml +6 -0
  100. package/core/modules/angular/stack-profile.yaml +38 -0
  101. package/core/modules/context-engineering/architecture-snippets/context-design.md +119 -0
  102. package/core/modules/context-engineering/module.yaml +9 -0
  103. package/core/modules/context-engineering/stack-profile.yaml +61 -0
  104. package/core/modules/dotnet/architecture-snippets/clean-arch.md +160 -0
  105. package/core/modules/dotnet/module.yaml +6 -0
  106. package/core/modules/dotnet/stack-profile.yaml +50 -0
  107. package/core/modules/flutter/module.yaml +14 -0
  108. package/core/modules/flutter/stack-profile.yaml +59 -0
  109. package/core/modules/golang/architecture-snippets/domain-layout.md +283 -0
  110. package/core/modules/golang/module.yaml +6 -0
  111. package/core/modules/golang/stack-profile.yaml +40 -0
  112. package/core/modules/ios-swiftui/module.yaml +13 -0
  113. package/core/modules/ios-swiftui/stack-profile.yaml +55 -0
  114. package/core/modules/java-spring/architecture-snippets/layered-arch.md +201 -0
  115. package/core/modules/java-spring/module.yaml +15 -0
  116. package/core/modules/java-spring/stack-profile.yaml +28 -0
  117. package/core/modules/nextjs/architecture-snippets/app-router-patterns.md +269 -0
  118. package/core/modules/nextjs/module.yaml +14 -0
  119. package/core/modules/nextjs/stack-profile.yaml +74 -0
  120. package/core/modules/nuxt/module.yaml +14 -0
  121. package/core/modules/nuxt/stack-profile.yaml +58 -0
  122. package/core/modules/php-laravel/architecture-snippets/service-repository.md +302 -0
  123. package/core/modules/php-laravel/module.yaml +15 -0
  124. package/core/modules/php-laravel/stack-profile.yaml +56 -0
  125. package/core/modules/qc-playwright/stack-profile.yaml +66 -0
  126. package/core/modules/react/architecture-snippets/hooks-query-patterns.md +254 -0
  127. package/core/modules/react/module.yaml +14 -0
  128. package/core/modules/react/stack-profile.yaml +63 -0
  129. package/core/modules/react-native/module.yaml +14 -0
  130. package/core/modules/react-native/stack-profile.yaml +56 -0
  131. package/core/modules/vue/module.yaml +14 -0
  132. package/core/modules/vue/stack-profile.yaml +65 -0
  133. package/core/rules/data-protection.md +80 -0
  134. package/core/rules/workflow.md +44 -0
  135. package/core/skills/code/SKILL.md +19 -0
  136. package/core/skills/debug/SKILL.md +19 -0
  137. package/core/skills/design-spec/SKILL.md +11 -0
  138. package/core/skills/discovery/SKILL.md +14 -0
  139. package/core/skills/prd/SKILL.md +19 -0
  140. package/core/skills/qc/qa-analyst/DOC_GAPS.template.md +63 -0
  141. package/core/skills/qc/qa-analyst/acceptance-criteria.md +60 -0
  142. package/core/skills/qc/qa-analyst/business-rules.md +59 -0
  143. package/core/skills/qc/qa-analyst/data-flow.md +64 -0
  144. package/core/skills/qc/qa-analyst/spec-breakdown.md +61 -0
  145. package/core/skills/qc/qa-designer/e2e/journey.md +41 -0
  146. package/core/skills/qc/qa-designer/exploratory/charter.md +68 -0
  147. package/core/skills/qc/qa-designer/exploratory/explore-to-functional.md +43 -0
  148. package/core/skills/qc/qa-designer/functional/api.md +45 -0
  149. package/core/skills/qc/qa-designer/functional/gui-feature.md +46 -0
  150. package/core/skills/qc/qa-designer/functional/gui-screen.md +52 -0
  151. package/core/skills/qc/qa-designer/integration/api.md +42 -0
  152. package/core/skills/qc/qa-designer/integration/db.md +39 -0
  153. package/core/skills/qc/qa-designer/integration/gui.md +40 -0
  154. package/core/skills/qc/qa-designer/integration/kafka.md +40 -0
  155. package/core/skills/qc/qa-designer/non-functional.md +40 -0
  156. package/core/skills/qc/qa-planner/test-plan.md +120 -0
  157. package/core/skills/qc/qa-reviewer/script/e2e.md +87 -0
  158. package/core/skills/qc/qa-reviewer/script/exploratory.md +45 -0
  159. package/core/skills/qc/qa-reviewer/script/functional.md +101 -0
  160. package/core/skills/qc/qa-reviewer/script/integration.md +91 -0
  161. package/core/skills/qc/qa-reviewer/script/non-functional.md +126 -0
  162. package/core/skills/qc/qa-reviewer/test-case/e2e.md +73 -0
  163. package/core/skills/qc/qa-reviewer/test-case/exploratory.md +43 -0
  164. package/core/skills/qc/qa-reviewer/test-case/functional.md +76 -0
  165. package/core/skills/qc/qa-reviewer/test-case/integration.md +69 -0
  166. package/core/skills/qc/qa-reviewer/test-case/non-functional.md +73 -0
  167. package/core/skills/qc/qa-runner/e2e.md +49 -0
  168. package/core/skills/qc/qa-runner/exploratory/session.md +36 -0
  169. package/core/skills/qc/qa-runner/functional/api.md +35 -0
  170. package/core/skills/qc/qa-runner/functional/gui-feature.md +51 -0
  171. package/core/skills/qc/qa-runner/functional/gui-screen.md +55 -0
  172. package/core/skills/qc/qa-runner/integration.md +47 -0
  173. package/core/skills/qc/qa-runner/non-functional.md +49 -0
  174. package/core/skills/qc/qa-runner/report/report.md +37 -0
  175. package/core/skills/setup-ai-first/SKILL.md +11 -0
  176. package/core/skills/spec/SKILL.md +19 -0
  177. package/core/skills/test/SKILL.md +18 -0
  178. package/core/steps/business-language.md +56 -0
  179. package/core/steps/capture-lesson.md +79 -0
  180. package/core/steps/context-loader.md +311 -0
  181. package/core/steps/gate.md +88 -0
  182. package/core/steps/report-footer.md +100 -0
  183. package/core/steps/review-fanout.md +159 -0
  184. package/core/steps/spawn-agent.md +129 -0
  185. package/core/steps/trace-mirror.md +26 -0
  186. package/core/templates/architecture.template.md +113 -0
  187. package/core/templates/design-spec.template.md +217 -0
  188. package/core/templates/feature.template +120 -0
  189. package/core/templates/platform-guide.template.md +145 -0
  190. package/core/templates/prd.template.md +224 -0
  191. package/core/templates/product-definition.template.md +188 -0
  192. package/core/templates/project-context.yaml +161 -0
  193. package/core/templates/tech-design.template.md +498 -0
  194. package/docs/01-getting-started/README.md +19 -0
  195. package/docs/01-getting-started/core-concepts.md +102 -0
  196. package/docs/01-getting-started/installation.md +156 -0
  197. package/docs/01-getting-started/quickstart.md +86 -0
  198. package/docs/02-guides/README.md +26 -0
  199. package/docs/02-guides/bdd-input-checklist.md +68 -0
  200. package/docs/02-guides/developer/README.md +49 -0
  201. package/docs/02-guides/developer/bdd-and-trace.md +126 -0
  202. package/docs/02-guides/developer/commands.md +76 -0
  203. package/docs/02-guides/developer/pr-checklist.md +16 -0
  204. package/docs/02-guides/developer/scenarios.md +460 -0
  205. package/docs/02-guides/developer/workflow.md +121 -0
  206. package/docs/02-guides/prd-input-checklist.md +94 -0
  207. package/docs/02-guides/product-owner/README.md +81 -0
  208. package/docs/02-guides/product-owner/commands.md +30 -0
  209. package/docs/02-guides/product-owner/handoff-checklist.md +42 -0
  210. package/docs/02-guides/product-owner/prd-writing-rules.md +45 -0
  211. package/docs/02-guides/product-owner/scenarios.md +438 -0
  212. package/docs/02-guides/tech-docs-input-checklist.md +109 -0
  213. package/docs/02-guides/tester/README.md +75 -0
  214. package/docs/02-guides/tester/bug-reporting.md +117 -0
  215. package/docs/02-guides/tester/qc-automation.md +165 -0
  216. package/docs/02-guides/tester/reading-specs.md +79 -0
  217. package/docs/02-guides/tester/scenarios.md +186 -0
  218. package/docs/02-guides/tester/spec-manifest.md +130 -0
  219. package/docs/02-guides/tester/test-checklist.md +31 -0
  220. package/docs/02-guides/tester/workflow.md +77 -0
  221. package/docs/03-concepts/README.md +20 -0
  222. package/docs/03-concepts/architecture.md +248 -0
  223. package/docs/03-concepts/mechanisms-explained.md +124 -0
  224. package/docs/03-concepts/pipeline.md +278 -0
  225. package/docs/03-concepts/traceability.md +152 -0
  226. package/docs/04-operations/README.md +33 -0
  227. package/docs/04-operations/bug-flow.md +364 -0
  228. package/docs/04-operations/publishing.md +154 -0
  229. package/docs/04-operations/sync-and-update.md +522 -0
  230. package/docs/05-reference/README.md +34 -0
  231. package/docs/05-reference/command-cheatsheet.md +147 -0
  232. package/docs/05-reference/commands.md +234 -0
  233. package/docs/05-reference/model-selection.md +74 -0
  234. package/docs/05-reference/modules.md +110 -0
  235. package/docs/05-reference/trace-schema.md +154 -0
  236. package/docs/06-commands/README.md +75 -0
  237. package/docs/06-commands/explain-debug.md +32 -0
  238. package/docs/06-commands/explain-define-product.md +43 -0
  239. package/docs/06-commands/explain-dev-gen-test.md +28 -0
  240. package/docs/06-commands/explain-dev-run-test.md +24 -0
  241. package/docs/06-commands/explain-dev-smoke-test.md +25 -0
  242. package/docs/06-commands/explain-fix-bug.md +28 -0
  243. package/docs/06-commands/explain-generate-bdd.md +45 -0
  244. package/docs/06-commands/explain-generate-code.md +53 -0
  245. package/docs/06-commands/explain-generate-design-spec.md +54 -0
  246. package/docs/06-commands/explain-generate-prd.md +45 -0
  247. package/docs/06-commands/explain-generate-spec-manifest.md +20 -0
  248. package/docs/06-commands/explain-generate-tech-docs.md +56 -0
  249. package/docs/06-commands/explain-learn.md +21 -0
  250. package/docs/06-commands/explain-map-testids.md +28 -0
  251. package/docs/06-commands/explain-propose-scenario.md +24 -0
  252. package/docs/06-commands/explain-qc-analyze.md +22 -0
  253. package/docs/06-commands/explain-qc-design-test.md +20 -0
  254. package/docs/06-commands/explain-qc-plan.md +21 -0
  255. package/docs/06-commands/explain-qc-report.md +23 -0
  256. package/docs/06-commands/explain-qc-review.md +24 -0
  257. package/docs/06-commands/explain-qc-run-test.md +27 -0
  258. package/docs/06-commands/explain-refine-prd.md +51 -0
  259. package/docs/06-commands/explain-report-bug.md +24 -0
  260. package/docs/06-commands/explain-review-code.md +45 -0
  261. package/docs/06-commands/explain-review-context.md +68 -0
  262. package/docs/06-commands/explain-review-tech-docs.md +45 -0
  263. package/docs/06-commands/explain-setup-ai-first.md +25 -0
  264. package/docs/06-commands/explain-sync.md +24 -0
  265. package/docs/06-commands/explain-update-framework.md +22 -0
  266. package/docs/06-commands/explain-validate-traces.md +25 -0
  267. package/docs/README.md +53 -0
  268. package/docs/t-sample.md +826 -0
  269. package/hooks/data-guard.js +141 -0
  270. package/hooks/settings.json +18 -0
  271. package/modules/android-compose/module.yaml +13 -0
  272. package/modules/android-compose/stack-profile.yaml +57 -0
  273. package/modules/angular/architecture-snippets/component-patterns.md +187 -0
  274. package/modules/angular/module.yaml +6 -0
  275. package/modules/angular/stack-profile.yaml +38 -0
  276. package/modules/context-engineering/architecture-snippets/context-design.md +119 -0
  277. package/modules/context-engineering/module.yaml +9 -0
  278. package/modules/context-engineering/stack-profile.yaml +61 -0
  279. package/modules/dotnet/architecture-snippets/clean-arch.md +160 -0
  280. package/modules/dotnet/module.yaml +6 -0
  281. package/modules/dotnet/stack-profile.yaml +50 -0
  282. package/modules/flutter/module.yaml +14 -0
  283. package/modules/flutter/stack-profile.yaml +59 -0
  284. package/modules/golang/architecture-snippets/domain-layout.md +283 -0
  285. package/modules/golang/module.yaml +6 -0
  286. package/modules/golang/stack-profile.yaml +40 -0
  287. package/modules/ios-swiftui/module.yaml +13 -0
  288. package/modules/ios-swiftui/stack-profile.yaml +55 -0
  289. package/modules/java-spring/architecture-snippets/layered-arch.md +201 -0
  290. package/modules/java-spring/module.yaml +15 -0
  291. package/modules/java-spring/stack-profile.yaml +28 -0
  292. package/modules/nextjs/architecture-snippets/app-router-patterns.md +269 -0
  293. package/modules/nextjs/module.yaml +14 -0
  294. package/modules/nextjs/stack-profile.yaml +74 -0
  295. package/modules/nuxt/module.yaml +14 -0
  296. package/modules/nuxt/stack-profile.yaml +58 -0
  297. package/modules/php-laravel/architecture-snippets/service-repository.md +302 -0
  298. package/modules/php-laravel/module.yaml +15 -0
  299. package/modules/php-laravel/stack-profile.yaml +56 -0
  300. package/modules/qc-playwright/stack-profile.yaml +66 -0
  301. package/modules/react/architecture-snippets/hooks-query-patterns.md +254 -0
  302. package/modules/react/module.yaml +14 -0
  303. package/modules/react/stack-profile.yaml +63 -0
  304. package/modules/react-native/module.yaml +14 -0
  305. package/modules/react-native/stack-profile.yaml +56 -0
  306. package/modules/vue/module.yaml +14 -0
  307. package/modules/vue/stack-profile.yaml +65 -0
  308. package/package.json +49 -0
  309. package/readme.txt +1 -0
  310. package/rules/data-protection.md +80 -0
  311. package/rules/workflow.md +44 -0
  312. package/scripts/init.sh +49 -0
  313. package/scripts/migrate-specs.js +258 -0
  314. package/scripts/rename-prd-files.js +174 -0
  315. package/scripts/upgrade.sh +94 -0
  316. package/skills/code/SKILL.md +19 -0
  317. package/skills/code/SKILL.tmpl +19 -0
  318. package/skills/debug/SKILL.md +19 -0
  319. package/skills/debug/SKILL.tmpl +19 -0
  320. package/skills/design-spec/SKILL.md +11 -0
  321. package/skills/design-spec/SKILL.tmpl +11 -0
  322. package/skills/discovery/SKILL.md +14 -0
  323. package/skills/discovery/SKILL.tmpl +14 -0
  324. package/skills/prd/SKILL.md +19 -0
  325. package/skills/prd/SKILL.tmpl +19 -0
  326. package/skills/qc/qa-analyst/DOC_GAPS.template.md +63 -0
  327. package/skills/qc/qa-analyst/acceptance-criteria.md +60 -0
  328. package/skills/qc/qa-analyst/business-rules.md +59 -0
  329. package/skills/qc/qa-analyst/data-flow.md +64 -0
  330. package/skills/qc/qa-analyst/spec-breakdown.md +61 -0
  331. package/skills/qc/qa-designer/e2e/journey.md +41 -0
  332. package/skills/qc/qa-designer/exploratory/charter.md +68 -0
  333. package/skills/qc/qa-designer/exploratory/explore-to-functional.md +43 -0
  334. package/skills/qc/qa-designer/functional/api.md +45 -0
  335. package/skills/qc/qa-designer/functional/gui-feature.md +46 -0
  336. package/skills/qc/qa-designer/functional/gui-screen.md +52 -0
  337. package/skills/qc/qa-designer/integration/api.md +42 -0
  338. package/skills/qc/qa-designer/integration/db.md +39 -0
  339. package/skills/qc/qa-designer/integration/gui.md +40 -0
  340. package/skills/qc/qa-designer/integration/kafka.md +40 -0
  341. package/skills/qc/qa-designer/non-functional.md +40 -0
  342. package/skills/qc/qa-planner/test-plan.md +120 -0
  343. package/skills/qc/qa-reviewer/script/e2e.md +87 -0
  344. package/skills/qc/qa-reviewer/script/exploratory.md +45 -0
  345. package/skills/qc/qa-reviewer/script/functional.md +101 -0
  346. package/skills/qc/qa-reviewer/script/integration.md +91 -0
  347. package/skills/qc/qa-reviewer/script/non-functional.md +126 -0
  348. package/skills/qc/qa-reviewer/test-case/e2e.md +73 -0
  349. package/skills/qc/qa-reviewer/test-case/exploratory.md +43 -0
  350. package/skills/qc/qa-reviewer/test-case/functional.md +76 -0
  351. package/skills/qc/qa-reviewer/test-case/integration.md +69 -0
  352. package/skills/qc/qa-reviewer/test-case/non-functional.md +73 -0
  353. package/skills/qc/qa-runner/e2e.md +49 -0
  354. package/skills/qc/qa-runner/exploratory/session.md +36 -0
  355. package/skills/qc/qa-runner/functional/api.md +35 -0
  356. package/skills/qc/qa-runner/functional/gui-feature.md +51 -0
  357. package/skills/qc/qa-runner/functional/gui-screen.md +55 -0
  358. package/skills/qc/qa-runner/integration.md +47 -0
  359. package/skills/qc/qa-runner/non-functional.md +49 -0
  360. package/skills/qc/qa-runner/report/report.md +37 -0
  361. package/skills/setup-ai-first/SKILL.md +11 -0
  362. package/skills/setup-ai-first/SKILL.tmpl +11 -0
  363. package/skills/spec/SKILL.md +19 -0
  364. package/skills/spec/SKILL.tmpl +19 -0
  365. package/skills/test/SKILL.md +18 -0
  366. package/skills/test/SKILL.tmpl +18 -0
  367. package/steps/business-language.md +56 -0
  368. package/steps/capture-lesson.md +79 -0
  369. package/steps/context-loader.md +311 -0
  370. package/steps/gate.md +88 -0
  371. package/steps/report-footer.md +100 -0
  372. package/steps/review-fanout.md +159 -0
  373. package/steps/spawn-agent.md +129 -0
  374. package/steps/trace-mirror.md +26 -0
  375. package/templates/architecture.template.md +113 -0
  376. package/templates/design-spec.template.md +217 -0
  377. package/templates/feature.template +120 -0
  378. package/templates/platform-guide.template.md +145 -0
  379. package/templates/prd.template.md +224 -0
  380. package/templates/product-definition.template.md +188 -0
  381. package/templates/project-context.yaml +161 -0
  382. package/templates/tech-design.template.md +498 -0
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * migrate-specs.js — migrate a consumer project's specs from the LEGACY
5
+ * artifact-type-first layout to the FEATURE-PACKAGE layout.
6
+ *
7
+ * OLD NEW
8
+ * specs/prd/{domain}/{slug}.md specs/{domain}/{slug}/{TICKET-ID}-{slug}.md
9
+ * specs/bdd/{domain}/{rest} specs/{domain}/{prd-slug}/bdd/{rest}
10
+ * specs/tech-docs/{domain}/{file} specs/{domain}/{prd-slug}/tech-docs/{file}
11
+ * specs/design-spec/{domain}/{file} specs/{domain}/{prd-slug}/design-spec/{file}
12
+ * .trace/{UC-ID}.tsv .trace/{domain}/{prd-slug}/{UC-ID}.tsv
13
+ *
14
+ * The {prd-slug} for a BDD / tech-doc / design-spec / trace file is resolved by
15
+ * reading its `@trace.source` header (the PRD it derives from) or its `@trace.uc`
16
+ * tag (mapped to a PRD via the .feature index). Files that cannot be resolved are
17
+ * LEFT IN PLACE and listed in the report — never moved to a guessed location.
18
+ *
19
+ * DRY-RUN by default (prints the plan, changes nothing). Pass --apply to execute.
20
+ * Tracked files are moved with `git mv` to preserve history; the rest with fs.rename.
21
+ * After moving, internal `@trace.source` / path references inside the moved files
22
+ * are rewritten to the new locations.
23
+ *
24
+ * Usage (from the consumer project root):
25
+ * node scripts/migrate-specs.js # dry-run, prints plan
26
+ * node scripts/migrate-specs.js --apply # execute the migration
27
+ * node scripts/migrate-specs.js --specs specs --trace .trace --root .
28
+ */
29
+
30
+ const fs = require('fs');
31
+ const path = require('path');
32
+ const { execSync } = require('child_process');
33
+
34
+ // ── args ────────────────────────────────────────────────────────────────────
35
+ const argv = process.argv.slice(2);
36
+ const has = f => argv.includes(f);
37
+ const flag = (f, d) => { const i = argv.indexOf(f); return i !== -1 ? argv[i + 1] : d; };
38
+
39
+ const APPLY = has('--apply');
40
+ const ROOT = path.resolve(flag('--root', '.'));
41
+ const SPECS = flag('--specs', 'specs');
42
+ const TRACE = flag('--trace', '.trace');
43
+
44
+ const specsAbs = path.join(ROOT, SPECS);
45
+ const traceAbs = path.join(ROOT, TRACE);
46
+
47
+ // ── git tracked set (for `git mv`) ────────────────────────────────────────────
48
+ let tracked = null;
49
+ try {
50
+ const out = execSync('git ls-files', { cwd: ROOT, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
51
+ tracked = new Set(out.split('\n').filter(Boolean).map(p => p.replace(/\\/g, '/')));
52
+ } catch { tracked = null; }
53
+
54
+ const rel = abs => path.relative(ROOT, abs).replace(/\\/g, '/');
55
+ const isTracked = abs => !!(tracked && tracked.has(rel(abs)));
56
+
57
+ // ── helpers ───────────────────────────────────────────────────────────────────
58
+ function walk(dir) {
59
+ const out = [];
60
+ if (!fs.existsSync(dir)) return out;
61
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
62
+ const p = path.join(dir, e.name);
63
+ if (e.isDirectory()) out.push(...walk(p));
64
+ else out.push(p);
65
+ }
66
+ return out;
67
+ }
68
+ const head = (file, n = 4096) => { try { return fs.readFileSync(file, 'utf8').slice(0, n); } catch { return ''; } };
69
+
70
+ const reSource = /@trace\.source\s*[=:]\s*([^\s)'"]+)/;
71
+ const reUc = /@trace\.(?:uc|id)\s*[=:]\s*([A-Za-z0-9_-]+)/;
72
+ const reUcName = /\b([A-Za-z][A-Za-z0-9]*-UC\d+)\b/; // e.g. PAY-UC1, FT-UC3
73
+ // extract {domain}/{slug} from a legacy PRD ref like specs/prd/payment/create-invoice.md
74
+ const slugFromPrdRef = ref => { const m = ref && ref.match(/prd\/([^/]+)\/([^/]+)\.md/); return m ? { domain: m[1], slug: m[2] } : null; };
75
+
76
+ // ── plan state ─────────────────────────────────────────────────────────────────
77
+ const moves = []; // { from(abs), to(abs), type }
78
+ const unresolved = []; // { file(rel), type, reason }
79
+ const prdByDomain = {}; // domain -> Set(slug)
80
+ const ucToSlug = {}; // `${domain}/${UC}` -> slug
81
+ const ticketToSlug = {}; // `${domain}/${TICKET}` -> slug (from PRD metadata)
82
+
83
+ const addSlug = (domain, slug) => { (prdByDomain[domain] = prdByDomain[domain] || new Set()).add(slug); };
84
+ const onlySlug = domain => { const s = prdByDomain[domain]; return s && s.size === 1 ? [...s][0] : null; };
85
+
86
+ // ── Phase 1 — PRDs: specs/prd/{domain}/{slug}.md → specs/{domain}/{slug}/{TICKET-ID}-{slug}.md ──
87
+ const prdRoot = path.join(specsAbs, 'prd');
88
+ for (const file of walk(prdRoot).filter(f => f.endsWith('.md'))) {
89
+ const parts = rel(file).split('/'); // [SPECS, 'prd', domain, ...rest, name.md]
90
+ const after = parts.slice(parts.indexOf('prd') + 1); // [domain, ...rest, name.md]
91
+ if (after.length !== 2) { unresolved.push({ file: rel(file), type: 'prd', reason: `expected specs/prd/{domain}/{slug}.md (got depth ${after.length})` }); continue; }
92
+ const [domain, name] = after;
93
+ const slug = name.replace(/\.md$/, '');
94
+ addSlug(domain, slug);
95
+ // map this PRD's Ticket + UC ids → slug (fallback resolution for other artifacts)
96
+ const body = head(file, 16384);
97
+ const ticket = (body.match(/\|\s*\*\*(?:PRD ID|Ticket)\*\*\s*\|\s*([A-Za-z0-9_-]+)/) || [])[1];
98
+ if (ticket) ticketToSlug[`${domain}/${ticket}`] = slug;
99
+ let m; const reUcG = new RegExp(reUcName.source, 'g');
100
+ while ((m = reUcG.exec(body))) ucToSlug[`${domain}/${m[1]}`] = ucToSlug[`${domain}/${m[1]}`] || slug;
101
+ // PRD file name follows the {TICKET-ID}-{slug}.md convention (falls back to {slug}.md if no ticket found)
102
+ const prdFile = ticket ? `${ticket}-${slug}.md` : `${slug}.md`;
103
+ moves.push({ from: file, to: path.join(specsAbs, domain, slug, prdFile), type: 'prd' });
104
+ }
105
+
106
+ // ── Phase 2 — BDD: specs/bdd/{domain}/{rest} → specs/{domain}/{prd-slug}/bdd/{rest}
107
+ const bddRoot = path.join(specsAbs, 'bdd');
108
+ for (const file of walk(bddRoot).filter(f => f.endsWith('.feature'))) {
109
+ const after = rel(file).split('/').slice(rel(file).split('/').indexOf('bdd') + 1); // [domain, ...rest]
110
+ const domain = after[0];
111
+ const rest = after.slice(1).join('/'); // e.g. system/PAY-UC1.feature OR PAY-UC1.feature
112
+ const h = head(file);
113
+ let resolved = slugFromPrdRef((h.match(reSource) || [])[1]);
114
+ const uc = (h.match(reUc) || [])[1] || (path.basename(file).match(reUcName) || [])[1];
115
+ let slug = resolved && resolved.domain === domain ? resolved.slug : null;
116
+ if (!slug && uc) slug = ucToSlug[`${domain}/${uc}`];
117
+ if (!slug) slug = onlySlug(domain);
118
+ if (!slug) { unresolved.push({ file: rel(file), type: 'bdd', reason: 'cannot resolve prd-slug (no @trace.source / @trace.uc match, and domain has multiple PRDs)' }); continue; }
119
+ if (uc) ucToSlug[`${domain}/${uc}`] = ucToSlug[`${domain}/${uc}`] || slug;
120
+ moves.push({ from: file, to: path.join(specsAbs, domain, slug, 'bdd', ...rest.split('/')), type: 'bdd' });
121
+ }
122
+
123
+ // ── Phase 3 — tech-docs → specs/{domain}/{prd-slug}/tech-docs/{file} ────────────
124
+ const techRoot = path.join(specsAbs, 'tech-docs');
125
+ for (const file of walk(techRoot).filter(f => f.endsWith('.md'))) {
126
+ const after = rel(file).split('/').slice(rel(file).split('/').indexOf('tech-docs') + 1);
127
+ const domain = after[0];
128
+ const rest = after.slice(1).join('/');
129
+ const h = head(file);
130
+ const src = (h.match(reSource) || [])[1];
131
+ let slug = (slugFromPrdRef(src) || {}).slug; // when @trace.source points at the PRD
132
+ const uc = (h.match(reUc) || [])[1] || (path.basename(file).match(reUcName) || [])[1];
133
+ if (!slug && uc) slug = ucToSlug[`${domain}/${uc}`];
134
+ if (!slug && src) { const m = src.match(/bdd\/(?:.*\/)?([A-Za-z][A-Za-z0-9]*-UC\d+)/); if (m) slug = ucToSlug[`${domain}/${m[1]}`]; }
135
+ if (!slug) slug = onlySlug(domain);
136
+ if (!slug) { unresolved.push({ file: rel(file), type: 'tech-docs', reason: 'cannot resolve prd-slug from @trace.source / UC-ID' }); continue; }
137
+ moves.push({ from: file, to: path.join(specsAbs, domain, slug, 'tech-docs', ...rest.split('/')), type: 'tech-docs' });
138
+ }
139
+
140
+ // ── Phase 4 — design-spec → specs/{domain}/{prd-slug}/design-spec/{file} ────────
141
+ const dsRoot = path.join(specsAbs, 'design-spec');
142
+ for (const file of walk(dsRoot).filter(f => f.endsWith('.md'))) {
143
+ const after = rel(file).split('/').slice(rel(file).split('/').indexOf('design-spec') + 1);
144
+ const domain = after[0];
145
+ const rest = after.slice(1).join('/');
146
+ const h = head(file);
147
+ let slug = (slugFromPrdRef((h.match(reSource) || [])[1]) || {}).slug;
148
+ const ticket = (path.basename(file).match(/^([A-Za-z][A-Za-z0-9]*-\d+|[A-Za-z]+-UC\d+)/) || [])[1];
149
+ if (!slug && ticket) slug = ticketToSlug[`${domain}/${ticket}`] || ucToSlug[`${domain}/${ticket}`];
150
+ if (!slug) slug = onlySlug(domain);
151
+ if (!slug) { unresolved.push({ file: rel(file), type: 'design-spec', reason: 'cannot resolve prd-slug (no @trace.source / ticket match)' }); continue; }
152
+ moves.push({ from: file, to: path.join(specsAbs, domain, slug, 'design-spec', ...rest.split('/')), type: 'design-spec' });
153
+ }
154
+
155
+ // ── Phase 5 — trace: flat .trace/{UC-ID}.tsv → .trace/{domain}/{prd-slug}/{UC}.tsv
156
+ if (fs.existsSync(traceAbs)) {
157
+ for (const file of fs.readdirSync(traceAbs).filter(f => f.endsWith('.tsv'))) {
158
+ const uc = file.replace(/\.tsv$/, '');
159
+ const keys = Object.keys(ucToSlug).filter(k => k.endsWith(`/${uc}`));
160
+ if (keys.length === 0) { unresolved.push({ file: `${TRACE}/${file}`, type: 'trace', reason: `no PRD/feature maps UC ${uc}` }); continue; }
161
+ if (keys.length > 1) { unresolved.push({ file: `${TRACE}/${file}`, type: 'trace', reason: `UC ${uc} is ambiguous across domains: ${keys.join(', ')}` }); continue; }
162
+ const [domain] = keys[0].split('/');
163
+ const slug = ucToSlug[keys[0]];
164
+ moves.push({ from: path.join(traceAbs, file), to: path.join(traceAbs, domain, slug, file), type: 'trace' });
165
+ }
166
+ }
167
+
168
+ // ── build old→new ref map (repo-root-relative, forward slashes) ────────────────
169
+ const refMap = new Map();
170
+ for (const m of moves) refMap.set(rel(m.from), rel(m.to));
171
+
172
+ // ── report ──────────────────────────────────────────────────────────────────────
173
+ const byType = moves.reduce((a, m) => ((a[m.type] = (a[m.type] || 0) + 1), a), {});
174
+ console.log('');
175
+ console.log('╔════════════════════════════════════════════╗');
176
+ console.log(`║ migrate-specs — ${APPLY ? 'APPLY' : 'DRY RUN'}${' '.repeat(APPLY ? 20 : 18)}║`);
177
+ console.log('╚════════════════════════════════════════════╝');
178
+ console.log(`Root : ${ROOT}`);
179
+ console.log(`Specs : ${SPECS}/ Trace: ${TRACE}/ Git: ${tracked ? 'yes (git mv)' : 'no (fs move)'}`);
180
+ console.log('');
181
+ if (moves.length === 0 && unresolved.length === 0) {
182
+ console.log('Nothing to migrate — no legacy specs/prd, specs/bdd, specs/tech-docs, specs/design-spec, or flat .trace/*.tsv found.');
183
+ process.exit(0);
184
+ }
185
+ console.log(`Planned moves: ${moves.length} (${Object.entries(byType).map(([k, v]) => `${k}:${v}`).join(' ')})`);
186
+ console.log('');
187
+ for (const m of moves) console.log(` ${rel(m.from)}\n → ${rel(m.to)}`);
188
+ if (unresolved.length) {
189
+ console.log('');
190
+ console.log(`⚠️ Unresolved (LEFT IN PLACE — fix the file's @trace.source/@trace.uc or move manually):`);
191
+ for (const u of unresolved) console.log(` [${u.type}] ${u.file}\n ${u.reason}`);
192
+ }
193
+ console.log('');
194
+
195
+ // ── apply ────────────────────────────────────────────────────────────────────────
196
+ function gitMv(from, to) {
197
+ fs.mkdirSync(path.dirname(to), { recursive: true });
198
+ execSync(`git mv -k "${rel(from)}" "${rel(to)}"`, { cwd: ROOT, stdio: ['ignore', 'ignore', 'pipe'] });
199
+ }
200
+ function fsMv(from, to) {
201
+ fs.mkdirSync(path.dirname(to), { recursive: true });
202
+ fs.renameSync(from, to);
203
+ }
204
+ function rewriteRefs(absFile) {
205
+ if (!/\.(md|feature|tsv|ya?ml)$/.test(absFile)) return 0;
206
+ let txt; try { txt = fs.readFileSync(absFile, 'utf8'); } catch { return 0; }
207
+ let n = 0, out = txt;
208
+ for (const [oldRef, newRef] of refMap) {
209
+ if (out.includes(oldRef)) { out = out.split(oldRef).join(newRef); n++; }
210
+ }
211
+ if (n) fs.writeFileSync(absFile, out, 'utf8');
212
+ return n;
213
+ }
214
+ function pruneEmptyDirs(root) {
215
+ if (!fs.existsSync(root)) return;
216
+ for (const e of fs.readdirSync(root, { withFileTypes: true })) {
217
+ if (e.isDirectory()) pruneEmptyDirs(path.join(root, e.name));
218
+ }
219
+ try { if (fs.readdirSync(root).length === 0) fs.rmdirSync(root); } catch {}
220
+ }
221
+
222
+ if (!APPLY) {
223
+ console.log('DRY RUN — nothing changed. Re-run with --apply to execute.');
224
+ console.log('After applying, grep your CODE for stale spec refs the move did not touch:');
225
+ console.log(' @trace.source=specs/bdd/... and specs/{prd,bdd,tech-docs,design-spec}/');
226
+ process.exit(0);
227
+ }
228
+
229
+ let moved = 0, failed = 0;
230
+ for (const m of moves) {
231
+ try {
232
+ if (fs.existsSync(m.to)) throw new Error('target already exists');
233
+ (isTracked(m.from) ? gitMv : fsMv)(m.from, m.to);
234
+ moved++;
235
+ } catch (e) {
236
+ failed++;
237
+ console.log(` ❌ ${rel(m.from)} — ${e.message}`);
238
+ }
239
+ }
240
+ // rewrite internal references in every moved file (now at its new path)
241
+ let rewritten = 0;
242
+ for (const m of moves) if (fs.existsSync(m.to)) rewritten += rewriteRefs(m.to) > 0 ? 1 : 0;
243
+
244
+ // remove now-empty legacy roots
245
+ [prdRoot, bddRoot, techRoot, dsRoot].forEach(pruneEmptyDirs);
246
+
247
+ console.log('');
248
+ console.log(`✅ Moved ${moved}/${moves.length} files${failed ? ` (${failed} failed)` : ''}.`);
249
+ console.log(`✅ Rewrote internal references in ${rewritten} file(s).`);
250
+ if (unresolved.length) console.log(`⚠️ ${unresolved.length} file(s) left in place (see list above).`);
251
+ console.log('');
252
+ console.log('Next:');
253
+ console.log(' 1. Review the moves (git status / git diff).');
254
+ console.log(' 2. Grep CODE for stale refs the move did not touch:');
255
+ console.log(' @trace.source=specs/bdd/... and specs/{prd,bdd,tech-docs,design-spec}/');
256
+ console.log(' 3. Run /validate-traces to confirm coverage still resolves.');
257
+ console.log(' 4. Commit.');
258
+ console.log('');
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * rename-prd-files.js — rename feature-package PRD files from the old fixed
5
+ * name `prd.md` to the `{TICKET-ID}-{slug}.md` convention.
6
+ *
7
+ * OLD NEW
8
+ * specs/{domain}/{slug}/prd.md specs/{domain}/{slug}/{TICKET-ID}-{slug}.md
9
+ *
10
+ * For each `specs/{domain}/{slug}/prd.md`:
11
+ * - slug = the feature-package folder name (parent dir)
12
+ * - TICKET-ID is read from the PRD body — the Metadata table row
13
+ * (| **PRD ID** | … | / | **Ticket** | … |) or, failing that, the leading
14
+ * token of the H1 title (`# SEG01-…`). PRDs where no ticket can be resolved
15
+ * are LEFT IN PLACE and listed in the report — never renamed to a guess.
16
+ *
17
+ * After moving, any reference to the old `…/{slug}/prd.md` path inside other
18
+ * spec / trace files (.md, .feature, .tsv, .yaml) is rewritten to the new path.
19
+ *
20
+ * DRY-RUN by default (prints the plan, changes nothing). Pass --apply to execute.
21
+ * Tracked files move with `git mv` to preserve history; the rest with fs.rename.
22
+ *
23
+ * Usage (from the consumer project root):
24
+ * node scripts/rename-prd-files.js # dry-run, prints plan
25
+ * node scripts/rename-prd-files.js --apply # execute the rename
26
+ * node scripts/rename-prd-files.js --specs specs --trace .trace --root .
27
+ */
28
+
29
+ const fs = require('fs');
30
+ const path = require('path');
31
+ const { execSync } = require('child_process');
32
+
33
+ // ── args ────────────────────────────────────────────────────────────────────
34
+ const argv = process.argv.slice(2);
35
+ const has = f => argv.includes(f);
36
+ const flag = (f, d) => { const i = argv.indexOf(f); return i !== -1 ? argv[i + 1] : d; };
37
+
38
+ const APPLY = has('--apply');
39
+ const ROOT = path.resolve(flag('--root', '.'));
40
+ const SPECS = flag('--specs', 'specs');
41
+ const TRACE = flag('--trace', '.trace');
42
+
43
+ const specsAbs = path.join(ROOT, SPECS);
44
+ const traceAbs = path.join(ROOT, TRACE);
45
+
46
+ // ── git tracked set (for `git mv`) ────────────────────────────────────────────
47
+ let tracked = null;
48
+ try {
49
+ const out = execSync('git ls-files', { cwd: ROOT, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
50
+ tracked = new Set(out.split('\n').filter(Boolean).map(p => p.replace(/\\/g, '/')));
51
+ } catch { tracked = null; }
52
+
53
+ const rel = abs => path.relative(ROOT, abs).replace(/\\/g, '/');
54
+ const isTracked = abs => !!(tracked && tracked.has(rel(abs)));
55
+
56
+ // ── helpers ───────────────────────────────────────────────────────────────────
57
+ function walk(dir) {
58
+ const out = [];
59
+ if (!fs.existsSync(dir)) return out;
60
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
61
+ const p = path.join(dir, e.name);
62
+ if (e.isDirectory()) out.push(...walk(p));
63
+ else out.push(p);
64
+ }
65
+ return out;
66
+ }
67
+ const head = (file, n = 16384) => { try { return fs.readFileSync(file, 'utf8').slice(0, n); } catch { return ''; } };
68
+
69
+ // Extract the TICKET-ID from a PRD body. Tries the Metadata table first, then the H1 title.
70
+ function extractTicket(body) {
71
+ // | **PRD ID** | SEG01 | / | **Ticket** | [SEG01](...) | / | **TICKET-ID** | SEG01 |
72
+ let m = body.match(/\|\s*\*\*\s*(?:PRD ID|Ticket(?:\s*ID)?|TICKET-ID|Mã(?:\s*ticket)?)\s*\*\*\s*\|\s*\[?\s*([A-Za-z][A-Za-z0-9_.-]*?)\s*\]?\s*(?:\]\([^)]*\))?\s*\|/i);
73
+ if (m) return m[1];
74
+ // H1 title: "# SEG01-segment-scoring-service ..." or "# SEG01 Feature Name"
75
+ m = body.match(/^#\s+([A-Za-z][A-Za-z0-9_.]*(?:-?\d+)?)\b/m);
76
+ if (m) return m[1];
77
+ return null;
78
+ }
79
+
80
+ // ── plan ───────────────────────────────────────────────────────────────────────
81
+ const moves = []; // { from(abs), to(abs) }
82
+ const unresolved = []; // { file(rel), reason }
83
+
84
+ // Scan specs/{domain}/{slug}/prd.md (PRD lives directly in the feature-package folder)
85
+ for (const file of walk(specsAbs).filter(f => path.basename(f) === 'prd.md')) {
86
+ const parts = rel(file).split('/'); // [SPECS, domain, slug, 'prd.md']
87
+ if (parts.length < 4) { unresolved.push({ file: rel(file), reason: `not a feature-package PRD (expected ${SPECS}/{domain}/{slug}/prd.md)` }); continue; }
88
+ const slug = parts[parts.length - 2];
89
+ const ticket = extractTicket(head(file));
90
+ if (!ticket) { unresolved.push({ file: rel(file), reason: 'no TICKET-ID found (add a Metadata "PRD ID"/"Ticket" row or an H1 title, then re-run)' }); continue; }
91
+ const to = path.join(path.dirname(file), `${ticket}-${slug}.md`);
92
+ if (rel(to) === rel(file)) continue; // already correctly named (shouldn't happen for prd.md)
93
+ moves.push({ from: file, to });
94
+ }
95
+
96
+ // ── old→new ref map (repo-root-relative, forward slashes) ──────────────────────
97
+ const refMap = new Map();
98
+ for (const m of moves) refMap.set(rel(m.from), rel(m.to));
99
+
100
+ // ── report ──────────────────────────────────────────────────────────────────────
101
+ console.log('');
102
+ console.log('╔════════════════════════════════════════════╗');
103
+ console.log(`║ rename-prd-files — ${APPLY ? 'APPLY' : 'DRY RUN'}${' '.repeat(APPLY ? 16 : 14)}║`);
104
+ console.log('╚════════════════════════════════════════════╝');
105
+ console.log(`Root : ${ROOT}`);
106
+ console.log(`Specs : ${SPECS}/ Trace: ${TRACE}/ Git: ${tracked ? 'yes (git mv)' : 'no (fs move)'}`);
107
+ console.log('');
108
+ if (moves.length === 0 && unresolved.length === 0) {
109
+ console.log(`Nothing to rename — no ${SPECS}/{domain}/{slug}/prd.md files found (already on the {TICKET-ID}-{slug}.md convention?).`);
110
+ process.exit(0);
111
+ }
112
+ console.log(`Planned renames: ${moves.length}`);
113
+ console.log('');
114
+ for (const m of moves) console.log(` ${rel(m.from)}\n → ${rel(m.to)}`);
115
+ if (unresolved.length) {
116
+ console.log('');
117
+ console.log('⚠️ Left in place (fix the PRD, then re-run):');
118
+ for (const u of unresolved) console.log(` ${u.file}\n ${u.reason}`);
119
+ }
120
+ console.log('');
121
+
122
+ // ── apply ────────────────────────────────────────────────────────────────────────
123
+ function gitMv(from, to) {
124
+ fs.mkdirSync(path.dirname(to), { recursive: true });
125
+ execSync(`git mv -k "${rel(from)}" "${rel(to)}"`, { cwd: ROOT, stdio: ['ignore', 'ignore', 'pipe'] });
126
+ }
127
+ function fsMv(from, to) {
128
+ fs.mkdirSync(path.dirname(to), { recursive: true });
129
+ fs.renameSync(from, to);
130
+ }
131
+ function rewriteRefs(absFile) {
132
+ if (!/\.(md|feature|tsv|ya?ml)$/.test(absFile)) return 0;
133
+ let txt; try { txt = fs.readFileSync(absFile, 'utf8'); } catch { return 0; }
134
+ let n = 0, out = txt;
135
+ for (const [oldRef, newRef] of refMap) {
136
+ if (out.includes(oldRef)) { out = out.split(oldRef).join(newRef); n++; }
137
+ }
138
+ if (n) fs.writeFileSync(absFile, out, 'utf8');
139
+ return n;
140
+ }
141
+
142
+ if (!APPLY) {
143
+ console.log('DRY RUN — nothing changed. Re-run with --apply to execute.');
144
+ process.exit(0);
145
+ }
146
+
147
+ let moved = 0, failed = 0;
148
+ for (const m of moves) {
149
+ try {
150
+ if (fs.existsSync(m.to)) throw new Error('target already exists');
151
+ (isTracked(m.from) ? gitMv : fsMv)(m.from, m.to);
152
+ moved++;
153
+ } catch (e) {
154
+ failed++;
155
+ console.log(` ❌ ${rel(m.from)} — ${e.message}`);
156
+ }
157
+ }
158
+
159
+ // rewrite references to the old prd.md paths across specs/ and .trace/
160
+ let rewritten = 0;
161
+ const scanForRefs = [...walk(specsAbs), ...walk(traceAbs)];
162
+ for (const f of scanForRefs) rewritten += rewriteRefs(f) > 0 ? 1 : 0;
163
+
164
+ console.log('');
165
+ console.log(`✅ Renamed ${moved}/${moves.length} PRD file(s)${failed ? ` (${failed} failed)` : ''}.`);
166
+ console.log(`✅ Rewrote internal references in ${rewritten} file(s).`);
167
+ if (unresolved.length) console.log(`⚠️ ${unresolved.length} file(s) left in place (see list above).`);
168
+ console.log('');
169
+ console.log('Next:');
170
+ console.log(' 1. Review the renames (git status / git diff).');
171
+ console.log(' 2. Grep your CODE for stale `…/prd.md` refs the move did not touch.');
172
+ console.log(' 3. Run /validate-traces to confirm coverage still resolves.');
173
+ console.log(' 4. Commit.');
174
+ console.log('');
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env bash
2
+ # upgrade.sh — Upgrade SDD Framework framework in an existing project.
3
+ #
4
+ # Usage:
5
+ # bash scripts/upgrade.sh
6
+ # bash scripts/upgrade.sh --module java-spring # also upgrade a stack module
7
+ #
8
+ # What it does:
9
+ # 1. Reads current installed version from .agent/FRAMEWORK_VERSION
10
+ # 2. Checks npm registry for the latest published version
11
+ # 3. If newer: runs npx @educa-corp/sdd-framework@latest --init to update .agent/
12
+ # 4. Reports what changed so you can review before committing
13
+ #
14
+ # Requirements:
15
+ # - Project was set up with init.sh (or npx ... --init)
16
+ # - .agent/FRAMEWORK_VERSION exists
17
+
18
+ set -euo pipefail
19
+
20
+ AGENT_DIR=".agent"
21
+ VERSION_FILE="${AGENT_DIR}/FRAMEWORK_VERSION"
22
+
23
+ echo ""
24
+ echo "╔══════════════════════════════════════════╗"
25
+ echo "║ SDD Framework — Upgrade ║"
26
+ echo "╚══════════════════════════════════════════╝"
27
+ echo ""
28
+
29
+ # ── Prerequisite checks ───────────────────────────────────────────────────────
30
+
31
+ if ! command -v node &> /dev/null; then
32
+ echo "❌ Node.js is required. Install from https://nodejs.org"
33
+ exit 1
34
+ fi
35
+
36
+ if ! command -v npm &> /dev/null; then
37
+ echo "❌ npm is required. Install Node.js from https://nodejs.org"
38
+ exit 1
39
+ fi
40
+
41
+ if [ ! -f "$VERSION_FILE" ]; then
42
+ echo "❌ .agent/FRAMEWORK_VERSION not found."
43
+ echo ""
44
+ echo " This project was not set up with --init."
45
+ echo " To set up the new structure:"
46
+ echo ""
47
+ echo " bash scripts/init.sh"
48
+ echo " or:"
49
+ echo " npx @educa-corp/sdd-framework --init"
50
+ echo ""
51
+ exit 1
52
+ fi
53
+
54
+ # ── Version comparison ────────────────────────────────────────────────────────
55
+
56
+ CURRENT=$(cat "$VERSION_FILE" | tr -d '[:space:]')
57
+ echo "Checking npm registry ..."
58
+
59
+ LATEST=$(npm view @educa-corp/sdd-framework version 2>/dev/null || echo "unknown")
60
+
61
+ echo ""
62
+ echo " Installed : v${CURRENT}"
63
+ echo " Latest : v${LATEST}"
64
+ echo ""
65
+
66
+ if [ "$LATEST" = "unknown" ]; then
67
+ echo "⚠️ Could not reach npm registry. Check your internet connection."
68
+ exit 1
69
+ fi
70
+
71
+ if [ "$CURRENT" = "$LATEST" ]; then
72
+ echo "✅ Already up to date (v${CURRENT}). Nothing to do."
73
+ echo ""
74
+ exit 0
75
+ fi
76
+
77
+ # ── Upgrade ───────────────────────────────────────────────────────────────────
78
+
79
+ echo "Upgrading v${CURRENT} → v${LATEST} ..."
80
+ echo ""
81
+
82
+ npx -y @educa-corp/sdd-framework@latest --init "$@"
83
+
84
+ # ── Post-upgrade guidance ─────────────────────────────────────────────────────
85
+
86
+ echo ""
87
+ echo "✅ Upgraded to v${LATEST}!"
88
+ echo ""
89
+ echo "Review what changed in .agent/ before committing:"
90
+ echo ""
91
+ echo " git diff .agent/"
92
+ echo " git add .agent/"
93
+ echo " git commit -m 'chore: upgrade spec-driven-docs v${CURRENT} → v${LATEST}'"
94
+ echo ""
@@ -0,0 +1,19 @@
1
+ ---
2
+ description: Sinh implementation code từ BDD spec đã duyệt kèm tag traceability, hoặc review code read-only đối chiếu spec compliance và quy tắc kiến trúc. Trigger when: "/generate-code", "/review-code", "sinh code", "generate code", "viết code", "implement feature", "review code", "kiểm tra code", "code review", "check implementation".
3
+ ---
4
+
5
+ # Code Skills — Generate & Review
6
+
7
+ Skill này xử lý `/generate-code` và `/review-code`. Để **không lệch schema/gate**, skill KHÔNG nhân bản — mỗi lệnh thực thi **y hệt** command tương ứng.
8
+
9
+ ## /generate-code — Sinh Implementation Code
10
+
11
+ → **Đọc và tuân theo `commands/generate-code.md`** với cùng `$ARGUMENTS`.
12
+
13
+ Command lo: guard mềm BDD `@trace.status` approved + Design Spec (approved/độ-tươi/sanity) cho FE/App · `--phase=ui`/`--phase=integration` · branch + build verify · trace TSV (22 cột) `@trace.implements`.
14
+
15
+ ## /review-code — Code Review chỉ-đọc (READ-ONLY)
16
+
17
+ → **Đọc và tuân theo `commands/review-code.md`** với cùng `$ARGUMENTS`.
18
+
19
+ Command lo: Pre-Review Scan · 4 lăng kính (Traceability · Layer Architecture · Coding Standards · Spec Compliance) · đề xuất ghi Lesson cho lỗi AI lặp.
@@ -0,0 +1,19 @@
1
+ ---
2
+ description: Sinh implementation code từ BDD spec đã duyệt kèm tag traceability, hoặc review code read-only đối chiếu spec compliance và quy tắc kiến trúc. Trigger when: "/generate-code", "/review-code", "sinh code", "generate code", "viết code", "implement feature", "review code", "kiểm tra code", "code review", "check implementation".
3
+ ---
4
+
5
+ # Code Skills — Generate & Review
6
+
7
+ Skill này xử lý `/generate-code` và `/review-code`. Để **không lệch schema/gate**, skill KHÔNG nhân bản — mỗi lệnh thực thi **y hệt** command tương ứng.
8
+
9
+ ## /generate-code — Sinh Implementation Code
10
+
11
+ → **Đọc và tuân theo `commands/generate-code.md`** với cùng `$ARGUMENTS`.
12
+
13
+ Command lo: guard mềm BDD `@trace.status` approved + Design Spec (approved/độ-tươi/sanity) cho FE/App · `--phase=ui`/`--phase=integration` · branch + build verify · trace TSV (22 cột) `@trace.implements`.
14
+
15
+ ## /review-code — Code Review chỉ-đọc (READ-ONLY)
16
+
17
+ → **Đọc và tuân theo `commands/review-code.md`** với cùng `$ARGUMENTS`.
18
+
19
+ Command lo: Pre-Review Scan · 4 lăng kính (Traceability · Layer Architecture · Coding Standards · Spec Compliance) · đề xuất ghi Lesson cho lỗi AI lặp.
@@ -0,0 +1,19 @@
1
+ ---
2
+ description: Fix bug với full workflow (branch, test, commit), phân tích debug nhanh các lỗi hoặc hành vi bất ngờ, hoặc kiểm chứng độ phủ traceability giữa spec và code. Trigger when: "/fix-bug", "/debug", "/validate-traces", "fix bug", "sửa bug", "debug lỗi", "phân tích lỗi", "tại sao lỗi này", "validate traces", "kiểm tra traceability", "coverage matrix", "trace drift".
3
+ ---
4
+
5
+ # Debug & Quality Skills — Fix Bug, Debug, Validate Traces
6
+
7
+ Skill này xử lý `/fix-bug`, `/debug`, `/validate-traces`. Để **không lệch schema/flow**, skill KHÔNG nhân bản — mỗi lệnh thực thi **y hệt** command.
8
+
9
+ ## /fix-bug — Full Bug Fix Workflow
10
+ → **Đọc và tuân theo `commands/fix-bug.md`** với cùng `$ARGUMENTS`.
11
+ (Command lo: bug-type table theo platform · đọc `{BUG-ID}` report · regression test · build + push 2 tầng (umbrella) · BUG State `Open→Fixed`→`Closed` · đề xuất Lesson.)
12
+
13
+ ## /debug — Phân tích nhanh
14
+ → **Đọc và tuân theo `commands/debug.md`** với cùng `$ARGUMENTS`.
15
+ (Command lo: 4 path (stack trace / reproduce / test fail / câu hỏi code) · bảng lỗi theo từng platform/module · stack-trace đọc dưới-lên.)
16
+
17
+ ## /validate-traces — Traceability Coverage
18
+ → **Đọc và tuân theo `commands/validate-traces.md`** với cùng `$ARGUMENTS`.
19
+ (Command lo: đọc trace TSV 22 cột authoritative · tính OK/DRIFT/GAP/UNTRACKED + PRD/TECHDOC drift · sync `uc_status` ← `@trace.status` · aggregate dashboard.)
@@ -0,0 +1,19 @@
1
+ ---
2
+ description: Fix bug với full workflow (branch, test, commit), phân tích debug nhanh các lỗi hoặc hành vi bất ngờ, hoặc kiểm chứng độ phủ traceability giữa spec và code. Trigger when: "/fix-bug", "/debug", "/validate-traces", "fix bug", "sửa bug", "debug lỗi", "phân tích lỗi", "tại sao lỗi này", "validate traces", "kiểm tra traceability", "coverage matrix", "trace drift".
3
+ ---
4
+
5
+ # Debug & Quality Skills — Fix Bug, Debug, Validate Traces
6
+
7
+ Skill này xử lý `/fix-bug`, `/debug`, `/validate-traces`. Để **không lệch schema/flow**, skill KHÔNG nhân bản — mỗi lệnh thực thi **y hệt** command.
8
+
9
+ ## /fix-bug — Full Bug Fix Workflow
10
+ → **Đọc và tuân theo `commands/fix-bug.md`** với cùng `$ARGUMENTS`.
11
+ (Command lo: bug-type table theo platform · đọc `{BUG-ID}` report · regression test · build + push 2 tầng (umbrella) · BUG State `Open→Fixed`→`Closed` · đề xuất Lesson.)
12
+
13
+ ## /debug — Phân tích nhanh
14
+ → **Đọc và tuân theo `commands/debug.md`** với cùng `$ARGUMENTS`.
15
+ (Command lo: 4 path (stack trace / reproduce / test fail / câu hỏi code) · bảng lỗi theo từng platform/module · stack-trace đọc dưới-lên.)
16
+
17
+ ## /validate-traces — Traceability Coverage
18
+ → **Đọc và tuân theo `commands/validate-traces.md`** với cùng `$ARGUMENTS`.
19
+ (Command lo: đọc trace TSV 22 cột authoritative · tính OK/DRIFT/GAP/UNTRACKED + PRD/TECHDOC drift · sync `uc_status` ← `@trace.status` · aggregate dashboard.)
@@ -0,0 +1,11 @@
1
+ ---
2
+ description: Sinh tài liệu Design Specification cho platform FE hoặc App từ một Business PRD. Trigger when: "/generate-design-spec", "tạo design spec", "generate design spec", "viết design spec", "tạo tài liệu thiết kế UI", "generate UI spec", "cần design spec cho", "tôi muốn spec UI", "tài liệu cho FE", "tài liệu cho app".
3
+ ---
4
+
5
+ # /generate-design-spec — Generate Design Specification (FE / App)
6
+
7
+ Skill này xử lý `/generate-design-spec`. Để **không lệch gate/schema**, skill KHÔNG nhân bản — thực thi **y hệt** command.
8
+
9
+ → **Đọc và tuân theo `commands/generate-design-spec.md`** với cùng `$ARGUMENTS`.
10
+
11
+ Command lo: guard PRD approved (mềm) · ghi `Built from PRD` + Version Check drift · Figma per-screen node-level link (`?node-id=`) fetch qua MCP, màn thiếu link → ❌ Missing → Status giữ `draft` · Screen Inventory/Specs/States · Interaction Patterns + Platform Considerations theo platform · AC-UI (Verified by) · **Self-Review Gate** trước khi ghi · chỉ FE/App (BE bị từ chối).
@@ -0,0 +1,11 @@
1
+ ---
2
+ description: Sinh tài liệu Design Specification cho platform FE hoặc App từ một Business PRD. Trigger when: "/generate-design-spec", "tạo design spec", "generate design spec", "viết design spec", "tạo tài liệu thiết kế UI", "generate UI spec", "cần design spec cho", "tôi muốn spec UI", "tài liệu cho FE", "tài liệu cho app".
3
+ ---
4
+
5
+ # /generate-design-spec — Generate Design Specification (FE / App)
6
+
7
+ Skill này xử lý `/generate-design-spec`. Để **không lệch gate/schema**, skill KHÔNG nhân bản — thực thi **y hệt** command.
8
+
9
+ → **Đọc và tuân theo `commands/generate-design-spec.md`** với cùng `$ARGUMENTS`.
10
+
11
+ Command lo: guard PRD approved (mềm) · ghi `Built from PRD` + Version Check drift · Figma per-screen node-level link (`?node-id=`) fetch qua MCP, màn thiếu link → ❌ Missing → Status giữ `draft` · Screen Inventory/Specs/States · Interaction Patterns + Platform Considerations theo platform · AC-UI (Verified by) · **Self-Review Gate** trước khi ghi · chỉ FE/App (BE bị từ chối).
@@ -0,0 +1,14 @@
1
+ ---
2
+ description: Dẫn dắt product discovery cho một feature mới qua Q&A có cấu trúc. Trigger when: "/define-product", "khám phá tính năng", "define new feature", "start new feature", "product discovery", "tôi muốn build tính năng mới", "let's define a feature", "begin feature discovery".
3
+ ---
4
+
5
+ # /define-product — Feature Discovery (Q&A theo phase)
6
+
7
+ Lệnh này thực thi **y hệt** `commands/define-product.md` — không nhân bản logic ở đây để tránh lệch cấu trúc / phase / path output.
8
+
9
+ `commands/define-product.md` dẫn PO qua các phase Q&A có checkpoint:
10
+ Knowledge Sync → Feature Definition (Context/Problem/Goal/Actor/In&Out Scope/User Story/Phụ thuộc liên service) → User Flow (kèm Edge Cases) → Clarification Log → Business Rules → Business Logic → Acceptance Criteria → Validation Report.
11
+
12
+ Output ghi `{paths.product_definitions_dir}/{TICKET-ID}-{slug}.md` theo `templates/product-definition.template.md` — input cho `/generate-prd`.
13
+
14
+ → **Đọc và tuân theo `commands/define-product.md`** với cùng `$ARGUMENTS`.