@geraldmaron/construct 1.2.3 → 1.3.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 (504) hide show
  1. package/README.md +7 -10
  2. package/bin/construct +235 -209
  3. package/bin/construct-postinstall.mjs +0 -21
  4. package/commands/work/optimize-prompts.md +1 -1
  5. package/examples/distribution/sources/adr.md +2 -2
  6. package/examples/seed-observations/decisions.md +1 -1
  7. package/lib/artifact-loop-core.mjs +412 -0
  8. package/lib/artifact-manifest.mjs +6 -0
  9. package/lib/artifact-release-gate.mjs +115 -49
  10. package/lib/audit-rules.mjs +2 -4
  11. package/lib/audit-skills.mjs +32 -20
  12. package/lib/audit-specialists.mjs +44 -26
  13. package/lib/auto-docs.mjs +6 -5
  14. package/lib/brand-prose.mjs +3 -3
  15. package/lib/brand-tokens.mjs +2 -2
  16. package/lib/certification/artifact-fixtures.mjs +4 -1
  17. package/lib/certification/demo-parity.mjs +6 -32
  18. package/lib/certification/real-llm-scenarios.mjs +58 -13
  19. package/lib/certification/role-cards.mjs +7 -6
  20. package/lib/certification/role-overlays.mjs +4 -4
  21. package/lib/certification/runner.mjs +9 -2
  22. package/lib/certification/skill-inventory.mjs +34 -22
  23. package/lib/certification/skill-scenarios.mjs +21 -8
  24. package/lib/certification/specialist-contracts.mjs +4 -3
  25. package/lib/certification/specialist-scenarios.mjs +7 -6
  26. package/lib/certification/status.mjs +5 -4
  27. package/lib/cli-commands.mjs +55 -54
  28. package/lib/comment-lint.mjs +1 -5
  29. package/lib/completions.mjs +20 -2
  30. package/lib/config/legacy-config-migration.mjs +90 -24
  31. package/lib/config/schema.mjs +5 -5
  32. package/lib/config/source-targets.mjs +80 -0
  33. package/lib/contracts/validate.mjs +119 -51
  34. package/lib/decisions/golden.mjs +3 -2
  35. package/lib/decisions/registry.mjs +11 -6
  36. package/lib/demo-project.mjs +188 -0
  37. package/lib/demo-recording.mjs +9 -34
  38. package/lib/demo-script.mjs +2 -2
  39. package/lib/demo-surface.mjs +13 -131
  40. package/lib/demo-tour-renderer.mjs +92 -0
  41. package/lib/demo.mjs +69 -54
  42. package/lib/diagram-export.mjs +63 -14
  43. package/lib/doctor/source-checkout.mjs +3 -4
  44. package/lib/doctor/watchers/consistency.mjs +90 -22
  45. package/lib/doctor/watchers/credential-parity.mjs +97 -0
  46. package/lib/doctor/watchers/mcp-protocol.mjs +1 -1
  47. package/lib/doctor/watchers/service-health.mjs +4 -32
  48. package/lib/document-export.mjs +73 -9
  49. package/lib/document-extract.mjs +10 -198
  50. package/lib/embed/artifact.mjs +2 -3
  51. package/lib/embed/cli.mjs +1 -1
  52. package/lib/embed/config.mjs +1 -2
  53. package/lib/embed/customer-profiles.mjs +1 -1
  54. package/lib/embed/daemon.mjs +5 -6
  55. package/lib/embed/demand-fetch.mjs +114 -2
  56. package/lib/embed/docs-lifecycle.mjs +9 -5
  57. package/lib/embed/intake-metrics.mjs +2 -2
  58. package/lib/embed/notifications.mjs +2 -3
  59. package/lib/embed/recommendation-store.mjs +25 -22
  60. package/lib/embed/role-framing.mjs +4 -9
  61. package/lib/embedded-contract/capability.mjs +4 -2
  62. package/lib/embedded-contract/contract-version.mjs +1 -1
  63. package/lib/env-config.mjs +2 -2
  64. package/lib/flavors/loader.mjs +21 -19
  65. package/lib/graph/build-from-registry.mjs +31 -7
  66. package/lib/graph/staleness.mjs +1 -1
  67. package/lib/headhunt.mjs +82 -35
  68. package/lib/hooks/agent-tracker.mjs +2 -2
  69. package/lib/hooks/config-protection.mjs +1 -1
  70. package/lib/hooks/registry-sync.mjs +3 -3
  71. package/lib/host-capabilities.mjs +5 -5
  72. package/lib/improvement/controller.mjs +2 -2
  73. package/lib/init-unified.mjs +19 -21
  74. package/lib/intake/classify.mjs +26 -0
  75. package/lib/intake/daemon.mjs +2 -3
  76. package/lib/intake/prepare.mjs +10 -3
  77. package/lib/intake/session-prelude.mjs +1 -1
  78. package/lib/intake/tables/creative.mjs +9 -9
  79. package/lib/intake/tables/operations.mjs +4 -4
  80. package/lib/intake/tables/research.mjs +2 -2
  81. package/lib/integrations/intake-integrations.mjs +9 -10
  82. package/lib/knowledge/research-store.mjs +2 -2
  83. package/lib/mcp/server.mjs +104 -61
  84. package/lib/mcp/tool-budget.mjs +1 -46
  85. package/lib/mcp/tool-recovery.mjs +44 -0
  86. package/lib/mcp/tools/artifact-author.mjs +36 -0
  87. package/lib/mcp/tools/find-tool.mjs +86 -0
  88. package/lib/mcp/tools/orchestration-run.mjs +107 -69
  89. package/lib/mcp/tools/project.mjs +4 -3
  90. package/lib/mcp/tools/{profile.mjs → scope.mjs} +54 -52
  91. package/lib/mcp/tools/skills.mjs +39 -22
  92. package/lib/mcp/tools/telemetry.mjs +2 -1
  93. package/lib/mcp/tools/workflow.mjs +1 -1
  94. package/lib/mcp-platform-config.mjs +7 -5
  95. package/lib/migrations/index.mjs +4 -2
  96. package/lib/migrations/v2-unified-registry.mjs +35 -0
  97. package/lib/model-router.mjs +203 -36
  98. package/lib/models/catalog.mjs +25 -9
  99. package/lib/models/execution-capability-profile.mjs +3 -3
  100. package/lib/models/execution-policy.mjs +7 -6
  101. package/lib/models/provider-poll.mjs +18 -4
  102. package/lib/opencode-config.mjs +56 -1
  103. package/lib/opencode-runtime-plugin.mjs +13 -10
  104. package/lib/oracle/artifact-gate.mjs +14 -4
  105. package/lib/oracle/cli.mjs +2 -0
  106. package/lib/oracle/dispatch.mjs +18 -1
  107. package/lib/oracle/execute.mjs +39 -7
  108. package/lib/oracle/index.mjs +1 -1
  109. package/lib/oracle/org-graph.mjs +10 -5
  110. package/lib/oracle/policy.mjs +6 -0
  111. package/lib/oracle/read-model.mjs +103 -6
  112. package/lib/oracle/reconcile.mjs +31 -4
  113. package/lib/oracle/remediation-dispatch.mjs +53 -0
  114. package/lib/oracle/routing.mjs +5 -0
  115. package/lib/oracle/synthesize.mjs +80 -3
  116. package/lib/orchestration/routing-tables.mjs +44 -10
  117. package/lib/orchestration/runtime.mjs +2 -0
  118. package/lib/orchestration/worker.mjs +1 -1
  119. package/lib/orchestration-policy.mjs +351 -62
  120. package/lib/overrides/resolver.mjs +1 -12
  121. package/lib/parity.mjs +37 -11
  122. package/lib/policy/engine.mjs +80 -15
  123. package/lib/prompt-composer.js +51 -15
  124. package/lib/prompt-metadata.mjs +3 -2
  125. package/lib/providers/connection-probe.mjs +58 -0
  126. package/lib/providers/copilot-auth.mjs +1 -1
  127. package/lib/providers/credential-bootstrap.mjs +1 -1
  128. package/lib/providers/op-run.mjs +3 -4
  129. package/lib/providers/secret-resolver.mjs +31 -0
  130. package/lib/publish-tooling.mjs +3 -11
  131. package/lib/publish.mjs +12 -29
  132. package/lib/reconcile/mcp-entry-reconcile.mjs +14 -9
  133. package/lib/reflect.mjs +2 -2
  134. package/lib/registry/agent-manifest.mjs +190 -0
  135. package/lib/registry/assemble.mjs +133 -0
  136. package/lib/registry/catalog.mjs +171 -0
  137. package/lib/registry/cli.mjs +590 -6
  138. package/lib/registry/consolidation.mjs +5 -4
  139. package/lib/registry/docs-sync.mjs +67 -0
  140. package/lib/registry/loader.mjs +147 -0
  141. package/lib/registry/org-io.mjs +76 -0
  142. package/lib/registry/retired-paths.mjs +71 -0
  143. package/lib/registry/surface-map.mjs +5 -7
  144. package/lib/registry/validator.mjs +438 -0
  145. package/lib/research-execution-policy.mjs +173 -0
  146. package/lib/roles/catalog.mjs +4 -9
  147. package/lib/roles/fence.mjs +107 -1
  148. package/lib/roles/flavor-bindings.mjs +68 -0
  149. package/lib/roles/gateway.mjs +140 -29
  150. package/lib/roles/manifest.mjs +22 -13
  151. package/lib/roles/router.mjs +1 -1
  152. package/lib/scopes/enrich.mjs +67 -0
  153. package/lib/scopes/hooks.mjs +12 -0
  154. package/lib/{profiles → scopes}/lifecycle.mjs +70 -70
  155. package/lib/scopes/loader.mjs +104 -0
  156. package/lib/scopes/rebrand.mjs +32 -0
  157. package/lib/scopes/research-profile.mjs +16 -0
  158. package/lib/scopes/teams.mjs +98 -0
  159. package/lib/service-manager.mjs +1 -117
  160. package/lib/setup-prompts.mjs +1 -1
  161. package/lib/setup.mjs +6 -26
  162. package/lib/skills/composition-graph.mjs +98 -0
  163. package/lib/skills/router.mjs +80 -0
  164. package/lib/specialist-contracts.mjs +17 -18
  165. package/lib/specialists/postconditions.mjs +2 -2
  166. package/lib/specialists/prompt-schema.mjs +6 -5
  167. package/lib/specialists/roster.mjs +7 -12
  168. package/lib/specialists/schema.mjs +9 -6
  169. package/lib/status.mjs +25 -90
  170. package/lib/storage/file-lock.mjs +6 -3
  171. package/lib/telemetry/skill-calls.mjs +1 -1
  172. package/lib/templates/doc-presentation.mjs +63 -0
  173. package/lib/templates/visual-requirements.mjs +35 -2
  174. package/lib/term-format.mjs +107 -2
  175. package/lib/test-env-setup.mjs +21 -0
  176. package/lib/ui/components.mjs +42 -0
  177. package/lib/ui/glyphs.mjs +58 -0
  178. package/lib/ui/links.mjs +115 -0
  179. package/lib/ui/theme.mjs +108 -0
  180. package/lib/uninstall/uninstall.mjs +2 -1
  181. package/lib/validator.mjs +45 -8
  182. package/lib/validators/skill-effectiveness.mjs +174 -0
  183. package/lib/validators/skills.mjs +1 -1
  184. package/package.json +12 -8
  185. package/personas/construct.md +12 -3
  186. package/platforms/claude/CLAUDE.md +1 -1
  187. package/rules/common/beads-hygiene.md +52 -0
  188. package/rules/common/neurodivergent-output.md +4 -7
  189. package/rules/common/research.md +2 -0
  190. package/scripts/sync-specialists.mjs +260 -49
  191. package/skills/ai/prompt-optimizer.md +3 -3
  192. package/skills/brand/output-vibe.md +48 -0
  193. package/skills/docs/adr-workflow.md +3 -0
  194. package/skills/docs/backlog-proposal-workflow.md +3 -0
  195. package/skills/docs/codebase-research-workflow.md +5 -2
  196. package/skills/docs/customer-profile-workflow.md +3 -0
  197. package/skills/docs/document-ingest-workflow.md +3 -0
  198. package/skills/docs/evidence-ingest-workflow.md +4 -1
  199. package/skills/docs/init-project.md +1 -1
  200. package/skills/docs/prd-workflow.md +1 -1
  201. package/skills/docs/prfaq-workflow.md +3 -0
  202. package/skills/docs/product-intelligence-workflow.md +4 -1
  203. package/skills/docs/product-signal-workflow.md +3 -0
  204. package/skills/docs/research-workflow.md +13 -6
  205. package/skills/docs/runbook-workflow.md +3 -0
  206. package/skills/docs/strategy-workflow.md +3 -0
  207. package/skills/docs/user-research-workflow.md +6 -3
  208. package/skills/operating/orchestration-reference.md +1 -1
  209. package/skills/roles/{engineer.ai.md → ai-engineer.md} +2 -2
  210. package/skills/roles/architect.ai-systems.md +1 -1
  211. package/skills/roles/architect.data.md +1 -1
  212. package/skills/roles/architect.enterprise.md +1 -1
  213. package/skills/roles/architect.integration.md +1 -1
  214. package/skills/roles/architect.md +1 -1
  215. package/skills/roles/architect.platform.md +1 -1
  216. package/skills/roles/{product-manager.business-strategy.md → business-strategist.md} +3 -3
  217. package/skills/roles/data-analyst.experiment.md +1 -1
  218. package/skills/roles/data-analyst.md +1 -1
  219. package/skills/roles/data-analyst.product-intelligence.md +1 -1
  220. package/skills/roles/data-analyst.product.md +1 -1
  221. package/skills/roles/data-analyst.telemetry.md +1 -1
  222. package/skills/roles/{engineer.data.md → data-engineer.md} +2 -2
  223. package/skills/roles/data-engineer.pipeline.md +2 -2
  224. package/skills/roles/data-engineer.vector-retrieval.md +2 -2
  225. package/skills/roles/data-engineer.warehouse.md +2 -2
  226. package/skills/roles/debugger.md +1 -1
  227. package/skills/roles/designer.accessibility.md +1 -1
  228. package/skills/roles/designer.md +1 -1
  229. package/skills/roles/{reviewer.devil-advocate.md → devil-advocate.md} +2 -2
  230. package/skills/roles/{operator.docs.md → docs-keeper.md} +3 -3
  231. package/skills/roles/engineer.md +3 -7
  232. package/skills/roles/{reviewer.evaluator.md → evaluator.md} +2 -2
  233. package/skills/roles/{researcher.explorer.md → explorer.md} +2 -2
  234. package/skills/roles/{operator.md → operations.md} +2 -5
  235. package/skills/roles/orchestrator.md +1 -1
  236. package/skills/roles/{engineer.platform.md → platform-engineer.md} +2 -2
  237. package/skills/roles/product-manager.ai-product.md +1 -1
  238. package/skills/roles/product-manager.enterprise.md +1 -1
  239. package/skills/roles/product-manager.growth.md +1 -2
  240. package/skills/roles/product-manager.md +1 -2
  241. package/skills/roles/product-manager.platform.md +1 -1
  242. package/skills/roles/product-manager.product.md +1 -1
  243. package/skills/roles/qa.ai-eval.md +1 -1
  244. package/skills/roles/qa.api-contract.md +1 -1
  245. package/skills/roles/qa.data-pipeline.md +1 -1
  246. package/skills/roles/qa.md +1 -1
  247. package/skills/roles/qa.web-ui.md +1 -1
  248. package/skills/roles/{operator.release.md → release-manager.md} +3 -3
  249. package/skills/roles/researcher.md +1 -1
  250. package/skills/roles/reviewer.md +1 -1
  251. package/skills/roles/security.ai.md +1 -1
  252. package/skills/roles/security.appsec.md +1 -1
  253. package/skills/roles/security.cloud.md +1 -1
  254. package/skills/roles/security.legal-compliance.md +1 -1
  255. package/skills/roles/security.md +1 -1
  256. package/skills/roles/security.privacy.md +1 -1
  257. package/skills/roles/security.supply-chain.md +1 -1
  258. package/skills/roles/{operator.sre.md → sre.md} +3 -3
  259. package/skills/roles/{qa.test-automation.md → test-automation.md} +2 -2
  260. package/skills/roles/{reviewer.trace.md → trace-reviewer.md} +2 -2
  261. package/skills/roles/{researcher.ux.md → ux-researcher.md} +2 -2
  262. package/skills/routing.json +18 -0
  263. package/skills/routing.md +1 -1
  264. package/specialists/artifact-manifest.json +2 -1
  265. package/specialists/audit-enrichments.json +14 -14
  266. package/specialists/org/contracts/accessibility-to-qa.json +37 -0
  267. package/specialists/org/contracts/any-to-business-strategist.json +57 -0
  268. package/specialists/org/contracts/any-to-debugger.json +38 -0
  269. package/specialists/org/contracts/any-to-designer.json +33 -0
  270. package/specialists/org/contracts/any-to-docs-keeper.json +34 -0
  271. package/specialists/org/contracts/any-to-explorer.json +39 -0
  272. package/specialists/org/contracts/any-to-sre-incident.json +33 -0
  273. package/specialists/org/contracts/any-to-trace-reviewer.json +32 -0
  274. package/specialists/org/contracts/architect-to-ai-engineer.json +32 -0
  275. package/specialists/org/contracts/architect-to-data-engineer.json +52 -0
  276. package/specialists/org/contracts/architect-to-devil-advocate.json +38 -0
  277. package/specialists/org/contracts/architect-to-engineer.json +34 -0
  278. package/specialists/org/contracts/architect-to-evaluator.json +59 -0
  279. package/specialists/org/contracts/architect-to-legal-compliance.json +55 -0
  280. package/specialists/org/contracts/architect-to-operations.json +45 -0
  281. package/specialists/org/contracts/architect-to-platform-engineer.json +42 -0
  282. package/specialists/org/contracts/business-strategist-to-product-manager.json +39 -0
  283. package/specialists/org/contracts/construct-to-orchestrator.json +36 -0
  284. package/specialists/org/contracts/construct-to-rd-lead.json +53 -0
  285. package/specialists/org/contracts/data-analyst-to-product-manager.json +43 -0
  286. package/specialists/org/contracts/data-engineer-to-platform-engineer.json +36 -0
  287. package/specialists/org/contracts/designer-to-accessibility.json +36 -0
  288. package/specialists/org/contracts/engineer-to-qa.json +34 -0
  289. package/specialists/org/contracts/engineer-to-reviewer.json +52 -0
  290. package/specialists/org/contracts/explorer-to-engineer.json +38 -0
  291. package/specialists/org/contracts/legal-compliance-to-release-manager.json +43 -0
  292. package/specialists/org/contracts/platform-engineer-to-engineer.json +31 -0
  293. package/specialists/org/contracts/product-manager-to-architect.json +71 -0
  294. package/specialists/org/contracts/product-manager-to-data-analyst.json +49 -0
  295. package/specialists/org/contracts/product-manager-to-ux-researcher.json +51 -0
  296. package/specialists/org/contracts/qa-to-release-manager.json +42 -0
  297. package/specialists/org/contracts/qa-to-test-automation.json +42 -0
  298. package/specialists/org/contracts/rd-lead-to-architect.json +38 -0
  299. package/specialists/org/contracts/researcher-to-architect.json +40 -0
  300. package/specialists/org/contracts/researcher-to-product-manager.json +57 -0
  301. package/specialists/org/contracts/reviewer-to-security.json +41 -0
  302. package/specialists/org/contracts/sre-to-release-manager.json +36 -0
  303. package/specialists/org/contracts/test-automation-to-engineer.json +34 -0
  304. package/specialists/org/contracts/trace-reviewer-to-sre.json +41 -0
  305. package/specialists/org/contracts/user-to-construct.json +30 -0
  306. package/specialists/org/groups/engineering-group.json +43 -0
  307. package/specialists/org/groups/governance-group.json +38 -0
  308. package/specialists/org/groups/operations-group.json +41 -0
  309. package/specialists/org/groups/product-group.json +46 -0
  310. package/specialists/org/groups/quality-group.json +42 -0
  311. package/specialists/org/groups/strategy-group.json +41 -0
  312. package/specialists/org/policies/action-approval.json +13 -0
  313. package/specialists/org/policies/agents-routing.json +13 -0
  314. package/specialists/org/policies/architecture.json +20 -0
  315. package/specialists/org/policies/bash-safety.json +13 -0
  316. package/specialists/org/policies/beads-hygiene.json +13 -0
  317. package/specialists/org/policies/bootstrap-state.json +13 -0
  318. package/specialists/org/policies/code-review.json +13 -0
  319. package/specialists/org/policies/coding-style.json +13 -0
  320. package/specialists/org/policies/comments.json +13 -0
  321. package/specialists/org/policies/commit-approval.json +13 -0
  322. package/specialists/org/policies/contract-preconditions.json +13 -0
  323. package/specialists/org/policies/deployment.json +20 -0
  324. package/specialists/org/policies/description.json +14 -0
  325. package/specialists/org/policies/design-approval.json +19 -0
  326. package/specialists/org/policies/doc-ownership.json +13 -0
  327. package/specialists/org/policies/file-path-fence.json +13 -0
  328. package/specialists/org/policies/framing.json +13 -0
  329. package/specialists/org/policies/git-workflow.json +13 -0
  330. package/specialists/org/policies/incident-response.json +15 -0
  331. package/specialists/org/policies/intake-triage.json +15 -0
  332. package/specialists/org/policies/neurodivergent-output.json +13 -0
  333. package/specialists/org/policies/no-fabrication.json +13 -0
  334. package/specialists/org/policies/patterns.json +13 -0
  335. package/specialists/org/policies/quality-gate-approval.json +17 -0
  336. package/specialists/org/policies/release-gates.json +13 -0
  337. package/specialists/org/policies/research-evidence.json +13 -0
  338. package/specialists/org/policies/review-before-change.json +13 -0
  339. package/specialists/org/policies/rollback.json +15 -0
  340. package/specialists/org/policies/scope-change.json +20 -0
  341. package/specialists/org/policies/secret-scan.json +13 -0
  342. package/specialists/org/policies/security-approval.json +17 -0
  343. package/specialists/org/policies/security.json +13 -0
  344. package/specialists/org/policies/session-efficiency.json +13 -0
  345. package/specialists/org/policies/skill-routing.json +13 -0
  346. package/specialists/org/policies/strategic-prioritization.json +17 -0
  347. package/specialists/org/policies/testing.json +13 -0
  348. package/specialists/org/policies/tool-invisibility.json +14 -0
  349. package/specialists/org/scopes/creative.json +54 -0
  350. package/specialists/org/scopes/operations.json +51 -0
  351. package/specialists/org/scopes/research.json +60 -0
  352. package/specialists/org/scopes/rnd.json +81 -0
  353. package/specialists/org/specialists/cx-accessibility.json +69 -0
  354. package/specialists/org/specialists/cx-ai-engineer.json +75 -0
  355. package/specialists/org/specialists/cx-architect.json +89 -0
  356. package/specialists/org/specialists/cx-business-strategist.json +72 -0
  357. package/specialists/org/specialists/cx-data-analyst.json +68 -0
  358. package/specialists/org/specialists/cx-data-engineer.json +71 -0
  359. package/specialists/org/specialists/cx-debugger.json +75 -0
  360. package/specialists/org/specialists/cx-designer.json +85 -0
  361. package/specialists/org/specialists/cx-devil-advocate.json +71 -0
  362. package/specialists/org/specialists/cx-docs-keeper.json +82 -0
  363. package/specialists/org/specialists/cx-engineer.json +106 -0
  364. package/specialists/org/specialists/cx-evaluator.json +69 -0
  365. package/specialists/org/specialists/cx-explorer.json +69 -0
  366. package/specialists/org/specialists/cx-legal-compliance.json +74 -0
  367. package/specialists/org/specialists/cx-operations.json +72 -0
  368. package/specialists/org/specialists/cx-oracle.json +46 -0
  369. package/specialists/org/specialists/cx-orchestrator.json +81 -0
  370. package/specialists/org/specialists/cx-platform-engineer.json +80 -0
  371. package/specialists/org/specialists/cx-product-manager.json +102 -0
  372. package/specialists/org/specialists/cx-qa.json +79 -0
  373. package/specialists/org/specialists/cx-rd-lead.json +73 -0
  374. package/specialists/org/specialists/cx-release-manager.json +77 -0
  375. package/specialists/org/specialists/cx-researcher.json +82 -0
  376. package/specialists/org/specialists/cx-reviewer.json +71 -0
  377. package/specialists/org/specialists/cx-security.json +91 -0
  378. package/specialists/org/specialists/cx-sre.json +94 -0
  379. package/specialists/org/specialists/cx-test-automation.json +69 -0
  380. package/specialists/org/specialists/cx-trace-reviewer.json +69 -0
  381. package/specialists/org/specialists/cx-ux-researcher.json +68 -0
  382. package/specialists/org/teams/accessibility-team.json +39 -0
  383. package/specialists/org/teams/design-team.json +40 -0
  384. package/specialists/org/teams/engineering-team.json +50 -0
  385. package/specialists/org/teams/governance-team.json +41 -0
  386. package/specialists/org/teams/operations-team.json +46 -0
  387. package/specialists/org/teams/product-management-team.json +45 -0
  388. package/specialists/org/teams/quality-team.json +49 -0
  389. package/specialists/org/teams/research-team.json +39 -0
  390. package/specialists/org/teams/strategy-team.json +48 -0
  391. package/specialists/org/teams/ux-research-team.json +39 -0
  392. package/specialists/prompts/_shared/validation-contract.md +1 -1
  393. package/specialists/prompts/_team-template.md +10 -0
  394. package/specialists/prompts/cx-accessibility.md +1 -0
  395. package/specialists/prompts/cx-ai-engineer.md +1 -1
  396. package/specialists/prompts/cx-business-strategist.md +1 -1
  397. package/specialists/prompts/cx-data-engineer.md +1 -1
  398. package/specialists/prompts/cx-designer.md +1 -0
  399. package/specialists/prompts/cx-devil-advocate.md +1 -1
  400. package/specialists/prompts/cx-docs-keeper.md +1 -1
  401. package/specialists/prompts/cx-evaluator.md +1 -1
  402. package/specialists/prompts/cx-explorer.md +1 -1
  403. package/specialists/prompts/cx-operations.md +1 -1
  404. package/specialists/prompts/cx-oracle.md +7 -3
  405. package/specialists/prompts/cx-orchestrator.md +17 -1
  406. package/specialists/prompts/cx-platform-engineer.md +1 -1
  407. package/specialists/prompts/cx-product-manager.md +2 -0
  408. package/specialists/prompts/cx-release-manager.md +1 -1
  409. package/specialists/prompts/cx-researcher.md +7 -4
  410. package/specialists/prompts/cx-sre.md +1 -1
  411. package/specialists/prompts/cx-test-automation.md +2 -2
  412. package/specialists/prompts/cx-trace-reviewer.md +3 -3
  413. package/specialists/prompts/cx-ux-researcher.md +2 -1
  414. package/templates/demos/scripts/architecture-review-adr.json +30 -0
  415. package/templates/demos/scripts/capability-contract.json +25 -0
  416. package/templates/demos/scripts/intake-triage.json +25 -0
  417. package/templates/demos/scripts/profile-doctor-health.json +25 -0
  418. package/templates/demos/tapes/agentic-platforms-prd.tape +2 -2
  419. package/templates/demos/tapes/architecture-review-adr.tape +44 -0
  420. package/templates/demos/tapes/capability-contract.tape +39 -0
  421. package/templates/demos/tapes/intake-triage.tape +39 -0
  422. package/templates/demos/tapes/profile-doctor-health.tape +39 -0
  423. package/templates/distribution/construct-brand.typ +23 -18
  424. package/templates/distribution/construct-decision.typ +1 -1
  425. package/templates/distribution/construct-pdf.typ +1 -1
  426. package/templates/distribution/construct-prd.typ +1 -1
  427. package/templates/distribution/construct-research.typ +1 -1
  428. package/templates/distribution/mermaid-puppeteer.json +8 -0
  429. package/templates/docs/persona-artifact.md +1 -1
  430. package/templates/docs/prd.md +6 -0
  431. package/apps/chat/engine/ai-sdk-agent.mjs +0 -183
  432. package/apps/chat/engine/loop-driver.mjs +0 -211
  433. package/apps/chat/engine/models.mjs +0 -122
  434. package/apps/chat/engine/provider-adapters.mjs +0 -171
  435. package/apps/chat/engine/tools/permission.mjs +0 -54
  436. package/apps/chat/engine/tools/primitives.mjs +0 -180
  437. package/apps/chat/engine/tools/registry.mjs +0 -122
  438. package/apps/chat/engine/turn-controls.mjs +0 -70
  439. package/lib/boundary.mjs +0 -127
  440. package/lib/certification/dashboard-api.mjs +0 -71
  441. package/lib/chat/cli.mjs +0 -333
  442. package/lib/chat/command-suggest.mjs +0 -161
  443. package/lib/chat/commands.mjs +0 -215
  444. package/lib/chat/config.mjs +0 -142
  445. package/lib/chat/context-compactor.mjs +0 -250
  446. package/lib/chat/context-continuation.mjs +0 -253
  447. package/lib/chat/continuation-source.mjs +0 -58
  448. package/lib/chat/demo-guide.mjs +0 -61
  449. package/lib/chat/design-tokens.mjs +0 -91
  450. package/lib/chat/desktop-binary.mjs +0 -81
  451. package/lib/chat/desktop-build.mjs +0 -130
  452. package/lib/chat/desktop-launcher.mjs +0 -133
  453. package/lib/chat/evidence.mjs +0 -145
  454. package/lib/chat/export.mjs +0 -74
  455. package/lib/chat/harness/driver.mjs +0 -91
  456. package/lib/chat/list-picker.mjs +0 -112
  457. package/lib/chat/model-picker.mjs +0 -356
  458. package/lib/chat/openrouter-fallback.mjs +0 -151
  459. package/lib/chat/permission-prompt.mjs +0 -33
  460. package/lib/chat/picker-catalog.mjs +0 -45
  461. package/lib/chat/policy-telemetry.mjs +0 -34
  462. package/lib/chat/present.mjs +0 -246
  463. package/lib/chat/session-context.mjs +0 -39
  464. package/lib/chat/session-persist.mjs +0 -73
  465. package/lib/chat/session-restore.mjs +0 -71
  466. package/lib/chat/session-settings.mjs +0 -53
  467. package/lib/chat/system-prompt.mjs +0 -52
  468. package/lib/chat/transparency.mjs +0 -93
  469. package/lib/chat/tui/color-scheme.mjs +0 -42
  470. package/lib/chat/tui/markdown.mjs +0 -123
  471. package/lib/chat/tui/presentation.mjs +0 -100
  472. package/lib/chat/tui/render.mjs +0 -500
  473. package/lib/chat/tui/turn-block.mjs +0 -284
  474. package/lib/chat/tui/turn-present.mjs +0 -18
  475. package/lib/chat/tui/turn-state.mjs +0 -88
  476. package/lib/chat/tui/usage.mjs +0 -122
  477. package/lib/chat/web-commands.mjs +0 -146
  478. package/lib/chat/web-launcher.mjs +0 -63
  479. package/lib/chat/web-picker-keys.mjs +0 -46
  480. package/lib/chat/web-session.mjs +0 -159
  481. package/lib/config/alias.mjs +0 -57
  482. package/lib/dashboard-demo.mjs +0 -71
  483. package/lib/dashboard-static.mjs +0 -175
  484. package/lib/install/desktop-binary-download.mjs +0 -88
  485. package/lib/profiles/loader.mjs +0 -123
  486. package/lib/profiles/rebrand.mjs +0 -46
  487. package/lib/server/auth.mjs +0 -169
  488. package/lib/server/chat-loop.mjs +0 -622
  489. package/lib/server/chat.mjs +0 -336
  490. package/lib/server/cors.mjs +0 -77
  491. package/lib/server/csrf.mjs +0 -103
  492. package/lib/server/demo-preview.mjs +0 -63
  493. package/lib/server/index.mjs +0 -2641
  494. package/lib/server/insights.mjs +0 -780
  495. package/lib/server/langfuse-login.mjs +0 -58
  496. package/lib/server/rate-limit.mjs +0 -93
  497. package/lib/server/telemetry-login.mjs +0 -100
  498. package/lib/server/webhook.mjs +0 -512
  499. package/specialists/contracts.json +0 -1032
  500. package/specialists/contracts.schema.json +0 -83
  501. package/specialists/policy-inventory.json +0 -188
  502. package/specialists/registry.json +0 -1412
  503. package/specialists/role-manifests.json +0 -217
  504. package/specialists/teams.json +0 -94
@@ -19,6 +19,7 @@ import { join } from 'node:path';
19
19
  import { homedir } from 'node:os';
20
20
  import { spawnSync } from 'node:child_process';
21
21
  import { configDir } from '../config/xdg.mjs';
22
+ import { resolveOpRef } from '../providers/secret-resolver.mjs';
22
23
 
23
24
  // ── Multi-method auth helpers ────────────────────────────────────────────
24
25
 
@@ -628,8 +629,7 @@ function resolveCredentialSync(varName, homeDir) {
628
629
  const opMatch = content.match(opRe);
629
630
  if (opMatch) {
630
631
  try {
631
- const result = spawnSync('op', ['read', opMatch[1]], { encoding: 'utf8', timeout: 5000 });
632
- if (result.status === 0) return result.stdout.trim();
632
+ return resolveOpRef(opMatch[1]);
633
633
  } catch { /* op read failed */ }
634
634
  }
635
635
  }
@@ -730,16 +730,15 @@ function resolveCredential(varName, homeDir) {
730
730
  const opRe = new RegExp(`export\\s+${varName}=["']?\\$\\(op read '([^']+)'\\)["']?`, 'm');
731
731
  const opMatch = content.match(opRe);
732
732
  if (opMatch) {
733
+ // op read failures often mean the rc-file field name doesn't match the
734
+ // actual 1Password item field; surface them under the debug flag.
733
735
  try {
734
- const result = spawnSync('op', ['read', opMatch[1]], { encoding: 'utf8', timeout: 5000 });
735
- if (result.status === 0) return result.stdout.trim();
736
- // Log op read failures — often the field name in the rc file
737
- // doesn't match the actual 1Password item field name.
738
- const errMsg = (result.stderr || '').trim().slice(0, 200);
739
- if (errMsg && process.env.CONSTRUCT_DEBUG_CREDENTIALS === '1') {
740
- process.stderr.write(`[credentials] op read failed for ${varName}: ${errMsg}\n`);
736
+ return resolveOpRef(opMatch[1]);
737
+ } catch (err) {
738
+ if (process.env.CONSTRUCT_DEBUG_CREDENTIALS === '1') {
739
+ process.stderr.write(`[credentials] op read failed for ${varName}: ${String(err.message).slice(0, 200)}\n`);
741
740
  }
742
- } catch { /* op read failed */ }
741
+ }
743
742
  }
744
743
 
745
744
  // If the value uses command substitution ($(...)), try evaluating via
@@ -18,7 +18,7 @@
18
18
  import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
19
19
  import { dirname, join } from 'node:path';
20
20
  import { syncFileStateToSql } from '../storage/sync.mjs';
21
- import { resolveActiveProfile } from '../profiles/loader.mjs';
21
+ import { resolveActiveScope } from '../scopes/loader.mjs';
22
22
  import { ensureCxDir } from '../project-init-shared.mjs';
23
23
 
24
24
  const ROOT = '.cx/knowledge/external/research';
@@ -64,7 +64,7 @@ export async function addResearchFinding({
64
64
  throw new Error('addResearchFinding: confidence=confirmed requires at least one source');
65
65
  }
66
66
 
67
- const profile = resolveActiveProfile(cwd);
67
+ const profile = resolveActiveScope(cwd);
68
68
  const now = new Date();
69
69
  const expiresAt = new Date(now.getTime() + ttlDays * 24 * 60 * 60 * 1000).toISOString();
70
70
 
@@ -3,7 +3,7 @@
3
3
  * lib/mcp/server.mjs — Construct MCP server: tool registry and request dispatcher.
4
4
  *
5
5
  * Thin dispatcher only — all tool implementations live in lib/mcp/tools/*.mjs.
6
- * Registers 52 tools across 8 modules: project, document, storage, skills, workflow, telemetry, memory, profile.
6
+ * Registers 52 tools across 8 modules: project, document, storage, skills, workflow, telemetry, memory, scope.
7
7
  * Consumed by Claude Code, OpenCode, and any MCP-compatible host.
8
8
  */
9
9
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
@@ -38,7 +38,7 @@ import {
38
38
  } from './tools/storage.mjs';
39
39
  import {
40
40
  listSkills, getSkill, searchSkills, getTemplate, listTemplates,
41
- agentContract, brokerCheck, orchestrationPolicy, workerRun, listTeams, getTeam,
41
+ agentContract, brokerCheck, orchestrationPolicy, workerRun, listTeams, getTeam, suggestSkillsTool,
42
42
  } from './tools/skills.mjs';
43
43
  import {
44
44
  workflowInit, workflowAddTask, workflowUpdateTask,
@@ -53,12 +53,15 @@ import {
53
53
  sessionList, sessionLoad, sessionSearch, sessionSave, rovoSearch,
54
54
  } from './tools/memory.mjs';
55
55
  import {
56
- profileShow, profileList, profileDrafts, profileHealthTool,
56
+ scopeShow, scopeList, scopeDrafts, scopeHealthTool,
57
57
  outcomesSummary, outcomesRecord, knowledgeAdd,
58
- profileCreate, profileArchive, sandboxList, learningStatus,
58
+ scopeCreate, scopeArchive, sandboxList, learningStatus,
59
59
  knowledgeGraphAsk,
60
- } from './tools/profile.mjs';
60
+ } from './tools/scope.mjs';
61
61
  import { modelResolve, triageRecommend, workflowInvoke, capabilityDescribe, executionResolve, artifactWorkflow } from './tools/embedded-contract.mjs';
62
+ import { authorArtifact } from './tools/artifact-author.mjs';
63
+ import { findTool } from './tools/find-tool.mjs';
64
+ import { recoverToolName, recordToolNameMiss, isGatewayName } from './tool-recovery.mjs';
62
65
 
63
66
  const DEFAULT_ROOT_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
64
67
  const ROOT_DIR = resolve(process.env.CX_TOOLKIT_DIR || DEFAULT_ROOT_DIR);
@@ -470,11 +473,11 @@ const ALL_TOOL_DEFS = [
470
473
  },
471
474
  {
472
475
  name: 'broker_check',
473
- description: 'Queries the MCP broker policy gate for a pending action without executing it. Agents call this BEFORE attempting a high-risk action so the response (allowed / approvalRequired / reason / source) can be surfaced to the user in the agent\'s voice rather than triggering a denial after the fact. In solo mode the broker is off by default — returns `brokerActive: false` with `allowed: true` so the call is cheap and agents don\'t waste tokens on an inactive gate. Always emits a `tool.called` trace event for audit-trail parity. Reads specialists/role-manifests.json fence rules in team / enterprise mode.',
476
+ description: 'Queries the MCP broker policy gate for a pending action without executing it. Agents call this BEFORE attempting a high-risk action so the response (allowed / approvalRequired / reason / source) can be surfaced to the user in the agent\'s voice rather than triggering a denial after the fact. In solo mode the broker is off by default — returns `brokerActive: false` with `allowed: true` so the call is cheap and agents don\'t waste tokens on an inactive gate. Always emits a `tool.called` trace event for audit-trail parity. Reads specialists/org fence rules in team / enterprise mode.',
474
477
  inputSchema: {
475
478
  type: 'object',
476
479
  properties: {
477
- role: { type: 'string', description: 'Persona name (e.g. `engineer`, `security`). Must match a key in specialists/role-manifests.json for team / enterprise mode.' },
480
+ role: { type: 'string', description: 'Persona name (e.g. `engineer`, `security`). Must match a key in specialists/org for team / enterprise mode.' },
478
481
  project: { type: 'string', description: 'Optional project scope for the decision.' },
479
482
  tool: { type: 'string', description: 'The tool the agent wants to invoke (e.g. `github`, `fs`).' },
480
483
  action: { type: 'string', description: 'The action on that tool (e.g. `create_pr`, `edit:lib/foo.mjs`).' },
@@ -486,7 +489,7 @@ const ALL_TOOL_DEFS = [
486
489
  },
487
490
  {
488
491
  name: 'agent_contract',
489
- description: 'Looks up explicit agent-to-agent service contracts (from specialists/contracts.json). Specialists should call this at the start of a handoff to see the expected input shape, preconditions, and what postconditions they must satisfy. Use without args to get all contracts; pass producer/consumer to narrow; pass id for a specific contract.',
492
+ description: 'Looks up explicit agent-to-agent service contracts (from specialists/org). Specialists should call this at the start of a handoff to see the expected input shape, preconditions, and what postconditions they must satisfy. Use without args to get all contracts; pass producer/consumer to narrow; pass id for a specific contract.',
490
493
  inputSchema: {
491
494
  type: 'object',
492
495
  properties: {
@@ -496,6 +499,18 @@ const ALL_TOOL_DEFS = [
496
499
  },
497
500
  },
498
501
  },
502
+ {
503
+ name: 'find_tool',
504
+ description: 'Find Construct tools by intent when you do not know the exact name. Describe what you want to do; returns the best-matching tools with their input schemas, ranked by hybrid semantic + lexical relevance. Then invoke a result via the `call` gateway (or directly if it is a flat tool).',
505
+ inputSchema: {
506
+ type: 'object',
507
+ properties: {
508
+ query: { type: 'string', description: 'Natural-language description of the task (e.g. "export a markdown file to pdf").' },
509
+ limit: { type: 'number', description: 'Max tools to return (default 5, max 20).' },
510
+ },
511
+ required: ['query'],
512
+ },
513
+ },
499
514
  {
500
515
  name: 'get_template',
501
516
  description: 'Reads a doc template by name (e.g. "prd", "meta-prd", "prfaq", "evidence-brief", "adr", "runbook"). Resolves .cx/templates/docs/{name}.md first, then templates/docs/{name}.md.',
@@ -529,14 +544,16 @@ const ALL_TOOL_DEFS = [
529
544
  inputSchema: { type: 'object', properties: {} },
530
545
  },
531
546
  {
532
- name: 'get_team',
533
- description: 'Returns the full definition of a named team template including members, skills, and promotion gates.',
547
+ name: 'suggest_skills',
548
+ description: 'Rank skills from the central catalog for a natural-language intent. Optional specialistId filters entitlement metadata.',
534
549
  inputSchema: {
535
550
  type: 'object',
536
551
  properties: {
537
- name: { type: 'string', description: 'Team template name (e.g. feature, incident, architecture).' },
552
+ intent: { type: 'string', description: 'Task description or keywords' },
553
+ specialistId: { type: 'string', description: 'Optional cx-* id for entitlement hints' },
554
+ limit: { type: 'number', description: 'Max suggestions (default 5)' },
538
555
  },
539
- required: ['name'],
556
+ required: ['intent'],
540
557
  },
541
558
  },
542
559
  {
@@ -757,41 +774,43 @@ const ALL_TOOL_DEFS = [
757
774
  properties: {
758
775
  query: { type: 'string', description: 'The user\'s question or the project/repo name (e.g. "project iverson", "hashicorp/project-iverson", "PLAT"). The tool matches this against configured GITHUB_REPOS, JIRA_PROJECTS, LINEAR_TEAMS.' },
759
776
  root_dir: { type: 'string', description: 'Data root dir override (default: homedir()). Use CX_DATA_DIR value if set.' },
777
+ team_id: { type: 'string', description: 'Optional team id (from the unified registry). Scopes the fetch to that team\'s declared sources; observations are tagged team:<id>.' },
778
+ target_ids: { type: 'array', items: { type: 'string' }, description: 'Optional source-target ids to restrict to (must belong to team_id). A target outside the team returns a typed OUT_OF_SCOPE error rather than a silent wrong-source fetch.' },
760
779
  },
761
780
  },
762
781
  },
763
782
  {
764
- name: 'profile_show',
765
- description: 'Return the active Construct org profile (id, displayName, roles, departments, intake taxonomy, doc templates). Use when a specialist needs to know which role set, classification taxonomy, or doc templates apply before drafting work.',
783
+ name: 'scope_show',
784
+ description: 'Return the active Construct scope (id, displayName, roles, departments, intake taxonomy, doc templates). Use when a specialist needs to know which role set, classification taxonomy, or doc templates apply before drafting work.',
766
785
  inputSchema: {
767
786
  type: 'object',
768
787
  properties: {
769
788
  cwd: { type: 'string', description: 'Project root (default: server cwd).' },
770
- id: { type: 'string', description: 'Force a specific profile id instead of resolving from config.' },
789
+ id: { type: 'string', description: 'Force a specific scope id instead of resolving from config.' },
771
790
  },
772
791
  },
773
792
  },
774
793
  {
775
- name: 'profile_list',
776
- description: 'List the curated org profile catalog (rnd, operations, creative, research) with role/department counts. Use to discover which profiles are available before suggesting `construct profile set`.',
794
+ name: 'scope_list',
795
+ description: 'List the curated org scope catalog (rnd, operations, creative, research) with role/department counts. Use to discover which scopes are available before suggesting `construct scope set`.',
777
796
  inputSchema: { type: 'object', properties: {} },
778
797
  },
779
798
  {
780
- name: 'profile_drafts',
781
- description: 'List in-progress draft profiles under `.cx/profiles/draft-*` and any user-defined custom profile at `.cx/profile.json`. Use to see what profile work is pending before scaffolding another draft.',
799
+ name: 'scope_drafts',
800
+ description: 'List in-progress draft scopes under `.cx/scopes/draft-*` and any user-defined custom scope at `.cx/scope.json`. Use to see what scope work is pending before scaffolding another draft.',
782
801
  inputSchema: {
783
802
  type: 'object',
784
803
  properties: { cwd: { type: 'string', description: 'Project root (default: server cwd).' } },
785
804
  },
786
805
  },
787
806
  {
788
- name: 'profile_health',
789
- description: 'Per-profile health rollup over a window: observation count, per-role outcome runs and success rates. Use to check whether a profile is producing data before recommending changes or archive.',
807
+ name: 'scope_health',
808
+ description: 'Per-scope health rollup over a window: observation count, per-role outcome runs and success rates. Use to check whether a scope is producing data before recommending changes or archive.',
790
809
  inputSchema: {
791
810
  type: 'object',
792
811
  properties: {
793
812
  cwd: { type: 'string', description: 'Project root (default: server cwd).' },
794
- id: { type: 'string', description: 'Profile id (default: active profile).' },
813
+ id: { type: 'string', description: 'Scope id (default: active scope).' },
795
814
  window_days: { type: 'number', description: 'Window in days (default 30).' },
796
815
  },
797
816
  },
@@ -819,7 +838,7 @@ const ALL_TOOL_DEFS = [
819
838
  role: { type: 'string', description: 'Specialist id (e.g. cx-engineer, product-manager).' },
820
839
  success: { type: 'boolean' },
821
840
  intake_id: { type: 'string' },
822
- profile: { type: 'string', description: 'Override active profile id stamp.' },
841
+ profile: { type: 'string', description: 'Override active scope id stamp.' },
823
842
  escalated: { type: 'boolean' },
824
843
  duration_ms: { type: 'number' },
825
844
  notes: { type: 'string', description: 'Trimmed to 500 chars.' },
@@ -829,7 +848,7 @@ const ALL_TOOL_DEFS = [
829
848
  },
830
849
  {
831
850
  name: 'knowledge_add',
832
- description: 'Persist a research finding as `.cx/knowledge/external/research/<slug>.md` with research-specific frontmatter (topic, confidence, sources, expiresAt, profile). Writes durable state — requires `confirm=true`. `confidence=confirmed` requires at least one source.',
851
+ description: 'Persist a research finding as `.cx/knowledge/external/research/<slug>.md` with research-specific frontmatter (topic, confidence, sources, expiresAt, scope). Writes durable state — requires `confirm=true`. `confidence=confirmed` requires at least one source.',
833
852
  inputSchema: {
834
853
  type: 'object',
835
854
  required: ['confirm', 'slug', 'topic', 'body'],
@@ -858,15 +877,15 @@ const ALL_TOOL_DEFS = [
858
877
  },
859
878
  },
860
879
  {
861
- name: 'profile_create',
862
- description: 'Scaffold a draft org profile under `.cx/profiles/draft-<id>/` (requirements.md + profile.json + persona stubs + department charters). Writes durable state — requires `confirm=true`. For curated catalog work, follow `docs/guides/concepts/profile-lifecycle.md` after creation.',
880
+ name: 'scope_create',
881
+ description: 'Scaffold a draft org scope under `.cx/scopes/draft-<id>/` (requirements.md + scope.json + persona stubs + department charters). Writes durable state — requires `confirm=true`. For curated catalog work, follow `docs/guides/concepts/scope-lifecycle.md` after creation.',
863
882
  inputSchema: {
864
883
  type: 'object',
865
884
  required: ['confirm', 'id'],
866
885
  properties: {
867
886
  confirm: { type: 'boolean', description: 'Must be true.' },
868
887
  cwd: { type: 'string' },
869
- id: { type: 'string', description: 'Profile id (^[a-z][a-z0-9-]{1,30}$).' },
888
+ id: { type: 'string', description: 'Scope id (^[a-z][a-z0-9-]{1,30}$).' },
870
889
  display_name: { type: 'string' },
871
890
  seed_roles: {
872
891
  type: 'array',
@@ -889,8 +908,8 @@ const ALL_TOOL_DEFS = [
889
908
  },
890
909
  },
891
910
  {
892
- name: 'profile_archive',
893
- description: 'Archive a curated profile: moves `profiles/<id>.json` and its intake table into `archive/profiles/<id>/` with an archive note. Destructive — requires `confirm=true` and a substantive `reason` (>=8 chars). Observations and outcomes are preserved.',
911
+ name: 'scope_archive',
912
+ description: 'Archive a curated scope: moves `specialists/org/scopes/<id>.json` and its intake table into `archive/scopes/<id>/` with an archive note. Destructive — requires `confirm=true` and a substantive `reason` (>=8 chars). Observations and outcomes are preserved.',
894
913
  inputSchema: {
895
914
  type: 'object',
896
915
  required: ['confirm', 'id', 'reason'],
@@ -924,7 +943,7 @@ const ALL_TOOL_DEFS = [
924
943
  },
925
944
  {
926
945
  name: 'learning_status',
927
- description: 'One-shot mirror of `npm run learning:status`: active profile, observation counts (last 24h + total), research finding count, per-role outcome rollup. Use to answer "is Construct learning?" without spawning a shell.',
946
+ description: 'One-shot mirror of `npm run learning:status`: active scope, observation counts (last 24h + total), research finding count, per-role outcome rollup. Use to answer "is Construct learning?" without spawning a shell.',
928
947
  inputSchema: {
929
948
  type: 'object',
930
949
  properties: { cwd: { type: 'string', description: 'Project root (default: server cwd).' } },
@@ -947,14 +966,13 @@ const ALL_TOOL_DEFS = [
947
966
  },
948
967
  {
949
968
  name: 'publish_detect',
950
- description: 'Detect availability of publish pipeline tooling: Pandoc/Typst export, pandoc-ext/diagram figures, VHS terminal demos, and Playwright dashboard demos.',
969
+ description: 'Detect availability of publish pipeline tooling: Pandoc/Typst export, pandoc-ext/diagram figures, and VHS terminal demos.',
951
970
  inputSchema: {
952
971
  type: 'object',
953
972
  properties: {
954
973
  format: { type: 'string', enum: ['pdf', 'docx', 'doc', 'deck', 'pptx', 'html', 'rtf', 'odt', 'epub', 'tex', 'txt', 'md', 'mdx'], description: 'Export format to probe (default pdf).' },
955
974
  figures: { type: 'boolean', description: 'Include figure binaries (default true).' },
956
975
  demo: { type: 'string', description: 'When set, require VHS/asciinema for terminal demo.' },
957
- dashboard_demo: { type: 'string', description: 'When set, require Playwright workspace for dashboard demo.' },
958
976
  },
959
977
  },
960
978
  },
@@ -969,7 +987,6 @@ const ALL_TOOL_DEFS = [
969
987
  output_path: { type: 'string', description: 'Optional output path for export.' },
970
988
  format: { type: 'string', enum: ['pdf', 'docx', 'doc', 'deck', 'pptx', 'html', 'rtf', 'odt', 'epub', 'tex', 'txt', 'md', 'mdx'], description: 'Target format (default pdf).' },
971
989
  demo: { type: 'string', description: 'Terminal tape name to record.' },
972
- dashboard_demo: { type: 'string', description: 'Dashboard Playwright demo spec basename.' },
973
990
  figures: { type: 'boolean', description: 'Render diagrams (default true).' },
974
991
  strict: { type: 'boolean', description: 'Fail when toolchain or release gate fails (default true).' },
975
992
  source_only: { type: 'boolean', description: 'Write sources only (default false).' },
@@ -1088,7 +1105,7 @@ const ALL_TOOL_DEFS = [
1088
1105
  },
1089
1106
  {
1090
1107
  name: 'workflow_contract_validate',
1091
- description: 'Validate a producer→consumer handoff against specialists/contracts.json. Required when a specialist hands off to another role: enforces input.mustContain, output schema, disk-artifact postconditions, and binary postconditions per producer (rubber-stamp prevention, post-hoc threat-model prevention, etc.). Self-enforcing: a producer with binary rules MUST pass `packet`, or the call itself is a contract violation.',
1108
+ description: 'Validate a producer→consumer handoff against specialists/org. Required when a specialist hands off to another role: enforces input.mustContain, output schema, disk-artifact postconditions, and binary postconditions per producer (rubber-stamp prevention, post-hoc threat-model prevention, etc.). Self-enforcing: a producer with binary rules MUST pass `packet`, or the call itself is a contract violation.',
1092
1109
  inputSchema: {
1093
1110
  type: 'object',
1094
1111
  required: ['producer', 'consumer'],
@@ -1151,6 +1168,19 @@ const ALL_TOOL_DEFS = [
1151
1168
  },
1152
1169
  },
1153
1170
  },
1171
+ {
1172
+ name: 'author_artifact',
1173
+ description: 'Materialize a typed Construct artifact you have drafted (prd, prd-platform, prd-business, meta-prd, adr, rfc, research-brief, evidence-brief, runbook) to disk and run the release gate. YOU draft the full markdown — start with a single # title and include the type\'s required ## sections (call get_template first for the shape) — and pass it as draft_markdown; the canonical file is written and the gate verdict + errors are returned so you can fix and re-call. This is the Construct author→materialize→validate pass for supported hosts.',
1174
+ inputSchema: {
1175
+ type: 'object',
1176
+ properties: {
1177
+ draft_markdown: { type: 'string', description: 'The complete artifact markdown you authored. Must start with one # title line and contain the required ## sections for the type.' },
1178
+ artifact_type: { type: 'string', description: 'Artifact type (prd, meta-prd, adr, rfc, research-brief, evidence-brief, runbook, …). Defaults to prd; inferred from subject when omitted.' },
1179
+ subject: { type: 'string', description: 'Short subject/title hint (e.g. "OIDC integration") used for the filename and type inference.' },
1180
+ },
1181
+ required: ['draft_markdown'],
1182
+ },
1183
+ },
1154
1184
  {
1155
1185
  name: 'model_resolve',
1156
1186
  description: 'Resolve which model an embedded Construct workflow should use given the host/IDE provider context. Precedence: host model → same-provider-family fallback → Construct tier default → structured config error. Never reads or returns credential values (requiresCredential is a boolean) and never claims unverified provider health. Read-only; performs no writes.',
@@ -1235,7 +1265,7 @@ const ALL_TOOL_DEFS = [
1235
1265
  },
1236
1266
  {
1237
1267
  name: 'orchestration_run',
1238
- description: 'EXECUTE a real multi-specialist orchestration run via the local Construct daemon and return per-specialist output — the executing counterpart to workflow_invoke (which only plans). For MCP hosts with no subagent primitive (VS Code/Copilot, Cursor), this is how you actually run a specialist chain: the engine owns orchestration, this tool is the thin client (ADR-0022). Requires a running daemon (`construct dashboard`); if it is unreachable the tool fails fast with how to start it rather than silently degrading to a single-persona pass. Real specialist output requires the daemon to run the `provider` worker backend (a provider key configured); the default `inline` backend prepares tasks only.',
1268
+ description: 'EXECUTE a real multi-specialist orchestration run and return per-specialist output — the executing counterpart to workflow_invoke (which only plans). For MCP hosts with no subagent primitive (VS Code/Copilot, Cursor), this is how you actually run a specialist chain: the engine owns orchestration, this tool is the thin client (ADR-0022). Solo runs execute in-process no daemon, no port, no token; a remote/team orchestration service is opt-in via CONSTRUCT_ORCHESTRATION_URL. Real specialist output requires the `provider` worker backend (a provider key configured); the default `inline` backend prepares tasks only.',
1239
1269
  inputSchema: {
1240
1270
  type: 'object',
1241
1271
  required: ['request'],
@@ -1273,17 +1303,14 @@ const ALL_TOOL_DEFS = [
1273
1303
  // host/model; the long tail is reachable, just not front-loaded.
1274
1304
 
1275
1305
  const CORE_TOOL_NAMES = new Set([
1276
- 'orchestration_policy', 'get_skill', 'search_skills', 'knowledge_search',
1277
- 'memory_search', 'project_context', 'summarize_diff',
1306
+ 'orchestration_policy', 'get_skill', 'get_template', 'search_skills', 'knowledge_search',
1307
+ 'memory_search', 'project_context', 'summarize_diff', 'find_tool',
1308
+ 'author_artifact', 'document_export', 'publish_run', 'artifact_workflow',
1309
+ 'workflow_invoke', 'triage_recommend',
1278
1310
  ]);
1279
1311
 
1280
- function firstSentence(text) {
1281
- const s = String(text || '').replace(/\s+/g, ' ').trim();
1282
- const end = s.search(/\.(\s|$)/);
1283
- return (end > 0 ? s.slice(0, end) : s).slice(0, 140);
1284
- }
1285
-
1286
1312
  const LONG_TAIL_DEFS = ALL_TOOL_DEFS.filter((t) => !CORE_TOOL_NAMES.has(t.name));
1313
+ const KNOWN_TOOL_NAMES = new Set(ALL_TOOL_DEFS.map((t) => t.name));
1287
1314
 
1288
1315
  // One dispatcher for the long tail. `tool` is constrained to an enum of valid
1289
1316
  // names (≈1 token each — kills hallucinated names, the key small-model lever),
@@ -1291,11 +1318,12 @@ const LONG_TAIL_DEFS = ALL_TOOL_DEFS.filter((t) => !CORE_TOOL_NAMES.has(t.name))
1291
1318
  // schemas. Dispatch reuses the same handlers via dispatchToolByName.
1292
1319
 
1293
1320
  const CONSTRUCT_CALL_TOOL = {
1294
- name: 'construct_call',
1321
+ name: 'call',
1295
1322
  description:
1296
- 'Invoke any non-core Construct tool by name. Put the tool name in `tool` and its arguments in `args`. '
1297
- + 'Available tools:\n'
1298
- + LONG_TAIL_DEFS.map((t) => `- ${t.name} ${firstSentence(t.description)}`).join('\n'),
1323
+ 'Invoke any non-core Construct tool by name: provide `tool` and `args`. '
1324
+ + 'If you do not know the exact name, call find_tool with a description of your task to get ranked tools and their schemas. '
1325
+ + `Long-tail tool groups: ${[...new Set(LONG_TAIL_DEFS.map((t) => t.name.split('_')[0]))].sort().map((g) => `${g}_*`).join(', ')}. `
1326
+ + 'The `tool` value must be a catalog name (constrained by the enum below).',
1299
1327
  inputSchema: {
1300
1328
  type: 'object',
1301
1329
  properties: {
@@ -1349,7 +1377,7 @@ export async function dispatchToolByName(name, args = {}) {
1349
1377
  else if (name === 'workflow_contract_validate') result = await workflowContractValidate(args);
1350
1378
  else if (name === 'workflow_import_plan') result = workflowImportPlan(args);
1351
1379
  else if (name === 'list_teams') result = listTeams(opts);
1352
- else if (name === 'get_team') result = getTeam(args, opts);
1380
+ else if (name === 'suggest_skills') result = suggestSkillsTool(args, opts);
1353
1381
  else if (name === 'cx_trace_telemetry') { const m = await import('./tools/telemetry.mjs'); result = await m.cxTrace(args, opts); }
1354
1382
  else if (name === 'cx_trace') result = await cxTrace(args, opts);
1355
1383
  else if (name === 'cx_score') result = await cxScore(args);
@@ -1367,7 +1395,7 @@ export async function dispatchToolByName(name, args = {}) {
1367
1395
  else if (name === 'session_usage') result = await sessionUsage(args, opts);
1368
1396
  else if (name === 'provider_fetch') {
1369
1397
  const { demandFetch } = await import('../embed/demand-fetch.mjs');
1370
- result = await demandFetch({ query: args.query, rootDir: args.root_dir });
1398
+ result = await demandFetch({ query: args.query, rootDir: args.root_dir, teamId: args.team_id, targetIds: args.target_ids });
1371
1399
  }
1372
1400
  else if (name === 'knowledge_search') {
1373
1401
  const { knowledgeSearch } = await import('../knowledge/search.mjs');
@@ -1392,7 +1420,6 @@ export async function dispatchToolByName(name, args = {}) {
1392
1420
  format: args.format || 'pdf',
1393
1421
  includeFigures: args.figures !== false,
1394
1422
  includeTerminalDemo: Boolean(args.demo),
1395
- includeDashboardDemo: Boolean(args.dashboard_demo),
1396
1423
  });
1397
1424
  }
1398
1425
  else if (name === 'publish_run') {
@@ -1403,7 +1430,6 @@ export async function dispatchToolByName(name, args = {}) {
1403
1430
  format: args.format || 'pdf',
1404
1431
  includeFigures: args.figures !== false,
1405
1432
  includeTerminalDemo: Boolean(args.demo),
1406
- includeDashboardDemo: Boolean(args.dashboard_demo),
1407
1433
  });
1408
1434
  } else {
1409
1435
  result = runPublish({
@@ -1411,7 +1437,6 @@ export async function dispatchToolByName(name, args = {}) {
1411
1437
  format: args.format || 'pdf',
1412
1438
  outputPath: args.output_path,
1413
1439
  demos: args.demo ? [args.demo] : [],
1414
- dashboardDemos: args.dashboard_demo ? [args.dashboard_demo] : [],
1415
1440
  figures: args.figures !== false,
1416
1441
  strict: args.strict !== false,
1417
1442
  gate: args.no_gate !== true,
@@ -1421,15 +1446,15 @@ export async function dispatchToolByName(name, args = {}) {
1421
1446
  });
1422
1447
  }
1423
1448
  }
1424
- else if (name === 'profile_show') result = profileShow(args);
1425
- else if (name === 'profile_list') result = profileList();
1426
- else if (name === 'profile_drafts') result = profileDrafts(args);
1427
- else if (name === 'profile_health') result = profileHealthTool(args);
1449
+ else if (name === 'scope_show') result = scopeShow(args);
1450
+ else if (name === 'scope_list') result = scopeList();
1451
+ else if (name === 'scope_drafts') result = scopeDrafts(args);
1452
+ else if (name === 'scope_health') result = scopeHealthTool(args);
1428
1453
  else if (name === 'outcomes_summary') result = outcomesSummary(args);
1429
1454
  else if (name === 'outcomes_record') result = outcomesRecord(args);
1430
1455
  else if (name === 'knowledge_add') result = await knowledgeAdd(args);
1431
- else if (name === 'profile_create') result = profileCreate(args);
1432
- else if (name === 'profile_archive') result = profileArchive(args);
1456
+ else if (name === 'scope_create') result = scopeCreate(args);
1457
+ else if (name === 'scope_archive') result = scopeArchive(args);
1433
1458
  else if (name === 'sandbox_list') result = sandboxList();
1434
1459
  else if (name === 'learning_status') result = learningStatus(args);
1435
1460
  else if (name === 'knowledge_graph_ask') result = knowledgeGraphAsk(args);
@@ -1439,17 +1464,35 @@ export async function dispatchToolByName(name, args = {}) {
1439
1464
  else if (name === 'capability_describe') result = capabilityDescribe(args);
1440
1465
  else if (name === 'construct_execution_resolve') result = executionResolve(args);
1441
1466
  else if (name === 'artifact_workflow') result = artifactWorkflow(args);
1467
+ else if (name === 'author_artifact') result = await authorArtifact(args, opts);
1468
+ else if (name === 'find_tool') result = await findTool(args, { toolDefs: ALL_TOOL_DEFS, env: process.env });
1442
1469
  else if (name === 'orchestration_run') { const m = await import('./tools/orchestration-run.mjs'); result = await m.orchestrationRun(args); }
1443
1470
  else if (name === 'orchestration_status') { const m = await import('./tools/orchestration-run.mjs'); result = await m.orchestrationStatus(args); }
1444
- else if (name === 'construct_call') {
1471
+ else if (name === 'call') {
1445
1472
  const inner = String(args?.tool || '');
1446
- if (!inner || inner === 'construct_call') result = { error: "construct_call requires a 'tool' name (not 'construct_call')" };
1473
+ if (!inner || isGatewayName(inner)) result = { error: "call requires a 'tool' name to invoke (e.g. { tool: 'document_export', args: {…} })" };
1447
1474
  else result = await dispatchToolByName(inner, args?.args || {});
1448
1475
  }
1449
- else result = { error: `Unknown tool: ${name}` };
1476
+ else result = await resolveUnknownToolName(name, args);
1450
1477
  return result;
1451
1478
  }
1452
1479
 
1480
+ // The agent reached for a name no branch matches. Recover the obvious cases (the
1481
+ // gateway under an alias, a known tool wearing the host prefix) and record every
1482
+ // miss so the discoverability gap is measurable instead of silent.
1483
+
1484
+ async function resolveUnknownToolName(name, args = {}) {
1485
+ const recovered = recoverToolName(name, KNOWN_TOOL_NAMES);
1486
+ recordToolNameMiss(ROOT_DIR, { name, recovered: recovered?.name || (recovered?.gateway ? 'call' : null) });
1487
+ if (recovered?.gateway) {
1488
+ const inner = String(args?.tool || '');
1489
+ if (!inner || isGatewayName(inner)) return { error: "call requires a 'tool' name to invoke (e.g. { tool: 'document_export', args: {…} })" };
1490
+ return dispatchToolByName(inner, args?.args || {});
1491
+ }
1492
+ if (recovered?.name) return dispatchToolByName(recovered.name, args);
1493
+ return { error: `Unknown tool: ${name}. Core tools are flat; invoke any other tool via { name: 'call', arguments: { tool: '<name>', args: {…} } }.` };
1494
+ }
1495
+
1453
1496
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
1454
1497
  const { name, arguments: args = {} } = request.params;
1455
1498
 
@@ -8,9 +8,7 @@
8
8
  * 2. which external MCP servers are `enabled` in opencode.json — sync disables
9
9
  * the heavy ones for local-capable setups (they cannot be trimmed at runtime).
10
10
  * Holds the shared token-sizing helper and the external-server id list both
11
- * levers reason about, plus the owned-loop tool-budget filter that trims the
12
- * Vercel AI SDK tool set to a compiled execution policy's allowed groups and
13
- * schema cap (lib/models/execution-policy.mjs).
11
+ * levers reason about.
14
12
  */
15
13
 
16
14
  import { getMeasuredHeavyExternalMcpTokenCost } from './external-schema-cost.mjs';
@@ -59,46 +57,3 @@ export function estimateToolTokens(tools) {
59
57
  }
60
58
 
61
59
  export { getMeasuredHeavyExternalMcpTokenCost };
62
-
63
- // Maps the owned loop's agent tool names (apps/chat/engine/tools/registry.mjs)
64
- // onto the execution-policy tool groups (lib/models/execution-policy.mjs) so a
65
- // compiled policy can trim the serialized tool surface for a capability-
66
- // constrained model. construct_tool is the single MCP gateway, so it stands in
67
- // for the whole 'construct' group. An unrecognized name falls back to
68
- // 'construct' — a group present in every tier — so an unclassified tool is never
69
- // silently dropped from a constrained surface.
70
-
71
- const AGENT_TOOL_GROUPS = Object.freeze({
72
- read: 'read',
73
- glob: 'search',
74
- grep: 'search',
75
- write: 'edit',
76
- edit: 'edit',
77
- shell: 'shell',
78
- construct_tool: 'construct',
79
- });
80
-
81
- export function toolGroupForName(name) {
82
- return AGENT_TOOL_GROUPS[name] || 'construct';
83
- }
84
-
85
- // Trim a tool set to the compiled policy's envelope: drop any tool whose group is
86
- // outside allowedToolGroups, then cap the survivors at maxToolSchemas in stable
87
- // insertion order. A null allowedToolGroups means "no group filter" and an
88
- // unbounded cap means "no count limit", so the rich/hosted-direct envelope (all
89
- // groups, cap 32) returns the input set unchanged.
90
-
91
- export function applyToolBudget(tools, { allowedToolGroups = null, maxToolSchemas = Infinity } = {}) {
92
- if (!tools || typeof tools !== 'object') return tools;
93
- const allow = Array.isArray(allowedToolGroups) ? new Set(allowedToolGroups) : null;
94
- const cap = Number.isFinite(maxToolSchemas) ? Math.max(0, Math.floor(maxToolSchemas)) : Infinity;
95
- const out = {};
96
- let kept = 0;
97
- for (const [name, def] of Object.entries(tools)) {
98
- if (allow && !allow.has(toolGroupForName(name))) continue;
99
- if (kept >= cap) break;
100
- out[name] = def;
101
- kept += 1;
102
- }
103
- return out;
104
- }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * lib/mcp/tool-recovery.mjs — Tolerant dispatch fallback + tool-name-miss telemetry.
3
+ *
4
+ * Hosts and models routinely mis-name Construct tools: the `call` gateway under
5
+ * its former `construct_call` name, a long-tail tool invoked directly, or a name
6
+ * carrying a stray `construct-mcp_` host prefix. Recovering the intent when it is
7
+ * unambiguous keeps work flowing; recording every miss closes a discoverability
8
+ * blind spot — calls rejected at the host's tool-validation layer never reach the
9
+ * server, so without this record those failures stay invisible to Construct.
10
+ */
11
+ import fs from 'node:fs';
12
+ import path from 'node:path';
13
+
14
+ const GATEWAY_NAMES = new Set(['call', 'construct_call']);
15
+
16
+ function stripHostPrefix(name) {
17
+ return String(name || '').replace(/^construct[-_]mcp[-_]/i, '');
18
+ }
19
+
20
+ export function isGatewayName(name) {
21
+ return GATEWAY_NAMES.has(name) || GATEWAY_NAMES.has(stripHostPrefix(name));
22
+ }
23
+
24
+ // Resolve an unrecognized name to a real target when the intent is unambiguous:
25
+ // a gateway alias, or a known tool wearing the host prefix. Anything else is a
26
+ // genuine miss with no safe recovery.
27
+
28
+ export function recoverToolName(name, knownNames) {
29
+ if (isGatewayName(name)) return { gateway: true };
30
+ const stripped = stripHostPrefix(name);
31
+ if (stripped !== name && knownNames.has(stripped)) return { name: stripped };
32
+ return null;
33
+ }
34
+
35
+ export function recordToolNameMiss(rootDir, { name, recovered = null } = {}) {
36
+ try {
37
+ const dir = path.join(rootDir, '.cx', 'observations');
38
+ fs.mkdirSync(dir, { recursive: true });
39
+ const line = `${JSON.stringify({ at: new Date().toISOString(), kind: 'tool-name-miss', name, recovered })}\n`;
40
+ fs.appendFileSync(path.join(dir, 'tool-name-misses.jsonl'), line);
41
+ } catch {
42
+ /* telemetry is best-effort; never break dispatch */
43
+ }
44
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * lib/mcp/tools/artifact-author.mjs — MCP `author_artifact` tool.
3
+ *
4
+ * OpenCode-reachable author pass: the calling agent is the model and supplies
5
+ * the drafted typed-artifact markdown,
6
+ * which gets materialized to its canonical path and run through the release gate.
7
+ * Returns the path and a structured verdict so the agent can fix and re-call.
8
+ * allowScaffold stays off — a real draft is required, never an empty scaffold.
9
+ */
10
+ import { runConstructArtifactLoop } from '../../artifact-loop-core.mjs';
11
+
12
+ export async function authorArtifact(args = {}, { ROOT_DIR } = {}) {
13
+ const draftMarkdown = args.draft_markdown || args.draft || '';
14
+ const cwd = args.cwd || process.cwd();
15
+ const result = await runConstructArtifactLoop({
16
+ draftMarkdown,
17
+ artifactType: args.artifact_type,
18
+ text: args.subject || args.text || '',
19
+ cwd,
20
+ rootDir: ROOT_DIR,
21
+ explicit: true,
22
+ allowScaffold: false,
23
+ });
24
+
25
+ return {
26
+ ok: Boolean(result.ok),
27
+ artifact_type: result.artifactType,
28
+ path: result.relPath,
29
+ written: !result.draftMissing,
30
+ gate: result.validation?.ok ? 'PASS' : 'FAIL',
31
+ errors: result.validation?.errors || [],
32
+ warnings: result.validation?.warnings || [],
33
+ workflow_plan: (result.invokePlan?.selectedRoles || []).map((r) => `cx-${r}`),
34
+ summary: result.summary,
35
+ };
36
+ }