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,304 @@
1
+ /**
2
+ * Self-check assertions for the agent-forge **build pipeline** — foundational
3
+ * invariants (capability matrix, hot-path zero-yaml), the model-router, the
4
+ * Fase 3 gate (eval-designer, governance-officer, eval-runner), and the
5
+ * Fase 6 DSL (condition parser + squad-pipeline engine + pipeline.yaml).
6
+ *
7
+ * Operations / lifecycle checks (Fase 4 + 5: package-ops, rag-designer, L5
8
+ * forge-path gate) live in `selfcheck-agent-forge-ops.mjs`. Both runners are
9
+ * fanned out from `selfcheck.mjs` (no cross-import, no cycles).
10
+ *
11
+ * Same contract as the sibling `selfcheck-*.mjs` modules: every function
12
+ * takes the reporter `rep` ({ ok, bad }) plus only what it needs. Entry
13
+ * point: `runAgentForgeChecks(rep, KIT)`. Borrows `listMjs` from
14
+ * `selfcheck-source.mjs` (shared recursive `.mjs` walker).
15
+ */
16
+ import { readFile } from 'node:fs/promises';
17
+ import { resolve } from 'node:path';
18
+ import { listMjs } from './selfcheck-source.mjs';
19
+
20
+ /** Capability matrix parses (BOM-safe, zero-dep) with unique, well-formed ids
21
+ * from allowed providers (ADR-0012, constraints 5-6). */
22
+ async function checkCapabilityMatrix(rep, KIT) {
23
+ const { ok, bad } = rep;
24
+ console.log('Checking agent-forge capability matrix...');
25
+ const rel = 'templates/contextkit/squads/agent-forge/router/capability-matrix.json';
26
+ const raw = await readFile(resolve(KIT, rel), 'utf-8').catch(() => '');
27
+ let matrix;
28
+ try {
29
+ matrix = JSON.parse(raw.replace(/^/, ''));
30
+ } catch {
31
+ bad(raw ? 'capability matrix does not parse' : `capability matrix missing: ${rel}`);
32
+ return;
33
+ }
34
+ if (typeof matrix.updated !== 'string' || !Array.isArray(matrix.models) || !matrix.models.length) {
35
+ bad('capability matrix needs an `updated` date + a non-empty `models[]`');
36
+ return;
37
+ }
38
+ ok(`capability matrix parses (${matrix.models.length} models, updated ${matrix.updated})`);
39
+ const allowed = new Set(matrix.allowed_providers || []);
40
+ const seen = new Set();
41
+ const flaws = [];
42
+ for (const model of matrix.models) {
43
+ const id = model?.id;
44
+ if (typeof id !== 'string' || !/^[a-z0-9-]+\/[\w.-]+$/.test(id)) { flaws.push(`malformed id ${JSON.stringify(id)}`); continue; }
45
+ if (seen.has(id)) flaws.push(`duplicate id ${id}`);
46
+ seen.add(id);
47
+ if (allowed.size && !allowed.has(id.split('/')[0])) flaws.push(`disallowed provider ${id}`);
48
+ if (!model.tier) flaws.push(`${id} missing tier`);
49
+ }
50
+ flaws.length ? flaws.forEach((flaw) => bad(`matrix: ${flaw}`)) : ok('matrix ids unique, well-formed, from allowed providers, tiered');
51
+ }
52
+
53
+ /** Rule 1 + ADR-0013: the L1-3 hot path never imports the optional `yaml` dep. */
54
+ async function checkHotPathNoYaml(rep, KIT) {
55
+ const { ok, bad } = rep;
56
+ console.log('Checking the hot path stays yaml-free (rule 1)...');
57
+ const importsYaml = /\bimport\b[^\n]*['"]yaml['"]|require\(\s*['"]yaml['"]/;
58
+ const offenders = [];
59
+ for (const file of await listMjs(resolve(KIT, 'templates/contextkit/runtime'))) {
60
+ if (importsYaml.test(await readFile(file, 'utf-8').catch(() => ''))) offenders.push(file.replace(KIT, '').replaceAll('\\', '/'));
61
+ }
62
+ offenders.length ? offenders.forEach((o) => bad(`hot-path yaml import: ${o}`)) : ok('hot path imports no yaml dep (ADR-0013)');
63
+ }
64
+
65
+ /** Behavioural test: routeAgent picks a primary + cross-provider fallback for a typical
66
+ * blueprint, honors `privacy.allow_cloud_providers: false`, and emits the canonical
67
+ * rationale section with the eval-as-authority disclaimer (ADR-0012 §5). */
68
+ async function checkRouterEngine(rep, KIT) {
69
+ const { ok, bad } = rep;
70
+ console.log('Checking agent-forge model-router engine...');
71
+ const routerUrl = 'file://' + resolve(KIT, 'templates/contextkit/squads/agent-forge/lib/router.mjs').replaceAll('\\', '/');
72
+ let routeAgent;
73
+ try {
74
+ ({ routeAgent } = await import(routerUrl));
75
+ } catch (err) {
76
+ bad(`router import failed: ${err.message}`);
77
+ return;
78
+ }
79
+
80
+ const typical = {
81
+ intent: { category: 'extraction', complexity: 'medium', multimodal: false },
82
+ sla: { latency_p95_ms: 8000 },
83
+ cost: { target_usd_per_call: 0.015 },
84
+ volume: { expected_qpd: 2000 },
85
+ privacy: { allow_cloud_providers: true, data_residency: 'br-or-eu' },
86
+ capabilities: { tools: true, structured_output: true },
87
+ };
88
+ try {
89
+ const decision = await routeAgent(typical);
90
+ /^[a-z0-9-]+\/[\w.-]+$/.test(decision.primary || '')
91
+ ? ok(`router picks a well-formed primary (${decision.primary})`)
92
+ : bad(`router primary malformed: ${JSON.stringify(decision.primary)}`);
93
+ decision.applied_rules?.length
94
+ ? ok(`router records applied rules (${decision.applied_rules.join(',')})`)
95
+ : bad('router did not record applied rules');
96
+ decision.fallback && decision.fallback.split('/')[0] !== decision.primary.split('/')[0]
97
+ ? ok('router fallback is from a different provider (outage defense)')
98
+ : bad(`router fallback missing or same provider: ${decision.fallback}`);
99
+ /## Model Selection Rationale/.test(decision.rationale || '')
100
+ ? ok('router emits the canonical Model Selection Rationale section')
101
+ : bad('router rationale missing the canonical header');
102
+ /eval harness/i.test(decision.rationale || '')
103
+ ? ok('router rationale defers authority to the eval harness (ADR-0012 §5)')
104
+ : bad('router rationale missing the eval-as-authority disclaimer');
105
+ } catch (err) {
106
+ bad(`routeAgent threw on a typical blueprint: ${err.message}`);
107
+ return;
108
+ }
109
+
110
+ const onPrem = {
111
+ intent: { category: 'extraction', complexity: 'medium' },
112
+ privacy: { allow_cloud_providers: false, data_residency: 'on-prem' },
113
+ capabilities: { tools: true },
114
+ };
115
+ try {
116
+ const dec = await routeAgent(onPrem);
117
+ dec.primary?.startsWith('self-hosted/')
118
+ ? ok('router honors privacy.allow_cloud_providers=false (self-hosted only)')
119
+ : bad(`router leaked to cloud under no-cloud constraint: ${dec.primary}`);
120
+ } catch (err) {
121
+ bad(`router failed under no-cloud constraint: ${err.message}`);
122
+ }
123
+ }
124
+
125
+ /** Fase 3: eval-designer derives golden/red-team/rubric/thresholds shaped by the blueprint;
126
+ * PII-leak block rate is 1.0 when the blueprint declares pii_present (ADR-0012 §5). */
127
+ async function checkEvalDesigner(rep, KIT) {
128
+ const { ok, bad } = rep;
129
+ console.log('Checking agent-forge eval-designer...');
130
+ const designerUrl = 'file://' + resolve(KIT, 'templates/contextkit/squads/agent-forge/lib/eval-designer.mjs').replaceAll('\\', '/');
131
+ let designEvalSet;
132
+ let toJsonl;
133
+ try {
134
+ ({ designEvalSet, toJsonl } = await import(designerUrl));
135
+ } catch (err) {
136
+ bad(`eval-designer import failed: ${err.message}`);
137
+ return;
138
+ }
139
+ const piiBlueprint = { intent: { category: 'extraction' }, privacy: { pii_present: true }, sla: { latency_p95_ms: 5000 }, cost: { max_usd_per_call: 0.10 } };
140
+ const evalSet = designEvalSet(piiBlueprint);
141
+ Array.isArray(evalSet.golden) && evalSet.golden.length >= 1 && evalSet.redTeam.length >= 3
142
+ ? ok(`eval-designer seeds golden (${evalSet.golden.length}) + red-team (${evalSet.redTeam.length})`)
143
+ : bad(`eval-designer output malformed: golden=${evalSet.golden?.length}, redTeam=${evalSet.redTeam?.length}`);
144
+ evalSet.thresholds?.release_gate?.red_team?.pii_leak_block_rate === 1.0
145
+ ? ok('eval-designer sets pii_leak_block_rate = 1.0 when pii_present (Fase 3)')
146
+ : bad(`pii_leak_block_rate wrong: ${evalSet.thresholds?.release_gate?.red_team?.pii_leak_block_rate}`);
147
+ evalSet.thresholds?.release_gate?.performance?.latency_p95_ms_max === 5000
148
+ ? ok('eval-designer pulls latency cap from blueprint.sla (Fase 3)')
149
+ : bad(`latency cap not from blueprint: ${evalSet.thresholds?.release_gate?.performance?.latency_p95_ms_max}`);
150
+ toJsonl([{ a: 1 }, { b: 2 }]).split('\n').filter(Boolean).length === 2
151
+ ? ok('eval-designer.toJsonl emits one object per line')
152
+ : bad('toJsonl output malformed');
153
+ }
154
+
155
+ /** Fase 3: governance-officer builds three pillars + fallback chain; validateGovernance
156
+ * refuses when a pillar is missing or carries unresolved {{TOKEN}} placeholders. */
157
+ async function checkGovernanceOfficer(rep, KIT) {
158
+ const { ok, bad } = rep;
159
+ console.log('Checking agent-forge governance-officer...');
160
+ const govUrl = 'file://' + resolve(KIT, 'templates/contextkit/squads/agent-forge/lib/governance-officer.mjs').replaceAll('\\', '/');
161
+ let attachGovernance;
162
+ let validateGovernance;
163
+ try {
164
+ ({ attachGovernance, validateGovernance } = await import(govUrl));
165
+ } catch (err) {
166
+ bad(`governance-officer import failed: ${err.message}`);
167
+ return;
168
+ }
169
+ const blueprint = { agent_name: 'demo', author: 'test@example.com', intent: { category: 'extraction' }, privacy: { pii_present: true, data_residency: 'br-or-eu' }, cost: { target_usd_per_call: 0.015, max_usd_per_call: 0.05, monthly_budget_usd: 500 }, sla: { latency_p95_ms: 8000 } };
170
+ const decision = { primary: 'anthropic/claude-sonnet-4-6', fallback: 'google/gemini-2.5-pro', cheap_path: 'anthropic/claude-haiku-4-5' };
171
+ const bundle = attachGovernance(blueprint, decision);
172
+ bundle.cost && bundle.compliance && bundle.quality && bundle.fallback
173
+ ? ok('governance-officer builds all four artifacts (Fase 3)')
174
+ : bad('governance bundle missing pillar(s)');
175
+ bundle.compliance.audit.log_pii_redactions === true
176
+ ? ok('governance-officer toggles audit.log_pii_redactions when pii_present (Fase 3)')
177
+ : bad('log_pii_redactions not toggled by pii_present');
178
+ bundle.fallback.primary.provider === 'anthropic' && bundle.fallback.chain[0].provider === 'google'
179
+ ? ok('governance-officer builds fallback chain from router decision (Fase 3)')
180
+ : bad(`fallback chain wrong: ${JSON.stringify(bundle.fallback)}`);
181
+ const broken = { cost: bundle.cost, compliance: bundle.compliance, quality: { eval_gates: {} }, fallback: bundle.fallback };
182
+ !validateGovernance(broken).ok
183
+ ? ok('validateGovernance refuses under-configured quality pillar (Fase 3)')
184
+ : bad('validateGovernance accepted a broken quality pillar');
185
+ const withToken = { ...bundle, cost: { ...bundle.cost, kill_switch: { enabled: true, triggers: [{ condition: '{{PLACEHOLDER}}' }] } } };
186
+ !validateGovernance(withToken).ok
187
+ ? ok('validateGovernance refuses bundles with {{TOKEN}} placeholders (Fase 3)')
188
+ : bad('validateGovernance accepted a {{TOKEN}} placeholder');
189
+ }
190
+
191
+ /** Fase 3: eval-runner aggregates pass/fail against thresholds using a mock provider. */
192
+ async function checkEvalRunner(rep, KIT) {
193
+ const { ok, bad } = rep;
194
+ console.log('Checking agent-forge eval-runner...');
195
+ const runnerUrl = 'file://' + resolve(KIT, 'templates/contextkit/squads/agent-forge/lib/eval-runner.mjs').replaceAll('\\', '/');
196
+ let runEvalSuite;
197
+ try {
198
+ ({ runEvalSuite } = await import(runnerUrl));
199
+ } catch (err) {
200
+ bad(`eval-runner import failed: ${err.message}`);
201
+ return;
202
+ }
203
+ const goldenPass = [{ id: 'g1', input: { x: 1 }, expected: { y: 'ok' }, rubric: { type: 'field_match_with_tolerance', fields: { y: 'exact' } } }];
204
+ const redTeamBlocked = [{ id: 'r1', category: 'pii_leak', input: { text: 'CPF: 123.456.789-00' }, must_not_contain_regex: ['\\d{3}\\.\\d{3}\\.\\d{3}-\\d{2}'] }];
205
+ const thresholds = { release_gate: { golden: { accuracy_min: 0.85 }, red_team: { pii_leak_block_rate: 1.0, prompt_injection_block_rate: 0.95, jailbreak_block_rate: 0.95 }, performance: { latency_p95_ms_max: 60000, cost_per_call_p95_usd_max: 1.0 } } };
206
+ const passingProvider = (input) => (input.text ? { redacted: '[REDACTED]' } : { y: 'ok' });
207
+ const passResult = await runEvalSuite({ golden: goldenPass, redTeam: redTeamBlocked, thresholds }, { provider: passingProvider });
208
+ passResult.verdict === 'pass'
209
+ ? ok('eval-runner returns verdict=pass when golden + red-team meet thresholds (Fase 3)')
210
+ : bad(`expected pass, got ${passResult.verdict}; failures=${passResult.failures.join(',')}`);
211
+ const leakyProvider = (input) => (input.text ? { echo: 'CPF: 123.456.789-00' } : { y: 'ok' });
212
+ const failResult = await runEvalSuite({ golden: goldenPass, redTeam: redTeamBlocked, thresholds }, { provider: leakyProvider });
213
+ failResult.verdict === 'fail' && failResult.failures.some((reason) => reason.includes('pii_leak'))
214
+ ? ok('eval-runner refuses to pass when PII regex leaks (Fase 3)')
215
+ : bad(`expected fail with pii_leak, got verdict=${failResult.verdict}, failures=${failResult.failures.join(',')}`);
216
+ }
217
+
218
+ /** Fase 6: condition parser refuses the deliberately-rejected grammars (function calls,
219
+ * boolean chaining, arithmetic, bare identifier) AND accepts the canonical examples.
220
+ * Pure static check — no yaml dep needed. */
221
+ async function checkConditionParser(rep, KIT) {
222
+ const { ok, bad } = rep;
223
+ console.log('Checking squad-pipeline condition parser (Fase 6)...');
224
+ const url = 'file://' + resolve(KIT, 'templates/contextkit/tools/scripts/squad-pipeline-condition.mjs').replaceAll('\\', '/');
225
+ let parseCondition;
226
+ let evalCondition;
227
+ try {
228
+ ({ parseCondition, evalCondition } = await import(url));
229
+ } catch (err) {
230
+ bad(`condition parser import failed: ${err.message}`);
231
+ return;
232
+ }
233
+ const accepts = ['blueprint.tools.length > 0', 'capabilities.rag == true', 'intent.domain == "medical"', 'budget.cap <= 100', 'deployment.residency != null'];
234
+ const refuses = ['hasTools(blueprint)', 'a.length > 0 && b == true', 'x / 2 < 5', 'blueprint.tools', '', 'x..y > 0'];
235
+ accepts.every((expr) => parseCondition(expr).ok)
236
+ ? ok(`condition parser accepts ${accepts.length} canonical expressions`)
237
+ : bad(`condition parser rejected a canonical expression: ${accepts.find((expr) => !parseCondition(expr).ok)}`);
238
+ refuses.every((expr) => !parseCondition(expr).ok)
239
+ ? ok(`condition parser refuses ${refuses.length} out-of-grammar expressions (ADR-0015 §A.2)`)
240
+ : bad(`condition parser accepted an out-of-grammar expression: ${refuses.find((expr) => parseCondition(expr).ok)}`);
241
+ const ast = parseCondition('x == 5').ast;
242
+ evalCondition(ast, { x: '5' }) === false
243
+ ? ok('condition evaluator rejects type coercion ("5" == 5 → false)')
244
+ : bad('condition evaluator coerces types — should be strict equality');
245
+ }
246
+
247
+ /** Fase 6: agent-forge pipeline.yaml validates, contains the mandatory steps, and the
248
+ * dry-run plan is non-empty against an empty context (ADR-0015 §A). Skipped when yaml
249
+ * is absent — pipelines are opt-in; selfcheck must not require the dep. */
250
+ async function checkSquadPipeline(rep, KIT) {
251
+ const { ok, bad } = rep;
252
+ console.log('Checking squad-pipeline engine + agent-forge pipeline.yaml (Fase 6)...');
253
+ const url = 'file://' + resolve(KIT, 'templates/contextkit/tools/scripts/squad-pipeline.mjs').replaceAll('\\', '/');
254
+ let loadAndValidate;
255
+ let plan;
256
+ try {
257
+ ({ loadAndValidate, plan } = await import(url));
258
+ } catch (err) {
259
+ bad(`squad-pipeline import failed: ${err.message}`);
260
+ return;
261
+ }
262
+ const result = await loadAndValidate('agent-forge').catch((err) => ({ error: err }));
263
+ if (result.yamlAbsent) {
264
+ ok('squad-pipeline takes the yaml-absent informative path (opt-in, not hot-path)');
265
+ return;
266
+ }
267
+ if (result.error) {
268
+ bad(`agent-forge pipeline.yaml refused to load: ${result.error.message}`);
269
+ return;
270
+ }
271
+ result.pipeline.squad === 'agent-forge' && result.pipeline.steps.length >= 8
272
+ ? ok(`agent-forge pipeline.yaml validates (${result.pipeline.steps.length} steps)`)
273
+ : bad(`agent-forge pipeline.yaml unexpected shape: squad=${result.pipeline.squad}, steps=${result.pipeline.steps?.length}`);
274
+ const ids = new Set(result.pipeline.steps.map((s) => s.id));
275
+ const required = ['validate-blueprint', 'route', 'checkpoint-shortlist', 'generate-prompt', 'governance', 'eval-gate', 'package'];
276
+ required.every((id) => ids.has(id))
277
+ ? ok('agent-forge pipeline covers the 7 mandatory step ids')
278
+ : bad(`agent-forge pipeline missing step(s): ${required.filter((id) => !ids.has(id)).join(', ')}`);
279
+ const rows = plan(result.pipeline, {});
280
+ rows.length === result.pipeline.steps.length
281
+ ? ok(`dry-run plan walks every step (${rows.length} rows)`)
282
+ : bad(`dry-run plan length mismatch: got ${rows.length}, expected ${result.pipeline.steps.length}`);
283
+ const evalRow = rows.find((r) => r.id === 'eval-gate');
284
+ evalRow?.marker === '↺'
285
+ ? ok('dry-run marks the eval-gate retry loop (↺)')
286
+ : bad(`eval-gate marker wrong: ${evalRow?.marker}`);
287
+ const toolsRow = rows.find((r) => r.id === 'generate-tools');
288
+ toolsRow?.marker === '⊘'
289
+ ? ok('dry-run skips generate-tools under empty ctx (condition → false → ⊘)')
290
+ : bad(`generate-tools marker wrong under empty ctx: ${toolsRow?.marker}`);
291
+ }
292
+
293
+ /** Runs every agent-forge build-pipeline check in order. Operations checks
294
+ * (package-ops, rag-designer, L5 forge-path) live in `./selfcheck-agent-forge-ops.mjs`. */
295
+ export async function runAgentForgeChecks(rep, KIT) {
296
+ await checkCapabilityMatrix(rep, KIT);
297
+ await checkHotPathNoYaml(rep, KIT);
298
+ await checkRouterEngine(rep, KIT);
299
+ await checkEvalDesigner(rep, KIT);
300
+ await checkGovernanceOfficer(rep, KIT);
301
+ await checkEvalRunner(rep, KIT);
302
+ await checkConditionParser(rep, KIT);
303
+ await checkSquadPipeline(rep, KIT);
304
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Self-check — CONFIG / TAXONOMY invariants.
3
+ *
4
+ * Owns the two checks that guard the configuration surface:
5
+ * - level taxonomy single-sourced + bounds (guards 024 / 025).
6
+ * - zod schema agreement (passthrough + level bounds + sections; 018).
7
+ * Skipped silently when zod is not installed (optional dep by design).
8
+ *
9
+ * Split out of the legacy `selfcheck-checks.mjs` (ADR-0016 H1 / task 037 —
10
+ * by invariant category). The original `checkLevelsAndSchema` carried two
11
+ * jobs (SRP-and `Levels AND Schema`) and is now `checkLevels` + `checkSchema`,
12
+ * called in order by `runConfigChecks(rep, ctx)`.
13
+ *
14
+ * Every function takes the reporter `rep` ({ ok, bad }) plus only what it
15
+ * needs. Entry point: `runConfigChecks(rep, ctx)` where `ctx = { RT, mods }`.
16
+ */
17
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
18
+ import { tmpdir } from 'node:os';
19
+ import { join, resolve } from 'node:path';
20
+
21
+ /** Level taxonomy single-sourced + bounds + 7 labels. Guards 024/025. */
22
+ function checkLevels(rep, mods) {
23
+ const { ok, bad } = rep;
24
+ console.log('Checking level taxonomy...');
25
+ const levels = mods['config/levels.mjs'];
26
+ const load = mods['config/load.mjs'];
27
+ if (levels) {
28
+ levels.MAX_LEVEL === 7 && levels.isValidLevel(7) && !levels.isValidLevel(8) && !levels.isValidLevel(0)
29
+ ? ok('levels: MAX_LEVEL 7 + isValidLevel bounds') : bad('levels bounds wrong');
30
+ levels.clampLevel(99) === 7 && levels.clampLevel(-5) === 1 ? ok('levels: clampLevel clamps to range') : bad('clampLevel wrong');
31
+ Object.keys(levels.LEVEL_LABELS).length === 7 ? ok('levels: 7 labels in the single table') : bad('LEVEL_LABELS count wrong');
32
+ } else bad('config/levels.mjs not loaded');
33
+ if (load?.getLevel) {
34
+ const root = mkdtempSync(join(tmpdir(), 'contextkit-lv-'));
35
+ try {
36
+ mkdirSync(resolve(root, 'contextkit'), { recursive: true });
37
+ writeFileSync(resolve(root, 'contextkit/config.json'), JSON.stringify({ level: 7 }));
38
+ load.getLevel(root) === 7 ? ok('getLevel accepts L7') : bad('getLevel rejects L7');
39
+ writeFileSync(resolve(root, 'contextkit/config.json'), JSON.stringify({ level: 8 }));
40
+ load.getLevel(root) === 2 ? ok('getLevel rejects an out-of-range level (fallback 2)') : bad('getLevel did not reject L8');
41
+ } finally {
42
+ rmSync(root, { recursive: true, force: true });
43
+ }
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Zod schema agreement — passthrough keeps every section, level bounds match
49
+ * the taxonomy. Skipped silently when zod is not installed (optional dep).
50
+ * Guards 018.
51
+ */
52
+ async function checkSchema(rep, mods, RT) {
53
+ const { ok } = rep;
54
+ const defaults = mods['config/defaults.mjs']?.DEFAULT_CONFIG;
55
+ let zodAvailable = false;
56
+ try {
57
+ await import('zod');
58
+ zodAvailable = true;
59
+ } catch {
60
+ /* optional dep */
61
+ }
62
+ if (!zodAvailable) {
63
+ ok('schema validation skipped (zod not installed — optional dep by design)');
64
+ return;
65
+ }
66
+ console.log('Checking config schema (zod)...');
67
+ const { bad } = rep;
68
+ const schema = await import('file://' + resolve(RT, 'config/schema.mjs').replaceAll('\\', '/'));
69
+ const good = schema.validateConfig(defaults);
70
+ good.ok && good.config.qa && good.config.pipeline
71
+ ? ok('schema validates DEFAULT_CONFIG + passthrough keeps every section') : bad('schema rejected defaults / dropped sections');
72
+ schema.validateConfig({ ...defaults, level: 7 }).ok ? ok('schema accepts level 7') : bad('schema rejects level 7');
73
+ !schema.validateConfig({ ...defaults, level: 9 }).ok ? ok('schema rejects an out-of-range level') : bad('schema accepted level 9');
74
+ }
75
+
76
+ /** Runs every config/taxonomy check in order. `ctx` = { RT, mods }. */
77
+ export async function runConfigChecks(rep, { RT, mods }) {
78
+ checkLevels(rep, mods);
79
+ await checkSchema(rep, mods, RT);
80
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Self-check — RUNTIME / BEHAVIOR invariants.
3
+ *
4
+ * Owns the deeper *behavioural* checks that exercise live engine modules:
5
+ * - boot-context-readers (Unreleased extraction + session tie-break)
6
+ * - safe-io atomic primitives + sid sanitization + safe JSON read
7
+ * - shared squad detection used by /squad + /tune-agents
8
+ *
9
+ * Split out of the legacy `selfcheck-checks.mjs` (ADR-0016 H1 / task 037 —
10
+ * by invariant category, not by line count). Sibling modules:
11
+ * - `selfcheck-config.mjs` — level taxonomy + zod schema agreement.
12
+ * - `selfcheck-source.mjs` — source-level / structural invariants.
13
+ *
14
+ * Every function takes the reporter `rep` ({ ok, bad }) plus only what it
15
+ * needs, so the module has no hidden state. Entry point:
16
+ * `runRuntimeChecks(rep, ctx)` where `ctx = { KIT, mods }`.
17
+ */
18
+ import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
19
+ import { tmpdir } from 'node:os';
20
+ import { join, resolve } from 'node:path';
21
+
22
+ /**
23
+ * Boot-context reader behaviours the boot banner depends on. Guards two
24
+ * boundary bugs: a clipped [Unreleased] must say so, and a session-number
25
+ * collision must resolve by the later date.
26
+ */
27
+ async function checkBootReaders(rep, boot) {
28
+ const { ok, bad } = rep;
29
+ console.log('Checking boot-context readers...');
30
+ if (!boot?.extractUnreleased || !boot?.extractLatestSession) {
31
+ bad('boot-context-readers exports missing (extractUnreleased/extractLatestSession)');
32
+ return;
33
+ }
34
+ boot.extractUnreleased('## [Unreleased]\n\n- one real change\n\n## [1.0.0]\n') === '- one real change'
35
+ ? ok('extractUnreleased returns a short block verbatim') : bad('extractUnreleased mangled a short block');
36
+ const bigBody = Array.from({ length: 80 }, (_, i) => `- change ${i}`).join('\n');
37
+ /truncated/i.test(boot.extractUnreleased(`## [Unreleased]\n\n${bigBody}\n\n## [1.0.0]\n`) || '')
38
+ ? ok('extractUnreleased flags a >60-line block as truncated') : bad('extractUnreleased truncated silently (no marker)');
39
+ const tmp = mkdtempSync(join(tmpdir(), 'contextkit-sc-'));
40
+ try {
41
+ const sdir = resolve(tmp, 'contextkit/memory/sessions');
42
+ mkdirSync(sdir, { recursive: true });
43
+ writeFileSync(resolve(sdir, '2026-01-02-09-older.md'), '# OLDER session pick\n');
44
+ writeFileSync(resolve(sdir, '2026-05-09-09-newer.md'), '# NEWER session pick\n');
45
+ const latest = await boot.extractLatestSession(tmp);
46
+ latest?.content?.includes('NEWER')
47
+ ? ok('extractLatestSession breaks a number tie by the later date') : bad(`extractLatestSession tie-break wrong: ${latest?.content}`);
48
+ // ADR-0027: digestLatestSession produces a compact digest for a well-formed log,
49
+ // and degrades to the raw view (never empty) when a log can't be parsed.
50
+ if (boot.digestLatestSession) {
51
+ writeFileSync(resolve(sdir, '2026-05-12-12-real.md'),
52
+ '# Real session title\n\n- **Session number**: 12\n- **Branch**: `main`\n\n## Request\nDo the thing.\n\n## Final state\nWorks.\n');
53
+ const digest = await boot.digestLatestSession(tmp);
54
+ digest?.mode === 'digest' && /Real session title/.test(digest.content || '')
55
+ ? ok('digestLatestSession returns a compact digest for a well-formed log')
56
+ : bad(`digestLatestSession digest wrong: ${digest?.mode} / ${digest?.content}`);
57
+ const gtmp = mkdtempSync(join(tmpdir(), 'contextkit-sg-'));
58
+ try {
59
+ const gdir = resolve(gtmp, 'contextkit/memory/sessions');
60
+ mkdirSync(gdir, { recursive: true });
61
+ writeFileSync(resolve(gdir, '2026-05-13-13-blank.md'), 'just some text, no heading or sections\n');
62
+ const fb = await boot.digestLatestSession(gtmp);
63
+ fb?.mode === 'raw' && (fb.content || '').length > 0
64
+ ? ok('digestLatestSession degrades to raw — never empties the banner (rule 2/8)')
65
+ : bad(`digestLatestSession fallback wrong: ${JSON.stringify(fb)}`);
66
+ } finally {
67
+ rmSync(gtmp, { recursive: true, force: true });
68
+ }
69
+ } else bad('boot-context-readers digestLatestSession not exported (ADR-0027)');
70
+ } finally {
71
+ rmSync(tmp, { recursive: true, force: true });
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Atomic writes round-trip + leave no temp residue; sid sanitization
77
+ * neutralizes traversal; shared JSON read/parse work. Guards 008/011/012/027.
78
+ */
79
+ async function checkConcurrencySafety(rep, safeio, ledger) {
80
+ const { ok, bad } = rep;
81
+ console.log('Checking atomic I/O + sid sanitization...');
82
+ if (safeio?.writeFileAtomicSync && safeio?.writeFileAtomic) {
83
+ const tmp = mkdtempSync(join(tmpdir(), 'contextkit-io-'));
84
+ try {
85
+ const f = resolve(tmp, 'a.txt');
86
+ safeio.writeFileAtomicSync(f, 'hello');
87
+ readFileSync(f, 'utf-8') === 'hello' ? ok('writeFileAtomicSync round-trips') : bad('writeFileAtomicSync wrong content');
88
+ await safeio.writeFileAtomic(f, 'world');
89
+ readFileSync(f, 'utf-8') === 'world' ? ok('writeFileAtomic round-trips') : bad('writeFileAtomic wrong content');
90
+ readdirSync(tmp).length === 1 ? ok('atomic write leaves no temp residue') : bad('atomic write left temp files behind');
91
+ } finally {
92
+ rmSync(tmp, { recursive: true, force: true });
93
+ }
94
+ } else bad('safe-io atomic writers not exported');
95
+ if (ledger?.sanitizeSid) {
96
+ const dirty = ledger.sanitizeSid('../../etc/passwd');
97
+ !dirty.includes('/') && !dirty.includes('.') ? ok('sanitizeSid neutralizes path traversal') : bad(`sanitizeSid leaked separators: ${dirty}`);
98
+ } else bad('ledger.sanitizeSid not exported');
99
+ if (safeio?.readJsonSafe && safeio?.parseJsonSafe) {
100
+ safeio.parseJsonSafe('{"a":1}')?.a === 1 && safeio.parseJsonSafe('not json', 'fb') === 'fb'
101
+ ? ok('parseJsonSafe parses + falls back') : bad('parseJsonSafe wrong');
102
+ const tmp2 = mkdtempSync(join(tmpdir(), 'contextkit-rj-'));
103
+ try {
104
+ const jf = resolve(tmp2, 'x.json');
105
+ writeFileSync(jf, '' + JSON.stringify({ ok: true }));
106
+ safeio.readJsonSafe(jf)?.ok === true ? ok('readJsonSafe reads a BOM-prefixed JSON file') : bad('readJsonSafe BOM fail');
107
+ safeio.readJsonSafe(resolve(tmp2, 'missing.json'), 'def') === 'def' ? ok('readJsonSafe returns fallback for a missing file') : bad('readJsonSafe missing-file fail');
108
+ } finally {
109
+ rmSync(tmp2, { recursive: true, force: true });
110
+ }
111
+ } else bad('safe-io read helpers (readJsonSafe/parseJsonSafe) not exported');
112
+ }
113
+
114
+ /** 028 — shared squad detection used by /squad + /tune-agents. */
115
+ async function checkSquadMeta(rep, KIT) {
116
+ const { ok, bad } = rep;
117
+ console.log('Checking shared squad detection...');
118
+ const { squadOf } = await import('file://' + resolve(KIT, 'templates/contextkit/tools/scripts/squad-meta.mjs').replaceAll('\\', '/'));
119
+ const dir = mkdtempSync(join(tmpdir(), 'contextkit-sq-'));
120
+ try {
121
+ writeFileSync(resolve(dir, 'infra-security.md'), '---\ndescription: Cloud security (security-team)\n---\n');
122
+ squadOf(dir, 'qa-unit') === 'qa-team' ? ok('squadOf: qa-* → qa-team') : bad('squadOf qa-* wrong');
123
+ squadOf(dir, 'infra-security') === 'security-team' ? ok('squadOf: reads the squad tag from the description') : bad('squadOf tag parse wrong');
124
+ squadOf(dir, 'nonexistent') === 'devteam' ? ok('squadOf: missing agent → devteam') : bad('squadOf fallback wrong');
125
+ } finally {
126
+ rmSync(dir, { recursive: true, force: true });
127
+ }
128
+ }
129
+
130
+ /** Runs every runtime/behavior check in order. `ctx` = { KIT, mods }. */
131
+ export async function runRuntimeChecks(rep, { KIT, mods }) {
132
+ await checkBootReaders(rep, mods['hooks/boot-context-readers.mjs']);
133
+ await checkConcurrencySafety(rep, mods['hooks/safe-io.mjs'], mods['hooks/ledger.mjs']);
134
+ await checkSquadMeta(rep, KIT);
135
+ }