@geraldmaron/construct 1.2.3 → 1.3.1

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 (505) 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/cli.mjs +12 -2
  44. package/lib/doctor/source-checkout.mjs +3 -4
  45. package/lib/doctor/watchers/consistency.mjs +148 -43
  46. package/lib/doctor/watchers/credential-parity.mjs +97 -0
  47. package/lib/doctor/watchers/mcp-protocol.mjs +1 -1
  48. package/lib/doctor/watchers/service-health.mjs +4 -32
  49. package/lib/document-export.mjs +73 -9
  50. package/lib/document-extract.mjs +10 -198
  51. package/lib/embed/artifact.mjs +2 -3
  52. package/lib/embed/cli.mjs +1 -1
  53. package/lib/embed/config.mjs +1 -2
  54. package/lib/embed/customer-profiles.mjs +1 -1
  55. package/lib/embed/daemon.mjs +5 -6
  56. package/lib/embed/demand-fetch.mjs +114 -2
  57. package/lib/embed/docs-lifecycle.mjs +9 -5
  58. package/lib/embed/intake-metrics.mjs +2 -2
  59. package/lib/embed/notifications.mjs +2 -3
  60. package/lib/embed/recommendation-store.mjs +25 -22
  61. package/lib/embed/role-framing.mjs +4 -9
  62. package/lib/embedded-contract/capability.mjs +4 -2
  63. package/lib/embedded-contract/contract-version.mjs +1 -1
  64. package/lib/env-config.mjs +2 -2
  65. package/lib/flavors/loader.mjs +21 -19
  66. package/lib/graph/build-from-registry.mjs +31 -7
  67. package/lib/graph/staleness.mjs +1 -1
  68. package/lib/headhunt.mjs +82 -35
  69. package/lib/hooks/agent-tracker.mjs +2 -2
  70. package/lib/hooks/config-protection.mjs +1 -1
  71. package/lib/hooks/registry-sync.mjs +3 -3
  72. package/lib/host-capabilities.mjs +5 -5
  73. package/lib/improvement/controller.mjs +2 -2
  74. package/lib/init-unified.mjs +19 -21
  75. package/lib/intake/classify.mjs +26 -0
  76. package/lib/intake/daemon.mjs +2 -3
  77. package/lib/intake/prepare.mjs +10 -3
  78. package/lib/intake/session-prelude.mjs +1 -1
  79. package/lib/intake/tables/creative.mjs +9 -9
  80. package/lib/intake/tables/operations.mjs +4 -4
  81. package/lib/intake/tables/research.mjs +2 -2
  82. package/lib/integrations/intake-integrations.mjs +9 -10
  83. package/lib/knowledge/research-store.mjs +2 -2
  84. package/lib/mcp/server.mjs +104 -61
  85. package/lib/mcp/tool-budget.mjs +1 -46
  86. package/lib/mcp/tool-recovery.mjs +44 -0
  87. package/lib/mcp/tools/artifact-author.mjs +36 -0
  88. package/lib/mcp/tools/find-tool.mjs +86 -0
  89. package/lib/mcp/tools/orchestration-run.mjs +107 -69
  90. package/lib/mcp/tools/project.mjs +4 -3
  91. package/lib/mcp/tools/{profile.mjs → scope.mjs} +54 -52
  92. package/lib/mcp/tools/skills.mjs +39 -22
  93. package/lib/mcp/tools/telemetry.mjs +2 -1
  94. package/lib/mcp/tools/workflow.mjs +1 -1
  95. package/lib/mcp-platform-config.mjs +7 -5
  96. package/lib/migrations/index.mjs +4 -2
  97. package/lib/migrations/v2-unified-registry.mjs +35 -0
  98. package/lib/model-router.mjs +203 -36
  99. package/lib/models/catalog.mjs +25 -9
  100. package/lib/models/execution-capability-profile.mjs +3 -3
  101. package/lib/models/execution-policy.mjs +7 -6
  102. package/lib/models/provider-poll.mjs +18 -4
  103. package/lib/opencode-config.mjs +56 -1
  104. package/lib/opencode-runtime-plugin.mjs +13 -10
  105. package/lib/oracle/artifact-gate.mjs +14 -4
  106. package/lib/oracle/cli.mjs +2 -0
  107. package/lib/oracle/dispatch.mjs +18 -1
  108. package/lib/oracle/execute.mjs +39 -7
  109. package/lib/oracle/index.mjs +1 -1
  110. package/lib/oracle/org-graph.mjs +10 -5
  111. package/lib/oracle/policy.mjs +6 -0
  112. package/lib/oracle/read-model.mjs +103 -6
  113. package/lib/oracle/reconcile.mjs +31 -4
  114. package/lib/oracle/remediation-dispatch.mjs +53 -0
  115. package/lib/oracle/routing.mjs +5 -0
  116. package/lib/oracle/synthesize.mjs +80 -3
  117. package/lib/orchestration/routing-tables.mjs +44 -10
  118. package/lib/orchestration/runtime.mjs +2 -0
  119. package/lib/orchestration/worker.mjs +1 -1
  120. package/lib/orchestration-policy.mjs +351 -62
  121. package/lib/overrides/resolver.mjs +1 -12
  122. package/lib/parity.mjs +37 -11
  123. package/lib/policy/engine.mjs +80 -15
  124. package/lib/prompt-composer.js +51 -15
  125. package/lib/prompt-metadata.mjs +3 -2
  126. package/lib/providers/connection-probe.mjs +58 -0
  127. package/lib/providers/copilot-auth.mjs +1 -1
  128. package/lib/providers/credential-bootstrap.mjs +1 -1
  129. package/lib/providers/op-run.mjs +3 -4
  130. package/lib/providers/secret-resolver.mjs +31 -0
  131. package/lib/publish-tooling.mjs +3 -11
  132. package/lib/publish.mjs +12 -29
  133. package/lib/reconcile/mcp-entry-reconcile.mjs +14 -9
  134. package/lib/reflect.mjs +2 -2
  135. package/lib/registry/agent-manifest.mjs +190 -0
  136. package/lib/registry/assemble.mjs +133 -0
  137. package/lib/registry/catalog.mjs +171 -0
  138. package/lib/registry/cli.mjs +590 -6
  139. package/lib/registry/consolidation.mjs +5 -4
  140. package/lib/registry/docs-sync.mjs +67 -0
  141. package/lib/registry/loader.mjs +147 -0
  142. package/lib/registry/org-io.mjs +76 -0
  143. package/lib/registry/retired-paths.mjs +71 -0
  144. package/lib/registry/surface-map.mjs +5 -7
  145. package/lib/registry/validator.mjs +438 -0
  146. package/lib/research-execution-policy.mjs +173 -0
  147. package/lib/roles/catalog.mjs +4 -9
  148. package/lib/roles/fence.mjs +107 -1
  149. package/lib/roles/flavor-bindings.mjs +68 -0
  150. package/lib/roles/gateway.mjs +140 -29
  151. package/lib/roles/manifest.mjs +22 -13
  152. package/lib/roles/router.mjs +1 -1
  153. package/lib/scopes/enrich.mjs +67 -0
  154. package/lib/scopes/hooks.mjs +12 -0
  155. package/lib/{profiles → scopes}/lifecycle.mjs +70 -70
  156. package/lib/scopes/loader.mjs +104 -0
  157. package/lib/scopes/rebrand.mjs +32 -0
  158. package/lib/scopes/research-profile.mjs +16 -0
  159. package/lib/scopes/teams.mjs +98 -0
  160. package/lib/service-manager.mjs +1 -117
  161. package/lib/setup-prompts.mjs +1 -1
  162. package/lib/setup.mjs +6 -26
  163. package/lib/skills/composition-graph.mjs +98 -0
  164. package/lib/skills/router.mjs +80 -0
  165. package/lib/specialist-contracts.mjs +17 -18
  166. package/lib/specialists/postconditions.mjs +2 -2
  167. package/lib/specialists/prompt-schema.mjs +6 -5
  168. package/lib/specialists/roster.mjs +7 -12
  169. package/lib/specialists/schema.mjs +9 -6
  170. package/lib/status.mjs +25 -90
  171. package/lib/storage/file-lock.mjs +6 -3
  172. package/lib/telemetry/skill-calls.mjs +1 -1
  173. package/lib/templates/doc-presentation.mjs +63 -0
  174. package/lib/templates/visual-requirements.mjs +35 -2
  175. package/lib/term-format.mjs +107 -2
  176. package/lib/test-env-setup.mjs +21 -0
  177. package/lib/ui/components.mjs +42 -0
  178. package/lib/ui/glyphs.mjs +58 -0
  179. package/lib/ui/links.mjs +115 -0
  180. package/lib/ui/theme.mjs +108 -0
  181. package/lib/uninstall/uninstall.mjs +2 -1
  182. package/lib/validator.mjs +45 -8
  183. package/lib/validators/skill-effectiveness.mjs +174 -0
  184. package/lib/validators/skills.mjs +1 -1
  185. package/package.json +12 -8
  186. package/personas/construct.md +12 -3
  187. package/platforms/claude/CLAUDE.md +1 -1
  188. package/rules/common/beads-hygiene.md +52 -0
  189. package/rules/common/neurodivergent-output.md +4 -7
  190. package/rules/common/research.md +2 -0
  191. package/scripts/sync-specialists.mjs +269 -51
  192. package/skills/ai/prompt-optimizer.md +3 -3
  193. package/skills/brand/output-vibe.md +48 -0
  194. package/skills/docs/adr-workflow.md +3 -0
  195. package/skills/docs/backlog-proposal-workflow.md +3 -0
  196. package/skills/docs/codebase-research-workflow.md +5 -2
  197. package/skills/docs/customer-profile-workflow.md +3 -0
  198. package/skills/docs/document-ingest-workflow.md +3 -0
  199. package/skills/docs/evidence-ingest-workflow.md +4 -1
  200. package/skills/docs/init-project.md +1 -1
  201. package/skills/docs/prd-workflow.md +1 -1
  202. package/skills/docs/prfaq-workflow.md +3 -0
  203. package/skills/docs/product-intelligence-workflow.md +4 -1
  204. package/skills/docs/product-signal-workflow.md +3 -0
  205. package/skills/docs/research-workflow.md +13 -6
  206. package/skills/docs/runbook-workflow.md +3 -0
  207. package/skills/docs/strategy-workflow.md +3 -0
  208. package/skills/docs/user-research-workflow.md +6 -3
  209. package/skills/operating/orchestration-reference.md +1 -1
  210. package/skills/roles/{engineer.ai.md → ai-engineer.md} +2 -2
  211. package/skills/roles/architect.ai-systems.md +1 -1
  212. package/skills/roles/architect.data.md +1 -1
  213. package/skills/roles/architect.enterprise.md +1 -1
  214. package/skills/roles/architect.integration.md +1 -1
  215. package/skills/roles/architect.md +1 -1
  216. package/skills/roles/architect.platform.md +1 -1
  217. package/skills/roles/{product-manager.business-strategy.md → business-strategist.md} +3 -3
  218. package/skills/roles/data-analyst.experiment.md +1 -1
  219. package/skills/roles/data-analyst.md +1 -1
  220. package/skills/roles/data-analyst.product-intelligence.md +1 -1
  221. package/skills/roles/data-analyst.product.md +1 -1
  222. package/skills/roles/data-analyst.telemetry.md +1 -1
  223. package/skills/roles/{engineer.data.md → data-engineer.md} +2 -2
  224. package/skills/roles/data-engineer.pipeline.md +2 -2
  225. package/skills/roles/data-engineer.vector-retrieval.md +2 -2
  226. package/skills/roles/data-engineer.warehouse.md +2 -2
  227. package/skills/roles/debugger.md +1 -1
  228. package/skills/roles/designer.accessibility.md +1 -1
  229. package/skills/roles/designer.md +1 -1
  230. package/skills/roles/{reviewer.devil-advocate.md → devil-advocate.md} +2 -2
  231. package/skills/roles/{operator.docs.md → docs-keeper.md} +3 -3
  232. package/skills/roles/engineer.md +3 -7
  233. package/skills/roles/{reviewer.evaluator.md → evaluator.md} +2 -2
  234. package/skills/roles/{researcher.explorer.md → explorer.md} +2 -2
  235. package/skills/roles/{operator.md → operations.md} +2 -5
  236. package/skills/roles/orchestrator.md +1 -1
  237. package/skills/roles/{engineer.platform.md → platform-engineer.md} +2 -2
  238. package/skills/roles/product-manager.ai-product.md +1 -1
  239. package/skills/roles/product-manager.enterprise.md +1 -1
  240. package/skills/roles/product-manager.growth.md +1 -2
  241. package/skills/roles/product-manager.md +1 -2
  242. package/skills/roles/product-manager.platform.md +1 -1
  243. package/skills/roles/product-manager.product.md +1 -1
  244. package/skills/roles/qa.ai-eval.md +1 -1
  245. package/skills/roles/qa.api-contract.md +1 -1
  246. package/skills/roles/qa.data-pipeline.md +1 -1
  247. package/skills/roles/qa.md +1 -1
  248. package/skills/roles/qa.web-ui.md +1 -1
  249. package/skills/roles/{operator.release.md → release-manager.md} +3 -3
  250. package/skills/roles/researcher.md +1 -1
  251. package/skills/roles/reviewer.md +1 -1
  252. package/skills/roles/security.ai.md +1 -1
  253. package/skills/roles/security.appsec.md +1 -1
  254. package/skills/roles/security.cloud.md +1 -1
  255. package/skills/roles/security.legal-compliance.md +1 -1
  256. package/skills/roles/security.md +1 -1
  257. package/skills/roles/security.privacy.md +1 -1
  258. package/skills/roles/security.supply-chain.md +1 -1
  259. package/skills/roles/{operator.sre.md → sre.md} +3 -3
  260. package/skills/roles/{qa.test-automation.md → test-automation.md} +2 -2
  261. package/skills/roles/{reviewer.trace.md → trace-reviewer.md} +2 -2
  262. package/skills/roles/{researcher.ux.md → ux-researcher.md} +2 -2
  263. package/skills/routing.json +18 -0
  264. package/skills/routing.md +1 -1
  265. package/specialists/artifact-manifest.json +2 -1
  266. package/specialists/audit-enrichments.json +14 -14
  267. package/specialists/org/contracts/accessibility-to-qa.json +37 -0
  268. package/specialists/org/contracts/any-to-business-strategist.json +57 -0
  269. package/specialists/org/contracts/any-to-debugger.json +38 -0
  270. package/specialists/org/contracts/any-to-designer.json +33 -0
  271. package/specialists/org/contracts/any-to-docs-keeper.json +34 -0
  272. package/specialists/org/contracts/any-to-explorer.json +39 -0
  273. package/specialists/org/contracts/any-to-sre-incident.json +33 -0
  274. package/specialists/org/contracts/any-to-trace-reviewer.json +32 -0
  275. package/specialists/org/contracts/architect-to-ai-engineer.json +32 -0
  276. package/specialists/org/contracts/architect-to-data-engineer.json +52 -0
  277. package/specialists/org/contracts/architect-to-devil-advocate.json +38 -0
  278. package/specialists/org/contracts/architect-to-engineer.json +34 -0
  279. package/specialists/org/contracts/architect-to-evaluator.json +59 -0
  280. package/specialists/org/contracts/architect-to-legal-compliance.json +55 -0
  281. package/specialists/org/contracts/architect-to-operations.json +45 -0
  282. package/specialists/org/contracts/architect-to-platform-engineer.json +42 -0
  283. package/specialists/org/contracts/business-strategist-to-product-manager.json +39 -0
  284. package/specialists/org/contracts/construct-to-orchestrator.json +36 -0
  285. package/specialists/org/contracts/construct-to-rd-lead.json +53 -0
  286. package/specialists/org/contracts/data-analyst-to-product-manager.json +43 -0
  287. package/specialists/org/contracts/data-engineer-to-platform-engineer.json +36 -0
  288. package/specialists/org/contracts/designer-to-accessibility.json +36 -0
  289. package/specialists/org/contracts/engineer-to-qa.json +34 -0
  290. package/specialists/org/contracts/engineer-to-reviewer.json +52 -0
  291. package/specialists/org/contracts/explorer-to-engineer.json +38 -0
  292. package/specialists/org/contracts/legal-compliance-to-release-manager.json +43 -0
  293. package/specialists/org/contracts/platform-engineer-to-engineer.json +31 -0
  294. package/specialists/org/contracts/product-manager-to-architect.json +71 -0
  295. package/specialists/org/contracts/product-manager-to-data-analyst.json +49 -0
  296. package/specialists/org/contracts/product-manager-to-ux-researcher.json +51 -0
  297. package/specialists/org/contracts/qa-to-release-manager.json +42 -0
  298. package/specialists/org/contracts/qa-to-test-automation.json +42 -0
  299. package/specialists/org/contracts/rd-lead-to-architect.json +38 -0
  300. package/specialists/org/contracts/researcher-to-architect.json +40 -0
  301. package/specialists/org/contracts/researcher-to-product-manager.json +57 -0
  302. package/specialists/org/contracts/reviewer-to-security.json +41 -0
  303. package/specialists/org/contracts/sre-to-release-manager.json +36 -0
  304. package/specialists/org/contracts/test-automation-to-engineer.json +34 -0
  305. package/specialists/org/contracts/trace-reviewer-to-sre.json +41 -0
  306. package/specialists/org/contracts/user-to-construct.json +30 -0
  307. package/specialists/org/groups/engineering-group.json +43 -0
  308. package/specialists/org/groups/governance-group.json +38 -0
  309. package/specialists/org/groups/operations-group.json +41 -0
  310. package/specialists/org/groups/product-group.json +46 -0
  311. package/specialists/org/groups/quality-group.json +42 -0
  312. package/specialists/org/groups/strategy-group.json +41 -0
  313. package/specialists/org/policies/action-approval.json +13 -0
  314. package/specialists/org/policies/agents-routing.json +13 -0
  315. package/specialists/org/policies/architecture.json +20 -0
  316. package/specialists/org/policies/bash-safety.json +13 -0
  317. package/specialists/org/policies/beads-hygiene.json +13 -0
  318. package/specialists/org/policies/bootstrap-state.json +13 -0
  319. package/specialists/org/policies/code-review.json +13 -0
  320. package/specialists/org/policies/coding-style.json +13 -0
  321. package/specialists/org/policies/comments.json +13 -0
  322. package/specialists/org/policies/commit-approval.json +13 -0
  323. package/specialists/org/policies/contract-preconditions.json +13 -0
  324. package/specialists/org/policies/deployment.json +20 -0
  325. package/specialists/org/policies/description.json +14 -0
  326. package/specialists/org/policies/design-approval.json +19 -0
  327. package/specialists/org/policies/doc-ownership.json +13 -0
  328. package/specialists/org/policies/file-path-fence.json +13 -0
  329. package/specialists/org/policies/framing.json +13 -0
  330. package/specialists/org/policies/git-workflow.json +13 -0
  331. package/specialists/org/policies/incident-response.json +15 -0
  332. package/specialists/org/policies/intake-triage.json +15 -0
  333. package/specialists/org/policies/neurodivergent-output.json +13 -0
  334. package/specialists/org/policies/no-fabrication.json +13 -0
  335. package/specialists/org/policies/patterns.json +13 -0
  336. package/specialists/org/policies/quality-gate-approval.json +17 -0
  337. package/specialists/org/policies/release-gates.json +13 -0
  338. package/specialists/org/policies/research-evidence.json +13 -0
  339. package/specialists/org/policies/review-before-change.json +13 -0
  340. package/specialists/org/policies/rollback.json +15 -0
  341. package/specialists/org/policies/scope-change.json +20 -0
  342. package/specialists/org/policies/secret-scan.json +13 -0
  343. package/specialists/org/policies/security-approval.json +17 -0
  344. package/specialists/org/policies/security.json +13 -0
  345. package/specialists/org/policies/session-efficiency.json +13 -0
  346. package/specialists/org/policies/skill-routing.json +13 -0
  347. package/specialists/org/policies/strategic-prioritization.json +17 -0
  348. package/specialists/org/policies/testing.json +13 -0
  349. package/specialists/org/policies/tool-invisibility.json +14 -0
  350. package/specialists/org/scopes/creative.json +54 -0
  351. package/specialists/org/scopes/operations.json +51 -0
  352. package/specialists/org/scopes/research.json +60 -0
  353. package/specialists/org/scopes/rnd.json +81 -0
  354. package/specialists/org/specialists/cx-accessibility.json +69 -0
  355. package/specialists/org/specialists/cx-ai-engineer.json +75 -0
  356. package/specialists/org/specialists/cx-architect.json +89 -0
  357. package/specialists/org/specialists/cx-business-strategist.json +72 -0
  358. package/specialists/org/specialists/cx-data-analyst.json +68 -0
  359. package/specialists/org/specialists/cx-data-engineer.json +71 -0
  360. package/specialists/org/specialists/cx-debugger.json +75 -0
  361. package/specialists/org/specialists/cx-designer.json +85 -0
  362. package/specialists/org/specialists/cx-devil-advocate.json +71 -0
  363. package/specialists/org/specialists/cx-docs-keeper.json +82 -0
  364. package/specialists/org/specialists/cx-engineer.json +106 -0
  365. package/specialists/org/specialists/cx-evaluator.json +69 -0
  366. package/specialists/org/specialists/cx-explorer.json +69 -0
  367. package/specialists/org/specialists/cx-legal-compliance.json +74 -0
  368. package/specialists/org/specialists/cx-operations.json +72 -0
  369. package/specialists/org/specialists/cx-oracle.json +46 -0
  370. package/specialists/org/specialists/cx-orchestrator.json +81 -0
  371. package/specialists/org/specialists/cx-platform-engineer.json +80 -0
  372. package/specialists/org/specialists/cx-product-manager.json +102 -0
  373. package/specialists/org/specialists/cx-qa.json +79 -0
  374. package/specialists/org/specialists/cx-rd-lead.json +73 -0
  375. package/specialists/org/specialists/cx-release-manager.json +77 -0
  376. package/specialists/org/specialists/cx-researcher.json +82 -0
  377. package/specialists/org/specialists/cx-reviewer.json +71 -0
  378. package/specialists/org/specialists/cx-security.json +91 -0
  379. package/specialists/org/specialists/cx-sre.json +94 -0
  380. package/specialists/org/specialists/cx-test-automation.json +69 -0
  381. package/specialists/org/specialists/cx-trace-reviewer.json +69 -0
  382. package/specialists/org/specialists/cx-ux-researcher.json +68 -0
  383. package/specialists/org/teams/accessibility-team.json +39 -0
  384. package/specialists/org/teams/design-team.json +40 -0
  385. package/specialists/org/teams/engineering-team.json +50 -0
  386. package/specialists/org/teams/governance-team.json +41 -0
  387. package/specialists/org/teams/operations-team.json +46 -0
  388. package/specialists/org/teams/product-management-team.json +45 -0
  389. package/specialists/org/teams/quality-team.json +49 -0
  390. package/specialists/org/teams/research-team.json +39 -0
  391. package/specialists/org/teams/strategy-team.json +48 -0
  392. package/specialists/org/teams/ux-research-team.json +39 -0
  393. package/specialists/prompts/_shared/validation-contract.md +1 -1
  394. package/specialists/prompts/_team-template.md +10 -0
  395. package/specialists/prompts/cx-accessibility.md +1 -0
  396. package/specialists/prompts/cx-ai-engineer.md +1 -1
  397. package/specialists/prompts/cx-business-strategist.md +1 -1
  398. package/specialists/prompts/cx-data-engineer.md +1 -1
  399. package/specialists/prompts/cx-designer.md +1 -0
  400. package/specialists/prompts/cx-devil-advocate.md +1 -1
  401. package/specialists/prompts/cx-docs-keeper.md +1 -1
  402. package/specialists/prompts/cx-evaluator.md +1 -1
  403. package/specialists/prompts/cx-explorer.md +1 -1
  404. package/specialists/prompts/cx-operations.md +1 -1
  405. package/specialists/prompts/cx-oracle.md +7 -3
  406. package/specialists/prompts/cx-orchestrator.md +17 -1
  407. package/specialists/prompts/cx-platform-engineer.md +1 -1
  408. package/specialists/prompts/cx-product-manager.md +2 -0
  409. package/specialists/prompts/cx-release-manager.md +1 -1
  410. package/specialists/prompts/cx-researcher.md +7 -4
  411. package/specialists/prompts/cx-sre.md +1 -1
  412. package/specialists/prompts/cx-test-automation.md +2 -2
  413. package/specialists/prompts/cx-trace-reviewer.md +3 -3
  414. package/specialists/prompts/cx-ux-researcher.md +2 -1
  415. package/templates/demos/scripts/architecture-review-adr.json +30 -0
  416. package/templates/demos/scripts/capability-contract.json +25 -0
  417. package/templates/demos/scripts/intake-triage.json +25 -0
  418. package/templates/demos/scripts/profile-doctor-health.json +25 -0
  419. package/templates/demos/tapes/agentic-platforms-prd.tape +2 -2
  420. package/templates/demos/tapes/architecture-review-adr.tape +44 -0
  421. package/templates/demos/tapes/capability-contract.tape +39 -0
  422. package/templates/demos/tapes/intake-triage.tape +39 -0
  423. package/templates/demos/tapes/profile-doctor-health.tape +39 -0
  424. package/templates/distribution/construct-brand.typ +23 -18
  425. package/templates/distribution/construct-decision.typ +1 -1
  426. package/templates/distribution/construct-pdf.typ +1 -1
  427. package/templates/distribution/construct-prd.typ +1 -1
  428. package/templates/distribution/construct-research.typ +1 -1
  429. package/templates/distribution/mermaid-puppeteer.json +8 -0
  430. package/templates/docs/persona-artifact.md +1 -1
  431. package/templates/docs/prd.md +6 -0
  432. package/apps/chat/engine/ai-sdk-agent.mjs +0 -183
  433. package/apps/chat/engine/loop-driver.mjs +0 -211
  434. package/apps/chat/engine/models.mjs +0 -122
  435. package/apps/chat/engine/provider-adapters.mjs +0 -171
  436. package/apps/chat/engine/tools/permission.mjs +0 -54
  437. package/apps/chat/engine/tools/primitives.mjs +0 -180
  438. package/apps/chat/engine/tools/registry.mjs +0 -122
  439. package/apps/chat/engine/turn-controls.mjs +0 -70
  440. package/lib/boundary.mjs +0 -127
  441. package/lib/certification/dashboard-api.mjs +0 -71
  442. package/lib/chat/cli.mjs +0 -333
  443. package/lib/chat/command-suggest.mjs +0 -161
  444. package/lib/chat/commands.mjs +0 -215
  445. package/lib/chat/config.mjs +0 -142
  446. package/lib/chat/context-compactor.mjs +0 -250
  447. package/lib/chat/context-continuation.mjs +0 -253
  448. package/lib/chat/continuation-source.mjs +0 -58
  449. package/lib/chat/demo-guide.mjs +0 -61
  450. package/lib/chat/design-tokens.mjs +0 -91
  451. package/lib/chat/desktop-binary.mjs +0 -81
  452. package/lib/chat/desktop-build.mjs +0 -130
  453. package/lib/chat/desktop-launcher.mjs +0 -133
  454. package/lib/chat/evidence.mjs +0 -145
  455. package/lib/chat/export.mjs +0 -74
  456. package/lib/chat/harness/driver.mjs +0 -91
  457. package/lib/chat/list-picker.mjs +0 -112
  458. package/lib/chat/model-picker.mjs +0 -356
  459. package/lib/chat/openrouter-fallback.mjs +0 -151
  460. package/lib/chat/permission-prompt.mjs +0 -33
  461. package/lib/chat/picker-catalog.mjs +0 -45
  462. package/lib/chat/policy-telemetry.mjs +0 -34
  463. package/lib/chat/present.mjs +0 -246
  464. package/lib/chat/session-context.mjs +0 -39
  465. package/lib/chat/session-persist.mjs +0 -73
  466. package/lib/chat/session-restore.mjs +0 -71
  467. package/lib/chat/session-settings.mjs +0 -53
  468. package/lib/chat/system-prompt.mjs +0 -52
  469. package/lib/chat/transparency.mjs +0 -93
  470. package/lib/chat/tui/color-scheme.mjs +0 -42
  471. package/lib/chat/tui/markdown.mjs +0 -123
  472. package/lib/chat/tui/presentation.mjs +0 -100
  473. package/lib/chat/tui/render.mjs +0 -500
  474. package/lib/chat/tui/turn-block.mjs +0 -284
  475. package/lib/chat/tui/turn-present.mjs +0 -18
  476. package/lib/chat/tui/turn-state.mjs +0 -88
  477. package/lib/chat/tui/usage.mjs +0 -122
  478. package/lib/chat/web-commands.mjs +0 -146
  479. package/lib/chat/web-launcher.mjs +0 -63
  480. package/lib/chat/web-picker-keys.mjs +0 -46
  481. package/lib/chat/web-session.mjs +0 -159
  482. package/lib/config/alias.mjs +0 -57
  483. package/lib/dashboard-demo.mjs +0 -71
  484. package/lib/dashboard-static.mjs +0 -175
  485. package/lib/install/desktop-binary-download.mjs +0 -88
  486. package/lib/profiles/loader.mjs +0 -123
  487. package/lib/profiles/rebrand.mjs +0 -46
  488. package/lib/server/auth.mjs +0 -169
  489. package/lib/server/chat-loop.mjs +0 -622
  490. package/lib/server/chat.mjs +0 -336
  491. package/lib/server/cors.mjs +0 -77
  492. package/lib/server/csrf.mjs +0 -103
  493. package/lib/server/demo-preview.mjs +0 -63
  494. package/lib/server/index.mjs +0 -2641
  495. package/lib/server/insights.mjs +0 -780
  496. package/lib/server/langfuse-login.mjs +0 -58
  497. package/lib/server/rate-limit.mjs +0 -93
  498. package/lib/server/telemetry-login.mjs +0 -100
  499. package/lib/server/webhook.mjs +0 -512
  500. package/specialists/contracts.json +0 -1032
  501. package/specialists/contracts.schema.json +0 -83
  502. package/specialists/policy-inventory.json +0 -188
  503. package/specialists/registry.json +0 -1412
  504. package/specialists/role-manifests.json +0 -217
  505. package/specialists/teams.json +0 -94
package/lib/demo.mjs CHANGED
@@ -2,19 +2,23 @@
2
2
  * lib/demo.mjs — `construct demo` terminal recordings via VHS `.tape` files.
3
3
  *
4
4
  * Shipped tapes live in templates/demos/tapes/; project overrides in
5
- * .cx/demos/tapes/. Built-in scaffolds via `construct demo init --from=`.
6
- * Default run mode launches construct chat with a demo script; use `record` or
7
- * --surface=tape for VHS. Dashboard demos delegate to lib/dashboard-demo.mjs.
5
+ * .cx/demos/tapes/. Built-in scaffolds via `construct demo init --from=`;
6
+ * `--from-project` scaffolds a project demo plug-in (manifest + script + tape)
7
+ * under .cx/demos/ seeded from real project signals (see lib/demo-project.mjs).
8
+ * Default run mode writes or records a VHS tape; use `tour` for a linear
9
+ * guided walkthrough and `--surface=playwright` for recording manifests.
8
10
  */
9
11
 
10
12
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
11
13
  import { spawnSync } from 'node:child_process';
12
14
  import { join, resolve, dirname, basename, relative } from 'node:path';
13
15
  import { fileURLToPath } from 'node:url';
14
- import { listDemoScripts } from './demo-script.mjs';
16
+ import { listDemoScripts, loadDemoScript } from './demo-script.mjs';
15
17
  import { DEMO_SURFACES } from './demo-surface.mjs';
18
+ import { renderTour } from './demo-tour-renderer.mjs';
16
19
  import { listDemoRecordings, loadDemoRecording } from './demo-recording.mjs';
17
20
  import { recordPlaywrightDemo } from './playwright-demo.mjs';
21
+ import { scaffoldProjectDemo } from './demo-project.mjs';
18
22
 
19
23
  const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
20
24
 
@@ -219,7 +223,7 @@ export function initConstructCockpitRecording(name, { cwd, repoRoot = REPO_ROOT
219
223
  ...reference,
220
224
  name,
221
225
  title: reference.title,
222
- output: { format: 'mp4', path: `.cx/demos/dashboard/${name}.mp4` },
226
+ output: { format: 'mp4', path: `.cx/demos/${name}.mp4` },
223
227
  _reference: 'agentic-platforms-prd',
224
228
  };
225
229
  delete recording.sourcePath;
@@ -228,7 +232,7 @@ export function initConstructCockpitRecording(name, { cwd, repoRoot = REPO_ROOT
228
232
  return {
229
233
  ok: true,
230
234
  recordingPath: recPath,
231
- message: `Scaffolded Construct cockpit recording ${recPath} (references apps/dashboard spec)`,
235
+ message: `Scaffolded Construct cockpit recording ${recPath}`,
232
236
  };
233
237
  }
234
238
 
@@ -306,10 +310,6 @@ export function listProjectTapes({ cwd = process.cwd(), repoRoot = REPO_ROOT } =
306
310
  }
307
311
 
308
312
  export function resolveTapeSource(name, { cwd, repoRoot = REPO_ROOT, artifactPath } = {}) {
309
- if (name.startsWith('dashboard:')) {
310
- return { kind: 'dashboard', name: name.slice('dashboard:'.length) };
311
- }
312
-
313
313
  const tapePath = resolveTapeFile(name, { cwd, repoRoot });
314
314
  if (tapePath) {
315
315
  let source = readFileSync(tapePath, 'utf8');
@@ -402,10 +402,6 @@ export function runDemoRecord(name, {
402
402
  required = false,
403
403
  surface = null,
404
404
  } = {}) {
405
- if (name.startsWith('dashboard:')) {
406
- return { ok: false, name, message: 'Use recordDashboardDemo for dashboard: demos' };
407
- }
408
-
409
405
  const recording = loadDemoRecording(name, { cwd, repoRoot });
410
406
  const usePlaywright = surface !== 'tape'
411
407
  && (surface === 'playwright' || (recording && recording.engine === 'playwright'));
@@ -506,28 +502,28 @@ export function printHelp() {
506
502
  Commands:
507
503
  list List tapes, recordings, and demo scripts
508
504
  init <name> [--from=T] Scaffold tape or Playwright recording
505
+ init <name> --from-project Scaffold a project demo plug-in under .cx/demos/
509
506
  record <name> Record VHS tape or Playwright demo manifest
510
- <name> Run guided demo (default: construct chat)
507
+ tour [name] Linear, screen-reader-friendly guided tour
508
+ <name> Record or print the demo (default: tape)
511
509
 
512
- Default run uses construct chat with a demo script (templates/demos/scripts/).
513
- Falls back to web chat, VHS tape, Playwright, dashboard, or printed steps.
510
+ Default run uses VHS tape templates and falls back to printed script steps.
514
511
 
515
512
  Options:
516
513
  --surface=<s> ${surfaces}
517
- --model <id> Pin model for chat demo
518
- --web Open web chat (/chat/) instead of terminal
519
- --plain Linear chat renderer
520
- --free OpenRouter free-router mode
514
+ --accessible Screen-reader-friendly linear renderer (tour)
515
+ --skip-input Tour: auto-advance without waiting for Enter (headless/CI)
521
516
  --format <f> gif (default) | mp4 | webm
522
517
  --out <path> Output path (recording)
518
+ --from-project init: scaffold a project demo plug-in under .cx/demos/
523
519
  --source-only Tape: write .tape only; skip recording
524
520
  -h, --help Show this message
525
521
 
526
522
  Examples:
527
523
  construct demo agentic-platforms-prd
524
+ construct demo tour agentic-platforms-prd --accessible
528
525
  construct demo record agentic-platforms-prd --format mp4
529
526
  construct demo init marketing --from=nextjs-static
530
- construct demo dashboard:cockpit-tour
531
527
  `);
532
528
  }
533
529
 
@@ -539,22 +535,19 @@ function parseArgs(argv) {
539
535
  from: 'quickstart',
540
536
  command: null,
541
537
  name: null,
542
- surface: 'chat',
543
- model: null,
544
- plain: false,
538
+ surface: 'tape',
545
539
  accessible: false,
546
- web: false,
547
- free: false,
540
+ skipInput: false,
541
+ fromProject: false,
548
542
  };
549
543
  const positional = [];
550
544
  for (let i = 0; i < argv.length; i += 1) {
551
545
  const arg = argv[i];
552
546
  if (arg === '--help' || arg === '-h') { options.help = true; continue; }
547
+ if (arg === '--from-project') { options.fromProject = true; continue; }
553
548
  if (arg === '--source-only') { options.sourceOnly = true; continue; }
554
- if (arg === '--plain') { options.plain = true; continue; }
555
549
  if (arg === '--accessible') { options.accessible = true; continue; }
556
- if (arg === '--web') { options.web = true; continue; }
557
- if (arg === '--free') { options.free = true; continue; }
550
+ if (arg === '--skip-input') { options.skipInput = true; continue; }
558
551
  if (arg === '--format') { options.format = argv[++i]; continue; }
559
552
  if (arg.startsWith('--format=')) { options.format = arg.slice(9); continue; }
560
553
  if (arg === '--out') { options.out = argv[++i]; continue; }
@@ -563,13 +556,12 @@ function parseArgs(argv) {
563
556
  if (arg.startsWith('--from=')) { options.from = arg.slice(7); continue; }
564
557
  if (arg === '--surface') { options.surface = argv[++i]; continue; }
565
558
  if (arg.startsWith('--surface=')) { options.surface = arg.slice(10); continue; }
566
- if (arg === '--model') { options.model = argv[++i]; continue; }
567
- if (arg.startsWith('--model=')) { options.model = arg.slice(8); continue; }
568
559
  positional.push(arg);
569
560
  }
570
561
  if (positional[0] === 'list') options.command = 'list';
571
562
  else if (positional[0] === 'init') { options.command = 'init'; options.name = positional[1]; }
572
563
  else if (positional[0] === 'record') { options.command = 'record'; options.name = positional[1]; }
564
+ else if (positional[0] === 'tour') { options.command = 'tour'; options.name = positional[1] || null; }
573
565
  else options.name = positional[0] || null;
574
566
  return options;
575
567
  }
@@ -591,7 +583,7 @@ export async function runDemoCli(argv = [], { cwd = process.cwd(), repoRoot } =
591
583
  console.log('\nPlaywright recordings (.cx/demos/recordings/ overrides templates/demos/recordings/):');
592
584
  if (!recordings.length) console.log(' (none — run `construct demo init <name> --from=nextjs-static`)');
593
585
  else for (const r of recordings) console.log(` ${r}`);
594
- console.log('\nDemo scripts (chat-guided; templates/demos/scripts/):');
586
+ console.log('\nDemo scripts (tour steps; templates/demos/scripts/):');
595
587
  if (!scripts.length) console.log(' (none)');
596
588
  else for (const s of scripts) console.log(` ${s}`);
597
589
  console.log(`\nScaffold templates: ${RECORDING_INIT_TEMPLATES.join(', ')}`);
@@ -599,8 +591,21 @@ export async function runDemoCli(argv = [], { cwd = process.cwd(), repoRoot } =
599
591
  }
600
592
 
601
593
  if (options.command === 'init') {
594
+ if (options.fromProject) {
595
+ if (!options.name) {
596
+ console.error('Usage: construct demo init <name> --from-project');
597
+ process.exit(1);
598
+ }
599
+ const result = scaffoldProjectDemo(options.name, { cwd, repoRoot });
600
+ if (!result.ok) {
601
+ console.error(result.message);
602
+ process.exit(1);
603
+ }
604
+ console.log(result.message);
605
+ return;
606
+ }
602
607
  if (!options.name) {
603
- console.error(`Usage: construct demo init <name> [--from=${RECORDING_INIT_TEMPLATES.join('|')}]`);
608
+ console.error(`Usage: construct demo init <name> [--from=${RECORDING_INIT_TEMPLATES.join('|')}] | --from-project`);
604
609
  process.exit(1);
605
610
  }
606
611
  const result = initProjectRecording(options.name, { cwd, from: options.from, repoRoot });
@@ -612,28 +617,45 @@ export async function runDemoCli(argv = [], { cwd = process.cwd(), repoRoot } =
612
617
  return;
613
618
  }
614
619
 
615
- const demoName = options.command === 'record' ? options.name : options.name;
616
- if (!demoName) {
617
- printHelp();
618
- process.exit(1);
619
- }
620
-
621
- if (demoName.startsWith('dashboard:')) {
622
- const { recordDashboardDemo } = await import('./dashboard-demo.mjs');
623
- const result = recordDashboardDemo(demoName.slice('dashboard:'.length), { cwd, repoRoot });
620
+ if (options.command === 'tour') {
621
+ const scripts = listDemoScripts({ cwd, repoRoot });
622
+ const tourName = options.name || scripts[0] || null;
623
+ if (!tourName) {
624
+ console.error('No demo scripts found. Add one under templates/demos/scripts/ or .cx/demos/scripts/.');
625
+ process.exit(1);
626
+ }
627
+ const script = loadDemoScript(tourName, { cwd, repoRoot });
628
+ if (!script) {
629
+ console.error(`Unknown demo: ${tourName}. Run \`construct demo list\` to see available scripts.`);
630
+ process.exit(1);
631
+ }
632
+ // A non-TTY stdout (pipe, file, CI) advances on its own even without --skip-input.
633
+ const skipInput = options.skipInput || !process.stdout.isTTY;
634
+ const result = await renderTour({
635
+ script,
636
+ output: process.stdout,
637
+ input: process.stdin,
638
+ env: process.env,
639
+ accessible: options.accessible,
640
+ skipInput,
641
+ });
624
642
  if (!result.ok) {
625
643
  console.error(result.message);
626
- process.exit(result.missing?.length ? 2 : 1);
644
+ process.exit(1);
627
645
  }
628
- console.log(result.message);
629
- for (const v of result.videos || []) console.log(` ${v}`);
630
646
  return;
631
647
  }
632
648
 
649
+ const demoName = options.command === 'record' ? options.name : options.name;
650
+ if (!demoName) {
651
+ printHelp();
652
+ process.exit(1);
653
+ }
654
+
633
655
  const preferPlaywright = options.surface === 'playwright'
634
656
  || (options.command === 'record' && loadDemoRecording(demoName, { cwd, repoRoot })?.engine === 'playwright');
635
657
  const useTape = options.surface === 'tape'
636
- || (options.command === 'record' && !preferPlaywright && options.surface !== 'dashboard');
658
+ || (options.command === 'record' && !preferPlaywright);
637
659
  if (useTape || (options.command === 'record' && preferPlaywright)) {
638
660
  const result = runDemoRecord(demoName, {
639
661
  cwd,
@@ -669,11 +691,7 @@ export async function runDemoCli(argv = [], { cwd = process.cwd(), repoRoot } =
669
691
  format: options.format,
670
692
  out: options.out,
671
693
  sourceOnly: options.sourceOnly,
672
- model: options.model,
673
- plain: options.plain,
674
694
  accessible: options.accessible,
675
- web: options.web,
676
- free: options.free,
677
695
  });
678
696
 
679
697
  if (!result.ok) {
@@ -684,9 +702,6 @@ export async function runDemoCli(argv = [], { cwd = process.cwd(), repoRoot } =
684
702
  if (result.notices?.length) {
685
703
  for (const n of result.notices) console.error(`note: ${n}`);
686
704
  }
687
- if (result.surface === 'chat' || result.surface === 'web') {
688
- return;
689
- }
690
705
  if (result.artifactPath) {
691
706
  console.log(`Demo (${demoName}) [${result.surface}] recorded to:`);
692
707
  console.log(` ${result.artifactPath}`);
@@ -14,6 +14,7 @@ import { fileURLToPath } from 'node:url';
14
14
 
15
15
  const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
16
16
  const ICON_DIR = path.join(REPO_ROOT, 'templates', 'distribution', 'icons');
17
+ const MERMAID_PPTR_CONFIG = path.join(REPO_ROOT, 'templates', 'distribution', 'mermaid-puppeteer.json');
17
18
 
18
19
  // Monochrome diagram palette, mirroring the ink ramp in construct-brand.typ so
19
20
  // embedded diagrams and surrounding body share one design language.
@@ -36,9 +37,9 @@ export const DISTRIBUTION_D2_SCALE = '0.72';
36
37
  export const DISTRIBUTION_D2_SKETCH = '1';
37
38
  export const DISTRIBUTION_D2_FONT_SIZE = '14';
38
39
  export const DISTRIBUTION_MERMAID_MIME = 'image/png';
39
- export const DISTRIBUTION_MERMAID_WIDTH = '480';
40
- export const DISTRIBUTION_MERMAID_SCALE = '1';
41
- export const DISTRIBUTION_FIGURE_MAX_WIDTH = '58%';
40
+ export const DISTRIBUTION_MERMAID_WIDTH = '2400';
41
+ export const DISTRIBUTION_MERMAID_SCALE = '2';
42
+ export const DISTRIBUTION_FIGURE_MAX_WIDTH = '92%';
42
43
 
43
44
  // Handwritten font for Mermaid labels so its hand-drawn look matches D2 sketch
44
45
  // mode. Caveat ships bundled (templates/distribution/fonts/handwritten) and is
@@ -51,6 +52,9 @@ const MERMAID_INIT = `%%{init: {
51
52
  'theme': 'base',
52
53
  'look': 'handDrawn',
53
54
  'fontFamily': '${MERMAID_FONT}',
55
+ 'flowchart': {
56
+ 'htmlLabels': false
57
+ },
54
58
  'themeVariables': {
55
59
  'fontFamily': '${MERMAID_FONT}',
56
60
  'fontSize': '19px',
@@ -86,17 +90,8 @@ const MERMAID_INIT = `%%{init: {
86
90
  }
87
91
  }}%%`;
88
92
 
89
- const CHROME_CANDIDATES = [
90
- '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
91
- '/Applications/Chromium.app/Contents/MacOS/Chromium',
92
- '/usr/bin/google-chrome',
93
- '/usr/bin/chromium',
94
- '/usr/bin/chromium-browser',
95
- ];
96
-
97
- export function resolvePuppeteerExecutable(env = process.env) {
98
- if (env.PUPPETEER_EXECUTABLE_PATH) return env.PUPPETEER_EXECUTABLE_PATH;
99
- for (const candidate of CHROME_CANDIDATES) {
93
+ function firstExistingPath(paths = []) {
94
+ for (const candidate of paths) {
100
95
  try {
101
96
  if (fs.existsSync(candidate)) return candidate;
102
97
  } catch {
@@ -106,6 +101,59 @@ export function resolvePuppeteerExecutable(env = process.env) {
106
101
  return null;
107
102
  }
108
103
 
104
+ function playwrightChromeCandidates(home = process.env.HOME || '') {
105
+ if (!home) return [];
106
+ const cacheRoot = path.join(home, 'Library', 'Caches', 'ms-playwright');
107
+ let entries = [];
108
+ try {
109
+ entries = fs.readdirSync(cacheRoot, { withFileTypes: true });
110
+ } catch {
111
+ return [];
112
+ }
113
+ entries = entries
114
+ .filter((entry) => entry.isDirectory())
115
+ .sort((a, b) => {
116
+ const aHeadless = a.name.startsWith('chromium_headless_shell-') ? 0 : 1;
117
+ const bHeadless = b.name.startsWith('chromium_headless_shell-') ? 0 : 1;
118
+ if (aHeadless !== bHeadless) return aHeadless - bHeadless;
119
+ const aVer = Number((a.name.match(/-(\d+)/) || [])[1] || 0);
120
+ const bVer = Number((b.name.match(/-(\d+)/) || [])[1] || 0);
121
+ return bVer - aVer;
122
+ });
123
+ const candidates = [];
124
+ for (const entry of entries) {
125
+ const base = path.join(cacheRoot, entry.name);
126
+ if (entry.name.startsWith('chromium_headless_shell-')) {
127
+ candidates.push(path.join(base, 'chrome-headless-shell-mac-arm64', 'chrome-headless-shell'));
128
+ candidates.push(path.join(base, 'chrome-headless-shell-mac', 'chrome-headless-shell'));
129
+ }
130
+ if (entry.name.startsWith('chromium-')) {
131
+ candidates.push(path.join(base, 'chrome-mac-arm64', 'Chromium.app', 'Contents', 'MacOS', 'Chromium'));
132
+ candidates.push(path.join(base, 'chrome-mac-arm64', 'chrome'));
133
+ candidates.push(path.join(base, 'chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium'));
134
+ candidates.push(path.join(base, 'chrome-mac', 'chrome'));
135
+ }
136
+ }
137
+ return candidates;
138
+ }
139
+
140
+ function chromeCandidates(env = process.env) {
141
+ return [
142
+ ...playwrightChromeCandidates(env.HOME),
143
+ '/Applications/Chromium.app/Contents/MacOS/Chromium',
144
+ '/Applications/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing',
145
+ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
146
+ '/usr/bin/google-chrome',
147
+ '/usr/bin/chromium',
148
+ '/usr/bin/chromium-browser',
149
+ ];
150
+ }
151
+
152
+ export function resolvePuppeteerExecutable(env = process.env) {
153
+ if (env.PUPPETEER_EXECUTABLE_PATH) return env.PUPPETEER_EXECUTABLE_PATH;
154
+ return firstExistingPath(chromeCandidates(env));
155
+ }
156
+
109
157
  export function injectMermaidBrandTheme(code) {
110
158
  const body = String(code || '').trim();
111
159
  if (!body) return body;
@@ -170,6 +218,7 @@ export function buildDistributionDiagramEnv(baseEnv = process.env) {
170
218
  CONSTRUCT_MERMAID_WIDTH: DISTRIBUTION_MERMAID_WIDTH,
171
219
  CONSTRUCT_MERMAID_SCALE: DISTRIBUTION_MERMAID_SCALE,
172
220
  };
221
+ if (fs.existsSync(MERMAID_PPTR_CONFIG)) env.CONSTRUCT_MERMAID_PPTR_CONFIG = MERMAID_PPTR_CONFIG;
173
222
  const chrome = resolvePuppeteerExecutable(baseEnv);
174
223
  if (chrome) env.PUPPETEER_EXECUTABLE_PATH = chrome;
175
224
  return env;
@@ -101,16 +101,26 @@ export async function runCli(args) {
101
101
  }
102
102
 
103
103
  if (sub === 'consistency') {
104
+ const strict = args.some((a) => a === '--strict' || a === '--all' || a === '--debug');
104
105
  const { runAllChecks } = await import('./watchers/consistency.mjs');
105
106
  const result = await runAllChecks();
106
107
  const blocking = result.findings.filter((f) => f.severity === 'blocking');
107
108
  const warnings = result.findings.filter((f) => f.severity === 'warning');
108
109
 
110
+ // Default output carries only user-actionable signal; package/maintainer drift
111
+ // (tier 'internal') is gated behind --strict so a clean install reads clean.
112
+
113
+ const visibleWarnings = strict ? warnings : warnings.filter((f) => f.tier !== 'internal');
114
+ const internalWarnings = warnings.filter((f) => f.tier === 'internal');
115
+
109
116
  for (const p of result.passed) console.log(` ✓ ${p.category.padEnd(18)} ${p.summary}`);
110
- for (const w of warnings) console.log(` ⚠ ${w.category.padEnd(18)} ${w.summary}`);
117
+ for (const w of visibleWarnings) console.log(` ⚠ ${w.category.padEnd(18)} ${w.summary}`);
111
118
  for (const b of blocking) console.log(` ✗ ${b.category.padEnd(18)} ${b.summary}`);
112
119
 
113
- console.log(`\n${result.passed.length} category(s) clean, ${warnings.length} warning(s), ${blocking.length} blocking finding(s)`);
120
+ console.log(`\n${result.passed.length} category(s) clean, ${visibleWarnings.length} warning(s), ${blocking.length} blocking finding(s)`);
121
+ if (!strict && internalWarnings.length > 0) {
122
+ console.log(` (+${internalWarnings.length} package-internal diagnostic(s) — run \`construct doctor consistency --strict\` to view)`);
123
+ }
114
124
  return blocking.length > 0 ? 1 : 0;
115
125
  }
116
126
 
@@ -2,8 +2,8 @@
2
2
  * lib/doctor/source-checkout.mjs — distinguish Construct source tree vs npm install.
3
3
  *
4
4
  * `isConstructPackageRepo` is true for both checkouts and consumer installs.
5
- * Source-only doctor checks (dashboard static export, certification role cards)
6
- * should run only when this returns true.
5
+ * Source-only doctor checks (certification role cards) should run only when this
6
+ * returns true.
7
7
  */
8
8
 
9
9
  import fs from 'node:fs';
@@ -11,6 +11,5 @@ import path from 'node:path';
11
11
 
12
12
  export function isConstructSourceCheckout(rootDir) {
13
13
  const root = path.resolve(rootDir);
14
- return fs.existsSync(path.join(root, 'apps', 'dashboard'))
15
- || fs.existsSync(path.join(root, 'tests', 'certification', 'specialists'));
14
+ return fs.existsSync(path.join(root, 'tests', 'certification', 'specialists'));
16
15
  }