@geraldmaron/construct 1.2.3 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (505) hide show
  1. package/README.md +7 -10
  2. package/bin/construct +235 -209
  3. package/bin/construct-postinstall.mjs +0 -21
  4. package/commands/work/optimize-prompts.md +1 -1
  5. package/examples/distribution/sources/adr.md +2 -2
  6. package/examples/seed-observations/decisions.md +1 -1
  7. package/lib/artifact-loop-core.mjs +412 -0
  8. package/lib/artifact-manifest.mjs +6 -0
  9. package/lib/artifact-release-gate.mjs +115 -49
  10. package/lib/audit-rules.mjs +2 -4
  11. package/lib/audit-skills.mjs +32 -20
  12. package/lib/audit-specialists.mjs +44 -26
  13. package/lib/auto-docs.mjs +6 -5
  14. package/lib/brand-prose.mjs +3 -3
  15. package/lib/brand-tokens.mjs +2 -2
  16. package/lib/certification/artifact-fixtures.mjs +4 -1
  17. package/lib/certification/demo-parity.mjs +6 -32
  18. package/lib/certification/real-llm-scenarios.mjs +58 -13
  19. package/lib/certification/role-cards.mjs +7 -6
  20. package/lib/certification/role-overlays.mjs +4 -4
  21. package/lib/certification/runner.mjs +9 -2
  22. package/lib/certification/skill-inventory.mjs +34 -22
  23. package/lib/certification/skill-scenarios.mjs +21 -8
  24. package/lib/certification/specialist-contracts.mjs +4 -3
  25. package/lib/certification/specialist-scenarios.mjs +7 -6
  26. package/lib/certification/status.mjs +5 -4
  27. package/lib/cli-commands.mjs +55 -54
  28. package/lib/comment-lint.mjs +1 -5
  29. package/lib/completions.mjs +20 -2
  30. package/lib/config/legacy-config-migration.mjs +90 -24
  31. package/lib/config/schema.mjs +5 -5
  32. package/lib/config/source-targets.mjs +80 -0
  33. package/lib/contracts/validate.mjs +119 -51
  34. package/lib/decisions/golden.mjs +3 -2
  35. package/lib/decisions/registry.mjs +11 -6
  36. package/lib/demo-project.mjs +188 -0
  37. package/lib/demo-recording.mjs +9 -34
  38. package/lib/demo-script.mjs +2 -2
  39. package/lib/demo-surface.mjs +13 -131
  40. package/lib/demo-tour-renderer.mjs +92 -0
  41. package/lib/demo.mjs +69 -54
  42. package/lib/diagram-export.mjs +63 -14
  43. package/lib/doctor/cli.mjs +12 -2
  44. package/lib/doctor/source-checkout.mjs +3 -4
  45. package/lib/doctor/watchers/consistency.mjs +148 -43
  46. package/lib/doctor/watchers/credential-parity.mjs +97 -0
  47. package/lib/doctor/watchers/mcp-protocol.mjs +1 -1
  48. package/lib/doctor/watchers/service-health.mjs +4 -32
  49. package/lib/document-export.mjs +73 -9
  50. package/lib/document-extract.mjs +10 -198
  51. package/lib/embed/artifact.mjs +2 -3
  52. package/lib/embed/cli.mjs +1 -1
  53. package/lib/embed/config.mjs +1 -2
  54. package/lib/embed/customer-profiles.mjs +1 -1
  55. package/lib/embed/daemon.mjs +5 -6
  56. package/lib/embed/demand-fetch.mjs +114 -2
  57. package/lib/embed/docs-lifecycle.mjs +9 -5
  58. package/lib/embed/intake-metrics.mjs +2 -2
  59. package/lib/embed/notifications.mjs +2 -3
  60. package/lib/embed/recommendation-store.mjs +25 -22
  61. package/lib/embed/role-framing.mjs +4 -9
  62. package/lib/embedded-contract/capability.mjs +4 -2
  63. package/lib/embedded-contract/contract-version.mjs +1 -1
  64. package/lib/env-config.mjs +2 -2
  65. package/lib/flavors/loader.mjs +21 -19
  66. package/lib/graph/build-from-registry.mjs +31 -7
  67. package/lib/graph/staleness.mjs +1 -1
  68. package/lib/headhunt.mjs +82 -35
  69. package/lib/hooks/agent-tracker.mjs +2 -2
  70. package/lib/hooks/config-protection.mjs +1 -1
  71. package/lib/hooks/registry-sync.mjs +3 -3
  72. package/lib/host-capabilities.mjs +5 -5
  73. package/lib/improvement/controller.mjs +2 -2
  74. package/lib/init-unified.mjs +19 -21
  75. package/lib/intake/classify.mjs +26 -0
  76. package/lib/intake/daemon.mjs +2 -3
  77. package/lib/intake/prepare.mjs +10 -3
  78. package/lib/intake/session-prelude.mjs +1 -1
  79. package/lib/intake/tables/creative.mjs +9 -9
  80. package/lib/intake/tables/operations.mjs +4 -4
  81. package/lib/intake/tables/research.mjs +2 -2
  82. package/lib/integrations/intake-integrations.mjs +9 -10
  83. package/lib/knowledge/research-store.mjs +2 -2
  84. package/lib/mcp/server.mjs +104 -61
  85. package/lib/mcp/tool-budget.mjs +1 -46
  86. package/lib/mcp/tool-recovery.mjs +44 -0
  87. package/lib/mcp/tools/artifact-author.mjs +36 -0
  88. package/lib/mcp/tools/find-tool.mjs +86 -0
  89. package/lib/mcp/tools/orchestration-run.mjs +107 -69
  90. package/lib/mcp/tools/project.mjs +4 -3
  91. package/lib/mcp/tools/{profile.mjs → scope.mjs} +54 -52
  92. package/lib/mcp/tools/skills.mjs +39 -22
  93. package/lib/mcp/tools/telemetry.mjs +2 -1
  94. package/lib/mcp/tools/workflow.mjs +1 -1
  95. package/lib/mcp-platform-config.mjs +7 -5
  96. package/lib/migrations/index.mjs +4 -2
  97. package/lib/migrations/v2-unified-registry.mjs +35 -0
  98. package/lib/model-router.mjs +203 -36
  99. package/lib/models/catalog.mjs +25 -9
  100. package/lib/models/execution-capability-profile.mjs +3 -3
  101. package/lib/models/execution-policy.mjs +7 -6
  102. package/lib/models/provider-poll.mjs +18 -4
  103. package/lib/opencode-config.mjs +56 -1
  104. package/lib/opencode-runtime-plugin.mjs +13 -10
  105. package/lib/oracle/artifact-gate.mjs +14 -4
  106. package/lib/oracle/cli.mjs +2 -0
  107. package/lib/oracle/dispatch.mjs +18 -1
  108. package/lib/oracle/execute.mjs +39 -7
  109. package/lib/oracle/index.mjs +1 -1
  110. package/lib/oracle/org-graph.mjs +10 -5
  111. package/lib/oracle/policy.mjs +6 -0
  112. package/lib/oracle/read-model.mjs +103 -6
  113. package/lib/oracle/reconcile.mjs +31 -4
  114. package/lib/oracle/remediation-dispatch.mjs +53 -0
  115. package/lib/oracle/routing.mjs +5 -0
  116. package/lib/oracle/synthesize.mjs +80 -3
  117. package/lib/orchestration/routing-tables.mjs +44 -10
  118. package/lib/orchestration/runtime.mjs +2 -0
  119. package/lib/orchestration/worker.mjs +1 -1
  120. package/lib/orchestration-policy.mjs +351 -62
  121. package/lib/overrides/resolver.mjs +1 -12
  122. package/lib/parity.mjs +37 -11
  123. package/lib/policy/engine.mjs +80 -15
  124. package/lib/prompt-composer.js +51 -15
  125. package/lib/prompt-metadata.mjs +3 -2
  126. package/lib/providers/connection-probe.mjs +58 -0
  127. package/lib/providers/copilot-auth.mjs +1 -1
  128. package/lib/providers/credential-bootstrap.mjs +1 -1
  129. package/lib/providers/op-run.mjs +3 -4
  130. package/lib/providers/secret-resolver.mjs +31 -0
  131. package/lib/publish-tooling.mjs +3 -11
  132. package/lib/publish.mjs +12 -29
  133. package/lib/reconcile/mcp-entry-reconcile.mjs +14 -9
  134. package/lib/reflect.mjs +2 -2
  135. package/lib/registry/agent-manifest.mjs +190 -0
  136. package/lib/registry/assemble.mjs +133 -0
  137. package/lib/registry/catalog.mjs +171 -0
  138. package/lib/registry/cli.mjs +590 -6
  139. package/lib/registry/consolidation.mjs +5 -4
  140. package/lib/registry/docs-sync.mjs +67 -0
  141. package/lib/registry/loader.mjs +147 -0
  142. package/lib/registry/org-io.mjs +76 -0
  143. package/lib/registry/retired-paths.mjs +71 -0
  144. package/lib/registry/surface-map.mjs +5 -7
  145. package/lib/registry/validator.mjs +438 -0
  146. package/lib/research-execution-policy.mjs +173 -0
  147. package/lib/roles/catalog.mjs +4 -9
  148. package/lib/roles/fence.mjs +107 -1
  149. package/lib/roles/flavor-bindings.mjs +68 -0
  150. package/lib/roles/gateway.mjs +140 -29
  151. package/lib/roles/manifest.mjs +22 -13
  152. package/lib/roles/router.mjs +1 -1
  153. package/lib/scopes/enrich.mjs +67 -0
  154. package/lib/scopes/hooks.mjs +12 -0
  155. package/lib/{profiles → scopes}/lifecycle.mjs +70 -70
  156. package/lib/scopes/loader.mjs +104 -0
  157. package/lib/scopes/rebrand.mjs +32 -0
  158. package/lib/scopes/research-profile.mjs +16 -0
  159. package/lib/scopes/teams.mjs +98 -0
  160. package/lib/service-manager.mjs +1 -117
  161. package/lib/setup-prompts.mjs +1 -1
  162. package/lib/setup.mjs +6 -26
  163. package/lib/skills/composition-graph.mjs +98 -0
  164. package/lib/skills/router.mjs +80 -0
  165. package/lib/specialist-contracts.mjs +17 -18
  166. package/lib/specialists/postconditions.mjs +2 -2
  167. package/lib/specialists/prompt-schema.mjs +6 -5
  168. package/lib/specialists/roster.mjs +7 -12
  169. package/lib/specialists/schema.mjs +9 -6
  170. package/lib/status.mjs +25 -90
  171. package/lib/storage/file-lock.mjs +6 -3
  172. package/lib/telemetry/skill-calls.mjs +1 -1
  173. package/lib/templates/doc-presentation.mjs +63 -0
  174. package/lib/templates/visual-requirements.mjs +35 -2
  175. package/lib/term-format.mjs +107 -2
  176. package/lib/test-env-setup.mjs +21 -0
  177. package/lib/ui/components.mjs +42 -0
  178. package/lib/ui/glyphs.mjs +58 -0
  179. package/lib/ui/links.mjs +115 -0
  180. package/lib/ui/theme.mjs +108 -0
  181. package/lib/uninstall/uninstall.mjs +2 -1
  182. package/lib/validator.mjs +45 -8
  183. package/lib/validators/skill-effectiveness.mjs +174 -0
  184. package/lib/validators/skills.mjs +1 -1
  185. package/package.json +12 -8
  186. package/personas/construct.md +12 -3
  187. package/platforms/claude/CLAUDE.md +1 -1
  188. package/rules/common/beads-hygiene.md +52 -0
  189. package/rules/common/neurodivergent-output.md +4 -7
  190. package/rules/common/research.md +2 -0
  191. package/scripts/sync-specialists.mjs +269 -51
  192. package/skills/ai/prompt-optimizer.md +3 -3
  193. package/skills/brand/output-vibe.md +48 -0
  194. package/skills/docs/adr-workflow.md +3 -0
  195. package/skills/docs/backlog-proposal-workflow.md +3 -0
  196. package/skills/docs/codebase-research-workflow.md +5 -2
  197. package/skills/docs/customer-profile-workflow.md +3 -0
  198. package/skills/docs/document-ingest-workflow.md +3 -0
  199. package/skills/docs/evidence-ingest-workflow.md +4 -1
  200. package/skills/docs/init-project.md +1 -1
  201. package/skills/docs/prd-workflow.md +1 -1
  202. package/skills/docs/prfaq-workflow.md +3 -0
  203. package/skills/docs/product-intelligence-workflow.md +4 -1
  204. package/skills/docs/product-signal-workflow.md +3 -0
  205. package/skills/docs/research-workflow.md +13 -6
  206. package/skills/docs/runbook-workflow.md +3 -0
  207. package/skills/docs/strategy-workflow.md +3 -0
  208. package/skills/docs/user-research-workflow.md +6 -3
  209. package/skills/operating/orchestration-reference.md +1 -1
  210. package/skills/roles/{engineer.ai.md → ai-engineer.md} +2 -2
  211. package/skills/roles/architect.ai-systems.md +1 -1
  212. package/skills/roles/architect.data.md +1 -1
  213. package/skills/roles/architect.enterprise.md +1 -1
  214. package/skills/roles/architect.integration.md +1 -1
  215. package/skills/roles/architect.md +1 -1
  216. package/skills/roles/architect.platform.md +1 -1
  217. package/skills/roles/{product-manager.business-strategy.md → business-strategist.md} +3 -3
  218. package/skills/roles/data-analyst.experiment.md +1 -1
  219. package/skills/roles/data-analyst.md +1 -1
  220. package/skills/roles/data-analyst.product-intelligence.md +1 -1
  221. package/skills/roles/data-analyst.product.md +1 -1
  222. package/skills/roles/data-analyst.telemetry.md +1 -1
  223. package/skills/roles/{engineer.data.md → data-engineer.md} +2 -2
  224. package/skills/roles/data-engineer.pipeline.md +2 -2
  225. package/skills/roles/data-engineer.vector-retrieval.md +2 -2
  226. package/skills/roles/data-engineer.warehouse.md +2 -2
  227. package/skills/roles/debugger.md +1 -1
  228. package/skills/roles/designer.accessibility.md +1 -1
  229. package/skills/roles/designer.md +1 -1
  230. package/skills/roles/{reviewer.devil-advocate.md → devil-advocate.md} +2 -2
  231. package/skills/roles/{operator.docs.md → docs-keeper.md} +3 -3
  232. package/skills/roles/engineer.md +3 -7
  233. package/skills/roles/{reviewer.evaluator.md → evaluator.md} +2 -2
  234. package/skills/roles/{researcher.explorer.md → explorer.md} +2 -2
  235. package/skills/roles/{operator.md → operations.md} +2 -5
  236. package/skills/roles/orchestrator.md +1 -1
  237. package/skills/roles/{engineer.platform.md → platform-engineer.md} +2 -2
  238. package/skills/roles/product-manager.ai-product.md +1 -1
  239. package/skills/roles/product-manager.enterprise.md +1 -1
  240. package/skills/roles/product-manager.growth.md +1 -2
  241. package/skills/roles/product-manager.md +1 -2
  242. package/skills/roles/product-manager.platform.md +1 -1
  243. package/skills/roles/product-manager.product.md +1 -1
  244. package/skills/roles/qa.ai-eval.md +1 -1
  245. package/skills/roles/qa.api-contract.md +1 -1
  246. package/skills/roles/qa.data-pipeline.md +1 -1
  247. package/skills/roles/qa.md +1 -1
  248. package/skills/roles/qa.web-ui.md +1 -1
  249. package/skills/roles/{operator.release.md → release-manager.md} +3 -3
  250. package/skills/roles/researcher.md +1 -1
  251. package/skills/roles/reviewer.md +1 -1
  252. package/skills/roles/security.ai.md +1 -1
  253. package/skills/roles/security.appsec.md +1 -1
  254. package/skills/roles/security.cloud.md +1 -1
  255. package/skills/roles/security.legal-compliance.md +1 -1
  256. package/skills/roles/security.md +1 -1
  257. package/skills/roles/security.privacy.md +1 -1
  258. package/skills/roles/security.supply-chain.md +1 -1
  259. package/skills/roles/{operator.sre.md → sre.md} +3 -3
  260. package/skills/roles/{qa.test-automation.md → test-automation.md} +2 -2
  261. package/skills/roles/{reviewer.trace.md → trace-reviewer.md} +2 -2
  262. package/skills/roles/{researcher.ux.md → ux-researcher.md} +2 -2
  263. package/skills/routing.json +18 -0
  264. package/skills/routing.md +1 -1
  265. package/specialists/artifact-manifest.json +2 -1
  266. package/specialists/audit-enrichments.json +14 -14
  267. package/specialists/org/contracts/accessibility-to-qa.json +37 -0
  268. package/specialists/org/contracts/any-to-business-strategist.json +57 -0
  269. package/specialists/org/contracts/any-to-debugger.json +38 -0
  270. package/specialists/org/contracts/any-to-designer.json +33 -0
  271. package/specialists/org/contracts/any-to-docs-keeper.json +34 -0
  272. package/specialists/org/contracts/any-to-explorer.json +39 -0
  273. package/specialists/org/contracts/any-to-sre-incident.json +33 -0
  274. package/specialists/org/contracts/any-to-trace-reviewer.json +32 -0
  275. package/specialists/org/contracts/architect-to-ai-engineer.json +32 -0
  276. package/specialists/org/contracts/architect-to-data-engineer.json +52 -0
  277. package/specialists/org/contracts/architect-to-devil-advocate.json +38 -0
  278. package/specialists/org/contracts/architect-to-engineer.json +34 -0
  279. package/specialists/org/contracts/architect-to-evaluator.json +59 -0
  280. package/specialists/org/contracts/architect-to-legal-compliance.json +55 -0
  281. package/specialists/org/contracts/architect-to-operations.json +45 -0
  282. package/specialists/org/contracts/architect-to-platform-engineer.json +42 -0
  283. package/specialists/org/contracts/business-strategist-to-product-manager.json +39 -0
  284. package/specialists/org/contracts/construct-to-orchestrator.json +36 -0
  285. package/specialists/org/contracts/construct-to-rd-lead.json +53 -0
  286. package/specialists/org/contracts/data-analyst-to-product-manager.json +43 -0
  287. package/specialists/org/contracts/data-engineer-to-platform-engineer.json +36 -0
  288. package/specialists/org/contracts/designer-to-accessibility.json +36 -0
  289. package/specialists/org/contracts/engineer-to-qa.json +34 -0
  290. package/specialists/org/contracts/engineer-to-reviewer.json +52 -0
  291. package/specialists/org/contracts/explorer-to-engineer.json +38 -0
  292. package/specialists/org/contracts/legal-compliance-to-release-manager.json +43 -0
  293. package/specialists/org/contracts/platform-engineer-to-engineer.json +31 -0
  294. package/specialists/org/contracts/product-manager-to-architect.json +71 -0
  295. package/specialists/org/contracts/product-manager-to-data-analyst.json +49 -0
  296. package/specialists/org/contracts/product-manager-to-ux-researcher.json +51 -0
  297. package/specialists/org/contracts/qa-to-release-manager.json +42 -0
  298. package/specialists/org/contracts/qa-to-test-automation.json +42 -0
  299. package/specialists/org/contracts/rd-lead-to-architect.json +38 -0
  300. package/specialists/org/contracts/researcher-to-architect.json +40 -0
  301. package/specialists/org/contracts/researcher-to-product-manager.json +57 -0
  302. package/specialists/org/contracts/reviewer-to-security.json +41 -0
  303. package/specialists/org/contracts/sre-to-release-manager.json +36 -0
  304. package/specialists/org/contracts/test-automation-to-engineer.json +34 -0
  305. package/specialists/org/contracts/trace-reviewer-to-sre.json +41 -0
  306. package/specialists/org/contracts/user-to-construct.json +30 -0
  307. package/specialists/org/groups/engineering-group.json +43 -0
  308. package/specialists/org/groups/governance-group.json +38 -0
  309. package/specialists/org/groups/operations-group.json +41 -0
  310. package/specialists/org/groups/product-group.json +46 -0
  311. package/specialists/org/groups/quality-group.json +42 -0
  312. package/specialists/org/groups/strategy-group.json +41 -0
  313. package/specialists/org/policies/action-approval.json +13 -0
  314. package/specialists/org/policies/agents-routing.json +13 -0
  315. package/specialists/org/policies/architecture.json +20 -0
  316. package/specialists/org/policies/bash-safety.json +13 -0
  317. package/specialists/org/policies/beads-hygiene.json +13 -0
  318. package/specialists/org/policies/bootstrap-state.json +13 -0
  319. package/specialists/org/policies/code-review.json +13 -0
  320. package/specialists/org/policies/coding-style.json +13 -0
  321. package/specialists/org/policies/comments.json +13 -0
  322. package/specialists/org/policies/commit-approval.json +13 -0
  323. package/specialists/org/policies/contract-preconditions.json +13 -0
  324. package/specialists/org/policies/deployment.json +20 -0
  325. package/specialists/org/policies/description.json +14 -0
  326. package/specialists/org/policies/design-approval.json +19 -0
  327. package/specialists/org/policies/doc-ownership.json +13 -0
  328. package/specialists/org/policies/file-path-fence.json +13 -0
  329. package/specialists/org/policies/framing.json +13 -0
  330. package/specialists/org/policies/git-workflow.json +13 -0
  331. package/specialists/org/policies/incident-response.json +15 -0
  332. package/specialists/org/policies/intake-triage.json +15 -0
  333. package/specialists/org/policies/neurodivergent-output.json +13 -0
  334. package/specialists/org/policies/no-fabrication.json +13 -0
  335. package/specialists/org/policies/patterns.json +13 -0
  336. package/specialists/org/policies/quality-gate-approval.json +17 -0
  337. package/specialists/org/policies/release-gates.json +13 -0
  338. package/specialists/org/policies/research-evidence.json +13 -0
  339. package/specialists/org/policies/review-before-change.json +13 -0
  340. package/specialists/org/policies/rollback.json +15 -0
  341. package/specialists/org/policies/scope-change.json +20 -0
  342. package/specialists/org/policies/secret-scan.json +13 -0
  343. package/specialists/org/policies/security-approval.json +17 -0
  344. package/specialists/org/policies/security.json +13 -0
  345. package/specialists/org/policies/session-efficiency.json +13 -0
  346. package/specialists/org/policies/skill-routing.json +13 -0
  347. package/specialists/org/policies/strategic-prioritization.json +17 -0
  348. package/specialists/org/policies/testing.json +13 -0
  349. package/specialists/org/policies/tool-invisibility.json +14 -0
  350. package/specialists/org/scopes/creative.json +54 -0
  351. package/specialists/org/scopes/operations.json +51 -0
  352. package/specialists/org/scopes/research.json +60 -0
  353. package/specialists/org/scopes/rnd.json +81 -0
  354. package/specialists/org/specialists/cx-accessibility.json +69 -0
  355. package/specialists/org/specialists/cx-ai-engineer.json +75 -0
  356. package/specialists/org/specialists/cx-architect.json +89 -0
  357. package/specialists/org/specialists/cx-business-strategist.json +72 -0
  358. package/specialists/org/specialists/cx-data-analyst.json +68 -0
  359. package/specialists/org/specialists/cx-data-engineer.json +71 -0
  360. package/specialists/org/specialists/cx-debugger.json +75 -0
  361. package/specialists/org/specialists/cx-designer.json +85 -0
  362. package/specialists/org/specialists/cx-devil-advocate.json +71 -0
  363. package/specialists/org/specialists/cx-docs-keeper.json +82 -0
  364. package/specialists/org/specialists/cx-engineer.json +106 -0
  365. package/specialists/org/specialists/cx-evaluator.json +69 -0
  366. package/specialists/org/specialists/cx-explorer.json +69 -0
  367. package/specialists/org/specialists/cx-legal-compliance.json +74 -0
  368. package/specialists/org/specialists/cx-operations.json +72 -0
  369. package/specialists/org/specialists/cx-oracle.json +46 -0
  370. package/specialists/org/specialists/cx-orchestrator.json +81 -0
  371. package/specialists/org/specialists/cx-platform-engineer.json +80 -0
  372. package/specialists/org/specialists/cx-product-manager.json +102 -0
  373. package/specialists/org/specialists/cx-qa.json +79 -0
  374. package/specialists/org/specialists/cx-rd-lead.json +73 -0
  375. package/specialists/org/specialists/cx-release-manager.json +77 -0
  376. package/specialists/org/specialists/cx-researcher.json +82 -0
  377. package/specialists/org/specialists/cx-reviewer.json +71 -0
  378. package/specialists/org/specialists/cx-security.json +91 -0
  379. package/specialists/org/specialists/cx-sre.json +94 -0
  380. package/specialists/org/specialists/cx-test-automation.json +69 -0
  381. package/specialists/org/specialists/cx-trace-reviewer.json +69 -0
  382. package/specialists/org/specialists/cx-ux-researcher.json +68 -0
  383. package/specialists/org/teams/accessibility-team.json +39 -0
  384. package/specialists/org/teams/design-team.json +40 -0
  385. package/specialists/org/teams/engineering-team.json +50 -0
  386. package/specialists/org/teams/governance-team.json +41 -0
  387. package/specialists/org/teams/operations-team.json +46 -0
  388. package/specialists/org/teams/product-management-team.json +45 -0
  389. package/specialists/org/teams/quality-team.json +49 -0
  390. package/specialists/org/teams/research-team.json +39 -0
  391. package/specialists/org/teams/strategy-team.json +48 -0
  392. package/specialists/org/teams/ux-research-team.json +39 -0
  393. package/specialists/prompts/_shared/validation-contract.md +1 -1
  394. package/specialists/prompts/_team-template.md +10 -0
  395. package/specialists/prompts/cx-accessibility.md +1 -0
  396. package/specialists/prompts/cx-ai-engineer.md +1 -1
  397. package/specialists/prompts/cx-business-strategist.md +1 -1
  398. package/specialists/prompts/cx-data-engineer.md +1 -1
  399. package/specialists/prompts/cx-designer.md +1 -0
  400. package/specialists/prompts/cx-devil-advocate.md +1 -1
  401. package/specialists/prompts/cx-docs-keeper.md +1 -1
  402. package/specialists/prompts/cx-evaluator.md +1 -1
  403. package/specialists/prompts/cx-explorer.md +1 -1
  404. package/specialists/prompts/cx-operations.md +1 -1
  405. package/specialists/prompts/cx-oracle.md +7 -3
  406. package/specialists/prompts/cx-orchestrator.md +17 -1
  407. package/specialists/prompts/cx-platform-engineer.md +1 -1
  408. package/specialists/prompts/cx-product-manager.md +2 -0
  409. package/specialists/prompts/cx-release-manager.md +1 -1
  410. package/specialists/prompts/cx-researcher.md +7 -4
  411. package/specialists/prompts/cx-sre.md +1 -1
  412. package/specialists/prompts/cx-test-automation.md +2 -2
  413. package/specialists/prompts/cx-trace-reviewer.md +3 -3
  414. package/specialists/prompts/cx-ux-researcher.md +2 -1
  415. package/templates/demos/scripts/architecture-review-adr.json +30 -0
  416. package/templates/demos/scripts/capability-contract.json +25 -0
  417. package/templates/demos/scripts/intake-triage.json +25 -0
  418. package/templates/demos/scripts/profile-doctor-health.json +25 -0
  419. package/templates/demos/tapes/agentic-platforms-prd.tape +2 -2
  420. package/templates/demos/tapes/architecture-review-adr.tape +44 -0
  421. package/templates/demos/tapes/capability-contract.tape +39 -0
  422. package/templates/demos/tapes/intake-triage.tape +39 -0
  423. package/templates/demos/tapes/profile-doctor-health.tape +39 -0
  424. package/templates/distribution/construct-brand.typ +23 -18
  425. package/templates/distribution/construct-decision.typ +1 -1
  426. package/templates/distribution/construct-pdf.typ +1 -1
  427. package/templates/distribution/construct-prd.typ +1 -1
  428. package/templates/distribution/construct-research.typ +1 -1
  429. package/templates/distribution/mermaid-puppeteer.json +8 -0
  430. package/templates/docs/persona-artifact.md +1 -1
  431. package/templates/docs/prd.md +6 -0
  432. package/apps/chat/engine/ai-sdk-agent.mjs +0 -183
  433. package/apps/chat/engine/loop-driver.mjs +0 -211
  434. package/apps/chat/engine/models.mjs +0 -122
  435. package/apps/chat/engine/provider-adapters.mjs +0 -171
  436. package/apps/chat/engine/tools/permission.mjs +0 -54
  437. package/apps/chat/engine/tools/primitives.mjs +0 -180
  438. package/apps/chat/engine/tools/registry.mjs +0 -122
  439. package/apps/chat/engine/turn-controls.mjs +0 -70
  440. package/lib/boundary.mjs +0 -127
  441. package/lib/certification/dashboard-api.mjs +0 -71
  442. package/lib/chat/cli.mjs +0 -333
  443. package/lib/chat/command-suggest.mjs +0 -161
  444. package/lib/chat/commands.mjs +0 -215
  445. package/lib/chat/config.mjs +0 -142
  446. package/lib/chat/context-compactor.mjs +0 -250
  447. package/lib/chat/context-continuation.mjs +0 -253
  448. package/lib/chat/continuation-source.mjs +0 -58
  449. package/lib/chat/demo-guide.mjs +0 -61
  450. package/lib/chat/design-tokens.mjs +0 -91
  451. package/lib/chat/desktop-binary.mjs +0 -81
  452. package/lib/chat/desktop-build.mjs +0 -130
  453. package/lib/chat/desktop-launcher.mjs +0 -133
  454. package/lib/chat/evidence.mjs +0 -145
  455. package/lib/chat/export.mjs +0 -74
  456. package/lib/chat/harness/driver.mjs +0 -91
  457. package/lib/chat/list-picker.mjs +0 -112
  458. package/lib/chat/model-picker.mjs +0 -356
  459. package/lib/chat/openrouter-fallback.mjs +0 -151
  460. package/lib/chat/permission-prompt.mjs +0 -33
  461. package/lib/chat/picker-catalog.mjs +0 -45
  462. package/lib/chat/policy-telemetry.mjs +0 -34
  463. package/lib/chat/present.mjs +0 -246
  464. package/lib/chat/session-context.mjs +0 -39
  465. package/lib/chat/session-persist.mjs +0 -73
  466. package/lib/chat/session-restore.mjs +0 -71
  467. package/lib/chat/session-settings.mjs +0 -53
  468. package/lib/chat/system-prompt.mjs +0 -52
  469. package/lib/chat/transparency.mjs +0 -93
  470. package/lib/chat/tui/color-scheme.mjs +0 -42
  471. package/lib/chat/tui/markdown.mjs +0 -123
  472. package/lib/chat/tui/presentation.mjs +0 -100
  473. package/lib/chat/tui/render.mjs +0 -500
  474. package/lib/chat/tui/turn-block.mjs +0 -284
  475. package/lib/chat/tui/turn-present.mjs +0 -18
  476. package/lib/chat/tui/turn-state.mjs +0 -88
  477. package/lib/chat/tui/usage.mjs +0 -122
  478. package/lib/chat/web-commands.mjs +0 -146
  479. package/lib/chat/web-launcher.mjs +0 -63
  480. package/lib/chat/web-picker-keys.mjs +0 -46
  481. package/lib/chat/web-session.mjs +0 -159
  482. package/lib/config/alias.mjs +0 -57
  483. package/lib/dashboard-demo.mjs +0 -71
  484. package/lib/dashboard-static.mjs +0 -175
  485. package/lib/install/desktop-binary-download.mjs +0 -88
  486. package/lib/profiles/loader.mjs +0 -123
  487. package/lib/profiles/rebrand.mjs +0 -46
  488. package/lib/server/auth.mjs +0 -169
  489. package/lib/server/chat-loop.mjs +0 -622
  490. package/lib/server/chat.mjs +0 -336
  491. package/lib/server/cors.mjs +0 -77
  492. package/lib/server/csrf.mjs +0 -103
  493. package/lib/server/demo-preview.mjs +0 -63
  494. package/lib/server/index.mjs +0 -2641
  495. package/lib/server/insights.mjs +0 -780
  496. package/lib/server/langfuse-login.mjs +0 -58
  497. package/lib/server/rate-limit.mjs +0 -93
  498. package/lib/server/telemetry-login.mjs +0 -100
  499. package/lib/server/webhook.mjs +0 -512
  500. package/specialists/contracts.json +0 -1032
  501. package/specialists/contracts.schema.json +0 -83
  502. package/specialists/policy-inventory.json +0 -188
  503. package/specialists/registry.json +0 -1412
  504. package/specialists/role-manifests.json +0 -217
  505. package/specialists/teams.json +0 -94
@@ -1,71 +0,0 @@
1
- /**
2
- * lib/chat/session-restore.mjs — resume prior construct chat sessions from jsonl.
3
- *
4
- * Session timelines persist under .cx/chat-sessions/*.jsonl. Transcript rows use
5
- * { type: 'transcript_block', block } for turn fidelity or legacy { type:
6
- * 'transcript', role, text }; usage events replay into the shared usage
7
- * accumulator so /usage and the session dock stay truthful after --resume.
8
- */
9
-
10
- import fs from 'node:fs';
11
- import path from 'node:path';
12
- import { resolveProjectScopedPath } from '../project-root.mjs';
13
- import { createSessionUsage, addUsage } from './tui/usage.mjs';
14
- import { restoreBlocksFromSessionLines, turnBlocksToLegacyTranscript } from './tui/turn-block.mjs';
15
- import { rehydrateContinuation } from './context-continuation.mjs';
16
- import { createContinuationResolver } from './continuation-source.mjs';
17
-
18
- export function sessionDir({ cwd = process.cwd() } = {}) {
19
- return resolveProjectScopedPath('chat-sessions', { cwd, ensureDir: false });
20
- }
21
-
22
- export function listSessionFiles({ cwd = process.cwd() } = {}) {
23
- const dir = sessionDir({ cwd });
24
- if (!dir || !fs.existsSync(dir)) return [];
25
- return fs.readdirSync(dir)
26
- .filter((name) => name.endsWith('.jsonl'))
27
- .map((name) => path.join(dir, name))
28
- .sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
29
- }
30
-
31
- export function resolveResumePath({ cwd = process.cwd(), resume = null } = {}) {
32
- if (resume == null || resume === false) return null;
33
- if (typeof resume === 'string' && resume !== 'true' && resume !== '') {
34
- const direct = path.resolve(resume);
35
- return fs.existsSync(direct) ? direct : null;
36
- }
37
- return listSessionFiles({ cwd })[0] || null;
38
- }
39
-
40
- export function restoreFromSession(filePath, { cwd = process.cwd() } = {}) {
41
- const turnBlocks = [];
42
- const usage = createSessionUsage();
43
- if (!filePath || !fs.existsSync(filePath)) {
44
- return { turnBlocks, transcript: [], usage, sessionFile: null, continuations: [] };
45
- }
46
-
47
- const lines = fs.readFileSync(filePath, 'utf8').split('\n').filter((l) => l.trim());
48
- for (const line of lines) {
49
- let event;
50
- try { event = JSON.parse(line); } catch { continue; }
51
- if (event.type === 'usage') addUsage(usage, event);
52
- }
53
-
54
- const blocks = restoreBlocksFromSessionLines(lines);
55
- for (const item of blocks) {
56
- if (item.kind === 'turn' || item.kind === 'legacy') turnBlocks.push(item);
57
- }
58
-
59
- // Resume rehydrates any persisted continuation packet through the one shared
60
- // resolver (AC3), so a resumed session reconstructs the same reconstructible
61
- // layers — via the same composer — that the live and export surfaces use.
62
- const resolver = createContinuationResolver({ cwd });
63
- const continuations = [];
64
- for (const item of turnBlocks) {
65
- const packet = item?.block?.continuation;
66
- if (packet) continuations.push({ packet, layers: rehydrateContinuation(packet, { resolveSource: resolver.resolveSource }) });
67
- }
68
-
69
- const transcript = turnBlocksToLegacyTranscript(turnBlocks);
70
- return { turnBlocks, transcript, usage, sessionFile: filePath, continuations };
71
- }
@@ -1,53 +0,0 @@
1
- /**
2
- * lib/chat/session-settings.mjs — apply validated chat settings to session + config.
3
- *
4
- * Shared by slash commands and Ink list pickers so /set and picker commits stay aligned.
5
- */
6
-
7
- import { saveChatConfig, validateSetting } from './config.mjs';
8
-
9
- export function applySessionSetting(session, layers, key, rawValue, { cwd, hostId = 'construct' } = {}) {
10
- const result = validateSetting(key, rawValue);
11
- if (!result.ok) return result;
12
-
13
- const targetKey = result.key || key;
14
- if (targetKey.startsWith('layers.')) {
15
- const layer = targetKey.slice('layers.'.length);
16
- layers[layer] = result.value;
17
- session.layers = { ...layers };
18
- } else if (targetKey === 'thinking') {
19
- layers.thinking = result.value;
20
- session.layers = { ...layers };
21
- session.thinking = result.value;
22
- } else if (targetKey === 'model') {
23
- session.model = result.value;
24
- session.modelMode = 'pinned';
25
- session.savedModel = result.value;
26
- session.modelNotice = null;
27
- } else if (targetKey === 'permissionMode') {
28
- session.permissionMode = result.value;
29
- } else if (targetKey === 'sandbox') {
30
- session.sandbox = result.value;
31
- } else if (targetKey === 'ui.ascii') {
32
- session.ui = { ...(session.ui || { ascii: false, inspector: 'auto', theme: 'auto' }), ascii: result.value };
33
- } else if (targetKey === 'ui.inspector') {
34
- session.ui = { ...(session.ui || { ascii: false, inspector: 'auto', theme: 'auto' }), inspector: result.value };
35
- } else if (targetKey === 'ui.theme') {
36
- session.ui = { ...(session.ui || { ascii: false, inspector: 'auto', theme: 'auto' }), theme: result.value };
37
- }
38
-
39
- try {
40
- saveChatConfig({
41
- host: hostId,
42
- model: session.modelMode === 'pinned' ? session.model : null,
43
- modelMode: session.modelMode || 'pinned',
44
- layers,
45
- thinking: layers?.thinking,
46
- permissionMode: session.permissionMode,
47
- sandbox: session.sandbox,
48
- ui: session.ui,
49
- }, { cwd });
50
- } catch { /* persistence is best-effort */ }
51
-
52
- return { ok: true, key: targetKey, value: result.value };
53
- }
@@ -1,52 +0,0 @@
1
- /**
2
- * lib/chat/system-prompt.mjs — owned-loop system prompt for construct chat.
3
- *
4
- * Keeps a short Construct identity and research discipline without inlining the
5
- * full orchestrator persona. Turn-scoped policy text is injected per prompt by
6
- * the engine when an overlay is present.
7
- */
8
-
9
- export const CHAT_SYSTEM_BASE = `You are Construct — a transparent terminal coding agent operating inside a real repository.
10
-
11
- Rules:
12
- - Use read, grep, glob, and construct_tool before making load-bearing claims about this project.
13
- - For competitive, landscape, or research questions: consult repo files (docs/, ADR/, STRATEGY.md) and cite paths.
14
- - Call construct_tool with orchestration_policy or knowledge_search when routing or prior artifacts matter.
15
- - Mark any claim you cannot tie to a tool result as [unverified].
16
- - Prefer structured markdown answers: headings, short paragraphs, compact tables when useful.
17
- - Keep actions scoped to the user's request; use write/edit/shell only when asked.`;
18
-
19
- export const CHAT_SYSTEM_SMALL = `You are Construct in a local/small-model profile. Be concise.
20
- - One tool call at a time when possible; cite file paths for claims.
21
- - Use construct_tool for orchestration_policy when routing is non-trivial.
22
- - Mark unverified claims explicitly.`;
23
-
24
- // Per-turn routing policy belongs in the SYSTEM role, not the user message:
25
- // otherwise a weak model echoes it back as "the system told me…" in its visible
26
- // reasoning, and it compounds in the conversation history. These lines carry the
27
- // substance that improves answer quality (evidence discipline, the resolved
28
- // route) without exposing internal scaffolding to the user.
29
-
30
- export function turnPolicyLines(overlay) {
31
- if (!overlay) return [];
32
- const lines = [];
33
- if (overlay.intent || overlay.workCategory) {
34
- lines.push(`Classified intent: ${overlay.intent || 'unknown'}${overlay.workCategory ? ` (${overlay.workCategory})` : ''}.`);
35
- }
36
- if (overlay.specialists?.length) {
37
- lines.push(`Resolved route (a policy overlay, not separate agents): ${overlay.specialists.join(' -> ')}.`);
38
- }
39
- if (overlay.externalResearch?.required) {
40
- lines.push('Repo evidence is REQUIRED this turn: grep/read the relevant files and cite their paths. Do not write a long essay without it.');
41
- }
42
- if (overlay.assumptionsBlocked) {
43
- lines.push('Do not infer the project’s purpose, architecture, or behavior from file names or prior knowledge — read the files first. Mark any claim you cannot tie to a tool result as [unverified].');
44
- }
45
- return lines;
46
- }
47
-
48
- export function buildSystemPrompt({ base = CHAT_SYSTEM_BASE, overlay = null, capabilityTier = 'full' } = {}) {
49
- const effectiveBase = capabilityTier === 'full' ? base : CHAT_SYSTEM_SMALL;
50
- const lines = turnPolicyLines(overlay);
51
- return lines.length ? `${effectiveBase}\n\nTurn policy (internal — never restate this to the user):\n${lines.join('\n')}` : effectiveBase;
52
- }
@@ -1,93 +0,0 @@
1
- /**
2
- * lib/chat/transparency.mjs — the transparency layer for `construct chat`.
3
- *
4
- * The terminal's differentiator is visibility into the loop, so this module
5
- * decides what the user sees and enriches the host stream with Construct's own
6
- * orchestration knowledge. It resolves which transparency layers are active
7
- * (thinking, planned path, specialist routing, tool calls, observability),
8
- * classifies each normalized driver event into a channel, and — before a turn
9
- * runs — derives the specialist path Construct's policy would route the request
10
- * through (orchestration-policy.mjs) so the planned route is shown alongside the
11
- * host's actual execution.
12
- *
13
- * Transparency-first by default: every layer is on unless explicitly disabled,
14
- * matching the surface's promise of maximum visibility with opt-out, not opt-in.
15
- */
16
-
17
- const LAYER_KEYS = ['thinking', 'path', 'specialists', 'tools', 'observability'];
18
-
19
- export function resolveLayers({ flags = {}, env = process.env } = {}) {
20
- const layers = Object.fromEntries(LAYER_KEYS.map((k) => [k, true]));
21
-
22
- if (flags.thinking === false || env.CX_CHAT_THINKING === '0') layers.thinking = false;
23
- if (flags.path === false) layers.path = false;
24
- if (flags.specialists === false) layers.specialists = false;
25
- if (flags.tools === false) layers.tools = false;
26
- if (flags.observability === false || flags.quiet === true) layers.observability = false;
27
-
28
- return layers;
29
- }
30
-
31
- const CHANNEL_BY_TYPE = {
32
- thinking: 'thinking',
33
- text: 'message',
34
- plan: 'path',
35
- tool_call: 'tools',
36
- tool_update: 'tools',
37
- usage: 'observability',
38
- specialist: 'specialists',
39
- permission: 'permission',
40
- error: 'error',
41
- done: 'system',
42
- };
43
-
44
- export function channelFor(event) {
45
- return CHANNEL_BY_TYPE[event?.type] || 'system';
46
- }
47
-
48
- // message, permission, error and system are structural and always shown; the
49
- // optional layers gate everything else so toggles change visibility without
50
- // changing the underlying event stream (which still flows to persistence).
51
-
52
- export function isVisible(event, layers) {
53
- const channel = channelFor(event);
54
- if (channel === 'message' || channel === 'permission' || channel === 'error' || channel === 'system') return true;
55
- return Boolean(layers[channel]);
56
- }
57
-
58
- export async function planTurn(request, { env = process.env, context = null } = {}) {
59
- try {
60
- const { routeRequest } = await import('../orchestration-policy.mjs');
61
- const route = routeRequest({ request, context: context || {} });
62
- const projectQuestion = context?.projectQuestion
63
- || /\b(what is this project|what('s| is) this (repo|project|codebase)|describe this project)\b/i.test(String(request));
64
- const assumptionsBlocked = projectQuestion
65
- || (context?.vagueFollowUp && !context?.priorIntent);
66
-
67
- return {
68
- intent: route.intent,
69
- workCategory: route.workCategory,
70
- specialists: route.specialists,
71
- externalResearch: route.externalResearch,
72
- riskFlags: route.riskFlags,
73
- track: route.track,
74
- contractChain: route.contractChain,
75
- framingChallenge: route.framingChallenge,
76
- dispatchSummary: route.dispatchSummary,
77
- dispatchReasons: route.dispatchReasons,
78
- triggers: route.triggers,
79
- docAuthoring: route.docAuthoring,
80
- artifactReview: route.artifactReview,
81
- sessionTurnIndex: context?.turnIndex ?? 0,
82
- priorIntent: context?.priorIntent ?? null,
83
- workingBranch: context?.workingBranch ?? null,
84
- assumptionsBlocked,
85
- };
86
- } catch {
87
- return null;
88
- }
89
- }
90
-
91
- // Per-turn policy is carried in the system prompt via lib/chat/system-prompt.mjs
92
- // `turnPolicyLines`/`buildSystemPrompt`, not prepended to the user message, so a
93
- // model cannot echo it back as user-visible reasoning.
@@ -1,42 +0,0 @@
1
- /**
2
- * lib/chat/tui/color-scheme.mjs — terminal light/dark detection for construct chat.
3
- *
4
- * Resolves auto|light|dark from CX_CHAT_THEME, saved ui.theme, and COLORFGBG
5
- * (macOS Terminal, iTerm, Linux VTE, Windows Terminal). Falls back to dark when
6
- * the background cannot be inferred — set CX_CHAT_THEME=light on legacy Windows
7
- * conhost if needed.
8
- */
9
-
10
- const THEME_VALUES = new Set(['auto', 'light', 'dark']);
11
-
12
- export function schemeFromColorFgBg(value) {
13
- const parts = String(value).split(';').map((p) => parseInt(p, 10)).filter((n) => !Number.isNaN(n));
14
- if (!parts.length) return null;
15
- const bg = parts.length >= 2 ? parts[1] : parts[parts.length - 1];
16
- if (bg === 7 || bg === 15) return 'light';
17
- if (bg >= 0 && bg <= 6) return 'dark';
18
- if (bg === 8) return 'dark';
19
- if (bg >= 9 && bg <= 14) return 'light';
20
- return null;
21
- }
22
-
23
- export function detectTerminalColorScheme(env = process.env) {
24
- const fromFgBg = env.COLORFGBG ? schemeFromColorFgBg(env.COLORFGBG) : null;
25
- if (fromFgBg) return fromFgBg;
26
- return 'dark';
27
- }
28
-
29
- export function resolveTerminalColorScheme(env = process.env, configTheme = null) {
30
- const envTheme = String(env.CX_CHAT_THEME || env.CONSTRUCT_CHAT_THEME || '').trim().toLowerCase();
31
- if (envTheme === 'light' || envTheme === 'dark') return envTheme;
32
-
33
- const saved = String(configTheme || '').trim().toLowerCase();
34
- if (saved === 'light' || saved === 'dark') return saved;
35
-
36
- return detectTerminalColorScheme(env);
37
- }
38
-
39
- export function normalizeThemeSetting(value) {
40
- const v = String(value || 'auto').trim().toLowerCase();
41
- return THEME_VALUES.has(v) ? v : null;
42
- }
@@ -1,123 +0,0 @@
1
- /**
2
- * lib/chat/tui/markdown.mjs — terminal-safe markdown subset for construct chat.
3
- *
4
- * Renders headings, lists, inline/fenced code, horizontal rules, and simple
5
- * pipe tables into plain lines suitable for Ink Text or linear stdout. Unknown
6
- * constructs pass through unchanged; the renderer never throws on bad input.
7
- */
8
-
9
- export function parseMarkdownLines(text, { width = 80 } = {}) {
10
- if (!text) return [];
11
- const lines = String(text).split('\n');
12
- const out = [];
13
- let inFence = false;
14
- let fenceBuf = [];
15
- let tableBuf = [];
16
-
17
- const flushTable = () => {
18
- if (!tableBuf.length) return;
19
- out.push(...renderTable(tableBuf, width));
20
- tableBuf = [];
21
- };
22
-
23
- for (const line of lines) {
24
- if (/^```/.test(line.trim())) {
25
- flushTable();
26
- if (inFence) {
27
- out.push(...fenceBuf.map((l) => ({ type: 'code', text: l })));
28
- fenceBuf = [];
29
- inFence = false;
30
- } else {
31
- inFence = true;
32
- }
33
- continue;
34
- }
35
- if (inFence) {
36
- fenceBuf.push(line);
37
- continue;
38
- }
39
-
40
- if (isTableRow(line)) {
41
- tableBuf.push(line);
42
- continue;
43
- }
44
- flushTable();
45
-
46
- if (/^---+\s*$/.test(line.trim())) {
47
- out.push({ type: 'rule' });
48
- continue;
49
- }
50
-
51
- const heading = line.match(/^(#{1,3})\s+(.+)$/);
52
- if (heading) {
53
- out.push({ type: 'heading', level: heading[1].length, text: stripInline(heading[2]) });
54
- continue;
55
- }
56
-
57
- const bullet = line.match(/^(\s*)[-*]\s+(.+)$/);
58
- if (bullet) {
59
- const indent = Math.floor(bullet[1].length / 2);
60
- out.push({ type: 'bullet', indent, text: stripInline(bullet[2]) });
61
- continue;
62
- }
63
-
64
- if (line.trim() === '') {
65
- out.push({ type: 'blank' });
66
- continue;
67
- }
68
-
69
- out.push({ type: 'paragraph', text: stripInline(line) });
70
- }
71
-
72
- flushTable();
73
- if (inFence && fenceBuf.length) out.push(...fenceBuf.map((l) => ({ type: 'code', text: l })));
74
- return out;
75
- }
76
-
77
- function isTableRow(line) {
78
- const t = line.trim();
79
- return t.includes('|') && !/^[\s|:-]+$/.test(t.replace(/\|/g, ''));
80
- }
81
-
82
- function renderTable(rows, width) {
83
- const parsed = rows
84
- .filter((r) => !/^\s*\|?[\s:-]+\|/.test(r))
85
- .map((r) => r.split('|').map((c) => stripInline(c.trim())).filter((c, i, a) => !(i === 0 && c === '') && !(i === a.length - 1 && c === '')));
86
- if (!parsed.length) return rows.map((r) => ({ type: 'paragraph', text: r }));
87
-
88
- const cols = Math.max(...parsed.map((r) => r.length));
89
- const colWidth = Math.max(8, Math.floor((width - cols - 1) / cols));
90
- const out = [{ type: 'paragraph', text: '' }];
91
- for (const row of parsed) {
92
- const cells = row.map((c) => truncate(c, colWidth));
93
- while (cells.length < cols) cells.push('');
94
- out.push({ type: 'paragraph', text: cells.join(' | ') });
95
- }
96
- return out;
97
- }
98
-
99
- function truncate(s, max) {
100
- if (s.length <= max) return s.padEnd(max);
101
- return `${s.slice(0, max - 1)}…`;
102
- }
103
-
104
- function stripInline(s) {
105
- return String(s)
106
- .replace(/\*\*(.+?)\*\*/g, '$1')
107
- .replace(/\*(.+?)\*/g, '$1')
108
- .replace(/`([^`]+)`/g, '$1')
109
- .replace(/\[(.+?)\]\([^)]+\)/g, '$1');
110
- }
111
-
112
- export function markdownToPlain(text, { width = 80 } = {}) {
113
- return parseMarkdownLines(text, { width })
114
- .map((part) => {
115
- if (part.type === 'heading') return `${'#'.repeat(part.level)} ${part.text}`;
116
- if (part.type === 'bullet') return `${' '.repeat(part.indent)}- ${part.text}`;
117
- if (part.type === 'code') return ` ${part.text}`;
118
- if (part.type === 'rule') return '---';
119
- if (part.type === 'blank') return '';
120
- return part.text || '';
121
- })
122
- .join('\n');
123
- }
@@ -1,100 +0,0 @@
1
- /**
2
- * lib/chat/tui/presentation.mjs — shared semantic presentation tokens for chat.
3
- *
4
- * Ink named colours and linear ANSI codes derive from one semantic map so the
5
- * rich and linear surfaces stay visually aligned across light and dark terminals.
6
- * Scheme resolution lives in color-scheme.mjs.
7
- */
8
-
9
- import { shouldUseColor } from '../../term-format.mjs';
10
- import { chatTerminalSemantic } from '../design-tokens.mjs';
11
- import { resolveTerminalColorScheme } from './color-scheme.mjs';
12
-
13
- const ESC = '\u001b[';
14
-
15
- const ASCII_GLYPHS = Object.freeze({
16
- spinner: ['|', '/', '-', '\\'],
17
- bullet: '*',
18
- check: 'OK',
19
- cross: 'X',
20
- arrow: '->',
21
- boxH: '-',
22
- boxV: '|',
23
- });
24
-
25
- const UNICODE_GLYPHS = Object.freeze({
26
- spinner: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
27
- bullet: '•',
28
- check: '✓',
29
- cross: '✗',
30
- arrow: '→',
31
- boxH: '─',
32
- boxV: '│',
33
- });
34
-
35
- const DARK_SEMANTIC = Object.freeze(chatTerminalSemantic('dark'));
36
- const LIGHT_SEMANTIC = Object.freeze(chatTerminalSemantic('light'));
37
-
38
- function semanticForScheme(scheme = 'dark') {
39
- return scheme === 'light' ? LIGHT_SEMANTIC : DARK_SEMANTIC;
40
- }
41
-
42
- export function inkPalette({ scheme = 'dark' } = {}) {
43
- const semantic = semanticForScheme(scheme);
44
- return Object.fromEntries(Object.entries(semantic).map(([k, v]) => [k, v.ink]));
45
- }
46
-
47
- export function chatAnsiCodes({ scheme = 'dark' } = {}) {
48
- const semantic = semanticForScheme(scheme);
49
- return Object.fromEntries(Object.entries(semantic).map(([k, v]) => [k, v.code]));
50
- }
51
-
52
- export function resolveChatColors({
53
- enabled = true,
54
- stream = process.stdout,
55
- env = process.env,
56
- scheme: explicitScheme = null,
57
- configTheme = null,
58
- } = {}) {
59
- const scheme = explicitScheme || resolveTerminalColorScheme(env, configTheme);
60
- const useColor = shouldUseColor({ enabled, stream, env });
61
- const codes = chatAnsiCodes({ scheme });
62
- const reset = useColor ? `${ESC}0m` : '';
63
- const wrap = (code) => (useColor && code ? `${ESC}${code}m` : '');
64
-
65
- const colors = {
66
- scheme,
67
- reset,
68
- bold: wrap('1'),
69
- dim: wrap('2'),
70
- text: wrap(codes.text),
71
- muted: wrap(codes.muted),
72
- accent: wrap(codes.accent),
73
- accentAlt: wrap(codes.accentAlt),
74
- ok: wrap(codes.ok),
75
- warn: wrap(codes.warn),
76
- danger: wrap(codes.danger),
77
- badgeFg: wrap(codes.badgeFg),
78
- surface: wrap(codes.surface),
79
- surfaceMuted: wrap(codes.surfaceMuted),
80
- border: wrap(codes.border),
81
- brandAccent: wrap(codes.brandAccent),
82
- green: wrap(codes.ok),
83
- yellow: wrap(codes.warn),
84
- cyan: wrap(codes.accent),
85
- red: wrap(codes.danger),
86
- };
87
-
88
- return colors;
89
- }
90
-
91
- export function createTheme({ scheme = 'dark', ascii = false, env = process.env, configTheme = null } = {}) {
92
- const resolvedScheme = scheme || resolveTerminalColorScheme(env, configTheme);
93
- return {
94
- scheme: resolvedScheme,
95
- palette: inkPalette({ scheme: resolvedScheme }),
96
- glyphs: ascii ? ASCII_GLYPHS : UNICODE_GLYPHS,
97
- };
98
- }
99
-
100
- export { DARK_SEMANTIC, LIGHT_SEMANTIC };