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,80 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Squad helper โ€” the deterministic half of `/squad` (the command adds judgment).
4
+ *
5
+ * Scaffolds the **tier-2 rich briefing** for an agent into its squad folder, so
6
+ * the two-tier pattern (lean agent in `.claude/agents/` + deep briefing in
7
+ * `contextkit/squads/<squad>/`) is real, not just convention.
8
+ *
9
+ * node .../squad.mjs list # agents + which have a tier-2 briefing
10
+ * node .../squad.mjs brief <agent> # scaffold contextkit/squads/<squad>/<agent>.md
11
+ *
12
+ * Squad detection: `qa-*` โ†’ qa-team; otherwise the `(... squad)` / `(...-team)`
13
+ * tag in the agent's `description`; falls back to `devteam`.
14
+ */
15
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
16
+ import { resolve } from 'node:path';
17
+ import { squadOf } from './squad-meta.mjs';
18
+ import { pathsFor } from '../../runtime/config/paths.mjs';
19
+
20
+ const ROOT = process.cwd();
21
+ const AGENTS = resolve(ROOT, '.claude/agents');
22
+ const SQUADS = pathsFor(ROOT).squads;
23
+ const squadFor = (agent) => squadOf(AGENTS, agent);
24
+
25
+ function listAgents() {
26
+ try {
27
+ return readdirSync(AGENTS).filter((f) => f.endsWith('.md') && f !== '_TEMPLATE.md').map((f) => f.slice(0, -3));
28
+ } catch {
29
+ return [];
30
+ }
31
+ }
32
+
33
+ function brief() {
34
+ const agent = process.argv[3];
35
+ if (!agent) {
36
+ console.error('Usage: squad.mjs brief <agent>');
37
+ process.exit(1);
38
+ }
39
+ if (!existsSync(resolve(AGENTS, `${agent}.md`))) {
40
+ console.error(`No agent at .claude/agents/${agent}.md (Level < 4?).`);
41
+ process.exit(1);
42
+ }
43
+ const squad = squadFor(agent);
44
+ mkdirSync(resolve(SQUADS, squad), { recursive: true });
45
+ const dest = resolve(SQUADS, squad, `${agent}.md`);
46
+ if (existsSync(dest)) {
47
+ console.log(`โ„น๏ธ Briefing already exists: contextkit/squads/${squad}/${agent}.md`);
48
+ return;
49
+ }
50
+ let tpl = '# {{AGENT}} โ€” rich briefing ({{SQUAD}} squad)\n';
51
+ try {
52
+ tpl = readFileSync(resolve(SQUADS, '_BRIEFING.md.tpl'), 'utf-8');
53
+ } catch {
54
+ /* fall back to the one-line stub */
55
+ }
56
+ writeFileSync(dest, tpl.replaceAll('{{AGENT}}', agent).replaceAll('{{SQUAD}}', squad), 'utf-8');
57
+ console.log(`โœ… Scaffolded contextkit/squads/${squad}/${agent}.md โ€” now fill it with real anti-patterns / recipes / edge cases.`);
58
+ }
59
+
60
+ function list() {
61
+ const agents = listAgents();
62
+ if (agents.length === 0) {
63
+ console.log('No agents found (Level < 4?). Run /context-level 4 to install the squads.');
64
+ return;
65
+ }
66
+ console.log(`๐Ÿ‘ฅ ${agents.length} agents (๐Ÿ“„ = has a tier-2 briefing):`);
67
+ for (const a of agents) {
68
+ const squad = squadFor(a);
69
+ const has = existsSync(resolve(SQUADS, squad, `${a}.md`));
70
+ console.log(` ${has ? '๐Ÿ“„' : ' '} ${a} โ€” ${squad}`);
71
+ }
72
+ }
73
+
74
+ const cmd = process.argv[2];
75
+ if (cmd === 'brief') brief();
76
+ else if (cmd === 'list') list();
77
+ else {
78
+ console.error('Usage: squad.mjs <list | brief <agent>>');
79
+ process.exit(1);
80
+ }
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Platform telemetry โ€” how healthy is the ContextDevKit practice on this project?
4
+ *
5
+ * Reports: registered sessions, sessions per ISO week, avg files/session,
6
+ * drift rate (Stop hook had to nudge), ADR count, agents installed, level.
7
+ * Reads archived ledgers in `.claude/.sessions/.archive/` + live ledgers, and
8
+ * the memory tree. Zero-dependency.
9
+ *
10
+ * Usage: node contextkit/tools/scripts/stats.mjs [--json]
11
+ */
12
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
13
+ import { resolve } from 'node:path';
14
+ import { getLevel } from '../../runtime/config/load.mjs';
15
+ import { pathsFor } from '../../runtime/config/paths.mjs';
16
+ import { readJsonSafe } from '../../runtime/hooks/safe-io.mjs';
17
+
18
+ const ROOT = process.cwd();
19
+ const P = pathsFor(ROOT);
20
+
21
+ const readJson = (p) => readJsonSafe(p);
22
+
23
+ function listJson(dir) {
24
+ try {
25
+ return readdirSync(dir).filter((f) => f.endsWith('.json')).map((f) => readJson(resolve(dir, f))).filter(Boolean);
26
+ } catch {
27
+ return [];
28
+ }
29
+ }
30
+
31
+ function count(dir, re) {
32
+ try {
33
+ return readdirSync(dir).filter((f) => re.test(f)).length;
34
+ } catch {
35
+ return 0;
36
+ }
37
+ }
38
+
39
+ function isoWeek(ms) {
40
+ const d = new Date(ms);
41
+ const t = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
42
+ t.setUTCDate(t.getUTCDate() - ((t.getUTCDay() + 6) % 7) + 3);
43
+ const firstThu = new Date(Date.UTC(t.getUTCFullYear(), 0, 4));
44
+ const week = 1 + Math.floor(Math.round((t - firstThu) / 86_400_000) / 7);
45
+ return `${t.getUTCFullYear()}-W${String(week).padStart(2, '0')}`;
46
+ }
47
+
48
+ function collectForge() {
49
+ const root = resolve(ROOT, 'agent-packages');
50
+ let entries = [];
51
+ try { entries = readdirSync(root, { withFileTypes: true }); } catch { return null; }
52
+ const pkgs = entries.filter((entry) => entry.isDirectory() && /^[a-z][a-z0-9-]*@\d+\.\d+\.\d+/.test(entry.name));
53
+ if (!pkgs.length) return null;
54
+ let evaluated = 0;
55
+ let monthlyTarget = 0;
56
+ let monthlyHardCap = 0;
57
+ const byPrimary = {};
58
+ for (const entry of pkgs) {
59
+ const manifestPath = resolve(root, entry.name, 'manifest.yaml');
60
+ let manifest = '';
61
+ try { manifest = readFileSync(manifestPath, 'utf-8'); } catch { continue; }
62
+ const evalLine = manifest.match(/eval_passed_at:\s*['"]?([^'\n]+)['"]?/);
63
+ if (evalLine && evalLine[1].trim() !== 'null') evaluated += 1;
64
+ const target = Number((manifest.match(/monthly_budget_usd:\s*([\d.]+)/) || [])[1] || 0);
65
+ monthlyTarget += target;
66
+ monthlyHardCap += Math.round(target * 1.5);
67
+ const providerMatch = manifest.match(/primary:\s*\n\s*provider:\s*(\w[\w-]*)/);
68
+ const provider = providerMatch ? providerMatch[1] : 'unknown';
69
+ byPrimary[provider] = (byPrimary[provider] || 0) + 1;
70
+ }
71
+ return { packages: pkgs.length, evaluated, unevaluated: pkgs.length - evaluated, monthlyTarget, monthlyHardCap, byPrimary };
72
+ }
73
+
74
+ function collect() {
75
+ const ledgers = [
76
+ ...listJson(resolve(ROOT, '.claude/.sessions')),
77
+ ...listJson(resolve(ROOT, '.claude/.sessions/.archive')),
78
+ ];
79
+ const registeredSessions = count(P.sessions, /^\d{4}-\d{2}-\d{2}-\d{2,}-.+\.md$/);
80
+ const adrs = count(P.decisions, /^\d{4}-.+\.md$/);
81
+ const agents = count(resolve(ROOT, '.claude/agents'), /\.md$/);
82
+ const commands = count(resolve(ROOT, '.claude/commands'), /\.md$/);
83
+ const forge = collectForge();
84
+
85
+ const perWeek = {};
86
+ let totalFiles = 0;
87
+ let nudged = 0;
88
+ for (const l of ledgers) {
89
+ if (typeof l.startedAt === 'number') perWeek[isoWeek(l.startedAt)] = (perWeek[isoWeek(l.startedAt)] || 0) + 1;
90
+ totalFiles += new Set((l.modifications || []).map((m) => m.path)).size;
91
+ if (typeof l.stopWarnedAt === 'number') nudged += 1;
92
+ }
93
+ const n = ledgers.length || 1;
94
+ return {
95
+ level: getLevel(ROOT),
96
+ registeredSessions,
97
+ ledgersSeen: ledgers.length,
98
+ avgFilesPerSession: +(totalFiles / n).toFixed(1),
99
+ driftRatePct: +((nudged / n) * 100).toFixed(1),
100
+ adrs,
101
+ agents,
102
+ commands,
103
+ perWeek,
104
+ forge,
105
+ };
106
+ }
107
+
108
+ function main() {
109
+ const s = collect();
110
+ if (process.argv.includes('--json')) {
111
+ process.stdout.write(JSON.stringify(s, null, 2) + '\n');
112
+ return;
113
+ }
114
+ console.log('๐Ÿ“Š ContextDevKit stats\n');
115
+ console.log(`Level: L${s.level}`);
116
+ console.log(`Registered sessions: ${s.registeredSessions}`);
117
+ console.log(`ADRs: ${s.adrs}`);
118
+ console.log(`Agents / commands: ${s.agents} / ${s.commands}`);
119
+ console.log(`Ledgers analyzed: ${s.ledgersSeen}`);
120
+ console.log(`Avg files / session: ${s.avgFilesPerSession}`);
121
+ console.log(`Drift rate (nudged): ${s.driftRatePct}%`);
122
+ const weeks = Object.entries(s.perWeek).sort();
123
+ if (weeks.length) {
124
+ console.log('\nSessions per ISO week:');
125
+ for (const [w, c] of weeks) console.log(` ${w} ${'โ–ˆ'.repeat(c)} (${c})`);
126
+ }
127
+ if (s.forge) {
128
+ console.log('\n๐Ÿ”ฅ Forge Stats (agent-packages/)');
129
+ console.log(` Packages: ${s.forge.packages}`);
130
+ console.log(` Eval-stamped: ${s.forge.evaluated} / ${s.forge.packages}` + (s.forge.unevaluated ? ` โš ๏ธ ${s.forge.unevaluated} unevaluated` : ''));
131
+ console.log(` Monthly target: $${s.forge.monthlyTarget.toFixed(2)}`);
132
+ console.log(` Monthly hard cap: $${s.forge.monthlyHardCap.toFixed(2)}`);
133
+ const providers = Object.entries(s.forge.byPrimary).sort((a, b) => b[1] - a[1]);
134
+ if (providers.length) console.log(' By primary provider: ' + providers.map(([p, c]) => `${p}=${c}`).join(', '));
135
+ }
136
+ }
137
+
138
+ main();
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * GitHub sync awareness โ€” facts for `/dev-start` (preflight) and `/git pr` (prepr).
4
+ *
5
+ * The boot banner already shows branch/commit divergence and recent branches;
6
+ * `pre-push` blocks textual conflicts. This script adds the missing **PR** layer
7
+ * at the two moments that matter, WITHOUT touching the SessionStart hot path:
8
+ *
9
+ * - preflight (before coding): ahead/behind, recent in-flight branches, and
10
+ * OPEN PRs with CI/review status โ€” flagging PRs *awaiting status* that may
11
+ * overlap the objective.
12
+ * - prepr (before opening a PR): re-check divergence vs the default branch and
13
+ * detect a DUPLICATE open PR for the current branch.
14
+ *
15
+ * `gh` is optional. Absent/unauthed โ‡’ the git-only half runs and the PR half is
16
+ * reported as **skipped, never a pass** (Rule 8). No remote / offline โ‡’ silent,
17
+ * exit 0. Read-only: it never creates, edits, or merges a PR. Zero deps. [ADR-0026]
18
+ *
19
+ * Usage:
20
+ * node contextkit/tools/scripts/sync-check.mjs preflight [--json]
21
+ * node contextkit/tools/scripts/sync-check.mjs prepr [--json]
22
+ */
23
+ import { execFileSync } from 'node:child_process';
24
+
25
+ const ROOT = process.cwd();
26
+
27
+ /**
28
+ * Hard ceiling (ms) for any git/`gh` subprocess. A hung `git fetch` or `gh pr
29
+ * list` against an unreachable remote must not freeze the dev flow. On timeout
30
+ * `execFileSync` throws โ†’ `run()` returns `{ ok:false }` (the failed-command
31
+ * path) and the report degrades gracefully. Env-overridable for fast tests.
32
+ */
33
+ const CMD_TIMEOUT_MS = Number.parseInt(process.env.CONTEXT_GIT_TIMEOUT_MS || '', 10) || 10000;
34
+
35
+ /** PR fields pulled from `gh` โ€” enough to derive checks + review status. */
36
+ const PR_FIELDS = 'number,title,headRefName,state,statusCheckRollup,reviewDecision,updatedAt,url,isDraft';
37
+
38
+ function run(cmd, args) {
39
+ try {
40
+ return { ok: true, out: execFileSync(cmd, args, { cwd: ROOT, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'], timeout: CMD_TIMEOUT_MS }).trim() };
41
+ } catch (err) {
42
+ return { ok: false, out: '', code: err?.status };
43
+ }
44
+ }
45
+
46
+ function int(value) {
47
+ return Number.parseInt(value ?? '0', 10) || 0;
48
+ }
49
+
50
+ /** Strip a UTF-8 BOM and parse; returns null on any malformation (Rule 4). */
51
+ function parseJson(text) {
52
+ try {
53
+ return JSON.parse(text.replace(/^๏ปฟ/, ''));
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ function currentBranch() {
60
+ return run('git', ['symbolic-ref', '--short', 'HEAD']).out || null;
61
+ }
62
+
63
+ function hasRemote() {
64
+ return Boolean(run('git', ['remote', 'get-url', 'origin']).out);
65
+ }
66
+
67
+ /** The default branch (origin/HEAD target), falling back to "main". */
68
+ function mainBranch() {
69
+ const ref = run('git', ['symbolic-ref', '--short', 'refs/remotes/origin/HEAD']);
70
+ return ref.ok && ref.out ? ref.out.replace(/^origin\//, '') : 'main';
71
+ }
72
+
73
+ /**
74
+ * ahead/behind after a best-effort fetch. Prefers the branch's own upstream
75
+ * (`@{u}`); a branch with no upstream (fresh feature branch) falls back to
76
+ * `origin/<main>` so "am I behind the trunk?" still answers. null when unknowable.
77
+ */
78
+ function divergence(main) {
79
+ run('git', ['fetch', 'origin', '--quiet']);
80
+ const upstream = run('git', ['rev-list', '--left-right', '--count', 'HEAD...@{u}']);
81
+ if (upstream.ok) {
82
+ const [a, b] = upstream.out.split(/\s+/);
83
+ return { ahead: int(a), behind: int(b), against: '@{u}' };
84
+ }
85
+ const trunk = run('git', ['rev-list', '--left-right', '--count', `HEAD...origin/${main}`]);
86
+ if (!trunk.ok) return null;
87
+ const [a, b] = trunk.out.split(/\s+/);
88
+ return { ahead: int(a), behind: int(b), against: `origin/${main}` };
89
+ }
90
+
91
+ /** The 20 most-recent OTHER remote branches (in-flight work), newest first. */
92
+ function recentBranches(branch, limit = 20) {
93
+ const r = run('git', ['for-each-ref', '--sort=-committerdate', `--count=${limit}`, '--format=%(refname:short)|%(committerdate:relative)|%(authorname)', 'refs/remotes']);
94
+ if (!r.ok) return [];
95
+ return r.out.split('\n').map((line) => line.trim()).filter(Boolean)
96
+ .map((line) => line.split('|'))
97
+ .filter(([ref]) => ref && ref.includes('/') && !/\/(main|master|HEAD)$/.test(ref) && ref !== `origin/${branch}`)
98
+ .map(([ref, age, author]) => ({ ref, age, author }));
99
+ }
100
+
101
+ /** `gh` is usable only when installed AND authenticated. */
102
+ function ghReady() {
103
+ return run('gh', ['--version']).ok && run('gh', ['auth', 'status']).ok;
104
+ }
105
+
106
+ /** Collapse a PR's check-rollup into one of: passing | failing | pending | none. */
107
+ function rollupChecks(rollup) {
108
+ if (!Array.isArray(rollup) || rollup.length === 0) return 'none';
109
+ let pending = false;
110
+ let failing = false;
111
+ for (const check of rollup) {
112
+ const { status, conclusion, state } = check ?? {};
113
+ if (state === 'PENDING' || (status && status !== 'COMPLETED')) pending = true;
114
+ if (['FAILURE', 'TIMED_OUT', 'CANCELLED', 'ACTION_REQUIRED', 'STARTUP_FAILURE'].includes(conclusion)) failing = true;
115
+ if (state === 'FAILURE' || state === 'ERROR') failing = true;
116
+ }
117
+ if (failing) return 'failing';
118
+ if (pending) return 'pending';
119
+ return 'passing';
120
+ }
121
+
122
+ function reviewLabel(decision) {
123
+ if (decision === 'APPROVED') return 'approved';
124
+ if (decision === 'CHANGES_REQUESTED') return 'changes-requested';
125
+ if (decision === 'REVIEW_REQUIRED') return 'review-required';
126
+ return 'none';
127
+ }
128
+
129
+ /** Project a raw `gh` PR into the kit's summary shape + the "awaiting" verdict. */
130
+ function summarizePr(pr) {
131
+ const checks = rollupChecks(pr.statusCheckRollup);
132
+ const review = reviewLabel(pr.reviewDecision);
133
+ const awaiting = checks === 'pending' || checks === 'failing' || review === 'review-required' || review === 'changes-requested';
134
+ return { number: pr.number, title: pr.title, head: pr.headRefName, draft: Boolean(pr.isDraft), url: pr.url, updated: pr.updatedAt, checks, review, awaiting };
135
+ }
136
+
137
+ /** Open PRs (optionally filtered), or null when `gh` couldn't answer (a SKIP). */
138
+ function listOpenPRs(extraArgs = []) {
139
+ const r = run('gh', ['pr', 'list', '--state', 'open', '--limit', '30', '--json', PR_FIELDS, ...extraArgs]);
140
+ if (!r.ok) return null;
141
+ const parsed = parseJson(r.out);
142
+ return Array.isArray(parsed) ? parsed.map(summarizePr) : null;
143
+ }
144
+
145
+ function preflight() {
146
+ const branch = currentBranch();
147
+ const remote = hasRemote();
148
+ const main = mainBranch();
149
+ const ghOk = remote && ghReady();
150
+ return {
151
+ mode: 'preflight',
152
+ branch,
153
+ remote,
154
+ divergence: remote ? divergence(main) : null,
155
+ recentBranches: remote ? recentBranches(branch) : [],
156
+ ghReady: ghOk,
157
+ prs: ghOk ? listOpenPRs() : null,
158
+ };
159
+ }
160
+
161
+ function prepr() {
162
+ const branch = currentBranch();
163
+ const remote = hasRemote();
164
+ const main = mainBranch();
165
+ const ghOk = remote && ghReady();
166
+ const branchPrs = ghOk && branch ? listOpenPRs(['--head', branch]) : null;
167
+ return {
168
+ mode: 'prepr',
169
+ branch,
170
+ main,
171
+ remote,
172
+ divergence: remote ? divergence(main) : null,
173
+ ghReady: ghOk,
174
+ existingPr: Array.isArray(branchPrs) && branchPrs.length ? branchPrs[0] : (ghOk ? null : undefined),
175
+ };
176
+ }
177
+
178
+ function printPreflight(s) {
179
+ console.log('๐Ÿ”„ Sync preflight\n');
180
+ console.log(`branch: ${s.branch ?? 'โ€”'}`);
181
+ if (!s.remote) { console.log('remote: NONE โ†’ nothing to sync against yet.'); return; }
182
+ if (s.divergence) console.log(`sync: ahead ${s.divergence.ahead} / behind ${s.divergence.behind} (vs ${s.divergence.against})`);
183
+ if (s.recentBranches.length) {
184
+ console.log('\nRecent remote branches (in flight):');
185
+ for (const b of s.recentBranches.slice(0, 8)) console.log(` - ${b.ref} โ€” ${b.age} by ${b.author}`);
186
+ }
187
+ if (!s.ghReady) { console.log('\nPR checks skipped (gh not installed/authed) โ€” git-only view above.'); return; }
188
+ if (s.prs == null) { console.log('\nPR checks skipped (gh query failed) โ€” git-only view above.'); return; }
189
+ if (s.prs.length === 0) { console.log('\nOpen PRs: none.'); return; }
190
+ console.log(`\nOpen PRs (${s.prs.length}):`);
191
+ for (const pr of s.prs) {
192
+ console.log(` #${pr.number} ${pr.awaiting ? 'โณ awaiting' : 'โœ“ ready'} โ€” ${pr.title}`);
193
+ console.log(` head ${pr.head} ยท checks ${pr.checks} ยท review ${pr.review}${pr.draft ? ' ยท draft' : ''}`);
194
+ }
195
+ const awaiting = s.prs.filter((pr) => pr.awaiting).length;
196
+ if (awaiting) console.log(`\nโ†’ ${awaiting} PR(s) awaiting status/review โ€” check overlap with your objective before coding.`);
197
+ }
198
+
199
+ function printPrepr(s) {
200
+ console.log('๐Ÿ”„ Pre-PR check\n');
201
+ console.log(`branch: ${s.branch ?? 'โ€”'}`);
202
+ if (!s.remote) { console.log('remote: NONE โ†’ set one up with /git before opening a PR.'); return; }
203
+ if (s.divergence) {
204
+ console.log(`sync: ahead ${s.divergence.ahead} / behind ${s.divergence.behind} (vs ${s.divergence.against})`);
205
+ if (s.divergence.behind > 0) console.log(` โš ๏ธ behind by ${s.divergence.behind} โ€” rebase first: git pull --rebase origin ${s.main}`);
206
+ }
207
+ if (!s.ghReady) { console.log('\nPR dedupe skipped (gh not installed/authed) โ€” verify manually before opening.'); return; }
208
+ if (!s.existingPr) { console.log('\nNo open PR for this branch โ€” safe to create one.'); return; }
209
+ const pr = s.existingPr;
210
+ console.log(`\nโš ๏ธ An open PR already exists for ${pr.head}:`);
211
+ console.log(` #${pr.number} โ€” ${pr.title}`);
212
+ console.log(` ${pr.url}`);
213
+ console.log(` checks ${pr.checks} ยท review ${pr.review}${pr.draft ? ' ยท draft' : ''}`);
214
+ console.log(' โ†’ Push to update it instead of creating a duplicate.');
215
+ }
216
+
217
+ const mode = process.argv[2];
218
+ const asJson = process.argv.includes('--json');
219
+
220
+ if (mode !== 'preflight' && mode !== 'prepr') {
221
+ console.error('Usage: sync-check.mjs <preflight|prepr> [--json]');
222
+ process.exit(2);
223
+ }
224
+
225
+ try {
226
+ const summary = mode === 'preflight' ? preflight() : prepr();
227
+ if (asJson) console.log(JSON.stringify(summary, null, 2));
228
+ else if (mode === 'preflight') printPreflight(summary);
229
+ else printPrepr(summary);
230
+ process.exit(0);
231
+ } catch (err) {
232
+ // Never break the dev flow โ€” degrade to a one-line note (Rule 2).
233
+ process.stderr.write(`[sync-check] ${err?.message ?? err}\n`);
234
+ process.exit(0);
235
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Tech-debt detectors โ€” pure functions over file content, STACK-AGNOSTIC.
3
+ *
4
+ * Each detector takes `(relPath, content, opts)` and returns findings:
5
+ * { kind, severity, path, line?, snippet?, message }
6
+ * severity: 1..5 (5 = blocker, 1 = nit)
7
+ *
8
+ * Regex-based (no AST) so the scan is fast and dependency-free. False
9
+ * positives are acceptable โ€” the board is human-reviewed, not enforcing.
10
+ */
11
+
12
+ const CODE_RE = /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|rb|php|swift|c|cpp|cs)$/;
13
+
14
+ /** File length vs the constitution's line budget (configurable). */
15
+ export function detectLineBudget(relPath, content, { yellow = 240, red = 308 } = {}) {
16
+ const total = content.split('\n').length;
17
+ if (total > red) {
18
+ return [{ kind: 'line-budget', severity: 5, path: relPath, line: total, message: `${total} lines โ€” RED ZONE (> ${red}). Split by responsibility.` }];
19
+ }
20
+ if (total >= yellow) {
21
+ return [{ kind: 'line-budget', severity: 3, path: relPath, line: total, message: `${total} lines โ€” yellow zone (>= ${yellow}). Plan a split or document cohesion at the top.` }];
22
+ }
23
+ return [];
24
+ }
25
+
26
+ /** Identifiers whose names join two responsibilities ("And"/"Or"/"E"). */
27
+ export function detectSrpAnd(relPath, content) {
28
+ if (!CODE_RE.test(relPath)) return [];
29
+ const findings = [];
30
+ const lines = content.split('\n');
31
+ const jsDecl = /(?:function\s+|const\s+|let\s+|var\s+|async\s+function\s+|export\s+(?:function\s+|const\s+|async\s+function\s+))([a-z][a-zA-Z0-9_]*)/g;
32
+ const jsBad = /[a-z](And|Or|E)[A-Z][a-zA-Z0-9]*/;
33
+ const pyDecl = /def\s+([a-z][a-z0-9_]*)/g;
34
+ const pyBad = /_(and|or)_/;
35
+ for (let i = 0; i < lines.length; i += 1) {
36
+ const line = lines[i];
37
+ for (const [re, bad] of [[jsDecl, jsBad], [pyDecl, pyBad]]) {
38
+ re.lastIndex = 0;
39
+ let m;
40
+ while ((m = re.exec(line)) !== null) {
41
+ if (bad.test(m[1])) {
42
+ findings.push({ kind: 'srp-and', severity: 2, path: relPath, line: i + 1, snippet: line.trim().slice(0, 120), message: `Identifier \`${m[1]}\` joins two responsibilities โ€” split into separate functions.` });
43
+ }
44
+ }
45
+ }
46
+ }
47
+ return findings;
48
+ }
49
+
50
+ /** Flags the four standard unresolved-debt markers the author left in code. */
51
+ export function detectTodoMarkers(relPath, content) {
52
+ if (!CODE_RE.test(relPath)) return [];
53
+ const findings = [];
54
+ const re = /\b(TODO|FIXME|HACK|XXX)\b/;
55
+ content.split('\n').forEach((line, i) => {
56
+ if (re.test(line) && /\/\/|#|\/\*|\*/.test(line)) {
57
+ findings.push({ kind: 'todo-marker', severity: 1, path: relPath, line: i + 1, snippet: line.trim().slice(0, 120), message: 'Unresolved TODO/FIXME marker.' });
58
+ }
59
+ });
60
+ return findings;
61
+ }
62
+
63
+ /** React components with > 2 useState AND >= 1 useEffect โ†’ extract a hook. */
64
+ export function detectReactStateLoop(relPath, content) {
65
+ if (!/\.(tsx|jsx)$/.test(relPath)) return [];
66
+ if (/(^|\/)hooks?\//.test(relPath) || /use[A-Z]/.test(relPath.split('/').pop() || '')) return [];
67
+ const states = (content.match(/\buseState\s*\(/g) || []).length;
68
+ const effects = (content.match(/\buseEffect\s*\(/g) || []).length;
69
+ if (states > 2 && effects >= 1) {
70
+ return [{ kind: 'react-state-loop', severity: 3, path: relPath, message: `${states} useState + ${effects} useEffect โ€” extract logic into a custom hook.` }];
71
+ }
72
+ return [];
73
+ }
74
+
75
+ export const ALL_DETECTORS = [detectLineBudget, detectSrpAnd, detectTodoMarkers, detectReactStateLoop];
76
+ export { CODE_RE };