@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,408 @@
1
+ /**
2
+ * lib/embed/cli.mjs — CLI handler for `construct embed <subcommand>`.
3
+ *
4
+ * Subcommands:
5
+ * start [--config <path>] Fork detached embed daemon
6
+ * stop Send SIGTERM to running daemon
7
+ * status Print daemon status + last snapshot summary
8
+ * snapshot [--config <path>] Run a one-shot snapshot and print to stdout
9
+ *
10
+ * Exports:
11
+ * resolveEmbedStatus(env, homeDir) — returns { level, label, detail }
12
+ * level: 'running' | 'stopped' | 'none'
13
+ * Consumed by session-start hook and dashboard /api/embed/status endpoint.
14
+ *
15
+ * autoStartEmbedIfNeeded(env, rootDir, homeDir) — spawns daemon when
16
+ * provider credentials are present but daemon is stopped. No-op if already
17
+ * running or no credentials. Returns { started: bool, pid?, reason? }.
18
+ */
19
+
20
+ import fs from 'node:fs';
21
+ import os from 'node:os';
22
+ import path from 'node:path';
23
+ import { spawn } from 'node:child_process';
24
+
25
+ const STATE_FILE = 'embed-daemon.json';
26
+ const LOG_FILE = 'embed-daemon.log';
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Paths
30
+ // ---------------------------------------------------------------------------
31
+
32
+ function runtimeDir(homeDir = os.homedir()) {
33
+ return path.join(homeDir, '.cx', 'runtime');
34
+ }
35
+
36
+ function statePath(homeDir = os.homedir()) {
37
+ return path.join(runtimeDir(homeDir), STATE_FILE);
38
+ }
39
+
40
+ function logPath(homeDir = os.homedir()) {
41
+ return path.join(runtimeDir(homeDir), LOG_FILE);
42
+ }
43
+
44
+ // ---------------------------------------------------------------------------
45
+ // State helpers
46
+ // ---------------------------------------------------------------------------
47
+
48
+ function readState(homeDir = os.homedir()) {
49
+ const p = statePath(homeDir);
50
+ if (!fs.existsSync(p)) return null;
51
+ try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch (err) { process.stderr.write('[cli.mjs] readState: ' + (err?.message ?? String(err)) + '\n'); return null; }
52
+ }
53
+
54
+ function writeState(obj, homeDir = os.homedir()) {
55
+ const dir = runtimeDir(homeDir);
56
+ fs.mkdirSync(dir, { recursive: true });
57
+ fs.writeFileSync(statePath(homeDir), JSON.stringify(obj, null, 2));
58
+ }
59
+
60
+ function clearState(homeDir = os.homedir()) {
61
+ const p = statePath(homeDir);
62
+ if (fs.existsSync(p)) fs.rmSync(p, { force: true });
63
+ }
64
+
65
+ function processExists(pid) {
66
+ if (!pid) return false;
67
+ try { process.kill(Number(pid), 0); return true; } catch (err) { process.stderr.write('[cli.mjs] processExists: ' + (err?.message ?? String(err)) + '\n'); return false; }
68
+ }
69
+
70
+ function readRunningState(homeDir = os.homedir()) {
71
+ const s = readState(homeDir);
72
+ if (!s) return null;
73
+ if (!processExists(s.pid)) { clearState(homeDir); return null; }
74
+ return s;
75
+ }
76
+
77
+ // ---------------------------------------------------------------------------
78
+ // Exported status + auto-start utilities
79
+ // ---------------------------------------------------------------------------
80
+
81
+ /**
82
+ * Resolve embed daemon status without side effects.
83
+ *
84
+ * @param {object} [env] - Env object (default: process.env)
85
+ * @param {string} [homeDir] - Home dir override
86
+ * @returns {{ level: 'running'|'stopped'|'none', label: string, detail: string }}
87
+ * level='none' — no provider credentials configured; embed not applicable
88
+ * level='stopped' — credentials present but daemon not running
89
+ * level='running' — daemon process is live
90
+ */
91
+ export function resolveEmbedStatus(env = process.env, homeDir = os.homedir()) {
92
+ const hasProviders = !!(
93
+ env.GITHUB_TOKEN || env.GITHUB_PERSONAL_ACCESS_TOKEN ||
94
+ env.SLACK_BOT_TOKEN ||
95
+ env.LINEAR_API_KEY ||
96
+ (env.JIRA_API_TOKEN && env.JIRA_USER_EMAIL && env.JIRA_BASE_URL)
97
+ );
98
+
99
+ if (!hasProviders) {
100
+ return { level: 'none', label: 'embed: no providers', detail: 'no provider credentials in config.env' };
101
+ }
102
+
103
+ const state = readRunningState(homeDir);
104
+ if (state) {
105
+ return {
106
+ level: 'running',
107
+ label: `embed: running (pid ${state.pid})`,
108
+ detail: `started ${state.startedAt ?? 'unknown'} · config: ${state.configPath ?? 'auto'}`,
109
+ };
110
+ }
111
+
112
+ return {
113
+ level: 'stopped',
114
+ label: 'embed: providers configured, daemon stopped',
115
+ detail: 'run `construct embed start` or set CX_AUTO_EMBED=1',
116
+ };
117
+ }
118
+
119
+ /**
120
+ * Auto-start the embed daemon when credentials are present but daemon is stopped.
121
+ * Silently no-ops if already running or no credentials.
122
+ *
123
+ * @param {object} [env] - Env object (default: process.env)
124
+ * @param {string} [rootDir] - Construct root dir (where lib/embed/worker.mjs lives)
125
+ * @param {string} [homeDir] - Home dir override
126
+ * @returns {{ started: boolean, pid?: number, reason?: string }}
127
+ */
128
+ export async function autoStartEmbedIfNeeded(env = process.env, rootDir, homeDir = os.homedir()) {
129
+ if (!env.CX_AUTO_EMBED && env.CX_AUTO_EMBED !== '1') {
130
+ return { started: false, reason: 'CX_AUTO_EMBED not set' };
131
+ }
132
+
133
+ const status = resolveEmbedStatus(env, homeDir);
134
+ if (status.level !== 'stopped') {
135
+ return { started: false, reason: status.level === 'running' ? 'already_running' : 'no_providers' };
136
+ }
137
+
138
+ const resolvedRoot = rootDir ?? new URL('../..', import.meta.url).pathname;
139
+ try {
140
+ const workerPath = path.join(resolvedRoot, 'lib', 'embed', 'worker.mjs');
141
+ const log = logPath(homeDir);
142
+ fs.mkdirSync(path.dirname(log), { recursive: true });
143
+ const fd = fs.openSync(log, 'a');
144
+
145
+ const child = spawn(process.execPath, [workerPath], {
146
+ detached: true,
147
+ stdio: ['ignore', fd, fd],
148
+ env: { ...env },
149
+ });
150
+ child.unref();
151
+
152
+ writeState({ pid: child.pid, configPath: 'auto', startedAt: new Date().toISOString() }, homeDir);
153
+ return { started: true, pid: child.pid };
154
+ } catch (err) {
155
+ return { started: false, reason: `spawn_failed: ${err.message}` };
156
+ }
157
+ }
158
+
159
+ // ---------------------------------------------------------------------------
160
+ // Parse args helpers
161
+ // ---------------------------------------------------------------------------
162
+
163
+ function parseArgs(args) {
164
+ const flags = {};
165
+ for (let i = 0; i < args.length; i++) {
166
+ if ((args[i] === '--config' || args[i] === '-c') && args[i + 1]) {
167
+ flags.config = args[++i];
168
+ }
169
+ }
170
+ return flags;
171
+ }
172
+
173
+ // ---------------------------------------------------------------------------
174
+ // Subcommand: start
175
+ // ---------------------------------------------------------------------------
176
+
177
+ async function cmdEmbedStart(args, { homeDir = os.homedir(), rootDir } = {}) {
178
+ const existing = readRunningState(homeDir);
179
+ if (existing) {
180
+ process.stdout.write(`embed daemon already running (pid ${existing.pid})\n`);
181
+ return;
182
+ }
183
+
184
+ const { config } = parseArgs(args);
185
+ const configPath = config
186
+ ? path.resolve(config)
187
+ : fs.existsSync(path.join(os.homedir(), '.construct', 'embed.yaml'))
188
+ ? path.join(os.homedir(), '.construct', 'embed.yaml')
189
+ : null;
190
+
191
+ const workerPath = path.join(rootDir, 'lib', 'embed', 'worker.mjs');
192
+ const workerArgs = configPath ? [workerPath, '--config', configPath] : [workerPath];
193
+ const log = logPath(homeDir);
194
+ fs.mkdirSync(path.dirname(log), { recursive: true });
195
+ const fd = fs.openSync(log, 'a');
196
+
197
+ const child = spawn(process.execPath, workerArgs, {
198
+ detached: true,
199
+ stdio: ['ignore', fd, fd],
200
+ env: { ...process.env },
201
+ });
202
+ child.unref();
203
+
204
+ writeState({ pid: child.pid, configPath: configPath ?? 'auto', startedAt: new Date().toISOString() }, homeDir);
205
+ process.stdout.write(`embed daemon started (pid ${child.pid})\n`);
206
+ process.stdout.write(`config: ${configPath ?? 'auto-discover from config.env'}\n`);
207
+ process.stdout.write(`log: ${log}\n`);
208
+ }
209
+
210
+ // ---------------------------------------------------------------------------
211
+ // Subcommand: stop
212
+ // ---------------------------------------------------------------------------
213
+
214
+ function cmdEmbedStop(_args, { homeDir = os.homedir() } = {}) {
215
+ const state = readRunningState(homeDir);
216
+ if (!state) {
217
+ process.stdout.write('embed daemon is not running\n');
218
+ return;
219
+ }
220
+ try {
221
+ process.kill(Number(state.pid), 'SIGTERM');
222
+ clearState(homeDir);
223
+ process.stdout.write(`embed daemon stopped (pid ${state.pid})\n`);
224
+ } catch (err) {
225
+ process.stderr.write(`Failed to stop daemon: ${err.message}\n`);
226
+ clearState(homeDir);
227
+ process.exit(1);
228
+ }
229
+ }
230
+
231
+ // ---------------------------------------------------------------------------
232
+ // Subcommand: status
233
+ // ---------------------------------------------------------------------------
234
+
235
+ function cmdEmbedStatus(_args, { homeDir = os.homedir() } = {}) {
236
+ const state = readRunningState(homeDir);
237
+ if (!state) {
238
+ process.stdout.write('embed daemon: stopped\n');
239
+ return;
240
+ }
241
+ process.stdout.write(`embed daemon: running\n`);
242
+ process.stdout.write(` pid: ${state.pid}\n`);
243
+ process.stdout.write(` config: ${state.configPath}\n`);
244
+ process.stdout.write(` started at: ${state.startedAt}\n`);
245
+ process.stdout.write(` log: ${logPath(homeDir)}\n`);
246
+ }
247
+
248
+ // ---------------------------------------------------------------------------
249
+ // Subcommand: snapshot (one-shot, in-process)
250
+ // ---------------------------------------------------------------------------
251
+
252
+ async function cmdEmbedSnapshot(args, { homeDir = os.homedir() } = {}) {
253
+ const { config } = parseArgs(args);
254
+ const configPath = config
255
+ ? path.resolve(config)
256
+ : path.join(os.homedir(), '.construct', 'embed.yaml');
257
+
258
+ const { loadEmbedConfig, EMPTY_CONFIG } = await import('./config.mjs');
259
+ const { SnapshotEngine, renderMarkdown } = await import('./snapshot.mjs');
260
+ const { ProviderRegistry } = await import('./providers/registry.mjs');
261
+ const { loadConstructEnv } = await import('../env-config.mjs');
262
+
263
+ const env = loadConstructEnv();
264
+ const registry = await ProviderRegistry.fromEnv(env);
265
+
266
+ let cfg;
267
+ if (fs.existsSync(configPath)) {
268
+ cfg = loadEmbedConfig(configPath);
269
+ } else {
270
+ cfg = { ...EMPTY_CONFIG, sources: registry.autoSources(env) };
271
+ }
272
+
273
+ if (!cfg.sources.length) {
274
+ process.stderr.write('embed snapshot: no sources configured and no credentials found in config.env\n');
275
+ process.exit(1);
276
+ }
277
+
278
+ const engine = new SnapshotEngine(registry, cfg);
279
+
280
+ process.stderr.write('embed: generating snapshot…\n');
281
+ const snapshot = await engine.generate();
282
+ process.stdout.write(renderMarkdown(snapshot));
283
+ process.stderr.write(`\n${snapshot.summary.totalItems} items, ${snapshot.summary.errorCount} errors\n`);
284
+ }
285
+
286
+ // ---------------------------------------------------------------------------
287
+ // Main export
288
+ // ---------------------------------------------------------------------------
289
+
290
+ /**
291
+ * Entry point called by bin/construct.
292
+ * @param {string[]} args - argv after 'embed'
293
+ * @param {object} [opts] - { homeDir, rootDir }
294
+ */
295
+ export async function runEmbedCli(args, opts = {}) {
296
+ const sub = args[0];
297
+ const subArgs = args.slice(1);
298
+ const homeDir = opts.homeDir ?? os.homedir();
299
+ const rootDir = opts.rootDir ?? new URL('../..', import.meta.url).pathname;
300
+
301
+ switch (sub) {
302
+ case 'start': return cmdEmbedStart(subArgs, { homeDir, rootDir });
303
+ case 'stop': return cmdEmbedStop(subArgs, { homeDir });
304
+ case 'status': return cmdEmbedStatus(subArgs, { homeDir });
305
+ case 'snapshot': return cmdEmbedSnapshot(subArgs, { homeDir });
306
+ case 'migrate-model': return cmdEmbedMigrateModel(subArgs);
307
+ case 'supervise': {
308
+ const { installSupervision } = await import('./supervision.mjs');
309
+ const result = await installSupervision();
310
+ process.stdout.write(`embed daemon supervised via ${result.method}\n`);
311
+ if (result.file) process.stdout.write(` service file: ${result.file}\n`);
312
+ return;
313
+ }
314
+ case 'unsupervise': {
315
+ const { uninstallSupervision } = await import('./supervision.mjs');
316
+ const result = await uninstallSupervision();
317
+ if (result.wasInstalled) {
318
+ process.stdout.write(`supervision removed (${result.method})\n`);
319
+ } else {
320
+ process.stdout.write(`supervision was not installed\n`);
321
+ }
322
+ return;
323
+ }
324
+ default:
325
+ process.stderr.write(
326
+ `Usage: construct embed <start|stop|status|snapshot|migrate-model|supervise|unsupervise> [--config <path>]\n`,
327
+ );
328
+ if (sub && sub !== '--help' && sub !== '-h') {
329
+ process.stderr.write(`Unknown subcommand: ${sub}\n`);
330
+ process.exit(1);
331
+ }
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Reconcile the pgvector schema with the engine's currently-active embedding
337
+ * model and re-embed the corpus. Run this after changing
338
+ * CONSTRUCT_EMBEDDING_MODEL when the new model produces a different
339
+ * dimensionality than the on-disk schema. The pass:
340
+ * 1. Resolves the engine's active model + dim.
341
+ * 2. Reads the actual `construct_embeddings.embedding` column dim from
342
+ * `pg_attribute` and compares.
343
+ * 3. If they differ AND the operator passed `--apply`, truncates
344
+ * `construct_embeddings` and re-types the column.
345
+ * 4. Re-runs `syncFileStateToSql` to repopulate embeddings at the new dim.
346
+ *
347
+ * Without `--apply`, prints what would change and exits.
348
+ */
349
+ async function cmdEmbedMigrateModel(args) {
350
+ const apply = args.includes('--apply');
351
+ const { getEmbeddingModelInfo } = await import('../storage/embeddings-engine.mjs');
352
+ const { createSqlClient, closeSqlClient } = await import('../storage/backend.mjs');
353
+ const { syncFileStateToSql } = await import('../storage/sync.mjs');
354
+
355
+ const info = await getEmbeddingModelInfo();
356
+ const targetDim = info.dimensions;
357
+ process.stdout.write(`Active engine model: ${info.model} (${targetDim}d)\n`);
358
+
359
+ const client = createSqlClient(process.env);
360
+ if (!client) {
361
+ process.stderr.write('No DATABASE_URL configured — nothing to migrate.\n');
362
+ process.exit(1);
363
+ }
364
+
365
+ try {
366
+ const rows = await client`
367
+ SELECT format_type(atttypid, atttypmod) AS pg_type
368
+ FROM pg_attribute
369
+ WHERE attrelid = 'construct_embeddings'::regclass
370
+ AND attname = 'embedding'
371
+ AND NOT attisdropped
372
+ `;
373
+ const declared = rows?.[0]?.pg_type || '';
374
+ const match = declared.match(/vector\((\d+)\)/);
375
+ const schemaDim = match ? Number(match[1]) : null;
376
+
377
+ if (schemaDim === null) {
378
+ process.stdout.write(`Schema column type is '${declared}'; cannot migrate automatically. Run migrations first.\n`);
379
+ process.exit(1);
380
+ }
381
+ if (schemaDim === targetDim) {
382
+ process.stdout.write(`Schema is already ${schemaDim}d — nothing to migrate.\n`);
383
+ return;
384
+ }
385
+
386
+ process.stdout.write(`Schema declares vector(${schemaDim}); engine produces ${targetDim}d.\n`);
387
+ if (!apply) {
388
+ process.stdout.write('Re-run with --apply to truncate construct_embeddings and re-type the column.\n');
389
+ return;
390
+ }
391
+
392
+ process.stdout.write(`Applying migration: TRUNCATE + ALTER COLUMN to vector(${targetDim})…\n`);
393
+ await client.unsafe(
394
+ `BEGIN; TRUNCATE TABLE construct_embeddings; ` +
395
+ `ALTER TABLE construct_embeddings ALTER COLUMN embedding TYPE vector(${targetDim}); COMMIT;`
396
+ );
397
+ process.stdout.write('Re-embedding the corpus…\n');
398
+ const result = await syncFileStateToSql(process.cwd());
399
+ process.stdout.write(
400
+ `Done. embeddingsSynced=${result.embeddingsSynced} model=${result.embeddingModel}\n`
401
+ );
402
+ } catch (err) {
403
+ process.stderr.write(`migrate-model failed: ${err.message}\n`);
404
+ process.exit(1);
405
+ } finally {
406
+ await closeSqlClient(client);
407
+ }
408
+ }