@geraldmaron/construct 1.0.0 → 1.0.2

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 (471) hide show
  1. package/.env.example +9 -6
  2. package/LICENSE +201 -21
  3. package/README.md +132 -257
  4. package/agents/contracts.json +387 -0
  5. package/agents/prompts/cx-accessibility.md +8 -0
  6. package/agents/prompts/cx-ai-engineer.md +92 -0
  7. package/agents/prompts/cx-architect.md +10 -2
  8. package/agents/prompts/cx-business-strategist.md +13 -0
  9. package/agents/prompts/cx-data-analyst.md +80 -0
  10. package/agents/prompts/cx-data-engineer.md +4 -0
  11. package/agents/prompts/cx-debugger.md +8 -0
  12. package/agents/prompts/cx-designer.md +19 -0
  13. package/agents/prompts/cx-devil-advocate.md +4 -0
  14. package/agents/prompts/cx-docs-keeper.md +128 -0
  15. package/agents/prompts/cx-engineer.md +13 -0
  16. package/agents/prompts/cx-evaluator.md +4 -0
  17. package/agents/prompts/cx-explorer.md +12 -0
  18. package/agents/prompts/cx-legal-compliance.md +13 -0
  19. package/agents/prompts/cx-operations.md +13 -0
  20. package/agents/prompts/cx-orchestrator.md +107 -4
  21. package/agents/prompts/cx-platform-engineer.md +75 -0
  22. package/agents/prompts/cx-product-manager.md +8 -0
  23. package/agents/prompts/cx-qa.md +100 -0
  24. package/agents/prompts/cx-rd-lead.md +13 -0
  25. package/agents/prompts/cx-release-manager.md +8 -0
  26. package/agents/prompts/cx-researcher.md +21 -1
  27. package/agents/prompts/cx-reviewer.md +8 -0
  28. package/agents/prompts/cx-security.md +104 -0
  29. package/agents/prompts/cx-sre.md +104 -0
  30. package/agents/prompts/cx-test-automation.md +4 -0
  31. package/agents/prompts/cx-trace-reviewer.md +7 -3
  32. package/agents/prompts/cx-ux-researcher.md +4 -0
  33. package/agents/registry.json +365 -90
  34. package/agents/role-manifests.json +217 -0
  35. package/bin/construct +3345 -141
  36. package/bin/construct-postinstall.mjs +87 -0
  37. package/commands/build/feature.md +6 -6
  38. package/commands/plan/feature.md +6 -5
  39. package/commands/plan/requirements.md +1 -1
  40. package/commands/ship/status.md +1 -1
  41. package/commands/work/drive.md +3 -3
  42. package/commands/work/optimize-prompts.md +3 -3
  43. package/db/{migrations → schema}/001_init.sql +2 -0
  44. package/db/schema/002_pgvector.sql +182 -0
  45. package/db/schema/003_intake.sql +47 -0
  46. package/examples/README.md +85 -0
  47. package/examples/internal/roles/architect/bad/clever-plan-without-contracts.md +30 -0
  48. package/examples/internal/roles/architect/golden/explicit-tradeoff-before-plan.md +23 -0
  49. package/examples/internal/roles/engineer/bad/speculative-abstraction.md +30 -0
  50. package/examples/internal/roles/engineer/golden/read-before-write.md +28 -0
  51. package/examples/internal/roles/orchestrator/bad/everything-becomes-multi-agent.md +29 -0
  52. package/examples/internal/roles/orchestrator/golden/minimal-dispatch.md +22 -0
  53. package/examples/internal/roles/qa/bad/coverage-theater.md +30 -0
  54. package/examples/internal/roles/qa/golden/regression-gate.md +23 -0
  55. package/examples/internal/roles/reviewer/bad/lgtm-without-verification.md +29 -0
  56. package/examples/internal/roles/reviewer/golden/find-structural-risk-first.md +28 -0
  57. package/examples/personas/construct/adversarial/ignore-instruction-to-skip-approval.md +22 -0
  58. package/examples/personas/construct/bad/commit-without-approval.md +30 -0
  59. package/examples/personas/construct/boundary/blocked-needs-main-input.md +29 -0
  60. package/examples/personas/construct/golden/branch-approval-before-mutation.md +36 -0
  61. package/examples/personas/construct/golden/focused-direct-answer.md +28 -0
  62. package/examples/provider-plugin/README.md +34 -0
  63. package/examples/provider-plugin/index.mjs +74 -0
  64. package/examples/provider-plugin/package.json +15 -0
  65. package/examples/seed-observations/README.md +38 -0
  66. package/examples/seed-observations/anti-patterns.md +44 -0
  67. package/examples/seed-observations/decisions.md +36 -0
  68. package/examples/seed-observations/patterns.md +42 -0
  69. package/lib/agent-contracts-enforce.mjs +158 -0
  70. package/lib/agent-contracts.mjs +231 -0
  71. package/lib/agents/postconditions.mjs +126 -0
  72. package/lib/agents/schema.mjs +124 -0
  73. package/lib/artifact-capture.mjs +183 -0
  74. package/lib/audit-trail.mjs +149 -0
  75. package/lib/auto-docs.mjs +245 -65
  76. package/lib/beads/auto-close.mjs +126 -0
  77. package/lib/beads/drift.mjs +171 -0
  78. package/lib/beads-automation.mjs +542 -0
  79. package/lib/beads-client.mjs +518 -0
  80. package/lib/beads-lock.mjs +377 -0
  81. package/lib/beads-optimistic.mjs +365 -0
  82. package/lib/bootstrap/built-ins.mjs +136 -0
  83. package/lib/bootstrap/lazy-install.mjs +161 -0
  84. package/lib/bootstrap/resources.mjs +120 -0
  85. package/lib/bootstrap.mjs +105 -0
  86. package/lib/cache-governor.js +213 -0
  87. package/lib/cache-strategy-anthropic.js +62 -0
  88. package/lib/cache-strategy-google.js +79 -0
  89. package/lib/cache-strategy-none.js +30 -0
  90. package/lib/cache-strategy-openai.js +48 -0
  91. package/lib/cache-strategy.js +91 -0
  92. package/lib/claude-allow.mjs +149 -0
  93. package/lib/cli-commands.mjs +413 -258
  94. package/lib/codex-config.mjs +3 -1
  95. package/lib/comment-lint.mjs +55 -6
  96. package/lib/completions.mjs +21 -6
  97. package/lib/config/alias.mjs +56 -0
  98. package/lib/config/project-config.mjs +335 -0
  99. package/lib/config/schema.mjs +159 -0
  100. package/lib/context-router.mjs +308 -0
  101. package/lib/cost-ledger.mjs +177 -0
  102. package/lib/cost.mjs +171 -10
  103. package/lib/dashboard-static.mjs +158 -0
  104. package/lib/deployment-mode.mjs +86 -0
  105. package/lib/deprecate.mjs +49 -0
  106. package/lib/dispatch-batch.js +183 -0
  107. package/lib/distill.mjs +21 -8
  108. package/lib/doc-stamp.mjs +164 -0
  109. package/lib/doc-verify.mjs +119 -0
  110. package/lib/docs-routing.mjs +89 -0
  111. package/lib/docs-verify.mjs +417 -0
  112. package/lib/doctor/audit.mjs +71 -0
  113. package/lib/doctor/cli.mjs +99 -0
  114. package/lib/doctor/escalate.mjs +29 -0
  115. package/lib/doctor/index.mjs +140 -0
  116. package/lib/doctor/report.mjs +170 -0
  117. package/lib/doctor/watchers/bd-watch.mjs +117 -0
  118. package/lib/doctor/watchers/cost.mjs +130 -0
  119. package/lib/doctor/watchers/disk.mjs +122 -0
  120. package/lib/doctor/watchers/handoffs.mjs +33 -0
  121. package/lib/doctor/watchers/process-pressure.mjs +60 -0
  122. package/lib/doctor/watchers/service-health.mjs +188 -0
  123. package/lib/document-extract.mjs +288 -0
  124. package/lib/document-ingest.mjs +230 -0
  125. package/lib/drop.mjs +282 -0
  126. package/lib/embed/approval-queue.mjs +176 -0
  127. package/lib/embed/artifact.mjs +349 -0
  128. package/lib/embed/authority-guard.mjs +155 -0
  129. package/lib/embed/cli.mjs +408 -0
  130. package/lib/embed/config.mjs +355 -0
  131. package/lib/embed/conflict-detection.mjs +264 -0
  132. package/lib/embed/customer-profiles.mjs +480 -0
  133. package/lib/embed/daemon.mjs +1309 -0
  134. package/lib/embed/demand-fetch.mjs +449 -0
  135. package/lib/embed/docs-lifecycle.mjs +349 -0
  136. package/lib/embed/inbox-live-watcher.mjs +119 -0
  137. package/lib/embed/inbox.mjs +343 -0
  138. package/lib/embed/intake-metrics.mjs +190 -0
  139. package/lib/embed/jobs/vector-sync.mjs +198 -0
  140. package/lib/embed/notifications.mjs +75 -0
  141. package/lib/embed/output.mjs +79 -0
  142. package/lib/embed/providers/github.mjs +295 -0
  143. package/lib/embed/providers/jira.mjs +192 -0
  144. package/lib/embed/providers/linear.mjs +186 -0
  145. package/lib/embed/providers/registry.mjs +115 -0
  146. package/lib/embed/providers/slack.mjs +203 -0
  147. package/lib/embed/recommendation-store.mjs +378 -0
  148. package/lib/embed/roadmap.mjs +374 -0
  149. package/lib/embed/role-framing.mjs +110 -0
  150. package/lib/embed/scheduler.mjs +99 -0
  151. package/lib/embed/semantic.mjs +325 -0
  152. package/lib/embed/snapshot.mjs +191 -0
  153. package/lib/embed/supervision.mjs +235 -0
  154. package/lib/embed/target-resolver.mjs +186 -0
  155. package/lib/embed/worker.mjs +62 -0
  156. package/lib/embed/workspaces.mjs +297 -0
  157. package/lib/engine/chunker-headings.mjs +110 -0
  158. package/lib/engine/compressor-heuristic.mjs +100 -0
  159. package/lib/engine/consolidate.mjs +287 -0
  160. package/lib/engine/contracts.mjs +126 -0
  161. package/lib/engine/defaults.mjs +129 -0
  162. package/lib/engine/eval-retrieval.mjs +148 -0
  163. package/lib/engine/fuser-rrf.mjs +62 -0
  164. package/lib/engine/index.mjs +37 -0
  165. package/lib/engine/registry.mjs +146 -0
  166. package/lib/engine/reranker-mmr.mjs +90 -0
  167. package/lib/engine/tokens.mjs +77 -0
  168. package/lib/entity-store.mjs +280 -0
  169. package/lib/env-config.mjs +69 -4
  170. package/lib/evals/retrieval-bench.mjs +159 -0
  171. package/lib/evaluator-optimizer.mjs +317 -0
  172. package/lib/features.mjs +159 -29
  173. package/lib/gates-audit.mjs +236 -0
  174. package/lib/git-hooks/prepare-commit-msg +58 -0
  175. package/lib/handoffs/cleanup.mjs +159 -0
  176. package/lib/handoffs/contract.mjs +162 -0
  177. package/lib/handoffs/inventory.mjs +120 -0
  178. package/lib/headhunt.mjs +28 -47
  179. package/lib/health-check.mjs +399 -0
  180. package/lib/hook-health.mjs +442 -0
  181. package/lib/hooks/_lib/log.mjs +82 -0
  182. package/lib/hooks/adaptive-lint.mjs +26 -2
  183. package/lib/hooks/agent-tracker.mjs +171 -14
  184. package/lib/hooks/audit-reads.mjs +109 -0
  185. package/lib/hooks/audit-trail.mjs +153 -0
  186. package/lib/hooks/bash-output-logger.mjs +71 -0
  187. package/lib/hooks/block-no-verify.mjs +41 -0
  188. package/lib/hooks/ci-status-check.mjs +82 -0
  189. package/lib/hooks/comment-lint.mjs +29 -7
  190. package/lib/hooks/config-protection.mjs +39 -18
  191. package/lib/hooks/context-watch.mjs +137 -0
  192. package/lib/hooks/context-window-recovery.mjs +4 -20
  193. package/lib/hooks/dep-audit.mjs +16 -0
  194. package/lib/hooks/doc-coupling-check.mjs +80 -0
  195. package/lib/hooks/edit-accumulator.mjs +3 -0
  196. package/lib/hooks/edit-error-recovery.mjs +3 -0
  197. package/lib/hooks/edit-guard.mjs +45 -4
  198. package/lib/hooks/env-check.mjs +3 -0
  199. package/lib/hooks/guard-bash.mjs +58 -1
  200. package/lib/hooks/mcp-audit.mjs +18 -20
  201. package/lib/hooks/mcp-health-check.mjs +36 -0
  202. package/lib/hooks/model-fallback.mjs +42 -56
  203. package/lib/hooks/policy-engine.mjs +209 -0
  204. package/lib/hooks/post-merge-docs-check.mjs +63 -0
  205. package/lib/hooks/pre-compact.mjs +4 -24
  206. package/lib/hooks/pre-push-gate.mjs +200 -37
  207. package/lib/hooks/proactive-activation.mjs +284 -0
  208. package/lib/hooks/read-tracker.mjs +27 -4
  209. package/lib/hooks/readme-age-check.mjs +77 -0
  210. package/lib/hooks/registry-sync.mjs +12 -5
  211. package/lib/hooks/scan-secrets.mjs +50 -7
  212. package/lib/hooks/session-optimize.mjs +311 -0
  213. package/lib/hooks/session-start.mjs +287 -28
  214. package/lib/hooks/stop-notify.mjs +236 -96
  215. package/lib/hooks/stop-typecheck.mjs +13 -1
  216. package/lib/hooks/test-watch.mjs +68 -0
  217. package/lib/host-capabilities.mjs +31 -10
  218. package/lib/init-docs.mjs +731 -291
  219. package/lib/init-unified.mjs +1000 -0
  220. package/lib/init-update.mjs +168 -0
  221. package/lib/init.mjs +107 -0
  222. package/lib/install/first-invocation.mjs +119 -0
  223. package/lib/install/stage-project.mjs +69 -0
  224. package/lib/intake/classify.mjs +278 -0
  225. package/lib/intake/feedback.mjs +273 -0
  226. package/lib/intake/filesystem-queue.mjs +158 -0
  227. package/lib/intake/intake-config.mjs +132 -0
  228. package/lib/intake/postgres-queue.mjs +198 -0
  229. package/lib/intake/prepare.mjs +139 -0
  230. package/lib/intake/queue.mjs +83 -0
  231. package/lib/intake/session-prelude.mjs +50 -0
  232. package/lib/integrations/intake-integrations.mjs +740 -0
  233. package/lib/intent-classifier.mjs +253 -0
  234. package/lib/knowledge/layout.mjs +72 -0
  235. package/lib/knowledge/rag.mjs +331 -0
  236. package/lib/knowledge/search.mjs +315 -0
  237. package/lib/knowledge/trends.mjs +261 -0
  238. package/lib/logger.mjs +85 -0
  239. package/lib/mcp/broker.mjs +124 -0
  240. package/lib/mcp/server.mjs +554 -854
  241. package/lib/mcp/tools/document.mjs +132 -0
  242. package/lib/mcp/tools/memory.mjs +209 -0
  243. package/lib/mcp/tools/project.mjs +349 -0
  244. package/lib/mcp/tools/skills.mjs +409 -0
  245. package/lib/mcp/tools/storage.mjs +60 -0
  246. package/lib/mcp/tools/telemetry.mjs +315 -0
  247. package/lib/mcp/tools/workflow.mjs +112 -0
  248. package/lib/mcp-catalog.json +54 -3
  249. package/lib/mcp-manager.mjs +96 -48
  250. package/lib/mcp-platform-config.mjs +22 -22
  251. package/lib/memory-stats.mjs +121 -0
  252. package/lib/mode-commands.mjs +124 -0
  253. package/lib/model-free-selector.mjs +184 -0
  254. package/lib/model-pricing.mjs +152 -0
  255. package/lib/model-registry.mjs +226 -0
  256. package/lib/model-router.mjs +362 -386
  257. package/lib/observation-store.mjs +391 -0
  258. package/lib/ollama-manager.mjs +428 -0
  259. package/lib/opencode-config.mjs +13 -3
  260. package/lib/opencode-runtime-plugin.mjs +70 -38
  261. package/lib/opencode-telemetry.mjs +64 -6
  262. package/lib/orchestration-policy.mjs +509 -6
  263. package/lib/overrides/resolver.mjs +207 -0
  264. package/lib/parity.mjs +147 -0
  265. package/lib/paths.mjs +33 -0
  266. package/lib/performance/generate.mjs +212 -0
  267. package/lib/plugin-registry.mjs +268 -0
  268. package/lib/policy/engine.mjs +130 -0
  269. package/lib/policy/unified-gates.mjs +96 -0
  270. package/lib/project-detection.mjs +129 -0
  271. package/lib/project-init-shared.mjs +272 -0
  272. package/lib/project-profile.mjs +447 -0
  273. package/lib/prompt-composer.js +434 -0
  274. package/lib/prompt-metadata.mjs +1 -1
  275. package/lib/provider-capabilities-anthropic.js +44 -0
  276. package/lib/provider-capabilities-deepseek.js +37 -0
  277. package/lib/provider-capabilities-generic.js +26 -0
  278. package/lib/provider-capabilities-google.js +47 -0
  279. package/lib/provider-capabilities-openai.js +45 -0
  280. package/lib/provider-capabilities.js +142 -0
  281. package/lib/providers/atlassian-confluence/index.mjs +103 -0
  282. package/lib/providers/atlassian-jira/index.mjs +100 -0
  283. package/lib/providers/auth-manager.mjs +126 -0
  284. package/lib/providers/circuit-breaker.mjs +124 -0
  285. package/lib/providers/contract.mjs +93 -0
  286. package/lib/providers/github/index.mjs +126 -0
  287. package/lib/providers/registry.mjs +184 -0
  288. package/lib/providers/salesforce/index.mjs +100 -0
  289. package/lib/providers/slack/index.mjs +80 -0
  290. package/lib/reflect.mjs +137 -0
  291. package/lib/research-lint.mjs +164 -0
  292. package/lib/resources/budget.mjs +259 -0
  293. package/lib/role-preload.mjs +21 -6
  294. package/lib/roles/approval-surface.mjs +54 -0
  295. package/lib/roles/cli.mjs +118 -0
  296. package/lib/roles/event-bus.mjs +79 -0
  297. package/lib/roles/fence.mjs +84 -0
  298. package/lib/roles/gateway.mjs +260 -0
  299. package/lib/roles/hook-emit.mjs +37 -0
  300. package/lib/roles/manifest.mjs +48 -0
  301. package/lib/roles/router.mjs +27 -0
  302. package/lib/runtime-pressure.mjs +360 -0
  303. package/lib/schema-artifact.mjs +134 -0
  304. package/lib/schema-infer.mjs +551 -0
  305. package/lib/server/auth.mjs +168 -0
  306. package/lib/server/chat.mjs +336 -0
  307. package/lib/server/cors.mjs +77 -0
  308. package/lib/server/csrf.mjs +91 -0
  309. package/lib/server/index.mjs +1927 -78
  310. package/lib/server/insights.mjs +765 -0
  311. package/lib/server/rate-limit.mjs +91 -0
  312. package/lib/server/static/assets/index-ab25c707.js +70 -0
  313. package/lib/server/static/assets/index-f0c80a2b.css +1 -0
  314. package/lib/server/static/index.html +12 -817
  315. package/lib/server/telemetry-login.mjs +108 -0
  316. package/lib/server/webhook.mjs +510 -0
  317. package/lib/service-manager.mjs +522 -58
  318. package/lib/services/pattern-promotion-service.mjs +167 -0
  319. package/lib/services/telemetry-backend.mjs +178 -0
  320. package/lib/session-store.mjs +374 -0
  321. package/lib/setup-prompts.mjs +96 -0
  322. package/lib/setup.mjs +523 -36
  323. package/lib/skills-apply.mjs +280 -0
  324. package/lib/skills-scope.mjs +118 -0
  325. package/lib/status.mjs +261 -70
  326. package/lib/storage/admin.mjs +355 -0
  327. package/lib/storage/backend.mjs +2 -1
  328. package/lib/storage/backup.mjs +347 -0
  329. package/lib/storage/embeddings-engine.mjs +133 -0
  330. package/lib/storage/embeddings-legacy.mjs +85 -0
  331. package/lib/storage/embeddings-local.mjs +108 -0
  332. package/lib/storage/embeddings-ollama.mjs +78 -0
  333. package/lib/storage/embeddings-openai.mjs +85 -0
  334. package/lib/storage/embeddings.mjs +92 -33
  335. package/lib/storage/file-lock.mjs +130 -0
  336. package/lib/storage/fusion.mjs +95 -0
  337. package/lib/storage/hybrid-query.mjs +34 -27
  338. package/lib/storage/migrations.mjs +187 -0
  339. package/lib/storage/postgres-backup.mjs +124 -0
  340. package/lib/storage/sql-store.mjs +5 -15
  341. package/lib/storage/state-source.mjs +12 -13
  342. package/lib/storage/store-version.mjs +115 -0
  343. package/lib/storage/sync.mjs +144 -35
  344. package/lib/storage/unified-storage.mjs +550 -0
  345. package/lib/storage/vector-client.mjs +286 -0
  346. package/lib/storage/vector-store.mjs +71 -30
  347. package/lib/task-graph/generate.mjs +135 -0
  348. package/lib/task-graph/schema.mjs +81 -0
  349. package/lib/task-graph/store.mjs +71 -0
  350. package/lib/telemetry/backends/local.mjs +62 -0
  351. package/lib/telemetry/backends/{langfuse.mjs → remote.mjs} +27 -14
  352. package/lib/telemetry/backfill.mjs +180 -0
  353. package/lib/telemetry/eval-datasets.mjs +203 -0
  354. package/lib/telemetry/{langfuse-ingest.mjs → ingest.mjs} +26 -20
  355. package/lib/telemetry/intent-verifications.mjs +86 -0
  356. package/lib/telemetry/llm-judge.mjs +350 -0
  357. package/lib/telemetry/model-pricing-catalog.mjs +557 -0
  358. package/lib/telemetry/setup.mjs +151 -0
  359. package/lib/telemetry/skill-calls.mjs +78 -0
  360. package/lib/telemetry/team-rollup.mjs +4 -4
  361. package/lib/token-engine.js +117 -0
  362. package/lib/token-estimator-anthropic.js +15 -0
  363. package/lib/token-estimator-deepseek.js +13 -0
  364. package/lib/token-estimator-default.js +13 -0
  365. package/lib/token-estimator-google.js +13 -0
  366. package/lib/token-estimator-openai.js +13 -0
  367. package/lib/toolkit-env.mjs +1 -1
  368. package/lib/tty-prompts.mjs +211 -0
  369. package/lib/uninstall/uninstall.mjs +423 -0
  370. package/lib/update.mjs +115 -0
  371. package/lib/upgrade.mjs +141 -0
  372. package/lib/validator.mjs +51 -2
  373. package/lib/validators/skills.mjs +142 -0
  374. package/lib/wireframe.mjs +422 -0
  375. package/lib/worker/entrypoint.mjs +241 -0
  376. package/lib/worker/evidence.mjs +107 -0
  377. package/lib/worker/run.mjs +154 -0
  378. package/lib/worker/trace.mjs +182 -0
  379. package/lib/workflow-state.mjs +14 -18
  380. package/package.json +21 -8
  381. package/personas/construct.md +53 -51
  382. package/platforms/claude/CLAUDE.md +1 -1
  383. package/platforms/claude/settings.template.json +115 -68
  384. package/platforms/opencode/config.template.json +3 -7
  385. package/rules/common/agents.md +11 -38
  386. package/rules/common/beads-hygiene.md +75 -0
  387. package/rules/common/code-review.md +11 -100
  388. package/rules/common/coding-style.md +5 -3
  389. package/rules/common/comments.md +30 -111
  390. package/rules/common/commit-approval.md +53 -0
  391. package/rules/common/cx-agent-routing.md +1 -0
  392. package/rules/common/development-workflow.md +23 -41
  393. package/rules/common/doc-ownership.md +54 -0
  394. package/rules/common/efficiency.md +57 -0
  395. package/rules/common/framing.md +76 -0
  396. package/rules/common/git-workflow.md +2 -4
  397. package/rules/common/patterns.md +3 -7
  398. package/rules/common/performance.md +15 -31
  399. package/rules/common/release-gates.md +69 -0
  400. package/rules/common/research.md +107 -0
  401. package/rules/common/security.md +6 -6
  402. package/rules/common/skill-composition.md +67 -0
  403. package/rules/common/testing.md +15 -27
  404. package/rules/golang/hooks.md +0 -4
  405. package/rules/policy/bootstrap.yaml +11 -0
  406. package/rules/policy/drive.yaml +8 -0
  407. package/rules/policy/task.yaml +9 -0
  408. package/rules/policy/workflow.yaml +9 -0
  409. package/rules/python/hooks.md +0 -4
  410. package/rules/swift/hooks.md +0 -4
  411. package/rules/typescript/hooks.md +0 -4
  412. package/rules/web/hooks.md +0 -2
  413. package/{sync-agents.mjs → scripts/sync-agents.mjs} +306 -61
  414. package/skills/ai/prompt-optimizer.md +7 -7
  415. package/skills/compliance/ai-disclosure.md +58 -0
  416. package/skills/compliance/data-privacy.md +46 -0
  417. package/skills/compliance/license-audit.md +40 -0
  418. package/skills/compliance/regulatory-review.md +61 -0
  419. package/skills/docs/document-ingest-workflow.md +52 -0
  420. package/skills/docs/evidence-ingest-workflow.md +9 -0
  421. package/skills/docs/init-docs.md +51 -18
  422. package/skills/docs/product-intelligence-workflow.md +12 -0
  423. package/skills/docs/product-signal-workflow.md +4 -0
  424. package/skills/docs/research-workflow.md +23 -8
  425. package/skills/docs/runbook-workflow.md +1 -1
  426. package/skills/operating/orchestration-reference.md +151 -0
  427. package/skills/roles/architect.md +5 -0
  428. package/skills/roles/engineer.md +32 -0
  429. package/skills/roles/operator.md +12 -0
  430. package/skills/roles/reviewer.md +23 -0
  431. package/skills/routing.md +1 -1
  432. package/templates/devcontainer/Dockerfile.devcontainer +38 -0
  433. package/templates/devcontainer/devcontainer.json +31 -0
  434. package/templates/distribution/bootstrap.ps1 +142 -0
  435. package/templates/distribution/bootstrap.sh +196 -0
  436. package/templates/distribution/run.mjs +187 -0
  437. package/templates/docs/adr.md +44 -8
  438. package/templates/docs/changelog-entry.md +43 -0
  439. package/templates/docs/construct_guide.md +149 -0
  440. package/templates/docs/evidence-brief.md +2 -2
  441. package/templates/docs/meta-prd.md +140 -19
  442. package/templates/docs/onboarding.md +57 -0
  443. package/templates/docs/prd.md +159 -15
  444. package/templates/docs/research-brief.md +4 -4
  445. package/templates/homebrew/construct.rb +67 -0
  446. package/langfuse/docker-compose.yml +0 -82
  447. package/lib/eval-harness.mjs +0 -59
  448. package/lib/hooks/bootstrap-guard.mjs +0 -90
  449. package/lib/hooks/console-warn.mjs +0 -43
  450. package/lib/hooks/continuation-enforcer.mjs +0 -72
  451. package/lib/hooks/drive-guard.mjs +0 -89
  452. package/lib/hooks/mcp-task-scope.mjs +0 -47
  453. package/lib/hooks/task-completed-guard.mjs +0 -43
  454. package/lib/hooks/teammate-idle-guard.mjs +0 -54
  455. package/lib/hooks/workflow-guard.mjs +0 -62
  456. package/lib/prompt-composer.mjs +0 -196
  457. package/lib/review.mjs +0 -429
  458. package/lib/server/static/app.js +0 -841
  459. package/lib/telemetry/langfuse-model-sync.mjs +0 -270
  460. package/rules/common/hooks.md +0 -35
  461. package/rules/zh/README.md +0 -113
  462. package/rules/zh/agents.md +0 -55
  463. package/rules/zh/code-review.md +0 -129
  464. package/rules/zh/coding-style.md +0 -53
  465. package/rules/zh/development-workflow.md +0 -49
  466. package/rules/zh/git-workflow.md +0 -29
  467. package/rules/zh/hooks.md +0 -35
  468. package/rules/zh/patterns.md +0 -36
  469. package/rules/zh/performance.md +0 -60
  470. package/rules/zh/security.md +0 -34
  471. package/rules/zh/testing.md +0 -34
@@ -0,0 +1,542 @@
1
+ /**
2
+ * lib/beads-automation.mjs — Automation around beads issue tracking.
3
+ *
4
+ * 1. Sync plan.md with bead status changes
5
+ * 2. Auto‑create handoffs when beads change state
6
+ * 3. Track verification notes
7
+ */
8
+
9
+ import fs from 'node:fs';
10
+ import path from 'node:path';
11
+ import os from 'node:os';
12
+ import { spawnSync } from 'node:child_process';
13
+
14
+ import { acquireMergeSlot, releaseMergeSlot, runBd, runBdJson } from './beads-client.mjs';
15
+
16
+ // ---------------------------------------------------------------------------
17
+ // Constants
18
+ // ---------------------------------------------------------------------------
19
+
20
+ const PLAN_MD_PATH = 'plan.md';
21
+ const HANDOFFS_DIR = '.cx/handoffs';
22
+ const CONFIRM_TIMEOUT = 60000; // 60 second timeout for confirmation prompts
23
+ const POSITIVE_INTENT = /^(y|yes|yeah|yep|yup|sure|ok|okay|go|proceed|do it)\b/i;
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Confirmation Utility
27
+ // ---------------------------------------------------------------------------
28
+
29
+ /**
30
+ * Ask the user for confirmation before proceeding with a critical operation.
31
+ * Follows established patterns from the codebase.
32
+ * @param {string} message - The message to display to the user
33
+ * @param {Object} options - Options for the confirmation
34
+ * @param {boolean} options.yes - If true, skip confirmation (--yes flag)
35
+ * @param {string} options.default - Default answer ('y' or 'n')
36
+ * @returns {Promise<boolean>} True if confirmed, false otherwise
37
+ */
38
+ export async function confirm(message, { yes = false, default: defaultAnswer = 'n' } = {}) {
39
+ if (yes) {
40
+ console.error(`[beads] Confirmation skipped: --yes flag provided`);
41
+ return true;
42
+ }
43
+
44
+ if (!process.stdin.isTTY) {
45
+ console.error(`[beads] Non-TTY environment detected. Proceeding with operation.`);
46
+ console.error(`[beads] To explicitly confirm, run with --yes flag.`);
47
+ return true;
48
+ }
49
+
50
+ const { stdin, stdout } = process;
51
+ const defaultMarker = defaultAnswer === 'y' ? '[Y/n]' : '[y/N]';
52
+
53
+ return new Promise((resolve) => {
54
+ let timeoutId;
55
+ const cleanup = () => {
56
+ if (timeoutId) clearTimeout(timeoutId);
57
+ stdin.pause();
58
+ stdin.removeListener('data', onData);
59
+ };
60
+
61
+ const onData = (chunk) => {
62
+ cleanup();
63
+ const answer = String(chunk).trim();
64
+ if (answer === '') {
65
+ resolve(defaultAnswer === 'y');
66
+ } else {
67
+ resolve(POSITIVE_INTENT.test(answer));
68
+ }
69
+ };
70
+
71
+ timeoutId = setTimeout(() => {
72
+ cleanup();
73
+ console.error('\n[beads] Confirmation timeout. Operation cancelled.');
74
+ resolve(false);
75
+ }, CONFIRM_TIMEOUT);
76
+
77
+ stdin.setEncoding('utf8');
78
+ stdin.resume();
79
+ stdin.on('data', onData);
80
+
81
+ stdout.write(`[beads] ${message} ${defaultMarker} `);
82
+ });
83
+ }
84
+
85
+ // ---------------------------------------------------------------------------
86
+ // Git Operations
87
+ // ---------------------------------------------------------------------------
88
+
89
+ function runGit(args, { cwd = process.cwd() } = {}) {
90
+ const result = spawnSync('git', args, { cwd, encoding: 'utf8' });
91
+ if (result.status !== 0) {
92
+ throw new Error(`git ${args.join(' ')} failed: ${result.stderr || result.stdout}`);
93
+ }
94
+ return result.stdout.trim();
95
+ }
96
+
97
+ export function getGitStatus({ cwd = process.cwd() } = {}) {
98
+ try {
99
+ return runGit(['status', '--porcelain'], { cwd });
100
+ } catch {
101
+ return '';
102
+ }
103
+ }
104
+
105
+ export function getGitDiffStat({ cwd = process.cwd() } = {}) {
106
+ try {
107
+ return runGit(['diff', '--stat'], { cwd });
108
+ } catch {
109
+ return '';
110
+ }
111
+ }
112
+
113
+ export function getStagedDiffStat({ cwd = process.cwd() } = {}) {
114
+ try {
115
+ return runGit(['diff', '--cached', '--stat'], { cwd });
116
+ } catch {
117
+ return '';
118
+ }
119
+ }
120
+
121
+ export async function confirmAndCommit({
122
+ message,
123
+ beadId,
124
+ cwd = process.cwd(),
125
+ yes = false,
126
+ } = {}) {
127
+ const status = getGitStatus({ cwd });
128
+ const staged = getStagedDiffStat({ cwd });
129
+
130
+ if (!status && !staged) {
131
+ console.error('[beads] No changes to commit');
132
+ return null;
133
+ }
134
+
135
+ console.error('');
136
+ console.error('[beads] Proposed commit:');
137
+ console.error('═══════════════════════════════════════════════');
138
+ console.error(message);
139
+ console.error('═══════════════════════════════════════════════');
140
+
141
+ if (staged) {
142
+ console.error('[beads] Staged changes:');
143
+ console.error(staged);
144
+ }
145
+ if (status) {
146
+ console.error('[beads] Unstaged changes:');
147
+ console.error(status);
148
+ }
149
+ console.error('');
150
+
151
+ const confirmed = await confirm(
152
+ 'Commit these changes?',
153
+ { yes, default: 'n' }
154
+ );
155
+
156
+ if (!confirmed) {
157
+ console.error('[beads] Commit cancelled');
158
+ return null;
159
+ }
160
+
161
+ runGit(['commit', '-m', message], { cwd });
162
+ console.error('[beads] Committed');
163
+ return true;
164
+ }
165
+
166
+ // ---------------------------------------------------------------------------
167
+ // Plan.md sync
168
+ // ---------------------------------------------------------------------------
169
+
170
+ /**
171
+ * Find all bead IDs mentioned in plan.md and their current status.
172
+ * Returns [ [lineNumber, construct-xxx, currentStatus], ... ]
173
+ */
174
+ export function extractBeadsFromPlan(planContent) {
175
+ const lines = planContent.split('\n');
176
+ const beadLines = [];
177
+
178
+ for (let i = 0; i < lines.length; i++) {
179
+ const line = lines[i];
180
+
181
+ // Look for construct-xxx patterns
182
+ const beadMatches = line.match(/(construct-[a-z0-9]+)/g);
183
+ if (!beadMatches) continue;
184
+
185
+ // Parse table row status (if in a table)
186
+ let status = 'unknown';
187
+ const tableMatch = line.match(/\|.*\|.*\|.*\|\s*([^|]+)\s*\|/);
188
+ if (tableMatch) {
189
+ const statusCell = tableMatch[1].trim();
190
+ if (statusCell.match(/^(done|in_progress|pending)$/i)) {
191
+ status = statusCell.toLowerCase();
192
+ }
193
+ }
194
+
195
+ // Look for P0/P1/P2/P3 as well
196
+ const priorityMatch = line.match(/\bP([0-3])\b/);
197
+ const priority = priorityMatch ? `P${priorityMatch[1]}` : null;
198
+
199
+ for (const beadId of beadMatches) {
200
+ beadLines.push({
201
+ line: i + 1,
202
+ content: line,
203
+ beadId,
204
+ status,
205
+ priority,
206
+ });
207
+ }
208
+ }
209
+
210
+ return beadLines;
211
+ }
212
+
213
+ /**
214
+ * Update plan.md based on actual bead status.
215
+ * Returns true if plan.md changed, false otherwise.
216
+ */
217
+ export async function syncPlanWithBeads({ cwd = process.cwd(), dryRun = false } = {}) {
218
+ const planPath = path.join(cwd, PLAN_MD_PATH);
219
+ if (!fs.existsSync(planPath)) {
220
+ console.error(`[beads] No ${PLAN_MD_PATH} found in ${cwd}`);
221
+ return false;
222
+ }
223
+
224
+ const content = fs.readFileSync(planPath, 'utf8');
225
+ const beadLines = extractBeadsFromPlan(content);
226
+ if (!beadLines.length) return false;
227
+
228
+ const lines = content.split('\n');
229
+ let changed = false;
230
+
231
+ for (const bl of beadLines) {
232
+ const { beadId, line: lineIndex } = bl;
233
+ try {
234
+ // Get current bead status
235
+ const bead = await runBdJson(['show', beadId], { cwd, silent: true });
236
+ const actualStatus = bead?.status || 'unknown';
237
+
238
+ // Update line if needed
239
+ const currentLine = lines[lineIndex - 1];
240
+
241
+ // Table format: | task | status | notes |
242
+ if (currentLine.includes('|') && currentLine.includes(beadId)) {
243
+ // Find status column (assume second column for simplicity)
244
+ const parts = currentLine.split('|').map(p => p.trim());
245
+ if (parts.length >= 3) {
246
+ const oldStatus = parts[2].trim();
247
+ if (oldStatus.toLowerCase() !== actualStatus.toLowerCase()) {
248
+ parts[2] = ` ${actualStatus} `;
249
+ const newLine = `|${parts.slice(1).join('|')}|`;
250
+ lines[lineIndex - 1] = newLine;
251
+ changed = true;
252
+ console.error(`[beads] Updated ${beadId}: ${oldStatus} → ${actualStatus}`);
253
+ }
254
+ }
255
+ }
256
+ // Inline format: - construct-xxx (in progress)
257
+ else {
258
+ const statusMatch = currentLine.match(/\(([^)]+)\)/);
259
+ const oldStatus = statusMatch ? statusMatch[1].trim() : '';
260
+ if (oldStatus !== actualStatus) {
261
+ const newLine = currentLine.replace(
262
+ /\([^)]*\)/,
263
+ `(${actualStatus})`
264
+ ) || `${currentLine} (${actualStatus})`;
265
+ lines[lineIndex - 1] = newLine;
266
+ changed = true;
267
+ console.error(`[beads] Updated ${beadId}: ${oldStatus} → ${actualStatus}`);
268
+ }
269
+ }
270
+ } catch (error) {
271
+ console.error(`[beads] Could not fetch ${beadId}: ${error.message}`);
272
+ }
273
+ }
274
+
275
+ if (changed && !dryRun) {
276
+ fs.writeFileSync(planPath, lines.join('\n'), 'utf8');
277
+ console.error(`[beads] Updated ${PLAN_MD_PATH}`);
278
+ }
279
+
280
+ return changed;
281
+ }
282
+
283
+ // ---------------------------------------------------------------------------
284
+ // Handoff automation
285
+ // ---------------------------------------------------------------------------
286
+
287
+ /**
288
+ * Create a handoff file for active beads.
289
+ * Returns the path to the created handoff.
290
+ */
291
+ export async function createHandoff({
292
+ beads = [],
293
+ actor = 'construct',
294
+ summary = 'Session handoff',
295
+ decisions = [],
296
+ nextActions = [],
297
+ risks = [],
298
+ doNotTouch = [],
299
+ cwd = process.cwd(),
300
+ }) {
301
+ const date = new Date().toISOString().split('T')[0];
302
+ const slug = summary
303
+ .toLowerCase()
304
+ .replace(/[^a-z0-9]+/g, '-')
305
+ .replace(/^-|-$/g, '')
306
+ .slice(0, 50);
307
+
308
+ const handoffFileName = `${date}-${slug}.md`;
309
+ const handoffDir = path.join(cwd, HANDOFFS_DIR);
310
+ const handoffPath = path.join(handoffDir, handoffFileName);
311
+
312
+ fs.mkdirSync(handoffDir, { recursive: true });
313
+
314
+ // Gather bead details
315
+ const beadDetails = [];
316
+ for (const beadId of beads) {
317
+ try {
318
+ const bead = await runBdJson(['show', beadId], { cwd, silent: true });
319
+ beadDetails.push({
320
+ id: beadId,
321
+ subject: bead.subject || 'unknown',
322
+ status: bead.status || 'unknown',
323
+ priority: bead.priority || 'P3',
324
+ summary: `${beadId}: ${bead.subject} (${bead.status}, ${bead.priority})`,
325
+ });
326
+ } catch {
327
+ beadDetails.push({ id: beadId, summary: `${beadId}: unknown` });
328
+ }
329
+ }
330
+
331
+ // Build markdown
332
+ const parts = [
333
+ `# Handoff: ${summary}`,
334
+ '',
335
+ `Date: ${date}`,
336
+ `Actor: ${actor}`,
337
+ beads.length ? `Beads: ${beads.join(', ')}` : null,
338
+ '',
339
+ '## Current state',
340
+ '',
341
+ ...beadDetails.map(b => `- ${b.summary}`),
342
+ beadDetails.length === 0 ? '(No beads active)' : '',
343
+ '',
344
+ decisions.length ? '## Recent decisions' : '',
345
+ ...decisions.map(d => d.includes('|') ? d : `- ${d}`),
346
+ '',
347
+ nextActions.length ? '## Next actions' : '',
348
+ ...nextActions.map(a => a.includes('|') ? a : `1. ${a}`),
349
+ '',
350
+ risks.length ? '## Risks' : '',
351
+ ...risks.map(r => r.includes('|') ? r : `- ${r}`),
352
+ '',
353
+ doNotTouch.length ? '## Do not touch' : '',
354
+ ...doNotTouch.map(f => f.includes('|') ? f : `- ${f}`),
355
+ '',
356
+ '## Verification',
357
+ '',
358
+ `- Session completed by ${actor}`,
359
+ `- Beads status synced with ${PLAN_MD_PATH}`,
360
+ beads.length ? `- Handoff attached to ${beads.length} bead(s)` : '',
361
+ ].filter(Boolean);
362
+
363
+ const content = parts.join('\n');
364
+ fs.writeFileSync(handoffPath, content, 'utf8');
365
+
366
+ // Attach handoff to each bead as a note
367
+ for (const beadId of beads) {
368
+ try {
369
+ spawnSync('bd', ['note', beadId, '--message', `Handoff: ${handoffFileName}`], {
370
+ cwd,
371
+ stdio: 'ignore',
372
+ });
373
+ } catch {
374
+ // Ignore note failures
375
+ }
376
+ }
377
+
378
+ console.error(`[beads] Handoff written to ${path.relative(cwd, handoffPath)}`);
379
+ return handoffPath;
380
+ }
381
+
382
+ /**
383
+ * Auto-create handoff based on beads that were worked on this session.
384
+ * Scans `bd list` for beads that were touched within the last hour.
385
+ */
386
+ export async function autoCreateHandoff({ actor = 'unknown', cwd = process.cwd() } = {}) {
387
+ try {
388
+ const beads = await runBdJson(['list', '--json'], { cwd, silent: true });
389
+ const oneHourAgo = new Date(Date.now() - 3600 * 1000).toISOString();
390
+
391
+ const recent = beads.filter(b => {
392
+ const updated = b.updated_at || b.created_at;
393
+ return updated && new Date(updated) > oneHourAgo;
394
+ });
395
+
396
+ if (!recent.length) {
397
+ console.error('[beads] No recent beads to create handoff for');
398
+ return null;
399
+ }
400
+
401
+ const beadIds = recent.slice(0, 5).map(b => b.id);
402
+ const summary = `Session for ${recent[0].subject?.split(' ')[0] || 'work'}`;
403
+
404
+ const decisions = [
405
+ `Used beads client with locking to avoid conflicts`,
406
+ recent.length > 1 ? `Worked on ${recent.length} beads` : 'Focused on single bead',
407
+ ];
408
+
409
+ const nextActions = [
410
+ 'Continue with next ready bead from `bd ready`',
411
+ 'Sync plan.md after bead status changes',
412
+ ];
413
+
414
+ const risks = [
415
+ 'Parallel agent access still requires merge-slot coordination for batch operations',
416
+ ];
417
+
418
+ const handoffPath = await createHandoff({
419
+ beads: beadIds,
420
+ actor,
421
+ summary,
422
+ decisions,
423
+ nextActions,
424
+ risks,
425
+ cwd,
426
+ });
427
+
428
+ return handoffPath;
429
+ } catch (error) {
430
+ console.error(`[beads] Failed to auto‑create handoff: ${error.message}`);
431
+ return null;
432
+ }
433
+ }
434
+
435
+ // ---------------------------------------------------------------------------
436
+ // Hooks
437
+ // ---------------------------------------------------------------------------
438
+
439
+ /**
440
+ * Post‑bead‑update hook that syncs plan.md if bead status changed.
441
+ * Call this after `bd update`, `bd close`, etc.
442
+ */
443
+ export async function postBeadUpdateHook(beadId, { cwd = process.cwd() } = {}) {
444
+ try {
445
+ const changed = await syncPlanWithBeads({ cwd, dryRun: false });
446
+ if (changed) {
447
+ console.error(`[beads] plan.md updated for ${beadId}`);
448
+ }
449
+ } catch (error) {
450
+ console.error(`[beads] Plan sync failed for ${beadId}: ${error.message}`);
451
+ }
452
+ }
453
+
454
+ /**
455
+ * End‑of‑session hook.
456
+ */
457
+ export async function endOfSessionHook({ actor = 'unknown', cwd = process.cwd(), yes = false } = {}) {
458
+ console.error('[beads] Running end‑of‑session hooks…');
459
+
460
+ await syncPlanWithBeads({ cwd });
461
+
462
+ const handoffPath = await autoCreateHandoff({ actor, cwd });
463
+
464
+ let mergeSlotHeld = false;
465
+ try {
466
+ const mergeSlot = await acquireMergeSlot({ cwd, actor });
467
+ mergeSlotHeld = Boolean(mergeSlot?.success);
468
+
469
+ const confirmed = await confirm(
470
+ 'About to push beads changes to remote. Continue?',
471
+ { yes, default: 'n' }
472
+ );
473
+
474
+ if (!confirmed) {
475
+ console.error('[beads] Beads push cancelled by user');
476
+ return handoffPath;
477
+ }
478
+
479
+ await runBd(['dolt', 'push'], { cwd, silent: true, actor });
480
+ console.error('[beads] Beads changes pushed');
481
+ } catch (pushError) {
482
+ console.error(`[beads] dolt push failed: ${pushError.message}`);
483
+ } finally {
484
+ if (mergeSlotHeld) {
485
+ await releaseMergeSlot({ cwd, actor });
486
+ }
487
+ }
488
+
489
+ return handoffPath;
490
+ }
491
+
492
+ // ---------------------------------------------------------------------------
493
+ // CLI entry point (for direct invocation)
494
+ // ---------------------------------------------------------------------------
495
+
496
+ export async function runBeadsAutomationCli(args) {
497
+ const sub = args[0] || 'status';
498
+ const subArgs = args.slice(1);
499
+ const cwd = process.cwd();
500
+ const yes = subArgs.includes('--yes') || subArgs.includes('-y');
501
+
502
+ if (sub === 'sync-plan') {
503
+ const dryRun = subArgs.includes('--dry-run');
504
+ const changed = await syncPlanWithBeads({ cwd, dryRun });
505
+ console.log(changed ? 'plan.md updated' : 'plan.md unchanged');
506
+ return;
507
+ }
508
+
509
+ if (sub === 'create-handoff') {
510
+ const actor = process.env.USER || 'unknown';
511
+ const beads = subArgs.filter(arg => !arg.startsWith('--'));
512
+ const summary = beads.length ? `Working on ${beads[0]}` : 'Session handoff';
513
+
514
+ const handoffPath = await createHandoff({
515
+ beads,
516
+ actor,
517
+ summary,
518
+ cwd,
519
+ });
520
+ console.log(`Created: ${handoffPath}`);
521
+ return;
522
+ }
523
+
524
+ if (sub === 'end-session') {
525
+ const actor = process.env.USER || 'unknown';
526
+ const handoffPath = await endOfSessionHook({ actor, cwd, yes });
527
+ if (handoffPath) {
528
+ console.log(`Session ended. Handoff: ${handoffPath}`);
529
+ } else {
530
+ console.log('Session ended (no handoff generated)');
531
+ }
532
+ return;
533
+ }
534
+
535
+ console.error('Usage:');
536
+ console.error(' sync-plan Sync plan.md with bead status');
537
+ console.error(' create-handoff Create a handoff for given beads');
538
+ console.error(' end-session Run all end‑of‑session hooks');
539
+ console.error('');
540
+ console.error('Options:');
541
+ console.error(' --yes, -y Skip confirmation prompts (for automation)');
542
+ }