contextdevkit 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. package/CHANGELOG.md +592 -0
  2. package/LICENSE +21 -0
  3. package/README.md +401 -0
  4. package/docs/AGENT-PACKAGE-FORMAT.md +140 -0
  5. package/docs/ARCHITECTURE.md +258 -0
  6. package/docs/CHANGELOG.md +559 -0
  7. package/docs/CUSTOMIZING.md +211 -0
  8. package/docs/LEVELS.md +151 -0
  9. package/docs/ROADMAP.md +385 -0
  10. package/docs/SQUAD-PIPELINE-FORMAT.md +258 -0
  11. package/docs/SQUADS/agent-forge.md +65 -0
  12. package/docs/SQUADS/design-team.md +161 -0
  13. package/docs/token-economy-plan.md +135 -0
  14. package/install.mjs +273 -0
  15. package/instrucoes.md +274 -0
  16. package/package.json +46 -0
  17. package/templates/CLAUDE.md.tpl +133 -0
  18. package/templates/claude/agents/_TEMPLATE.md +52 -0
  19. package/templates/claude/agents/accessibility.md +36 -0
  20. package/templates/claude/agents/agent-architect.md +37 -0
  21. package/templates/claude/agents/architect.md +39 -0
  22. package/templates/claude/agents/code-reviewer.md +43 -0
  23. package/templates/claude/agents/code-security.md +59 -0
  24. package/templates/claude/agents/context-keeper.md +40 -0
  25. package/templates/claude/agents/devops.md +40 -0
  26. package/templates/claude/agents/eval-designer.md +40 -0
  27. package/templates/claude/agents/forge-orchestrator.md +42 -0
  28. package/templates/claude/agents/governance-officer.md +45 -0
  29. package/templates/claude/agents/growth.md +92 -0
  30. package/templates/claude/agents/infra-security.md +53 -0
  31. package/templates/claude/agents/landing-architect.md +154 -0
  32. package/templates/claude/agents/model-router.md +34 -0
  33. package/templates/claude/agents/packager.md +38 -0
  34. package/templates/claude/agents/privacy-lgpd.md +64 -0
  35. package/templates/claude/agents/product-owner.md +51 -0
  36. package/templates/claude/agents/prompt-engineer.md +33 -0
  37. package/templates/claude/agents/qa-e2e.md +52 -0
  38. package/templates/claude/agents/qa-fuzzer.md +24 -0
  39. package/templates/claude/agents/qa-integration.md +21 -0
  40. package/templates/claude/agents/qa-orchestrator.md +40 -0
  41. package/templates/claude/agents/qa-perf.md +40 -0
  42. package/templates/claude/agents/qa-unit.md +39 -0
  43. package/templates/claude/agents/rag-designer.md +54 -0
  44. package/templates/claude/agents/retention.md +85 -0
  45. package/templates/claude/agents/security.md +48 -0
  46. package/templates/claude/agents/seo-specialist.md +106 -0
  47. package/templates/claude/agents/test-engineer.md +48 -0
  48. package/templates/claude/agents/tool-designer.md +32 -0
  49. package/templates/claude/agents/ui-designer.md +37 -0
  50. package/templates/claude/agents/ux-designer.md +38 -0
  51. package/templates/claude/commands/README.md +95 -0
  52. package/templates/claude/commands/advise.md +80 -0
  53. package/templates/claude/commands/audit/analyze-code-ia-practices.md +75 -0
  54. package/templates/claude/commands/audit/audit.md +35 -0
  55. package/templates/claude/commands/audit/contract-check.md +21 -0
  56. package/templates/claude/commands/audit/deep-analysis.md +48 -0
  57. package/templates/claude/commands/audit/deps-audit.md +49 -0
  58. package/templates/claude/commands/audit/security-setup.md +35 -0
  59. package/templates/claude/commands/audit/seo-audit.md +63 -0
  60. package/templates/claude/commands/audit/tech-debt-sweep.md +35 -0
  61. package/templates/claude/commands/bug-hunt.md +42 -0
  62. package/templates/claude/commands/claude-md.md +36 -0
  63. package/templates/claude/commands/close-version.md +25 -0
  64. package/templates/claude/commands/context-refresh.md +19 -0
  65. package/templates/claude/commands/context-stats.md +15 -0
  66. package/templates/claude/commands/dashboard.md +66 -0
  67. package/templates/claude/commands/distill-apply.md +19 -0
  68. package/templates/claude/commands/distill-sessions.md +26 -0
  69. package/templates/claude/commands/fleet.md +47 -0
  70. package/templates/claude/commands/forge/forge-audit.md +16 -0
  71. package/templates/claude/commands/forge/forge-budget.md +16 -0
  72. package/templates/claude/commands/forge/forge-deprecate.md +16 -0
  73. package/templates/claude/commands/forge/forge-doctor.md +17 -0
  74. package/templates/claude/commands/forge/forge-eval.md +16 -0
  75. package/templates/claude/commands/forge/forge-fallback-test.md +17 -0
  76. package/templates/claude/commands/forge/forge-killswitch.md +17 -0
  77. package/templates/claude/commands/forge/forge-list.md +17 -0
  78. package/templates/claude/commands/forge/forge-new.md +41 -0
  79. package/templates/claude/commands/forge/forge-policy.md +16 -0
  80. package/templates/claude/commands/forge/forge-redteam.md +17 -0
  81. package/templates/claude/commands/forge/forge-refresh-matrix.md +20 -0
  82. package/templates/claude/commands/forge/forge-route.md +17 -0
  83. package/templates/claude/commands/forge/forge-show.md +16 -0
  84. package/templates/claude/commands/landing-page.md +71 -0
  85. package/templates/claude/commands/log-session.md +59 -0
  86. package/templates/claude/commands/media-gen.md +93 -0
  87. package/templates/claude/commands/new-adr.md +30 -0
  88. package/templates/claude/commands/pipeline/dev-start.md +64 -0
  89. package/templates/claude/commands/pipeline/pipeline.md +36 -0
  90. package/templates/claude/commands/pipeline/resume.md +70 -0
  91. package/templates/claude/commands/pipeline/retro.md +34 -0
  92. package/templates/claude/commands/pipeline/runs.md +63 -0
  93. package/templates/claude/commands/pipeline/ship.md +54 -0
  94. package/templates/claude/commands/pipeline/workflow.md +85 -0
  95. package/templates/claude/commands/playbook.md +27 -0
  96. package/templates/claude/commands/predictions-review.md +28 -0
  97. package/templates/claude/commands/qa/qa-signoff.md +24 -0
  98. package/templates/claude/commands/qa/scaffold-tests.md +27 -0
  99. package/templates/claude/commands/qa/test-plan.md +26 -0
  100. package/templates/claude/commands/qa/visual-test.md +42 -0
  101. package/templates/claude/commands/roadmap.md +48 -0
  102. package/templates/claude/commands/setup/aidevtool-from0.md +104 -0
  103. package/templates/claude/commands/setup/context-config.md +25 -0
  104. package/templates/claude/commands/setup/context-doctor.md +21 -0
  105. package/templates/claude/commands/setup/context-level.md +17 -0
  106. package/templates/claude/commands/setup/setupcontextdevkit.md +121 -0
  107. package/templates/claude/commands/simulate-impact.md +32 -0
  108. package/templates/claude/commands/squad.md +44 -0
  109. package/templates/claude/commands/state.md +21 -0
  110. package/templates/claude/commands/token-report.md +29 -0
  111. package/templates/claude/commands/tune-agents.md +35 -0
  112. package/templates/claude/commands/vcs/claim.md +18 -0
  113. package/templates/claude/commands/vcs/git.md +83 -0
  114. package/templates/claude/commands/vcs/release.md +15 -0
  115. package/templates/claude/commands/vcs/worktree-new.md +18 -0
  116. package/templates/claude/commands/watch.md +47 -0
  117. package/templates/contextkit/.env.example +36 -0
  118. package/templates/contextkit/CLAUDE.child.md.tpl +38 -0
  119. package/templates/contextkit/README.md +74 -0
  120. package/templates/contextkit/behaviors-examples.md +183 -0
  121. package/templates/contextkit/behaviors.md +116 -0
  122. package/templates/contextkit/best-practices.md +323 -0
  123. package/templates/contextkit/config.json +66 -0
  124. package/templates/contextkit/detectors/README.md +45 -0
  125. package/templates/contextkit/detectors/example-detector.mjs.example +25 -0
  126. package/templates/contextkit/instrucoes.md +114 -0
  127. package/templates/contextkit/memory/GLOSSARY.md +13 -0
  128. package/templates/contextkit/memory/SESSIONS.md +9 -0
  129. package/templates/contextkit/memory/WORKSPACE.md +7 -0
  130. package/templates/contextkit/memory/business-rules/_TEMPLATE.md +33 -0
  131. package/templates/contextkit/memory/decisions/0000-record-architecture-decisions.md +34 -0
  132. package/templates/contextkit/memory/decisions/_TEMPLATE.md +25 -0
  133. package/templates/contextkit/memory/predictions/.gitkeep +0 -0
  134. package/templates/contextkit/memory/roadmap.md +28 -0
  135. package/templates/contextkit/memory/sessions/.gitkeep +0 -0
  136. package/templates/contextkit/memory/workflows/.gitkeep +0 -0
  137. package/templates/contextkit/pipeline/backlog/.gitkeep +0 -0
  138. package/templates/contextkit/pipeline/conclusion/.gitkeep +0 -0
  139. package/templates/contextkit/pipeline/devpipeline.md +9 -0
  140. package/templates/contextkit/pipeline/testing/.gitkeep +0 -0
  141. package/templates/contextkit/pipeline/working/.gitkeep +0 -0
  142. package/templates/contextkit/review-protocol.md +214 -0
  143. package/templates/contextkit/runtime/config/defaults.mjs +215 -0
  144. package/templates/contextkit/runtime/config/levels.mjs +42 -0
  145. package/templates/contextkit/runtime/config/load.mjs +105 -0
  146. package/templates/contextkit/runtime/config/paths.mjs +92 -0
  147. package/templates/contextkit/runtime/config/presets.mjs +47 -0
  148. package/templates/contextkit/runtime/config/schema.mjs +88 -0
  149. package/templates/contextkit/runtime/config/settings-compose.mjs +55 -0
  150. package/templates/contextkit/runtime/git-hooks/commit-msg.mjs +55 -0
  151. package/templates/contextkit/runtime/git-hooks/pre-commit.mjs +47 -0
  152. package/templates/contextkit/runtime/git-hooks/pre-push.mjs +102 -0
  153. package/templates/contextkit/runtime/hooks/boot-context-readers.mjs +111 -0
  154. package/templates/contextkit/runtime/hooks/boot-signals.mjs +135 -0
  155. package/templates/contextkit/runtime/hooks/check-registration.mjs +228 -0
  156. package/templates/contextkit/runtime/hooks/concurrency-guard.mjs +110 -0
  157. package/templates/contextkit/runtime/hooks/ledger.mjs +231 -0
  158. package/templates/contextkit/runtime/hooks/md-extract.mjs +65 -0
  159. package/templates/contextkit/runtime/hooks/path-classification.mjs +62 -0
  160. package/templates/contextkit/runtime/hooks/safe-io.mjs +84 -0
  161. package/templates/contextkit/runtime/hooks/session-digest-core.mjs +85 -0
  162. package/templates/contextkit/runtime/hooks/session-start.mjs +248 -0
  163. package/templates/contextkit/runtime/hooks/simulate-gate.mjs +108 -0
  164. package/templates/contextkit/runtime/hooks/track-edits.mjs +154 -0
  165. package/templates/contextkit/runtime/providers/media/_adapter.mjs +120 -0
  166. package/templates/contextkit/runtime/providers/media/nano-banana.mjs +110 -0
  167. package/templates/contextkit/runtime/providers/media/veo.mjs +162 -0
  168. package/templates/contextkit/runtime/providers/review/_adapter.mjs +71 -0
  169. package/templates/contextkit/runtime/providers/review/detect.mjs +115 -0
  170. package/templates/contextkit/runtime/providers/review/gh.mjs +103 -0
  171. package/templates/contextkit/runtime/state/state-io.mjs +172 -0
  172. package/templates/contextkit/runtime/statusline.mjs +51 -0
  173. package/templates/contextkit/squads/README.md +115 -0
  174. package/templates/contextkit/squads/_BRIEFING.md.tpl +27 -0
  175. package/templates/contextkit/squads/agent-forge/README.md +69 -0
  176. package/templates/contextkit/squads/agent-forge/ROADMAP.md +108 -0
  177. package/templates/contextkit/squads/agent-forge/best-practices.md +89 -0
  178. package/templates/contextkit/squads/agent-forge/cli/forge-admin.mjs +132 -0
  179. package/templates/contextkit/squads/agent-forge/cli/forge-eval-cli.mjs +163 -0
  180. package/templates/contextkit/squads/agent-forge/cli/forge-new.mjs +97 -0
  181. package/templates/contextkit/squads/agent-forge/cli/forge-ops.mjs +177 -0
  182. package/templates/contextkit/squads/agent-forge/lib/architect.mjs +112 -0
  183. package/templates/contextkit/squads/agent-forge/lib/eval-designer.mjs +133 -0
  184. package/templates/contextkit/squads/agent-forge/lib/eval-runner.mjs +167 -0
  185. package/templates/contextkit/squads/agent-forge/lib/governance-officer.mjs +178 -0
  186. package/templates/contextkit/squads/agent-forge/lib/package-ops.mjs +101 -0
  187. package/templates/contextkit/squads/agent-forge/lib/packager.mjs +219 -0
  188. package/templates/contextkit/squads/agent-forge/lib/prompt-gen.mjs +122 -0
  189. package/templates/contextkit/squads/agent-forge/lib/rag-designer.mjs +102 -0
  190. package/templates/contextkit/squads/agent-forge/lib/router.mjs +165 -0
  191. package/templates/contextkit/squads/agent-forge/lib/tool-gen.mjs +113 -0
  192. package/templates/contextkit/squads/agent-forge/lib/yaml.mjs +47 -0
  193. package/templates/contextkit/squads/agent-forge/pipeline.yaml +65 -0
  194. package/templates/contextkit/squads/agent-forge/router/capability-matrix.json +112 -0
  195. package/templates/contextkit/squads/agent-forge/router/decision-rules.json +120 -0
  196. package/templates/contextkit/squads/agent-forge/templates/agent-package/.agentforgerc +12 -0
  197. package/templates/contextkit/squads/agent-forge/templates/agent-package/CHANGELOG.md +13 -0
  198. package/templates/contextkit/squads/agent-forge/templates/agent-package/LICENSE +5 -0
  199. package/templates/contextkit/squads/agent-forge/templates/agent-package/README.md +39 -0
  200. package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/go/README.md +10 -0
  201. package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/go/agent.go +14 -0
  202. package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/go/go.mod +3 -0
  203. package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/node/README.md +11 -0
  204. package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/node/index.js +53 -0
  205. package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/node/package.json +9 -0
  206. package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/python/README.md +10 -0
  207. package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/python/agent.py +16 -0
  208. package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/python/pyproject.toml +10 -0
  209. package/templates/contextkit/squads/agent-forge/templates/agent-package/evals/golden.jsonl +1 -0
  210. package/templates/contextkit/squads/agent-forge/templates/agent-package/evals/red-team.jsonl +3 -0
  211. package/templates/contextkit/squads/agent-forge/templates/agent-package/evals/rubric.yaml +14 -0
  212. package/templates/contextkit/squads/agent-forge/templates/agent-package/evals/run-eval.md +17 -0
  213. package/templates/contextkit/squads/agent-forge/templates/agent-package/evals/thresholds.yaml +18 -0
  214. package/templates/contextkit/squads/agent-forge/templates/agent-package/examples/basic.node.md +17 -0
  215. package/templates/contextkit/squads/agent-forge/templates/agent-package/examples/with-fallback.node.md +24 -0
  216. package/templates/contextkit/squads/agent-forge/templates/agent-package/examples/with-rag.python.md +20 -0
  217. package/templates/contextkit/squads/agent-forge/templates/agent-package/governance/audit.schema.json +23 -0
  218. package/templates/contextkit/squads/agent-forge/templates/agent-package/governance/compliance.policy.yaml +43 -0
  219. package/templates/contextkit/squads/agent-forge/templates/agent-package/governance/cost.policy.yaml +36 -0
  220. package/templates/contextkit/squads/agent-forge/templates/agent-package/governance/fallback-chain.yaml +16 -0
  221. package/templates/contextkit/squads/agent-forge/templates/agent-package/governance/quality.policy.yaml +43 -0
  222. package/templates/contextkit/squads/agent-forge/templates/agent-package/manifest.yaml +91 -0
  223. package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.anthropic.md +19 -0
  224. package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.canonical.md +25 -0
  225. package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.deepseek.md +21 -0
  226. package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.google.md +19 -0
  227. package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.ollama.md +21 -0
  228. package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.openai.md +20 -0
  229. package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/config.yaml +17 -0
  230. package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/index/.gitkeep +3 -0
  231. package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/ingestion/chunker.config.yaml +6 -0
  232. package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/ingestion/sources.yaml +8 -0
  233. package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/retrieval/query-template.md +16 -0
  234. package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/retrieval/rerank.config.yaml +6 -0
  235. package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/adapters/anthropic.tools.json +11 -0
  236. package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/adapters/deepseek.tools.json +14 -0
  237. package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/adapters/google.tools.json +11 -0
  238. package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/adapters/ollama.tools.json +14 -0
  239. package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/adapters/openai.tools.json +14 -0
  240. package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/schemas.canonical.json +25 -0
  241. package/templates/contextkit/starters/tanstack/README.md +86 -0
  242. package/templates/contextkit/starters/tanstack/index.html +12 -0
  243. package/templates/contextkit/starters/tanstack/package.json +25 -0
  244. package/templates/contextkit/starters/tanstack/src/main.tsx +40 -0
  245. package/templates/contextkit/starters/tanstack/src/router.tsx +12 -0
  246. package/templates/contextkit/starters/tanstack/src/routes/__root.tsx +10 -0
  247. package/templates/contextkit/starters/tanstack/src/routes/index.tsx +17 -0
  248. package/templates/contextkit/starters/tanstack/tsconfig.json +19 -0
  249. package/templates/contextkit/starters/tanstack/vite.config.ts +10 -0
  250. package/templates/contextkit/tools/scripts/adr-digest-core.mjs +42 -0
  251. package/templates/contextkit/tools/scripts/adr-digest.mjs +78 -0
  252. package/templates/contextkit/tools/scripts/agent-tuning.mjs +74 -0
  253. package/templates/contextkit/tools/scripts/aiso-audit.mjs +174 -0
  254. package/templates/contextkit/tools/scripts/audit-shared.mjs +129 -0
  255. package/templates/contextkit/tools/scripts/claim.mjs +133 -0
  256. package/templates/contextkit/tools/scripts/claude-md.mjs +123 -0
  257. package/templates/contextkit/tools/scripts/clean-drive.mjs +78 -0
  258. package/templates/contextkit/tools/scripts/context-config.mjs +111 -0
  259. package/templates/contextkit/tools/scripts/context-level.mjs +98 -0
  260. package/templates/contextkit/tools/scripts/context-pack.mjs +120 -0
  261. package/templates/contextkit/tools/scripts/contract-scan.mjs +186 -0
  262. package/templates/contextkit/tools/scripts/dashboard-data.mjs +198 -0
  263. package/templates/contextkit/tools/scripts/dashboard-html.mjs +215 -0
  264. package/templates/contextkit/tools/scripts/dashboard-server.mjs +129 -0
  265. package/templates/contextkit/tools/scripts/dashboard.mjs +107 -0
  266. package/templates/contextkit/tools/scripts/deep-analysis.mjs +62 -0
  267. package/templates/contextkit/tools/scripts/deps-audit.mjs +201 -0
  268. package/templates/contextkit/tools/scripts/detect-stack.mjs +164 -0
  269. package/templates/contextkit/tools/scripts/distill-detect.mjs +90 -0
  270. package/templates/contextkit/tools/scripts/doctor.mjs +165 -0
  271. package/templates/contextkit/tools/scripts/fleet.mjs +170 -0
  272. package/templates/contextkit/tools/scripts/generate-context.mjs +142 -0
  273. package/templates/contextkit/tools/scripts/gh-alerts.mjs +117 -0
  274. package/templates/contextkit/tools/scripts/git.mjs +97 -0
  275. package/templates/contextkit/tools/scripts/home.mjs +106 -0
  276. package/templates/contextkit/tools/scripts/mark-simulation.mjs +78 -0
  277. package/templates/contextkit/tools/scripts/media-gen.mjs +154 -0
  278. package/templates/contextkit/tools/scripts/pipeline-board.mjs +74 -0
  279. package/templates/contextkit/tools/scripts/pipeline-prioritize.mjs +68 -0
  280. package/templates/contextkit/tools/scripts/pipeline-session.mjs +99 -0
  281. package/templates/contextkit/tools/scripts/pipeline-validate.mjs +136 -0
  282. package/templates/contextkit/tools/scripts/pipeline.mjs +302 -0
  283. package/templates/contextkit/tools/scripts/playbook.mjs +123 -0
  284. package/templates/contextkit/tools/scripts/predictions-review.mjs +113 -0
  285. package/templates/contextkit/tools/scripts/release.mjs +60 -0
  286. package/templates/contextkit/tools/scripts/resume.mjs +114 -0
  287. package/templates/contextkit/tools/scripts/roadmap.mjs +86 -0
  288. package/templates/contextkit/tools/scripts/runs.mjs +116 -0
  289. package/templates/contextkit/tools/scripts/seo-audit.mjs +150 -0
  290. package/templates/contextkit/tools/scripts/session-digest.mjs +89 -0
  291. package/templates/contextkit/tools/scripts/session-reindex.mjs +91 -0
  292. package/templates/contextkit/tools/scripts/setup-complete.mjs +69 -0
  293. package/templates/contextkit/tools/scripts/squad-meta.mjs +23 -0
  294. package/templates/contextkit/tools/scripts/squad-pipeline-condition.mjs +192 -0
  295. package/templates/contextkit/tools/scripts/squad-pipeline.mjs +301 -0
  296. package/templates/contextkit/tools/scripts/squad.mjs +80 -0
  297. package/templates/contextkit/tools/scripts/stats.mjs +138 -0
  298. package/templates/contextkit/tools/scripts/sync-check.mjs +235 -0
  299. package/templates/contextkit/tools/scripts/tech-debt-detectors.mjs +76 -0
  300. package/templates/contextkit/tools/scripts/tech-debt-scan.mjs +164 -0
  301. package/templates/contextkit/tools/scripts/token-report.mjs +153 -0
  302. package/templates/contextkit/tools/scripts/visual-test.mjs +132 -0
  303. package/templates/contextkit/tools/scripts/watch.mjs +106 -0
  304. package/templates/contextkit/tools/scripts/workflow.mjs +136 -0
  305. package/templates/contextkit/tools/scripts/workspace-sync.mjs +220 -0
  306. package/templates/contextkit/tools/scripts/worktree-new.mjs +50 -0
  307. package/templates/contextkit/workflows/L1-static-loading.md +59 -0
  308. package/templates/contextkit/workflows/L2-session-ledger.md +86 -0
  309. package/templates/contextkit/workflows/L3-multi-session.md +80 -0
  310. package/templates/contextkit/workflows/L4-squads.md +68 -0
  311. package/templates/contextkit/workflows/L5-proactive.md +88 -0
  312. package/templates/contextkit/workflows/README.md +47 -0
  313. package/templates/contextkit/workflows/playbooks/distillation-cycle.md +74 -0
  314. package/templates/contextkit/workflows/playbooks/landing-page.md +197 -0
  315. package/templates/contextkit/workflows/playbooks/security-batch.md +68 -0
  316. package/templates/contextkit/workflows/playbooks/seo-aiso.md +288 -0
  317. package/templates/contextkit/workflows/playbooks/simulate-impact.md +83 -0
  318. package/templates/contextkit/workflows/playbooks/tanstack.md +164 -0
  319. package/templates/contextkit/workflows/playbooks/tech-debt-sweep.md +77 -0
  320. package/templates/docs/CHANGELOG.md.tpl +11 -0
  321. package/templates/gitattributes +3 -0
  322. package/templates/github/ISSUE_TEMPLATE/bug_report.md +30 -0
  323. package/templates/github/ISSUE_TEMPLATE/feature_request.md +22 -0
  324. package/templates/github/PULL_REQUEST_TEMPLATE.md +27 -0
  325. package/templates/github/dependabot.yml +27 -0
  326. package/templates/github/workflows/quality.yml +36 -0
  327. package/templates/github/workflows/security.yml +54 -0
  328. package/tools/install/cli.mjs +62 -0
  329. package/tools/install/fs.mjs +56 -0
  330. package/tools/install/git.mjs +114 -0
  331. package/tools/install/project.mjs +51 -0
  332. package/tools/install/uninstall.mjs +54 -0
  333. package/tools/integration-test-compozy.mjs +88 -0
  334. package/tools/integration-test-guards.mjs +269 -0
  335. package/tools/integration-test-tooling-agent-forge.mjs +189 -0
  336. package/tools/integration-test-tooling-pipeline.mjs +164 -0
  337. package/tools/integration-test-tooling.mjs +172 -0
  338. package/tools/integration-test.mjs +228 -0
  339. package/tools/it-helpers.mjs +60 -0
  340. package/tools/selfcheck-agent-forge-ops.mjs +107 -0
  341. package/tools/selfcheck-agent-forge.mjs +304 -0
  342. package/tools/selfcheck-config.mjs +80 -0
  343. package/tools/selfcheck-runtime.mjs +135 -0
  344. package/tools/selfcheck-source.mjs +326 -0
  345. package/tools/selfcheck.mjs +268 -0
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Version-control diagnostics — facts for the `/git` skill.
4
+ *
5
+ * Reports git presence, repo/commit state, the remote + inferred provider
6
+ * (GitHub/GitLab/Bitbucket/Azure), whether the provider CLI (`gh`/`glab`) is
7
+ * installed and authenticated, the current branch, dirtiness, and ahead/behind
8
+ * vs upstream. `/git` reads this and suggests the exact next commands.
9
+ *
10
+ * Usage: node contextkit/tools/scripts/git.mjs status [--json]
11
+ */
12
+ import { execFileSync } from 'node:child_process';
13
+
14
+ const ROOT = process.cwd();
15
+
16
+ /**
17
+ * Hard ceiling (ms) for any git/CLI subprocess. A hung network call — `git fetch`
18
+ * against an unreachable remote, or `gh auth status` with no connectivity — must
19
+ * not freeze `/git status`. On timeout `execFileSync` throws, so `run()` returns
20
+ * `{ ok:false }` (the same path as a failed command) and the report degrades
21
+ * gracefully. Overridable via env so tests can drive the timeout path fast.
22
+ */
23
+ const CMD_TIMEOUT_MS = Number.parseInt(process.env.CONTEXT_GIT_TIMEOUT_MS || '', 10) || 10000;
24
+
25
+ function run(cmd, args) {
26
+ try {
27
+ return { ok: true, out: execFileSync(cmd, args, { cwd: ROOT, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'], timeout: CMD_TIMEOUT_MS }).trim() };
28
+ } catch (err) {
29
+ return { ok: false, out: '', code: err?.status };
30
+ }
31
+ }
32
+
33
+ function providerFromUrl(url) {
34
+ if (!url) return null;
35
+ if (/github\.com/i.test(url)) return 'github';
36
+ if (/gitlab/i.test(url)) return 'gitlab';
37
+ if (/bitbucket\.org/i.test(url)) return 'bitbucket';
38
+ if (/dev\.azure\.com|visualstudio\.com/i.test(url)) return 'azure';
39
+ return 'other';
40
+ }
41
+
42
+ function collect() {
43
+ const gitV = run('git', ['--version']);
44
+ const isRepo = run('git', ['rev-parse', '--is-inside-work-tree']).ok;
45
+ const hasCommits = isRepo && run('git', ['rev-parse', 'HEAD']).ok;
46
+ const remoteUrl = run('git', ['remote', 'get-url', 'origin']).out || null;
47
+ const provider = providerFromUrl(remoteUrl);
48
+ const branch = run('git', ['symbolic-ref', '--short', 'HEAD']).out || null;
49
+ const dirty = isRepo ? run('git', ['status', '--porcelain']).out.length > 0 : false;
50
+
51
+ // Provider CLIs.
52
+ const gh = run('gh', ['--version']).ok;
53
+ const ghAuth = gh ? run('gh', ['auth', 'status']).ok : false;
54
+ const glab = run('glab', ['--version']).ok;
55
+ const glabAuth = glab ? run('glab', ['auth', 'status']).ok : false;
56
+
57
+ // ahead/behind vs upstream.
58
+ let ahead = null;
59
+ let behind = null;
60
+ if (remoteUrl && branch) {
61
+ run('git', ['fetch', 'origin', '--quiet']);
62
+ const counts = run('git', ['rev-list', '--left-right', '--count', 'HEAD...@{u}']);
63
+ if (counts.ok) {
64
+ const [a, b] = counts.out.split(/\s+/);
65
+ ahead = Number.parseInt(a ?? '0', 10);
66
+ behind = Number.parseInt(b ?? '0', 10);
67
+ }
68
+ }
69
+
70
+ return {
71
+ git: gitV.ok ? gitV.out.replace('git version ', '') : null,
72
+ isRepo,
73
+ hasCommits,
74
+ remoteUrl,
75
+ provider,
76
+ branch,
77
+ dirty,
78
+ cli: { gh, ghAuth, glab, glabAuth },
79
+ ahead,
80
+ behind,
81
+ };
82
+ }
83
+
84
+ const s = collect();
85
+ if (process.argv.includes('--json')) {
86
+ console.log(JSON.stringify(s, null, 2));
87
+ } else {
88
+ console.log('🔧 Version control\n');
89
+ console.log(`git: ${s.git ?? 'NOT INSTALLED'}`);
90
+ console.log(`repo: ${s.isRepo ? (s.hasCommits ? 'yes (has commits)' : 'yes (no commits yet)') : 'NOT a git repo'}`);
91
+ console.log(`branch: ${s.branch ?? '—'}${s.dirty ? ' (uncommitted changes)' : ''}`);
92
+ console.log(`remote: ${s.remoteUrl ?? 'NONE'}${s.provider ? ` [${s.provider}]` : ''}`);
93
+ if (s.ahead != null) console.log(`sync: ahead ${s.ahead} / behind ${s.behind}`);
94
+ console.log(`gh CLI: ${s.cli.gh ? (s.cli.ghAuth ? 'installed + authed' : 'installed, NOT authed') : 'not installed'}`);
95
+ console.log(`glab CLI: ${s.cli.glab ? (s.cli.glabAuth ? 'installed + authed' : 'installed, NOT authed') : 'not installed'}`);
96
+ if (!s.remoteUrl) console.log('\n→ No remote. Run /git to set one up (GitHub/GitLab/other) + install the CLI.');
97
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Home-scoped state helper — single owner of `~/.contextdevkit/` resolution +
3
+ * atomic write contract (ADR-0020).
4
+ *
5
+ * Why this exists:
6
+ * Cross-repo registries (fleet.json), per-machine preferences, and
7
+ * regenerable caches all need to live outside any single repo. Before
8
+ * this helper, `fleet.mjs` resolved the path and wrote the file inline;
9
+ * any future consumer would have reinvented (and likely gotten slightly
10
+ * wrong) the same logic.
11
+ *
12
+ * Contract (ADR-0020):
13
+ * - Lazy creation. The directory is created on demand.
14
+ * - `CONTEXTDEVKIT_HOME` env var overrides the directory (for tests and
15
+ * sandboxed environments).
16
+ * - All files are plain JSON, UTF-8, no BOM.
17
+ * - Each file declares its own `version` field. Absent = legacy /
18
+ * pre-versioning (adopted on next write). An *explicitly unknown*
19
+ * value triggers a timestamped `.bak.<ms>` copy and a fresh read.
20
+ * - Atomic write via tmp + rename (`renameSync` after `writeFileSync`).
21
+ * - Graceful refuse on every error path (rule 2 — hooks never break
22
+ * real work). Returns `null` instead of throwing on read failures.
23
+ *
24
+ * Zero deps. No HTTP, no SQLite, no daemon (ADR-0020 explicitly rules
25
+ * those out).
26
+ */
27
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
28
+ import { homedir } from 'node:os';
29
+ import { resolve } from 'node:path';
30
+
31
+ const HOME_DIR_NAME = '.contextdevkit';
32
+ const CURRENT_VERSION = 1;
33
+
34
+ /**
35
+ * Resolve and lazily create the home-scoped state directory.
36
+ *
37
+ * Honours `CONTEXTDEVKIT_HOME` first; otherwise falls back to
38
+ * `~/.contextdevkit/`. The directory is created on first call; subsequent
39
+ * calls are silent.
40
+ *
41
+ * @returns {string} absolute directory path
42
+ */
43
+ export function resolveHome() {
44
+ const dir = process.env.CONTEXTDEVKIT_HOME || resolve(homedir(), HOME_DIR_NAME);
45
+ if (!existsSync(dir)) {
46
+ try { mkdirSync(dir, { recursive: true }); } catch { /* defensive */ }
47
+ }
48
+ return dir;
49
+ }
50
+
51
+ /**
52
+ * Read a JSON file from `~/.contextdevkit/`. Returns `null` when the file is
53
+ * absent, malformed, not a plain object, or written by a future version
54
+ * the helper does not recognise (in which case the bad file is moved to
55
+ * `<name>.bak.<timestamp>` so the next write starts clean).
56
+ *
57
+ * A file without a `version` field is treated as legacy and adopted —
58
+ * the next write stamps `version: 1`. This avoids destroying existing
59
+ * `fleet.json` data on first read by the new helper.
60
+ *
61
+ * @param {string} name file name relative to the home dir (e.g. `fleet.json`)
62
+ * @returns {object | null}
63
+ */
64
+ export function readHomeFile(name) {
65
+ const path = resolve(resolveHome(), name);
66
+ if (!existsSync(path)) return null;
67
+ let parsed;
68
+ try {
69
+ parsed = JSON.parse(readFileSync(path, 'utf-8').replace(/^/, ''));
70
+ } catch {
71
+ return null;
72
+ }
73
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return null;
74
+ const v = parsed.version;
75
+ if (v !== undefined && v !== CURRENT_VERSION) {
76
+ try { renameSync(path, `${path}.bak.${Date.now()}`); } catch { /* defensive */ }
77
+ return null;
78
+ }
79
+ return parsed;
80
+ }
81
+
82
+ /**
83
+ * Atomically write a JSON file under `~/.contextdevkit/`. Stamps the current
84
+ * `version` field if absent — callers do not need to track schema
85
+ * versioning themselves.
86
+ *
87
+ * Atomicity: writes to `<name>.tmp.<pid>` then `renameSync`s into place,
88
+ * matching the kit's installer posture.
89
+ *
90
+ * @param {string} name file name relative to the home dir
91
+ * @param {object} data plain object to serialise
92
+ * @throws {Error} when `data` is not a plain object
93
+ */
94
+ export function writeHomeFile(name, data) {
95
+ if (data === null || typeof data !== 'object' || Array.isArray(data)) {
96
+ throw new Error('writeHomeFile: data must be a plain object');
97
+ }
98
+ const stamped = data.version === CURRENT_VERSION ? data : { version: CURRENT_VERSION, ...data };
99
+ const path = resolve(resolveHome(), name);
100
+ const tmp = `${path}.tmp.${process.pid}`;
101
+ writeFileSync(tmp, JSON.stringify(stamped, null, 2) + '\n', 'utf-8');
102
+ renameSync(tmp, path);
103
+ }
104
+
105
+ /** Current schema version recognised by this helper. Exported for selfcheck. */
106
+ export const HOME_SCHEMA_VERSION = CURRENT_VERSION;
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Records a `/simulate-impact` result on the current session's ledger so the
4
+ * Level 5 PreToolUse gate authorizes edits inside the covered paths.
5
+ *
6
+ * Usage:
7
+ * node contextkit/tools/scripts/mark-simulation.mjs "<objective>" <path> [path2 ...]
8
+ * node contextkit/tools/scripts/mark-simulation.mjs "BYPASS: typo fix" path/to/file
9
+ *
10
+ * Pass directory prefixes WITH a trailing slash to cover everything inside.
11
+ */
12
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
13
+ import { resolve } from 'node:path';
14
+ import { markSimulation, readLedger, toRepoRelative, writeLedger } from '../../runtime/hooks/ledger.mjs';
15
+ import { pathsFor } from '../../runtime/config/paths.mjs';
16
+
17
+ const LAST_TOUCHED = resolve(process.cwd(), '.claude/.sessions/.last-touched');
18
+
19
+ async function sessionId() {
20
+ try {
21
+ return JSON.parse(await readFile(LAST_TOUCHED, 'utf-8')).sessionId;
22
+ } catch {
23
+ return `local_${process.pid}`;
24
+ }
25
+ }
26
+
27
+ async function main() {
28
+ const [objective, ...rawPaths] = process.argv.slice(2);
29
+ if (!objective || rawPaths.length === 0) {
30
+ console.error('Usage: mark-simulation.mjs "<objective>" <path> [path2 ...]');
31
+ process.exit(1);
32
+ }
33
+ const coveredPaths = rawPaths.map((p) => {
34
+ const norm = toRepoRelative(p);
35
+ // Preserve an explicit trailing slash (directory claim).
36
+ return p.endsWith('/') && !norm.endsWith('/') ? `${norm}/` : norm;
37
+ });
38
+
39
+ const sid = await sessionId();
40
+ const ledger = await readLedger(sid);
41
+ const predFile = await writePrediction(sid, objective, coveredPaths);
42
+ markSimulation(ledger, { objective, coveredPaths, predictionFile: predFile });
43
+ await writeLedger(sid, ledger);
44
+ console.log(`✅ Simulation recorded for session ${sid.slice(0, 8)} covering: ${coveredPaths.join(', ')}`);
45
+ if (predFile) console.log(` 📄 prediction trail: ${predFile}`);
46
+ }
47
+
48
+ /** Writes a prediction file (ancestor parity) for a later predicted-vs-actual review. */
49
+ async function writePrediction(sid, objective, coveredPaths) {
50
+ const date = new Date().toISOString().slice(0, 10);
51
+ const slug = objective.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 40) || 'prediction';
52
+ const rel = `contextkit/memory/predictions/${date}-${sid.slice(0, 8)}-${slug}.md`;
53
+ try {
54
+ await mkdir(pathsFor(process.cwd()).predictions, { recursive: true });
55
+ await writeFile(resolve(process.cwd(), rel), [
56
+ `# Prediction — ${objective}`,
57
+ '',
58
+ `- **Date**: ${date}`,
59
+ `- **Session**: ${sid.slice(0, 8)}`,
60
+ `- **Covered paths**: ${coveredPaths.join(', ') || '—'}`,
61
+ '',
62
+ '## Predicted blast radius',
63
+ '_What you expect to change + the risks (from /simulate-impact)._',
64
+ '',
65
+ '## Actual — fill on review',
66
+ '_What actually changed. Was the prediction right? Lessons for next time._',
67
+ '',
68
+ ].join('\n'), 'utf-8');
69
+ return rel;
70
+ } catch {
71
+ return null;
72
+ }
73
+ }
74
+
75
+ main().catch((err) => {
76
+ console.error('❌ mark-simulation failed:', err);
77
+ process.exit(1);
78
+ });
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * /media-gen — CLI entry for the media-provider adapters (ADR-0024).
4
+ *
5
+ * node contextkit/tools/scripts/media-gen.mjs image --prompt "..." --out path.png
6
+ * node contextkit/tools/scripts/media-gen.mjs video --prompt "..." --out path.mp4
7
+ * node contextkit/tools/scripts/media-gen.mjs image --prompt "..." --out path.png --dry-run
8
+ *
9
+ * Reads credentials from process.env (recommended: run via
10
+ * `node --env-file=contextkit/.env contextkit/tools/scripts/media-gen.mjs ...`
11
+ * on Node 20.6+). Refuses cleanly with NO_CREDENTIALS pointing at
12
+ * contextkit/.env.example when keys are absent.
13
+ *
14
+ * Defensive (rule 2). Zero deps.
15
+ */
16
+ import { readdirSync } from 'node:fs';
17
+ import { dirname, resolve } from 'node:path';
18
+ import { fileURLToPath, pathToFileURL } from 'node:url';
19
+ import { validateAdapter, MediaProviderError, MEDIA_ERROR_CODES, readCostCapUsd } from '../../runtime/providers/media/_adapter.mjs';
20
+
21
+ const ADAPTERS_DIR = resolve(fileURLToPath(import.meta.url), '..', '..', '..', 'runtime', 'providers', 'media');
22
+
23
+ const help = `Usage:
24
+ media-gen.mjs <image|video> --prompt "..." --out PATH [options]
25
+
26
+ Common options:
27
+ --prompt "..." what to generate (required)
28
+ --out PATH where to write the file (required unless --dry-run)
29
+ --provider ID force a specific adapter id (e.g. nano-banana, veo)
30
+ --aspect-ratio R 16:9 | 9:16 | 1:1 | 3:4 | 4:3 (provider-dependent)
31
+ --duration N seconds (video only; default 8)
32
+ --model ID override the adapter's default model
33
+ --sample-count N image only; 1..4 (only the first is written)
34
+ --dry-run show what would be called; make no network request
35
+ --help this message
36
+
37
+ Env:
38
+ GOOGLE_AI_API_KEY required for nano-banana + veo
39
+ CONTEXTDEVKIT_MEDIA_MAX_USD optional per-process spend cap (USD)
40
+
41
+ See contextkit/.env.example for the template.
42
+ `;
43
+
44
+ function parseArgs(argv) {
45
+ const args = { _: [] };
46
+ for (let i = 0; i < argv.length; i++) {
47
+ const a = argv[i];
48
+ if (a === '--dry-run') args.dryRun = true;
49
+ else if (a === '--help' || a === '-h') args.help = true;
50
+ else if (a.startsWith('--')) {
51
+ const name = a.slice(2);
52
+ const next = argv[i + 1];
53
+ if (next && !next.startsWith('--')) { args[camel(name)] = next; i++; }
54
+ else args[camel(name)] = true;
55
+ } else {
56
+ args._.push(a);
57
+ }
58
+ }
59
+ return args;
60
+ }
61
+ const camel = (s) => s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
62
+
63
+ async function loadAdapters() {
64
+ const files = readdirSync(ADAPTERS_DIR)
65
+ .filter((f) => f.endsWith('.mjs') && !f.startsWith('_'));
66
+ const out = [];
67
+ for (const file of files) {
68
+ const url = pathToFileURL(resolve(ADAPTERS_DIR, file)).href;
69
+ const mod = await import(url);
70
+ const verdict = validateAdapter(mod);
71
+ if (verdict.ok) out.push(mod);
72
+ else process.stderr.write(`media-gen: skipping ${file} — invalid adapter: ${verdict.reasons.join('; ')}\n`);
73
+ }
74
+ return out;
75
+ }
76
+
77
+ function pickAdapter(adapters, args) {
78
+ const kind = args._[0]; // 'image' | 'video'
79
+ if (!kind || (kind !== 'image' && kind !== 'video')) {
80
+ throw new Error(`first positional arg must be "image" or "video"; got: ${kind || '(nothing)'}`);
81
+ }
82
+ const wantId = args.provider;
83
+ const pool = adapters.filter((a) => a.kind === kind);
84
+ if (!pool.length) throw new Error(`no media adapter of kind="${kind}" is installed`);
85
+ if (wantId) {
86
+ const hit = pool.find((a) => a.id === wantId);
87
+ if (!hit) throw new Error(`no adapter with id="${wantId}" of kind="${kind}". Available: ${pool.map((a) => a.id).join(', ')}`);
88
+ return hit;
89
+ }
90
+ return pool[0];
91
+ }
92
+
93
+ function buildOptions(args) {
94
+ const o = {};
95
+ if (args.aspectRatio) o.aspectRatio = args.aspectRatio;
96
+ if (args.model) o.model = args.model;
97
+ if (args.duration) o.durationSeconds = Number(args.duration);
98
+ if (args.sampleCount) o.sampleCount = Number(args.sampleCount);
99
+ return o;
100
+ }
101
+
102
+ const isMain = (() => {
103
+ try {
104
+ const here = new URL(import.meta.url).pathname.toLowerCase();
105
+ const entry = process.argv[1]
106
+ ? new URL('file://' + process.argv[1].replace(/\\/g, '/')).pathname.toLowerCase()
107
+ : '';
108
+ return here === entry;
109
+ } catch { return false; }
110
+ })();
111
+
112
+ if (isMain) {
113
+ (async () => {
114
+ const args = parseArgs(process.argv.slice(2));
115
+ if (args.help || process.argv.length <= 2) {
116
+ process.stdout.write(help);
117
+ process.exit(0);
118
+ }
119
+ const adapters = await loadAdapters();
120
+ let adapter;
121
+ try { adapter = pickAdapter(adapters, args); }
122
+ catch (err) { process.stderr.write(`media-gen: ${err.message}\n`); process.exit(2); }
123
+
124
+ if (!args.prompt) { process.stderr.write('media-gen: --prompt is required\n'); process.exit(2); }
125
+ if (!args.out && !args.dryRun) { process.stderr.write('media-gen: --out PATH is required (or pass --dry-run)\n'); process.exit(2); }
126
+
127
+ const options = buildOptions(args);
128
+ const cap = readCostCapUsd();
129
+ const capLine = cap !== null ? ` · cost cap $${cap.toFixed(2)}` : '';
130
+
131
+ if (args.dryRun) {
132
+ process.stdout.write(`🎬 dry-run · ${adapter.id} (${adapter.kind})${capLine}\n`);
133
+ process.stdout.write(` prompt: ${args.prompt}\n`);
134
+ process.stdout.write(` out: ${args.out || '(none)'}\n`);
135
+ process.stdout.write(` options: ${JSON.stringify(options)}\n`);
136
+ process.stdout.write(` env required: ${adapter.requiredEnv.join(', ')}${adapter.requiredEnv.every((n) => process.env[n]) ? ' ✓ set' : ' ✗ missing'}\n`);
137
+ process.exit(0);
138
+ }
139
+
140
+ try {
141
+ const r = await adapter.generate({ prompt: args.prompt, outPath: resolve(args.out), options });
142
+ process.stdout.write(`✅ ${adapter.id}: wrote ${r.outPath}\n`);
143
+ process.stdout.write(` duration: ${r.durationMs} ms · est. cost: $${r.costEstimateUsd.toFixed(2)}${r.providerRequestId ? ` · req: ${r.providerRequestId}` : ''}\n`);
144
+ process.exit(0);
145
+ } catch (err) {
146
+ if (err instanceof MediaProviderError) {
147
+ process.stderr.write(`✗ ${err.code}: ${err.message}\n`);
148
+ process.exit(err.code === MEDIA_ERROR_CODES.NO_CREDENTIALS ? 3 : 1);
149
+ }
150
+ process.stderr.write(`media-gen: ${err.message}\n`);
151
+ process.exit(1);
152
+ }
153
+ })();
154
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * DevPipeline board rendering — turns the task list into `devpipeline.md`.
3
+ *
4
+ * Pure (takes the task array), so `pipeline.mjs` (the CLI) stays lean. Shows the
5
+ * WSJF priority + SLA, and flags overdue items (⏰).
6
+ */
7
+ import { isOverdue } from './pipeline-prioritize.mjs';
8
+ import { blockedBy } from './pipeline-validate.mjs';
9
+
10
+ function table(tasks, allTasks) {
11
+ if (tasks.length === 0) return '_(empty)_\n';
12
+ const rows = ['| ID | Pri | WSJF | Type | Cx | Title | SLA | Roadmap |', '| --- | --- | --- | --- | --- | --- | --- | --- |'];
13
+ for (const t of tasks) {
14
+ const sla = t.sla ? (isOverdue(t) ? `⏰ ${t.sla}` : t.sla) : '—';
15
+ const cx = t.complexity || '—';
16
+ const n = blockedBy(t, allTasks);
17
+ const title = n > 0 ? `${t.title} ↘ blocked by ${n}` : t.title;
18
+ rows.push(`| ${t.id} | ${t.priority} | ${t.wsjf || '—'} | ${t.type} | ${cx} | ${title} | ${sla} | ${t.roadmap || '—'} |`);
19
+ }
20
+ return rows.join('\n') + '\n';
21
+ }
22
+
23
+ /** Full `devpipeline.md` markdown from the task list. */
24
+ export function renderBoard(tasks) {
25
+ const by = (s) => tasks.filter((t) => t.stage === s);
26
+ const overdue = tasks.filter(isOverdue);
27
+ const out = [];
28
+ out.push('# DevPipeline — execution board');
29
+ out.push('');
30
+ out.push('> ⚠️ **AUTO-GENERATED** by `pipeline.mjs sync` (also on pre-commit). Do not hand-edit.');
31
+ out.push('> Product/business plan is `contextkit/memory/roadmap.md`. THIS is execution control:');
32
+ out.push('> bugs / increments / chores with **WSJF** priority + **SLA** (⏰ = overdue).');
33
+ out.push('');
34
+ out.push(`Backlog **${by('backlog').length}** · Working **${by('working').length}** · Testing **${by('testing').length}** · Concluded **${by('conclusion').length}** · ⏰ Overdue **${overdue.length}**`);
35
+ out.push('');
36
+ out.push('## 🔵 Working (active, owned by a session)');
37
+ out.push('');
38
+ out.push(table(by('working'), tasks));
39
+ out.push('## 🟡 In testing (code written, awaiting QA)');
40
+ out.push('');
41
+ out.push(table(by('testing'), tasks));
42
+ out.push('## 📋 Backlog (by priority)');
43
+ out.push('');
44
+ out.push(table(by('backlog'), tasks));
45
+ out.push('## ✅ Concluded (recent)');
46
+ out.push('');
47
+ out.push(table(by('conclusion').slice(-15), tasks));
48
+ return out.join('\n');
49
+ }
50
+
51
+ const SEV_ORDER = ['S1', 'S2', 'S3', 'S4', ''];
52
+ const SEV_LABEL = { S1: 'S1 · Critical', S2: 'S2 · High', S3: 'S3 · Medium', S4: 'S4 · Low', '': 'Unclassified' };
53
+
54
+ /** Known-bugs map: every `type: bug` task, grouped by severity, open vs resolved. */
55
+ export function renderKnownBugs(tasks) {
56
+ const bugs = tasks.filter((t) => t.type === 'bug');
57
+ const out = ['# Known Bugs — map', ''];
58
+ out.push('> ⚠️ AUTO-GENERATED by `pipeline.mjs sync`. The bug registry, grouped by severity.');
59
+ out.push(`> ${bugs.length} known · ${bugs.filter((b) => b.stage !== 'conclusion').length} open · ${bugs.filter(isOverdue).length} ⏰ overdue`);
60
+ out.push('');
61
+ if (bugs.length === 0) return out.concat(['✅ No bugs on record.', '']).join('\n');
62
+ for (const sev of SEV_ORDER) {
63
+ const inSev = bugs.filter((b) => (b.severity || '') === sev);
64
+ if (inSev.length === 0) continue;
65
+ out.push(`## ${SEV_LABEL[sev]} (${inSev.length})`, '', '| ID | Status | Bug type | Title | SLA |', '| --- | --- | --- | --- | --- |');
66
+ for (const b of inSev) {
67
+ const status = b.stage === 'conclusion' ? '✅ resolved' : b.stage === 'testing' ? '🟡 testing' : b.stage === 'working' ? '🔵 working' : '📋 open';
68
+ const sla = b.sla ? (isOverdue(b) ? `⏰ ${b.sla}` : b.sla) : '—';
69
+ out.push(`| ${b.id} | ${status} | ${b.bugType || '—'} | ${b.title} | ${sla} |`);
70
+ }
71
+ out.push('');
72
+ }
73
+ return out.join('\n');
74
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * DevPipeline prioritization — WSJF (SAFe) + bug severity (S1–S4) + SLA.
3
+ *
4
+ * Pure functions over plain numbers/strings, zero deps. The bands / SLA / bug
5
+ * taxonomy can be overridden in `contextkit/config.json` → `pipeline.*`; these are
6
+ * the defaults the CLI falls back to.
7
+ *
8
+ * Model: every task lands on a priority **P0–P3**, derived from one of —
9
+ * • WSJF score (value items) → `wsjfToPriority`
10
+ * • bug severity S1–S4 (bugs) → `bugSeverityToPriority`
11
+ * • scanner severity 1–5 → `severityToPriority`
12
+ * — and the **SLA due date** follows from the priority (`slaDue`).
13
+ */
14
+ export const DEFAULTS = {
15
+ wsjfBands: { p0: 8, p1: 5, p2: 2 }, // WSJF score ≥ → priority
16
+ severityPriority: { S1: 'P0', S2: 'P1', S3: 'P2', S4: 'P3' }, // ITIL bug severity
17
+ slaDays: { P0: 1, P1: 3, P2: 14, P3: 60 }, // resolution target per priority
18
+ bugTypes: ['functional', 'regression', 'security', 'performance', 'data', 'integration', 'ui', 'build', 'flaky', 'other'],
19
+ workingStaleAfterMinutes: 90, // task auto-evicts from working/ if owning session is silent past this (ADR-0015 §B)
20
+ };
21
+
22
+ function num(x) {
23
+ const n = Number(x);
24
+ return Number.isFinite(n) ? n : 0;
25
+ }
26
+
27
+ /** WSJF (SAFe) = Cost of Delay ÷ Job Size. Inputs 1–10; returns a rounded score. */
28
+ export function wsjfScore({ userValue = 0, timeCriticality = 0, riskReduction = 0, jobSize = 1 }) {
29
+ const cod = num(userValue) + num(timeCriticality) + num(riskReduction);
30
+ return Math.round((cod / Math.max(num(jobSize) || 1, 1)) * 10) / 10;
31
+ }
32
+
33
+ /** WSJF score → priority band. */
34
+ export function wsjfToPriority(score, bands = DEFAULTS.wsjfBands) {
35
+ const s = num(score);
36
+ if (s >= bands.p0) return 'P0';
37
+ if (s >= bands.p1) return 'P1';
38
+ if (s >= bands.p2) return 'P2';
39
+ return 'P3';
40
+ }
41
+
42
+ /** Scanner numeric severity (1–5, 5 = worst) → priority. Debt caps at P1. */
43
+ export function severityToPriority(sev) {
44
+ const n = num(sev);
45
+ if (n >= 4) return 'P1';
46
+ if (n >= 3) return 'P2';
47
+ return 'P3';
48
+ }
49
+
50
+ /** Bug severity label (S1–S4, S1 = critical) → priority. */
51
+ export function bugSeverityToPriority(sev, map = DEFAULTS.severityPriority) {
52
+ return map[String(sev || '').toUpperCase()] || 'P2';
53
+ }
54
+
55
+ /** Resolution due date = created + SLA days for the priority (ISO yyyy-mm-dd). */
56
+ export function slaDue(priority, createdISO, slaDays = DEFAULTS.slaDays) {
57
+ const days = slaDays[priority] ?? 30;
58
+ const base = createdISO ? new Date(createdISO) : new Date();
59
+ if (Number.isNaN(base.getTime())) return '';
60
+ return new Date(base.getTime() + days * 86400000).toISOString().slice(0, 10);
61
+ }
62
+
63
+ /** True when a not-yet-done task is past its SLA date. */
64
+ export function isOverdue(task) {
65
+ if (!task || !task.sla || task.stage === 'conclusion') return false;
66
+ const due = new Date(task.sla);
67
+ return !Number.isNaN(due.getTime()) && due < new Date();
68
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Session-aware DevPipeline transitions — `start` / `stop`.
3
+ *
4
+ * Separates a distinct responsibility from `pipeline.mjs` (pure CRUD on task
5
+ * files): these two transitions couple a task to a **session** via the
6
+ * workspace record (`claim.mjs`), and are the only places where a task move
7
+ * also writes session-level state. The CLI dispatch in `pipeline.mjs`
8
+ * delegates here.
9
+ *
10
+ * Cohesion: both halves share the same `findTaskFile` helper + the same
11
+ * stage-transition shape (rename + status rewrite + sync). Keeping them in one
12
+ * file makes start/stop symmetrical and lets the next maintainer read the full
13
+ * lifecycle in one place. See [ADR-0015 §B](../../memory/decisions/0015-pipeline-dsl-working-stage-and-multi-session-work-claims.md).
14
+ */
15
+ import { execFileSync } from 'node:child_process';
16
+ import { existsSync, readFileSync, readdirSync, renameSync } from 'node:fs';
17
+ import { resolve } from 'node:path';
18
+ import { writeFileAtomicSync } from '../../runtime/hooks/safe-io.mjs';
19
+ import { readState, writeState } from '../../runtime/state/state-io.mjs';
20
+ import { attachTask, detachTask } from './claim.mjs';
21
+
22
+ function gitOut(args, cwd, fallback) {
23
+ try {
24
+ return execFileSync('git', args, { cwd, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }).trim() || fallback;
25
+ } catch {
26
+ return fallback;
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Resolves a task id (with or without zero-padding) to its current stage + file
32
+ * path. Returns `null` when the task isn't found — caller decides how to fail.
33
+ *
34
+ * @param {string} pipeDir — repo-relative pipeline dir (`contextkit/pipeline/`)
35
+ * @param {string} rawId
36
+ * @returns {{ stage: string, file: string } | null}
37
+ */
38
+ function findTaskFile(pipeDir, rawId) {
39
+ const id = String(rawId).padStart(3, '0');
40
+ for (const stage of ['backlog', 'working', 'testing', 'conclusion']) {
41
+ const dir = resolve(pipeDir, stage);
42
+ if (!existsSync(dir)) continue;
43
+ const file = readdirSync(dir).find((f) => f.startsWith(`${id}-`) && f.endsWith('.md'));
44
+ if (file) return { stage, file };
45
+ }
46
+ return null;
47
+ }
48
+
49
+ function moveStage(pipeDir, from, to, file, statusValue) {
50
+ const fromPath = resolve(pipeDir, from, file);
51
+ const toPath = resolve(pipeDir, to, file);
52
+ const text = readFileSync(fromPath, 'utf-8').replace(/^(status:).*$/m, `status: ${statusValue}`);
53
+ writeFileAtomicSync(fromPath, text);
54
+ renameSync(fromPath, toPath);
55
+ }
56
+
57
+ /**
58
+ * `/pipeline start <id>` — moves a backlog task to `working/` AND attaches it
59
+ * to the current session's workspace record. Refuses when the task isn't in
60
+ * `backlog/` so a working/testing task can't be silently re-stamped.
61
+ *
62
+ * @param {string} pipeDir
63
+ * @param {string} rawId
64
+ * @param {(all: Array<object>) => void} sync — caller's sync function (renders board)
65
+ */
66
+ export async function startTask(pipeDir, rawId, sync) {
67
+ const found = findTaskFile(pipeDir, rawId);
68
+ if (!found) throw new Error(`No task with id ${rawId}.`);
69
+ if (found.stage !== 'backlog') throw new Error(`Task ${rawId} is in '${found.stage}', not backlog — refusing to start.`);
70
+ moveStage(pipeDir, 'backlog', 'working', found.file, 'working');
71
+ sync();
72
+ await attachTask(rawId);
73
+ const id = String(rawId).padStart(3, '0');
74
+ // ADR-0015 §C — stamp the canonical state.json substrate.
75
+ try {
76
+ const cwd = pipeDir.split(/[\\/]+contextkit[\\/]+/)[0] || process.cwd();
77
+ writeState(pipeDir, id, { kind: 'task', status: 'working', branch: gitOut(['symbolic-ref', '--short', 'HEAD'], cwd, null), ownerUser: gitOut(['config', 'user.name'], cwd, null), endedAt: null });
78
+ } catch { /* best-effort: state.json is observability, not the source of truth */ }
79
+ return { id, stage: 'working' };
80
+ }
81
+
82
+ /**
83
+ * `/pipeline stop <id>` — moves a `working/` task BACK to `backlog/` (NOT
84
+ * testing/ — testing/ is "code done, awaiting QA", reached via explicit `move`)
85
+ * and detaches it from the session. Mirror of start.
86
+ */
87
+ export async function stopTask(pipeDir, rawId, sync) {
88
+ const found = findTaskFile(pipeDir, rawId);
89
+ if (!found) throw new Error(`No task with id ${rawId}.`);
90
+ if (found.stage !== 'working') throw new Error(`Task ${rawId} is in '${found.stage}', not working — nothing to stop.`);
91
+ moveStage(pipeDir, 'working', 'backlog', found.file, 'backlog');
92
+ sync();
93
+ await detachTask(rawId);
94
+ const id = String(rawId).padStart(3, '0');
95
+ try {
96
+ if (readState(pipeDir, id)) writeState(pipeDir, id, { status: 'backlog', endedAt: Date.now() });
97
+ } catch { /* best-effort */ }
98
+ return { id, stage: 'backlog' };
99
+ }