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
@@ -0,0 +1,91 @@
1
+ /**
2
+ * src/ui/utils/tool-summary.ts
3
+ *
4
+ * Phrasing for the tool-group panel. Pure string helpers, no React, so the
5
+ * wording is unit-testable and the component stays presentational.
6
+ *
7
+ * Active: "Reading 2 files…" (header, present participle)
8
+ * Done: "Read 2 files, ran 1 shell command" (past-tense recap)
9
+ *
10
+ * Counting is per CATEGORY, not per tool name: read_file and
11
+ * mcp__filesystem__read_text_file are both "files" to a reader.
12
+ */
13
+ import { verbForTool } from "./tools.js";
14
+ const CATEGORIES = {
15
+ read: { gerund: "Reading", past: "read", noun: "file", nounPlural: "files" },
16
+ write: { gerund: "Writing", past: "wrote", noun: "file", nounPlural: "files" },
17
+ edit: { gerund: "Editing", past: "edited", noun: "file", nounPlural: "files" },
18
+ bash: { gerund: "Running", past: "ran", noun: "shell command", nounPlural: "shell commands" },
19
+ search: { gerund: "Searching", past: "ran", noun: "search", nounPlural: "searches" },
20
+ agent: { gerund: "Exploring", past: "ran", noun: "sub-agent", nounPlural: "sub-agents" },
21
+ other: { gerund: "Working", past: "ran", noun: "tool", nounPlural: "tools" },
22
+ };
23
+ /** Stable phrase order so the recap doesn't reshuffle as items land. */
24
+ const ORDER = ["read", "write", "edit", "bash", "search", "agent", "other"];
25
+ export function categoryForTool(name) {
26
+ if (name === "write_file" || /^mcp_+filesystem__write_file$/.test(name))
27
+ return "write";
28
+ if (name === "edit_file" || /^mcp_+filesystem__edit_file$/.test(name))
29
+ return "edit";
30
+ if (name === "bash")
31
+ return "bash";
32
+ if (name === "task" || name === "delegate")
33
+ return "agent";
34
+ // Fall back to the existing verb vocabulary so a new tool inherits sane
35
+ // phrasing without being enumerated here twice.
36
+ const verb = verbForTool(name);
37
+ if (verb === "Reading")
38
+ return "read";
39
+ if (verb === "Searching")
40
+ return "search";
41
+ return "other";
42
+ }
43
+ function countByCategory(toolNames) {
44
+ const counts = new Map();
45
+ for (const n of toolNames) {
46
+ const c = categoryForTool(n);
47
+ counts.set(c, (counts.get(c) ?? 0) + 1);
48
+ }
49
+ return counts;
50
+ }
51
+ function phrase(cat, n, past) {
52
+ const noun = n === 1 ? cat.noun : cat.nounPlural;
53
+ return past ? `${cat.past} ${n} ${noun}` : `${cat.gerund} ${n} ${noun}`;
54
+ }
55
+ /**
56
+ * Header while the group runs: "Reading 2 files…".
57
+ * With a mixed batch the dominant category wins and the rest are summed into a
58
+ * trailing "+N more" so the header never claims work it isn't doing.
59
+ */
60
+ export function activeToolGroupHeader(toolNames) {
61
+ if (toolNames.length === 0)
62
+ return "Working…";
63
+ const counts = countByCategory(toolNames);
64
+ let bestKey = "other";
65
+ let best = 0;
66
+ for (const key of ORDER) {
67
+ const c = counts.get(key) ?? 0;
68
+ if (c > best) {
69
+ best = c;
70
+ bestKey = key;
71
+ }
72
+ }
73
+ const rest = toolNames.length - best;
74
+ const head = phrase(CATEGORIES[bestKey], best, false);
75
+ return rest > 0 ? `${head} +${rest} more…` : `${head}…`;
76
+ }
77
+ /** Past-tense recap once the group closes: "Read 2 files, ran 1 shell command". */
78
+ export function doneToolGroupSummary(toolNames) {
79
+ if (toolNames.length === 0)
80
+ return "Done";
81
+ const counts = countByCategory(toolNames);
82
+ const parts = [];
83
+ for (const key of ORDER) {
84
+ const n = counts.get(key) ?? 0;
85
+ if (n > 0)
86
+ parts.push(phrase(CATEGORIES[key], n, true));
87
+ }
88
+ const joined = parts.join(", ");
89
+ return joined.charAt(0).toUpperCase() + joined.slice(1);
90
+ }
91
+ //# sourceMappingURL=tool-summary.js.map
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * Plan 06 (status bar) subscribes to DowngradeEvent for UI updates.
9
9
  */
10
- import { getModelByTier } from "../models/registry.js";
10
+ import { getRoutedModelByTier } from "../router/peak-hour.js";
11
11
  import { getDefaultProvider } from "../utils/settings.js";
12
12
  function buildDowngradeChain() {
13
13
  const provider = getDefaultProvider() ?? undefined;
@@ -15,7 +15,7 @@ function buildDowngradeChain() {
15
15
  const seen = new Set();
16
16
  const chain = [];
17
17
  for (const tier of tiers) {
18
- const m = getModelByTier(tier, provider);
18
+ const m = getRoutedModelByTier(tier, provider);
19
19
  if (m && !seen.has(m.id)) {
20
20
  chain.push(m.id);
21
21
  seen.add(m.id);
@@ -24,12 +24,12 @@ async function ensureDirectory(filePath) {
24
24
  export async function appendProductLedger(productRunId, entry, homeOverride) {
25
25
  const filePath = getProductLedgerPath(productRunId, homeOverride);
26
26
  await ensureDirectory(filePath);
27
- // Ensure file exists for lockfile to target
27
+ // Ensure file exists for lockfile to target without truncating it concurrently
28
28
  try {
29
29
  await fs.access(filePath);
30
30
  }
31
31
  catch {
32
- await fs.writeFile(filePath, "");
32
+ await fs.appendFile(filePath, "");
33
33
  }
34
34
  const releaseLock = await lockfile.lock(filePath, {
35
35
  retries: { retries: 10, minTimeout: 10, maxTimeout: 100 },
@@ -0,0 +1,85 @@
1
+ /**
2
+ * src/utils/event-loop-monitor.ts
3
+ *
4
+ * Event-loop block detector.
5
+ *
6
+ * Root cause it addresses (observed live, 2026-07-16, session 90c3ff533826):
7
+ * the TUI froze for 304.5s mid-turn — keystrokes and mouse clicks produced
8
+ * nothing during the freeze, then ALL replayed at once when it ended (the
9
+ * signature of a blocked event loop, not a stalled render). Crucially the
10
+ * 120s provider stall watchdog (tool-engine.ts) did NOT rescue the turn at its
11
+ * deadline: `stall_rescue` landed at 09:05:47, 6.7s AFTER the loop recovered at
12
+ * 09:05:41. A setTimeout cannot fire while the loop is blocked, so every
13
+ * existing guard in this codebase is blind to this failure mode BY
14
+ * CONSTRUCTION — they are all loop-driven. Same pattern measured across 4
15
+ * models / 4 providers (grok-composer 304.5s, deepseek-v4-flash 320.2s,
16
+ * kimi-k2.7-code 329.7s + 314.8s), so it is not a provider quirk.
17
+ *
18
+ * This module is the missing instrument: a timer that measures its OWN lateness.
19
+ * It cannot prevent a block (it is loop-driven too), but the drift it observes
20
+ * on the first tick AFTER the loop frees up measures the block that just
21
+ * happened. Pair it with the CPU profiler in `loop-profiler.ts`, whose V8
22
+ * sampling thread runs INDEPENDENTLY of the JS thread and therefore captures
23
+ * the culprit stack DURING the block.
24
+ *
25
+ * Deliberately dependency-free and cheap: one unref'd interval, no allocation
26
+ * per tick. `detectBlock` is pure so the drift maths is unit-testable without
27
+ * timers.
28
+ */
29
+ /** A detected event-loop block, reported to `onBlock`. */
30
+ export interface EventLoopBlock {
31
+ /**
32
+ * How long the loop was blocked, in ms. Measured as the monitor tick's own
33
+ * lateness, so it UNDER-reports by up to one tick interval (a block shorter
34
+ * than the tick can hide entirely between two ticks). Treat it as a lower
35
+ * bound.
36
+ */
37
+ blockedMs: number;
38
+ /** What the process last said it was doing — see {@link setLoopBreadcrumb}. */
39
+ breadcrumb: string | null;
40
+ /** ISO timestamp of the tick that observed the block (i.e. after it ended). */
41
+ detectedAt: string;
42
+ }
43
+ /**
44
+ * Decide whether an interval tick's lateness constitutes a block.
45
+ *
46
+ * A healthy tick fires ~`tickMs` after the previous one; the loop being busy
47
+ * pushes it later. Lateness beyond `thresholdMs` is reported as a block of that
48
+ * duration. Pure so the drift maths is testable without real timers.
49
+ *
50
+ * @param expectedAt when this tick was due (monotonic ms)
51
+ * @param actualAt when it actually ran (monotonic ms)
52
+ * @param thresholdMs report only blocks at least this long; <= 0 disables
53
+ * @returns block duration in ms, or null when the tick was on time
54
+ */
55
+ export declare function detectBlock(expectedAt: number, actualAt: number, thresholdMs: number): number | null;
56
+ /**
57
+ * Record what the process is about to do, so a block report can name a suspect
58
+ * instead of just a duration. Call it around anything that could plausibly run
59
+ * long and synchronously (tool execution, a stream step). Cheap — a single
60
+ * assignment; safe to call on a hot path.
61
+ *
62
+ * Pass null to clear. Not a stack: last writer wins, by design — the goal is a
63
+ * hint for the profile, and the profile is the real evidence.
64
+ */
65
+ export declare function setLoopBreadcrumb(label: string | null): void;
66
+ /** The current breadcrumb, or null. */
67
+ export declare function getLoopBreadcrumb(): string | null;
68
+ /** Options for {@link startEventLoopMonitor}. */
69
+ export interface EventLoopMonitorOpts {
70
+ /** Report blocks at least this long. <= 0 disables the monitor entirely. */
71
+ thresholdMs: number;
72
+ /**
73
+ * How often to check. Bounds both the detection granularity and the amount a
74
+ * block can be under-reported by. 500ms costs ~2 wakeups/sec.
75
+ */
76
+ tickMs?: number;
77
+ /** Called once per detected block. Must not throw (it is guarded anyway). */
78
+ onBlock: (block: EventLoopBlock) => void;
79
+ }
80
+ /**
81
+ * Start watching for event-loop blocks. Returns a stop function (idempotent).
82
+ *
83
+ * The interval is unref'd so it never keeps the process alive on its own.
84
+ */
85
+ export declare function startEventLoopMonitor(opts: EventLoopMonitorOpts): () => void;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * src/utils/event-loop-monitor.ts
3
+ *
4
+ * Event-loop block detector.
5
+ *
6
+ * Root cause it addresses (observed live, 2026-07-16, session 90c3ff533826):
7
+ * the TUI froze for 304.5s mid-turn — keystrokes and mouse clicks produced
8
+ * nothing during the freeze, then ALL replayed at once when it ended (the
9
+ * signature of a blocked event loop, not a stalled render). Crucially the
10
+ * 120s provider stall watchdog (tool-engine.ts) did NOT rescue the turn at its
11
+ * deadline: `stall_rescue` landed at 09:05:47, 6.7s AFTER the loop recovered at
12
+ * 09:05:41. A setTimeout cannot fire while the loop is blocked, so every
13
+ * existing guard in this codebase is blind to this failure mode BY
14
+ * CONSTRUCTION — they are all loop-driven. Same pattern measured across 4
15
+ * models / 4 providers (grok-composer 304.5s, deepseek-v4-flash 320.2s,
16
+ * kimi-k2.7-code 329.7s + 314.8s), so it is not a provider quirk.
17
+ *
18
+ * This module is the missing instrument: a timer that measures its OWN lateness.
19
+ * It cannot prevent a block (it is loop-driven too), but the drift it observes
20
+ * on the first tick AFTER the loop frees up measures the block that just
21
+ * happened. Pair it with the CPU profiler in `loop-profiler.ts`, whose V8
22
+ * sampling thread runs INDEPENDENTLY of the JS thread and therefore captures
23
+ * the culprit stack DURING the block.
24
+ *
25
+ * Deliberately dependency-free and cheap: one unref'd interval, no allocation
26
+ * per tick. `detectBlock` is pure so the drift maths is unit-testable without
27
+ * timers.
28
+ */
29
+ import { logger } from "./logger.js";
30
+ /**
31
+ * Decide whether an interval tick's lateness constitutes a block.
32
+ *
33
+ * A healthy tick fires ~`tickMs` after the previous one; the loop being busy
34
+ * pushes it later. Lateness beyond `thresholdMs` is reported as a block of that
35
+ * duration. Pure so the drift maths is testable without real timers.
36
+ *
37
+ * @param expectedAt when this tick was due (monotonic ms)
38
+ * @param actualAt when it actually ran (monotonic ms)
39
+ * @param thresholdMs report only blocks at least this long; <= 0 disables
40
+ * @returns block duration in ms, or null when the tick was on time
41
+ */
42
+ export function detectBlock(expectedAt, actualAt, thresholdMs) {
43
+ if (!(thresholdMs > 0))
44
+ return null;
45
+ const lateBy = actualAt - expectedAt;
46
+ if (!Number.isFinite(lateBy) || lateBy < thresholdMs)
47
+ return null;
48
+ return Math.round(lateBy);
49
+ }
50
+ let _breadcrumb = null;
51
+ /**
52
+ * Record what the process is about to do, so a block report can name a suspect
53
+ * instead of just a duration. Call it around anything that could plausibly run
54
+ * long and synchronously (tool execution, a stream step). Cheap — a single
55
+ * assignment; safe to call on a hot path.
56
+ *
57
+ * Pass null to clear. Not a stack: last writer wins, by design — the goal is a
58
+ * hint for the profile, and the profile is the real evidence.
59
+ */
60
+ export function setLoopBreadcrumb(label) {
61
+ _breadcrumb = label;
62
+ }
63
+ /** The current breadcrumb, or null. */
64
+ export function getLoopBreadcrumb() {
65
+ return _breadcrumb;
66
+ }
67
+ /**
68
+ * Start watching for event-loop blocks. Returns a stop function (idempotent).
69
+ *
70
+ * The interval is unref'd so it never keeps the process alive on its own.
71
+ */
72
+ export function startEventLoopMonitor(opts) {
73
+ const { thresholdMs, onBlock } = opts;
74
+ const tickMs = opts.tickMs && opts.tickMs > 0 ? opts.tickMs : 500;
75
+ if (!(thresholdMs > 0))
76
+ return () => { };
77
+ let expectedAt = performance.now() + tickMs;
78
+ const timer = setInterval(() => {
79
+ const actualAt = performance.now();
80
+ const blockedMs = detectBlock(expectedAt, actualAt, thresholdMs);
81
+ expectedAt = actualAt + tickMs;
82
+ if (blockedMs === null)
83
+ return;
84
+ try {
85
+ onBlock({
86
+ blockedMs,
87
+ breadcrumb: getLoopBreadcrumb(),
88
+ detectedAt: new Date().toISOString(),
89
+ });
90
+ }
91
+ catch (err) {
92
+ logger.error("cli", `[event-loop-monitor] onBlock handler threw: ${err?.message}`, {
93
+ error: err,
94
+ blockedMs,
95
+ });
96
+ }
97
+ }, tickMs);
98
+ timer.unref?.();
99
+ let stopped = false;
100
+ return () => {
101
+ if (stopped)
102
+ return;
103
+ stopped = true;
104
+ clearInterval(timer);
105
+ };
106
+ }
107
+ //# sourceMappingURL=event-loop-monitor.js.map
@@ -194,7 +194,8 @@ export function detectInstallMethod(homeDir = os.homedir()) {
194
194
  }
195
195
  // Not under node_modules and not launched by node/bun → standalone binary.
196
196
  const exeBase = ((process.execPath || "").replace(/\\/g, "/").split("/").pop() ?? "").toLowerCase();
197
- if (!modPath.includes("/node_modules/") && !/^(node|bun)(\.exe)?$/.test(exeBase)) {
197
+ const isNodeOrBunRunner = /^(node|bun)(\.exe|-[\d.]+)?$/i.test(exeBase);
198
+ if (!modPath.includes("/node_modules/") && !isNodeOrBunRunner) {
198
199
  return "compiled";
199
200
  }
200
201
  // Linked/source build run from a git checkout (e.g. `bun link`, a symlinked
@@ -50,3 +50,17 @@ export declare function withDeadlineRace<T>(fn: () => Promise<T>, deadlineMs: nu
50
50
  * The short grace lets the normal fetch-level abort win first when it's quick.
51
51
  */
52
52
  abortSignal?: AbortSignal, abortGraceMs?: number): Promise<T>;
53
+ /**
54
+ * Wall-clock backstop (ms) for an isolated sub-agent task (`runIsolatedTask`).
55
+ *
56
+ * The council `generate()` chokepoint and the sprint impl/verify stages already
57
+ * have deadlines, but the *other* `runIsolatedTask` await points — plan-adherence
58
+ * review + fix, council research, grounding-verify — were bare `await`s. A
59
+ * provider that hangs on the JS side after the sub-agent's stream finishes wedges
60
+ * the whole pipeline with no error (observed live: run mrhc43f0fb9b impl, and the
61
+ * scoping stall). Wrap those calls in `withDeadlineRace(fn, getIsolatedTaskDeadlineMs(), ...)`
62
+ * so a hang surfaces as a rejection the caller already handles. Generous by
63
+ * default so a legitimately long tool-using sub-agent is not cut short; override
64
+ * with MUONROI_IDEAL_ISOLATED_TASK_MS. Clamped to [60s, 30min].
65
+ */
66
+ export declare function getIsolatedTaskDeadlineMs(): number;
@@ -106,4 +106,23 @@ abortSignal, abortGraceMs = 1500) {
106
106
  abortSignal.removeEventListener("abort", abortListener);
107
107
  }
108
108
  }
109
+ /**
110
+ * Wall-clock backstop (ms) for an isolated sub-agent task (`runIsolatedTask`).
111
+ *
112
+ * The council `generate()` chokepoint and the sprint impl/verify stages already
113
+ * have deadlines, but the *other* `runIsolatedTask` await points — plan-adherence
114
+ * review + fix, council research, grounding-verify — were bare `await`s. A
115
+ * provider that hangs on the JS side after the sub-agent's stream finishes wedges
116
+ * the whole pipeline with no error (observed live: run mrhc43f0fb9b impl, and the
117
+ * scoping stall). Wrap those calls in `withDeadlineRace(fn, getIsolatedTaskDeadlineMs(), ...)`
118
+ * so a hang surfaces as a rejection the caller already handles. Generous by
119
+ * default so a legitimately long tool-using sub-agent is not cut short; override
120
+ * with MUONROI_IDEAL_ISOLATED_TASK_MS. Clamped to [60s, 30min].
121
+ */
122
+ export function getIsolatedTaskDeadlineMs() {
123
+ const raw = Number.parseInt(process.env.MUONROI_IDEAL_ISOLATED_TASK_MS ?? "", 10);
124
+ if (Number.isFinite(raw) && raw >= 60_000 && raw <= 1_800_000)
125
+ return raw;
126
+ return 900_000; // 15 min backstop
127
+ }
109
128
  //# sourceMappingURL=llm-deadline.js.map
@@ -1,6 +1,6 @@
1
- import * as fs from "fs";
2
- import * as path from "path";
1
+ import fs from "fs";
3
2
  import * as os from "os";
3
+ import * as path from "path";
4
4
  const LEVEL_WEIGHTS = {
5
5
  debug: 0,
6
6
  info: 1,
@@ -0,0 +1,102 @@
1
+ /**
2
+ * src/utils/loop-profiler.ts
3
+ *
4
+ * Rolling V8 CPU profiler — the instrument that names the culprit when the
5
+ * event loop blocks (see `event-loop-monitor.ts` for the incident this exists
6
+ * for).
7
+ *
8
+ * Why a CPU profile and not a stack dump: while the JS thread is blocked, NO
9
+ * JS can run — you cannot ask the process what it is doing, because asking is
10
+ * itself JS. V8's sampling profiler runs on its OWN thread and samples the JS
11
+ * thread regardless of whether that thread is stuck, so the profile taken
12
+ * across a block contains the blocking frames. Verified under Bun 1.3.13: a
13
+ * deliberate 400ms synchronous block yielded 54 samples.
14
+ *
15
+ * Rolling segments keep the retained profile small without losing the block:
16
+ * rotation is loop-driven, so it CANNOT run during a block — whichever segment
17
+ * is in flight when the loop freezes stays in flight for the whole freeze, and
18
+ * is still open when the monitor detects the block right after. So `capture()`
19
+ * always writes a profile containing the entire block, however long it ran.
20
+ *
21
+ * Off by default (`MUONROI_LOOP_PROFILE=1` to arm) — continuous profiling has a
22
+ * real, if small, cost and this is a diagnostic, not a feature.
23
+ */
24
+ /** Minimal shape of the V8 CPU profile we consume (`Profiler.stop` result). */
25
+ interface CpuProfileNode {
26
+ id: number;
27
+ callFrame: {
28
+ functionName?: string;
29
+ url?: string;
30
+ lineNumber?: number;
31
+ };
32
+ children?: number[];
33
+ }
34
+ interface CpuProfile {
35
+ nodes: CpuProfileNode[];
36
+ samples?: number[];
37
+ }
38
+ /**
39
+ * Reduce a CPU profile to the single hottest stack, leaf-first.
40
+ *
41
+ * Why not just the top frame: samples land on the LEAF, which for a blocking
42
+ * loop is whatever primitive it calls (`Date.now`, a regex step, a syscall) —
43
+ * true but useless. Verified on a synthetic 3s block: the leaf was `now` with
44
+ * 188 samples while the actual culprit `theGuiltyFunction` had 4. The CALLERS
45
+ * are the answer, so we walk up from the hottest leaf and return the chain.
46
+ *
47
+ * This is what makes the profile readable from debug.log alone, without
48
+ * requiring anyone to open Chrome DevTools.
49
+ *
50
+ * Pure — unit-testable with a hand-built profile.
51
+ *
52
+ * @param maxFrames how many frames of the chain to return, leaf-first
53
+ * @returns frames like `theGuiltyFunction (file.ts:12)`, or [] if unusable
54
+ */
55
+ export declare function summarizeHotStack(profile: CpuProfile, maxFrames?: number): string[];
56
+ /** What a successful {@link LoopProfiler.capture} produced. */
57
+ export interface CaptureResult {
58
+ /** Path of the written `.cpuprofile` (open in Chrome DevTools for detail). */
59
+ file: string;
60
+ /** Hottest stack, leaf-first — readable without DevTools. See {@link summarizeHotStack}. */
61
+ hotStack: string[];
62
+ }
63
+ /** A rolling CPU profiler. All methods are best-effort and never throw. */
64
+ export interface LoopProfiler {
65
+ /**
66
+ * Discard the current segment and start a fresh one. Call periodically from
67
+ * the event loop to bound profile size — it is a no-op during a block, which
68
+ * is exactly what preserves the evidence.
69
+ */
70
+ rotate(): void;
71
+ /**
72
+ * Stop the current segment, write it to disk, and start a fresh one.
73
+ *
74
+ * Async because the inspector delivers `Profiler.stop` on a later tick
75
+ * (measured under Bun 1.3.13 — the callback does NOT run synchronously). The
76
+ * loop is already free by the time this is called, so awaiting is safe.
77
+ *
78
+ * @returns the profile path plus the hottest stack, or null on failure.
79
+ */
80
+ capture(reason: string): Promise<CaptureResult | null>;
81
+ /** Stop profiling and disconnect. Idempotent. */
82
+ dispose(): void;
83
+ }
84
+ /** Options for {@link createLoopProfiler}. */
85
+ export interface LoopProfilerOpts {
86
+ /**
87
+ * V8 sampling interval in microseconds. 10_000 (10ms) is ~100 samples/sec —
88
+ * plenty to identify a multi-second blocking frame, at a fraction of the cost
89
+ * of the 1ms default.
90
+ */
91
+ samplingIntervalUs?: number;
92
+ /** Directory for `.cpuprofile` files. Defaults to `~/.muonroi-cli/profiles`. */
93
+ dir?: string;
94
+ }
95
+ /**
96
+ * Create and arm a rolling CPU profiler.
97
+ *
98
+ * Returns null when the inspector is unavailable (some runtimes/builds) — the
99
+ * caller keeps the block detector, just without stacks. Never throws.
100
+ */
101
+ export declare function createLoopProfiler(opts?: LoopProfilerOpts): Promise<LoopProfiler | null>;
102
+ export {};