@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,449 @@
1
+ /**
2
+ * lib/embed/demand-fetch.mjs — on-demand provider snapshot.
3
+ *
4
+ * Fires a targeted one-shot snapshot for a named source when knowledge is
5
+ * stale or absent. Triggered by the MCP `provider_fetch` tool when Construct
6
+ * detects a user question names a known configured repo or project.
7
+ *
8
+ * Design:
9
+ * - Resolves source config from env (same path as the daemon's auto-discovery)
10
+ * - Matches a query string against known repo names, project keys, and aliases
11
+ * - Runs a single provider.read() call for the matched source
12
+ * - Writes results as observations into the knowledge base
13
+ * - Returns a structured result the MCP layer can surface directly
14
+ *
15
+ * Does NOT require the daemon to be running.
16
+ */
17
+
18
+ import { homedir } from 'node:os';
19
+ import { join } from 'node:path';
20
+ import { loadConstructEnv } from '../env-config.mjs';
21
+ import { addObservation } from '../observation-store.mjs';
22
+
23
+ // ─── Self-query detection ────────────────────────────────────────────────────
24
+
25
+ /**
26
+ * Detect queries that are asking about Construct itself (not an external provider).
27
+ * These should route to knowledge_search, not to external providers.
28
+ *
29
+ * IMPORTANT: Only match when the query is clearly about Construct-the-tool,
30
+ * not about an external repo/project that happens to use similar words.
31
+ * When in doubt, let matchSourceFromQuery() decide — provider queries should
32
+ * never be blocked by this gate.
33
+ */
34
+ const SELF_QUERY_PATTERNS = [
35
+ /\bconstruct\b/i,
36
+ /\bwhat (is|are) (this|the) (tool|system|agent|platform)\b/i,
37
+ /\bhow does (this|the) (tool|system|agent) work\b/i,
38
+ /\bwhat can (you|it|this) do\b/i,
39
+ /\bwhat commands?\b/i,
40
+ /\bavailable commands?\b/i,
41
+ /\bembed (mode|daemon)\b/i,
42
+ /\bauthority guard\b/i,
43
+ /\bcx[\s\/]knowledge\b/i,
44
+ /\bprovider (framework|interface|abstraction)\b/i,
45
+ ];
46
+
47
+ /**
48
+ * @param {string} query
49
+ * @returns {boolean}
50
+ */
51
+ function isSelfQuery(query) {
52
+ if (!query) return false;
53
+ return SELF_QUERY_PATTERNS.some(re => re.test(query));
54
+ }
55
+
56
+ // ─── Source name resolution ──────────────────────────────────────────────────
57
+
58
+ /**
59
+ * Build a flat list of known source identifiers from env.
60
+ * Maps each identifier to a { provider, ref } descriptor.
61
+ *
62
+ * @param {object} env
63
+ * @returns {{ id: string, provider: string, ref: string, display: string }[]}
64
+ */
65
+ export function resolveKnownSources(env = process.env) {
66
+ const sources = [];
67
+
68
+ // GitHub repos
69
+ const repos = (env.GITHUB_REPOS ?? '').split(',').map(r => r.trim()).filter(Boolean);
70
+ for (const repo of repos) {
71
+ const short = repo.split('/').pop(); // "project-iverson" from "hashicorp/project-iverson"
72
+ sources.push({ id: repo.toLowerCase(), provider: 'github', ref: repo, display: repo });
73
+ sources.push({ id: short.toLowerCase(), provider: 'github', ref: repo, display: repo });
74
+ // Normalised: "projectiverson", "iverson"
75
+ sources.push({ id: short.replace(/-/g, '').toLowerCase(), provider: 'github', ref: repo, display: repo });
76
+ // Last word: "iverson" from "project-iverson"
77
+ const words = short.split('-');
78
+ if (words.length > 1) {
79
+ sources.push({ id: words[words.length - 1].toLowerCase(), provider: 'github', ref: repo, display: repo });
80
+ }
81
+ }
82
+
83
+ // Jira projects
84
+ const jiraUrl = (env.JIRA_BASE_URL ?? '').trim();
85
+ if (jiraUrl) {
86
+ // JIRA_PROJECTS=PLAT,INF,ENG — optional explicit list
87
+ const projects = (env.JIRA_PROJECTS ?? '').split(',').map(p => p.trim()).filter(Boolean);
88
+ for (const proj of projects) {
89
+ sources.push({ id: proj.toLowerCase(), provider: 'jira', ref: proj, display: `Jira/${proj}` });
90
+ }
91
+ // Always add a generic "jira" entry
92
+ sources.push({ id: 'jira', provider: 'jira', ref: null, display: 'Jira' });
93
+ }
94
+
95
+ // Linear
96
+ if (env.LINEAR_API_KEY) {
97
+ sources.push({ id: 'linear', provider: 'linear', ref: null, display: 'Linear' });
98
+ const teams = (env.LINEAR_TEAMS ?? '').split(',').map(t => t.trim()).filter(Boolean);
99
+ for (const team of teams) {
100
+ sources.push({ id: team.toLowerCase(), provider: 'linear', ref: team, display: `Linear/${team}` });
101
+ }
102
+ }
103
+
104
+ return sources;
105
+ }
106
+
107
+ /**
108
+ * Match a free-text query against known source identifiers.
109
+ * Returns the best match or null.
110
+ *
111
+ * @param {string} query
112
+ * @param {object} env
113
+ * @returns {{ provider: string, ref: string, display: string } | null}
114
+ */
115
+ export function matchSourceFromQuery(query, env = process.env) {
116
+ const sources = resolveKnownSources(env);
117
+ const q = query.toLowerCase();
118
+
119
+ // Exact or substring match — longest id wins
120
+ const matches = sources.filter(s => q.includes(s.id));
121
+ if (!matches.length) return null;
122
+
123
+ // Prefer longer (more specific) ids
124
+ matches.sort((a, b) => b.id.length - a.id.length);
125
+ return matches[0];
126
+ }
127
+
128
+ // ─── On-demand fetch ─────────────────────────────────────────────────────────
129
+
130
+ /**
131
+ * Fire a targeted one-shot fetch for a named source. When no specific source
132
+ * matches the query, falls back to fetching from ALL configured providers
133
+ * (the "I don't know what you mean, pull everything fresh" path).
134
+ *
135
+ * @param {object} opts
136
+ * @param {string} opts.query - Free-text query naming the source
137
+ * @param {string} [opts.rootDir] - Data root dir (default: homedir())
138
+ * @param {object} [opts.env] - Env override
139
+ * @returns {Promise<DemandFetchResult>}
140
+ */
141
+ export async function demandFetch({ query, rootDir, env } = {}) {
142
+ const resolvedEnv = env ?? loadConstructEnv();
143
+ const root = rootDir ?? (resolvedEnv.CX_DATA_DIR?.trim() || homedir());
144
+
145
+ // Provider match takes priority: if the query names a configured repo/project,
146
+ // always fetch from that provider — even if isSelfQuery() also fires.
147
+ const match = matchSourceFromQuery(query, resolvedEnv);
148
+
149
+ // Self-referential queries about Construct itself → route to knowledge_search,
150
+ // but only when no external provider source was matched.
151
+ if (!match && isSelfQuery(query)) {
152
+ const { knowledgeSearch } = await import('../knowledge/search.mjs');
153
+ const result = knowledgeSearch({ query, topK: 5 });
154
+ return {
155
+ ok: result.ok,
156
+ reason: result.ok ? 'knowledge_search' : 'knowledge_search_empty',
157
+ message: result.message,
158
+ items: result.hits.map(h => ({
159
+ title: h.heading || h.file,
160
+ summary: h.text,
161
+ url: null,
162
+ state: null,
163
+ source: h.file,
164
+ })),
165
+ knowledgeHits: result.hits,
166
+ sources: result.sources,
167
+ };
168
+ }
169
+
170
+ if (!match) {
171
+ // No specific source match and not a self-query — fetch from all configured providers
172
+ return demandFetchAll({ query, rootDir: root, env: resolvedEnv });
173
+ }
174
+
175
+ // Dynamically import provider registry to avoid loading all providers at module init
176
+ const { ProviderRegistry } = await import('./providers/registry.mjs');
177
+ const registry = await ProviderRegistry.fromEnv(resolvedEnv);
178
+ const provider = registry.get(match.provider);
179
+
180
+ if (!provider) {
181
+ return {
182
+ ok: false,
183
+ reason: 'provider_not_registered',
184
+ message: `Provider "${match.provider}" is not registered (check credentials in config.env)`,
185
+ items: [],
186
+ match,
187
+ };
188
+ }
189
+
190
+ // Build read calls for the matched source and execute them
191
+ const readCalls = buildReadCalls(match, resolvedEnv);
192
+ if (!readCalls.length) {
193
+ return {
194
+ ok: false,
195
+ reason: 'unsupported_provider',
196
+ message: `No read strategy defined for provider "${match.provider}"`,
197
+ items: [],
198
+ match,
199
+ };
200
+ }
201
+
202
+ let rawItems = [];
203
+ try {
204
+ for (const { ref, opts } of readCalls) {
205
+ const items = await provider.read(ref, opts);
206
+ if (items?.length) rawItems.push(...items);
207
+ }
208
+ } catch (err) {
209
+ return {
210
+ ok: false,
211
+ reason: 'fetch_error',
212
+ message: `Failed to fetch from ${match.display}: ${err.message}`,
213
+ items: [],
214
+ match,
215
+ };
216
+ }
217
+
218
+ if (!rawItems?.length) {
219
+ return {
220
+ ok: true,
221
+ reason: 'empty',
222
+ message: `${match.display} returned no items (check permissions or try again)`,
223
+ items: [],
224
+ match,
225
+ };
226
+ }
227
+
228
+ // Separate real items from error sentinels the provider may have returned
229
+ const errorItems = rawItems.filter(i => i.type === 'error');
230
+ const dataItems = rawItems.filter(i => i.type !== 'error');
231
+
232
+ if (!dataItems.length && errorItems.length) {
233
+ const errMsg = errorItems.map(i => i.message).join('; ');
234
+ return {
235
+ ok: false,
236
+ reason: 'provider_error',
237
+ message: `${match.display} returned errors: ${errMsg}`,
238
+ items: [],
239
+ errors: errorItems,
240
+ match,
241
+ };
242
+ }
243
+
244
+ // Write each item as an observation so future queries find them in the knowledge base
245
+ let written = 0;
246
+ for (const item of dataItems) {
247
+ try {
248
+ addObservation(root, {
249
+ role: 'construct',
250
+ category: 'insight',
251
+ summary: item.title ?? item.summary ?? item.id,
252
+ content: buildObservationContent(item, match),
253
+ tags: ['demand-fetch', match.provider, match.ref ?? match.provider],
254
+ confidence: 0.9,
255
+ source: `demand-fetch:${match.provider}`,
256
+ });
257
+ written++;
258
+ } catch (err) { process.stderr.write('[demand-fetch.mjs] store-observation: ' + (err?.message ?? String(err)) + '\n'); }
259
+ }
260
+
261
+ return {
262
+ ok: true,
263
+ reason: 'fetched',
264
+ message: `Fetched ${dataItems.length} item(s) from ${match.display} and stored ${written} observation(s)${errorItems.length ? ` (${errorItems.length} error(s): ${errorItems.map(i => i.message).join('; ')})` : ''}`,
265
+ items: dataItems,
266
+ match,
267
+ written,
268
+ errors: errorItems.length ? errorItems : undefined,
269
+ };
270
+ }
271
+
272
+ // ─── Universal fetch (all providers) ─────────────────────────────────────────
273
+
274
+ /**
275
+ * Fetch from ALL configured providers. Used when no specific source matches a
276
+ * query — gives Construct a broad current-state refresh across every integration.
277
+ *
278
+ * @param {object} opts
279
+ * @param {string} [opts.query] - Original query (for logging/tagging only)
280
+ * @param {string} [opts.rootDir] - Data root dir
281
+ * @param {object} [opts.env] - Resolved env
282
+ * @returns {Promise<DemandFetchResult>}
283
+ */
284
+ async function demandFetchAll({ query, rootDir, env } = {}) {
285
+ const { ProviderRegistry } = await import('./providers/registry.mjs');
286
+ const registry = await ProviderRegistry.fromEnv(env);
287
+ const providerNames = registry.names();
288
+
289
+ if (!providerNames.length) {
290
+ return {
291
+ ok: false,
292
+ reason: 'no_providers',
293
+ message: 'No provider credentials configured in config.env',
294
+ items: [],
295
+ };
296
+ }
297
+
298
+ const allItems = [];
299
+ const errors = [];
300
+ const sources = resolveKnownSources(env);
301
+
302
+ // Group known sources by provider so we can batch-fetch per-provider
303
+ const byProvider = new Map();
304
+ for (const src of sources) {
305
+ if (!byProvider.has(src.provider)) byProvider.set(src.provider, []);
306
+ byProvider.get(src.provider).push(src);
307
+ }
308
+
309
+ // Also include providers that have no explicit sources (Jira, Linear default fetch)
310
+ for (const name of providerNames) {
311
+ if (!byProvider.has(name)) byProvider.set(name, []);
312
+ }
313
+
314
+ for (const [providerName, provSources] of byProvider) {
315
+ const provider = registry.get(providerName);
316
+ if (!provider) continue;
317
+
318
+ // Build read calls — one set per known source, or a default if none listed
319
+ const matchList = provSources.length > 0
320
+ ? provSources
321
+ : [{ provider: providerName, ref: null, display: providerName }];
322
+
323
+ for (const src of matchList) {
324
+ const readCalls = buildReadCalls(src, env);
325
+ if (!readCalls.length) continue;
326
+ for (const { ref, opts, display } of readCalls) {
327
+ try {
328
+ const items = await provider.read(ref, opts);
329
+ if (items?.length) {
330
+ allItems.push(...items);
331
+ for (const item of items) {
332
+ try {
333
+ addObservation(rootDir, {
334
+ role: 'construct',
335
+ category: 'insight',
336
+ summary: item.title ?? item.summary ?? item.id,
337
+ content: buildObservationContent(item, { provider: providerName, ref: src.ref, display: display ?? src.display ?? providerName }),
338
+ tags: ['demand-fetch', 'universal', providerName],
339
+ confidence: 0.85,
340
+ source: `demand-fetch:all:${providerName}`,
341
+ });
342
+ } catch (err) { process.stderr.write('[demand-fetch.mjs] universal-store-obs: ' + (err?.message ?? String(err)) + '\n'); }
343
+ }
344
+ }
345
+ } catch (err) {
346
+ errors.push({ provider: providerName, ref: src.ref ?? null, error: err.message });
347
+ }
348
+ }
349
+ }
350
+ }
351
+
352
+ const knownSourceList = sources.map(s => s.display).filter((v, i, a) => a.indexOf(v) === i).join(', ') || 'none';
353
+
354
+ if (!allItems.length && errors.length) {
355
+ return {
356
+ ok: false,
357
+ reason: 'fetch_errors',
358
+ message: `Universal fetch failed for all providers. Errors: ${errors.map(e => `${e.provider}: ${e.error}`).join('; ')}`,
359
+ items: [],
360
+ errors,
361
+ };
362
+ }
363
+
364
+ return {
365
+ ok: true,
366
+ reason: allItems.length ? 'fetched_all' : 'empty_all',
367
+ message: allItems.length
368
+ ? `Universal fetch: ${allItems.length} item(s) from ${providerNames.join(', ')}${errors.length ? ` (${errors.length} provider error(s))` : ''}`
369
+ : `Universal fetch returned no items from any provider (${knownSourceList})`,
370
+ items: allItems,
371
+ written: allItems.length,
372
+ providers: providerNames,
373
+ errors: errors.length ? errors : undefined,
374
+ query,
375
+ };
376
+ }
377
+
378
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
379
+
380
+ /**
381
+ * Build a list of { ref, opts } pairs to pass to provider.read(ref, opts).
382
+ *
383
+ * @param {{ provider: string, ref: string|null, display: string }} match
384
+ * @param {object} env
385
+ * @returns {{ ref: string, opts: object, display: string }[]}
386
+ */
387
+ function buildReadCalls(match, env) {
388
+ if (match.provider === 'github') {
389
+ const opts = { repos: [match.ref], limit: 25 };
390
+ return [
391
+ { ref: 'meta', opts, display: match.display },
392
+ { ref: 'readme', opts, display: match.display },
393
+ { ref: 'docs', opts, display: match.display },
394
+ { ref: 'prs', opts, display: match.display },
395
+ { ref: 'issues', opts, display: match.display },
396
+ { ref: 'commits', opts, display: match.display },
397
+ ];
398
+ }
399
+ if (match.provider === 'jira') {
400
+ const projects = (env.JIRA_PROJECTS ?? '').split(',').map(p => p.trim()).filter(Boolean);
401
+ const recencyDays = parseInt(env.JIRA_FETCH_RECENCY_DAYS, 10) || 30;
402
+
403
+ let jql;
404
+ if (match.ref) {
405
+ // Targeted project fetch — no recency cutoff, user asked for this project
406
+ jql = `project = "${match.ref}" AND statusCategory != Done ORDER BY updated DESC`;
407
+ } else if (projects.length > 0) {
408
+ // Broad/fallback fetch — scoped to configured projects with recency guard
409
+ const projectList = projects.map(p => `"${p}"`).join(', ');
410
+ jql = `project IN (${projectList}) AND updated >= -${recencyDays}d ORDER BY updated DESC`;
411
+ } else {
412
+ // No JIRA_PROJECTS configured — skip Jira entirely rather than defaulting to user-scoped
413
+ return [];
414
+ }
415
+ return [{ ref: 'issues', opts: { jql, limit: 50 }, display: match.display }];
416
+ }
417
+ if (match.provider === 'linear') {
418
+ return [{ ref: 'issues', opts: { team: match.ref ?? null, limit: 50 }, display: match.display }];
419
+ }
420
+ return [];
421
+ }
422
+
423
+ function buildObservationContent(item, match) {
424
+ const lines = [`Source: ${match.display}`, `Provider: ${match.provider}`];
425
+ if (item.url) lines.push(`URL: ${item.url}`);
426
+
427
+ if (item.type === 'meta') {
428
+ if (item.description) lines.push(`Description: ${item.description}`);
429
+ if (item.language) lines.push(`Language: ${item.language}`);
430
+ if (item.visibility) lines.push(`Visibility: ${item.visibility}`);
431
+ if (item.topics?.length) lines.push(`Topics: ${item.topics.join(', ')}`);
432
+ if (item.defaultBranch) lines.push(`Default branch: ${item.defaultBranch}`);
433
+ if (item.pushedAt) lines.push(`Last push: ${item.pushedAt}`);
434
+ return lines.join('\n');
435
+ }
436
+
437
+ if (item.type === 'doc') {
438
+ if (item.path) lines.push(`Path: ${item.path}`);
439
+ if (item.content) lines.push(`\n${item.content}`);
440
+ return lines.join('\n');
441
+ }
442
+
443
+ if (item.state ?? item.status) lines.push(`Status: ${item.state ?? item.status}`);
444
+ if (item.body ?? item.description) {
445
+ const body = String(item.body ?? item.description ?? '').slice(0, 500);
446
+ if (body) lines.push(`\n${body}`);
447
+ }
448
+ return lines.join('\n');
449
+ }