@xulthekl/team-flow 0.22.4

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 (405) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.agents/skills +1 -0
  3. package/.claude/always/phase-guard.md +3 -0
  4. package/.claude-plugin/marketplace.json +20 -0
  5. package/.claude-plugin/plugin.json +31 -0
  6. package/.codex-plugin/plugin.json +45 -0
  7. package/.codexignore +6 -0
  8. package/.cursor-plugin/marketplace.json +17 -0
  9. package/.cursor-plugin/plugin.json +31 -0
  10. package/.github/copilot-instructions.md +15 -0
  11. package/.github/dependabot.yml +10 -0
  12. package/.github/plugin/marketplace.json +42 -0
  13. package/.github/workflows/ci.yml +98 -0
  14. package/.github/workflows/hol-plugin-scanner.yml +17 -0
  15. package/.opencode/INSTALL.md +61 -0
  16. package/.opencode/plugins/team-flow.js +70 -0
  17. package/AGENTS.md +280 -0
  18. package/CHANGELOG.md +635 -0
  19. package/CONTRIBUTING.md +115 -0
  20. package/GEMINI.md +14 -0
  21. package/HANDOFF.md +219 -0
  22. package/INSTALL.md +810 -0
  23. package/LICENSE +21 -0
  24. package/README.md +185 -0
  25. package/SECURITY.md +37 -0
  26. package/agents/bug-investigator.md +180 -0
  27. package/agents/change-split-auditor.md +257 -0
  28. package/agents/code-reviewer.md +171 -0
  29. package/agents/cross-change-consistency-checker.md +215 -0
  30. package/agents/prd-completeness-reviewer.md +197 -0
  31. package/agents/prototype-builder.md +230 -0
  32. package/agents/prototype-env-scout.md +156 -0
  33. package/agents/prototype-reviewer.md +226 -0
  34. package/assets/icon.svg +6 -0
  35. package/dist/index.d.ts +13 -0
  36. package/dist/index.js +5 -0
  37. package/dist/parsing/change-parser.d.ts +12 -0
  38. package/dist/parsing/change-parser.js +54 -0
  39. package/dist/parsing/requirement-blocks.d.ts +31 -0
  40. package/dist/parsing/requirement-blocks.js +192 -0
  41. package/dist/schema/base.d.ts +7 -0
  42. package/dist/schema/base.js +1 -0
  43. package/dist/schema/change.d.ts +25 -0
  44. package/dist/schema/change.js +1 -0
  45. package/dist/schema/index.d.ts +3 -0
  46. package/dist/schema/index.js +1 -0
  47. package/dist/schema/spec.d.ts +11 -0
  48. package/dist/schema/spec.js +1 -0
  49. package/dist/validation/constants.d.ts +42 -0
  50. package/dist/validation/constants.js +42 -0
  51. package/dist/validation/tokenizer.d.ts +17 -0
  52. package/dist/validation/tokenizer.js +173 -0
  53. package/dist/validation/types.d.ts +40 -0
  54. package/dist/validation/types.js +1 -0
  55. package/dist/validation/validator.d.ts +21 -0
  56. package/dist/validation/validator.js +489 -0
  57. package/docs/README_en.md +358 -0
  58. package/docs/artifact-contract.md +96 -0
  59. package/docs/decision-points.md +88 -0
  60. package/docs/e2e-integration-design.md +207 -0
  61. package/docs/examples/README.md +25 -0
  62. package/docs/examples/add-dark-mode/README.md +13 -0
  63. package/docs/examples/add-dark-mode/design.md +49 -0
  64. package/docs/examples/add-dark-mode/execution-contract.md +56 -0
  65. package/docs/examples/add-dark-mode/proposal.md +46 -0
  66. package/docs/examples/add-dark-mode/specs/ui-theme/spec.md +35 -0
  67. package/docs/examples/add-dark-mode/tasks.md +26 -0
  68. package/docs/examples/refactor-auth-boundary/README.md +15 -0
  69. package/docs/examples/refactor-auth-boundary/design.md +41 -0
  70. package/docs/examples/refactor-auth-boundary/execution-contract.md +61 -0
  71. package/docs/examples/refactor-auth-boundary/proposal.md +47 -0
  72. package/docs/examples/refactor-auth-boundary/specs/auth-boundary/spec.md +45 -0
  73. package/docs/examples/refactor-auth-boundary/tasks.md +25 -0
  74. package/docs/plans/2026-07-07-fix-batch-design.md +68 -0
  75. package/docs/plans/2026-07-20-001-refactor-skill-collaboration-protocol-plan.md +128 -0
  76. package/docs/platform-matrix.md +45 -0
  77. package/docs/prototype-design-research.md +206 -0
  78. package/docs/release-checklist.md +96 -0
  79. package/docs/showcase.html +699 -0
  80. package/docs/skill-rename-v0.8.0.md +49 -0
  81. package/docs/state-machine.md +162 -0
  82. package/gemini-extension.json +6 -0
  83. package/hooks/hooks-cursor.json +8 -0
  84. package/hooks/hooks.json +26 -0
  85. package/hooks/pre-tool-use-guard +116 -0
  86. package/hooks/session-start +14 -0
  87. package/llms.txt +51 -0
  88. package/package.json +48 -0
  89. package/plugin.json +27 -0
  90. package/prd/v1/plan.md +443 -0
  91. package/prd/v1/prd.md +580 -0
  92. package/scripts/check-update.mjs +91 -0
  93. package/scripts/check-version-consistency.mjs +345 -0
  94. package/scripts/ensure-branch.mjs +71 -0
  95. package/scripts/get-config +31 -0
  96. package/scripts/guard/checks/artifacts-exist.mjs +36 -0
  97. package/scripts/guard/checks/contract-current.mjs +33 -0
  98. package/scripts/guard/checks/contract-fresh.mjs +17 -0
  99. package/scripts/guard/checks/dp-gate-passed.mjs +35 -0
  100. package/scripts/guard/checks/dp3-approved.mjs +22 -0
  101. package/scripts/guard/checks/execution-plan-ready.mjs +40 -0
  102. package/scripts/guard/checks/execution-reviews-passed.mjs +36 -0
  103. package/scripts/guard/checks/schema-valid.mjs +63 -0
  104. package/scripts/guard/checks/specs-merged.mjs +51 -0
  105. package/scripts/guard/checks/tasks-complete.mjs +31 -0
  106. package/scripts/guard/checks/tests-passing.mjs +31 -0
  107. package/scripts/guard/design-token-guard.mjs +237 -0
  108. package/scripts/guard/guard.mjs +205 -0
  109. package/scripts/infer-workflow.mjs +136 -0
  110. package/scripts/install-amazon-q.mjs +9 -0
  111. package/scripts/install-cline.mjs +9 -0
  112. package/scripts/install-continue.mjs +9 -0
  113. package/scripts/install-cursor.mjs +265 -0
  114. package/scripts/install-git-hooks.mjs +82 -0
  115. package/scripts/install-kiro.mjs +9 -0
  116. package/scripts/install-pi.mjs +9 -0
  117. package/scripts/install-qoder.mjs +9 -0
  118. package/scripts/install-qwen.mjs +9 -0
  119. package/scripts/install-roocode.mjs +9 -0
  120. package/scripts/install-windsurf.mjs +9 -0
  121. package/scripts/install-zcode.mjs +265 -0
  122. package/scripts/lib/cmd-audit.mjs +127 -0
  123. package/scripts/lib/cmd-checkpoint.mjs +118 -0
  124. package/scripts/lib/cmd-config.mjs +88 -0
  125. package/scripts/lib/cmd-doctor.mjs +267 -0
  126. package/scripts/lib/cmd-execution.mjs +206 -0
  127. package/scripts/lib/cmd-handoff.mjs +94 -0
  128. package/scripts/lib/cmd-inject.mjs +310 -0
  129. package/scripts/lib/cmd-install-amazon-q.mjs +11 -0
  130. package/scripts/lib/cmd-install-cline.mjs +11 -0
  131. package/scripts/lib/cmd-install-continue.mjs +11 -0
  132. package/scripts/lib/cmd-install-cursor.mjs +14 -0
  133. package/scripts/lib/cmd-install-kiro.mjs +11 -0
  134. package/scripts/lib/cmd-install-pi.mjs +11 -0
  135. package/scripts/lib/cmd-install-qoder.mjs +11 -0
  136. package/scripts/lib/cmd-install-qwen.mjs +11 -0
  137. package/scripts/lib/cmd-install-roocode.mjs +11 -0
  138. package/scripts/lib/cmd-install-windsurf.mjs +11 -0
  139. package/scripts/lib/cmd-install-workbuddy.mjs +359 -0
  140. package/scripts/lib/cmd-install-zcode.mjs +14 -0
  141. package/scripts/lib/cmd-isolate.mjs +37 -0
  142. package/scripts/lib/cmd-list.mjs +71 -0
  143. package/scripts/lib/cmd-runtime.mjs +85 -0
  144. package/scripts/lib/cmd-solutions.mjs +71 -0
  145. package/scripts/lib/cmd-state.mjs +231 -0
  146. package/scripts/lib/cmd-sync.mjs +102 -0
  147. package/scripts/lib/cmd-validate.mjs +105 -0
  148. package/scripts/lib/cmd-version.mjs +148 -0
  149. package/scripts/lib/config-loader.mjs +107 -0
  150. package/scripts/lib/execution-plan.mjs +492 -0
  151. package/scripts/lib/execution-recommendation.mjs +221 -0
  152. package/scripts/lib/hash.mjs +74 -0
  153. package/scripts/lib/install.mjs +267 -0
  154. package/scripts/lib/platform-runtime-inventory.mjs +27 -0
  155. package/scripts/lib/platforms.mjs +165 -0
  156. package/scripts/lib/prototype-sync.mjs +192 -0
  157. package/scripts/lib/sdd-overlay.mjs +262 -0
  158. package/scripts/lib/shell-quote.mjs +4 -0
  159. package/scripts/lib/solutions-capture.mjs +102 -0
  160. package/scripts/lib/solutions-index-gen.mjs +112 -0
  161. package/scripts/lib/solutions-inject.mjs +77 -0
  162. package/scripts/lib/solutions-promote.mjs +145 -0
  163. package/scripts/lib/spec-paths.mjs +85 -0
  164. package/scripts/lib/state-loader.mjs +154 -0
  165. package/scripts/lint/lint-skills.mjs +149 -0
  166. package/scripts/lint/rules/behavior-consistency.mjs +56 -0
  167. package/scripts/lint/rules/dp-trigger-points.mjs +60 -0
  168. package/scripts/lint/rules/exception-handling.mjs +59 -0
  169. package/scripts/lint/rules/no-contradictory-instructions.mjs +67 -0
  170. package/scripts/lint/rules/no-redundant-checks.mjs +50 -0
  171. package/scripts/lint/rules/token-rules.mjs +122 -0
  172. package/scripts/review-package +44 -0
  173. package/scripts/task-brief +40 -0
  174. package/scripts/team-flow.mjs +164 -0
  175. package/scripts/token-baseline.mjs +158 -0
  176. package/scripts/validate-artifacts +96 -0
  177. package/scripts/verify-marketplace-release.mjs +59 -0
  178. package/skills/architecture-design/SKILL.md +140 -0
  179. package/skills/architecture-design/chapters/ch01-4a-domains.md +27 -0
  180. package/skills/architecture-design/chapters/ch02-change-cascade.md +27 -0
  181. package/skills/architecture-design/chapters/ch03-architecture-outputs.md +25 -0
  182. package/skills/architecture-design/chapters/ch04-entity-to-aggregate.md +27 -0
  183. package/skills/architecture-design/chapters/ch05-cqrs.md +32 -0
  184. package/skills/architecture-design/chapters/ch06-integration.md +54 -0
  185. package/skills/architecture-design/cheatsheet.md +51 -0
  186. package/skills/architecture-design/glossary.md +23 -0
  187. package/skills/architecture-design/patterns.md +32 -0
  188. package/skills/bug-investigator/SKILL.md +77 -0
  189. package/skills/build-executor/SKILL.md +163 -0
  190. package/skills/build-executor/implementer-prompt.md +162 -0
  191. package/skills/build-executor/references/execution-modes.md +86 -0
  192. package/skills/build-executor/task-reviewer-prompt.md +195 -0
  193. package/skills/ce-brainstorm/SKILL.md +415 -0
  194. package/skills/ce-brainstorm/references/agents/slack-researcher.md +127 -0
  195. package/skills/ce-brainstorm/references/blindspot-pass.md +70 -0
  196. package/skills/ce-brainstorm/references/brainstorm-sections.md +285 -0
  197. package/skills/ce-brainstorm/references/handoff.md +168 -0
  198. package/skills/ce-brainstorm/references/html-rendering.md +634 -0
  199. package/skills/ce-brainstorm/references/markdown-rendering.md +241 -0
  200. package/skills/ce-brainstorm/references/model-tiers.md +9 -0
  201. package/skills/ce-brainstorm/references/prd-mapping.md +71 -0
  202. package/skills/ce-brainstorm/references/product-pressure-test.md +42 -0
  203. package/skills/ce-brainstorm/references/reasoning-elevation.md +63 -0
  204. package/skills/ce-brainstorm/references/settled-decisions.md +45 -0
  205. package/skills/ce-brainstorm/references/synthesis-summary.md +282 -0
  206. package/skills/ce-brainstorm/references/universal-brainstorming.md +73 -0
  207. package/skills/ce-brainstorm/references/verdict-routing.md +26 -0
  208. package/skills/ce-brainstorm/references/visual-probes.md +158 -0
  209. package/skills/ce-brainstorm/scripts/visual-probe-server.js +418 -0
  210. package/skills/ce-compound/SKILL.md +114 -0
  211. package/skills/ce-compound/assets/resolution-template.md +94 -0
  212. package/skills/ce-compound/references/agents/best-practices-researcher.md +115 -0
  213. package/skills/ce-compound/references/agents/data-integrity-guardian.md +68 -0
  214. package/skills/ce-compound/references/agents/framework-docs-researcher.md +93 -0
  215. package/skills/ce-compound/references/agents/pattern-recognition-specialist.md +55 -0
  216. package/skills/ce-compound/references/agents/performance-oracle.md +108 -0
  217. package/skills/ce-compound/references/agents/security-sentinel.md +91 -0
  218. package/skills/ce-compound/references/agents/session-historian.md +83 -0
  219. package/skills/ce-compound/references/concepts-vocabulary.md +78 -0
  220. package/skills/ce-compound/references/full-mode-workflow.md +413 -0
  221. package/skills/ce-compound/references/grounding-validation.md +84 -0
  222. package/skills/ce-compound/references/lightweight-mode.md +53 -0
  223. package/skills/ce-compound/references/output-standards.md +182 -0
  224. package/skills/ce-compound/references/promotion-rules.md +38 -0
  225. package/skills/ce-compound/references/schema.yaml +231 -0
  226. package/skills/ce-compound/references/three-tier-index.md +55 -0
  227. package/skills/ce-compound/references/v0.5-upgrade.md +32 -0
  228. package/skills/ce-compound/references/write-flow.md +36 -0
  229. package/skills/ce-compound/references/yaml-schema.md +118 -0
  230. package/skills/ce-compound/scripts/session-history/discover-sessions.sh +130 -0
  231. package/skills/ce-compound/scripts/session-history/extract-errors.py +254 -0
  232. package/skills/ce-compound/scripts/session-history/extract-metadata.py +456 -0
  233. package/skills/ce-compound/scripts/session-history/extract-skeleton.py +575 -0
  234. package/skills/ce-compound/scripts/validate-doc-claims.py +346 -0
  235. package/skills/ce-compound/scripts/validate-frontmatter.py +137 -0
  236. package/skills/ce-ideate/SKILL.md +402 -0
  237. package/skills/ce-ideate/references/agents/issue-intelligence-analyst.md +200 -0
  238. package/skills/ce-ideate/references/agents/learnings-researcher.md +247 -0
  239. package/skills/ce-ideate/references/agents/slack-researcher.md +127 -0
  240. package/skills/ce-ideate/references/agents/web-researcher.md +121 -0
  241. package/skills/ce-ideate/references/divergent-ideation.md +89 -0
  242. package/skills/ce-ideate/references/html-rendering.md +634 -0
  243. package/skills/ce-ideate/references/ideation-sections.md +191 -0
  244. package/skills/ce-ideate/references/markdown-rendering.md +238 -0
  245. package/skills/ce-ideate/references/post-ideation-workflow.md +167 -0
  246. package/skills/ce-ideate/references/universal-ideation.md +107 -0
  247. package/skills/ce-ideate/references/web-research-cache.md +56 -0
  248. package/skills/ce-plan/SKILL.md +137 -0
  249. package/skills/ce-plan/references/agents/agent-native-planning-strategist.md +62 -0
  250. package/skills/ce-plan/references/agents/architecture-strategist.md +46 -0
  251. package/skills/ce-plan/references/agents/best-practices-researcher.md +114 -0
  252. package/skills/ce-plan/references/agents/data-integrity-guardian.md +68 -0
  253. package/skills/ce-plan/references/agents/data-migration-reviewer.md +103 -0
  254. package/skills/ce-plan/references/agents/deployment-verification-agent.md +157 -0
  255. package/skills/ce-plan/references/agents/framework-docs-researcher.md +93 -0
  256. package/skills/ce-plan/references/agents/git-history-analyzer.md +40 -0
  257. package/skills/ce-plan/references/agents/learnings-researcher.md +247 -0
  258. package/skills/ce-plan/references/agents/pattern-recognition-specialist.md +55 -0
  259. package/skills/ce-plan/references/agents/performance-oracle.md +108 -0
  260. package/skills/ce-plan/references/agents/repo-research-analyst.md +258 -0
  261. package/skills/ce-plan/references/agents/security-sentinel.md +91 -0
  262. package/skills/ce-plan/references/agents/slack-researcher.md +127 -0
  263. package/skills/ce-plan/references/agents/spec-flow-analyzer.md +80 -0
  264. package/skills/ce-plan/references/agents/web-researcher.md +121 -0
  265. package/skills/ce-plan/references/approach-altitude.md +55 -0
  266. package/skills/ce-plan/references/change-splitting.md +65 -0
  267. package/skills/ce-plan/references/completion-contract.md +33 -0
  268. package/skills/ce-plan/references/core-principles.md +40 -0
  269. package/skills/ce-plan/references/deepening-workflow.md +263 -0
  270. package/skills/ce-plan/references/dependency-graph.md +36 -0
  271. package/skills/ce-plan/references/html-rendering.md +634 -0
  272. package/skills/ce-plan/references/intake-routing.md +189 -0
  273. package/skills/ce-plan/references/markdown-rendering.md +238 -0
  274. package/skills/ce-plan/references/plan-handoff.md +150 -0
  275. package/skills/ce-plan/references/plan-sections.md +427 -0
  276. package/skills/ce-plan/references/plan-structure.md +120 -0
  277. package/skills/ce-plan/references/planning-modes.md +69 -0
  278. package/skills/ce-plan/references/reasoning-elevation.md +63 -0
  279. package/skills/ce-plan/references/research-workflow.md +165 -0
  280. package/skills/ce-plan/references/review-and-write.md +127 -0
  281. package/skills/ce-plan/references/settled-decisions.md +45 -0
  282. package/skills/ce-plan/references/synthesis-summary.md +418 -0
  283. package/skills/ce-plan/references/universal-planning.md +168 -0
  284. package/skills/ce-proof/SKILL.md +346 -0
  285. package/skills/ce-strategy/SKILL.md +97 -0
  286. package/skills/ce-strategy/references/interview.md +143 -0
  287. package/skills/ce-strategy/references/strategy-template.md +89 -0
  288. package/skills/code-reviewer/SKILL.md +84 -0
  289. package/skills/code-reviewer/code-reviewer-prompt.md +195 -0
  290. package/skills/contract-builder/SKILL.md +72 -0
  291. package/skills/design-system/SKILL.md +75 -0
  292. package/skills/design-system/references/agents/design-system-architect.md +138 -0
  293. package/skills/design-system/references/creation-flow.md +170 -0
  294. package/skills/design-system/references/preview-template.html +319 -0
  295. package/skills/design-system/references/token-derivation.md +115 -0
  296. package/skills/design-system/references/variant-schema.md +60 -0
  297. package/skills/e2e/SKILL.md +56 -0
  298. package/skills/e2e/references/test-verifier.md +40 -0
  299. package/skills/need-explorer/SKILL.md +79 -0
  300. package/skills/prototype/SKILL.md +98 -0
  301. package/skills/prototype/references/agents/design-system-architect.md +122 -0
  302. package/skills/prototype/references/checklist.md +82 -0
  303. package/skills/prototype/references/craft/accessibility-baseline.md +71 -0
  304. package/skills/prototype/references/craft/anti-ai-slop.md +87 -0
  305. package/skills/prototype/references/craft/laws-of-ux.md +60 -0
  306. package/skills/prototype/references/craft/state-coverage.md +81 -0
  307. package/skills/prototype/references/craft/typography-hierarchy.md +50 -0
  308. package/skills/prototype/references/layouts.md +223 -0
  309. package/skills/prototype/references/orchestration-flow.md +101 -0
  310. package/skills/prototype/references/prototype-scaffold/assets/design-tokens.css +19 -0
  311. package/skills/prototype/references/prototype-scaffold/components/button.html +3 -0
  312. package/skills/prototype/references/prototype-scaffold/design-system.md +7 -0
  313. package/skills/prototype/references/prototype-scaffold/flow.md +11 -0
  314. package/skills/prototype/references/prototype-scaffold/index.html +20 -0
  315. package/skills/prototype/references/prototype-scaffold/pages/index.html +11 -0
  316. package/skills/prototype/references/template.html +396 -0
  317. package/skills/release-archivist/SKILL.md +166 -0
  318. package/skills/release-archivist/references/closing-procedures.md +81 -0
  319. package/skills/session-handoff/SKILL.md +110 -0
  320. package/skills/session-handoff/references/context-extraction.md +70 -0
  321. package/skills/session-handoff/references/handoff-template.md +90 -0
  322. package/skills/session-handoff/references/skill-recommendation.md +43 -0
  323. package/skills/spec-merger/SKILL.md +66 -0
  324. package/skills/spec-writer/SKILL.md +149 -0
  325. package/skills/workflow-bootstrap/SKILL.md +148 -0
  326. package/skills/workflow-bootstrap/references/agents/codebase-recon-analyst.md +121 -0
  327. package/skills/workflow-bootstrap/references/b1-reconnaissance.md +80 -0
  328. package/skills/workflow-bootstrap/scripts/recon-probe.sh +328 -0
  329. package/skills/workflow-feedback/SKILL.md +120 -0
  330. package/skills/workflow-feedback/references/category-guide.md +121 -0
  331. package/skills/workflow-feedback/references/feedback-template.md +73 -0
  332. package/skills/workflow-feedback/references/review-mode.md +92 -0
  333. package/skills/workflow-orchestrator/SKILL.md +94 -0
  334. package/skills/workflow-orchestrator/references/feedback-loops.md +56 -0
  335. package/skills/workflow-orchestrator/references/s1-path-router.md +81 -0
  336. package/skills/workflow-orchestrator/references/s2-prd-prototype-loop.md +96 -0
  337. package/skills/workflow-orchestrator/references/s3-plan-pipeline.md +50 -0
  338. package/skills/workflow-orchestrator/references/s4-split-validate.md +108 -0
  339. package/skills/workflow-orchestrator/references/s5-monitoring.md +61 -0
  340. package/skills/workflow-orchestrator/references/state-model.md +185 -0
  341. package/skills/workflow-start/SKILL.md +147 -0
  342. package/skills/workflow-start/references/routing-rules.md +155 -0
  343. package/src/index.ts +16 -0
  344. package/src/parsing/change-parser.ts +79 -0
  345. package/src/parsing/requirement-blocks.ts +244 -0
  346. package/src/schema/base.ts +8 -0
  347. package/src/schema/change.ts +29 -0
  348. package/src/schema/index.ts +3 -0
  349. package/src/schema/spec.ts +12 -0
  350. package/src/validation/constants.ts +53 -0
  351. package/src/validation/tokenizer.ts +180 -0
  352. package/src/validation/types.ts +47 -0
  353. package/src/validation/validator.ts +552 -0
  354. package/templates/abandonment-summary.md +29 -0
  355. package/templates/design.md +37 -0
  356. package/templates/execution-contract.md +99 -0
  357. package/templates/plan.md +86 -0
  358. package/templates/prd.md +468 -0
  359. package/templates/proposal.md +37 -0
  360. package/templates/spec.md +31 -0
  361. package/templates/tasks.md +47 -0
  362. package/tests/e2e.test.mjs +266 -0
  363. package/tests/lib/cmd-audit.test.mjs +202 -0
  364. package/tests/lib/cmd-checkpoint.test.mjs +98 -0
  365. package/tests/lib/cmd-config.test.mjs +101 -0
  366. package/tests/lib/cmd-doctor.test.mjs +450 -0
  367. package/tests/lib/cmd-execution.test.mjs +647 -0
  368. package/tests/lib/cmd-handoff.test.mjs +137 -0
  369. package/tests/lib/cmd-inject.test.mjs +218 -0
  370. package/tests/lib/cmd-install-workbuddy.test.mjs +113 -0
  371. package/tests/lib/cmd-install-zcode.test.mjs +42 -0
  372. package/tests/lib/cmd-isolate.test.mjs +68 -0
  373. package/tests/lib/cmd-list.test.mjs +127 -0
  374. package/tests/lib/cmd-runtime.test.mjs +83 -0
  375. package/tests/lib/cmd-state-missing.test.mjs +65 -0
  376. package/tests/lib/cmd-state.test.mjs +365 -0
  377. package/tests/lib/cmd-sync-paths.test.mjs +84 -0
  378. package/tests/lib/cmd-validate-paths.test.mjs +90 -0
  379. package/tests/lib/config-loader.test.mjs +175 -0
  380. package/tests/lib/ensure-branch.test.mjs +59 -0
  381. package/tests/lib/execution-control-plane.test.mjs +168 -0
  382. package/tests/lib/execution-plan.test.mjs +474 -0
  383. package/tests/lib/guard-specs-merged.test.mjs +108 -0
  384. package/tests/lib/guard-tests-passing.test.mjs +112 -0
  385. package/tests/lib/guard-transitions.test.mjs +262 -0
  386. package/tests/lib/guard.test.mjs +611 -0
  387. package/tests/lib/hash.test.mjs +138 -0
  388. package/tests/lib/infer-workflow.test.mjs +161 -0
  389. package/tests/lib/install-git-hooks.test.mjs +20 -0
  390. package/tests/lib/marketplace-release-docs.test.mjs +31 -0
  391. package/tests/lib/minimality-discipline.test.mjs +37 -0
  392. package/tests/lib/model-profiles-docs.test.mjs +33 -0
  393. package/tests/lib/node20-compatibility.test.mjs +73 -0
  394. package/tests/lib/node20-test-entry.test.mjs +17 -0
  395. package/tests/lib/platform-runtime-distribution.test.mjs +150 -0
  396. package/tests/lib/raw-mode-smoke.test.mjs +42 -0
  397. package/tests/lib/sdd-overlay.test.mjs +118 -0
  398. package/tests/lib/spec-paths.test.mjs +80 -0
  399. package/tests/lib/state-loader.test.mjs +251 -0
  400. package/tests/lib/token-baseline.test.mjs +72 -0
  401. package/tests/lib/token-rules.test.mjs +94 -0
  402. package/tests/lib/verify-marketplace-release.test.mjs +128 -0
  403. package/tests/tsconfig.json +12 -0
  404. package/token-baseline.json +95 -0
  405. package/tsconfig.json +14 -0
@@ -0,0 +1,31 @@
1
+ # 能力规格
2
+
3
+ ## ADDED Requirements
4
+
5
+ ### Requirement: 需求名称
6
+
7
+ The system SHALL 提供清晰且可测试的所需行为。
8
+
9
+ #### Scenario: 正常路径
10
+
11
+ - **WHEN** 触发动作发生
12
+ - **THEN** 系统产生预期结果
13
+
14
+ ## MODIFIED Requirements
15
+
16
+ ### Requirement: 现有需求名称
17
+
18
+ The system SHALL 按此处描述的更新行为执行。
19
+
20
+ #### Scenario: 更新后的行为
21
+
22
+ - **WHEN** 执行某个已知现有路径
23
+ - **THEN** 出现新的 approved behavior
24
+
25
+ ## REMOVED Requirements
26
+
27
+ ### Requirement: 已弃用需求名称
28
+
29
+ **Reason**: 为什么要移除该行为。
30
+
31
+ **Migration**: 应该用什么替代它。
@@ -0,0 +1,47 @@
1
+ # 实现任务
2
+
3
+ ## 文件结构
4
+
5
+ - `Create: path/to/new-file.ts` — 一句话说明职责
6
+ - `Modify: path/to/existing.ts` — 改什么、为什么
7
+
8
+ ## 接口
9
+
10
+ ### Batch N → Batch M
11
+ - **Produces**: `type/function name` — 被 Batch M 用于什么目的
12
+
13
+ ## 1. Batch 1: [批次目标]
14
+
15
+ - [ ] **1.1 编写失败的测试**
16
+
17
+ ```language
18
+ // 带精确断言的测试代码
19
+ ```
20
+
21
+ **Files**: `Create/Modify: exact/path`
22
+
23
+ - [ ] **1.2 运行测试并确认失败**
24
+
25
+ Run: `exact command`
26
+ Expected: FAIL with "specific error message"
27
+
28
+ - [ ] **1.3 实现最小化代码**
29
+
30
+ ```language
31
+ // 实现代码
32
+ ```
33
+
34
+ **Files**: `Create/Modify: exact/path`
35
+ **Interfaces**: Produces `name(type): returnType` — 被 Batch N 消费
36
+
37
+ - [ ] **1.4 运行测试并确认通过**
38
+
39
+ Run: `exact command`
40
+ Expected: PASS
41
+
42
+ - [ ] **1.5 提交**
43
+
44
+ ```bash
45
+ git add files
46
+ git commit -m "feat: description"
47
+ ```
@@ -0,0 +1,266 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFileSync } from 'node:fs';
4
+ import { resolve, dirname } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ import {
8
+ parseDeltaSpec,
9
+ parseChangeMarkdown,
10
+ Validator,
11
+ tokenize,
12
+ detectLanguage,
13
+ } from '../dist/index.js';
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ const EXAMPLES_DIR = resolve(__dirname, '../docs/examples');
17
+
18
+ function readExample(...parts) {
19
+ return readFileSync(resolve(EXAMPLES_DIR, ...parts), 'utf-8');
20
+ }
21
+
22
+ describe('parseDeltaSpec', () => {
23
+ it('parses add-dark-mode spec with 3 ADDED requirements', () => {
24
+ const content = readExample('add-dark-mode', 'specs', 'ui-theme', 'spec.md');
25
+ const plan = parseDeltaSpec(content);
26
+
27
+ assert.equal(plan.added.length, 3);
28
+ assert.equal(plan.modified.length, 0);
29
+ assert.equal(plan.removed.length, 0);
30
+ assert.equal(plan.renamed.length, 0);
31
+ assert.equal(plan.sectionPresence.added, true);
32
+
33
+ const names = plan.added.map(b => b.name);
34
+ assert.ok(names.includes('User can use dark mode'));
35
+ assert.ok(names.includes('User preference persists'));
36
+ assert.ok(names.includes('Theme maintains readable contrast'));
37
+ });
38
+
39
+ it('parses refactor-auth-boundary spec with 3 MODIFIED requirements', () => {
40
+ const content = readExample('refactor-auth-boundary', 'specs', 'auth-boundary', 'spec.md');
41
+ const plan = parseDeltaSpec(content);
42
+
43
+ assert.equal(plan.added.length, 0);
44
+ assert.equal(plan.modified.length, 3);
45
+ assert.equal(plan.removed.length, 0);
46
+ assert.equal(plan.renamed.length, 0);
47
+ assert.equal(plan.sectionPresence.modified, true);
48
+
49
+ const names = plan.modified.map(b => b.name);
50
+ assert.ok(names.includes('Protected requests use one authentication boundary'));
51
+ assert.ok(names.includes('Auth failures map consistently'));
52
+ assert.ok(names.includes('Existing approved login behavior remains unchanged'));
53
+ });
54
+ });
55
+
56
+ describe('parseChangeMarkdown', () => {
57
+ it('parses add-dark-mode proposal with why and whatChanges', () => {
58
+ const content = readExample('add-dark-mode', 'proposal.md');
59
+ const change = parseChangeMarkdown(content, 'add-dark-mode');
60
+
61
+ assert.equal(change.name, 'add-dark-mode');
62
+ assert.ok(change.why.length > 50, `why section too short: ${change.why.length} chars`);
63
+ assert.ok(change.whatChanges.length > 0, 'whatChanges section is empty');
64
+
65
+ // proposal.md uses "## Capabilities" not "## ADDED/MODIFIED Requirements"
66
+ // so deltas array will be empty (no delta sections found)
67
+ assert.equal(change.deltas.length, 0);
68
+ });
69
+
70
+ it('parses refactor-auth-boundary proposal with why and whatChanges', () => {
71
+ const content = readExample('refactor-auth-boundary', 'proposal.md');
72
+ const change = parseChangeMarkdown(content, 'refactor-auth-boundary');
73
+
74
+ assert.equal(change.name, 'refactor-auth-boundary');
75
+ assert.ok(change.why.length > 50, `why section too short: ${change.why.length} chars`);
76
+ assert.ok(change.whatChanges.length > 0, 'whatChanges section is empty');
77
+ });
78
+ });
79
+
80
+ describe('Validator.validateDeltaSpec', () => {
81
+ const validator = new Validator();
82
+
83
+ it('validates add-dark-mode delta spec structure', () => {
84
+ const content = readExample('add-dark-mode', 'specs', 'ui-theme', 'spec.md');
85
+ const report = validator.validateDeltaSpec(content);
86
+
87
+ // Delta specs should have deltas (ADDED/MODIFIED/REMOVED/RENAMED)
88
+ // The validator checks for presence of delta sections
89
+ assert.equal(report.valid, true, `Expected valid but got issues: ${JSON.stringify(report.issues, null, 2)}`);
90
+ assert.equal(report.summary.errors, 0);
91
+ });
92
+
93
+ it('validates refactor-auth-boundary delta spec structure', () => {
94
+ const content = readExample('refactor-auth-boundary', 'specs', 'auth-boundary', 'spec.md');
95
+ const report = validator.validateDeltaSpec(content);
96
+
97
+ assert.equal(report.valid, true, `Expected valid but got issues: ${JSON.stringify(report.issues, null, 2)}`);
98
+ assert.equal(report.summary.errors, 0);
99
+ });
100
+ });
101
+
102
+ describe('Validator.validateChangeContent', () => {
103
+ const validator = new Validator();
104
+
105
+ it('validates add-dark-mode proposal as valid', () => {
106
+ const content = readExample('add-dark-mode', 'proposal.md');
107
+ const report = validator.validateChangeContent('add-dark-mode', content);
108
+
109
+ assert.equal(report.valid, true, `Expected valid but got issues: ${JSON.stringify(report.issues, null, 2)}`);
110
+ assert.equal(report.summary.errors, 0);
111
+ });
112
+
113
+ it('validates refactor-auth-boundary proposal as valid', () => {
114
+ const content = readExample('refactor-auth-boundary', 'proposal.md');
115
+ const report = validator.validateChangeContent('refactor-auth-boundary', content);
116
+
117
+ assert.equal(report.valid, true, `Expected valid but got issues: ${JSON.stringify(report.issues, null, 2)}`);
118
+ assert.equal(report.summary.errors, 0);
119
+ });
120
+ });
121
+
122
+ describe('Validator.validateImplementation', () => {
123
+ const validator = new Validator();
124
+
125
+ it('returns VerificationReport with three dimensions', () => {
126
+ const report = validator.validateImplementation(
127
+ 'Added auth middleware in src/middleware/auth.ts',
128
+ '### Requirement: Auth middleware\nThe system SHALL authenticate all API requests.\n#### Scenario: Valid token\n- **WHEN** a request has a valid token\n- **THEN** the system SHALL allow access',
129
+ '## Decisions\n### Decision 1\n- Choice: JWT-based auth\n- Rationale: stateless'
130
+ );
131
+ assert.ok(report.dimensions);
132
+ assert.equal(report.dimensions.length, 3);
133
+ const names = report.dimensions.map(d => d.name);
134
+ assert.ok(names.includes('Completeness'));
135
+ assert.ok(names.includes('Correctness'));
136
+ assert.ok(names.includes('Coherence'));
137
+ assert.ok(['PASS', 'FAIL', 'CONDITIONAL'].includes(report.verdict));
138
+ });
139
+
140
+ it('detects missing requirement in diff (Completeness FAIL)', () => {
141
+ const report = validator.validateImplementation(
142
+ 'Added logging to src/utils/logger.ts',
143
+ '### Requirement: Auth middleware\nThe system SHALL authenticate all API requests.\n\n### Requirement: Rate limiting\nThe system SHALL limit requests to 100 per minute.',
144
+ '## Decisions\n### Decision 1\n- Choice: JWT\n- Rationale: stateless'
145
+ );
146
+ const completeness = report.dimensions.find(d => d.name === 'Completeness');
147
+ assert.ok(completeness);
148
+ assert.equal(completeness.status, 'FAIL');
149
+ assert.ok(completeness.findings.some(f => f.message.includes('Rate limiting')));
150
+ });
151
+
152
+ it('detects placeholder markers in diff (Correctness FAIL)', () => {
153
+ const report = validator.validateImplementation(
154
+ 'Added auth middleware. TODO: implement rate limiting',
155
+ '### Requirement: Auth middleware\nThe system SHALL authenticate all API requests.',
156
+ '## Decisions\n### Decision 1\n- Choice: JWT\n- Rationale: stateless'
157
+ );
158
+ const correctness = report.dimensions.find(d => d.name === 'Correctness');
159
+ assert.equal(correctness.status, 'FAIL');
160
+ });
161
+
162
+ it('passes when all requirements covered and no placeholders', () => {
163
+ const report = validator.validateImplementation(
164
+ 'Added JWT auth middleware in src/middleware/auth.ts, rate limiter in src/middleware/rate-limit.ts',
165
+ '### Requirement: Auth middleware\nThe system SHALL authenticate all API requests.\n\n### Requirement: Rate limiting\nThe system SHALL limit requests to 100 per minute.',
166
+ '## Decisions\n### Decision 1\n- Choice: JWT-based auth\n- Rationale: stateless'
167
+ );
168
+ assert.equal(report.verdict, 'PASS');
169
+ });
170
+
171
+ it('detects coherence gaps when design decisions not in diff', () => {
172
+ const report = validator.validateImplementation(
173
+ 'Added session-based auth in src/auth.ts',
174
+ '### Requirement: Auth middleware\nThe system SHALL authenticate all API requests.',
175
+ '## Decisions\n### Decision 1\n- Choice: JWT-based auth\n- Rationale: stateless'
176
+ );
177
+ const coherence = report.dimensions.find(d => d.name === 'Coherence');
178
+ assert.ok(coherence.findings.length > 0);
179
+ });
180
+
181
+ it('verifies Chinese spec content with Chinese tokenizer', () => {
182
+ const report = validator.validateImplementation(
183
+ '新增速率限制模块,使用令牌桶算法实现 src/middleware/rate-limit.ts',
184
+ '### Requirement: 速率限制\n系统必须实现令牌桶算法进行速率限制。\n#### Scenario: 正常请求\n- **WHEN** 请求频率在限制内\n- **THEN** 系统必须正常处理',
185
+ '## Decisions\n### Decision 1\n- Choice: 令牌桶算法\n- Rationale: 平滑限流'
186
+ );
187
+ const completeness = report.dimensions.find(d => d.name === 'Completeness');
188
+ assert.ok(completeness, 'Missing Completeness dimension');
189
+ assert.equal(completeness.status, 'PASS', `Expected PASS but got ${completeness.status}: ${JSON.stringify(completeness.findings)}`);
190
+ });
191
+
192
+ it('detects missing requirement in Chinese spec (Completeness FAIL)', () => {
193
+ const report = validator.validateImplementation(
194
+ '新增日志模块 src/utils/logger.ts',
195
+ '### Requirement: 速率限制\n系统必须实现令牌桶算法进行速率限制。\n\n### Requirement: 日志记录\n系统必须记录所有API请求日志。',
196
+ '## Decisions\n### Decision 1\n- Choice: 令牌桶算法\n- Rationale: 平滑限流'
197
+ );
198
+ const completeness = report.dimensions.find(d => d.name === 'Completeness');
199
+ assert.equal(completeness.status, 'FAIL');
200
+ assert.ok(completeness.findings.some(f => f.message.includes('速率限制')));
201
+ });
202
+ });
203
+
204
+ describe('tokenize', () => {
205
+ it('tokenizes English text with stemming', () => {
206
+ const tokens = tokenize('Rate limiting middleware implementation', 'en');
207
+ assert.ok(tokens.has('limit'), `Expected "limit" in tokens: ${[...tokens].join(', ')}`);
208
+ assert.ok(tokens.has('rate'), `Expected "rate" in tokens: ${[...tokens].join(', ')}`);
209
+ assert.ok(tokens.has('middleware'), `Expected "middleware" in tokens: ${[...tokens].join(', ')}`);
210
+ assert.ok(tokens.has('implement'), `Expected "implement" in tokens: ${[...tokens].join(', ')}`);
211
+ });
212
+
213
+ it('tokenizes Chinese text with CJK extraction', () => {
214
+ const tokens = tokenize('速率限制模块必须支持令牌桶算法', 'zh');
215
+ assert.ok(tokens.size > 0, 'Expected non-empty token set for Chinese text');
216
+ assert.ok(tokens.has('速率'), `Expected "速率" in tokens: ${[...tokens].join(', ')}`);
217
+ assert.ok(tokens.has('限制'), `Expected "限制" in tokens: ${[...tokens].join(', ')}`);
218
+ assert.ok(tokens.has('令牌'), `Expected "令牌" in tokens: ${[...tokens].join(', ')}`);
219
+ });
220
+
221
+ it('auto-detects language from text content', () => {
222
+ assert.equal(detectLanguage('Rate limiting middleware implementation'), 'en');
223
+ assert.equal(detectLanguage('速率限制模块必须支持令牌桶算法'), 'zh');
224
+ const mixed = detectLanguage('使用 Redis 实现速率限制模块的令牌桶算法');
225
+ assert.ok(['zh', 'mixed'].includes(mixed), `Expected zh or mixed, got: ${mixed}`);
226
+ });
227
+ });
228
+
229
+ describe('Validator.detectSyncConflicts', () => {
230
+ const validator = new Validator();
231
+
232
+ it('returns no conflicts when delta specs modify different requirements', () => {
233
+ const deltas = [
234
+ {
235
+ changeName: 'change-a',
236
+ content: '## MODIFIED Requirements\n### Requirement: Auth middleware\nThe system SHALL use JWT.\n#### Scenario: test\n- **WHEN** x\n- **THEN** y',
237
+ },
238
+ {
239
+ changeName: 'change-b',
240
+ content: '## MODIFIED Requirements\n### Requirement: Rate limiting\nThe system SHALL limit to 100 req/min.\n#### Scenario: test\n- **WHEN** x\n- **THEN** y',
241
+ },
242
+ ];
243
+ const report = validator.detectSyncConflicts(deltas);
244
+ assert.equal(report.hasConflicts, false);
245
+ assert.equal(report.conflicts.length, 0);
246
+ });
247
+
248
+ it('detects conflicts when two changes modify the same requirement', () => {
249
+ const deltas = [
250
+ {
251
+ changeName: 'change-a',
252
+ content: '## MODIFIED Requirements\n### Requirement: Auth middleware\nThe system SHALL use JWT tokens.\n#### Scenario: test\n- **WHEN** x\n- **THEN** y',
253
+ },
254
+ {
255
+ changeName: 'change-b',
256
+ content: '## MODIFIED Requirements\n### Requirement: Auth middleware\nThe system SHALL use session cookies.\n#### Scenario: test\n- **WHEN** x\n- **THEN** y',
257
+ },
258
+ ];
259
+ const report = validator.detectSyncConflicts(deltas);
260
+ assert.equal(report.hasConflicts, true);
261
+ assert.equal(report.conflicts.length, 1);
262
+ assert.equal(report.conflicts[0].requirement, 'Auth middleware');
263
+ assert.ok(report.conflicts[0].changes.includes('change-a'));
264
+ assert.ok(report.conflicts[0].changes.includes('change-b'));
265
+ });
266
+ });
@@ -0,0 +1,202 @@
1
+ // tests/lib/cmd-audit.test.mjs
2
+ // Tests for scripts/lib/cmd-audit.mjs
3
+ import { describe, it, before, after } from 'node:test';
4
+ import assert from 'node:assert/strict';
5
+ import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ import { tmpdir } from 'node:os';
8
+
9
+ let tempDir;
10
+
11
+ describe('cmd-audit: generateReport()', () => {
12
+ let generateReport, DP_NAMES;
13
+
14
+ before(async () => {
15
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-audit-test-'));
16
+ const modulePath = join(process.cwd(), 'scripts/lib/cmd-audit.mjs');
17
+ const mod = await import(modulePath);
18
+ generateReport = mod.generateReport;
19
+ DP_NAMES = mod.DP_NAMES;
20
+ });
21
+
22
+ after(() => {
23
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
24
+ });
25
+
26
+ it('generates report with all 8 DP rows (DP-0 through DP-7)', () => {
27
+ const state = {
28
+ change_name: 'test-change',
29
+ state: 'closing',
30
+ dp_0_result: 'confirmed',
31
+ dp_1_result: 'confirmed: csv export',
32
+ dp_2_result: 'approved: artifacts ok',
33
+ dp_3_result: 'contract signed',
34
+ dp_4_result: null,
35
+ dp_5_result: null,
36
+ dp_6_result: null,
37
+ dp_7_result: null,
38
+ };
39
+
40
+ const report = generateReport(tempDir, state);
41
+
42
+ // Should contain all 8 DPs in the summary table
43
+ for (let i = 0; i <= 7; i++) {
44
+ assert.ok(report.includes(`DP-${i}`), `Report should include DP-${i}`);
45
+ }
46
+ });
47
+
48
+ it('includes change name and state in header', () => {
49
+ const state = { change_name: 'export-csv', state: 'executing' };
50
+ const report = generateReport(tempDir, state);
51
+
52
+ assert.ok(report.includes('export-csv'));
53
+ assert.ok(report.includes('executing'));
54
+ assert.ok(report.includes('# Decision-Point Audit Report'));
55
+ });
56
+
57
+ it('reports correct recorded/missing counts', () => {
58
+ const state = {
59
+ change_name: 'test',
60
+ state: 'specifying',
61
+ dp_0_result: 'confirmed',
62
+ dp_1_result: 'confirmed: ok',
63
+ // dp_2 through dp_7 are all null (not recorded)
64
+ };
65
+
66
+ const report = generateReport(tempDir, state);
67
+
68
+ assert.ok(report.includes('2/8 已记录'), `Expected 2/8 recorded but got: ${report}`);
69
+ assert.ok(report.includes('6/8 未记录'), `Expected 6/8 missing but got: ${report}`);
70
+ });
71
+
72
+ it('treats confirmed DP-0 state as recorded without dp_0_result', () => {
73
+ const state = {
74
+ change_name: 'test',
75
+ state: 'specifying',
76
+ dp_0_decisions: 'scope confirmed',
77
+ dp_0_confirmed: 'true',
78
+ dp_0_timestamp: '2026-07-06T10:50:00Z',
79
+ };
80
+
81
+ const report = generateReport(tempDir, state);
82
+
83
+ assert.ok(
84
+ report.includes('| DP-0 | 用户确认门禁 | confirmed | 2026-07-06T10:50:00Z |'),
85
+ `Expected DP-0 to be recorded from dp_0_confirmed but got: ${report}`,
86
+ );
87
+ assert.ok(report.includes('1/8 已记录'), `Expected 1/8 recorded but got: ${report}`);
88
+ });
89
+
90
+ it('marks unrecorded DPs with interpretation hint', () => {
91
+ const state = {
92
+ change_name: 'test',
93
+ state: 'exploring',
94
+ // No DPs recorded at all
95
+ };
96
+
97
+ const report = generateReport(tempDir, state);
98
+
99
+ // Should have 'not recorded' for all DPs
100
+ const notRecordedCount = (report.match(/not recorded/g) || []).length;
101
+ assert.ok(notRecordedCount >= 8, `Expected at least 8 'not recorded' but got ${notRecordedCount}`);
102
+
103
+ // Unrecorded DPs should have the interpretation hint
104
+ assert.ok(report.includes('尚未记录结果'), 'Should include hint for unrecorded DPs');
105
+ });
106
+
107
+ it('includes all DP names from DP_NAMES constant', () => {
108
+ const state = {
109
+ change_name: 'test',
110
+ state: 'closing',
111
+ dp_0_result: 'ok',
112
+ dp_0_timestamp: '2026-07-01T00:00:00Z',
113
+ dp_1_result: 'ok',
114
+ dp_1_timestamp: '2026-07-01T00:00:00Z',
115
+ dp_2_result: 'ok',
116
+ dp_2_timestamp: '2026-07-01T00:00:00Z',
117
+ dp_3_result: 'ok',
118
+ dp_3_timestamp: '2026-07-01T00:00:00Z',
119
+ dp_4_result: 'ok',
120
+ dp_4_timestamp: '2026-07-01T00:00:00Z',
121
+ dp_5_result: 'ok',
122
+ dp_5_timestamp: '2026-07-01T00:00:00Z',
123
+ dp_6_result: 'ok',
124
+ dp_6_timestamp: '2026-07-01T00:00:00Z',
125
+ dp_7_result: 'ok',
126
+ dp_7_timestamp: '2026-07-01T00:00:00Z',
127
+ };
128
+
129
+ const report = generateReport(tempDir, state);
130
+
131
+ for (const [dpNum, name] of Object.entries(DP_NAMES)) {
132
+ assert.ok(report.includes(name), `Report should include DP-${dpNum} name: ${name}`);
133
+ }
134
+
135
+ assert.ok(report.includes('8/8 已记录'));
136
+ });
137
+
138
+ it('formats timestamps correctly', () => {
139
+ const state = {
140
+ change_name: 'test',
141
+ state: 'closing',
142
+ dp_0_result: 'confirmed',
143
+ dp_0_timestamp: '2026-07-01T08:30:00Z',
144
+ };
145
+
146
+ const report = generateReport(tempDir, state);
147
+ assert.ok(report.includes('2026-07-01T08:30:00Z'));
148
+ });
149
+
150
+ it('handles empty string as not recorded', () => {
151
+ const state = {
152
+ change_name: 'test',
153
+ state: 'exploring',
154
+ dp_0_result: '',
155
+ dp_0_timestamp: '',
156
+ };
157
+
158
+ const report = generateReport(tempDir, state);
159
+ assert.ok(report.includes('not recorded'), 'Empty strings should be treated as not recorded');
160
+ });
161
+
162
+ it('uses directory basename when change_name is null', () => {
163
+ const state = { state: 'exploring' };
164
+ const report = generateReport(tempDir, state);
165
+
166
+ // tempDir basename should appear
167
+ const dirName = tempDir.split('/').filter(Boolean).pop();
168
+ assert.ok(report.includes(dirName), `Report should include directory name "${dirName}" as fallback`);
169
+ });
170
+
171
+ it('generates per-DP interpretation section for each DP', () => {
172
+ const state = {
173
+ change_name: 'test',
174
+ state: 'bridging',
175
+ dp_0_result: 'confirmed: scope ok',
176
+ };
177
+
178
+ const report = generateReport(tempDir, state);
179
+
180
+ // Should have per-DP sections
181
+ for (let i = 0; i <= 7; i++) {
182
+ assert.ok(report.includes(`### DP-${i}`), `Report should have section for DP-${i}`);
183
+ }
184
+
185
+ // Recorded DP should have the recorded interpretation
186
+ assert.ok(report.includes('已记录为'));
187
+ });
188
+
189
+ it('generates a valid markdown table', () => {
190
+ const state = {
191
+ change_name: 'test',
192
+ state: 'specifying',
193
+ dp_0_result: 'confirmed',
194
+ };
195
+
196
+ const report = generateReport(tempDir, state);
197
+
198
+ // Verify table structure
199
+ assert.ok(report.includes('| DP | 名称 | 结果 | 时间戳 |'), 'Should have table header');
200
+ assert.ok(report.includes('|----|------|------|--------|'), 'Should have table separator');
201
+ });
202
+ });
@@ -0,0 +1,98 @@
1
+ // tests/lib/cmd-checkpoint.test.mjs
2
+ // Dispatcher-level tests for tf checkpoint.
3
+ import { describe, it, beforeEach, afterEach } from 'node:test';
4
+ import assert from 'node:assert/strict';
5
+ import { execFileSync } from 'node:child_process';
6
+ import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
7
+ import { tmpdir } from 'node:os';
8
+ import { join } from 'node:path';
9
+
10
+ const CLI = join(process.cwd(), 'scripts/team-flow.mjs');
11
+ let changeDir;
12
+
13
+ function runSsf(args) {
14
+ try {
15
+ const stdout = execFileSync(process.execPath, [CLI, ...args], {
16
+ encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
17
+ });
18
+ return { exitCode: 0, stdout, stderr: '' };
19
+ } catch (error) {
20
+ return {
21
+ exitCode: error.status || 1,
22
+ stdout: error.stdout?.toString() || '',
23
+ stderr: error.stderr?.toString() || error.message,
24
+ };
25
+ }
26
+ }
27
+
28
+ beforeEach(() => {
29
+ changeDir = mkdtempSync(join(tmpdir(), 'tf-checkpoint-'));
30
+ writeFileSync(join(changeDir, 'tasks.md'), '# Tasks\n\n- [ ] 1.1 Original task text\n');
31
+ });
32
+
33
+ afterEach(() => {
34
+ rmSync(changeDir, { recursive: true, force: true });
35
+ });
36
+
37
+ describe('tf checkpoint', () => {
38
+ it('advertises checkpoint and handoff syntax in --help', () => {
39
+ const result = runSsf(['--help']);
40
+ assert.equal(result.exitCode, 0, result.stderr);
41
+ assert.match(result.stdout, /checkpoint save <change-dir>/);
42
+ assert.match(result.stdout, /handoff create <change-dir>/);
43
+ });
44
+
45
+ it('saves and shows a task checkpoint', () => {
46
+ const result = runSsf([
47
+ 'checkpoint', 'save', changeDir, '--task', '1.1', '--next', 'Run focused tests',
48
+ '--completed', 'Added parser tests', '--verification', 'tests/lib/sdd-overlay.test.mjs',
49
+ '--review', 'review.md', '--risk', 'None', '--commit-start', 'aaaaaaa', '--commit-end', 'bbbbbbb',
50
+ ]);
51
+ assert.equal(result.exitCode, 0, result.stderr);
52
+ const show = runSsf(['checkpoint', 'show', changeDir, '1.1', '--json']);
53
+ assert.equal(show.exitCode, 0, show.stderr);
54
+ const shown = JSON.parse(show.stdout).checkpoint;
55
+ assert.equal(shown.next, 'Run focused tests');
56
+ assert.equal(shown.completed, 'Added parser tests');
57
+ assert.equal(shown.evidence, 'tests/lib/sdd-overlay.test.mjs');
58
+ assert.equal(shown.review, 'review.md');
59
+ assert.equal(shown.risk, 'None');
60
+ assert.equal(shown.commit_start, 'aaaaaaa');
61
+ assert.equal(shown.commit_end, 'bbbbbbb');
62
+
63
+ const listed = runSsf(['checkpoint', 'list', changeDir, '--json']);
64
+ assert.equal(listed.exitCode, 0, listed.stderr);
65
+ const listedCheckpoint = JSON.parse(listed.stdout).checkpoints[0];
66
+ assert.equal(listedCheckpoint.completed, 'Added parser tests');
67
+ assert.equal(listedCheckpoint.evidence, 'tests/lib/sdd-overlay.test.mjs');
68
+ assert.equal(listedCheckpoint.review, 'review.md');
69
+ assert.equal(listedCheckpoint.risk, 'None');
70
+ assert.equal(listedCheckpoint.commit_start, 'aaaaaaa');
71
+ assert.equal(listedCheckpoint.commit_end, 'bbbbbbb');
72
+ });
73
+
74
+ it('rejects save without --next before creating a checkpoint file', () => {
75
+ const result = runSsf(['checkpoint', 'save', changeDir, '--task', '1.1']);
76
+ assert.equal(result.exitCode, 2);
77
+ assert.equal(existsSync(join(changeDir, '.superpowers', 'sdd', 'checkpoints', '1.1.md')), false);
78
+ });
79
+
80
+ it('lists a stale checkpoint as JSON', () => {
81
+ const save = runSsf(['checkpoint', 'save', changeDir, '--task', '1.1', '--next', 'Run focused tests']);
82
+ assert.equal(save.exitCode, 0, save.stderr);
83
+ writeFileSync(join(changeDir, 'tasks.md'), '# Tasks\n\n- [ ] 1.1 Changed task text\n');
84
+
85
+ const result = runSsf(['checkpoint', 'list', changeDir, '--json']);
86
+ assert.equal(result.exitCode, 0, result.stderr);
87
+ const payload = JSON.parse(result.stdout);
88
+ assert.equal(payload.ok, true);
89
+ assert.equal(payload.checkpoints.length, 1);
90
+ assert.equal(payload.checkpoints[0].task_id, '1.1');
91
+ assert.equal(payload.checkpoints[0].stale, true);
92
+ });
93
+
94
+ it('rejects an unknown task ID when showing a checkpoint', () => {
95
+ const result = runSsf(['checkpoint', 'show', changeDir, '9.9']);
96
+ assert.equal(result.exitCode, 1);
97
+ });
98
+ });