@getpaseo/server 0.1.15 → 0.1.17

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 (364) hide show
  1. package/dist/scripts/daemon-runner.js +53 -14
  2. package/dist/scripts/daemon-runner.js.map +1 -1
  3. package/dist/scripts/dev-runner.js +9 -16
  4. package/dist/scripts/dev-runner.js.map +1 -1
  5. package/dist/scripts/supervisor.js +40 -13
  6. package/dist/scripts/supervisor.js.map +1 -1
  7. package/dist/server/client/daemon-client.d.ts +63 -6
  8. package/dist/server/client/daemon-client.d.ts.map +1 -1
  9. package/dist/server/client/daemon-client.js +436 -92
  10. package/dist/server/client/daemon-client.js.map +1 -1
  11. package/dist/server/server/agent/agent-manager.d.ts +13 -1
  12. package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
  13. package/dist/server/server/agent/agent-manager.js +404 -39
  14. package/dist/server/server/agent/agent-manager.js.map +1 -1
  15. package/dist/server/server/agent/agent-metadata-generator.d.ts.map +1 -1
  16. package/dist/server/server/agent/agent-metadata-generator.js +13 -4
  17. package/dist/server/server/agent/agent-metadata-generator.js.map +1 -1
  18. package/dist/server/server/agent/agent-projections.d.ts +5 -0
  19. package/dist/server/server/agent/agent-projections.d.ts.map +1 -1
  20. package/dist/server/server/agent/agent-projections.js +24 -0
  21. package/dist/server/server/agent/agent-projections.js.map +1 -1
  22. package/dist/server/server/agent/agent-response-loop.js +1 -1
  23. package/dist/server/server/agent/agent-response-loop.js.map +1 -1
  24. package/dist/server/server/agent/agent-sdk-types.d.ts +20 -0
  25. package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
  26. package/dist/server/server/agent/agent-sdk-types.js +11 -1
  27. package/dist/server/server/agent/agent-sdk-types.js.map +1 -1
  28. package/dist/server/server/agent/agent-storage.d.ts +20 -6
  29. package/dist/server/server/agent/agent-storage.d.ts.map +1 -1
  30. package/dist/server/server/agent/agent-storage.js +43 -72
  31. package/dist/server/server/agent/agent-storage.js.map +1 -1
  32. package/dist/server/server/agent/agent-title-limits.d.ts +3 -0
  33. package/dist/server/server/agent/agent-title-limits.d.ts.map +1 -0
  34. package/dist/server/server/agent/agent-title-limits.js +3 -0
  35. package/dist/server/server/agent/agent-title-limits.js.map +1 -0
  36. package/dist/server/server/agent/providers/claude/model-catalog.d.ts +29 -0
  37. package/dist/server/server/agent/providers/claude/model-catalog.d.ts.map +1 -0
  38. package/dist/server/server/agent/providers/claude/model-catalog.js +70 -0
  39. package/dist/server/server/agent/providers/claude/model-catalog.js.map +1 -0
  40. package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts +44 -0
  41. package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts.map +1 -0
  42. package/dist/server/server/agent/providers/claude/task-notification-tool-call.js +250 -0
  43. package/dist/server/server/agent/providers/claude/task-notification-tool-call.js.map +1 -0
  44. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts.map +1 -1
  45. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +17 -0
  46. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js.map +1 -1
  47. package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts.map +1 -1
  48. package/dist/server/server/agent/providers/claude/tool-call-mapper.js +2 -0
  49. package/dist/server/server/agent/providers/claude/tool-call-mapper.js.map +1 -1
  50. package/dist/server/server/agent/providers/claude-agent.d.ts +10 -3
  51. package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
  52. package/dist/server/server/agent/providers/claude-agent.js +1702 -330
  53. package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
  54. package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts.map +1 -1
  55. package/dist/server/server/agent/providers/codex/tool-call-mapper.js +81 -28
  56. package/dist/server/server/agent/providers/codex/tool-call-mapper.js.map +1 -1
  57. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
  58. package/dist/server/server/agent/providers/codex-app-server-agent.js +50 -9
  59. package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
  60. package/dist/server/server/agent/providers/opencode-agent.d.ts +10 -1
  61. package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -1
  62. package/dist/server/server/agent/providers/opencode-agent.js +207 -176
  63. package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
  64. package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +55 -0
  65. package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
  66. package/dist/server/server/agent/providers/tool-call-detail-primitives.js +1 -0
  67. package/dist/server/server/agent/providers/tool-call-detail-primitives.js.map +1 -1
  68. package/dist/server/server/agent/timeline-projection.d.ts +20 -0
  69. package/dist/server/server/agent/timeline-projection.d.ts.map +1 -1
  70. package/dist/server/server/agent/timeline-projection.js +73 -0
  71. package/dist/server/server/agent/timeline-projection.js.map +1 -1
  72. package/dist/server/server/bootstrap.d.ts +15 -0
  73. package/dist/server/server/bootstrap.d.ts.map +1 -1
  74. package/dist/server/server/bootstrap.js +27 -4
  75. package/dist/server/server/bootstrap.js.map +1 -1
  76. package/dist/server/server/client-message-id.d.ts +3 -0
  77. package/dist/server/server/client-message-id.d.ts.map +1 -0
  78. package/dist/server/server/client-message-id.js +12 -0
  79. package/dist/server/server/client-message-id.js.map +1 -0
  80. package/dist/server/server/file-download/token-store.d.ts +0 -1
  81. package/dist/server/server/file-download/token-store.d.ts.map +1 -1
  82. package/dist/server/server/file-download/token-store.js.map +1 -1
  83. package/dist/server/server/file-explorer/service.d.ts.map +1 -1
  84. package/dist/server/server/file-explorer/service.js +56 -36
  85. package/dist/server/server/file-explorer/service.js.map +1 -1
  86. package/dist/server/server/index.js +85 -29
  87. package/dist/server/server/index.js.map +1 -1
  88. package/dist/server/server/logger.d.ts +24 -3
  89. package/dist/server/server/logger.d.ts.map +1 -1
  90. package/dist/server/server/logger.js +157 -21
  91. package/dist/server/server/logger.js.map +1 -1
  92. package/dist/server/server/persisted-config.d.ts +94 -8
  93. package/dist/server/server/persisted-config.d.ts.map +1 -1
  94. package/dist/server/server/persisted-config.js +25 -3
  95. package/dist/server/server/persisted-config.js.map +1 -1
  96. package/dist/server/server/persistence-hooks.js +1 -1
  97. package/dist/server/server/persistence-hooks.js.map +1 -1
  98. package/dist/server/server/pid-lock.d.ts +6 -2
  99. package/dist/server/server/pid-lock.d.ts.map +1 -1
  100. package/dist/server/server/pid-lock.js +7 -10
  101. package/dist/server/server/pid-lock.js.map +1 -1
  102. package/dist/server/server/relay-transport.js +28 -28
  103. package/dist/server/server/relay-transport.js.map +1 -1
  104. package/dist/server/server/session.d.ts +60 -4
  105. package/dist/server/server/session.d.ts.map +1 -1
  106. package/dist/server/server/session.js +854 -190
  107. package/dist/server/server/session.js.map +1 -1
  108. package/dist/server/server/websocket-server.d.ts +24 -5
  109. package/dist/server/server/websocket-server.d.ts.map +1 -1
  110. package/dist/server/server/websocket-server.js +400 -77
  111. package/dist/server/server/websocket-server.js.map +1 -1
  112. package/dist/server/server/worktree-bootstrap.d.ts.map +1 -1
  113. package/dist/server/server/worktree-bootstrap.js +45 -2
  114. package/dist/server/server/worktree-bootstrap.js.map +1 -1
  115. package/dist/server/shared/daemon-endpoints.d.ts +9 -1
  116. package/dist/server/shared/daemon-endpoints.d.ts.map +1 -1
  117. package/dist/server/shared/daemon-endpoints.js +18 -3
  118. package/dist/server/shared/daemon-endpoints.js.map +1 -1
  119. package/dist/server/shared/messages.d.ts +4432 -380
  120. package/dist/server/shared/messages.d.ts.map +1 -1
  121. package/dist/server/shared/messages.js +139 -6
  122. package/dist/server/shared/messages.js.map +1 -1
  123. package/dist/server/shared/tool-call-display.d.ts.map +1 -1
  124. package/dist/server/shared/tool-call-display.js +7 -0
  125. package/dist/server/shared/tool-call-display.js.map +1 -1
  126. package/dist/server/terminal/terminal-manager.d.ts.map +1 -1
  127. package/dist/server/terminal/terminal-manager.js +1 -13
  128. package/dist/server/terminal/terminal-manager.js.map +1 -1
  129. package/dist/server/terminal/terminal.d.ts.map +1 -1
  130. package/dist/server/terminal/terminal.js +29 -5
  131. package/dist/server/terminal/terminal.js.map +1 -1
  132. package/dist/server/utils/worktree.d.ts +1 -0
  133. package/dist/server/utils/worktree.d.ts.map +1 -1
  134. package/dist/server/utils/worktree.js +17 -2
  135. package/dist/server/utils/worktree.js.map +1 -1
  136. package/dist/src/server/agent/activity-curator.js +228 -0
  137. package/dist/src/server/agent/activity-curator.js.map +1 -0
  138. package/dist/src/server/agent/agent-manager.js +1712 -0
  139. package/dist/src/server/agent/agent-manager.js.map +1 -0
  140. package/dist/src/server/agent/agent-metadata-generator.js +163 -0
  141. package/dist/src/server/agent/agent-metadata-generator.js.map +1 -0
  142. package/dist/src/server/agent/agent-projections.js +262 -0
  143. package/dist/src/server/agent/agent-projections.js.map +1 -0
  144. package/dist/src/server/agent/agent-response-loop.js +304 -0
  145. package/dist/src/server/agent/agent-response-loop.js.map +1 -0
  146. package/dist/src/server/agent/agent-sdk-types.js +12 -0
  147. package/dist/src/server/agent/agent-sdk-types.js.map +1 -0
  148. package/dist/src/server/agent/agent-storage.js +299 -0
  149. package/dist/src/server/agent/agent-storage.js.map +1 -0
  150. package/dist/src/server/agent/agent-title-limits.js +3 -0
  151. package/dist/src/server/agent/agent-title-limits.js.map +1 -0
  152. package/dist/src/server/agent/audio-utils.js +19 -0
  153. package/dist/src/server/agent/audio-utils.js.map +1 -0
  154. package/dist/src/server/agent/dictation-debug.js +50 -0
  155. package/dist/src/server/agent/dictation-debug.js.map +1 -0
  156. package/dist/src/server/agent/mcp-server.js +787 -0
  157. package/dist/src/server/agent/mcp-server.js.map +1 -0
  158. package/dist/src/server/agent/orchestrator-instructions.js +51 -0
  159. package/dist/src/server/agent/orchestrator-instructions.js.map +1 -0
  160. package/dist/src/server/agent/pcm16-resampler.js +63 -0
  161. package/dist/src/server/agent/pcm16-resampler.js.map +1 -0
  162. package/dist/src/server/agent/provider-launch-config.js +83 -0
  163. package/dist/src/server/agent/provider-launch-config.js.map +1 -0
  164. package/dist/src/server/agent/provider-manifest.js +97 -0
  165. package/dist/src/server/agent/provider-manifest.js.map +1 -0
  166. package/dist/src/server/agent/provider-registry.js +45 -0
  167. package/dist/src/server/agent/provider-registry.js.map +1 -0
  168. package/dist/src/server/agent/providers/claude/model-catalog.js +70 -0
  169. package/dist/src/server/agent/providers/claude/model-catalog.js.map +1 -0
  170. package/dist/src/server/agent/providers/claude/task-notification-tool-call.js +250 -0
  171. package/dist/src/server/agent/providers/claude/task-notification-tool-call.js.map +1 -0
  172. package/dist/src/server/agent/providers/claude/tool-call-detail-parser.js +109 -0
  173. package/dist/src/server/agent/providers/claude/tool-call-detail-parser.js.map +1 -0
  174. package/dist/src/server/agent/providers/claude/tool-call-mapper.js +238 -0
  175. package/dist/src/server/agent/providers/claude/tool-call-mapper.js.map +1 -0
  176. package/dist/src/server/agent/providers/claude-agent.js +3747 -0
  177. package/dist/src/server/agent/providers/claude-agent.js.map +1 -0
  178. package/dist/src/server/agent/providers/codex/tool-call-detail-parser.js +104 -0
  179. package/dist/src/server/agent/providers/codex/tool-call-detail-parser.js.map +1 -0
  180. package/dist/src/server/agent/providers/codex/tool-call-mapper.js +720 -0
  181. package/dist/src/server/agent/providers/codex/tool-call-mapper.js.map +1 -0
  182. package/dist/src/server/agent/providers/codex-app-server-agent.js +2601 -0
  183. package/dist/src/server/agent/providers/codex-app-server-agent.js.map +1 -0
  184. package/dist/src/server/agent/providers/codex-rollout-timeline.js +487 -0
  185. package/dist/src/server/agent/providers/codex-rollout-timeline.js.map +1 -0
  186. package/dist/src/server/agent/providers/opencode/tool-call-detail-parser.js +39 -0
  187. package/dist/src/server/agent/providers/opencode/tool-call-detail-parser.js.map +1 -0
  188. package/dist/src/server/agent/providers/opencode/tool-call-mapper.js +151 -0
  189. package/dist/src/server/agent/providers/opencode/tool-call-mapper.js.map +1 -0
  190. package/dist/src/server/agent/providers/opencode-agent.js +905 -0
  191. package/dist/src/server/agent/providers/opencode-agent.js.map +1 -0
  192. package/dist/src/server/agent/providers/tool-call-detail-primitives.js +552 -0
  193. package/dist/src/server/agent/providers/tool-call-detail-primitives.js.map +1 -0
  194. package/dist/src/server/agent/providers/tool-call-mapper-utils.js +109 -0
  195. package/dist/src/server/agent/providers/tool-call-mapper-utils.js.map +1 -0
  196. package/dist/src/server/agent/recordings-debug.js +19 -0
  197. package/dist/src/server/agent/recordings-debug.js.map +1 -0
  198. package/dist/src/server/agent/stt-debug.js +33 -0
  199. package/dist/src/server/agent/stt-debug.js.map +1 -0
  200. package/dist/src/server/agent/stt-manager.js +233 -0
  201. package/dist/src/server/agent/stt-manager.js.map +1 -0
  202. package/dist/src/server/agent/timeline-append.js +27 -0
  203. package/dist/src/server/agent/timeline-append.js.map +1 -0
  204. package/dist/src/server/agent/timeline-projection.js +215 -0
  205. package/dist/src/server/agent/timeline-projection.js.map +1 -0
  206. package/dist/src/server/agent/tool-name-normalization.js +45 -0
  207. package/dist/src/server/agent/tool-name-normalization.js.map +1 -0
  208. package/dist/src/server/agent/tts-debug.js +24 -0
  209. package/dist/src/server/agent/tts-debug.js.map +1 -0
  210. package/dist/src/server/agent/tts-manager.js +249 -0
  211. package/dist/src/server/agent/tts-manager.js.map +1 -0
  212. package/dist/src/server/agent/wait-for-agent-tracker.js +53 -0
  213. package/dist/src/server/agent/wait-for-agent-tracker.js.map +1 -0
  214. package/dist/src/server/agent-attention-policy.js +40 -0
  215. package/dist/src/server/agent-attention-policy.js.map +1 -0
  216. package/dist/src/server/allowed-hosts.js +94 -0
  217. package/dist/src/server/allowed-hosts.js.map +1 -0
  218. package/dist/src/server/bootstrap.js +498 -0
  219. package/dist/src/server/bootstrap.js.map +1 -0
  220. package/dist/src/server/client-message-id.js +12 -0
  221. package/dist/src/server/client-message-id.js.map +1 -0
  222. package/dist/src/server/config.js +84 -0
  223. package/dist/src/server/config.js.map +1 -0
  224. package/dist/src/server/connection-offer.js +60 -0
  225. package/dist/src/server/connection-offer.js.map +1 -0
  226. package/dist/src/server/daemon-keypair.js +40 -0
  227. package/dist/src/server/daemon-keypair.js.map +1 -0
  228. package/dist/src/server/daemon-version.js +22 -0
  229. package/dist/src/server/daemon-version.js.map +1 -0
  230. package/dist/src/server/dictation/dictation-stream-manager.js +568 -0
  231. package/dist/src/server/dictation/dictation-stream-manager.js.map +1 -0
  232. package/dist/src/server/file-download/token-store.js +40 -0
  233. package/dist/src/server/file-download/token-store.js.map +1 -0
  234. package/dist/src/server/file-explorer/service.js +183 -0
  235. package/dist/src/server/file-explorer/service.js.map +1 -0
  236. package/dist/src/server/json-utils.js +45 -0
  237. package/dist/src/server/json-utils.js.map +1 -0
  238. package/dist/src/server/messages.js +29 -0
  239. package/dist/src/server/messages.js.map +1 -0
  240. package/dist/src/server/package-version.js +47 -0
  241. package/dist/src/server/package-version.js.map +1 -0
  242. package/dist/src/server/paseo-home.js +19 -0
  243. package/dist/src/server/paseo-home.js.map +1 -0
  244. package/dist/src/server/path-utils.js +20 -0
  245. package/dist/src/server/path-utils.js.map +1 -0
  246. package/dist/src/server/persisted-config.js +259 -0
  247. package/dist/src/server/persisted-config.js.map +1 -0
  248. package/dist/src/server/persistence-hooks.js +60 -0
  249. package/dist/src/server/persistence-hooks.js.map +1 -0
  250. package/dist/src/server/pid-lock.js +126 -0
  251. package/dist/src/server/pid-lock.js.map +1 -0
  252. package/dist/src/server/push/push-service.js +68 -0
  253. package/dist/src/server/push/push-service.js.map +1 -0
  254. package/dist/src/server/push/token-store.js +70 -0
  255. package/dist/src/server/push/token-store.js.map +1 -0
  256. package/dist/src/server/relay-transport.js +457 -0
  257. package/dist/src/server/relay-transport.js.map +1 -0
  258. package/dist/src/server/server-id.js +63 -0
  259. package/dist/src/server/server-id.js.map +1 -0
  260. package/dist/src/server/session.js +5947 -0
  261. package/dist/src/server/session.js.map +1 -0
  262. package/dist/src/server/speech/audio.js +101 -0
  263. package/dist/src/server/speech/audio.js.map +1 -0
  264. package/dist/src/server/speech/provider-resolver.js +7 -0
  265. package/dist/src/server/speech/provider-resolver.js.map +1 -0
  266. package/dist/src/server/speech/providers/local/config.js +83 -0
  267. package/dist/src/server/speech/providers/local/config.js.map +1 -0
  268. package/dist/src/server/speech/providers/local/models.js +17 -0
  269. package/dist/src/server/speech/providers/local/models.js.map +1 -0
  270. package/dist/src/server/speech/providers/local/pocket/pocket-tts-onnx.js +422 -0
  271. package/dist/src/server/speech/providers/local/pocket/pocket-tts-onnx.js.map +1 -0
  272. package/dist/src/server/speech/providers/local/runtime.js +253 -0
  273. package/dist/src/server/speech/providers/local/runtime.js.map +1 -0
  274. package/dist/src/server/speech/providers/local/sherpa/model-catalog.js +166 -0
  275. package/dist/src/server/speech/providers/local/sherpa/model-catalog.js.map +1 -0
  276. package/dist/src/server/speech/providers/local/sherpa/model-downloader.js +165 -0
  277. package/dist/src/server/speech/providers/local/sherpa/model-downloader.js.map +1 -0
  278. package/dist/src/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js +68 -0
  279. package/dist/src/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js.map +1 -0
  280. package/dist/src/server/speech/providers/local/sherpa/sherpa-online-recognizer.js +79 -0
  281. package/dist/src/server/speech/providers/local/sherpa/sherpa-online-recognizer.js.map +1 -0
  282. package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-loader.js +11 -0
  283. package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-loader.js.map +1 -0
  284. package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +102 -0
  285. package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js.map +1 -0
  286. package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +131 -0
  287. package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js.map +1 -0
  288. package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +132 -0
  289. package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js.map +1 -0
  290. package/dist/src/server/speech/providers/local/sherpa/sherpa-realtime-session.js +112 -0
  291. package/dist/src/server/speech/providers/local/sherpa/sherpa-realtime-session.js.map +1 -0
  292. package/dist/src/server/speech/providers/local/sherpa/sherpa-stt.js +140 -0
  293. package/dist/src/server/speech/providers/local/sherpa/sherpa-stt.js.map +1 -0
  294. package/dist/src/server/speech/providers/local/sherpa/sherpa-tts.js +95 -0
  295. package/dist/src/server/speech/providers/local/sherpa/sherpa-tts.js.map +1 -0
  296. package/dist/src/server/speech/providers/openai/config.js +99 -0
  297. package/dist/src/server/speech/providers/openai/config.js.map +1 -0
  298. package/dist/src/server/speech/providers/openai/realtime-transcription-session.js +165 -0
  299. package/dist/src/server/speech/providers/openai/realtime-transcription-session.js.map +1 -0
  300. package/dist/src/server/speech/providers/openai/runtime.js +114 -0
  301. package/dist/src/server/speech/providers/openai/runtime.js.map +1 -0
  302. package/dist/src/server/speech/providers/openai/stt.js +208 -0
  303. package/dist/src/server/speech/providers/openai/stt.js.map +1 -0
  304. package/dist/src/server/speech/providers/openai/tts.js +46 -0
  305. package/dist/src/server/speech/providers/openai/tts.js.map +1 -0
  306. package/dist/src/server/speech/speech-config-resolver.js +85 -0
  307. package/dist/src/server/speech/speech-config-resolver.js.map +1 -0
  308. package/dist/src/server/speech/speech-provider.js +2 -0
  309. package/dist/src/server/speech/speech-provider.js.map +1 -0
  310. package/dist/src/server/speech/speech-runtime.js +497 -0
  311. package/dist/src/server/speech/speech-runtime.js.map +1 -0
  312. package/dist/src/server/speech/speech-types.js +8 -0
  313. package/dist/src/server/speech/speech-types.js.map +1 -0
  314. package/dist/src/server/utils/diff-highlighter.js +244 -0
  315. package/dist/src/server/utils/diff-highlighter.js.map +1 -0
  316. package/dist/src/server/utils/syntax-highlighter.js +145 -0
  317. package/dist/src/server/utils/syntax-highlighter.js.map +1 -0
  318. package/dist/src/server/voice-config.js +51 -0
  319. package/dist/src/server/voice-config.js.map +1 -0
  320. package/dist/src/server/voice-mcp-bridge-command.js +31 -0
  321. package/dist/src/server/voice-mcp-bridge-command.js.map +1 -0
  322. package/dist/src/server/voice-mcp-bridge.js +109 -0
  323. package/dist/src/server/voice-mcp-bridge.js.map +1 -0
  324. package/dist/src/server/voice-permission-policy.js +13 -0
  325. package/dist/src/server/voice-permission-policy.js.map +1 -0
  326. package/dist/src/server/voice-types.js +2 -0
  327. package/dist/src/server/voice-types.js.map +1 -0
  328. package/dist/src/server/websocket-server.js +967 -0
  329. package/dist/src/server/websocket-server.js.map +1 -0
  330. package/dist/src/server/worktree-bootstrap.js +497 -0
  331. package/dist/src/server/worktree-bootstrap.js.map +1 -0
  332. package/dist/src/shared/agent-attention-notification.js +130 -0
  333. package/dist/src/shared/agent-attention-notification.js.map +1 -0
  334. package/dist/src/shared/agent-lifecycle.js +8 -0
  335. package/dist/src/shared/agent-lifecycle.js.map +1 -0
  336. package/dist/src/shared/binary-mux.js +114 -0
  337. package/dist/src/shared/binary-mux.js.map +1 -0
  338. package/dist/src/shared/connection-offer.js +17 -0
  339. package/dist/src/shared/connection-offer.js.map +1 -0
  340. package/dist/src/shared/daemon-endpoints.js +113 -0
  341. package/dist/src/shared/daemon-endpoints.js.map +1 -0
  342. package/dist/src/shared/messages.js +2001 -0
  343. package/dist/src/shared/messages.js.map +1 -0
  344. package/dist/src/shared/path-utils.js +16 -0
  345. package/dist/src/shared/path-utils.js.map +1 -0
  346. package/dist/src/shared/tool-call-display.js +93 -0
  347. package/dist/src/shared/tool-call-display.js.map +1 -0
  348. package/dist/src/terminal/terminal-manager.js +136 -0
  349. package/dist/src/terminal/terminal-manager.js.map +1 -0
  350. package/dist/src/terminal/terminal.js +410 -0
  351. package/dist/src/terminal/terminal.js.map +1 -0
  352. package/dist/src/utils/checkout-git.js +1397 -0
  353. package/dist/src/utils/checkout-git.js.map +1 -0
  354. package/dist/src/utils/directory-suggestions.js +655 -0
  355. package/dist/src/utils/directory-suggestions.js.map +1 -0
  356. package/dist/src/utils/path.js +15 -0
  357. package/dist/src/utils/path.js.map +1 -0
  358. package/dist/src/utils/project-icon.js +391 -0
  359. package/dist/src/utils/project-icon.js.map +1 -0
  360. package/dist/src/utils/worktree-metadata.js +116 -0
  361. package/dist/src/utils/worktree-metadata.js.map +1 -0
  362. package/dist/src/utils/worktree.js +741 -0
  363. package/dist/src/utils/worktree.js.map +1 -0
  364. package/package.json +15 -7
@@ -1,16 +1,22 @@
1
- import { AgentCreateFailedStatusPayloadSchema, AgentCreatedStatusPayloadSchema, AgentRefreshedStatusPayloadSchema, AgentResumedStatusPayloadSchema, RestartRequestedStatusPayloadSchema, SessionInboundMessageSchema, WSOutboundMessageSchema, } from '../shared/messages.js';
1
+ import { AgentCreateFailedStatusPayloadSchema, AgentCreatedStatusPayloadSchema, AgentRefreshedStatusPayloadSchema, AgentResumedStatusPayloadSchema, RestartRequestedStatusPayloadSchema, ShutdownRequestedStatusPayloadSchema, SessionInboundMessageSchema, WSOutboundMessageSchema, } from '../shared/messages.js';
2
2
  import { getAgentProviderDefinition } from '../server/agent/provider-manifest.js';
3
3
  import { isRelayClientWebSocketUrl } from '../shared/daemon-endpoints.js';
4
4
  import { asUint8Array, decodeBinaryMuxFrame, encodeBinaryMuxFrame, BinaryMuxChannel, TerminalBinaryFlags, TerminalBinaryMessageType, } from '../shared/binary-mux.js';
5
5
  import { encodeTerminalKeyInput } from '../shared/terminal-key-input.js';
6
6
  import { TerminalStreamManager, } from './daemon-client-terminal-stream-manager.js';
7
- import { createRelayE2eeTransportFactory, createWebSocketTransportFactory, decodeMessageData, defaultWebSocketFactory, describeTransportClose, describeTransportError, encodeUtf8String, safeRandomId, } from './daemon-client-transport.js';
7
+ import { createRelayE2eeTransportFactory, createWebSocketTransportFactory, decodeMessageData, defaultWebSocketFactory, describeTransportClose, describeTransportError, encodeUtf8String, } from './daemon-client-transport.js';
8
8
  const consoleLogger = {
9
- debug: (obj, msg) => console.debug(msg, obj),
9
+ debug: () => { },
10
10
  info: (obj, msg) => console.info(msg, obj),
11
11
  warn: (obj, msg) => console.warn(msg, obj),
12
12
  error: (obj, msg) => console.error(msg, obj),
13
13
  };
14
+ function getNowMs() {
15
+ if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
16
+ return performance.now();
17
+ }
18
+ return Date.now();
19
+ }
14
20
  class DaemonRpcError extends Error {
15
21
  constructor(params) {
16
22
  super(params.error);
@@ -22,6 +28,7 @@ class DaemonRpcError extends Error {
22
28
  }
23
29
  const DEFAULT_RECONNECT_BASE_DELAY_MS = 1500;
24
30
  const DEFAULT_RECONNECT_MAX_DELAY_MS = 30000;
31
+ const DEFAULT_CONNECT_TIMEOUT_MS = 15000;
25
32
  /** Default timeout for waiting for connection before sending queued messages */
26
33
  const DEFAULT_SEND_QUEUE_TIMEOUT_MS = 10000;
27
34
  const DEFAULT_DICTATION_FINISH_ACCEPT_TIMEOUT_MS = 15000;
@@ -30,6 +37,42 @@ const DEFAULT_DICTATION_FINISH_TIMEOUT_GRACE_MS = 5000;
30
37
  function isWaiterTimeoutError(error) {
31
38
  return error instanceof Error && error.message.startsWith('Timeout waiting for message');
32
39
  }
40
+ function normalizeClientId(value) {
41
+ if (typeof value !== 'string') {
42
+ return null;
43
+ }
44
+ const trimmed = value.trim();
45
+ return trimmed.length > 0 ? trimmed : null;
46
+ }
47
+ function hashForLog(value) {
48
+ let hash = 0;
49
+ for (let index = 0; index < value.length; index += 1) {
50
+ hash = (hash * 31 + value.charCodeAt(index)) | 0;
51
+ }
52
+ return `h_${Math.abs(hash).toString(16)}`;
53
+ }
54
+ function toReasonCode(reason) {
55
+ if (!reason) {
56
+ return null;
57
+ }
58
+ const normalized = reason.toLowerCase();
59
+ if (normalized.includes('timed out')) {
60
+ return 'connect_timeout';
61
+ }
62
+ if (normalized.includes('disposed')) {
63
+ return 'disposed';
64
+ }
65
+ if (normalized.includes('client closed')) {
66
+ return 'client_closed';
67
+ }
68
+ if (normalized.includes('transport')) {
69
+ return 'transport_error';
70
+ }
71
+ if (normalized.includes('failed to connect')) {
72
+ return 'connect_failed';
73
+ }
74
+ return 'unknown';
75
+ }
33
76
  export class DaemonClient {
34
77
  constructor(config) {
35
78
  this.config = config;
@@ -42,6 +85,7 @@ export class DaemonClient {
42
85
  this.checkoutStatusInFlight = new Map();
43
86
  this.connectionListeners = new Set();
44
87
  this.reconnectTimeout = null;
88
+ this.connectTimeout = null;
45
89
  this.pendingGenericTransportErrorTimeout = null;
46
90
  this.reconnectAttempt = 0;
47
91
  this.shouldReconnect = true;
@@ -53,8 +97,28 @@ export class DaemonClient {
53
97
  this.checkoutDiffSubscriptions = new Map();
54
98
  this.terminalDirectorySubscriptions = new Set();
55
99
  this.pendingSendQueue = [];
56
- this.relayClientId = null;
100
+ this.lastWelcomeMessage = null;
57
101
  this.logger = config.logger ?? consoleLogger;
102
+ this.logConnectionPath = isRelayClientWebSocketUrl(this.config.url) ? 'relay' : 'direct';
103
+ let parsedUrlForLog = null;
104
+ try {
105
+ parsedUrlForLog = new URL(this.config.url);
106
+ }
107
+ catch {
108
+ parsedUrlForLog = null;
109
+ }
110
+ const parsedServerIdForLog = normalizeClientId(parsedUrlForLog?.searchParams.get('serverId'));
111
+ this.logServerId = parsedServerIdForLog ?? parsedUrlForLog?.host ?? null;
112
+ const resolvedClientId = normalizeClientId(this.config.clientId);
113
+ if (!resolvedClientId) {
114
+ throw new Error('Daemon client requires a non-empty clientId');
115
+ }
116
+ this.config.clientId = resolvedClientId;
117
+ this.logClientIdHash = hashForLog(resolvedClientId);
118
+ this.logGeneration =
119
+ typeof this.config.runtimeGeneration === 'number' && Number.isFinite(this.config.runtimeGeneration)
120
+ ? this.config.runtimeGeneration
121
+ : null;
58
122
  this.terminalStreams = new TerminalStreamManager({
59
123
  sendAck: (ack) => {
60
124
  this.sendBinaryFrame({
@@ -66,27 +130,22 @@ export class DaemonClient {
66
130
  });
67
131
  },
68
132
  });
69
- // Relay requires a clientId so the daemon can create an independent
70
- // socket + E2EE channel per connected client. Generate one per DaemonClient
71
- // instance (stable across reconnects in this tab/app session).
72
- if (isRelayClientWebSocketUrl(this.config.url)) {
73
- try {
74
- const parsed = new URL(this.config.url);
75
- if (!parsed.searchParams.get('clientId')) {
76
- this.relayClientId = `clt_${safeRandomId()}`;
77
- parsed.searchParams.set('clientId', this.relayClientId);
78
- this.config.url = parsed.toString();
79
- }
80
- }
81
- catch {
82
- // ignore - invalid URL will be handled on connect
83
- }
133
+ }
134
+ emitDiagnosticsEvent(event) {
135
+ try {
136
+ this.config.onDiagnosticsEvent?.(event);
137
+ }
138
+ catch {
139
+ // Diagnostics hooks must never break daemon message handling.
84
140
  }
85
141
  }
86
142
  // ============================================================================
87
143
  // Connection
88
144
  // ============================================================================
89
145
  async connect() {
146
+ if (this.connectionState.status === 'disposed') {
147
+ throw new Error('Daemon client is disposed');
148
+ }
90
149
  if (this.connectionState.status === 'connected') {
91
150
  return;
92
151
  }
@@ -102,6 +161,10 @@ export class DaemonClient {
102
161
  return this.connectPromise;
103
162
  }
104
163
  attemptConnect() {
164
+ if (this.connectionState.status === 'disposed') {
165
+ this.rejectConnect(new Error('Daemon client is disposed'));
166
+ return;
167
+ }
105
168
  if (!this.shouldReconnect) {
106
169
  this.rejectConnect(new Error('Daemon client is closed'));
107
170
  return;
@@ -114,10 +177,8 @@ export class DaemonClient {
114
177
  headers['Authorization'] = this.config.authHeader;
115
178
  }
116
179
  try {
117
- // If we reconnect while the previous socket is still open (common in browsers
118
- // where `onerror` may fire before `onclose`), we can end up with multiple
119
- // concurrent relay sockets. Cloudflare then closes the old one with
120
- // "Replaced by new connection", causing a disconnect loop.
180
+ // Reconnect can overlap with browser close/error delivery ordering.
181
+ // Always dispose previous transport before constructing the next one.
121
182
  this.disposeTransport();
122
183
  const baseTransportFactory = this.config.transportFactory ??
123
184
  createWebSocketTransportFactory(this.config.webSocketFactory ?? defaultWebSocketFactory);
@@ -134,12 +195,28 @@ export class DaemonClient {
134
195
  logger: this.logger,
135
196
  });
136
197
  }
137
- const transport = transportFactory({ url: this.config.url, headers });
198
+ const transportUrl = this.resolveTransportUrlForAttempt();
199
+ const transport = transportFactory({ url: transportUrl, headers });
138
200
  this.transport = transport;
201
+ this.lastWelcomeMessage = null;
139
202
  this.updateConnectionState({
140
203
  status: 'connecting',
141
204
  attempt: this.reconnectAttempt,
142
- });
205
+ }, { event: 'CONNECT_REQUEST' });
206
+ this.resetConnectTimeout();
207
+ const timeoutMs = Math.max(1, this.config.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS);
208
+ this.connectTimeout = setTimeout(() => {
209
+ if (this.connectionState.status !== 'connecting') {
210
+ return;
211
+ }
212
+ this.lastErrorValue = 'Connection timed out';
213
+ this.disposeTransport(1001, 'Connection timed out');
214
+ this.scheduleReconnect({
215
+ reason: 'Connection timed out',
216
+ event: 'CONNECT_TIMEOUT',
217
+ reasonCode: 'connect_timeout',
218
+ });
219
+ }, timeoutMs);
143
220
  this.transportCleanup = [
144
221
  transport.onOpen(() => {
145
222
  if (this.pendingGenericTransportErrorTimeout) {
@@ -147,48 +224,26 @@ export class DaemonClient {
147
224
  this.pendingGenericTransportErrorTimeout = null;
148
225
  }
149
226
  this.lastErrorValue = null;
150
- this.reconnectAttempt = 0;
151
- this.updateConnectionState({ status: 'connected' });
152
- this.resubscribeCheckoutDiffSubscriptions();
153
- this.resubscribeTerminalDirectorySubscriptions();
154
- this.flushPendingSendQueue();
155
- this.resolveConnect();
227
+ this.sendHelloMessage();
156
228
  }),
157
229
  transport.onClose((event) => {
230
+ this.resetConnectTimeout();
158
231
  if (this.pendingGenericTransportErrorTimeout) {
159
232
  clearTimeout(this.pendingGenericTransportErrorTimeout);
160
233
  this.pendingGenericTransportErrorTimeout = null;
161
234
  }
162
- const closeRecord = event;
163
- const closeCode = closeRecord && typeof closeRecord === 'object' && typeof closeRecord.code === 'number'
164
- ? closeRecord.code
165
- : null;
166
- const closeReason = closeRecord && typeof closeRecord === 'object' && typeof closeRecord.reason === 'string'
167
- ? closeRecord.reason
168
- : null;
169
235
  const reason = describeTransportClose(event);
170
236
  if (reason) {
171
237
  this.lastErrorValue = reason;
172
238
  }
173
- this.updateConnectionState({
174
- status: 'disconnected',
175
- ...(reason ? { reason } : {}),
239
+ this.scheduleReconnect({
240
+ reason,
241
+ event: 'TRANSPORT_CLOSE',
242
+ reasonCode: 'transport_closed',
176
243
  });
177
- // When connecting over the relay, only one client connection is allowed at a time.
178
- // If another device/tab takes over, we should not auto-reconnect and "fight" the new
179
- // connection (which causes flapping where both sides repeatedly replace each other).
180
- if (isRelayClientWebSocketUrl(this.config.url) &&
181
- closeCode === 1008 &&
182
- (closeReason ?? reason) === 'Replaced by new connection') {
183
- this.shouldReconnect = false;
184
- this.clearWaiters(new Error(reason ?? 'Replaced by new connection'));
185
- this.rejectPendingSendQueue(new Error(reason ?? 'Replaced by new connection'));
186
- this.rejectConnect(new Error(reason ?? 'Replaced by new connection'));
187
- return;
188
- }
189
- this.scheduleReconnect(reason);
190
244
  }),
191
245
  transport.onError((event) => {
246
+ this.resetConnectTimeout();
192
247
  const reason = describeTransportError(event);
193
248
  const isGeneric = reason === 'Transport error';
194
249
  // Browser WebSocket.onerror often provides no useful details and is followed
@@ -202,8 +257,11 @@ export class DaemonClient {
202
257
  if (this.connectionState.status === 'connected' ||
203
258
  this.connectionState.status === 'connecting') {
204
259
  this.lastErrorValue = reason;
205
- this.updateConnectionState({ status: 'disconnected', reason });
206
- this.scheduleReconnect(reason);
260
+ this.scheduleReconnect({
261
+ reason,
262
+ event: 'TRANSPORT_ERROR',
263
+ reasonCode: 'transport_error',
264
+ });
207
265
  }
208
266
  }, 250);
209
267
  }
@@ -214,16 +272,24 @@ export class DaemonClient {
214
272
  this.pendingGenericTransportErrorTimeout = null;
215
273
  }
216
274
  this.lastErrorValue = reason;
217
- this.updateConnectionState({ status: 'disconnected', reason });
218
- this.scheduleReconnect(reason);
275
+ this.scheduleReconnect({
276
+ reason,
277
+ event: 'TRANSPORT_ERROR',
278
+ reasonCode: 'transport_error',
279
+ });
219
280
  }),
220
281
  transport.onMessage((data) => this.handleTransportMessage(data)),
221
282
  ];
222
283
  }
223
284
  catch (error) {
285
+ this.resetConnectTimeout();
224
286
  const message = error instanceof Error ? error.message : 'Failed to connect';
225
287
  this.lastErrorValue = message;
226
- this.scheduleReconnect(message);
288
+ this.scheduleReconnect({
289
+ reason: message,
290
+ event: 'CONNECT_FAILED',
291
+ reasonCode: 'connect_failed',
292
+ });
227
293
  this.rejectConnect(error instanceof Error ? error : new Error(message));
228
294
  }
229
295
  }
@@ -244,6 +310,9 @@ export class DaemonClient {
244
310
  this.connectReject = null;
245
311
  }
246
312
  async close() {
313
+ if (this.connectionState.status === 'disposed') {
314
+ return;
315
+ }
247
316
  this.shouldReconnect = false;
248
317
  this.connectPromise = null;
249
318
  this.connectResolve = null;
@@ -252,15 +321,18 @@ export class DaemonClient {
252
321
  clearTimeout(this.reconnectTimeout);
253
322
  this.reconnectTimeout = null;
254
323
  }
324
+ this.resetConnectTimeout();
255
325
  this.disposeTransport(1000, 'Client closed');
256
326
  this.clearWaiters(new Error('Daemon client closed'));
327
+ this.rejectPendingSendQueue(new Error('Daemon client closed'));
257
328
  this.terminalStreams.clearAll();
258
- this.updateConnectionState({
259
- status: 'disconnected',
260
- reason: 'client_closed',
261
- });
329
+ this.lastWelcomeMessage = null;
330
+ this.updateConnectionState({ status: 'disposed' }, { event: 'DISPOSE', reason: 'Client closed', reasonCode: 'disposed' });
262
331
  }
263
332
  ensureConnected() {
333
+ if (this.connectionState.status === 'disposed') {
334
+ return;
335
+ }
264
336
  if (!this.shouldReconnect) {
265
337
  this.shouldReconnect = true;
266
338
  }
@@ -589,6 +661,32 @@ export class DaemonClient {
589
661
  },
590
662
  });
591
663
  }
664
+ async fetchWorkspaces(options) {
665
+ const resolvedRequestId = this.createRequestId(options?.requestId);
666
+ const message = SessionInboundMessageSchema.parse({
667
+ type: 'fetch_workspaces_request',
668
+ requestId: resolvedRequestId,
669
+ ...(options?.filter ? { filter: options.filter } : {}),
670
+ ...(options?.sort ? { sort: options.sort } : {}),
671
+ ...(options?.page ? { page: options.page } : {}),
672
+ ...(options?.subscribe ? { subscribe: options.subscribe } : {}),
673
+ });
674
+ return this.sendRequest({
675
+ requestId: resolvedRequestId,
676
+ message,
677
+ timeout: 10000,
678
+ options: { skipQueue: true },
679
+ select: (msg) => {
680
+ if (msg.type !== 'fetch_workspaces_response') {
681
+ return null;
682
+ }
683
+ if (msg.payload.requestId !== resolvedRequestId) {
684
+ return null;
685
+ }
686
+ return msg.payload;
687
+ },
688
+ });
689
+ }
592
690
  async fetchAgent(agentId, requestId) {
593
691
  const resolvedRequestId = this.createRequestId(requestId);
594
692
  const message = SessionInboundMessageSchema.parse({
@@ -614,7 +712,10 @@ export class DaemonClient {
614
712
  if (payload.error) {
615
713
  throw new Error(payload.error);
616
714
  }
617
- return payload.agent;
715
+ if (!payload.agent) {
716
+ return null;
717
+ }
718
+ return { agent: payload.agent, project: payload.project ?? null };
618
719
  }
619
720
  resubscribeCheckoutDiffSubscriptions() {
620
721
  if (this.checkoutDiffSubscriptions.size === 0) {
@@ -653,6 +754,7 @@ export class DaemonClient {
653
754
  requestId,
654
755
  config,
655
756
  ...(options.initialPrompt ? { initialPrompt: options.initialPrompt } : {}),
757
+ ...(options.clientMessageId ? { clientMessageId: options.clientMessageId } : {}),
656
758
  ...(options.outputSchema ? { outputSchema: options.outputSchema } : {}),
657
759
  ...(options.images && options.images.length > 0 ? { images: options.images } : {}),
658
760
  ...(options.git ? { git: options.git } : {}),
@@ -991,6 +1093,32 @@ export class DaemonClient {
991
1093
  },
992
1094
  });
993
1095
  }
1096
+ async shutdownServer(requestId) {
1097
+ const resolvedRequestId = this.createRequestId(requestId);
1098
+ const message = SessionInboundMessageSchema.parse({
1099
+ type: 'shutdown_server_request',
1100
+ requestId: resolvedRequestId,
1101
+ });
1102
+ return this.sendRequest({
1103
+ requestId: resolvedRequestId,
1104
+ message,
1105
+ timeout: 10000,
1106
+ options: { skipQueue: true },
1107
+ select: (msg) => {
1108
+ if (msg.type !== 'status') {
1109
+ return null;
1110
+ }
1111
+ const shutdown = ShutdownRequestedStatusPayloadSchema.safeParse(msg.payload);
1112
+ if (!shutdown.success) {
1113
+ return null;
1114
+ }
1115
+ if (shutdown.data.requestId !== resolvedRequestId) {
1116
+ return null;
1117
+ }
1118
+ return shutdown.data;
1119
+ },
1120
+ });
1121
+ }
994
1122
  // ============================================================================
995
1123
  // Audio / Voice
996
1124
  // ============================================================================
@@ -1457,12 +1585,12 @@ export class DaemonClient {
1457
1585
  // ============================================================================
1458
1586
  // File Explorer
1459
1587
  // ============================================================================
1460
- async exploreFileSystem(agentId, path, mode = 'list', requestId) {
1588
+ async exploreFileSystem(cwd, path, mode = 'list', requestId) {
1461
1589
  return this.sendCorrelatedSessionRequest({
1462
1590
  requestId,
1463
1591
  message: {
1464
1592
  type: 'file_explorer_request',
1465
- agentId,
1593
+ cwd,
1466
1594
  path,
1467
1595
  mode,
1468
1596
  },
@@ -1470,12 +1598,12 @@ export class DaemonClient {
1470
1598
  timeout: 10000,
1471
1599
  });
1472
1600
  }
1473
- async requestDownloadToken(agentId, path, requestId) {
1601
+ async requestDownloadToken(cwd, path, requestId) {
1474
1602
  return this.sendCorrelatedSessionRequest({
1475
1603
  requestId,
1476
1604
  message: {
1477
1605
  type: 'file_download_token_request',
1478
- agentId,
1606
+ cwd,
1479
1607
  path,
1480
1608
  },
1481
1609
  responseType: 'file_download_token_response',
@@ -1505,7 +1633,8 @@ export class DaemonClient {
1505
1633
  cwd: options?.cwd,
1506
1634
  },
1507
1635
  responseType: 'list_provider_models_response',
1508
- timeout: 30000,
1636
+ // Provider SDK cold starts (especially model discovery) can exceed 30s.
1637
+ timeout: 45000,
1509
1638
  });
1510
1639
  }
1511
1640
  async listAvailableProviders(options) {
@@ -1594,29 +1723,106 @@ export class DaemonClient {
1594
1723
  // Waiting / Streaming Helpers
1595
1724
  // ============================================================================
1596
1725
  async waitForAgentUpsert(agentId, predicate, timeout = 60000) {
1597
- const startedAt = Date.now();
1598
- while (Date.now() - startedAt < timeout) {
1599
- const snapshot = await this.fetchAgent(agentId).catch(() => null);
1600
- if (snapshot && predicate(snapshot)) {
1601
- return snapshot;
1602
- }
1603
- await new Promise((resolve) => setTimeout(resolve, 250));
1604
- }
1605
- throw new Error(`Timed out waiting for agent ${agentId}`);
1726
+ const initialResult = await this.fetchAgent(agentId).catch(() => null);
1727
+ if (initialResult && predicate(initialResult.agent)) {
1728
+ return initialResult.agent;
1729
+ }
1730
+ const deadline = Date.now() + timeout;
1731
+ return await new Promise((resolve, reject) => {
1732
+ let settled = false;
1733
+ let pollInFlight = false;
1734
+ let pollTimer = null;
1735
+ let timeoutTimer = null;
1736
+ let unsubscribe = null;
1737
+ const finish = (result) => {
1738
+ if (settled) {
1739
+ return;
1740
+ }
1741
+ settled = true;
1742
+ if (timeoutTimer) {
1743
+ clearTimeout(timeoutTimer);
1744
+ timeoutTimer = null;
1745
+ }
1746
+ if (pollTimer) {
1747
+ clearInterval(pollTimer);
1748
+ pollTimer = null;
1749
+ }
1750
+ if (unsubscribe) {
1751
+ unsubscribe();
1752
+ unsubscribe = null;
1753
+ }
1754
+ if (result.kind === 'ok') {
1755
+ resolve(result.snapshot);
1756
+ return;
1757
+ }
1758
+ reject(result.error);
1759
+ };
1760
+ const maybeResolve = (snapshot) => {
1761
+ if (!snapshot) {
1762
+ return false;
1763
+ }
1764
+ if (!predicate(snapshot)) {
1765
+ return false;
1766
+ }
1767
+ finish({ kind: 'ok', snapshot });
1768
+ return true;
1769
+ };
1770
+ const poll = async () => {
1771
+ if (settled || pollInFlight) {
1772
+ return;
1773
+ }
1774
+ pollInFlight = true;
1775
+ try {
1776
+ const result = await this.fetchAgent(agentId).catch(() => null);
1777
+ maybeResolve(result?.agent ?? null);
1778
+ }
1779
+ finally {
1780
+ pollInFlight = false;
1781
+ }
1782
+ };
1783
+ unsubscribe = this.on('agent_update', (message) => {
1784
+ if (settled) {
1785
+ return;
1786
+ }
1787
+ if (message.type !== 'agent_update') {
1788
+ return;
1789
+ }
1790
+ if (message.payload.kind !== 'upsert') {
1791
+ return;
1792
+ }
1793
+ const snapshot = message.payload.agent;
1794
+ if (snapshot.id !== agentId) {
1795
+ return;
1796
+ }
1797
+ maybeResolve(snapshot);
1798
+ });
1799
+ const remaining = Math.max(1, deadline - Date.now());
1800
+ timeoutTimer = setTimeout(() => {
1801
+ finish({
1802
+ kind: 'error',
1803
+ error: new Error(`Timed out waiting for agent ${agentId}`),
1804
+ });
1805
+ }, remaining);
1806
+ pollTimer = setInterval(() => {
1807
+ void poll();
1808
+ }, 250);
1809
+ void poll();
1810
+ });
1606
1811
  }
1607
1812
  async waitForFinish(agentId, timeout = 60000) {
1608
1813
  const requestId = this.createRequestId();
1814
+ const hasTimeout = Number.isFinite(timeout) && timeout > 0;
1609
1815
  const message = SessionInboundMessageSchema.parse({
1610
1816
  type: 'wait_for_finish_request',
1611
1817
  requestId,
1612
1818
  agentId,
1613
- timeoutMs: timeout,
1819
+ ...(hasTimeout ? { timeoutMs: timeout } : {}),
1614
1820
  });
1615
1821
  const payload = await this.sendCorrelatedRequest({
1616
1822
  requestId,
1617
1823
  message,
1618
1824
  responseType: 'wait_for_finish_response',
1619
- timeout: timeout + 5000,
1825
+ timeout: hasTimeout ? timeout + 5000 : 0,
1620
1826
  options: { skipQueue: true },
1621
1827
  });
1622
1828
  return {
@@ -1822,6 +2028,39 @@ export class DaemonClient {
1822
2028
  createRequestId(requestId) {
1823
2029
  return requestId ?? crypto.randomUUID();
1824
2030
  }
2031
+ getLastWelcomeMessage() {
2032
+ return this.lastWelcomeMessage;
2033
+ }
2034
+ resolveTransportUrlForAttempt() {
2035
+ return this.config.url;
2036
+ }
2037
+ sendHelloMessage() {
2038
+ if (!this.transport) {
2039
+ this.scheduleReconnect({
2040
+ reason: 'Transport unavailable before hello',
2041
+ event: 'HELLO_TRANSPORT_MISSING',
2042
+ reasonCode: 'transport_error',
2043
+ });
2044
+ return;
2045
+ }
2046
+ try {
2047
+ this.transport.send(JSON.stringify({
2048
+ type: 'hello',
2049
+ clientId: this.config.clientId,
2050
+ clientType: this.config.clientType ?? 'cli',
2051
+ protocolVersion: 1,
2052
+ }));
2053
+ }
2054
+ catch (error) {
2055
+ const message = error instanceof Error ? error.message : 'Failed to send hello message';
2056
+ this.lastErrorValue = message;
2057
+ this.scheduleReconnect({
2058
+ reason: message,
2059
+ event: 'HELLO_SEND_FAILED',
2060
+ reasonCode: 'transport_error',
2061
+ });
2062
+ }
2063
+ }
1825
2064
  disposeTransport(code = 1001, reason = 'Reconnecting') {
1826
2065
  this.cleanupTransport();
1827
2066
  if (this.transport) {
@@ -1835,6 +2074,7 @@ export class DaemonClient {
1835
2074
  }
1836
2075
  }
1837
2076
  cleanupTransport() {
2077
+ this.resetConnectTimeout();
1838
2078
  if (this.pendingGenericTransportErrorTimeout) {
1839
2079
  clearTimeout(this.pendingGenericTransportErrorTimeout);
1840
2080
  this.pendingGenericTransportErrorTimeout = null;
@@ -1849,12 +2089,39 @@ export class DaemonClient {
1849
2089
  }
1850
2090
  this.transportCleanup = [];
1851
2091
  }
2092
+ resetConnectTimeout() {
2093
+ if (!this.connectTimeout) {
2094
+ return;
2095
+ }
2096
+ clearTimeout(this.connectTimeout);
2097
+ this.connectTimeout = null;
2098
+ }
1852
2099
  handleTransportMessage(data) {
2100
+ const startedAtMs = getNowMs();
1853
2101
  const rawData = data && typeof data === 'object' && 'data' in data ? data.data : data;
2102
+ if (typeof Blob !== 'undefined' &&
2103
+ rawData instanceof Blob &&
2104
+ typeof rawData.arrayBuffer === 'function') {
2105
+ void rawData
2106
+ .arrayBuffer()
2107
+ .then((buffer) => {
2108
+ this.handleTransportMessage(buffer);
2109
+ })
2110
+ .catch(() => {
2111
+ // Ignore failed blob decoding and allow reconnect logic to recover.
2112
+ });
2113
+ return;
2114
+ }
1854
2115
  const rawBytes = asUint8Array(rawData);
1855
2116
  if (rawBytes) {
1856
2117
  const frame = decodeBinaryMuxFrame(rawBytes);
1857
2118
  if (frame) {
2119
+ this.emitDiagnosticsEvent({
2120
+ type: 'transport_binary_frame',
2121
+ channel: frame.channel,
2122
+ messageType: frame.messageType,
2123
+ payloadBytes: frame.payload?.byteLength ?? 0,
2124
+ });
1858
2125
  this.handleBinaryFrame(frame);
1859
2126
  return;
1860
2127
  }
@@ -1864,21 +2131,64 @@ export class DaemonClient {
1864
2131
  return;
1865
2132
  }
1866
2133
  let parsedJson;
2134
+ let parseMs = 0;
1867
2135
  try {
2136
+ const parseStartedAtMs = getNowMs();
1868
2137
  parsedJson = JSON.parse(payload);
2138
+ parseMs = getNowMs() - parseStartedAtMs;
1869
2139
  }
1870
2140
  catch {
2141
+ this.emitDiagnosticsEvent({
2142
+ type: 'transport_message_timing',
2143
+ messageType: 'unknown',
2144
+ payloadBytes: payload.length,
2145
+ parseMs: 0,
2146
+ validateMs: 0,
2147
+ totalMs: getNowMs() - startedAtMs,
2148
+ outcome: 'parse_error',
2149
+ });
1871
2150
  return;
1872
2151
  }
2152
+ const validateStartedAtMs = getNowMs();
1873
2153
  const parsed = WSOutboundMessageSchema.safeParse(parsedJson);
2154
+ const validateMs = getNowMs() - validateStartedAtMs;
1874
2155
  if (!parsed.success) {
1875
- const msgType = parsedJson?.message?.type ?? 'unknown';
2156
+ const msgType = parsedJson?.type ?? 'unknown';
2157
+ this.emitDiagnosticsEvent({
2158
+ type: 'transport_message_timing',
2159
+ messageType: msgType,
2160
+ payloadBytes: payload.length,
2161
+ parseMs,
2162
+ validateMs,
2163
+ totalMs: getNowMs() - startedAtMs,
2164
+ outcome: 'validation_error',
2165
+ });
1876
2166
  this.logger.warn({ msgType, error: parsed.error.message }, 'Message validation failed');
1877
2167
  return;
1878
2168
  }
2169
+ this.emitDiagnosticsEvent({
2170
+ type: 'transport_message_timing',
2171
+ messageType: parsed.data.type,
2172
+ payloadBytes: payload.length,
2173
+ parseMs,
2174
+ validateMs,
2175
+ totalMs: getNowMs() - startedAtMs,
2176
+ outcome: 'ok',
2177
+ });
1879
2178
  if (parsed.data.type === 'pong') {
1880
2179
  return;
1881
2180
  }
2181
+ if (parsed.data.type === 'welcome') {
2182
+ this.lastWelcomeMessage = parsed.data;
2183
+ this.resetConnectTimeout();
2184
+ this.reconnectAttempt = 0;
2185
+ this.updateConnectionState({ status: 'connected' }, { event: 'HELLO_WELCOME' });
2186
+ this.resubscribeCheckoutDiffSubscriptions();
2187
+ this.resubscribeTerminalDirectorySubscriptions();
2188
+ this.flushPendingSendQueue();
2189
+ this.resolveConnect();
2190
+ return;
2191
+ }
1882
2192
  this.handleSessionMessage(parsed.data.message);
1883
2193
  }
1884
2194
  handleBinaryFrame(frame) {
@@ -1895,8 +2205,25 @@ export class DaemonClient {
1895
2205
  return;
1896
2206
  }
1897
2207
  }
1898
- updateConnectionState(next) {
2208
+ updateConnectionState(next, metadata) {
2209
+ const previous = this.connectionState;
1899
2210
  this.connectionState = next;
2211
+ const reasonFromNext = next.status === 'disconnected' && typeof next.reason === 'string'
2212
+ ? next.reason
2213
+ : null;
2214
+ const reason = metadata?.reason ?? reasonFromNext;
2215
+ const reasonCode = metadata?.reasonCode ?? toReasonCode(reason);
2216
+ this.logger.debug({
2217
+ serverId: this.logServerId,
2218
+ clientIdHash: this.logClientIdHash,
2219
+ from: previous.status,
2220
+ to: next.status,
2221
+ event: metadata?.event ?? 'STATE_UPDATE',
2222
+ connectionPath: this.logConnectionPath,
2223
+ generation: this.logGeneration,
2224
+ reasonCode,
2225
+ reason,
2226
+ }, 'DaemonClientTransition');
1900
2227
  for (const listener of this.connectionListeners) {
1901
2228
  try {
1902
2229
  listener(next);
@@ -1906,20 +2233,13 @@ export class DaemonClient {
1906
2233
  }
1907
2234
  }
1908
2235
  }
1909
- scheduleReconnect(reason) {
2236
+ scheduleReconnect(input) {
1910
2237
  if (this.reconnectTimeout) {
1911
2238
  clearTimeout(this.reconnectTimeout);
1912
2239
  this.reconnectTimeout = null;
1913
2240
  }
1914
- if (!this.shouldReconnect || this.config.reconnect?.enabled === false) {
1915
- this.rejectConnect(new Error(reason ?? 'Transport disconnected before connect'));
1916
- return;
1917
- }
1918
- const attempt = this.reconnectAttempt;
1919
- const baseDelay = this.config.reconnect?.baseDelayMs ?? DEFAULT_RECONNECT_BASE_DELAY_MS;
1920
- const maxDelay = this.config.reconnect?.maxDelayMs ?? DEFAULT_RECONNECT_MAX_DELAY_MS;
1921
- const delay = Math.min(baseDelay * 2 ** attempt, maxDelay);
1922
- this.reconnectAttempt = attempt + 1;
2241
+ const wasDisposed = this.connectionState.status === 'disposed';
2242
+ const reason = input?.reason;
1923
2243
  if (typeof reason === 'string' && reason.trim().length > 0) {
1924
2244
  this.lastErrorValue = reason.trim();
1925
2245
  }
@@ -1928,10 +2248,28 @@ export class DaemonClient {
1928
2248
  this.clearWaiters(new Error(reason ?? 'Connection lost'));
1929
2249
  this.rejectPendingSendQueue(new Error(reason ?? 'Connection lost'));
1930
2250
  this.terminalStreams.clearAll();
2251
+ this.lastWelcomeMessage = null;
2252
+ if (wasDisposed) {
2253
+ this.rejectConnect(new Error(reason ?? 'Daemon client is disposed'));
2254
+ return;
2255
+ }
1931
2256
  this.updateConnectionState({
1932
2257
  status: 'disconnected',
1933
2258
  ...(reason ? { reason } : {}),
2259
+ }, {
2260
+ event: input?.event ?? 'TRANSPORT_CLOSE',
2261
+ ...(reason ? { reason } : {}),
2262
+ ...(input?.reasonCode ? { reasonCode: input.reasonCode } : {}),
1934
2263
  });
2264
+ if (!this.shouldReconnect || this.config.reconnect?.enabled === false) {
2265
+ this.rejectConnect(new Error(reason ?? 'Transport disconnected before connect'));
2266
+ return;
2267
+ }
2268
+ const attempt = this.reconnectAttempt;
2269
+ const baseDelay = this.config.reconnect?.baseDelayMs ?? DEFAULT_RECONNECT_BASE_DELAY_MS;
2270
+ const maxDelay = this.config.reconnect?.maxDelayMs ?? DEFAULT_RECONNECT_MAX_DELAY_MS;
2271
+ const delay = Math.min(baseDelay * 2 ** attempt, maxDelay);
2272
+ this.reconnectAttempt = attempt + 1;
1935
2273
  this.reconnectTimeout = setTimeout(() => {
1936
2274
  this.reconnectTimeout = null;
1937
2275
  if (!this.shouldReconnect) {
@@ -2002,6 +2340,12 @@ export class DaemonClient {
2002
2340
  agentId: msg.payload.kind === 'upsert' ? msg.payload.agent.id : msg.payload.agentId,
2003
2341
  payload: msg.payload,
2004
2342
  };
2343
+ case 'workspace_update':
2344
+ return {
2345
+ type: 'workspace_update',
2346
+ workspaceId: msg.payload.kind === 'upsert' ? msg.payload.workspace.id : msg.payload.id,
2347
+ payload: msg.payload,
2348
+ };
2005
2349
  case 'agent_stream':
2006
2350
  return {
2007
2351
  type: 'agent_stream',