muonroi-cli 1.8.4 → 1.9.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 (562) hide show
  1. package/LICENSE +17 -5
  2. package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
  3. package/dist/packages/agent-harness-core/src/driver.js +46 -0
  4. package/dist/packages/agent-harness-core/src/event-filter.js +11 -0
  5. package/dist/packages/agent-harness-core/src/event-redact.js +7 -0
  6. package/dist/packages/agent-harness-core/src/event-tee.d.ts +64 -0
  7. package/dist/packages/agent-harness-core/src/event-tee.js +104 -0
  8. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +25 -0
  9. package/dist/packages/agent-harness-core/src/mcp-server.js +169 -21
  10. package/dist/packages/agent-harness-core/src/predicate.d.ts +1 -1
  11. package/dist/packages/agent-harness-core/src/protocol.d.ts +90 -4
  12. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  13. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  14. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  15. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  16. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  17. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  18. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  19. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  20. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  21. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  22. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  23. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  24. package/dist/src/agent-harness/mock-model.d.ts +38 -0
  25. package/dist/src/agent-harness/mock-model.js +69 -3
  26. package/dist/src/agent-harness/test-spawn.js +31 -0
  27. package/dist/src/chat/chat-keychain.d.ts +7 -12
  28. package/dist/src/chat/chat-keychain.js +19 -86
  29. package/dist/src/cli/config/screen-providers.js +1 -1
  30. package/dist/src/cli/cost-forensics.d.ts +10 -0
  31. package/dist/src/cli/cost-forensics.js +18 -3
  32. package/dist/src/cli/keys-bundle.d.ts +1 -1
  33. package/dist/src/cli/keys-bundle.js +1 -1
  34. package/dist/src/cli/keys.d.ts +10 -47
  35. package/dist/src/cli/keys.js +31 -399
  36. package/dist/src/council/clarifier.d.ts +31 -3
  37. package/dist/src/council/clarifier.js +220 -32
  38. package/dist/src/council/context.js +49 -15
  39. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  40. package/dist/src/council/debate-checkpoint.js +176 -0
  41. package/dist/src/council/debate-planner.js +54 -5
  42. package/dist/src/council/debate-summary.d.ts +25 -0
  43. package/dist/src/council/debate-summary.js +85 -0
  44. package/dist/src/council/debate.d.ts +169 -2
  45. package/dist/src/council/debate.js +1265 -135
  46. package/dist/src/council/index.d.ts +108 -1
  47. package/dist/src/council/index.js +670 -197
  48. package/dist/src/council/leader.d.ts +26 -0
  49. package/dist/src/council/leader.js +150 -9
  50. package/dist/src/council/llm.d.ts +94 -0
  51. package/dist/src/council/llm.js +348 -55
  52. package/dist/src/council/panel-select.d.ts +30 -0
  53. package/dist/src/council/panel-select.js +82 -0
  54. package/dist/src/council/planner.js +40 -0
  55. package/dist/src/council/preflight.d.ts +17 -0
  56. package/dist/src/council/preflight.js +50 -2
  57. package/dist/src/council/prompts.d.ts +39 -4
  58. package/dist/src/council/prompts.js +256 -69
  59. package/dist/src/council/stance-recall.d.ts +42 -0
  60. package/dist/src/council/stance-recall.js +57 -0
  61. package/dist/src/council/strip-think.d.ts +17 -0
  62. package/dist/src/council/strip-think.js +33 -0
  63. package/dist/src/council/types.d.ts +138 -0
  64. package/dist/src/ee/artifact-cache.d.ts +16 -0
  65. package/dist/src/ee/artifact-cache.js +32 -0
  66. package/dist/src/ee/auth.d.ts +20 -0
  67. package/dist/src/ee/auth.js +54 -2
  68. package/dist/src/ee/bridge.d.ts +10 -0
  69. package/dist/src/ee/bridge.js +58 -0
  70. package/dist/src/ee/client.js +109 -21
  71. package/dist/src/ee/ee-onboarding.js +6 -26
  72. package/dist/src/ee/export-transcripts.d.ts +1 -0
  73. package/dist/src/ee/export-transcripts.js +8 -10
  74. package/dist/src/ee/extract-session.js +29 -0
  75. package/dist/src/ee/extract-style.d.ts +58 -0
  76. package/dist/src/ee/extract-style.js +270 -0
  77. package/dist/src/ee/recall-ledger.d.ts +9 -0
  78. package/dist/src/ee/recall-ledger.js +3 -0
  79. package/dist/src/ee/scope.d.ts +1 -0
  80. package/dist/src/ee/scope.js +26 -1
  81. package/dist/src/ee/search.d.ts +7 -0
  82. package/dist/src/ee/search.js +24 -0
  83. package/dist/src/ee/transcript-emit.js +2 -0
  84. package/dist/src/ee/types.d.ts +22 -0
  85. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  86. package/dist/src/ee/who-am-i-brain.js +220 -0
  87. package/dist/src/ee/who-am-i.d.ts +10 -3
  88. package/dist/src/ee/who-am-i.js +12 -0
  89. package/dist/src/ee/workflow-event.d.ts +48 -0
  90. package/dist/src/ee/workflow-event.js +81 -0
  91. package/dist/src/flow/compaction/compress.d.ts +3 -3
  92. package/dist/src/flow/compaction/compress.js +58 -8
  93. package/dist/src/flow/compaction/extract.d.ts +4 -7
  94. package/dist/src/flow/compaction/extract.js +50 -10
  95. package/dist/src/flow/compaction/index.d.ts +14 -1
  96. package/dist/src/flow/compaction/index.js +96 -3
  97. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  98. package/dist/src/flow/compaction/input-guard.js +43 -0
  99. package/dist/src/flow/compaction/progress.d.ts +35 -0
  100. package/dist/src/flow/compaction/progress.js +35 -0
  101. package/dist/src/flow/fold-planning.d.ts +36 -0
  102. package/dist/src/flow/fold-planning.js +83 -0
  103. package/dist/src/flow/hierarchy.d.ts +146 -0
  104. package/dist/src/flow/hierarchy.js +427 -0
  105. package/dist/src/flow/index.d.ts +1 -0
  106. package/dist/src/flow/index.js +2 -0
  107. package/dist/src/flow/run-artifacts.d.ts +102 -0
  108. package/dist/src/flow/run-artifacts.js +208 -0
  109. package/dist/src/generated/version.d.ts +1 -1
  110. package/dist/src/generated/version.js +1 -1
  111. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  112. package/dist/src/gsd/assessment-schema.js +134 -0
  113. package/dist/src/gsd/capability-registry.d.ts +45 -0
  114. package/dist/src/gsd/capability-registry.js +337 -0
  115. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  116. package/dist/src/gsd/complexity-assessor.js +152 -0
  117. package/dist/src/gsd/config-bridge.d.ts +7 -0
  118. package/dist/src/gsd/config-bridge.js +114 -0
  119. package/dist/src/gsd/config-loader.d.ts +27 -0
  120. package/dist/src/gsd/config-loader.js +50 -0
  121. package/dist/src/gsd/council-context.d.ts +44 -0
  122. package/dist/src/gsd/council-context.js +114 -0
  123. package/dist/src/gsd/ee-closure.d.ts +28 -0
  124. package/dist/src/gsd/ee-closure.js +49 -0
  125. package/dist/src/gsd/flags.d.ts +66 -0
  126. package/dist/src/gsd/flags.js +102 -0
  127. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  128. package/dist/src/gsd/gsd-dispatch.js +131 -0
  129. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  130. package/dist/src/gsd/gsd-runtime.js +37 -0
  131. package/dist/src/gsd/host-adapter.d.ts +11 -0
  132. package/dist/src/gsd/host-adapter.js +29 -0
  133. package/dist/src/gsd/index.d.ts +24 -1
  134. package/dist/src/gsd/index.js +27 -0
  135. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  136. package/dist/src/gsd/loop-host-contract.js +39 -0
  137. package/dist/src/gsd/loop-host.d.ts +69 -0
  138. package/dist/src/gsd/loop-host.js +245 -0
  139. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  140. package/dist/src/gsd/loop-resolver.js +79 -0
  141. package/dist/src/gsd/model-tier.d.ts +13 -0
  142. package/dist/src/gsd/model-tier.js +45 -0
  143. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  144. package/dist/src/gsd/mutation-gate.js +41 -0
  145. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  146. package/dist/src/gsd/native-roadmap.js +343 -0
  147. package/dist/src/gsd/native-state.d.ts +47 -0
  148. package/dist/src/gsd/native-state.js +220 -0
  149. package/dist/src/gsd/paths.d.ts +23 -0
  150. package/dist/src/gsd/paths.js +66 -0
  151. package/dist/src/gsd/phase-dag.d.ts +12 -0
  152. package/dist/src/gsd/phase-dag.js +94 -0
  153. package/dist/src/gsd/phase-sync.d.ts +42 -0
  154. package/dist/src/gsd/phase-sync.js +321 -0
  155. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  156. package/dist/src/gsd/pil-gate-context.js +64 -0
  157. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  158. package/dist/src/gsd/pil-gate-critic.js +74 -0
  159. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  160. package/dist/src/gsd/plan-council-prompts.js +79 -0
  161. package/dist/src/gsd/plan-council.d.ts +44 -0
  162. package/dist/src/gsd/plan-council.js +283 -0
  163. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  164. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  165. package/dist/src/gsd/product-workspace.d.ts +13 -0
  166. package/dist/src/gsd/product-workspace.js +124 -0
  167. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  168. package/dist/src/gsd/ship-bridge.js +65 -0
  169. package/dist/src/gsd/state-document.d.ts +40 -0
  170. package/dist/src/gsd/state-document.js +163 -0
  171. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  172. package/dist/src/gsd/verdict-schema.js +144 -0
  173. package/dist/src/gsd/verify-context.d.ts +22 -0
  174. package/dist/src/gsd/verify-context.js +27 -0
  175. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  176. package/dist/src/gsd/verify-council-prompts.js +85 -0
  177. package/dist/src/gsd/verify-council.d.ts +25 -0
  178. package/dist/src/gsd/verify-council.js +119 -0
  179. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  180. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  181. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  182. package/dist/src/gsd/workflow-engine.js +207 -0
  183. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  184. package/dist/src/gsd/workflow-tools.js +277 -0
  185. package/dist/src/headless/council-answers.js +4 -0
  186. package/dist/src/hooks/index.js +1 -1
  187. package/dist/src/index.js +172 -270
  188. package/dist/src/lsp/builtins.js +3 -1
  189. package/dist/src/lsp/manager.d.ts +5 -1
  190. package/dist/src/lsp/manager.js +249 -3
  191. package/dist/src/lsp/npm-cache.d.ts +11 -1
  192. package/dist/src/lsp/npm-cache.js +17 -1
  193. package/dist/src/lsp/runtime.d.ts +6 -1
  194. package/dist/src/lsp/runtime.js +17 -1
  195. package/dist/src/lsp/types.d.ts +83 -1
  196. package/dist/src/lsp/types.js +10 -0
  197. package/dist/src/maintain/pr-builder.js +23 -13
  198. package/dist/src/mcp/auto-setup.js +57 -32
  199. package/dist/src/mcp/client-pool.js +44 -16
  200. package/dist/src/mcp/lsp-tools.d.ts +5 -1
  201. package/dist/src/mcp/lsp-tools.js +93 -2
  202. package/dist/src/mcp/mcp-keychain.d.ts +3 -5
  203. package/dist/src/mcp/mcp-keychain.js +9 -49
  204. package/dist/src/mcp/research-onboarding.js +8 -7
  205. package/dist/src/mcp/runtime.js +34 -2
  206. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  207. package/dist/src/mcp/setup-guide-text.js +22 -2
  208. package/dist/src/mcp/tools-server.d.ts +10 -0
  209. package/dist/src/mcp/tools-server.js +10 -2
  210. package/dist/src/models/catalog-client.d.ts +87 -0
  211. package/dist/src/models/catalog-client.js +105 -38
  212. package/dist/src/models/catalog.json +528 -265
  213. package/dist/src/models/registry.d.ts +22 -7
  214. package/dist/src/models/registry.js +73 -10
  215. package/dist/src/ops/doctor.js +1 -1
  216. package/dist/src/orchestrator/ask-user.d.ts +61 -0
  217. package/dist/src/orchestrator/ask-user.js +65 -0
  218. package/dist/src/orchestrator/auto-commit.js +1 -1
  219. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  220. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  221. package/dist/src/orchestrator/cache-prefix.js +83 -0
  222. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  223. package/dist/src/orchestrator/compact-request.js +41 -0
  224. package/dist/src/orchestrator/compaction.d.ts +12 -3
  225. package/dist/src/orchestrator/compaction.js +35 -15
  226. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  227. package/dist/src/orchestrator/council-manager.js +74 -32
  228. package/dist/src/orchestrator/council-request.d.ts +49 -0
  229. package/dist/src/orchestrator/council-request.js +62 -0
  230. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  231. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  232. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  233. package/dist/src/orchestrator/error-utils.js +132 -24
  234. package/dist/src/orchestrator/grounding-check.js +39 -1
  235. package/dist/src/orchestrator/interactive-pause.d.ts +26 -0
  236. package/dist/src/orchestrator/interactive-pause.js +36 -0
  237. package/dist/src/orchestrator/message-processor.d.ts +4 -0
  238. package/dist/src/orchestrator/message-processor.js +268 -41
  239. package/dist/src/orchestrator/orchestrator.d.ts +64 -3
  240. package/dist/src/orchestrator/orchestrator.js +823 -120
  241. package/dist/src/orchestrator/preprocessor.js +3 -3
  242. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  243. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  244. package/dist/src/orchestrator/prompts.js +17 -17
  245. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  246. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  247. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  248. package/dist/src/orchestrator/retry-classifier.js +46 -2
  249. package/dist/src/orchestrator/safety-askcard.d.ts +1 -1
  250. package/dist/src/orchestrator/safety-askcard.js +5 -2
  251. package/dist/src/orchestrator/safety-intercept.d.ts +50 -0
  252. package/dist/src/orchestrator/safety-intercept.js +62 -0
  253. package/dist/src/orchestrator/scope-reminder.js +1 -1
  254. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  255. package/dist/src/orchestrator/session-experience.js +2 -1
  256. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  257. package/dist/src/orchestrator/should-run-gate.js +18 -0
  258. package/dist/src/orchestrator/stall-watchdog.d.ts +31 -3
  259. package/dist/src/orchestrator/stall-watchdog.js +65 -10
  260. package/dist/src/orchestrator/stream-runner.d.ts +13 -3
  261. package/dist/src/orchestrator/stream-runner.js +115 -49
  262. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  263. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  264. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  265. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  266. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  267. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  268. package/dist/src/orchestrator/tool-engine.d.ts +41 -0
  269. package/dist/src/orchestrator/tool-engine.js +846 -66
  270. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  271. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  272. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  273. package/dist/src/orchestrator/turn-watchdog.d.ts +44 -0
  274. package/dist/src/orchestrator/turn-watchdog.js +84 -0
  275. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  276. package/dist/src/pil/agent-operating-contract.js +6 -4
  277. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  278. package/dist/src/pil/cheap-model-playbook.js +5 -1
  279. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  280. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  281. package/dist/src/pil/discovery-types.d.ts +1 -0
  282. package/dist/src/pil/discovery.d.ts +1 -1
  283. package/dist/src/pil/discovery.js +18 -13
  284. package/dist/src/pil/layer1-intent.d.ts +18 -6
  285. package/dist/src/pil/layer1-intent.js +66 -757
  286. package/dist/src/pil/layer15-context-scan.js +15 -1
  287. package/dist/src/pil/layer1_5-complexity-size.d.ts +7 -0
  288. package/dist/src/pil/layer1_5-complexity-size.js +31 -5
  289. package/dist/src/pil/layer3-ee-injection.js +23 -8
  290. package/dist/src/pil/layer4-gsd.js +69 -16
  291. package/dist/src/pil/layer5-context.js +7 -3
  292. package/dist/src/pil/layer6-output.d.ts +23 -0
  293. package/dist/src/pil/layer6-output.js +5 -1
  294. package/dist/src/pil/llm-classify.d.ts +111 -5
  295. package/dist/src/pil/llm-classify.js +421 -189
  296. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  297. package/dist/src/pil/native-capabilities-workbook.js +8 -0
  298. package/dist/src/pil/pipeline.js +36 -2
  299. package/dist/src/pil/repo-grounding-probe.d.ts +15 -0
  300. package/dist/src/pil/repo-grounding-probe.js +136 -0
  301. package/dist/src/pil/repo-structure-hints.d.ts +7 -0
  302. package/dist/src/pil/repo-structure-hints.js +45 -0
  303. package/dist/src/pil/response-tools.js +5 -3
  304. package/dist/src/pil/schema.d.ts +1 -0
  305. package/dist/src/pil/schema.js +2 -0
  306. package/dist/src/pil/types.d.ts +18 -0
  307. package/dist/src/playbook/directives.d.ts +4 -0
  308. package/dist/src/playbook/directives.js +17 -5
  309. package/dist/src/product-loop/artifact-io.js +4 -0
  310. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  311. package/dist/src/product-loop/backlog-builder.js +30 -6
  312. package/dist/src/product-loop/criteria-seed.d.ts +51 -0
  313. package/dist/src/product-loop/criteria-seed.js +200 -0
  314. package/dist/src/product-loop/discovery-context-format.js +3 -1
  315. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  316. package/dist/src/product-loop/discovery-interview.d.ts +9 -0
  317. package/dist/src/product-loop/discovery-interview.js +60 -12
  318. package/dist/src/product-loop/discovery-recommender.js +2 -1
  319. package/dist/src/product-loop/discovery-schema.js +19 -2
  320. package/dist/src/product-loop/discovery-triage.d.ts +23 -0
  321. package/dist/src/product-loop/discovery-triage.js +109 -0
  322. package/dist/src/product-loop/gather.js +150 -2
  323. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  324. package/dist/src/product-loop/ideal-trace.js +64 -0
  325. package/dist/src/product-loop/index.d.ts +13 -1
  326. package/dist/src/product-loop/index.js +340 -52
  327. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  328. package/dist/src/product-loop/loop-driver.js +330 -106
  329. package/dist/src/product-loop/phase-plan.d.ts +21 -0
  330. package/dist/src/product-loop/phase-plan.js +81 -6
  331. package/dist/src/product-loop/phase-rituals.d.ts +3 -0
  332. package/dist/src/product-loop/phase-rituals.js +8 -3
  333. package/dist/src/product-loop/phase-runner.js +39 -12
  334. package/dist/src/product-loop/plan-adherence-review.d.ts +26 -0
  335. package/dist/src/product-loop/plan-adherence-review.js +144 -0
  336. package/dist/src/product-loop/sprint-runner.d.ts +173 -0
  337. package/dist/src/product-loop/sprint-runner.js +863 -19
  338. package/dist/src/product-loop/types.d.ts +61 -5
  339. package/dist/src/providers/adapter.d.ts +1 -1
  340. package/dist/src/providers/adapter.js +3 -4
  341. package/dist/src/providers/anthropic.d.ts +9 -8
  342. package/dist/src/providers/anthropic.js +13 -47
  343. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  344. package/dist/src/providers/auth/browser-flow.js +1 -1
  345. package/dist/src/providers/auth/grok-oauth.d.ts +1 -0
  346. package/dist/src/providers/auth/grok-oauth.js +30 -5
  347. package/dist/src/providers/auth/openai-oauth.d.ts +1 -0
  348. package/dist/src/providers/auth/openai-oauth.js +15 -1
  349. package/dist/src/providers/auth/registry.js +0 -34
  350. package/dist/src/providers/auth/token-store.d.ts +9 -9
  351. package/dist/src/providers/auth/token-store.js +8 -67
  352. package/dist/src/providers/auth/types.d.ts +9 -1
  353. package/dist/src/providers/auth/types.js +1 -1
  354. package/dist/src/providers/capabilities.d.ts +24 -5
  355. package/dist/src/providers/capabilities.js +42 -24
  356. package/dist/src/providers/endpoints.d.ts +2 -2
  357. package/dist/src/providers/endpoints.js +11 -10
  358. package/dist/src/providers/env-store.d.ts +17 -0
  359. package/dist/src/providers/env-store.js +228 -0
  360. package/dist/src/providers/keychain.d.ts +22 -18
  361. package/dist/src/providers/keychain.js +127 -140
  362. package/dist/src/providers/mcp-vision-bridge.js +56 -146
  363. package/dist/src/providers/openai-compatible.js +8 -1
  364. package/dist/src/providers/pricing.d.ts +2 -2
  365. package/dist/src/providers/pricing.js +3 -13
  366. package/dist/src/providers/runtime.d.ts +43 -3
  367. package/dist/src/providers/runtime.js +88 -14
  368. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  369. package/dist/src/providers/strategies/base.strategy.js +24 -1
  370. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  371. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  372. package/dist/src/providers/strategies/registry.js +4 -4
  373. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  374. package/dist/src/providers/strategies/thinking-mode.js +288 -1
  375. package/dist/src/providers/strategies/xai.strategy.js +27 -0
  376. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  377. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  378. package/dist/src/providers/types.d.ts +5 -6
  379. package/dist/src/providers/types.js +2 -2
  380. package/dist/src/providers/vision-backend.d.ts +47 -0
  381. package/dist/src/providers/vision-backend.js +258 -0
  382. package/dist/src/providers/vision-proxy.d.ts +22 -9
  383. package/dist/src/providers/vision-proxy.js +63 -132
  384. package/dist/src/providers/warm.d.ts +65 -0
  385. package/dist/src/providers/warm.js +145 -0
  386. package/dist/src/providers/wire-debug.js +95 -0
  387. package/dist/src/router/decide.d.ts +13 -0
  388. package/dist/src/router/decide.js +138 -36
  389. package/dist/src/router/peak-hour.d.ts +38 -0
  390. package/dist/src/router/peak-hour.js +107 -0
  391. package/dist/src/router/step-router.js +3 -2
  392. package/dist/src/router/warm.js +4 -5
  393. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  394. package/dist/src/scaffold/continuation-prompt.js +26 -0
  395. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  396. package/dist/src/scaffold/point-to-existing.js +25 -0
  397. package/dist/src/self-qa/agentic-loop.js +6 -5
  398. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  399. package/dist/src/{ui/state → state}/active-run.js +21 -0
  400. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  401. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  402. package/dist/src/state/turn-trace.d.ts +43 -0
  403. package/dist/src/state/turn-trace.js +32 -0
  404. package/dist/src/storage/db.js +2 -1
  405. package/dist/src/storage/index.d.ts +1 -1
  406. package/dist/src/storage/index.js +1 -1
  407. package/dist/src/storage/interaction-log.d.ts +1 -1
  408. package/dist/src/storage/migrations.js +71 -1
  409. package/dist/src/storage/sessions.d.ts +28 -10
  410. package/dist/src/storage/sessions.js +78 -21
  411. package/dist/src/storage/transcript-view.js +1 -1
  412. package/dist/src/storage/transcript.d.ts +51 -0
  413. package/dist/src/storage/transcript.js +340 -15
  414. package/dist/src/tools/file.d.ts +15 -0
  415. package/dist/src/tools/file.js +32 -0
  416. package/dist/src/tools/git-safety.d.ts +19 -0
  417. package/dist/src/tools/git-safety.js +168 -0
  418. package/dist/src/tools/native-tools.d.ts +1 -1
  419. package/dist/src/tools/native-tools.js +81 -1
  420. package/dist/src/tools/registry.d.ts +20 -0
  421. package/dist/src/tools/registry.js +576 -23
  422. package/dist/src/tools/research.d.ts +29 -0
  423. package/dist/src/tools/research.js +233 -0
  424. package/dist/src/types/index.d.ts +147 -4
  425. package/dist/src/ui/app.js +0 -0
  426. package/dist/src/ui/cards/product-status-card.js +1 -1
  427. package/dist/src/ui/components/agent-rail-activities.d.ts +26 -0
  428. package/dist/src/ui/components/agent-rail-activities.js +47 -0
  429. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  430. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  431. package/dist/src/ui/components/compact-progress-card.d.ts +24 -0
  432. package/dist/src/ui/components/compact-progress-card.js +42 -0
  433. package/dist/src/ui/components/context-rail.d.ts +26 -0
  434. package/dist/src/ui/components/context-rail.js +33 -0
  435. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  436. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  437. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  438. package/dist/src/ui/components/council-debate-pill.js +34 -0
  439. package/dist/src/ui/components/council-info-card.js +2 -2
  440. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  441. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  442. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  443. package/dist/src/ui/components/council-message-bubble.js +16 -15
  444. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  445. package/dist/src/ui/components/council-phase-timeline.js +66 -17
  446. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  447. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  448. package/dist/src/ui/components/council-question-card.js +13 -12
  449. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  450. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  451. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  452. package/dist/src/ui/components/council-round-group.js +88 -0
  453. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  454. package/dist/src/ui/components/council-status-list.js +36 -24
  455. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  456. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  457. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  458. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  459. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  460. package/dist/src/ui/components/message-view.d.ts +15 -0
  461. package/dist/src/ui/components/message-view.js +50 -1
  462. package/dist/src/ui/components/prompt-box.js +18 -16
  463. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  464. package/dist/src/ui/components/session-tree-card.js +46 -0
  465. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  466. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  467. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  468. package/dist/src/ui/components/task-list-panel.js +22 -2
  469. package/dist/src/ui/components/tool-group.d.ts +15 -3
  470. package/dist/src/ui/components/tool-group.js +69 -11
  471. package/dist/src/ui/containers/modals-layer.d.ts +4 -2
  472. package/dist/src/ui/containers/modals-layer.js +2 -2
  473. package/dist/src/ui/council-harness-event.d.ts +57 -0
  474. package/dist/src/ui/council-harness-event.js +46 -0
  475. package/dist/src/ui/heartbeat-debug.d.ts +29 -0
  476. package/dist/src/ui/heartbeat-debug.js +45 -0
  477. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  478. package/dist/src/ui/mcp-modal.js +2 -4
  479. package/dist/src/ui/modals/api-key-modal.js +1 -1
  480. package/dist/src/ui/modals/connect-modal.js +4 -3
  481. package/dist/src/ui/modals/model-picker-modal.d.ts +8 -18
  482. package/dist/src/ui/modals/model-picker-modal.js +8 -10
  483. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  484. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  485. package/dist/src/ui/picker-providers.d.ts +1 -1
  486. package/dist/src/ui/picker-providers.js +1 -1
  487. package/dist/src/ui/primitives/index.d.ts +1 -0
  488. package/dist/src/ui/primitives/index.js +2 -0
  489. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  490. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  491. package/dist/src/ui/slash/compact.js +5 -7
  492. package/dist/src/ui/slash/cost.js +1 -1
  493. package/dist/src/ui/slash/council.js +19 -1
  494. package/dist/src/ui/slash/debug.d.ts +3 -31
  495. package/dist/src/ui/slash/debug.js +9 -20
  496. package/dist/src/ui/slash/ee.js +81 -0
  497. package/dist/src/ui/slash/ideal.d.ts +6 -2
  498. package/dist/src/ui/slash/ideal.js +97 -7
  499. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  500. package/dist/src/ui/slash/menu-items.js +23 -20
  501. package/dist/src/ui/slash/registry.d.ts +2 -0
  502. package/dist/src/ui/slash/registry.js +4 -0
  503. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  504. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  505. package/dist/src/ui/status-bar/index.d.ts +1 -1
  506. package/dist/src/ui/status-bar/index.js +7 -3
  507. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  508. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  509. package/dist/src/ui/theme.d.ts +1 -0
  510. package/dist/src/ui/theme.js +2 -0
  511. package/dist/src/ui/types.d.ts +7 -0
  512. package/dist/src/ui/use-app-logic.js +0 -0
  513. package/dist/src/ui/utils/agent-activities.d.ts +39 -0
  514. package/dist/src/ui/utils/agent-activities.js +96 -0
  515. package/dist/src/ui/utils/format.d.ts +14 -0
  516. package/dist/src/ui/utils/format.js +23 -3
  517. package/dist/src/ui/utils/group-tool-entries.d.ts +26 -0
  518. package/dist/src/ui/utils/group-tool-entries.js +111 -0
  519. package/dist/src/ui/utils/tool-summary.d.ts +21 -0
  520. package/dist/src/ui/utils/tool-summary.js +91 -0
  521. package/dist/src/usage/downgrade.js +2 -2
  522. package/dist/src/usage/product-ledger.js +2 -2
  523. package/dist/src/utils/event-loop-monitor.d.ts +85 -0
  524. package/dist/src/utils/event-loop-monitor.js +107 -0
  525. package/dist/src/utils/install-manager.js +2 -1
  526. package/dist/src/utils/llm-deadline.d.ts +14 -0
  527. package/dist/src/utils/llm-deadline.js +19 -0
  528. package/dist/src/utils/logger.js +2 -2
  529. package/dist/src/utils/loop-profiler.d.ts +102 -0
  530. package/dist/src/utils/loop-profiler.js +202 -0
  531. package/dist/src/utils/permission-mode.js +5 -3
  532. package/dist/src/utils/redactor.js +1 -1
  533. package/dist/src/utils/settings.d.ts +180 -5
  534. package/dist/src/utils/settings.js +271 -31
  535. package/dist/src/utils/side-question.d.ts +1 -2
  536. package/dist/src/utils/side-question.js +2 -2
  537. package/dist/src/utils/visible-retry.d.ts +11 -0
  538. package/dist/src/utils/visible-retry.js +10 -1
  539. package/dist/src/verify/entrypoint.d.ts +1 -1
  540. package/dist/src/verify/entrypoint.js +52 -17
  541. package/dist/src/verify/orchestrator.d.ts +1 -1
  542. package/dist/src/verify/orchestrator.js +20 -3
  543. package/dist/src/verify/recipes.d.ts +13 -0
  544. package/dist/src/verify/recipes.js +15 -0
  545. package/package.json +134 -132
  546. package/dist/src/cli/bw-vault.d.ts +0 -55
  547. package/dist/src/cli/bw-vault.js +0 -133
  548. package/dist/src/mcp/ee-tools.d.ts +0 -46
  549. package/dist/src/mcp/ee-tools.js +0 -193
  550. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  551. package/dist/src/providers/auth/gcloud.js +0 -102
  552. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  553. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  554. package/dist/src/providers/gemini.d.ts +0 -11
  555. package/dist/src/providers/gemini.js +0 -45
  556. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  557. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  558. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  559. package/dist/src/providers/strategies/google.strategy.js +0 -174
  560. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  561. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  562. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -1,6 +1,14 @@
1
1
  import { buildStackLockSection } from "./decisions-lock.js";
2
2
  // ── Clarification prompts ────────────────────────────────────────────────────
3
- export function buildClarificationPrompt(topic, conversationContext, previousQA) {
3
+ export function buildClarificationPrompt(topic, conversationContext, previousQA,
4
+ /**
5
+ * Interview language, already resolved by the caller (runClarification): a
6
+ * concrete language name ("vietnamese", "english", a pinned locale) or "auto".
7
+ * Feeds the shared `buildLanguageRule` so the cards follow the SAME language
8
+ * policy as the debate — the user's conversation language, not English-by-
9
+ * default. Defaults to "auto" so existing no-arg callers keep auto-detection.
10
+ */
11
+ lang = "auto") {
4
12
  const qaSection = previousQA?.length
5
13
  ? `\n\n## Already Clarified\n${previousQA.map((qa) => `Q: ${qa.question}\nA: ${qa.answer}`).join("\n\n")}`
6
14
  : "";
@@ -12,10 +20,28 @@ export function buildClarificationPrompt(topic, conversationContext, previousQA)
12
20
  `- SCOPE: what is in/out of scope for THIS change?\n` +
13
21
  `- CONSTRAINTS: hard technical/time/business constraints not already implied by the context.\n` +
14
22
  `- SUCCESS CRITERIA: how "done" is judged, when it isn't already obvious.\n\n` +
23
+ `## Ground your questions in the research (IMPORTANT)\n` +
24
+ `If a "## Scope Research" section is present, it is evidence gathered about THIS topic before you ` +
25
+ `were asked to clarify. Read it first, then use it to ask SHARPER, better-grounded questions — ` +
26
+ `research makes your questions more pointed, it does NOT reduce the need to ask. Treat the research's ` +
27
+ `own guesses/speculation as UNVERIFIED, never as the user's answer: if the research had to assume ` +
28
+ `what the user actually wants (their real goal, the concrete task, the system of record, the target ` +
29
+ `user), that assumption IS the gray area you must confirm with them — do not adopt it silently. ` +
30
+ `In particular, when the request is vague and the research could only speculate about the core goal, ` +
31
+ `asking the user to name that goal/pain concretely is the single highest-value question — ask it. ` +
32
+ `Only skip a question when the research (or the topic/context) settles it with real evidence, not a guess.\n\n` +
15
33
  `## How many questions\n` +
16
34
  `Ask the minimum that unblocks a focused discussion — typically 0-2. A well-scoped topic, or one ` +
17
35
  `whose context already answers the gaps, needs ZERO questions: return []. Do NOT pad to a quota, ` +
18
36
  `and never ask a question whose answer is already in the topic or the project context.\n\n` +
37
+ `## Ask ONLY when the answer forks the debate (ROI gate — critical)\n` +
38
+ `Before emitting ANY question, ask yourself: "If the user said 'you decide', would I be confident?" ` +
39
+ `If YES and picking wrong would be cheap to correct once the debate surfaces it, DO NOT ask — return [] ` +
40
+ `and let the debate proceed on your recommended reading. A card that merely asks the user to CONFIRM the ` +
41
+ `default you already recommend is pure noise: it cost a real user 60s for zero new information. Only ask ` +
42
+ `when the answer MATERIALLY changes what the experts debate — e.g. two incompatible scopes that produce ` +
43
+ `entirely different debates — AND you genuinely cannot pick for them. When in doubt, return [] and proceed ` +
44
+ `on your best reading; the debate itself will expose any wrong assumption far more cheaply than a gate.\n\n` +
19
45
  `## Existing-repo grounding (IMPORTANT)\n` +
20
46
  `If a "## Current Project" section is present you are working in an EXISTING repository — NOT a ` +
21
47
  `greenfield project. Ground every question and every option in what that snapshot actually shows ` +
@@ -28,17 +54,19 @@ export function buildClarificationPrompt(topic, conversationContext, previousQA)
28
54
  `the project IS the one described in the "## Current Project" section of the context. DO NOT ask which project.\n` +
29
55
  `- Only ask about project identity when the topic mentions multiple distinct projects or external products.\n` +
30
56
  `- Use the project's package.json name and description as implicit context for follow-up questions.\n\n` +
31
- `## Language Rule (mandatory)\n` +
32
- `Write the "question", "why", and every "suggestions"/"recommended" option in the SAME ` +
33
- `language the user used in the Topic below detect it; if the user wrote Vietnamese, write ` +
34
- `Vietnamese; if English, English. The user reads and answers these on a card, so they must ` +
35
- `NOT default to English. Keep code identifiers, file paths, tech/product names, and JSON keys in English.\n\n` +
57
+ buildLanguageRule(lang) +
58
+ `The user reads and answers these on a card, so the "question", "why", and every option ` +
59
+ `"label"/"description" MUST be in that languagenever default to English for card text, and ` +
60
+ `do NOT mirror the language of any "## Scope Research"/context block; follow the user's language.\n\n` +
36
61
  `Output ONLY a JSON array (no markdown, no preamble):\n` +
37
- `[{"question": "...", "why": "why this matters for a focused discussion", "suggestions": ["option A", "option B"], "recommended": "option A", "isRequired": true}]\n\n` +
38
- `Rules for "recommended" (be decisive the user should never face an unranked list):\n` +
39
- `- ALWAYS include "recommended" the single option you would choose if the user said "you decide", given the topic + project context.\n` +
40
- `- Its value MUST be exactly equal to one of the entries in "suggestions".\n` +
41
- `- Omit it ONLY in a genuine 50/50 tie where recommending either option would be misleading. A missing recommendation must be the rare exception, not the default.\n` +
62
+ `[{"question": "...", "why": "why this matters for a focused discussion", "options": [` +
63
+ `{"label": "option A", "description": "what picking this means and its trade-off one line", "recommended": true}, ` +
64
+ `{"label": "option B", "description": "what picking this means and its trade-off one line"}], "isRequired": true}]\n\n` +
65
+ `Rules for "options" (each option is a real, distinct fork the user picks between):\n` +
66
+ `- Every option MUST carry a "label" (the short button text) AND a "description" (one line explaining what choosing it means / its trade-off) so the user can decide without guessing. Never emit a bare label with no description.\n` +
67
+ `- Mark EXACTLY ONE option with "recommended": true — the option you would choose if the user said "you decide", given the topic + project context. Be decisive; the user should never face an unranked list.\n` +
68
+ `- Omit "recommended" on every option ONLY in a genuine 50/50 tie where recommending either would be misleading. A missing recommendation must be the rare exception, not the default.\n` +
69
+ `- Provide 2-4 options per question. Do NOT add "type your own" / "let's discuss" options yourself — those escape hatches are appended automatically.\n` +
42
70
  `Return [] if no clarification is needed.`,
43
71
  prompt: `## Topic\n${topic}\n\n` +
44
72
  (conversationContext ? `## Conversation Context\n${conversationContext}\n` : "") +
@@ -125,6 +153,79 @@ const ENGLISH_ONLY_RULE = `\n## Language Rule (mandatory)\n` +
125
153
  `Code identifiers, tool output, JSON keys, and citation tags must remain in English. ` +
126
154
  `The user-facing summary at the end of the council is the only place where ` +
127
155
  `the user's native language is used; the debate is engineering-internal.\n`;
156
+ /**
157
+ * Feature B — the debate language rule, parameterized. The user's chosen
158
+ * language IS the debate language (no separate translate-back pass), so the
159
+ * prompts that used to hard-force English now select their rule from the
160
+ * resolved `councilLanguage` setting.
161
+ *
162
+ * Regardless of language, machine-readable tokens stay verbatim English so the
163
+ * original stability guarantee (citation tags, JSON, cross-turn citations) is
164
+ * preserved: `[CONFIRMED via …]` / `[REFUTED via …]` / `[UNVERIFIED: …]` tags,
165
+ * JSON keys and the `type` field, code identifiers, tool output, and STACK LOCK
166
+ * technology names.
167
+ *
168
+ * Modes (`lang` is already normalized by `normalizeCouncilLanguage`):
169
+ * - undefined / "english" → the historical English-only rule, byte-identical
170
+ * so existing prompt-string tests and machine-stability are unaffected.
171
+ * - "auto" → write in the SAME language as the user's brief/topic (detected
172
+ * from the brief that every debate prompt already embeds).
173
+ * - any other value → write in that named language.
174
+ */
175
+ const NON_ENGLISH_TOKENS_RULE = `Keep these verbatim in English no matter what: code identifiers, tool output, ` +
176
+ `JSON keys and the \`type\` field, citation tags (\`[CONFIRMED via …]\`, ` +
177
+ `\`[REFUTED via …]\`, \`[UNVERIFIED: …]\`), and any STACK LOCK technology names. ` +
178
+ `Only your prose/analysis text switches language.\n`;
179
+ export function buildLanguageRule(lang) {
180
+ if (!lang || lang === "english")
181
+ return ENGLISH_ONLY_RULE;
182
+ if (lang === "auto") {
183
+ return (`\n## Language Rule (mandatory)\n` +
184
+ `Write your ENTIRE response in the SAME language the user used in the ` +
185
+ `Discussion Brief / topic below. If the brief is in Vietnamese, write in ` +
186
+ `Vietnamese; if Japanese, Japanese; if English, English. ` +
187
+ NON_ENGLISH_TOKENS_RULE);
188
+ }
189
+ return (`\n## Language Rule (mandatory)\n` +
190
+ `Write your ENTIRE response in ${lang}. Do not switch to English for the ` +
191
+ `prose even if the brief or your partner's message is in another language. ` +
192
+ NON_ENGLISH_TOKENS_RULE);
193
+ }
194
+ /**
195
+ * Feature B — synthesis-specific language rule. The synthesis prompt already
196
+ * localizes its user-facing output to the user's language; this only adjusts (a)
197
+ * the now-possibly-inaccurate "debate above is entirely in English" preamble and
198
+ * (b) the language-selection instruction when the user PINNED a specific locale.
199
+ *
200
+ * undefined / "english" → the historical block, byte-identical (debate was
201
+ * English-only, output detected from the Problem Statement).
202
+ * "auto" → same "detect from the Problem Statement" output behavior, but the
203
+ * preamble no longer falsely claims the debate ran in English.
204
+ * pinned locale → force all prose into that language instead of detecting it.
205
+ */
206
+ export function buildSynthesisLanguageRule(lang) {
207
+ const pinned = lang && lang !== "english" && lang !== "auto" ? lang : undefined;
208
+ const debatePreamble = !lang || lang === "english"
209
+ ? `The debate above is entirely in English (debate language is forced). `
210
+ : `The debate above was conducted in the same language as the Problem Statement. `;
211
+ const selectLine = pinned
212
+ ? `- Write ALL prose (JSON free-text values AND Part-2 markdown body) in ${pinned}. ` +
213
+ `Do not translate code, identifiers, or quoted citation tags ` +
214
+ `(\`[REFUTED via ...]\`, \`[CONFIRMED via ...]\`).\n\n`
215
+ : `- Detect the user's language from the Problem Statement. If it's Vietnamese, write in ` +
216
+ `Vietnamese. If Japanese, Japanese. If English, English. Do not translate code, identifiers, ` +
217
+ `or quoted citation tags (\`[REFUTED via ...]\`, \`[CONFIRMED via ...]\`).\n\n`;
218
+ return (`## Language Rule (mandatory)\n` +
219
+ `${debatePreamble}The user wrote the ` +
220
+ `Problem Statement above in their own native language. You must:\n` +
221
+ `- **Part 1 (JSON)**: keys, the \`type\` field, and citation/tag strings stay in ENGLISH. ` +
222
+ `Free-text values inside JSON fields (\`summary\`, list items, prose sections) MUST use ` +
223
+ `the SAME language the user used in the Problem Statement.\n` +
224
+ `- **Part 2 (Markdown)**: write entirely in the user's native language. Markdown headings ` +
225
+ `that we control (the ones listed below) stay in English as printed, but body text under ` +
226
+ `each heading is in the user's language.\n` +
227
+ selectLine);
228
+ }
128
229
  /**
129
230
  * Evidence rule injected into stance prompts. Verification tools may be
130
231
  * absent (fast-tier participants skip them) — the rule covers both cases.
@@ -159,6 +260,20 @@ const EVIDENCE_RULE_FOLLOWUP = `\n## Evidence Rule\n` +
159
260
  `- Most follow-up turns will not need any tool call.\n` +
160
261
  `Tag verified results: \`[CONFIRMED via <tool>:<evidence>]\` or \`[REFUTED via <tool>:<evidence>]\`.\n` +
161
262
  `Uncited numbers you cannot verify: \`[UNVERIFIED: <claim>]\`.\n`;
263
+ /**
264
+ * Scope discipline (F10). Debate turns are for DIRECTION — a stance, its
265
+ * reasoning, and a cross-question — not for delivering the work product. Left
266
+ * unconstrained, models "over-deliver": a researcher opening once emitted a full
267
+ * `docs/plans/…-implementation-plan.md` with file contents and a
268
+ * "REQUIRED SUB-SKILL: executing-plans / Which approach?" handoff — the
269
+ * synthesis stage's job, not a debate turn's. This keeps turns argumentative and
270
+ * leaves the plan/spec/code to the Leader's synthesis.
271
+ */
272
+ const DEBATE_SCOPE_RULE = `\n## Scope\n` +
273
+ `This is a debate about DIRECTION, not an implementation handoff. In your turn do NOT:\n` +
274
+ `- write out file contents, code files, or a full step-by-step implementation/execution plan;\n` +
275
+ `- emit task lists, "Final file content:", plan-file templates, or "next steps / which approach?" handoffs.\n` +
276
+ `Argue your position and its trade-offs; the Leader's synthesis owns the plan and any artifacts.\n`;
162
277
  /**
163
278
  * Length discipline injected into every debate turn (F13 token-thrift). The
164
279
  * debate-turn ceilings are generous (4096-6144 maxTokens) and reasoning models
@@ -187,7 +302,33 @@ function personaOf(role, stance) {
187
302
  focus: stance.focus ?? "",
188
303
  };
189
304
  }
190
- return { label: `${role} specialist`, lens: `your ${role} perspective`, focus: "" };
305
+ return {
306
+ label: `${role} specialist`,
307
+ lens: `the ${role} discipline — what a proposal costs, breaks, or unlocks in your domain, judged with a practitioner's scar tissue`,
308
+ focus: "",
309
+ };
310
+ }
311
+ /**
312
+ * Ongoing-task context block, threaded from `spec.parentContext`. Both the
313
+ * explicit `/council` path and auto-council attach the session/task context onto
314
+ * the spec (see council/index.ts), so EVERY debate stage — rebuttal, follow-up,
315
+ * leader evaluation, synthesis — stays anchored to the parent task and the
316
+ * decisions already made, instead of drifting off the isolated sub-task.
317
+ *
318
+ * `buildOpeningPrompt` already injects `conversationContext` directly, so it does
319
+ * NOT call this (avoids double-inclusion in the opening statement). Capped so a
320
+ * long session context cannot blow the per-turn debate prompt budget.
321
+ */
322
+ function ongoingContextBlock(spec, cap = 4000) {
323
+ const ctx = spec.parentContext?.trim();
324
+ if (!ctx)
325
+ return "";
326
+ const body = ctx.length > cap ? `${ctx.slice(0, cap)}\n…(earlier context truncated)` : ctx;
327
+ return (`\n## Ongoing Task Context\n` +
328
+ `You are mid-way through a larger task — this debate continues that work; it does not restart it. ` +
329
+ `Treat every decision recorded below as settled input: build directly on it, and make your arguments advance the parent task from where it stands now. ` +
330
+ `Do not reopen settled decisions, do not propose starting over, and do not wander onto any problem other than the one this step serves.\n` +
331
+ `${body}\n\n---\n\n`);
191
332
  }
192
333
  export function buildOpeningPrompt(ctx) {
193
334
  const me = personaOf(ctx.speakerRole, ctx.speakerStance);
@@ -198,11 +339,14 @@ export function buildOpeningPrompt(ctx) {
198
339
  const focusLine = me.focus ? `\nYour specific focus: ${me.focus}\n` : "";
199
340
  const stackLock = buildStackLockSection(ctx.spec);
200
341
  return {
201
- system: `You are the "${me.label}". Your lens: ${me.lens}.\n` +
202
- `You are entering a discussion with the "${them.label}" (${them.lens}).\n` +
342
+ system: `You are the "${me.label}", and you own that chair. Your lens: ${me.lens}. ` +
343
+ `Speak like someone who has watched this exact class of problem fail before — not like a document.\n` +
344
+ `You are entering a discussion with the "${them.label}" (${them.lens}). ` +
345
+ `They are sharp and they will push back; a claim you cannot defend is a claim you should not open with.\n` +
203
346
  focusLine +
204
- ENGLISH_ONLY_RULE +
347
+ buildLanguageRule(ctx.language) +
205
348
  EVIDENCE_RULE_OPENING +
349
+ DEBATE_SCOPE_RULE +
206
350
  concisenessRule(220) +
207
351
  (stackLock ? `\n${stackLock}\n` : "") +
208
352
  guardrails +
@@ -212,9 +356,10 @@ export function buildOpeningPrompt(ctx) {
212
356
  `Constraints: ${ctx.spec.constraints.join("; ")}\n` +
213
357
  `Success Criteria: ${ctx.spec.successCriteria.join("; ")}\n` +
214
358
  `Scope: ${ctx.spec.scope}\n\n` +
215
- `Share your analysis from your stated lens. Focus on the success criteria address each one. ` +
216
- `End by asking the "${them.label}" for their perspective on your analysis.`,
217
- prompt: `Analyze the problem through your stated lens. Be specific, evidence-based, and stay within your stance do not drift into another role's perspective.`,
359
+ `Deliver your opening analysis in your own voice. Take the success criteria one by one: say plainly ` +
360
+ `which are easy, which are hard, and where from your seat — the bodies are buried. ` +
361
+ `Close by putting one pointed question to the "${them.label}": the question you most need answered before you would sign off.`,
362
+ prompt: `Open the debate from your stated lens. Stake out a real position — a stance nobody could disagree with is not a stance. Be specific and evidence-based, and do not drift into another role's perspective; your value here is depth, not coverage.`,
218
363
  };
219
364
  }
220
365
  export function buildResponsePrompt(ctx) {
@@ -222,19 +367,22 @@ export function buildResponsePrompt(ctx) {
222
367
  const them = personaOf(ctx.partnerRole, ctx.partnerStance);
223
368
  const stackLock = buildStackLockSection(ctx.spec);
224
369
  return {
225
- system: `You are the "${me.label}" (lens: ${me.lens}) responding to the "${them.label}" (lens: ${them.lens}).\n` +
226
- ENGLISH_ONLY_RULE +
370
+ system: `You are the "${me.label}" (lens: ${me.lens}) responding to the "${them.label}" (lens: ${them.lens}). ` +
371
+ `This is a working session between peers — candid, specific, zero diplomacy theater.\n` +
372
+ buildLanguageRule(ctx.language) +
227
373
  EVIDENCE_RULE_RESPONSE +
374
+ DEBATE_SCOPE_RULE +
228
375
  concisenessRule(160) +
229
376
  (stackLock ? `\n${stackLock}\n` : "") +
230
377
  `\n## Discussion Brief\n` +
231
378
  `Problem: ${ctx.spec.problemStatement}\n` +
232
379
  `Success Criteria: ${ctx.spec.successCriteria.join("; ")}\n\n` +
233
- `Give your honest take:\n` +
234
- `- Where you agree, say so briefly and build on it\n` +
235
- `- Where you disagree, explain why with your own reasoning\n` +
236
- `- Share what they might be missing from your stated lens\n\n` +
237
- `End with a question back to them.\n\n` +
380
+ ongoingContextBlock(ctx.spec) +
381
+ `React the way a good colleague does:\n` +
382
+ `- Where they are right, concede fast one line — then build their point somewhere they did not take it\n` +
383
+ `- Where they are wrong, say so plainly and name the exact assumption that breaks\n` +
384
+ `- Name the blind spot: the thing your lens sees that theirs structurally cannot\n\n` +
385
+ `End by pressing them with one sharp question — aimed at the weakest joint in their argument.\n\n` +
238
386
  `Do NOT include round numbers (e.g. "Round N", "Round 2 Response", "Reply #3") ` +
239
387
  `or any numeric counter referring to the discussion round in your output. ` +
240
388
  `The orchestrator already prints round headers above your response.`,
@@ -247,28 +395,41 @@ export function buildFollowupPrompt(ctx) {
247
395
  const them = personaOf(ctx.partnerRole, ctx.partnerStance);
248
396
  const stackLock = buildStackLockSection(ctx.spec);
249
397
  return {
250
- system: `You are the "${me.label}" (lens: ${me.lens}) continuing a discussion (round ${ctx.round}) with the "${them.label}" (lens: ${them.lens}).\n` +
251
- ENGLISH_ONLY_RULE +
398
+ // Cache-prefix stability (see project_cache_prefix_stability): every clause
399
+ // here depends ONLY on (speaker, partner, stance, spec, language) — all
400
+ // stable across rounds — so this `system` string is byte-identical from
401
+ // round 2..N for the same speaker. The per-round-dynamic bits (round number,
402
+ // running summary) MUST live in the `prompt` tail below, never here: a
403
+ // provider prompt-cache keys on the exact prefix, and the round number used
404
+ // to sit in the FIRST sentence, busting the cached prefix every round.
405
+ system: `You are the "${me.label}" (lens: ${me.lens}) continuing a discussion with the "${them.label}" (lens: ${them.lens}). ` +
406
+ `The easy points are settled; what remains is the hard residue — spend your words only there.\n` +
407
+ buildLanguageRule(ctx.language) +
252
408
  EVIDENCE_RULE_FOLLOWUP +
253
409
  concisenessRule(140) +
254
410
  (stackLock ? `\n${stackLock}\n` : "") +
255
411
  `\n` +
256
- (ctx.runningSummary
257
- ? `## Discussion State So Far\n${ctx.runningSummary}\n\nFocus on UNRESOLVED points only. Do not repeat agreed positions.\n\n`
258
- : "") +
412
+ ongoingContextBlock(ctx.spec) +
259
413
  `## Success Criteria (what we need to resolve)\n` +
260
414
  ctx.spec.successCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n") +
261
415
  `\n\n` +
262
- `Read their latest response. Then:\n` +
263
- `- If they raised valid points, acknowledge them and update your thinking\n` +
264
- `- If you still disagree, bring new evidence or a different angle\n` +
265
- `- If you've changed your mind, say so explicitly\n\n` +
266
- `Stay within your lens; do not drift into the other specialist's role. ` +
416
+ `Read their latest response like a peer, not a debater scoring points. Then:\n` +
417
+ `- If they landed a real hit, say so and update — changing your mind on evidence is strength, not defeat\n` +
418
+ `- If you still disagree, do not repeat yourself louder; bring NEW evidence or attack from an angle you have not used\n` +
419
+ `- If you have genuinely converged, declare it in one sentence and stop arguing\n\n` +
420
+ `Stay in your lane your lens, not theirs. ` +
267
421
  `Be concise. End with: do you agree on where we've landed?\n\n` +
422
+ `When a "Discussion State So Far" summary is present in the message below, ` +
423
+ `focus on UNRESOLVED points only — restating agreed positions is dead weight.\n\n` +
268
424
  `Do NOT include round numbers (e.g. "Round N", "Response Round 2", "Round 4") ` +
269
425
  `or any numeric counter referring to the discussion round in your output. ` +
270
426
  `The orchestrator already prints round headers above your response.`,
271
- prompt: (ctx.speakerLastPosition ? `Your previous position:\n${ctx.speakerLastPosition}\n\n` : "") +
427
+ // Per-round dynamic content lives here so the `system` prefix above stays
428
+ // cacheable. The first user message already changes every round (partner's
429
+ // latest response differs), so nothing cacheable is lost by placing the
430
+ // round number / running summary here.
431
+ prompt: (ctx.runningSummary ? `## Discussion State So Far\n${ctx.runningSummary}\n\n` : "") +
432
+ (ctx.speakerLastPosition ? `Your previous position:\n${ctx.speakerLastPosition}\n\n` : "") +
272
433
  `Their latest (${them.label}):\n${ctx.partnerPosition}`,
273
434
  };
274
435
  }
@@ -284,11 +445,12 @@ export function buildLeaderEvaluationPrompt(ctx) {
284
445
  : "";
285
446
  return {
286
447
  system: `You are the discussion moderator evaluating whether a multi-expert debate has produced sufficient results.\n` +
287
- ENGLISH_ONLY_RULE +
448
+ buildLanguageRule(ctx.language) +
288
449
  (stackLock ? `\n${stackLock}\n` : "") +
289
450
  `\n## Success Criteria to Evaluate\n` +
290
451
  ctx.spec.successCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n") +
291
452
  `\n\n` +
453
+ ongoingContextBlock(ctx.spec) +
292
454
  `For EACH criterion, determine:\n` +
293
455
  `- Is it adequately addressed by the debate? (met/not-met)\n` +
294
456
  `- What evidence from the debate supports this?\n\n` +
@@ -302,8 +464,9 @@ export function buildLeaderEvaluationPrompt(ctx) {
302
464
  outOfStackCheck +
303
465
  `Output ONLY a JSON object (no markdown):\n` +
304
466
  `{\n` +
467
+ ` "nextRoundFocus": "one short phrase naming the single most important point the NEXT round should resolve (empty string if you are stopping)",\n` +
305
468
  ` "allCriteriaMet": true/false,\n` +
306
- ` "criteriaStatus": [{"criterion": "...", "met": true/false, "evidence": "..."}],\n` +
469
+ ` "criteriaStatus": [{"criterion": "...", "met": true/false, "evidence": "..."}], // EXACTLY one entry per Success Criterion above, IN THE SAME ORDER. Do not merge, split, reorder, or invent criteria — the user pins these and watches each one.\n` +
307
470
  ` "unresolvedPoints": ["point 1"],\n` +
308
471
  ` "needsResearch": false,\n` +
309
472
  ` "researchQuery": null,\n` +
@@ -319,15 +482,17 @@ export function buildLeaderEvaluationPrompt(ctx) {
319
482
  };
320
483
  }
321
484
  // ── Round summary ────────────────────────────────────────────────────────────
322
- export function buildRoundSummaryPrompt(allExchanges, topic, round) {
485
+ export function buildRoundSummaryPrompt(allExchanges, topic, round,
486
+ /** Feature B — resolved council debate language (undefined → English). */
487
+ language) {
323
488
  return {
324
489
  system: `Summarize this discussion in 3-5 bullet points.` +
325
- ENGLISH_ONLY_RULE +
326
- `\nFocus on:\n` +
327
- `1. Points where participants AGREE\n` +
328
- `2. Points still in DISPUTE (with each side's core argument)\n` +
329
- `3. New EVIDENCE or perspectives raised this round\n` +
330
- `Be concise — one line per bullet. No preamble. ` +
490
+ buildLanguageRule(language) +
491
+ `\nYou are the debate's working memory — later turns see ONLY your bullets, so anything you drop is lost. Capture:\n` +
492
+ `1. AGREED points both sides now share\n` +
493
+ `2. DISPUTED live disagreements, with each side's strongest single argument (not their weakest)\n` +
494
+ `3. NEW evidence, verified facts, or angles that first surfaced this round\n` +
495
+ `Be concise — one line per bullet. No preamble, no color commentary. ` +
331
496
  `Do NOT write "Round N" or any round-number counter in your bullets — this summary is fed into later turns, where round labels read as robotic noise. Refer to points by their content.`,
332
497
  prompt: `Round ${round} discussion on: ${topic}\n\n${allExchanges}`,
333
498
  };
@@ -431,7 +596,8 @@ export function buildDebatePlanPrompt(spec) {
431
596
  prompt: `## Topic\n${spec.problemStatement}\n\n` +
432
597
  `## Constraints\n${spec.constraints.map((c) => `- ${c}`).join("\n") || "- (none)"}\n\n` +
433
598
  `## Success Criteria\n${spec.successCriteria.map((c) => `- ${c}`).join("\n")}\n\n` +
434
- `## Scope\n${spec.scope || "(unspecified)"}`,
599
+ `## Scope\n${spec.scope || "(unspecified)"}` +
600
+ ongoingContextBlock(spec),
435
601
  };
436
602
  }
437
603
  function shapeHint(s) {
@@ -505,33 +671,26 @@ export function buildSynthesisPrompt(ctx) {
505
671
  const decisiveness = finalShape.kind === "decision" || finalShape.kind === "implementation_plan"
506
672
  ? `\n## Decisiveness (recommendation/verdict)\n` +
507
673
  `Lead with the single choice you would make if the user said "you decide" — name it in the first sentence of the recommendation. ` +
508
- `Do NOT hedge with "it depends", "both have merits", or an unranked list of options. ` +
674
+ `Do NOT hedge with "it depends", "both have merits", or an unranked list of options; the user hired a panel to get a call, not a menu. ` +
509
675
  `If the debate genuinely did not converge, say so in one sentence and STILL give your best single recommendation plus the one condition that would change it.\n`
510
676
  : "";
511
- let system = `You are the team lead synthesizing a multi-specialist discussion.\n\n` +
677
+ let system = `You are the team lead synthesizing a multi-specialist discussion. The panel has argued; now you rule. ` +
678
+ `Work like an editor-in-chief: keep what survived scrutiny, cut what got refuted, credit the dissent worth keeping, ` +
679
+ `and hand the user something they can act on without re-reading the debate.\n\n` +
512
680
  `## Original Brief\n` +
513
681
  `Problem: ${ctx.spec.problemStatement}\n` +
514
682
  `Constraints: ${ctx.spec.constraints.join("; ")}\n` +
515
683
  `Success Criteria: ${ctx.spec.successCriteria.join("; ")}\n` +
684
+ ongoingContextBlock(ctx.spec) +
516
685
  intent +
517
686
  (stackLockForSynth ? `\n${stackLockForSynth}\n` : "") +
518
687
  guardrailBlock +
519
688
  decisiveness +
520
- `\nProduce the answer the user requested — do NOT default to an implementation plan ` +
689
+ `\nProduce the answer the user actually asked for — do NOT default to an implementation plan ` +
521
690
  `unless the output shape explicitly asks for actionItems/plan. ` +
522
- `Stay grounded in the discussion; do not invent facts; mark unverified claims explicitly.\n\n` +
523
- `## Language Rule (mandatory)\n` +
524
- `The debate above is entirely in English (debate language is forced). The user wrote the ` +
525
- `Problem Statement above in their own native language. You must:\n` +
526
- `- **Part 1 (JSON)**: keys, the \`type\` field, and citation/tag strings stay in ENGLISH. ` +
527
- `Free-text values inside JSON fields (\`summary\`, list items, prose sections) MUST use ` +
528
- `the SAME language the user used in the Problem Statement.\n` +
529
- `- **Part 2 (Markdown)**: write entirely in the user's native language. Markdown headings ` +
530
- `that we control (the ones listed below) stay in English as printed, but body text under ` +
531
- `each heading is in the user's language.\n` +
532
- `- Detect the user's language from the Problem Statement. If it's Vietnamese, write in ` +
533
- `Vietnamese. If Japanese, Japanese. If English, English. Do not translate code, identifiers, ` +
534
- `or quoted citation tags (\`[REFUTED via ...]\`, \`[CONFIRMED via ...]\`).\n\n` +
691
+ `Stay grounded in what was actually said in the debate: you may sharpen and arbitrate, but never invent facts ` +
692
+ `the specialists did not raise, and mark unverified claims explicitly.\n\n` +
693
+ buildSynthesisLanguageRule(ctx.language) +
535
694
  `Output TWO parts separated by the exact line \`---READABLE---\`:\n\n` +
536
695
  `**Part 1: JSON** — a single JSON object:\n` +
537
696
  `{\n` +
@@ -539,10 +698,36 @@ export function buildSynthesisPrompt(ctx) {
539
698
  ` "summary": "1-2 sentence executive summary in the user's native language",\n` +
540
699
  sectionLines +
541
700
  "\n" +
701
+ ` "nextActions": [ /* 2-4 items, see the Next Actions rule below */ ]\n` +
542
702
  `}\n\n` +
703
+ `## Next Actions (mandatory — YOU decide, do not default)\n` +
704
+ `After reading this outcome, what should the user be offered to do NEXT? This depends ` +
705
+ `entirely on WHY this debate happened — a bug investigation, an evaluation, a plan, and a ` +
706
+ `decision each warrant DIFFERENT follow-ups. A fixed "accept / research / apply" menu is wrong. ` +
707
+ `Choose 2-4 actions from this fixed vocabulary, ordered best-first (index 0 = your recommended ` +
708
+ `default), writing each label/reason in the user's native language:\n` +
709
+ ` - "implement" → the conclusion is ready to BUILD. Offer this whenever acting on the outcome ` +
710
+ `means changing code — INCLUDING a decision to refactor / remove / add. The conclusion itself is ` +
711
+ `the spec (no separate plan artifact needed); picking it loads that spec and carries it out ` +
712
+ `through the normal workflow (plan → change → verify). Make it the recommended default (index 0) ` +
713
+ `when the debate converged on a concrete, buildable decision. Label it with the ACTION (e.g. ` +
714
+ `"Triển khai …" / "Implement …"), never "continue".\n` +
715
+ ` - "continue_session" → return to the composer WITHOUT building. The user keeps DISCUSSING with ` +
716
+ `this debate as context (their next message inherits the conclusion automatically). The right ` +
717
+ `default for a pure evaluation / discussion whose deliverable is the analysis itself, or when the ` +
718
+ `user should weigh in before any code change. This ALSO covers "ask a follow-up" — do NOT emit a ` +
719
+ `separate follow-up action.\n` +
720
+ ` - "save_exit" → the analysis IS the deliverable; save it and stop here.\n` +
721
+ `Rules: choose from {"implement","continue_session","save_exit"}. Offer "implement" whenever the ` +
722
+ `outcome is actionable in code (a build decision, an implementation_plan, or a bug investigation ` +
723
+ `ready to fix) and make it index 0; otherwise lead with "continue_session". NEVER attach an ` +
724
+ `implementation-flavoured label ("triển khai", "build", "fix now") to "continue_session" — if you ` +
725
+ `mean build, the action MUST be "implement". Always include an escape ("save_exit" or ` +
726
+ `"continue_session"). Emit each as ` +
727
+ `{"action":"<id>","label":"<short button text>","reason":"<one line: why this fits THIS debate>"}.\n\n` +
543
728
  `**Part 2: Human-readable** — after \`---READABLE---\`, write in markdown with these headings (in this order):\n` +
544
729
  headingLines +
545
- `\n\nBe decisive but evidence-grounded.`;
730
+ `\n\nBe decisive but evidence-grounded — a verdict without evidence is noise; evidence without a verdict is homework handed back to the user.`;
546
731
  if (styleDirective) {
547
732
  system = `${styleDirective}\n\n${system}`;
548
733
  }
@@ -582,16 +767,18 @@ ${ctx.allExchanges}${extraContext}`,
582
767
  /**
583
768
  * Builds the system prompt for the research role.
584
769
  *
585
- * When `hasUrl` is true, injects a mandatory instruction to invoke a Playwright
586
- * or Chrome-DevTools tool before reporting Frontend Findings (CQ-04).
770
+ * When `hasUrl` is true, injects a mandatory instruction to use fetch_url (preferred
771
+ * for content) or a browser tool (playwright/chrome when screenshots or heavy JS interaction
772
+ * are required) before reporting Frontend Findings (CQ-04).
587
773
  *
588
774
  * Output format enforces 3 labelled sections with citation requirements (CQ-05).
589
775
  */
590
776
  export function buildResearchSystemPrompt(hasUrl, internetFirst = false) {
591
777
  const urlInstruction = hasUrl
592
778
  ? `\n## URL Research Requirement\n` +
593
- `This topic contains a URL. You MUST invoke a Playwright or Chrome-DevTools tool ` +
594
- `to navigate to it before reporting Frontend Findings. Do not skip this step.\n`
779
+ `This topic contains a URL. You MUST use the native fetch_url tool (preferred for most pages) ` +
780
+ `or a browser tool (playwright/chrome-devtools when you need screenshots, rendered layout, or interaction) ` +
781
+ `before reporting Frontend Findings. Do not skip this step.\n`
595
782
  : "";
596
783
  const modeBlock = internetFirst
597
784
  ? `\n## Research Mode: INTERNET-FIRST\n` +
@@ -615,8 +802,8 @@ export function buildResearchSystemPrompt(hasUrl, internetFirst = false) {
615
802
  `If no internet search was performed, write: ` +
616
803
  `_No internet research performed (tavily/web-fetch unavailable or not needed)._\n\n` +
617
804
  `## Frontend Findings (live)\n` +
618
- `Each finding must cite [snapshot:uid] from a Playwright screenshot or Chrome-DevTools inspection.\n` +
619
- `If no URL was present or browser tool was not invoked, write: _No live frontend inspection performed._\n\n` +
805
+ `Each finding must cite [snapshot:uid] from a Playwright/Chrome-DevTools screenshot/inspection **if** a browser tool was used.\n` +
806
+ `For ordinary pages, cite the result of fetch_url. If no URL inspection happened, write: _No live frontend inspection performed._\n\n` +
620
807
  `Do NOT speculate. Only report what you verified with tools.`);
621
808
  }
622
809
  //# sourceMappingURL=prompts.js.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * src/council/stance-recall.ts
3
+ *
4
+ * Sprint-2 item 3 — per-stance recall at debate opening. Builds the
5
+ * `CouncilConfig.stanceRecall` function from an EE client: given the panel's
6
+ * unique roles and a query, it fires ONE stance-weighted `/api/recall` per role
7
+ * (in parallel, bounded, failure-tolerant) and returns a `role → seed-text` map.
8
+ *
9
+ * The server weights the recall collections by the stance/role hint (researcher
10
+ * → principles, implementer → behavioral, verifier → self-QA), so each stance
11
+ * opens grounded in the slice of the brain its lens cares about — instead of the
12
+ * whole panel sharing one generic recall.
13
+ *
14
+ * Contract: never throws. A role whose recall fails/empties/ times out simply
15
+ * gets no entry in the map (that participant opens unchanged).
16
+ */
17
+ import type { EERecallResponse } from "../ee/types.js";
18
+ /** Minimal EE-client surface this helper needs (keeps it unit-testable). */
19
+ export interface StanceRecallClient {
20
+ recall(query: string, opts?: {
21
+ stance?: string;
22
+ cwd?: string;
23
+ project?: string;
24
+ sourceSession?: string;
25
+ timeoutMs?: number;
26
+ }): Promise<EERecallResponse | null>;
27
+ }
28
+ export interface StanceRecallOptions {
29
+ cwd?: string;
30
+ project?: string;
31
+ sourceSession?: string;
32
+ /** Per-recall timeout. Kept modest so N parallel recalls don't stall openings. */
33
+ timeoutMs?: number;
34
+ /** Cap the seed text folded into each opening so it can't blow the prompt. */
35
+ maxSeedChars?: number;
36
+ }
37
+ /**
38
+ * Build a `stanceRecall(roles, query)` function bound to an EE client. Returns
39
+ * undefined when no client is available, so callers can spread it into
40
+ * CouncilConfig without a conditional (`stanceRecall: makeStanceRecall(...)`).
41
+ */
42
+ export declare function makeStanceRecall(client: StanceRecallClient | null | undefined, opts?: StanceRecallOptions): ((roles: string[], query: string) => Promise<Map<string, string>>) | undefined;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * src/council/stance-recall.ts
3
+ *
4
+ * Sprint-2 item 3 — per-stance recall at debate opening. Builds the
5
+ * `CouncilConfig.stanceRecall` function from an EE client: given the panel's
6
+ * unique roles and a query, it fires ONE stance-weighted `/api/recall` per role
7
+ * (in parallel, bounded, failure-tolerant) and returns a `role → seed-text` map.
8
+ *
9
+ * The server weights the recall collections by the stance/role hint (researcher
10
+ * → principles, implementer → behavioral, verifier → self-QA), so each stance
11
+ * opens grounded in the slice of the brain its lens cares about — instead of the
12
+ * whole panel sharing one generic recall.
13
+ *
14
+ * Contract: never throws. A role whose recall fails/empties/ times out simply
15
+ * gets no entry in the map (that participant opens unchanged).
16
+ */
17
+ const DEFAULT_TIMEOUT_MS = 4000;
18
+ const DEFAULT_MAX_SEED_CHARS = 1200;
19
+ /**
20
+ * Build a `stanceRecall(roles, query)` function bound to an EE client. Returns
21
+ * undefined when no client is available, so callers can spread it into
22
+ * CouncilConfig without a conditional (`stanceRecall: makeStanceRecall(...)`).
23
+ */
24
+ export function makeStanceRecall(client, opts = {}) {
25
+ if (!client)
26
+ return undefined;
27
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
28
+ const maxSeedChars = opts.maxSeedChars ?? DEFAULT_MAX_SEED_CHARS;
29
+ return async (roles, query) => {
30
+ const seeds = new Map();
31
+ const q = (query ?? "").trim();
32
+ if (!q)
33
+ return seeds;
34
+ const unique = Array.from(new Set(roles.filter((r) => typeof r === "string" && r.trim())));
35
+ if (unique.length === 0)
36
+ return seeds;
37
+ await Promise.all(unique.map(async (role) => {
38
+ try {
39
+ const resp = await client.recall(q, {
40
+ stance: role,
41
+ cwd: opts.cwd,
42
+ project: opts.project,
43
+ sourceSession: opts.sourceSession,
44
+ timeoutMs,
45
+ });
46
+ const text = resp?.text?.trim();
47
+ if (text)
48
+ seeds.set(role, text.slice(0, maxSeedChars));
49
+ }
50
+ catch {
51
+ /* per-role failure is non-fatal — that stance just opens unseeded */
52
+ }
53
+ }));
54
+ return seeds;
55
+ };
56
+ }
57
+ //# sourceMappingURL=stance-recall.js.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Strip inline chain-of-thought markup from council LLM output.
3
+ *
4
+ * Some providers (kimi-k2.7 via opencode-go, GLM thinking variants) emit
5
+ * reasoning inline as `<think>…</think>` in `result.text` instead of the AI
6
+ * SDK's separated `reasoningText`. Rendered verbatim, the user sees hundreds
7
+ * of words of internal drafting above every debate turn (live-verified
8
+ * 2026-07-06). Applied at the council LLM boundary (src/council/llm.ts) so
9
+ * every consumer — debate turns, leader evals, synthesis — is covered.
10
+ *
11
+ * Handles three shapes:
12
+ * - complete `<think>…</think>` blocks anywhere (global, case-insensitive)
13
+ * - an unclosed trailing `<think>…` block (output truncated mid-reasoning)
14
+ * - a stray leading `…</think>` (model omitted the opener; everything up to
15
+ * and including the close tag is reasoning)
16
+ */
17
+ export declare function stripThinkBlocks(text: string): string;