mixdog 1.2.1 → 1.2.3

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 (557) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/scripts/provider-pingpong-live.mjs +509 -0
  6. package/src/agents/advisor/AGENT.md +1 -1
  7. package/src/agents/advisor/agent.json +1 -1
  8. package/src/agents/reviewer/AGENT.md +3 -3
  9. package/src/agents/reviewer/agent.json +1 -1
  10. package/src/defaults/shipped-history.json +6 -0
  11. package/src/defaults/skills/setup/SKILL.md +6 -1
  12. package/src/defaults/skills/setup/references/actions.md +44 -22
  13. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  14. package/src/headless-exec.mjs +15 -8
  15. package/src/lib/keychain-cjs.cjs +7 -4
  16. package/src/output-styles/common.md +11 -10
  17. package/src/repl/slash-commands.mjs +16 -1
  18. package/src/rules/agent/AGENT.md +5 -5
  19. package/src/rules/lead/LEAD.md +5 -5
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  21. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  22. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  23. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  24. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
  33. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  36. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  37. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  38. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  39. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  40. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  41. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  43. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  44. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  45. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +98 -0
  46. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  47. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  48. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +48 -37
  49. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +10 -7
  50. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  51. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  54. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +102 -45
  58. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  59. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  62. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  63. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  65. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  66. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -7
  70. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  71. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  72. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +88 -21
  73. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -10
  74. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +106 -0
  75. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
  76. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +94 -15
  77. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  78. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
  79. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  80. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +75 -10
  81. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  82. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  83. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +103 -23
  84. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
  85. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  86. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +32 -6
  87. package/src/runtime/agent/orchestrator/providers/cursor.mjs +27 -3
  88. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
  89. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
  90. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  91. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  92. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  93. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +80 -18
  94. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +46 -8
  96. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +273 -0
  97. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  98. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  99. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  100. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  101. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  102. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +369 -112
  103. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +140 -35
  105. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +70 -24
  106. package/src/runtime/agent/orchestrator/providers/gemini.mjs +80 -29
  107. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  108. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  109. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +69 -19
  110. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  111. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  112. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
  113. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  114. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  115. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
  116. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  117. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  118. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  119. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  120. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
  121. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
  122. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  123. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  124. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  125. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  126. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  127. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
  128. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  129. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
  130. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +123 -61
  132. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  133. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +27 -2
  134. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
  135. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  136. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  137. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  138. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
  139. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  140. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  141. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
  142. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +64 -23
  143. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +79 -33
  144. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  145. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
  146. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  147. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +144 -15
  148. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  149. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  150. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +9 -2
  151. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  152. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +109 -26
  153. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +27 -6
  154. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +34 -20
  155. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +23 -4
  156. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +37 -28
  157. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  158. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  159. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  160. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +43 -15
  161. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  162. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  163. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +5 -2
  164. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  165. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +7 -3
  166. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  167. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  168. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  169. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  170. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +37 -4
  171. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +12 -1
  172. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  173. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -1
  174. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +76 -33
  175. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  176. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
  177. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  178. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
  179. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  180. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  181. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
  182. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  183. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  184. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  185. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  186. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  187. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  188. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +41 -22
  189. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
  190. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
  191. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
  192. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +720 -0
  193. package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
  194. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  195. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +123 -219
  196. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  197. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  198. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  199. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  200. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  201. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
  202. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
  203. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  204. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
  205. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
  206. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  207. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
  208. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  209. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  210. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  211. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  212. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
  213. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  214. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  215. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
  216. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  217. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  218. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  219. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
  220. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
  221. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  222. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -1
  223. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  224. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
  225. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  226. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
  227. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  228. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  229. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
  230. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  231. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
  232. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  233. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  234. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  235. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
  236. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
  237. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
  238. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
  239. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
  240. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +104 -19
  241. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  242. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  243. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
  244. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  245. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
  246. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -2
  247. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
  248. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
  249. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
  250. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  251. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +57 -21
  252. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  253. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  254. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  255. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  256. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
  257. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
  258. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +16 -4
  259. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
  260. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  261. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
  262. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  263. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  264. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  265. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
  266. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  267. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +168 -29
  268. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  269. package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
  270. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
  271. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  272. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
  273. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  274. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
  275. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  276. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
  277. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
  278. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  279. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  280. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  281. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +6 -0
  282. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +13 -0
  283. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +13 -1
  284. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
  285. package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
  286. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
  287. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
  288. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  289. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  290. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  291. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
  292. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
  293. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  294. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  295. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  296. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  297. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  298. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  299. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
  300. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
  301. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  302. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  303. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  304. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  305. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  306. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  307. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  308. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  309. package/src/runtime/computer-bridge/action-schema.mjs +44 -21
  310. package/src/runtime/github/tool.mjs +92 -2
  311. package/src/runtime/memory/index.mjs +1 -0
  312. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  313. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  314. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  315. package/src/runtime/memory/lib/pg/process.mjs +65 -50
  316. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  317. package/src/runtime/memory/lib/pg/supervisor.mjs +124 -16
  318. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  319. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  320. package/src/runtime/office/README.md +2 -2
  321. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  322. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  323. package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
  324. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  325. package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
  326. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  327. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  328. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  329. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  330. package/src/runtime/office/core/office-sessions.mjs +5 -0
  331. package/src/runtime/office/core/office-transactions.mjs +3 -0
  332. package/src/runtime/office/core/office-write-ledger.mjs +98 -0
  333. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  334. package/src/runtime/office/index.mjs +30 -0
  335. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  336. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  337. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  338. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  339. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  340. package/src/runtime/office/shared/values.mjs +0 -5
  341. package/src/runtime/shared/background-tasks.mjs +92 -14
  342. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  343. package/src/runtime/shared/bounded-line-diff.mjs +182 -0
  344. package/src/runtime/shared/buffered-appender.mjs +18 -0
  345. package/src/runtime/shared/config.mjs +78 -18
  346. package/src/runtime/shared/err-text.mjs +31 -0
  347. package/src/runtime/shared/error-presentation.mjs +159 -19
  348. package/src/runtime/shared/file-permissions.d.mts +6 -1
  349. package/src/runtime/shared/file-permissions.mjs +54 -6
  350. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  351. package/src/runtime/shared/llm/anthropic-effort.mjs +129 -134
  352. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  353. package/src/runtime/shared/llm/model-catalog.mjs +53 -40
  354. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  355. package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
  356. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  357. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  358. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  359. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  360. package/src/runtime/shared/loopback-listener.mjs +9 -0
  361. package/src/runtime/shared/model-display.mjs +13 -0
  362. package/src/runtime/shared/provider-api-key.mjs +2 -0
  363. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  364. package/src/runtime/shared/review-diff.mjs +52 -0
  365. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  366. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  367. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  368. package/src/runtime/shared/slow-span.mjs +114 -0
  369. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  370. package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
  371. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  372. package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
  373. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  374. package/src/runtime/shared/tool-card-model.mjs +5 -2
  375. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  376. package/src/runtime/shared/tool-primitives.mjs +13 -0
  377. package/src/runtime/shared/tool-result-summary.mjs +8 -1
  378. package/src/runtime/shared/tool-surface.mjs +18 -3
  379. package/src/runtime/shared/tool-work-units.mjs +40 -4
  380. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  381. package/src/runtime/shared/transcript-writer.mjs +10 -2
  382. package/src/runtime/shared/turn-changes.mjs +670 -274
  383. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  384. package/src/runtime/shared/turn-snapshot-store.mjs +94 -2
  385. package/src/runtime/shared/turn-snapshot.mjs +986 -690
  386. package/src/runtime/shared/turn-worktree-snapshot.mjs +279 -262
  387. package/src/runtime/shared/user-data-guard.mjs +262 -49
  388. package/src/runtime/shared/worktrees/carry.mjs +531 -0
  389. package/src/runtime/shared/worktrees/contract.mjs +34 -24
  390. package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
  391. package/src/runtime/shared/worktrees/git-head.mjs +205 -0
  392. package/src/runtime/shared/worktrees/git.mjs +8 -3
  393. package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
  394. package/src/runtime/shared/worktrees/manager.mjs +156 -8
  395. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  396. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  397. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  398. package/src/runtime/terminal-bridge/client.mjs +44 -11
  399. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  400. package/src/runtime/tidy/apply.mjs +47 -2
  401. package/src/runtime/tidy/run-engines.mjs +11 -5
  402. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  403. package/src/session-runtime/boot/apis.mjs +19 -5
  404. package/src/session-runtime/boot/facade.mjs +1 -0
  405. package/src/session-runtime/boot/infrastructure.mjs +12 -1
  406. package/src/session-runtime/boot/session.mjs +0 -1
  407. package/src/session-runtime/boot/tools.mjs +4 -1
  408. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  409. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
  410. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  411. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
  412. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
  413. package/src/session-runtime/internal-tool-executor.mjs +6 -2
  414. package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
  415. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  416. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -3
  417. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  418. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
  419. package/src/session-runtime/lifecycle/teardown.mjs +73 -8
  420. package/src/session-runtime/lifecycle-api.mjs +1 -0
  421. package/src/session-runtime/mcp-glue/connect.mjs +46 -14
  422. package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
  423. package/src/session-runtime/mcp-glue.mjs +3 -0
  424. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  425. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  426. package/src/session-runtime/model-route/set-route.mjs +85 -17
  427. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  428. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  429. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  430. package/src/session-runtime/native-web-search.mjs +10 -1
  431. package/src/session-runtime/new-session-config.mjs +4 -2
  432. package/src/session-runtime/provider-auth/login.mjs +4 -0
  433. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  434. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  435. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  436. package/src/session-runtime/resource-extension-sync.mjs +4 -0
  437. package/src/session-runtime/resource-mcp-api.mjs +98 -2
  438. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  439. package/src/session-runtime/runtime-review-api.mjs +21 -2
  440. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  441. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  442. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  443. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  444. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  445. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
  446. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  447. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  448. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  449. package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
  450. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  451. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  452. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  453. package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
  454. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  455. package/src/session-runtime/services/agent-tool.mjs +3 -0
  456. package/src/session-runtime/services/channel-admin.mjs +19 -3
  457. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  458. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  459. package/src/session-runtime/services/provider-admin.mjs +81 -15
  460. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  461. package/src/session-runtime/session-turn-api.mjs +14 -5
  462. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
  463. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  464. package/src/session-runtime/setup-tool/executor.mjs +36 -6
  465. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  466. package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
  467. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
  468. package/src/session-runtime/skills-api.mjs +3 -5
  469. package/src/session-runtime/tool-surface.mjs +5 -1
  470. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  471. package/src/session-runtime/turn/session-ops.mjs +7 -5
  472. package/src/session-runtime/turn/side-question-ops.mjs +22 -0
  473. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
  474. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
  475. package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
  476. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  477. package/src/session-runtime/turn/turn-run.mjs +25 -9
  478. package/src/session-runtime/usage-stats-api.mjs +43 -11
  479. package/src/session-runtime/workspace/project-branches.mjs +7 -5
  480. package/src/session-runtime/workspace/transition-steps.mjs +129 -31
  481. package/src/session-runtime/workspace/transitions.mjs +190 -15
  482. package/src/standalone/daemon-agent-control.mjs +9 -1
  483. package/src/standalone/daemon-drain-policy.mjs +8 -0
  484. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  485. package/src/standalone/daemon-owner.mjs +17 -4
  486. package/src/standalone/daemon-pg-stop.mjs +51 -0
  487. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  488. package/src/standalone/daemon-stop-budget.mjs +18 -0
  489. package/src/standalone/daemon-stored-session-views.mjs +2 -0
  490. package/src/standalone/daemon-telemetry.mjs +74 -0
  491. package/src/standalone/daemon.mjs +64 -8
  492. package/src/standalone/desktop-service-registry.mjs +5 -0
  493. package/src/standalone/local-session-runtime.mjs +70 -19
  494. package/src/standalone/session-client.mjs +42 -0
  495. package/src/standalone/session-protocol.mjs +14 -0
  496. package/src/standalone/session-proxy/projection.mjs +41 -4
  497. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  498. package/src/standalone/session-runtime-inline-host.mjs +1 -0
  499. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  500. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  501. package/src/standalone/session-service/agent-tree.mjs +12 -0
  502. package/src/standalone/session-service/quota-resume.mjs +8 -0
  503. package/src/standalone/session-service/retention/busy.mjs +15 -1
  504. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  505. package/src/standalone/session-service-api.mjs +11 -1
  506. package/src/standalone/session-service.mjs +1 -0
  507. package/src/standalone/session-state-patch.d.mts +2 -1
  508. package/src/standalone/session-state-patch.mjs +41 -1
  509. package/src/tui/App.jsx +25 -0
  510. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  511. package/src/tui/app/app-view.jsx +1 -0
  512. package/src/tui/app/btw-controller.mjs +118 -0
  513. package/src/tui/app/create-app-pickers.mjs +6 -0
  514. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  515. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  516. package/src/tui/app/extension-pickers.mjs +2 -1
  517. package/src/tui/app/model-options.mjs +11 -16
  518. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  519. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  520. package/src/tui/app/slash-commands.mjs +20 -5
  521. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  522. package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
  523. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  524. package/src/tui/app/use-global-key-input.mjs +5 -12
  525. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  526. package/src/tui/components/BtwPanel.jsx +53 -0
  527. package/src/tui/components/QuestionPanel.jsx +275 -0
  528. package/src/tui/components/StatusLine.jsx +2 -0
  529. package/src/tui/components/question-panel-model.mjs +156 -0
  530. package/src/tui/components/status-line/local-line.mjs +5 -2
  531. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  532. package/src/tui/dist/index.mjs +3221 -1500
  533. package/src/tui/session/context-state.mjs +4 -2
  534. package/src/tui/session/quota-resume.mjs +46 -14
  535. package/src/tui/session/session-api/commands.mjs +43 -24
  536. package/src/tui/session/session-api/controls.mjs +2 -2
  537. package/src/tui/session/session-api/extensions.mjs +22 -0
  538. package/src/tui/session/session-api/integrations.mjs +16 -2
  539. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  540. package/src/tui/session/session-api/lifecycle.mjs +7 -2
  541. package/src/tui/session/session-api/routes.mjs +71 -7
  542. package/src/tui/session/session-api/settings.mjs +11 -14
  543. package/src/tui/session/session-api.mjs +1 -0
  544. package/src/tui/session/session-flow/drain.mjs +7 -1
  545. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  546. package/src/tui/session/tool-approval.mjs +10 -7
  547. package/src/tui/session/transcript-spill.mjs +14 -7
  548. package/src/tui/session/turn-stream.mjs +174 -31
  549. package/src/tui/session/turn.mjs +46 -16
  550. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  551. package/src/ui/statusline-agents.mjs +15 -4
  552. package/src/ui/statusline.mjs +7 -3
  553. package/src/ui/streaming-markdown-heal.mjs +34 -3
  554. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  555. package/src/workflows/default/WORKFLOW.md +3 -1
  556. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  557. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
@@ -37,6 +37,7 @@ export function createAppPickers({
37
37
  setSettingsPrompt,
38
38
  setOnboardingActive,
39
39
  closeUsagePanel,
40
+ btw,
40
41
  oauthSubmitRef,
41
42
  clearModelCaches,
42
43
  onboardingRef,
@@ -88,6 +89,8 @@ export function createAppPickers({
88
89
  const {
89
90
  openMcpServersPicker,
90
91
  openMcpPicker,
92
+ loginMcpServer,
93
+ logoutMcpServer,
91
94
  openProjectSkillsPicker,
92
95
  openSkillsPicker,
93
96
  openSkillDetailPicker,
@@ -205,6 +208,7 @@ export function createAppPickers({
205
208
  normalizeSlashCommandName,
206
209
  surface,
207
210
  closeUsagePanel,
211
+ btw,
208
212
  openModelPicker: (...a) => openModelPicker(...a),
209
213
  modelSwitchNotice,
210
214
  openWebSearchPicker: (...a) => openWebSearchPicker(...a),
@@ -219,6 +223,8 @@ export function createAppPickers({
219
223
  enterProject: (...a) => enterProject(...a),
220
224
  openProjectPicker: (...a) => openProjectPicker(...a),
221
225
  openMcpPicker: (...a) => openMcpPicker(...a),
226
+ loginMcpServer,
227
+ logoutMcpServer,
222
228
  openSkillsPicker: (...a) => openSkillsPicker(...a),
223
229
  openPluginsPicker: (...a) => openPluginsPicker(...a),
224
230
  openProviderSetupPicker: (...a) => openProviderSetupPicker(...a),
@@ -0,0 +1,107 @@
1
+ // extension-pickers/mcp-login.mjs
2
+ // `/mcp login <name>` and `/mcp logout <name>`. The sign-in URL is always
3
+ // printed (and kept in the live prompt); the runtime may open the browser. The
4
+ // flow is polled while a paste prompt (the shared 'oauth-code' provider prompt)
5
+ // accepts the final redirect address. Pasted text is never echoed.
6
+ const POLL_MS = 1500;
7
+
8
+ export function createMcpLogin({ store, setProviderPrompt, pollMs = POLL_MS }) {
9
+ let active = null;
10
+
11
+ const stop = (flow) => {
12
+ flow.finished = true;
13
+ clearTimeout(flow.timer);
14
+ if (active === flow) active = null;
15
+ };
16
+
17
+ const closePrompt = (flow) => setProviderPrompt((prompt) => (prompt === flow.prompt ? null : prompt));
18
+
19
+ const showPrompt = (flow) => {
20
+ if (flow.finished) return;
21
+ const prompt = {
22
+ kind: 'oauth-code',
23
+ providerName: `MCP ${flow.name}`,
24
+ // The shared prompt pushes the one completion notice; no provider picker follows.
25
+ successReturn: () => {},
26
+ label: `MCP sign-in · ${flow.name}`,
27
+ hint: 'If the browser page fails to load, paste its address here.',
28
+ detail: flow.url,
29
+ login: {
30
+ completeCode: async (text) => {
31
+ const result = await store.completeMcpOAuthLogin(flow.id, text);
32
+ if (result?.state !== 'complete') throw new Error(result?.error || 'sign-in did not complete');
33
+ stop(flow);
34
+ },
35
+ cancel: () => {
36
+ if (flow.finished) return;
37
+ stop(flow);
38
+ void Promise.resolve(store.cancelMcpOAuthLogin(flow.id)).catch(() => {});
39
+ store.pushNotice(`MCP sign-in cancelled for ${flow.name}`, 'info');
40
+ },
41
+ },
42
+ failureReturn: () => showPrompt(flow),
43
+ };
44
+ flow.prompt = prompt;
45
+ setProviderPrompt(prompt);
46
+ };
47
+
48
+ const poll = (flow) => {
49
+ flow.timer = setTimeout(async () => {
50
+ if (flow.finished) return;
51
+ let status;
52
+ try {
53
+ status = await store.getMcpOAuthLoginStatus(flow.id);
54
+ } catch (e) {
55
+ if (flow.finished) return;
56
+ stop(flow);
57
+ closePrompt(flow);
58
+ store.pushNotice(`MCP sign-in failed for ${flow.name}: ${e?.message || e}`, 'error');
59
+ return;
60
+ }
61
+ if (flow.finished) return;
62
+ if (status?.state === 'pending') {
63
+ poll(flow);
64
+ return;
65
+ }
66
+ stop(flow);
67
+ closePrompt(flow);
68
+ if (status?.state === 'complete') store.pushNotice(`MCP sign-in complete for ${flow.name}`, 'info');
69
+ else if (status?.state === 'cancelled') store.pushNotice(`MCP sign-in cancelled for ${flow.name}`, 'info');
70
+ else store.pushNotice(`MCP sign-in failed for ${flow.name}${status?.error ? `: ${status.error}` : ''}`, 'error');
71
+ }, pollMs);
72
+ };
73
+
74
+ const loginMcpServer = async (name) => {
75
+ if (active) {
76
+ const previous = active;
77
+ stop(previous);
78
+ closePrompt(previous);
79
+ void Promise.resolve(store.cancelMcpOAuthLogin(previous.id)).catch(() => {});
80
+ }
81
+ try {
82
+ const started = await store.beginMcpOAuthLogin(name, { openBrowser: true });
83
+ if (started?.state === 'complete') {
84
+ store.pushNotice(`MCP sign-in complete for ${name}`, 'info');
85
+ return;
86
+ }
87
+ const flow = { id: started.flowId, name, url: started.url || '', finished: false, timer: null, prompt: null };
88
+ active = flow;
89
+ if (flow.url) store.pushNotice(`Sign in to ${name}: ${flow.url}`, 'info');
90
+ showPrompt(flow);
91
+ poll(flow);
92
+ } catch (e) {
93
+ store.pushNotice(`MCP sign-in failed for ${name}: ${e?.message || e}`, 'error');
94
+ }
95
+ };
96
+
97
+ const logoutMcpServer = async (name) => {
98
+ try {
99
+ await store.signOutMcpServer(name);
100
+ store.pushNotice(`MCP signed out of ${name}`, 'info');
101
+ } catch (e) {
102
+ store.pushNotice(`MCP sign-out failed for ${name}: ${e?.message || e}`, 'error');
103
+ }
104
+ };
105
+
106
+ return { loginMcpServer, logoutMcpServer };
107
+ }
@@ -8,8 +8,9 @@ const serverDescription = (server, pending, optimistic) => {
8
8
  const transport = server.transport || 'unknown';
9
9
  if (pending) return `${optimistic.enabled ? 'enabling' : 'disabling'}… · ${transport}`;
10
10
  const error = server.error ? ` · ${server.error}` : '';
11
+ const signIn = server.authRequired ? ` · sign-in required: /mcp login ${server.name}` : '';
11
12
  return withScope(
12
- `${server.source || 'config'} · ${server.status || 'unknown'} · ${transport} · ${server.toolCount || 0} tools${error}`,
13
+ `${server.source || 'config'} · ${server.status || 'unknown'} · ${transport} · ${server.toolCount || 0} tools${error}${signIn}`,
13
14
  server
14
15
  );
15
16
  };
@@ -7,6 +7,7 @@
7
7
  * store state, so they can't be pure. openMcpPicker is exposed for the
8
8
  * plugin-detail enable-mcp path (also aliased on the App body).
9
9
  */
10
+ import { createMcpLogin } from './extension-pickers/mcp-login.mjs';
10
11
  import { createMcpServersPicker } from './extension-pickers/mcp-servers-picker.mjs';
11
12
  import { createPluginsPickers } from './extension-pickers/plugins-pickers.mjs';
12
13
  import { createSkillsPickers } from './extension-pickers/skills-pickers.mjs';
@@ -43,5 +44,5 @@ export function createExtensionPickers({
43
44
  setSettingsPrompt,
44
45
  openMcpPicker: mcp.openMcpPicker,
45
46
  });
46
- return { ...mcp, ...skills, ...plugins };
47
+ return { ...mcp, ...createMcpLogin({ store, setProviderPrompt }), ...skills, ...plugins };
47
48
  }
@@ -6,7 +6,7 @@
6
6
  * displayModelName formatter.
7
7
  */
8
8
  import { theme } from '../theme.mjs';
9
- import { displayModelName } from '../../runtime/shared/model-display.mjs';
9
+ import { displayModelName, effortDisplayLabel } from '../../runtime/shared/model-display.mjs';
10
10
  import { isRollingModelAlias } from '../../runtime/shared/model-alias.mjs';
11
11
  import { DAYBREAK_PROVIDER, daybreakBlueOn } from '../../runtime/shared/llm/openai-daybreak.mjs';
12
12
 
@@ -248,18 +248,7 @@ const PROVIDER_DISPLAY_RANKS = {
248
248
 
249
249
  export const providerDisplayRank = (provider) => PROVIDER_DISPLAY_RANKS[String(provider || '').toLowerCase()] ?? 900;
250
250
 
251
- const titleCaseOption = (value) =>
252
- String(value || '')
253
- .split(/([\s_-]+)/)
254
- .map((part) => (/^[\s_-]+$/.test(part) ? part : `${part.charAt(0).toUpperCase()}${part.slice(1).toLowerCase()}`))
255
- .join('');
256
-
257
- export const effortDisplayLabel = (value) => {
258
- const text = String(value || '').trim();
259
- if (!text) return '';
260
- if (text.toLowerCase() === 'xhigh') return 'XHigh';
261
- return titleCaseOption(text);
262
- };
251
+ export { effortDisplayLabel };
263
252
 
264
253
  export const fastDisplayLabel = (enabled = true) => `Fast ${enabled ? 'On' : 'Off'}`;
265
254
 
@@ -330,9 +319,15 @@ export const buildProviderModelItems = (models, provider, currentRoute = null) =
330
319
  }));
331
320
  };
332
321
 
333
- // Model · Effort · Fast, dropping the empty parts.
322
+ // The configured speed tier: Ultrafast when the fast route asks for it.
323
+ const routeSpeedLabel = (route) => {
324
+ if (!route?.fast) return '';
325
+ return route.modelParameters?.serviceTier === 'ultrafast' ? 'Ultrafast' : 'Fast';
326
+ };
327
+
328
+ // Model · Effort · Fast/Ultrafast, dropping the empty parts.
334
329
  const routeModelDetails = (route) =>
335
- [routeModelDisplayName(route), route.effort ? effortDisplayLabel(route.effort) : '', route.fast ? 'Fast' : '']
330
+ [routeModelDisplayName(route), route.effort ? effortDisplayLabel(route.effort) : '', routeSpeedLabel(route)]
336
331
  .filter(Boolean)
337
332
  .join(' · ');
338
333
 
@@ -348,7 +343,7 @@ export const agentModelProfile = (route) => (route?.model ? routeModelDetails(ro
348
343
  export const agentModelParts = (route) => [
349
344
  { text: route?.model ? routeModelDisplayName(route) : '', width: 17 },
350
345
  { text: route?.effort ? effortDisplayLabel(route.effort) : '', width: 6 },
351
- { text: route?.fast ? 'Fast' : '', width: 4 },
346
+ { text: routeSpeedLabel(route), width: 9 },
352
347
  ];
353
348
 
354
349
  export const routeFromModel = (model, effort = null) => ({
@@ -5,7 +5,9 @@
5
5
  */
6
6
  import { isLiveSpinnerMetaVisible } from '../live-spinner-visibility.mjs';
7
7
  import { promptContentRows, wrappedDetailRows, queuedBandRows } from '../text-layout.mjs';
8
+ import { questionPanelRows, questionsOf } from '../../components/question-panel-model.mjs';
8
9
  import { CORE_MULTILINE_TEXT_ENTRY_KINDS } from '../panel-signature.mjs';
10
+ import { btwPanelRows } from '../btw-controller.mjs';
9
11
 
10
12
  const SCROLL_HINT_ROWS = 0;
11
13
  const LIVE_STATUS_ROWS = 0;
@@ -114,20 +116,25 @@ function floatingPanelBudget({
114
116
  picker,
115
117
  contextPanel,
116
118
  usagePanel,
119
+ btwPanel,
117
120
  slashPaletteOpen,
118
121
  hasTextEntryPrompt,
119
122
  TEXT_ENTRY_ROWS,
120
123
  OPTION_PANEL_EXTRA_ROWS,
121
124
  maxFloatingPanelRows,
125
+ frameColumns,
122
126
  }) {
123
127
  let desiredFloatingPanelRows = 0;
124
- if (toolApproval) desiredFloatingPanelRows = PANEL_CHROME_ROWS + 2 + OPTION_PANEL_EXTRA_ROWS;
128
+ if (toolApproval?.kind === 'question' && questionsOf(toolApproval).length > 0) {
129
+ desiredFloatingPanelRows = questionPanelRows(questionsOf(toolApproval), frameColumns);
130
+ } else if (toolApproval) desiredFloatingPanelRows = PANEL_CHROME_ROWS + 2 + OPTION_PANEL_EXTRA_ROWS;
125
131
  else if (picker?.fillAvailable) desiredFloatingPanelRows = maxFloatingPanelRows;
126
132
  else if (picker) desiredFloatingPanelRows = PANEL_BASE_ROWS + OPTION_PANEL_EXTRA_ROWS;
127
133
  else if (contextPanel) desiredFloatingPanelRows = PANEL_BASE_ROWS + OPTION_PANEL_EXTRA_ROWS + 3;
128
134
  else if (usagePanel) desiredFloatingPanelRows = PANEL_BASE_ROWS + OPTION_PANEL_EXTRA_ROWS;
129
135
  else if (slashPaletteOpen) desiredFloatingPanelRows = SLASH_PALETTE_ROWS;
130
136
  else if (hasTextEntryPrompt) desiredFloatingPanelRows = TEXT_ENTRY_ROWS;
137
+ else if (btwPanel) desiredFloatingPanelRows = btwPanelRows(btwPanel, frameColumns);
131
138
  const floatingPanelRows = desiredFloatingPanelRows > 0 ? Math.min(desiredFloatingPanelRows, maxFloatingPanelRows) : 0;
132
139
  // Give the list every content row the panel exposes. The panel already grew
133
140
  // by OPTION_PANEL_EXTRA_ROWS; previously that growth was subtracted back out
@@ -174,6 +181,7 @@ export function computeRowBudgets({
174
181
  picker,
175
182
  contextPanel,
176
183
  usagePanel,
184
+ btwPanel,
177
185
  slashPaletteOpen,
178
186
  }) {
179
187
  const { textEntryPrompt, hasTextEntryPrompt, hasFloatingPanel, expandedOptionPanel, inputBoxHidden } = surfaces;
@@ -211,11 +219,13 @@ export function computeRowBudgets({
211
219
  picker,
212
220
  contextPanel,
213
221
  usagePanel,
222
+ btwPanel,
214
223
  slashPaletteOpen,
215
224
  hasTextEntryPrompt,
216
225
  TEXT_ENTRY_ROWS: textEntry.TEXT_ENTRY_ROWS,
217
226
  OPTION_PANEL_EXTRA_ROWS,
218
227
  maxFloatingPanelRows,
228
+ frameColumns,
219
229
  });
220
230
  const rows = {
221
231
  floatingPanelRows: panel.floatingPanelRows,
@@ -10,6 +10,7 @@ export function deriveSurfaces({
10
10
  picker,
11
11
  contextPanel,
12
12
  usagePanel,
13
+ btwPanel,
13
14
  slashPaletteOpen,
14
15
  tuiReady,
15
16
  state,
@@ -24,7 +25,8 @@ export function deriveSurfaces({
24
25
  contextPanel ||
25
26
  usagePanel ||
26
27
  slashPaletteOpen ||
27
- hasTextEntryPrompt
28
+ hasTextEntryPrompt ||
29
+ btwPanel
28
30
  );
29
31
  const expandedOptionPanel = !!(toolApproval || picker || contextPanel || usagePanel || hasTextEntryPrompt);
30
32
  if (panelTransitionRef.current.signature.includes('picker:project') && !picker) {
@@ -15,6 +15,12 @@ export const SLASH_COMMANDS = [
15
15
  description: 'Switch working directory (project)',
16
16
  },
17
17
  { name: 'compact', usage: '/compact', description: 'Compact older conversation context' },
18
+ {
19
+ name: 'btw',
20
+ usage: '/btw',
21
+ params: '<question>',
22
+ description: 'Ask a quick side question without interrupting the current work',
23
+ },
18
24
  {
19
25
  name: 'goal',
20
26
  usage: '/goal',
@@ -30,9 +36,12 @@ export const SLASH_COMMANDS = [
30
36
  { name: 'resume', usage: '/resume', params: '[id]', description: 'Resume a saved chat' },
31
37
  { name: 'context', usage: '/context', description: 'Show current context surface' },
32
38
  {
33
- name: 'inherit',
34
- usage: '/inherit',
35
- description: 'Carry this conversation into a new session on the current model',
39
+ name: 'fork',
40
+ usage: '/fork',
41
+ aliases: ['inherit'],
42
+ aliasUsage: ['inherit'],
43
+ showAliasUsage: false,
44
+ description: 'Fork this conversation into a new session on the current model',
36
45
  },
37
46
  { name: 'usage', usage: '/usage', params: '[refresh]', description: 'Show total provider quota / balance' },
38
47
  { name: 'model', usage: '/model', params: '[name|refresh]', description: 'Switch model for subsequent turns' },
@@ -50,8 +59,13 @@ export const SLASH_COMMANDS = [
50
59
  { name: 'theme', usage: '/theme', params: '[id]', description: 'Change the TUI color theme' },
51
60
  { name: 'agents', usage: '/agents', params: '[refresh]', description: 'Show available workflow agents' },
52
61
  { name: 'effort', usage: '/effort', params: '[level]', description: 'Set reasoning effort for the current model' },
53
- { name: 'fast', usage: '/fast', params: '[on|off|ultra]', description: 'Set Fast or Ultrafast mode for the current model' },
54
- { name: 'mcp', usage: '/mcp', description: 'Manage MCP servers and tools' },
62
+ {
63
+ name: 'fast',
64
+ usage: '/fast',
65
+ params: '[on|off|ultra]',
66
+ description: 'Set Fast or Ultrafast mode for the current model',
67
+ },
68
+ { name: 'mcp', usage: '/mcp', params: '[login|logout <name>]', description: 'Manage MCP servers and tools' },
55
69
  { name: 'skills', usage: '/skills', description: 'Choose a skill for the next request' },
56
70
  { name: 'memory', usage: '/memory', params: '[status|core ...]', description: 'List and edit core memories' },
57
71
  { name: 'plugins', usage: '/plugins', description: 'Manage local plugin integrations' },
@@ -104,6 +118,7 @@ export function overlayBlocksGlobalTranscriptScroll(owner = {}) {
104
118
  owner.toolApproval ||
105
119
  owner.contextPanel ||
106
120
  owner.usagePanel ||
121
+ owner.btwPanel ||
107
122
  owner.providerPrompt ||
108
123
  owner.settingsPrompt
109
124
  );
@@ -14,6 +14,8 @@ const desktopOnlyNotice = (ctx) => {
14
14
  return true;
15
15
  };
16
16
 
17
+ const openMcpPanel = panelCommand('mcp', 'MCP Servers', (deps) => deps.openMcpPicker());
18
+
17
19
  const openSettings = panelCommand('settings', 'Settings', (deps) => deps.openSettingsPicker());
18
20
 
19
21
  export const panelCommands = {
@@ -26,7 +28,20 @@ export const panelCommands = {
26
28
  ctx.openSlashPanel('project', 'Projects', () => ctx.deps.openProjectPicker());
27
29
  return true;
28
30
  },
29
- mcp: panelCommand('mcp', 'MCP Servers', (deps) => deps.openMcpPicker()),
31
+ mcp(ctx, arg) {
32
+ const [sub, ...rest] = arg.trim().split(/\s+/);
33
+ const action = sub?.toLowerCase();
34
+ if (action === 'login' || action === 'logout') {
35
+ const name = rest.join(' ');
36
+ if (!name) {
37
+ ctx.store.pushNotice(`usage: /mcp ${action} <name>`, 'warn');
38
+ return true;
39
+ }
40
+ void (action === 'login' ? ctx.deps.loginMcpServer(name) : ctx.deps.logoutMcpServer(name));
41
+ return true;
42
+ }
43
+ return openMcpPanel(ctx);
44
+ },
30
45
  skills: panelCommand('skills', 'Skills', (deps) => deps.openSkillsPicker()),
31
46
  plugins: panelCommand('plugins', 'Plugins', (deps) => deps.openPluginsPicker()),
32
47
  providers: panelCommand('providers', 'Providers', (deps) => deps.openProviderSetupPicker()),
@@ -1,8 +1,9 @@
1
1
  // slash-dispatch/session-commands.mjs
2
2
  // Slash commands that act on the session itself: clear/new, compact, goal,
3
- // resume, inherit, doctor and quit. Busy guards refuse the destructive ones
3
+ // resume, fork (alias inherit), doctor and quit. Busy guards refuse the destructive ones
4
4
  // while a turn or session command is running.
5
5
  import { presentErrorText } from '../../../runtime/shared/err-text.mjs';
6
+ import { BTW_USAGE_HINT } from '../btw-controller.mjs';
6
7
 
7
8
  function compactFailureNotice(error) {
8
9
  if (error == null || String(error).trim() === '') return 'Compact failed.';
@@ -63,6 +64,18 @@ export const sessionCommands = {
63
64
  return true;
64
65
  },
65
66
 
67
+ // Side question: allowed mid-turn; never queued, steered, or interrupting.
68
+ btw(ctx, arg) {
69
+ const { store, deps } = ctx;
70
+ const question = String(arg || '').trim();
71
+ if (!question) {
72
+ store.pushNotice(BTW_USAGE_HINT, 'warn');
73
+ return true;
74
+ }
75
+ deps.btw.ask(question);
76
+ return true;
77
+ },
78
+
66
79
  goal(ctx, arg) {
67
80
  const { store } = ctx;
68
81
  void Promise.resolve(store.goalControl?.({ command: arg }))
@@ -91,18 +104,18 @@ export const sessionCommands = {
91
104
  return true;
92
105
  },
93
106
 
94
- inherit(ctx) {
107
+ fork(ctx, _arg, rawName) {
95
108
  const { state, store } = ctx;
96
- if (state.busy) return refuseWhileBusy(store, 'inherit');
109
+ if (state.busy) return refuseWhileBusy(store, rawName === 'inherit' ? 'inherit' : 'fork');
97
110
  void Promise.resolve(store.inheritSession?.())
98
111
  .then((result) => {
99
112
  if (!result) {
100
- store.pushNotice('nothing to inherit', 'warn');
113
+ store.pushNotice('nothing to fork', 'warn');
101
114
  return;
102
115
  }
103
- store.pushNotice(`inherited ${result.messages} messages into ${result.sessionId}`, 'info');
116
+ store.pushNotice(`forked ${result.messages} messages into ${result.sessionId}`, 'info');
104
117
  })
105
- .catch((e) => store.pushNotice(`inherit failed: ${e?.message || e}`, 'error'));
118
+ .catch((e) => store.pushNotice(`fork failed: ${e?.message || e}`, 'error'));
106
119
  return true;
107
120
  },
108
121
 
@@ -0,0 +1,12 @@
1
+ // Global tool-approval shortcuts: Esc/d/n deny, a/y approve. Returns the
2
+ // decision to resolve with, or null. Question approvals (ask_user) are
3
+ // answered only inside QuestionPanel, so typed letters and Esc never reach here.
4
+ export function approvalShortcutDecision(toolApproval, input, key) {
5
+ if (!toolApproval || toolApproval.kind === 'question') return null;
6
+ const value = String(input || '')
7
+ .trim()
8
+ .toLowerCase();
9
+ if (key.escape || value === 'd' || value === 'n') return { approved: false, reason: 'denied by user' };
10
+ if (value === 'a' || value === 'y') return { approved: true, reason: 'approved by user' };
11
+ return null;
12
+ }
@@ -8,6 +8,7 @@
8
8
  import { useInput } from 'ink';
9
9
  import { overlayBlocksGlobalTranscriptScroll } from './slash-commands.mjs';
10
10
  import { copyActiveSelection } from './use-global-key-input/copy-first.mjs';
11
+ import { approvalShortcutDecision } from './use-global-key-input/approval-shortcut.mjs';
11
12
  import { decodeSelectionMoveChord } from './use-global-key-input/shift-arrow.mjs';
12
13
  export function useGlobalKeyInput({
13
14
  store,
@@ -43,18 +44,10 @@ export function useGlobalKeyInput({
43
44
  // settle it through the same path a real release takes, before any branch
44
45
  // below reads the selection.
45
46
  settleStuckDrag?.();
46
- if (toolApproval) {
47
- const value = String(input || '')
48
- .trim()
49
- .toLowerCase();
50
- if (key.escape || value === 'd' || value === 'n') {
51
- store.resolveToolApproval?.(toolApproval.id, { approved: false, reason: 'denied by user' });
52
- return;
53
- }
54
- if (value === 'a' || value === 'y') {
55
- store.resolveToolApproval?.(toolApproval.id, { approved: true, reason: 'approved by user' });
56
- return;
57
- }
47
+ const decision = approvalShortcutDecision(toolApproval, input, key);
48
+ if (decision) {
49
+ store.resolveToolApproval?.(toolApproval.id, decision);
50
+ return;
58
51
  }
59
52
  if (key.ctrl && (input === 'c' || input === 'C')) {
60
53
  copyActiveSelection({ promptSelectionRef, dragRef, copySelection, showSelectionCopyHint });
@@ -36,6 +36,8 @@ export function usePromptHandlers({
36
36
  usagePanel,
37
37
  closeUsagePanel,
38
38
  contextPanel,
39
+ btwPanel,
40
+ closeBtwPanel,
39
41
  // paste-attachment helpers (owned by App, threaded in explicitly)
40
42
  installPastedImages,
41
43
  clearPastedImagesSnapshot,
@@ -72,6 +74,13 @@ export function usePromptHandlers({
72
74
  return true;
73
75
  }
74
76
 
77
+ // /btw side panel: Esc closes it (cancelling a pending ask) before the
78
+ // turn interrupt / draft handling sees the key.
79
+ if (btwPanel) {
80
+ closeBtwPanel();
81
+ return true;
82
+ }
83
+
75
84
  if (meta.phase === 'clear-arm') {
76
85
  showPromptHint('Esc again to clear', 'plain', PROMPT_ESCAPE_HINT_TIMEOUT_MS);
77
86
  return true;
@@ -107,6 +116,8 @@ export function usePromptHandlers({
107
116
  },
108
117
  [
109
118
  contextPanel,
119
+ btwPanel,
120
+ closeBtwPanel,
110
121
  surface,
111
122
  usagePanel,
112
123
  closeUsagePanel,
@@ -0,0 +1,53 @@
1
+ /**
2
+ * components/BtwPanel.jsx — transient `/btw` side-question panel above the prompt.
3
+ */
4
+ import { useEffect, useState } from 'react';
5
+ import { Box, Text, useInput } from 'ink';
6
+ import { theme } from '../theme.mjs';
7
+ import { Markdown } from './Markdown.jsx';
8
+ import { BTW_CHROME_ROWS, btwContentRows, btwScrollMax, btwScrollOffset } from '../app/btw-controller.mjs';
9
+
10
+ export function BtwPanel({ panel, columns = 80, panelRows, themeEpoch = 0 }) {
11
+ const bodyRows = Math.max(1, (panelRows ?? BTW_CHROME_ROWS + 1) - BTW_CHROME_ROWS);
12
+ const total = btwContentRows(panel, columns);
13
+ const maxOffset = btwScrollMax(total, bodyRows);
14
+ const [offset, setOffset] = useState(0);
15
+ const top = Math.min(offset, maxOffset);
16
+ const scrollable = maxOffset > 0;
17
+
18
+ // A new question or a settled answer starts from the top.
19
+ useEffect(() => {
20
+ setOffset(0);
21
+ }, [panel.question, panel.status]);
22
+
23
+ useInput((_input, key) => {
24
+ if (!scrollable || (!key.pageUp && !key.pageDown)) return;
25
+ setOffset((current) => btwScrollOffset(key, current, bodyRows, total));
26
+ });
27
+
28
+ let body;
29
+ if (panel.status === 'pending') body = <Text color={theme.inactive}>answering… (Esc to cancel)</Text>;
30
+ else if (panel.status === 'error') body = <Text color={theme.error}>{panel.text}</Text>;
31
+ else
32
+ body = (
33
+ <Markdown themeEpoch={themeEpoch} columns={columns}>
34
+ {panel.text}
35
+ </Markdown>
36
+ );
37
+ return (
38
+ <Box flexDirection="column" flexShrink={0} width="100%">
39
+ <Box borderStyle="round" borderColor={theme.promptBorder} paddingX={1} width="100%" flexDirection="column">
40
+ <Text color={theme.panelTitle} wrap="truncate-end">{`btw · ${panel.question}`}</Text>
41
+ <Box flexDirection="column" height={bodyRows} overflow="hidden">
42
+ <Box flexDirection="column" flexShrink={0} marginTop={-top}>
43
+ {body}
44
+ </Box>
45
+ </Box>
46
+ <Text color={theme.inactive}>
47
+ {scrollable ? `PgUp/PgDn scroll (${top + 1}-${Math.min(total, top + bodyRows)}/${total}) · ` : ''}
48
+ Esc to close · not saved to the conversation
49
+ </Text>
50
+ </Box>
51
+ </Box>
52
+ );
53
+ }