@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,133 +0,0 @@
1
- /**
2
- * lib/chat/desktop-launcher.mjs — start dashboard and open Construct chat in the native window.
3
- *
4
- * Launch order when the construct-chat binary is missing: build it from the Tauri
5
- * source on disk (dev/branch path), else download the prebuilt release asset, else
6
- * fail loudly with remediation. Chrome app-mode is never an implicit substitute —
7
- * the native window is the contract, and `construct chat --web` is the explicit
8
- * browser path.
9
- */
10
-
11
- import { spawn } from 'node:child_process';
12
- import os from 'node:os';
13
- import { startDashboard, readDashboardState } from '../service-manager.mjs';
14
- import { hasGuiDisplay, resolveDesktopBinary } from './desktop-binary.mjs';
15
- import { buildDesktopBinary, hasDesktopSource } from './desktop-build.mjs';
16
-
17
- async function ensureDashboard({ cwd, env, errorOutput }) {
18
- let dash = readDashboardState();
19
- if (dash?.port) return dash;
20
-
21
- const result = await startDashboard({
22
- rootDir: cwd,
23
- preferredPort: parseInt(env.PORT || env.DASHBOARD_PORT || '4242', 10),
24
- });
25
- if (result.started || result.reused) {
26
- return { port: result.port, url: result.url || `http://127.0.0.1:${result.port}` };
27
- }
28
- errorOutput.write(`Failed to start dashboard: ${result.reason || 'unknown error'}\n`);
29
- return null;
30
- }
31
-
32
- function waitForChild(child) {
33
- return new Promise((resolve) => {
34
- let settled = false;
35
- const finish = (code) => {
36
- if (settled) return;
37
- settled = true;
38
- resolve(code ?? 0);
39
- };
40
-
41
- if (child) {
42
- child.on('exit', (code) => finish(code));
43
- child.on('error', () => finish(1));
44
- }
45
-
46
- const onSignal = () => {
47
- try { child?.kill('SIGTERM'); } catch { /* already exited */ }
48
- finish(0);
49
- };
50
- process.once('SIGINT', onSignal);
51
- process.once('SIGTERM', onSignal);
52
-
53
- if (!child) finish(0);
54
- });
55
- }
56
-
57
- function spawnDesktopBinary(bin, chatUrl, env) {
58
- if (/\.(mjs|cjs|js)$/i.test(bin)) {
59
- return spawn(process.execPath, [bin, '--url', chatUrl], {
60
- env: { ...env, CONSTRUCT_CHAT_URL: chatUrl },
61
- stdio: 'ignore',
62
- detached: false,
63
- });
64
- }
65
- return spawn(bin, ['--url', chatUrl], {
66
- env: { ...env, CONSTRUCT_CHAT_URL: chatUrl },
67
- stdio: 'ignore',
68
- detached: false,
69
- });
70
- }
71
-
72
- async function tryDownloadBinary(env) {
73
- try {
74
- const { downloadDesktopBinary } = await import('../install/desktop-binary-download.mjs');
75
- const result = await downloadDesktopBinary({ homeDir: os.homedir(), env });
76
- if (result.status === 'downloaded') return resolveDesktopBinary();
77
- } catch {
78
- /* fall through to loud failure below */
79
- }
80
- return null;
81
- }
82
-
83
- function resolveBinaryToLaunch({ cwd, env, output, errorOutput }) {
84
- const existing = resolveDesktopBinary({ repoRoot: cwd, env });
85
- if (existing) return existing;
86
-
87
- if (hasDesktopSource(cwd)) {
88
- const built = buildDesktopBinary({ repoRoot: cwd, env, output, errorOutput });
89
- if (built.ok) return built.binaryPath;
90
- errorOutput.write(`Could not build the Construct Chat window: ${built.reason}\n`);
91
- return null;
92
- }
93
-
94
- return null;
95
- }
96
-
97
- export async function runDesktopChat({
98
- cwd = process.cwd(),
99
- env = process.env,
100
- output = process.stdout,
101
- errorOutput = process.stderr,
102
- binaryPath = null,
103
- dashOverride = null,
104
- } = {}) {
105
- if (!hasGuiDisplay(env)) {
106
- errorOutput.write('No graphical display available. Use `construct chat --plain` for terminal mode.\n');
107
- return 1;
108
- }
109
-
110
- let bin = binaryPath || resolveBinaryToLaunch({ cwd, env, output, errorOutput });
111
-
112
- if (!bin && !hasDesktopSource(cwd)) {
113
- bin = await tryDownloadBinary(env);
114
- }
115
-
116
- if (!bin) {
117
- errorOutput.write(
118
- 'The Construct Chat native window is unavailable.\n'
119
- + 'Build it with: npm run build:chat-desktop (requires the Rust toolchain from https://rustup.rs)\n'
120
- + 'Or open chat in a browser tab with: construct chat --web\n',
121
- );
122
- return 1;
123
- }
124
-
125
- const dash = dashOverride || await ensureDashboard({ cwd, env, errorOutput });
126
- if (!dash) return 1;
127
-
128
- const base = (dash.url || `http://127.0.0.1:${dash.port}`).replace(/\/$/, '');
129
- const chatUrl = `${base}/chat/?surface=desktop`;
130
-
131
- const child = spawnDesktopBinary(bin, chatUrl, env);
132
- return waitForChild(child);
133
- }
@@ -1,145 +0,0 @@
1
- /** Per-turn evidence provenance for chat surfaces. */
2
-
3
- export const EVIDENCE_SCHEMA_VERSION = 1;
4
-
5
- const REPO_EVIDENCE_TOOLS = new Set(['read', 'grep', 'glob']);
6
- const GLOB_META_RE = /[*?\[\]{}]/;
7
-
8
- function freeze(value) {
9
- if (Array.isArray(value)) value.forEach(freeze);
10
- else if (value && typeof value === 'object') Object.values(value).forEach(freeze);
11
- return Object.freeze(value);
12
- }
13
-
14
- function concreteTarget(value) {
15
- if (typeof value !== 'string' || !value.trim() || GLOB_META_RE.test(value)) return null;
16
- return value;
17
- }
18
-
19
- function toolResult(tool = {}) {
20
- const result = tool.content ?? tool.result;
21
- return result && typeof result === 'object' ? result : null;
22
- }
23
-
24
- function concreteTargets(tool = {}) {
25
- const result = toolResult(tool);
26
- const name = String(tool.title || tool.kind || '');
27
- if (!result) return [];
28
- if (name === 'read') return [concreteTarget(result.path || tool.input?.path)].filter(Boolean);
29
-
30
- // grep/glob requests describe a search, not a source. Only the concrete files
31
- // returned by a successful result become evidence records.
32
- const matches = Array.isArray(result.matches) ? result.matches : [];
33
- return [...new Set(matches.map((match) => concreteTarget(typeof match === 'string' ? match : match?.file || match?.path)).filter(Boolean))];
34
- }
35
-
36
- export function evidenceTarget(tool = {}) {
37
- return concreteTargets(tool)[0] || null;
38
- }
39
-
40
- export function isSuccessfulEvidenceTool(tool = {}) {
41
- if (!REPO_EVIDENCE_TOOLS.has(String(tool.title || tool.kind || ''))) return false;
42
- if (tool.status !== 'completed') return false;
43
- const result = toolResult(tool);
44
- return Boolean(result && result.ok !== false && result.denied !== true && !result.error && concreteTargets(tool).length);
45
- }
46
-
47
- export function evidenceRecords(tools = [], { turnId = null } = {}) {
48
- const records = [];
49
- for (const tool of tools) {
50
- if (!isSuccessfulEvidenceTool(tool)) continue;
51
- for (const target of concreteTargets(tool)) {
52
- records.push(freeze({
53
- schemaVersion: EVIDENCE_SCHEMA_VERSION,
54
- recordId: `${turnId || 'turn'}:${String(tool.id || '')}:${target}`,
55
- turnId: turnId ? String(turnId) : null,
56
- toolId: String(tool.id || ''),
57
- tool: String(tool.title || tool.kind),
58
- requestedTarget: String(tool.input?.path || tool.input?.glob || tool.input?.pattern || ''),
59
- target,
60
- sourceId: `repo:${target}`,
61
- completion: 'completed',
62
- result: 'success',
63
- }));
64
- }
65
- }
66
- return freeze(records);
67
- }
68
-
69
- function escapeRegExp(value) {
70
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
71
- }
72
-
73
- export function citationMatches(text, record) {
74
- const target = String(record?.target || '');
75
- const sourceId = String(record?.sourceId || '');
76
- if (!target) return false;
77
- const escapedTarget = escapeRegExp(target);
78
- const targetPattern = new RegExp(`(^|[^A-Za-z0-9_./-])${escapedTarget}(?=$|[^A-Za-z0-9_./-])`);
79
- const sourcePattern = sourceId
80
- ? new RegExp(`\\[source:\\s*${escapeRegExp(sourceId)}\\s*\\]`, 'i')
81
- : null;
82
- return targetPattern.test(text) || Boolean(sourcePattern?.test(text));
83
- }
84
-
85
- function verdict({ status, records = [], citations = [], reasonCodes = [] }) {
86
- return freeze({
87
- schemaVersion: EVIDENCE_SCHEMA_VERSION,
88
- status,
89
- records: [...records],
90
- citations: [...new Set(citations)],
91
- reasonCodes: [...reasonCodes],
92
- });
93
- }
94
-
95
- export function deriveEvidenceVerdict({ id = null, overlay = null, tools = [], assistant = '', evidenceVisible = true, migration = false } = {}) {
96
- const required = overlay?.assumptionsBlocked || overlay?.externalResearch?.required;
97
- const migrationCode = migration ? ['legacy_snapshot_without_evidence'] : [];
98
- if (!required) return verdict({ status: 'not_applicable', reasonCodes: ['evidence_not_required', ...migrationCode] });
99
- if (!evidenceVisible) return verdict({ status: 'insufficient_evidence', reasonCodes: ['evidence_layer_hidden', ...migrationCode] });
100
-
101
- const records = evidenceRecords(tools, { turnId: id });
102
- if (!records.length) return verdict({ status: 'insufficient_evidence', records, reasonCodes: ['no_successful_concrete_evidence', ...migrationCode] });
103
- const text = String(assistant || '');
104
- const citations = records.filter((record) => citationMatches(text, record)).map((record) => record.target);
105
- if (!citations.length) return verdict({ status: 'uncited_evidence', records, citations, reasonCodes: ['evidence_not_cited', ...migrationCode] });
106
- return verdict({
107
- status: citations.length === records.length ? 'verified' : 'partially_verified',
108
- records,
109
- citations,
110
- reasonCodes: [citations.length === records.length ? 'all_recorded_evidence_cited' : 'some_recorded_evidence_uncited', ...migrationCode],
111
- });
112
- }
113
-
114
- export function migrateEvidenceVerdict(turn = {}) {
115
- if (turn.evidence?.schemaVersion === EVIDENCE_SCHEMA_VERSION) return turn.evidence;
116
- if (turn.evidence?.status) {
117
- const records = (turn.evidence.records || []).map((record, index) => freeze({
118
- schemaVersion: EVIDENCE_SCHEMA_VERSION,
119
- recordId: record.recordId || `${turn.id || 'turn'}:${record.toolId || ''}:${record.target || index}`,
120
- turnId: record.turnId || turn.id || null,
121
- toolId: record.toolId || '',
122
- tool: record.tool || 'unknown',
123
- requestedTarget: record.requestedTarget || record.target || '',
124
- target: record.target || '',
125
- sourceId: record.sourceId || `repo:${record.target || ''}`,
126
- completion: record.completion || 'completed',
127
- result: record.result || 'success',
128
- })).filter((record) => record.target);
129
- return verdict({
130
- status: turn.evidence.status,
131
- records,
132
- citations: turn.evidence.citations || [],
133
- reasonCodes: [...(turn.evidence.reasonCodes || []), 'legacy_evidence_unversioned'],
134
- });
135
- }
136
- return deriveEvidenceVerdict({ ...turn, migration: true });
137
- }
138
-
139
- export function evidenceNotice(verdict) {
140
- if (!verdict || verdict.status === 'not_applicable' || verdict.status === 'verified') return null;
141
- if (verdict.reasonCodes?.includes('evidence_layer_hidden')) return 'Evidence tools were hidden for this turn, so no source was verified';
142
- if (verdict.status === 'uncited_evidence') return 'Evidence was read but the answer does not cite its recorded paths — treat claims as unverified';
143
- if (verdict.status === 'partially_verified') return 'Only some recorded evidence paths are cited — treat uncited claims as unverified';
144
- return 'Answer produced without successful recorded repo evidence — treat as unverified';
145
- }
@@ -1,74 +0,0 @@
1
- /**
2
- * lib/chat/export.mjs — plain markdown export for construct chat turns.
3
- */
4
-
5
- import fs from 'node:fs';
6
- import path from 'node:path';
7
- import { resolveProjectScopedPath } from '../project-root.mjs';
8
- import { summarizeSources } from './tui/turn-present.mjs';
9
- import { rehydrateContinuation } from './context-continuation.mjs';
10
- import { createContinuationResolver } from './continuation-source.mjs';
11
-
12
- function exportDir({ cwd }) {
13
- const base = resolveProjectScopedPath('chat-sessions', { cwd, ensureDir: true });
14
- const dir = path.join(base, 'exports');
15
- fs.mkdirSync(dir, { recursive: true });
16
- return dir;
17
- }
18
-
19
- // Render a persisted continuation packet by rehydrating it through the one shared
20
- // resolver (AC3): reconstructible layers re-derive via the same composer a live
21
- // turn runs, elided layers report as summarized, and the budget accounting stays
22
- // re-verifiable in the export.
23
-
24
- function continuationToMarkdown(packet, { cwd }) {
25
- if (!packet || typeof packet !== 'object') return '';
26
- const resolver = createContinuationResolver({ cwd });
27
- const layers = rehydrateContinuation(packet, { resolveSource: resolver.resolveSource });
28
- const budget = packet.budget || {};
29
- const lines = ['### context continuation', '',
30
- `compacted to fit ~${budget.triggerTokens ?? 'n/a'} tokens — retained ${budget.retainedTokens ?? 0}, summarized ${budget.elidedTokens ?? 0}, referenced ${budget.referencedCount ?? 0}`];
31
- if (packet.blocker) {
32
- lines.push('', `blocker: ${packet.blocker.reason} (required ${packet.blocker.requiredTokens} > budget ${packet.blocker.budgetTokens})`);
33
- }
34
- const reconstructed = layers.filter((l) => l.sourceId || l.elided);
35
- if (reconstructed.length) {
36
- lines.push('', 'layers on rehydrate:');
37
- for (const layer of reconstructed) {
38
- if (layer.elided) lines.push(`- ${layer.kind}: summarized (elided)`);
39
- else lines.push(`- ${layer.kind}: ${layer.resolved ? `re-derived from ${layer.sourceId}` : `unresolved (${layer.sourceId})`}`);
40
- }
41
- }
42
- return lines.join('\n');
43
- }
44
-
45
- function turnToMarkdown(turn, { cwd = process.cwd() } = {}) {
46
- const lines = [`## you`, '', turn.userText || '', ''];
47
- const evidence = turn.evidence || null;
48
- if (evidence) lines.push(`evidence: ${evidence.status}${evidence.reasonCodes?.length ? ` (${evidence.reasonCodes.join(', ')})` : ''}`, '');
49
- const src = summarizeSources(evidence?.records?.map((record) => ({ tool: record.tool, ref: record.target })) || turn.sources || []);
50
- if (src.total) {
51
- lines.push(`sources: ${src.refs.join(', ')}`, '');
52
- }
53
- lines.push('## construct', '', turn.assistant || '(no answer)', '');
54
- if (turn.continuation) {
55
- const cont = continuationToMarkdown(turn.continuation, { cwd });
56
- if (cont) lines.push('', cont, '');
57
- }
58
- return lines.join('\n');
59
- }
60
-
61
- export function exportTurns(turnBlocks, { scope = 'last', cwd = process.cwd() } = {}) {
62
- const turns = turnBlocks.filter((item) => item.kind === 'turn').map((item) => item.block);
63
- if (!turns.length) return { ok: false, error: 'no turns to export' };
64
-
65
- let selected = turns;
66
- if (scope === 'last') selected = [turns[turns.length - 1]];
67
- else if (scope === 'turn' && turns.length) selected = [turns[turns.length - 1]];
68
-
69
- const body = selected.map((turn) => turnToMarkdown(turn, { cwd })).join('\n---\n\n');
70
- const stamp = new Date().toISOString().replace(/[:.]/g, '-');
71
- const file = path.join(exportDir({ cwd }), `${stamp}-${scope}-answer.md`);
72
- fs.writeFileSync(file, `${body}\n`, 'utf8');
73
- return { ok: true, path: file, count: selected.length };
74
- }
@@ -1,91 +0,0 @@
1
- /**
2
- * lib/chat/harness/driver.mjs — normalized harness driver contract for the
3
- * construct terminal chat surface.
4
- *
5
- * A driver runs the agent loop and normalizes its streaming output into one event
6
- * model, so the transparency engine and the TUI never depend on how the loop is
7
- * produced. ADR-0041: Construct's owned loop (apps/chat/engine) implements this
8
- * contract; the union stays the stable seam between the engine and the renderers.
9
- * Every driver exposes the same shape:
10
- * start() opens a session and returns { sessionId, capabilities }
11
- * prompt(text, opts) async-iterable of normalized events for one turn; opts may
12
- * carry { model, sandbox, permissionMode } when the host supports them
13
- * cancel() aborts the active turn
14
- * stop() tears down the host process / connection
15
- * listModels() optional: returns [{ id, label, ... }] when the host can enumerate models
16
- *
17
- * Normalized event union consumed by the rest of the surface:
18
- * { type: 'thinking', text, messageId } agent internal reasoning chunk
19
- * { type: 'text', text, messageId } agent message chunk
20
- * { type: 'plan', entries } planned path / task entries
21
- * { type: 'tool_call', id, title, kind, status }
22
- * { type: 'tool_update', id, status, content }
23
- * { type: 'usage', tokens, cost, context, model }
24
- * tokens: { input, output, cacheRead, cacheWrite, reasoning, total }
25
- * cost: { amount, currency } context: { used, size }
26
- * every field optional — adapters emit only what the host
27
- * reports (no fabricated splits)
28
- * { type: 'specialist', role, status, detail } construct orchestration overlay
29
- * { type: 'permission', requestId, toolCall, options }
30
- * { type: 'notice', level, code, message } surface-visible advisory (e.g. context-pressure)
31
- * { type: 'context_continuation', packet, compacted } persisted continuation packet (construct-6zga.1.10)
32
- * { type: 'error', message }
33
- * { type: 'done', stopReason }
34
- *
35
- * Keeping this union stable is what lets ACP agents and per-host adapters be
36
- * swapped without touching the transparency or rendering layers.
37
- */
38
-
39
- export const EVENT_TYPES = Object.freeze({
40
- THINKING: 'thinking',
41
- TEXT: 'text',
42
- PLAN: 'plan',
43
- TOOL_CALL: 'tool_call',
44
- TOOL_UPDATE: 'tool_update',
45
- USAGE: 'usage',
46
- SPECIALIST: 'specialist',
47
- PERMISSION: 'permission',
48
- NOTICE: 'notice',
49
- CONTEXT_CONTINUATION: 'context_continuation',
50
- ERROR: 'error',
51
- DONE: 'done',
52
- });
53
-
54
- // A single-producer/single-consumer queue that is also an async iterable. The
55
- // line-router pushes normalized events as they arrive; the turn loop awaits them
56
- // until the producer closes the queue on stop reason or error.
57
-
58
- export class AsyncEventQueue {
59
- constructor() {
60
- this.buffer = [];
61
- this.waiters = [];
62
- this.closed = false;
63
- }
64
-
65
- push(value) {
66
- if (this.closed) return;
67
- const waiter = this.waiters.shift();
68
- if (waiter) waiter({ value, done: false });
69
- else this.buffer.push(value);
70
- }
71
-
72
- close() {
73
- if (this.closed) return;
74
- this.closed = true;
75
- while (this.waiters.length) this.waiters.shift()({ value: undefined, done: true });
76
- }
77
-
78
- [Symbol.asyncIterator]() {
79
- return {
80
- next: () => {
81
- if (this.buffer.length) return Promise.resolve({ value: this.buffer.shift(), done: false });
82
- if (this.closed) return Promise.resolve({ value: undefined, done: true });
83
- return new Promise((resolve) => this.waiters.push(resolve));
84
- },
85
- return: () => {
86
- this.close();
87
- return Promise.resolve({ value: undefined, done: true });
88
- },
89
- };
90
- }
91
- }
@@ -1,112 +0,0 @@
1
- /**
2
- * lib/chat/list-picker.mjs — searchable list picker for construct chat Ink.
3
- *
4
- * Pure state/helpers for arrow-key overlays: type-to-filter, windowed viewport,
5
- * and selection index clamping for model, setting, and permission pickers.
6
- */
7
-
8
- export function filterPickerItems(items = [], query = '') {
9
- const q = String(query || '').trim().toLowerCase();
10
- if (!q) return items;
11
- return items.filter((item) => {
12
- const hay = [item.id, item.label, item.detail, item.tag]
13
- .filter(Boolean)
14
- .join(' ')
15
- .toLowerCase();
16
- return hay.includes(q);
17
- });
18
- }
19
-
20
- export function pickerStartIndex(items, selectedId, idKey = 'id') {
21
- if (!items?.length) return 0;
22
- const idx = items.findIndex((item) => item[idKey] === selectedId);
23
- if (idx >= 0 && !items[idx]?.disabled) return idx;
24
- const firstEnabled = items.findIndex((item) => !item.disabled);
25
- if (firstEnabled >= 0) return firstEnabled;
26
- return idx >= 0 ? idx : 0;
27
- }
28
-
29
- export function windowPickerItems(items, index, windowSize = 12) {
30
- if (!items?.length) return { items: [], offset: 0 };
31
- const size = Math.max(5, windowSize);
32
- let start = Math.max(0, index - Math.floor(size / 2));
33
- if (start + size > items.length) start = Math.max(0, items.length - size);
34
- return { items: items.slice(start, start + size), offset: start };
35
- }
36
-
37
- export function clampPickerIndex(state) {
38
- const visible = filterPickerItems(state.items, state.query);
39
- const max = Math.max(0, visible.length - 1);
40
- return { ...state, index: Math.min(state.index, max) };
41
- }
42
-
43
- /**
44
- * @param {{
45
- * kind?: string,
46
- * title?: string,
47
- * items?: Array<Record<string, unknown>>,
48
- * selectedId?: string | null,
49
- * context?: string | null,
50
- * query?: string,
51
- * }} [opts]
52
- */
53
- export function createListPickerState({
54
- kind, title, items, selectedId = null, context = null, query = '',
55
- } = {}) {
56
- const visible = filterPickerItems(items, query);
57
- return {
58
- kind,
59
- title,
60
- items,
61
- query,
62
- index: pickerStartIndex(visible, selectedId),
63
- context,
64
- };
65
- }
66
-
67
- export function getPickerVisibleItems(state) {
68
- return filterPickerItems(state?.items || [], state?.query || '');
69
- }
70
-
71
- export function getPickerSelectedItem(state) {
72
- const visible = getPickerVisibleItems(state);
73
- return visible[state?.index ?? 0] || null;
74
- }
75
-
76
- export function movePickerIndex(state, delta) {
77
- const visible = getPickerVisibleItems(state);
78
- if (!visible.length) return state;
79
- let idx = state.index ?? 0;
80
- for (let step = 0; step < visible.length; step++) {
81
- idx = Math.max(0, Math.min(visible.length - 1, idx + delta));
82
- if (!visible[idx]?.disabled) return { ...state, index: idx };
83
- if ((delta < 0 && idx === 0) || (delta > 0 && idx === visible.length - 1)) break;
84
- }
85
- return { ...state, index: idx };
86
- }
87
-
88
- export function appendPickerQuery(state, char) {
89
- if (!char) return state;
90
- return clampPickerIndex({ ...state, query: `${state.query || ''}${char}`, index: 0 });
91
- }
92
-
93
- export function backspacePickerQuery(state) {
94
- return clampPickerIndex({ ...state, query: (state.query || '').slice(0, -1), index: 0 });
95
- }
96
-
97
- export function reducePickerKey(state, { char, key } = {}) {
98
- if (!state) return { state: null, action: 'none' };
99
- if (key?.escape) return { state: null, action: 'cancel' };
100
- if (key?.return) return { state, action: 'commit' };
101
- if (key?.upArrow) return { state: movePickerIndex(state, -1), action: 'none' };
102
- if (key?.downArrow) return { state: movePickerIndex(state, 1), action: 'none' };
103
- if (key?.backspace || key?.delete) return { state: backspacePickerQuery(state), action: 'none' };
104
- if (char && !key?.ctrl && !key?.meta) return { state: appendPickerQuery(state, char), action: 'none' };
105
- return { state, action: 'none' };
106
- }
107
-
108
- export function pickerViewport(state, windowSize = 14) {
109
- const visible = getPickerVisibleItems(state);
110
- const clamped = clampPickerIndex({ ...state, items: visible });
111
- return windowPickerItems(visible, clamped.index, windowSize);
112
- }