@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
package/lib/chat/cli.mjs DELETED
@@ -1,333 +0,0 @@
1
- /**
2
- * lib/chat/cli.mjs — `construct chat` command handler (zero-dep launcher).
3
- *
4
- * ADR-0041: Construct owns the loop. This launcher stays in the zero-dep core and
5
- * only orchestrates — it loads project settings, resolves the model, builds the
6
- * owned-loop driver (apps/chat/engine, which lazy-imports the optional Vercel AI
7
- * SDK and provider packages), persists the normalized event timeline under
8
- * .cx/chat-sessions/, and then chooses a surface.
9
- *
10
- * Surface selection: desktop window (Tauri or Chromium app mode) is the default on
11
- * machines with a display; `--web` opens a browser tab; `--plain`, `--accessible`,
12
- * NO_COLOR, TERM=dumb, and non-TTY streams route to the linear renderer.
13
- * `--window` is an alias for the desktop path. `--no-window` forces a browser tab.
14
- *
15
- * `--list` reports the model catalog and which providers are configured; `--model`
16
- * pins the model for this launch; `--resume` restores the latest (or given) session
17
- * transcript from `.cx/chat-sessions/`; the `--no-*` flags override saved transparency
18
- * layers.
19
- */
20
-
21
- import path from 'node:path';
22
- import { fileURLToPath } from 'node:url';
23
- import { resolveColors } from '../term-format.mjs';
24
- import { resolveLayers } from './transparency.mjs';
25
- import { runChatLoop } from './tui/render.mjs';
26
- import { createSessionUsage } from './tui/usage.mjs';
27
- import { loadChatConfig } from './config.mjs';
28
- import { loadConstructEnv } from '../env-config.mjs';
29
- import { createCommands } from './commands.mjs';
30
- import { resolveResumePath, restoreFromSession } from './session-restore.mjs';
31
- import { buildSystemPrompt } from './system-prompt.mjs';
32
- import { resolveExecutionCapabilityProfile } from '../models/execution-capability-profile.mjs';
33
- import { compileExecutionPolicy } from '../models/execution-policy.mjs';
34
- import { createChatPersister } from './session-persist.mjs';
35
- import { hasGuiDisplay } from './desktop-binary.mjs';
36
- import { createOwnedLoopDriver } from '../../apps/chat/engine/loop-driver.mjs';
37
- import { listChatModels, resolveChatModelSelectionAsync, resolveSessionModel } from '../../apps/chat/engine/models.mjs';
38
- import { resolveDemoGuideForChat } from '../demo-surface.mjs';
39
-
40
- const HERE = path.dirname(fileURLToPath(import.meta.url));
41
- const REPO_ROOT = path.resolve(HERE, '..', '..');
42
-
43
- function parseFlags(args) {
44
- const flags = {
45
- plain: false,
46
- accessible: false,
47
- web: false,
48
- window: false,
49
- noWindow: false,
50
- list: false,
51
- quiet: false,
52
- free: false,
53
- model: null,
54
- resume: null,
55
- ascii: null,
56
- demo: null,
57
- };
58
- for (let i = 0; i < args.length; i++) {
59
- const arg = args[i];
60
- if (arg === '--list') flags.list = true;
61
- else if (arg === '--plain') flags.plain = true;
62
- else if (arg === '--accessible') flags.accessible = true;
63
- else if (arg === '--web') flags.web = true;
64
- else if (arg === '--window') flags.window = true;
65
- else if (arg === '--no-window') flags.noWindow = true;
66
- else if (arg === '--quiet') flags.quiet = true;
67
- else if (arg === '--free') flags.free = true;
68
- else if (arg === '--ascii') flags.ascii = true;
69
- else if (arg === '--resume') flags.resume = true;
70
- else if (arg.startsWith('--resume=')) flags.resume = arg.slice('--resume='.length);
71
- else if (arg === '--no-thinking') flags.thinking = false;
72
- else if (arg === '--no-path') flags.path = false;
73
- else if (arg === '--no-specialists') flags.specialists = false;
74
- else if (arg === '--no-tools') flags.tools = false;
75
- else if (arg === '--no-observability') flags.observability = false;
76
- else if (arg === '--model') flags.model = args[++i] || null;
77
- else if (arg.startsWith('--model=')) flags.model = arg.slice('--model='.length);
78
- else if (arg === '--demo') flags.demo = args[++i] || null;
79
- else if (arg.startsWith('--demo=')) flags.demo = arg.slice('--demo='.length);
80
- }
81
- return flags;
82
- }
83
-
84
- function printModels(output, env) {
85
- const colors = resolveColors({ stream: output, env });
86
- const models = listChatModels({ env });
87
- const configured = models.filter((m) => m.configured);
88
- output.write(`${colors.bold}Owned loop \u2014 model catalog${colors.reset}\n`);
89
- if (!configured.length) {
90
- output.write(`${colors.dim}No provider configured. Set a key (a value or an op:// reference) in ~/.construct/config.env, run \`construct creds login copilot\` for GitHub Copilot, or start Ollama locally.${colors.reset}\n`);
91
- }
92
- for (const m of models) {
93
- const mark = m.configured ? `${colors.green}\u2713${colors.reset}` : `${colors.dim}\u00b7${colors.reset}`;
94
- output.write(` ${mark} ${m.id}${m.local ? `${colors.dim} (local)${colors.reset}` : ''}\n`);
95
- }
96
- }
97
-
98
- function createPersister({ cwd, sessionId, resumePath = null }) {
99
- return createChatPersister({ cwd, sessionId, resumePath, host: 'construct' });
100
- }
101
-
102
- function wantsLinearSurface({ flags, env, output, input }) {
103
- if (flags.plain || flags.accessible) return true;
104
- if (env.NO_COLOR || env.TERM === 'dumb') return true;
105
- if (env.CX_CHAT_FORCE_LINEAR === '1') return true;
106
- if (!output.isTTY || !input.isTTY) return true;
107
- return false;
108
- }
109
-
110
- function resolveChatSurface({ flags, env, output, input }) {
111
- if (wantsLinearSurface({ flags, env, output, input })) return 'linear';
112
- if (flags.web || flags.noWindow) return 'web';
113
- if (flags.window || env.CONSTRUCT_CHAT_WINDOW === '1' || hasGuiDisplay(env)) return 'desktop';
114
- return 'headless';
115
- }
116
-
117
- // Desktop means the native construct-chat window: an existing binary, or Tauri
118
- // source that runDesktopChat builds on demand. A browser does not qualify;
119
- // `construct chat --web` is the explicit browser path.
120
-
121
- async function canLaunchDesktop(env, cwd = process.cwd()) {
122
- const { hasGuiDisplay, resolveDesktopBinary } = await import('./desktop-binary.mjs');
123
- if (!hasGuiDisplay(env)) return false;
124
- if (resolveDesktopBinary()) return true;
125
- const { hasDesktopSource } = await import('./desktop-build.mjs');
126
- return hasDesktopSource(cwd);
127
- }
128
-
129
- function resolveAsciiMode({ flags, env, config }) {
130
- if (flags.ascii === true) return true;
131
- if (env.CX_CHAT_ASCII === '1') return true;
132
- if (config.ui?.ascii) return true;
133
- if (process.platform === 'win32' && !env.WT_SESSION && !env.WT_PROFILE_ID && env.TERM !== 'xterm-256color') {
134
- return true;
135
- }
136
- return false;
137
- }
138
-
139
- function createPermissionHandler({ session, bridge }) {
140
- return async (req) => {
141
- const mode = session.permissionMode || 'allow_once';
142
- if (mode === 'reject') return 'reject';
143
- if (mode === 'allow_always') return 'allow_always';
144
- if (mode === 'allow_once') return 'allow';
145
- if (mode === 'ask' && bridge?.prompt) return bridge.prompt(req);
146
- return 'allow';
147
- };
148
- }
149
-
150
- export async function runChat(args = [], { env = process.env, cwd = process.cwd(), input = process.stdin, output = process.stdout, errorOutput = process.stderr } = {}) {
151
- const flags = parseFlags(args);
152
- if (!flags.demo && env.CONSTRUCT_DEMO) flags.demo = env.CONSTRUCT_DEMO;
153
-
154
- const effectiveEnv = loadConstructEnv({ rootDir: cwd, env: flags.plain ? { ...env, NO_COLOR: '1' } : env, warn: false });
155
-
156
- if (flags.list) { printModels(output, effectiveEnv); return 0; }
157
-
158
- const { config } = loadChatConfig({ cwd });
159
-
160
- let modelMode = config.modelMode || 'pinned';
161
- if (flags.free) modelMode = 'free-router';
162
-
163
- const savedModel = flags.model || (modelMode === 'pinned' ? config.model : null) || null;
164
-
165
- let resolvedModel = savedModel;
166
- if (modelMode === 'free-router') {
167
- const sessionStub = { modelMode: 'free-router', failedModels: new Set() };
168
- resolvedModel = await resolveSessionModel(sessionStub, { env: effectiveEnv, tier: 'standard' });
169
- if (!resolvedModel && !flags.list) {
170
- errorOutput.write('OpenRouter free router needs OPENROUTER_API_KEY in ~/.construct/config.env, or no free models are available.\n');
171
- return 1;
172
- }
173
- }
174
-
175
- // Saved layers seed the run; --no-* overrides win for this launch.
176
- const layers = resolveLayers({ flags, env: effectiveEnv });
177
- for (const key of Object.keys(config.layers)) {
178
- if (flags[key] === undefined && config.layers[key] === false) layers[key] = false;
179
- }
180
- if (config.thinking === false && flags.thinking === undefined) layers.thinking = false;
181
-
182
- const resumePath = resolveResumePath({ cwd, resume: flags.resume });
183
- const restored = resumePath ? restoreFromSession(resumePath) : null;
184
-
185
- const demoPack = flags.demo
186
- ? resolveDemoGuideForChat(flags.demo, { cwd, repoRoot: REPO_ROOT })
187
- : null;
188
-
189
- const modelResolution = modelMode === 'free-router' && resolvedModel
190
- ? { id: resolvedModel, source: 'free-router', notice: null, rejected: [] }
191
- : await resolveChatModelSelectionAsync({
192
- env: effectiveEnv,
193
- requested: savedModel,
194
- });
195
-
196
- const session = {
197
- model: modelResolution.id || resolvedModel,
198
- savedModel: modelMode === 'pinned' ? (savedModel || modelResolution.id) : null,
199
- modelMode,
200
- modelNotice: modelResolution.notice || null,
201
- failedModels: new Set(),
202
- layers,
203
- thinking: layers.thinking,
204
- permissionMode: config.permissionMode || 'allow_once',
205
- sandbox: config.sandbox || 'workspace-write',
206
- ui: {
207
- ascii: resolveAsciiMode({ flags, env: effectiveEnv, config }),
208
- inspector: config.ui?.inspector || 'auto',
209
- theme: config.ui?.theme || 'auto',
210
- },
211
- usage: restored?.usage || createSessionUsage(),
212
- demoGuide: demoPack?.guide || null,
213
- demoTitle: demoPack?.script?.title || null,
214
- };
215
-
216
- let surface = resolveChatSurface({ flags, env: effectiveEnv, output, input });
217
-
218
- if (surface === 'headless') {
219
- errorOutput.write('No graphical display available. Use `construct chat --plain` for terminal mode.\n');
220
- return 1;
221
- }
222
-
223
- if (surface === 'desktop') {
224
- if (!(await canLaunchDesktop(effectiveEnv, cwd))) {
225
- errorOutput.write('No graphical display available. Use `construct chat --plain` for terminal mode, or `construct chat --web` for a browser tab.\n');
226
- return 1;
227
- }
228
- try {
229
- const { runDesktopChat } = await import('./desktop-launcher.mjs');
230
- return runDesktopChat({ cwd, env: effectiveEnv, output, errorOutput });
231
- } catch (err) {
232
- errorOutput.write(`Desktop chat unavailable: ${err.message}\n`);
233
- return 1;
234
- }
235
- }
236
-
237
- if (surface === 'web') {
238
- try {
239
- const { runWebChat } = await import('./web-launcher.mjs');
240
- return runWebChat({ cwd, env: effectiveEnv, output, errorOutput });
241
- } catch (err) {
242
- errorOutput.write(`Web chat unavailable: ${err.message}\n`);
243
- return 1;
244
- }
245
- }
246
-
247
- const permissionBridge = { prompt: null };
248
- const handlers = {
249
- getSandbox: () => session.sandbox,
250
- getPermissionMode: () => session.permissionMode,
251
- requestPermission: createPermissionHandler({ session, bridge: permissionBridge }),
252
- };
253
-
254
- const createAgent = async (opts) => {
255
- const { createAiSdkAgent } = await import('../../apps/chat/engine/ai-sdk-agent.mjs');
256
- return createAiSdkAgent(opts);
257
- };
258
-
259
- const driver = createOwnedLoopDriver({
260
- env: effectiveEnv,
261
- cwd,
262
- model: session.model,
263
- handlers,
264
- systemPrompt: (() => {
265
- const base = buildSystemPrompt({ capabilityTier: compileExecutionPolicy({ profile: resolveExecutionCapabilityProfile({ model: session.model }) }).prompt.systemPromptTier });
266
- return demoPack?.systemOverlay ? `${base}\n\nDemo script:\n${demoPack.systemOverlay}` : base;
267
- })(),
268
- createAgent,
269
- });
270
-
271
- let started;
272
- try {
273
- started = await driver.start();
274
- } catch (err) {
275
- const hint = /Cannot find package|ERR_MODULE_NOT_FOUND|find module/i.test(err.message)
276
- ? '\nThe owned loop needs its optional dependencies. Install them with:\n npm install ai @ai-sdk/anthropic @ai-sdk/openai @ai-sdk/openai-compatible zod'
277
- : '';
278
- errorOutput.write(`Failed to start the owned loop: ${err.message}${hint}\n`);
279
- try { driver.stop?.(); } catch { /* nothing started */ }
280
- return 1;
281
- }
282
-
283
- const notices = [];
284
- if (modelResolution.notice) notices.push(modelResolution.notice);
285
- if (demoPack?.welcome) notices.push(demoPack.welcome);
286
- if (!session.model) {
287
- notices.push('no model resolved \u2014 set a provider key or run `construct creds login copilot`, then use /model');
288
- }
289
- if (flags.resume && !restored?.sessionFile) {
290
- notices.push('no prior session found to resume \u2014 starting fresh');
291
- } else if (restored?.sessionFile && (restored.turnBlocks?.length || restored.transcript.length)) {
292
- const count = restored.turnBlocks?.length || restored.transcript.length;
293
- notices.push(`resumed ${count} turn(s) from ${path.basename(restored.sessionFile)}`);
294
- }
295
-
296
- const persist = createPersister({ cwd, sessionId: started.sessionId, resumePath: restored?.sessionFile || null });
297
- const commands = createCommands({
298
- driver,
299
- host: 'construct',
300
- hostId: 'construct',
301
- version: null,
302
- cwd,
303
- env: effectiveEnv,
304
- turnBlocksRef: () => [],
305
- demoGuide: demoPack?.guide || null,
306
- });
307
-
308
- try {
309
- await runChatLoop({
310
- driver,
311
- host: 'construct',
312
- version: null,
313
- layers,
314
- input,
315
- env: effectiveEnv,
316
- output,
317
- persist,
318
- commands,
319
- session,
320
- notices,
321
- permissionBridge,
322
- initialTranscript: restored?.transcript || [],
323
- initialTurnBlocks: restored?.turnBlocks || [],
324
- cwd,
325
- flags,
326
- });
327
- } finally {
328
- try { driver.stop?.(); } catch { /* already stopped */ }
329
- }
330
- return 0;
331
- }
332
-
333
- export { resolveChatSurface, wantsLinearSurface };
@@ -1,161 +0,0 @@
1
- /**
2
- * lib/chat/command-suggest.mjs — slash-command autocomplete for construct chat.
3
- *
4
- * Single source of truth for the advertised commands and their one-line actions,
5
- * shared by the web composer dropdown, the Ink footer (ghost completion + Tab),
6
- * and tests. No I/O. `/models` is intentionally absent here — it stays a hidden
7
- * alias of `/model` in the command handlers so only one model command is shown.
8
- */
9
-
10
- export const SLASH_COMMAND_INFO = Object.freeze([
11
- { cmd: '/help', desc: 'list every command and what it does' },
12
- { cmd: '/model', desc: 'show or pick the model (opens a searchable picker)' },
13
- { cmd: '/free', desc: 'switch to OpenRouter free-router mode' },
14
- { cmd: '/set', desc: 'change a setting — /set <key> <on|off|value>' },
15
- { cmd: '/settings', desc: 'show the current settings' },
16
- { cmd: '/layers', desc: 'show transparency layers (Ctrl+1–5 to toggle)' },
17
- { cmd: '/usage', desc: 'session token and cost breakdown' },
18
- { cmd: '/oracle', desc: 'Oracle overseer verdict and pending approvals' },
19
- { cmd: '/host', desc: 'show the active engine / host' },
20
- { cmd: '/inspect', desc: 'toggle the inspector panel' },
21
- { cmd: '/export', desc: 'save the answer to markdown — /export [last|session]' },
22
- { cmd: '/clear', desc: 'clear the conversation' },
23
- { cmd: '/exit', desc: 'quit (terminal only)' },
24
- ]);
25
-
26
- export const SLASH_COMMANDS = Object.freeze(SLASH_COMMAND_INFO.map((c) => c.cmd));
27
-
28
- export const SETTING_KEY_INFO = Object.freeze([
29
- { key: 'thinking', desc: 'show model reasoning inline' },
30
- { key: 'path', desc: 'show the routing path' },
31
- { key: 'specialists', desc: 'show the specialist chain' },
32
- { key: 'tools', desc: 'show tool calls' },
33
- { key: 'observability', desc: 'show usage + telemetry' },
34
- { key: 'permission', desc: 'ask | allow_once | allow_always | reject' },
35
- { key: 'sandbox', desc: 'read-only | workspace-write | danger-full-access' },
36
- { key: 'model', desc: 'set the model id' },
37
- { key: 'ascii', desc: 'ASCII-only glyphs (on|off)' },
38
- { key: 'inspector', desc: 'inspector panel (on|off|auto)' },
39
- ]);
40
-
41
- export const SETTING_KEYS = Object.freeze(SETTING_KEY_INFO.map((s) => s.key));
42
-
43
- const DESC_BY_CMD = new Map(SLASH_COMMAND_INFO.map((c) => [c.cmd, c.desc]));
44
- const DESC_BY_KEY = new Map(SETTING_KEY_INFO.map((s) => [s.key, s.desc]));
45
-
46
- export function slashCommandMatches(input) {
47
- const trimmed = String(input || '').trimStart();
48
- if (!trimmed.startsWith('/')) return [];
49
- const token = trimmed.split(/\s+/)[0].toLowerCase();
50
- if (!token || token === '/') return [...SLASH_COMMANDS];
51
- return SLASH_COMMANDS.filter((cmd) => cmd.startsWith(token));
52
- }
53
-
54
- export function slashCommandGhost(input) {
55
- const matches = slashCommandMatches(input);
56
- if (!matches.length) return '';
57
- const trimmed = String(input || '').trimStart();
58
- const token = trimmed.split(/\s+/)[0];
59
- const best = matches.find((cmd) => cmd.startsWith(token.toLowerCase())) || matches[0];
60
- if (best.length <= token.length) return '';
61
- return best.slice(token.length);
62
- }
63
-
64
- export function completeSlashCommand(input) {
65
- const trimmed = String(input || '').trimStart();
66
- if (!trimmed.startsWith('/')) return input;
67
- const parts = trimmed.split(/\s+/);
68
- const token = parts[0];
69
- const matches = slashCommandMatches(token);
70
- if (!matches.length) return input;
71
- const lower = token.toLowerCase();
72
- const exact = matches.find((cmd) => cmd === lower);
73
- const best = exact || matches.find((cmd) => cmd.startsWith(lower)) || matches[0];
74
- const rest = parts.slice(1).join(' ');
75
- const completed = rest ? `${best} ${rest}` : `${best} `;
76
- const prefix = input.startsWith(' ') ? input.slice(0, input.indexOf('/')) : '';
77
- return `${prefix}${completed}`;
78
- }
79
-
80
- export function cycleSlashCommand(input, direction = 1) {
81
- const matches = slashCommandMatches(input);
82
- if (!matches.length) return input;
83
- const trimmed = String(input || '').trimStart();
84
- const token = trimmed.split(/\s+/)[0].toLowerCase();
85
- const idx = Math.max(0, matches.findIndex((cmd) => cmd.startsWith(token)));
86
- const next = matches[(idx + direction + matches.length) % matches.length];
87
- const prefix = input.startsWith(' ') ? input.slice(0, input.indexOf('/')) : '';
88
- return `${prefix}${next} `;
89
- }
90
-
91
- export function setKeyMatches(input) {
92
- const trimmed = String(input || '').trimStart();
93
- const m = trimmed.match(/^\/set\s+(\S*)$/i);
94
- if (!m) return [];
95
- const partial = (m[1] || '').toLowerCase();
96
- if (!partial) return [...SETTING_KEYS];
97
- return SETTING_KEYS.filter((k) => k.startsWith(partial));
98
- }
99
-
100
- export function completeSetKey(input) {
101
- const trimmed = String(input || '').trimStart();
102
- const m = trimmed.match(/^\/set\s+(\S*)$/i);
103
- if (!m) return input;
104
- const partial = m[1] || '';
105
- const matches = setKeyMatches(input);
106
- if (!matches.length) return input;
107
- const best = matches.find((k) => k.startsWith(partial.toLowerCase())) || matches[0];
108
- return `/set ${best} `;
109
- }
110
-
111
- // Rich suggestions for the composer dropdown: each entry carries the token to
112
- // complete plus its one-line action. Returns `/set` keys while the user is
113
- // typing a setting, otherwise the matching commands. Empty once an argument is
114
- // being typed for a non-/set command, so the dropdown gets out of the way.
115
-
116
- export function slashCommandSuggestions(input, { limit = 8 } = {}) {
117
- const raw = String(input || '');
118
- const trimmed = raw.trimStart();
119
- if (!trimmed.startsWith('/')) return { kind: 'none', items: [] };
120
-
121
- if (/^\/set(\s|$)/i.test(trimmed)) {
122
- const keys = setKeyMatches(trimmed);
123
- if (keys.length) {
124
- return {
125
- kind: 'set',
126
- items: keys.slice(0, limit).map((key) => ({ value: key, desc: DESC_BY_KEY.get(key) || '' })),
127
- };
128
- }
129
- return { kind: 'none', items: [] };
130
- }
131
-
132
- if (trimmed.includes(' ')) return { kind: 'none', items: [] };
133
-
134
- const matches = slashCommandMatches(trimmed);
135
- return {
136
- kind: 'command',
137
- items: matches.slice(0, limit).map((cmd) => ({ value: cmd, desc: DESC_BY_CMD.get(cmd) || '' })),
138
- };
139
- }
140
-
141
- export function commandSuggestHint(input) {
142
- if (!String(input || '').trimStart().startsWith('/')) return '';
143
- const cmdMatches = slashCommandMatches(input);
144
- if (cmdMatches.length && !input.trim().includes(' ')) {
145
- return cmdMatches.slice(0, 6).join(' ');
146
- }
147
- const setMatches = setKeyMatches(input);
148
- if (setMatches.length) return setMatches.slice(0, 8).join(' ');
149
- return '';
150
- }
151
-
152
- export function applyTabCompletion(input) {
153
- const setDone = completeSetKey(input);
154
- if (setDone !== input) return setDone;
155
- return completeSlashCommand(input);
156
- }
157
-
158
- export function isSlashOnlyInput(input) {
159
- const trimmed = String(input || '').trimStart();
160
- return trimmed.startsWith('/') && !trimmed.includes(' ');
161
- }