@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,518 @@
1
+ /**
2
+ * lib/beads-client.mjs — Wrapper for bd commands with lock‑management and queueing.
3
+ *
4
+ * VERSION 2.0: Now uses optimistic locking by default for better concurrency.
5
+ * All external bd calls should go through `runBd()` to ensure serialized access
6
+ * to the embedded Dolt database.
7
+ *
8
+ * Changes:
9
+ * - Reads are now lock-free (concurrent safe)
10
+ * - Writes use optimistic locking with automatic retry
11
+ * - Legacy file-based lock is fallback only
12
+ * - Better error messages and conflict resolution
13
+ */
14
+
15
+ import { spawnSync } from 'node:child_process';
16
+ import fs from 'node:fs';
17
+ import path from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+
20
+ import {
21
+ acquireLock,
22
+ releaseLock,
23
+ getLockStatus,
24
+ cleanupStaleLock,
25
+ enqueueRequest,
26
+ removeFromQueue,
27
+ readQueue,
28
+ cleanupStaleQueue,
29
+ } from './beads-lock.mjs';
30
+
31
+ import {
32
+ concurrentRead,
33
+ optimisticWrite,
34
+ batchReadBeads,
35
+ updateBeadOptimistic,
36
+ claimBeadOptimistic,
37
+ shouldUseOptimisticLocking,
38
+ recordOperationStats,
39
+ } from './beads-optimistic.mjs';
40
+
41
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
42
+
43
+ // ---------------------------------------------------------------------------
44
+ // Configuration and defaults
45
+ // ---------------------------------------------------------------------------
46
+
47
+ const DEFAULT_OPTIONS = {
48
+ actor: 'construct',
49
+ silent: false,
50
+ timeoutSeconds: 30, // Time to wait for lock before giving up
51
+ commandTimeoutSeconds: 120, // Max runtime for the bd child process
52
+ queuePollMs: 100, // How often to check for lock release when queued
53
+ maxQueueWaitSeconds: 300, // Max total time allowed in queue
54
+ useOptimisticLocking: true, // NEW: Use optimistic locking by default
55
+ fallbackToLegacy: true, // NEW: Fall back to legacy locking on failure
56
+ maxRetries: 5, // NEW: Max retries for optimistic locking
57
+ };
58
+
59
+ // Track which operations are reads vs writes
60
+ const READ_OPERATIONS = new Set([
61
+ 'list', 'show', 'ready', 'search', 'merge-slot', 'check',
62
+ 'status', 'log', 'diff', 'note',
63
+ ]);
64
+
65
+ const WRITE_OPERATIONS = new Set([
66
+ 'create', 'update', 'close', 'claim', 'note', 'label',
67
+ 'assign', 'link', 'unlink', 'move', 'archive',
68
+ ]);
69
+
70
+ // ---------------------------------------------------------------------------
71
+ // Operation classification
72
+ // ---------------------------------------------------------------------------
73
+
74
+ function isReadOperation(args) {
75
+ if (!args || args.length === 0) return true;
76
+ const cmd = args[0];
77
+ return READ_OPERATIONS.has(cmd) || !WRITE_OPERATIONS.has(cmd);
78
+ }
79
+
80
+ function isWriteOperation(args) {
81
+ if (!args || args.length === 0) return false;
82
+ const cmd = args[0];
83
+ return WRITE_OPERATIONS.has(cmd);
84
+ }
85
+
86
+ function extractBeadId(args) {
87
+ // Try to find a bead ID in the arguments (typically the second arg)
88
+ if (args.length >= 2 && args[1] && !args[1].startsWith('--')) {
89
+ return args[1];
90
+ }
91
+ return null;
92
+ }
93
+
94
+ // ---------------------------------------------------------------------------
95
+ // Core wrapper with optimistic locking support
96
+ // ---------------------------------------------------------------------------
97
+
98
+ /**
99
+ * Run a bd command with appropriate locking strategy.
100
+ *
101
+ * STRATEGY:
102
+ * 1. Read operations: Lock-free concurrent execution
103
+ * 2. Write operations: Optimistic locking with retry
104
+ * 3. Legacy lock: Fallback only when optimistic fails
105
+ *
106
+ * @param {string[]} args - Arguments for `bd`
107
+ * @param {Object} [options]
108
+ * @param {string} options.actor - Who is running this (for logging)
109
+ * @param {number} options.timeoutSeconds - Max seconds to wait for lock
110
+ * @param {number} options.commandTimeoutSeconds - Max seconds to let bd run after lock acquisition
111
+ * @param {boolean} options.silent - Suppress logging of success/queue status
112
+ * @param {boolean} options.useOptimisticLocking - Use optimistic locking (default: true)
113
+ * @param {boolean} options.fallbackToLegacy - Fall back to legacy lock on failure (default: true)
114
+ * @param {number} options.maxRetries - Max retries for optimistic locking (default: 5)
115
+ * @param {string} options.cwd - Working directory (default: process.cwd())
116
+ * @returns {Object} { success: boolean, output: string, error?: string, attempts?: number, method?: string }
117
+ */
118
+ export async function runBd(args, options = {}) {
119
+ const opts = { ...DEFAULT_OPTIONS, ...options };
120
+ const cwd = opts.cwd || process.cwd();
121
+ const commandDesc = args.join(' ');
122
+ const isRead = isReadOperation(args);
123
+ const beadId = extractBeadId(args);
124
+
125
+ if (!opts.silent) {
126
+ const opType = isRead ? 'read' : 'write';
127
+ console.error(`[beads] ${opts.actor} ${opType}: bd ${commandDesc}`);
128
+ }
129
+
130
+ // ==========================================================================
131
+ // PATH 1: Lock-free reads (fastest, most concurrent)
132
+ // ==========================================================================
133
+ if (isRead && opts.useOptimisticLocking) {
134
+ const startTime = Date.now();
135
+
136
+ const result = spawnSync('bd', args, {
137
+ cwd,
138
+ encoding: 'utf8',
139
+ env: { ...process.env, BEADS_ACTOR: opts.actor },
140
+ timeout: Math.max(1, Math.round(opts.commandTimeoutSeconds * 1000)),
141
+ });
142
+
143
+ const execTime = Date.now() - startTime;
144
+
145
+ // Handle timeout error
146
+ if (result.error?.code === 'ETIMEDOUT') {
147
+ return {
148
+ success: false,
149
+ error: `bd ${commandDesc} timed out after ${opts.commandTimeoutSeconds}s`,
150
+ exitCode: null,
151
+ execTimeMs: execTime,
152
+ method: 'concurrent-read',
153
+ };
154
+ }
155
+
156
+ if (!opts.silent) {
157
+ console.error(`[beads] ✓ Read completed in ${execTime}ms (lock-free)`);
158
+ }
159
+
160
+ return {
161
+ success: result.status === 0 && !result.error,
162
+ output: result.stdout,
163
+ error: result.stderr || result.error?.message,
164
+ exitCode: result.status,
165
+ execTimeMs: execTime,
166
+ method: 'concurrent-read',
167
+ };
168
+ }
169
+
170
+ // ==========================================================================
171
+ // PATH 2: Optimistic locking for writes (scalable, conflict-resistant)
172
+ // ==========================================================================
173
+ if (!isRead && opts.useOptimisticLocking && shouldUseOptimisticLocking()) {
174
+ const startTime = Date.now();
175
+
176
+ const result = await optimisticWrite({
177
+ beadId: beadId || 'unknown',
178
+ cwd,
179
+ maxRetries: opts.maxRetries,
180
+ execute: async () => {
181
+ const execResult = spawnSync('bd', args, {
182
+ cwd,
183
+ encoding: 'utf8',
184
+ env: { ...process.env, BEADS_ACTOR: opts.actor },
185
+ timeout: Math.max(1, Math.round(opts.commandTimeoutSeconds * 1000)),
186
+ });
187
+
188
+ if (execResult.status !== 0) {
189
+ throw new Error(execResult.stderr || 'Command failed');
190
+ }
191
+
192
+ return execResult.stdout;
193
+ },
194
+ });
195
+
196
+ const totalTime = Date.now() - startTime;
197
+
198
+ recordOperationStats(commandDesc, result, cwd);
199
+
200
+ if (result.success) {
201
+ if (!opts.silent) {
202
+ console.error(`[beads] ✓ Write completed in ${totalTime}ms (optimistic, ${result.attempts} attempt${result.attempts !== 1 ? 's' : ''})`);
203
+ }
204
+ return {
205
+ success: true,
206
+ output: result.result,
207
+ attempts: result.attempts,
208
+ execTimeMs: totalTime,
209
+ method: 'optimistic-locking',
210
+ };
211
+ }
212
+
213
+ // Optimistic locking failed
214
+ if (!opts.fallbackToLegacy) {
215
+ return {
216
+ success: false,
217
+ error: result.error,
218
+ attempts: result.attempts,
219
+ method: 'optimistic-locking',
220
+ };
221
+ }
222
+
223
+ if (!opts.silent) {
224
+ console.error(`[beads] ⚠ Optimistic locking failed: ${result.error}`);
225
+ console.error(`[beads] ↘ Falling back to legacy lock...`);
226
+ }
227
+ }
228
+
229
+ // ==========================================================================
230
+ // PATH 3: Legacy file-based locking (fallback, most conservative)
231
+ // ==========================================================================
232
+ return runWithLegacyLock(args, opts, cwd, commandDesc);
233
+ }
234
+
235
+ /**
236
+ * Legacy locking implementation (original behavior).
237
+ * Used as fallback when optimistic locking fails.
238
+ */
239
+ async function runWithLegacyLock(args, opts, cwd, commandDesc) {
240
+ // Clean up any stale locks before trying
241
+ cleanupStaleLock({ cwd });
242
+ cleanupStaleQueue({ cwd });
243
+
244
+ // Try to acquire the lock
245
+ const startWait = Date.now();
246
+ const lock = await acquireLock({
247
+ actor: opts.actor,
248
+ command: commandDesc,
249
+ timeoutSeconds: opts.timeoutSeconds,
250
+ cwd,
251
+ });
252
+
253
+ if (!lock) {
254
+ // Failed to get lock; add to queue if allowed
255
+ const maxQueueWaitMs = opts.maxQueueWaitSeconds * 1000;
256
+ if (Date.now() - startWait + maxQueueWaitMs > maxQueueWaitMs) {
257
+ return {
258
+ success: false,
259
+ error: `Timeout waiting for lock after ${opts.timeoutSeconds}s`,
260
+ queued: false,
261
+ method: 'legacy-lock',
262
+ };
263
+ }
264
+
265
+ const queueEntry = enqueueRequest({
266
+ actor: opts.actor,
267
+ command: commandDesc,
268
+ args,
269
+ cwd,
270
+ });
271
+
272
+ if (!opts.silent) {
273
+ console.error(`[beads] ↘ Added to queue (position ${readQueue({ cwd }).length})`);
274
+ }
275
+
276
+ // Wait in queue, polling periodically
277
+ while (Date.now() - startWait < opts.maxQueueWaitSeconds * 1000) {
278
+ await new Promise((resolve) => setTimeout(resolve, opts.queuePollMs));
279
+
280
+ cleanupStaleLock({ cwd });
281
+ const status = getLockStatus({ cwd });
282
+ if (!status.locked) {
283
+ // Lock free, remove from queue and try again
284
+ removeFromQueue(queueEntry.timestamp || queueEntry.pid, { cwd });
285
+ return await runBd(args, { ...opts, silent: true });
286
+ }
287
+ }
288
+
289
+ // Queue timeout
290
+ removeFromQueue(queueEntry.timestamp || queueEntry.pid, { cwd });
291
+ return {
292
+ success: false,
293
+ error: `Timeout in queue after ${opts.maxQueueWaitSeconds}s`,
294
+ queued: true,
295
+ waitTimeMs: Date.now() - startWait,
296
+ method: 'legacy-lock',
297
+ };
298
+ }
299
+
300
+ const execStart = Date.now();
301
+ let result;
302
+ try {
303
+ result = spawnSync('bd', args, {
304
+ cwd,
305
+ encoding: 'utf8',
306
+ env: { ...process.env, BEADS_ACTOR: opts.actor },
307
+ killSignal: 'SIGTERM',
308
+ timeout: Math.max(1, Math.round(opts.commandTimeoutSeconds * 1000)),
309
+ });
310
+ } finally {
311
+ releaseLock({ cwd });
312
+ }
313
+
314
+ const totalTime = Date.now() - startWait;
315
+ const execTime = Date.now() - execStart;
316
+
317
+ if (!opts.silent) {
318
+ console.error(`[beads] ✓ Executed in ${execTime}ms (legacy lock, total: ${totalTime}ms)`);
319
+ }
320
+
321
+ return {
322
+ success: result.status === 0 && !result.error,
323
+ output: result.stdout,
324
+ error: result.error?.code === 'ETIMEDOUT'
325
+ ? `bd ${commandDesc} timed out after ${opts.commandTimeoutSeconds}s`
326
+ : (result.stderr || result.error?.message),
327
+ exitCode: result.status,
328
+ waitTimeMs: execStart - startWait,
329
+ execTimeMs: execTime,
330
+ totalTimeMs: totalTime,
331
+ method: 'legacy-lock',
332
+ };
333
+ }
334
+
335
+ // ---------------------------------------------------------------------------
336
+ // Higher‑level convenience functions (enhanced with optimistic locking)
337
+ // ---------------------------------------------------------------------------
338
+
339
+ /**
340
+ * Quick wrapper that returns parsed JSON output.
341
+ * Uses concurrent read (no locking) for better performance.
342
+ */
343
+ export async function runBdJson(args, options = {}) {
344
+ const result = await runBd([...args, '--json'], { ...options, useOptimisticLocking: true });
345
+ if (!result.success) {
346
+ throw new Error(`bd failed: ${result.error}`);
347
+ }
348
+ try {
349
+ return JSON.parse(result.output);
350
+ } catch (e) {
351
+ throw new Error(`Failed to parse JSON from bd: ${e.message}\n${result.output}`);
352
+ }
353
+ }
354
+
355
+ /**
356
+ * Get issue list (commonly used).
357
+ * Uses concurrent reads for better performance.
358
+ */
359
+ export async function listIssues(options = {}) {
360
+ return runBdJson(['list'], { useOptimisticLocking: true, ...options });
361
+ }
362
+
363
+ /**
364
+ * Show a specific issue.
365
+ * Uses concurrent read (no locking needed).
366
+ */
367
+ export async function showIssue(id, options = {}) {
368
+ return runBdJson(['show', id], { useOptimisticLocking: true, ...options });
369
+ }
370
+
371
+ /**
372
+ * Claim an issue with optimistic locking.
373
+ * Uses optimistic locking for better concurrency.
374
+ */
375
+ export async function claimIssue(id, options = {}) {
376
+ // Use the specialized optimistic claim function
377
+ const result = await claimBeadOptimistic(id, options);
378
+
379
+ if (result.success) {
380
+ return { success: true, output: JSON.stringify(result.result) };
381
+ }
382
+
383
+ // Fall back to legacy
384
+ return runBd(['update', id, '--claim'], { ...options, useOptimisticLocking: false });
385
+ }
386
+
387
+ /**
388
+ * Close an issue.
389
+ */
390
+ export async function closeIssue(id, options = {}) {
391
+ return runBd(['close', id], options);
392
+ }
393
+
394
+ /**
395
+ * Check ready issues.
396
+ * Uses concurrent read (no locking needed).
397
+ */
398
+ export async function getReadyIssues(options = {}) {
399
+ return runBdJson(['ready'], { useOptimisticLocking: true, ...options });
400
+ }
401
+
402
+ /**
403
+ * Check merge‑slot availability.
404
+ * Uses concurrent read.
405
+ */
406
+ export async function getMergeSlotStatus(options = {}) {
407
+ return runBd(['merge-slot', 'check'], { silent: true, useOptimisticLocking: true, ...options });
408
+ }
409
+
410
+ /**
411
+ * Try to acquire merge‑slot (with fallback if it doesn't exist).
412
+ * Uses optimistic locking for the acquire operation.
413
+ */
414
+ export async function acquireMergeSlot(options = {}) {
415
+ const { success, error } = await runBd(['merge-slot', 'acquire'], {
416
+ silent: true,
417
+ useOptimisticLocking: true,
418
+ ...options
419
+ });
420
+
421
+ if (!success && error?.includes('merge slot bead')) {
422
+ // Slot might not exist; create it first
423
+ await runBd(['merge-slot', 'create'], { silent: true, useOptimisticLocking: true, ...options });
424
+ return runBd(['merge-slot', 'acquire'], { silent: true, useOptimisticLocking: true, ...options });
425
+ }
426
+
427
+ return { success, error };
428
+ }
429
+
430
+ /**
431
+ * Release merge‑slot.
432
+ */
433
+ export async function releaseMergeSlot(options = {}) {
434
+ return runBd(['merge-slot', 'release'], { silent: true, useOptimisticLocking: true, ...options });
435
+ }
436
+
437
+ /**
438
+ * Batch read multiple issues efficiently.
439
+ * NEW: Concurrent batch reading for better performance.
440
+ */
441
+ export async function batchShowIssues(ids, options = {}) {
442
+ return batchReadBeads(ids, options.cwd || process.cwd());
443
+ }
444
+
445
+ // ---------------------------------------------------------------------------
446
+ // Status and utility exports
447
+ // ---------------------------------------------------------------------------
448
+
449
+ export { getLockStatus, cleanupStaleLock, cleanupStaleQueue, readQueue } from './beads-lock.mjs';
450
+ export {
451
+ getContentionStats,
452
+ recordOperationStats,
453
+ shouldUseOptimisticLocking
454
+ } from './beads-optimistic.mjs';
455
+
456
+ /**
457
+ * Shortcut to get current queue length.
458
+ */
459
+ export function getQueueLength(cwd = process.cwd()) {
460
+ return readQueue({ cwd }).length;
461
+ }
462
+
463
+ /**
464
+ * Get human‑readable status string (lock + queue + contention stats).
465
+ * ENHANCED: Now includes optimistic locking statistics.
466
+ */
467
+ export async function getHumanStatus(cwd = process.cwd()) {
468
+ const status = getLockStatus({ cwd });
469
+
470
+ let out = '';
471
+
472
+ // Optimistic locking status
473
+ out += 'Locking Strategy:\n';
474
+ out += ` Mode: ${shouldUseOptimisticLocking() ? 'Optimistic (concurrent reads + versioned writes)' : 'Legacy (exclusive locks)'}\n`;
475
+
476
+ // Try to get stats if available
477
+ try {
478
+ const { getContentionStats } = await import('./beads-optimistic.mjs');
479
+ const stats = await getContentionStats(cwd);
480
+ if (stats.totalOperations > 0) {
481
+ out += ` Operations: ${stats.totalOperations}\n`;
482
+ out += ` Conflicts: ${stats.conflicts} (${((stats.conflicts / stats.totalOperations) * 100).toFixed(1)}%)\n`;
483
+ out += ` Avg attempts: ${stats.avgAttempts?.toFixed(2) || '1.00'}\n`;
484
+ }
485
+ } catch {
486
+ // Stats not available, skip
487
+ }
488
+
489
+ out += '\n';
490
+
491
+ // Legacy lock status (for debugging)
492
+ if (status.lock) {
493
+ const { lock } = status;
494
+ out += `Legacy Lock:\n`;
495
+ out += ` Held by: ${lock.actor} (pid ${lock.pid})\n`;
496
+ out += ` Command: ${lock.command}\n`;
497
+ out += ` Started: ${lock.startedAt}${lock.alive ? '' : ' ⚠️ process dead'}\n`;
498
+ } else if (status.nativeLock) {
499
+ const { nativeLock } = status;
500
+ out += `Native Lock:\n`;
501
+ out += ` Held by: ${nativeLock.command} (pid ${nativeLock.pid})\n`;
502
+ } else {
503
+ out += 'No lock held\n';
504
+ }
505
+
506
+ const queue = readQueue({ cwd });
507
+ if (queue.length) {
508
+ out += `\nQueue (${queue.length} waiting):\n`;
509
+ queue.forEach((entry, idx) => {
510
+ const alive = entry.pid && (() => {
511
+ try { process.kill(entry.pid, 0); return true; } catch { return false; }
512
+ })();
513
+ out += ` ${idx + 1}. ${entry.actor} – ${entry.command || entry.args?.join(' ')}${alive ? '' : ' ⚠️ dead'}\n`;
514
+ });
515
+ }
516
+
517
+ return out;
518
+ }