@geraldmaron/construct 1.0.0 → 1.0.1

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 +10 -7
  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 +1116 -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 +525 -38
  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,86 @@
1
+ /**
2
+ * lib/telemetry/intent-verifications.mjs — offline log of LLM-vs-keyword
3
+ * routing agreement.
4
+ *
5
+ * Each entry pins the keyword classifier's verdict alongside the fast-tier
6
+ * LLM's verdict so disagreements can be analyzed without gating dispatch
7
+ * on the LLM round-trip. A future tuning pass can replay this log to find
8
+ * flavors with low LLM agreement (candidates for keyword rewording or a
9
+ * confidence-thresholded re-introduction of inline verification).
10
+ *
11
+ * Disable with `CONSTRUCT_INTENT_VERIFY=off` to skip the background call
12
+ * entirely; the dispatch path itself is unaffected either way.
13
+ */
14
+
15
+ import fs from 'node:fs';
16
+ import os from 'node:os';
17
+ import path from 'node:path';
18
+
19
+ export const DEFAULT_LOG_PATH = path.join(os.homedir(), '.cx', 'intent-verifications.jsonl');
20
+
21
+ /**
22
+ * Fire-and-forget append of one verification event.
23
+ *
24
+ * @param {object} event
25
+ * @param {string} event.request — the user request that hit the classifier
26
+ * @param {string} event.specialist — cx-* slug the keyword classifier picked
27
+ * @param {string} event.flavor — flavor the keyword classifier matched
28
+ * @param {boolean} event.keywordVerdict — always true at the call site (the
29
+ * classifier matched; this is the baseline we're comparing against)
30
+ * @param {boolean} event.llmVerdict — what the LLM judge returned
31
+ * @param {boolean} event.agreed — convenience: keywordVerdict === llmVerdict
32
+ * @param {number} event.confidence — 0-1 from the LLM judge
33
+ * @param {string} event.reason — LLM's one-sentence justification
34
+ * @param {string} event.source — 'llm' | 'cache' | 'fallback' | 'disabled' | 'no-flavor'
35
+ * @param {number} event.latencyMs — wall-clock of the LLM call
36
+ * @param {object} [opts]
37
+ * @param {string} [opts.logPath]
38
+ */
39
+ export function logIntentVerification(event, opts = {}) {
40
+ if (!event) return;
41
+ const logPath = opts.logPath || DEFAULT_LOG_PATH;
42
+ const entry = {
43
+ ts: new Date().toISOString(),
44
+ requestExcerpt: String(event.request || '').slice(0, 200),
45
+ specialist: event.specialist,
46
+ flavor: event.flavor,
47
+ keywordVerdict: event.keywordVerdict !== false,
48
+ llmVerdict: Boolean(event.llmVerdict),
49
+ agreed: event.agreed === undefined
50
+ ? (event.keywordVerdict !== false) === Boolean(event.llmVerdict)
51
+ : Boolean(event.agreed),
52
+ confidence: typeof event.confidence === 'number' ? event.confidence : null,
53
+ reason: String(event.reason || '').slice(0, 240),
54
+ source: event.source || 'unknown',
55
+ latencyMs: typeof event.latencyMs === 'number' ? event.latencyMs : null,
56
+ };
57
+
58
+ try {
59
+ fs.mkdirSync(path.dirname(logPath), { recursive: true });
60
+ fs.appendFileSync(logPath, JSON.stringify(entry) + '\n', 'utf8');
61
+ } catch {
62
+ // Telemetry must never throw — the routing path doesn't await us anyway.
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Aggregate a verifications log into agreement stats per (specialist, flavor).
68
+ * Useful for the audit CLI and tests.
69
+ */
70
+ export function summarizeIntentVerifications({ logPath = DEFAULT_LOG_PATH } = {}) {
71
+ if (!fs.existsSync(logPath)) return { totalEvents: 0, byFlavor: {} };
72
+ const lines = fs.readFileSync(logPath, 'utf8').split('\n').filter(Boolean);
73
+ const byFlavor = {};
74
+ for (const line of lines) {
75
+ let entry;
76
+ try { entry = JSON.parse(line); } catch { continue; }
77
+ if (!entry?.specialist || !entry?.flavor) continue;
78
+ const key = `${entry.specialist}/${entry.flavor}`;
79
+ const slot = byFlavor[key] ||= { matches: 0, agreed: 0, disagreed: 0, lastSeen: null };
80
+ slot.matches += 1;
81
+ if (entry.agreed) slot.agreed += 1;
82
+ else slot.disagreed += 1;
83
+ if (entry.ts && (!slot.lastSeen || entry.ts > slot.lastSeen)) slot.lastSeen = entry.ts;
84
+ }
85
+ return { totalEvents: lines.length, byFlavor };
86
+ }
@@ -0,0 +1,350 @@
1
+ /**
2
+ * lib/telemetry/llm-judge.mjs — LLM-as-a-judge evaluation system.
3
+ *
4
+ * Automatically evaluates agent work by:
5
+ * 1. Sampling traces that lack scores
6
+ * 2. Using an LLM to score quality based on the task and output
7
+ * 3. Recording scores back to the telemetry backend for continuous improvement
8
+ *
9
+ * Evaluation criteria includes:
10
+ * - Task completion accuracy (did it solve the problem?)
11
+ * - Code quality (if applicable)
12
+ * - Adherence to requirements
13
+ * - Best practices followed
14
+ * - Documentation completeness
15
+ * - Error handling robustness
16
+ */
17
+
18
+ import { homedir } from 'node:os';
19
+ import { addObservation } from '../observation-store.mjs';
20
+ import { loadConstructEnv } from '../env-config.mjs';
21
+
22
+ const CONF_ENV = loadConstructEnv({ warn: false });
23
+
24
+ function telemetryHeaders() {
25
+ const key = CONF_ENV.CONSTRUCT_TELEMETRY_PUBLIC_KEY ?? process.env.CONSTRUCT_TELEMETRY_PUBLIC_KEY;
26
+ const secret = CONF_ENV.CONSTRUCT_TELEMETRY_SECRET_KEY ?? process.env.CONSTRUCT_TELEMETRY_SECRET_KEY;
27
+ if (!key || !secret) throw new Error('CONSTRUCT_TELEMETRY_PUBLIC_KEY and CONSTRUCT_TELEMETRY_SECRET_KEY must be set.');
28
+ return {
29
+ Authorization: `Basic ${Buffer.from(`${key}:${secret}`).toString('base64')}`,
30
+ 'Content-Type': 'application/json',
31
+ };
32
+ }
33
+
34
+ function telemetryBaseUrl() {
35
+ return (CONF_ENV.CONSTRUCT_TELEMETRY_URL ?? process.env.CONSTRUCT_TELEMETRY_URL ?? '').replace(/\/$/, '');
36
+ }
37
+
38
+ /**
39
+ * Fetch recent traces that have no scores yet
40
+ */
41
+ async function fetchUnscoredTraces({ url, headers, limit = 50, fetchImpl = globalThis.fetch }) {
42
+ // First get recent traces
43
+ const recentRes = await fetchImpl(`${url}/api/public/traces?limit=${limit * 2}&orderBy=timestamp.desc`, { headers });
44
+ if (!recentRes.ok) throw new Error(`Telemetry traces fetch ${recentRes.status}`);
45
+ const recentJson = await recentRes.json().catch(() => ({}));
46
+ const recentTraces = Array.isArray(recentJson.data) ? recentJson.data : [];
47
+
48
+ // Get scores to filter out already-scored traces
49
+ const scoresRes = await fetchImpl(`${url}/api/public/scores?name=quality&limit=100`, { headers });
50
+ if (!scoresRes.ok) throw new Error(`Telemetry scores fetch ${scoresRes.status}`);
51
+ const scoresJson = await scoresRes.json().catch(() => ({}));
52
+ const scoredTraceIds = new Set((Array.isArray(scoresJson.data) ? scoresJson.data : [])
53
+ .map(s => s.traceId)
54
+ .filter(Boolean));
55
+
56
+ // Filter to traces without scores
57
+ const unscored = recentTraces
58
+ .filter(trace => !scoredTraceIds.has(trace.id))
59
+ .slice(0, limit);
60
+
61
+ return unscored;
62
+ }
63
+
64
+ /**
65
+ * Build evaluation prompt for the LLM judge
66
+ */
67
+ function buildEvaluationPrompt(trace, metadata = {}) {
68
+ const agentName = trace?.metadata?.agentName || trace?.name || 'unknown';
69
+ const task = typeof trace.input === 'string' ? trace.input : JSON.stringify(trace.input || '');
70
+ const output = typeof trace.output === 'string' ? trace.output : JSON.stringify(trace.output || '');
71
+
72
+ const isCodeTask = task.toLowerCase().includes('code') ||
73
+ task.toLowerCase().includes('implement') ||
74
+ task.toLowerCase().includes('fix') ||
75
+ task.toLowerCase().includes('write');
76
+
77
+ const criteria = isCodeTask ? `
78
+ Rate this code implementation on a scale of 0.0 (complete failure) to 1.0 (perfect):
79
+ 1. **Task Completion (0.3 weight)**: Did it solve the exact problem stated?
80
+ 2. **Code Quality (0.25 weight)**: Clean, readable, follows best practices?
81
+ 3. **Requirements Adherence (0.2 weight)**: Followed all specifications/constraints?
82
+ 4. **Robustness (0.15 weight)**: Handles edge cases, proper error handling?
83
+ 5. **Documentation (0.1 weight)**: Comments, clarity, maintainability?
84
+ ` : `
85
+ Rate this agent work on a scale of 0.0 (complete failure) to 1.0 (perfect):
86
+ 1. **Task Completion (0.4 weight)**: Did it solve the exact problem stated?
87
+ 2. **Requirements Adherence (0.3 weight)**: Followed all specifications/constraints?
88
+ 3. **Clarity & Quality (0.2 weight)**: Clear, well-structured, professional?
89
+ 4. **Thoroughness (0.1 weight)**: Complete, covers all aspects needed?
90
+ `;
91
+
92
+ const responseFormat = `Return ONLY a JSON object with:
93
+ {
94
+ "score": 0.85, // numeric score 0.0-1.0
95
+ "comment": "Brief explanation of the score",
96
+ "category": "quality",
97
+ "breakdown": {
98
+ "task_completion": 0.9,
99
+ "code_quality": 0.8,
100
+ "requirements_adherence": 0.9,
101
+ "robustness": 0.7,
102
+ "documentation": 0.8
103
+ }
104
+ }`;
105
+
106
+ return {
107
+ system: `You are an expert quality evaluator for AI agent work. Evaluate the work objectively based on the criteria.`,
108
+ user: `# Agent Task
109
+ Agent: ${agentName}
110
+ Task: ${task}
111
+
112
+ # Agent Output
113
+ ${output}
114
+
115
+ # Evaluation Criteria
116
+ ${criteria}
117
+
118
+ # Instructions
119
+ ${responseFormat}
120
+
121
+ # Additional Context
122
+ ${metadata?.workCategory ? `Work category: ${metadata.workCategory}` : ''}
123
+ ${metadata?.routeIntent ? `Intent: ${metadata.routeIntent}` : ''}
124
+ ${trace?.metadata?.goal ? `Goal: ${trace.metadata.goal}` : ''}`,
125
+ };
126
+ }
127
+
128
+ /**
129
+ * Call LLM for evaluation
130
+ */
131
+ async function callLLMJudge(prompt, { model = 'claude-3-5-sonnet-20241022', apiKey, baseUrl = 'https://api.anthropic.com' }) {
132
+ const headers = {
133
+ 'x-api-key': apiKey,
134
+ 'anthropic-version': '2023-06-01',
135
+ 'content-type': 'application/json',
136
+ };
137
+
138
+ const body = {
139
+ model,
140
+ max_tokens: 1000,
141
+ messages: [
142
+ { role: 'system', content: prompt.system },
143
+ { role: 'user', content: prompt.user },
144
+ ],
145
+ temperature: 0.1,
146
+ };
147
+
148
+ const res = await fetch(`${baseUrl}/v1/messages`, {
149
+ method: 'POST',
150
+ headers,
151
+ body: JSON.stringify(body),
152
+ });
153
+
154
+ if (!res.ok) {
155
+ const errorText = await res.text().catch(() => '');
156
+ throw new Error(`LLM API error ${res.status}: ${errorText.slice(0, 200)}`);
157
+ }
158
+
159
+ const data = await res.json();
160
+ const content = data.content?.[0]?.text || '';
161
+
162
+ // Parse JSON from response
163
+ try {
164
+ const jsonMatch = content.match(/\{[\s\S]*\}/);
165
+ if (jsonMatch) {
166
+ return JSON.parse(jsonMatch[0]);
167
+ }
168
+ // Fallback: try to extract score
169
+ const scoreMatch = content.match(/"score":\s*([0-9.]+)/);
170
+ const commentMatch = content.match(/"comment":\s*"([^"]+)"/);
171
+ return {
172
+ score: scoreMatch ? parseFloat(scoreMatch[1]) : 0.5,
173
+ comment: commentMatch ? commentMatch[1] : 'Could not parse evaluation',
174
+ category: 'quality',
175
+ };
176
+ } catch (err) {
177
+ return {
178
+ score: 0.5,
179
+ comment: `Failed to parse LLM response: ${err.message}`,
180
+ category: 'quality',
181
+ };
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Score a trace using LLM judge
187
+ */
188
+ async function scoreTraceWithLLM(trace, { llmApiKey, llmModel, fetchImpl = globalThis.fetch }) {
189
+ if (!llmApiKey) {
190
+ throw new Error('LLM API key required for judge evaluations');
191
+ }
192
+
193
+ const prompt = buildEvaluationPrompt(trace, trace.metadata);
194
+ const evaluation = await callLLMJudge(prompt, {
195
+ model: llmModel || 'claude-3-5-sonnet-20241022',
196
+ apiKey: llmApiKey,
197
+ });
198
+
199
+ return {
200
+ traceId: trace.id,
201
+ score: evaluation.score,
202
+ comment: evaluation.comment,
203
+ breakdown: evaluation.breakdown,
204
+ metadata: {
205
+ evaluatedAt: new Date().toISOString(),
206
+ evaluatorModel: llmModel || 'claude-3-5-sonnet-20241022',
207
+ source: 'llm-judge',
208
+ },
209
+ };
210
+ }
211
+
212
+ /**
213
+ * Post score to telemetry backend
214
+ */
215
+ async function postScoreToTelemetry({ url, headers, scoreData, fetchImpl = globalThis.fetch }) {
216
+ const body = {
217
+ id: crypto.randomUUID(),
218
+ traceId: scoreData.traceId,
219
+ name: 'quality',
220
+ value: scoreData.score,
221
+ dataType: 'NUMERIC',
222
+ comment: scoreData.comment,
223
+ metadata: scoreData.metadata,
224
+ };
225
+
226
+ const res = await fetchImpl(`${url}/api/public/scores`, {
227
+ method: 'POST',
228
+ headers,
229
+ body: JSON.stringify(body),
230
+ });
231
+
232
+ if (!res.ok) {
233
+ const text = await res.text().catch(() => '');
234
+ throw new Error(`Telemetry score post ${res.status}: ${text.slice(0, 200)}`);
235
+ }
236
+
237
+ return res.json().catch(() => ({}));
238
+ }
239
+
240
+ /**
241
+ * Record evaluation observation for learning
242
+ */
243
+ function recordEvaluationObservation(scoreData, trace) {
244
+ const rootDir = homedir();
245
+ const agentName = trace?.metadata?.agentName || trace?.name || 'construct';
246
+
247
+ addObservation(rootDir, {
248
+ role: 'llm-judge',
249
+ category: 'evaluation',
250
+ summary: `LLM judge scored ${agentName} work at ${scoreData.score.toFixed(2)}: ${scoreData.comment.slice(0, 100)}`,
251
+ content: `Trace: ${scoreData.traceId}
252
+ Score: ${scoreData.score}
253
+ Comment: ${scoreData.comment}
254
+ Agent: ${agentName}
255
+ Task: ${typeof trace.input === 'string' ? trace.input.slice(0, 500) : 'N/A'}
256
+ Evaluator: ${scoreData.metadata.evaluatorModel}
257
+ Breakdown: ${JSON.stringify(scoreData.breakdown || {}, null, 2)}`,
258
+ tags: ['llm-judge', 'quality-score', agentName, 'auto-evaluated'],
259
+ confidence: 0.9,
260
+ source: 'llm-judge',
261
+ });
262
+ }
263
+
264
+ /**
265
+ * Main entrypoint: Run LLM judge evaluations on unscored traces
266
+ */
267
+ export async function runLLMJudgeEvaluations({
268
+ publicKey = CONF_ENV.CONSTRUCT_TELEMETRY_PUBLIC_KEY ?? process.env.CONSTRUCT_TELEMETRY_PUBLIC_KEY,
269
+ secretKey = CONF_ENV.CONSTRUCT_TELEMETRY_SECRET_KEY ?? process.env.CONSTRUCT_TELEMETRY_SECRET_KEY,
270
+ llmApiKey = CONF_ENV.ANTHROPIC_API_KEY ?? process.env.ANTHROPIC_API_KEY,
271
+ llmModel = 'claude-3-5-sonnet-20241022',
272
+ limit = 10,
273
+ bestEffort = true,
274
+ fetchImpl = globalThis.fetch,
275
+ } = {}) {
276
+ if (!publicKey || !secretKey) {
277
+ return { evaluated: 0, errors: ['Telemetry credentials not configured'] };
278
+ }
279
+
280
+ if (!llmApiKey) {
281
+ return { evaluated: 0, errors: ['LLM API key (ANTHROPIC_API_KEY) required for judge evaluations'] };
282
+ }
283
+
284
+ const url = telemetryBaseUrl();
285
+ const headers = telemetryHeaders();
286
+ const errors = [];
287
+ let evaluated = 0;
288
+
289
+ try {
290
+ // Get unscored traces
291
+ const unscoredTraces = await fetchUnscoredTraces({ url, headers, limit, fetchImpl });
292
+
293
+ for (const trace of unscoredTraces) {
294
+ try {
295
+ // Score with LLM
296
+ const scoreData = await scoreTraceWithLLM(trace, { llmApiKey, llmModel, fetchImpl });
297
+
298
+ // Post score to telemetry backend
299
+ await postScoreToTelemetry({ url, headers, scoreData, fetchImpl });
300
+
301
+ // Record observation for learning
302
+ recordEvaluationObservation(scoreData, trace);
303
+
304
+ evaluated++;
305
+
306
+ } catch (err) {
307
+ if (bestEffort) {
308
+ errors.push(`${trace?.id}: ${err.message}`);
309
+ } else {
310
+ throw err;
311
+ }
312
+ }
313
+ }
314
+
315
+ } catch (err) {
316
+ if (bestEffort) {
317
+ errors.push(`Initialization error: ${err.message}`);
318
+ } else {
319
+ throw err;
320
+ }
321
+ }
322
+
323
+ return { evaluated, errors };
324
+ }
325
+
326
+ /**
327
+ * CLI entrypoint
328
+ */
329
+ export async function runLLMJudgeCli(args = []) {
330
+ const limitArg = args.find((a) => a.startsWith('--limit='));
331
+ const limit = limitArg ? parseInt(limitArg.split('=')[1], 10) || 10 : 10;
332
+
333
+ const modelArg = args.find((a) => a.startsWith('--model='));
334
+ const model = modelArg ? modelArg.split('=')[1] : 'claude-3-5-sonnet-20241022';
335
+
336
+ process.stdout.write(`Running LLM judge evaluations (limit: ${limit}, model: ${model})…\n`);
337
+
338
+ const result = await runLLMJudgeEvaluations({
339
+ limit,
340
+ llmModel: model,
341
+ bestEffort: false,
342
+ });
343
+
344
+ process.stdout.write(`Done. evaluated=${result.evaluated}${result.errors.length ? ` errors=${result.errors.length}` : ''}\n`);
345
+ if (result.errors.length) {
346
+ for (const e of result.errors) process.stderr.write(` ${e}\n`);
347
+ }
348
+
349
+ return result;
350
+ }