@code-yeongyu/senpi 2026.8.26 → 2026.8.28-2

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 (335) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/README.md +3 -3
  3. package/dist/cli/args.d.ts +5 -1
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +18 -1
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/core/agent-session-services.d.ts.map +1 -1
  8. package/dist/core/agent-session-services.js +2 -0
  9. package/dist/core/agent-session-services.js.map +1 -1
  10. package/dist/core/agent-session.d.ts +5 -0
  11. package/dist/core/agent-session.d.ts.map +1 -1
  12. package/dist/core/agent-session.js +11 -1
  13. package/dist/core/agent-session.js.map +1 -1
  14. package/dist/core/auth-storage.d.ts +1 -0
  15. package/dist/core/auth-storage.d.ts.map +1 -1
  16. package/dist/core/auth-storage.js +3 -0
  17. package/dist/core/auth-storage.js.map +1 -1
  18. package/dist/core/bash-executor.d.ts.map +1 -1
  19. package/dist/core/bash-executor.js +67 -29
  20. package/dist/core/bash-executor.js.map +1 -1
  21. package/dist/core/credential-accounts.d.ts +31 -0
  22. package/dist/core/credential-accounts.d.ts.map +1 -0
  23. package/dist/core/credential-accounts.js +135 -0
  24. package/dist/core/credential-accounts.js.map +1 -0
  25. package/dist/core/credential-pool/classify.d.ts +47 -0
  26. package/dist/core/credential-pool/classify.d.ts.map +1 -0
  27. package/dist/core/credential-pool/classify.js +92 -0
  28. package/dist/core/credential-pool/classify.js.map +1 -0
  29. package/dist/core/credential-pool/env-slots.d.ts +22 -0
  30. package/dist/core/credential-pool/env-slots.d.ts.map +1 -0
  31. package/dist/core/credential-pool/env-slots.js +37 -0
  32. package/dist/core/credential-pool/env-slots.js.map +1 -0
  33. package/dist/core/credential-pool/failover.d.ts +62 -0
  34. package/dist/core/credential-pool/failover.d.ts.map +1 -0
  35. package/dist/core/credential-pool/failover.js +124 -0
  36. package/dist/core/credential-pool/failover.js.map +1 -0
  37. package/dist/core/credential-pool/rotation-stream.d.ts +54 -0
  38. package/dist/core/credential-pool/rotation-stream.d.ts.map +1 -0
  39. package/dist/core/credential-pool/rotation-stream.js +183 -0
  40. package/dist/core/credential-pool/rotation-stream.js.map +1 -0
  41. package/dist/core/credential-pool/state-store.d.ts +89 -0
  42. package/dist/core/credential-pool/state-store.d.ts.map +1 -0
  43. package/dist/core/credential-pool/state-store.js +166 -0
  44. package/dist/core/credential-pool/state-store.js.map +1 -0
  45. package/dist/core/extensions/builtin/account/index.d.ts +9 -0
  46. package/dist/core/extensions/builtin/account/index.d.ts.map +1 -0
  47. package/dist/core/extensions/builtin/account/index.js +69 -0
  48. package/dist/core/extensions/builtin/account/index.js.map +1 -0
  49. package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
  50. package/dist/core/extensions/builtin/compaction/index.js +67 -0
  51. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  52. package/dist/core/extensions/builtin/compaction/log.d.ts +1 -1
  53. package/dist/core/extensions/builtin/compaction/log.d.ts.map +1 -1
  54. package/dist/core/extensions/builtin/compaction/log.js +1 -0
  55. package/dist/core/extensions/builtin/compaction/log.js.map +1 -1
  56. package/dist/core/extensions/builtin/config-reload/index.js +14 -22
  57. package/dist/core/extensions/builtin/config-reload/index.js.map +1 -1
  58. package/dist/core/extensions/builtin/goal/continuation-recovery.d.ts +1 -0
  59. package/dist/core/extensions/builtin/goal/continuation-recovery.d.ts.map +1 -1
  60. package/dist/core/extensions/builtin/goal/continuation-recovery.js +2 -0
  61. package/dist/core/extensions/builtin/goal/continuation-recovery.js.map +1 -1
  62. package/dist/core/extensions/builtin/goal/continuation.d.ts +8 -1
  63. package/dist/core/extensions/builtin/goal/continuation.d.ts.map +1 -1
  64. package/dist/core/extensions/builtin/goal/continuation.js +15 -0
  65. package/dist/core/extensions/builtin/goal/continuation.js.map +1 -1
  66. package/dist/core/extensions/builtin/goal/direct-input-lifecycle.js +2 -2
  67. package/dist/core/extensions/builtin/goal/direct-input-lifecycle.js.map +1 -1
  68. package/dist/core/extensions/builtin/goal/format.d.ts +6 -1
  69. package/dist/core/extensions/builtin/goal/format.d.ts.map +1 -1
  70. package/dist/core/extensions/builtin/goal/format.js +6 -0
  71. package/dist/core/extensions/builtin/goal/format.js.map +1 -1
  72. package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
  73. package/dist/core/extensions/builtin/goal/index.js +7 -0
  74. package/dist/core/extensions/builtin/goal/index.js.map +1 -1
  75. package/dist/core/extensions/builtin/goal/lifecycle-helpers.d.ts.map +1 -1
  76. package/dist/core/extensions/builtin/goal/lifecycle-helpers.js +5 -2
  77. package/dist/core/extensions/builtin/goal/lifecycle-helpers.js.map +1 -1
  78. package/dist/core/extensions/builtin/goal/monitor-continuation.d.ts.map +1 -1
  79. package/dist/core/extensions/builtin/goal/monitor-continuation.js +31 -7
  80. package/dist/core/extensions/builtin/goal/monitor-continuation.js.map +1 -1
  81. package/dist/core/extensions/builtin/goal/persistence.js +2 -0
  82. package/dist/core/extensions/builtin/goal/persistence.js.map +1 -1
  83. package/dist/core/extensions/builtin/goal/renderers.d.ts +14 -0
  84. package/dist/core/extensions/builtin/goal/renderers.d.ts.map +1 -0
  85. package/dist/core/extensions/builtin/goal/renderers.js +153 -0
  86. package/dist/core/extensions/builtin/goal/renderers.js.map +1 -0
  87. package/dist/core/extensions/builtin/goal/store.d.ts +6 -2
  88. package/dist/core/extensions/builtin/goal/store.d.ts.map +1 -1
  89. package/dist/core/extensions/builtin/goal/store.js +8 -2
  90. package/dist/core/extensions/builtin/goal/store.js.map +1 -1
  91. package/dist/core/extensions/builtin/goal/tool-registration.d.ts.map +1 -1
  92. package/dist/core/extensions/builtin/goal/tool-registration.js +16 -6
  93. package/dist/core/extensions/builtin/goal/tool-registration.js.map +1 -1
  94. package/dist/core/extensions/builtin/goal/types.d.ts +1 -0
  95. package/dist/core/extensions/builtin/goal/types.d.ts.map +1 -1
  96. package/dist/core/extensions/builtin/goal/types.js.map +1 -1
  97. package/dist/core/extensions/builtin/imagegen/index.d.ts.map +1 -1
  98. package/dist/core/extensions/builtin/imagegen/index.js +10 -3
  99. package/dist/core/extensions/builtin/imagegen/index.js.map +1 -1
  100. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  101. package/dist/core/extensions/builtin/index.js +4 -0
  102. package/dist/core/extensions/builtin/index.js.map +1 -1
  103. package/dist/core/extensions/builtin/service-tier.d.ts.map +1 -1
  104. package/dist/core/extensions/builtin/service-tier.js +13 -0
  105. package/dist/core/extensions/builtin/service-tier.js.map +1 -1
  106. package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
  107. package/dist/core/extensions/builtin/terminal/extension.js +4 -2
  108. package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
  109. package/dist/core/extensions/builtin/todotools/index.js +1 -1
  110. package/dist/core/extensions/builtin/todotools/index.js.map +1 -1
  111. package/dist/core/extensions/builtin/todotools/native-todo-mirror.d.ts +1 -1
  112. package/dist/core/extensions/builtin/todotools/native-todo-mirror.d.ts.map +1 -1
  113. package/dist/core/extensions/builtin/todotools/native-todo-mirror.js +1 -1
  114. package/dist/core/extensions/builtin/todotools/native-todo-mirror.js.map +1 -1
  115. package/dist/core/hidden-stdout-log.d.ts +10 -0
  116. package/dist/core/hidden-stdout-log.d.ts.map +1 -1
  117. package/dist/core/hidden-stdout-log.js +36 -5
  118. package/dist/core/hidden-stdout-log.js.map +1 -1
  119. package/dist/core/model-config-schema.d.ts +85 -12
  120. package/dist/core/model-config-schema.d.ts.map +1 -1
  121. package/dist/core/model-config-schema.js +25 -0
  122. package/dist/core/model-config-schema.js.map +1 -1
  123. package/dist/core/model-runtime.d.ts +36 -1
  124. package/dist/core/model-runtime.d.ts.map +1 -1
  125. package/dist/core/model-runtime.js +142 -12
  126. package/dist/core/model-runtime.js.map +1 -1
  127. package/dist/core/retry-fallback/chains.d.ts +23 -1
  128. package/dist/core/retry-fallback/chains.d.ts.map +1 -1
  129. package/dist/core/retry-fallback/chains.js +59 -3
  130. package/dist/core/retry-fallback/chains.js.map +1 -1
  131. package/dist/core/retry-fallback/controller.d.ts.map +1 -1
  132. package/dist/core/retry-fallback/controller.js +9 -2
  133. package/dist/core/retry-fallback/controller.js.map +1 -1
  134. package/dist/core/retry-fallback/settings.d.ts.map +1 -1
  135. package/dist/core/retry-fallback/settings.js +9 -0
  136. package/dist/core/retry-fallback/settings.js.map +1 -1
  137. package/dist/core/retry-fallback/validate.js +1 -1
  138. package/dist/core/retry-fallback/validate.js.map +1 -1
  139. package/dist/core/sdk.js +1 -1
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/session-manager.d.ts +9 -0
  142. package/dist/core/session-manager.d.ts.map +1 -1
  143. package/dist/core/session-manager.js +31 -0
  144. package/dist/core/session-manager.js.map +1 -1
  145. package/dist/core/tools/output-accumulator.d.ts +2 -0
  146. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  147. package/dist/core/tools/output-accumulator.js +32 -7
  148. package/dist/core/tools/output-accumulator.js.map +1 -1
  149. package/dist/index.d.ts +1 -1
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/index.js +1 -1
  152. package/dist/index.js.map +1 -1
  153. package/dist/main.d.ts +7 -0
  154. package/dist/main.d.ts.map +1 -1
  155. package/dist/main.js +48 -4
  156. package/dist/main.js.map +1 -1
  157. package/dist/modes/app-server/server/account.d.ts.map +1 -1
  158. package/dist/modes/app-server/server/account.js +5 -5
  159. package/dist/modes/app-server/server/account.js.map +1 -1
  160. package/dist/modes/index.d.ts +1 -0
  161. package/dist/modes/index.d.ts.map +1 -1
  162. package/dist/modes/index.js +1 -0
  163. package/dist/modes/index.js.map +1 -1
  164. package/dist/modes/interactive/components/footer.d.ts +11 -3
  165. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  166. package/dist/modes/interactive/components/footer.js +31 -1
  167. package/dist/modes/interactive/components/footer.js.map +1 -1
  168. package/dist/modes/interactive/components/tool-execution-fallback.d.ts.map +1 -1
  169. package/dist/modes/interactive/components/tool-execution-fallback.js +82 -1
  170. package/dist/modes/interactive/components/tool-execution-fallback.js.map +1 -1
  171. package/dist/modes/interactive/grok/chrome.d.ts +4 -4
  172. package/dist/modes/interactive/grok/chrome.d.ts.map +1 -1
  173. package/dist/modes/interactive/grok/chrome.js.map +1 -1
  174. package/dist/modes/interactive/grok/footer.d.ts +3 -3
  175. package/dist/modes/interactive/grok/footer.d.ts.map +1 -1
  176. package/dist/modes/interactive/grok/footer.js.map +1 -1
  177. package/dist/modes/interactive/interactive-host-runtime.d.ts +44 -0
  178. package/dist/modes/interactive/interactive-host-runtime.d.ts.map +1 -0
  179. package/dist/modes/interactive/interactive-host-runtime.js +529 -0
  180. package/dist/modes/interactive/interactive-host-runtime.js.map +1 -0
  181. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  182. package/dist/modes/interactive/interactive-mode.js +340 -257
  183. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  184. package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
  185. package/dist/modes/rpc/connection-handler.js +151 -30
  186. package/dist/modes/rpc/connection-handler.js.map +1 -1
  187. package/dist/modes/rpc/host-ensure.d.ts +41 -0
  188. package/dist/modes/rpc/host-ensure.d.ts.map +1 -0
  189. package/dist/modes/rpc/host-ensure.js +245 -0
  190. package/dist/modes/rpc/host-ensure.js.map +1 -0
  191. package/dist/modes/rpc/host-lifecycle.d.ts +57 -0
  192. package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -0
  193. package/dist/modes/rpc/host-lifecycle.js +491 -0
  194. package/dist/modes/rpc/host-lifecycle.js.map +1 -0
  195. package/dist/modes/rpc/host-watchdog.d.ts +33 -0
  196. package/dist/modes/rpc/host-watchdog.d.ts.map +1 -0
  197. package/dist/modes/rpc/host-watchdog.js +142 -0
  198. package/dist/modes/rpc/host-watchdog.js.map +1 -0
  199. package/dist/modes/rpc/multi-session-host.d.ts +7 -1
  200. package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
  201. package/dist/modes/rpc/multi-session-host.js +216 -32
  202. package/dist/modes/rpc/multi-session-host.js.map +1 -1
  203. package/dist/modes/rpc/rpc-client.d.ts +115 -8
  204. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  205. package/dist/modes/rpc/rpc-client.js +200 -32
  206. package/dist/modes/rpc/rpc-client.js.map +1 -1
  207. package/dist/modes/rpc/rpc-mode.d.ts +4 -2
  208. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  209. package/dist/modes/rpc/rpc-mode.js +4 -2
  210. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  211. package/dist/modes/rpc/rpc-types.d.ts +166 -3
  212. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  213. package/dist/modes/rpc/rpc-types.js.map +1 -1
  214. package/dist/modes/rpc/session-command-router.d.ts +22 -0
  215. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  216. package/dist/modes/rpc/session-command-router.js +165 -16
  217. package/dist/modes/rpc/session-command-router.js.map +1 -1
  218. package/dist/modes/rpc/session-event-writer.d.ts +15 -2
  219. package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
  220. package/dist/modes/rpc/session-event-writer.js +69 -25
  221. package/dist/modes/rpc/session-event-writer.js.map +1 -1
  222. package/dist/modes/rpc/session-registry.d.ts +16 -0
  223. package/dist/modes/rpc/session-registry.d.ts.map +1 -1
  224. package/dist/modes/rpc/session-registry.js +40 -3
  225. package/dist/modes/rpc/session-registry.js.map +1 -1
  226. package/docs/providers.md +48 -0
  227. package/docs/rpc.md +96 -5
  228. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +56 -0
  229. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  230. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +13 -1
  231. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/inline-worker.ts +15 -1
  232. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-indirect-eval.js +711 -1
  233. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/transport.ts +14 -1
  234. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +10 -10
  235. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-eval-result.ts +9 -3
  236. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +6 -1
  237. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.d.ts.map +1 -1
  238. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js +20 -4
  239. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js.map +1 -1
  240. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/index.d.ts +1 -1
  241. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/index.d.ts.map +1 -1
  242. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/index.js.map +1 -1
  243. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/post-mutate.d.ts +21 -0
  244. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/post-mutate.d.ts.map +1 -0
  245. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/post-mutate.js +27 -0
  246. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/post-mutate.js.map +1 -0
  247. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/tool-context.d.ts +24 -0
  248. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/tool-context.d.ts.map +1 -1
  249. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/tool-context.js.map +1 -1
  250. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/write.d.ts.map +1 -1
  251. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/write.js +7 -2
  252. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/write.js.map +1 -1
  253. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  254. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-tool-pairs.d.ts +1 -1
  255. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-tool-pairs.d.ts.map +1 -1
  256. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-tool-pairs.js +46 -14
  257. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-tool-pairs.js.map +1 -1
  258. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +11 -0
  259. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts.map +1 -1
  260. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js +30 -16
  261. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
  262. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.d.ts +2 -1
  263. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.d.ts.map +1 -1
  264. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js +2 -1
  265. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js.map +1 -1
  266. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/classify.d.ts +16 -0
  267. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/classify.d.ts.map +1 -0
  268. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/classify.js +75 -0
  269. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/classify.js.map +1 -0
  270. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.d.ts +45 -0
  271. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.d.ts.map +1 -0
  272. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.js +81 -0
  273. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.js.map +1 -0
  274. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/select.d.ts +31 -0
  275. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/select.d.ts.map +1 -0
  276. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/select.js +65 -0
  277. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/select.js.map +1 -0
  278. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts +12 -0
  279. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts.map +1 -1
  280. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js +37 -0
  281. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js.map +1 -1
  282. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.d.ts +6 -0
  283. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.d.ts.map +1 -1
  284. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js +32 -6
  285. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js.map +1 -1
  286. package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts +3 -2
  287. package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts.map +1 -1
  288. package/node_modules/@earendil-works/pi-ai/dist/auth/types.js.map +1 -1
  289. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.d.ts +6 -0
  290. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.d.ts.map +1 -1
  291. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js +6 -1
  292. package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js.map +1 -1
  293. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +75 -0
  294. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  295. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +75 -0
  296. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
  297. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  298. package/node_modules/@earendil-works/pi-ai/dist/providers/data/alibaba-token-plan.json +1 -1
  299. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  300. package/node_modules/@earendil-works/pi-ai/dist/providers/data/baseten.json +1 -1
  301. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  302. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
  303. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
  304. package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
  305. package/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json +1 -1
  306. package/node_modules/@earendil-works/pi-ai/dist/providers/data/minimax-cn.json +1 -1
  307. package/node_modules/@earendil-works/pi-ai/dist/providers/data/minimax.json +1 -1
  308. package/node_modules/@earendil-works/pi-ai/dist/providers/data/mistral.json +1 -1
  309. package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -1
  310. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai-codex.json +1 -1
  311. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai.json +1 -1
  312. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  313. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  314. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opengateway.json +1 -1
  315. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  316. package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan-cn.json +1 -1
  317. package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan.json +1 -1
  318. package/node_modules/@earendil-works/pi-ai/dist/providers/data/together.json +1 -1
  319. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  320. package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai-coding-cn.json +1 -1
  321. package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai.json +1 -1
  322. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.d.ts.map +1 -1
  323. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +4 -0
  324. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js.map +1 -1
  325. package/node_modules/@earendil-works/pi-ai/package.json +5 -5
  326. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  327. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  328. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +5 -0
  329. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
  330. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +90 -1
  331. package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
  332. package/node_modules/@earendil-works/pi-tui/dist/tui.js +1 -1
  333. package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +1 -1
  334. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  335. package/package.json +7 -7
@@ -17,7 +17,7 @@ import { envValue } from "../../core/brand.js";
17
17
  import { CACHE_TTL_MS, collectCacheMisses, computeCacheWaste, detectCacheMiss, } from "../../core/cache-stats.js";
18
18
  import { buildNoticeBox } from "../../core/extensions/notice/index.js";
19
19
  import { FooterDataProvider } from "../../core/footer-data-provider.js";
20
- import { appendHiddenTuiStdout } from "../../core/hidden-stdout-log.js";
20
+ import { appendHiddenTuiStdout, appendUncaughtCrashLog } from "../../core/hidden-stdout-log.js";
21
21
  import { buildHighReasoningWarning } from "../../core/high-reasoning-warning.js";
22
22
  import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
23
23
  import { KeybindingsManager } from "../../core/keybindings.js";
@@ -143,6 +143,8 @@ function isCompactionCostNotice(item) {
143
143
  return "type" in item && item.type === "compaction_cost";
144
144
  }
145
145
  const DEAD_TERMINAL_ERROR_CODES = new Set(["EIO", "EPIPE", "ENOTCONN"]);
146
+ // Bun's macOS tty shim can report a dead terminal as raw positive errno 5 without a string code.
147
+ const EIO_ERRNO = 5;
146
148
  const DEFAULT_RETRY_STATUS_REFRESH_INTERVAL_MS = 80;
147
149
  const LARGE_SESSION_RETRY_STATUS_REFRESH_INTERVAL_MS = 60_000;
148
150
  const DEFAULT_WORKING_STATUS_REFRESH_INTERVAL_MS = 600;
@@ -207,11 +209,33 @@ function formatWorkingStatusShimmerText(text, intensity) {
207
209
  return `\x1b[1m\x1b[38;2;${color.r};${color.g};${color.b}m${text}\x1b[39m\x1b[22m`;
208
210
  }
209
211
  function isDeadTerminalError(error) {
210
- if (!error || typeof error !== "object" || !("code" in error)) {
212
+ if (!error || typeof error !== "object") {
211
213
  return false;
212
214
  }
215
+ if ("code" in error) {
216
+ const code = error.code;
217
+ if (code !== undefined && DEAD_TERMINAL_ERROR_CODES.has(code)) {
218
+ return true;
219
+ }
220
+ }
221
+ if ("errno" in error) {
222
+ const errno = error.errno;
223
+ return errno === EIO_ERRNO || errno === -EIO_ERRNO;
224
+ }
225
+ return false;
226
+ }
227
+ function storageWriteCrashMessage(error) {
228
+ if (!error || typeof error !== "object" || !("code" in error)) {
229
+ return undefined;
230
+ }
213
231
  const code = error.code;
214
- return code !== undefined && DEAD_TERMINAL_ERROR_CODES.has(code);
232
+ if (code === "EDQUOT") {
233
+ return "Disk quota exceeded (EDQUOT). Free space or quota on the filesystem, then retry.";
234
+ }
235
+ if (code === "ENOSPC") {
236
+ return "Disk full (ENOSPC). Free space on the filesystem, then retry.";
237
+ }
238
+ return undefined;
215
239
  }
216
240
  const ANTHROPIC_SUBSCRIPTION_AUTH_WARNING = "Anthropic subscription auth is active. Third-party harness usage draws from extra usage and is billed per token, not your Claude plan limits. Manage extra usage at https://claude.ai/settings/usage. Disable this warning in /settings.";
217
241
  function isAnthropicSubscriptionAuthKey(apiKey) {
@@ -479,6 +503,8 @@ export class InteractiveMode {
479
503
  this.ui.setMaxRenderFps(fps);
480
504
  }
481
505
  // Convenience accessors
506
+ // The session may be the local AgentSession or the shared-host RPC proxy; the
507
+ // four reads widened on InteractiveSession must be awaited at every call site.
482
508
  get session() {
483
509
  return this.runtimeHost.session;
484
510
  }
@@ -2974,7 +3000,7 @@ export class InteractiveMode {
2974
3000
  this.showTreeSelector();
2975
3001
  }
2976
3002
  else {
2977
- this.showUserMessageSelector();
3003
+ void this.showUserMessageSelector().catch((error) => this.showError(error instanceof Error ? error.message : String(error)));
2978
3004
  }
2979
3005
  this.lastEscapeTime = 0;
2980
3006
  }
@@ -2988,7 +3014,9 @@ export class InteractiveMode {
2988
3014
  this.defaultEditor.onAction("app.clear", () => this.handleCtrlC());
2989
3015
  this.defaultEditor.onCtrlD = () => this.handleCtrlD();
2990
3016
  this.defaultEditor.onAction("app.suspend", () => this.handleCtrlZ());
2991
- this.defaultEditor.onAction("app.thinking.cycle", () => this.cycleThinkingLevel());
3017
+ this.defaultEditor.onAction("app.thinking.cycle", () => {
3018
+ void this.cycleThinkingLevel().catch((error) => this.showError(error instanceof Error ? error.message : String(error)));
3019
+ });
2992
3020
  this.defaultEditor.onAction("app.model.cycleForward", () => this.cycleModel("forward"));
2993
3021
  this.defaultEditor.onAction("app.model.cycleBackward", () => this.cycleModel("backward"));
2994
3022
  // Global debug handler on TUI (works regardless of focus)
@@ -3010,7 +3038,7 @@ export class InteractiveMode {
3010
3038
  this.defaultEditor.onAction("app.message.dequeue", () => this.handleDequeue());
3011
3039
  this.defaultEditor.onAction("app.session.new", () => this.handleClearCommand());
3012
3040
  this.defaultEditor.onAction("app.session.tree", () => this.showTreeSelector());
3013
- this.defaultEditor.onAction("app.session.fork", () => this.showUserMessageSelector());
3041
+ this.defaultEditor.onAction("app.session.fork", () => void this.showUserMessageSelector().catch((error) => this.showError(error instanceof Error ? error.message : String(error))));
3014
3042
  this.defaultEditor.onAction("app.session.resume", () => this.showSessionSelector());
3015
3043
  this.defaultEditor.onChange = (text) => {
3016
3044
  const wasBashMode = this.isBashMode;
@@ -3166,197 +3194,158 @@ export class InteractiveMode {
3166
3194
  }
3167
3195
  setupEditorSubmitHandler() {
3168
3196
  this.defaultEditor.onSubmit = async (text) => {
3169
- // Capture-then-clear BEFORE any branch: handleFollowUp's non-streaming
3170
- // path pre-resolves images and hands off here, but slash / extension /
3171
- // bash submissions return before the consuming branches below. Clearing
3172
- // only after use would leak a stale array into a later ordinary
3173
- // submission whose text never references it.
3174
- const preResolvedImages = this.preResolvedSubmissionImages;
3175
- this.preResolvedSubmissionImages = undefined;
3176
- this.hideShortcutOverlay();
3177
- this.lastEditorText = "";
3178
- text = text.trim();
3179
- if (!text)
3180
- return;
3181
- // Handle commands
3182
- if (text === "/settings") {
3183
- this.showSettingsSelector();
3184
- this.editor.setText("");
3185
- return;
3186
- }
3187
- if (text === "/favorite-models") {
3188
- this.editor.setText("");
3189
- await this.showFavoriteModelsSelector();
3190
- return;
3191
- }
3192
- if (text === "/scoped-models") {
3193
- this.editor.setText("");
3194
- this.showScopedModelsSelector();
3195
- return;
3196
- }
3197
- if (text === "/model" || text.startsWith("/model ")) {
3198
- const searchTerm = text.startsWith("/model ") ? text.slice(7).trim() : undefined;
3199
- this.editor.setText("");
3200
- await this.handleModelCommand(searchTerm);
3201
- return;
3202
- }
3203
- if (text === "/export" || text.startsWith("/export ")) {
3204
- await this.handleExportCommand(text);
3205
- this.editor.setText("");
3206
- return;
3207
- }
3208
- if (text === "/import" || text.startsWith("/import ")) {
3209
- await this.handleImportCommand(text);
3210
- this.editor.setText("");
3211
- return;
3212
- }
3213
- if (text === "/share") {
3214
- await this.handleShareCommand();
3215
- this.editor.setText("");
3216
- return;
3217
- }
3218
- if (text === "/copy") {
3219
- await this.handleCopyCommand();
3220
- this.editor.setText("");
3221
- return;
3222
- }
3223
- if (text === "/name" || text.startsWith("/name ")) {
3224
- this.handleNameCommand(text);
3225
- this.editor.setText("");
3226
- return;
3227
- }
3228
- if (text === "/session") {
3229
- this.handleSessionCommand();
3230
- this.editor.setText("");
3231
- return;
3232
- }
3233
- if (text === "/changelog") {
3234
- this.handleChangelogCommand();
3235
- this.editor.setText("");
3236
- return;
3237
- }
3238
- if (text === "/keybindings") {
3239
- this.editor.setText("");
3240
- await this.handleKeybindingsCommand();
3241
- return;
3242
- }
3243
- if (text === "/hotkeys") {
3244
- this.handleHotkeysCommand();
3245
- this.editor.setText("");
3246
- return;
3247
- }
3248
- if (text === "/fork") {
3249
- this.showUserMessageSelector();
3250
- this.editor.setText("");
3251
- return;
3252
- }
3253
- if (text === "/clone") {
3254
- this.editor.setText("");
3255
- await this.handleCloneCommand();
3256
- return;
3257
- }
3258
- if (text === "/tree") {
3259
- this.showTreeSelector();
3260
- this.editor.setText("");
3261
- return;
3262
- }
3263
- if (text === "/trust") {
3264
- this.showTrustSelector();
3265
- this.editor.setText("");
3266
- return;
3267
- }
3268
- if (text === "/login" || text.startsWith("/login ")) {
3269
- const providerRef = text.startsWith("/login ") ? text.slice(7).trim() : undefined;
3270
- this.editor.setText("");
3271
- await this.handleLoginCommand(providerRef);
3272
- return;
3273
- }
3274
- if (text === "/logout") {
3275
- this.showOAuthSelector("logout");
3276
- this.editor.setText("");
3277
- return;
3278
- }
3279
- if (text === "/new") {
3280
- this.editor.setText("");
3281
- await this.handleClearCommand();
3282
- return;
3283
- }
3284
- if (text === "/compact" || text.startsWith("/compact ")) {
3285
- const customInstructions = text.startsWith("/compact ") ? text.slice(9).trim() : undefined;
3286
- this.editor.setText("");
3287
- await this.handleCompactCommand(customInstructions);
3288
- return;
3289
- }
3290
- if (text === "/reload") {
3291
- this.editor.setText("");
3292
- await this.handleReloadCommand();
3293
- return;
3294
- }
3295
- if (text === "/debug") {
3296
- this.handleDebugCommand();
3297
- this.editor.setText("");
3298
- return;
3299
- }
3300
- if (text === "/arminsayshi") {
3301
- this.handleArminSaysHi();
3302
- this.editor.setText("");
3303
- return;
3304
- }
3305
- if (text === "/dementedelves") {
3306
- this.handleDementedDelves();
3307
- this.editor.setText("");
3308
- return;
3309
- }
3310
- if (text === "/resume") {
3311
- this.showSessionSelector();
3312
- this.editor.setText("");
3313
- return;
3314
- }
3315
- if (text === "/quit" || text === "/exit") {
3316
- this.editor.setText("");
3317
- await this.shutdown();
3318
- return;
3319
- }
3320
- if (this.isExtensionCommand(text)) {
3321
- this.editor.addToHistory?.(text);
3322
- this.editor.setText("");
3323
- const pendingEchoId = this.optimisticUserEchoes.begin(text);
3324
- try {
3325
- await this.session.prompt(text, this.optimisticUserEchoes.promptOptions(pendingEchoId));
3197
+ try {
3198
+ // Capture-then-clear BEFORE any branch: handleFollowUp's non-streaming
3199
+ // path pre-resolves images and hands off here, but slash / extension /
3200
+ // bash submissions return before the consuming branches below. Clearing
3201
+ // only after use would leak a stale array into a later ordinary
3202
+ // submission whose text never references it.
3203
+ const preResolvedImages = this.preResolvedSubmissionImages;
3204
+ this.preResolvedSubmissionImages = undefined;
3205
+ this.hideShortcutOverlay();
3206
+ this.lastEditorText = "";
3207
+ text = text.trim();
3208
+ if (!text)
3209
+ return;
3210
+ // Handle commands
3211
+ if (text === "/settings") {
3212
+ await this.showSettingsSelector();
3213
+ this.editor.setText("");
3214
+ return;
3326
3215
  }
3327
- catch (error) {
3328
- this.optimisticUserEchoes.reject(pendingEchoId);
3329
- throw error;
3216
+ if (text === "/favorite-models") {
3217
+ this.editor.setText("");
3218
+ await this.showFavoriteModelsSelector();
3219
+ return;
3330
3220
  }
3331
- return;
3332
- }
3333
- // Handle bash command (! for normal, !! for excluded from context)
3334
- if (text.startsWith("!")) {
3335
- const isExcluded = text.startsWith("!!");
3336
- const command = isExcluded ? text.slice(2).trim() : text.slice(1).trim();
3337
- if (command) {
3338
- if (this.session.isBashRunning) {
3339
- this.showWarning("A bash command is already running. Press Esc to cancel it first.");
3340
- this.editor.setText(text);
3341
- return;
3342
- }
3343
- this.editor.addToHistory?.(text);
3344
- await this.handleBashCommand(command, isExcluded);
3345
- this.isBashMode = false;
3346
- this.updateEditorBorderColor();
3221
+ if (text === "/scoped-models") {
3222
+ this.editor.setText("");
3223
+ this.showScopedModelsSelector();
3224
+ return;
3225
+ }
3226
+ if (text === "/model" || text.startsWith("/model ")) {
3227
+ const searchTerm = text.startsWith("/model ") ? text.slice(7).trim() : undefined;
3228
+ this.editor.setText("");
3229
+ await this.handleModelCommand(searchTerm);
3230
+ return;
3231
+ }
3232
+ if (text === "/export" || text.startsWith("/export ")) {
3233
+ await this.handleExportCommand(text);
3234
+ this.editor.setText("");
3235
+ return;
3236
+ }
3237
+ if (text === "/import" || text.startsWith("/import ")) {
3238
+ await this.handleImportCommand(text);
3239
+ this.editor.setText("");
3240
+ return;
3241
+ }
3242
+ if (text === "/share") {
3243
+ await this.handleShareCommand();
3244
+ this.editor.setText("");
3245
+ return;
3246
+ }
3247
+ if (text === "/copy") {
3248
+ await this.handleCopyCommand();
3249
+ this.editor.setText("");
3250
+ return;
3251
+ }
3252
+ if (text === "/name" || text.startsWith("/name ")) {
3253
+ await this.handleNameCommand(text);
3254
+ this.editor.setText("");
3255
+ return;
3256
+ }
3257
+ if (text === "/session") {
3258
+ await this.handleSessionCommand();
3259
+ this.editor.setText("");
3260
+ return;
3261
+ }
3262
+ if (text === "/changelog") {
3263
+ this.handleChangelogCommand();
3264
+ this.editor.setText("");
3265
+ return;
3266
+ }
3267
+ if (text === "/keybindings") {
3268
+ this.editor.setText("");
3269
+ await this.handleKeybindingsCommand();
3270
+ return;
3271
+ }
3272
+ if (text === "/hotkeys") {
3273
+ this.handleHotkeysCommand();
3274
+ this.editor.setText("");
3275
+ return;
3276
+ }
3277
+ if (text === "/fork") {
3278
+ await this.showUserMessageSelector();
3279
+ this.editor.setText("");
3280
+ return;
3281
+ }
3282
+ if (text === "/clone") {
3283
+ this.editor.setText("");
3284
+ await this.handleCloneCommand();
3285
+ return;
3286
+ }
3287
+ if (text === "/tree") {
3288
+ this.showTreeSelector();
3289
+ this.editor.setText("");
3290
+ return;
3291
+ }
3292
+ if (text === "/trust") {
3293
+ this.showTrustSelector();
3294
+ this.editor.setText("");
3295
+ return;
3296
+ }
3297
+ if (text === "/login" || text.startsWith("/login ")) {
3298
+ const providerRef = text.startsWith("/login ") ? text.slice(7).trim() : undefined;
3299
+ this.editor.setText("");
3300
+ await this.handleLoginCommand(providerRef);
3301
+ return;
3302
+ }
3303
+ if (text === "/logout") {
3304
+ this.showOAuthSelector("logout");
3305
+ this.editor.setText("");
3306
+ return;
3307
+ }
3308
+ if (text === "/new") {
3309
+ this.editor.setText("");
3310
+ await this.handleClearCommand();
3311
+ return;
3312
+ }
3313
+ if (text === "/compact" || text.startsWith("/compact ")) {
3314
+ const customInstructions = text.startsWith("/compact ") ? text.slice(9).trim() : undefined;
3315
+ this.editor.setText("");
3316
+ await this.handleCompactCommand(customInstructions);
3317
+ return;
3318
+ }
3319
+ if (text === "/reload") {
3320
+ this.editor.setText("");
3321
+ await this.handleReloadCommand();
3322
+ return;
3323
+ }
3324
+ if (text === "/debug") {
3325
+ this.handleDebugCommand();
3326
+ this.editor.setText("");
3327
+ return;
3328
+ }
3329
+ if (text === "/arminsayshi") {
3330
+ this.handleArminSaysHi();
3331
+ this.editor.setText("");
3332
+ return;
3333
+ }
3334
+ if (text === "/dementedelves") {
3335
+ this.handleDementedDelves();
3336
+ this.editor.setText("");
3337
+ return;
3338
+ }
3339
+ if (text === "/resume") {
3340
+ this.showSessionSelector();
3341
+ this.editor.setText("");
3342
+ return;
3343
+ }
3344
+ if (text === "/quit" || text === "/exit") {
3345
+ this.editor.setText("");
3346
+ await this.shutdown();
3347
3347
  return;
3348
3348
  }
3349
- }
3350
- // Queue non-command input during compaction.
3351
- // Extension commands short-circuit at the isExtensionCommand branch above and
3352
- // dispatch immediately inside AgentSession.prompt(), so the only text that
3353
- // reaches this compaction branch is non-command user input, which is queued
3354
- // for delivery after compaction settles.
3355
- //
3356
- // Note: the isExtensionCommand re-check below is already unreachable today
3357
- // (the branch above returns first) and stays harmless after the
3358
- // immediate-dispatch hoist in prompt().
3359
- if (this.session.isCompacting) {
3360
3349
  if (this.isExtensionCommand(text)) {
3361
3350
  this.editor.addToHistory?.(text);
3362
3351
  this.editor.setText("");
@@ -3368,52 +3357,96 @@ export class InteractiveMode {
3368
3357
  this.optimisticUserEchoes.reject(pendingEchoId);
3369
3358
  throw error;
3370
3359
  }
3360
+ return;
3371
3361
  }
3372
- else {
3373
- this.queueCompactionSubmission(text, "steer");
3362
+ // Handle bash command (! for normal, !! for excluded from context)
3363
+ if (text.startsWith("!")) {
3364
+ const isExcluded = text.startsWith("!!");
3365
+ const command = isExcluded ? text.slice(2).trim() : text.slice(1).trim();
3366
+ if (command) {
3367
+ if (this.session.isBashRunning) {
3368
+ this.showWarning("A bash command is already running. Press Esc to cancel it first.");
3369
+ this.editor.setText(text);
3370
+ return;
3371
+ }
3372
+ this.editor.addToHistory?.(text);
3373
+ await this.handleBashCommand(command, isExcluded);
3374
+ this.isBashMode = false;
3375
+ this.updateEditorBorderColor();
3376
+ return;
3377
+ }
3374
3378
  }
3375
- return;
3376
- }
3377
- // If streaming, use prompt() with steer behavior.
3378
- // Extension commands are dispatched immediately by AgentSession.prompt()
3379
- // (short-circuited at the isExtensionCommand branch above); the steer
3380
- // behavior here applies only to ordinary text, prompt template expansion,
3381
- // and queueing.
3382
- if (this.session.isStreaming) {
3383
- // Resolve BEFORE setText(""): the editor's prune chain fires
3384
- // onImageMarkersChanged([]) and destroys pendingImages.
3379
+ // Queue non-command input during compaction.
3380
+ // Extension commands short-circuit at the isExtensionCommand branch above and
3381
+ // dispatch immediately inside AgentSession.prompt(), so the only text that
3382
+ // reaches this compaction branch is non-command user input, which is queued
3383
+ // for delivery after compaction settles.
3384
+ //
3385
+ // Note: the isExtensionCommand re-check below is already unreachable today
3386
+ // (the branch above returns first) and stays harmless after the
3387
+ // immediate-dispatch hoist in prompt().
3388
+ if (this.session.isCompacting) {
3389
+ if (this.isExtensionCommand(text)) {
3390
+ this.editor.addToHistory?.(text);
3391
+ this.editor.setText("");
3392
+ const pendingEchoId = this.optimisticUserEchoes.begin(text);
3393
+ try {
3394
+ await this.session.prompt(text, this.optimisticUserEchoes.promptOptions(pendingEchoId));
3395
+ }
3396
+ catch (error) {
3397
+ this.optimisticUserEchoes.reject(pendingEchoId);
3398
+ throw error;
3399
+ }
3400
+ }
3401
+ else {
3402
+ this.queueCompactionSubmission(text, "steer");
3403
+ }
3404
+ return;
3405
+ }
3406
+ // If streaming, use prompt() with steer behavior.
3407
+ // Extension commands are dispatched immediately by AgentSession.prompt()
3408
+ // (short-circuited at the isExtensionCommand branch above); the steer
3409
+ // behavior here applies only to ordinary text, prompt template expansion,
3410
+ // and queueing.
3411
+ if (this.session.isStreaming) {
3412
+ // Resolve BEFORE setText(""): the editor's prune chain fires
3413
+ // onImageMarkersChanged([]) and destroys pendingImages.
3414
+ const images = preResolvedImages ?? this.takeSubmissionImages(text);
3415
+ this.editor.addToHistory?.(text);
3416
+ this.editor.setText("");
3417
+ const pendingEchoId = this.optimisticUserEchoes.begin(text);
3418
+ try {
3419
+ await this.session.prompt(text, {
3420
+ streamingBehavior: "steer",
3421
+ ...(images.length > 0 ? { images } : {}),
3422
+ ...this.optimisticUserEchoes.promptOptions(pendingEchoId),
3423
+ });
3424
+ }
3425
+ catch (error) {
3426
+ this.optimisticUserEchoes.reject(pendingEchoId);
3427
+ throw error;
3428
+ }
3429
+ this.updatePendingMessagesDisplay();
3430
+ this.ui.requestRender();
3431
+ return;
3432
+ }
3433
+ // Normal message submission
3434
+ // First, move any pending bash components to chat
3435
+ this.flushPendingBashComponents();
3385
3436
  const images = preResolvedImages ?? this.takeSubmissionImages(text);
3386
- this.editor.addToHistory?.(text);
3387
- this.editor.setText("");
3388
3437
  const pendingEchoId = this.optimisticUserEchoes.begin(text);
3389
- try {
3390
- await this.session.prompt(text, {
3391
- streamingBehavior: "steer",
3392
- ...(images.length > 0 ? { images } : {}),
3393
- ...this.optimisticUserEchoes.promptOptions(pendingEchoId),
3394
- });
3438
+ const submission = images.length > 0 ? { text, images, pendingEchoId } : { text, pendingEchoId };
3439
+ if (this.onInputCallback) {
3440
+ this.onInputCallback(submission);
3395
3441
  }
3396
- catch (error) {
3397
- this.optimisticUserEchoes.reject(pendingEchoId);
3398
- throw error;
3442
+ else {
3443
+ this.pendingUserInputs.push(submission);
3399
3444
  }
3400
- this.updatePendingMessagesDisplay();
3401
- this.ui.requestRender();
3402
- return;
3403
- }
3404
- // Normal message submission
3405
- // First, move any pending bash components to chat
3406
- this.flushPendingBashComponents();
3407
- const images = preResolvedImages ?? this.takeSubmissionImages(text);
3408
- const pendingEchoId = this.optimisticUserEchoes.begin(text);
3409
- const submission = images.length > 0 ? { text, images, pendingEchoId } : { text, pendingEchoId };
3410
- if (this.onInputCallback) {
3411
- this.onInputCallback(submission);
3445
+ this.editor.addToHistory?.(text);
3412
3446
  }
3413
- else {
3414
- this.pendingUserInputs.push(submission);
3447
+ catch (error) {
3448
+ this.showError(error instanceof Error ? error.message : String(error));
3415
3449
  }
3416
- this.editor.addToHistory?.(text);
3417
3450
  };
3418
3451
  }
3419
3452
  subscribeToAgent() {
@@ -3474,6 +3507,7 @@ export class InteractiveMode {
3474
3507
  case "thinking_level_changed":
3475
3508
  this.footer.invalidate();
3476
3509
  this.updateEditorBorderColor();
3510
+ this.showStatus(`Thinking level: ${event.level}`);
3477
3511
  break;
3478
3512
  case "high_reasoning_warning":
3479
3513
  this.showHighReasoningWarning(event);
@@ -3724,15 +3758,24 @@ export class InteractiveMode {
3724
3758
  // Keep the structural fallback for focused handler consumers while using
3725
3759
  // the session-owned manager on the real TUI path.
3726
3760
  const sessionManager = this.session.sessionManager ?? this.sessionManager;
3727
- const entries = sessionManager.buildContextEntries();
3761
+ let entries = sessionManager?.buildContextEntries?.() ?? [];
3728
3762
  if (entries[0]?.type !== "compaction") {
3729
- throw new Error("Completed compaction is missing from the session context");
3763
+ try {
3764
+ sessionManager?.reloadFromDisk?.();
3765
+ entries = sessionManager?.buildContextEntries?.() ?? entries;
3766
+ }
3767
+ catch {
3768
+ // Retain existing entries on reload error
3769
+ }
3730
3770
  }
3731
3771
  this.chatContainer.clear();
3732
3772
  const summaryMessage = createCompactionSummaryMessage(sanitizeTerminalLabel(event.result.summary), event.result.tokensBefore, new Date().toISOString(), event.result.details);
3733
3773
  if (typeof this.renderSessionEntries === "function") {
3734
3774
  // The latest compaction is prepended for model context; append it below at its chronological position.
3735
- this.renderSessionEntries(entries.slice(1));
3775
+ const entriesToRender = entries[0]?.type === "compaction"
3776
+ ? entries.slice(1)
3777
+ : entries.filter((e) => e.type !== "compaction");
3778
+ this.renderSessionEntries(entriesToRender);
3736
3779
  this.addMessageToChat(summaryMessage);
3737
3780
  if (event.result.usage) {
3738
3781
  this.addCompactionCostNotice({
@@ -4032,8 +4075,12 @@ export class InteractiveMode {
4032
4075
  this.ui.requestRender();
4033
4076
  const removePending = () => {
4034
4077
  const componentIndex = this.chatContainer.children.indexOf(component);
4035
- const insertionIndex = spacer ? this.chatContainer.children.indexOf(spacer) : componentIndex;
4036
- if (spacer)
4078
+ if (componentIndex === -1) {
4079
+ return this.chatContainer.children.length;
4080
+ }
4081
+ const spacerIndex = spacer ? this.chatContainer.children.indexOf(spacer) : -1;
4082
+ const insertionIndex = spacerIndex >= 0 ? spacerIndex : componentIndex;
4083
+ if (spacerIndex >= 0 && spacer)
4037
4084
  this.chatContainer.removeChild(spacer);
4038
4085
  this.chatContainer.removeChild(component);
4039
4086
  return insertionIndex;
@@ -4423,6 +4470,12 @@ export class InteractiveMode {
4423
4470
  };
4424
4471
  }
4425
4472
  rebuildChatFromMessages() {
4473
+ try {
4474
+ this.sessionManager?.reloadFromDisk?.();
4475
+ }
4476
+ catch {
4477
+ // Keep in-memory entries if file reload is unavailable
4478
+ }
4426
4479
  this.chatContainer.clear();
4427
4480
  this.renderSessionEntries(this.sessionManager.buildContextEntries());
4428
4481
  }
@@ -4479,8 +4532,17 @@ export class InteractiveMode {
4479
4532
  }
4480
4533
  process.exit(0);
4481
4534
  }
4482
- emergencyTerminalExit() {
4535
+ emergencyTerminalExit(crash) {
4483
4536
  this.isShuttingDown = true;
4537
+ // This exit is silent by design (the terminal is gone, so a banner would go
4538
+ // nowhere), which makes the debug log the ONLY surface that can record this
4539
+ // crash class — exactly the EIO case that left the 2026-08-26 diagnosis with no
4540
+ // evidence. Write before the cleanup below, which is unguarded and could throw.
4541
+ // A logging failure must never alter the exit path.
4542
+ try {
4543
+ appendUncaughtCrashLog(crash.origin, crash.error);
4544
+ }
4545
+ catch { }
4484
4546
  this.unregisterSignalHandlers();
4485
4547
  killTrackedDetachedChildren();
4486
4548
  // The terminal is gone. Do not run normal shutdown because TUI and
@@ -4502,6 +4564,13 @@ export class InteractiveMode {
4502
4564
  if (this.isShuttingDown) {
4503
4565
  process.exit(1);
4504
4566
  }
4567
+ if (isDeadTerminalError(error)) {
4568
+ // The terminal died under the session (e.g. an stdin read EIO after
4569
+ // the controlling terminal vanished or this pgrp lost the tty
4570
+ // foreground). Same handling as terminal write errors: exit silently
4571
+ // instead of printing a crash banner to a terminal that is gone.
4572
+ this.emergencyTerminalExit({ origin: `dead-terminal ${origin}`, error });
4573
+ }
4505
4574
  if (isRecoverableInspectorVmImportError(error, origin)) {
4506
4575
  this.showWarning(INSPECTOR_VM_IMPORT_WARNING);
4507
4576
  return;
@@ -4519,7 +4588,18 @@ export class InteractiveMode {
4519
4588
  this.ui.stop();
4520
4589
  }
4521
4590
  catch { }
4591
+ // Record the crash before the terminal handoff: the banner below only reaches
4592
+ // terminal scrollback, which is gone when the terminal is closed or is itself
4593
+ // the thing that failed. A logging failure must never alter the crash path.
4594
+ try {
4595
+ appendUncaughtCrashLog(origin, error);
4596
+ }
4597
+ catch { }
4522
4598
  restoreInteractiveStderr();
4599
+ const storageMessage = storageWriteCrashMessage(error);
4600
+ if (storageMessage !== undefined) {
4601
+ console.error(storageMessage);
4602
+ }
4523
4603
  console.error(`${APP_NAME} exiting due to uncaughtException:`);
4524
4604
  console.error(error);
4525
4605
  process.exit(1);
@@ -4552,7 +4632,7 @@ export class InteractiveMode {
4552
4632
  }
4553
4633
  const terminalErrorHandler = (error) => {
4554
4634
  if (isDeadTerminalError(error)) {
4555
- this.emergencyTerminalExit();
4635
+ this.emergencyTerminalExit({ origin: "dead-terminal stdio error", error });
4556
4636
  }
4557
4637
  throw error;
4558
4638
  };
@@ -4700,16 +4780,15 @@ export class InteractiveMode {
4700
4780
  }
4701
4781
  this.ui.requestRender();
4702
4782
  }
4703
- cycleThinkingLevel() {
4704
- const newLevel = this.session.cycleThinkingLevel();
4783
+ async cycleThinkingLevel() {
4784
+ // The shared-host proxy answers this over RPC. The level itself is rendered
4785
+ // from the thinking_level_changed event (single path for local and remote,
4786
+ // and for changes made by OTHER attached clients); the awaited value only
4787
+ // distinguishes "model does not support thinking".
4788
+ const newLevel = await this.session.cycleThinkingLevel();
4705
4789
  if (newLevel === undefined) {
4706
4790
  this.showStatus("Current model does not support thinking");
4707
4791
  }
4708
- else {
4709
- this.footer.invalidate();
4710
- this.updateEditorBorderColor();
4711
- this.showStatus(`Thinking level: ${newLevel}`);
4712
- }
4713
4792
  }
4714
4793
  async cycleModel(direction) {
4715
4794
  try {
@@ -5191,7 +5270,9 @@ export class InteractiveMode {
5191
5270
  this.ui.setFocus(created.focus);
5192
5271
  this.ui.requestRender();
5193
5272
  }
5194
- showSettingsSelector() {
5273
+ async showSettingsSelector() {
5274
+ // Awaited at the boundary: the shared-host proxy answers this over RPC.
5275
+ const availableThinkingLevels = await this.session.getAvailableThinkingLevels();
5195
5276
  this.showSelector((done) => {
5196
5277
  let selector;
5197
5278
  selector = new SettingsSelectorComponent({
@@ -5206,7 +5287,7 @@ export class InteractiveMode {
5206
5287
  transport: this.settingsManager.getTransport(),
5207
5288
  httpIdleTimeoutMs: this.settingsManager.getHttpIdleTimeoutMs(),
5208
5289
  thinkingLevel: this.session.thinkingLevel,
5209
- availableThinkingLevels: this.session.getAvailableThinkingLevels(),
5290
+ availableThinkingLevels,
5210
5291
  currentTheme: this.themeController.getThemeSelection() || "dark",
5211
5292
  terminalTheme: this.themeController.getTerminalTheme(),
5212
5293
  availableThemes: getAvailableThemes(),
@@ -5794,8 +5875,9 @@ export class InteractiveMode {
5794
5875
  };
5795
5876
  });
5796
5877
  }
5797
- showUserMessageSelector() {
5798
- const userMessages = this.session.getUserMessagesForForking();
5878
+ async showUserMessageSelector() {
5879
+ // Awaited at the boundary: the shared-host proxy answers this over RPC.
5880
+ const userMessages = await this.session.getUserMessagesForForking();
5799
5881
  if (userMessages.length === 0) {
5800
5882
  this.showStatus("No messages to fork from");
5801
5883
  return;
@@ -6574,7 +6656,7 @@ export class InteractiveMode {
6574
6656
  const outputPath = this.getPathCommandArgument(text, "/export");
6575
6657
  try {
6576
6658
  if (outputPath?.endsWith(".jsonl")) {
6577
- const filePath = this.session.exportToJsonl(outputPath);
6659
+ const filePath = await this.session.exportToJsonl(outputPath);
6578
6660
  this.showStatus(`Session exported to: ${filePath}`);
6579
6661
  }
6580
6662
  else {
@@ -6763,7 +6845,7 @@ export class InteractiveMode {
6763
6845
  this.showError(error instanceof Error ? error.message : String(error));
6764
6846
  }
6765
6847
  }
6766
- handleNameCommand(text) {
6848
+ async handleNameCommand(text) {
6767
6849
  const name = text.replace(/^\/name\s*/, "").trim();
6768
6850
  if (!name) {
6769
6851
  const currentName = this.sessionManager.getSessionName();
@@ -6777,8 +6859,8 @@ export class InteractiveMode {
6777
6859
  this.ui.requestRender();
6778
6860
  return;
6779
6861
  }
6780
- this.session.setSessionName(name);
6781
- const sessionName = this.sessionManager.getSessionName();
6862
+ await this.session.setSessionName(name);
6863
+ const sessionName = this.session.sessionName;
6782
6864
  if (sessionName !== name) {
6783
6865
  this.showWarning(`Session name was normalized from ${JSON.stringify(name)} to ${JSON.stringify(sessionName)}`);
6784
6866
  }
@@ -6786,9 +6868,10 @@ export class InteractiveMode {
6786
6868
  this.chatContainer.addChild(new Text(theme.fg("dim", `Session name set: ${sessionName ?? name}`), 1, 0));
6787
6869
  this.ui.requestRender();
6788
6870
  }
6789
- handleSessionCommand() {
6790
- const stats = this.session.getSessionStats();
6791
- const sessionName = this.sessionManager.getSessionName();
6871
+ async handleSessionCommand() {
6872
+ // Awaited at the boundary: the shared-host proxy answers this over RPC.
6873
+ const stats = await this.session.getSessionStats();
6874
+ const sessionName = this.session.sessionName;
6792
6875
  const entries = this.sessionManager.getEntries();
6793
6876
  const cacheWaste = computeCacheWaste(entries, this.session.modelRuntime);
6794
6877
  // Cost/token totals per provider/model actually used (e.g. OpenRouter `auto`
@@ -7070,7 +7153,7 @@ export class InteractiveMode {
7070
7153
  }
7071
7154
  this.bashComponent.setComplete(result.exitCode, result.cancelled, result.truncated ? { truncated: true, content: result.output } : undefined, result.fullOutputPath);
7072
7155
  // Record the result in session
7073
- this.session.recordBashResult(command, result, { excludeFromContext });
7156
+ void this.session.recordBashResult(command, result, { excludeFromContext });
7074
7157
  this.bashComponent = undefined;
7075
7158
  this.ui.requestRender();
7076
7159
  return;