@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,345 @@
1
+ #!/usr/bin/env node
2
+ // check-version-consistency.mjs — CI guard: fail if any file has a version
3
+ // that doesn't match package.json. Prevents doc/code drift after tf version.
4
+ //
5
+ // Usage:
6
+ // node scripts/check-version-consistency.mjs # check only (exit 1 on mismatch)
7
+ // node scripts/check-version-consistency.mjs --fix # auto-fix skill counts & npx refs
8
+ //
9
+ // Exit 0: all versions consistent (or fixed successfully)
10
+ // Exit 1: mismatches found (lists every file and its version)
11
+
12
+ import { readFileSync, writeFileSync, readdirSync, existsSync } from 'node:fs';
13
+ import { join, dirname } from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+
16
+ const __dirname = dirname(fileURLToPath(import.meta.url));
17
+ const ROOT = join(__dirname, '..');
18
+ const AUTO_FIX = process.argv.includes('--fix');
19
+
20
+ // Canonical version from package.json
21
+ const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8'));
22
+ const CANONICAL = pkg.version;
23
+ if (!CANONICAL || !/^\d+\.\d+\.\d+$/.test(CANONICAL)) {
24
+ console.error('❌ package.json version is missing or invalid');
25
+ process.exit(1);
26
+ }
27
+
28
+ const errors = [];
29
+ const fixes = [];
30
+
31
+ // ── JSON manifests ──
32
+ const JSON_CHECKS = [
33
+ { file: 'plugin.json', path: ['version'] },
34
+ { file: '.claude-plugin/plugin.json', path: ['version'] },
35
+ { file: '.claude-plugin/marketplace.json', path: ['plugins', '0', 'version'] },
36
+ { file: '.cursor-plugin/plugin.json', path: ['version'] },
37
+ { file: '.cursor-plugin/marketplace.json', path: ['metadata', 'version'] },
38
+ { file: '.codex-plugin/plugin.json', path: ['version'] },
39
+ { file: 'gemini-extension.json', path: ['version'] },
40
+ { file: '.github/plugin/marketplace.json', path: ['metadata', 'version'] },
41
+ { file: '.github/plugin/marketplace.json', path: ['plugins', '0', 'version'] },
42
+ ];
43
+
44
+ for (const check of JSON_CHECKS) {
45
+ const fp = join(ROOT, check.file);
46
+ if (!existsSync(fp)) {
47
+ errors.push({ file: check.file, found: 'FILE_NOT_FOUND', expected: CANONICAL });
48
+ continue;
49
+ }
50
+ try {
51
+ const obj = JSON.parse(readFileSync(fp, 'utf-8'));
52
+ let val = obj;
53
+ for (const p of check.path) val = val?.[p];
54
+ if (val !== CANONICAL) {
55
+ errors.push({ file: `${check.file} [${check.path.join('.')}]`, found: val, expected: CANONICAL });
56
+ }
57
+ } catch (e) {
58
+ errors.push({ file: check.file, found: `PARSE_ERROR: ${e.message}`, expected: CANONICAL });
59
+ }
60
+ }
61
+
62
+ // ── Text files (extraction-pattern check) ──
63
+ // Each entry has a regex that extracts ONLY the declared version (capture group 1),
64
+ // not historical references like "v0.6.0 起支持".
65
+ // Note: CLAUDE.md is intentionally gitignored (project-local AI instructions).
66
+ const TEXT_CHECKS = [
67
+ { file: 'README.md', extract: /当前版本:`v(\d+\.\d+\.\d+)`/ },
68
+ { file: 'INSTALL.md', extract: /当前发布版本:\*\*v(\d+\.\d+\.\d+)\*\*/ },
69
+ { file: 'docs/README_en.md', extract: /Current: `v(\d+\.\d+\.\d+)`/ },
70
+ { file: 'hooks/session-start', extract: /# v(\d+\.\d+\.\d+): conditional injection/ },
71
+ { file: 'llms.txt', extract: /Current version: v(\d+\.\d+\.\d+)\./ },
72
+ { file: '.claude/always/phase-guard.md', extract: /# team-flow v(\d+\.\d+\.\d+) \|/ },
73
+ { file: 'GEMINI.md', extract: /# team-flow v(\d+\.\d+\.\d+) \|/ },
74
+ ];
75
+
76
+ for (const check of TEXT_CHECKS) {
77
+ const fp = join(ROOT, check.file);
78
+ if (!existsSync(fp)) {
79
+ errors.push({ file: check.file, found: 'FILE_NOT_FOUND', expected: CANONICAL });
80
+ continue;
81
+ }
82
+ const content = readFileSync(fp, 'utf-8');
83
+ const match = content.match(check.extract);
84
+ if (!match) {
85
+ errors.push({ file: check.file, found: 'PATTERN_NOT_MATCHED', expected: CANONICAL });
86
+ } else if (match[1] !== CANONICAL) {
87
+ errors.push({ file: check.file, found: match[1], expected: CANONICAL });
88
+ }
89
+ }
90
+
91
+ const RUNTIME_FILES = [
92
+ 'workflow-start', 'need-explorer', 'spec-writer', 'contract-builder',
93
+ 'build-executor', 'code-reviewer', 'bug-investigator', 'release-archivist', 'spec-merger',
94
+ ].map(skill => `skills/${skill}/SKILL.md`).concat([
95
+ 'skills/build-executor/implementer-prompt.md',
96
+ 'skills/build-executor/task-reviewer-prompt.md',
97
+ 'skills/code-reviewer/code-reviewer-prompt.md',
98
+ ]);
99
+ for (const file of RUNTIME_FILES) {
100
+ const fp = join(ROOT, file);
101
+ if (!existsSync(fp)) {
102
+ errors.push({ file, found: 'FILE_NOT_FOUND', expected: CANONICAL });
103
+ continue;
104
+ }
105
+ const versions = [...readFileSync(fp, 'utf8').matchAll(/npx --yes --package @xulthekl\/team-flow@(\d+\.\d+\.\d+) tf/g)]
106
+ .map(match => match[1]);
107
+ if (versions.length === 0) {
108
+ errors.push({ file, found: 'RUNTIME_PREFIX_NOT_FOUND', expected: CANONICAL });
109
+ } else if (versions.some(version => version !== CANONICAL)) {
110
+ errors.push({ file, found: [...new Set(versions)].join(', '), expected: CANONICAL });
111
+ }
112
+ }
113
+
114
+ // ── Skill count consistency ──
115
+ // Count actual skill directories under skills/ and compare against the count
116
+ // documented in manifests and docs. Prevents skill-count drift after add/remove.
117
+ const skillsDir = join(ROOT, 'skills');
118
+ const skillDirs = readdirSync(skillsDir, { withFileTypes: true })
119
+ .filter(entry => entry.isDirectory());
120
+ const ACTUAL_SKILL_COUNT = skillDirs.length;
121
+
122
+ // JSON manifests: extract the "N skills" number from the description field.
123
+ const SKILL_COUNT_JSON_CHECKS = [
124
+ { file: 'plugin.json', path: ['description'], extract: /(\d+) skills/ },
125
+ { file: '.claude-plugin/plugin.json', path: ['description'], extract: /(\d+) skills/ },
126
+ ];
127
+
128
+ for (const check of SKILL_COUNT_JSON_CHECKS) {
129
+ const fp = join(ROOT, check.file);
130
+ if (!existsSync(fp)) {
131
+ errors.push({ file: check.file, found: 'FILE_NOT_FOUND', expected: ACTUAL_SKILL_COUNT });
132
+ continue;
133
+ }
134
+ try {
135
+ const obj = JSON.parse(readFileSync(fp, 'utf-8'));
136
+ let val = obj;
137
+ for (const p of check.path) val = val?.[p];
138
+ const match = typeof val === 'string' ? val.match(check.extract) : null;
139
+ if (!match) {
140
+ errors.push({ file: `${check.file} [${check.path.join('.')}]`, found: 'PATTERN_NOT_MATCHED', expected: ACTUAL_SKILL_COUNT });
141
+ } else if (Number(match[1]) !== ACTUAL_SKILL_COUNT) {
142
+ if (AUTO_FIX) {
143
+ // Auto-fix: update skill count in JSON
144
+ const newVal = val.replace(check.extract, `${ACTUAL_SKILL_COUNT} skills`);
145
+ obj[check.path[0]] = newVal;
146
+ writeFileSync(fp, JSON.stringify(obj, null, 2) + '\n', 'utf-8');
147
+ fixes.push(`${check.file}: ${match[1]} → ${ACTUAL_SKILL_COUNT}`);
148
+ } else {
149
+ errors.push({ file: `${check.file} [${check.path.join('.')}]`, found: match[1], expected: ACTUAL_SKILL_COUNT });
150
+ }
151
+ }
152
+ } catch (e) {
153
+ errors.push({ file: check.file, found: `PARSE_ERROR: ${e.message}`, expected: ACTUAL_SKILL_COUNT });
154
+ }
155
+ }
156
+
157
+ // Text files: extract the documented skill count.
158
+ const SKILL_COUNT_TEXT_CHECKS = [
159
+ { file: 'README.md', extract: /(\d+) skills/, replace: (content, count) => content.replace(/(\d+) skills/, `${count} skills`) },
160
+ { file: 'AGENTS.md', extract: /Skills 索引((\d+) 个)/, replace: (content, count) => content.replace(/Skills 索引((\d+) 个)/, `Skills 索引(${count} 个)`) },
161
+ ];
162
+
163
+ for (const check of SKILL_COUNT_TEXT_CHECKS) {
164
+ const fp = join(ROOT, check.file);
165
+ if (!existsSync(fp)) {
166
+ errors.push({ file: check.file, found: 'FILE_NOT_FOUND', expected: ACTUAL_SKILL_COUNT });
167
+ continue;
168
+ }
169
+ const content = readFileSync(fp, 'utf-8');
170
+ const match = content.match(check.extract);
171
+ if (!match) {
172
+ errors.push({ file: check.file, found: 'PATTERN_NOT_MATCHED', expected: ACTUAL_SKILL_COUNT });
173
+ } else if (Number(match[1]) !== ACTUAL_SKILL_COUNT) {
174
+ if (AUTO_FIX) {
175
+ // Auto-fix: update skill count in text
176
+ const newContent = check.replace(content, ACTUAL_SKILL_COUNT);
177
+ writeFileSync(fp, newContent, 'utf-8');
178
+ fixes.push(`${check.file}: ${match[1]} → ${ACTUAL_SKILL_COUNT}`);
179
+ } else {
180
+ errors.push({ file: check.file, found: match[1], expected: ACTUAL_SKILL_COUNT });
181
+ }
182
+ }
183
+ }
184
+
185
+ // ── npx version reference consistency ──
186
+ // Scan every skills/*/SKILL.md for `team-flow@X.Y.Z` references and ensure
187
+ // each one matches the canonical version. Catches stale npx pins in any skill —
188
+ // broader than RUNTIME_FILES above, which only covers the known runtime set.
189
+ const SKILL_MD_FILES = skillDirs
190
+ .map(entry => `skills/${entry.name}/SKILL.md`)
191
+ .filter(file => existsSync(join(ROOT, file)));
192
+
193
+ // Also scan references/ subdirectories for stale npx refs
194
+ const REFERENCES_FILES = [];
195
+ function scanDir(dir, prefix = '') {
196
+ const entries = readdirSync(dir, { withFileTypes: true });
197
+ for (const entry of entries) {
198
+ const fullPath = join(dir, entry.name);
199
+ const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
200
+ if (entry.isDirectory()) {
201
+ scanDir(fullPath, relPath);
202
+ } else if (entry.name.endsWith('.md')) {
203
+ REFERENCES_FILES.push(relPath);
204
+ }
205
+ }
206
+ }
207
+ const refsDir = join(ROOT, 'skills');
208
+ for (const skillEntry of skillDirs) {
209
+ const refsPath = join(refsDir, skillEntry.name, 'references');
210
+ if (existsSync(refsPath)) {
211
+ scanDir(refsPath, `skills/${skillEntry.name}/references`);
212
+ }
213
+ }
214
+
215
+ const ALL_SCANNABLE_FILES = [...SKILL_MD_FILES, ...REFERENCES_FILES];
216
+
217
+ for (const file of ALL_SCANNABLE_FILES) {
218
+ const fp = join(ROOT, file);
219
+ if (!existsSync(fp)) continue;
220
+
221
+ const content = readFileSync(fp, 'utf-8');
222
+ const versions = [...content.matchAll(/team-flow@(\d+\.\d+\.\d+)/g)]
223
+ .map(match => match[1]);
224
+ const stale = [...new Set(versions)].filter(version => version !== CANONICAL);
225
+
226
+ if (stale.length > 0) {
227
+ if (AUTO_FIX) {
228
+ // Auto-fix: update all stale npx references
229
+ let newContent = content;
230
+ for (const oldVer of stale) {
231
+ newContent = newContent.replaceAll(`team-flow@${oldVer}`, `team-flow@${CANONICAL}`);
232
+ }
233
+ writeFileSync(fp, newContent, 'utf-8');
234
+ fixes.push(`${file}: ${stale.join(', ')} → ${CANONICAL}`);
235
+ } else {
236
+ errors.push({ file, found: stale.join(', '), expected: CANONICAL });
237
+ }
238
+ }
239
+ }
240
+
241
+ // ── Detect new skills not in any manifest ──
242
+ const MANIFEST_SKILLS = new Set();
243
+ // Extract from plugin.json description
244
+ const pluginDesc = pkg.description || '';
245
+ const skillListMatch = pluginDesc.match(/(\d+) skills/);
246
+ // We'll check AGENTS.md for skill list (table format: | skill-name | ... |)
247
+ const agentsMd = readFileSync(join(ROOT, 'AGENTS.md'), 'utf-8');
248
+ const skillIndexMatch = agentsMd.match(/## Skills 索引[\s\S]*?(?=##|$)/);
249
+ if (skillIndexMatch) {
250
+ // Match table rows: | skill-name | ... |
251
+ const skillNames = [...skillIndexMatch[0].matchAll(/^\|\s*([a-z][a-z0-9-]*)\s*\|/gm)]
252
+ .map(m => m[1])
253
+ .filter(name => name !== 'Skill'); // Skip header row
254
+ skillNames.forEach(name => MANIFEST_SKILLS.add(name));
255
+ }
256
+
257
+ const newSkills = skillDirs
258
+ .map(entry => entry.name)
259
+ .filter(name => !MANIFEST_SKILLS.has(name));
260
+
261
+ if (newSkills.length > 0) {
262
+ console.warn(`⚠️ New skills detected not in AGENTS.md index: ${newSkills.join(', ')}`);
263
+ console.warn(` Consider adding them to AGENTS.md Skills 索引`);
264
+ }
265
+
266
+ // ── Post-fix verification (only in --fix mode) ──
267
+ // If we made any fixes, re-verify that all fixed files are now consistent.
268
+ // This catches cases where auto-fix introduced new issues (e.g., wrong count).
269
+ if (AUTO_FIX && fixes.length > 0) {
270
+ console.log('🔍 Verifying fixes...');
271
+
272
+ // Re-check skill counts
273
+ for (const check of SKILL_COUNT_JSON_CHECKS) {
274
+ const fp = join(ROOT, check.file);
275
+ if (!existsSync(fp)) continue;
276
+ try {
277
+ const obj = JSON.parse(readFileSync(fp, 'utf-8'));
278
+ let val = obj;
279
+ for (const p of check.path) val = val?.[p];
280
+ const match = typeof val === 'string' ? val.match(check.extract) : null;
281
+ if (match && Number(match[1]) !== ACTUAL_SKILL_COUNT) {
282
+ errors.push({
283
+ file: `${check.file} [${check.path.join('.')}]`,
284
+ found: match[1],
285
+ expected: ACTUAL_SKILL_COUNT,
286
+ note: 'Post-fix verification failed'
287
+ });
288
+ }
289
+ } catch (e) { /* ignore parse errors in verification */ }
290
+ }
291
+
292
+ for (const check of SKILL_COUNT_TEXT_CHECKS) {
293
+ const fp = join(ROOT, check.file);
294
+ if (!existsSync(fp)) continue;
295
+ const content = readFileSync(fp, 'utf-8');
296
+ const match = content.match(check.extract);
297
+ if (match && Number(match[1]) !== ACTUAL_SKILL_COUNT) {
298
+ errors.push({
299
+ file: check.file,
300
+ found: match[1],
301
+ expected: ACTUAL_SKILL_COUNT,
302
+ note: 'Post-fix verification failed'
303
+ });
304
+ }
305
+ }
306
+
307
+ if (errors.length > 0) {
308
+ console.error('❌ Post-fix verification found remaining issues:');
309
+ for (const e of errors) {
310
+ console.error(` ${e.file}: expected ${e.expected}, found ${e.found}`);
311
+ }
312
+ console.error('\nAuto-fix may have introduced errors. Please fix manually.');
313
+ process.exit(1);
314
+ }
315
+
316
+ console.log('✅ All fixes verified\n');
317
+ }
318
+
319
+ // ── Report ──
320
+ if (fixes.length > 0) {
321
+ console.log(`🔧 Auto-fixed ${fixes.length} issue(s):`);
322
+ for (const fix of fixes) {
323
+ console.log(` ${fix}`);
324
+ }
325
+ console.log('');
326
+ }
327
+
328
+ if (errors.length === 0) {
329
+ const msg = fixes.length > 0
330
+ ? `✅ Version consistency check passed after auto-fix — all files at ${CANONICAL}`
331
+ : `✅ Version consistency check passed — all files at ${CANONICAL}`;
332
+ console.log(msg);
333
+ process.exit(0);
334
+ }
335
+
336
+ console.log(`❌ Version consistency check FAILED — canonical version is ${CANONICAL}\n`);
337
+ console.log('Mismatches found:');
338
+ for (const e of errors) {
339
+ console.log(` ${e.file}`);
340
+ console.log(` expected: ${e.expected}`);
341
+ console.log(` found: ${e.found}`);
342
+ }
343
+ console.log(`\nRun: npm run check-versions -- --fix`);
344
+ console.log(`Then manually verify and commit.`);
345
+ process.exit(1);
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ // scripts/ensure-branch.mjs — enforce git isolation before editing main/master
3
+ // Used by build-executor as a mandatory preflight. Exits non-zero when it
4
+ // cannot create an isolated context and no --force approval was given, so the
5
+ // agent MUST stop and ask the user instead of silently editing main/master.
6
+ //
7
+ // Usage: node ensure-branch.mjs <change-dir> [change-name] [--force]
8
+ //
9
+ // Security: every git invocation uses execFileSync with a LITERAL command
10
+ // ('git') and a LITERAL argument array (no shell, no variable args array) —
11
+ // the same form proven safe by install-cursor.mjs / install.mjs. There is no
12
+ // string-form shell command, no variable command, and no dynamic args array.
13
+ import { execFileSync } from 'node:child_process';
14
+
15
+ const changeDir = process.argv[2];
16
+ const changeName = process.argv[3];
17
+ const force = process.argv.includes('--force');
18
+
19
+ if (!changeDir) {
20
+ console.error('Usage: node ensure-branch.mjs <change-dir> [change-name] [--force]');
21
+ process.exit(2);
22
+ }
23
+
24
+ const PROTECTED = ['main', 'master'];
25
+ const GIT_OPTS = { encoding: 'utf-8', cwd: changeDir, stdio: ['ignore', 'pipe', 'pipe'] };
26
+
27
+ // Determine current branch (literal arg array).
28
+ let branch = '';
29
+ try {
30
+ branch = (execFileSync('git', ['branch', '--show-current'], GIT_OPTS) || '').trim();
31
+ } catch {
32
+ console.error('ensure-branch: could not determine current git branch. Is <change-dir> inside a git repository?');
33
+ process.exit(1);
34
+ }
35
+
36
+ if (!PROTECTED.includes(branch)) {
37
+ console.log(`ensure-branch: already isolated on branch '${branch}'. Proceed with implementation edits.`);
38
+ process.exit(0);
39
+ }
40
+
41
+ console.error(`ensure-branch: on protected branch '${branch}'. Creating an isolated implementation context...`);
42
+
43
+ const repoName = changeDir.split('/').filter(Boolean).pop() || 'repo';
44
+ const name = changeName || repoName;
45
+ const worktreePath = `../${repoName}-${name}`;
46
+
47
+ // Preferred: git worktree (literal arg array).
48
+ try {
49
+ execFileSync('git', ['worktree', 'add', worktreePath, '-b', name], { ...GIT_OPTS, stdio: 'inherit' });
50
+ console.log(`ensure-branch: created git worktree at ${worktreePath} on branch '${name}'. Make all implementation edits there.`);
51
+ process.exit(0);
52
+ } catch (e) {
53
+ console.error(`ensure-branch: worktree creation failed: ${(e.stderr || e.stdout || e.message || 'unknown').toString().trim()}`);
54
+ }
55
+
56
+ // Fallback: local branch (literal arg array).
57
+ try {
58
+ execFileSync('git', ['switch', '-c', name], { ...GIT_OPTS, stdio: 'inherit' });
59
+ console.log(`ensure-branch: created branch '${name}' via git switch -c. Make implementation edits there.`);
60
+ process.exit(0);
61
+ } catch (e) {
62
+ console.error(`ensure-branch: branch creation failed: ${(e.stderr || e.stdout || e.message || 'unknown').toString().trim()}`);
63
+ }
64
+
65
+ // Both failed → require explicit approval to edit in place.
66
+ if (force) {
67
+ console.error('ensure-branch: WARNING — editing protected branch in place with --force. This modifies main/master directly.');
68
+ process.exit(0);
69
+ }
70
+ console.error('ensure-branch: could not create an isolated context and no --force given. STOP and ask the user for explicit approval before editing main/master.');
71
+ process.exit(1);
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env bash
2
+ # Read a config field from team-flow.config.json
3
+ # Usage: get-config <field-path>
4
+ # Example: get-config execution.inlineThreshold → outputs "3"
5
+ set -euo pipefail
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ field_path="${1:-}"
9
+
10
+ if [ -z "$field_path" ]; then
11
+ echo "Usage: get-config <field-path>" >&2
12
+ echo "Example: get-config execution.inlineThreshold" >&2
13
+ exit 2
14
+ fi
15
+
16
+ # Use node to load config and extract field
17
+ node --input-type=module -e "
18
+ import { loadConfig } from '${SCRIPT_DIR}/lib/config-loader.mjs';
19
+ const config = loadConfig(process.cwd());
20
+ const parts = '${field_path}'.split('.');
21
+ let val = config;
22
+ for (const p of parts) {
23
+ if (val === undefined || val === null) { val = undefined; break; }
24
+ val = val[p];
25
+ }
26
+ if (val !== undefined) {
27
+ process.stdout.write(typeof val === 'object' ? JSON.stringify(val) : String(val));
28
+ } else {
29
+ process.exit(1);
30
+ }
31
+ " 2>/dev/null || exit 1
@@ -0,0 +1,36 @@
1
+ // scripts/guard/checks/artifacts-exist.mjs — check that required planning artifacts are present and non-empty
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { loadConfig } from '../../lib/config-loader.mjs';
5
+ import { validateSpecPathLayout } from '../../lib/spec-paths.mjs';
6
+
7
+ /**
8
+ * Check that required planning artifacts exist and are non-empty,
9
+ * and that the specs/ directory has at least one spec file.
10
+ * Honors artifacts.skip from team-flow.config.json.
11
+ */
12
+ export function checkArtifactsExist(changeDir) {
13
+ const failures = [];
14
+ const config = loadConfig(changeDir);
15
+ const skipList = config.artifacts?.skip || [];
16
+
17
+ const required = ['proposal.md', 'design.md', 'tasks.md'].filter(
18
+ f => !skipList.includes(f.replace('.md', ''))
19
+ );
20
+
21
+ for (const file of required) {
22
+ const filePath = path.join(changeDir, file);
23
+ if (!fs.existsSync(filePath)) {
24
+ failures.push(`${file}: missing`);
25
+ } else if (fs.readFileSync(filePath, 'utf-8').trim().length === 0) {
26
+ failures.push(`${file}: empty`);
27
+ }
28
+ }
29
+
30
+ if (!skipList.includes('specs')) {
31
+ const specLayout = validateSpecPathLayout(changeDir, { requireSpecs: true });
32
+ failures.push(...specLayout.failures);
33
+ }
34
+
35
+ return { pass: failures.length === 0, failures };
36
+ }
@@ -0,0 +1,33 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { readState } from '../../lib/state-loader.mjs';
4
+ import { computeContractHash } from '../../lib/hash.mjs';
5
+
6
+ export function checkContractCurrent(changeDir) {
7
+ const contractPath = path.join(changeDir, 'execution-contract.md');
8
+ if (!fs.existsSync(contractPath)) {
9
+ return { pass: false, failures: ['execution-contract.md: missing'] };
10
+ }
11
+
12
+ const content = fs.readFileSync(contractPath, 'utf-8').trim();
13
+ if (content.length === 0) {
14
+ return { pass: false, failures: ['execution-contract.md: empty'] };
15
+ }
16
+
17
+ const state = readState(changeDir);
18
+ const current = computeContractHash(changeDir);
19
+ if (!state.contract_hash || state.contract_hash === 'null') {
20
+ return {
21
+ pass: false,
22
+ failures: ['execution-contract.md is not recorded in state. Run tf state init <change-dir> after contract generation.'],
23
+ };
24
+ }
25
+ if (state.contract_hash !== current) {
26
+ return {
27
+ pass: false,
28
+ failures: ['execution-contract.md is stale: contract hash mismatch. Re-run contract-builder or tf state rebuild.'],
29
+ };
30
+ }
31
+
32
+ return { pass: true, failures: [] };
33
+ }
@@ -0,0 +1,17 @@
1
+ // scripts/guard/checks/contract-fresh.mjs — check contract staleness via hash comparison
2
+ import { isContractFresh } from '../../lib/hash.mjs';
3
+
4
+ /**
5
+ * Compare stored artifacts_hash in .team-flow.yaml against current artifact hashes.
6
+ * Returns { pass, failures[] }.
7
+ */
8
+ export function checkContractFresh(changeDir) {
9
+ const fresh = isContractFresh(changeDir);
10
+ if (fresh) {
11
+ return { pass: true, failures: [] };
12
+ }
13
+ return {
14
+ pass: false,
15
+ failures: ['execution-contract.md is stale: artifacts hash mismatch. Re-run contract-builder to regenerate.'],
16
+ };
17
+ }
@@ -0,0 +1,35 @@
1
+ // scripts/guard/checks/dp-gate-passed.mjs — check that required decision points are recorded before allowing a transition
2
+ import { readState } from '../../lib/state-loader.mjs';
3
+
4
+ /**
5
+ * Mapping of transitions that require specific DPs to be recorded.
6
+ * Each entry lists the DP fields that must have a non-null value.
7
+ */
8
+ const REQUIRED_DPS = {
9
+ // DP-4: Execution mode must be selected before entering executing
10
+ 'approved-for-build→executing': ['dp_4_result'],
11
+ // DP-3: Contract must be approved before executing (hard gate)
12
+ 'bridging→approved-for-build': ['dp_3_result'],
13
+ };
14
+
15
+ export function check(changeDir, fromState, toState) {
16
+ const key = `${fromState}→${toState}`;
17
+ const required = REQUIRED_DPS[key];
18
+
19
+ if (!required) {
20
+ return { pass: true, failures: [] };
21
+ }
22
+
23
+ const state = readState(changeDir);
24
+ const failures = [];
25
+
26
+ for (const dpField of required) {
27
+ const value = state[dpField];
28
+ if (value === null || value === undefined || value === '') {
29
+ const dpNum = dpField.match(/dp_(\d+)_/)?.[1] || '?';
30
+ failures.push(`DP-${dpNum} (${dpField}) is not recorded — this decision point must be confirmed before ${fromState} → ${toState}`);
31
+ }
32
+ }
33
+
34
+ return { pass: failures.length === 0, failures };
35
+ }
@@ -0,0 +1,22 @@
1
+ import { readState } from '../../lib/state-loader.mjs';
2
+
3
+ export function checkDp3Approved(changeDir) {
4
+ const state = readState(changeDir);
5
+ const decision = typeof state.dp_3_result === 'string' ? state.dp_3_result.trim() : '';
6
+
7
+ if (!decision) {
8
+ return {
9
+ pass: false,
10
+ failures: ['DP-3 (dp_3_result) is not recorded — minimal contract approval is required before hotfix build'],
11
+ };
12
+ }
13
+
14
+ if (!/^approved\b/i.test(decision)) {
15
+ return {
16
+ pass: false,
17
+ failures: [`DP-3 (dp_3_result) must start with "approved"; got: ${decision}`],
18
+ };
19
+ }
20
+
21
+ return { pass: true, failures: [] };
22
+ }
@@ -0,0 +1,40 @@
1
+ import { readPlan, validatePlan } from '../../lib/execution-plan.mjs';
2
+ import { readState } from '../../lib/state-loader.mjs';
3
+
4
+ /**
5
+ * Verifies that DP-4 refers to the current, persisted execution plan.
6
+ *
7
+ * A non-empty DP-4 field is not sufficient: it must name the current plan
8
+ * revision, whose hashes, workflow, mode, and state summary remain current.
9
+ */
10
+ export function checkExecutionPlanReady(changeDir) {
11
+ const plan = readPlan(changeDir);
12
+ if (!plan) {
13
+ return {
14
+ pass: false,
15
+ failures: ['execution plan is missing. Record a current plan with "tf execution plan" before entering executing.'],
16
+ };
17
+ }
18
+
19
+ const validation = validatePlan(changeDir, plan);
20
+ if (!validation.valid) {
21
+ return { pass: false, failures: validation.failures };
22
+ }
23
+
24
+ const state = readState(changeDir);
25
+ const expectedRevision = `plan revision ${plan.revision}`;
26
+ const decision = typeof state.dp_4_result === 'string' ? state.dp_4_result : '';
27
+ const revisionReference = new RegExp(`\\bplan revision\\s+${escapeRegExp(String(plan.revision))}\\b`, 'i');
28
+ if (!revisionReference.test(decision)) {
29
+ return {
30
+ pass: false,
31
+ failures: [`DP-4 must precisely reference current ${expectedRevision}; recorded value is '${decision || 'null'}'. Re-record the execution plan.`],
32
+ };
33
+ }
34
+
35
+ return { pass: true, failures: [] };
36
+ }
37
+
38
+ function escapeRegExp(value) {
39
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
40
+ }
@@ -0,0 +1,36 @@
1
+ import { readCurrentReview, readPlan, validatePlan } from '../../lib/execution-plan.mjs';
2
+
3
+ /**
4
+ * Verifies that every wave in the current execution plan has a passing review
5
+ * receipt. A failed or malformed receipt is a blocking result, never a signal
6
+ * that a later wave may proceed to closing.
7
+ */
8
+ export function checkExecutionReviewsPassed(changeDir) {
9
+ const plan = readPlan(changeDir);
10
+ if (!plan) {
11
+ // This dimension only evaluates receipts. Full/hotfix transitions pair it
12
+ // with execution-plan-ready, which rejects a missing plan; tweak omits
13
+ // this dimension entirely. Keep the missing-plan result owned by that
14
+ // dedicated dimension rather than duplicating it here.
15
+ return { pass: true, failures: [] };
16
+ }
17
+
18
+ const validation = validatePlan(changeDir, plan);
19
+ if (!validation.valid) {
20
+ return { pass: false, failures: validation.failures };
21
+ }
22
+
23
+ const failures = [];
24
+ for (const wave of plan.waves) {
25
+ const receipt = readCurrentReview(changeDir, wave.id, plan);
26
+ if (!receipt) {
27
+ failures.push(`review receipt missing for planned wave '${wave.id}'. Record a passing review before closing.`);
28
+ continue;
29
+ }
30
+ if (receipt?.status !== 'pass') {
31
+ failures.push(`review receipt for planned wave '${wave.id}' has status '${receipt?.status ?? 'missing'}'; expected 'pass'.`);
32
+ }
33
+ }
34
+
35
+ return { pass: failures.length === 0, failures };
36
+ }