@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,378 @@
1
+ /**
2
+ * lib/embed/recommendation-store.mjs — Durable recommendation memory
3
+ * with deduplication and prioritization scoring.
4
+ *
5
+ * Tracks artifact recommendations across daemon lifecycle cycles so the
6
+ * same recommendation isn't surfaced repeatedly. Supports explicit
7
+ * dismissal, automatic suppression after 7 days, and re-surfacing when
8
+ * new signals arrive.
9
+ *
10
+ * Storage:
11
+ * ~/.cx/intake/recommendations.jsonl — append-only log
12
+ * ~/.cx/intake/recommendations-index.json — fast lookup by id
13
+ *
14
+ * Prioritization formula:
15
+ * score = (signalCount * 2) + (customerImpact * 3) + (recencyBonus) + (strategicBonus)
16
+ * P0: score >= 10, P1: >= 7, P2: >= 4, P3: < 4
17
+ */
18
+
19
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, appendFileSync } from 'node:fs';
20
+ import { join } from 'node:path';
21
+ import { randomUUID } from 'node:crypto';
22
+ import { homedir } from 'node:os';
23
+
24
+ const STORE_DIR = join(homedir(), '.cx', 'intake');
25
+ const LOG_FILE = join(STORE_DIR, 'recommendations.jsonl');
26
+ const INDEX_FILE = join(STORE_DIR, 'recommendations-index.json');
27
+
28
+ const DEFAULT_SUPPRESS_DAYS = 7;
29
+ const SUPERSEDE_WITHIN_HOURS = 72;
30
+
31
+ /**
32
+ * Ensure store directory exists.
33
+ */
34
+ function ensureDir() {
35
+ if (!existsSync(STORE_DIR)) mkdirSync(STORE_DIR, { recursive: true });
36
+ }
37
+
38
+ /**
39
+ * Read the index (fast lookup).
40
+ */
41
+ function readIndex() {
42
+ if (!existsSync(INDEX_FILE)) return {};
43
+ try {
44
+ return JSON.parse(readFileSync(INDEX_FILE, 'utf8'));
45
+ } catch {
46
+ return {};
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Write the index.
52
+ */
53
+ function writeIndex(index) {
54
+ ensureDir();
55
+ writeFileSync(INDEX_FILE, JSON.stringify(index, null, 2) + '\n');
56
+ }
57
+
58
+ /**
59
+ * Compute priority tier from score.
60
+ */
61
+ function priorityTier(score) {
62
+ if (score >= 10) return 'P0';
63
+ if (score >= 7) return 'P1';
64
+ if (score >= 4) return 'P2';
65
+ return 'P3';
66
+ }
67
+
68
+ /**
69
+ * Compute a dedup key from recommendation properties.
70
+ * Two recommendations with the same dedup key are considered identical.
71
+ */
72
+ function dedupKey(type, title) {
73
+ return `${type}::${title.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 60)}`;
74
+ }
75
+
76
+ /**
77
+ * Create a recommendation.
78
+ *
79
+ * @param {object} opts
80
+ * @param {string} opts.type - 'prd' | 'adr' | 'rfc' | 'runbook' | 'postmortem'
81
+ * @param {string} opts.title - Human-readable title
82
+ * @param {string} opts.reason - Why this is being recommended
83
+ * @param {number} [opts.signalCount=1] - Number of signals triggering this
84
+ * @param {number} [opts.customerImpact=0] - 0-3: how many customers affected
85
+ * @param {number} [opts.recencyBonus=0] - 0-3: how recent the signals are
86
+ * @param {number} [opts.strategicBonus=0] - 0-3: strategic alignment
87
+ * @param {string[]} [opts.sourceSignalIds] - IDs of intake signals that triggered this
88
+ * @param {string} [opts.lane] - Docs lane this belongs to
89
+ * @returns {{ id: string, dedupKey: string, priority: string, score: number }}
90
+ */
91
+ export function createRecommendation({ type, title, reason, signalCount = 1, customerImpact = 0, recencyBonus = 0, strategicBonus = 0, sourceSignalIds = [], lane }) {
92
+ if (!type || !title) throw new Error('type and title are required');
93
+
94
+ ensureDir();
95
+ const key = dedupKey(type, title);
96
+ const index = readIndex();
97
+
98
+ // Check if already exists (dedup)
99
+ if (index[key]) {
100
+ const existing = index[key];
101
+ if (!existing.supersededAt) {
102
+ // Update existing — increment signal count, extend dates
103
+ const updated = {
104
+ ...existing,
105
+ lastSeen: new Date().toISOString(),
106
+ totalSignalCount: (existing.totalSignalCount || 0) + signalCount,
107
+ signalCount: (existing.signalCount || 0) + signalCount,
108
+ lastSignals: sourceSignalIds.slice(0, 5),
109
+ customerImpact: Math.max(existing.customerImpact || 0, customerImpact),
110
+ recencyBonus: Math.max(existing.recencyBonus || 0, recencyBonus),
111
+ };
112
+ const score = computeScore(updated);
113
+ updated.score = score;
114
+ updated.priority = priorityTier(score);
115
+ index[key] = updated;
116
+ writeIndex(index);
117
+ return { id: existing.id, dedupKey: key, priority: updated.priority, score, existing: true, updatedAt: updated.lastSeen };
118
+ }
119
+ // Existing was dismissed — create new instance with new signals
120
+ // (superseded recommendations can be revived with fresh signals)
121
+ }
122
+
123
+ const id = `rec-${randomUUID().slice(0, 8)}`;
124
+ const score = computeScore({ signalCount, customerImpact, recencyBonus, strategicBonus });
125
+ const rec = {
126
+ id,
127
+ type,
128
+ title,
129
+ reason,
130
+ lane: lane || `${type}s`,
131
+ signalCount,
132
+ totalSignalCount: signalCount,
133
+ customerImpact,
134
+ recencyBonus,
135
+ strategicBonus,
136
+ score,
137
+ priority: priorityTier(score),
138
+ sourceSignalIds: sourceSignalIds.slice(0, 10),
139
+ firstSeen: new Date().toISOString(),
140
+ lastSeen: new Date().toISOString(),
141
+ dismissedAt: null,
142
+ supersededAt: null,
143
+ supersededById: null,
144
+ suppressedUntil: null,
145
+ };
146
+
147
+ // Append to log
148
+ appendFileSync(LOG_FILE, JSON.stringify(rec) + '\n', 'utf8');
149
+
150
+ // Update index
151
+ index[key] = rec;
152
+ writeIndex(index);
153
+
154
+ return { id, dedupKey: key, priority: rec.priority, score, existing: false };
155
+ }
156
+
157
+ /**
158
+ * Compute prioritization score.
159
+ * score = (signalCount * 2) + (customerImpact * 3) + (recencyBonus) + (strategicBonus)
160
+ */
161
+ function computeScore({ signalCount = 1, customerImpact = 0, recencyBonus = 0, strategicBonus = 0 }) {
162
+ return (signalCount * 2) + (customerImpact * 3) + (recencyBonus) + (strategicBonus);
163
+ }
164
+
165
+ /**
166
+ * Dismiss a recommendation (suppress permanently or for N days).
167
+ *
168
+ * @param {string} dedupKey - Dedup key
169
+ * @param {object} [opts]
170
+ * @param {string} [opts.reason] - Why dismissed
171
+ * @param {number} [opts.suppressDays] - Days to suppress (default: forever)
172
+ * @returns {{ success: boolean }}
173
+ */
174
+ export function dismissRecommendation(dedupKey, { reason = 'manually dismissed', suppressDays } = {}) {
175
+ const index = readIndex();
176
+ if (!index[dedupKey]) {
177
+ throw new Error(`Recommendation not found: ${dedupKey}`);
178
+ }
179
+
180
+ index[dedupKey] = {
181
+ ...index[dedupKey],
182
+ dismissedAt: new Date().toISOString(),
183
+ dismissReason: reason,
184
+ suppressedUntil: suppressDays
185
+ ? new Date(Date.now() + suppressDays * 24 * 60 * 60 * 1000).toISOString()
186
+ : null,
187
+ };
188
+
189
+ writeIndex(index);
190
+ return { success: true };
191
+ }
192
+
193
+ /**
194
+ * Supersede a recommendation (mark as replaced by a newer one).
195
+ *
196
+ * @param {string} dedupKey - Existing recommendation to supersede
197
+ * @param {string} supersedingId - ID of the recommendation that replaces it
198
+ * @returns {{ success: boolean }}
199
+ */
200
+ export function supersedeRecommendation(dedupKey, supersedingId) {
201
+ const index = readIndex();
202
+ if (!index[dedupKey]) {
203
+ throw new Error(`Recommendation not found: ${dedupKey}`);
204
+ }
205
+
206
+ index[dedupKey] = {
207
+ ...index[dedupKey],
208
+ supersededAt: new Date().toISOString(),
209
+ supersededById: supersedingId,
210
+ };
211
+
212
+ writeIndex(index);
213
+ return { success: true };
214
+ }
215
+
216
+ /**
217
+ * List active (non-dismissed, non-superseded) recommendations.
218
+ *
219
+ * @param {object} [opts]
220
+ * @param {string} [opts.type] - Filter by type
221
+ * @param {string} [opts.priority] - Filter by priority (P0, P1, etc.)
222
+ * @param {number} [opts.limit=20]
223
+ * @returns {Array<object>}
224
+ */
225
+ export function listActiveRecommendations({ type, priority, limit = 20 } = {}) {
226
+ const index = readIndex();
227
+ const now = new Date();
228
+ let results = Object.values(index).filter(rec => {
229
+ // Skip dismissed (unless temporary suppress and still active)
230
+ if (rec.dismissedAt) {
231
+ if (rec.suppressedUntil && new Date(rec.suppressedUntil) > now) return false;
232
+ if (!rec.suppressedUntil) return false;
233
+ }
234
+ // Skip superseded
235
+ if (rec.supersededAt) return false;
236
+ // Skip suppressed
237
+ if (rec.suppressedUntil && new Date(rec.suppressedUntil) > now) return false;
238
+ return true;
239
+ });
240
+
241
+ if (type) results = results.filter(r => r.type === type);
242
+ if (priority) results = results.filter(r => r.priority === priority);
243
+
244
+ return results
245
+ .sort((a, b) => (b.score || 0) - (a.score || 0))
246
+ .slice(0, limit);
247
+ }
248
+
249
+ /**
250
+ * Auto-suppress recommendations that have been active for DEFAULT_SUPPRESS_DAYS
251
+ * without new signals, or that were superseded more than SUPERSEDE_WITHIN_HOURS ago.
252
+ * Call from docs-lifecycle or a scheduled daemon job.
253
+ *
254
+ * @returns {number} Number of recommendations suppressed
255
+ */
256
+ export function autoSuppressStale() {
257
+ const index = readIndex();
258
+ const now = Date.now();
259
+ let suppressed = 0;
260
+
261
+ for (const [key, rec] of Object.entries(index)) {
262
+ if (rec.dismissedAt || rec.supersededAt) continue;
263
+
264
+ // Suppress if lastSeen is older than DEFAULT_SUPPRESS_DAYS
265
+ const lastSeen = new Date(rec.lastSeen || rec.firstSeen).getTime();
266
+ const ageDays = (now - lastSeen) / (24 * 60 * 60 * 1000);
267
+ if (ageDays > DEFAULT_SUPPRESS_DAYS) {
268
+ index[key] = {
269
+ ...rec,
270
+ suppressedUntil: new Date(now + DEFAULT_SUPPRESS_DAYS * 24 * 60 * 60 * 1000).toISOString(),
271
+ suppressReason: 'stale',
272
+ };
273
+ suppressed++;
274
+ continue;
275
+ }
276
+
277
+ // Suppress superseded older than threshold
278
+ if (rec.supersededAt) {
279
+ const supersededAt = new Date(rec.supersededAt).getTime();
280
+ if ((now - supersededAt) > SUPERSEDE_WITHIN_HOURS * 60 * 60 * 1000) {
281
+ index[key] = {
282
+ ...rec,
283
+ suppressedUntil: new Date(now + 30 * 24 * 60 * 60 * 1000).toISOString(),
284
+ suppressReason: 'superseded',
285
+ };
286
+ suppressed++;
287
+ }
288
+ }
289
+ }
290
+
291
+ if (suppressed) writeIndex(index);
292
+ return suppressed;
293
+ }
294
+
295
+ /**
296
+ * Revive a recommendation from dismissal with new signals.
297
+ *
298
+ * @param {string} dedupKey
299
+ * @param {object} newSignals
300
+ * @param {number} [newSignals.signalCount=1]
301
+ * @param {string[]} [newSignals.sourceSignalIds]
302
+ * @returns {{ success: boolean }}
303
+ */
304
+ export function reviveRecommendation(dedupKey, { signalCount = 1, sourceSignalIds = [] } = {}) {
305
+ const index = readIndex();
306
+ if (!index[dedupKey]) {
307
+ throw new Error(`Recommendation not found: ${dedupKey}`);
308
+ }
309
+
310
+ const existing = index[dedupKey];
311
+ const updatedSignalCount = (existing.totalSignalCount || 0) + signalCount;
312
+ const score = computeScore({
313
+ signalCount: updatedSignalCount,
314
+ customerImpact: existing.customerImpact || 0,
315
+ recencyBonus: 3, // recent signals get max recency bonus
316
+ strategicBonus: existing.strategicBonus || 0,
317
+ });
318
+
319
+ index[dedupKey] = {
320
+ ...existing,
321
+ lastSeen: new Date().toISOString(),
322
+ totalSignalCount: updatedSignalCount,
323
+ signalCount,
324
+ score,
325
+ priority: priorityTier(score),
326
+ sourceSignalIds: [...(existing.sourceSignalIds || []), ...sourceSignalIds].slice(0, 10),
327
+ dismissedAt: null,
328
+ suppressedUntil: null,
329
+ dismissReason: null,
330
+ };
331
+
332
+ writeIndex(index);
333
+ return { success: true };
334
+ }
335
+
336
+ /**
337
+ * Get store statistics.
338
+ *
339
+ * @returns {{ total: number, active: number, dismissed: number, superseded: number, byPriority: object }}
340
+ */
341
+ export function recommendationStats() {
342
+ const index = readIndex();
343
+ const entries = Object.values(index);
344
+ const byPriority = {};
345
+ let active = 0, dismissed = 0, superseded = 0;
346
+
347
+ for (const rec of entries) {
348
+ if (rec.dismissedAt) { dismissed++; continue; }
349
+ if (rec.supersededAt) { superseded++; continue; }
350
+ active++;
351
+ byPriority[rec.priority] = (byPriority[rec.priority] || 0) + 1;
352
+ }
353
+
354
+ return {
355
+ total: entries.length,
356
+ active,
357
+ dismissed,
358
+ superseded,
359
+ byPriority,
360
+ byType: entries.reduce((acc, r) => { acc[r.type] = (acc[r.type] || 0) + 1; return acc; }, {}),
361
+ };
362
+ }
363
+
364
+ /**
365
+ * Check if a recommendation with the given dedup key is active.
366
+ *
367
+ * @param {string} type
368
+ * @param {string} title
369
+ * @returns {{ active: boolean, existing: object|null }}
370
+ */
371
+ export function isRecommendationActive(type, title) {
372
+ const key = dedupKey(type, title);
373
+ const index = readIndex();
374
+ const rec = index[key];
375
+ if (!rec) return { active: false, existing: null };
376
+ if (rec.dismissedAt || rec.supersededAt) return { active: false, existing: rec };
377
+ return { active: true, existing: rec };
378
+ }