@geraldmaron/construct 1.4.1 → 1.5.0

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 (556) hide show
  1. package/.env.example +36 -0
  2. package/README.md +41 -7
  3. package/bin/construct +1029 -65
  4. package/bin/construct-postinstall.mjs +27 -2
  5. package/config/tag-vocabulary.json +264 -0
  6. package/examples/distribution/sources/deck-one-pager.md +1 -1
  7. package/lib/acp/server.mjs +21 -7
  8. package/lib/adapters-sync.mjs +2 -1
  9. package/lib/audit-trail.mjs +185 -2
  10. package/lib/beads/auto-close.mjs +2 -1
  11. package/lib/beads/drift.mjs +2 -1
  12. package/lib/bridges/copilot-proxy.mjs +20 -5
  13. package/lib/certification/skill-inventory.mjs +10 -1
  14. package/lib/cli/approvals.mjs +147 -0
  15. package/lib/cli-commands.mjs +105 -14
  16. package/lib/comment-lint.mjs +127 -8
  17. package/lib/config/schema.mjs +7 -30
  18. package/lib/config/source-target-registry.mjs +70 -0
  19. package/lib/config/source-targets.mjs +179 -205
  20. package/lib/contracts/coverage.mjs +77 -0
  21. package/lib/contracts/validate.mjs +102 -13
  22. package/lib/contracts/violation-log.mjs +50 -4
  23. package/lib/db/migrate.mjs +69 -0
  24. package/lib/db/migrations/001_orchestration_runs.sql +9 -0
  25. package/lib/db/migrations/002_queue_provider.sql +50 -0
  26. package/lib/db/migrations/003_worker_registry.sql +17 -0
  27. package/lib/db/migrations/004_trace_events.sql +16 -0
  28. package/lib/db/migrations/005_shared_memory.sql +15 -0
  29. package/lib/db/migrations/006_orchestration_runs_tenant.sql +5 -0
  30. package/lib/decisions/enforced-baseline.json +0 -2
  31. package/lib/decisions/registry.mjs +3 -2
  32. package/lib/deployment/parity-contract.mjs +1 -1
  33. package/lib/deployment-mode.mjs +78 -2
  34. package/lib/diagram-export.mjs +10 -1
  35. package/lib/distill.mjs +5 -2
  36. package/lib/docs-verify.mjs +2 -1
  37. package/lib/doctor/cli.mjs +1 -0
  38. package/lib/doctor/command-on-path.mjs +24 -0
  39. package/lib/doctor/diagnosis.mjs +109 -0
  40. package/lib/doctor/embedding-health.mjs +50 -0
  41. package/lib/doctor/engine-health.mjs +93 -0
  42. package/lib/doctor/graph-validate.mjs +47 -0
  43. package/lib/doctor/index.mjs +23 -4
  44. package/lib/doctor/sidecar-providers.mjs +56 -0
  45. package/lib/doctor/watchers/consistency.mjs +93 -1
  46. package/lib/doctor/watchers/cx-budget.mjs +1 -1
  47. package/lib/doctor/watchers/graph-staleness.mjs +1 -1
  48. package/lib/doctor/watchers/mcp-protocol.mjs +17 -0
  49. package/lib/doctor/watchers/oracle-liveness.mjs +92 -0
  50. package/lib/doctor/watchers/orchestration-runs.mjs +108 -0
  51. package/lib/doctor/watchers/provider-breaker.mjs +78 -0
  52. package/lib/document-export.mjs +52 -27
  53. package/lib/document-extract/docling-client.mjs +9 -5
  54. package/lib/document-extract/docling-sidecar.py +30 -0
  55. package/lib/document-extract.mjs +1 -1
  56. package/lib/document-ingest.mjs +9 -0
  57. package/lib/embed/approval-queue.mjs +184 -88
  58. package/lib/embed/authority-guard.mjs +65 -2
  59. package/lib/embed/capability-jobs.mjs +365 -0
  60. package/lib/embed/capability-lifecycle.mjs +219 -0
  61. package/lib/embed/capability-loader.mjs +303 -0
  62. package/lib/embed/capability-runtime.mjs +58 -0
  63. package/lib/embed/cli.mjs +185 -8
  64. package/lib/embed/config.mjs +4 -0
  65. package/lib/embed/daemon.mjs +125 -6
  66. package/lib/embed/demand-fetch.mjs +190 -54
  67. package/lib/embed/inbox.mjs +12 -10
  68. package/lib/embed/presets/ops-triage.mjs +236 -0
  69. package/lib/embed/presets/pm-feedback.mjs +341 -0
  70. package/lib/embed/presets/tpm.mjs +401 -0
  71. package/lib/embed/providers/jira.mjs +72 -1
  72. package/lib/embed/providers/registry.mjs +140 -33
  73. package/lib/embed/worker.mjs +5 -0
  74. package/lib/embedded-contract/capability.mjs +4 -0
  75. package/lib/embedded-contract/execution.mjs +1 -1
  76. package/lib/embedded-contract/model-resolve.mjs +53 -3
  77. package/lib/embedded-contract/workflow-defs.mjs +48 -73
  78. package/lib/embedded-contract/workflow-invoke.mjs +144 -4
  79. package/lib/embedded-contract/workflows/architecture-review.manifest.json +15 -0
  80. package/lib/embedded-contract/workflows/data-structure.manifest.json +14 -0
  81. package/lib/embedded-contract/workflows/evidence-ingest.manifest.json +14 -0
  82. package/lib/embedded-contract/workflows/memo-draft.manifest.json +14 -0
  83. package/lib/embedded-contract/workflows/operations-triage.manifest.json +18 -0
  84. package/lib/embedded-contract/workflows/operations.manifest.json +18 -0
  85. package/lib/embedded-contract/workflows/pm-feedback.manifest.json +18 -0
  86. package/lib/embedded-contract/workflows/prd-draft.manifest.json +15 -0
  87. package/lib/embedded-contract/workflows/proposal-review.manifest.json +15 -0
  88. package/lib/embedded-contract/workflows/research-synthesis.manifest.json +14 -0
  89. package/lib/embedded-contract/workflows/risk-review.manifest.json +15 -0
  90. package/lib/embedded-contract/workflows/structure-notes.manifest.json +14 -0
  91. package/lib/embedded-contract/workflows/transcript-process.manifest.json +14 -0
  92. package/lib/embedded-contract/workflows/triage.manifest.json +14 -0
  93. package/lib/env-config.mjs +60 -11
  94. package/lib/export-validate.mjs +34 -2
  95. package/lib/extensions/index.mjs +27 -0
  96. package/lib/extensions/loader.mjs +120 -0
  97. package/lib/extensions/manifest-schema.mjs +141 -0
  98. package/lib/extensions/manifests/anthropic.manifest.json +12 -0
  99. package/lib/extensions/manifests/atlassian-confluence.manifest.json +12 -0
  100. package/lib/extensions/manifests/atlassian-jira.manifest.json +53 -0
  101. package/lib/extensions/manifests/directory.manifest.json +12 -0
  102. package/lib/extensions/manifests/docling.manifest.json +37 -0
  103. package/lib/extensions/manifests/echo.manifest.json +8 -0
  104. package/lib/extensions/manifests/feedback.manifest.json +12 -0
  105. package/lib/extensions/manifests/github-copilot.manifest.json +12 -0
  106. package/lib/extensions/manifests/github.manifest.json +52 -0
  107. package/lib/extensions/manifests/linear.manifest.json +50 -0
  108. package/lib/extensions/manifests/local.manifest.json +12 -0
  109. package/lib/extensions/manifests/ollama.manifest.json +12 -0
  110. package/lib/extensions/manifests/openai.manifest.json +12 -0
  111. package/lib/extensions/manifests/openrouter-anthropic.manifest.json +12 -0
  112. package/lib/extensions/manifests/openrouter-deepseek.manifest.json +12 -0
  113. package/lib/extensions/manifests/openrouter-google.manifest.json +12 -0
  114. package/lib/extensions/manifests/openrouter-llama.manifest.json +12 -0
  115. package/lib/extensions/manifests/openrouter-qwen.manifest.json +12 -0
  116. package/lib/extensions/manifests/openrouter.manifest.json +12 -0
  117. package/lib/extensions/manifests/postgres.manifest.json +12 -0
  118. package/lib/extensions/manifests/salesforce.manifest.json +12 -0
  119. package/lib/extensions/manifests/slack.manifest.json +58 -0
  120. package/lib/extensions/manifests/whisper.manifest.json +36 -0
  121. package/lib/extensions/validate.mjs +175 -0
  122. package/lib/features.mjs +13 -9
  123. package/lib/flows/checkpoint.mjs +184 -0
  124. package/lib/flows/constants.mjs +27 -0
  125. package/lib/flows/define.mjs +146 -0
  126. package/lib/flows/engine.mjs +249 -0
  127. package/lib/flows/errors.mjs +19 -0
  128. package/lib/flows/index.mjs +27 -0
  129. package/lib/flows/joins.mjs +18 -0
  130. package/lib/flows/schema.mjs +90 -0
  131. package/lib/flows/state.mjs +31 -0
  132. package/lib/frameworks/loader.mjs +99 -0
  133. package/lib/frameworks/schema.mjs +157 -0
  134. package/lib/graph/build-from-corpus.mjs +67 -0
  135. package/lib/graph/build-from-embed.mjs +82 -0
  136. package/lib/graph/build-from-registry.mjs +164 -3
  137. package/lib/graph/cli.mjs +456 -12
  138. package/lib/graph/gap-queries.mjs +156 -0
  139. package/lib/graph/gaps.mjs +41 -0
  140. package/lib/graph/impacted.mjs +129 -0
  141. package/lib/graph/runtime-evidence.mjs +177 -0
  142. package/lib/graph/security-coverage.mjs +113 -0
  143. package/lib/graph/staleness.mjs +241 -10
  144. package/lib/graph/store.mjs +24 -7
  145. package/lib/graph/validate.mjs +161 -0
  146. package/lib/headhunt.mjs +9 -8
  147. package/lib/health-check.mjs +15 -7
  148. package/lib/hook-health.mjs +1 -1
  149. package/lib/hooks/agent-tracker.mjs +10 -4
  150. package/lib/hooks/edit-guard.mjs +3 -3
  151. package/lib/hooks/graph-impact-advisory.mjs +2 -2
  152. package/lib/hooks/guard-bash.mjs +41 -15
  153. package/lib/hooks/mcp-health-check.mjs +11 -4
  154. package/lib/hooks/model-fallback.mjs +50 -6
  155. package/lib/hooks/orchestration-dispatch-guard.mjs +14 -3
  156. package/lib/hooks/pre-compact.mjs +181 -173
  157. package/lib/hooks/rule-verifier.mjs +2 -1
  158. package/lib/hooks/session-reflect.mjs +2 -1
  159. package/lib/hooks/session-start.mjs +3 -3
  160. package/lib/host/readiness.mjs +109 -0
  161. package/lib/host-capabilities.mjs +13 -2
  162. package/lib/host-disposition.mjs +29 -8
  163. package/lib/identity.mjs +92 -0
  164. package/lib/ingest/degraded-extract.mjs +96 -0
  165. package/lib/ingest/docling-remote.mjs +2 -1
  166. package/lib/ingest/provider-extract.mjs +7 -19
  167. package/lib/ingest/sidecar-providers.mjs +196 -0
  168. package/lib/ingest-tooling.mjs +11 -5
  169. package/lib/init-unified.mjs +55 -38
  170. package/lib/init-update.mjs +2 -1
  171. package/lib/install/legacy-global-cleanup.mjs +25 -0
  172. package/lib/install/stage-project.mjs +41 -4
  173. package/lib/intake/daemon.mjs +99 -8
  174. package/lib/intake/git-queue.mjs +110 -38
  175. package/lib/intake/prepare.mjs +2 -0
  176. package/lib/intake/queue-registry.mjs +50 -0
  177. package/lib/intake/queue.mjs +133 -17
  178. package/lib/intake/session-prelude.mjs +57 -8
  179. package/lib/integrations/intake-integrations.mjs +61 -111
  180. package/lib/intent-classifier.mjs +43 -5
  181. package/lib/libreoffice-export.mjs +8 -8
  182. package/lib/logging/rotate.mjs +5 -4
  183. package/lib/mcp/broker.mjs +332 -17
  184. package/lib/mcp/denied-store.mjs +95 -0
  185. package/lib/mcp/destructive-approval.mjs +57 -0
  186. package/lib/mcp/destructive-gate.mjs +30 -0
  187. package/lib/mcp/dispatch-envelope.mjs +199 -0
  188. package/lib/mcp/memory-bridge.mjs +2 -1
  189. package/lib/mcp/server.mjs +185 -1268
  190. package/lib/mcp/tool-definitions-memory.mjs +376 -0
  191. package/lib/mcp/tool-definitions-project.mjs +271 -0
  192. package/lib/mcp/tool-definitions-skills.mjs +311 -0
  193. package/lib/mcp/tool-definitions-workflow.mjs +398 -0
  194. package/lib/mcp/tool-definitions.mjs +25 -0
  195. package/lib/mcp/tool-rate-limit.mjs +47 -0
  196. package/lib/mcp/tool-registry.mjs +107 -0
  197. package/lib/mcp/tool-safety.mjs +95 -0
  198. package/lib/mcp/tool-surface-parity.mjs +60 -0
  199. package/lib/mcp/tools/orchestration-delegation-next.tool.mjs +68 -0
  200. package/lib/mcp/tools/orchestration-run.mjs +197 -19
  201. package/lib/mcp/tools/orchestration-task-result.tool.mjs +77 -0
  202. package/lib/mcp/tools/project.mjs +25 -8
  203. package/lib/mcp/tools/provider-write.mjs +187 -0
  204. package/lib/mcp/tools/scope.mjs +0 -3
  205. package/lib/mcp/tools/skills.mjs +1 -1
  206. package/lib/mcp/tools/storage.mjs +2 -2
  207. package/lib/mcp/tools/web-search-governance.mjs +96 -0
  208. package/lib/mcp/tools/web-search.mjs +5 -76
  209. package/lib/mcp/transport/auth.mjs +238 -0
  210. package/lib/mcp/transport/http.mjs +136 -0
  211. package/lib/mcp/transport/mode.mjs +31 -0
  212. package/lib/mcp/transport/stdio.mjs +22 -0
  213. package/lib/mcp-catalog.json +4 -4
  214. package/lib/mcp-manager.mjs +34 -23
  215. package/lib/mcp-platform-config.mjs +53 -20
  216. package/lib/mode-capabilities.mjs +109 -0
  217. package/lib/model-router.mjs +42 -9
  218. package/lib/models/catalog.mjs +40 -1
  219. package/lib/net-guard.mjs +247 -0
  220. package/lib/observation-store.mjs +6 -2
  221. package/lib/ollama/provision-context.mjs +2 -1
  222. package/lib/opencode-config.mjs +22 -3
  223. package/lib/opencode-runtime-plugin.mjs +120 -2
  224. package/lib/oracle/actions.mjs +204 -10
  225. package/lib/oracle/cli.mjs +24 -3
  226. package/lib/oracle/daemon-entry.mjs +6 -0
  227. package/lib/oracle/dispatch.mjs +2 -1
  228. package/lib/oracle/execute.mjs +2 -2
  229. package/lib/oracle/gaps.mjs +3 -3
  230. package/lib/oracle/heartbeat.mjs +53 -0
  231. package/lib/oracle/read-model.mjs +69 -13
  232. package/lib/oracle/reconcile.mjs +3 -46
  233. package/lib/oracle/routing.mjs +37 -31
  234. package/lib/oracle/synthesize.mjs +1 -1
  235. package/lib/orchestration/classification.mjs +434 -0
  236. package/lib/orchestration/delegation-flow.mjs +132 -0
  237. package/lib/orchestration/flow-selection.mjs +418 -0
  238. package/lib/orchestration/gates.mjs +244 -0
  239. package/lib/orchestration/host-sampling.mjs +121 -0
  240. package/lib/orchestration/policy-constants.mjs +48 -0
  241. package/lib/orchestration/provider-outcome.mjs +197 -0
  242. package/lib/orchestration/readiness.mjs +114 -13
  243. package/lib/orchestration/run-store-postgres.mjs +32 -26
  244. package/lib/orchestration/run-store-sqlite.mjs +8 -14
  245. package/lib/orchestration/run-store.mjs +25 -12
  246. package/lib/orchestration/runtime.mjs +508 -62
  247. package/lib/orchestration/store.mjs +87 -12
  248. package/lib/orchestration/trace-store.mjs +125 -0
  249. package/lib/orchestration/web-capability.mjs +60 -0
  250. package/lib/orchestration/worker-runtime.mjs +162 -0
  251. package/lib/orchestration/worker.mjs +763 -80
  252. package/lib/orchestration-policy.mjs +67 -1111
  253. package/lib/output-quality.mjs +61 -2
  254. package/lib/packs/cli.mjs +144 -0
  255. package/lib/packs/core-pack.mjs +112 -0
  256. package/lib/packs/enablement.mjs +187 -0
  257. package/lib/packs/index.mjs +23 -0
  258. package/lib/packs/loader.mjs +176 -0
  259. package/lib/packs/manifest-schema.mjs +58 -0
  260. package/lib/packs/prompts.mjs +120 -0
  261. package/lib/packs/validate.mjs +208 -0
  262. package/lib/path-policy.mjs +56 -0
  263. package/lib/plugin-registry.mjs +4 -5
  264. package/lib/policy/audit-gate.mjs +42 -0
  265. package/lib/policy/consumption-budget.mjs +149 -0
  266. package/lib/policy/engine.mjs +81 -6
  267. package/lib/policy/role-authority.mjs +89 -0
  268. package/lib/prompt-composer.js +19 -3
  269. package/lib/providers/contract/adapters/confluence/governed-write.mjs +215 -0
  270. package/lib/providers/contract/adapters/confluence/manifest.json +17 -0
  271. package/lib/providers/contract/adapters/confluence/transport.mjs +135 -0
  272. package/lib/providers/contract/adapters/github/governed-write.mjs +121 -0
  273. package/lib/providers/contract/adapters/github/index.mjs +38 -3
  274. package/lib/providers/contract/adapters/jira/adf.mjs +151 -0
  275. package/lib/providers/contract/adapters/jira/createmeta.mjs +143 -0
  276. package/lib/providers/contract/adapters/jira/governed-write.mjs +182 -0
  277. package/lib/providers/contract/adapters/jira/manifest.json +17 -0
  278. package/lib/providers/contract/adapters/jira/transport.mjs +119 -0
  279. package/lib/providers/contract.mjs +207 -0
  280. package/lib/providers/credential-bootstrap.mjs +7 -4
  281. package/lib/providers/credential-sources.mjs +14 -2
  282. package/lib/providers/directory/index.mjs +261 -0
  283. package/lib/providers/feedback/index.mjs +392 -0
  284. package/lib/providers/filter-audit.mjs +68 -0
  285. package/lib/providers/filter-schema.mjs +54 -0
  286. package/lib/providers/github/index.mjs +31 -0
  287. package/lib/providers/instance-config.mjs +215 -0
  288. package/lib/providers/op-locate.mjs +96 -0
  289. package/lib/providers/op-run.mjs +64 -9
  290. package/lib/providers/registry.mjs +26 -3
  291. package/lib/providers/secret-audit-wiring.mjs +41 -18
  292. package/lib/providers/secret-resolver.mjs +263 -31
  293. package/lib/publish-template.mjs +6 -3
  294. package/lib/publish-tooling.mjs +4 -0
  295. package/lib/publish.mjs +32 -4
  296. package/lib/queue/pg-queue.mjs +395 -0
  297. package/lib/reflect.mjs +2 -1
  298. package/lib/registry/assemble.mjs +28 -2
  299. package/lib/registry/catalog.mjs +6 -0
  300. package/lib/registry/consolidation.mjs +8 -1
  301. package/lib/registry/custom-scaffold.mjs +200 -0
  302. package/lib/registry/custom-schema.mjs +137 -0
  303. package/lib/registry/loader.mjs +15 -4
  304. package/lib/registry/manifests/format-engines.default.json +15 -0
  305. package/lib/registry/manifests/surface-map.default.json +46 -0
  306. package/lib/registry/retired-paths.mjs +1 -0
  307. package/lib/registry/surface-map.mjs +100 -50
  308. package/lib/registry/validate.mjs +3 -3
  309. package/lib/render-visual-check.mjs +240 -0
  310. package/lib/resources/budget.mjs +40 -17
  311. package/lib/roles/flavor-bindings.mjs +36 -14
  312. package/lib/roles/gateway.mjs +15 -8
  313. package/lib/roots.mjs +107 -0
  314. package/lib/runtime/uv-bootstrap.mjs +32 -6
  315. package/lib/runtime/whisper-bootstrap.mjs +11 -3
  316. package/lib/runtime-env.mjs +5 -2
  317. package/lib/sandbox.mjs +1 -1
  318. package/lib/scheduler/index.mjs +8 -20
  319. package/lib/schema-infer.mjs +31 -2
  320. package/lib/scopes/lifecycle.mjs +29 -25
  321. package/lib/scopes/loader.mjs +49 -12
  322. package/lib/scopes/teams.mjs +1 -1
  323. package/lib/security/ingest-boundary.mjs +80 -0
  324. package/lib/security/recall-wrapper.mjs +99 -0
  325. package/lib/security/trust.mjs +132 -0
  326. package/lib/service-manager.mjs +93 -24
  327. package/lib/setup.mjs +41 -23
  328. package/lib/skills-apply.mjs +4 -2
  329. package/lib/specialists/postconditions.mjs +2 -2
  330. package/lib/state-root.mjs +147 -0
  331. package/lib/status.mjs +597 -6
  332. package/lib/storage/admin.mjs +84 -7
  333. package/lib/storage/backend-registry.mjs +73 -0
  334. package/lib/storage/backend.mjs +63 -9
  335. package/lib/storage/embeddings-openai.mjs +12 -2
  336. package/lib/storage/hybrid-query.mjs +11 -3
  337. package/lib/storage/retrieval-hardening.mjs +384 -0
  338. package/lib/storage/shared-memory.mjs +158 -0
  339. package/lib/storage/vector-client.mjs +69 -2
  340. package/lib/team/health.mjs +72 -0
  341. package/lib/telemetry/backends/local.mjs +9 -3
  342. package/lib/telemetry/client.mjs +3 -7
  343. package/lib/template-registry.mjs +10 -12
  344. package/lib/tenant/context.mjs +82 -0
  345. package/lib/tenant/isolation.mjs +129 -0
  346. package/lib/test-corpus-inventory.mjs +103 -2
  347. package/lib/uninstall/uninstall.mjs +78 -12
  348. package/lib/validator.mjs +4 -6
  349. package/lib/worker/entrypoint.mjs +2 -1
  350. package/lib/worker/run.mjs +2 -2
  351. package/lib/worker/trace.mjs +5 -11
  352. package/lib/workflow-state.mjs +52 -8
  353. package/lib/workflows/liveness.mjs +203 -0
  354. package/lib/workflows/loader.mjs +177 -0
  355. package/lib/workflows/manifest-schema.mjs +71 -0
  356. package/lib/workflows/surface-parity.mjs +118 -0
  357. package/lib/workflows/validate.mjs +127 -0
  358. package/lib/writes/control-plane.mjs +140 -0
  359. package/lib/writes/envelope.mjs +206 -0
  360. package/lib/writes/sent-log.mjs +86 -0
  361. package/lib/writes/write-intent.mjs +109 -0
  362. package/package.json +20 -7
  363. package/personas/construct.md +12 -3
  364. package/registry/agent-manifest.json +117 -0
  365. package/registry/capabilities.json +1987 -0
  366. package/rules/common/comments.md +1 -0
  367. package/schemas/brand-voice.schema.json +24 -0
  368. package/schemas/capability-registry.schema.json +72 -0
  369. package/schemas/certification-run.schema.json +130 -0
  370. package/schemas/demo-recording.schema.json +46 -0
  371. package/schemas/eval-dataset.schema.json +79 -0
  372. package/schemas/execution-capability-profile.schema.json +46 -0
  373. package/schemas/execution-policy.schema.json +114 -0
  374. package/schemas/improvement-proposal.schema.json +65 -0
  375. package/schemas/mcp-tool-output.schema.json +61 -0
  376. package/schemas/platform-capabilities.schema.json +83 -0
  377. package/schemas/project-config.schema.json +215 -0
  378. package/schemas/project-demo.schema.json +60 -0
  379. package/schemas/provider-behavior-matrix.schema.json +91 -0
  380. package/schemas/scope.schema.json +197 -0
  381. package/schemas/specialist-trace.schema.json +107 -0
  382. package/schemas/team.schema.json +99 -0
  383. package/schemas/unified-registry.schema.json +546 -0
  384. package/scripts/sync-specialists.mjs +336 -106
  385. package/skills/docs/adr-workflow.md +1 -1
  386. package/skills/docs/codebase-research-workflow.md +3 -3
  387. package/skills/docs/prd-workflow.md +5 -6
  388. package/skills/docs/runbook-workflow.md +2 -2
  389. package/skills/docs/user-research-workflow.md +3 -3
  390. package/skills/operating/fleet-health-routing.md +77 -0
  391. package/skills/roles/ai-engineer.md +1 -1
  392. package/skills/roles/architect.md +0 -1
  393. package/skills/roles/business-strategist.md +1 -1
  394. package/skills/roles/data-analyst.telemetry.md +1 -1
  395. package/skills/roles/data-engineer.md +1 -1
  396. package/skills/roles/data-engineer.pipeline.md +1 -1
  397. package/skills/roles/data-engineer.vector-retrieval.md +1 -2
  398. package/skills/roles/data-engineer.warehouse.md +1 -1
  399. package/skills/roles/designer.accessibility.md +1 -1
  400. package/skills/roles/designer.md +0 -1
  401. package/skills/roles/devil-advocate.md +1 -1
  402. package/skills/roles/docs-keeper.md +1 -1
  403. package/skills/roles/evaluator.md +1 -1
  404. package/skills/roles/explorer.md +1 -1
  405. package/skills/roles/platform-engineer.md +1 -1
  406. package/skills/roles/qa.ai-eval.md +1 -2
  407. package/skills/roles/qa.api-contract.md +0 -1
  408. package/skills/roles/qa.data-pipeline.md +0 -1
  409. package/skills/roles/qa.md +0 -1
  410. package/skills/roles/qa.web-ui.md +0 -1
  411. package/skills/roles/release-manager.md +1 -1
  412. package/skills/roles/researcher.md +0 -2
  413. package/skills/roles/reviewer.md +0 -3
  414. package/skills/roles/security.ai.md +1 -1
  415. package/skills/roles/security.legal-compliance.md +1 -1
  416. package/skills/roles/security.md +0 -1
  417. package/skills/roles/security.privacy.md +0 -1
  418. package/skills/roles/security.supply-chain.md +1 -1
  419. package/skills/roles/sre.md +1 -1
  420. package/skills/roles/test-automation.md +1 -1
  421. package/skills/roles/trace-reviewer.md +1 -1
  422. package/skills/roles/ux-researcher.md +1 -1
  423. package/specialists/artifact-manifest.json +36 -36
  424. package/specialists/org/contracts/accessibility-to-qa.json +11 -3
  425. package/specialists/org/contracts/any-to-business-strategist.json +19 -7
  426. package/specialists/org/contracts/any-to-debugger.json +7 -1
  427. package/specialists/org/contracts/any-to-designer.json +7 -1
  428. package/specialists/org/contracts/any-to-docs-keeper.json +18 -4
  429. package/specialists/org/contracts/any-to-explorer.json +13 -4
  430. package/specialists/org/contracts/any-to-sre-incident.json +6 -2
  431. package/specialists/org/contracts/any-to-trace-reviewer.json +16 -4
  432. package/specialists/org/contracts/architect-to-ai-engineer.json +6 -2
  433. package/specialists/org/contracts/architect-to-data-engineer.json +17 -5
  434. package/specialists/org/contracts/architect-to-devil-advocate.json +11 -3
  435. package/specialists/org/contracts/architect-to-engineer.json +20 -4
  436. package/specialists/org/contracts/architect-to-evaluator.json +15 -5
  437. package/specialists/org/contracts/architect-to-legal-compliance.json +15 -5
  438. package/specialists/org/contracts/architect-to-operations.json +17 -4
  439. package/specialists/org/contracts/architect-to-platform-engineer.json +20 -4
  440. package/specialists/org/contracts/construct-to-orchestrator.json +10 -2
  441. package/specialists/org/contracts/data-analyst-to-product-manager.json +11 -2
  442. package/specialists/org/contracts/engineer-to-qa.json +20 -4
  443. package/specialists/org/contracts/engineer-to-reviewer.json +29 -5
  444. package/specialists/org/contracts/explorer-to-engineer.json +11 -3
  445. package/specialists/org/contracts/legal-compliance-to-release-manager.json +12 -4
  446. package/specialists/org/contracts/operations-to-user.json +53 -0
  447. package/specialists/org/contracts/operations-triage-output.json +53 -0
  448. package/specialists/org/contracts/pm-requirements-candidates.json +53 -0
  449. package/specialists/org/contracts/product-manager-to-architect.json +30 -10
  450. package/specialists/org/contracts/product-manager-to-data-analyst.json +13 -3
  451. package/specialists/org/contracts/product-manager-to-ux-researcher.json +15 -5
  452. package/specialists/org/contracts/qa-to-release-manager.json +11 -3
  453. package/specialists/org/contracts/researcher-to-architect.json +10 -2
  454. package/specialists/org/contracts/researcher-to-product-manager.json +16 -5
  455. package/specialists/org/contracts/reviewer-to-security.json +17 -3
  456. package/specialists/org/contracts/test-automation-to-engineer.json +11 -3
  457. package/specialists/org/contracts/trace-reviewer-to-sre.json +12 -4
  458. package/specialists/org/contracts/user-to-construct.json +11 -4
  459. package/specialists/org/frameworks/cx-architect-constraint-option-failure.md +66 -0
  460. package/specialists/org/frameworks/cx-engineer-feasibility-blast-radius.md +66 -0
  461. package/specialists/org/frameworks/cx-ops-dependency-sequencing.md +74 -0
  462. package/specialists/org/frameworks/cx-pm-value-tradeoff.md +66 -0
  463. package/specialists/org/frameworks/cx-qa-risk-based-coverage.md +69 -0
  464. package/specialists/org/groups/engineering-group.json +2 -6
  465. package/specialists/org/groups/governance-group.json +2 -3
  466. package/specialists/org/groups/operations-group.json +5 -8
  467. package/specialists/org/groups/product-group.json +4 -8
  468. package/specialists/org/groups/quality-group.json +3 -7
  469. package/specialists/org/groups/strategy-group.json +6 -9
  470. package/specialists/org/models.json.example +8 -0
  471. package/specialists/org/scopes/creative.json +6 -1
  472. package/specialists/org/scopes/operations.json +7 -1
  473. package/specialists/org/scopes/research.json +6 -1
  474. package/specialists/org/scopes/rnd.json +7 -1
  475. package/specialists/org/specialists/cx-architect.json +27 -8
  476. package/specialists/org/specialists/cx-designer.json +22 -8
  477. package/specialists/org/specialists/cx-engineer.json +71 -7
  478. package/specialists/org/specialists/cx-operations.json +89 -15
  479. package/specialists/org/specialists/cx-orchestrator.json +16 -4
  480. package/specialists/org/specialists/cx-product-manager.json +28 -9
  481. package/specialists/org/specialists/cx-qa.json +16 -6
  482. package/specialists/org/specialists/cx-researcher.json +41 -7
  483. package/specialists/org/specialists/cx-reviewer.json +61 -11
  484. package/specialists/org/specialists/cx-security.json +30 -10
  485. package/specialists/org/teams/design-team.json +3 -4
  486. package/specialists/org/teams/engineering-team.json +3 -10
  487. package/specialists/org/teams/governance-team.json +3 -5
  488. package/specialists/org/teams/operations-team.json +6 -12
  489. package/specialists/org/teams/product-management-team.json +2 -3
  490. package/specialists/org/teams/quality-team.json +4 -12
  491. package/specialists/org/teams/research-team.json +3 -3
  492. package/specialists/org/teams/strategy-team.json +7 -14
  493. package/specialists/prompts/cx-architect.md +20 -1
  494. package/specialists/prompts/cx-data-analyst.md +1 -1
  495. package/specialists/prompts/cx-designer.md +12 -4
  496. package/specialists/prompts/cx-engineer.md +15 -1
  497. package/specialists/prompts/cx-operations.md +14 -2
  498. package/specialists/prompts/cx-orchestrator.md +9 -5
  499. package/specialists/prompts/cx-product-manager.md +5 -1
  500. package/specialists/prompts/cx-qa.md +6 -2
  501. package/specialists/prompts/cx-researcher.md +27 -31
  502. package/specialists/prompts/cx-reviewer.md +19 -1
  503. package/specialists/prompts/cx-security.md +5 -1
  504. package/templates/distribution/construct-brand.typ +123 -59
  505. package/templates/distribution/construct-decision.typ +6 -3
  506. package/templates/distribution/construct-pdf.typ +11 -4
  507. package/templates/distribution/construct-prd.typ +6 -3
  508. package/templates/distribution/construct-research.typ +7 -4
  509. package/vendor/pandoc-ext/README.md +3 -0
  510. package/vendor/pandoc-ext/diagram.lua +687 -0
  511. package/lib/providers/contract/adapters/git/index.mjs +0 -115
  512. package/lib/providers/contract/adapters/slack/index.mjs +0 -175
  513. package/specialists/org/contracts/business-strategist-to-product-manager.json +0 -39
  514. package/specialists/org/contracts/construct-to-rd-lead.json +0 -53
  515. package/specialists/org/contracts/data-engineer-to-platform-engineer.json +0 -36
  516. package/specialists/org/contracts/designer-to-accessibility.json +0 -36
  517. package/specialists/org/contracts/platform-engineer-to-engineer.json +0 -31
  518. package/specialists/org/contracts/qa-to-test-automation.json +0 -42
  519. package/specialists/org/contracts/rd-lead-to-architect.json +0 -38
  520. package/specialists/org/contracts/sre-to-release-manager.json +0 -36
  521. package/specialists/org/specialists/cx-accessibility.json +0 -69
  522. package/specialists/org/specialists/cx-ai-engineer.json +0 -75
  523. package/specialists/org/specialists/cx-business-strategist.json +0 -72
  524. package/specialists/org/specialists/cx-data-engineer.json +0 -71
  525. package/specialists/org/specialists/cx-devil-advocate.json +0 -71
  526. package/specialists/org/specialists/cx-docs-keeper.json +0 -82
  527. package/specialists/org/specialists/cx-evaluator.json +0 -69
  528. package/specialists/org/specialists/cx-explorer.json +0 -69
  529. package/specialists/org/specialists/cx-legal-compliance.json +0 -74
  530. package/specialists/org/specialists/cx-oracle.json +0 -46
  531. package/specialists/org/specialists/cx-platform-engineer.json +0 -80
  532. package/specialists/org/specialists/cx-rd-lead.json +0 -73
  533. package/specialists/org/specialists/cx-release-manager.json +0 -77
  534. package/specialists/org/specialists/cx-sre.json +0 -94
  535. package/specialists/org/specialists/cx-test-automation.json +0 -69
  536. package/specialists/org/specialists/cx-trace-reviewer.json +0 -69
  537. package/specialists/org/specialists/cx-ux-researcher.json +0 -68
  538. package/specialists/org/teams/accessibility-team.json +0 -39
  539. package/specialists/org/teams/ux-research-team.json +0 -39
  540. package/specialists/prompts/cx-accessibility.md +0 -55
  541. package/specialists/prompts/cx-ai-engineer.md +0 -124
  542. package/specialists/prompts/cx-business-strategist.md +0 -58
  543. package/specialists/prompts/cx-data-engineer.md +0 -55
  544. package/specialists/prompts/cx-devil-advocate.md +0 -59
  545. package/specialists/prompts/cx-docs-keeper.md +0 -164
  546. package/specialists/prompts/cx-evaluator.md +0 -49
  547. package/specialists/prompts/cx-explorer.md +0 -71
  548. package/specialists/prompts/cx-legal-compliance.md +0 -58
  549. package/specialists/prompts/cx-oracle.md +0 -98
  550. package/specialists/prompts/cx-platform-engineer.md +0 -97
  551. package/specialists/prompts/cx-rd-lead.md +0 -59
  552. package/specialists/prompts/cx-release-manager.md +0 -54
  553. package/specialists/prompts/cx-sre.md +0 -111
  554. package/specialists/prompts/cx-test-automation.md +0 -55
  555. package/specialists/prompts/cx-trace-reviewer.md +0 -101
  556. package/specialists/prompts/cx-ux-researcher.md +0 -53
@@ -23,18 +23,33 @@ async function getCopilotToken() {
23
23
  }
24
24
  }
25
25
 
26
- const server = http.createServer(async (req, res) => {
27
- // CORS
28
- res.setHeader('Access-Control-Allow-Origin', '*');
29
- res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
30
- res.setHeader('Access-Control-Allow-Headers', '*');
26
+ // Fail closed: the bridge fronts the user's Copilot entitlement, so every request
27
+ // must carry the per-launch bearer token service-manager injects, and an unconfigured
28
+ // token means no access at all. No CORS headers are emitted — the only legitimate
29
+ // caller is a loopback server process (OpenCode), never a browser page, so a wildcard
30
+ // Access-Control-Allow-Origin would just let any open tab drive the entitlement.
31
+
32
+ const EXPECTED_TOKEN = process.env.CONSTRUCT_COPILOT_BRIDGE_TOKEN || null;
33
+
34
+ function isAuthorized(req) {
35
+ if (!EXPECTED_TOKEN) return false;
36
+ const match = String(req.headers.authorization || '').match(/^Bearer\s+(.+)$/i);
37
+ return Boolean(match) && match[1] === EXPECTED_TOKEN;
38
+ }
31
39
 
40
+ const server = http.createServer(async (req, res) => {
32
41
  if (req.method === 'OPTIONS') {
33
42
  res.writeHead(204);
34
43
  res.end();
35
44
  return;
36
45
  }
37
46
 
47
+ if (!isAuthorized(req)) {
48
+ res.writeHead(401, { 'Content-Type': 'application/json' });
49
+ res.end(JSON.stringify({ error: 'Unauthorized: missing or invalid bridge bearer token.' }));
50
+ return;
51
+ }
52
+
38
53
  if (req.url === '/v1/chat/completions' && req.method === 'POST') {
39
54
  const token = await getCopilotToken();
40
55
  if (!token) {
@@ -13,6 +13,7 @@ import { createHash } from 'node:crypto';
13
13
  import { artifactTypes, loadArtifactManifest } from '../artifact-manifest.mjs';
14
14
  import { validateSkillEffectiveness } from '../validators/skill-effectiveness.mjs';
15
15
  import { collectScopeRoleIds } from '../scopes/enrich.mjs';
16
+ import { bindingForSpecialist } from '../roles/flavor-bindings.mjs';
16
17
 
17
18
  function findConstructRoot(startPath = process.cwd()) {
18
19
  let current = path.resolve(startPath);
@@ -95,7 +96,7 @@ function verificationHooks(meta, body) {
95
96
  }
96
97
 
97
98
  function resolveOwners(skillId, { registry, declaredSkills, ownerBases }) {
98
- if (skillId.startsWith('brand/')) return ['cx-docs-keeper'];
99
+ if (skillId.startsWith('brand/')) return ['cx-operations'];
99
100
  const owners = new Set();
100
101
  for (const agent of Object.values(registry.specialists ?? {})) {
101
102
  if ((agent.skills ?? []).includes(skillId)) owners.add(`cx-${agent.name}`);
@@ -107,6 +108,14 @@ function resolveOwners(skillId, { registry, declaredSkills, ownerBases }) {
107
108
  }
108
109
  if (!owners.size) owners.add(`scope-role:${base}`);
109
110
  }
111
+ // A roles/*.md overlay's base name is not always a live specialist name —
112
+ // some overlays are skill bundles loaded onto a differently-named anchor.
113
+ // lib/roles/flavor-bindings.mjs is the source of truth for which
114
+ // specialist actually loads a given overlay; fall back to it here.
115
+ if (base && owners.size === 0) {
116
+ const binding = bindingForSpecialist(base);
117
+ if (binding?.specialistId) owners.add(binding.specialistId);
118
+ }
110
119
  if (declaredSkills.has(skillId) && owners.size === 0) {
111
120
  for (const agent of Object.values(registry.specialists ?? {})) {
112
121
  if ((agent.skills ?? []).includes(skillId)) owners.add(`cx-${agent.name}`);
@@ -0,0 +1,147 @@
1
+ /**
2
+ * lib/cli/approvals.mjs — `construct approvals` CLI handler.
3
+ *
4
+ * Loads the ApprovalQueue from the appropriate persistence path and
5
+ * implements list / approve / deny / status subcommands.
6
+ *
7
+ * `approve` is the operator's decision point and the sole production drain
8
+ * for J6 governed write intents: once a record whose tool names a known
9
+ * governed provider (jira/github/confluence) is approved, the control plane
10
+ * (lib/writes/control-plane.mjs) executes it through the J2 envelope — the
11
+ * only place recommend becomes execute. Non-write-intent approvals (embed
12
+ * tool proposals) are left for their own runtime to act on and are not
13
+ * touched here.
14
+ */
15
+
16
+ import { ApprovalQueue } from '../embed/approval-queue.mjs';
17
+ import { getDeploymentMode } from '../deployment-mode.mjs';
18
+ import { executeApprovedWriteIntent } from '../writes/control-plane.mjs';
19
+ import { parseWriteIntentToolName, KNOWN_PROVIDERS } from '../writes/write-intent.mjs';
20
+
21
+ /**
22
+ * Run the approvals CLI command.
23
+ * @param {string[]} args
24
+ * @param {object} ctx
25
+ * @param {string} ctx.rootDir
26
+ * @param {string} ctx.homeDir
27
+ * @param {object} ctx.env
28
+ * @param {Function} ctx.println
29
+ * @param {Function} ctx.errorln
30
+ * @returns {number} exit code
31
+ */
32
+ export async function runApprovalsCli(args, { rootDir, homeDir, env, println, errorln }) {
33
+ const sub = args[0];
34
+ if (!sub || sub === '--help' || sub === '-h') {
35
+ println('Usage: construct approvals <list|approve|deny|status>');
36
+ println('');
37
+ println('Subcommands:');
38
+ println(' list List pending approvals');
39
+ println(' approve <id> Approve a pending approval by id');
40
+ println(' deny <id> Deny a pending approval by id');
41
+ println(' status <id> Show full status of a specific approval');
42
+ return 0;
43
+ }
44
+
45
+ const deploymentMode = getDeploymentMode(env, { cwd: rootDir });
46
+ const persistPath = ApprovalQueue.resolvePersistPath(rootDir, deploymentMode);
47
+ const queue = new ApprovalQueue({ persistPath });
48
+
49
+ if (sub === 'list') {
50
+ const pending = queue.getPending();
51
+ if (pending.length === 0) {
52
+ println('No pending approvals.');
53
+ return 0;
54
+ }
55
+ for (const r of pending) {
56
+ const rb = r.requestedBy || {};
57
+ const by = rb.role || rb.userId || rb.serviceId || 'unknown';
58
+ println(`${r.approvalId}`);
59
+ println(` tool: ${r.toolCall?.tool || '?'}`);
60
+ println(` requestedAt: ${r.requestedAt}`);
61
+ println(` requestedBy: ${by}`);
62
+ println(` expiresAt: ${r.expiresAt}`);
63
+ println('');
64
+ }
65
+ return 0;
66
+ }
67
+
68
+ if (sub === 'approve') {
69
+ const id = args[1];
70
+ if (!id) {
71
+ errorln('Usage: construct approvals approve <id>');
72
+ return 1;
73
+ }
74
+ try {
75
+ const record = queue.approve(id, {
76
+ decidedBy: {
77
+ role: process.env.CONSTRUCT_ROLE || 'cli-operator',
78
+ userId: process.env.USER || process.env.USERNAME || null,
79
+ source: 'cli',
80
+ },
81
+ });
82
+ println(`Approved: ${record.approvalId} (tool: ${record.toolCall?.tool})`);
83
+
84
+ // Only a governed write intent (tool "<provider>.<kind>" naming a known
85
+ // governed provider) is executed here; anything else is another
86
+ // runtime's proposal and stays untouched.
87
+
88
+ const parsed = parseWriteIntentToolName(record.toolCall?.tool);
89
+ if (parsed && KNOWN_PROVIDERS.includes(parsed.providerId)) {
90
+ try {
91
+ const result = await executeApprovedWriteIntent(record, { rootDir });
92
+ println(`Executed ${parsed.providerId}.${parsed.writeKind} via control plane (status: ${result?.status ?? 'unknown'})`);
93
+ } catch (execErr) {
94
+ errorln(`Approved, but control-plane execution failed: ${execErr.message}`);
95
+ return 1;
96
+ }
97
+ }
98
+ return 0;
99
+ } catch (err) {
100
+ errorln(`Error: ${err.message}`);
101
+ return 1;
102
+ }
103
+ }
104
+
105
+ if (sub === 'deny') {
106
+ const id = args[1];
107
+ if (!id) {
108
+ errorln('Usage: construct approvals deny <id> [--reason=...]');
109
+ return 1;
110
+ }
111
+ const reasonFlag = args.find((a) => a.startsWith('--reason='));
112
+ const reason = reasonFlag ? reasonFlag.slice('--reason='.length) : 'denied by operator';
113
+ try {
114
+ const record = queue.deny(id, {
115
+ decidedBy: {
116
+ role: process.env.CONSTRUCT_ROLE || 'cli-operator',
117
+ userId: process.env.USER || process.env.USERNAME || null,
118
+ source: 'cli',
119
+ },
120
+ reason,
121
+ });
122
+ println(`Denied: ${record.approvalId} (reason: ${reason})`);
123
+ return 0;
124
+ } catch (err) {
125
+ errorln(`Error: ${err.message}`);
126
+ return 1;
127
+ }
128
+ }
129
+
130
+ if (sub === 'status') {
131
+ const id = args[1];
132
+ if (!id) {
133
+ errorln('Usage: construct approvals status <id>');
134
+ return 1;
135
+ }
136
+ const record = queue.getById(id);
137
+ if (!record) {
138
+ errorln(`Approval not found: ${id}`);
139
+ return 1;
140
+ }
141
+ println(JSON.stringify(record, null, 2));
142
+ return 0;
143
+ }
144
+
145
+ errorln(`Unknown approvals subcommand: ${sub}. Available: list, approve, deny, status`);
146
+ return 1;
147
+ }
@@ -24,14 +24,14 @@ export const CLI_COMMANDS = [
24
24
  category: 'Core',
25
25
  core: true,
26
26
  description: 'Start services for development',
27
- usage: 'construct dev [--select] [--only=postgres,...]',
27
+ usage: 'construct dev [--select] [--only=memory,opencode,...]',
28
28
  examples: [
29
29
  { cmd: 'construct dev', desc: 'Start the default service set' },
30
- { cmd: 'construct dev --only=postgres', desc: 'Start just Postgres' },
30
+ { cmd: 'construct dev --only=memory', desc: 'Start just the memory (cm) service' },
31
31
  ],
32
32
  options: [
33
33
  { flag: '--select', desc: 'Pick which services to start from an interactive checklist' },
34
- { flag: '--only=<a,b,c>', desc: 'Start only the named services (postgres, telemetry, memory, opencode)' },
34
+ { flag: '--only=<a,b,c>', desc: 'Start only the named services (telemetry, memory, opencode, copilot-bridge)' },
35
35
  ],
36
36
  },
37
37
  {
@@ -61,22 +61,37 @@ export const CLI_COMMANDS = [
61
61
  { flag: '--json', desc: 'Output full status payload as JSON' },
62
62
  ],
63
63
  },
64
+ {
65
+ name: 'workers',
66
+ emoji: '🫀',
67
+ category: 'Core',
68
+ core: true,
69
+ description: 'List registered team workers and heartbeat freshness',
70
+ usage: 'construct workers <list> [--json]',
71
+ strictFlags: true,
72
+ examples: [
73
+ { cmd: 'construct workers list', desc: 'Show live/stale registered workers' },
74
+ { cmd: 'construct workers list --json', desc: 'Machine-readable worker status' },
75
+ ],
76
+ options: [
77
+ { flag: '--json', desc: 'Output worker list as JSON' },
78
+ ],
79
+ },
64
80
  {
65
81
  name: 'install',
66
82
  emoji: '🛠️',
67
83
  category: 'Core',
68
84
  core: true,
69
85
  description: 'Machine setup (scoped per ADR-0029): --scope=project|user|both, default project',
70
- usage: 'construct install [--scope=project|user|both] [--yes] [--dry-run] [--no-docker] [--no-launch-agent] [--reconfigure] [--with-docling]',
86
+ usage: 'construct install [--scope=project|user|both] [--yes] [--dry-run] [--no-launch-agent] [--reconfigure] [--with-docling]',
71
87
  examples: [
72
88
  { cmd: 'construct install --dry-run', desc: 'Preview the plan before writing anything' },
73
89
  { cmd: 'construct install --scope=user --yes', desc: 'Non-interactive user-scope install' },
74
90
  ],
75
91
  options: [
76
- { flag: '--scope=<s>', desc: 'project (default, no-op + guidance) | user (writes ~/.construct/, MCP, ~/.claude/* via consent) | both' },
92
+ { flag: '--scope=<s>', desc: 'project (default, no-op + guidance) | user (writes ~/.config/construct/, MCP, ~/.claude/* via consent) | both' },
77
93
  { flag: '--yes', desc: 'Apply defaults without prompts (only meaningful with --scope=user|both)' },
78
94
  { flag: '--dry-run', desc: 'Preview the install plan (scopes, files, services) without writing anything' },
79
- { flag: '--no-docker', desc: 'Skip Docker-based service setup (local Postgres)' },
80
95
  { flag: '--no-launch-agent', desc: 'Skip background macOS LaunchAgent registration' },
81
96
  { flag: '--reconfigure', desc: 'Re-prompt for service consent, ignoring cached answers' },
82
97
  { flag: '--with-docling', desc: 'Eagerly provision the docling document-extraction venv now (heavy, ~10 min; else lazy on first ingest)' },
@@ -407,9 +422,25 @@ export const CLI_COMMANDS = [
407
422
  category: 'Work',
408
423
  core: false,
409
424
  description: 'Task graph management',
410
- usage: 'construct graph <list|show|from-intake|recommend>',
425
+ usage: 'construct graph <list|show|from-intake|recommend|build|stat|query|validate|explain|owasp>',
411
426
  subcommands: [
412
427
  { name: 'recommend --json [--text|--file|<stdin>]', desc: 'Return a role-aware plan for an artifact without enqueuing (embedded contract; alias of intake classify)' },
428
+ { name: 'build|stat|query|validate|explain', desc: 'Living dependency graph — build/inspect/validate the typed file↔capability↔workflow↔test↔embed graph (replaces `construct matrix`)' },
429
+ { name: 'owasp | missing-tests --security', desc: 'OWASP GenAI Top-10 coverage matrix and the workflow/preset security-coverage gap list (LMCP-N8)' },
430
+ ],
431
+ },
432
+ {
433
+ name: 'pack',
434
+ emoji: '📦',
435
+ category: 'Work',
436
+ core: false,
437
+ description: 'Specialist/team/profile pack enable/disable lifecycle (LMCP-E3)',
438
+ usage: 'construct pack <list|enable|disable|info> [--json]',
439
+ subcommands: [
440
+ { name: 'list', desc: 'Every pack discovered across builtin/user/project tiers with its durable enabled state' },
441
+ { name: 'enable <pack-id>[@version]', desc: 'Validate the pack manifest and record it enabled in .cx/packs.json; refuses on an incompatible compatVersion or other validation failure' },
442
+ { name: 'disable <pack-id>', desc: 'Remove the pack\'s enabled entry (idempotent; the core pack cannot be disabled)' },
443
+ { name: 'info <pack-id>', desc: 'Full manifest plus enabled state for one pack' },
413
444
  ],
414
445
  },
415
446
  {
@@ -462,6 +493,30 @@ export const CLI_COMMANDS = [
462
493
  { name: 'preflight [--host H] [--json] [--no-probe]', desc: 'Verify orchestration tool attachment/readiness and return a typed reason plus recovery step' },
463
494
  ],
464
495
  },
496
+ {
497
+ name: 'flow',
498
+ emoji: '🧵',
499
+ category: 'Models & Integrations',
500
+ core: false,
501
+ description: 'Deterministic flow-engine runs: start or resume a checkpointed flow, or inspect its status',
502
+ usage: 'construct flow <resume|status> <run-id> [--flow=<path>] [--state=<json>]',
503
+ subcommands: [
504
+ { name: 'resume <run-id> --flow=<path> [--state=<json>]', desc: 'Start (new run-id) or resume a checkpointed flow and drive it to completion' },
505
+ { name: 'status <run-id>', desc: 'Read a flow checkpoint without driving it' },
506
+ ],
507
+ },
508
+ {
509
+ name: 'db',
510
+ emoji: '🗄️',
511
+ category: 'Models & Integrations',
512
+ core: false,
513
+ description: 'Inspect and migrate the optional Postgres backend',
514
+ usage: 'construct db <status|migrate> [--json]',
515
+ subcommands: [
516
+ { name: 'status [--json]', desc: 'Check Postgres reachability and migration state' },
517
+ { name: 'migrate [--json]', desc: 'Apply pending Postgres migrations idempotently' },
518
+ ],
519
+ },
465
520
  {
466
521
  name: 'acp',
467
522
  emoji: '🔗',
@@ -601,11 +656,12 @@ export const CLI_COMMANDS = [
601
656
  emoji: '👥',
602
657
  category: 'Work',
603
658
  core: false,
604
- description: 'Team review and template listing (`team:add` / `team:remove` are internal registry editors)',
605
- usage: 'construct team <list|show|review|templates>',
659
+ description: 'Team review, template listing, and custom team authoring (`team:add` / `team:remove` are internal registry editors)',
660
+ usage: 'construct team <list|show|create|review|templates>',
606
661
  subcommands: [
607
662
  { name: 'list', desc: 'List macro groups and squads (--kind group|squad)' },
608
663
  { name: 'show', desc: 'Show one group or squad by id' },
664
+ { name: 'create', desc: 'Scaffold a custom team into .cx/org/ (or ~/.construct/org/ with --user) — see docs/guides/cookbook/custom-specialists-and-teams.md' },
609
665
  { name: 'review', desc: 'Team review workflow' },
610
666
  { name: 'templates', desc: 'List team doc templates' },
611
667
  ],
@@ -785,7 +841,7 @@ export const CLI_COMMANDS = [
785
841
  { flag: '--dry-run', desc: 'Print the plan and exit; change nothing' },
786
842
  { flag: '--yes', desc: 'Remove auto-risk (✓) categories without prompting' },
787
843
  { flag: '--all', desc: 'Combined with --yes: also remove ask-risk (◐) categories (project data, machine config)' },
788
- { flag: '--keep-state', desc: 'Only remove the launcher + adapters; preserve .cx/, ~/.construct, Postgres' },
844
+ { flag: '--keep-state', desc: 'Only remove the launcher + adapters; preserve .cx/, ~/.config/construct, Postgres' },
789
845
  { flag: '--scope=<...>', desc: 'Limit to project | machine | all (default: all)' },
790
846
  ],
791
847
  },
@@ -835,7 +891,16 @@ export const CLI_COMMANDS = [
835
891
  category: 'Advanced',
836
892
  core: false,
837
893
  description: 'Embed mode management',
838
- usage: 'construct embed start|stop|status',
894
+ usage: 'construct embed start|stop|status|list|enable|disable|dry-run',
895
+ subcommands: [
896
+ { name: 'start', desc: 'Fork the detached embed daemon' },
897
+ { name: 'stop', desc: 'Stop the running embed daemon' },
898
+ { name: 'status [<id>] [--json]', desc: 'Daemon status, or per-capability bindings/filter/runtime/last-tick with an id' },
899
+ { name: 'list [--json]', desc: 'Available embed capabilities and per-project enabled state (ADR-0061)' },
900
+ { name: 'enable <id>', desc: 'Enable an embed capability: validate and write .cx/embed/<id>.manifest.json' },
901
+ { name: 'disable <id>', desc: 'Disable an embed capability (idempotent)' },
902
+ { name: 'dry-run <id> [--json]', desc: 'Resolve the specialist→providers→filter→framework→authority→runtime chain; no side effects' },
903
+ ],
839
904
  },
840
905
  {
841
906
  name: 'backup',
@@ -957,7 +1022,19 @@ export const CLI_COMMANDS = [
957
1022
  category: 'Advanced',
958
1023
  core: false,
959
1024
  description: 'Provider management',
960
- usage: 'construct provider list|test',
1025
+ usage: 'construct provider list|status|health|validate|test|add|configure',
1026
+ subcommands: [
1027
+ { name: 'list', desc: 'List all resolved providers with capabilities and health' },
1028
+ { name: 'status [--json]', desc: 'Alias of list with breaker state, degradation, and active filter columns' },
1029
+ { name: 'health [id] [--json]', desc: 'Run health probes; exits non-zero if any probe fails' },
1030
+ { name: 'validate <path|id> [--strict] [--json]', desc: 'Validate a manifest file or provider id against the B1 schema' },
1031
+ { name: 'info <id>', desc: 'Show a single provider\'s metadata and config schema' },
1032
+ { name: 'test <id>', desc: 'Run one provider\'s health probe; exits non-zero on failure' },
1033
+ { name: 'add <id> [--json]', desc: 'Scaffold instance config from the provider\'s configSchema defaults, persisted to .cx/providers/<id>.json' },
1034
+ { name: 'configure <id> [--key.path value ...] [--json]', desc: 'Merge + validate instance config (incl. ADR-0060 filter block) against configSchema; rejects with the schema path on failure' },
1035
+ { name: 'plugins <add|remove> <id> [<package>] [--global]', desc: 'Register or remove a plugin provider override' },
1036
+ { name: 'new <name> [--capabilities=...]', desc: 'Scaffold a new provider module' },
1037
+ ],
961
1038
  },
962
1039
  {
963
1040
  name: 'auth:status',
@@ -967,6 +1044,20 @@ export const CLI_COMMANDS = [
967
1044
  description: 'Check auth status',
968
1045
  usage: 'construct auth:status',
969
1046
  },
1047
+ {
1048
+ name: 'approvals',
1049
+ emoji: '✅',
1050
+ category: 'Core',
1051
+ core: true,
1052
+ description: 'Manage pending MCP tool approvals',
1053
+ usage: 'construct approvals list|approve|deny|status',
1054
+ subcommands: [
1055
+ { name: 'list', desc: 'List pending approvals with tool name, requestedAt, requestedBy' },
1056
+ { name: 'approve <id>', desc: 'Approve a pending approval by id' },
1057
+ { name: 'deny <id> [--reason=...]', desc: 'Deny a pending approval by id' },
1058
+ { name: 'status <id>', desc: 'Show the full status of a specific approval' },
1059
+ ],
1060
+ },
970
1061
  {
971
1062
  name: 'tags',
972
1063
  emoji: '🏷',
@@ -1133,7 +1224,7 @@ export const CLI_COMMANDS = [
1133
1224
  { name: 'lint:research', category: 'Internal', core: false, internal: true, description: 'Internal lint: research artifacts', usage: 'construct lint:research' },
1134
1225
  { name: 'lint:templates', category: 'Internal', core: false, internal: true, description: 'Internal lint: shipped templates', usage: 'construct lint:templates' },
1135
1226
  { name: 'lint:prompts', category: 'Internal', core: false, internal: true, description: 'Internal lint: specialist prompt frontmatter + sections', usage: 'construct lint:prompts' },
1136
- { name: 'specialist', category: 'Internal', core: false, internal: true, description: 'Maintainer tool: scaffold, edit, and lint specialist prompts', usage: 'construct specialist <create|edit|lint>' },
1227
+ { name: 'specialist', category: 'Internal', core: false, internal: true, description: 'Maintainer tool: scaffold/edit/lint built-in specialist prompts; `create --custom` scaffolds a user-authored specialist into .cx/org/ or ~/.construct/org/', usage: 'construct specialist <create|edit|lint> [--custom]' },
1137
1228
  { name: 'registry:status', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Dev: capability registry inspector', usage: 'construct registry:status [--json]' },
1138
1229
  { name: 'registry:validate', category: 'Internal', core: false, internal: true, surface: 'internal', strictFlags: true, description: 'Validate registry/capabilities.json against repo reality; --unified validates specialists/org (+ .cx overlay) invariants', usage: 'construct registry:validate [--json] [--unified]', options: [
1139
1230
  { flag: '--json', desc: 'Emit the validation report as JSON' },
@@ -1147,7 +1238,7 @@ export const CLI_COMMANDS = [
1147
1238
  { name: 'specialist:add', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Add a new specialist to a team', usage: 'construct specialist:add <specialist-id> --team <team-id>' },
1148
1239
  { name: 'specialist:remove', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Remove a specialist from the unified registry', usage: 'construct specialist:remove <specialist-id> [--force]' },
1149
1240
  { name: 'oracle', emoji: '🔮', category: 'Core', core: true, description: 'Oracle meta-controller — fleet health review and bounded-auto maintenance', usage: 'construct oracle start|status|review|pending|approve|gaps|reconcile' },
1150
- { name: 'matrix', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Living dependency matrix build/inspect the typed file↔capability↔workflow↔test graph', usage: 'construct matrix build|stat|query <node-id> [--json]' },
1241
+ { name: 'matrix', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Deprecated alias of `construct graph` living dependency graph', usage: 'construct matrix build|stat|query|validate <node-id> [--json]' },
1151
1242
  { name: 'impact', category: 'Diagnostics', core: false, internal: false, surface: 'thin-cli', description: 'Change-impact analysis — map changed files to affected tests, capabilities, and workflows', usage: 'construct impact [files…] [--stdin] [--run] [--json]' },
1152
1243
  { name: 'rules', category: 'Diagnostics', core: false, internal: false, surface: 'thin-cli', description: 'Rule and hook reference telemetry rollup', usage: 'construct rules usage [--since=30d]' },
1153
1244
  { name: 'evaluator:rubrics', category: 'Internal', core: false, internal: true, description: 'Internal: list registered evaluator rubrics', usage: 'construct evaluator:rubrics' },
@@ -4,6 +4,12 @@
4
4
  * lintFile(path) checks a single file. lintRepo({ rootDir, fix }) checks all
5
5
  * scoped paths and optionally inserts stub headers for files missing one.
6
6
  * Used by `construct lint:comments`, the comment-lint PostToolUse hook, and CI.
7
+ * Also enforces the future-state doc marker convention (construct-9oi4.15.3 /
8
+ * LMCP-O3): a guide/operations doc claiming a capability is "staged/
9
+ * experimental" or "not yet {implemented,active,shipped,supported}" must cite
10
+ * a construct-* bead id within two lines. And bans naming another project by
11
+ * name in a code comment (BANNED_EXTERNAL_PROJECTS) outside docs/decisions/**
12
+ * and docs/notes/**, where a prior-art comparison can carry a citation.
7
13
  */
8
14
 
9
15
  import fs from 'node:fs';
@@ -202,11 +208,125 @@ const BANNED_ARTIFACT = [
202
208
  },
203
209
  ];
204
210
 
211
+ // Future-state doc markers (construct-9oi4.15.3 / LMCP-O3): a guide or
212
+ // operations doc that tells the reader a capability is "staged/experimental"
213
+ // or "not yet {implemented,active,shipped,supported}" must cite a tracked
214
+ // construct-* bead within two lines, or the claim is unfalsifiable — nobody
215
+ // can check whether the gap is still open. Scope is guides/operations/README,
216
+ // matching where the M3 sweep (construct-9oi4.13.3) found and fixed its
217
+ // contradictions. ADRs/RFCs carry their own Status/Tracking header convention
218
+ // and docs/notes/research/** are working notes, not shipped-behavior claims —
219
+ // both excluded. hooks-deprecated.md is excluded: it is a self-governing
220
+ // ledger of removed hooks (checked separately by `construct doctor`), not a
221
+ // forward-looking capability claim.
222
+
223
+ const FUTURE_STATE_DOC_INCLUDE = [
224
+ /^docs\/guides\//,
225
+ /^docs\/operations\//,
226
+ /^docs\/README\.md$/,
227
+ ];
228
+
229
+ const FUTURE_STATE_DOC_EXCLUDE = [
230
+ /^docs\/guides\/reference\/hooks-deprecated\.md$/,
231
+ ];
232
+
233
+ function isFutureStateDocPath(rel) {
234
+ return FUTURE_STATE_DOC_INCLUDE.some((r) => r.test(rel)) && !FUTURE_STATE_DOC_EXCLUDE.some((r) => r.test(rel));
235
+ }
236
+
237
+ const FUTURE_STATE_MARKERS = [
238
+ /\bstaged\/experimental\b/i,
239
+ /\bnot\s+yet\s+(?:implemented|active|shipped|supported)\b/i,
240
+ /\bplanned[;:—-]+\s*not\s+(?:yet\s+)?implemented\b/i,
241
+ ];
242
+
243
+ const BEAD_ID_RE = /\bconstruct-[a-z0-9]+(?:\.[a-z0-9]+)*\b/i;
244
+
245
+ function hasBeadIdNearby(lines, idx) {
246
+ const lo = Math.max(0, idx - 2);
247
+ const hi = Math.min(lines.length, idx + 3);
248
+ for (let i = lo; i < hi; i++) {
249
+ if (BEAD_ID_RE.test(lines[i])) return true;
250
+ }
251
+ return false;
252
+ }
253
+
254
+ function checkFutureStateMarkers(content, rel) {
255
+ if (!isFutureStateDocPath(rel)) return [];
256
+ const lines = content.split('\n');
257
+ const skip = buildSkipMap(lines);
258
+ const violations = [];
259
+ for (let i = 0; i < lines.length; i++) {
260
+ if (skip[i]) continue;
261
+ if (lines[i].includes('construct-lint-ignore')) continue;
262
+ for (const pattern of FUTURE_STATE_MARKERS) {
263
+ if (pattern.test(lines[i]) && !hasBeadIdNearby(lines, i)) {
264
+ violations.push({
265
+ line: i + 1,
266
+ label: 'future-state doc marker ("staged/experimental" / "not yet implemented" / "planned — not implemented") has no construct-* bead id within 2 lines (rules/common/no-fabrication.md)',
267
+ kind: 'artifact',
268
+ });
269
+ }
270
+ }
271
+ }
272
+ return violations;
273
+ }
274
+
205
275
  function isBannedCheckSkipped(filePath) {
206
276
  if (!filePath) return false;
207
277
  return BANNED_CHECK_SKIP.some((suffix) => filePath.endsWith(suffix));
208
278
  }
209
279
 
280
+ // External project names named in a code comment read as an unverifiable
281
+ // comparison — no-fabrication requires prior-art comparisons carry a citation,
282
+ // and only a decision document carries one. docs/decisions/** and docs/notes/**
283
+ // are that citation-bearing exception; every other comment in the repo
284
+ // describes this codebase's own behavior. A variant of CMT excludes the `//`
285
+ // in a URL scheme (`https://…`) so a cited reference link doesn't misread as
286
+ // a comment marker — this check runs on markdown prose too, unlike the other
287
+ // BANNED entries above, so citation URLs are common in its input.
288
+
289
+ const BANNED_EXTERNAL_PROJECTS = ['CrewAI', 'LangGraph', 'AutoGen', 'LangChain', 'MetaGPT', 'Aider', 'Devin'];
290
+
291
+ const EXTERNAL_PROJECT_CMT = '(?:(?<!:)\\/\\/|^\\s*\\*(?!\\/))';
292
+
293
+ const EXTERNAL_PROJECT_NAME_RE = new RegExp(
294
+ `${EXTERNAL_PROJECT_CMT}.*\\b(?:${BANNED_EXTERNAL_PROJECTS.join('|')})\\b`,
295
+ 'i',
296
+ );
297
+
298
+ const EXTERNAL_PROJECT_EXEMPT_GLOBS = [
299
+ /^docs\/decisions\//,
300
+ /^docs\/notes\//,
301
+ ];
302
+
303
+ function isExternalProjectExempt(rel) {
304
+ return EXTERNAL_PROJECT_EXEMPT_GLOBS.some((r) => r.test(rel));
305
+ }
306
+
307
+ function checkExternalProjectNames(content, filePath, rel) {
308
+ if (isBannedCheckSkipped(filePath)) return [];
309
+ if (isExternalProjectExempt(rel)) return [];
310
+
311
+ // Same JS/TS comment-convention scope as checkBanned: the "// " / " * "
312
+ // detection matches markdown's own "**bold**"/"* bullet" syntax as a
313
+ // false positive, so markdown/MDX prose is out of scope for this check.
314
+ if (filePath && ['.md', '.mdx'].includes(path.extname(filePath))) return [];
315
+ const lines = content.split('\n');
316
+ const violations = [];
317
+ for (let i = 0; i < lines.length; i++) {
318
+ if (lines[i].includes('construct-lint-ignore')) continue;
319
+ if (EXTERNAL_PROJECT_NAME_RE.test(lines[i])) {
320
+ violations.push({
321
+ line: i + 1,
322
+ label: 'external project name in a code comment — prior-art comparisons belong in docs/decisions or docs/notes with citations (rules/common/comments.md)',
323
+ kind: 'artifact',
324
+ });
325
+ }
326
+ }
327
+ return violations;
328
+ }
329
+
210
330
  // Track fenced code blocks ( ``` … ``` ) and YAML frontmatter ( --- … --- )
211
331
  // so artifact-prose patterns inside code or metadata are not flagged.
212
332
  function buildSkipMap(lines) {
@@ -327,11 +447,8 @@ function checkArtifactBanned(content, rel) {
327
447
  // path and must never throw on a missing or malformed registry file.
328
448
 
329
449
  export const KNOWN_CX_ROLE_IDS = [
330
- 'accessibility', 'ai-engineer', 'architect', 'business-strategist', 'data-analyst',
331
- 'data-engineer', 'debugger', 'designer', 'devil-advocate', 'docs-keeper', 'engineer',
332
- 'evaluator', 'explorer', 'legal-compliance', 'operations', 'oracle', 'orchestrator',
333
- 'platform-engineer', 'product-manager', 'qa', 'rd-lead', 'release-manager', 'researcher',
334
- 'reviewer', 'security', 'sre', 'test-automation', 'trace-reviewer', 'ux-researcher',
450
+ 'architect', 'data-analyst', 'debugger', 'designer', 'engineer', 'operations',
451
+ 'orchestrator', 'product-manager', 'qa', 'researcher', 'reviewer', 'security',
335
452
  ];
336
453
 
337
454
  const CX_ROLE_LEAK = new RegExp(
@@ -392,8 +509,8 @@ function findToolIdentityLeaks(content) {
392
509
  function checkBanned(content, filePath) {
393
510
  if (isBannedCheckSkipped(filePath)) return [];
394
511
 
395
- // Banned patterns are JS/TS comment conventions — they don't apply to markdown prose.
396
- if (filePath && path.extname(filePath) === '.md') return [];
512
+ // Banned patterns are JS/TS comment conventions — they don't apply to markdown/MDX prose.
513
+ if (filePath && ['.md', '.mdx'].includes(path.extname(filePath))) return [];
397
514
 
398
515
  const warnings = [];
399
516
  const lines = content.split('\n');
@@ -465,6 +582,8 @@ export function lintFile(filePath, { rootDir = process.cwd(), fix = false } = {}
465
582
  // the finding.
466
583
  const artifactHits = checkArtifactBanned(content, rel);
467
584
  if (isArtifactPath(rel)) artifactHits.push(...findDanglingCitations(content, { rootDir }));
585
+ artifactHits.push(...checkFutureStateMarkers(content, rel));
586
+ artifactHits.push(...checkExternalProjectNames(content, filePath, rel));
468
587
  if (artifactHits.length > 0) {
469
588
  const mode = process.env.CONSTRUCT_ARTIFACT_LINT_MODE || 'warn';
470
589
  const bucket = mode === 'block' ? errors : warnings;
@@ -514,7 +633,7 @@ export function lintRepo({ rootDir = process.cwd(), fix = false } = {}) {
514
633
  const rel = relPath(rootDir, f);
515
634
  const { required } = requiresHeader(rel);
516
635
  const ext = path.extname(f);
517
- if (!required && !['.mjs', '.md', '.sh'].includes(ext)) continue;
636
+ if (!required && !['.mjs', '.md', '.mdx', '.sh'].includes(ext)) continue;
518
637
  const result = lintFile(f, { rootDir, fix });
519
638
  if (result.errors.length || result.warnings.length) results.push(result);
520
639
  }