@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,355 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * lib/storage/admin.mjs — storage lifecycle helpers for status, reset, cleanup, and retention.
4
+ */
5
+ import { existsSync, readdirSync, rmSync, statSync } from 'node:fs';
6
+ import { basename, extname, join, resolve } from 'node:path';
7
+ import { closeSqlClient, createSqlClient, probeSqlClient, readVectorConfig } from './backend.mjs';
8
+ import { purgeConstructDbStashes } from './postgres-backup.mjs';
9
+ import { readLocalVectorIndex, writeLocalVectorIndex } from './vector-store.mjs';
10
+ import { getEmbeddingModelInfo } from './embeddings-engine.mjs';
11
+ import { KNOWLEDGE_ROOT } from '../knowledge/layout.mjs';
12
+
13
+ function ingestedDir(rootDir) {
14
+ return resolve(rootDir, KNOWLEDGE_ROOT);
15
+ }
16
+
17
+ export function inferProjectName(rootDir) {
18
+ return basename(resolve(rootDir)).trim() || 'construct';
19
+ }
20
+
21
+ function ensureConfirmed(confirm, action) {
22
+ if (confirm !== true) {
23
+ throw new Error(`${action} requires explicit confirmation`);
24
+ }
25
+ }
26
+
27
+ function ensureInsideDir(filePath, allowedDir, action) {
28
+ const resolvedFile = resolve(filePath);
29
+ const resolvedDir = resolve(allowedDir);
30
+ if (resolvedFile !== resolvedDir && !resolvedFile.startsWith(`${resolvedDir}/`)) {
31
+ throw new Error(`${action} only allows files inside ${resolvedDir}`);
32
+ }
33
+ }
34
+
35
+ export function listIngestedArtifacts(rootDir) {
36
+ const dir = ingestedDir(rootDir);
37
+ if (!existsSync(dir)) return [];
38
+ const results = [];
39
+ function walk(current) {
40
+ for (const entry of readdirSync(current, { withFileTypes: true })) {
41
+ const full = join(current, entry.name);
42
+ if (entry.isDirectory()) {
43
+ walk(full);
44
+ } else if (entry.isFile() && extname(entry.name).toLowerCase() === '.md') {
45
+ results.push(full);
46
+ }
47
+ }
48
+ }
49
+ walk(dir);
50
+ return results.sort((a, b) => a.localeCompare(b));
51
+ }
52
+
53
+ export async function getStorageStatus(rootDir, { env = process.env, project = inferProjectName(rootDir) } = {}) {
54
+ const vector = readVectorConfig(env);
55
+ const ingestedArtifacts = listIngestedArtifacts(rootDir);
56
+ const localVector = vector.indexPath
57
+ ? (() => {
58
+ const index = readLocalVectorIndex(vector.indexPath);
59
+ return {
60
+ configured: true,
61
+ indexPath: vector.indexPath,
62
+ model: index.model,
63
+ recordCount: index.records.length,
64
+ updatedAt: index.updatedAt,
65
+ };
66
+ })()
67
+ : {
68
+ configured: false,
69
+ indexPath: null,
70
+ model: null,
71
+ recordCount: 0,
72
+ updatedAt: null,
73
+ };
74
+
75
+ const client = createSqlClient(env);
76
+ let sql = { status: 'unavailable', message: 'No SQL store configured', project, documentCount: 0 };
77
+ if (client) {
78
+ try {
79
+ const health = await probeSqlClient(client);
80
+ if (health.status === 'healthy') {
81
+ const rows = await client`select count(*)::int as count from construct_documents where project = ${project}`;
82
+ sql = {
83
+ status: 'healthy',
84
+ message: health.message,
85
+ project,
86
+ documentCount: Number(rows[0]?.count || 0),
87
+ };
88
+ } else {
89
+ sql = {
90
+ status: health.status,
91
+ message: health.message,
92
+ project,
93
+ documentCount: 0,
94
+ };
95
+ }
96
+ } finally {
97
+ await closeSqlClient(client);
98
+ }
99
+ }
100
+
101
+ return {
102
+ project,
103
+ sql,
104
+ vector,
105
+ localVector,
106
+ ingested: {
107
+ dir: ingestedDir(rootDir),
108
+ count: ingestedArtifacts.length,
109
+ files: ingestedArtifacts,
110
+ },
111
+ };
112
+ }
113
+
114
+ export async function resetStorage(rootDir, {
115
+ env = process.env,
116
+ project = inferProjectName(rootDir),
117
+ resetSql = true,
118
+ resetVector = true,
119
+ resetIngested = false,
120
+ confirm = false,
121
+ } = {}) {
122
+ ensureConfirmed(confirm, 'storage reset');
123
+ const result = {
124
+ project,
125
+ sql: { status: 'skipped' },
126
+ localVector: { status: 'skipped' },
127
+ ingested: { status: 'skipped', deletedCount: 0, files: [] },
128
+ observations: { status: 'skipped' },
129
+ sessions: { status: 'skipped' },
130
+ postgresStashes: { status: 'skipped' },
131
+ };
132
+
133
+ if (resetVector) {
134
+ const vector = readVectorConfig(env);
135
+ if (vector.indexPath) {
136
+ const modelInfo = await getEmbeddingModelInfo({ env });
137
+ const payload = writeLocalVectorIndex(vector.indexPath, [], { model: modelInfo.model });
138
+ result.localVector = {
139
+ status: 'ok',
140
+ indexPath: vector.indexPath,
141
+ model: payload.model,
142
+ recordsSynced: 0,
143
+ updatedAt: payload.updatedAt,
144
+ };
145
+ } else {
146
+ result.localVector = { status: 'unavailable', note: 'No local vector index configured' };
147
+ }
148
+
149
+ // Wipe observation vectors and session vectors
150
+ const obsVectors = join(rootDir, '.cx', 'observations', 'vectors.json');
151
+ const entityVectors = join(rootDir, '.cx', 'observations', 'entity-vectors.json');
152
+ const sessionVectors = join(rootDir, '.cx', 'sessions', 'vectors.json');
153
+ let wipedFiles = 0;
154
+ for (const p of [obsVectors, entityVectors, sessionVectors]) {
155
+ if (existsSync(p)) { rmSync(p, { force: true }); wipedFiles++; }
156
+ }
157
+ result.observations = { status: 'ok', wipedVectorFiles: wipedFiles };
158
+ result.sessions = { status: 'ok', wipedVectorFiles: wipedFiles > 0 ? 1 : 0 };
159
+ }
160
+
161
+ if (resetSql) {
162
+ const client = createSqlClient(env);
163
+ if (!client) {
164
+ result.sql = { status: 'unavailable', note: 'No DATABASE_URL configured' };
165
+ } else {
166
+ try {
167
+ const ids = await client`
168
+ select id from construct_documents where project = ${project}
169
+ `;
170
+ const documentIds = ids.map((row) => row.id).filter(Boolean);
171
+ if (documentIds.length > 0) {
172
+ await client`
173
+ delete from construct_embeddings
174
+ where document_id = any(${documentIds})
175
+ `;
176
+ }
177
+ await client`
178
+ delete from construct_documents where project = ${project}
179
+ `;
180
+ await client`
181
+ delete from construct_sync_runs where project = ${project}
182
+ `;
183
+ result.sql = {
184
+ status: 'ok',
185
+ deletedDocuments: documentIds.length,
186
+ };
187
+ } catch (error) {
188
+ result.sql = {
189
+ status: 'degraded',
190
+ error: error?.message || 'SQL reset failed',
191
+ };
192
+ } finally {
193
+ await closeSqlClient(client);
194
+ }
195
+ }
196
+
197
+ // Purge postgres stash backups
198
+ try {
199
+ const purged = await purgeConstructDbStashes({ keepCount: 0 });
200
+ result.postgresStashes = { status: 'ok', purged };
201
+ } catch (err) {
202
+ result.postgresStashes = { status: 'degraded', error: err?.message };
203
+ }
204
+ }
205
+
206
+ if (resetIngested) {
207
+ const files = listIngestedArtifacts(rootDir);
208
+ for (const file of files) rmSync(file, { force: true });
209
+ result.ingested = {
210
+ status: 'ok',
211
+ deletedCount: files.length,
212
+ files,
213
+ };
214
+ }
215
+
216
+ return result;
217
+ }
218
+
219
+ export function validateDeleteIngestedRequest(rootDir, { files = [], confirm = false } = {}) {
220
+ ensureConfirmed(confirm, 'ingested artifact deletion');
221
+ const allowedDir = ingestedDir(rootDir);
222
+ for (const file of files) ensureInsideDir(resolve(rootDir, file), allowedDir, 'ingested artifact deletion');
223
+ }
224
+
225
+ export function deleteIngestedArtifacts(rootDir, { files = [], confirm = false } = {}) {
226
+ validateDeleteIngestedRequest(rootDir, { files, confirm });
227
+ const allowedDir = ingestedDir(rootDir);
228
+ const targets = files.length > 0
229
+ ? files.map((file) => {
230
+ const resolvedFile = resolve(rootDir, file);
231
+ ensureInsideDir(resolvedFile, allowedDir, 'ingested artifact deletion');
232
+ return resolvedFile;
233
+ })
234
+ : listIngestedArtifacts(rootDir);
235
+ const deleted = [];
236
+ for (const file of targets) {
237
+ if (!existsSync(file)) continue;
238
+ rmSync(file, { force: true });
239
+ deleted.push(file);
240
+ }
241
+ return {
242
+ status: 'ok',
243
+ deletedCount: deleted.length,
244
+ files: deleted,
245
+ };
246
+ }
247
+
248
+ /**
249
+ * Purge data older than CONSTRUCT_DATA_RETENTION_DAYS from all storage layers.
250
+ *
251
+ * Scope:
252
+ * - SQL: deletes construct_documents (+ cascading construct_embeddings) older than cutoff
253
+ * - Local vector index: removes records whose updatedAt is older than cutoff
254
+ * - Observation individual files: removes .cx/observations/<id>.json files older than cutoff
255
+ * and prunes them from index.json and vectors.json
256
+ *
257
+ * Returns a summary of what was deleted.
258
+ */
259
+ export async function purgeExpiredData(rootDir, {
260
+ env = process.env,
261
+ project = inferProjectName(rootDir),
262
+ retentionDays = null,
263
+ } = {}) {
264
+ const days = retentionDays ?? Number(env.CONSTRUCT_DATA_RETENTION_DAYS ?? 0);
265
+ if (!days || days <= 0) return { status: 'skipped', reason: 'CONSTRUCT_DATA_RETENTION_DAYS not set or zero' };
266
+
267
+ const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
268
+ const result = { status: 'ok', cutoff: cutoff.toISOString(), retentionDays: days, sql: null, localVector: null, observations: null };
269
+
270
+ // SQL: delete documents older than cutoff
271
+ const client = createSqlClient(env);
272
+ if (client) {
273
+ try {
274
+ const deleted = await client`
275
+ delete from construct_documents
276
+ where project = ${project} and updated_at < ${cutoff}
277
+ returning id
278
+ `;
279
+ await client`
280
+ delete from construct_sync_runs
281
+ where project = ${project} and created_at < ${cutoff}
282
+ `;
283
+ result.sql = { status: 'ok', deletedDocuments: deleted.length };
284
+ } catch (error) {
285
+ result.sql = { status: 'degraded', error: error?.message };
286
+ } finally {
287
+ await closeSqlClient(client);
288
+ }
289
+ } else {
290
+ result.sql = { status: 'unavailable' };
291
+ }
292
+
293
+ // Local vector index: drop records older than cutoff. Preserve the
294
+ // existing index's model id so prune doesn't accidentally rewrite the
295
+ // header to a different model than the records were embedded with.
296
+ const vector = readVectorConfig(env);
297
+ if (vector.indexPath) {
298
+ const index = readLocalVectorIndex(vector.indexPath);
299
+ const before = index.records.length;
300
+ const fresh = index.records.filter((r) => {
301
+ if (!r.updatedAt) return true;
302
+ return new Date(r.updatedAt) >= cutoff;
303
+ });
304
+ if (fresh.length < before) {
305
+ const model = index.model || (await getEmbeddingModelInfo({ env })).model;
306
+ writeLocalVectorIndex(vector.indexPath, fresh, { model });
307
+ }
308
+ result.localVector = { status: 'ok', removedRecords: before - fresh.length };
309
+ } else {
310
+ result.localVector = { status: 'unavailable' };
311
+ }
312
+
313
+ // Observations: remove individual files older than cutoff
314
+ const obsDir = join(rootDir, '.cx', 'observations');
315
+ const obsIndexPath = join(obsDir, 'index.json');
316
+ const obsVectorsPath = join(obsDir, 'vectors.json');
317
+ if (existsSync(obsDir)) {
318
+ try {
319
+ const { readdirSync: rd, rmSync: rm, readFileSync: rf, writeFileSync: wf } = await import('node:fs');
320
+ const files = rd(obsDir).filter((f) => f.startsWith('obs-') && f.endsWith('.json'));
321
+ let removedObs = 0;
322
+ const removedIds = new Set();
323
+ for (const file of files) {
324
+ const filePath = join(obsDir, file);
325
+ const st = statSync(filePath);
326
+ if (st.mtimeMs < cutoff.getTime()) {
327
+ rm(filePath, { force: true });
328
+ removedIds.add(file.replace('.json', ''));
329
+ removedObs++;
330
+ }
331
+ }
332
+ if (removedIds.size > 0) {
333
+ if (existsSync(obsIndexPath)) {
334
+ try {
335
+ const index = JSON.parse(rf(obsIndexPath, 'utf8'));
336
+ wf(obsIndexPath, JSON.stringify(index.filter((e) => !removedIds.has(e.id)), null, 2) + '\n');
337
+ } catch { /* best effort */ }
338
+ }
339
+ if (existsSync(obsVectorsPath)) {
340
+ try {
341
+ const vectors = JSON.parse(rf(obsVectorsPath, 'utf8'));
342
+ wf(obsVectorsPath, JSON.stringify(vectors.filter((v) => !removedIds.has(v.id)), null, 2) + '\n');
343
+ } catch { /* best effort */ }
344
+ }
345
+ }
346
+ result.observations = { status: 'ok', removedFiles: removedObs };
347
+ } catch (error) {
348
+ result.observations = { status: 'degraded', error: error?.message };
349
+ }
350
+ } else {
351
+ result.observations = { status: 'unavailable' };
352
+ }
353
+
354
+ return result;
355
+ }
@@ -3,13 +3,14 @@
3
3
  * lib/storage/backend.mjs — shared storage backend helpers for SQL/vector wiring.
4
4
  */
5
5
  import postgres from 'postgres';
6
+ import { resolveDatabaseUrl } from '../env-config.mjs';
6
7
 
7
8
  function cleanUrl(url) {
8
9
  return String(url || '').trim();
9
10
  }
10
11
 
11
12
  export function createSqlClient(env = process.env) {
12
- const databaseUrl = cleanUrl(env.DATABASE_URL);
13
+ const databaseUrl = cleanUrl(resolveDatabaseUrl(env));
13
14
  if (!databaseUrl) return null;
14
15
  return postgres(databaseUrl, {
15
16
  max: Number.parseInt(env.CONSTRUCT_DB_POOL_SIZE || '5', 10),