@getpaseo/server 0.1.35 → 0.1.38

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 (363) hide show
  1. package/dist/scripts/dev-runner.js +1 -1
  2. package/dist/scripts/dev-runner.js.map +1 -1
  3. package/dist/scripts/{daemon-runner.js → supervisor-entrypoint.js} +38 -10
  4. package/dist/scripts/supervisor-entrypoint.js.map +1 -0
  5. package/dist/scripts/supervisor.js +33 -7
  6. package/dist/scripts/supervisor.js.map +1 -1
  7. package/dist/server/client/daemon-client.d.ts +175 -0
  8. package/dist/server/client/daemon-client.d.ts.map +1 -1
  9. package/dist/server/client/daemon-client.js +235 -0
  10. package/dist/server/client/daemon-client.js.map +1 -1
  11. package/dist/server/server/agent/agent-manager.d.ts +13 -0
  12. package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
  13. package/dist/server/server/agent/agent-manager.js +53 -0
  14. package/dist/server/server/agent/agent-manager.js.map +1 -1
  15. package/dist/server/server/agent/agent-storage.d.ts +10 -10
  16. package/dist/server/server/agent/agent-storage.js +9 -4
  17. package/dist/server/server/agent/agent-storage.js.map +1 -1
  18. package/dist/server/server/agent/provider-launch-config.d.ts.map +1 -1
  19. package/dist/server/server/agent/provider-launch-config.js +38 -1
  20. package/dist/server/server/agent/provider-launch-config.js.map +1 -1
  21. package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
  22. package/dist/server/server/agent/providers/claude-agent.js +24 -5
  23. package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
  24. package/dist/server/server/agent-attention-policy.d.ts +1 -1
  25. package/dist/server/server/agent-attention-policy.d.ts.map +1 -1
  26. package/dist/server/server/bootstrap.d.ts +0 -4
  27. package/dist/server/server/bootstrap.d.ts.map +1 -1
  28. package/dist/server/server/bootstrap.js +65 -40
  29. package/dist/server/server/bootstrap.js.map +1 -1
  30. package/dist/server/server/chat/chat-mentions.d.ts +31 -0
  31. package/dist/server/server/chat/chat-mentions.d.ts.map +1 -0
  32. package/dist/server/server/chat/chat-mentions.js +71 -0
  33. package/dist/server/server/chat/chat-mentions.js.map +1 -0
  34. package/dist/server/server/chat/chat-rpc-schemas.d.ts +728 -0
  35. package/dist/server/server/chat/chat-rpc-schemas.d.ts.map +1 -0
  36. package/dist/server/server/chat/chat-rpc-schemas.js +103 -0
  37. package/dist/server/server/chat/chat-rpc-schemas.js.map +1 -0
  38. package/dist/server/server/chat/chat-service.d.ts +74 -0
  39. package/dist/server/server/chat/chat-service.d.ts.map +1 -0
  40. package/dist/server/server/chat/chat-service.js +330 -0
  41. package/dist/server/server/chat/chat-service.js.map +1 -0
  42. package/dist/server/server/chat/chat-types.d.ts +75 -0
  43. package/dist/server/server/chat/chat-types.d.ts.map +1 -0
  44. package/dist/server/server/chat/chat-types.js +22 -0
  45. package/dist/server/server/chat/chat-types.js.map +1 -0
  46. package/dist/server/server/checkout-diff-manager.d.ts +41 -0
  47. package/dist/server/server/checkout-diff-manager.d.ts.map +1 -0
  48. package/dist/server/server/checkout-diff-manager.js +272 -0
  49. package/dist/server/server/checkout-diff-manager.js.map +1 -0
  50. package/dist/server/server/checkout-git-utils.d.ts +9 -0
  51. package/dist/server/server/checkout-git-utils.d.ts.map +1 -0
  52. package/dist/server/server/checkout-git-utils.js +37 -0
  53. package/dist/server/server/checkout-git-utils.js.map +1 -0
  54. package/dist/server/server/index.js +0 -4
  55. package/dist/server/server/index.js.map +1 -1
  56. package/dist/server/server/loop/rpc-schemas.d.ts +2937 -0
  57. package/dist/server/server/loop/rpc-schemas.d.ts.map +1 -0
  58. package/dist/server/server/loop/rpc-schemas.js +159 -0
  59. package/dist/server/server/loop/rpc-schemas.js.map +1 -0
  60. package/dist/server/server/loop-service.d.ts +520 -0
  61. package/dist/server/server/loop-service.d.ts.map +1 -0
  62. package/dist/server/server/loop-service.js +741 -0
  63. package/dist/server/server/loop-service.js.map +1 -0
  64. package/dist/server/server/persisted-config.d.ts +10 -10
  65. package/dist/server/server/pid-lock.d.ts +7 -2
  66. package/dist/server/server/pid-lock.d.ts.map +1 -1
  67. package/dist/server/server/pid-lock.js +21 -0
  68. package/dist/server/server/pid-lock.js.map +1 -1
  69. package/dist/server/server/schedule/cron.d.ts +4 -0
  70. package/dist/server/server/schedule/cron.d.ts.map +1 -0
  71. package/dist/server/server/schedule/cron.js +103 -0
  72. package/dist/server/server/schedule/cron.js.map +1 -0
  73. package/dist/server/server/schedule/rpc-schemas.d.ts +2773 -0
  74. package/dist/server/server/schedule/rpc-schemas.d.ts.map +1 -0
  75. package/dist/server/server/schedule/rpc-schemas.js +112 -0
  76. package/dist/server/server/schedule/rpc-schemas.js.map +1 -0
  77. package/dist/server/server/schedule/service.d.ts +39 -0
  78. package/dist/server/server/schedule/service.d.ts.map +1 -0
  79. package/dist/server/server/schedule/service.js +397 -0
  80. package/dist/server/server/schedule/service.js.map +1 -0
  81. package/dist/server/server/schedule/store.d.ts +13 -0
  82. package/dist/server/server/schedule/store.d.ts.map +1 -0
  83. package/dist/server/server/schedule/store.js +56 -0
  84. package/dist/server/server/schedule/store.js.map +1 -0
  85. package/dist/server/server/schedule/types.d.ts +710 -0
  86. package/dist/server/server/schedule/types.d.ts.map +1 -0
  87. package/dist/server/server/schedule/types.js +73 -0
  88. package/dist/server/server/schedule/types.js.map +1 -0
  89. package/dist/server/server/session.d.ts +40 -19
  90. package/dist/server/server/session.d.ts.map +1 -1
  91. package/dist/server/server/session.js +779 -568
  92. package/dist/server/server/session.js.map +1 -1
  93. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.d.ts.map +1 -1
  94. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.js +19 -3
  95. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.js.map +1 -1
  96. package/dist/server/server/websocket-server.d.ts +12 -1
  97. package/dist/server/server/websocket-server.d.ts.map +1 -1
  98. package/dist/server/server/websocket-server.js +71 -14
  99. package/dist/server/server/websocket-server.js.map +1 -1
  100. package/dist/server/shared/messages.d.ts +37933 -16895
  101. package/dist/server/shared/messages.d.ts.map +1 -1
  102. package/dist/server/shared/messages.js +41 -0
  103. package/dist/server/shared/messages.js.map +1 -1
  104. package/dist/server/terminal/terminal-manager.js +2 -2
  105. package/dist/server/terminal/terminal-manager.js.map +1 -1
  106. package/dist/server/utils/checkout-git.d.ts +12 -0
  107. package/dist/server/utils/checkout-git.d.ts.map +1 -1
  108. package/dist/server/utils/checkout-git.js +73 -3
  109. package/dist/server/utils/checkout-git.js.map +1 -1
  110. package/dist/server/utils/directory-suggestions.js +20 -4
  111. package/dist/server/utils/directory-suggestions.js.map +1 -1
  112. package/dist/src/server/pid-lock.js +21 -0
  113. package/dist/src/server/pid-lock.js.map +1 -1
  114. package/dist/src/server/speech/providers/local/sherpa/sherpa-runtime-env.js +19 -3
  115. package/dist/src/server/speech/providers/local/sherpa/sherpa-runtime-env.js.map +1 -1
  116. package/package.json +4 -3
  117. package/dist/scripts/daemon-runner.js.map +0 -1
  118. package/dist/src/server/agent/activity-curator.js +0 -243
  119. package/dist/src/server/agent/activity-curator.js.map +0 -1
  120. package/dist/src/server/agent/agent-manager.js +0 -1802
  121. package/dist/src/server/agent/agent-manager.js.map +0 -1
  122. package/dist/src/server/agent/agent-metadata-generator.js +0 -161
  123. package/dist/src/server/agent/agent-metadata-generator.js.map +0 -1
  124. package/dist/src/server/agent/agent-projections.js +0 -254
  125. package/dist/src/server/agent/agent-projections.js.map +0 -1
  126. package/dist/src/server/agent/agent-response-loop.js +0 -304
  127. package/dist/src/server/agent/agent-response-loop.js.map +0 -1
  128. package/dist/src/server/agent/agent-sdk-types.js +0 -12
  129. package/dist/src/server/agent/agent-sdk-types.js.map +0 -1
  130. package/dist/src/server/agent/agent-storage.js +0 -297
  131. package/dist/src/server/agent/agent-storage.js.map +0 -1
  132. package/dist/src/server/agent/agent-title-limits.js +0 -3
  133. package/dist/src/server/agent/agent-title-limits.js.map +0 -1
  134. package/dist/src/server/agent/audio-utils.js +0 -19
  135. package/dist/src/server/agent/audio-utils.js.map +0 -1
  136. package/dist/src/server/agent/dictation-debug.js +0 -50
  137. package/dist/src/server/agent/dictation-debug.js.map +0 -1
  138. package/dist/src/server/agent/mcp-server.js +0 -754
  139. package/dist/src/server/agent/mcp-server.js.map +0 -1
  140. package/dist/src/server/agent/orchestrator-instructions.js +0 -51
  141. package/dist/src/server/agent/orchestrator-instructions.js.map +0 -1
  142. package/dist/src/server/agent/pcm16-resampler.js +0 -63
  143. package/dist/src/server/agent/pcm16-resampler.js.map +0 -1
  144. package/dist/src/server/agent/provider-launch-config.js +0 -176
  145. package/dist/src/server/agent/provider-launch-config.js.map +0 -1
  146. package/dist/src/server/agent/provider-manifest.js +0 -127
  147. package/dist/src/server/agent/provider-manifest.js.map +0 -1
  148. package/dist/src/server/agent/provider-registry.js +0 -45
  149. package/dist/src/server/agent/provider-registry.js.map +0 -1
  150. package/dist/src/server/agent/providers/claude/partial-json.js +0 -306
  151. package/dist/src/server/agent/providers/claude/partial-json.js.map +0 -1
  152. package/dist/src/server/agent/providers/claude/sdk-model-resolver.js +0 -104
  153. package/dist/src/server/agent/providers/claude/sdk-model-resolver.js.map +0 -1
  154. package/dist/src/server/agent/providers/claude/sidechain-tracker.js +0 -230
  155. package/dist/src/server/agent/providers/claude/sidechain-tracker.js.map +0 -1
  156. package/dist/src/server/agent/providers/claude/task-notification-tool-call.js +0 -267
  157. package/dist/src/server/agent/providers/claude/task-notification-tool-call.js.map +0 -1
  158. package/dist/src/server/agent/providers/claude/tool-call-detail-parser.js +0 -121
  159. package/dist/src/server/agent/providers/claude/tool-call-detail-parser.js.map +0 -1
  160. package/dist/src/server/agent/providers/claude/tool-call-mapper.js +0 -252
  161. package/dist/src/server/agent/providers/claude/tool-call-mapper.js.map +0 -1
  162. package/dist/src/server/agent/providers/claude-agent.js +0 -3147
  163. package/dist/src/server/agent/providers/claude-agent.js.map +0 -1
  164. package/dist/src/server/agent/providers/codex/tool-call-detail-parser.js +0 -104
  165. package/dist/src/server/agent/providers/codex/tool-call-detail-parser.js.map +0 -1
  166. package/dist/src/server/agent/providers/codex/tool-call-mapper.js +0 -758
  167. package/dist/src/server/agent/providers/codex/tool-call-mapper.js.map +0 -1
  168. package/dist/src/server/agent/providers/codex-app-server-agent.js +0 -2949
  169. package/dist/src/server/agent/providers/codex-app-server-agent.js.map +0 -1
  170. package/dist/src/server/agent/providers/codex-rollout-timeline.js +0 -544
  171. package/dist/src/server/agent/providers/codex-rollout-timeline.js.map +0 -1
  172. package/dist/src/server/agent/providers/opencode/tool-call-detail-parser.js +0 -39
  173. package/dist/src/server/agent/providers/opencode/tool-call-detail-parser.js.map +0 -1
  174. package/dist/src/server/agent/providers/opencode/tool-call-mapper.js +0 -144
  175. package/dist/src/server/agent/providers/opencode/tool-call-mapper.js.map +0 -1
  176. package/dist/src/server/agent/providers/opencode-agent.js +0 -1193
  177. package/dist/src/server/agent/providers/opencode-agent.js.map +0 -1
  178. package/dist/src/server/agent/providers/tool-call-detail-primitives.js +0 -686
  179. package/dist/src/server/agent/providers/tool-call-detail-primitives.js.map +0 -1
  180. package/dist/src/server/agent/providers/tool-call-mapper-utils.js +0 -115
  181. package/dist/src/server/agent/providers/tool-call-mapper-utils.js.map +0 -1
  182. package/dist/src/server/agent/recordings-debug.js +0 -19
  183. package/dist/src/server/agent/recordings-debug.js.map +0 -1
  184. package/dist/src/server/agent/stt-debug.js +0 -33
  185. package/dist/src/server/agent/stt-debug.js.map +0 -1
  186. package/dist/src/server/agent/stt-manager.js +0 -232
  187. package/dist/src/server/agent/stt-manager.js.map +0 -1
  188. package/dist/src/server/agent/timeline-append.js +0 -27
  189. package/dist/src/server/agent/timeline-append.js.map +0 -1
  190. package/dist/src/server/agent/timeline-projection.js +0 -215
  191. package/dist/src/server/agent/timeline-projection.js.map +0 -1
  192. package/dist/src/server/agent/tool-name-normalization.js +0 -45
  193. package/dist/src/server/agent/tool-name-normalization.js.map +0 -1
  194. package/dist/src/server/agent/tts-debug.js +0 -24
  195. package/dist/src/server/agent/tts-debug.js.map +0 -1
  196. package/dist/src/server/agent/tts-manager.js +0 -374
  197. package/dist/src/server/agent/tts-manager.js.map +0 -1
  198. package/dist/src/server/agent/wait-for-agent-tracker.js +0 -53
  199. package/dist/src/server/agent/wait-for-agent-tracker.js.map +0 -1
  200. package/dist/src/server/agent-attention-policy.js +0 -40
  201. package/dist/src/server/agent-attention-policy.js.map +0 -1
  202. package/dist/src/server/allowed-hosts.js +0 -94
  203. package/dist/src/server/allowed-hosts.js.map +0 -1
  204. package/dist/src/server/bootstrap.js +0 -581
  205. package/dist/src/server/bootstrap.js.map +0 -1
  206. package/dist/src/server/client-message-id.js +0 -12
  207. package/dist/src/server/client-message-id.js.map +0 -1
  208. package/dist/src/server/config.js +0 -73
  209. package/dist/src/server/config.js.map +0 -1
  210. package/dist/src/server/connection-offer.js +0 -59
  211. package/dist/src/server/connection-offer.js.map +0 -1
  212. package/dist/src/server/daemon-keypair.js +0 -40
  213. package/dist/src/server/daemon-keypair.js.map +0 -1
  214. package/dist/src/server/daemon-version.js +0 -22
  215. package/dist/src/server/daemon-version.js.map +0 -1
  216. package/dist/src/server/dictation/dictation-stream-manager.js +0 -571
  217. package/dist/src/server/dictation/dictation-stream-manager.js.map +0 -1
  218. package/dist/src/server/file-download/token-store.js +0 -40
  219. package/dist/src/server/file-download/token-store.js.map +0 -1
  220. package/dist/src/server/file-explorer/service.js +0 -180
  221. package/dist/src/server/file-explorer/service.js.map +0 -1
  222. package/dist/src/server/json-utils.js +0 -45
  223. package/dist/src/server/json-utils.js.map +0 -1
  224. package/dist/src/server/messages.js +0 -29
  225. package/dist/src/server/messages.js.map +0 -1
  226. package/dist/src/server/package-version.js +0 -46
  227. package/dist/src/server/package-version.js.map +0 -1
  228. package/dist/src/server/pairing-offer.js +0 -45
  229. package/dist/src/server/pairing-offer.js.map +0 -1
  230. package/dist/src/server/pairing-qr.js +0 -45
  231. package/dist/src/server/pairing-qr.js.map +0 -1
  232. package/dist/src/server/path-utils.js +0 -20
  233. package/dist/src/server/path-utils.js.map +0 -1
  234. package/dist/src/server/persisted-config.js +0 -265
  235. package/dist/src/server/persisted-config.js.map +0 -1
  236. package/dist/src/server/persistence-hooks.js +0 -60
  237. package/dist/src/server/persistence-hooks.js.map +0 -1
  238. package/dist/src/server/push/push-service.js +0 -68
  239. package/dist/src/server/push/push-service.js.map +0 -1
  240. package/dist/src/server/push/token-store.js +0 -70
  241. package/dist/src/server/push/token-store.js.map +0 -1
  242. package/dist/src/server/relay-transport.js +0 -461
  243. package/dist/src/server/relay-transport.js.map +0 -1
  244. package/dist/src/server/server-id.js +0 -63
  245. package/dist/src/server/server-id.js.map +0 -1
  246. package/dist/src/server/session.js +0 -6170
  247. package/dist/src/server/session.js.map +0 -1
  248. package/dist/src/server/speech/audio.js +0 -101
  249. package/dist/src/server/speech/audio.js.map +0 -1
  250. package/dist/src/server/speech/provider-resolver.js +0 -7
  251. package/dist/src/server/speech/provider-resolver.js.map +0 -1
  252. package/dist/src/server/speech/providers/local/config.js +0 -74
  253. package/dist/src/server/speech/providers/local/config.js.map +0 -1
  254. package/dist/src/server/speech/providers/local/models.js +0 -17
  255. package/dist/src/server/speech/providers/local/models.js.map +0 -1
  256. package/dist/src/server/speech/providers/local/pocket/pocket-tts-onnx.js +0 -436
  257. package/dist/src/server/speech/providers/local/pocket/pocket-tts-onnx.js.map +0 -1
  258. package/dist/src/server/speech/providers/local/runtime.js +0 -238
  259. package/dist/src/server/speech/providers/local/runtime.js.map +0 -1
  260. package/dist/src/server/speech/providers/local/sherpa/model-catalog.js +0 -166
  261. package/dist/src/server/speech/providers/local/sherpa/model-catalog.js.map +0 -1
  262. package/dist/src/server/speech/providers/local/sherpa/model-downloader.js +0 -165
  263. package/dist/src/server/speech/providers/local/sherpa/model-downloader.js.map +0 -1
  264. package/dist/src/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js +0 -73
  265. package/dist/src/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js.map +0 -1
  266. package/dist/src/server/speech/providers/local/sherpa/sherpa-online-recognizer.js +0 -84
  267. package/dist/src/server/speech/providers/local/sherpa/sherpa-online-recognizer.js.map +0 -1
  268. package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-loader.js +0 -11
  269. package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-loader.js.map +0 -1
  270. package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +0 -102
  271. package/dist/src/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js.map +0 -1
  272. package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +0 -135
  273. package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js.map +0 -1
  274. package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +0 -130
  275. package/dist/src/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js.map +0 -1
  276. package/dist/src/server/speech/providers/local/sherpa/sherpa-realtime-session.js +0 -110
  277. package/dist/src/server/speech/providers/local/sherpa/sherpa-realtime-session.js.map +0 -1
  278. package/dist/src/server/speech/providers/local/sherpa/sherpa-stt.js +0 -138
  279. package/dist/src/server/speech/providers/local/sherpa/sherpa-stt.js.map +0 -1
  280. package/dist/src/server/speech/providers/local/sherpa/sherpa-tts.js +0 -98
  281. package/dist/src/server/speech/providers/local/sherpa/sherpa-tts.js.map +0 -1
  282. package/dist/src/server/speech/providers/local/sherpa/silero-vad-provider.js +0 -23
  283. package/dist/src/server/speech/providers/local/sherpa/silero-vad-provider.js.map +0 -1
  284. package/dist/src/server/speech/providers/local/sherpa/silero-vad-session.js +0 -107
  285. package/dist/src/server/speech/providers/local/sherpa/silero-vad-session.js.map +0 -1
  286. package/dist/src/server/speech/providers/openai/config.js +0 -80
  287. package/dist/src/server/speech/providers/openai/config.js.map +0 -1
  288. package/dist/src/server/speech/providers/openai/realtime-transcription-session.js +0 -168
  289. package/dist/src/server/speech/providers/openai/realtime-transcription-session.js.map +0 -1
  290. package/dist/src/server/speech/providers/openai/runtime.js +0 -112
  291. package/dist/src/server/speech/providers/openai/runtime.js.map +0 -1
  292. package/dist/src/server/speech/providers/openai/stt.js +0 -206
  293. package/dist/src/server/speech/providers/openai/stt.js.map +0 -1
  294. package/dist/src/server/speech/providers/openai/tts.js +0 -46
  295. package/dist/src/server/speech/providers/openai/tts.js.map +0 -1
  296. package/dist/src/server/speech/speech-config-resolver.js +0 -102
  297. package/dist/src/server/speech/speech-config-resolver.js.map +0 -1
  298. package/dist/src/server/speech/speech-provider.js +0 -2
  299. package/dist/src/server/speech/speech-provider.js.map +0 -1
  300. package/dist/src/server/speech/speech-runtime.js +0 -530
  301. package/dist/src/server/speech/speech-runtime.js.map +0 -1
  302. package/dist/src/server/speech/speech-types.js +0 -8
  303. package/dist/src/server/speech/speech-types.js.map +0 -1
  304. package/dist/src/server/speech/turn-detection-provider.js +0 -2
  305. package/dist/src/server/speech/turn-detection-provider.js.map +0 -1
  306. package/dist/src/server/utils/diff-highlighter.js +0 -257
  307. package/dist/src/server/utils/diff-highlighter.js.map +0 -1
  308. package/dist/src/server/voice/fixed-duration-pcm-ring-buffer.js +0 -35
  309. package/dist/src/server/voice/fixed-duration-pcm-ring-buffer.js.map +0 -1
  310. package/dist/src/server/voice/voice-turn-controller.js +0 -159
  311. package/dist/src/server/voice/voice-turn-controller.js.map +0 -1
  312. package/dist/src/server/voice-config.js +0 -51
  313. package/dist/src/server/voice-config.js.map +0 -1
  314. package/dist/src/server/voice-mcp-bridge-command.js +0 -31
  315. package/dist/src/server/voice-mcp-bridge-command.js.map +0 -1
  316. package/dist/src/server/voice-mcp-bridge.js +0 -109
  317. package/dist/src/server/voice-mcp-bridge.js.map +0 -1
  318. package/dist/src/server/voice-permission-policy.js +0 -13
  319. package/dist/src/server/voice-permission-policy.js.map +0 -1
  320. package/dist/src/server/voice-types.js +0 -2
  321. package/dist/src/server/voice-types.js.map +0 -1
  322. package/dist/src/server/websocket-server.js +0 -991
  323. package/dist/src/server/websocket-server.js.map +0 -1
  324. package/dist/src/server/workspace-registry-bootstrap.js +0 -98
  325. package/dist/src/server/workspace-registry-bootstrap.js.map +0 -1
  326. package/dist/src/server/workspace-registry-model.js +0 -175
  327. package/dist/src/server/workspace-registry-model.js.map +0 -1
  328. package/dist/src/server/workspace-registry.js +0 -151
  329. package/dist/src/server/workspace-registry.js.map +0 -1
  330. package/dist/src/server/worktree-bootstrap.js +0 -508
  331. package/dist/src/server/worktree-bootstrap.js.map +0 -1
  332. package/dist/src/shared/agent-attention-notification.js +0 -130
  333. package/dist/src/shared/agent-attention-notification.js.map +0 -1
  334. package/dist/src/shared/agent-lifecycle.js +0 -8
  335. package/dist/src/shared/agent-lifecycle.js.map +0 -1
  336. package/dist/src/shared/connection-offer.js +0 -17
  337. package/dist/src/shared/connection-offer.js.map +0 -1
  338. package/dist/src/shared/daemon-endpoints.js +0 -122
  339. package/dist/src/shared/daemon-endpoints.js.map +0 -1
  340. package/dist/src/shared/messages.js +0 -2066
  341. package/dist/src/shared/messages.js.map +0 -1
  342. package/dist/src/shared/path-utils.js +0 -16
  343. package/dist/src/shared/path-utils.js.map +0 -1
  344. package/dist/src/shared/terminal-stream-protocol.js +0 -99
  345. package/dist/src/shared/terminal-stream-protocol.js.map +0 -1
  346. package/dist/src/shared/tool-call-display.js +0 -122
  347. package/dist/src/shared/tool-call-display.js.map +0 -1
  348. package/dist/src/terminal/terminal-manager.js +0 -136
  349. package/dist/src/terminal/terminal-manager.js.map +0 -1
  350. package/dist/src/terminal/terminal.js +0 -333
  351. package/dist/src/terminal/terminal.js.map +0 -1
  352. package/dist/src/utils/checkout-git.js +0 -1448
  353. package/dist/src/utils/checkout-git.js.map +0 -1
  354. package/dist/src/utils/directory-suggestions.js +0 -655
  355. package/dist/src/utils/directory-suggestions.js.map +0 -1
  356. package/dist/src/utils/path.js +0 -15
  357. package/dist/src/utils/path.js.map +0 -1
  358. package/dist/src/utils/project-icon.js +0 -389
  359. package/dist/src/utils/project-icon.js.map +0 -1
  360. package/dist/src/utils/worktree-metadata.js +0 -116
  361. package/dist/src/utils/worktree-metadata.js.map +0 -1
  362. package/dist/src/utils/worktree.js +0 -744
  363. package/dist/src/utils/worktree.js.map +0 -1
@@ -1,991 +0,0 @@
1
- import { WebSocketServer } from "ws";
2
- import { join } from "path";
3
- import { hostname as getHostname } from "node:os";
4
- import { WSInboundMessageSchema, wrapSessionMessage, } from "./messages.js";
5
- import { asUint8Array, decodeTerminalStreamFrame, } from "../shared/terminal-stream-protocol.js";
6
- import { isHostAllowed } from "./allowed-hosts.js";
7
- import { Session } from "./session.js";
8
- import { PushTokenStore } from "./push/token-store.js";
9
- import { PushService } from "./push/push-service.js";
10
- import { computeShouldNotifyClient, computeShouldSendPush, } from "./agent-attention-policy.js";
11
- import { buildAgentAttentionNotificationPayload, findLatestAssistantMessageFromTimeline, findLatestPermissionRequest, } from "../shared/agent-attention-notification.js";
12
- function createNoopProjectRegistry() {
13
- return {
14
- initialize: async () => { },
15
- existsOnDisk: async () => true,
16
- list: async () => [],
17
- get: async () => null,
18
- upsert: async () => { },
19
- archive: async () => { },
20
- remove: async () => { },
21
- };
22
- }
23
- function createNoopWorkspaceRegistry() {
24
- return {
25
- initialize: async () => { },
26
- existsOnDisk: async () => true,
27
- list: async () => [],
28
- get: async () => null,
29
- upsert: async () => { },
30
- archive: async () => { },
31
- remove: async () => { },
32
- };
33
- }
34
- function toServerCapabilityState(params) {
35
- const { state, reason } = params;
36
- return {
37
- enabled: state.enabled,
38
- reason,
39
- };
40
- }
41
- function resolveCapabilityReason(params) {
42
- const { state, readiness } = params;
43
- if (state.available) {
44
- return "";
45
- }
46
- if (readiness.voiceFeature.reasonCode === "model_download_in_progress") {
47
- const baseMessage = readiness.voiceFeature.message.trim();
48
- if (baseMessage.includes("Try again in a few minutes")) {
49
- return baseMessage;
50
- }
51
- return `${baseMessage} Try again in a few minutes.`;
52
- }
53
- return state.message;
54
- }
55
- function buildServerCapabilities(params) {
56
- const readiness = params.readiness;
57
- if (!readiness) {
58
- return undefined;
59
- }
60
- return {
61
- voice: {
62
- dictation: toServerCapabilityState({
63
- state: readiness.dictation,
64
- reason: resolveCapabilityReason({
65
- state: readiness.dictation,
66
- readiness,
67
- }),
68
- }),
69
- voice: toServerCapabilityState({
70
- state: readiness.realtimeVoice,
71
- reason: resolveCapabilityReason({
72
- state: readiness.realtimeVoice,
73
- readiness,
74
- }),
75
- }),
76
- },
77
- };
78
- }
79
- function areServerCapabilitiesEqual(current, next) {
80
- return JSON.stringify(current ?? null) === JSON.stringify(next ?? null);
81
- }
82
- function bufferFromWsData(data) {
83
- if (typeof data === "string")
84
- return Buffer.from(data, "utf8");
85
- if (Array.isArray(data)) {
86
- return Buffer.concat(data.map((item) => (Buffer.isBuffer(item) ? item : Buffer.from(item))));
87
- }
88
- if (Buffer.isBuffer(data))
89
- return data;
90
- return Buffer.from(data);
91
- }
92
- const EXTERNAL_SESSION_DISCONNECT_GRACE_MS = 90000;
93
- const HELLO_TIMEOUT_MS = 15000;
94
- const WS_CLOSE_HELLO_TIMEOUT = 4001;
95
- const WS_CLOSE_INVALID_HELLO = 4002;
96
- const WS_CLOSE_INCOMPATIBLE_PROTOCOL = 4003;
97
- const WS_PROTOCOL_VERSION = 1;
98
- const WS_RUNTIME_METRICS_FLUSH_MS = 30000;
99
- export class MissingDaemonVersionError extends Error {
100
- constructor() {
101
- super("VoiceAssistantWebSocketServer requires a non-empty daemonVersion.");
102
- this.name = "MissingDaemonVersionError";
103
- }
104
- }
105
- /**
106
- * WebSocket server that only accepts sockets + parses/forwards messages to the session layer.
107
- */
108
- export class VoiceAssistantWebSocketServer {
109
- constructor(server, logger, serverId, agentManager, agentStorage, downloadTokenStore, paseoHome, createAgentMcpTransport, wsConfig, speech, terminalManager, voice, dictation, agentProviderRuntimeSettings, daemonVersion, onLifecycleIntent, projectRegistry, workspaceRegistry) {
110
- this.pendingConnections = new Map();
111
- this.sessions = new Map();
112
- this.externalSessionsByKey = new Map();
113
- this.voiceSpeakHandlers = new Map();
114
- this.voiceCallerContexts = new Map();
115
- this.runtimeWindowStartedAt = Date.now();
116
- this.runtimeCounters = {
117
- connectedAwaitingHello: 0,
118
- helloResumed: 0,
119
- helloNew: 0,
120
- pendingDisconnected: 0,
121
- sessionDisconnectedWaitingReconnect: 0,
122
- sessionSocketDisconnectedAttached: 0,
123
- sessionCleanup: 0,
124
- validationFailed: 0,
125
- binaryBeforeHelloRejected: 0,
126
- pendingMessageRejectedBeforeHello: 0,
127
- missingConnectionForMessage: 0,
128
- unexpectedHelloOnActiveConnection: 0,
129
- relayExternalSocketAttached: 0,
130
- originRejected: 0,
131
- hostRejected: 0,
132
- };
133
- this.inboundMessageCounts = new Map();
134
- this.inboundSessionRequestCounts = new Map();
135
- this.runtimeMetricsInterval = null;
136
- this.ACTIVITY_THRESHOLD_MS = 120000;
137
- this.logger = logger.child({ module: "websocket-server" });
138
- this.serverId = serverId;
139
- if (typeof daemonVersion !== "string" || daemonVersion.trim().length === 0) {
140
- throw new MissingDaemonVersionError();
141
- }
142
- this.daemonVersion = daemonVersion.trim();
143
- this.agentManager = agentManager;
144
- this.agentStorage = agentStorage;
145
- this.projectRegistry = projectRegistry ?? createNoopProjectRegistry();
146
- this.workspaceRegistry = workspaceRegistry ?? createNoopWorkspaceRegistry();
147
- this.downloadTokenStore = downloadTokenStore;
148
- this.paseoHome = paseoHome;
149
- this.createAgentMcpTransport = createAgentMcpTransport;
150
- this.turnDetection = speech?.turnDetection ?? null;
151
- this.stt = speech?.stt ?? null;
152
- this.tts = speech?.tts ?? null;
153
- this.terminalManager = terminalManager ?? null;
154
- this.voice = voice ?? null;
155
- this.dictation = dictation ?? null;
156
- this.agentProviderRuntimeSettings = agentProviderRuntimeSettings;
157
- this.onLifecycleIntent = onLifecycleIntent ?? null;
158
- this.serverCapabilities = buildServerCapabilities({
159
- readiness: this.dictation?.getSpeechReadiness?.() ?? null,
160
- });
161
- const pushLogger = this.logger.child({ module: "push" });
162
- this.pushTokenStore = new PushTokenStore(pushLogger, join(paseoHome, "push-tokens.json"));
163
- this.pushService = new PushService(pushLogger, this.pushTokenStore);
164
- this.agentManager.setAgentAttentionCallback((params) => {
165
- this.broadcastAgentAttention(params);
166
- });
167
- const { allowedOrigins, allowedHosts } = wsConfig;
168
- this.wss = new WebSocketServer({
169
- server,
170
- path: "/ws",
171
- verifyClient: ({ req }, callback) => {
172
- const requestMetadata = extractSocketRequestMetadata(req);
173
- const origin = requestMetadata.origin;
174
- const requestHost = requestMetadata.host ?? null;
175
- if (requestHost && !isHostAllowed(requestHost, allowedHosts)) {
176
- this.incrementRuntimeCounter("hostRejected");
177
- this.logger.warn({ ...requestMetadata, host: requestHost }, "Rejected connection from disallowed host");
178
- callback(false, 403, "Host not allowed");
179
- return;
180
- }
181
- const sameOrigin = !!origin &&
182
- !!requestHost &&
183
- (origin === `http://${requestHost}` || origin === `https://${requestHost}`);
184
- if (!origin || allowedOrigins.has(origin) || sameOrigin) {
185
- callback(true);
186
- }
187
- else {
188
- this.incrementRuntimeCounter("originRejected");
189
- this.logger.warn({ ...requestMetadata, origin }, "Rejected connection from origin");
190
- callback(false, 403, "Origin not allowed");
191
- }
192
- },
193
- });
194
- this.wss.on("connection", (ws, request) => {
195
- void this.attachSocket(ws, request);
196
- });
197
- const runtimeMetricsInterval = setInterval(() => {
198
- this.flushRuntimeMetrics();
199
- }, WS_RUNTIME_METRICS_FLUSH_MS);
200
- this.runtimeMetricsInterval = runtimeMetricsInterval;
201
- runtimeMetricsInterval.unref?.();
202
- this.logger.info("WebSocket server initialized on /ws");
203
- }
204
- broadcast(message) {
205
- const payload = JSON.stringify(message);
206
- for (const ws of this.sessions.keys()) {
207
- // WebSocket.OPEN = 1
208
- if (ws.readyState === 1) {
209
- ws.send(payload);
210
- }
211
- }
212
- }
213
- publishSpeechReadiness(readiness) {
214
- this.updateServerCapabilities(buildServerCapabilities({ readiness }));
215
- }
216
- updateServerCapabilities(capabilities) {
217
- const next = capabilities ?? undefined;
218
- if (areServerCapabilitiesEqual(this.serverCapabilities, next)) {
219
- return;
220
- }
221
- this.serverCapabilities = next;
222
- this.broadcastCapabilitiesUpdate();
223
- }
224
- async attachExternalSocket(ws, metadata) {
225
- if (metadata?.transport === "relay") {
226
- this.incrementRuntimeCounter("relayExternalSocketAttached");
227
- }
228
- await this.attachSocket(ws, undefined, metadata);
229
- }
230
- async close() {
231
- if (this.runtimeMetricsInterval) {
232
- clearInterval(this.runtimeMetricsInterval);
233
- this.runtimeMetricsInterval = null;
234
- }
235
- this.flushRuntimeMetrics({ final: true });
236
- const uniqueConnections = new Set([
237
- ...this.sessions.values(),
238
- ...this.externalSessionsByKey.values(),
239
- ]);
240
- const pendingSockets = new Set(this.pendingConnections.keys());
241
- for (const pending of this.pendingConnections.values()) {
242
- if (pending.helloTimeout) {
243
- clearTimeout(pending.helloTimeout);
244
- pending.helloTimeout = null;
245
- }
246
- }
247
- const cleanupPromises = [];
248
- for (const connection of uniqueConnections) {
249
- if (connection.externalDisconnectCleanupTimeout) {
250
- clearTimeout(connection.externalDisconnectCleanupTimeout);
251
- connection.externalDisconnectCleanupTimeout = null;
252
- }
253
- cleanupPromises.push(connection.session.cleanup());
254
- for (const ws of connection.sockets) {
255
- cleanupPromises.push(new Promise((resolve) => {
256
- // WebSocket.CLOSED = 3
257
- if (ws.readyState === 3) {
258
- resolve();
259
- return;
260
- }
261
- ws.once("close", () => resolve());
262
- ws.close();
263
- }));
264
- }
265
- }
266
- for (const ws of pendingSockets) {
267
- cleanupPromises.push(new Promise((resolve) => {
268
- if (ws.readyState === 3) {
269
- resolve();
270
- return;
271
- }
272
- ws.once("close", () => resolve());
273
- ws.close();
274
- }));
275
- }
276
- await Promise.all(cleanupPromises);
277
- this.pendingConnections.clear();
278
- this.sessions.clear();
279
- this.externalSessionsByKey.clear();
280
- this.wss.close();
281
- }
282
- sendToClient(ws, message) {
283
- // WebSocket.OPEN = 1
284
- if (ws.readyState === 1) {
285
- ws.send(JSON.stringify(message));
286
- }
287
- }
288
- sendBinaryToClient(ws, frame) {
289
- if (ws.readyState !== 1) {
290
- return;
291
- }
292
- ws.send(frame);
293
- }
294
- sendToConnection(connection, message) {
295
- for (const ws of connection.sockets) {
296
- this.sendToClient(ws, message);
297
- }
298
- }
299
- sendBinaryToConnection(connection, frame) {
300
- for (const ws of connection.sockets) {
301
- this.sendBinaryToClient(ws, frame);
302
- }
303
- }
304
- async attachSocket(ws, request, metadata) {
305
- const requestMetadata = extractSocketRequestMetadata(request);
306
- const connectionLoggerFields = {
307
- transport: metadata?.transport === "relay" ? "relay" : "direct",
308
- };
309
- if (requestMetadata.host) {
310
- connectionLoggerFields.host = requestMetadata.host;
311
- }
312
- if (requestMetadata.origin) {
313
- connectionLoggerFields.origin = requestMetadata.origin;
314
- }
315
- if (requestMetadata.userAgent) {
316
- connectionLoggerFields.userAgent = requestMetadata.userAgent;
317
- }
318
- if (requestMetadata.remoteAddress) {
319
- connectionLoggerFields.remoteAddress = requestMetadata.remoteAddress;
320
- }
321
- const connectionLogger = this.logger.child(connectionLoggerFields);
322
- const pending = {
323
- connectionLogger,
324
- helloTimeout: null,
325
- };
326
- const timeout = setTimeout(() => {
327
- if (this.pendingConnections.get(ws) !== pending) {
328
- return;
329
- }
330
- pending.helloTimeout = null;
331
- this.pendingConnections.delete(ws);
332
- pending.connectionLogger.warn({ timeoutMs: HELLO_TIMEOUT_MS }, "Closing connection due to missing hello");
333
- try {
334
- ws.close(WS_CLOSE_HELLO_TIMEOUT, "Hello timeout");
335
- }
336
- catch {
337
- // ignore close errors
338
- }
339
- }, HELLO_TIMEOUT_MS);
340
- pending.helloTimeout = timeout;
341
- timeout.unref?.();
342
- this.pendingConnections.set(ws, pending);
343
- this.incrementRuntimeCounter("connectedAwaitingHello");
344
- this.bindSocketHandlers(ws);
345
- pending.connectionLogger.trace({
346
- totalPendingConnections: this.pendingConnections.size,
347
- }, "Client connected; awaiting hello");
348
- }
349
- createSessionConnection(params) {
350
- const { ws, clientId, connectionLogger } = params;
351
- let connection = null;
352
- const session = new Session({
353
- clientId,
354
- onMessage: (msg) => {
355
- if (!connection) {
356
- return;
357
- }
358
- this.sendToConnection(connection, wrapSessionMessage(msg));
359
- },
360
- onBinaryMessage: (frame) => {
361
- if (!connection) {
362
- return;
363
- }
364
- this.sendBinaryToConnection(connection, frame);
365
- },
366
- getBinaryBufferedAmount: () => {
367
- if (!connection) {
368
- return 0;
369
- }
370
- let bufferedAmount = 0;
371
- for (const socket of connection.sockets) {
372
- bufferedAmount = Math.max(bufferedAmount, socket.bufferedAmount ?? 0);
373
- }
374
- return bufferedAmount;
375
- },
376
- onLifecycleIntent: (intent) => {
377
- this.onLifecycleIntent?.(intent);
378
- },
379
- logger: connectionLogger.child({ module: "session" }),
380
- downloadTokenStore: this.downloadTokenStore,
381
- pushTokenStore: this.pushTokenStore,
382
- paseoHome: this.paseoHome,
383
- agentManager: this.agentManager,
384
- agentStorage: this.agentStorage,
385
- projectRegistry: this.projectRegistry,
386
- workspaceRegistry: this.workspaceRegistry,
387
- createAgentMcpTransport: this.createAgentMcpTransport,
388
- stt: this.stt,
389
- tts: this.tts,
390
- terminalManager: this.terminalManager,
391
- voice: {
392
- ...(this.voice ?? {}),
393
- turnDetection: this.turnDetection,
394
- },
395
- voiceBridge: {
396
- registerVoiceSpeakHandler: (agentId, handler) => {
397
- this.voiceSpeakHandlers.set(agentId, handler);
398
- },
399
- unregisterVoiceSpeakHandler: (agentId) => {
400
- this.voiceSpeakHandlers.delete(agentId);
401
- },
402
- registerVoiceCallerContext: (agentId, context) => {
403
- this.voiceCallerContexts.set(agentId, context);
404
- },
405
- unregisterVoiceCallerContext: (agentId) => {
406
- this.voiceCallerContexts.delete(agentId);
407
- },
408
- ensureVoiceMcpSocketForAgent: this.voice?.ensureVoiceMcpSocketForAgent,
409
- removeVoiceMcpSocketForAgent: this.voice?.removeVoiceMcpSocketForAgent,
410
- },
411
- dictation: this.dictation ?? undefined,
412
- agentProviderRuntimeSettings: this.agentProviderRuntimeSettings,
413
- });
414
- connection = {
415
- session,
416
- clientId,
417
- connectionLogger,
418
- sockets: new Set([ws]),
419
- externalDisconnectCleanupTimeout: null,
420
- };
421
- return connection;
422
- }
423
- clearPendingConnection(ws) {
424
- const pending = this.pendingConnections.get(ws);
425
- if (!pending) {
426
- return null;
427
- }
428
- if (pending.helloTimeout) {
429
- clearTimeout(pending.helloTimeout);
430
- pending.helloTimeout = null;
431
- }
432
- this.pendingConnections.delete(ws);
433
- return pending;
434
- }
435
- handleHello(params) {
436
- const { ws, message, pending } = params;
437
- if (message.protocolVersion !== WS_PROTOCOL_VERSION) {
438
- this.clearPendingConnection(ws);
439
- pending.connectionLogger.warn({
440
- receivedProtocolVersion: message.protocolVersion,
441
- expectedProtocolVersion: WS_PROTOCOL_VERSION,
442
- }, "Rejected hello due to protocol version mismatch");
443
- try {
444
- ws.close(WS_CLOSE_INCOMPATIBLE_PROTOCOL, "Incompatible protocol version");
445
- }
446
- catch {
447
- // ignore close errors
448
- }
449
- return;
450
- }
451
- const clientId = message.clientId.trim();
452
- if (clientId.length === 0) {
453
- this.clearPendingConnection(ws);
454
- pending.connectionLogger.warn("Rejected hello with empty clientId");
455
- try {
456
- ws.close(WS_CLOSE_INVALID_HELLO, "Invalid hello");
457
- }
458
- catch {
459
- // ignore close errors
460
- }
461
- return;
462
- }
463
- this.clearPendingConnection(ws);
464
- const existing = this.externalSessionsByKey.get(clientId);
465
- if (existing) {
466
- this.incrementRuntimeCounter("helloResumed");
467
- if (existing.externalDisconnectCleanupTimeout) {
468
- clearTimeout(existing.externalDisconnectCleanupTimeout);
469
- existing.externalDisconnectCleanupTimeout = null;
470
- }
471
- existing.sockets.add(ws);
472
- this.sessions.set(ws, existing);
473
- this.sendToClient(ws, this.createServerInfoMessage());
474
- existing.connectionLogger.trace({
475
- clientId,
476
- resumed: true,
477
- totalSessions: this.sessions.size,
478
- }, "Client connected via hello");
479
- return;
480
- }
481
- const connectionLogger = pending.connectionLogger.child({ clientId });
482
- this.incrementRuntimeCounter("helloNew");
483
- const connection = this.createSessionConnection({
484
- ws,
485
- clientId,
486
- connectionLogger,
487
- });
488
- this.sessions.set(ws, connection);
489
- this.externalSessionsByKey.set(clientId, connection);
490
- this.sendToClient(ws, this.createServerInfoMessage());
491
- connection.connectionLogger.trace({
492
- clientId,
493
- resumed: false,
494
- totalSessions: this.sessions.size,
495
- }, "Client connected via hello");
496
- }
497
- buildServerInfoStatusPayload() {
498
- return {
499
- status: "server_info",
500
- serverId: this.serverId,
501
- hostname: getHostname(),
502
- version: this.daemonVersion,
503
- ...(this.serverCapabilities ? { capabilities: this.serverCapabilities } : {}),
504
- };
505
- }
506
- createServerInfoMessage() {
507
- return {
508
- type: "session",
509
- message: {
510
- type: "status",
511
- payload: this.buildServerInfoStatusPayload(),
512
- },
513
- };
514
- }
515
- broadcastCapabilitiesUpdate() {
516
- this.broadcast(this.createServerInfoMessage());
517
- }
518
- bindSocketHandlers(ws) {
519
- ws.on("message", (data) => {
520
- void this.handleRawMessage(ws, data);
521
- });
522
- ws.on("close", async (code, reason) => {
523
- await this.detachSocket(ws, {
524
- code: typeof code === "number" ? code : undefined,
525
- reason,
526
- });
527
- });
528
- ws.on("error", async (error) => {
529
- const err = error instanceof Error ? error : new Error(String(error));
530
- const active = this.sessions.get(ws);
531
- const pending = this.pendingConnections.get(ws);
532
- const log = active?.connectionLogger ?? pending?.connectionLogger ?? this.logger;
533
- log.error({ err }, "Client error");
534
- await this.detachSocket(ws, { error: err });
535
- });
536
- }
537
- resolveVoiceSpeakHandler(callerAgentId) {
538
- return this.voiceSpeakHandlers.get(callerAgentId) ?? null;
539
- }
540
- resolveVoiceCallerContext(callerAgentId) {
541
- return this.voiceCallerContexts.get(callerAgentId) ?? null;
542
- }
543
- async detachSocket(ws, details) {
544
- const pending = this.clearPendingConnection(ws);
545
- if (pending) {
546
- this.incrementRuntimeCounter("pendingDisconnected");
547
- pending.connectionLogger.trace({
548
- code: details.code,
549
- reason: stringifyCloseReason(details.reason),
550
- }, "Pending client disconnected");
551
- return;
552
- }
553
- const connection = this.sessions.get(ws);
554
- if (!connection) {
555
- return;
556
- }
557
- this.sessions.delete(ws);
558
- connection.sockets.delete(ws);
559
- if (connection.sockets.size === 0) {
560
- this.incrementRuntimeCounter("sessionDisconnectedWaitingReconnect");
561
- if (connection.externalDisconnectCleanupTimeout) {
562
- clearTimeout(connection.externalDisconnectCleanupTimeout);
563
- }
564
- const timeout = setTimeout(() => {
565
- if (connection.externalDisconnectCleanupTimeout !== timeout) {
566
- return;
567
- }
568
- connection.externalDisconnectCleanupTimeout = null;
569
- void this.cleanupConnection(connection, "Client disconnected (grace timeout)");
570
- }, EXTERNAL_SESSION_DISCONNECT_GRACE_MS);
571
- connection.externalDisconnectCleanupTimeout = timeout;
572
- connection.connectionLogger.trace({
573
- clientId: connection.clientId,
574
- code: details.code,
575
- reason: stringifyCloseReason(details.reason),
576
- reconnectGraceMs: EXTERNAL_SESSION_DISCONNECT_GRACE_MS,
577
- }, "Client disconnected; waiting for reconnect");
578
- return;
579
- }
580
- if (connection.sockets.size > 0) {
581
- this.incrementRuntimeCounter("sessionSocketDisconnectedAttached");
582
- connection.connectionLogger.trace({
583
- clientId: connection.clientId,
584
- remainingSockets: connection.sockets.size,
585
- code: details.code,
586
- reason: stringifyCloseReason(details.reason),
587
- }, "Client socket disconnected; session remains attached");
588
- return;
589
- }
590
- await this.cleanupConnection(connection, "Client disconnected");
591
- }
592
- async cleanupConnection(connection, logMessage) {
593
- this.incrementRuntimeCounter("sessionCleanup");
594
- if (connection.externalDisconnectCleanupTimeout) {
595
- clearTimeout(connection.externalDisconnectCleanupTimeout);
596
- connection.externalDisconnectCleanupTimeout = null;
597
- }
598
- for (const socket of connection.sockets) {
599
- this.sessions.delete(socket);
600
- }
601
- connection.sockets.clear();
602
- const existing = this.externalSessionsByKey.get(connection.clientId);
603
- if (existing === connection) {
604
- this.externalSessionsByKey.delete(connection.clientId);
605
- }
606
- connection.connectionLogger.trace({ clientId: connection.clientId, totalSessions: this.sessions.size }, logMessage);
607
- await connection.session.cleanup();
608
- }
609
- async handleRawMessage(ws, data) {
610
- const activeConnection = this.sessions.get(ws);
611
- const pendingConnection = this.pendingConnections.get(ws);
612
- const log = activeConnection?.connectionLogger ?? pendingConnection?.connectionLogger ?? this.logger;
613
- try {
614
- const buffer = bufferFromWsData(data);
615
- const asBytes = asUint8Array(buffer);
616
- if (asBytes) {
617
- const frame = decodeTerminalStreamFrame(asBytes);
618
- if (frame) {
619
- if (!activeConnection) {
620
- this.incrementRuntimeCounter("binaryBeforeHelloRejected");
621
- log.warn("Rejected binary frame before hello");
622
- this.clearPendingConnection(ws);
623
- try {
624
- ws.close(WS_CLOSE_INVALID_HELLO, "Session message before hello");
625
- }
626
- catch {
627
- // ignore close errors
628
- }
629
- return;
630
- }
631
- activeConnection.session.handleBinaryFrame(frame);
632
- return;
633
- }
634
- }
635
- const parsed = JSON.parse(buffer.toString());
636
- const parsedMessage = WSInboundMessageSchema.safeParse(parsed);
637
- if (!parsedMessage.success) {
638
- this.incrementRuntimeCounter("validationFailed");
639
- if (pendingConnection) {
640
- pendingConnection.connectionLogger.warn({
641
- error: parsedMessage.error.message,
642
- }, "Rejected pending message before hello");
643
- this.clearPendingConnection(ws);
644
- try {
645
- ws.close(WS_CLOSE_INVALID_HELLO, "Invalid hello");
646
- }
647
- catch {
648
- // ignore close errors
649
- }
650
- return;
651
- }
652
- const requestInfo = extractRequestInfoFromUnknownWsInbound(parsed);
653
- const isUnknownSchema = requestInfo?.requestId != null &&
654
- typeof parsed === "object" &&
655
- parsed != null &&
656
- "type" in parsed &&
657
- parsed.type === "session";
658
- log.warn({
659
- clientId: activeConnection?.clientId,
660
- requestId: requestInfo?.requestId,
661
- requestType: requestInfo?.requestType,
662
- error: parsedMessage.error.message,
663
- }, "WS inbound message validation failed");
664
- if (requestInfo) {
665
- this.sendToClient(ws, wrapSessionMessage({
666
- type: "rpc_error",
667
- payload: {
668
- requestId: requestInfo.requestId,
669
- requestType: requestInfo.requestType,
670
- error: isUnknownSchema ? "Unknown request schema" : "Invalid message",
671
- code: isUnknownSchema ? "unknown_schema" : "invalid_message",
672
- },
673
- }));
674
- return;
675
- }
676
- const errorMessage = `Invalid message: ${parsedMessage.error.message}`;
677
- this.sendToClient(ws, wrapSessionMessage({
678
- type: "status",
679
- payload: {
680
- status: "error",
681
- message: errorMessage,
682
- },
683
- }));
684
- return;
685
- }
686
- const message = parsedMessage.data;
687
- this.recordInboundMessageType(message.type);
688
- if (message.type === "ping") {
689
- this.sendToClient(ws, { type: "pong" });
690
- return;
691
- }
692
- if (message.type === "recording_state") {
693
- return;
694
- }
695
- if (pendingConnection) {
696
- if (message.type === "hello") {
697
- this.handleHello({
698
- ws,
699
- message,
700
- pending: pendingConnection,
701
- });
702
- return;
703
- }
704
- pendingConnection.connectionLogger.warn({
705
- messageType: message.type,
706
- }, "Rejected pending message before hello");
707
- this.incrementRuntimeCounter("pendingMessageRejectedBeforeHello");
708
- this.clearPendingConnection(ws);
709
- try {
710
- ws.close(WS_CLOSE_INVALID_HELLO, "Session message before hello");
711
- }
712
- catch {
713
- // ignore close errors
714
- }
715
- return;
716
- }
717
- if (!activeConnection) {
718
- this.incrementRuntimeCounter("missingConnectionForMessage");
719
- this.logger.error("No connection found for websocket");
720
- return;
721
- }
722
- if (message.type === "hello") {
723
- this.incrementRuntimeCounter("unexpectedHelloOnActiveConnection");
724
- activeConnection.connectionLogger.warn("Received hello on active connection");
725
- try {
726
- ws.close(WS_CLOSE_INVALID_HELLO, "Unexpected hello");
727
- }
728
- catch {
729
- // ignore close errors
730
- }
731
- return;
732
- }
733
- if (message.type === "session") {
734
- this.recordInboundSessionRequestType(message.message.type);
735
- await activeConnection.session.handleMessage(message.message);
736
- }
737
- }
738
- catch (error) {
739
- const err = error instanceof Error ? error : new Error(String(error));
740
- let rawPayload = null;
741
- let parsedPayload = null;
742
- try {
743
- const buffer = bufferFromWsData(data);
744
- rawPayload = buffer.toString();
745
- parsedPayload = JSON.parse(rawPayload);
746
- }
747
- catch (payloadError) {
748
- rawPayload = rawPayload ?? "<unreadable>";
749
- parsedPayload = parsedPayload ?? rawPayload;
750
- const payloadErr = payloadError instanceof Error ? payloadError : new Error(String(payloadError));
751
- this.logger.error({ err: payloadErr }, "Failed to decode raw payload");
752
- }
753
- const trimmedRawPayload = typeof rawPayload === "string" && rawPayload.length > 2000
754
- ? `${rawPayload.slice(0, 2000)}... (truncated)`
755
- : rawPayload;
756
- log.error({
757
- err,
758
- rawPayload: trimmedRawPayload,
759
- parsedPayload,
760
- }, "Failed to parse/handle message");
761
- if (this.pendingConnections.has(ws)) {
762
- this.clearPendingConnection(ws);
763
- try {
764
- ws.close(WS_CLOSE_INVALID_HELLO, "Invalid hello");
765
- }
766
- catch {
767
- // ignore close errors
768
- }
769
- return;
770
- }
771
- const requestInfo = extractRequestInfoFromUnknownWsInbound(parsedPayload);
772
- if (requestInfo) {
773
- this.sendToClient(ws, wrapSessionMessage({
774
- type: "rpc_error",
775
- payload: {
776
- requestId: requestInfo.requestId,
777
- requestType: requestInfo.requestType,
778
- error: "Invalid message",
779
- code: "invalid_message",
780
- },
781
- }));
782
- return;
783
- }
784
- this.sendToClient(ws, wrapSessionMessage({
785
- type: "status",
786
- payload: {
787
- status: "error",
788
- message: `Invalid message: ${err.message}`,
789
- },
790
- }));
791
- }
792
- }
793
- incrementRuntimeCounter(counter) {
794
- this.runtimeCounters[counter] += 1;
795
- }
796
- incrementCount(map, key) {
797
- map.set(key, (map.get(key) ?? 0) + 1);
798
- }
799
- recordInboundMessageType(type) {
800
- this.incrementCount(this.inboundMessageCounts, type);
801
- }
802
- recordInboundSessionRequestType(type) {
803
- this.incrementCount(this.inboundSessionRequestCounts, type);
804
- }
805
- getTopCounts(map, limit) {
806
- return [...map.entries()].sort((a, b) => b[1] - a[1]).slice(0, limit);
807
- }
808
- collectSessionRuntimeMetrics() {
809
- const uniqueConnections = new Set(this.externalSessionsByKey.values());
810
- let checkoutDiffTargetCount = 0;
811
- let checkoutDiffSubscriptionCount = 0;
812
- let checkoutDiffWatcherCount = 0;
813
- let checkoutDiffFallbackRefreshTargetCount = 0;
814
- let terminalDirectorySubscriptionCount = 0;
815
- let terminalSubscriptionCount = 0;
816
- for (const connection of uniqueConnections) {
817
- const sessionMetrics = connection.session.getRuntimeMetrics();
818
- checkoutDiffTargetCount += sessionMetrics.checkoutDiffTargetCount;
819
- checkoutDiffSubscriptionCount += sessionMetrics.checkoutDiffSubscriptionCount;
820
- checkoutDiffWatcherCount += sessionMetrics.checkoutDiffWatcherCount;
821
- checkoutDiffFallbackRefreshTargetCount +=
822
- sessionMetrics.checkoutDiffFallbackRefreshTargetCount;
823
- terminalDirectorySubscriptionCount += sessionMetrics.terminalDirectorySubscriptionCount;
824
- terminalSubscriptionCount += sessionMetrics.terminalSubscriptionCount;
825
- }
826
- return {
827
- checkoutDiffTargetCount,
828
- checkoutDiffSubscriptionCount,
829
- checkoutDiffWatcherCount,
830
- checkoutDiffFallbackRefreshTargetCount,
831
- terminalDirectorySubscriptionCount,
832
- terminalSubscriptionCount,
833
- };
834
- }
835
- flushRuntimeMetrics(options) {
836
- const now = Date.now();
837
- const windowMs = Math.max(0, now - this.runtimeWindowStartedAt);
838
- const activeConnections = new Set(this.sessions.values()).size;
839
- const activeSockets = this.sessions.size;
840
- const pendingConnections = this.pendingConnections.size;
841
- const reconnectGraceSessions = [...this.externalSessionsByKey.values()].filter((connection) => connection.sockets.size === 0 && connection.externalDisconnectCleanupTimeout !== null).length;
842
- const sessionMetrics = this.collectSessionRuntimeMetrics();
843
- this.logger.info({
844
- windowMs,
845
- final: Boolean(options?.final),
846
- sessions: {
847
- activeConnections,
848
- externalSessionKeys: this.externalSessionsByKey.size,
849
- reconnectGraceSessions,
850
- },
851
- sockets: {
852
- activeSockets,
853
- pendingConnections,
854
- },
855
- counters: { ...this.runtimeCounters },
856
- inboundMessageTypesTop: this.getTopCounts(this.inboundMessageCounts, 12),
857
- inboundSessionRequestTypesTop: this.getTopCounts(this.inboundSessionRequestCounts, 20),
858
- runtime: sessionMetrics,
859
- }, "ws_runtime_metrics");
860
- for (const counter of Object.keys(this.runtimeCounters)) {
861
- this.runtimeCounters[counter] = 0;
862
- }
863
- this.inboundMessageCounts.clear();
864
- this.inboundSessionRequestCounts.clear();
865
- this.runtimeWindowStartedAt = now;
866
- }
867
- getClientActivityState(session) {
868
- const activity = session.getClientActivity();
869
- if (!activity) {
870
- return { deviceType: null, focusedAgentId: null, isStale: true, appVisible: false };
871
- }
872
- const now = Date.now();
873
- const ageMs = now - activity.lastActivityAt.getTime();
874
- const isStale = ageMs >= this.ACTIVITY_THRESHOLD_MS;
875
- return {
876
- deviceType: activity.deviceType,
877
- focusedAgentId: activity.focusedAgentId,
878
- isStale,
879
- appVisible: activity.appVisible,
880
- };
881
- }
882
- broadcastAgentAttention(params) {
883
- const clientEntries = [];
884
- for (const [ws, connection] of this.sessions) {
885
- clientEntries.push({
886
- ws,
887
- state: this.getClientActivityState(connection.session),
888
- });
889
- }
890
- const allStates = clientEntries.map((e) => e.state);
891
- const agent = this.agentManager.getAgent(params.agentId);
892
- const notification = buildAgentAttentionNotificationPayload({
893
- reason: params.reason,
894
- serverId: this.serverId,
895
- agentId: params.agentId,
896
- assistantMessage: agent ? findLatestAssistantMessageFromTimeline(agent.timeline) : null,
897
- permissionRequest: agent ? findLatestPermissionRequest(agent.pendingPermissions) : null,
898
- });
899
- // Push is only a fallback when the user is away from desktop/web.
900
- // Also suppress push if they're actively using the mobile app.
901
- const shouldSendPush = computeShouldSendPush({
902
- reason: params.reason,
903
- allClientStates: allStates,
904
- });
905
- if (shouldSendPush) {
906
- const tokens = this.pushTokenStore.getAllTokens();
907
- this.logger.info({ tokenCount: tokens.length }, "Sending push notification");
908
- if (tokens.length > 0) {
909
- void this.pushService.sendPush(tokens, notification);
910
- }
911
- }
912
- for (const { ws, state } of clientEntries) {
913
- const shouldNotify = computeShouldNotifyClient({
914
- clientState: state,
915
- allClientStates: allStates,
916
- agentId: params.agentId,
917
- });
918
- const message = wrapSessionMessage({
919
- type: "agent_stream",
920
- payload: {
921
- agentId: params.agentId,
922
- event: {
923
- type: "attention_required",
924
- provider: params.provider,
925
- reason: params.reason,
926
- timestamp: new Date().toISOString(),
927
- shouldNotify,
928
- notification,
929
- },
930
- timestamp: new Date().toISOString(),
931
- },
932
- });
933
- this.sendToClient(ws, message);
934
- }
935
- }
936
- }
937
- function extractSocketRequestMetadata(request) {
938
- if (!request || typeof request !== "object") {
939
- return {};
940
- }
941
- const record = request;
942
- const host = typeof record.headers?.host === "string" ? record.headers.host : undefined;
943
- const origin = typeof record.headers?.origin === "string" ? record.headers.origin : undefined;
944
- const userAgent = typeof record.headers?.["user-agent"] === "string" ? record.headers["user-agent"] : undefined;
945
- const remoteAddress = typeof record.socket?.remoteAddress === "string" ? record.socket.remoteAddress : undefined;
946
- return {
947
- ...(host ? { host } : {}),
948
- ...(origin ? { origin } : {}),
949
- ...(userAgent ? { userAgent } : {}),
950
- ...(remoteAddress ? { remoteAddress } : {}),
951
- };
952
- }
953
- function stringifyCloseReason(reason) {
954
- if (typeof reason === "string") {
955
- return reason.length > 0 ? reason : null;
956
- }
957
- if (Buffer.isBuffer(reason)) {
958
- const text = reason.toString();
959
- return text.length > 0 ? text : null;
960
- }
961
- if (reason == null) {
962
- return null;
963
- }
964
- const text = String(reason);
965
- return text.length > 0 ? text : null;
966
- }
967
- function extractRequestInfoFromUnknownWsInbound(payload) {
968
- if (!payload || typeof payload !== "object") {
969
- return null;
970
- }
971
- const record = payload;
972
- // Session-wrapped messages
973
- if (record.type === "session" && record.message && typeof record.message === "object") {
974
- const msg = record.message;
975
- if (typeof msg.requestId === "string") {
976
- return {
977
- requestId: msg.requestId,
978
- ...(typeof msg.type === "string" ? { requestType: msg.type } : {}),
979
- };
980
- }
981
- }
982
- // Non-session messages (future-proof)
983
- if (typeof record.requestId === "string") {
984
- return {
985
- requestId: record.requestId,
986
- ...(typeof record.type === "string" ? { requestType: record.type } : {}),
987
- };
988
- }
989
- return null;
990
- }
991
- //# sourceMappingURL=websocket-server.js.map