@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,127 @@
1
+ // tests/lib/cmd-list.test.mjs
2
+ // Tests for scripts/lib/cmd-list.mjs — detectChangeStatus logic
3
+ import { describe, it, before, after } from 'node:test';
4
+ import assert from 'node:assert/strict';
5
+ import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ import { tmpdir } from 'node:os';
8
+
9
+ let tempDir;
10
+
11
+ describe('cmd-list: detectChangeStatus()', () => {
12
+ let detectChangeStatus;
13
+
14
+ before(async () => {
15
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-list-test-'));
16
+ const modulePath = join(process.cwd(), 'scripts/lib/cmd-list.mjs');
17
+ const mod = await import(modulePath);
18
+ detectChangeStatus = mod.detectChangeStatus;
19
+ });
20
+
21
+ after(() => {
22
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
23
+ });
24
+
25
+ function writeStateFile(dir, state) {
26
+ const lines = [];
27
+ for (const [key, value] of Object.entries(state)) {
28
+ lines.push(`${key}: ${value}`);
29
+ }
30
+ writeFileSync(join(dir, '.team-flow.yaml'), lines.join('\n'));
31
+ }
32
+
33
+ it('returns EXPLORING when state file says exploring', () => {
34
+ writeStateFile(tempDir, { state: 'exploring' });
35
+ const result = detectChangeStatus(tempDir);
36
+ assert.equal(result.status, 'EXPLORING');
37
+ assert.ok(result.detail.includes('exploring'));
38
+ });
39
+
40
+ it('returns SPECIFYING when state file says specifying', () => {
41
+ writeStateFile(tempDir, { state: 'specifying' });
42
+ const result = detectChangeStatus(tempDir);
43
+ assert.equal(result.status, 'SPECIFYING');
44
+ });
45
+
46
+ it('returns BRIDGED when state file says bridging', () => {
47
+ writeStateFile(tempDir, { state: 'bridging' });
48
+ const result = detectChangeStatus(tempDir);
49
+ assert.equal(result.status, 'BRIDGED');
50
+ });
51
+
52
+ it('returns APPROVED when state file says approved-for-build', () => {
53
+ writeStateFile(tempDir, { state: 'approved-for-build' });
54
+ const result = detectChangeStatus(tempDir);
55
+ assert.equal(result.status, 'APPROVED');
56
+ });
57
+
58
+ it('returns EXECUTING when state file says executing', () => {
59
+ writeStateFile(tempDir, { state: 'executing' });
60
+ const result = detectChangeStatus(tempDir);
61
+ assert.equal(result.status, 'EXECUTING');
62
+ });
63
+
64
+ it('returns DEBUGGING when state file says debugging', () => {
65
+ writeStateFile(tempDir, { state: 'debugging' });
66
+ const result = detectChangeStatus(tempDir);
67
+ assert.equal(result.status, 'DEBUGGING');
68
+ });
69
+
70
+ it('returns CLOSED when state file says closing', () => {
71
+ writeStateFile(tempDir, { state: 'closing' });
72
+ const result = detectChangeStatus(tempDir);
73
+ assert.equal(result.status, 'CLOSED');
74
+ });
75
+
76
+ it('returns ABANDONED when state file says abandoned', () => {
77
+ writeStateFile(tempDir, { state: 'abandoned' });
78
+ const result = detectChangeStatus(tempDir);
79
+ assert.equal(result.status, 'ABANDONED');
80
+ });
81
+
82
+ it('includes workflow mode in detail for non-full workflows', () => {
83
+ writeStateFile(tempDir, { state: 'executing', workflow: 'hotfix' });
84
+ const result = detectChangeStatus(tempDir);
85
+ assert.equal(result.status, 'EXECUTING');
86
+ assert.ok(result.detail.includes('hotfix'));
87
+ });
88
+
89
+ it('does not include workflow detail for full mode', () => {
90
+ writeStateFile(tempDir, { state: 'executing', workflow: 'full' });
91
+ const result = detectChangeStatus(tempDir);
92
+ assert.equal(result.status, 'EXECUTING');
93
+ assert.equal(result.detail, 'executing');
94
+ });
95
+
96
+ // Fallback: when no state file exists, infer from file presence
97
+ // Each test must clean up previous state file to test fallback path
98
+ it('falls back to INCOMPLETE when no state file and no proposal', () => {
99
+ rmSync(join(tempDir, '.team-flow.yaml'), { force: true });
100
+ const result = detectChangeStatus(tempDir);
101
+ assert.equal(result.status, 'INCOMPLETE');
102
+ assert.ok(result.detail.includes('Missing proposal.md'));
103
+ });
104
+
105
+ it('falls back to SPECIFYING when proposal exists but no contract and no state file', () => {
106
+ rmSync(join(tempDir, '.team-flow.yaml'), { force: true });
107
+ writeFileSync(join(tempDir, 'proposal.md'), '## Why\nTest proposal');
108
+ const result = detectChangeStatus(tempDir);
109
+ assert.equal(result.status, 'SPECIFYING');
110
+ });
111
+
112
+ it('falls back to ABANDONED when abandonment-summary.md exists', () => {
113
+ rmSync(join(tempDir, '.team-flow.yaml'), { force: true });
114
+ writeFileSync(join(tempDir, 'abandonment-summary.md'), '# Abandoned\nGave up on this');
115
+ const result = detectChangeStatus(tempDir);
116
+ assert.equal(result.status, 'ABANDONED');
117
+ });
118
+
119
+ it('falls back to UNKNOWN when artifacts exist but no state file', () => {
120
+ rmSync(join(tempDir, '.team-flow.yaml'), { force: true });
121
+ rmSync(join(tempDir, 'abandonment-summary.md'), { force: true });
122
+ writeFileSync(join(tempDir, 'proposal.md'), '## Why\nTest proposal');
123
+ writeFileSync(join(tempDir, 'execution-contract.md'), '## Intent Lock\nTest contract');
124
+ const result = detectChangeStatus(tempDir);
125
+ assert.equal(result.status, 'UNKNOWN');
126
+ });
127
+ });
@@ -0,0 +1,83 @@
1
+ // Runtime facade regression tests. These execute the public CLI so the
2
+ // canonical-skill protocol is tested without relying on a plugin-root env var.
3
+ import { afterEach, describe, it } from 'node:test';
4
+ import assert from 'node:assert/strict';
5
+ import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
6
+ import { spawnSync } from 'node:child_process';
7
+ import { join, delimiter } from 'node:path';
8
+ import { tmpdir } from 'node:os';
9
+
10
+ const ROOT = process.cwd();
11
+ const CLI = join(ROOT, 'scripts', 'team-flow.mjs');
12
+ const tempDirs = [];
13
+
14
+ afterEach(() => {
15
+ while (tempDirs.length > 0) {
16
+ rmSync(tempDirs.pop(), { recursive: true, force: true });
17
+ }
18
+ });
19
+
20
+ function runRuntime(args, options = {}) {
21
+ return spawnSync(process.execPath, [CLI, 'runtime', ...args], {
22
+ cwd: options.cwd || ROOT,
23
+ encoding: 'utf8',
24
+ env: { ...process.env, ...options.env },
25
+ });
26
+ }
27
+
28
+ describe('tf runtime', () => {
29
+ it('reads approved assets from the package root without a plugin-root environment variable', () => {
30
+ const result = runRuntime(['asset', 'read', 'templates/execution-contract.md'], {
31
+ env: { CLAUDE_PLUGIN_ROOT: '', PLUGIN_ROOT: '' },
32
+ });
33
+
34
+ assert.equal(result.status, 0, result.stderr);
35
+ assert.match(result.stdout, /# 执行合同/);
36
+ });
37
+
38
+ it('rejects traversal and assets outside the allowlist', () => {
39
+ const result = runRuntime(['asset', 'read', '../package.json']);
40
+
41
+ assert.equal(result.status, 2);
42
+ assert.match(result.stderr, /allowed|allowlist/i);
43
+ });
44
+
45
+ it('dispatches infer and guard while preserving their established output', () => {
46
+ const infer = runRuntime(['infer', '/tmp/tf-runtime-missing-change']);
47
+ const guard = runRuntime(['guard', 'check', 'docs/examples/add-dark-mode', 'exploring', 'specifying', '--json']);
48
+
49
+ assert.equal(infer.status, 0, infer.stderr);
50
+ assert.deepEqual(JSON.parse(infer.stdout).mode, 'full');
51
+ assert.equal(guard.status, 0, guard.stderr);
52
+ assert.equal(JSON.parse(guard.stdout).pass, true);
53
+ });
54
+
55
+ it('provides read-only config and rejects config writes', () => {
56
+ const tempDir = mkdtempSync(join(tmpdir(), 'tf-runtime-config-'));
57
+ tempDirs.push(tempDir);
58
+ const read = runRuntime(['config', '--get', 'execution.inlineThreshold'], { cwd: tempDir });
59
+ const write = runRuntime(['config', '--set', 'execution.inlineThreshold=99'], { cwd: tempDir });
60
+
61
+ assert.equal(read.status, 0, read.stderr);
62
+ assert.equal(read.stdout.trim(), '3');
63
+ assert.equal(write.status, 2);
64
+ assert.match(write.stderr, /read-only|--set/i);
65
+ });
66
+
67
+ it('uses the existing update-check result without requiring a global tf command', () => {
68
+ const tempDir = mkdtempSync(join(tmpdir(), 'tf-runtime-update-'));
69
+ tempDirs.push(tempDir);
70
+ const binDir = join(tempDir, 'bin');
71
+ const fakeNpm = join(binDir, 'npm');
72
+ mkdirSync(binDir);
73
+ writeFileSync(fakeNpm, '#!/bin/sh\nprintf "0.9.0\\n"\n', 'utf8');
74
+ chmodSync(fakeNpm, 0o755);
75
+
76
+ const result = runRuntime(['check-update'], {
77
+ env: { PATH: `${binDir}${delimiter}${process.env.PATH}` },
78
+ });
79
+
80
+ assert.equal(result.status, 0, result.stderr);
81
+ assert.match(result.stdout, /up to date/i);
82
+ });
83
+ });
@@ -0,0 +1,65 @@
1
+ // tests/lib/cmd-state-missing.test.mjs
2
+ // Regression for BUG-B: `tf state` subcommands must error (not silently drift)
3
+ // when the .team-flow.yaml does not exist. Previously `set` would create a
4
+ // phantom state file in the wrong directory.
5
+
6
+ import { describe, it, before, after } from 'node:test';
7
+ import assert from 'node:assert/strict';
8
+ import { execSync } from 'node:child_process';
9
+ import { mkdtempSync, rmSync, existsSync } from 'node:fs';
10
+ import { join } from 'node:path';
11
+ import { tmpdir } from 'node:os';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { dirname } from 'node:path';
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ const ROOT = join(__dirname, '..', '..');
17
+ const CLI = join(ROOT, 'scripts', 'team-flow.mjs');
18
+
19
+ function makeEmptyDir() {
20
+ // A directory with NO .team-flow.yaml on purpose.
21
+ return mkdtempSync(join(tmpdir(), 'tf-state-missing-'));
22
+ }
23
+
24
+ function cleanup(dir) {
25
+ if (existsSync(dir)) rmSync(dir, { recursive: true, force: true });
26
+ }
27
+
28
+ function run(args) {
29
+ try {
30
+ execSync(`node ${CLI} ${args}`, { stdio: 'pipe', timeout: 5000 });
31
+ return { ok: true, out: '' };
32
+ } catch (e) {
33
+ const out = `${e.stdout?.toString() || ''}\n${e.stderr?.toString() || ''}`;
34
+ return { ok: false, out: out || e.message };
35
+ }
36
+ }
37
+
38
+ describe('BUG-B: tf state errors on missing state file (no phantom drift)', () => {
39
+ let dir;
40
+ before(() => { dir = makeEmptyDir(); });
41
+ after(() => { cleanup(dir); });
42
+
43
+ it('SHALL error on `state transition` when no state file', () => {
44
+ const r = run(`state transition "${dir}" closing`);
45
+ assert.equal(r.ok, false, 'transition must fail without a state file');
46
+ assert.match(r.out, /No state file/i);
47
+ });
48
+
49
+ it('SHALL error on `state get` when no state file', () => {
50
+ const r = run(`state get "${dir}" workflow`);
51
+ assert.equal(r.ok, false, 'get must fail without a state file');
52
+ assert.match(r.out, /No state file/i);
53
+ });
54
+
55
+ it('SHALL error on `state set` and NOT create a phantom state file', () => {
56
+ const r = run(`state set "${dir}" dp_0_confirmed true`);
57
+ assert.equal(r.ok, false, 'set must fail without a state file');
58
+ assert.match(r.out, /No state file/i);
59
+ assert.equal(
60
+ existsSync(join(dir, '.team-flow.yaml')),
61
+ false,
62
+ 'set must NOT create a phantom .team-flow.yaml in a missing-state directory',
63
+ );
64
+ });
65
+ });
@@ -0,0 +1,365 @@
1
+ // tests/lib/cmd-state.test.mjs
2
+ // Tests for scripts/lib/cmd-state.mjs
3
+ import { describe, it, before, after } from 'node:test';
4
+ import assert from 'node:assert/strict';
5
+ import { mkdtempSync, writeFileSync, mkdirSync, rmSync, existsSync, chmodSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ import { tmpdir } from 'node:os';
8
+ import { execSync } from 'node:child_process';
9
+
10
+ const CLI_PATH = join(process.cwd(), 'scripts/team-flow.mjs');
11
+ let tempDir;
12
+
13
+ function tf(args, options = {}) {
14
+ try {
15
+ const result = execSync(
16
+ `${shellQuote(process.execPath)} ${shellQuote(CLI_PATH)} ${args}`,
17
+ { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], ...options }
18
+ );
19
+ return { exitCode: 0, stdout: result.trim(), stderr: '' };
20
+ } catch (err) {
21
+ return { exitCode: err.status || 1, stdout: err.stdout?.trim() || '', stderr: err.stderr?.trim() || err.message };
22
+ }
23
+ }
24
+
25
+ function shellQuote(value) {
26
+ return `'${value.replaceAll("'", "'\\''")}'`;
27
+ }
28
+
29
+ describe('cmd-state: init', () => {
30
+ before(() => {
31
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-state-cmd-'));
32
+ // Create minimal artifacts for hash computation
33
+ writeFileSync(join(tempDir, 'proposal.md'), '## Why\nTest proposal for state command testing, needs to be long enough for validation rules\n## What Changes\n- Add feature X');
34
+ });
35
+
36
+ after(() => {
37
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
38
+ });
39
+
40
+ it('creates .team-flow.yaml with hashes', () => {
41
+ const result = tf(`state init ${tempDir}`);
42
+ assert.equal(result.exitCode, 0, `Expected exit 0 but got ${result.exitCode}: ${result.stderr}`);
43
+
44
+ const stateFile = join(tempDir, '.team-flow.yaml');
45
+ assert.ok(existsSync(stateFile));
46
+ });
47
+
48
+ it('reports artifacts_hash in init output', () => {
49
+ const result = tf(`state init ${tempDir}`);
50
+ assert.ok(result.stdout.includes('artifacts_hash'));
51
+ });
52
+
53
+ it('--json flag outputs JSON with ok: true', () => {
54
+ const result = tf(`state init ${tempDir} --json`);
55
+ const parsed = JSON.parse(result.stdout);
56
+ assert.equal(parsed.ok, true);
57
+ assert.ok(parsed.artifacts_hash.startsWith('sha256:'));
58
+ });
59
+ });
60
+
61
+ describe('cmd-state: check', () => {
62
+ before(() => {
63
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-state-check-'));
64
+ writeFileSync(join(tempDir, 'proposal.md'), '## Why\nTest proposal for state checking with enough chars to pass validation rules.\n## What Changes\n- Feature X');
65
+ });
66
+
67
+ after(() => {
68
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
69
+ });
70
+
71
+ it('reports consistent after init', () => {
72
+ tf(`state init ${tempDir}`);
73
+ const result = tf(`state check ${tempDir}`);
74
+ assert.equal(result.exitCode, 0);
75
+ assert.ok(result.stdout.includes('consistent'));
76
+ });
77
+
78
+ it('reports inconsistent after artifact change', () => {
79
+ tf(`state init ${tempDir}`);
80
+ // Modify an artifact
81
+ writeFileSync(join(tempDir, 'proposal.md'), '## Why\nModified proposal with different content for inconsistency testing.\n## What Changes\n- Modified feature');
82
+ const result = tf(`state check ${tempDir}`);
83
+ assert.equal(result.exitCode, 1);
84
+ assert.ok(result.stdout.includes('INCONSISTENT'));
85
+ });
86
+
87
+ it('--json outputs structured data', () => {
88
+ tf(`state init ${tempDir}`);
89
+ const result = tf(`state check ${tempDir} --json`);
90
+ const parsed = JSON.parse(result.stdout);
91
+ assert.equal(parsed.consistent, true);
92
+ assert.ok(parsed.stored_hash);
93
+ assert.ok(parsed.current_hash);
94
+ assert.equal(parsed.state, 'exploring');
95
+ });
96
+ });
97
+
98
+ describe('cmd-state: transition', () => {
99
+ before(() => {
100
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-state-trans-'));
101
+ writeFileSync(join(tempDir, 'proposal.md'), '## Why\nTest proposal for state transition validation, meeting the minimum length requirement.\n## What Changes\n- Add feature');
102
+ writeFileSync(join(tempDir, 'design.md'), '# Design\n## Context\nTest.\n## Goals\nTest.\n## Decisions\n### D1\n- Choice: Test\n- Rationale: Test\n\n## Risks And Trade-Offs\nNone.');
103
+ writeFileSync(join(tempDir, 'tasks.md'), '# Tasks\n- [x] Task 1');
104
+ mkdirSync(join(tempDir, 'specs', 'test'), { recursive: true });
105
+ writeFileSync(join(tempDir, 'specs', 'test', 'spec.md'), '## ADDED Requirements\n### Requirement: Test\nSHALL work.\n#### Scenario: Test\n- **WHEN** test\n- **THEN** test');
106
+ });
107
+
108
+ after(() => {
109
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
110
+ });
111
+
112
+ it('transitions from exploring to specifying', () => {
113
+ tf(`state init ${tempDir}`);
114
+ const result = tf(`state transition ${tempDir} specifying`);
115
+ assert.equal(result.exitCode, 0);
116
+ assert.ok(result.stdout.includes('exploring -> specifying'));
117
+ });
118
+
119
+ it('--json outputs from/to', () => {
120
+ // Re-init to ensure we start from exploring
121
+ rmSync(join(tempDir, '.team-flow.yaml'), { force: true });
122
+ tf(`state init ${tempDir}`);
123
+ // exploring→specifying is the next legal mainline transition
124
+ const result = tf(`state transition ${tempDir} specifying --json`);
125
+ const parsed = JSON.parse(result.stdout);
126
+ assert.equal(parsed.ok, true);
127
+ assert.equal(parsed.from, 'exploring');
128
+ assert.equal(parsed.to, 'specifying');
129
+ });
130
+
131
+ it('persists state across invocations', () => {
132
+ tf(`state init ${tempDir}`);
133
+ // Legal transition: exploring → specifying
134
+ tf(`state transition ${tempDir} specifying`);
135
+
136
+ // Check state persisted
137
+ const result = tf(`state check ${tempDir} --json`);
138
+ const parsed = JSON.parse(result.stdout);
139
+ assert.equal(parsed.state, 'specifying');
140
+ });
141
+
142
+ it('rejects exploring to approved-for-build when workflow is auto', () => {
143
+ rmSync(join(tempDir, '.team-flow.yaml'), { force: true });
144
+ tf(`state init ${tempDir}`);
145
+
146
+ const result = tf(`state transition ${tempDir} approved-for-build`);
147
+ assert.equal(result.exitCode, 1);
148
+ const output = result.stderr || result.stdout;
149
+ assert.match(output, /workflow-mode/i);
150
+ assert.match(output, /fast-path/i);
151
+ assert.match(output, /tweak/i);
152
+
153
+ const check = tf(`state get ${tempDir} state`);
154
+ assert.equal(check.stdout.trim(), 'exploring');
155
+ });
156
+
157
+ it('rejects exploring to bridging when workflow is full', () => {
158
+ rmSync(join(tempDir, '.team-flow.yaml'), { force: true });
159
+ tf(`state init ${tempDir}`);
160
+ tf(`state set ${tempDir} workflow full`);
161
+
162
+ const result = tf(`state transition ${tempDir} bridging`);
163
+ assert.equal(result.exitCode, 1);
164
+ const output = result.stderr || result.stdout;
165
+ assert.match(output, /workflow-mode/i);
166
+ assert.match(output, /fast-path/i);
167
+ assert.match(output, /hotfix/i);
168
+
169
+ const check = tf(`state get ${tempDir} state`);
170
+ assert.equal(check.stdout.trim(), 'exploring');
171
+ });
172
+
173
+ it('rejects transition when guard output is not valid JSON', () => {
174
+ rmSync(join(tempDir, '.team-flow.yaml'), { force: true });
175
+ tf(`state init ${tempDir}`);
176
+ tf(`state set ${tempDir} workflow invalid-mode`);
177
+
178
+ const result = tf(`state transition ${tempDir} specifying`);
179
+ assert.equal(result.exitCode, 1);
180
+ assert.match(result.stderr || result.stdout, /valid JSON|Invalid workflow|guard-error/i);
181
+
182
+ const check = tf(`state get ${tempDir} state`);
183
+ assert.equal(check.stdout.trim(), 'exploring');
184
+ });
185
+
186
+ it('rejects transition when guard pass is a truthy non-boolean value', () => {
187
+ rmSync(join(tempDir, '.team-flow.yaml'), { force: true });
188
+ tf(`state init ${tempDir}`);
189
+
190
+ const shimDir = mkdtempSync(join(tmpdir(), 'tf-node-shim-'));
191
+ const nodeShim = join(shimDir, 'node');
192
+ writeFileSync(nodeShim, [
193
+ '#!/bin/sh',
194
+ 'case "$1" in',
195
+ ' */scripts/guard/guard.mjs)',
196
+ ' printf \'%s\\n\' \'{"pass":"false","checks":[]}\'',
197
+ ' exit 0',
198
+ ' ;;',
199
+ 'esac',
200
+ `exec ${shellQuote(process.execPath)} "$@"`,
201
+ '',
202
+ ].join('\n'));
203
+ chmodSync(nodeShim, 0o755);
204
+
205
+ try {
206
+ const result = tf(`state transition ${tempDir} specifying`, {
207
+ env: { ...process.env, PATH: `${shimDir}:${process.env.PATH}` },
208
+ });
209
+ assert.equal(result.exitCode, 1);
210
+ assert.match(result.stderr || result.stdout, /guard-error|Guard check failed/i);
211
+
212
+ const check = tf(`state get ${tempDir} state`);
213
+ assert.equal(check.stdout.trim(), 'exploring');
214
+ } finally {
215
+ rmSync(shimDir, { recursive: true, force: true });
216
+ }
217
+ });
218
+
219
+ it('reports guard spawn errors without changing state', () => {
220
+ rmSync(join(tempDir, '.team-flow.yaml'), { force: true });
221
+ tf(`state init ${tempDir}`);
222
+
223
+ const result = tf(`state transition ${tempDir} specifying`, {
224
+ env: { ...process.env, PATH: '' },
225
+ });
226
+ assert.equal(result.exitCode, 1);
227
+ const output = result.stderr || result.stdout;
228
+ assert.match(output, /guard-error|spawn|ENOENT/i);
229
+ assert.doesNotMatch(output, /TypeError/i);
230
+
231
+ const check = tf(`state get ${tempDir} state`);
232
+ assert.equal(check.stdout.trim(), 'exploring');
233
+ });
234
+ });
235
+
236
+ describe('cmd-state: get', () => {
237
+ before(() => {
238
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-state-get-'));
239
+ writeFileSync(join(tempDir, 'proposal.md'), '## Why\nTest proposal for get command, needs to be long enough.\n## What Changes\n- Feature');
240
+ });
241
+
242
+ after(() => {
243
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
244
+ });
245
+
246
+ it('gets a field value', () => {
247
+ tf(`state init ${tempDir}`);
248
+ const result = tf(`state get ${tempDir} state`);
249
+ assert.equal(result.exitCode, 0);
250
+ assert.equal(result.stdout.trim(), 'exploring');
251
+ });
252
+
253
+ it('returns null for unset fields', () => {
254
+ tf(`state init ${tempDir}`);
255
+ const result = tf(`state get ${tempDir} dp_5_result`);
256
+ assert.ok(result.stdout.includes('null'));
257
+ });
258
+
259
+ it('--json returns structured output', () => {
260
+ tf(`state init ${tempDir}`);
261
+ const result = tf(`state get ${tempDir} state --json`);
262
+ const parsed = JSON.parse(result.stdout);
263
+ assert.equal(parsed.field, 'state');
264
+ assert.equal(parsed.value, 'exploring');
265
+ });
266
+
267
+ it('errors without field argument', () => {
268
+ const result = tf(`state get ${tempDir}`);
269
+ assert.equal(result.exitCode, 2);
270
+ });
271
+ });
272
+
273
+ describe('cmd-state: set', () => {
274
+ before(() => {
275
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-state-set-'));
276
+ writeFileSync(join(tempDir, 'proposal.md'), '## Why\nTest proposal for the set subcommand validation.\n## What Changes\n- Test feature');
277
+ });
278
+
279
+ after(() => {
280
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
281
+ });
282
+
283
+ it('sets a settable field', () => {
284
+ tf(`state init ${tempDir}`);
285
+ const result = tf(`state set ${tempDir} workflow hotfix`);
286
+ assert.equal(result.exitCode, 0);
287
+ assert.ok(result.stdout.includes('hotfix'));
288
+ });
289
+
290
+ it('sets a DP field', () => {
291
+ tf(`state init ${tempDir}`);
292
+ tf(`state set ${tempDir} dp_1_result "confirmed: csv export"`);
293
+ const get = tf(`state get ${tempDir} dp_1_result`);
294
+ assert.ok(get.stdout.includes('confirmed: csv export'));
295
+ });
296
+
297
+ it('rejects non-settable fields', () => {
298
+ tf(`state init ${tempDir}`);
299
+ const result = tf(`state set ${tempDir} state executing`);
300
+ assert.equal(result.exitCode, 1);
301
+ // Error goes to stderr for console.error
302
+ assert.ok(result.stderr.includes('not settable') || result.stdout.includes('not settable'),
303
+ `Expected 'not settable' in output but got stdout: "${result.stdout}" stderr: "${result.stderr}"`);
304
+ });
305
+
306
+ it('rejects manual edits to execution DP-4 fields', () => {
307
+ tf(`state init ${tempDir}`);
308
+ const result = tf(`state set ${tempDir} dp_4_result "forged execution approval"`);
309
+ assert.equal(result.exitCode, 1);
310
+ assert.match(result.stderr || result.stdout, /not settable/);
311
+ });
312
+
313
+ it('rejects unknown fields', () => {
314
+ tf(`state init ${tempDir}`);
315
+ const result = tf(`state set ${tempDir} nonexistent_field value`);
316
+ assert.equal(result.exitCode, 1);
317
+ });
318
+
319
+ it('--json outputs structured result', () => {
320
+ tf(`state init ${tempDir}`);
321
+ const result = tf(`state set ${tempDir} test_result pass --json`);
322
+ const parsed = JSON.parse(result.stdout);
323
+ assert.equal(parsed.ok, true);
324
+ assert.equal(parsed.field, 'test_result');
325
+ assert.equal(parsed.value, 'pass');
326
+ });
327
+ });
328
+
329
+ describe('cmd-state: rebuild', () => {
330
+ before(() => {
331
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-state-rebuild-'));
332
+ writeFileSync(join(tempDir, 'proposal.md'), '## Why\nRebuild test proposal with sufficient content length.\n## What Changes\n- Rebuild feature');
333
+ });
334
+
335
+ after(() => {
336
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
337
+ });
338
+
339
+ it('rebuilds state from artifacts', () => {
340
+ tf(`state init ${tempDir}`);
341
+ const result = tf(`state rebuild ${tempDir}`);
342
+ assert.equal(result.exitCode, 0);
343
+ assert.ok(result.stdout.includes('rebuilt'));
344
+ });
345
+
346
+ it('--json returns ok with state', () => {
347
+ tf(`state init ${tempDir}`);
348
+ const result = tf(`state rebuild ${tempDir} --json`);
349
+ const parsed = JSON.parse(result.stdout);
350
+ assert.equal(parsed.ok, true);
351
+ assert.equal(parsed.state, 'exploring');
352
+ });
353
+ });
354
+
355
+ describe('cmd-state: error handling', () => {
356
+ it('errors when no change-dir provided', () => {
357
+ const result = tf('state init');
358
+ assert.equal(result.exitCode, 2);
359
+ });
360
+
361
+ it('errors on unknown subcommand', () => {
362
+ const result = tf('state invalid-subcommand /tmp');
363
+ assert.equal(result.exitCode, 2);
364
+ });
365
+ });