@xopcai/xopc 0.0.86 → 0.0.87

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 (380) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/feishu/src/adapters/cli-login.js +3 -3
  3. package/dist/extensions/feishu/src/adapters/cli-login.js.map +1 -1
  4. package/dist/extensions/telegram/src/delivery-chat-id.d.ts +1 -1
  5. package/dist/extensions/telegram/src/delivery-chat-id.js +1 -1
  6. package/dist/extensions/telegram/src/delivery-chat-id.js.map +1 -1
  7. package/dist/extensions/telegram/src/routing-integration.js +1 -0
  8. package/dist/extensions/telegram/src/routing-integration.js.map +1 -1
  9. package/dist/extensions/telegram/xopc.extension.json +1 -1
  10. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js +2 -2
  11. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js.map +1 -1
  12. package/dist/extensions/weixin/src/api/api.js +2 -2
  13. package/dist/extensions/weixin/src/api/api.js.map +1 -1
  14. package/dist/extensions/weixin/src/auth/accounts.js +12 -12
  15. package/dist/extensions/weixin/src/auth/accounts.js.map +1 -1
  16. package/dist/extensions/weixin/src/delivery-to.js +2 -2
  17. package/dist/extensions/weixin/src/delivery-to.js.map +1 -1
  18. package/dist/extensions/weixin/src/messaging/debug-mode.js +5 -5
  19. package/dist/extensions/weixin/src/messaging/debug-mode.js.map +1 -1
  20. package/dist/extensions/weixin/src/messaging/inbound.js +11 -11
  21. package/dist/extensions/weixin/src/messaging/inbound.js.map +1 -1
  22. package/dist/extensions/weixin/src/storage/sync-buf.js +4 -4
  23. package/dist/extensions/weixin/src/storage/sync-buf.js.map +1 -1
  24. package/dist/extensions/weixin/src/workflow-progress.d.ts +1 -1
  25. package/dist/extensions/weixin/src/workflow-progress.js.map +1 -1
  26. package/dist/gateway/static/root/assets/{agents-mS3_HpRI.js → agents-BEAbXpuP.js} +6 -6
  27. package/dist/gateway/static/root/assets/{apps-page-DrfytjOb.js → apps-page-Dg8R-Szf.js} +1 -1
  28. package/dist/gateway/static/root/assets/{channels-settings-BG6b9KrW.js → channels-settings-yohw9YSu.js} +1 -1
  29. package/dist/gateway/static/root/assets/{channels-status-swr-Bs5kMCMI.js → channels-status-swr-BSHqqCF1.js} +1 -1
  30. package/dist/gateway/static/root/assets/{cron-api-BuVcZ5zR.js → cron-api-0h_QT8U3.js} +1 -1
  31. package/dist/gateway/static/root/assets/{cron-page-BMrloeFH.js → cron-page-BkfKFfFk.js} +1 -1
  32. package/dist/gateway/static/root/assets/{dist-CKU1OOTf.js → dist-Cmjp2APP.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-debug-page-BdW_46sN.js → extension-debug-page-CFa9z_1N.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-DW47KI82.js → extension-page-BI8eaTPq.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-settings-page-B-W4x2xP.js → extension-settings-page-x4BB7q1X.js} +1 -1
  36. package/dist/gateway/static/root/assets/{fetch-B2MYHbWg.js → fetch-DRqwef_Q.js} +1 -1
  37. package/dist/gateway/static/root/assets/{field-primitives-DPG-oJmx.js → field-primitives-BiNHBo2Y.js} +1 -1
  38. package/dist/gateway/static/root/assets/{heartbeat-config-api-C8dNts9i.js → heartbeat-config-api-ZRb8qhuz.js} +1 -1
  39. package/dist/gateway/static/root/assets/{index-BmVYculr.js → index-Cu7bKuUi.js} +96 -94
  40. package/dist/gateway/static/root/assets/index-a5gWIdZQ.css +1 -0
  41. package/dist/gateway/static/root/assets/{logs-page-sTsVWz0X.js → logs-page-BFZ8GgCv.js} +1 -1
  42. package/dist/gateway/static/root/assets/{sessions-page-FaG_Vlkb.js → sessions-page-CD7AfB-2.js} +1 -1
  43. package/dist/gateway/static/root/assets/{settings-form-section-DuvRQW--.js → settings-form-section-DiqqVs6m.js} +1 -1
  44. package/dist/gateway/static/root/assets/{settings-page-Bet1OerL.js → settings-page-BBOjEQW3.js} +1 -1
  45. package/dist/gateway/static/root/assets/{share-preview-page-BtG2kLDh.js → share-preview-page-n1Gprylk.js} +1 -1
  46. package/dist/gateway/static/root/assets/{skills-page-DhUO235y.js → skills-page-CcN_gj--.js} +1 -1
  47. package/dist/gateway/static/root/assets/{theme-store-DryYl3qD.js → theme-store-CZOh1nT3.js} +1 -1
  48. package/dist/gateway/static/root/assets/url-Dd8Q7kZZ.js +3 -0
  49. package/dist/gateway/static/root/assets/{utils-BY7bU1DT.js → utils-CkWBfxs4.js} +1 -1
  50. package/dist/gateway/static/root/assets/{voice-api-key-field-CGEydndO.js → voice-api-key-field-O6awz9hi.js} +1 -1
  51. package/dist/gateway/static/root/index.html +5 -5
  52. package/dist/package.js +1 -1
  53. package/dist/src/agent/agent-scope.d.ts +4 -0
  54. package/dist/src/agent/agent-scope.js +53 -10
  55. package/dist/src/agent/agent-scope.js.map +1 -1
  56. package/dist/src/agent/bootstrap/filter-bootstrap-files.js +2 -1
  57. package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
  58. package/dist/src/agent/embedded/session-tool-result-guard.js +2 -1
  59. package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
  60. package/dist/src/agent/embedded/tool-result-truncation.js +2 -1
  61. package/dist/src/agent/embedded/tool-result-truncation.js.map +1 -1
  62. package/dist/src/agent/fallback/candidates.js +2 -2
  63. package/dist/src/agent/fallback/candidates.js.map +1 -1
  64. package/dist/src/agent/goals/persistent-goal-apis.d.ts +0 -2
  65. package/dist/src/agent/goals/persistent-goal-service.js +0 -1
  66. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
  67. package/dist/src/agent/image/generation/normalization.js +2 -12
  68. package/dist/src/agent/image/generation/normalization.js.map +1 -1
  69. package/dist/src/agent/image/generation/provider-registry.d.ts +4 -8
  70. package/dist/src/agent/image/generation/provider-registry.js.map +1 -1
  71. package/dist/src/agent/image/generation/runtime.d.ts +2 -2
  72. package/dist/src/agent/image/generation/runtime.js.map +1 -1
  73. package/dist/src/agent/image/generation/types.d.ts +0 -18
  74. package/dist/src/agent/image/image-helpers.js +6 -1
  75. package/dist/src/agent/image/image-helpers.js.map +1 -1
  76. package/dist/src/agent/image/index.d.ts +1 -1
  77. package/dist/src/agent/inbound/inbound-loop.d.ts +5 -0
  78. package/dist/src/agent/inbound/inbound-loop.js +41 -10
  79. package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
  80. package/dist/src/agent/inbound/turn-dispatcher.d.ts +4 -0
  81. package/dist/src/agent/inbound/turn-dispatcher.js +6 -4
  82. package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
  83. package/dist/src/agent/mcp/bundle-mcp-materialize.js +2 -1
  84. package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
  85. package/dist/src/agent/mcp/bundle-mcp-names.js +2 -1
  86. package/dist/src/agent/mcp/bundle-mcp-names.js.map +1 -1
  87. package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -1
  88. package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
  89. package/dist/src/agent/mcp/mcp-transport-config.js +2 -1
  90. package/dist/src/agent/mcp/mcp-transport-config.js.map +1 -1
  91. package/dist/src/agent/mcp/mcp-transport.js +2 -1
  92. package/dist/src/agent/mcp/mcp-transport.js.map +1 -1
  93. package/dist/src/agent/media-generation/runtime-shared.js +2 -9
  94. package/dist/src/agent/media-generation/runtime-shared.js.map +1 -1
  95. package/dist/src/agent/messaging/command-handler.d.ts +6 -0
  96. package/dist/src/agent/messaging/command-handler.js +5 -0
  97. package/dist/src/agent/messaging/command-handler.js.map +1 -1
  98. package/dist/src/agent/prompt/safety.d.ts +0 -7
  99. package/dist/src/agent/prompt/safety.js +1 -20
  100. package/dist/src/agent/prompt/safety.js.map +1 -1
  101. package/dist/src/agent/service/build-direct-message-content.js +1 -1
  102. package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
  103. package/dist/src/agent/service/direct-turn-helpers.d.ts +3 -1
  104. package/dist/src/agent/service/direct-turn-helpers.js +6 -1
  105. package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
  106. package/dist/src/agent/service/process-direct-one-shot.d.ts +4 -0
  107. package/dist/src/agent/service/process-direct-one-shot.js +15 -2
  108. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  109. package/dist/src/agent/service/process-direct-streaming.d.ts +4 -0
  110. package/dist/src/agent/service/process-direct-streaming.js +34 -4
  111. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  112. package/dist/src/agent/service/webchat-tts.js +1 -1
  113. package/dist/src/agent/service/webchat-tts.js.map +1 -1
  114. package/dist/src/agent/service.d.ts +8 -0
  115. package/dist/src/agent/service.js +21 -1
  116. package/dist/src/agent/service.js.map +1 -1
  117. package/dist/src/agent/tools/create-share-tool.js +27 -20
  118. package/dist/src/agent/tools/create-share-tool.js.map +1 -1
  119. package/dist/src/agent/tools/factory.js +1 -1
  120. package/dist/src/agent/tools/index.d.ts +0 -1
  121. package/dist/src/agent/tools/index.js +4 -5
  122. package/dist/src/agent/tools/shell.js +0 -13
  123. package/dist/src/agent/tools/shell.js.map +1 -1
  124. package/dist/src/agent/tools/workflow-tool.js +7 -1
  125. package/dist/src/agent/tools/workflow-tool.js.map +1 -1
  126. package/dist/src/agent/workflow/channel-capability.d.ts +3 -3
  127. package/dist/src/agent/workflow/lint.d.ts +38 -0
  128. package/dist/src/agent/workflow/lint.js +74 -0
  129. package/dist/src/agent/workflow/lint.js.map +1 -0
  130. package/dist/src/agent/workflow/parser.js +4 -1
  131. package/dist/src/agent/workflow/parser.js.map +1 -1
  132. package/dist/src/agent/workflow/runtime.d.ts +3 -0
  133. package/dist/src/agent/workflow/runtime.js +76 -3
  134. package/dist/src/agent/workflow/runtime.js.map +1 -1
  135. package/dist/src/agent/workflow/types.d.ts +3 -1
  136. package/dist/src/browser/index.js +4 -4
  137. package/dist/src/browser/manager.d.ts +1 -3
  138. package/dist/src/browser/manager.js +0 -6
  139. package/dist/src/browser/manager.js.map +1 -1
  140. package/dist/src/browser/providers/browser-ext-install.d.ts +4 -4
  141. package/dist/src/browser/providers/browser-ext-install.js +38 -85
  142. package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
  143. package/dist/src/browser/providers/cloakbrowser.d.ts +0 -5
  144. package/dist/src/browser/providers/cloakbrowser.js +2 -55
  145. package/dist/src/browser/providers/cloakbrowser.js.map +1 -1
  146. package/dist/src/channels/attachments/voice-stt-webchat.js +10 -8
  147. package/dist/src/channels/attachments/voice-stt-webchat.js.map +1 -1
  148. package/dist/src/channels/pairing/allow-from-file.js +9 -9
  149. package/dist/src/channels/pairing/allow-from-file.js.map +1 -1
  150. package/dist/src/channels/pairing/pairing-store.js +6 -6
  151. package/dist/src/channels/pairing/pairing-store.js.map +1 -1
  152. package/dist/src/chat-commands/builtins/session.js +1 -1
  153. package/dist/src/chat-commands/builtins/session.js.map +1 -1
  154. package/dist/src/chat-commands/builtins/tts.js +2 -2
  155. package/dist/src/chat-commands/builtins/tts.js.map +1 -1
  156. package/dist/src/chat-commands/context.d.ts +3 -0
  157. package/dist/src/chat-commands/context.js +21 -3
  158. package/dist/src/chat-commands/context.js.map +1 -1
  159. package/dist/src/chat-commands/session-key.d.ts +4 -37
  160. package/dist/src/chat-commands/session-key.js +49 -85
  161. package/dist/src/chat-commands/session-key.js.map +1 -1
  162. package/dist/src/chat-commands/types.d.ts +2 -0
  163. package/dist/src/cli/commands/agent/interactive.js +2 -2
  164. package/dist/src/cli/commands/agent/interactive.js.map +1 -1
  165. package/dist/src/cli/commands/agent/sessions.js +2 -2
  166. package/dist/src/cli/commands/agent/sessions.js.map +1 -1
  167. package/dist/src/cli/commands/agent.js +4 -5
  168. package/dist/src/cli/commands/agent.js.map +1 -1
  169. package/dist/src/cli/commands/channels.js +1 -5
  170. package/dist/src/cli/commands/channels.js.map +1 -1
  171. package/dist/src/cli/commands/gateway/lifecycle-core.js +1 -1
  172. package/dist/src/cli/commands/gateway/lifecycle-core.js.map +1 -1
  173. package/dist/src/cli/commands/gateway/logs.d.ts +9 -0
  174. package/dist/src/cli/commands/gateway/logs.js +50 -17
  175. package/dist/src/cli/commands/gateway/logs.js.map +1 -1
  176. package/dist/src/cli/commands/image.js +22 -21
  177. package/dist/src/cli/commands/image.js.map +1 -1
  178. package/dist/src/cli/commands/session/utils.js +2 -2
  179. package/dist/src/cli/commands/session/utils.js.map +1 -1
  180. package/dist/src/cli/commands/update.js +26 -46
  181. package/dist/src/cli/commands/update.js.map +1 -1
  182. package/dist/src/cli/utils/session.d.ts +0 -5
  183. package/dist/src/cli/utils/session.js +1 -6
  184. package/dist/src/cli/utils/session.js.map +1 -1
  185. package/dist/src/commands/agents.config.js +1 -1
  186. package/dist/src/commands/agents.config.js.map +1 -1
  187. package/dist/src/config/agent-profile.js +5 -27
  188. package/dist/src/config/agent-profile.js.map +1 -1
  189. package/dist/src/config/index.js +2 -2
  190. package/dist/src/config/model-input.js +2 -5
  191. package/dist/src/config/model-input.js.map +1 -1
  192. package/dist/src/config/schema.d.ts +201 -217
  193. package/dist/src/config/schema.js +54 -39
  194. package/dist/src/config/schema.js.map +1 -1
  195. package/dist/src/config/workspace-path-helpers.d.ts +1 -2
  196. package/dist/src/config/workspace-path-helpers.js.map +1 -1
  197. package/dist/src/daemon/install-plan.js +25 -1
  198. package/dist/src/daemon/install-plan.js.map +1 -1
  199. package/dist/src/daemon/launchd.d.ts +8 -0
  200. package/dist/src/daemon/launchd.js +5 -12
  201. package/dist/src/daemon/launchd.js.map +1 -1
  202. package/dist/src/daemon/schtasks.d.ts +25 -0
  203. package/dist/src/daemon/schtasks.js +166 -46
  204. package/dist/src/daemon/schtasks.js.map +1 -1
  205. package/dist/src/daemon/service.js +5 -4
  206. package/dist/src/daemon/service.js.map +1 -1
  207. package/dist/src/daemon/systemd.d.ts +6 -0
  208. package/dist/src/daemon/systemd.js +18 -3
  209. package/dist/src/daemon/systemd.js.map +1 -1
  210. package/dist/src/extensions/activation-context.js +0 -1
  211. package/dist/src/extensions/activation-context.js.map +1 -1
  212. package/dist/src/extensions/normalize-manifest.js +0 -1
  213. package/dist/src/extensions/normalize-manifest.js.map +1 -1
  214. package/dist/src/extensions/types/manifest.d.ts +0 -2
  215. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  216. package/dist/src/gateway/agent-builtin-tools.js +1 -0
  217. package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
  218. package/dist/src/gateway/agents-admin.js +10 -2
  219. package/dist/src/gateway/agents-admin.js.map +1 -1
  220. package/dist/src/gateway/heartbeat/service.js +2 -2
  221. package/dist/src/gateway/heartbeat/service.js.map +1 -1
  222. package/dist/src/gateway/hono/app.js +1 -1
  223. package/dist/src/gateway/hono/lib/agent-model.d.ts +18 -10
  224. package/dist/src/gateway/hono/lib/agent-model.js +24 -35
  225. package/dist/src/gateway/hono/lib/agent-model.js.map +1 -1
  226. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  227. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  228. package/dist/src/gateway/hono/lib/safe-voice-config.js +14 -53
  229. package/dist/src/gateway/hono/lib/safe-voice-config.js.map +1 -1
  230. package/dist/src/gateway/hono/routes/config-patch/agents.js +17 -5
  231. package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -1
  232. package/dist/src/gateway/hono/routes/config-patch/channels.js +0 -11
  233. package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -1
  234. package/dist/src/gateway/hono/routes/goals.js +1 -1
  235. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  236. package/dist/src/gateway/hono/routes/sessions.js +28 -7
  237. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  238. package/dist/src/gateway/hono/routes/shares.js +14 -12
  239. package/dist/src/gateway/hono/routes/shares.js.map +1 -1
  240. package/dist/src/gateway/hono/routes/tunnel.js +1 -1
  241. package/dist/src/gateway/hono/routes/update.js +4 -2
  242. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  243. package/dist/src/gateway/hono/sse.js +16 -33
  244. package/dist/src/gateway/hono/sse.js.map +1 -1
  245. package/dist/src/gateway/lock.js +10 -10
  246. package/dist/src/gateway/lock.js.map +1 -1
  247. package/dist/src/gateway/ports.js +6 -6
  248. package/dist/src/gateway/ports.js.map +1 -1
  249. package/dist/src/gateway/resolve-webchat-session-key.d.ts +19 -0
  250. package/dist/src/gateway/resolve-webchat-session-key.js +46 -0
  251. package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -0
  252. package/dist/src/gateway/service/run-gateway-agent.js +27 -11
  253. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  254. package/dist/src/gateway/service/sessions-api.d.ts +3 -0
  255. package/dist/src/gateway/service/sessions-api.js +8 -0
  256. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  257. package/dist/src/gateway/service.d.ts +0 -2
  258. package/dist/src/gateway/service.js +2 -7
  259. package/dist/src/gateway/service.js.map +1 -1
  260. package/dist/src/gateway/session-reset-service.d.ts +20 -0
  261. package/dist/src/gateway/session-reset-service.js +54 -0
  262. package/dist/src/gateway/session-reset-service.js.map +1 -0
  263. package/dist/src/gateway/startup-readiness.d.ts +1 -1
  264. package/dist/src/gateway/startup-readiness.js +1 -0
  265. package/dist/src/gateway/startup-readiness.js.map +1 -1
  266. package/dist/src/heartbeat/index.js +1 -1
  267. package/dist/src/infra/gateway-processes.js +2 -2
  268. package/dist/src/infra/gateway-processes.js.map +1 -1
  269. package/dist/src/infra/run-command.d.ts +16 -0
  270. package/dist/src/infra/run-command.js +67 -0
  271. package/dist/src/infra/run-command.js.map +1 -0
  272. package/dist/src/infra/update-global.d.ts +45 -0
  273. package/dist/src/infra/update-global.js +224 -0
  274. package/dist/src/infra/update-global.js.map +1 -0
  275. package/dist/src/mcp/channel-bridge.js +1 -1
  276. package/dist/src/mcp/channel-shared.js +2 -1
  277. package/dist/src/mcp/channel-shared.js.map +1 -1
  278. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  279. package/dist/src/providers/auth-runtime/auth-profile-store.js.map +1 -1
  280. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -12
  281. package/dist/src/providers/auth-runtime/resolve-auth.js.map +1 -1
  282. package/dist/src/providers/auth-runtime/types.d.ts +6 -12
  283. package/dist/src/routing/agent-session-key.d.ts +58 -0
  284. package/dist/src/routing/agent-session-key.js +164 -0
  285. package/dist/src/routing/agent-session-key.js.map +1 -0
  286. package/dist/src/routing/index.d.ts +1 -1
  287. package/dist/src/routing/index.js +4 -2
  288. package/dist/src/routing/index.js.map +1 -1
  289. package/dist/src/routing/resolve-route.d.ts +15 -0
  290. package/dist/src/routing/resolve-route.js +41 -20
  291. package/dist/src/routing/resolve-route.js.map +1 -1
  292. package/dist/src/routing/resolve-tui-session-key.d.ts +25 -0
  293. package/dist/src/routing/resolve-tui-session-key.js +54 -0
  294. package/dist/src/routing/resolve-tui-session-key.js.map +1 -0
  295. package/dist/src/routing/session-key-utils.d.ts +24 -0
  296. package/dist/src/routing/session-key-utils.js +92 -0
  297. package/dist/src/routing/session-key-utils.js.map +1 -0
  298. package/dist/src/routing/session-key.d.ts +19 -49
  299. package/dist/src/routing/session-key.js +143 -116
  300. package/dist/src/routing/session-key.js.map +1 -1
  301. package/dist/src/session/index.d.ts +6 -0
  302. package/dist/src/session/index.js +7 -1
  303. package/dist/src/session/init-session-turn.d.ts +30 -0
  304. package/dist/src/session/init-session-turn.js +102 -0
  305. package/dist/src/session/init-session-turn.js.map +1 -0
  306. package/dist/src/session/lifecycle-timestamps.d.ts +8 -0
  307. package/dist/src/session/lifecycle-timestamps.js +16 -0
  308. package/dist/src/session/lifecycle-timestamps.js.map +1 -0
  309. package/dist/src/session/manager.d.ts +7 -1
  310. package/dist/src/session/manager.js +8 -1
  311. package/dist/src/session/manager.js.map +1 -1
  312. package/dist/src/session/parity/transcript-paths.js +2 -2
  313. package/dist/src/session/parity/transcript-paths.js.map +1 -1
  314. package/dist/src/session/parity/xopc-session-disk-entry.d.ts +6 -0
  315. package/dist/src/session/reset-policy.d.ts +32 -0
  316. package/dist/src/session/reset-policy.js +65 -0
  317. package/dist/src/session/reset-policy.js.map +1 -0
  318. package/dist/src/session/reset-triggers.d.ts +20 -0
  319. package/dist/src/session/reset-triggers.js +63 -0
  320. package/dist/src/session/reset-triggers.js.map +1 -0
  321. package/dist/src/session/reset-type.d.ts +12 -0
  322. package/dist/src/session/reset-type.js +25 -0
  323. package/dist/src/session/reset-type.js.map +1 -0
  324. package/dist/src/session/resolve-session.d.ts +30 -0
  325. package/dist/src/session/resolve-session.js +93 -0
  326. package/dist/src/session/resolve-session.js.map +1 -0
  327. package/dist/src/session/session-title.js +3 -2
  328. package/dist/src/session/session-title.js.map +1 -1
  329. package/dist/src/session/store.d.ts +11 -4
  330. package/dist/src/session/store.js +57 -6
  331. package/dist/src/session/store.js.map +1 -1
  332. package/dist/src/session/transcript-events.js +2 -1
  333. package/dist/src/session/transcript-events.js.map +1 -1
  334. package/dist/src/share/share-url.d.ts +33 -0
  335. package/dist/src/share/share-url.js +56 -14
  336. package/dist/src/share/share-url.js.map +1 -1
  337. package/dist/src/tui/backends/embedded-backend.js +4 -9
  338. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  339. package/dist/src/tui/backends/gateway-sse-backend.js +1 -1
  340. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  341. package/dist/src/tui/components/chat-log.js +3 -3
  342. package/dist/src/tui/components/chat-log.js.map +1 -1
  343. package/dist/src/tui/theme.d.ts +0 -2
  344. package/dist/src/tui/theme.js +1 -3
  345. package/dist/src/tui/theme.js.map +1 -1
  346. package/dist/src/tui/tui-commands.d.ts +3 -0
  347. package/dist/src/tui/tui-commands.js +45 -10
  348. package/dist/src/tui/tui-commands.js.map +1 -1
  349. package/dist/src/tui/tui-keybindings-file.js +1 -21
  350. package/dist/src/tui/tui-keybindings-file.js.map +1 -1
  351. package/dist/src/tui/tui-session-actions.d.ts +28 -0
  352. package/dist/src/tui/tui-session-actions.js +88 -0
  353. package/dist/src/tui/tui-session-actions.js.map +1 -0
  354. package/dist/src/tui/tui.js +52 -47
  355. package/dist/src/tui/tui.js.map +1 -1
  356. package/dist/src/utils/string-coerce.d.ts +2 -0
  357. package/dist/src/utils/string-coerce.js +10 -1
  358. package/dist/src/utils/string-coerce.js.map +1 -1
  359. package/dist/src/voice/stt/config-slice.d.ts +2 -5
  360. package/dist/src/voice/stt/config-slice.js +5 -26
  361. package/dist/src/voice/stt/config-slice.js.map +1 -1
  362. package/dist/src/voice/stt/types.d.ts +1 -18
  363. package/dist/src/voice/stt/types.js +4 -2
  364. package/dist/src/voice/stt/types.js.map +1 -1
  365. package/dist/src/voice/tts/config-slice.d.ts +3 -7
  366. package/dist/src/voice/tts/config-slice.js +7 -38
  367. package/dist/src/voice/tts/config-slice.js.map +1 -1
  368. package/dist/src/voice/tts/merge-config.js +2 -48
  369. package/dist/src/voice/tts/merge-config.js.map +1 -1
  370. package/dist/src/voice/tts/providers/alibaba-speech.js +1 -1
  371. package/dist/src/voice/tts/providers/alibaba-speech.js.map +1 -1
  372. package/dist/src/voice/tts/types.d.ts +1 -29
  373. package/dist/src/voice/tts/types.js +19 -17
  374. package/dist/src/voice/tts/types.js.map +1 -1
  375. package/package.json +1 -4
  376. package/dist/gateway/static/root/assets/index-ew_2L2We.css +0 -1
  377. package/dist/gateway/static/root/assets/url-BwNL6Rgk.js +0 -3
  378. package/dist/src/agent/tools/browser-legacy-tools.d.ts +0 -17
  379. package/dist/src/agent/tools/browser-legacy-tools.js +0 -766
  380. package/dist/src/agent/tools/browser-legacy-tools.js.map +0 -1
@@ -0,0 +1,88 @@
1
+ import { parseAgentSessionKey } from "../routing/session-key-utils.js";
2
+ import { init_agent_session_key } from "../routing/agent-session-key.js";
3
+ import { appendHistoryToChatLog } from "./chat-history.js";
4
+ import { clearPendingToolCallIds } from "./tui-agent-events.js";
5
+ //#region src/tui/tui-session-actions.ts
6
+ init_agent_session_key();
7
+ function createSessionActions(context) {
8
+ const { client, chatLog, tui, state, assembler, resolveSessionKey, updateHeader, updateFooter, setActivityStatus, historyLimit = 200, onAgentIdChange } = context;
9
+ let refreshSessionInfoPromise = Promise.resolve();
10
+ const updateAgentFromSessionKey = (key) => {
11
+ const parsed = parseAgentSessionKey(key);
12
+ if (!parsed?.agentId) return;
13
+ onAgentIdChange?.(parsed.agentId);
14
+ };
15
+ const runRefreshSessionInfo = async () => {
16
+ try {
17
+ state.sessionInfo = await client.getSessionInfo(state.currentSessionKey);
18
+ updateFooter();
19
+ tui.requestRender();
20
+ } catch {}
21
+ };
22
+ const refreshSessionInfo = async () => {
23
+ refreshSessionInfoPromise = refreshSessionInfoPromise.then(runRefreshSessionInfo, runRefreshSessionInfo);
24
+ await refreshSessionInfoPromise;
25
+ };
26
+ const clearChatForSessionSwitch = () => {
27
+ assembler.clear();
28
+ chatLog.clearAll();
29
+ clearPendingToolCallIds();
30
+ state.historyLoaded = false;
31
+ state.messageFollowUpQueue.length = 0;
32
+ };
33
+ const loadHistory = async () => {
34
+ try {
35
+ const { messages } = await client.loadHistory({
36
+ sessionKey: state.currentSessionKey,
37
+ limit: historyLimit
38
+ });
39
+ chatLog.clearAll();
40
+ appendHistoryToChatLog(chatLog, messages, state.toolsExpanded);
41
+ } catch {} finally {
42
+ state.historyLoaded = true;
43
+ await refreshSessionInfo();
44
+ tui.requestRender();
45
+ }
46
+ };
47
+ const setSession = async (rawKey) => {
48
+ const nextKey = resolveSessionKey(rawKey);
49
+ updateAgentFromSessionKey(nextKey);
50
+ state.currentSessionKey = nextKey;
51
+ state.activeRunId = null;
52
+ setActivityStatus("idle");
53
+ clearChatForSessionSwitch();
54
+ updateHeader();
55
+ updateFooter();
56
+ await loadHistory();
57
+ };
58
+ const abortActive = async (opts) => {
59
+ if (!state.activeRunId) return;
60
+ const runId = state.activeRunId;
61
+ state.activeRunId = null;
62
+ assembler.drop(runId);
63
+ if (opts?.clearUi !== false) chatLog.dropAssistant(runId);
64
+ setActivityStatus("idle");
65
+ tui.requestRender();
66
+ await client.abortChat({
67
+ sessionKey: state.currentSessionKey,
68
+ runId
69
+ }).catch(() => {});
70
+ };
71
+ const resetCurrentSession = async () => {
72
+ await client.resetSession(state.currentSessionKey);
73
+ clearChatForSessionSwitch();
74
+ await loadHistory();
75
+ };
76
+ return {
77
+ refreshSessionInfo,
78
+ loadHistory,
79
+ setSession,
80
+ abortActive,
81
+ resetCurrentSession,
82
+ clearChatForSessionSwitch
83
+ };
84
+ }
85
+ //#endregion
86
+ export { createSessionActions };
87
+
88
+ //# sourceMappingURL=tui-session-actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-session-actions.js","names":[],"sources":["../../../src/tui/tui-session-actions.ts"],"sourcesContent":["import type { TUI } from '@earendil-works/pi-tui';\n\nimport { parseAgentSessionKey } from '../routing/agent-session-key.js';\nimport { appendHistoryToChatLog } from './chat-history.js';\nimport type { ChatLog } from './components/chat-log.js';\nimport { clearPendingToolCallIds } from './tui-agent-events.js';\nimport type { TuiBackend } from './tui-backend.js';\nimport type { StreamAssembler } from './stream-assembler.js';\nimport type { TuiState } from './tui-types.js';\n\nexport type SessionActionsContext = {\n client: TuiBackend;\n chatLog: ChatLog;\n tui: TUI;\n state: TuiState;\n assembler: StreamAssembler;\n resolveSessionKey: (raw?: string) => string;\n updateHeader: () => void;\n updateFooter: () => void;\n setActivityStatus: (status: string) => void;\n historyLimit?: number;\n onAgentIdChange?: (agentId: string) => void;\n};\n\nexport function createSessionActions(context: SessionActionsContext) {\n const {\n client,\n chatLog,\n tui,\n state,\n assembler,\n resolveSessionKey,\n updateHeader,\n updateFooter,\n setActivityStatus,\n historyLimit = 200,\n onAgentIdChange,\n } = context;\n\n let refreshSessionInfoPromise: Promise<void> = Promise.resolve();\n\n const updateAgentFromSessionKey = (key: string) => {\n const parsed = parseAgentSessionKey(key);\n if (!parsed?.agentId) {\n return;\n }\n onAgentIdChange?.(parsed.agentId);\n };\n\n const runRefreshSessionInfo = async () => {\n try {\n state.sessionInfo = await client.getSessionInfo(state.currentSessionKey);\n updateFooter();\n tui.requestRender();\n } catch {\n // ignore\n }\n };\n\n const refreshSessionInfo = async () => {\n refreshSessionInfoPromise = refreshSessionInfoPromise.then(\n runRefreshSessionInfo,\n runRefreshSessionInfo,\n );\n await refreshSessionInfoPromise;\n };\n\n const clearChatForSessionSwitch = () => {\n assembler.clear();\n chatLog.clearAll();\n clearPendingToolCallIds();\n state.historyLoaded = false;\n state.messageFollowUpQueue.length = 0;\n };\n\n const loadHistory = async () => {\n try {\n const { messages } = await client.loadHistory({\n sessionKey: state.currentSessionKey,\n limit: historyLimit,\n });\n chatLog.clearAll();\n appendHistoryToChatLog(chatLog, messages, state.toolsExpanded);\n } catch {\n // ignore; footer already hints on disconnect\n } finally {\n state.historyLoaded = true;\n await refreshSessionInfo();\n tui.requestRender();\n }\n };\n\n const setSession = async (rawKey: string) => {\n const nextKey = resolveSessionKey(rawKey);\n updateAgentFromSessionKey(nextKey);\n state.currentSessionKey = nextKey;\n state.activeRunId = null;\n setActivityStatus('idle');\n clearChatForSessionSwitch();\n updateHeader();\n updateFooter();\n await loadHistory();\n };\n\n const abortActive = async (opts?: { clearUi?: boolean }) => {\n if (!state.activeRunId) {\n return;\n }\n const runId = state.activeRunId;\n state.activeRunId = null;\n assembler.drop(runId);\n if (opts?.clearUi !== false) {\n chatLog.dropAssistant(runId);\n }\n setActivityStatus('idle');\n tui.requestRender();\n await client.abortChat({ sessionKey: state.currentSessionKey, runId }).catch(() => {});\n };\n\n const resetCurrentSession = async () => {\n await client.resetSession(state.currentSessionKey);\n clearChatForSessionSwitch();\n await loadHistory();\n };\n\n return {\n refreshSessionInfo,\n loadHistory,\n setSession,\n abortActive,\n resetCurrentSession,\n clearChatForSessionSwitch,\n };\n}\n"],"mappings":";;;;;wBAEuE;AAsBvE,SAAgB,qBAAqB,SAAgC;CACnE,MAAM,EACJ,QACA,SACA,KACA,OACA,WACA,mBACA,cACA,cACA,mBACA,eAAe,KACf,oBACE;CAEJ,IAAI,4BAA2C,QAAQ,SAAS;CAEhE,MAAM,6BAA6B,QAAgB;EACjD,MAAM,SAAS,qBAAqB,IAAI;AACxC,MAAI,CAAC,QAAQ,QACX;AAEF,oBAAkB,OAAO,QAAQ;;CAGnC,MAAM,wBAAwB,YAAY;AACxC,MAAI;AACF,SAAM,cAAc,MAAM,OAAO,eAAe,MAAM,kBAAkB;AACxE,iBAAc;AACd,OAAI,eAAe;UACb;;CAKV,MAAM,qBAAqB,YAAY;AACrC,8BAA4B,0BAA0B,KACpD,uBACA,sBACD;AACD,QAAM;;CAGR,MAAM,kCAAkC;AACtC,YAAU,OAAO;AACjB,UAAQ,UAAU;AAClB,2BAAyB;AACzB,QAAM,gBAAgB;AACtB,QAAM,qBAAqB,SAAS;;CAGtC,MAAM,cAAc,YAAY;AAC9B,MAAI;GACF,MAAM,EAAE,aAAa,MAAM,OAAO,YAAY;IAC5C,YAAY,MAAM;IAClB,OAAO;IACR,CAAC;AACF,WAAQ,UAAU;AAClB,0BAAuB,SAAS,UAAU,MAAM,cAAc;UACxD,WAEE;AACR,SAAM,gBAAgB;AACtB,SAAM,oBAAoB;AAC1B,OAAI,eAAe;;;CAIvB,MAAM,aAAa,OAAO,WAAmB;EAC3C,MAAM,UAAU,kBAAkB,OAAO;AACzC,4BAA0B,QAAQ;AAClC,QAAM,oBAAoB;AAC1B,QAAM,cAAc;AACpB,oBAAkB,OAAO;AACzB,6BAA2B;AAC3B,gBAAc;AACd,gBAAc;AACd,QAAM,aAAa;;CAGrB,MAAM,cAAc,OAAO,SAAiC;AAC1D,MAAI,CAAC,MAAM,YACT;EAEF,MAAM,QAAQ,MAAM;AACpB,QAAM,cAAc;AACpB,YAAU,KAAK,MAAM;AACrB,MAAI,MAAM,YAAY,MACpB,SAAQ,cAAc,MAAM;AAE9B,oBAAkB,OAAO;AACzB,MAAI,eAAe;AACnB,QAAM,OAAO,UAAU;GAAE,YAAY,MAAM;GAAmB;GAAO,CAAC,CAAC,YAAY,GAAG;;CAGxF,MAAM,sBAAsB,YAAY;AACtC,QAAM,OAAO,aAAa,MAAM,kBAAkB;AAClD,6BAA2B;AAC3B,QAAM,aAAa;;AAGrB,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD"}
@@ -1,5 +1,9 @@
1
1
  import { version } from "../../package.js";
2
- import { appendHistoryToChatLog } from "./chat-history.js";
2
+ import { parseAgentSessionKey } from "../routing/session-key-utils.js";
3
+ import { init_agent_session_key } from "../routing/agent-session-key.js";
4
+ import { loadConfig } from "../config/loader.js";
5
+ import "../config/index.js";
6
+ import { resolveTuiSessionKey, resolveTuiStartupSessionKey } from "../routing/resolve-tui-session-key.js";
3
7
  import { saveClipboardImageToTempFile } from "./clipboard-image.js";
4
8
  import { createXopcTuiKeybindingsManager } from "./tui-keybindings-file.js";
5
9
  import { StreamAssembler } from "./stream-assembler.js";
@@ -13,6 +17,7 @@ import { createLocalShellRunner } from "./tui-local-shell.js";
13
17
  import { createOverlayHandlers } from "./tui-overlays.js";
14
18
  import { filterModelsForCycle, loadScopedModelRefs, saveScopedModelRefs } from "./tui-scoped-models.js";
15
19
  import { openModelPickerOverlay, openScopedModelsOverlay, openSessionPickerOverlay, openSettingsOverlay } from "./tui-picker-overlay.js";
20
+ import { createSessionActions } from "./tui-session-actions.js";
16
21
  import { loadTuiSettings, saveTuiSettings } from "./tui-settings.js";
17
22
  import { installTuiStdioFilter } from "./tui-stdio-filter.js";
18
23
  import { createEditorSubmitHandler, createSubmitBurstCoalescer, shouldEnableWindowsGitBashPasteFallback } from "./tui-submit.js";
@@ -32,6 +37,7 @@ import { mkdtempSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
32
37
  import { spawnSync } from "node:child_process";
33
38
  import { Container, Loader, ProcessTerminal, TUI, setKeybindings } from "@earendil-works/pi-tui";
34
39
  //#region src/tui/tui.ts
40
+ init_agent_session_key();
35
41
  const THINK_LEVEL_CYCLE = [
36
42
  "off",
37
43
  "minimal",
@@ -52,10 +58,23 @@ async function runTui(opts) {
52
58
  const stdioFilter = installTuiStdioFilter();
53
59
  const restoreStdio = () => stdioFilter.restore();
54
60
  const isLocalMode = opts.local === true;
55
- const sessionKey = opts.session ?? "cli:tui";
61
+ const startup = resolveTuiStartupSessionKey({
62
+ cfg: loadConfig(),
63
+ sessionOption: opts.session,
64
+ cwd: process.cwd()
65
+ });
66
+ let currentAgentId = startup.agentId;
67
+ const sessionScope = startup.sessionScope;
68
+ const sessionMainKey = startup.sessionMainKey;
69
+ const resolveSessionKey = (raw) => resolveTuiSessionKey({
70
+ raw,
71
+ sessionScope,
72
+ currentAgentId,
73
+ sessionMainKey
74
+ });
56
75
  let tuiSettings = loadTuiSettings();
57
76
  initTuiTheme({ themeId: opts.theme ?? tuiSettings.theme });
58
- const state = createInitialState(sessionKey);
77
+ const state = createInitialState(startup.sessionKey);
59
78
  state.scopedModelRefs = loadScopedModelRefs();
60
79
  state.showThinking = tuiSettings.showThinking;
61
80
  state.toolsExpanded = tuiSettings.toolsExpanded;
@@ -226,14 +245,6 @@ async function runTui(opts) {
226
245
  bottomBar.invalidate();
227
246
  tui.requestRender();
228
247
  };
229
- const refreshSessionInfo = async () => {
230
- try {
231
- state.sessionInfo = await client.getSessionInfo(state.currentSessionKey);
232
- updateEditorBorderColor();
233
- updateFooter();
234
- tui.requestRender();
235
- } catch {}
236
- };
237
248
  let finishTui = null;
238
249
  let exitResult = { exitReason: "exit" };
239
250
  const requestExit = () => {
@@ -255,18 +266,23 @@ async function runTui(opts) {
255
266
  process.exit(0);
256
267
  });
257
268
  };
258
- const abortActive = async () => {
259
- if (!state.activeRunId) return;
260
- const runId = state.activeRunId;
261
- state.activeRunId = null;
262
- assembler.drop(runId);
263
- chatLog.dropAssistant(runId);
264
- setActivityStatus("idle");
265
- tui.requestRender();
266
- await client.abortChat({
267
- sessionKey: state.currentSessionKey,
268
- runId
269
- }).catch(() => {});
269
+ const { refreshSessionInfo, loadHistory: loadSessionHistory, setSession, abortActive, resetCurrentSession, clearChatForSessionSwitch } = createSessionActions({
270
+ client,
271
+ chatLog,
272
+ tui,
273
+ state,
274
+ assembler,
275
+ resolveSessionKey,
276
+ updateHeader,
277
+ updateFooter,
278
+ setActivityStatus,
279
+ onAgentIdChange: (agentId) => {
280
+ currentAgentId = agentId;
281
+ }
282
+ });
283
+ const refreshSessionInfoWithBorder = async () => {
284
+ await refreshSessionInfo();
285
+ updateEditorBorderColor();
270
286
  };
271
287
  const resolveModelChoiceIndex = () => {
272
288
  const choices = cycleModelChoices();
@@ -411,7 +427,7 @@ async function runTui(opts) {
411
427
  } finally {
412
428
  state.isCompacting = false;
413
429
  setActivityStatus("idle");
414
- await refreshSessionInfo();
430
+ await refreshSessionInfoWithBorder();
415
431
  const queued = state.compactionQueue.shift();
416
432
  if (queued && !state.activeRunId) sendMessage(queued);
417
433
  updateFooter();
@@ -460,7 +476,10 @@ async function runTui(opts) {
460
476
  keybindings,
461
477
  uiOverlays,
462
478
  runCompaction,
463
- extensionSlashCommands: extensionRuntime.slashCommands
479
+ extensionSlashCommands: extensionRuntime.slashCommands,
480
+ currentAgentId,
481
+ setSession,
482
+ resetSession: resetCurrentSession
464
483
  });
465
484
  const { runLocalShellLine } = createLocalShellRunner({
466
485
  chatLog,
@@ -523,26 +542,12 @@ async function runTui(opts) {
523
542
  tui.requestRender();
524
543
  };
525
544
  const setSessionKey = (key) => {
526
- state.currentSessionKey = key;
527
- };
528
- const clearChatForSessionSwitch = () => {
529
- assembler.clear();
530
- chatLog.clearAll();
531
- clearPendingToolCallIds();
532
- state.historyLoaded = false;
533
- state.messageFollowUpQueue.length = 0;
545
+ state.currentSessionKey = resolveSessionKey(key);
546
+ updateAgentFromPicker(key);
534
547
  };
535
- const loadSessionHistory = async () => {
536
- try {
537
- const { messages } = await client.loadHistory({
538
- sessionKey: state.currentSessionKey,
539
- limit: 200
540
- });
541
- appendHistoryToChatLog(chatLog, messages, state.toolsExpanded);
542
- } catch {} finally {
543
- state.historyLoaded = true;
544
- tui.requestRender();
545
- }
548
+ const updateAgentFromPicker = (key) => {
549
+ const parsed = parseAgentSessionKey(resolveSessionKey(key));
550
+ if (parsed?.agentId) currentAgentId = parsed.agentId;
546
551
  };
547
552
  let ctrlCHandling = false;
548
553
  const handleCtrlC = () => {
@@ -685,7 +690,7 @@ async function runTui(opts) {
685
690
  chatLog.addSystem("⚠️ No stream activity for 30s; UI reset (connection may have stalled). Retry or check gateway.");
686
691
  state.activeRunId = null;
687
692
  setActivityStatus("idle");
688
- refreshSessionInfo().finally(() => {
693
+ refreshSessionInfoWithBorder().finally(() => {
689
694
  updateFooter();
690
695
  tui.requestRender();
691
696
  });
@@ -694,7 +699,7 @@ async function runTui(opts) {
694
699
  }, 5e3);
695
700
  const onAgentRunEnded = () => {
696
701
  state.progressMessage = null;
697
- refreshSessionInfo().finally(() => {
702
+ refreshSessionInfoWithBorder().finally(() => {
698
703
  updateFooter();
699
704
  tui.requestRender();
700
705
  });
@@ -709,7 +714,7 @@ async function runTui(opts) {
709
714
  setConnectionStatus(isLocalMode ? "local ready" : "gateway connected");
710
715
  touchStreamingActivity();
711
716
  (async () => {
712
- await refreshSessionInfo();
717
+ await refreshSessionInfoWithBorder();
713
718
  await refreshModelChoices();
714
719
  await loadSessionHistory();
715
720
  updateHeader();
@@ -1 +1 @@
1
- {"version":3,"file":"tui.js","names":["packageJson.version"],"sources":["../../../src/tui/tui.ts"],"sourcesContent":["import {\n Container,\n Loader,\n ProcessTerminal,\n setKeybindings,\n TUI,\n} from '@earendil-works/pi-tui';\nimport { mkdtempSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { spawnSync } from 'node:child_process';\n\nimport type { ThinkLevel } from '../agent/transcript/thinking-types.js';\nimport type { TuiBackend, TuiEvent, TuiModelChoice } from './tui-backend.js';\nimport { EmbeddedBackend } from './backends/embedded-backend.js';\nimport { GatewaySseBackend } from './backends/gateway-sse-backend.js';\nimport {\n clearPendingToolCallIds,\n DEFAULT_STREAMING_WATCHDOG_MS,\n dispatchAgentSSE,\n} from './tui-agent-events.js';\nimport { ChatLog } from './components/chat-log.js';\nimport { CustomEditor } from './components/custom-editor.js';\nimport { TuiBottomBar } from './components/tui-bottom-bar.js';\nimport { TuiHeader } from './components/tui-header.js';\nimport { StreamAssembler } from './stream-assembler.js';\nimport { createTuiCommandHandler, getSlashCommands } from './tui-commands.js';\nimport { createLocalShellRunner } from './tui-local-shell.js';\nimport {\n createBackspaceDeduper,\n drainAndStopTuiSafely,\n resolveCtrlCAction,\n} from './tui-lifecycle.js';\nimport {\n openModelPickerOverlay,\n openScopedModelsOverlay,\n openSessionPickerOverlay,\n openSettingsOverlay,\n} from './tui-picker-overlay.js';\nimport { createOverlayHandlers } from './tui-overlays.js';\nimport {\n createEditorSubmitHandler,\n createSubmitBurstCoalescer,\n shouldEnableWindowsGitBashPasteFallback,\n} from './tui-submit.js';\nimport { appendHistoryToChatLog } from './chat-history.js';\nimport { installTuiStdioFilter } from './tui-stdio-filter.js';\nimport { withTuiSuspended } from './tui-suspend.js';\nimport { saveClipboardImageToTempFile } from './clipboard-image.js';\nimport {\n applyThemeById,\n getBashExcludeBorderColor,\n getBashModeBorderColor,\n getThinkingBorderColor,\n initTuiTheme,\n} from './theme-manager.js';\nimport { editorTheme, theme } from './theme.js';\nimport { loadTuiSettings, saveTuiSettings, type TuiSettings } from './tui-settings.js';\nimport { resolveFdPath } from './tui-fd-path.js';\nimport packageJson from '../../package.json' with { type: 'json' };\nimport { createInitialState, type TuiOptions, type TuiResult, type TuiState } from './tui-types.js';\nimport { createXopcTuiKeybindingsManager } from './tui-keybindings-file.js';\nimport {\n filterModelsForCycle,\n loadScopedModelRefs,\n saveScopedModelRefs,\n} from './tui-scoped-models.js';\nimport { loadExtensionsForTuiLocalMode } from './extension-host/load-extensions.js';\nimport { createTuiExtensionRuntime } from './extension-host/runtime.js';\nimport type { ExtensionRegistryImpl } from '../extensions/loader.js';\n\nexport type { TuiOptions, TuiResult };\n\nexport {\n createBackspaceDeduper,\n drainAndStopTuiSafely,\n type DrainableTui,\n isIgnorableTuiStopError,\n resolveCtrlCAction,\n stopTuiSafely,\n} from './tui-lifecycle.js';\n\nexport { withTuiSuspended } from './tui-suspend.js';\n\nconst THINK_LEVEL_CYCLE: ThinkLevel[] = [\n 'off',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n 'adaptive',\n];\n\nfunction nextThinkLevel(current: string | undefined): ThinkLevel {\n const c = (current ?? 'medium').toLowerCase();\n const idx = THINK_LEVEL_CYCLE.indexOf(c as ThinkLevel);\n const mediumIdx = THINK_LEVEL_CYCLE.indexOf('medium');\n const base = idx >= 0 ? idx : mediumIdx >= 0 ? mediumIdx : 0;\n return THINK_LEVEL_CYCLE[(base + 1) % THINK_LEVEL_CYCLE.length]!;\n}\n\nconst DOUBLE_ESCAPE_WINDOW_MS = 500;\n\nexport async function runTui(opts: TuiOptions): Promise<TuiResult> {\n const stdioFilter = installTuiStdioFilter();\n const restoreStdio = () => stdioFilter.restore();\n\n const isLocalMode = opts.local === true;\n const sessionKey = opts.session ?? 'cli:tui';\n let tuiSettings = loadTuiSettings();\n initTuiTheme({ themeId: opts.theme ?? tuiSettings.theme });\n const state = createInitialState(sessionKey);\n state.scopedModelRefs = loadScopedModelRefs();\n state.showThinking = tuiSettings.showThinking;\n state.toolsExpanded = tuiSettings.toolsExpanded;\n const assembler = new StreamAssembler();\n\n let extensionRegistry: ExtensionRegistryImpl | undefined;\n if (isLocalMode) {\n extensionRegistry = await loadExtensionsForTuiLocalMode();\n }\n\n const client: TuiBackend = isLocalMode\n ? new EmbeddedBackend({ extensionRegistry })\n : new GatewaySseBackend({ url: opts.url ?? 'http://localhost:3120', token: opts.token });\n\n const keybindings = createXopcTuiKeybindingsManager();\n setKeybindings(keybindings);\n\n let modelChoices: TuiModelChoice[] = [];\n const cycleModelChoices = (): TuiModelChoice[] =>\n filterModelsForCycle(modelChoices, state.scopedModelRefs);\n\n const refreshCycleModels = () => {\n bottomBar.invalidate();\n tui.requestRender();\n };\n\n const tui = new TUI(new ProcessTerminal());\n const dedupeBackspace = createBackspaceDeduper();\n tui.addInputListener((data) => {\n const next = dedupeBackspace(data);\n if (next.length === 0) {\n return { consume: true };\n }\n return { data: next };\n });\n\n const header = new TuiHeader(() => ({\n version: packageJson.version ?? 'dev',\n connectionLabel: client.connectionLabel,\n sessionKey: state.currentSessionKey,\n showHints: tuiSettings.showStartupHints,\n }));\n const statusContainer = new Container();\n const bottomBar = new TuiBottomBar(() => state, () => opts.thinking);\n const chatLog = new ChatLog();\n chatLog.setToolsExpanded(state.toolsExpanded);\n const editor = new CustomEditor(tui, editorTheme, keybindings);\n const root = new Container();\n root.addChild(header);\n root.addChild(chatLog);\n root.addChild(statusContainer);\n root.addChild(editor);\n root.addChild(bottomBar);\n tui.addChild(root);\n tui.setFocus(editor);\n\n let isBashMode = false;\n let isBashExcludeContext = false;\n\n const updateEditorBorderColor = () => {\n if (isBashMode) {\n editor.borderColor = isBashExcludeContext\n ? getBashExcludeBorderColor()\n : getBashModeBorderColor();\n } else {\n const level = state.sessionInfo.thinkingLevel ?? opts.thinking ?? 'off';\n editor.borderColor = getThinkingBorderColor(level);\n }\n tui.requestRender();\n };\n\n editor.onChange = (text: string) => {\n const trimmed = text.trimStart();\n const nextExclude = trimmed.startsWith('!!');\n const nextBash = trimmed.startsWith('!');\n if (nextBash !== isBashMode || nextExclude !== isBashExcludeContext) {\n isBashMode = nextBash;\n isBashExcludeContext = nextExclude;\n updateEditorBorderColor();\n }\n };\n\n const { openOverlay, closeOverlay } = createOverlayHandlers(tui, editor);\n\n const slashCommands = getSlashCommands(isLocalMode);\n\n const extensionRuntime = createTuiExtensionRuntime({\n registry: extensionRegistry,\n tui,\n chatLog,\n header,\n bottomBar,\n getState: () => state,\n baseSlashCommands: slashCommands,\n cwd: process.cwd(),\n fdPath: resolveFdPath(),\n openOverlay,\n closeOverlay,\n onInvalidate: () => {\n updateHeader();\n updateFooter();\n tui.requestRender();\n },\n });\n\n editor.setAutocompleteProvider(extensionRuntime.autocompleteProvider);\n\n let statusLoader: Loader | null = null;\n let statusStartedAt: number | null = null;\n let lastActivityStatus = '';\n let elapsedTimerId: ReturnType<typeof setInterval> | null = null;\n const busyStates = new Set(['sending', 'waiting', 'streaming', 'running', 'compacting']);\n\n const syncTerminalProgress = () => {\n if (!tuiSettings.showTerminalProgress) {\n tui.terminal.setProgress(false);\n return;\n }\n tui.terminal.setProgress(busyStates.has(state.activityStatus));\n };\n\n let lastStreamActivityAt = Date.now();\n let streamWatchdogId: ReturnType<typeof setInterval> | null = null;\n\n const touchStreamingActivity = () => {\n lastStreamActivityAt = Date.now();\n };\n\n const formatElapsed = (startMs: number) => {\n const totalSeconds = Math.max(0, Math.floor((Date.now() - startMs) / 1000));\n if (totalSeconds < 60) return `${totalSeconds}s`;\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return `${minutes}m ${seconds}s`;\n };\n\n const renderStatus = () => {\n const isBusy = busyStates.has(state.activityStatus);\n if (isBusy) {\n if (!statusStartedAt || lastActivityStatus !== state.activityStatus) {\n statusStartedAt = Date.now();\n }\n if (!statusLoader) {\n statusContainer.clear();\n statusLoader = new Loader(\n tui,\n (spinner) => theme.accent(spinner),\n (text) => theme.bold(theme.accentSoft(text)),\n '',\n );\n statusContainer.addChild(statusLoader);\n }\n const elapsed = formatElapsed(statusStartedAt);\n statusLoader.setMessage(\n `${state.progressMessage ?? state.activityStatus} • ${elapsed} | ${state.connectionStatus}`,\n );\n if (!elapsedTimerId) {\n elapsedTimerId = setInterval(() => {\n if (statusStartedAt && statusLoader) {\n const el = formatElapsed(statusStartedAt);\n statusLoader.setMessage(\n `${state.progressMessage ?? state.activityStatus} • ${el} | ${state.connectionStatus}`,\n );\n }\n }, 1000);\n }\n } else {\n state.progressMessage = null;\n statusStartedAt = null;\n if (elapsedTimerId) {\n clearInterval(elapsedTimerId);\n elapsedTimerId = null;\n }\n statusLoader?.stop();\n statusLoader = null;\n statusContainer.clear();\n }\n lastActivityStatus = state.activityStatus;\n bottomBar.invalidate();\n syncTerminalProgress();\n tui.requestRender();\n };\n\n const setActivityStatus = (status: string) => {\n state.activityStatus = status as TuiState['activityStatus'];\n renderStatus();\n };\n\n const setConnectionStatus = (text: string) => {\n state.connectionStatus = text;\n renderStatus();\n };\n\n const updateHeader = () => {\n header.invalidate();\n syncTerminalTitle();\n };\n\n const syncTerminalTitle = () => {\n const shortKey =\n state.currentSessionKey.length > 48\n ? `${state.currentSessionKey.slice(0, 45)}…`\n : state.currentSessionKey;\n tui.terminal.setTitle(`xopc · ${shortKey}`);\n };\n\n const updateFooter = () => {\n bottomBar.invalidate();\n };\n\n const refreshModelChoices = async () => {\n try {\n modelChoices = await client.listModels();\n } catch {\n modelChoices = [];\n }\n bottomBar.invalidate();\n tui.requestRender();\n };\n\n const refreshSessionInfo = async () => {\n try {\n state.sessionInfo = await client.getSessionInfo(state.currentSessionKey);\n updateEditorBorderColor();\n updateFooter();\n tui.requestRender();\n } catch {\n // ignore\n }\n };\n\n let finishTui: (() => void) | null = null;\n let exitResult: TuiResult = { exitReason: 'exit' };\n\n const requestExit = () => {\n if (state.exitRequested) return;\n state.exitRequested = true;\n if (elapsedTimerId) {\n clearInterval(elapsedTimerId);\n elapsedTimerId = null;\n }\n if (streamWatchdogId) {\n clearInterval(streamWatchdogId);\n streamWatchdogId = null;\n }\n client.stop();\n tui.terminal.setProgress(false);\n void drainAndStopTuiSafely(tui).then(() => {\n restoreStdio();\n finishTui?.();\n process.exit(0);\n });\n };\n\n const abortActive = async () => {\n if (!state.activeRunId) return;\n const runId = state.activeRunId;\n state.activeRunId = null;\n assembler.drop(runId);\n chatLog.dropAssistant(runId);\n setActivityStatus('idle');\n tui.requestRender();\n await client.abortChat({ sessionKey: state.currentSessionKey, runId }).catch(() => {});\n };\n\n const resolveModelChoiceIndex = (): number => {\n const choices = cycleModelChoices();\n if (choices.length === 0) return -1;\n const p = state.sessionInfo.modelProvider;\n const m = state.sessionInfo.model;\n if (p && m) {\n const byParts = choices.findIndex((x) => x.provider === p && x.id === m);\n if (byParts >= 0) return byParts;\n }\n if (m?.includes('/')) {\n const [a, b] = m.split('/', 2);\n const bySlash = choices.findIndex((x) => x.provider === a && x.id === b);\n if (bySlash >= 0) return bySlash;\n }\n return 0;\n };\n\n const cycleModel = (dir: 'forward' | 'backward') => {\n const choices = cycleModelChoices();\n if (choices.length === 0) {\n void refreshModelChoices().then(() => {\n if (cycleModelChoices().length === 0) {\n chatLog.addSystem('No models available to cycle.');\n tui.requestRender();\n return;\n }\n cycleModel(dir);\n });\n return;\n }\n const idx = resolveModelChoiceIndex();\n const base = idx >= 0 ? idx : 0;\n const delta = dir === 'forward' ? 1 : -1;\n const next = choices[(base + delta + choices.length) % choices.length]!;\n sendMessage(`/switch ${next.provider}/${next.id}`);\n };\n\n const handleCtrlZ = () => {\n if (process.platform === 'win32') {\n chatLog.addSystem('Suspend (Ctrl+Z) is not supported on Windows.');\n tui.requestRender();\n return;\n }\n const suspendKeepAlive = setInterval(() => {}, 2 ** 30);\n const ignoreSigint = () => {};\n process.on('SIGINT', ignoreSigint);\n process.once('SIGCONT', () => {\n clearInterval(suspendKeepAlive);\n process.removeListener('SIGINT', ignoreSigint);\n tui.start();\n tui.setFocus(editor);\n tui.requestRender(true);\n });\n try {\n tui.stop();\n process.kill(0, 'SIGTSTP');\n } catch {\n clearInterval(suspendKeepAlive);\n process.removeListener('SIGINT', ignoreSigint);\n }\n };\n\n const openExternalEditor = () => {\n const dir = mkdtempSync(join(tmpdir(), 'xopc-tui-edit-'));\n const filePath = join(dir, 'message.md');\n writeFileSync(filePath, editor.getText(), 'utf8');\n const editorBin = process.env.EDITOR || process.env.VISUAL || 'vi';\n void (async () => {\n await withTuiSuspended(tui, async () => {\n spawnSync(editorBin, [filePath], { stdio: 'inherit' });\n });\n try {\n const next = readFileSync(filePath, 'utf8');\n editor.setText(next.replace(/\\r\\n/g, '\\n'));\n } catch {\n // ignore\n }\n try {\n unlinkSync(filePath);\n } catch {\n // ignore\n }\n tui.setFocus(editor);\n tui.requestRender(true);\n })();\n };\n\n const isAgentBusy = () =>\n state.activeRunId != null || state.isCompacting || busyStates.has(state.activityStatus);\n\n const steerMessage = (text: string) => {\n chatLog.addUser(text);\n touchStreamingActivity();\n tui.requestRender();\n void client\n .steerChat({ sessionKey: state.currentSessionKey, message: text })\n .then(({ ok }) => {\n if (!ok) {\n chatLog.addSystem(\n theme.dim(\n 'Could not steer — no active run or steer failed. Press Escape to abort, or Alt+Enter to queue a follow-up.',\n ),\n );\n } else {\n chatLog.addSystem(\n theme.dim('Steered — message injects at the next tool boundary (pi-style).'),\n );\n }\n tui.requestRender();\n })\n .catch((error: unknown) => {\n const errorMessage = error instanceof Error ? error.message : String(error);\n chatLog.addSystem(theme.dim(`Steer failed: ${errorMessage}`));\n tui.requestRender();\n });\n };\n\n const sendMessage = (text: string) => {\n if (state.isCompacting) {\n state.compactionQueue.push(text);\n chatLog.addSystem(\n theme.dim(`Queued during compaction (${state.compactionQueue.length}). Sends when compact finishes.`),\n );\n bottomBar.invalidate();\n tui.requestRender();\n return;\n }\n\n if (state.activeRunId) {\n chatLog.addSystem(\n 'A response is still in progress. Press Enter to steer, Alt+Enter to queue, or Escape to abort.',\n );\n tui.requestRender();\n return;\n }\n\n chatLog.addUser(text);\n setActivityStatus('sending');\n touchStreamingActivity();\n tui.requestRender();\n\n void client\n .sendChat({\n sessionKey: state.currentSessionKey,\n message: text,\n thinking: opts.thinking,\n })\n .catch((error: unknown) => {\n const errorMessage = error instanceof Error ? error.message : String(error);\n chatLog.addSystem(`❌ Failed to send: ${errorMessage}`);\n setActivityStatus('idle');\n tui.requestRender();\n });\n };\n\n const runCompaction = async () => {\n if (state.isCompacting) return;\n state.isCompacting = true;\n setActivityStatus('compacting');\n chatLog.addSystem(theme.dim('Compacting session…'));\n tui.requestRender();\n try {\n const result = await client.compactSession(state.currentSessionKey, { force: true });\n chatLog.addSystem(result.summary ?? (result.compacted ? 'Session compacted' : 'Nothing to compact'));\n if (result.compacted) {\n assembler.clear();\n clearPendingToolCallIds();\n state.historyLoaded = false;\n await loadSessionHistory();\n }\n } catch (error: unknown) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n chatLog.addSystem(`❌ Compaction failed: ${errorMessage}`);\n } finally {\n state.isCompacting = false;\n setActivityStatus('idle');\n await refreshSessionInfo();\n const queued = state.compactionQueue.shift();\n if (queued && !state.activeRunId) {\n sendMessage(queued);\n }\n updateFooter();\n tui.requestRender();\n }\n };\n\n const applyTuiSettings = (settings: TuiSettings) => {\n tuiSettings = { ...settings };\n saveTuiSettings(tuiSettings);\n state.showThinking = tuiSettings.showThinking;\n state.toolsExpanded = tuiSettings.toolsExpanded;\n chatLog.setToolsExpanded(tuiSettings.toolsExpanded);\n applyThemeById(tuiSettings.theme);\n header.invalidate();\n updateEditorBorderColor();\n syncTerminalProgress();\n bottomBar.invalidate();\n tui.requestRender();\n };\n\n const previewTheme = (themeId: string) => {\n applyThemeById(themeId);\n updateEditorBorderColor();\n tui.requestRender();\n };\n\n const reloadKeybindings = () => {\n keybindings.reload();\n setKeybindings(keybindings);\n tui.requestRender();\n };\n\n const uiOverlays = {\n openSessionPicker: () => {},\n openScopedModels: () => {},\n openSettings: () => {},\n reloadKeybindings: () => reloadKeybindings(),\n };\n\n const handleCommand = createTuiCommandHandler({\n state,\n chatLog,\n tui,\n assembler,\n isLocalMode,\n abortActive,\n sendMessage,\n requestExit,\n updateFooter,\n keybindings,\n uiOverlays,\n runCompaction,\n extensionSlashCommands: extensionRuntime.slashCommands,\n });\n\n const { runLocalShellLine } = createLocalShellRunner({\n chatLog,\n tui,\n editor,\n openOverlay,\n closeOverlay,\n pauseStdioFilter: () => stdioFilter.pause(),\n resumeStdioFilter: () => stdioFilter.resume(),\n runWithInheritedStdio: async (work) => {\n await withTuiSuspended(tui, work);\n },\n });\n\n const submitCore = createEditorSubmitHandler({\n editor,\n handleCommand,\n sendMessage,\n handleBangLine: runLocalShellLine,\n isAgentBusy,\n steerWhileBusy: steerMessage,\n });\n\n const submitBurst = createSubmitBurstCoalescer({\n submit: submitCore,\n enabled: shouldEnableWindowsGitBashPasteFallback(),\n });\n editor.onSubmit = submitBurst;\n\n const flushFollowUpQueue = () => {\n if (state.exitRequested) return;\n if (state.activeRunId) return;\n const next = state.messageFollowUpQueue.shift();\n if (next === undefined) return;\n sendMessage(next);\n };\n\n const handleFollowUp = () => {\n const text = editor.getText().trim();\n if (!text) return;\n if (isAgentBusy()) {\n editor.addToHistory(text);\n state.messageFollowUpQueue.push(text);\n editor.setText('');\n chatLog.addSystem(\n theme.dim(\n `Queued follow-up (${state.messageFollowUpQueue.length} in queue). Next sends when this reply finishes.`,\n ),\n );\n bottomBar.invalidate();\n tui.requestRender();\n return;\n }\n submitBurst(text);\n };\n\n const handleDequeue = () => {\n if (state.messageFollowUpQueue.length === 0) {\n chatLog.addSystem(theme.dim('No queued messages to restore.'));\n tui.requestRender();\n return;\n }\n const queued = [...state.messageFollowUpQueue];\n state.messageFollowUpQueue.length = 0;\n const current = editor.getText().trim();\n const combined = [queued.join('\\n\\n'), current].filter(Boolean).join('\\n\\n');\n editor.setText(combined);\n chatLog.addSystem(\n theme.dim(\n `Restored ${queued.length} queued message${queued.length > 1 ? 's' : ''} to editor.`,\n ),\n );\n bottomBar.invalidate();\n tui.requestRender();\n };\n\n const setSessionKey = (key: string) => {\n state.currentSessionKey = key;\n };\n\n const clearChatForSessionSwitch = () => {\n assembler.clear();\n chatLog.clearAll();\n clearPendingToolCallIds();\n state.historyLoaded = false;\n state.messageFollowUpQueue.length = 0;\n };\n\n const loadSessionHistory = async () => {\n try {\n const { messages } = await client.loadHistory({\n sessionKey: state.currentSessionKey,\n limit: 200,\n });\n appendHistoryToChatLog(chatLog, messages, state.toolsExpanded);\n } catch {\n // ignore; footer already hints on disconnect\n } finally {\n state.historyLoaded = true;\n tui.requestRender();\n }\n };\n\n let ctrlCHandling = false;\n const handleCtrlC = () => {\n if (ctrlCHandling) return;\n ctrlCHandling = true;\n try {\n const now = Date.now();\n const decision = resolveCtrlCAction({\n hasInput: editor.getText().trim().length > 0,\n now,\n lastCtrlCAt: state.lastCtrlCAt,\n });\n state.lastCtrlCAt = decision.nextLastCtrlCAt;\n if (decision.action === 'clear') {\n editor.setText('');\n setActivityStatus('cleared input; press ctrl+c again to exit');\n tui.requestRender();\n return;\n }\n if (decision.action === 'exit') {\n requestExit();\n return;\n }\n setActivityStatus('press ctrl+c again to exit');\n tui.requestRender();\n } finally {\n ctrlCHandling = false;\n }\n };\n\n const setModelChoices = (models: TuiModelChoice[]) => {\n modelChoices = models;\n };\n\n const pickerSvc = {\n tui,\n editor,\n openOverlay,\n closeOverlay,\n chatLog,\n client,\n sendMessage,\n refreshSessionInfo,\n updateHeader,\n state,\n setSessionKey,\n clearChatForSessionSwitch,\n loadSessionHistory,\n setModelChoices,\n getScopedModelRefs: () => state.scopedModelRefs,\n setScopedModelRefs: (refs: string[] | null) => {\n state.scopedModelRefs = refs;\n saveScopedModelRefs(refs);\n },\n refreshCycleModels,\n getTuiSettings: () => ({ ...tuiSettings }),\n applyTuiSettings,\n previewTheme,\n reloadKeybindings,\n };\n\n uiOverlays.openSessionPicker = () => void openSessionPickerOverlay(pickerSvc);\n uiOverlays.openScopedModels = () => void openScopedModelsOverlay(pickerSvc);\n uiOverlays.openSettings = () => openSettingsOverlay(pickerSvc);\n\n const handleDoubleEscape = () => {\n switch (tuiSettings.doubleEscapeAction) {\n case 'tree':\n chatLog.addSystem(theme.dim('Session tree is not available in xopc TUI yet.'));\n break;\n case 'fork':\n chatLog.addSystem(theme.dim('Session fork is not available in xopc TUI yet.'));\n break;\n default:\n break;\n }\n tui.requestRender();\n };\n\n editor.onEscape = () => {\n if (state.activeRunId) {\n void abortActive();\n return;\n }\n if (editor.getText().trim().length > 0) return;\n const now = Date.now();\n if (now - state.lastEscapeAt <= DOUBLE_ESCAPE_WINDOW_MS) {\n state.lastEscapeAt = 0;\n handleDoubleEscape();\n return;\n }\n state.lastEscapeAt = now;\n };\n editor.onCtrlD = () => requestExit();\n\n editor.onAction('app.clear', handleCtrlC);\n editor.onAction('app.exit', () => requestExit());\n editor.onAction('app.suspend', handleCtrlZ);\n editor.onAction('app.thinking.cycle', () => {\n const cur = state.sessionInfo.thinkingLevel ?? opts.thinking ?? 'medium';\n sendMessage(`/think ${nextThinkLevel(cur)}`);\n updateEditorBorderColor();\n });\n editor.onAction('app.model.cycleForward', () => cycleModel('forward'));\n editor.onAction('app.model.cycleBackward', () => cycleModel('backward'));\n editor.onAction('app.model.select', () => void openModelPickerOverlay(pickerSvc));\n editor.onAction('app.session.resume', () => void openSessionPickerOverlay(pickerSvc));\n editor.onAction('app.tools.expand', () => {\n state.toolsExpanded = !state.toolsExpanded;\n tuiSettings = { ...tuiSettings, toolsExpanded: state.toolsExpanded };\n saveTuiSettings(tuiSettings);\n chatLog.setToolsExpanded(state.toolsExpanded);\n setActivityStatus(state.toolsExpanded ? 'tools expanded' : 'tools collapsed');\n tui.requestRender();\n });\n editor.onAction('app.thinking.toggle', () => {\n state.showThinking = !state.showThinking;\n tuiSettings = { ...tuiSettings, showThinking: state.showThinking };\n saveTuiSettings(tuiSettings);\n updateFooter();\n tui.requestRender();\n });\n editor.onAction('app.editor.external', openExternalEditor);\n editor.onPasteImage = () => {\n void (async () => {\n const filePath = await saveClipboardImageToTempFile();\n if (!filePath) return;\n editor.insertTextAtCursor(filePath);\n chatLog.addSystem(theme.dim(`Pasted image path: ${filePath}`));\n tui.requestRender();\n })();\n };\n editor.onAction('app.message.followUp', handleFollowUp);\n editor.onAction('app.message.dequeue', handleDequeue);\n\n streamWatchdogId = setInterval(() => {\n if (!state.activeRunId) return;\n if (!busyStates.has(state.activityStatus)) return;\n if (Date.now() - lastStreamActivityAt < DEFAULT_STREAMING_WATCHDOG_MS) return;\n\n const rid = state.activeRunId;\n const finalText = assembler.finalize(rid, state.showThinking);\n if (finalText) {\n chatLog.finalizeAssistant(finalText, rid);\n }\n chatLog.addSystem(\n '⚠️ No stream activity for 30s; UI reset (connection may have stalled). Retry or check gateway.',\n );\n state.activeRunId = null;\n setActivityStatus('idle');\n void refreshSessionInfo().finally(() => {\n updateFooter();\n tui.requestRender();\n });\n flushFollowUpQueue();\n tui.requestRender();\n }, 5000);\n\n const onAgentRunEnded = () => {\n state.progressMessage = null;\n void refreshSessionInfo().finally(() => {\n updateFooter();\n tui.requestRender();\n });\n flushFollowUpQueue();\n };\n\n client.onEvent = (evt: TuiEvent) => {\n const data = (evt.data ?? {}) as Record<string, unknown>;\n dispatchAgentSSE(\n evt.event,\n data,\n state,\n chatLog,\n assembler,\n tui,\n setActivityStatus,\n touchStreamingActivity,\n onAgentRunEnded,\n );\n };\n\n client.onConnected = () => {\n state.isConnected = true;\n setConnectionStatus(isLocalMode ? 'local ready' : 'gateway connected');\n touchStreamingActivity();\n void (async () => {\n await refreshSessionInfo();\n await refreshModelChoices();\n await loadSessionHistory();\n updateHeader();\n updateFooter();\n tui.requestRender();\n if (!state.autoMessageSent && opts.message) {\n state.autoMessageSent = true;\n sendMessage(opts.message);\n }\n })();\n };\n\n client.onDisconnected = (reason: string) => {\n const wasConnected = state.isConnected;\n state.isConnected = false;\n touchStreamingActivity();\n if (isLocalMode) {\n setConnectionStatus(`local stopped: ${reason}`);\n } else {\n const hint =\n wasConnected || state.historyLoaded\n ? ` (${reason}). Reconnecting broadcast stream…`\n : `. Ensure gateway is running (xopc gateway) or use --local.`;\n setConnectionStatus(`disconnected${hint}`);\n if (!wasConnected && !state.historyLoaded) {\n const gatewayUrl = opts.url ?? 'http://localhost:3120';\n chatLog.addSystem(\n `Cannot reach gateway at ${gatewayUrl}.\\n` +\n 'Start the gateway (`xopc gateway`) or run `xopc tui --local` for embedded mode.',\n );\n }\n }\n tui.requestRender();\n };\n\n client.onGap = (info) => {\n chatLog.addSystem(\n `⚠️ Event gap: expected ${info.expected}, received ${info.received}. Some updates may be missing.`,\n );\n setConnectionStatus(`event gap: expected ${info.expected}, got ${info.received}`);\n tui.requestRender();\n };\n\n const sigintHandler = () => handleCtrlC();\n const sigtermHandler = () => requestExit();\n process.on('SIGINT', sigintHandler);\n process.on('SIGTERM', sigtermHandler);\n\n updateHeader();\n updateEditorBorderColor();\n setConnectionStatus(isLocalMode ? 'starting local runtime' : 'connecting');\n updateFooter();\n await extensionRuntime.activate();\n tui.start();\n client.start();\n\n await new Promise<void>((resolve) => {\n finishTui = () => {\n process.removeListener('SIGINT', sigintHandler);\n process.removeListener('SIGTERM', sigtermHandler);\n if (streamWatchdogId) {\n clearInterval(streamWatchdogId);\n streamWatchdogId = null;\n }\n finishTui = null;\n resolve();\n };\n });\n\n return exitResult;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tui.js","names":["packageJson.version"],"sources":["../../../src/tui/tui.ts"],"sourcesContent":["import {\n Container,\n Loader,\n ProcessTerminal,\n setKeybindings,\n TUI,\n} from '@earendil-works/pi-tui';\nimport { mkdtempSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { spawnSync } from 'node:child_process';\n\nimport type { ThinkLevel } from '../agent/transcript/thinking-types.js';\nimport { loadConfig } from '../config/index.js';\nimport { resolveTuiSessionKey, resolveTuiStartupSessionKey } from '../routing/resolve-tui-session-key.js';\nimport { parseAgentSessionKey } from '../routing/agent-session-key.js';\nimport type { TuiBackend, TuiEvent, TuiModelChoice } from './tui-backend.js';\nimport { EmbeddedBackend } from './backends/embedded-backend.js';\nimport { GatewaySseBackend } from './backends/gateway-sse-backend.js';\nimport {\n clearPendingToolCallIds,\n DEFAULT_STREAMING_WATCHDOG_MS,\n dispatchAgentSSE,\n} from './tui-agent-events.js';\nimport { ChatLog } from './components/chat-log.js';\nimport { CustomEditor } from './components/custom-editor.js';\nimport { TuiBottomBar } from './components/tui-bottom-bar.js';\nimport { TuiHeader } from './components/tui-header.js';\nimport { StreamAssembler } from './stream-assembler.js';\nimport { createTuiCommandHandler, getSlashCommands } from './tui-commands.js';\nimport { createLocalShellRunner } from './tui-local-shell.js';\nimport {\n createBackspaceDeduper,\n drainAndStopTuiSafely,\n resolveCtrlCAction,\n} from './tui-lifecycle.js';\nimport {\n openModelPickerOverlay,\n openScopedModelsOverlay,\n openSessionPickerOverlay,\n openSettingsOverlay,\n} from './tui-picker-overlay.js';\nimport { createOverlayHandlers } from './tui-overlays.js';\nimport {\n createEditorSubmitHandler,\n createSubmitBurstCoalescer,\n shouldEnableWindowsGitBashPasteFallback,\n} from './tui-submit.js';\nimport { installTuiStdioFilter } from './tui-stdio-filter.js';\nimport { withTuiSuspended } from './tui-suspend.js';\nimport { saveClipboardImageToTempFile } from './clipboard-image.js';\nimport {\n applyThemeById,\n getBashExcludeBorderColor,\n getBashModeBorderColor,\n getThinkingBorderColor,\n initTuiTheme,\n} from './theme-manager.js';\nimport { editorTheme, theme } from './theme.js';\nimport { loadTuiSettings, saveTuiSettings, type TuiSettings } from './tui-settings.js';\nimport { resolveFdPath } from './tui-fd-path.js';\nimport packageJson from '../../package.json' with { type: 'json' };\nimport { createSessionActions } from './tui-session-actions.js';\nimport { createInitialState, type TuiOptions, type TuiResult, type TuiState } from './tui-types.js';\nimport { createXopcTuiKeybindingsManager } from './tui-keybindings-file.js';\nimport {\n filterModelsForCycle,\n loadScopedModelRefs,\n saveScopedModelRefs,\n} from './tui-scoped-models.js';\nimport { loadExtensionsForTuiLocalMode } from './extension-host/load-extensions.js';\nimport { createTuiExtensionRuntime } from './extension-host/runtime.js';\nimport type { ExtensionRegistryImpl } from '../extensions/loader.js';\n\nexport type { TuiOptions, TuiResult };\n\nexport {\n createBackspaceDeduper,\n drainAndStopTuiSafely,\n type DrainableTui,\n isIgnorableTuiStopError,\n resolveCtrlCAction,\n stopTuiSafely,\n} from './tui-lifecycle.js';\n\nexport { withTuiSuspended } from './tui-suspend.js';\n\nconst THINK_LEVEL_CYCLE: ThinkLevel[] = [\n 'off',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n 'adaptive',\n];\n\nfunction nextThinkLevel(current: string | undefined): ThinkLevel {\n const c = (current ?? 'medium').toLowerCase();\n const idx = THINK_LEVEL_CYCLE.indexOf(c as ThinkLevel);\n const mediumIdx = THINK_LEVEL_CYCLE.indexOf('medium');\n const base = idx >= 0 ? idx : mediumIdx >= 0 ? mediumIdx : 0;\n return THINK_LEVEL_CYCLE[(base + 1) % THINK_LEVEL_CYCLE.length]!;\n}\n\nconst DOUBLE_ESCAPE_WINDOW_MS = 500;\n\nexport async function runTui(opts: TuiOptions): Promise<TuiResult> {\n const stdioFilter = installTuiStdioFilter();\n const restoreStdio = () => stdioFilter.restore();\n\n const isLocalMode = opts.local === true;\n const config = loadConfig();\n const startup = resolveTuiStartupSessionKey({\n cfg: config,\n sessionOption: opts.session,\n cwd: process.cwd(),\n });\n let currentAgentId = startup.agentId;\n const sessionScope = startup.sessionScope;\n const sessionMainKey = startup.sessionMainKey;\n const resolveSessionKey = (raw?: string) =>\n resolveTuiSessionKey({\n raw,\n sessionScope,\n currentAgentId,\n sessionMainKey,\n });\n let tuiSettings = loadTuiSettings();\n initTuiTheme({ themeId: opts.theme ?? tuiSettings.theme });\n const state = createInitialState(startup.sessionKey);\n state.scopedModelRefs = loadScopedModelRefs();\n state.showThinking = tuiSettings.showThinking;\n state.toolsExpanded = tuiSettings.toolsExpanded;\n const assembler = new StreamAssembler();\n\n let extensionRegistry: ExtensionRegistryImpl | undefined;\n if (isLocalMode) {\n extensionRegistry = await loadExtensionsForTuiLocalMode();\n }\n\n const client: TuiBackend = isLocalMode\n ? new EmbeddedBackend({ extensionRegistry })\n : new GatewaySseBackend({ url: opts.url ?? 'http://localhost:3120', token: opts.token });\n\n const keybindings = createXopcTuiKeybindingsManager();\n setKeybindings(keybindings);\n\n let modelChoices: TuiModelChoice[] = [];\n const cycleModelChoices = (): TuiModelChoice[] =>\n filterModelsForCycle(modelChoices, state.scopedModelRefs);\n\n const refreshCycleModels = () => {\n bottomBar.invalidate();\n tui.requestRender();\n };\n\n const tui = new TUI(new ProcessTerminal());\n const dedupeBackspace = createBackspaceDeduper();\n tui.addInputListener((data) => {\n const next = dedupeBackspace(data);\n if (next.length === 0) {\n return { consume: true };\n }\n return { data: next };\n });\n\n const header = new TuiHeader(() => ({\n version: packageJson.version ?? 'dev',\n connectionLabel: client.connectionLabel,\n sessionKey: state.currentSessionKey,\n showHints: tuiSettings.showStartupHints,\n }));\n const statusContainer = new Container();\n const bottomBar = new TuiBottomBar(() => state, () => opts.thinking);\n const chatLog = new ChatLog();\n chatLog.setToolsExpanded(state.toolsExpanded);\n const editor = new CustomEditor(tui, editorTheme, keybindings);\n const root = new Container();\n root.addChild(header);\n root.addChild(chatLog);\n root.addChild(statusContainer);\n root.addChild(editor);\n root.addChild(bottomBar);\n tui.addChild(root);\n tui.setFocus(editor);\n\n let isBashMode = false;\n let isBashExcludeContext = false;\n\n const updateEditorBorderColor = () => {\n if (isBashMode) {\n editor.borderColor = isBashExcludeContext\n ? getBashExcludeBorderColor()\n : getBashModeBorderColor();\n } else {\n const level = state.sessionInfo.thinkingLevel ?? opts.thinking ?? 'off';\n editor.borderColor = getThinkingBorderColor(level);\n }\n tui.requestRender();\n };\n\n editor.onChange = (text: string) => {\n const trimmed = text.trimStart();\n const nextExclude = trimmed.startsWith('!!');\n const nextBash = trimmed.startsWith('!');\n if (nextBash !== isBashMode || nextExclude !== isBashExcludeContext) {\n isBashMode = nextBash;\n isBashExcludeContext = nextExclude;\n updateEditorBorderColor();\n }\n };\n\n const { openOverlay, closeOverlay } = createOverlayHandlers(tui, editor);\n\n const slashCommands = getSlashCommands(isLocalMode);\n\n const extensionRuntime = createTuiExtensionRuntime({\n registry: extensionRegistry,\n tui,\n chatLog,\n header,\n bottomBar,\n getState: () => state,\n baseSlashCommands: slashCommands,\n cwd: process.cwd(),\n fdPath: resolveFdPath(),\n openOverlay,\n closeOverlay,\n onInvalidate: () => {\n updateHeader();\n updateFooter();\n tui.requestRender();\n },\n });\n\n editor.setAutocompleteProvider(extensionRuntime.autocompleteProvider);\n\n let statusLoader: Loader | null = null;\n let statusStartedAt: number | null = null;\n let lastActivityStatus = '';\n let elapsedTimerId: ReturnType<typeof setInterval> | null = null;\n const busyStates = new Set(['sending', 'waiting', 'streaming', 'running', 'compacting']);\n\n const syncTerminalProgress = () => {\n if (!tuiSettings.showTerminalProgress) {\n tui.terminal.setProgress(false);\n return;\n }\n tui.terminal.setProgress(busyStates.has(state.activityStatus));\n };\n\n let lastStreamActivityAt = Date.now();\n let streamWatchdogId: ReturnType<typeof setInterval> | null = null;\n\n const touchStreamingActivity = () => {\n lastStreamActivityAt = Date.now();\n };\n\n const formatElapsed = (startMs: number) => {\n const totalSeconds = Math.max(0, Math.floor((Date.now() - startMs) / 1000));\n if (totalSeconds < 60) return `${totalSeconds}s`;\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return `${minutes}m ${seconds}s`;\n };\n\n const renderStatus = () => {\n const isBusy = busyStates.has(state.activityStatus);\n if (isBusy) {\n if (!statusStartedAt || lastActivityStatus !== state.activityStatus) {\n statusStartedAt = Date.now();\n }\n if (!statusLoader) {\n statusContainer.clear();\n statusLoader = new Loader(\n tui,\n (spinner) => theme.accent(spinner),\n (text) => theme.bold(theme.accentSoft(text)),\n '',\n );\n statusContainer.addChild(statusLoader);\n }\n const elapsed = formatElapsed(statusStartedAt);\n statusLoader.setMessage(\n `${state.progressMessage ?? state.activityStatus} • ${elapsed} | ${state.connectionStatus}`,\n );\n if (!elapsedTimerId) {\n elapsedTimerId = setInterval(() => {\n if (statusStartedAt && statusLoader) {\n const el = formatElapsed(statusStartedAt);\n statusLoader.setMessage(\n `${state.progressMessage ?? state.activityStatus} • ${el} | ${state.connectionStatus}`,\n );\n }\n }, 1000);\n }\n } else {\n state.progressMessage = null;\n statusStartedAt = null;\n if (elapsedTimerId) {\n clearInterval(elapsedTimerId);\n elapsedTimerId = null;\n }\n statusLoader?.stop();\n statusLoader = null;\n statusContainer.clear();\n }\n lastActivityStatus = state.activityStatus;\n bottomBar.invalidate();\n syncTerminalProgress();\n tui.requestRender();\n };\n\n const setActivityStatus = (status: string) => {\n state.activityStatus = status as TuiState['activityStatus'];\n renderStatus();\n };\n\n const setConnectionStatus = (text: string) => {\n state.connectionStatus = text;\n renderStatus();\n };\n\n const updateHeader = () => {\n header.invalidate();\n syncTerminalTitle();\n };\n\n const syncTerminalTitle = () => {\n const shortKey =\n state.currentSessionKey.length > 48\n ? `${state.currentSessionKey.slice(0, 45)}…`\n : state.currentSessionKey;\n tui.terminal.setTitle(`xopc · ${shortKey}`);\n };\n\n const updateFooter = () => {\n bottomBar.invalidate();\n };\n\n const refreshModelChoices = async () => {\n try {\n modelChoices = await client.listModels();\n } catch {\n modelChoices = [];\n }\n bottomBar.invalidate();\n tui.requestRender();\n };\n\n let finishTui: (() => void) | null = null;\n let exitResult: TuiResult = { exitReason: 'exit' };\n\n const requestExit = () => {\n if (state.exitRequested) return;\n state.exitRequested = true;\n if (elapsedTimerId) {\n clearInterval(elapsedTimerId);\n elapsedTimerId = null;\n }\n if (streamWatchdogId) {\n clearInterval(streamWatchdogId);\n streamWatchdogId = null;\n }\n client.stop();\n tui.terminal.setProgress(false);\n void drainAndStopTuiSafely(tui).then(() => {\n restoreStdio();\n finishTui?.();\n process.exit(0);\n });\n };\n\n const sessionActions = createSessionActions({\n client,\n chatLog,\n tui,\n state,\n assembler,\n resolveSessionKey,\n updateHeader,\n updateFooter,\n setActivityStatus,\n onAgentIdChange: (agentId) => {\n currentAgentId = agentId;\n },\n });\n\n const {\n refreshSessionInfo,\n loadHistory: loadSessionHistory,\n setSession,\n abortActive,\n resetCurrentSession,\n clearChatForSessionSwitch,\n } = sessionActions;\n\n const refreshSessionInfoWithBorder = async () => {\n await refreshSessionInfo();\n updateEditorBorderColor();\n };\n\n const resolveModelChoiceIndex = (): number => {\n const choices = cycleModelChoices();\n if (choices.length === 0) return -1;\n const p = state.sessionInfo.modelProvider;\n const m = state.sessionInfo.model;\n if (p && m) {\n const byParts = choices.findIndex((x) => x.provider === p && x.id === m);\n if (byParts >= 0) return byParts;\n }\n if (m?.includes('/')) {\n const [a, b] = m.split('/', 2);\n const bySlash = choices.findIndex((x) => x.provider === a && x.id === b);\n if (bySlash >= 0) return bySlash;\n }\n return 0;\n };\n\n const cycleModel = (dir: 'forward' | 'backward') => {\n const choices = cycleModelChoices();\n if (choices.length === 0) {\n void refreshModelChoices().then(() => {\n if (cycleModelChoices().length === 0) {\n chatLog.addSystem('No models available to cycle.');\n tui.requestRender();\n return;\n }\n cycleModel(dir);\n });\n return;\n }\n const idx = resolveModelChoiceIndex();\n const base = idx >= 0 ? idx : 0;\n const delta = dir === 'forward' ? 1 : -1;\n const next = choices[(base + delta + choices.length) % choices.length]!;\n sendMessage(`/switch ${next.provider}/${next.id}`);\n };\n\n const handleCtrlZ = () => {\n if (process.platform === 'win32') {\n chatLog.addSystem('Suspend (Ctrl+Z) is not supported on Windows.');\n tui.requestRender();\n return;\n }\n const suspendKeepAlive = setInterval(() => {}, 2 ** 30);\n const ignoreSigint = () => {};\n process.on('SIGINT', ignoreSigint);\n process.once('SIGCONT', () => {\n clearInterval(suspendKeepAlive);\n process.removeListener('SIGINT', ignoreSigint);\n tui.start();\n tui.setFocus(editor);\n tui.requestRender(true);\n });\n try {\n tui.stop();\n process.kill(0, 'SIGTSTP');\n } catch {\n clearInterval(suspendKeepAlive);\n process.removeListener('SIGINT', ignoreSigint);\n }\n };\n\n const openExternalEditor = () => {\n const dir = mkdtempSync(join(tmpdir(), 'xopc-tui-edit-'));\n const filePath = join(dir, 'message.md');\n writeFileSync(filePath, editor.getText(), 'utf8');\n const editorBin = process.env.EDITOR || process.env.VISUAL || 'vi';\n void (async () => {\n await withTuiSuspended(tui, async () => {\n spawnSync(editorBin, [filePath], { stdio: 'inherit' });\n });\n try {\n const next = readFileSync(filePath, 'utf8');\n editor.setText(next.replace(/\\r\\n/g, '\\n'));\n } catch {\n // ignore\n }\n try {\n unlinkSync(filePath);\n } catch {\n // ignore\n }\n tui.setFocus(editor);\n tui.requestRender(true);\n })();\n };\n\n const isAgentBusy = () =>\n state.activeRunId != null || state.isCompacting || busyStates.has(state.activityStatus);\n\n const steerMessage = (text: string) => {\n chatLog.addUser(text);\n touchStreamingActivity();\n tui.requestRender();\n void client\n .steerChat({ sessionKey: state.currentSessionKey, message: text })\n .then(({ ok }) => {\n if (!ok) {\n chatLog.addSystem(\n theme.dim(\n 'Could not steer — no active run or steer failed. Press Escape to abort, or Alt+Enter to queue a follow-up.',\n ),\n );\n } else {\n chatLog.addSystem(\n theme.dim('Steered — message injects at the next tool boundary (pi-style).'),\n );\n }\n tui.requestRender();\n })\n .catch((error: unknown) => {\n const errorMessage = error instanceof Error ? error.message : String(error);\n chatLog.addSystem(theme.dim(`Steer failed: ${errorMessage}`));\n tui.requestRender();\n });\n };\n\n const sendMessage = (text: string) => {\n if (state.isCompacting) {\n state.compactionQueue.push(text);\n chatLog.addSystem(\n theme.dim(`Queued during compaction (${state.compactionQueue.length}). Sends when compact finishes.`),\n );\n bottomBar.invalidate();\n tui.requestRender();\n return;\n }\n\n if (state.activeRunId) {\n chatLog.addSystem(\n 'A response is still in progress. Press Enter to steer, Alt+Enter to queue, or Escape to abort.',\n );\n tui.requestRender();\n return;\n }\n\n chatLog.addUser(text);\n setActivityStatus('sending');\n touchStreamingActivity();\n tui.requestRender();\n\n void client\n .sendChat({\n sessionKey: state.currentSessionKey,\n message: text,\n thinking: opts.thinking,\n })\n .catch((error: unknown) => {\n const errorMessage = error instanceof Error ? error.message : String(error);\n chatLog.addSystem(`❌ Failed to send: ${errorMessage}`);\n setActivityStatus('idle');\n tui.requestRender();\n });\n };\n\n const runCompaction = async () => {\n if (state.isCompacting) return;\n state.isCompacting = true;\n setActivityStatus('compacting');\n chatLog.addSystem(theme.dim('Compacting session…'));\n tui.requestRender();\n try {\n const result = await client.compactSession(state.currentSessionKey, { force: true });\n chatLog.addSystem(result.summary ?? (result.compacted ? 'Session compacted' : 'Nothing to compact'));\n if (result.compacted) {\n assembler.clear();\n clearPendingToolCallIds();\n state.historyLoaded = false;\n await loadSessionHistory();\n }\n } catch (error: unknown) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n chatLog.addSystem(`❌ Compaction failed: ${errorMessage}`);\n } finally {\n state.isCompacting = false;\n setActivityStatus('idle');\n await refreshSessionInfoWithBorder();\n const queued = state.compactionQueue.shift();\n if (queued && !state.activeRunId) {\n sendMessage(queued);\n }\n updateFooter();\n tui.requestRender();\n }\n };\n\n const applyTuiSettings = (settings: TuiSettings) => {\n tuiSettings = { ...settings };\n saveTuiSettings(tuiSettings);\n state.showThinking = tuiSettings.showThinking;\n state.toolsExpanded = tuiSettings.toolsExpanded;\n chatLog.setToolsExpanded(tuiSettings.toolsExpanded);\n applyThemeById(tuiSettings.theme);\n header.invalidate();\n updateEditorBorderColor();\n syncTerminalProgress();\n bottomBar.invalidate();\n tui.requestRender();\n };\n\n const previewTheme = (themeId: string) => {\n applyThemeById(themeId);\n updateEditorBorderColor();\n tui.requestRender();\n };\n\n const reloadKeybindings = () => {\n keybindings.reload();\n setKeybindings(keybindings);\n tui.requestRender();\n };\n\n const uiOverlays = {\n openSessionPicker: () => {},\n openScopedModels: () => {},\n openSettings: () => {},\n reloadKeybindings: () => reloadKeybindings(),\n };\n\n const handleCommand = createTuiCommandHandler({\n state,\n chatLog,\n tui,\n assembler,\n isLocalMode,\n abortActive,\n sendMessage,\n requestExit,\n updateFooter,\n keybindings,\n uiOverlays,\n runCompaction,\n extensionSlashCommands: extensionRuntime.slashCommands,\n currentAgentId,\n setSession,\n resetSession: resetCurrentSession,\n });\n\n const { runLocalShellLine } = createLocalShellRunner({\n chatLog,\n tui,\n editor,\n openOverlay,\n closeOverlay,\n pauseStdioFilter: () => stdioFilter.pause(),\n resumeStdioFilter: () => stdioFilter.resume(),\n runWithInheritedStdio: async (work) => {\n await withTuiSuspended(tui, work);\n },\n });\n\n const submitCore = createEditorSubmitHandler({\n editor,\n handleCommand,\n sendMessage,\n handleBangLine: runLocalShellLine,\n isAgentBusy,\n steerWhileBusy: steerMessage,\n });\n\n const submitBurst = createSubmitBurstCoalescer({\n submit: submitCore,\n enabled: shouldEnableWindowsGitBashPasteFallback(),\n });\n editor.onSubmit = submitBurst;\n\n const flushFollowUpQueue = () => {\n if (state.exitRequested) return;\n if (state.activeRunId) return;\n const next = state.messageFollowUpQueue.shift();\n if (next === undefined) return;\n sendMessage(next);\n };\n\n const handleFollowUp = () => {\n const text = editor.getText().trim();\n if (!text) return;\n if (isAgentBusy()) {\n editor.addToHistory(text);\n state.messageFollowUpQueue.push(text);\n editor.setText('');\n chatLog.addSystem(\n theme.dim(\n `Queued follow-up (${state.messageFollowUpQueue.length} in queue). Next sends when this reply finishes.`,\n ),\n );\n bottomBar.invalidate();\n tui.requestRender();\n return;\n }\n submitBurst(text);\n };\n\n const handleDequeue = () => {\n if (state.messageFollowUpQueue.length === 0) {\n chatLog.addSystem(theme.dim('No queued messages to restore.'));\n tui.requestRender();\n return;\n }\n const queued = [...state.messageFollowUpQueue];\n state.messageFollowUpQueue.length = 0;\n const current = editor.getText().trim();\n const combined = [queued.join('\\n\\n'), current].filter(Boolean).join('\\n\\n');\n editor.setText(combined);\n chatLog.addSystem(\n theme.dim(\n `Restored ${queued.length} queued message${queued.length > 1 ? 's' : ''} to editor.`,\n ),\n );\n bottomBar.invalidate();\n tui.requestRender();\n };\n\n const setSessionKey = (key: string) => {\n state.currentSessionKey = resolveSessionKey(key);\n updateAgentFromPicker(key);\n };\n\n const updateAgentFromPicker = (key: string) => {\n const parsed = parseAgentSessionKey(resolveSessionKey(key));\n if (parsed?.agentId) {\n currentAgentId = parsed.agentId;\n }\n };\n\n let ctrlCHandling = false;\n const handleCtrlC = () => {\n if (ctrlCHandling) return;\n ctrlCHandling = true;\n try {\n const now = Date.now();\n const decision = resolveCtrlCAction({\n hasInput: editor.getText().trim().length > 0,\n now,\n lastCtrlCAt: state.lastCtrlCAt,\n });\n state.lastCtrlCAt = decision.nextLastCtrlCAt;\n if (decision.action === 'clear') {\n editor.setText('');\n setActivityStatus('cleared input; press ctrl+c again to exit');\n tui.requestRender();\n return;\n }\n if (decision.action === 'exit') {\n requestExit();\n return;\n }\n setActivityStatus('press ctrl+c again to exit');\n tui.requestRender();\n } finally {\n ctrlCHandling = false;\n }\n };\n\n const setModelChoices = (models: TuiModelChoice[]) => {\n modelChoices = models;\n };\n\n const pickerSvc = {\n tui,\n editor,\n openOverlay,\n closeOverlay,\n chatLog,\n client,\n sendMessage,\n refreshSessionInfo,\n updateHeader,\n state,\n setSessionKey,\n clearChatForSessionSwitch,\n loadSessionHistory,\n setModelChoices,\n getScopedModelRefs: () => state.scopedModelRefs,\n setScopedModelRefs: (refs: string[] | null) => {\n state.scopedModelRefs = refs;\n saveScopedModelRefs(refs);\n },\n refreshCycleModels,\n getTuiSettings: () => ({ ...tuiSettings }),\n applyTuiSettings,\n previewTheme,\n reloadKeybindings,\n };\n\n uiOverlays.openSessionPicker = () => void openSessionPickerOverlay(pickerSvc);\n uiOverlays.openScopedModels = () => void openScopedModelsOverlay(pickerSvc);\n uiOverlays.openSettings = () => openSettingsOverlay(pickerSvc);\n\n const handleDoubleEscape = () => {\n switch (tuiSettings.doubleEscapeAction) {\n case 'tree':\n chatLog.addSystem(theme.dim('Session tree is not available in xopc TUI yet.'));\n break;\n case 'fork':\n chatLog.addSystem(theme.dim('Session fork is not available in xopc TUI yet.'));\n break;\n default:\n break;\n }\n tui.requestRender();\n };\n\n editor.onEscape = () => {\n if (state.activeRunId) {\n void abortActive();\n return;\n }\n if (editor.getText().trim().length > 0) return;\n const now = Date.now();\n if (now - state.lastEscapeAt <= DOUBLE_ESCAPE_WINDOW_MS) {\n state.lastEscapeAt = 0;\n handleDoubleEscape();\n return;\n }\n state.lastEscapeAt = now;\n };\n editor.onCtrlD = () => requestExit();\n\n editor.onAction('app.clear', handleCtrlC);\n editor.onAction('app.exit', () => requestExit());\n editor.onAction('app.suspend', handleCtrlZ);\n editor.onAction('app.thinking.cycle', () => {\n const cur = state.sessionInfo.thinkingLevel ?? opts.thinking ?? 'medium';\n sendMessage(`/think ${nextThinkLevel(cur)}`);\n updateEditorBorderColor();\n });\n editor.onAction('app.model.cycleForward', () => cycleModel('forward'));\n editor.onAction('app.model.cycleBackward', () => cycleModel('backward'));\n editor.onAction('app.model.select', () => void openModelPickerOverlay(pickerSvc));\n editor.onAction('app.session.resume', () => void openSessionPickerOverlay(pickerSvc));\n editor.onAction('app.tools.expand', () => {\n state.toolsExpanded = !state.toolsExpanded;\n tuiSettings = { ...tuiSettings, toolsExpanded: state.toolsExpanded };\n saveTuiSettings(tuiSettings);\n chatLog.setToolsExpanded(state.toolsExpanded);\n setActivityStatus(state.toolsExpanded ? 'tools expanded' : 'tools collapsed');\n tui.requestRender();\n });\n editor.onAction('app.thinking.toggle', () => {\n state.showThinking = !state.showThinking;\n tuiSettings = { ...tuiSettings, showThinking: state.showThinking };\n saveTuiSettings(tuiSettings);\n updateFooter();\n tui.requestRender();\n });\n editor.onAction('app.editor.external', openExternalEditor);\n editor.onPasteImage = () => {\n void (async () => {\n const filePath = await saveClipboardImageToTempFile();\n if (!filePath) return;\n editor.insertTextAtCursor(filePath);\n chatLog.addSystem(theme.dim(`Pasted image path: ${filePath}`));\n tui.requestRender();\n })();\n };\n editor.onAction('app.message.followUp', handleFollowUp);\n editor.onAction('app.message.dequeue', handleDequeue);\n\n streamWatchdogId = setInterval(() => {\n if (!state.activeRunId) return;\n if (!busyStates.has(state.activityStatus)) return;\n if (Date.now() - lastStreamActivityAt < DEFAULT_STREAMING_WATCHDOG_MS) return;\n\n const rid = state.activeRunId;\n const finalText = assembler.finalize(rid, state.showThinking);\n if (finalText) {\n chatLog.finalizeAssistant(finalText, rid);\n }\n chatLog.addSystem(\n '⚠️ No stream activity for 30s; UI reset (connection may have stalled). Retry or check gateway.',\n );\n state.activeRunId = null;\n setActivityStatus('idle');\n void refreshSessionInfoWithBorder().finally(() => {\n updateFooter();\n tui.requestRender();\n });\n flushFollowUpQueue();\n tui.requestRender();\n }, 5000);\n\n const onAgentRunEnded = () => {\n state.progressMessage = null;\n void refreshSessionInfoWithBorder().finally(() => {\n updateFooter();\n tui.requestRender();\n });\n flushFollowUpQueue();\n };\n\n client.onEvent = (evt: TuiEvent) => {\n const data = (evt.data ?? {}) as Record<string, unknown>;\n dispatchAgentSSE(\n evt.event,\n data,\n state,\n chatLog,\n assembler,\n tui,\n setActivityStatus,\n touchStreamingActivity,\n onAgentRunEnded,\n );\n };\n\n client.onConnected = () => {\n state.isConnected = true;\n setConnectionStatus(isLocalMode ? 'local ready' : 'gateway connected');\n touchStreamingActivity();\n void (async () => {\n await refreshSessionInfoWithBorder();\n await refreshModelChoices();\n await loadSessionHistory();\n updateHeader();\n updateFooter();\n tui.requestRender();\n if (!state.autoMessageSent && opts.message) {\n state.autoMessageSent = true;\n sendMessage(opts.message);\n }\n })();\n };\n\n client.onDisconnected = (reason: string) => {\n const wasConnected = state.isConnected;\n state.isConnected = false;\n touchStreamingActivity();\n if (isLocalMode) {\n setConnectionStatus(`local stopped: ${reason}`);\n } else {\n const hint =\n wasConnected || state.historyLoaded\n ? ` (${reason}). Reconnecting broadcast stream…`\n : `. Ensure gateway is running (xopc gateway) or use --local.`;\n setConnectionStatus(`disconnected${hint}`);\n if (!wasConnected && !state.historyLoaded) {\n const gatewayUrl = opts.url ?? 'http://localhost:3120';\n chatLog.addSystem(\n `Cannot reach gateway at ${gatewayUrl}.\\n` +\n 'Start the gateway (`xopc gateway`) or run `xopc tui --local` for embedded mode.',\n );\n }\n }\n tui.requestRender();\n };\n\n client.onGap = (info) => {\n chatLog.addSystem(\n `⚠️ Event gap: expected ${info.expected}, received ${info.received}. Some updates may be missing.`,\n );\n setConnectionStatus(`event gap: expected ${info.expected}, got ${info.received}`);\n tui.requestRender();\n };\n\n const sigintHandler = () => handleCtrlC();\n const sigtermHandler = () => requestExit();\n process.on('SIGINT', sigintHandler);\n process.on('SIGTERM', sigtermHandler);\n\n updateHeader();\n updateEditorBorderColor();\n setConnectionStatus(isLocalMode ? 'starting local runtime' : 'connecting');\n updateFooter();\n await extensionRuntime.activate();\n tui.start();\n client.start();\n\n await new Promise<void>((resolve) => {\n finishTui = () => {\n process.removeListener('SIGINT', sigintHandler);\n process.removeListener('SIGTERM', sigtermHandler);\n if (streamWatchdogId) {\n clearInterval(streamWatchdogId);\n streamWatchdogId = null;\n }\n finishTui = null;\n resolve();\n };\n });\n\n return exitResult;\n}\n"],"mappings":"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"}
@@ -1,3 +1,5 @@
1
1
  /** Trim non-empty strings; otherwise undefined. */
2
2
  export declare function normalizeOptionalString(value: unknown): string | undefined;
3
3
  export declare function normalizeLowercaseStringOrEmpty(value: unknown): string;
4
+ /** Lowercase trimmed string, or undefined when empty/missing. */
5
+ export declare function normalizeOptionalLowercaseString(value: unknown): string | undefined;
@@ -1,3 +1,4 @@
1
+ import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
1
2
  //#region src/utils/string-coerce.ts
2
3
  /** Trim non-empty strings; otherwise undefined. */
3
4
  function normalizeOptionalString(value) {
@@ -9,7 +10,15 @@ function normalizeLowercaseStringOrEmpty(value) {
9
10
  if (typeof value !== "string") return "";
10
11
  return value.trim().toLowerCase();
11
12
  }
13
+ /** Lowercase trimmed string, or undefined when empty/missing. */
14
+ function normalizeOptionalLowercaseString(value) {
15
+ if (typeof value !== "string") return;
16
+ const trimmed = value.trim().toLowerCase();
17
+ return trimmed.length > 0 ? trimmed : void 0;
18
+ }
19
+ var init_string_coerce = __esmMin((() => {}));
12
20
  //#endregion
13
- export { normalizeLowercaseStringOrEmpty, normalizeOptionalString };
21
+ init_string_coerce();
22
+ export { init_string_coerce, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString };
14
23
 
15
24
  //# sourceMappingURL=string-coerce.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"string-coerce.js","names":[],"sources":["../../../src/utils/string-coerce.ts"],"sourcesContent":["/** Trim non-empty strings; otherwise undefined. */\nexport function normalizeOptionalString(value: unknown): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nexport function normalizeLowercaseStringOrEmpty(value: unknown): string {\n if (typeof value !== 'string') {\n return '';\n }\n return value.trim().toLowerCase();\n}\n"],"mappings":";;AACA,SAAgB,wBAAwB,OAAoC;AAC1E,KAAI,OAAO,UAAU,SACnB;CAEF,MAAM,UAAU,MAAM,MAAM;AAC5B,QAAO,QAAQ,SAAS,IAAI,UAAU,KAAA;;AAGxC,SAAgB,gCAAgC,OAAwB;AACtE,KAAI,OAAO,UAAU,SACnB,QAAO;AAET,QAAO,MAAM,MAAM,CAAC,aAAa"}
1
+ {"version":3,"file":"string-coerce.js","names":[],"sources":["../../../src/utils/string-coerce.ts"],"sourcesContent":["/** Trim non-empty strings; otherwise undefined. */\nexport function normalizeOptionalString(value: unknown): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nexport function normalizeLowercaseStringOrEmpty(value: unknown): string {\n if (typeof value !== 'string') {\n return '';\n }\n return value.trim().toLowerCase();\n}\n\n/** Lowercase trimmed string, or undefined when empty/missing. */\nexport function normalizeOptionalLowercaseString(value: unknown): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n const trimmed = value.trim().toLowerCase();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n"],"mappings":";;;AACA,SAAgB,wBAAwB,OAAoC;AAC1E,KAAI,OAAO,UAAU,SACnB;CAEF,MAAM,UAAU,MAAM,MAAM;AAC5B,QAAO,QAAQ,SAAS,IAAI,UAAU,KAAA;;AAGxC,SAAgB,gCAAgC,OAAwB;AACtE,KAAI,OAAO,UAAU,SACnB,QAAO;AAET,QAAO,MAAM,MAAM,CAAC,aAAa;;;AAInC,SAAgB,iCAAiC,OAAoC;AACnF,KAAI,OAAO,UAAU,SACnB;CAEF,MAAM,UAAU,MAAM,MAAM,CAAC,aAAa;AAC1C,QAAO,QAAQ,SAAS,IAAI,UAAU,KAAA"}
@@ -1,15 +1,12 @@
1
1
  /**
2
2
  * STT config slice resolution — maps persisted config to per-provider raw config.
3
3
  *
4
- * Supports OpenClaw-aligned `tools.media.audio.providers.<id>` plus legacy flat keys
5
- * (`tools.media.audio.openai`, `tools.media.audio.alibaba`, …).
4
+ * Reads `tools.media.audio.providers.<id>` only — there is no legacy flat-key form.
6
5
  */
7
6
  import type { STTConfig } from './types.js';
8
- /** Top-level `tools.media.audio` keys that are not provider config buckets. */
9
- export declare const STT_CONFIG_RESERVED_KEYS: Set<string>;
10
7
  /** Built-in env fallbacks when config slice has no apiKey. */
11
8
  export declare const STT_LEGACY_ENV_KEYS: Record<string, string>;
12
- /** Collect provider-id → raw config entries from providers map + legacy flat keys. */
9
+ /** Collect provider-id → raw config entries from the `providers` map. */
13
10
  export declare function collectSttProviderConfigEntries(config: Partial<STTConfig> | Record<string, unknown> | undefined): Record<string, Record<string, unknown>>;
14
11
  /** Resolve the raw config slice for one provider id. */
15
12
  export declare function resolveSttProviderConfigSlice(providerId: string, config: Partial<STTConfig> | Record<string, unknown> | undefined): Record<string, unknown>;
@@ -1,14 +1,4 @@
1
1
  //#region src/voice/stt/config-slice.ts
2
- /** Top-level `tools.media.audio` keys that are not provider config buckets. */
3
- const STT_CONFIG_RESERVED_KEYS = new Set([
4
- "enabled",
5
- "provider",
6
- "providers",
7
- "models",
8
- "fallback",
9
- "timeoutMs",
10
- "sharedModels"
11
- ]);
12
2
  /** Built-in env fallbacks when config slice has no apiKey. */
13
3
  const STT_LEGACY_ENV_KEYS = {
14
4
  openai: "OPENAI_API_KEY",
@@ -17,23 +7,12 @@ const STT_LEGACY_ENV_KEYS = {
17
7
  function asRecord(value) {
18
8
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
19
9
  }
20
- function asProviderConfig(value) {
21
- return asRecord(value) ?? {};
22
- }
23
- /** Collect provider-id → raw config entries from providers map + legacy flat keys. */
10
+ /** Collect provider-id → raw config entries from the `providers` map. */
24
11
  function collectSttProviderConfigEntries(config) {
25
- const raw = config ?? {};
12
+ const providers = asRecord((config ?? {}).providers);
13
+ if (!providers) return {};
26
14
  const entries = {};
27
- const providers = asRecord(raw.providers);
28
- if (providers) for (const [providerId, value] of Object.entries(providers)) entries[providerId] = {
29
- ...entries[providerId],
30
- ...asProviderConfig(value)
31
- };
32
- for (const [key, value] of Object.entries(raw)) {
33
- if (STT_CONFIG_RESERVED_KEYS.has(key)) continue;
34
- if (typeof value !== "object" || value === null || Array.isArray(value)) continue;
35
- if (entries[key] === void 0) entries[key] = asProviderConfig(value);
36
- }
15
+ for (const [providerId, value] of Object.entries(providers)) entries[providerId] = { ...asRecord(value) ?? {} };
37
16
  return entries;
38
17
  }
39
18
  /** Resolve the raw config slice for one provider id. */
@@ -71,6 +50,6 @@ function readSttProviderFields(slice, entryOverride) {
71
50
  };
72
51
  }
73
52
  //#endregion
74
- export { STT_CONFIG_RESERVED_KEYS, STT_LEGACY_ENV_KEYS, collectSttProviderConfigEntries, readSttProviderFields, resolveSttProviderConfigSlice };
53
+ export { STT_LEGACY_ENV_KEYS, collectSttProviderConfigEntries, readSttProviderFields, resolveSttProviderConfigSlice };
75
54
 
76
55
  //# sourceMappingURL=config-slice.js.map