@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
@@ -19,7 +19,7 @@
19
19
  */
20
20
 
21
21
  import { spawnSync } from 'node:child_process';
22
- import { existsSync, statSync, readFileSync } from 'node:fs';
22
+ import { existsSync, statSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
23
23
  import path from 'node:path';
24
24
  import { fileURLToPath } from 'node:url';
25
25
 
@@ -109,13 +109,19 @@ if (consumerPkg.name === '@geraldmaron/construct') {
109
109
  process.exit(0);
110
110
  }
111
111
 
112
+ // Track every project mutation for the itemized receipt written at the end.
113
+ // npm has no uninstall lifecycle hook so the manifest is the only machine-readable
114
+ // record of what the hook touched and how to revert it (CX-AUDIT-PACKAGE-004).
115
+ const mutations = [];
116
+
112
117
  try {
113
- stageProjectAdapters({
118
+ const stageResult = stageProjectAdapters({
114
119
  projectRoot: initCwd,
115
120
  packageRoot: PKG_ROOT,
116
121
  pkgVersion: PKG_VERSION,
117
122
  log,
118
123
  });
124
+ mutations.push({ path: '.construct', type: 'stage', synced: stageResult.synced });
119
125
 
120
126
  // ADR-0027: Ensure .gitignore covers the newly staged adapters (construct-f6l6).
121
127
  // Idempotent: missingIgnorePatterns returns only patterns not already present.
@@ -129,8 +135,27 @@ try {
129
135
  const block = `${prefix}\n${HEADER}\n${SUBHEADER}\n${missing.join('\n')}\n`;
130
136
  const { appendFileSync } = await import('node:fs');
131
137
  appendFileSync(giPath, block, 'utf8');
138
+ mutations.push({ path: '.gitignore', type: 'append', patterns: missing });
132
139
  log(`appended ${missing.length} Construct ignore pattern(s) to .gitignore`);
133
140
  }
141
+
142
+ // Write the itemized mutation receipt so consumers can audit and revert what the
143
+ // hook touched. Write is best-effort: a manifest failure must never break an install.
144
+ try {
145
+ mkdirSync(path.join(initCwd, '.construct'), { recursive: true });
146
+ const manifest = {
147
+ pkgVersion: PKG_VERSION,
148
+ ts: new Date().toISOString(),
149
+ files: mutations.map((m) => m.path),
150
+ mutations,
151
+ recovery: 'npx construct init --repair',
152
+ };
153
+ writeFileSync(
154
+ path.join(initCwd, '.construct', 'install-manifest.json'),
155
+ JSON.stringify(manifest, null, 2) + '\n',
156
+ );
157
+ log('wrote .construct/install-manifest.json');
158
+ } catch { /* manifest write must not fail the install */ }
134
159
  } catch (err) {
135
160
  fail(`Adapter staging failed: ${err.message}`, 'The package is installed; run `npx construct init` in this project to complete setup.');
136
161
  // Intentionally exit 0: staging is best-effort completion, and a non-zero exit
@@ -0,0 +1,264 @@
1
+ {
2
+ "version": 1,
3
+ "facets": {
4
+ "intake-type": { "exclusive": true, "auto_threshold": 0.80 },
5
+ "lifecycle": { "exclusive": true, "auto_threshold": 0.90 },
6
+ "priority": { "exclusive": true, "auto_threshold": 0.90 },
7
+ "signal-strength": { "exclusive": false, "auto_threshold": 0.95 },
8
+ "reversibility": { "exclusive": true, "auto_threshold": 0.85 },
9
+ "doctype": { "exclusive": true, "auto_threshold": 0.90 }
10
+ },
11
+ "tags": [
12
+ {
13
+ "id": "intake/bug",
14
+ "facet": "intake-type",
15
+ "label": "Bug",
16
+ "synonyms": ["defect", "regression", "error"],
17
+ "promote_to_graph": false,
18
+ "status": "active"
19
+ },
20
+ {
21
+ "id": "intake/user-signal",
22
+ "facet": "intake-type",
23
+ "label": "User Signal",
24
+ "synonyms": ["feedback", "user-feedback", "customer-signal"],
25
+ "promote_to_graph": false,
26
+ "status": "active"
27
+ },
28
+ {
29
+ "id": "intake/experiment",
30
+ "facet": "intake-type",
31
+ "label": "Experiment",
32
+ "synonyms": ["ab-test", "test", "trial"],
33
+ "promote_to_graph": false,
34
+ "status": "active"
35
+ },
36
+ {
37
+ "id": "intake/architecture",
38
+ "facet": "intake-type",
39
+ "label": "Architecture",
40
+ "synonyms": ["design", "system-design", "arch"],
41
+ "promote_to_graph": false,
42
+ "status": "active"
43
+ },
44
+ {
45
+ "id": "intake/incident",
46
+ "facet": "intake-type",
47
+ "label": "Incident",
48
+ "synonyms": ["outage", "postmortem", "production-issue"],
49
+ "promote_to_graph": false,
50
+ "status": "active"
51
+ },
52
+ {
53
+ "id": "intake/security",
54
+ "facet": "intake-type",
55
+ "label": "Security",
56
+ "synonyms": ["vulnerability", "cve", "threat"],
57
+ "promote_to_graph": false,
58
+ "status": "active"
59
+ },
60
+ {
61
+ "id": "intake/requirement",
62
+ "facet": "intake-type",
63
+ "label": "Requirement",
64
+ "synonyms": ["spec", "specification", "acceptance-criteria"],
65
+ "promote_to_graph": false,
66
+ "status": "active"
67
+ },
68
+ {
69
+ "id": "intake/research",
70
+ "facet": "intake-type",
71
+ "label": "Research",
72
+ "synonyms": ["study", "literature-review"],
73
+ "promote_to_graph": false,
74
+ "status": "active"
75
+ },
76
+ {
77
+ "id": "intake/ops",
78
+ "facet": "intake-type",
79
+ "label": "Ops",
80
+ "synonyms": ["operational", "runbook", "infra"],
81
+ "promote_to_graph": false,
82
+ "status": "active"
83
+ },
84
+ {
85
+ "id": "intake/eval-finding",
86
+ "facet": "intake-type",
87
+ "label": "Eval Finding",
88
+ "synonyms": ["evaluation", "eval", "benchmark-result"],
89
+ "promote_to_graph": false,
90
+ "status": "active"
91
+ },
92
+ {
93
+ "id": "intake/launch-asset",
94
+ "facet": "intake-type",
95
+ "label": "Launch Asset",
96
+ "synonyms": ["launch", "go-to-market", "release-material"],
97
+ "promote_to_graph": false,
98
+ "status": "active"
99
+ },
100
+ {
101
+ "id": "intake/legal-compliance",
102
+ "facet": "intake-type",
103
+ "label": "Legal Compliance",
104
+ "synonyms": ["legal", "compliance", "regulatory"],
105
+ "promote_to_graph": false,
106
+ "status": "active"
107
+ },
108
+ {
109
+ "id": "lifecycle/draft",
110
+ "facet": "lifecycle",
111
+ "label": "Draft",
112
+ "synonyms": ["wip", "in-progress"],
113
+ "promote_to_graph": false,
114
+ "status": "active"
115
+ },
116
+ {
117
+ "id": "lifecycle/approved",
118
+ "facet": "lifecycle",
119
+ "label": "Approved",
120
+ "synonyms": ["accepted", "ratified"],
121
+ "promote_to_graph": false,
122
+ "status": "active"
123
+ },
124
+ {
125
+ "id": "lifecycle/deprecated",
126
+ "facet": "lifecycle",
127
+ "label": "Deprecated",
128
+ "synonyms": ["sunset", "retiring"],
129
+ "promote_to_graph": false,
130
+ "status": "active"
131
+ },
132
+ {
133
+ "id": "lifecycle/superseded",
134
+ "facet": "lifecycle",
135
+ "label": "Superseded",
136
+ "synonyms": ["replaced", "obsolete"],
137
+ "promote_to_graph": false,
138
+ "status": "active"
139
+ },
140
+ {
141
+ "id": "lifecycle/archived",
142
+ "facet": "lifecycle",
143
+ "label": "Archived",
144
+ "synonyms": ["closed", "done"],
145
+ "promote_to_graph": false,
146
+ "status": "active"
147
+ },
148
+ {
149
+ "id": "priority/p0",
150
+ "facet": "priority",
151
+ "label": "P0 - Critical",
152
+ "synonyms": ["critical", "blocker", "sev0"],
153
+ "promote_to_graph": true,
154
+ "status": "active"
155
+ },
156
+ {
157
+ "id": "priority/p1",
158
+ "facet": "priority",
159
+ "label": "P1 - High",
160
+ "synonyms": ["high", "urgent", "sev1"],
161
+ "promote_to_graph": true,
162
+ "status": "active"
163
+ },
164
+ {
165
+ "id": "priority/p2",
166
+ "facet": "priority",
167
+ "label": "P2 - Medium",
168
+ "synonyms": ["medium", "normal", "sev2"],
169
+ "promote_to_graph": false,
170
+ "status": "active"
171
+ },
172
+ {
173
+ "id": "priority/p3",
174
+ "facet": "priority",
175
+ "label": "P3 - Low",
176
+ "synonyms": ["low", "nice-to-have", "sev3"],
177
+ "promote_to_graph": false,
178
+ "status": "active"
179
+ },
180
+ {
181
+ "id": "signal/high-customer-interest",
182
+ "facet": "signal-strength",
183
+ "label": "High Customer Interest",
184
+ "synonyms": ["customer-demand", "high-demand", "top-request"],
185
+ "promote_to_graph": true,
186
+ "anchor_entities": ["customer-feedback"],
187
+ "expected_cardinality": 100,
188
+ "cardinality_window_days": 90,
189
+ "status": "active"
190
+ },
191
+ {
192
+ "id": "signal/internal-alignment",
193
+ "facet": "signal-strength",
194
+ "label": "Internal Alignment",
195
+ "synonyms": ["aligned", "consensus", "cross-team"],
196
+ "promote_to_graph": false,
197
+ "status": "active"
198
+ },
199
+ {
200
+ "id": "signal/blocked",
201
+ "facet": "signal-strength",
202
+ "label": "Blocked",
203
+ "synonyms": ["dependency", "waiting", "stalled"],
204
+ "promote_to_graph": false,
205
+ "status": "active"
206
+ },
207
+ {
208
+ "id": "reversibility/irreversible",
209
+ "facet": "reversibility",
210
+ "label": "Irreversible",
211
+ "synonyms": ["one-way-door", "permanent"],
212
+ "promote_to_graph": true,
213
+ "status": "active"
214
+ },
215
+ {
216
+ "id": "reversibility/reversible",
217
+ "facet": "reversibility",
218
+ "label": "Reversible",
219
+ "synonyms": ["two-way-door", "rollback"],
220
+ "promote_to_graph": false,
221
+ "status": "active"
222
+ },
223
+ {
224
+ "id": "reversibility/quasi-reversible",
225
+ "facet": "reversibility",
226
+ "label": "Quasi-Reversible",
227
+ "synonyms": ["partially-reversible", "conditional-rollback"],
228
+ "promote_to_graph": false,
229
+ "status": "active"
230
+ },
231
+ {
232
+ "id": "doctype/prd",
233
+ "facet": "doctype",
234
+ "label": "PRD",
235
+ "synonyms": ["product-requirements", "product-spec"],
236
+ "promote_to_graph": false,
237
+ "status": "active"
238
+ },
239
+ {
240
+ "id": "doctype/adr",
241
+ "facet": "doctype",
242
+ "label": "ADR",
243
+ "synonyms": ["architecture-decision", "decision-record"],
244
+ "promote_to_graph": false,
245
+ "status": "active"
246
+ },
247
+ {
248
+ "id": "doctype/rfc",
249
+ "facet": "doctype",
250
+ "label": "RFC",
251
+ "synonyms": ["request-for-comments", "proposal"],
252
+ "promote_to_graph": false,
253
+ "status": "active"
254
+ },
255
+ {
256
+ "id": "doctype/postmortem",
257
+ "facet": "doctype",
258
+ "label": "Postmortem",
259
+ "synonyms": ["incident-review", "retrospective"],
260
+ "promote_to_graph": false,
261
+ "status": "active"
262
+ }
263
+ ]
264
+ }
@@ -60,6 +60,6 @@ One token set across all distributable formats:
60
60
 
61
61
  - Export: `construct export … --to=pptx`
62
62
  - Regenerate: `npm run examples:deck`
63
- - Matrix: [Document I/O reference](/guides/reference/document-io)
63
+ - Matrix: [Document I/O reference](../../../docs/guides/reference/document-io.md)
64
64
 
65
65
  Review outputs in `.tmp/distribution-examples/`.
@@ -12,6 +12,10 @@
12
12
  * methods: `initialize`, `session/new`, `session/prompt`, `session/cancel`;
13
13
  * progress streams as `session/update` notifications. The prompt bridges to
14
14
  * planRun/executeRun and forwards run-lifecycle events as agent message chunks.
15
+ *
16
+ * `fetchImpl` is injectable (mirrors lib/orchestration/worker.mjs) and threads
17
+ * straight through to executeRun, so a test can drive the provider backend
18
+ * without a live key or a real network call.
15
19
  */
16
20
 
17
21
  import { createInterface } from 'node:readline';
@@ -20,16 +24,26 @@ const PROTOCOL_VERSION = 1;
20
24
 
21
25
  function describeEvent(event) {
22
26
  if (event.type === 'planned') return `Planned ${event.tasks ?? ''} specialist task(s).`;
23
- if (event.type === 'running') return 'Running orchestration…';
24
- if (event.type === 'task') return `· ${event.role ?? 'task'} — ${event.status ?? ''}`;
25
- if (event.type === 'completed') return `Completed: ${event.status ?? 'done'}.`;
27
+ if (event.type === 'running') return `Running orchestration… (workerBackend=${event.workerBackend ?? 'inline'})`;
28
+ if (event.type === 'task') return `· ${event.role ?? 'task'} — ${event.status ?? ''}${event.executor ? ` (${event.executor})` : ''}`;
29
+ if (event.type === 'completed') {
30
+ const status = event.status ?? 'done';
31
+ if (status === 'completed') return 'Completed (specialist tasks executed).';
32
+ if (status === 'completed-prepare-only') return 'Completed (tasks prepared only — no specialist execution).';
33
+ if (status === 'completed-with-failures') return 'Completed with failures (some tasks failed).';
34
+ if (status === 'degraded') return 'Degraded — the run could not fully execute; see the summary.';
35
+ if (status === 'cancelled') return 'Cancelled.';
36
+ return `Completed: ${status}.`;
37
+ }
26
38
  if (event.type === 'error') return `Error: ${event.error?.message ?? 'run failed'}.`;
27
39
  return null;
28
40
  }
29
41
 
30
42
  function summarize(run) {
31
- const tasks = (run.tasks || []).map((t) => `- ${t.role} (${t.status})`).join('\n');
32
- return `Orchestration ${run.status} executionMode=${run.execution?.executionMode}.\n${tasks}`;
43
+ const tasks = (run.tasks || []).map((t) => `- ${t.role} (${t.status}${t.executor ? `, ${t.executor}` : ''})`).join('\n');
44
+ const exec = run.execution || {};
45
+ const degraded = run.degraded ? ` — degraded: ${run.degradationReason}` : '';
46
+ return `Orchestration ${run.status} — executionMode=${exec.executionMode}, workerBackend=${run.workerBackend}${degraded}.\n${tasks}`;
33
47
  }
34
48
 
35
49
  function textFromPrompt(prompt) {
@@ -37,7 +51,7 @@ function textFromPrompt(prompt) {
37
51
  return prompt.filter((b) => b && b.type === 'text' && typeof b.text === 'string').map((b) => b.text).join('\n').trim();
38
52
  }
39
53
 
40
- export function runAcpServer({ input, output, env = process.env, defaultCwd = process.cwd() } = {}) {
54
+ export function runAcpServer({ input, output, env = process.env, defaultCwd = process.cwd(), fetchImpl } = {}) {
41
55
  const sessions = new Map();
42
56
  let sessionCounter = 0;
43
57
 
@@ -63,7 +77,7 @@ export function runAcpServer({ input, output, env = process.env, defaultCwd = pr
63
77
  const line = describeEvent(event);
64
78
  if (line) update(sessionId, line);
65
79
  });
66
- const run = await executeRun(session.cwd, planned.runId, { env, workerBackend: 'inline' });
80
+ const run = await executeRun(session.cwd, planned.runId, { env, fetchImpl });
67
81
  off();
68
82
  update(sessionId, summarize(run));
69
83
  respond(id, { stopReason: isCancelRequested(planned.runId) ? 'cancelled' : 'end_turn' });
@@ -12,6 +12,7 @@ import { fileURLToPath } from 'node:url';
12
12
  import { detectHostCapabilities } from './host-capabilities.mjs';
13
13
  import { isConstructPackageRepo } from './host-disposition.mjs';
14
14
  import { stageProjectAdapters } from './install/stage-project.mjs';
15
+ import { isMainModule } from './roots.mjs';
15
16
 
16
17
  const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
17
18
  const PKG_ROOT = path.resolve(MODULE_DIR, '..');
@@ -58,7 +59,7 @@ export function runAdaptersScript({ cwd = process.cwd(), hosts = null } = {}) {
58
59
  return result.synced ? 0 : 1;
59
60
  }
60
61
 
61
- if (import.meta.url === `file://${process.argv[1]}`) {
62
+ if (isMainModule(import.meta.url)) {
62
63
  const args = new Set(process.argv.slice(2));
63
64
  const forceAll = args.has('--all-hosts');
64
65
  const hosts = forceAll ? resolveAdapterHosts({ forceAll: true }) : null;
@@ -17,14 +17,31 @@
17
17
  * the damaged prefix as immutable legacy and re-bases the live chain;
18
18
  * verifyChain validates only from the last boundary forward. See
19
19
  * docs/guides/concepts/observability.md.
20
+ *
21
+ * Every record passes through redactRecord before the chain hash is computed
22
+ * (redact-then-sign), so prev_line_hash always chains off the redacted form —
23
+ * a secret can never enter the signed chain even transiently. Redaction
24
+ * covers: (a) values resolved by lib/providers/secret-resolver.mjs, consulted
25
+ * read-only via its resolved-cache snapshot; (b) common token shapes (Bearer,
26
+ * ghp_, xoxb/xoxp/xoxa, sk-, op://); (c) custom patterns registered with
27
+ * configureRedactionPatterns. Matches are replaced with `<redacted:kind>`;
28
+ * the pass itself is audited as a count, never the matched text.
29
+ *
30
+ * LMCP-H5: checkAuditSinkAvailable performs a real write-probe against the
31
+ * audit directory (mkdir + append + unlink a sidecar file) so a caller can
32
+ * distinguish "sink healthy" from "sink down" (read-only filesystem, missing
33
+ * mount, permissions) before deciding whether to proceed. Enterprise mode's
34
+ * mandatory-audit gate (lib/policy/audit-gate.mjs) fails closed on this
35
+ * check; solo/team never call it.
20
36
  */
21
- import { readFileSync, existsSync, statSync, mkdirSync } from 'node:fs';
37
+ import { readFileSync, existsSync, statSync, mkdirSync, appendFileSync, unlinkSync } from 'node:fs';
22
38
  import { createHash } from 'node:crypto';
23
39
  import { join, dirname } from 'node:path';
24
40
 
25
41
  import { appendBounded, readLastLineAcrossSegments } from './logging/rotate.mjs';
26
42
  import { withFileLockSync } from './storage/file-lock.mjs';
27
43
  import { doctorRoot } from './config/xdg.mjs';
44
+ import { __resolvedSecretValues } from './providers/secret-resolver.mjs';
28
45
 
29
46
  const AUDIT_FILE = join(doctorRoot(), 'audit-trail.jsonl');
30
47
 
@@ -32,17 +49,183 @@ function sha256(input) {
32
49
  return createHash('sha256').update(input).digest('hex');
33
50
  }
34
51
 
52
+ export class AuditSinkUnavailableError extends Error {
53
+ constructor(message, { file, reason } = {}) {
54
+ super(message);
55
+ this.name = 'AuditSinkUnavailableError';
56
+ this.file = file ?? null;
57
+ this.reason = reason ?? null;
58
+ }
59
+ }
60
+
61
+ // A real write-probe, not a stat/existsSync check: a directory can exist and
62
+ // still refuse writes (read-only remount, quota, permission drop after
63
+ // mkdir). Writing and removing a sidecar file physically exercises the same
64
+ // path appendAuditRecord will take next, so "available" here means the next
65
+ // real append is actually expected to succeed.
66
+
67
+ export function checkAuditSinkAvailable({ file = AUDIT_FILE } = {}) {
68
+ const dir = dirname(file);
69
+ const probePath = join(dir, `.audit-sink-probe-${process.pid}-${Date.now()}`);
70
+ try {
71
+ mkdirSync(dir, { recursive: true });
72
+ appendFileSync(probePath, 'probe\n', 'utf8');
73
+ unlinkSync(probePath);
74
+ return { available: true, reason: null };
75
+ } catch (err) {
76
+ return { available: false, reason: err?.code || err?.message || 'unknown-error' };
77
+ }
78
+ }
79
+
80
+ // Built-in token shapes seen in the wild across providers: generic Bearer
81
+ // headers, GitHub PATs (ghp_), Slack bot/user/app tokens (xoxb/xoxp/xoxa),
82
+ // OpenAI-style secret keys (sk-), and 1Password references (op://...). Each
83
+ // pattern is tagged with a `kind` so the replacement reads `<redacted:kind>`
84
+ // rather than a single opaque marker, which keeps audit records diagnosable.
85
+
86
+ const BUILTIN_PATTERNS = [
87
+ { kind: 'bearer-token', re: /\bBearer\s+[A-Za-z0-9\-._~+/]+=*/g },
88
+ { kind: 'github-token', re: /\bghp_[A-Za-z0-9]{20,}\b/g },
89
+ { kind: 'slack-token', re: /\bxox[bpa]-[A-Za-z0-9-]{10,}\b/g },
90
+ { kind: 'api-key', re: /\bsk-[A-Za-z0-9]{16,}\b/g },
91
+ { kind: 'op-reference', re: /\bop:\/\/[^\s'"]+/g },
92
+ ];
93
+
94
+ // Custom patterns a caller wires in at startup (e.g. an org-specific token
95
+ // shape). Kept process-local and additive over BUILTIN_PATTERNS; never
96
+ // persisted, so a test or embedder can register/reset freely.
97
+
98
+ let customPatterns = [];
99
+
100
+ /**
101
+ * Register additional redaction patterns beyond the built-in token shapes.
102
+ * Each entry is `{ kind, re }` where `re` is a global RegExp. Replaces the
103
+ * full custom set on every call so a caller can reconfigure cleanly.
104
+ *
105
+ * @param {{kind:string, re:RegExp}[]} patterns
106
+ */
107
+ export function configureRedactionPatterns(patterns = []) {
108
+ customPatterns = Array.isArray(patterns) ? patterns.filter((p) => p && p.re instanceof RegExp && typeof p.kind === 'string') : [];
109
+ }
110
+
111
+ export function __resetRedactionPatterns() {
112
+ customPatterns = [];
113
+ }
114
+
115
+ // Secret values below this length are excluded from the known-value pass:
116
+ // short resolved values (flags, single-char tokens) produce false-positive
117
+ // redactions in ordinary prose.
118
+
119
+ const MIN_KNOWN_SECRET_LENGTH = 8;
120
+
121
+ function escapeRegExp(str) {
122
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
123
+ }
124
+
125
+ // A resolved secret is redacted by exact substring match, not by first
126
+ // hashing the haystack — a hash comparison can only ever confirm equality of
127
+ // two already-known values, never locate an unknown-length substring inside
128
+ // arbitrary free text. Instead, the "hashed comparison" the caller performs
129
+ // (recorded in the audit count, see below) is against sha256(value) so the
130
+ // count event that leaves the process never carries a byte of the plaintext,
131
+ // even though the in-process match itself must touch the plaintext to redact
132
+ // it — the same value already lives in secret-resolver's own cache in-process.
133
+
134
+ function knownSecretPatterns() {
135
+ const values = __resolvedSecretValues().filter(
136
+ (v) => typeof v === 'string' && v.length >= MIN_KNOWN_SECRET_LENGTH,
137
+ );
138
+ return values.map((value) => ({
139
+ kind: 'known-secret',
140
+ re: new RegExp(escapeRegExp(value), 'g'),
141
+ hash: sha256(value),
142
+ }));
143
+ }
144
+
145
+ // lib/providers/secret-audit-wiring.mjs already records the op:// reference
146
+ // itself (never the resolved value) under these exact key names as its
147
+ // value-free diagnostic contract — a bare op://vault/item/field pointer is
148
+ // not a secret, so the op-reference pattern must not clobber it there. Any
149
+ // other field carrying an op:// string (a tool result body, a raw env dump)
150
+ // is still redacted.
151
+
152
+ const OP_REF_EXEMPT_KEYS = new Set(['ref']);
153
+
154
+ // Walk every string reachable in `value`, applying every pattern in turn and
155
+ // replacing matches with `<redacted:kind>`. Returns the redacted clone plus a
156
+ // count-only tally (kind → number of matches) so the caller can audit that
157
+ // redaction occurred without ever recording the matched text.
158
+
159
+ function redactString(str, patterns, tally) {
160
+ let out = str;
161
+ for (const { kind, re } of patterns) {
162
+ re.lastIndex = 0;
163
+ const matches = out.match(re);
164
+ if (matches && matches.length) {
165
+ tally[kind] = (tally[kind] || 0) + matches.length;
166
+ out = out.replace(re, `<redacted:${kind}>`);
167
+ }
168
+ }
169
+ return out;
170
+ }
171
+
172
+ function redactValue(value, patterns, tally, key = null) {
173
+ if (typeof value === 'string') {
174
+ if (key && OP_REF_EXEMPT_KEYS.has(key)) {
175
+ const rest = patterns.filter((p) => p.kind !== 'op-reference');
176
+ return redactString(value, rest, tally);
177
+ }
178
+ return redactString(value, patterns, tally);
179
+ }
180
+ if (Array.isArray(value)) return value.map((v) => redactValue(v, patterns, tally));
181
+ if (value && typeof value === 'object') {
182
+ const out = {};
183
+ for (const [k, v] of Object.entries(value)) {
184
+ // Schema-marked redacted:true fields are already elided upstream by the
185
+ // caller's own schema; this pass is a second, pattern-based net over
186
+ // whatever free-text fields (detail, args, result, payload) remain.
187
+ out[k] = redactValue(v, patterns, tally, k);
188
+ }
189
+ return out;
190
+ }
191
+ return value;
192
+ }
193
+
194
+ /**
195
+ * Redact known secret values and token-shaped strings from an audit record.
196
+ * Runs BEFORE the chain hash is computed so the signature always covers the
197
+ * redacted form (redact-then-sign). Returns `{ record, tally }` where tally
198
+ * is a count-only map of kind → matches (never the matched text).
199
+ *
200
+ * @param {object} partial
201
+ * @returns {{record: object, tally: Record<string, number>}}
202
+ */
203
+ export function redactRecord(partial) {
204
+ const patterns = [...BUILTIN_PATTERNS, ...customPatterns, ...knownSecretPatterns()];
205
+ const tally = {};
206
+ const record = redactValue(partial, patterns, tally);
207
+ return { record, tally };
208
+ }
209
+
35
210
  // prev_line_hash and the append must be one atomic step or concurrent writers
36
211
  // race; the file lock serializes them across processes.
37
212
 
38
213
  export function appendAuditRecord(partial, { file = AUDIT_FILE } = {}) {
214
+ const { record: redacted, tally } = redactRecord(partial);
215
+
216
+ // Redaction is itself audited as a count only — never the secret — folded
217
+ // into the record's own field before it is hashed and written, so the
218
+ // signed line and the returned record always agree.
219
+
220
+ if (Object.keys(tally).length) redacted.redaction_counts = tally;
221
+
39
222
  return withFileLockSync(file, () => {
40
223
  let prev = null;
41
224
  try {
42
225
  const last = readLastLineAcrossSegments(file);
43
226
  if (last !== null) prev = sha256(last);
44
227
  } catch { /* first record, or unreadable tail */ }
45
- const record = { ...partial, prev_line_hash: prev };
228
+ const record = { ...redacted, prev_line_hash: prev };
46
229
  mkdirSync(dirname(file), { recursive: true });
47
230
  appendBounded('audit-trail', file, JSON.stringify(record) + '\n');
48
231
  return record;
@@ -21,6 +21,7 @@
21
21
  */
22
22
 
23
23
  import { spawnSync } from 'node:child_process';
24
+ import { isMainModule } from '../roots.mjs';
24
25
 
25
26
  const CLOSES_RE = /\b(?:closes?|close|fix(?:es)?|fixed|resolves?|resolved)\s+(construct-[a-z0-9]+)/gi;
26
27
 
@@ -105,7 +106,7 @@ export async function runAutoClose({ range, runner = spawnSync } = {}) {
105
106
  }
106
107
 
107
108
  // CLI entry: read --range, run, print summary.
108
- const invokedDirectly = import.meta.url === `file://${process.argv[1]}`;
109
+ const invokedDirectly = isMainModule(import.meta.url);
109
110
  if (invokedDirectly) {
110
111
  const args = process.argv.slice(2);
111
112
  const rangeArg = args.find((a) => a.startsWith('--range='));
@@ -25,6 +25,7 @@
25
25
  */
26
26
 
27
27
  import { spawnSync } from 'node:child_process';
28
+ import { isMainModule } from '../roots.mjs';
28
29
 
29
30
  const DEFAULT_STALE_OPEN_DAYS = 14;
30
31
  const DEFAULT_STUCK_IN_PROGRESS_DAYS = 3;
@@ -166,7 +167,7 @@ export function formatDriftReport(report) {
166
167
  }
167
168
 
168
169
  // CLI: print report, exit non-zero when thresholds breached unless --report-only.
169
- const invokedDirectly = import.meta.url === `file://${process.argv[1]}`;
170
+ const invokedDirectly = isMainModule(import.meta.url);
170
171
  if (invokedDirectly) {
171
172
  const args = process.argv.slice(2);
172
173
  const json = args.includes('--json');