@geraldmaron/construct 1.2.2 → 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 (497) hide show
  1. package/README.md +7 -10
  2. package/bin/construct +286 -220
  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 +56 -57
  28. package/lib/comment-lint.mjs +1 -5
  29. package/lib/completions.mjs +20 -2
  30. package/lib/config/legacy-config-migration.mjs +125 -0
  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/runtime-env.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 +17 -28
  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 -7
  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 +260 -49
  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/lib/boundary.mjs +0 -127
  433. package/lib/certification/dashboard-api.mjs +0 -71
  434. package/lib/chat/cli.mjs +0 -333
  435. package/lib/chat/command-suggest.mjs +0 -161
  436. package/lib/chat/commands.mjs +0 -215
  437. package/lib/chat/config.mjs +0 -142
  438. package/lib/chat/context-compactor.mjs +0 -250
  439. package/lib/chat/context-continuation.mjs +0 -253
  440. package/lib/chat/continuation-source.mjs +0 -58
  441. package/lib/chat/demo-guide.mjs +0 -61
  442. package/lib/chat/design-tokens.mjs +0 -91
  443. package/lib/chat/desktop-binary.mjs +0 -81
  444. package/lib/chat/desktop-build.mjs +0 -130
  445. package/lib/chat/desktop-launcher.mjs +0 -133
  446. package/lib/chat/evidence.mjs +0 -145
  447. package/lib/chat/export.mjs +0 -74
  448. package/lib/chat/harness/driver.mjs +0 -91
  449. package/lib/chat/list-picker.mjs +0 -112
  450. package/lib/chat/model-picker.mjs +0 -356
  451. package/lib/chat/openrouter-fallback.mjs +0 -151
  452. package/lib/chat/permission-prompt.mjs +0 -33
  453. package/lib/chat/picker-catalog.mjs +0 -45
  454. package/lib/chat/policy-telemetry.mjs +0 -34
  455. package/lib/chat/present.mjs +0 -246
  456. package/lib/chat/session-context.mjs +0 -39
  457. package/lib/chat/session-persist.mjs +0 -73
  458. package/lib/chat/session-restore.mjs +0 -71
  459. package/lib/chat/session-settings.mjs +0 -53
  460. package/lib/chat/system-prompt.mjs +0 -52
  461. package/lib/chat/transparency.mjs +0 -93
  462. package/lib/chat/tui/color-scheme.mjs +0 -42
  463. package/lib/chat/tui/markdown.mjs +0 -123
  464. package/lib/chat/tui/presentation.mjs +0 -100
  465. package/lib/chat/tui/render.mjs +0 -500
  466. package/lib/chat/tui/turn-block.mjs +0 -284
  467. package/lib/chat/tui/turn-present.mjs +0 -18
  468. package/lib/chat/tui/turn-state.mjs +0 -88
  469. package/lib/chat/tui/usage.mjs +0 -122
  470. package/lib/chat/web-commands.mjs +0 -146
  471. package/lib/chat/web-launcher.mjs +0 -63
  472. package/lib/chat/web-picker-keys.mjs +0 -46
  473. package/lib/chat/web-session.mjs +0 -159
  474. package/lib/config/alias.mjs +0 -57
  475. package/lib/dashboard-demo.mjs +0 -71
  476. package/lib/dashboard-static.mjs +0 -175
  477. package/lib/install/desktop-binary-download.mjs +0 -88
  478. package/lib/profiles/loader.mjs +0 -123
  479. package/lib/profiles/rebrand.mjs +0 -46
  480. package/lib/server/auth.mjs +0 -169
  481. package/lib/server/chat-loop.mjs +0 -622
  482. package/lib/server/chat.mjs +0 -336
  483. package/lib/server/cors.mjs +0 -77
  484. package/lib/server/csrf.mjs +0 -103
  485. package/lib/server/demo-preview.mjs +0 -63
  486. package/lib/server/index.mjs +0 -2641
  487. package/lib/server/insights.mjs +0 -780
  488. package/lib/server/langfuse-login.mjs +0 -58
  489. package/lib/server/rate-limit.mjs +0 -93
  490. package/lib/server/telemetry-login.mjs +0 -100
  491. package/lib/server/webhook.mjs +0 -512
  492. package/specialists/contracts.json +0 -1032
  493. package/specialists/contracts.schema.json +0 -83
  494. package/specialists/policy-inventory.json +0 -188
  495. package/specialists/registry.json +0 -1412
  496. package/specialists/role-manifests.json +0 -217
  497. package/specialists/teams.json +0 -94
@@ -1,253 +0,0 @@
1
- /**
2
- * lib/chat/context-continuation.mjs — the deterministic context-continuation
3
- * contract (construct-6zga.1.9).
4
- *
5
- * A chat session's context is an ordered set of layers — static instructions,
6
- * role guidance, the task packet, validated evidence, tool results, the
7
- * conversation summary, optional learned patterns, plus the protected state
8
- * (user constraints, approvals, unresolved blockers). When context pressure
9
- * crosses the capability profile's compaction trigger (the execution policy's
10
- * continuation budget, never a model-name fixed limit), the session must compact
11
- * without silent loss: it produces a structured continuation packet that retains
12
- * required state verbatim, references reconstructible layers by source id for
13
- * re-derivation, elides compactible layers with a truthful marker, and — when the
14
- * required state alone exceeds the budget — yields a user-visible blocker instead
15
- * of dropping anything. The packet carries source ids and token accounting so a
16
- * reader can re-verify it, and rehydrateContinuation feeds the same layer set back
17
- * through the composer on every surface. Reference shape:
18
- * schemas/continuation-packet.schema.json.
19
- */
20
-
21
- export const CONTINUATION_PACKET_SCHEMA_VERSION = 1;
22
-
23
- export const CONTEXT_LAYER_KINDS = Object.freeze([
24
- 'static-instructions',
25
- 'role-guidance',
26
- 'task-packet',
27
- 'validated-evidence',
28
- 'tool-results',
29
- 'conversation-summary',
30
- 'learned-patterns',
31
- 'user-constraints',
32
- 'approvals',
33
- 'blockers',
34
- ]);
35
-
36
- export const COMPACTION_ELIGIBILITY = Object.freeze(['required', 'reconstructible', 'compactible']);
37
-
38
- export const LAYER_DISPOSITIONS = Object.freeze(['retained', 'referenced', 'elided']);
39
-
40
- // The protected layers carry state the loop must never silently drop: user
41
- // constraints, approvals, the current task packet, evidence provenance, and
42
- // unresolved blockers. Reconstructible layers can be re-derived from a durable
43
- // source by id, so the packet references rather than stores them. Compactible
44
- // layers are conversation history that compacts lossily but is never silently
45
- // lost — an elided one keeps a truthful marker of what was removed.
46
-
47
- const DEFAULT_ELIGIBILITY = Object.freeze({
48
- 'user-constraints': 'required',
49
- approvals: 'required',
50
- 'task-packet': 'required',
51
- 'validated-evidence': 'required',
52
- blockers: 'required',
53
- 'static-instructions': 'reconstructible',
54
- 'role-guidance': 'reconstructible',
55
- 'learned-patterns': 'reconstructible',
56
- 'conversation-summary': 'compactible',
57
- 'tool-results': 'compactible',
58
- });
59
-
60
- function estimateTextTokens(text) {
61
- return Math.ceil(String(text || '').length / 4);
62
- }
63
-
64
- function sumTokens(layers) {
65
- return layers.reduce((total, l) => total + (Number.isFinite(l.tokens) ? l.tokens : 0), 0);
66
- }
67
-
68
- /**
69
- * Normalize a raw layer set into a deterministic inventory: assign each layer an
70
- * id, a known kind, its compaction eligibility (explicit or kind-defaulted), and a
71
- * token count. Order is preserved so callers control retention priority.
72
- */
73
- export function classifyContextLayers(layers = [], { estimateTokens = estimateTextTokens } = {}) {
74
- const list = Array.isArray(layers) ? layers : [];
75
- return list.map((raw, index) => {
76
- const kind = CONTEXT_LAYER_KINDS.includes(raw?.kind) ? raw.kind : 'conversation-summary';
77
- const eligibility = COMPACTION_ELIGIBILITY.includes(raw?.eligibility)
78
- ? raw.eligibility
79
- : (DEFAULT_ELIGIBILITY[kind] || 'compactible');
80
- const content = typeof raw?.content === 'string' ? raw.content : '';
81
- const tokens = Number.isFinite(raw?.tokens) ? raw.tokens : estimateTokens(content);
82
- return {
83
- id: raw?.id || `${kind}-${index}`,
84
- kind,
85
- eligibility,
86
- sourceId: raw?.sourceId ?? null,
87
- tokens,
88
- content,
89
- };
90
- });
91
- }
92
-
93
- function retainedLayer(layer) {
94
- return { id: layer.id, kind: layer.kind, eligibility: layer.eligibility, disposition: 'retained', tokens: layer.tokens, sourceId: layer.sourceId, content: layer.content };
95
- }
96
-
97
- function referencedLayer(layer) {
98
- return { id: layer.id, kind: layer.kind, eligibility: layer.eligibility, disposition: 'referenced', tokens: layer.tokens, sourceId: layer.sourceId, content: null };
99
- }
100
-
101
- function elidedLayer(layer) {
102
- return { id: layer.id, kind: layer.kind, eligibility: layer.eligibility, disposition: 'elided', tokens: layer.tokens, sourceId: layer.sourceId, content: null };
103
- }
104
-
105
- /**
106
- * Compact a classified inventory to the continuation budget. Required layers are
107
- * retained verbatim; a reconstructible layer with a source id is referenced for
108
- * re-derivation (and costs no budget), while one without a source id falls back to
109
- * the compactible pool so it is never lost. Compactible layers fill the remaining
110
- * budget in order and are elided with a marker once it is spent. When the required
111
- * state alone exceeds the budget the result is a truthful blocker — nothing is
112
- * dropped to make room for it.
113
- */
114
- export function compactContext(inventory = [], { triggerTokens = null } = {}) {
115
- const layers = classifyContextLayers(inventory);
116
- const required = layers.filter((l) => l.eligibility === 'required');
117
- const reconstructible = layers.filter((l) => l.eligibility === 'reconstructible');
118
- const compactible = layers.filter((l) => l.eligibility === 'compactible');
119
-
120
- const requiredTokens = sumTokens(required);
121
- const budget = Number.isFinite(triggerTokens) && triggerTokens > 0 ? triggerTokens : Infinity;
122
-
123
- const referenced = [];
124
- const pressurePool = [...compactible];
125
- for (const layer of reconstructible) {
126
- if (layer.sourceId) referenced.push(referencedLayer(layer));
127
- else pressurePool.push(layer);
128
- }
129
-
130
- const blocked = requiredTokens > budget;
131
- const blocker = blocked
132
- ? { reason: 'required-state-exceeds-budget', requiredTokens, budgetTokens: budget, overflowTokens: requiredTokens - budget }
133
- : null;
134
-
135
- const retainedCompactible = [];
136
- const elided = [];
137
- let used = 0;
138
- const remaining = blocked ? 0 : budget - requiredTokens;
139
- for (const layer of pressurePool) {
140
- if (!blocked && used + layer.tokens <= remaining) {
141
- retainedCompactible.push(retainedLayer(layer));
142
- used += layer.tokens;
143
- } else {
144
- elided.push(elidedLayer(layer));
145
- }
146
- }
147
-
148
- const packetLayers = [
149
- ...required.map(retainedLayer),
150
- ...referenced,
151
- ...retainedCompactible,
152
- ...elided,
153
- ];
154
-
155
- return buildContinuationPacket({
156
- layers: packetLayers,
157
- requiredState: required.map((l) => ({ id: l.id, kind: l.kind, sourceId: l.sourceId, tokens: l.tokens })),
158
- budget,
159
- requiredTokens,
160
- blocker,
161
- });
162
- }
163
-
164
- /**
165
- * Assemble a structured, JSON-serializable continuation packet from a compaction
166
- * result. Token accounting balances the retained, referenced, and elided layers
167
- * against the budget so the packet is independently re-verifiable.
168
- */
169
- export function buildContinuationPacket({ layers = [], requiredState = [], budget = Infinity, requiredTokens = 0, blocker = null } = {}) {
170
- const retainedTokens = sumTokens(layers.filter((l) => l.disposition === 'retained'));
171
- const elidedTokens = sumTokens(layers.filter((l) => l.disposition === 'elided'));
172
- const referencedCount = layers.filter((l) => l.disposition === 'referenced').length;
173
-
174
- return {
175
- schemaVersion: CONTINUATION_PACKET_SCHEMA_VERSION,
176
- budget: {
177
- triggerTokens: Number.isFinite(budget) ? budget : null,
178
- requiredTokens,
179
- retainedTokens,
180
- elidedTokens,
181
- referencedCount,
182
- },
183
- layers,
184
- requiredState,
185
- blocker,
186
- };
187
- }
188
-
189
- /**
190
- * Re-derive the ordered layer set a composer needs to resume a session. Required
191
- * and retained layers return their stored content; a referenced layer is re-derived
192
- * through resolveSource(sourceId) so reconstructible context returns intact; an
193
- * elided layer returns a truthful marker of what was removed. The same call backs
194
- * terminal, web, export, and resume — one rehydration path, no surface drift.
195
- */
196
- export function rehydrateContinuation(packet, { resolveSource = null } = {}) {
197
- const layers = Array.isArray(packet?.layers) ? packet.layers : [];
198
- return layers.map((layer) => {
199
- if (layer.disposition === 'referenced') {
200
- const content = typeof resolveSource === 'function' ? resolveSource(layer.sourceId, layer) : null;
201
- return { id: layer.id, kind: layer.kind, content: typeof content === 'string' ? content : null, resolved: typeof content === 'string', sourceId: layer.sourceId };
202
- }
203
- if (layer.disposition === 'elided') {
204
- return { id: layer.id, kind: layer.kind, content: null, elided: true, tokens: layer.tokens, sourceId: layer.sourceId };
205
- }
206
- return { id: layer.id, kind: layer.kind, content: layer.content ?? '' };
207
- });
208
- }
209
-
210
- /**
211
- * Read the continuation budget from a compiled execution policy
212
- * (lib/models/execution-policy.mjs). Capability-profile driven, never a model-name
213
- * fixed limit (construct-6zga.1.2 AC4).
214
- */
215
- export function continuationBudgetFromPolicy(policy) {
216
- const c = policy && typeof policy === 'object' ? policy.continuation : null;
217
- return {
218
- triggerTokens: Number.isFinite(c?.compactionTriggerTokens) ? c.compactionTriggerTokens : null,
219
- triggerRatio: Number.isFinite(c?.compactionTriggerRatio) ? c.compactionTriggerRatio : null,
220
- };
221
- }
222
-
223
- /**
224
- * Hand-rolled validator (no ajv — Construct stays dependency-free at startup).
225
- * Beyond shape, it enforces the no-silent-loss invariant: every required layer is
226
- * retained unless the packet carries a blocker.
227
- */
228
- export function validateContinuationPacket(packet) {
229
- const errors = [];
230
- if (!packet || typeof packet !== 'object') return { valid: false, errors: ['packet is not an object'] };
231
- if (packet.schemaVersion !== CONTINUATION_PACKET_SCHEMA_VERSION) errors.push(`schemaVersion must be ${CONTINUATION_PACKET_SCHEMA_VERSION}`);
232
-
233
- if (!Array.isArray(packet.layers)) errors.push('layers must be an array');
234
- else {
235
- for (const layer of packet.layers) {
236
- if (!CONTEXT_LAYER_KINDS.includes(layer?.kind)) errors.push(`layer.kind invalid: ${layer?.kind}`);
237
- if (!COMPACTION_ELIGIBILITY.includes(layer?.eligibility)) errors.push(`layer.eligibility invalid: ${layer?.eligibility}`);
238
- if (!LAYER_DISPOSITIONS.includes(layer?.disposition)) errors.push(`layer.disposition invalid: ${layer?.disposition}`);
239
- }
240
- }
241
-
242
- if (!Array.isArray(packet.requiredState)) errors.push('requiredState must be an array');
243
- if (!packet.budget || typeof packet.budget !== 'object') errors.push('budget missing');
244
- else if (!Number.isInteger(packet.budget.requiredTokens) || packet.budget.requiredTokens < 0) errors.push('budget.requiredTokens invalid');
245
-
246
- const hasBlocker = packet.blocker && typeof packet.blocker === 'object';
247
- if (Array.isArray(packet.layers) && !hasBlocker) {
248
- const droppedRequired = packet.layers.find((l) => l?.eligibility === 'required' && l?.disposition !== 'retained');
249
- if (droppedRequired) errors.push(`required layer not retained without a blocker: ${droppedRequired.id}`);
250
- }
251
-
252
- return { valid: errors.length === 0, errors };
253
- }
@@ -1,58 +0,0 @@
1
- /**
2
- * lib/chat/continuation-source.mjs — the one resolveSource every surface shares to
3
- * rehydrate a continuation packet's reconstructible layers (construct-6zga.1.10).
4
- *
5
- * A continuation packet stores required state verbatim but references reconstructible
6
- * layers (static instructions, role guidance, learned patterns) by source id, so
7
- * rehydration must re-derive them rather than read stored content. One shared
8
- * resolver across terminal, web, export, and resume guarantees every surface
9
- * reconstructs identical context (AC3). Static-instructions and role-guidance
10
- * families re-derive through the same composer a live turn runs
11
- * (lib/chat/system-prompt.mjs); learned-patterns re-derive from the observation
12
- * store, prefetched once because rehydration runs synchronously.
13
- */
14
-
15
- import { buildSystemPrompt } from './system-prompt.mjs';
16
-
17
- function observationText(record) {
18
- return [record?.summary, record?.content].filter(Boolean).join(' — ').trim();
19
- }
20
-
21
- export function createContinuationResolver({
22
- systemText = null,
23
- overlay = null,
24
- capabilityTier = 'full',
25
- cwd = process.cwd(),
26
- learnedPatterns = null,
27
- } = {}) {
28
- const composedSystem = typeof systemText === 'string' ? systemText : buildSystemPrompt({ overlay, capabilityTier });
29
- const cache = new Map([['prompt:system', composedSystem]]);
30
- if (typeof learnedPatterns === 'string') cache.set('learned-patterns', learnedPatterns);
31
-
32
- function resolveSource(sourceId) {
33
- if (sourceId == null) return null;
34
- if (cache.has(sourceId)) return cache.get(sourceId);
35
- if (sourceId.startsWith('prompt:') || sourceId.startsWith('role:')) return composedSystem;
36
- if (sourceId === 'learned-patterns' || sourceId.startsWith('observation:')) return cache.get('learned-patterns') ?? null;
37
- return null;
38
- }
39
-
40
- // Learned patterns live in the observation store and load asynchronously; a
41
- // surface that wants them prefetches once, after which the synchronous
42
- // resolveSource serves them from cache. A store miss leaves the layer null —
43
- // rehydration reports it unresolved rather than inventing content.
44
-
45
- async function loadLearnedPatterns(query, { limit = 5 } = {}) {
46
- try {
47
- const { searchObservations } = await import('../observation-store.mjs');
48
- const results = await searchObservations(cwd, query, { limit });
49
- const text = (results || []).map(observationText).filter(Boolean).map((line) => `- ${line}`).join('\n');
50
- cache.set('learned-patterns', text);
51
- return text;
52
- } catch {
53
- return cache.get('learned-patterns') ?? null;
54
- }
55
- }
56
-
57
- return { resolveSource, loadLearnedPatterns, get systemText() { return composedSystem; } };
58
- }
@@ -1,61 +0,0 @@
1
- /**
2
- * lib/chat/demo-guide.mjs — slash-command helpers for construct chat demo mode.
3
- */
4
-
5
- export function formatDemoStepLine(step, colors = {}) {
6
- const dim = colors.dim || '';
7
- const reset = colors.reset || '';
8
- const bold = colors.bold || '';
9
- const lines = [`${bold}Step ${step.index}${reset}: ${step.title || 'prompt'}`];
10
- if (step.prompt) lines.push(`${step.prompt}`);
11
- if (step.command) lines.push(`${dim}command: ${step.command}${reset}`);
12
- return lines.join('\n');
13
- }
14
-
15
- export function formatDemoStepsList(guide, colors = {}) {
16
- const dim = colors.dim || '';
17
- const reset = colors.reset || '';
18
- const bold = colors.bold || '';
19
- const lines = [`${bold}Demo steps${reset}`];
20
- guide.script.steps.forEach((step, i) => {
21
- lines.push(` ${i + 1}. ${step.title || step.prompt?.slice(0, 50) || 'step'}`);
22
- });
23
- lines.push(`${dim}Use /demo next for the next prompt${reset}`);
24
- return lines.join('\n');
25
- }
26
-
27
- export function registerDemoCommands(HELP, demoGuide) {
28
- if (!demoGuide) return HELP;
29
- return [
30
- ...HELP.slice(0, 1),
31
- ['/demo [next|steps|reset]', 'walk the active demo script'],
32
- ...HELP.slice(1),
33
- ];
34
- }
35
-
36
- export function handleDemoCommand(arg, { demoGuide, output, colors }) {
37
- if (!demoGuide) {
38
- output.write(`${colors.dim}No active demo. Launch with \`construct demo <name>\`.${colors.reset}\n`);
39
- return;
40
- }
41
- const action = (arg || 'steps').toLowerCase();
42
- if (action === 'reset') {
43
- demoGuide.reset();
44
- output.write(`${colors.green}Demo reset to step 1.${colors.reset}\n`);
45
- return;
46
- }
47
- if (action === 'next') {
48
- const step = demoGuide.next();
49
- if (!step) {
50
- output.write(`${colors.dim}Demo complete — all steps shown.${colors.reset}\n`);
51
- return;
52
- }
53
- output.write(`\n${formatDemoStepLine(step, colors)}\n\n`);
54
- return;
55
- }
56
- output.write(`${formatDemoStepsList(demoGuide, colors)}\n`);
57
- const peek = demoGuide.peek();
58
- if (peek) {
59
- output.write(`${colors.dim}Next: /demo next → ${peek.title || 'step'}${colors.reset}\n`);
60
- }
61
- }
@@ -1,91 +0,0 @@
1
- /**
2
- * lib/chat/design-tokens.mjs — semantic chat tokens derived from brand primitives.
3
- *
4
- * Maps lib/brand-tokens.mjs ink ramp to dark/light chat surfaces for web CSS vars
5
- * and terminal semantic colours. Single source for cockpit theming across linear
6
- * and web/desktop surfaces.
7
- */
8
-
9
- import { INK, FONTS, STATUS } from '../brand-tokens.mjs';
10
-
11
- export const CHAT_DARK = Object.freeze({
12
- bg: '#000000',
13
- surface: '#0b0b0c',
14
- border: INK.muted,
15
- text: '#ededed',
16
- muted: '#9a9a9e',
17
- accent: '#ffffff',
18
- accentAlt: INK.hairlineStrong,
19
- ...STATUS,
20
- });
21
-
22
- export const CHAT_LIGHT = Object.freeze({
23
- bg: '#f8f9fb',
24
- surface: INK.surfaceAlt,
25
- border: INK.hairlineStrong,
26
- text: INK.ink,
27
- muted: INK.muted,
28
- accent: INK.inkStrong,
29
- accentAlt: INK.muted,
30
- ok: '#15803d',
31
- warn: '#a16207',
32
- danger: STATUS.danger,
33
- });
34
-
35
- const TERMINAL_DARK = Object.freeze({
36
- text: { ink: 'white', code: '37' },
37
- muted: { ink: 'gray', code: '90' },
38
- accent: { ink: 'whiteBright', code: '97' },
39
- accentAlt: { ink: 'gray', code: '90' },
40
- brandAccent: { ink: 'whiteBright', code: '97' },
41
- surface: { ink: 'gray', code: '90' },
42
- surfaceMuted: { ink: 'gray', code: '90' },
43
- border: { ink: 'gray', code: '90' },
44
- ok: { ink: 'green', code: '32' },
45
- warn: { ink: 'yellow', code: '33' },
46
- danger: { ink: 'red', code: '31' },
47
- badgeFg: { ink: 'black', code: '30' },
48
- });
49
-
50
- const TERMINAL_LIGHT = Object.freeze({
51
- text: { ink: 'black', code: '30' },
52
- muted: { ink: 'gray', code: '90' },
53
- accent: { ink: 'black', code: '30' },
54
- accentAlt: { ink: 'gray', code: '90' },
55
- brandAccent: { ink: 'black', code: '30' },
56
- surface: { ink: 'gray', code: '90' },
57
- surfaceMuted: { ink: 'gray', code: '90' },
58
- border: { ink: 'gray', code: '90' },
59
- ok: { ink: 'green', code: '32' },
60
- warn: { ink: 'rgb(161,98,7)', code: '33' },
61
- danger: { ink: 'red', code: '31' },
62
- badgeFg: { ink: 'white', code: '97' },
63
- });
64
-
65
- export function chatPalette(scheme = 'dark') {
66
- return scheme === 'light' ? CHAT_LIGHT : CHAT_DARK;
67
- }
68
-
69
- export function chatCssVars(scheme = 'dark') {
70
- const p = chatPalette(scheme);
71
- return {
72
- '--cx-chat-bg': p.bg,
73
- '--cx-chat-surface': p.surface,
74
- '--cx-chat-border': p.border,
75
- '--cx-chat-text': p.text,
76
- '--cx-chat-muted': p.muted,
77
- '--cx-chat-accent': p.accent,
78
- '--cx-chat-accent-alt': p.accentAlt,
79
- '--cx-chat-warn': p.warn,
80
- '--cx-chat-danger': p.danger,
81
- '--cx-chat-ok': p.ok,
82
- '--cx-chat-font': FONTS.sans,
83
- '--cx-chat-mono': FONTS.mono,
84
- };
85
- }
86
-
87
- export function chatTerminalSemantic(scheme = 'dark') {
88
- return scheme === 'light' ? TERMINAL_LIGHT : TERMINAL_DARK;
89
- }
90
-
91
- export { FONTS, INK, STATUS };
@@ -1,81 +0,0 @@
1
- /**
2
- * lib/chat/desktop-binary.mjs — resolve the Construct chat desktop window binary.
3
- *
4
- * Search order: CONSTRUCT_CHAT_DESKTOP_BIN, repo dev build, the bin/ subdir of
5
- * the XDG state dir, then packaged sidecar next to construct.
6
- */
7
-
8
- import fs from 'node:fs';
9
- import os from 'node:os';
10
- import path from 'node:path';
11
- import { fileURLToPath } from 'node:url';
12
-
13
- import { stateDir } from '../config/xdg.mjs';
14
-
15
- const HERE = path.dirname(fileURLToPath(import.meta.url));
16
- const REPO_ROOT = path.resolve(HERE, '..', '..');
17
-
18
- function binaryName() {
19
- return process.platform === 'win32' ? 'construct-chat.exe' : 'construct-chat';
20
- }
21
-
22
- function isReadableFile(filePath) {
23
- try {
24
- const stat = fs.statSync(filePath);
25
- if (!stat.isFile()) return false;
26
- fs.accessSync(filePath, fs.constants.R_OK);
27
- return true;
28
- } catch {
29
- return false;
30
- }
31
- }
32
-
33
- function isExecutable(filePath) {
34
- try {
35
- fs.accessSync(filePath, fs.constants.X_OK);
36
- return fs.statSync(filePath).isFile();
37
- } catch {
38
- return false;
39
- }
40
- }
41
-
42
- function isLaunchableBinary(filePath) {
43
- if (!filePath) return false;
44
- if (isExecutable(filePath)) return true;
45
- return isReadableFile(filePath) && /\.(mjs|cjs|js)$/i.test(filePath);
46
- }
47
-
48
- export function desktopBinaryCandidates({ repoRoot = REPO_ROOT, homeDir = os.homedir(), env = process.env } = {}) {
49
- const name = binaryName();
50
- const tauriRoot = path.join(repoRoot, 'apps', 'chat', 'desktop', 'src-tauri', 'target');
51
- return [
52
- env.CONSTRUCT_CHAT_DESKTOP_BIN,
53
- path.join(tauriRoot, 'release', name),
54
- path.join(tauriRoot, 'debug', name),
55
- path.join(stateDir(homeDir), 'bin', name),
56
- path.join(repoRoot, 'apps', 'chat', 'desktop', 'bin', name),
57
- ].filter(Boolean);
58
- }
59
-
60
- export function resolveDesktopBinary(options = {}) {
61
- for (const candidate of desktopBinaryCandidates(options)) {
62
- if (isLaunchableBinary(candidate)) return candidate;
63
- }
64
- return null;
65
- }
66
-
67
- export function desktopBinaryInstallHint({ repoRoot = REPO_ROOT } = {}) {
68
- return [
69
- 'Construct chat desktop window is not installed.',
70
- 'Install it with: construct install --scope=user',
71
- `Or set CONSTRUCT_CHAT_DESKTOP_BIN to your construct-chat binary.`,
72
- `Dev build: npm run build:chat-desktop (output: ${path.join(repoRoot, 'apps', 'chat', 'desktop', 'src-tauri', 'target', 'release', binaryName())})`,
73
- ].join('\n');
74
- }
75
-
76
- export function hasGuiDisplay(env = process.env) {
77
- if (env.CX_CHAT_NO_DISPLAY === '1') return false;
78
- if (process.platform === 'win32') return true;
79
- if (process.platform === 'darwin') return true;
80
- return Boolean(env.DISPLAY || env.WAYLAND_DISPLAY);
81
- }
@@ -1,130 +0,0 @@
1
- /**
2
- * lib/chat/desktop-build.mjs — build the Construct chat desktop window from source.
3
- *
4
- * The native window is a Tauri (Rust) app at apps/chat/desktop/src-tauri, so a
5
- * build requires the Rust toolchain. Absent cargo, the rustup installer runs
6
- * first, then `cargo build --release` produces the binary at
7
- * target/release/construct-chat — exactly where resolveDesktopBinary looks.
8
- * Mirrors the build-chat-desktop job in .github/workflows/release.yml for
9
- * local, low-touch first-run setup.
10
- */
11
-
12
- import { spawnSync } from 'node:child_process';
13
- import fs from 'node:fs';
14
- import os from 'node:os';
15
- import path from 'node:path';
16
- import { fileURLToPath } from 'node:url';
17
- import { resolveDesktopBinary } from './desktop-binary.mjs';
18
-
19
- const HERE = path.dirname(fileURLToPath(import.meta.url));
20
- const REPO_ROOT = path.resolve(HERE, '..', '..');
21
-
22
- function srcTauriDir(repoRoot = REPO_ROOT) {
23
- return path.join(repoRoot, 'apps', 'chat', 'desktop', 'src-tauri');
24
- }
25
-
26
- export function hasDesktopSource(repoRoot = REPO_ROOT) {
27
- try {
28
- return fs.statSync(path.join(srcTauriDir(repoRoot), 'Cargo.toml')).isFile();
29
- } catch {
30
- return false;
31
- }
32
- }
33
-
34
- // rustup installs to ~/.cargo/bin, absent from a fresh shell's PATH until
35
- // ~/.cargo/env is sourced; prepend it for every child process here.
36
-
37
- export function cargoEnv(env = process.env, homeDir = os.homedir()) {
38
- const cargoBin = path.join(homeDir, '.cargo', 'bin');
39
- const sep = process.platform === 'win32' ? ';' : ':';
40
- const currentPath = env.PATH || '';
41
- const parts = currentPath.split(sep);
42
- if (!parts.includes(cargoBin)) {
43
- return { ...env, PATH: `${cargoBin}${sep}${currentPath}` };
44
- }
45
- return { ...env };
46
- }
47
-
48
- export function hasCargo(env = process.env, homeDir = os.homedir()) {
49
- const probe = spawnSync('cargo', ['--version'], {
50
- env: cargoEnv(env, homeDir),
51
- stdio: 'ignore',
52
- });
53
- return probe.status === 0;
54
- }
55
-
56
- export function ensureRustToolchain({
57
- env = process.env,
58
- homeDir = os.homedir(),
59
- output = process.stdout,
60
- errorOutput = process.stderr,
61
- } = {}) {
62
- if (hasCargo(env, homeDir)) return { ok: true };
63
-
64
- if (process.platform === 'win32') {
65
- return {
66
- ok: false,
67
- reason: 'Rust toolchain not found. Install it from https://rustup.rs and re-run.',
68
- };
69
- }
70
-
71
- output.write('Installing the Rust toolchain (one-time setup for the Construct Chat window)…\n');
72
- const installer = spawnSync(
73
- 'sh',
74
- ['-c', "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal"],
75
- { env, stdio: 'inherit' },
76
- );
77
-
78
- if (installer.status !== 0) {
79
- return {
80
- ok: false,
81
- reason: 'Rust toolchain install failed. Install it manually from https://rustup.rs and re-run.',
82
- };
83
- }
84
-
85
- if (!hasCargo(env, homeDir)) {
86
- return {
87
- ok: false,
88
- reason: 'Rust installed but cargo is still not resolvable on PATH (~/.cargo/bin).',
89
- };
90
- }
91
-
92
- return { ok: true };
93
- }
94
-
95
- export function buildDesktopBinary({
96
- repoRoot = REPO_ROOT,
97
- env = process.env,
98
- homeDir = os.homedir(),
99
- output = process.stdout,
100
- errorOutput = process.stderr,
101
- } = {}) {
102
- if (!hasDesktopSource(repoRoot)) {
103
- return { ok: false, reason: `Tauri source not found at ${srcTauriDir(repoRoot)}` };
104
- }
105
-
106
- const toolchain = ensureRustToolchain({ env, homeDir, output, errorOutput });
107
- if (!toolchain.ok) return { ok: false, reason: toolchain.reason };
108
-
109
- output.write('Building the Construct Chat desktop window (cargo build --release)…\n');
110
- const build = spawnSync('cargo', ['build', '--release'], {
111
- cwd: srcTauriDir(repoRoot),
112
- env: cargoEnv(env, homeDir),
113
- stdio: 'inherit',
114
- });
115
-
116
- if (build.status !== 0) {
117
- return { ok: false, reason: 'cargo build --release failed (see output above).' };
118
- }
119
-
120
- const binaryPath = resolveDesktopBinary({ repoRoot, homeDir });
121
- if (!binaryPath) {
122
- return {
123
- ok: false,
124
- reason: 'Build reported success but no binary resolved at target/release/construct-chat.',
125
- };
126
- }
127
-
128
- output.write(`Built Construct Chat window: ${binaryPath}\n`);
129
- return { ok: true, binaryPath };
130
- }