@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,246 +0,0 @@
1
- /**
2
- * lib/chat/present.mjs — headless formatters for construct chat surfaces.
3
- *
4
- * Shared by Ink TUI, linear renderer, and dashboard web cockpit. Keeps route
5
- * rows, tool grouping, usage ledgers, and SSE overlay serialization identical
6
- * across surfaces.
7
- */
8
-
9
- import { formatTokens, formatUsageFooter } from './tui/usage.mjs';
10
-
11
- export function summarizeToolCalls(tools = []) {
12
- const groups = new Map();
13
- for (const t of tools) {
14
- const title = t.title || t.kind || 'tool';
15
- if (!groups.has(title)) {
16
- groups.set(title, { title, count: 0, status: 'completed', refs: [] });
17
- }
18
- const g = groups.get(title);
19
- g.count += 1;
20
- if (t.status === 'failed') g.status = 'failed';
21
- else if (t.status === 'pending' && g.status !== 'failed') g.status = 'pending';
22
- else if (t.status === 'in_progress' && g.status === 'completed') g.status = 'in_progress';
23
- const ref = t.input?.path || t.input?.pattern || t.input?.glob || t.input?.name;
24
- if (ref) {
25
- const s = String(ref);
26
- if (!g.refs.includes(s)) g.refs.push(s);
27
- }
28
- }
29
- return [...groups.values()];
30
- }
31
-
32
- export function summarizeSources(sources = []) {
33
- if (!sources?.length) {
34
- return { total: 0, byTool: {}, refs: [] };
35
- }
36
- const byTool = {};
37
- const refs = [];
38
- for (const s of sources) {
39
- if (typeof s === 'string') {
40
- if (!refs.includes(s)) refs.push(s);
41
- continue;
42
- }
43
- byTool[s.tool] = (byTool[s.tool] || 0) + 1;
44
- if (s.ref && !refs.includes(s.ref)) refs.push(s.ref);
45
- }
46
- return { total: sources.length, byTool, refs };
47
- }
48
-
49
- export function formatRefsInline(refs, { max = 3 } = {}) {
50
- if (!refs?.length) return '';
51
- if (refs.length <= max) return refs.join(', ');
52
- const shown = refs.slice(0, max);
53
- return `${shown.join(', ')} +${refs.length - max} more`;
54
- }
55
-
56
- export function formatSourceToolCounts(byTool) {
57
- const entries = Object.entries(byTool || {});
58
- if (!entries.length) return '';
59
- return entries.map(([tool, n]) => `${tool} ${n}`).join(' ');
60
- }
61
-
62
- export function contextRows(overlay, { layers = null } = {}) {
63
- if (!overlay) return [];
64
- const rows = [];
65
- if (overlay.intent) rows.push({ label: 'intent', value: overlay.intent });
66
- if (overlay.workCategory) rows.push({ label: 'category', value: overlay.workCategory });
67
- if (overlay.track) rows.push({ label: 'track', value: overlay.track });
68
- if (overlay.specialists?.length && layers?.specialists !== false) {
69
- rows.push({ label: 'route', value: overlay.specialists.join(' → ') });
70
- }
71
- if (overlay.externalResearch?.required) {
72
- const shape = overlay.externalResearch.shape ? ` (${overlay.externalResearch.shape})` : '';
73
- rows.push({ label: 'research', value: `required${shape}` });
74
- }
75
- return rows;
76
- }
77
-
78
- export function splitSourceLines(refs, { limit = 4 } = {}) {
79
- if (!refs?.length) return { lines: ['none yet'], hidden: 0, total: 0 };
80
- const shown = refs.slice(0, limit);
81
- return {
82
- lines: shown,
83
- hidden: Math.max(0, refs.length - limit),
84
- total: refs.length,
85
- };
86
- }
87
-
88
- export function toolGroupLabel(group) {
89
- const count = group.count > 1 ? ` ×${group.count}` : '';
90
- const refs = formatRefsInline(group.refs, { max: 2 });
91
- return refs ? `${group.title}${count} ${refs}` : `${group.title}${count}`;
92
- }
93
-
94
- export function toolStatusGlyph(status) {
95
- if (status === 'completed') return '✓';
96
- if (status === 'failed') return '✗';
97
- if (status === 'in_progress') return '›';
98
- return '·';
99
- }
100
-
101
- /**
102
- * @param {Record<string, unknown> | null | undefined} overlay
103
- * @param {{ layers?: Record<string, boolean> | null }} [options]
104
- * @returns {{
105
- * chain: string[],
106
- * intent: string | null,
107
- * track: string | null,
108
- * gates: Array<{ label: string, value: string }>,
109
- * summary: string | null,
110
- * chainLine: string | null,
111
- * } | null}
112
- */
113
- export function formatRouteStrip(overlay, { layers = null } = {}) {
114
- if (!overlay) return null;
115
- const showSpecialists = layers?.specialists !== false;
116
- const chain = showSpecialists && Array.isArray(overlay.specialists)
117
- ? [...overlay.specialists]
118
- : [];
119
- const intent = overlay.intent || null;
120
- const track = overlay.track || null;
121
- const gates = formatGateRows(overlay);
122
- const summary = overlay.dispatchSummary || null;
123
- const chainLine = showSpecialists
124
- ? (chain.length ? chain.join(' → ') : 'direct')
125
- : null;
126
- return { chain, intent, track, gates, summary, chainLine };
127
- }
128
-
129
- /**
130
- * @param {Record<string, unknown> | null | undefined} overlay
131
- * @param {{ layers?: Record<string, boolean> | null }} [options]
132
- */
133
- export function formatRouteLogLine(overlay, { layers = null } = {}) {
134
- const strip = formatRouteStrip(overlay, { layers });
135
- if (!strip) return '';
136
- const parts = [];
137
- if (strip.intent) parts.push(`intent=${strip.intent}`);
138
- if (strip.track) parts.push(`track=${strip.track}`);
139
- if (strip.chainLine) parts.push(strip.chainLine);
140
- return parts.join(' · ');
141
- }
142
-
143
- export function formatRiskFlags(riskFlags = {}) {
144
- return Object.entries(riskFlags)
145
- .filter(([, v]) => v)
146
- .map(([k]) => k);
147
- }
148
-
149
- export function formatContractChain(chain = []) {
150
- return chain.map((edge) => `${edge.producer} → ${edge.consumer}${edge.stage ? ` (${edge.stage})` : ''}`);
151
- }
152
-
153
- export function formatGateRows(overlay) {
154
- if (!overlay) return [];
155
- const rows = [];
156
- if (overlay.externalResearch?.required) {
157
- const detail = overlay.externalResearch.shape || overlay.externalResearch.reason || 'yes';
158
- rows.push({ label: 'research', value: `required (${detail})` });
159
- }
160
- if (overlay.framingChallenge?.required) {
161
- rows.push({ label: 'framing', value: 'challenge required' });
162
- }
163
- if (overlay.docAuthoring?.docType) {
164
- rows.push({ label: 'doc', value: `${overlay.docAuthoring.docType} → ${overlay.docAuthoring.owner || 'unknown'}` });
165
- }
166
- if (overlay.artifactReview?.requiredReviewers?.length) {
167
- rows.push({
168
- label: 'reviewers',
169
- value: overlay.artifactReview.requiredReviewers.join(', '),
170
- });
171
- }
172
- return rows;
173
- }
174
-
175
- export function contextMeterBar(used, size, width = 18) {
176
- const ratio = size > 0 ? Math.max(0, Math.min(1, used / size)) : 0;
177
- const filled = Math.round(ratio * width);
178
- return {
179
- bar: '█'.repeat(filled) + '░'.repeat(Math.max(0, width - filled)),
180
- ratio,
181
- percent: `${Math.round(ratio * 100)}%`,
182
- label: `${formatTokens(used) || '0'}/${formatTokens(size) || '?'}`,
183
- };
184
- }
185
-
186
- export function sessionUsageSummary(session) {
187
- const t = session?.usage?.tokens || session?.tokens || {};
188
- const parts = [];
189
- if (t.total) parts.push(`${formatTokens(t.total)} tok`);
190
- const cost = session?.usage?.cost?.amount ?? session?.cost?.amount;
191
- if (cost > 0) parts.push(`~$${cost.toFixed(cost < 1 ? 3 : 2)}`);
192
- const turns = session?.usage?.turns ?? session?.turns;
193
- if (turns) parts.push(`${turns} turn${turns === 1 ? '' : 's'}`);
194
- return parts.join(' · ') || 'no tokens yet';
195
- }
196
-
197
- export function formatTurnUsageLine(usage) {
198
- return formatUsageFooter(usage, {}).replace(/^\[usage\] /, '');
199
- }
200
-
201
- export function overlayToSsePayload(overlay) {
202
- if (!overlay) return null;
203
- return {
204
- type: 'overlay',
205
- intent: overlay.intent || null,
206
- workCategory: overlay.workCategory || null,
207
- track: overlay.track || null,
208
- specialists: overlay.specialists || [],
209
- externalResearch: overlay.externalResearch || null,
210
- riskFlags: overlay.riskFlags || null,
211
- contractChain: overlay.contractChain || [],
212
- framingChallenge: overlay.framingChallenge || null,
213
- dispatchSummary: overlay.dispatchSummary || null,
214
- dispatchReasons: overlay.dispatchReasons || null,
215
- triggers: overlay.triggers || [],
216
- docAuthoring: overlay.docAuthoring || null,
217
- artifactReview: overlay.artifactReview || null,
218
- sessionTurnIndex: overlay.sessionTurnIndex ?? 0,
219
- priorIntent: overlay.priorIntent ?? null,
220
- workingBranch: overlay.workingBranch ?? null,
221
- };
222
- }
223
-
224
- export function sessionMetaToSsePayload({ session, layers, workingBranch, oracle, ctx = null }) {
225
- return {
226
- type: 'session_meta',
227
- model: session?.model || null,
228
- demoLabel: session?.demoGuide ? (session.demoTitle || 'scripted') : null,
229
- modelMode: session?.modelMode || 'pinned',
230
- sandbox: session?.sandbox || null,
231
- permissionMode: session?.permissionMode || null,
232
- layers: layers || {},
233
- workingBranch: workingBranch || null,
234
- ctx,
235
- oracle: oracle ? {
236
- visible: oracle.visible,
237
- summary: oracle.summary,
238
- topGaps: (oracle.topGaps || []).map((g) => ({ id: g.id, detail: g.detail || g.message || '' })),
239
- } : null,
240
- usage: session?.usage ? {
241
- turns: session.usage.turns,
242
- tokens: { ...session.usage.tokens },
243
- cost: session.usage.cost ? { ...session.usage.cost } : null,
244
- } : null,
245
- };
246
- }
@@ -1,39 +0,0 @@
1
- /**
2
- * lib/chat/session-context.mjs — session-scoped context for planTurn routing.
3
- */
4
-
5
- import fs from 'node:fs';
6
- import path from 'node:path';
7
- import { execSync } from 'node:child_process';
8
-
9
- export function buildPlanContext({ session, cwd = process.cwd(), turnBlocks = [], text = '' } = {}) {
10
- const turns = turnBlocks.filter((item) => item.kind === 'turn');
11
- const lastTurn = turns.length ? turns[turns.length - 1].block : null;
12
-
13
- let workingBranch = null;
14
- try {
15
- workingBranch = execSync('git branch --show-current', { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim() || null;
16
- } catch { /* not a git repo */ }
17
-
18
- let projectSummary = null;
19
- const contextPath = path.join(cwd, '.cx', 'context.md');
20
- try {
21
- if (fs.existsSync(contextPath)) {
22
- projectSummary = fs.readFileSync(contextPath, 'utf8').slice(0, 500);
23
- }
24
- } catch { /* unreadable */ }
25
-
26
- const trimmed = String(text).trim();
27
- const vagueFollowUp = /^(tell me more|what about|continue|go on|explain|elaborate|and\?)/i.test(trimmed);
28
- const projectQuestion = /\b(what is this project|what('s| is) this (repo|project|codebase)|describe this project)\b/i.test(trimmed);
29
-
30
- return {
31
- turnIndex: session?.usage?.turns ?? 0,
32
- priorIntent: lastTurn?.overlay?.intent ?? null,
33
- priorWorkCategory: lastTurn?.overlay?.workCategory ?? null,
34
- workingBranch,
35
- projectSummary,
36
- vagueFollowUp: vagueFollowUp && (session?.usage?.turns ?? 0) > 0,
37
- projectQuestion,
38
- };
39
- }
@@ -1,73 +0,0 @@
1
- /**
2
- * lib/chat/session-persist.mjs — JSONL transcript persistence for construct chat surfaces.
3
- *
4
- * Shared by CLI linear mode and dashboard owned-loop SSE so web/desktop resume
5
- * matches .cx/chat-sessions/ on disk.
6
- */
7
-
8
- import fs from 'node:fs';
9
- import path from 'node:path';
10
- import { resolveProjectScopedPath } from '../project-root.mjs';
11
- import { deserializeBlock, serializeBlock, snapshotTurn } from './tui/turn-block.mjs';
12
- import { migrateEvidenceVerdict } from './evidence.mjs';
13
-
14
- export function chatSessionFilePath({ cwd, convId, host = 'construct-web' }) {
15
- const dir = resolveProjectScopedPath('chat-sessions', { cwd });
16
- return path.join(dir, `${convId}-${host}.jsonl`);
17
- }
18
-
19
- export function createChatPersister({ cwd, sessionId, resumePath = null, host = 'construct' }) {
20
- try {
21
- const dir = resolveProjectScopedPath('chat-sessions', { cwd });
22
- fs.mkdirSync(dir, { recursive: true });
23
- const file = resumePath || path.join(dir, `${new Date().toISOString().replace(/[:.]/g, '-')}-${host}-${sessionId}.jsonl`);
24
- if (!resumePath) {
25
- fs.appendFileSync(file, `${JSON.stringify({ type: 'session_start', host, sessionId, ts: new Date().toISOString() })}\n`);
26
- }
27
- const append = (row) => {
28
- try {
29
- fs.appendFileSync(file, `${JSON.stringify({ ...row, ts: new Date().toISOString() })}\n`);
30
- } catch { /* log is best-effort */ }
31
- };
32
- return {
33
- filePath: file,
34
- event: (event) => append(event),
35
- transcript: (role, text) => append({ type: 'transcript', role, text }),
36
- transcriptBlock: (turn) => append(serializeBlock(turn)),
37
- };
38
- } catch {
39
- return null;
40
- }
41
- }
42
-
43
- export function loadPersistedTurns(filePath) {
44
- if (!filePath || !fs.existsSync(filePath)) return { turns: [], turnBlocks: [] };
45
- const turns = [];
46
- const turnBlocks = [];
47
- const lines = fs.readFileSync(filePath, 'utf8').split('\n').filter(Boolean);
48
- for (const line of lines) {
49
- try {
50
- const row = JSON.parse(line);
51
- const block = deserializeBlock(row);
52
- if (!block) continue;
53
- turnBlocks.push({ kind: 'turn', block });
54
- const snap = snapshotTurn(block);
55
- const evidence = migrateEvidenceVerdict(snap);
56
- turns.push({
57
- id: snap.id || `turn-${turns.length + 1}`,
58
- userText: snap.userText || '',
59
- assistant: snap.assistant || '',
60
- thinking: snap.thinking || '',
61
- tools: snap.tools || [],
62
- overlay: snap.overlay || null,
63
- sources: snap.sources || [],
64
- usage: snap.usage || null,
65
- evidence,
66
- unverified: ['insufficient_evidence', 'uncited_evidence', 'partially_verified'].includes(evidence.status),
67
- working: false,
68
- system: false,
69
- });
70
- } catch { /* skip malformed rows */ }
71
- }
72
- return { turns, turnBlocks };
73
- }
@@ -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
- }