@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
@@ -7,14 +7,17 @@
7
7
  */
8
8
 
9
9
  import fs from 'node:fs';
10
+ import { loadRegistry } from '../registry/loader.mjs';
10
11
  import path from 'node:path';
11
12
  import { createHash } from 'node:crypto';
12
13
  import { artifactTypes, loadArtifactManifest } from '../artifact-manifest.mjs';
14
+ import { validateSkillEffectiveness } from '../validators/skill-effectiveness.mjs';
15
+ import { collectScopeRoleIds } from '../scopes/enrich.mjs';
13
16
 
14
17
  function findConstructRoot(startPath = process.cwd()) {
15
18
  let current = path.resolve(startPath);
16
19
  while (true) {
17
- if (fs.existsSync(path.join(current, 'specialists', 'registry.json'))) return current;
20
+ if (fs.existsSync(path.join(current, 'specialists', 'org'))) return current;
18
21
  const parent = path.dirname(current);
19
22
  if (parent === current) return path.resolve(startPath);
20
23
  current = parent;
@@ -37,22 +40,18 @@ function collectSkillFiles(skillsDir) {
37
40
  return results.sort();
38
41
  }
39
42
 
40
- function collectProfileRoles(root) {
41
- const dir = path.join(root, 'profiles');
43
+ function collectScopeRoles(root) {
44
+ const dir = path.join(root, 'specialists', 'org', 'scopes');
42
45
  const roles = new Set();
43
- const scan = (node) => {
44
- if (Array.isArray(node)) { node.forEach(scan); return; }
45
- if (node && typeof node === 'object') {
46
- if (Array.isArray(node.roles)) for (const r of node.roles) if (typeof r === 'string') roles.add(r);
47
- for (const v of Object.values(node)) scan(v);
48
- }
49
- };
50
46
  try {
51
47
  for (const f of fs.readdirSync(dir)) {
52
48
  if (!f.endsWith('.json')) continue;
53
- try { scan(JSON.parse(fs.readFileSync(path.join(dir, f), 'utf8'))); } catch { /* skip malformed */ }
49
+ try {
50
+ const raw = JSON.parse(fs.readFileSync(path.join(dir, f), 'utf8'));
51
+ for (const r of collectScopeRoleIds(raw, { rootDir: root })) roles.add(r);
52
+ } catch { /* skip malformed */ }
54
53
  }
55
- } catch { /* no profiles dir */ }
54
+ } catch { /* no scopes dir */ }
56
55
  return roles;
57
56
  }
58
57
 
@@ -96,19 +95,20 @@ function verificationHooks(meta, body) {
96
95
  }
97
96
 
98
97
  function resolveOwners(skillId, { registry, declaredSkills, ownerBases }) {
98
+ if (skillId.startsWith('brand/')) return ['cx-docs-keeper'];
99
99
  const owners = new Set();
100
- for (const agent of registry.specialists ?? []) {
100
+ for (const agent of Object.values(registry.specialists ?? {})) {
101
101
  if ((agent.skills ?? []).includes(skillId)) owners.add(`cx-${agent.name}`);
102
102
  }
103
103
  const base = roleBase(skillId);
104
104
  if (base && ownerBases.has(base)) {
105
- for (const agent of registry.specialists ?? []) {
105
+ for (const agent of Object.values(registry.specialists ?? {})) {
106
106
  if (agent.name === base || agent.name.replace(/^cx-/, '') === base) owners.add(`cx-${agent.name}`);
107
107
  }
108
- if (!owners.size) owners.add(`profile-role:${base}`);
108
+ if (!owners.size) owners.add(`scope-role:${base}`);
109
109
  }
110
110
  if (declaredSkills.has(skillId) && owners.size === 0) {
111
- for (const agent of registry.specialists ?? []) {
111
+ for (const agent of Object.values(registry.specialists ?? {})) {
112
112
  if ((agent.skills ?? []).includes(skillId)) owners.add(`cx-${agent.name}`);
113
113
  }
114
114
  }
@@ -138,10 +138,11 @@ function detectConflictingOutputs(skills) {
138
138
  for (const [artifactType, entries] of byType) {
139
139
  if (entries.length < 2) continue;
140
140
  const bars = new Set(entries.map((e) => e.verificationHooks.find((h) => h.kind === 'verificationBar')?.value ?? ''));
141
+ if (bars.size <= 1) continue;
141
142
  conflicts.push({
142
143
  artifactType,
143
144
  skillIds: entries.map((e) => e.id),
144
- reason: bars.size > 1 ? 'divergent verificationBar across workflow skills' : 'multiple workflow skills claim the same manifest artifact type',
145
+ reason: 'divergent verificationBar across workflow skills',
145
146
  });
146
147
  }
147
148
  return conflicts;
@@ -154,15 +155,15 @@ export function defaultSkillInventoryPath(rootDir = process.cwd()) {
154
155
  export function buildSkillInventory({ rootDir } = {}) {
155
156
  const root = findConstructRoot(rootDir);
156
157
  const skillsDir = path.join(root, 'skills');
157
- const registry = JSON.parse(fs.readFileSync(path.join(root, 'specialists', 'registry.json'), 'utf8'));
158
+ const registry = loadRegistry({ rootDir: root });
158
159
  const manifest = loadArtifactManifest({ rootDir: root });
159
160
  const declaredSkills = new Set();
160
- for (const agent of registry.specialists ?? []) {
161
+ for (const agent of Object.values(registry.specialists ?? {})) {
161
162
  for (const skill of agent.skills ?? []) declaredSkills.add(skill);
162
163
  }
163
164
  const ownerBases = new Set([
164
- ...(registry.specialists ?? []).map((a) => a.name.replace(/^cx-/, '')),
165
- ...collectProfileRoles(root),
165
+ ...Object.values(registry.specialists ?? {}).map((a) => a.name.replace(/^cx-/, '')),
166
+ ...collectScopeRoles(root),
166
167
  ]);
167
168
  const workflowIds = workflowSkillIds(manifest);
168
169
 
@@ -202,6 +203,14 @@ export function buildSkillInventory({ rootDir } = {}) {
202
203
  });
203
204
  }
204
205
 
206
+ const effectiveness = validateSkillEffectiveness({ rootDir: root });
207
+ const effectivenessFindings = effectiveness.errors.map((message) => ({
208
+ kind: 'effectiveness',
209
+ severity: 'blocking',
210
+ message,
211
+ }));
212
+ blockingFindings.push(...effectivenessFindings);
213
+
205
214
  const payload = {
206
215
  version: 1,
207
216
  generatedAt: new Date().toISOString(),
@@ -209,6 +218,7 @@ export function buildSkillInventory({ rootDir } = {}) {
209
218
  skillCount: skills.length,
210
219
  skills,
211
220
  blockingFindings,
221
+ effectivenessFindings,
212
222
  digest: null,
213
223
  };
214
224
  const canonical = { ...payload, digest: undefined };
@@ -238,7 +248,9 @@ export function validateSkillInventory({ rootDir, inventory: supplied, checkFres
238
248
  }
239
249
 
240
250
  for (const finding of inventory.blockingFindings ?? []) {
241
- if (finding.severity === 'blocking') warnings.push(`blocking finding recorded: ${finding.kind} ${finding.skillId ?? finding.artifactType ?? ''}`.trim());
251
+ if (finding.severity === 'blocking') {
252
+ errors.push(`blocking finding: ${finding.kind} ${finding.skillId ?? finding.message ?? finding.artifactType ?? ''}`.trim());
253
+ }
242
254
  }
243
255
 
244
256
  if (checkFreshness) {
@@ -8,16 +8,19 @@
8
8
  import fs from 'node:fs';
9
9
  import path from 'node:path';
10
10
 
11
+ import { validateSkillEffectiveness } from '../validators/skill-effectiveness.mjs';
12
+ import { auditSkillComposition } from '../skills/composition-graph.mjs';
11
13
  import { defaultSkillInventoryPath } from './skill-inventory.mjs';
12
14
  import { defaultScenarioCatalogPath } from './scenarios.mjs';
13
15
 
14
- const HIGH_RISK_SKILLS = new Set([
15
- 'docs/prd-workflow',
16
- 'docs/product-intelligence-workflow',
17
- 'docs/evidence-ingest-workflow',
18
- 'quality-gates/verify-security',
19
- 'security/threat-intel',
20
- ]);
16
+ const HIGH_RISK_SKILLS = null;
17
+
18
+ function highRiskSkillIds(root) {
19
+ if (HIGH_RISK_SKILLS) return HIGH_RISK_SKILLS;
20
+ const file = defaultSkillInventoryPath(root);
21
+ const inventory = JSON.parse(fs.readFileSync(file, 'utf8'));
22
+ return new Set((inventory.skills ?? []).filter((s) => s.workflowSkill).map((s) => s.id));
23
+ }
21
24
 
22
25
  function findConstructRoot(startPath = process.cwd()) {
23
26
  let current = path.resolve(startPath);
@@ -50,6 +53,8 @@ export function buildPositiveScenario(skill) {
50
53
  verificationSteps: [
51
54
  'skill file exists under skills/',
52
55
  'inventory lists owners and workflowSkill=true',
56
+ 'effectiveness rubric passes (lint:scopes)',
57
+ 'get_skill and specialist refs resolve (composition graph)',
53
58
  ],
54
59
  owners: skill.owners ?? [],
55
60
  };
@@ -80,6 +85,14 @@ export function validateSkillScenarioFixture(fixture, { rootDir } = {}) {
80
85
  if (fixture.mode === 'positive' && !Array.isArray(fixture.verificationSteps)) {
81
86
  errors.push('positive fixture requires verificationSteps');
82
87
  }
88
+ if (fixture.mode === 'positive' && fixture.verificationSteps?.includes('effectiveness rubric passes (lint:scopes)')) {
89
+ const eff = validateSkillEffectiveness({ rootDir: root });
90
+ if (!eff.valid) errors.push(`effectiveness: ${eff.errors.find((e) => e.startsWith(fixture.skillId)) ?? eff.errors[0]}`);
91
+ }
92
+ if (fixture.mode === 'positive' && fixture.verificationSteps?.includes('get_skill and specialist refs resolve (composition graph)')) {
93
+ const comp = auditSkillComposition({ rootDir: root });
94
+ if (!comp.pass) errors.push(`composition: ${comp.blocking[0] ?? 'blocking'}`);
95
+ }
83
96
  if (fixture.mode === 'negative') {
84
97
  if (fixture.expected?.silentSuccess !== false) errors.push('negative fixture must forbid silent success');
85
98
  if (!fixture.expected?.errorType) errors.push('negative fixture requires expected.errorType');
@@ -121,7 +134,7 @@ export function writeSkillScenarioFixtures({ rootDir } = {}) {
121
134
  model: { provider: 'hermetic', requestedId: 'fixture/skill', resolvedId: 'fixture/skill', tier: 'hermetic' },
122
135
  });
123
136
  lines.push(`- \`${skill.id}\` — positive: \`${relPositive}\``);
124
- if (HIGH_RISK_SKILLS.has(skill.id)) {
137
+ if (highRiskSkillIds(root).has(skill.id)) {
125
138
  const negative = buildNegativeScenario(skill);
126
139
  const negativePath = path.join(dir, 'negative.json');
127
140
  fs.writeFileSync(negativePath, `${JSON.stringify(negative, null, 2)}\n`);
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import fs from 'node:fs';
9
+ import { loadRegistry } from '../registry/loader.mjs';
9
10
  import path from 'node:path';
10
11
 
11
12
  import { validatePromptContent } from '../specialists/prompt-schema.mjs';
@@ -13,7 +14,7 @@ import { validatePromptContent } from '../specialists/prompt-schema.mjs';
13
14
  function findConstructRoot(startPath = process.cwd()) {
14
15
  let current = path.resolve(startPath);
15
16
  while (true) {
16
- if (fs.existsSync(path.join(current, 'specialists', 'registry.json'))) return current;
17
+ if (fs.existsSync(path.join(current, 'specialists', 'org'))) return current;
17
18
  const parent = path.dirname(current);
18
19
  if (parent === current) return path.resolve(startPath);
19
20
  current = parent;
@@ -73,8 +74,8 @@ export function checkSpecialistContract(agent, { rootDir } = {}) {
73
74
 
74
75
  export function auditSpecialistContracts({ rootDir } = {}) {
75
76
  const root = findConstructRoot(rootDir);
76
- const registry = JSON.parse(fs.readFileSync(path.join(root, 'specialists', 'registry.json'), 'utf8'));
77
- const results = (registry.specialists ?? []).map((agent) => checkSpecialistContract(agent, { rootDir: root }));
77
+ const registry = loadRegistry({ rootDir: root });
78
+ const results = Object.values(registry.specialists ?? {}).map((agent) => checkSpecialistContract(agent, { rootDir: root }));
78
79
  const failures = results.filter((r) => !r.pass);
79
80
  return {
80
81
  pass: failures.length === 0,
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import fs from 'node:fs';
10
+ import { loadRegistry } from '../registry/loader.mjs';
10
11
  import path from 'node:path';
11
12
 
12
13
  import { roleCardsDir } from './role-cards.mjs';
@@ -16,7 +17,7 @@ import { defaultScenarioCatalogPath } from './scenarios.mjs';
16
17
  function findConstructRoot(startPath = process.cwd()) {
17
18
  let current = path.resolve(startPath);
18
19
  while (true) {
19
- if (fs.existsSync(path.join(current, 'specialists', 'registry.json'))) return current;
20
+ if (fs.existsSync(path.join(current, 'specialists', 'org'))) return current;
20
21
  const parent = path.dirname(current);
21
22
  if (parent === current) return path.resolve(startPath);
22
23
  current = parent;
@@ -75,8 +76,8 @@ export function validateSpecialistScenarioFixture(fixture, { rootDir } = {}) {
75
76
  if (!fixture?.capabilityId) errors.push('capabilityId required');
76
77
  if (!['normal', 'adversarial'].includes(fixture.mode)) errors.push('mode must be normal or adversarial');
77
78
 
78
- const registry = JSON.parse(fs.readFileSync(path.join(root, 'specialists', 'registry.json'), 'utf8'));
79
- const agent = (registry.specialists ?? []).find((entry) => `cx-${entry.name}` === fixture.specialistId);
79
+ const registry = loadRegistry({ rootDir: root });
80
+ const agent = Object.values(registry.specialists ?? {}).find((entry) => `cx-${entry.name}` === fixture.specialistId);
80
81
  if (!agent) errors.push(`unknown specialist: ${fixture.specialistId}`);
81
82
 
82
83
  const cardPath = path.join(roleCardsDir(root), `${fixture.specialistId}.role-card.json`);
@@ -110,7 +111,7 @@ export function validateSpecialistScenarioFixture(fixture, { rootDir } = {}) {
110
111
 
111
112
  export function writeSpecialistScenarioFixtures({ rootDir } = {}) {
112
113
  const root = findConstructRoot(rootDir);
113
- const registry = JSON.parse(fs.readFileSync(path.join(root, 'specialists', 'registry.json'), 'utf8'));
114
+ const registry = loadRegistry({ rootDir: root });
114
115
  const readme = path.join(root, 'tests', 'certification', 'scenarios', 'specialists', 'README.md');
115
116
  fs.mkdirSync(path.dirname(readme), { recursive: true });
116
117
  const lines = [
@@ -127,7 +128,7 @@ export function writeSpecialistScenarioFixtures({ rootDir } = {}) {
127
128
  ];
128
129
  const catalogEntries = [];
129
130
 
130
- for (const agent of registry.specialists ?? []) {
131
+ for (const agent of Object.values(registry.specialists ?? {})) {
131
132
  const specialistId = `cx-${agent.name}`;
132
133
  const cardPath = path.join(roleCardsDir(root), `${specialistId}.role-card.json`);
133
134
  if (!fs.existsSync(cardPath)) continue;
@@ -171,5 +172,5 @@ export function writeSpecialistScenarioFixtures({ rootDir } = {}) {
171
172
  && !String(s.id).startsWith('specialist.adversarial.'));
172
173
  catalog.scenarios = [...keep, ...catalogEntries];
173
174
  fs.writeFileSync(catalogPath, `${JSON.stringify(catalog, null, 2)}\n`);
174
- return { specialistCount: (registry.specialists ?? []).length, catalogEntries: catalogEntries.length, readme };
175
+ return { specialistCount: Object.values(registry.specialists ?? {}).length, catalogEntries: catalogEntries.length, readme };
175
176
  }
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import fs from 'node:fs';
9
+ import { loadRegistry } from '../registry/loader.mjs';
9
10
  import path from 'node:path';
10
11
 
11
12
  import { loadCapabilityLedger } from '../capability-ledger.mjs';
@@ -28,13 +29,13 @@ function findConstructRoot(startPath = process.cwd()) {
28
29
  }
29
30
 
30
31
  function readRegistry(rootDir) {
31
- const file = path.join(rootDir, 'specialists', 'registry.json');
32
- if (!fs.existsSync(file)) return { specialists: [] };
33
- return JSON.parse(fs.readFileSync(file, 'utf8'));
32
+ const dir = path.join(rootDir, 'specialists', 'org');
33
+ if (!fs.existsSync(dir)) return { specialists: [] };
34
+ return loadRegistry({ rootDir });
34
35
  }
35
36
 
36
37
  function listSpecialists(registry) {
37
- return registry.specialists ?? [];
38
+ return Object.values(registry.specialists ?? {});
38
39
  }
39
40
 
40
41
  function normalizeStatus({ verdict = null, stale = false, neverRun = true }) {
@@ -4,7 +4,6 @@
4
4
  * Consumed by:
5
5
  * - bin/construct (usage text + emoji output)
6
6
  * - lib/completions.mjs (bash + zsh completion generation)
7
- * - lib/server/index.mjs (/api/status → dashboard)
8
7
  *
9
8
  * Command Visibility:
10
9
  * - core: true → shown in default --help (90% of users)
@@ -13,6 +12,8 @@
13
12
  */
14
13
 
15
14
  import { resolveColors } from './term-format.mjs';
15
+ import { resolveUiColors } from './ui/theme.mjs';
16
+ import { formatPathLink, terminalLinksEnabled } from './ui/links.mjs';
16
17
  import { surfaceForCommand } from './registry/surface-map.mjs';
17
18
 
18
19
  export const CLI_COMMANDS = [
@@ -23,26 +24,14 @@ export const CLI_COMMANDS = [
23
24
  category: 'Core',
24
25
  core: true,
25
26
  description: 'Start services for development',
26
- usage: 'construct dev [--select] [--only=postgres,dashboard,...]',
27
+ usage: 'construct dev [--select] [--only=postgres,...]',
27
28
  examples: [
28
29
  { cmd: 'construct dev', desc: 'Start the default service set' },
29
- { cmd: 'construct dev --only=dashboard', desc: 'Start just the dashboard' },
30
+ { cmd: 'construct dev --only=postgres', desc: 'Start just Postgres' },
30
31
  ],
31
32
  options: [
32
33
  { flag: '--select', desc: 'Pick which services to start from an interactive checklist' },
33
- { flag: '--only=<a,b,c>', desc: 'Start only the named services (postgres, dashboard, telemetry, memory, opencode)' },
34
- ],
35
- },
36
- {
37
- name: 'dashboard',
38
- emoji: '📊',
39
- category: 'Core',
40
- core: true,
41
- description: 'Start the local dashboard/orchestration daemon (or --token to mint a dashboard token)',
42
- usage: 'construct dashboard [--token]',
43
- examples: [
44
- { cmd: 'construct dashboard', desc: 'Launch the local dashboard daemon' },
45
- { cmd: 'construct dashboard --token', desc: 'Mint a dashboard access token' },
34
+ { flag: '--only=<a,b,c>', desc: 'Start only the named services (postgres, telemetry, memory, opencode)' },
46
35
  ],
47
36
  },
48
37
  {
@@ -230,24 +219,24 @@ export const CLI_COMMANDS = [
230
219
  ],
231
220
  },
232
221
  {
233
- name: 'profile',
222
+ name: 'scope',
234
223
  emoji: '🧭',
235
224
  category: 'Core',
236
225
  core: true,
237
- description: 'Manage the active org profile and its lifecycle (draft, promote, archive, health)',
238
- usage: 'construct profile show|list|set|create|drafts|archive|health',
226
+ description: 'Manage the active org scope and its lifecycle (draft, promote, archive, health)',
227
+ usage: 'construct scope show|list|set|create|drafts|archive|health',
239
228
  examples: [
240
- { cmd: 'construct profile list', desc: 'List curated profiles' },
241
- { cmd: 'construct profile set <id>', desc: 'Switch the active profile' },
229
+ { cmd: 'construct scope list', desc: 'List curated scopes' },
230
+ { cmd: 'construct scope set <id>', desc: 'Switch the active scope' },
242
231
  ],
243
232
  subcommands: [
244
- { name: 'show', desc: 'Show the active profile' },
245
- { name: 'list', desc: 'List curated profiles' },
246
- { name: 'set <id>', desc: 'Switch the active profile (writes construct.config.json)' },
247
- { name: 'create <id> [--display=…] [--role=…] [--department=…] [--yes|--dry-run]', desc: 'Scaffold a draft profile; previews and confirms by default, prompts interactively when no flags' },
248
- { name: 'drafts', desc: 'List in-progress draft profiles' },
249
- { name: 'archive <id> --reason="..."', desc: 'Move a curated profile into archive/profiles/<id>/' },
250
- { name: 'health <id> [--days=N]', desc: 'Per-profile observation + outcome rollup' },
233
+ { name: 'show', desc: 'Show the active scope' },
234
+ { name: 'list', desc: 'List curated scopes' },
235
+ { name: 'set <id>', desc: 'Switch the active scope (writes construct.config.json)' },
236
+ { name: 'create <id> [--display=…] [--role=…] [--department=…] [--yes|--dry-run]', desc: 'Scaffold a draft scope; previews and confirms by default, prompts interactively when no flags' },
237
+ { name: 'drafts', desc: 'List in-progress draft scopes' },
238
+ { name: 'archive <id> --reason="..."', desc: 'Move a curated scope into archive/scopes/<id>/' },
239
+ { name: 'health <id> [--days=N]', desc: 'Per-scope observation + outcome rollup' },
251
240
  ],
252
241
  },
253
242
  {
@@ -354,7 +343,7 @@ export const CLI_COMMANDS = [
354
343
  { flag: '--output=<path>', desc: 'Output path (default: .cx/publish/<name>.<format>)' },
355
344
  { flag: '--type=<doc-type>', desc: 'Manifest doc type for release gate (inferred when omitted)' },
356
345
  { flag: '--demo=<name>', desc: 'Terminal VHS tape to record (repeatable)' },
357
- { flag: '--dashboard-demo=<name>', desc: 'Playwright demo spec basename (repeatable)' },
346
+ { flag: '--recording=<name>', desc: 'Playwright recording manifest (repeatable)' },
358
347
  { flag: '--figures', desc: 'Render d2/mermaid via diagram filter (default on)' },
359
348
  { flag: '--no-figures', desc: 'Skip diagram filter' },
360
349
  { flag: '--no-gate', desc: 'Skip artifact release gate (escape hatch only)' },
@@ -377,7 +366,6 @@ export const CLI_COMMANDS = [
377
366
  { flag: '--figures', desc: 'Include figure tooling (default on)' },
378
367
  { flag: '--no-figures', desc: 'Skip figure binaries' },
379
368
  { flag: '--demo=<name>', desc: 'Include terminal demo recorder check' },
380
- { flag: '--dashboard-demo=<name>', desc: 'Include dashboard Playwright check' },
381
369
  ],
382
370
  },
383
371
  {
@@ -480,14 +468,6 @@ export const CLI_COMMANDS = [
480
468
  description: 'Run Construct as an Agent Client Protocol (ACP) server over stdio for Zed/JetBrains/VS Code ACP clients',
481
469
  usage: 'construct acp',
482
470
  },
483
- {
484
- name: 'chat',
485
- emoji: '💬',
486
- category: 'Models & Integrations',
487
- core: false,
488
- description: "Interactive terminal chat on Construct's owned agent loop, with a multi-pane transparency surface (live token/cost/context usage, reasoning, tool timeline, and the planned specialist route); switch models, change settings, and see a token/cost breakdown in-session. Use --accessible or --plain for the linear, screen-reader-friendly renderer",
489
- usage: 'construct chat [--model <id>] [--free] [--web] [--list] [--resume[=file]] [--ascii] [--plain] [--accessible] [--no-thinking] [--no-path] [--no-specialists] [--no-tools] [--no-observability] [--quiet]',
490
- },
491
471
  {
492
472
  name: 'mcp',
493
473
  emoji: '🔌',
@@ -594,7 +574,7 @@ export const CLI_COMMANDS = [
594
574
  emoji: '🔁',
595
575
  category: 'Observability',
596
576
  core: false,
597
- surface: 'dashboard',
577
+ surface: 'thin-cli',
598
578
  description: 'Governed improvement loop — review, approve, and record apply/rollback for proposals',
599
579
  usage: 'construct improvement submit|review|pending|show|approve|apply|rollback|list',
600
580
  },
@@ -619,8 +599,14 @@ export const CLI_COMMANDS = [
619
599
  emoji: '👥',
620
600
  category: 'Work',
621
601
  core: false,
622
- description: 'Team review and template listing',
623
- usage: 'construct team <list|review>',
602
+ description: 'Team review and template listing (`team:add` / `team:remove` are internal registry editors)',
603
+ usage: 'construct team <list|show|review|templates>',
604
+ subcommands: [
605
+ { name: 'list', desc: 'List macro groups and squads (--kind group|squad)' },
606
+ { name: 'show', desc: 'Show one group or squad by id' },
607
+ { name: 'review', desc: 'Team review workflow' },
608
+ { name: 'templates', desc: 'List team doc templates' },
609
+ ],
624
610
  },
625
611
  {
626
612
  name: 'audit',
@@ -686,7 +672,7 @@ export const CLI_COMMANDS = [
686
672
  emoji: '🪞',
687
673
  category: 'Work',
688
674
  core: false,
689
- description: 'Capture improvement feedback from chat session and update Construct core',
675
+ description: 'Capture improvement feedback and update Construct core',
690
676
  usage: 'construct reflect',
691
677
  },
692
678
  {
@@ -734,18 +720,17 @@ export const CLI_COMMANDS = [
734
720
  emoji: '🎬',
735
721
  category: 'Work',
736
722
  core: false,
737
- description: 'Run guided demos via construct chat (default) or record VHS/asciinema tapes',
738
- usage: 'construct demo <list|init|record|name> [--surface=chat|web|tape|dashboard] [--format=gif|mp4|webm] [--out=<path>] [--source-only]',
723
+ description: 'Run guided tours or record VHS/asciinema tapes',
724
+ usage: 'construct demo <list|init|record|tour|name> [--surface=tape|playwright] [--format=gif|mp4|webm] [--out=<path>] [--source-only]',
739
725
  strictFlags: true,
740
726
  options: [
741
- { flag: '--surface=<s>', desc: 'chat (default) | web | tape | dashboard' },
742
- { flag: '--model=<id>', desc: 'Pin model for chat demo' },
743
- { flag: '--web', desc: 'Open web chat (/chat/) instead of terminal Ink' },
744
- { flag: '--plain', desc: 'Linear chat renderer (accessibility / non-TTY)' },
745
- { flag: '--free', desc: 'OpenRouter free-router mode for chat demo' },
727
+ { flag: '--surface=<s>', desc: 'tape (default) | playwright' },
728
+ { flag: '--accessible', desc: 'Screen-reader-friendly linear tour renderer' },
729
+ { flag: '--skip-input', desc: 'Tour: auto-advance without waiting for Enter (headless/CI)' },
746
730
  { flag: '--format=<f>', desc: 'gif (default) | mp4 | webm (tape surface only)' },
747
731
  { flag: '--out=<path>', desc: 'Output path (tape recording)' },
748
732
  { flag: '--from=<t>', desc: 'Template for init: quickstart | diagram' },
733
+ { flag: '--from-project', desc: 'init: scaffold a project demo plug-in under .cx/demos/' },
749
734
  { flag: '--source-only', desc: 'Tape: write .tape only; skip recording' },
750
735
  ],
751
736
  },
@@ -888,7 +873,13 @@ export const CLI_COMMANDS = [
888
873
  category: 'Advanced',
889
874
  core: false,
890
875
  description: 'Skill relevance detection',
891
- usage: 'construct skills scope|apply',
876
+ usage: 'construct skills <scope|apply|suggest|routing>',
877
+ subcommands: [
878
+ { name: 'scope', desc: 'Show skill scope for the active profile' },
879
+ { name: 'apply', desc: 'Apply skill profile to host config' },
880
+ { name: 'suggest', desc: 'Rank skills for an intent string' },
881
+ { name: 'routing', desc: 'Dump machine-readable routing table' },
882
+ ],
892
883
  },
893
884
  {
894
885
  name: 'hooks:health',
@@ -1133,7 +1124,6 @@ export const CLI_COMMANDS = [
1133
1124
  { name: 'hook', category: 'Internal', core: false, internal: true, description: 'Hook dispatch — invoked by the harness, not by users', usage: 'construct hook <event>' },
1134
1125
  { name: 'seed-traces', category: 'Internal', core: false, internal: true, description: 'Dev fixture: seed traces for testing', usage: 'construct seed-traces' },
1135
1126
  { name: 'migrate', category: 'Internal', core: false, internal: true, description: 'Internal: run pending storage migrations', usage: 'construct migrate' },
1136
- { name: 'dashboard:sync', category: 'Internal', core: false, internal: true, description: 'Internal: refresh dashboard state from the registry', usage: 'construct dashboard:sync' },
1137
1127
  { name: 'init:update', category: 'Internal', core: false, internal: true, description: 'Internal: re-run init scaffolding for an existing project', usage: 'construct init:update' },
1138
1128
  { name: 'lint:agents', category: 'Internal', core: false, internal: true, description: 'Internal lint: agent definitions', usage: 'construct lint:agents' },
1139
1129
  { name: 'lint:comments', category: 'Internal', core: false, internal: true, description: 'Internal lint: source comments', usage: 'construct lint:comments' },
@@ -1143,8 +1133,17 @@ export const CLI_COMMANDS = [
1143
1133
  { name: 'lint:prompts', category: 'Internal', core: false, internal: true, description: 'Internal lint: specialist prompt frontmatter + sections', usage: 'construct lint:prompts' },
1144
1134
  { name: 'specialist', category: 'Internal', core: false, internal: true, description: 'Maintainer tool: scaffold, edit, and lint specialist prompts', usage: 'construct specialist <create|edit|lint>' },
1145
1135
  { name: 'registry:status', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Dev: capability registry inspector', usage: 'construct registry:status [--json]' },
1146
- { name: 'registry:validate', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Validate registry/capabilities.json against repo reality', usage: 'construct registry:validate [--json]' },
1136
+ { name: 'registry:validate', category: 'Internal', core: false, internal: true, surface: 'internal', strictFlags: true, description: 'Validate registry/capabilities.json against repo reality; --unified validates specialists/org (+ .cx overlay) invariants', usage: 'construct registry:validate [--json] [--unified]', options: [
1137
+ { flag: '--json', desc: 'Emit the validation report as JSON' },
1138
+ { flag: '--unified', desc: 'Validate the unified registry (specialists/org + optional .cx overlay) against its 13 invariants instead of the capability registry' },
1139
+ ] },
1147
1140
  { name: 'registry:generate-docs', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Generate docs/guides/reference/capabilities.md from registry', usage: 'construct registry:generate-docs' },
1141
+ { name: 'registry:diff', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Show unified registry changes vs. last commit', usage: 'construct registry:diff [--json]' },
1142
+ { name: 'registry:prune', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'List orphaned specialist prompts and skills', usage: 'construct registry:prune [--json]' },
1143
+ { name: 'team:add', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Add a new team to the unified registry', usage: 'construct team:add <team-id>' },
1144
+ { name: 'team:remove', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Remove a team from the unified registry', usage: 'construct team:remove <team-id> [--force]' },
1145
+ { name: 'specialist:add', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Add a new specialist to a team', usage: 'construct specialist:add <specialist-id> --team <team-id>' },
1146
+ { name: 'specialist:remove', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Remove a specialist from the unified registry', usage: 'construct specialist:remove <specialist-id> [--force]' },
1148
1147
  { name: 'oracle', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Oracle meta-controller — fleet health review and bounded-auto maintenance', usage: 'construct oracle start|status|review|pending|approve|gaps|reconcile' },
1149
1148
  { name: 'matrix', category: 'Internal', core: false, internal: true, surface: 'internal', description: 'Living dependency matrix — build/inspect the typed file↔capability↔workflow↔test graph', usage: 'construct matrix build|stat|query <node-id> [--json]' },
1150
1149
  { name: 'impact', category: 'Diagnostics', core: false, internal: false, surface: 'thin-cli', description: 'Change-impact analysis — map changed files to affected tests, capabilities, and workflows', usage: 'construct impact [files…] [--stdin] [--run] [--json]' },
@@ -1220,7 +1219,8 @@ export function getCommandSpec(name) {
1220
1219
  // every command. Internal commands fall back to a minimal block.
1221
1220
 
1222
1221
  export function formatCommandHelp(name, { colors = false } = {}) {
1223
- const c = resolveColors({ enabled: colors });
1222
+ const c = resolveUiColors({ enabled: colors });
1223
+ const linksOn = terminalLinksEnabled(process.env);
1224
1224
  const spec = getCommandSpec(name);
1225
1225
  if (!spec) {
1226
1226
  return `Unknown command: ${name}\n\nRun 'construct --help' for available commands.\n`;
@@ -1269,7 +1269,8 @@ export function formatCommandHelp(name, { colors = false } = {}) {
1269
1269
  lines.push(`${c.dim}Next:${c.reset} ${next}`);
1270
1270
  lines.push('');
1271
1271
  }
1272
- lines.push(`${c.dim}See also:${c.reset} run \`construct --help\` for all commands; full reference in docs/guides/reference/cli/.`);
1272
+ const cliDocs = formatPathLink('docs/guides/reference/cli/', c, { enabled: linksOn });
1273
+ lines.push(`${c.dim}See also:${c.reset} run \`construct --help\` for all commands; full reference in ${cliDocs}.`);
1273
1274
  lines.push('');
1274
1275
  return lines.join('\n');
1275
1276
  }
@@ -93,10 +93,6 @@ function requiresHeader(rel) {
93
93
  if (['.yaml', '.yml', '.json', '.jsonl', '.toml', '.txt'].includes(ext)) return { required: false, type: null };
94
94
  const jsMatch = JS_HEADER_GLOBS.some(r => r.test(rel));
95
95
  const mdMatch = MD_HEADER_GLOBS.some(r => r.test(rel));
96
- // Exclude static assets under lib/server/static from requiring headers
97
- if (rel.startsWith('lib/server/static/')) {
98
- return { required: false, type: null };
99
- }
100
96
  // Exclude test fixture data files — these are project artifacts, not source files.
101
97
  if (rel.startsWith('tests/fixtures/projects/')
102
98
  || rel.startsWith('tests/fixtures/artifacts/')
@@ -324,7 +320,7 @@ function checkArtifactBanned(content, rel) {
324
320
 
325
321
  // Internal specialist role ids (cx-business-strategist, cx-product-manager, …) are
326
322
  // implementation detail; in a consuming project's deliverable they read as a tool-identity
327
- // leak. The set is anchored to the real role ids from specialists/registry.json — an
323
+ // leak. The set is anchored to the real role ids from specialists/org — an
328
324
  // open-ended /cx-[a-z-]+/ also matches unrelated npm packages (cx-ray, cx-pro, cx-widget)
329
325
  // and would fail the release gate on legitimate user content. Drift from the registry is
330
326
  // caught by tests/tool-invisibility.test.mjs, not at runtime: this module sits on the hook
@@ -31,6 +31,7 @@ function subcommandDesc(subcommand) {
31
31
 
32
32
  function buildBash() {
33
33
  const names = CLI_COMMANDS.map(c => c.name).join(' ');
34
+ const globalFlags = '--help -h --all -a --version -V';
34
35
 
35
36
  const subcommandCases = CLI_COMMANDS
36
37
  .filter(c => c.subcommands?.length)
@@ -68,15 +69,28 @@ _construct_completions() {
68
69
  }
69
70
 
70
71
  local commands="${names}"
72
+ local global_flags="${globalFlags}"
71
73
 
72
- # First argument: complete command names
74
+ # First argument: subcommand names or global flags
73
75
  if [[ $cword -eq 1 ]]; then
74
- COMPREPLY=($(compgen -W "$commands" -- "$cur"))
76
+ if [[ "$cur" == -* ]]; then
77
+ COMPREPLY=($(compgen -W "$global_flags" -- "$cur"))
78
+ else
79
+ COMPREPLY=($(compgen -W "$commands" -- "$cur"))
80
+ fi
75
81
  return 0
76
82
  fi
77
83
 
78
84
  local cmd="\${words[1]}"
79
85
 
86
+ # Global flag continuation
87
+ if [[ "$cmd" == -* ]]; then
88
+ if [[ "$cur" == -* ]]; then
89
+ COMPREPLY=($(compgen -W "$global_flags" -- "$cur"))
90
+ return 0
91
+ fi
92
+ fi
93
+
80
94
  # Subcommands
81
95
  if [[ $cword -eq 2 ]]; then
82
96
  case "$cmd" in
@@ -100,6 +114,9 @@ complete -F _construct_completions construct
100
114
  }
101
115
 
102
116
  function buildZsh() {
117
+ const globalFlagDescriptions = ['--help', '-h', '--all', '-a', '--version', '-V']
118
+ .map((f) => ` '${f}:global flag' \\`)
119
+ .join('\n');
103
120
  const commandDescriptions = CLI_COMMANDS
104
121
  .map(c => ` '${c.name}:${c.emoji || ''} ${(c.description || '').replace(/'/g, "\\'")}' \\`)
105
122
  .join('\n');
@@ -140,6 +157,7 @@ ${subcommandFunctions}
140
157
  _construct_commands() {
141
158
  local commands
142
159
  commands=(
160
+ ${globalFlagDescriptions}
143
161
  ${commandDescriptions}
144
162
  )
145
163
  _describe -t commands 'construct command' commands