@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,101 @@
1
+ import { describe, it, before, after } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { execFileSync } from 'node:child_process';
4
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { tmpdir } from 'node:os';
7
+
8
+ const CLI = join(process.cwd(), 'scripts/team-flow.mjs');
9
+ let tempDir;
10
+
11
+ before(() => {
12
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-cmd-config-test-'));
13
+ });
14
+
15
+ after(() => {
16
+ rmSync(tempDir, { recursive: true, force: true });
17
+ });
18
+
19
+ function writeConfig(config) {
20
+ writeFileSync(join(tempDir, 'team-flow.config.json'), JSON.stringify(config));
21
+ }
22
+
23
+ function runSsf(args) {
24
+ try {
25
+ return {
26
+ exitCode: 0,
27
+ stdout: execFileSync(process.execPath, [CLI, ...args], {
28
+ cwd: tempDir, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
29
+ }), stderr: '',
30
+ };
31
+ } catch (error) {
32
+ return {
33
+ exitCode: error.status ?? 1,
34
+ stdout: error.stdout?.toString() ?? '',
35
+ stderr: error.stderr?.toString() ?? error.message,
36
+ };
37
+ }
38
+ }
39
+
40
+ describe('tf config --resolve-model', () => {
41
+ it('documents model profile resolution in CLI help', () => {
42
+ const result = runSsf(['--help']);
43
+ assert.equal(result.exitCode, 0, result.stderr);
44
+ assert.match(result.stdout, /config --resolve-model <profile>/);
45
+ assert.match(result.stdout, /without switching models/);
46
+ });
47
+
48
+ it('prints configured standard model profile JSON through the dispatcher', () => {
49
+ writeConfig({ models: { standard: 'vendor-standard', strong: 'vendor-strong' } });
50
+ const result = runSsf(['config', '--resolve-model', 'standard']);
51
+ assert.equal(result.exitCode, 0, result.stderr);
52
+ assert.deepStrictEqual(JSON.parse(result.stdout), {
53
+ profile: 'standard', model: 'vendor-standard', configured: true,
54
+ });
55
+ });
56
+
57
+ it('prints configured strong model profile JSON through the dispatcher', () => {
58
+ writeConfig({ models: { standard: 'vendor-standard', strong: 'vendor-strong' } });
59
+ const result = runSsf(['config', '--resolve-model', 'strong']);
60
+ assert.equal(result.exitCode, 0, result.stderr);
61
+ assert.deepStrictEqual(JSON.parse(result.stdout), {
62
+ profile: 'strong', model: 'vendor-strong', configured: true,
63
+ });
64
+ });
65
+
66
+ it('prints a valid unmapped result', () => {
67
+ writeConfig({ models: {} });
68
+ const unmapped = runSsf(['config', '--resolve-model', 'review']);
69
+ assert.equal(unmapped.exitCode, 0, unmapped.stderr);
70
+ assert.deepStrictEqual(JSON.parse(unmapped.stdout), {
71
+ profile: 'review', model: null, configured: false,
72
+ });
73
+ });
74
+
75
+ it('rejects an unknown profile with supported names in stderr', () => {
76
+ const unknown = runSsf(['config', '--resolve-model', 'fast']);
77
+ assert.equal(unknown.exitCode, 1);
78
+ assert.match(unknown.stderr,
79
+ /Unknown model profile 'fast'.*mechanical.*standard.*strong.*review/);
80
+ });
81
+
82
+ it('rejects a blank mapped profile with an actionable config path in stderr', () => {
83
+ writeConfig({ models: { review: '' } });
84
+ const blank = runSsf(['config', '--resolve-model', 'review']);
85
+ assert.equal(blank.exitCode, 1);
86
+ assert.match(blank.stderr, /models\.review must be a non-empty string/);
87
+ });
88
+
89
+ it('rejects a non-string mapped profile with an actionable config path in stderr', () => {
90
+ writeConfig({ models: { strong: 42 } });
91
+ const nonString = runSsf(['config', '--resolve-model', 'strong']);
92
+ assert.equal(nonString.exitCode, 1);
93
+ assert.match(nonString.stderr, /models\.strong must be a non-empty string/);
94
+ });
95
+
96
+ it('rejects a missing profile argument and preserves normal config lookup', () => {
97
+ assert.equal(runSsf(['config', '--resolve-model']).exitCode, 2);
98
+ writeConfig({ models: {} });
99
+ assert.equal(runSsf(['config', '--get', 'execution.inlineThreshold']).stdout.trim(), '3');
100
+ });
101
+ });
@@ -0,0 +1,450 @@
1
+ // tests/lib/cmd-doctor.test.mjs
2
+ // Tests for scripts/lib/cmd-doctor.mjs check functions
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-doctor: checkVersionConsistency()', () => {
12
+ let checkVersionConsistency;
13
+
14
+ before(async () => {
15
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-doctor-ver-'));
16
+ const modulePath = join(process.cwd(), 'scripts/lib/cmd-doctor.mjs');
17
+ const mod = await import(modulePath);
18
+ checkVersionConsistency = mod.checkVersionConsistency;
19
+ });
20
+
21
+ after(() => {
22
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
23
+ });
24
+
25
+ it('passes when all manifests have same version', () => {
26
+ const version = '1.0.0';
27
+ writeFileSync(join(tempDir, 'package.json'), JSON.stringify({ version }));
28
+ writeFileSync(join(tempDir, 'plugin.json'), JSON.stringify({ version }));
29
+ mkdirSync(join(tempDir, '.claude-plugin'), { recursive: true });
30
+ writeFileSync(join(tempDir, '.claude-plugin', 'plugin.json'), JSON.stringify({ version }));
31
+
32
+ const result = checkVersionConsistency(tempDir);
33
+ assert.equal(result.pass, true);
34
+ });
35
+
36
+ it('fails when manifests have different versions', () => {
37
+ writeFileSync(join(tempDir, 'package.json'), JSON.stringify({ version: '1.0.0' }));
38
+ writeFileSync(join(tempDir, 'plugin.json'), JSON.stringify({ version: '0.9.0' }));
39
+
40
+ const result = checkVersionConsistency(tempDir);
41
+ assert.equal(result.pass, false);
42
+ assert.ok(result.message.includes('mismatch'));
43
+ });
44
+
45
+ it('handles missing manifests gracefully', () => {
46
+ // Clean up any lingering files from previous tests
47
+ rmSync(tempDir, { recursive: true, force: true });
48
+ mkdirSync(tempDir, { recursive: true });
49
+ writeFileSync(join(tempDir, 'package.json'), JSON.stringify({ version: '1.0.0' }));
50
+ // Don't create other manifests — should still pass (unique versions <= 1)
51
+
52
+ const result = checkVersionConsistency(tempDir);
53
+ assert.equal(result.pass, true, `Expected pass but got: ${result.message}`);
54
+ });
55
+
56
+ it('fails when a marketplace metadata version differs from the plugin version', () => {
57
+ rmSync(tempDir, { recursive: true, force: true });
58
+ mkdirSync(join(tempDir, '.github', 'plugin'), { recursive: true });
59
+ writeFileSync(join(tempDir, 'package.json'), JSON.stringify({ version: '1.0.0' }));
60
+ writeFileSync(join(tempDir, '.github', 'plugin', 'marketplace.json'), JSON.stringify({
61
+ metadata: { version: '0.9.0' },
62
+ plugins: [{ version: '1.0.0' }],
63
+ }));
64
+
65
+ const result = checkVersionConsistency(tempDir);
66
+ assert.equal(result.pass, false);
67
+ assert.ok(result.message.includes('.github/plugin/marketplace.json'));
68
+ });
69
+ });
70
+
71
+ describe('cmd-doctor: checkHooks()', () => {
72
+ let checkHooks;
73
+
74
+ before(async () => {
75
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-doctor-hooks-'));
76
+ const modulePath = join(process.cwd(), 'scripts/lib/cmd-doctor.mjs');
77
+ const mod = await import(modulePath);
78
+ checkHooks = mod.checkHooks;
79
+ });
80
+
81
+ after(() => {
82
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
83
+ });
84
+
85
+ it('fails when hooks.json does not exist', () => {
86
+ const result = checkHooks(tempDir);
87
+ assert.equal(result.pass, false);
88
+ assert.ok(result.message.includes('not found'));
89
+ });
90
+
91
+ it('passes when hooks.json has valid record format', () => {
92
+ mkdirSync(join(tempDir, 'hooks'), { recursive: true });
93
+ writeFileSync(join(tempDir, 'hooks', 'hooks.json'), JSON.stringify({
94
+ hooks: { SessionStart: [{ command: 'bash hooks/session-start' }] },
95
+ }));
96
+
97
+ const result = checkHooks(tempDir);
98
+ assert.equal(result.pass, true);
99
+ });
100
+
101
+ it('fails when hooks.json has array format (legacy)', () => {
102
+ writeFileSync(join(tempDir, 'hooks', 'hooks.json'), JSON.stringify({
103
+ hooks: [{ event: 'SessionStart', command: 'bash hooks/session-start' }],
104
+ }));
105
+
106
+ const result = checkHooks(tempDir);
107
+ assert.equal(result.pass, false);
108
+ assert.ok(result.message.includes('invalid format'));
109
+ });
110
+
111
+ it('fails on invalid JSON', () => {
112
+ writeFileSync(join(tempDir, 'hooks', 'hooks.json'), 'not json {{{');
113
+
114
+ const result = checkHooks(tempDir);
115
+ assert.equal(result.pass, false);
116
+ assert.ok(result.message.includes('parse error'));
117
+ });
118
+ });
119
+
120
+ describe('cmd-doctor: checkCodexManifest()', () => {
121
+ let checkCodexManifest;
122
+
123
+ before(async () => {
124
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-doctor-codex-'));
125
+ const modulePath = join(process.cwd(), 'scripts/lib/cmd-doctor.mjs');
126
+ const mod = await import(modulePath);
127
+ checkCodexManifest = mod.checkCodexManifest;
128
+ });
129
+
130
+ after(() => {
131
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
132
+ });
133
+
134
+ it('fails when Codex manifest is missing', () => {
135
+ const result = checkCodexManifest(tempDir);
136
+ assert.equal(result.pass, false);
137
+ assert.ok(result.message.includes('not found'));
138
+ });
139
+
140
+ it('fails when hooks is absent because Codex auto-discovers hooks/hooks.json', () => {
141
+ mkdirSync(join(tempDir, '.codex-plugin'), { recursive: true });
142
+ writeFileSync(join(tempDir, '.codex-plugin', 'plugin.json'), JSON.stringify({
143
+ interface: { category: 'Developer Tools' },
144
+ }));
145
+
146
+ const result = checkCodexManifest(tempDir);
147
+ assert.equal(result.pass, false);
148
+ assert.ok(result.message.includes('hooks to {}'));
149
+ });
150
+
151
+ it('fails when category is not Developer Tools', () => {
152
+ writeFileSync(join(tempDir, '.codex-plugin', 'plugin.json'), JSON.stringify({
153
+ hooks: {},
154
+ interface: { category: 'Productivity' },
155
+ }));
156
+
157
+ const result = checkCodexManifest(tempDir);
158
+ assert.equal(result.pass, false);
159
+ assert.ok(result.message.includes('Developer Tools'));
160
+ });
161
+
162
+ it('passes when hooks are explicitly suppressed and category is Developer Tools', () => {
163
+ writeFileSync(join(tempDir, '.codex-plugin', 'plugin.json'), JSON.stringify({
164
+ hooks: {},
165
+ interface: { category: 'Developer Tools' },
166
+ }));
167
+
168
+ const result = checkCodexManifest(tempDir);
169
+ assert.equal(result.pass, true);
170
+ });
171
+ });
172
+
173
+ describe('cmd-doctor: checkSkills()', () => {
174
+ let checkSkills;
175
+
176
+ before(async () => {
177
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-doctor-skills-'));
178
+ const modulePath = join(process.cwd(), 'scripts/lib/cmd-doctor.mjs');
179
+ const mod = await import(modulePath);
180
+ checkSkills = mod.checkSkills;
181
+ });
182
+
183
+ after(() => {
184
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
185
+ });
186
+
187
+ it('fails when skills/ directory does not exist', () => {
188
+ const result = checkSkills(tempDir);
189
+ assert.equal(result.pass, false);
190
+ });
191
+
192
+ it('passes when all skill dirs have SKILL.md', () => {
193
+ const skillsDir = join(tempDir, 'skills');
194
+ mkdirSync(join(skillsDir, 'workflow-start'), { recursive: true });
195
+ mkdirSync(join(skillsDir, 'need-explorer'), { recursive: true });
196
+ writeFileSync(join(skillsDir, 'workflow-start', 'SKILL.md'), '# Skill');
197
+ writeFileSync(join(skillsDir, 'need-explorer', 'SKILL.md'), '# Skill');
198
+
199
+ const result = checkSkills(tempDir);
200
+ assert.equal(result.pass, true);
201
+ assert.ok(result.message.includes('2/2'));
202
+ });
203
+
204
+ it('fails when some skills missing SKILL.md', () => {
205
+ const skillsDir = join(tempDir, 'skills');
206
+ rmSync(skillsDir, { recursive: true, force: true });
207
+ mkdirSync(join(skillsDir, 'workflow-start'), { recursive: true });
208
+ mkdirSync(join(skillsDir, 'empty-skill'), { recursive: true });
209
+ writeFileSync(join(skillsDir, 'workflow-start', 'SKILL.md'), '# Skill');
210
+ // empty-skill has no SKILL.md
211
+
212
+ const result = checkSkills(tempDir);
213
+ assert.equal(result.pass, false);
214
+ assert.ok(result.message.includes('empty-skill'));
215
+ assert.ok(result.message.includes('1/2'));
216
+ });
217
+ });
218
+
219
+ describe('cmd-doctor: checkDist()', () => {
220
+ let checkDist;
221
+
222
+ before(async () => {
223
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-doctor-dist-'));
224
+ const modulePath = join(process.cwd(), 'scripts/lib/cmd-doctor.mjs');
225
+ const mod = await import(modulePath);
226
+ checkDist = mod.checkDist;
227
+ });
228
+
229
+ after(() => {
230
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
231
+ });
232
+
233
+ it('fails when dist/ directory does not exist', () => {
234
+ const result = checkDist(tempDir);
235
+ assert.equal(result.pass, false);
236
+ });
237
+
238
+ it('fails when dist/index.js missing', () => {
239
+ mkdirSync(join(tempDir, 'dist'), { recursive: true });
240
+ const result = checkDist(tempDir);
241
+ assert.equal(result.pass, false);
242
+ assert.ok(result.message.includes('not found'));
243
+ });
244
+
245
+ it('passes when dist/index.js exists', () => {
246
+ writeFileSync(join(tempDir, 'dist', 'index.js'), '// compiled');
247
+ const result = checkDist(tempDir);
248
+ assert.equal(result.pass, true);
249
+ });
250
+ });
251
+
252
+ describe('cmd-doctor: checkRootPluginAuthor()', () => {
253
+ let checkRootPluginAuthor;
254
+
255
+ before(async () => {
256
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-doctor-author-'));
257
+ const modulePath = join(process.cwd(), 'scripts/lib/cmd-doctor.mjs');
258
+ const mod = await import(modulePath);
259
+ checkRootPluginAuthor = mod.checkRootPluginAuthor;
260
+ });
261
+
262
+ after(() => {
263
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
264
+ });
265
+
266
+ it('fails when plugin.json does not exist', () => {
267
+ const result = checkRootPluginAuthor(tempDir);
268
+ assert.equal(result.pass, false);
269
+ });
270
+
271
+ it('fails when author is a string (Copilot strict validation)', () => {
272
+ writeFileSync(join(tempDir, 'plugin.json'), JSON.stringify({
273
+ author: 'MageByte',
274
+ }));
275
+
276
+ const result = checkRootPluginAuthor(tempDir);
277
+ assert.equal(result.pass, false);
278
+ assert.ok(result.message.includes('must be an object'));
279
+ });
280
+
281
+ it('passes when author is an object with name', () => {
282
+ writeFileSync(join(tempDir, 'plugin.json'), JSON.stringify({
283
+ author: { name: 'MageByte' },
284
+ }));
285
+
286
+ const result = checkRootPluginAuthor(tempDir);
287
+ assert.equal(result.pass, true);
288
+ assert.ok(result.message.includes('MageByte'));
289
+ });
290
+
291
+ it('fails when author object missing name', () => {
292
+ writeFileSync(join(tempDir, 'plugin.json'), JSON.stringify({
293
+ author: { email: 'test@example.com' },
294
+ }));
295
+
296
+ const result = checkRootPluginAuthor(tempDir);
297
+ assert.equal(result.pass, false);
298
+ });
299
+ });
300
+
301
+ describe('cmd-doctor: checkNodeVersion()', () => {
302
+ let checkNodeVersion;
303
+
304
+ before(async () => {
305
+ const modulePath = join(process.cwd(), 'scripts/lib/cmd-doctor.mjs');
306
+ const mod = await import(modulePath);
307
+ checkNodeVersion = mod.checkNodeVersion;
308
+ });
309
+
310
+ it('accepts Node 20 as the minimum supported runtime', () => {
311
+ const result = checkNodeVersion('v20.0.0');
312
+ assert.equal(result.pass, true);
313
+ assert.equal(result.message, 'v20.0.0');
314
+ });
315
+
316
+ it('rejects Node 19 with the Node 20 repair guidance', () => {
317
+ const result = checkNodeVersion('v19.9.0');
318
+ assert.equal(result.pass, false);
319
+ assert.match(result.message, /v19\.9\.0 \(requires >= 20\)/);
320
+ });
321
+
322
+ it('checks the current Node.js version when no version is supplied', () => {
323
+ const result = checkNodeVersion();
324
+ assert.ok(result.message.includes(process.version));
325
+ });
326
+ });
327
+
328
+ describe('cmd-doctor: checkDocs()', () => {
329
+ let checkDocs;
330
+
331
+ before(async () => {
332
+ tempDir = mkdtempSync(join(tmpdir(), 'tf-doctor-docs-'));
333
+ const modulePath = join(process.cwd(), 'scripts/lib/cmd-doctor.mjs');
334
+ const mod = await import(modulePath);
335
+ checkDocs = mod.checkDocs;
336
+ });
337
+
338
+ after(() => {
339
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true });
340
+ });
341
+
342
+ it('returns skipped when no package.json', () => {
343
+ const result = checkDocs(tempDir);
344
+ assert.equal(result.pass, true);
345
+ assert.ok(result.message.includes('skipped'));
346
+ });
347
+
348
+ it('warns when CHANGELOG missing current version entry', () => {
349
+ writeFileSync(join(tempDir, 'package.json'), JSON.stringify({ version: '1.2.3' }));
350
+ writeFileSync(join(tempDir, 'CHANGELOG.md'), '# Changelog\n\n## [1.0.0]\n- old stuff');
351
+
352
+ const result = checkDocs(tempDir);
353
+ assert.equal(result.pass, false);
354
+ assert.ok(result.message.includes('1.2.3'));
355
+ });
356
+
357
+ it('passes when CHANGELOG has current version', () => {
358
+ writeFileSync(join(tempDir, 'package.json'), JSON.stringify({ version: '1.2.3' }));
359
+ writeFileSync(join(tempDir, 'CHANGELOG.md'), '# Changelog\n\n## [1.2.3]\n- new stuff');
360
+
361
+ const result = checkDocs(tempDir);
362
+ assert.equal(result.pass, true);
363
+ });
364
+ });
365
+
366
+ describe('cmd-doctor: checkRuntimeDistribution()', () => {
367
+ let checkRuntimeDistribution;
368
+
369
+ before(async () => {
370
+ const modulePath = join(process.cwd(), 'scripts/lib/cmd-doctor.mjs');
371
+ const mod = await import(modulePath);
372
+ checkRuntimeDistribution = mod.checkRuntimeDistribution;
373
+ });
374
+
375
+ it('passes for the canonical package and reports platform coverage', () => {
376
+ const result = checkRuntimeDistribution(process.cwd());
377
+
378
+ assert.equal(result.pass, true, result.message);
379
+ assert.match(result.message, /17 platforms/);
380
+ });
381
+
382
+ it('reports an unrewritten plugin-root placeholder as an upgrade issue', () => {
383
+ const root = mkdtempSync(join(tmpdir(), 'tf-doctor-runtime-'));
384
+ try {
385
+ mkdirSync(join(root, 'skills', 'workflow-start'), { recursive: true });
386
+ writeFileSync(join(root, 'package.json'), JSON.stringify({ version: '1.2.3' }));
387
+ writeFileSync(join(root, 'skills', 'workflow-start', 'SKILL.md'),
388
+ 'node "${CLAUDE_PLUGIN_ROOT}/scripts/team-flow.mjs" state get demo');
389
+
390
+ const result = checkRuntimeDistribution(root);
391
+ assert.equal(result.pass, false);
392
+ assert.match(result.message, /plugin-root placeholder|reinstall/i);
393
+ } finally {
394
+ rmSync(root, { recursive: true, force: true });
395
+ }
396
+ });
397
+
398
+ it('checks code-reviewer as a portable runtime skill', () => {
399
+ const root = mkdtempSync(join(tmpdir(), 'tf-doctor-code-reviewer-'));
400
+ try {
401
+ mkdirSync(join(root, 'skills', 'code-reviewer'), { recursive: true });
402
+ writeFileSync(join(root, 'package.json'), JSON.stringify({ version: '1.2.3' }));
403
+ writeFileSync(join(root, 'skills', 'code-reviewer', 'SKILL.md'),
404
+ 'node "${CLAUDE_PLUGIN_ROOT}/scripts/team-flow.mjs" execution review demo');
405
+
406
+ const result = checkRuntimeDistribution(root);
407
+ assert.equal(result.pass, false);
408
+ assert.match(result.message, /code-reviewer: plugin-root placeholder remains/);
409
+ } finally {
410
+ rmSync(root, { recursive: true, force: true });
411
+ }
412
+ });
413
+
414
+ it('rejects a local command whose referenced runtime file is missing', () => {
415
+ const root = mkdtempSync(join(tmpdir(), 'tf-doctor-stale-runtime-'));
416
+ try {
417
+ mkdirSync(join(root, 'skills', 'workflow-start'), { recursive: true });
418
+ mkdirSync(join(root, 'scripts'), { recursive: true });
419
+ writeFileSync(join(root, 'package.json'), JSON.stringify({ version: '1.2.3' }));
420
+ writeFileSync(join(root, 'scripts', 'team-flow.mjs'), '// unrelated bundled CLI');
421
+ writeFileSync(join(root, 'skills', 'workflow-start', 'SKILL.md'),
422
+ 'node "/tmp/missing-runtime/scripts/team-flow.mjs" state get demo');
423
+
424
+ const result = checkRuntimeDistribution(root);
425
+ assert.equal(result.pass, false);
426
+ assert.match(result.message, /workflow-start: local runtime tree is missing/);
427
+ } finally {
428
+ rmSync(root, { recursive: true, force: true });
429
+ }
430
+ });
431
+
432
+ it('accepts a POSIX-escaped local runtime path containing a single quote', () => {
433
+ const root = mkdtempSync(join(tmpdir(), "tf-doctor-quote-'"));
434
+ try {
435
+ const localCli = join(root, 'scripts', 'team-flow.mjs');
436
+ mkdirSync(join(root, 'skills', 'workflow-start'), { recursive: true });
437
+ mkdirSync(join(root, 'scripts'), { recursive: true });
438
+ writeFileSync(join(root, 'package.json'), JSON.stringify({ version: '1.2.3' }));
439
+ writeFileSync(localCli, '// bundled CLI');
440
+ const quotedCli = `'${localCli.replace(/'/g, "'\\''")}'`;
441
+ writeFileSync(join(root, 'skills', 'workflow-start', 'SKILL.md'),
442
+ `node ${quotedCli} state get demo`);
443
+
444
+ const result = checkRuntimeDistribution(root);
445
+ assert.equal(result.pass, true, result.message);
446
+ } finally {
447
+ rmSync(root, { recursive: true, force: true });
448
+ }
449
+ });
450
+ });