@hyperdrive.bot/fleet-server 0.3.99

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 (991) hide show
  1. package/.env.example +31 -0
  2. package/README.md +111 -0
  3. package/dist/scripts/dev-runner.js +37 -0
  4. package/dist/scripts/mcp-stdio-socket-bridge-cli.mjs +62 -0
  5. package/dist/scripts/supervisor-entrypoint.js +156 -0
  6. package/dist/scripts/supervisor-log-config.js +31 -0
  7. package/dist/scripts/supervisor.js +345 -0
  8. package/dist/server/executable-resolution/executable-resolution.d.ts +10 -0
  9. package/dist/server/executable-resolution/executable-resolution.js +118 -0
  10. package/dist/server/executable-resolution/windows.d.ts +18 -0
  11. package/dist/server/executable-resolution/windows.js +65 -0
  12. package/dist/server/extensions/daemon-backend.d.ts +11 -0
  13. package/dist/server/extensions/daemon-backend.js +146 -0
  14. package/dist/server/extensions/extension-host-manager.d.ts +48 -0
  15. package/dist/server/extensions/extension-host-manager.js +141 -0
  16. package/dist/server/extensions/extension-loader.d.ts +11 -0
  17. package/dist/server/extensions/extension-loader.js +47 -0
  18. package/dist/server/extensions/extension-service.d.ts +17 -0
  19. package/dist/server/extensions/extension-service.js +76 -0
  20. package/dist/server/server/agent/activity-curator.d.ts +28 -0
  21. package/dist/server/server/agent/activity-curator.js +227 -0
  22. package/dist/server/server/agent/agent-archive.d.ts +11 -0
  23. package/dist/server/server/agent/agent-archive.js +16 -0
  24. package/dist/server/server/agent/agent-list-filter.d.ts +76 -0
  25. package/dist/server/server/agent/agent-list-filter.js +184 -0
  26. package/dist/server/server/agent/agent-loading.d.ts +12 -0
  27. package/dist/server/server/agent/agent-loading.js +76 -0
  28. package/dist/server/server/agent/agent-manager.d.ts +628 -0
  29. package/dist/server/server/agent/agent-manager.js +3370 -0
  30. package/dist/server/server/agent/agent-projections.d.ts +65 -0
  31. package/dist/server/server/agent/agent-projections.js +548 -0
  32. package/dist/server/server/agent/agent-prompt.d.ts +65 -0
  33. package/dist/server/server/agent/agent-prompt.js +271 -0
  34. package/dist/server/server/agent/agent-response-loop.d.ts +67 -0
  35. package/dist/server/server/agent/agent-response-loop.js +326 -0
  36. package/dist/server/server/agent/agent-routes.d.ts +18 -0
  37. package/dist/server/server/agent/agent-routes.js +107 -0
  38. package/dist/server/server/agent/agent-sdk-types.d.ts +809 -0
  39. package/dist/server/server/agent/agent-sdk-types.js +22 -0
  40. package/dist/server/server/agent/agent-storage.d.ts +209 -0
  41. package/dist/server/server/agent/agent-storage.js +365 -0
  42. package/dist/server/server/agent/agent-stream-coalescer.d.ts +41 -0
  43. package/dist/server/server/agent/agent-stream-coalescer.js +166 -0
  44. package/dist/server/server/agent/agent-timeline-store-types.d.ts +50 -0
  45. package/dist/server/server/agent/agent-timeline-store-types.js +2 -0
  46. package/dist/server/server/agent/agent-timeline-store.d.ts +27 -0
  47. package/dist/server/server/agent/agent-timeline-store.js +277 -0
  48. package/dist/server/server/agent/audio-utils.d.ts +3 -0
  49. package/dist/server/server/agent/audio-utils.js +19 -0
  50. package/dist/server/server/agent/authorship-ledger.d.ts +139 -0
  51. package/dist/server/server/agent/authorship-ledger.js +207 -0
  52. package/dist/server/server/agent/authorship-markup.d.ts +198 -0
  53. package/dist/server/server/agent/authorship-markup.js +288 -0
  54. package/dist/server/server/agent/blocker-log.d.ts +81 -0
  55. package/dist/server/server/agent/blocker-log.js +113 -0
  56. package/dist/server/server/agent/card-move-log.d.ts +66 -0
  57. package/dist/server/server/agent/card-move-log.js +113 -0
  58. package/dist/server/server/agent/create-agent/create.d.ts +126 -0
  59. package/dist/server/server/agent/create-agent/create.js +378 -0
  60. package/dist/server/server/agent/create-agent/routine.d.ts +45 -0
  61. package/dist/server/server/agent/create-agent/routine.js +53 -0
  62. package/dist/server/server/agent/create-agent-lifecycle-dispatch.d.ts +54 -0
  63. package/dist/server/server/agent/create-agent-lifecycle-dispatch.js +152 -0
  64. package/dist/server/server/agent/create-agent-mode.d.ts +13 -0
  65. package/dist/server/server/agent/create-agent-mode.js +62 -0
  66. package/dist/server/server/agent/create-agent-title.d.ts +10 -0
  67. package/dist/server/server/agent/create-agent-title.js +34 -0
  68. package/dist/server/server/agent/dictation-debug.d.ts +13 -0
  69. package/dist/server/server/agent/dictation-debug.js +50 -0
  70. package/dist/server/server/agent/foreground-run-state.d.ts +50 -0
  71. package/dist/server/server/agent/foreground-run-state.js +160 -0
  72. package/dist/server/server/agent/import-sessions.d.ts +52 -0
  73. package/dist/server/server/agent/import-sessions.js +170 -0
  74. package/dist/server/server/agent/jarvis-judge.d.ts +157 -0
  75. package/dist/server/server/agent/jarvis-judge.js +289 -0
  76. package/dist/server/server/agent/judge-relay-gate.d.ts +70 -0
  77. package/dist/server/server/agent/judge-relay-gate.js +92 -0
  78. package/dist/server/server/agent/lifecycle-command.d.ts +75 -0
  79. package/dist/server/server/agent/lifecycle-command.js +97 -0
  80. package/dist/server/server/agent/mcp-server.d.ts +22 -0
  81. package/dist/server/server/agent/mcp-server.js +653 -0
  82. package/dist/server/server/agent/mcp-shared.d.ts +239 -0
  83. package/dist/server/server/agent/mcp-shared.js +200 -0
  84. package/dist/server/server/agent/output-language.d.ts +16 -0
  85. package/dist/server/server/agent/output-language.js +62 -0
  86. package/dist/server/server/agent/pcm16-resampler.d.ts +14 -0
  87. package/dist/server/server/agent/pcm16-resampler.js +63 -0
  88. package/dist/server/server/agent/permission-response.d.ts +15 -0
  89. package/dist/server/server/agent/permission-response.js +14 -0
  90. package/dist/server/server/agent/prompt-attachments.d.ts +7 -0
  91. package/dist/server/server/agent/prompt-attachments.js +90 -0
  92. package/dist/server/server/agent/provider-config-reload.d.ts +27 -0
  93. package/dist/server/server/agent/provider-config-reload.js +65 -0
  94. package/dist/server/server/agent/provider-history-timestamps.d.ts +2 -0
  95. package/dist/server/server/agent/provider-history-timestamps.js +16 -0
  96. package/dist/server/server/agent/provider-launch-config.d.ts +51 -0
  97. package/dist/server/server/agent/provider-launch-config.js +183 -0
  98. package/dist/server/server/agent/provider-notices.d.ts +3 -0
  99. package/dist/server/server/agent/provider-notices.js +5 -0
  100. package/dist/server/server/agent/provider-registry-contract.d.ts +40 -0
  101. package/dist/server/server/agent/provider-registry-contract.js +28 -0
  102. package/dist/server/server/agent/provider-registry.d.ts +97 -0
  103. package/dist/server/server/agent/provider-registry.js +686 -0
  104. package/dist/server/server/agent/provider-session-import.d.ts +10 -0
  105. package/dist/server/server/agent/provider-session-import.js +49 -0
  106. package/dist/server/server/agent/provider-snapshot-manager.d.ts +166 -0
  107. package/dist/server/server/agent/provider-snapshot-manager.js +760 -0
  108. package/dist/server/server/agent/providers/acp-agent.d.ts +354 -0
  109. package/dist/server/server/agent/providers/acp-agent.js +2438 -0
  110. package/dist/server/server/agent/providers/claude/agent.d.ts +491 -0
  111. package/dist/server/server/agent/providers/claude/agent.js +5128 -0
  112. package/dist/server/server/agent/providers/claude/background-shell-kill-keys.d.ts +32 -0
  113. package/dist/server/server/agent/providers/claude/background-shell-kill-keys.js +34 -0
  114. package/dist/server/server/agent/providers/claude/background-task-tracker.d.ts +217 -0
  115. package/dist/server/server/agent/providers/claude/background-task-tracker.js +511 -0
  116. package/dist/server/server/agent/providers/claude/background-work-kinds.d.ts +124 -0
  117. package/dist/server/server/agent/providers/claude/background-work-kinds.js +96 -0
  118. package/dist/server/server/agent/providers/claude/feature-definitions.d.ts +8 -0
  119. package/dist/server/server/agent/providers/claude/feature-definitions.js +24 -0
  120. package/dist/server/server/agent/providers/claude/hook-handler.d.ts +37 -0
  121. package/dist/server/server/agent/providers/claude/hook-handler.js +193 -0
  122. package/dist/server/server/agent/providers/claude/hooks/event-translator.d.ts +49 -0
  123. package/dist/server/server/agent/providers/claude/hooks/event-translator.js +151 -0
  124. package/dist/server/server/agent/providers/claude/image-compression.d.ts +10 -0
  125. package/dist/server/server/agent/providers/claude/image-compression.js +32 -0
  126. package/dist/server/server/agent/providers/claude/model-manifest.d.ts +116 -0
  127. package/dist/server/server/agent/providers/claude/model-manifest.js +279 -0
  128. package/dist/server/server/agent/providers/claude/models.d.ts +11 -0
  129. package/dist/server/server/agent/providers/claude/models.js +97 -0
  130. package/dist/server/server/agent/providers/claude/partial-json.d.ts +5 -0
  131. package/dist/server/server/agent/providers/claude/partial-json.js +306 -0
  132. package/dist/server/server/agent/providers/claude/project-dir.d.ts +6 -0
  133. package/dist/server/server/agent/providers/claude/project-dir.js +57 -0
  134. package/dist/server/server/agent/providers/claude/pty-session-launcher.d.ts +62 -0
  135. package/dist/server/server/agent/providers/claude/pty-session-launcher.js +175 -0
  136. package/dist/server/server/agent/providers/claude/resume-source.d.ts +11 -0
  137. package/dist/server/server/agent/providers/claude/resume-source.js +37 -0
  138. package/dist/server/server/agent/providers/claude/rewind.d.ts +30 -0
  139. package/dist/server/server/agent/providers/claude/rewind.js +30 -0
  140. package/dist/server/server/agent/providers/claude/sidechain-tracker.d.ts +22 -0
  141. package/dist/server/server/agent/providers/claude/sidechain-tracker.js +232 -0
  142. package/dist/server/server/agent/providers/claude/spawn-config-writer.d.ts +70 -0
  143. package/dist/server/server/agent/providers/claude/spawn-config-writer.js +229 -0
  144. package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts +47 -0
  145. package/dist/server/server/agent/providers/claude/task-notification-tool-call.js +292 -0
  146. package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.d.ts +24 -0
  147. package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.js +23 -0
  148. package/dist/server/server/agent/providers/claude/tool-allowlist-guard.d.ts +41 -0
  149. package/dist/server/server/agent/providers/claude/tool-allowlist-guard.js +95 -0
  150. package/dist/server/server/agent/providers/claude/tool-allowlist.d.ts +68 -0
  151. package/dist/server/server/agent/providers/claude/tool-allowlist.js +133 -0
  152. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts +3 -0
  153. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +130 -0
  154. package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts +16 -0
  155. package/dist/server/server/agent/providers/claude/tool-call-mapper.js +129 -0
  156. package/dist/server/server/agent/providers/claude/transport/claude-paths.d.ts +31 -0
  157. package/dist/server/server/agent/providers/claude/transport/claude-paths.js +63 -0
  158. package/dist/server/server/agent/providers/claude/transport/continue-flag.d.ts +31 -0
  159. package/dist/server/server/agent/providers/claude/transport/continue-flag.js +42 -0
  160. package/dist/server/server/agent/providers/claude/transport/pty-query.d.ts +493 -0
  161. package/dist/server/server/agent/providers/claude/transport/pty-query.js +2075 -0
  162. package/dist/server/server/agent/providers/claude/transport/pty.d.ts +153 -0
  163. package/dist/server/server/agent/providers/claude/transport/pty.js +367 -0
  164. package/dist/server/server/agent/providers/claude/transport/redact.d.ts +8 -0
  165. package/dist/server/server/agent/providers/claude/transport/redact.js +33 -0
  166. package/dist/server/server/agent/providers/claude/transport/sdk.d.ts +65 -0
  167. package/dist/server/server/agent/providers/claude/transport/sdk.js +219 -0
  168. package/dist/server/server/agent/providers/claude/transport/tmux.d.ts +141 -0
  169. package/dist/server/server/agent/providers/claude/transport/tmux.js +218 -0
  170. package/dist/server/server/agent/providers/claude/transport/transcript-sdk-reader.d.ts +53 -0
  171. package/dist/server/server/agent/providers/claude/transport/transcript-sdk-reader.js +243 -0
  172. package/dist/server/server/agent/providers/claude/transport/transcript-tailer.d.ts +28 -0
  173. package/dist/server/server/agent/providers/claude/transport/transcript-tailer.js +166 -0
  174. package/dist/server/server/agent/providers/claude/transport/truncate-session.d.ts +50 -0
  175. package/dist/server/server/agent/providers/claude/transport/truncate-session.js +121 -0
  176. package/dist/server/server/agent/providers/claude/transport/turn-id-reconciler.d.ts +36 -0
  177. package/dist/server/server/agent/providers/claude/transport/turn-id-reconciler.js +75 -0
  178. package/dist/server/server/agent/providers/claude/transport/types.d.ts +61 -0
  179. package/dist/server/server/agent/providers/claude/transport/types.js +2 -0
  180. package/dist/server/server/agent/providers/codex/app-server-transport.d.ts +90 -0
  181. package/dist/server/server/agent/providers/codex/app-server-transport.js +262 -0
  182. package/dist/server/server/agent/providers/codex/rewind.d.ts +21 -0
  183. package/dist/server/server/agent/providers/codex/rewind.js +46 -0
  184. package/dist/server/server/agent/providers/codex/test-utils/fake-app-server.d.ts +36 -0
  185. package/dist/server/server/agent/providers/codex/test-utils/fake-app-server.js +217 -0
  186. package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts +12 -0
  187. package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js +104 -0
  188. package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +24 -0
  189. package/dist/server/server/agent/providers/codex/tool-call-mapper.js +830 -0
  190. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +308 -0
  191. package/dist/server/server/agent/providers/codex-app-server-agent.js +4515 -0
  192. package/dist/server/server/agent/providers/codex-feature-definitions.d.ts +11 -0
  193. package/dist/server/server/agent/providers/codex-feature-definitions.js +45 -0
  194. package/dist/server/server/agent/providers/copilot-acp-agent.d.ts +26 -0
  195. package/dist/server/server/agent/providers/copilot-acp-agent.js +187 -0
  196. package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +15 -0
  197. package/dist/server/server/agent/providers/cursor-acp-agent.js +18 -0
  198. package/dist/server/server/agent/providers/diagnostic-utils.d.ts +36 -0
  199. package/dist/server/server/agent/providers/diagnostic-utils.js +355 -0
  200. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +42 -0
  201. package/dist/server/server/agent/providers/generic-acp-agent.js +161 -0
  202. package/dist/server/server/agent/providers/kiro-acp-agent.d.ts +17 -0
  203. package/dist/server/server/agent/providers/kiro-acp-agent.js +78 -0
  204. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +85 -0
  205. package/dist/server/server/agent/providers/mock-load-test-agent.js +1010 -0
  206. package/dist/server/server/agent/providers/mock-slow-provider.d.ts +14 -0
  207. package/dist/server/server/agent/providers/mock-slow-provider.js +39 -0
  208. package/dist/server/server/agent/providers/opencode/paths.d.ts +2 -0
  209. package/dist/server/server/agent/providers/opencode/paths.js +7 -0
  210. package/dist/server/server/agent/providers/opencode/rewind.d.ts +18 -0
  211. package/dist/server/server/agent/providers/opencode/rewind.js +14 -0
  212. package/dist/server/server/agent/providers/opencode/server-manager.d.ts +91 -0
  213. package/dist/server/server/agent/providers/opencode/server-manager.js +425 -0
  214. package/dist/server/server/agent/providers/opencode/test-server-manager.d.ts +25 -0
  215. package/dist/server/server/agent/providers/opencode/test-server-manager.js +39 -0
  216. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-harness.d.ts +92 -0
  217. package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-harness.js +268 -0
  218. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts +3 -0
  219. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +256 -0
  220. package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts +13 -0
  221. package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +53 -0
  222. package/dist/server/server/agent/providers/opencode-agent.d.ts +293 -0
  223. package/dist/server/server/agent/providers/opencode-agent.js +2908 -0
  224. package/dist/server/server/agent/providers/pi/agent.d.ts +137 -0
  225. package/dist/server/server/agent/providers/pi/agent.js +1651 -0
  226. package/dist/server/server/agent/providers/pi/cli-runtime.d.ts +21 -0
  227. package/dist/server/server/agent/providers/pi/cli-runtime.js +233 -0
  228. package/dist/server/server/agent/providers/pi/history-mapper.d.ts +9 -0
  229. package/dist/server/server/agent/providers/pi/history-mapper.js +140 -0
  230. package/dist/server/server/agent/providers/pi/rewind.d.ts +8 -0
  231. package/dist/server/server/agent/providers/pi/rewind.js +8 -0
  232. package/dist/server/server/agent/providers/pi/rpc-types.d.ts +208 -0
  233. package/dist/server/server/agent/providers/pi/rpc-types.js +2 -0
  234. package/dist/server/server/agent/providers/pi/runtime.d.ts +57 -0
  235. package/dist/server/server/agent/providers/pi/runtime.js +56 -0
  236. package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +16 -0
  237. package/dist/server/server/agent/providers/pi/session-descriptor.js +346 -0
  238. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +83 -0
  239. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +184 -0
  240. package/dist/server/server/agent/providers/pi/tool-call-mapper.d.ts +112 -0
  241. package/dist/server/server/agent/providers/pi/tool-call-mapper.js +284 -0
  242. package/dist/server/server/agent/providers/provider-image-output.d.ts +25 -0
  243. package/dist/server/server/agent/providers/provider-image-output.js +111 -0
  244. package/dist/server/server/agent/providers/provider-runner.d.ts +27 -0
  245. package/dist/server/server/agent/providers/provider-runner.js +81 -0
  246. package/dist/server/server/agent/providers/test-utils/session-stream-adapter.d.ts +3 -0
  247. package/dist/server/server/agent/providers/test-utils/session-stream-adapter.js +60 -0
  248. package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +884 -0
  249. package/dist/server/server/agent/providers/tool-call-detail-primitives.js +778 -0
  250. package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +25 -0
  251. package/dist/server/server/agent/providers/tool-call-mapper-utils.js +208 -0
  252. package/dist/server/server/agent/recordings-debug.d.ts +3 -0
  253. package/dist/server/server/agent/recordings-debug.js +19 -0
  254. package/dist/server/server/agent/render-file-attachment.d.ts +29 -0
  255. package/dist/server/server/agent/render-file-attachment.js +41 -0
  256. package/dist/server/server/agent/resolve-resume-cwd.d.ts +14 -0
  257. package/dist/server/server/agent/resolve-resume-cwd.js +49 -0
  258. package/dist/server/server/agent/rewind/rewind.d.ts +10 -0
  259. package/dist/server/server/agent/rewind/rewind.js +29 -0
  260. package/dist/server/server/agent/rewind/test-rewind-session.d.ts +48 -0
  261. package/dist/server/server/agent/rewind/test-rewind-session.js +88 -0
  262. package/dist/server/server/agent/runtime-mcp-config.d.ts +14 -0
  263. package/dist/server/server/agent/runtime-mcp-config.js +53 -0
  264. package/dist/server/server/agent/session-digest-generator.d.ts +64 -0
  265. package/dist/server/server/agent/session-digest-generator.js +306 -0
  266. package/dist/server/server/agent/session-digest.d.ts +81 -0
  267. package/dist/server/server/agent/session-digest.js +226 -0
  268. package/dist/server/server/agent/structured-generation-providers.d.ts +29 -0
  269. package/dist/server/server/agent/structured-generation-providers.js +236 -0
  270. package/dist/server/server/agent/stt-debug.d.ts +10 -0
  271. package/dist/server/server/agent/stt-debug.js +33 -0
  272. package/dist/server/server/agent/stt-manager.d.ts +47 -0
  273. package/dist/server/server/agent/stt-manager.js +263 -0
  274. package/dist/server/server/agent/system-prompt.d.ts +2 -0
  275. package/dist/server/server/agent/system-prompt.js +8 -0
  276. package/dist/server/server/agent/timeline-append.d.ts +10 -0
  277. package/dist/server/server/agent/timeline-append.js +27 -0
  278. package/dist/server/server/agent/timeline-projection.d.ts +71 -0
  279. package/dist/server/server/agent/timeline-projection.js +373 -0
  280. package/dist/server/server/agent/tools/paseo-tools.d.ts +66 -0
  281. package/dist/server/server/agent/tools/paseo-tools.js +2616 -0
  282. package/dist/server/server/agent/tools/read-only-surface.d.ts +53 -0
  283. package/dist/server/server/agent/tools/read-only-surface.js +69 -0
  284. package/dist/server/server/agent/tools/types.d.ts +41 -0
  285. package/dist/server/server/agent/tools/types.js +2 -0
  286. package/dist/server/server/agent/tts-debug.d.ts +8 -0
  287. package/dist/server/server/agent/tts-debug.js +24 -0
  288. package/dist/server/server/agent/tts-manager.d.ts +41 -0
  289. package/dist/server/server/agent/tts-manager.js +375 -0
  290. package/dist/server/server/agent/wait-for-agent-tracker.d.ts +15 -0
  291. package/dist/server/server/agent/wait-for-agent-tracker.js +53 -0
  292. package/dist/server/server/agent-attention-policy.d.ts +29 -0
  293. package/dist/server/server/agent-attention-policy.js +36 -0
  294. package/dist/server/server/atomic-file.d.ts +3 -0
  295. package/dist/server/server/atomic-file.js +19 -0
  296. package/dist/server/server/auth.d.ts +68 -0
  297. package/dist/server/server/auth.js +207 -0
  298. package/dist/server/server/auto-archive-on-merge/archive-if-safe.d.ts +40 -0
  299. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +92 -0
  300. package/dist/server/server/auto-archive-on-merge/index.d.ts +8 -0
  301. package/dist/server/server/auto-archive-on-merge/index.js +15 -0
  302. package/dist/server/server/bootstrap.d.ts +163 -0
  303. package/dist/server/server/bootstrap.js +1597 -0
  304. package/dist/server/server/browser-tools/broker.d.ts +45 -0
  305. package/dist/server/server/browser-tools/broker.js +390 -0
  306. package/dist/server/server/browser-tools/errors.d.ts +22 -0
  307. package/dist/server/server/browser-tools/errors.js +27 -0
  308. package/dist/server/server/browser-tools/policy.d.ts +10 -0
  309. package/dist/server/server/browser-tools/policy.js +16 -0
  310. package/dist/server/server/browser-tools/tools.d.ts +16 -0
  311. package/dist/server/server/browser-tools/tools.js +845 -0
  312. package/dist/server/server/chat/chat-mentions.d.ts +47 -0
  313. package/dist/server/server/chat/chat-mentions.js +113 -0
  314. package/dist/server/server/chat/chat-service.d.ts +78 -0
  315. package/dist/server/server/chat/chat-service.js +337 -0
  316. package/dist/server/server/checkout/status-projection.d.ts +19 -0
  317. package/dist/server/server/checkout/status-projection.js +102 -0
  318. package/dist/server/server/checkout-diff-manager.d.ts +41 -0
  319. package/dist/server/server/checkout-diff-manager.js +189 -0
  320. package/dist/server/server/checkout-git-utils.d.ts +11 -0
  321. package/dist/server/server/checkout-git-utils.js +34 -0
  322. package/dist/server/server/client-message-id.d.ts +3 -0
  323. package/dist/server/server/client-message-id.js +12 -0
  324. package/dist/server/server/config.d.ts +20 -0
  325. package/dist/server/server/config.js +427 -0
  326. package/dist/server/server/connection-offer.d.ts +20 -0
  327. package/dist/server/server/connection-offer.js +59 -0
  328. package/dist/server/server/daemon-config-store.d.ts +78 -0
  329. package/dist/server/server/daemon-config-store.js +320 -0
  330. package/dist/server/server/daemon-keypair.d.ts +8 -0
  331. package/dist/server/server/daemon-keypair.js +42 -0
  332. package/dist/server/server/daemon-version.d.ts +5 -0
  333. package/dist/server/server/daemon-version.js +22 -0
  334. package/dist/server/server/daemon-worker.d.ts +2 -0
  335. package/dist/server/server/daemon-worker.js +251 -0
  336. package/dist/server/server/dictation/dictation-stream-manager.d.ts +95 -0
  337. package/dist/server/server/dictation/dictation-stream-manager.js +581 -0
  338. package/dist/server/server/editor-targets.d.ts +18 -0
  339. package/dist/server/server/editor-targets.js +109 -0
  340. package/dist/server/server/ensure-workspace-for-create.d.ts +30 -0
  341. package/dist/server/server/ensure-workspace-for-create.js +20 -0
  342. package/dist/server/server/exports.d.ts +28 -0
  343. package/dist/server/server/exports.js +31 -0
  344. package/dist/server/server/file-download/token-store.d.ts +24 -0
  345. package/dist/server/server/file-download/token-store.js +40 -0
  346. package/dist/server/server/file-explorer/file-download-frames.d.ts +27 -0
  347. package/dist/server/server/file-explorer/file-download-frames.js +47 -0
  348. package/dist/server/server/file-explorer/mime-types.d.ts +58 -0
  349. package/dist/server/server/file-explorer/mime-types.js +212 -0
  350. package/dist/server/server/file-explorer/service.d.ts +97 -0
  351. package/dist/server/server/file-explorer/service.js +362 -0
  352. package/dist/server/server/file-upload/index.d.ts +27 -0
  353. package/dist/server/server/file-upload/index.js +158 -0
  354. package/dist/server/server/fleet/decision-service.d.ts +47 -0
  355. package/dist/server/server/fleet/decision-service.js +156 -0
  356. package/dist/server/server/fleet/fleet-controls.d.ts +77 -0
  357. package/dist/server/server/fleet/fleet-controls.js +217 -0
  358. package/dist/server/server/fleet/fleet-reader.d.ts +106 -0
  359. package/dist/server/server/fleet/fleet-reader.js +470 -0
  360. package/dist/server/server/fleet/fleet-scaffold.d.ts +26 -0
  361. package/dist/server/server/fleet/fleet-scaffold.js +48 -0
  362. package/dist/server/server/fleet/fleet-scheduler.d.ts +75 -0
  363. package/dist/server/server/fleet/fleet-scheduler.js +186 -0
  364. package/dist/server/server/fleet/fleet-service.d.ts +75 -0
  365. package/dist/server/server/fleet/fleet-service.js +134 -0
  366. package/dist/server/server/hostnames.d.ts +13 -0
  367. package/dist/server/server/hostnames.js +94 -0
  368. package/dist/server/server/ingestion/adapters.d.ts +21 -0
  369. package/dist/server/server/ingestion/adapters.js +27 -0
  370. package/dist/server/server/ingestion/apply.d.ts +220 -0
  371. package/dist/server/server/ingestion/apply.js +345 -0
  372. package/dist/server/server/ingestion/backfill.d.ts +123 -0
  373. package/dist/server/server/ingestion/backfill.js +160 -0
  374. package/dist/server/server/ingestion/cap-limiter.d.ts +148 -0
  375. package/dist/server/server/ingestion/cap-limiter.js +264 -0
  376. package/dist/server/server/ingestion/cohort-recorder-memory.d.ts +25 -0
  377. package/dist/server/server/ingestion/cohort-recorder-memory.js +78 -0
  378. package/dist/server/server/ingestion/cohort-recorder-store.d.ts +12 -0
  379. package/dist/server/server/ingestion/cohort-recorder-store.js +99 -0
  380. package/dist/server/server/ingestion/cohort-resume.d.ts +22 -0
  381. package/dist/server/server/ingestion/cohort-resume.js +171 -0
  382. package/dist/server/server/ingestion/cohort-store.d.ts +227 -0
  383. package/dist/server/server/ingestion/cohort-store.js +462 -0
  384. package/dist/server/server/ingestion/composio/gateway.d.ts +8 -0
  385. package/dist/server/server/ingestion/composio/gateway.js +469 -0
  386. package/dist/server/server/ingestion/dry-run.d.ts +70 -0
  387. package/dist/server/server/ingestion/dry-run.js +142 -0
  388. package/dist/server/server/ingestion/errors.d.ts +48 -0
  389. package/dist/server/server/ingestion/errors.js +63 -0
  390. package/dist/server/server/ingestion/external-user-id.d.ts +24 -0
  391. package/dist/server/server/ingestion/external-user-id.js +35 -0
  392. package/dist/server/server/ingestion/filters/store.d.ts +28 -0
  393. package/dist/server/server/ingestion/filters/store.js +74 -0
  394. package/dist/server/server/ingestion/fingerprint.d.ts +13 -0
  395. package/dist/server/server/ingestion/fingerprint.js +31 -0
  396. package/dist/server/server/ingestion/grouping.d.ts +26 -0
  397. package/dist/server/server/ingestion/grouping.js +116 -0
  398. package/dist/server/server/ingestion/hard-failure.d.ts +73 -0
  399. package/dist/server/server/ingestion/hard-failure.js +125 -0
  400. package/dist/server/server/ingestion/health.d.ts +38 -0
  401. package/dist/server/server/ingestion/health.js +90 -0
  402. package/dist/server/server/ingestion/ledger-schema.d.ts +99 -0
  403. package/dist/server/server/ingestion/ledger-schema.js +359 -0
  404. package/dist/server/server/ingestion/ledger.d.ts +562 -0
  405. package/dist/server/server/ingestion/ledger.js +881 -0
  406. package/dist/server/server/ingestion/match.d.ts +57 -0
  407. package/dist/server/server/ingestion/match.js +102 -0
  408. package/dist/server/server/ingestion/pipedream/gateway.d.ts +8 -0
  409. package/dist/server/server/ingestion/pipedream/gateway.js +282 -0
  410. package/dist/server/server/ingestion/presets.d.ts +57 -0
  411. package/dist/server/server/ingestion/presets.js +57 -0
  412. package/dist/server/server/ingestion/reconcile/artifact-kind.d.ts +19 -0
  413. package/dist/server/server/ingestion/reconcile/artifact-kind.js +65 -0
  414. package/dist/server/server/ingestion/reconcile/calendar.d.ts +19 -0
  415. package/dist/server/server/ingestion/reconcile/calendar.js +110 -0
  416. package/dist/server/server/ingestion/reconcile/constants.d.ts +60 -0
  417. package/dist/server/server/ingestion/reconcile/constants.js +62 -0
  418. package/dist/server/server/ingestion/reconcile/github.d.ts +21 -0
  419. package/dist/server/server/ingestion/reconcile/github.js +83 -0
  420. package/dist/server/server/ingestion/reconcile/gitlab.d.ts +23 -0
  421. package/dist/server/server/ingestion/reconcile/gitlab.js +94 -0
  422. package/dist/server/server/ingestion/reconcile/gmail.d.ts +9 -0
  423. package/dist/server/server/ingestion/reconcile/gmail.js +141 -0
  424. package/dist/server/server/ingestion/reconcile/jira.d.ts +17 -0
  425. package/dist/server/server/ingestion/reconcile/jira.js +76 -0
  426. package/dist/server/server/ingestion/reconcile/kinds.d.ts +16 -0
  427. package/dist/server/server/ingestion/reconcile/kinds.js +59 -0
  428. package/dist/server/server/ingestion/reconcile/mcp-call.d.ts +18 -0
  429. package/dist/server/server/ingestion/reconcile/mcp-call.js +105 -0
  430. package/dist/server/server/ingestion/reconcile/payload.d.ts +38 -0
  431. package/dist/server/server/ingestion/reconcile/payload.js +82 -0
  432. package/dist/server/server/ingestion/reconcile/registry.d.ts +40 -0
  433. package/dist/server/server/ingestion/reconcile/registry.js +72 -0
  434. package/dist/server/server/ingestion/reconcile/runner.d.ts +43 -0
  435. package/dist/server/server/ingestion/reconcile/runner.js +91 -0
  436. package/dist/server/server/ingestion/reconcile/sentry.d.ts +20 -0
  437. package/dist/server/server/ingestion/reconcile/sentry.js +85 -0
  438. package/dist/server/server/ingestion/reconcile/service.d.ts +134 -0
  439. package/dist/server/server/ingestion/reconcile/service.js +409 -0
  440. package/dist/server/server/ingestion/reconcile/signature-guard.d.ts +30 -0
  441. package/dist/server/server/ingestion/reconcile/signature-guard.js +82 -0
  442. package/dist/server/server/ingestion/reconcile/testing/fake-mcp-server.d.ts +68 -0
  443. package/dist/server/server/ingestion/reconcile/testing/fake-mcp-server.js +158 -0
  444. package/dist/server/server/ingestion/reconcile/types.d.ts +65 -0
  445. package/dist/server/server/ingestion/reconcile/types.js +11 -0
  446. package/dist/server/server/ingestion/reconcile/verdict-mapping.d.ts +54 -0
  447. package/dist/server/server/ingestion/reconcile/verdict-mapping.js +82 -0
  448. package/dist/server/server/ingestion/resolve-items.d.ts +23 -0
  449. package/dist/server/server/ingestion/resolve-items.js +54 -0
  450. package/dist/server/server/ingestion/run-projection.d.ts +35 -0
  451. package/dist/server/server/ingestion/run-projection.js +76 -0
  452. package/dist/server/server/ingestion/service.d.ts +147 -0
  453. package/dist/server/server/ingestion/service.js +364 -0
  454. package/dist/server/server/ingestion/sources/store.d.ts +27 -0
  455. package/dist/server/server/ingestion/sources/store.js +71 -0
  456. package/dist/server/server/ingestion/testing/claim-and-hang.d.ts +2 -0
  457. package/dist/server/server/ingestion/testing/claim-and-hang.js +21 -0
  458. package/dist/server/server/ingestion/testing/cohort-crash.d.ts +2 -0
  459. package/dist/server/server/ingestion/testing/cohort-crash.js +89 -0
  460. package/dist/server/server/ingestion/types.d.ts +226 -0
  461. package/dist/server/server/ingestion/types.js +18 -0
  462. package/dist/server/server/ingestion/utc-day.d.ts +27 -0
  463. package/dist/server/server/ingestion/utc-day.js +44 -0
  464. package/dist/server/server/json-utils.d.ts +11 -0
  465. package/dist/server/server/json-utils.js +45 -0
  466. package/dist/server/server/lifecycle-reasons.d.ts +4 -0
  467. package/dist/server/server/lifecycle-reasons.js +6 -0
  468. package/dist/server/server/logger.d.ts +29 -0
  469. package/dist/server/server/logger.js +125 -0
  470. package/dist/server/server/loop-service.d.ts +234 -0
  471. package/dist/server/server/loop-service.js +769 -0
  472. package/dist/server/server/managed-processes/managed-processes.d.ts +76 -0
  473. package/dist/server/server/managed-processes/managed-processes.js +326 -0
  474. package/dist/server/server/meetings/capture-http.d.ts +3 -0
  475. package/dist/server/server/meetings/capture-http.js +71 -0
  476. package/dist/server/server/meetings/capture-orchestrator.d.ts +123 -0
  477. package/dist/server/server/meetings/capture-orchestrator.js +531 -0
  478. package/dist/server/server/meetings/capture-stream-ws.d.ts +42 -0
  479. package/dist/server/server/meetings/capture-stream-ws.js +68 -0
  480. package/dist/server/server/meetings/live-transcription.d.ts +57 -0
  481. package/dist/server/server/meetings/live-transcription.js +280 -0
  482. package/dist/server/server/meetings/meetings-http.d.ts +42 -0
  483. package/dist/server/server/meetings/meetings-http.js +266 -0
  484. package/dist/server/server/messages.d.ts +9 -0
  485. package/dist/server/server/messages.js +29 -0
  486. package/dist/server/server/migrations/backfill-workspace-id.migration.d.ts +9 -0
  487. package/dist/server/server/migrations/backfill-workspace-id.migration.js +64 -0
  488. package/dist/server/server/monitoring/telemetry.d.ts +13 -0
  489. package/dist/server/server/monitoring/telemetry.js +21 -0
  490. package/dist/server/server/package-version.d.ts +19 -0
  491. package/dist/server/server/package-version.js +60 -0
  492. package/dist/server/server/pagination/cursor.d.ts +16 -0
  493. package/dist/server/server/pagination/cursor.js +62 -0
  494. package/dist/server/server/pagination/sortable-pager.d.ts +24 -0
  495. package/dist/server/server/pagination/sortable-pager.js +68 -0
  496. package/dist/server/server/pairing-offer.d.ts +18 -0
  497. package/dist/server/server/pairing-offer.js +47 -0
  498. package/dist/server/server/pairing-qr.d.ts +7 -0
  499. package/dist/server/server/pairing-qr.js +45 -0
  500. package/dist/server/server/paseo-env.d.ts +13 -0
  501. package/dist/server/server/paseo-env.js +53 -0
  502. package/dist/server/server/paseo-home.d.ts +2 -0
  503. package/dist/server/server/paseo-home.js +19 -0
  504. package/dist/server/server/paseo-worktree-service.d.ts +52 -0
  505. package/dist/server/server/paseo-worktree-service.js +294 -0
  506. package/dist/server/server/path-utils.d.ts +5 -0
  507. package/dist/server/server/path-utils.js +34 -0
  508. package/dist/server/server/persisted-config.d.ts +390 -0
  509. package/dist/server/server/persisted-config.js +424 -0
  510. package/dist/server/server/persistence-hooks.d.ts +32 -0
  511. package/dist/server/server/persistence-hooks.js +99 -0
  512. package/dist/server/server/pid-lock.d.ts +32 -0
  513. package/dist/server/server/pid-lock.js +170 -0
  514. package/dist/server/server/private-files.d.ts +6 -0
  515. package/dist/server/server/private-files.js +37 -0
  516. package/dist/server/server/process-diagnostics.d.ts +17 -0
  517. package/dist/server/server/process-diagnostics.js +22 -0
  518. package/dist/server/server/push/categories.d.ts +35 -0
  519. package/dist/server/server/push/categories.js +40 -0
  520. package/dist/server/server/push/expo-worker.d.ts +51 -0
  521. package/dist/server/server/push/expo-worker.js +188 -0
  522. package/dist/server/server/push/index.d.ts +39 -0
  523. package/dist/server/server/push/index.js +45 -0
  524. package/dist/server/server/push/notifications.d.ts +9 -0
  525. package/dist/server/server/push/notifications.js +15 -0
  526. package/dist/server/server/push/push-service.d.ts +20 -0
  527. package/dist/server/server/push/push-service.js +66 -0
  528. package/dist/server/server/push/routes.d.ts +28 -0
  529. package/dist/server/server/push/routes.js +74 -0
  530. package/dist/server/server/push/subscriptions.d.ts +42 -0
  531. package/dist/server/server/push/subscriptions.js +112 -0
  532. package/dist/server/server/push/token-store.d.ts +29 -0
  533. package/dist/server/server/push/token-store.js +78 -0
  534. package/dist/server/server/push/triggers.d.ts +68 -0
  535. package/dist/server/server/push/triggers.js +103 -0
  536. package/dist/server/server/push/vapid-keys.d.ts +15 -0
  537. package/dist/server/server/push/vapid-keys.js +52 -0
  538. package/dist/server/server/push/web-worker.d.ts +44 -0
  539. package/dist/server/server/push/web-worker.js +99 -0
  540. package/dist/server/server/reference-enricher.d.ts +41 -0
  541. package/dist/server/server/reference-enricher.js +392 -0
  542. package/dist/server/server/relay-transport.d.ts +31 -0
  543. package/dist/server/server/relay-transport.js +545 -0
  544. package/dist/server/server/resolve-workspace-id-for-path.d.ts +4 -0
  545. package/dist/server/server/resolve-workspace-id-for-path.js +71 -0
  546. package/dist/server/server/resolve-worktree-creation-intent.d.ts +32 -0
  547. package/dist/server/server/resolve-worktree-creation-intent.js +121 -0
  548. package/dist/server/server/restart-manifest.d.ts +83 -0
  549. package/dist/server/server/restart-manifest.js +122 -0
  550. package/dist/server/server/resume-after-restart.d.ts +50 -0
  551. package/dist/server/server/resume-after-restart.js +108 -0
  552. package/dist/server/server/schedule/create-cadence.d.ts +22 -0
  553. package/dist/server/server/schedule/create-cadence.js +70 -0
  554. package/dist/server/server/schedule/cron.d.ts +8 -0
  555. package/dist/server/server/schedule/cron.js +114 -0
  556. package/dist/server/server/schedule/service.d.ts +207 -0
  557. package/dist/server/server/schedule/service.js +867 -0
  558. package/dist/server/server/schedule/source-prompt.d.ts +42 -0
  559. package/dist/server/server/schedule/source-prompt.js +87 -0
  560. package/dist/server/server/schedule/store.d.ts +13 -0
  561. package/dist/server/server/schedule/store.js +57 -0
  562. package/dist/server/server/script-health-monitor.d.ts +39 -0
  563. package/dist/server/server/script-health-monitor.js +159 -0
  564. package/dist/server/server/script-proxy.d.ts +3 -0
  565. package/dist/server/server/script-proxy.js +2 -0
  566. package/dist/server/server/script-route-branch-handler.d.ts +10 -0
  567. package/dist/server/server/script-route-branch-handler.js +11 -0
  568. package/dist/server/server/script-status-projection.d.ts +36 -0
  569. package/dist/server/server/script-status-projection.js +200 -0
  570. package/dist/server/server/search/extract.d.ts +53 -0
  571. package/dist/server/server/search/extract.js +222 -0
  572. package/dist/server/server/search/index-store.d.ts +83 -0
  573. package/dist/server/server/search/index-store.js +241 -0
  574. package/dist/server/server/search/indexer.d.ts +69 -0
  575. package/dist/server/server/search/indexer.js +362 -0
  576. package/dist/server/server/search/resolve-cwd.d.ts +40 -0
  577. package/dist/server/server/search/resolve-cwd.js +109 -0
  578. package/dist/server/server/search/session-search-service.d.ts +59 -0
  579. package/dist/server/server/search/session-search-service.js +171 -0
  580. package/dist/server/server/server-id.d.ts +17 -0
  581. package/dist/server/server/server-id.js +68 -0
  582. package/dist/server/server/service-proxy.d.ts +237 -0
  583. package/dist/server/server/service-proxy.js +714 -0
  584. package/dist/server/server/session/agent-config/agent-config-session.d.ts +50 -0
  585. package/dist/server/server/session/agent-config/agent-config-session.js +98 -0
  586. package/dist/server/server/session/agent-updates/agent-updates-service.d.ts +59 -0
  587. package/dist/server/server/session/agent-updates/agent-updates-service.js +220 -0
  588. package/dist/server/server/session/chat/chat-ingestion-session.d.ts +285 -0
  589. package/dist/server/server/session/chat/chat-ingestion-session.js +504 -0
  590. package/dist/server/server/session/chat/chat-schedule-loop-session.d.ts +175 -0
  591. package/dist/server/server/session/chat/chat-schedule-loop-session.js +720 -0
  592. package/dist/server/server/session/checkout/checkout-session.d.ts +140 -0
  593. package/dist/server/server/session/checkout/checkout-session.js +927 -0
  594. package/dist/server/server/session/checkout/git-metadata-generator.d.ts +53 -0
  595. package/dist/server/server/session/checkout/git-metadata-generator.js +159 -0
  596. package/dist/server/server/session/daemon/daemon-self-update-session-controller.d.ts +32 -0
  597. package/dist/server/server/session/daemon/daemon-self-update-session-controller.js +88 -0
  598. package/dist/server/server/session/daemon/daemon-self-updater.d.ts +32 -0
  599. package/dist/server/server/session/daemon/daemon-self-updater.js +56 -0
  600. package/dist/server/server/session/daemon/daemon-session.d.ts +89 -0
  601. package/dist/server/server/session/daemon/daemon-session.js +179 -0
  602. package/dist/server/server/session/daemon/diagnostics.d.ts +41 -0
  603. package/dist/server/server/session/daemon/diagnostics.js +431 -0
  604. package/dist/server/server/session/daemon/install-origin.d.ts +7 -0
  605. package/dist/server/server/session/daemon/install-origin.js +64 -0
  606. package/dist/server/server/session/daemon/npm-global-cli.d.ts +29 -0
  607. package/dist/server/server/session/daemon/npm-global-cli.js +98 -0
  608. package/dist/server/server/session/files/workspace-files-session.d.ts +53 -0
  609. package/dist/server/server/session/files/workspace-files-session.js +245 -0
  610. package/dist/server/server/session/git-mutation/git-mutation-service.d.ts +34 -0
  611. package/dist/server/server/session/git-mutation/git-mutation-service.js +71 -0
  612. package/dist/server/server/session/ingestion/source-session.d.ts +78 -0
  613. package/dist/server/server/session/ingestion/source-session.js +191 -0
  614. package/dist/server/server/session/project-config/project-config-session.d.ts +34 -0
  615. package/dist/server/server/session/project-config/project-config-session.js +125 -0
  616. package/dist/server/server/session/provider/provider-catalog-session.d.ts +105 -0
  617. package/dist/server/server/session/provider/provider-catalog-session.js +364 -0
  618. package/dist/server/server/session/session-rename-route.d.ts +4 -0
  619. package/dist/server/server/session/session-rename-route.js +71 -0
  620. package/dist/server/server/session/session-rename-service.d.ts +25 -0
  621. package/dist/server/server/session/session-rename-service.js +76 -0
  622. package/dist/server/server/session/voice/voice-session.d.ts +166 -0
  623. package/dist/server/server/session/voice/voice-session.js +899 -0
  624. package/dist/server/server/session/voice/voice-turn-controller.d.ts +38 -0
  625. package/dist/server/server/session/voice/voice-turn-controller.js +393 -0
  626. package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.d.ts +36 -0
  627. package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.js +134 -0
  628. package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.d.ts +46 -0
  629. package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.js +214 -0
  630. package/dist/server/server/session/workspace-scripts/workspace-scripts-service.d.ts +41 -0
  631. package/dist/server/server/session/workspace-scripts/workspace-scripts-service.js +100 -0
  632. package/dist/server/server/session.d.ts +677 -0
  633. package/dist/server/server/session.js +6531 -0
  634. package/dist/server/server/speech/audio.d.ts +10 -0
  635. package/dist/server/server/speech/audio.js +101 -0
  636. package/dist/server/server/speech/provider-resolver.d.ts +3 -0
  637. package/dist/server/server/speech/provider-resolver.js +7 -0
  638. package/dist/server/server/speech/providers/local/config.d.ts +30 -0
  639. package/dist/server/server/speech/providers/local/config.js +134 -0
  640. package/dist/server/server/speech/providers/local/models.d.ts +11 -0
  641. package/dist/server/server/speech/providers/local/models.js +17 -0
  642. package/dist/server/server/speech/providers/local/runtime.d.ts +31 -0
  643. package/dist/server/server/speech/providers/local/runtime.js +135 -0
  644. package/dist/server/server/speech/providers/local/sherpa/assets/silero_vad.onnx +0 -0
  645. package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts +56 -0
  646. package/dist/server/server/speech/providers/local/sherpa/model-catalog.js +74 -0
  647. package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts +15 -0
  648. package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +142 -0
  649. package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts +49 -0
  650. package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js +73 -0
  651. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts +9 -0
  652. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +107 -0
  653. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts +28 -0
  654. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +137 -0
  655. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts +21 -0
  656. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +133 -0
  657. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.d.ts +18 -0
  658. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.js +84 -0
  659. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts +21 -0
  660. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js +101 -0
  661. package/dist/server/server/speech/providers/local/sherpa/silero-vad-provider.d.ts +19 -0
  662. package/dist/server/server/speech/providers/local/sherpa/silero-vad-provider.js +49 -0
  663. package/dist/server/server/speech/providers/local/sherpa/silero-vad-session.d.ts +38 -0
  664. package/dist/server/server/speech/providers/local/sherpa/silero-vad-session.js +176 -0
  665. package/dist/server/server/speech/providers/local/worker-bytes.d.ts +4 -0
  666. package/dist/server/server/speech/providers/local/worker-bytes.js +9 -0
  667. package/dist/server/server/speech/providers/local/worker-client.d.ts +93 -0
  668. package/dist/server/server/speech/providers/local/worker-client.js +611 -0
  669. package/dist/server/server/speech/providers/local/worker-process.d.ts +2 -0
  670. package/dist/server/server/speech/providers/local/worker-process.js +270 -0
  671. package/dist/server/server/speech/providers/local/worker-protocol.d.ts +95 -0
  672. package/dist/server/server/speech/providers/local/worker-protocol.js +2 -0
  673. package/dist/server/server/speech/providers/openai/config.d.ts +19 -0
  674. package/dist/server/server/speech/providers/openai/config.js +148 -0
  675. package/dist/server/server/speech/providers/openai/runtime.d.ts +29 -0
  676. package/dist/server/server/speech/providers/openai/runtime.js +102 -0
  677. package/dist/server/server/speech/providers/openai/stt.d.ts +23 -0
  678. package/dist/server/server/speech/providers/openai/stt.js +209 -0
  679. package/dist/server/server/speech/providers/openai/tts.d.ts +19 -0
  680. package/dist/server/server/speech/providers/openai/tts.js +48 -0
  681. package/dist/server/server/speech/speech-config-resolver.d.ts +11 -0
  682. package/dist/server/server/speech/speech-config-resolver.js +132 -0
  683. package/dist/server/server/speech/speech-provider.d.ts +59 -0
  684. package/dist/server/server/speech/speech-provider.js +2 -0
  685. package/dist/server/server/speech/speech-runtime.d.ts +45 -0
  686. package/dist/server/server/speech/speech-runtime.js +562 -0
  687. package/dist/server/server/speech/speech-types.d.ts +22 -0
  688. package/dist/server/server/speech/speech-types.js +8 -0
  689. package/dist/server/server/speech/turn-detection-provider.d.ts +23 -0
  690. package/dist/server/server/speech/turn-detection-provider.js +2 -0
  691. package/dist/server/server/tenant-token-verifier.d.ts +43 -0
  692. package/dist/server/server/tenant-token-verifier.js +79 -0
  693. package/dist/server/server/update/installer.d.ts +70 -0
  694. package/dist/server/server/update/installer.js +181 -0
  695. package/dist/server/server/update/registry.d.ts +47 -0
  696. package/dist/server/server/update/registry.js +95 -0
  697. package/dist/server/server/update/slots.d.ts +45 -0
  698. package/dist/server/server/update/slots.js +97 -0
  699. package/dist/server/server/update/state.d.ts +41 -0
  700. package/dist/server/server/update/state.js +65 -0
  701. package/dist/server/server/uploads/file-attachment-validation.d.ts +61 -0
  702. package/dist/server/server/uploads/file-attachment-validation.js +56 -0
  703. package/dist/server/server/uploads/staging-service.d.ts +91 -0
  704. package/dist/server/server/uploads/staging-service.js +144 -0
  705. package/dist/server/server/utils/diff-highlighter.d.ts +57 -0
  706. package/dist/server/server/utils/diff-highlighter.js +279 -0
  707. package/dist/server/server/voice/voice-turn-controller.d.ts +38 -0
  708. package/dist/server/server/voice/voice-turn-controller.js +393 -0
  709. package/dist/server/server/voice-config.d.ts +15 -0
  710. package/dist/server/server/voice-config.js +54 -0
  711. package/dist/server/server/voice-permission-policy.d.ts +4 -0
  712. package/dist/server/server/voice-permission-policy.js +13 -0
  713. package/dist/server/server/voice-types.d.ts +12 -0
  714. package/dist/server/server/voice-types.js +2 -0
  715. package/dist/server/server/watch/composer-dictate.d.ts +42 -0
  716. package/dist/server/server/watch/composer-dictate.js +37 -0
  717. package/dist/server/server/watch/notification-action.d.ts +38 -0
  718. package/dist/server/server/watch/notification-action.js +54 -0
  719. package/dist/server/server/watch/notification-registry.d.ts +16 -0
  720. package/dist/server/server/watch/notification-registry.js +2 -0
  721. package/dist/server/server/web-ui.d.ts +10 -0
  722. package/dist/server/server/web-ui.js +247 -0
  723. package/dist/server/server/websocket/runtime-metrics.d.ts +94 -0
  724. package/dist/server/server/websocket/runtime-metrics.js +148 -0
  725. package/dist/server/server/websocket-server.d.ts +231 -0
  726. package/dist/server/server/websocket-server.js +1853 -0
  727. package/dist/server/server/whatsapp-bridge.d.ts +74 -0
  728. package/dist/server/server/whatsapp-bridge.js +142 -0
  729. package/dist/server/server/workflow/workflow-agent-resolution.d.ts +82 -0
  730. package/dist/server/server/workflow/workflow-agent-resolution.js +105 -0
  731. package/dist/server/server/workflow/workflow-feature.d.ts +2 -0
  732. package/dist/server/server/workflow/workflow-feature.js +8 -0
  733. package/dist/server/server/workflow/workflow-http-routes.d.ts +27 -0
  734. package/dist/server/server/workflow/workflow-http-routes.js +97 -0
  735. package/dist/server/server/workflow/workflow-manager.d.ts +363 -0
  736. package/dist/server/server/workflow/workflow-manager.js +852 -0
  737. package/dist/server/server/workflow/workflow-progress.d.ts +148 -0
  738. package/dist/server/server/workflow/workflow-progress.js +274 -0
  739. package/dist/server/server/workflow/workflow-storage.d.ts +36 -0
  740. package/dist/server/server/workflow/workflow-storage.js +143 -0
  741. package/dist/server/server/workspace/all-sessions-route.d.ts +32 -0
  742. package/dist/server/server/workspace/all-sessions-route.js +218 -0
  743. package/dist/server/server/workspace/recall-search-feature.d.ts +2 -0
  744. package/dist/server/server/workspace/recall-search-feature.js +31 -0
  745. package/dist/server/server/workspace/session-openable.d.ts +16 -0
  746. package/dist/server/server/workspace/session-openable.js +48 -0
  747. package/dist/server/server/workspace/sessions-route.d.ts +15 -0
  748. package/dist/server/server/workspace/sessions-route.js +108 -0
  749. package/dist/server/server/workspace/sessions-search-route.d.ts +40 -0
  750. package/dist/server/server/workspace/sessions-search-route.js +74 -0
  751. package/dist/server/server/workspace-archive-service.d.ts +65 -0
  752. package/dist/server/server/workspace-archive-service.js +229 -0
  753. package/dist/server/server/workspace-auto-name.d.ts +55 -0
  754. package/dist/server/server/workspace-auto-name.js +128 -0
  755. package/dist/server/server/workspace-bootstrap-dedupe.d.ts +34 -0
  756. package/dist/server/server/workspace-bootstrap-dedupe.js +23 -0
  757. package/dist/server/server/workspace-directory.d.ts +93 -0
  758. package/dist/server/server/workspace-directory.js +440 -0
  759. package/dist/server/server/workspace-git-metadata.d.ts +24 -0
  760. package/dist/server/server/workspace-git-metadata.js +55 -0
  761. package/dist/server/server/workspace-git-service.d.ts +257 -0
  762. package/dist/server/server/workspace-git-service.js +1386 -0
  763. package/dist/server/server/workspace-reconciliation-service.d.ts +57 -0
  764. package/dist/server/server/workspace-reconciliation-service.js +278 -0
  765. package/dist/server/server/workspace-registry-bootstrap.d.ts +13 -0
  766. package/dist/server/server/workspace-registry-bootstrap.js +121 -0
  767. package/dist/server/server/workspace-registry-model.d.ts +55 -0
  768. package/dist/server/server/workspace-registry-model.js +190 -0
  769. package/dist/server/server/workspace-registry.d.ts +117 -0
  770. package/dist/server/server/workspace-registry.js +194 -0
  771. package/dist/server/server/workspace-script-runtime-store.d.ts +28 -0
  772. package/dist/server/server/workspace-script-runtime-store.js +78 -0
  773. package/dist/server/server/workspace-service-env.d.ts +18 -0
  774. package/dist/server/server/workspace-service-env.js +85 -0
  775. package/dist/server/server/workspace-service-port-registry.d.ts +19 -0
  776. package/dist/server/server/workspace-service-port-registry.js +59 -0
  777. package/dist/server/server/worktree/commands.d.ts +55 -0
  778. package/dist/server/server/worktree/commands.js +107 -0
  779. package/dist/server/server/worktree-bootstrap.d.ts +76 -0
  780. package/dist/server/server/worktree-bootstrap.js +720 -0
  781. package/dist/server/server/worktree-branch-name-generator.d.ts +35 -0
  782. package/dist/server/server/worktree-branch-name-generator.js +91 -0
  783. package/dist/server/server/worktree-core.d.ts +31 -0
  784. package/dist/server/server/worktree-core.js +105 -0
  785. package/dist/server/server/worktree-errors.d.ts +12 -0
  786. package/dist/server/server/worktree-errors.js +28 -0
  787. package/dist/server/server/worktree-session.d.ts +152 -0
  788. package/dist/server/server/worktree-session.js +466 -0
  789. package/dist/server/services/github-service.d.ts +337 -0
  790. package/dist/server/services/github-service.js +2101 -0
  791. package/dist/server/services/quota-fetcher/manifest.d.ts +4 -0
  792. package/dist/server/services/quota-fetcher/manifest.js +52 -0
  793. package/dist/server/services/quota-fetcher/provider.d.ts +17 -0
  794. package/dist/server/services/quota-fetcher/provider.js +2 -0
  795. package/dist/server/services/quota-fetcher/providers/claude.d.ts +26 -0
  796. package/dist/server/services/quota-fetcher/providers/claude.js +217 -0
  797. package/dist/server/services/quota-fetcher/providers/codex.d.ts +23 -0
  798. package/dist/server/services/quota-fetcher/providers/codex.js +211 -0
  799. package/dist/server/services/quota-fetcher/providers/copilot.d.ts +17 -0
  800. package/dist/server/services/quota-fetcher/providers/copilot.js +75 -0
  801. package/dist/server/services/quota-fetcher/providers/cursor.d.ts +17 -0
  802. package/dist/server/services/quota-fetcher/providers/cursor.js +123 -0
  803. package/dist/server/services/quota-fetcher/providers/grok.d.ts +18 -0
  804. package/dist/server/services/quota-fetcher/providers/grok.js +89 -0
  805. package/dist/server/services/quota-fetcher/providers/kimi.d.ts +20 -0
  806. package/dist/server/services/quota-fetcher/providers/kimi.js +89 -0
  807. package/dist/server/services/quota-fetcher/providers/minimax.d.ts +29 -0
  808. package/dist/server/services/quota-fetcher/providers/minimax.js +227 -0
  809. package/dist/server/services/quota-fetcher/providers/zai.d.ts +17 -0
  810. package/dist/server/services/quota-fetcher/providers/zai.js +58 -0
  811. package/dist/server/services/quota-fetcher/service.d.ts +28 -0
  812. package/dist/server/services/quota-fetcher/service.js +58 -0
  813. package/dist/server/services/quota-fetcher/usage.d.ts +22 -0
  814. package/dist/server/services/quota-fetcher/usage.js +49 -0
  815. package/dist/server/terminal/activity/terminal-activity-tracker.d.ts +20 -0
  816. package/dist/server/terminal/activity/terminal-activity-tracker.js +59 -0
  817. package/dist/server/terminal/agent-hooks/agent-hook-installer.d.ts +62 -0
  818. package/dist/server/terminal/agent-hooks/agent-hook-installer.js +117 -0
  819. package/dist/server/terminal/agent-hooks/claude/claude-settings.d.ts +7 -0
  820. package/dist/server/terminal/agent-hooks/claude/claude-settings.js +88 -0
  821. package/dist/server/terminal/agent-hooks/claude/claude.d.ts +4 -0
  822. package/dist/server/terminal/agent-hooks/claude/claude.js +47 -0
  823. package/dist/server/terminal/agent-hooks/codex/codex-settings.d.ts +7 -0
  824. package/dist/server/terminal/agent-hooks/codex/codex-settings.js +99 -0
  825. package/dist/server/terminal/agent-hooks/codex/codex.d.ts +4 -0
  826. package/dist/server/terminal/agent-hooks/codex/codex.js +30 -0
  827. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.d.ts +4 -0
  828. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.js +46 -0
  829. package/dist/server/terminal/agent-hooks/opencode/opencode.d.ts +3 -0
  830. package/dist/server/terminal/agent-hooks/opencode/opencode.js +23 -0
  831. package/dist/server/terminal/agent-hooks/provider-registry.d.ts +24 -0
  832. package/dist/server/terminal/agent-hooks/provider-registry.js +36 -0
  833. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.d.ts +10 -0
  834. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.js +26 -0
  835. package/dist/server/terminal/shell-integration/zsh/.zshenv +17 -0
  836. package/dist/server/terminal/shell-integration/zsh/paseo-integration.zsh +32 -0
  837. package/dist/server/terminal/terminal-capture.d.ts +12 -0
  838. package/dist/server/terminal/terminal-capture.js +43 -0
  839. package/dist/server/terminal/terminal-manager-factory.d.ts +6 -0
  840. package/dist/server/terminal/terminal-manager-factory.js +5 -0
  841. package/dist/server/terminal/terminal-manager.d.ts +78 -0
  842. package/dist/server/terminal/terminal-manager.js +319 -0
  843. package/dist/server/terminal/terminal-output-coalescer.d.ts +34 -0
  844. package/dist/server/terminal/terminal-output-coalescer.js +73 -0
  845. package/dist/server/terminal/terminal-restore.d.ts +18 -0
  846. package/dist/server/terminal/terminal-restore.js +52 -0
  847. package/dist/server/terminal/terminal-session-controller.d.ts +85 -0
  848. package/dist/server/terminal/terminal-session-controller.js +819 -0
  849. package/dist/server/terminal/terminal-ts-loader.mjs +20 -0
  850. package/dist/server/terminal/terminal-worker-process.d.ts +2 -0
  851. package/dist/server/terminal/terminal-worker-process.js +304 -0
  852. package/dist/server/terminal/terminal-worker-protocol.d.ts +119 -0
  853. package/dist/server/terminal/terminal-worker-protocol.js +2 -0
  854. package/dist/server/terminal/terminal.d.ts +151 -0
  855. package/dist/server/terminal/terminal.js +1161 -0
  856. package/dist/server/terminal/worker-terminal-manager.d.ts +20 -0
  857. package/dist/server/terminal/worker-terminal-manager.js +688 -0
  858. package/dist/server/utils/build-metadata-prompt.d.ts +19 -0
  859. package/dist/server/utils/build-metadata-prompt.js +29 -0
  860. package/dist/server/utils/checkout-git.d.ts +253 -0
  861. package/dist/server/utils/checkout-git.js +2238 -0
  862. package/dist/server/utils/directory-suggestions.d.ts +26 -0
  863. package/dist/server/utils/directory-suggestions.js +860 -0
  864. package/dist/server/utils/git-rev-parse-path.d.ts +3 -0
  865. package/dist/server/utils/git-rev-parse-path.js +21 -0
  866. package/dist/server/utils/github-remote.d.ts +9 -0
  867. package/dist/server/utils/github-remote.js +62 -0
  868. package/dist/server/utils/paseo-config-file.d.ts +30 -0
  869. package/dist/server/utils/paseo-config-file.js +90 -0
  870. package/dist/server/utils/path.d.ts +18 -0
  871. package/dist/server/utils/path.js +123 -0
  872. package/dist/server/utils/project-icon.d.ts +39 -0
  873. package/dist/server/utils/project-icon.js +364 -0
  874. package/dist/server/utils/promise-timeout.d.ts +9 -0
  875. package/dist/server/utils/promise-timeout.js +25 -0
  876. package/dist/server/utils/run-git-command.d.ts +37 -0
  877. package/dist/server/utils/run-git-command.js +232 -0
  878. package/dist/server/utils/spawn.d.ts +33 -0
  879. package/dist/server/utils/spawn.js +71 -0
  880. package/dist/server/utils/string-command-shell.d.ts +10 -0
  881. package/dist/server/utils/string-command-shell.js +21 -0
  882. package/dist/server/utils/tree-kill.d.ts +18 -0
  883. package/dist/server/utils/tree-kill.js +77 -0
  884. package/dist/server/utils/windows-command.d.ts +15 -0
  885. package/dist/server/utils/windows-command.js +41 -0
  886. package/dist/server/utils/worktree-metadata.d.ts +39 -0
  887. package/dist/server/utils/worktree-metadata.js +174 -0
  888. package/dist/server/utils/worktree.d.ts +205 -0
  889. package/dist/server/utils/worktree.js +1119 -0
  890. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css +1 -0
  891. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.br +0 -0
  892. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.gz +0 -0
  893. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js +5 -0
  894. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.br +0 -0
  895. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.gz +0 -0
  896. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.map.br +0 -0
  897. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-67f19cbfce758da6aa23c38c2dbd6a33.js.map.gz +0 -0
  898. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js +3 -0
  899. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.br +0 -0
  900. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.gz +0 -0
  901. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.map.br +0 -0
  902. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-6888615a6b700f975c1f78501ad8577c.js.map.gz +0 -0
  903. package/dist/server/web-ui/_expo/static/js/web/index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js +16683 -0
  904. package/dist/server/web-ui/_expo/static/js/web/index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.br +0 -0
  905. package/dist/server/web-ui/_expo/static/js/web/index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.gz +0 -0
  906. package/dist/server/web-ui/_expo/static/js/web/index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.map.br +0 -0
  907. package/dist/server/web-ui/_expo/static/js/web/index-dc1e81e7cbad84d30a01c48dcc9a5a3e.js.map.gz +0 -0
  908. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js +3 -0
  909. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.br +0 -0
  910. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.gz +0 -0
  911. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.map.br +0 -0
  912. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-991ae7fd00f9fed45084fbb39160e8b8.js.map.gz +0 -0
  913. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js +5 -0
  914. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.br +0 -0
  915. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.gz +0 -0
  916. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.map.br +0 -0
  917. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-fdb4d787a259ce350f76280ca0e2bfa2.js.map.gz +0 -0
  918. package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js +11 -0
  919. package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.br +0 -0
  920. package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.gz +0 -0
  921. package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.map.br +0 -0
  922. package/dist/server/web-ui/_expo/static/js/web/profiler-9502a8e721925a6353ec45f7613f537e.js.map.gz +0 -0
  923. package/dist/server/web-ui/_expo/static/js/web/startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js +60 -0
  924. package/dist/server/web-ui/_expo/static/js/web/startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.br +0 -0
  925. package/dist/server/web-ui/_expo/static/js/web/startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.gz +0 -0
  926. package/dist/server/web-ui/_expo/static/js/web/startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.map.br +0 -0
  927. package/dist/server/web-ui/_expo/static/js/web/startRecording-4ed5094aa059a0fc724f5ae70dd2f693.js.map.gz +0 -0
  928. package/dist/server/web-ui/apple-touch-icon.png +0 -0
  929. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png +0 -0
  930. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png +0 -0
  931. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png +0 -0
  932. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png +0 -0
  933. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png +0 -0
  934. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png +0 -0
  935. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png +0 -0
  936. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png +0 -0
  937. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png +0 -0
  938. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png +0 -0
  939. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png +0 -0
  940. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png +0 -0
  941. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png +0 -0
  942. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png +0 -0
  943. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png +0 -0
  944. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png +0 -0
  945. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png +0 -0
  946. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png +0 -0
  947. package/dist/server/web-ui/assets/assets/images/editor-apps/antigravity.6e91a685c33435e0b466a56db86cf141.png +0 -0
  948. package/dist/server/web-ui/assets/assets/images/editor-apps/cursor.c31d6bce4fe9aadc3fe59962f4c4fcf3.png +0 -0
  949. package/dist/server/web-ui/assets/assets/images/editor-apps/file-explorer.3e15e8f72c825c85ce336bcb0cdef776.png +0 -0
  950. package/dist/server/web-ui/assets/assets/images/editor-apps/finder.7f68fc2c475621a672e1be09309d5567.png +0 -0
  951. package/dist/server/web-ui/assets/assets/images/editor-apps/vscode.832bdb4c685d930f1c864c793703600b.png +0 -0
  952. package/dist/server/web-ui/assets/assets/images/editor-apps/webstorm.aa5dc2cd8c20cc0a155c4c5c5ab3c5f5.png +0 -0
  953. package/dist/server/web-ui/assets/assets/images/editor-apps/zed.f3a670b7f9aa226da4fe53fb86f1abbd.png +0 -0
  954. package/dist/server/web-ui/assets/assets/images/favicon-dark-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
  955. package/dist/server/web-ui/assets/assets/images/favicon-dark-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
  956. package/dist/server/web-ui/assets/assets/images/favicon-dark.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
  957. package/dist/server/web-ui/assets/assets/images/favicon-light-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
  958. package/dist/server/web-ui/assets/assets/images/favicon-light-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
  959. package/dist/server/web-ui/assets/assets/images/favicon-light.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
  960. package/dist/server/web-ui/assets/assets/images/notification-icon.3bf81d33ddbf380606bdd248ba83e158.png +0 -0
  961. package/dist/server/web-ui/favicon.ico +0 -0
  962. package/dist/server/web-ui/index.html +196 -0
  963. package/dist/server/web-ui/index.html.br +0 -0
  964. package/dist/server/web-ui/index.html.gz +0 -0
  965. package/dist/server/web-ui/manifest.json +27 -0
  966. package/dist/server/web-ui/manifest.json.br +0 -0
  967. package/dist/server/web-ui/manifest.json.gz +0 -0
  968. package/dist/server/web-ui/metadata.json +1 -0
  969. package/dist/server/web-ui/metadata.json.br +1 -0
  970. package/dist/server/web-ui/metadata.json.gz +0 -0
  971. package/dist/server/web-ui/pwa-icon-192.png +0 -0
  972. package/dist/server/web-ui/pwa-icon-512.png +0 -0
  973. package/dist/server/web-ui/robots.txt +2 -0
  974. package/dist/server/web-ui/service-worker.js +87 -0
  975. package/dist/server/web-ui/service-worker.js.br +0 -0
  976. package/dist/server/web-ui/service-worker.js.gz +0 -0
  977. package/dist/src/executable-resolution/executable-resolution.js +118 -0
  978. package/dist/src/executable-resolution/windows.js +65 -0
  979. package/dist/src/server/agent/provider-launch-config.js +183 -0
  980. package/dist/src/server/paseo-env.js +53 -0
  981. package/dist/src/server/paseo-home.js +19 -0
  982. package/dist/src/server/persisted-config.js +424 -0
  983. package/dist/src/server/pid-lock.js +170 -0
  984. package/dist/src/server/private-files.js +37 -0
  985. package/dist/src/server/speech/providers/local/sherpa/sherpa-runtime-env.js +84 -0
  986. package/dist/src/server/update/slots.js +97 -0
  987. package/dist/src/terminal/shell-integration/zsh/.zshenv +17 -0
  988. package/dist/src/terminal/shell-integration/zsh/paseo-integration.zsh +32 -0
  989. package/dist/src/utils/spawn.js +71 -0
  990. package/dist/src/utils/windows-command.js +41 -0
  991. package/package.json +146 -0
@@ -0,0 +1,3370 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { resolve } from "node:path";
3
+ import { stat } from "node:fs/promises";
4
+ import { AGENT_LIFECYCLE_STATUSES, } from "@hyperdrive.bot/fleet-protocol/agent-lifecycle";
5
+ import { getParentAgentIdFromLabels, isDelegatedAgent, PARENT_AGENT_ID_LABEL, } from "@hyperdrive.bot/fleet-protocol/agent-labels";
6
+ import { z } from "zod";
7
+ import { getAgentStreamEventTurnId, } from "./agent-sdk-types.js";
8
+ import { buildArchivedAgentRecord } from "./agent-archive.js";
9
+ import { KANBAN_LABEL_KEY } from "./card-move-log.js";
10
+ import { InMemoryAgentTimelineStore, } from "./agent-timeline-store.js";
11
+ import { AGENT_STREAM_COALESCE_DEFAULT_WINDOW_MS, AgentStreamCoalescer, } from "./agent-stream-coalescer.js";
12
+ import { ForegroundRunState } from "./foreground-run-state.js";
13
+ import { normalizeAllowedTools } from "@hyperdrive.bot/fleet-protocol/allowed-tools";
14
+ import { getAgentProviderDefinition } from "@hyperdrive.bot/fleet-protocol/provider-manifest";
15
+ import { invokeRewindCapability } from "./rewind/rewind.js";
16
+ import { isSystemInjectedEnvelope } from "./agent-prompt.js";
17
+ import { stripInternalPaseoMcpServer, withRuntimePaseoMcpServer } from "./runtime-mcp-config.js";
18
+ import { resolveCreateAgentTitles } from "./create-agent-title.js";
19
+ const RELOAD_SESSION_CLOSE_TIMEOUT_MS = 3000;
20
+ const INTERRUPT_SESSION_TIMEOUT_MS = 2000;
21
+ const STORED_AGENT_CAPABILITIES = {
22
+ supportsStreaming: false,
23
+ supportsSessionPersistence: true,
24
+ supportsDynamicModes: false,
25
+ supportsMcpServers: false,
26
+ supportsReasoningStream: false,
27
+ supportsToolInvocations: true,
28
+ supportsRewindConversation: false,
29
+ supportsRewindFiles: false,
30
+ supportsRewindBoth: false,
31
+ };
32
+ function formatProviderList(providers) {
33
+ return providers.length > 0 ? providers.join(", ") : "none";
34
+ }
35
+ // Exported for the round-trip test that asserts every persisted config key is
36
+ // restored. See agent-config-roundtrip.test.ts.
37
+ export function buildStoredAgentConfig(record) {
38
+ const config = {
39
+ provider: record.provider,
40
+ cwd: record.cwd,
41
+ };
42
+ if (!record.config) {
43
+ return config;
44
+ }
45
+ if (record.config.modeId != null)
46
+ config.modeId = record.config.modeId;
47
+ if (record.config.model != null)
48
+ config.model = record.config.model;
49
+ if (record.config.thinkingOptionId != null) {
50
+ config.thinkingOptionId = record.config.thinkingOptionId;
51
+ }
52
+ if (record.config.featureValues != null) {
53
+ config.featureValues = record.config.featureValues;
54
+ }
55
+ if (record.config.extra != null)
56
+ config.extra = record.config.extra;
57
+ if (record.config.systemPrompt != null) {
58
+ config.systemPrompt = record.config.systemPrompt;
59
+ }
60
+ if (record.config.outputLanguage != null) {
61
+ config.outputLanguage = record.config.outputLanguage;
62
+ }
63
+ if (record.config.goal != null)
64
+ config.goal = record.config.goal;
65
+ if (record.config.jobToBeDone != null)
66
+ config.jobToBeDone = record.config.jobToBeDone;
67
+ if (record.config.mcpServers != null)
68
+ config.mcpServers = record.config.mcpServers;
69
+ // Same omission class as outputLanguage, found while adding it: allowedTools
70
+ // was written by agent-projections but never read back here, so the tool
71
+ // allowlist evaporated on every daemon restart and resume - the exact failure
72
+ // its own schema comment says is "worse than none", because the operator
73
+ // still believes the run is fenced.
74
+ if (record.config.allowedTools != null) {
75
+ config.allowedTools = record.config.allowedTools;
76
+ }
77
+ return stripInternalPaseoMcpServer(config);
78
+ }
79
+ export { AGENT_LIFECYCLE_STATUSES };
80
+ /**
81
+ * Reject a create call that asks for a tool allowlist the chosen provider cannot
82
+ * enforce. Silently dropping it would hand the caller a guarantee that does not
83
+ * exist, so the failure is loud and names the provider.
84
+ */
85
+ function requireToolAllowlistSupport(client, config) {
86
+ if (!config.allowedTools || config.allowedTools.length === 0)
87
+ return;
88
+ if (client.supportsToolAllowlist === true)
89
+ return;
90
+ throw new Error(`Provider '${config.provider}' cannot enforce a tool allowlist (allowedTools). ` +
91
+ "Only the claude provider (and providers derived from it) supports runtime tool " +
92
+ "enforcement. Re-run without --allowed-tools, or use a claude-based provider.");
93
+ }
94
+ function resolveInitialAttention(input) {
95
+ if (input == null || !input.requiresAttention) {
96
+ return { requiresAttention: false };
97
+ }
98
+ return {
99
+ requiresAttention: true,
100
+ attentionReason: input.attentionReason,
101
+ attentionTimestamp: new Date(input.attentionTimestamp),
102
+ };
103
+ }
104
+ const SYSTEM_ERROR_PREFIX = "[System Error]";
105
+ function attachPersistenceCwd(handle, cwd) {
106
+ if (!handle) {
107
+ return null;
108
+ }
109
+ return {
110
+ ...handle,
111
+ metadata: {
112
+ ...handle.metadata,
113
+ cwd,
114
+ },
115
+ };
116
+ }
117
+ const BUSY_STATUSES = new Set(["initializing", "running"]);
118
+ const AgentIdSchema = z.guid();
119
+ function isAgentBusy(status) {
120
+ return BUSY_STATUSES.has(status);
121
+ }
122
+ function isTurnTerminalEvent(event) {
123
+ return (event.type === "turn_completed" ||
124
+ event.type === "turn_failed" ||
125
+ event.type === "turn_canceled");
126
+ }
127
+ function abortMessage(reason, fallbackMessage) {
128
+ if (typeof reason === "string")
129
+ return reason;
130
+ if (reason instanceof Error)
131
+ return reason.message;
132
+ return fallbackMessage;
133
+ }
134
+ function createAbortError(signal, fallbackMessage) {
135
+ const message = abortMessage(signal?.reason, fallbackMessage);
136
+ return Object.assign(new Error(message), { name: "AbortError" });
137
+ }
138
+ function validateAgentId(agentId, source) {
139
+ const result = AgentIdSchema.safeParse(agentId);
140
+ if (!result.success) {
141
+ throw new Error(`${source}: agentId must be a UUID`);
142
+ }
143
+ return result.data;
144
+ }
145
+ function applyLabelPatch(labels, patch) {
146
+ const nextLabels = { ...labels };
147
+ for (const [key, value] of Object.entries(patch)) {
148
+ if (value === null) {
149
+ delete nextLabels[key];
150
+ }
151
+ else {
152
+ nextLabels[key] = value;
153
+ }
154
+ }
155
+ return nextLabels;
156
+ }
157
+ function buildExplicitTimelineSeedForRegister(now, options) {
158
+ const hasTimeline = Boolean(options?.timeline?.length);
159
+ const hasTimelineRows = Boolean(options?.timelineRows?.length);
160
+ const hasTimelineNextSeq = options?.timelineNextSeq !== undefined;
161
+ if (!hasTimeline && !hasTimelineRows && !hasTimelineNextSeq) {
162
+ return null;
163
+ }
164
+ return {
165
+ items: options?.timeline,
166
+ rows: options?.timelineRows,
167
+ nextSeq: options?.timelineNextSeq,
168
+ timestamp: (options?.updatedAt ?? options?.createdAt ?? now).toISOString(),
169
+ };
170
+ }
171
+ function buildImportedTimelineRows(entries) {
172
+ const rows = [];
173
+ for (const entry of entries) {
174
+ if (entry.item.type === "user_message" && isSystemInjectedEnvelope(entry.item.text)) {
175
+ continue;
176
+ }
177
+ rows.push({
178
+ seq: rows.length + 1,
179
+ timestamp: entry.timestamp ?? new Date().toISOString(),
180
+ item: entry.item,
181
+ });
182
+ }
183
+ return rows;
184
+ }
185
+ function resolveImportedAgentTitle(config, timelineRows) {
186
+ const initialPrompt = getFirstUserMessageTextFromRows(timelineRows);
187
+ if (!initialPrompt) {
188
+ return null;
189
+ }
190
+ const { explicitTitle, provisionalTitle } = resolveCreateAgentTitles({
191
+ configTitle: config.title,
192
+ initialPrompt,
193
+ });
194
+ return explicitTitle ?? provisionalTitle ?? null;
195
+ }
196
+ function getFirstUserMessageTextFromRows(rows) {
197
+ for (const row of rows) {
198
+ const item = row.item;
199
+ if (item.type !== "user_message") {
200
+ continue;
201
+ }
202
+ const text = item.text.trim();
203
+ if (text) {
204
+ return text;
205
+ }
206
+ }
207
+ return null;
208
+ }
209
+ export class AgentManager {
210
+ constructor(options) {
211
+ this.clients = new Map();
212
+ this.providerEnabled = new Map();
213
+ /**
214
+ * Per-provider hot-swap metadata indexed by provider id. Populated by
215
+ * {@link updateProviderRegistry} from the daemon's ProviderEnabledMap.
216
+ * Empty when callers (mostly tests) pass only the bare `{enabled}` shape.
217
+ */
218
+ this.providerSwapMetadata = new Map();
219
+ this.agents = new Map();
220
+ this.timelineStore = new InMemoryAgentTimelineStore();
221
+ this.agentsAwaitingInitialSnapshotPersist = new Set();
222
+ this.sessionEventTails = new Map();
223
+ this.foregroundRuns = new ForegroundRunState();
224
+ this.subscribers = new Set();
225
+ this.previousStatuses = new Map();
226
+ this.backgroundTasks = new Set();
227
+ this.attentionListeners = new Set();
228
+ this.paseoToolsEnabled = true;
229
+ this.paseoToolCatalogFactory = null;
230
+ // Restored 2026-06-03: appendSystemPrompt and onAgentArchived references
231
+ // survived in this file's methods but the field declarations were dropped
232
+ // during the OSS hot-swap merge.
233
+ this.appendSystemPrompt = "";
234
+ this.idFactory = options?.idFactory ?? (() => randomUUID());
235
+ this.registry = options?.registry;
236
+ // Plain access, not `options?.`: the optional chain counts as a branch and
237
+ // tips this constructor over the oxlint complexity ceiling of 20.
238
+ this.cardMoveLog = options.cardMoveLog;
239
+ this.blockerLog = options.blockerLog;
240
+ this.authorshipLedger = options.authorshipLedger;
241
+ this.authorshipMarkup = options.authorshipMarkup;
242
+ this.durableTimelineStore = options?.durableTimelineStore;
243
+ if (options?.onAgentAttention) {
244
+ this.attentionListeners.add(options.onAgentAttention);
245
+ }
246
+ this.onWorkspaceStateMayHaveChanged = options?.onWorkspaceStateMayHaveChanged;
247
+ this.mcpBaseUrl = options?.mcpBaseUrl ?? null;
248
+ this.mcpAuthToken = options?.mcpAuthToken ?? null;
249
+ this.configurePaseoTools(options);
250
+ this.appendSystemPrompt = options.appendSystemPrompt ?? "";
251
+ this.logger = options.logger.child({
252
+ module: "agent",
253
+ component: "agent-manager",
254
+ });
255
+ this.rescueTimeouts = {
256
+ reloadSessionCloseMs: options.rescueTimeouts?.reloadSessionCloseMs ?? RELOAD_SESSION_CLOSE_TIMEOUT_MS,
257
+ interruptSessionMs: options.rescueTimeouts?.interruptSessionMs ?? INTERRUPT_SESSION_TIMEOUT_MS,
258
+ };
259
+ this.agentStreamCoalescer = new AgentStreamCoalescer({
260
+ windowMs: options.agentStreamCoalesceWindowMs ?? AGENT_STREAM_COALESCE_DEFAULT_WINDOW_MS,
261
+ timers: { setTimeout, clearTimeout },
262
+ onFlush: ({ agentId, item, provider, turnId }) => {
263
+ const event = this.recordAndDispatchTimelineItem(agentId, item, provider, turnId);
264
+ this.notifyForegroundTurnWaiters(agentId, event);
265
+ },
266
+ });
267
+ this.updateProviderRegistry({
268
+ providerDefinitions: options.providerDefinitions ?? {},
269
+ clients: options.clients ?? {},
270
+ });
271
+ }
272
+ configurePaseoTools(options) {
273
+ this.paseoToolsEnabled = options.paseoToolsEnabled ?? true;
274
+ this.paseoToolCatalogFactory = options.paseoToolCatalogFactory ?? null;
275
+ }
276
+ registerClient(provider, client) {
277
+ this.clients.set(provider, client);
278
+ }
279
+ updateProviderRegistry(input) {
280
+ for (const [provider, definition] of Object.entries(input.providerDefinitions)) {
281
+ if (definition) {
282
+ this.providerEnabled.set(provider, definition.enabled);
283
+ this.providerSwapMetadata.set(provider, {
284
+ wireFamily: definition.wireFamily,
285
+ compatibleProviders: definition.compatibleProviders ?? [],
286
+ });
287
+ }
288
+ }
289
+ for (const [provider, client] of Object.entries(input.clients)) {
290
+ if (client) {
291
+ this.clients.set(provider, client);
292
+ }
293
+ }
294
+ }
295
+ getRegisteredProviderIds() {
296
+ return Array.from(this.clients.keys());
297
+ }
298
+ /**
299
+ * @deprecated Use {@link addAgentAttentionListener} for multi-subscriber registration.
300
+ * Retained for back-compat: replaces all currently-registered listeners with `callback`.
301
+ */
302
+ setAgentAttentionCallback(callback) {
303
+ this.attentionListeners.clear();
304
+ this.attentionListeners.add(callback);
305
+ }
306
+ /**
307
+ * Register an additional attention listener. Returns an unsubscribe function.
308
+ * Multiple subscribers are supported (e.g. WebSocketServer + pushTrigger emitter).
309
+ */
310
+ addAgentAttentionListener(listener) {
311
+ this.attentionListeners.add(listener);
312
+ return () => {
313
+ this.attentionListeners.delete(listener);
314
+ };
315
+ }
316
+ setAgentArchivedCallback(callback) {
317
+ this.onAgentArchived = callback;
318
+ }
319
+ setMcpBaseUrl(url) {
320
+ this.mcpBaseUrl = url;
321
+ }
322
+ setPaseoToolsEnabled(enabled) {
323
+ this.paseoToolsEnabled = enabled;
324
+ }
325
+ setPaseoToolCatalogFactory(factory) {
326
+ this.paseoToolCatalogFactory = factory;
327
+ }
328
+ /**
329
+ * Capability token the daemon's own MCP clients must present to the Agent MCP
330
+ * endpoint when a daemon password is configured. Read by the per-client
331
+ * session to authenticate its own MCP connection. Stays in the daemon — never
332
+ * sent to remote clients.
333
+ */
334
+ getMcpAuthToken() {
335
+ return this.mcpAuthToken;
336
+ }
337
+ setAppendSystemPrompt(prompt) {
338
+ this.appendSystemPrompt = prompt ?? "";
339
+ }
340
+ getMetricsSnapshot() {
341
+ const byLifecycle = {};
342
+ let withActiveForegroundTurn = 0;
343
+ let totalItems = 0;
344
+ let maxItemsPerAgent = 0;
345
+ for (const agent of this.agents.values()) {
346
+ byLifecycle[agent.lifecycle] = (byLifecycle[agent.lifecycle] ?? 0) + 1;
347
+ if (agent.activeForegroundTurnId !== null) {
348
+ withActiveForegroundTurn++;
349
+ }
350
+ if (!this.timelineStore.has(agent.id)) {
351
+ continue;
352
+ }
353
+ const len = this.timelineStore.getItems(agent.id).length;
354
+ totalItems += len;
355
+ if (len > maxItemsPerAgent) {
356
+ maxItemsPerAgent = len;
357
+ }
358
+ }
359
+ return {
360
+ total: this.agents.size,
361
+ byLifecycle,
362
+ withActiveForegroundTurn,
363
+ timelineStats: {
364
+ totalItems,
365
+ maxItemsPerAgent,
366
+ },
367
+ };
368
+ }
369
+ touchUpdatedAt(agent) {
370
+ const nowMs = Date.now();
371
+ const previousMs = agent.updatedAt.getTime();
372
+ const nextMs = nowMs > previousMs ? nowMs : previousMs + 1;
373
+ const next = new Date(nextMs);
374
+ agent.updatedAt = next;
375
+ return next;
376
+ }
377
+ nextStoredUpdatedAt(record) {
378
+ const previousMs = Date.parse(record.updatedAt);
379
+ const nowMs = Date.now();
380
+ const nextMs = nowMs > previousMs ? nowMs : previousMs + 1;
381
+ return new Date(nextMs).toISOString();
382
+ }
383
+ /**
384
+ * Map a turn id the app sent onto one that exists in the agent's transcript.
385
+ *
386
+ * Duck-typed on purpose. Only the claude provider mints its own user-message ids ahead of
387
+ * the transcript (see ClaudeAgent#resolveTranscriptTurnId); every other provider, and every
388
+ * turn replayed off disk, already hands the app the real uuid. Anything that does not
389
+ * implement the hook -- including the pool-* wrappers -- passes straight through, so this
390
+ * can never make a working edit stop working.
391
+ */
392
+ resolveTranscriptTurnId(agentId, turnId) {
393
+ // Typed, not cast. This was a `session as { resolveTranscriptTurnId?: ... }` duck-type,
394
+ // and the cast is what made the wrapper's drop invisible: a method the wrapper forgot
395
+ // and a provider that does not implement one look identical through it. The method is
396
+ // declared optional on AgentSession now, so the compiler sees both sides.
397
+ const session = this.agents.get(agentId)?.session;
398
+ if (!session?.resolveTranscriptTurnId) {
399
+ return turnId;
400
+ }
401
+ try {
402
+ const resolved = session.resolveTranscriptTurnId(turnId);
403
+ return typeof resolved === "string" && resolved.length > 0 ? resolved : turnId;
404
+ }
405
+ catch {
406
+ return turnId;
407
+ }
408
+ }
409
+ /**
410
+ * The agent's rendered terminal screen, or null when it has no readable pane.
411
+ *
412
+ * Null covers three different facts the caller does not need to tell apart: no such agent,
413
+ * a provider with no terminal, and a terminal whose multiplexer did not answer. All three
414
+ * mean "no screen to show", and the client's affordance keys off exactly that.
415
+ */
416
+ async capturePane(agentId, options) {
417
+ const session = this.agents.get(agentId)?.session;
418
+ if (!session?.capturePane)
419
+ return null;
420
+ try {
421
+ return await session.capturePane(options);
422
+ }
423
+ catch {
424
+ return null;
425
+ }
426
+ }
427
+ /**
428
+ * Repoint an agent at a transcript forked from its own -- what "edit a message" produces.
429
+ *
430
+ * The agent keeps its id, workspace, labels and config; only the underlying session moves,
431
+ * so the conversation appears to rewind to the edited message and carry on. Editing used to
432
+ * spawn a whole SECOND agent instead, which left the user on the old conversation while the
433
+ * answer arrived somewhere they were never taken to.
434
+ *
435
+ * `rehydrateFromDisk` is the load-bearing half: it drops the committed timeline and mints a
436
+ * new epoch, so the app replaces its stream instead of appending to a history that no longer
437
+ * exists, and late events from the old session are dropped rather than interleaved.
438
+ * Repointing the provider alone would truncate the transcript while the UI kept showing
439
+ * every message that was just discarded.
440
+ *
441
+ * Returns false when the agent has no persistence handle to fork from, so the caller can
442
+ * decline rather than pretend the conversation moved.
443
+ */
444
+ async adoptForkedSession(agentId, sessionId) {
445
+ const existing = this.agents.get(agentId);
446
+ const handle = existing?.persistence;
447
+ if (!handle) {
448
+ return false;
449
+ }
450
+ try {
451
+ await this.reloadAgentSession(agentId, undefined, {
452
+ rehydrateFromDisk: true,
453
+ // `null` means "there is nothing to resume" -- editing the FIRST message truncates to
454
+ // a transcript with no conversation in it, and `claude --resume` on that fails with
455
+ // "No conversation found with session ID". Starting fresh is the right answer there
456
+ // anyway: the edited message becomes the first message again.
457
+ persistence: sessionId ? { ...handle, sessionId, nativeHandle: sessionId } : null,
458
+ });
459
+ await this.hydrateTimelineFromProvider(agentId);
460
+ return true;
461
+ }
462
+ catch (err) {
463
+ this.logger.warn({ err, agentId, sessionId }, "adoptForkedSession failed");
464
+ return false;
465
+ }
466
+ }
467
+ hasInFlightRun(agentId) {
468
+ const agent = this.agents.get(agentId);
469
+ if (!agent) {
470
+ return false;
471
+ }
472
+ return (agent.lifecycle === "running" ||
473
+ Boolean(agent.activeForegroundTurnId) ||
474
+ this.foregroundRuns.hasPendingRun(agentId));
475
+ }
476
+ subscribe(callback, options) {
477
+ const targetAgentId = options?.agentId == null ? null : validateAgentId(options.agentId, "subscribe");
478
+ const record = {
479
+ callback,
480
+ agentId: targetAgentId,
481
+ };
482
+ this.subscribers.add(record);
483
+ if (options?.replayState !== false) {
484
+ if (record.agentId) {
485
+ const agent = this.agents.get(record.agentId);
486
+ if (agent) {
487
+ callback({
488
+ type: "agent_state",
489
+ agent: { ...agent },
490
+ });
491
+ }
492
+ }
493
+ else {
494
+ // For global subscribers, skip internal agents during replay
495
+ for (const agent of this.agents.values()) {
496
+ if (agent.internal) {
497
+ continue;
498
+ }
499
+ callback({
500
+ type: "agent_state",
501
+ agent: { ...agent },
502
+ });
503
+ }
504
+ }
505
+ }
506
+ return () => {
507
+ this.subscribers.delete(record);
508
+ };
509
+ }
510
+ listAgents() {
511
+ return Array.from(this.agents.values())
512
+ .filter((agent) => !agent.internal)
513
+ .map((agent) => Object.assign({}, agent));
514
+ }
515
+ async listImportableSessions(options) {
516
+ const providerEntries = Array.from(this.clients.entries()).filter(([provider, client]) => client.capabilities.supportsSessionListing &&
517
+ !!client.listImportableSessions &&
518
+ this.isProviderImportable(provider, options?.providerFilter));
519
+ const sessionLists = await Promise.all(providerEntries.map(async ([provider, client]) => {
520
+ try {
521
+ return (await client.listImportableSessions({
522
+ limit: options?.limit,
523
+ cwd: options?.cwd,
524
+ })).map((session) => Object.assign(session, { provider }));
525
+ }
526
+ catch (error) {
527
+ this.logger.warn({ err: error, provider }, "Failed to list importable sessions for provider");
528
+ return [];
529
+ }
530
+ }));
531
+ const sessions = sessionLists.flat();
532
+ const limit = options?.limit ?? 20;
533
+ return sessions
534
+ .sort((a, b) => b.lastActivityAt.getTime() - a.lastActivityAt.getTime())
535
+ .slice(0, limit);
536
+ }
537
+ isProviderImportable(provider, providerFilter) {
538
+ if (this.providerEnabled.get(provider) === false) {
539
+ return false;
540
+ }
541
+ if (providerFilter && !providerFilter.has(provider)) {
542
+ return false;
543
+ }
544
+ return true;
545
+ }
546
+ async listProviderAvailability() {
547
+ return Promise.all(Array.from(this.clients.keys()).map((provider) => this.getProviderAvailability(provider)));
548
+ }
549
+ async getProviderAvailability(provider) {
550
+ const client = this.clients.get(provider);
551
+ if (!client) {
552
+ return {
553
+ provider,
554
+ available: false,
555
+ error: `No client registered for provider '${provider}'`,
556
+ };
557
+ }
558
+ try {
559
+ const available = await client.isAvailable();
560
+ return {
561
+ provider,
562
+ available,
563
+ error: null,
564
+ };
565
+ }
566
+ catch (error) {
567
+ const message = error instanceof Error ? error.message : String(error);
568
+ this.logger.warn({ err: error, provider }, "Failed to check provider availability");
569
+ return {
570
+ provider,
571
+ available: false,
572
+ error: message,
573
+ };
574
+ }
575
+ }
576
+ async listDraftCommands(config) {
577
+ const normalizedConfig = await this.normalizeConfig(config, {
578
+ resolveDefaultModel: false,
579
+ });
580
+ const client = this.requireClient(normalizedConfig.provider);
581
+ if (!normalizedConfig.model) {
582
+ return [];
583
+ }
584
+ const available = await client.isAvailable();
585
+ if (!available) {
586
+ throw new Error(`Provider '${normalizedConfig.provider}' is not available. Please ensure the CLI is installed.`);
587
+ }
588
+ if (client.listCommands) {
589
+ return await client.listCommands(normalizedConfig);
590
+ }
591
+ const session = await client.createSession(normalizedConfig);
592
+ try {
593
+ if (!session.listCommands) {
594
+ throw new Error(`Provider '${normalizedConfig.provider}' does not support listing commands`);
595
+ }
596
+ return await session.listCommands();
597
+ }
598
+ finally {
599
+ try {
600
+ await session.close();
601
+ }
602
+ catch (error) {
603
+ this.logger.warn({ err: error, provider: normalizedConfig.provider }, "Failed to close draft command listing session");
604
+ }
605
+ }
606
+ }
607
+ async listDraftFeatures(config) {
608
+ const normalizedConfig = await this.normalizeConfig(config, {
609
+ resolveDefaultModel: false,
610
+ });
611
+ const client = this.requireClient(normalizedConfig.provider);
612
+ if (!normalizedConfig.model) {
613
+ return [];
614
+ }
615
+ const available = await client.isAvailable();
616
+ if (!available) {
617
+ throw new Error(`Provider '${normalizedConfig.provider}' is not available. Please ensure the CLI is installed.`);
618
+ }
619
+ if (client.listFeatures) {
620
+ return await client.listFeatures(normalizedConfig);
621
+ }
622
+ const session = await client.createSession(normalizedConfig);
623
+ try {
624
+ return session.features ?? [];
625
+ }
626
+ finally {
627
+ try {
628
+ await session.close();
629
+ }
630
+ catch (error) {
631
+ this.logger.warn({ err: error, provider: normalizedConfig.provider }, "Failed to close draft feature listing session");
632
+ }
633
+ }
634
+ }
635
+ getAgent(id) {
636
+ const agent = this.agents.get(id);
637
+ return agent ? { ...agent } : null;
638
+ }
639
+ getTimeline(id) {
640
+ this.requireAgent(id);
641
+ return this.timelineStore.getItems(id);
642
+ }
643
+ /**
644
+ * Timeline epoch for an agent. Row `seq` restarts at 1 whenever the store is
645
+ * re-initialized without seeded rows, so a seq is only comparable WITHIN an
646
+ * epoch. Anything caching a high-water seq must cache this alongside it.
647
+ */
648
+ getTimelineEpoch(id) {
649
+ return this.timelineStore.getEpoch(id);
650
+ }
651
+ async getTimelineRows(id) {
652
+ this.requireAgent(id);
653
+ if (this.durableTimelineStore) {
654
+ return await this.durableTimelineStore.getCommittedRows(id);
655
+ }
656
+ return this.timelineStore.getRows(id);
657
+ }
658
+ fetchTimeline(id, options) {
659
+ this.requireAgent(id);
660
+ return this.timelineStore.fetch(id, options);
661
+ }
662
+ async createAgent(config, agentId, options) {
663
+ const resolvedAgentId = validateAgentId(agentId ?? this.idFactory(), "createAgent");
664
+ const { storedConfig, launchConfig } = await this.prepareSessionConfig(config, resolvedAgentId);
665
+ this.requireEnabledProvider(storedConfig.provider);
666
+ const client = await this.requireAvailableClient({
667
+ provider: storedConfig.provider,
668
+ });
669
+ requireToolAllowlistSupport(client, storedConfig);
670
+ const launchContext = await this.buildLaunchContext(resolvedAgentId, client, options?.env);
671
+ const providerLaunchConfig = this.resolveProviderLaunchConfig(launchConfig, launchContext);
672
+ const createOptions = this.buildCreateSessionOptions(options);
673
+ const session = await client.createSession(providerLaunchConfig, launchContext, createOptions);
674
+ return this.registerSession(session, storedConfig, resolvedAgentId, {
675
+ labels: options?.labels,
676
+ digest: options?.digest,
677
+ initialTitle: options?.initialTitle,
678
+ workspaceId: options?.workspaceId,
679
+ });
680
+ }
681
+ buildCreateSessionOptions(options) {
682
+ if (options?.persistSession === undefined && !options?.resumeSessionId) {
683
+ return undefined;
684
+ }
685
+ return {
686
+ ...(options.persistSession !== undefined ? { persistSession: options.persistSession } : {}),
687
+ ...(options.resumeSessionId ? { resumeSessionId: options.resumeSessionId } : {}),
688
+ };
689
+ }
690
+ // Reconstruct an agent from provider persistence. Callers should explicitly
691
+ // hydrate timeline history after resume.
692
+ async resumeAgentFromPersistence(handle, overrides, agentId, options) {
693
+ const resolvedAgentId = validateAgentId(agentId ?? this.idFactory(), "resumeAgentFromPersistence");
694
+ const metadata = (handle.metadata ?? {});
695
+ const mergedConfig = {
696
+ ...metadata,
697
+ ...overrides,
698
+ provider: handle.provider,
699
+ };
700
+ const { storedConfig, launchConfig } = await this.prepareSessionConfig(mergedConfig, resolvedAgentId);
701
+ const client = this.requireClient(handle.provider);
702
+ const available = await client.isAvailable();
703
+ if (!available) {
704
+ throw new Error(`Provider '${handle.provider}' is not available. Please ensure the CLI is installed.`);
705
+ }
706
+ const launchContext = await this.buildLaunchContext(resolvedAgentId, client);
707
+ const providerLaunchConfig = this.resolveProviderLaunchConfig(launchConfig, launchContext);
708
+ const session = await client.resumeSession(handle, providerLaunchConfig, launchContext);
709
+ return this.registerSession(session, storedConfig, resolvedAgentId, options);
710
+ }
711
+ async importProviderSession(input) {
712
+ const resolvedAgentId = validateAgentId(this.idFactory(), "importProviderSession");
713
+ this.requireEnabledProvider(input.provider);
714
+ const client = await this.requireAvailableClient({
715
+ provider: input.provider,
716
+ });
717
+ if (!client.importSession) {
718
+ throw new Error(`Provider '${input.provider}' does not support importing sessions`);
719
+ }
720
+ const { storedConfig, launchConfig } = await this.prepareSessionConfig({
721
+ ...input.config,
722
+ provider: input.provider,
723
+ cwd: input.cwd,
724
+ }, resolvedAgentId);
725
+ const launchContext = await this.buildLaunchContext(resolvedAgentId, client);
726
+ const providerLaunchConfig = this.resolveProviderLaunchConfig(launchConfig, launchContext);
727
+ const imported = await client.importSession({
728
+ providerHandleId: input.providerHandleId,
729
+ cwd: input.cwd,
730
+ }, { config: providerLaunchConfig, storedConfig, launchContext });
731
+ const importedConfig = await this.normalizeConfig(stripInternalPaseoMcpServer(imported.config));
732
+ const timelineRows = buildImportedTimelineRows(imported.timeline);
733
+ const initialTitle = resolveImportedAgentTitle(importedConfig, timelineRows);
734
+ return this.registerSession(imported.session, importedConfig, resolvedAgentId, {
735
+ labels: input.labels,
736
+ workspaceId: input.workspaceId,
737
+ timelineRows,
738
+ timelineNextSeq: timelineRows.length + 1,
739
+ persistence: imported.persistence,
740
+ historyPrimed: true,
741
+ initialTitle,
742
+ publishWhenReady: true,
743
+ });
744
+ }
745
+ /**
746
+ * Hot-swap a running agent's provider to a compatible alternative
747
+ * (e.g. Claude → Claude (Pool)). Compatibility is determined by the
748
+ * provider registry's effective `compatibleProviders` set — the swap is
749
+ * rejected if the target is not declared compatible.
750
+ *
751
+ * Preserves the session timeline, persistence handle, labels, and lifecycle
752
+ * metadata. Any in-flight turn is canceled first (best effort). On success,
753
+ * the session is recreated against the new provider's client using
754
+ * `resumeSession` with the existing persistence handle rewritten to the new
755
+ * provider, plus an optional model/mode override.
756
+ *
757
+ * Throws if the target provider has no registered client, is disabled, or
758
+ * is not in the current provider's compatible list.
759
+ */
760
+ async swapAgentProvider(agentId, newProviderId, overrides) {
761
+ const existing = this.requireSessionAgent(agentId);
762
+ const currentProvider = existing.provider;
763
+ if (currentProvider === newProviderId) {
764
+ throw new Error(`Agent '${agentId}' is already on provider '${newProviderId}' — nothing to swap.`);
765
+ }
766
+ // Validate compatibility via the daemon-wide swap metadata (sourced from
767
+ // provider-registry, which already resolved derived providers + ran
768
+ // symmetry validation).
769
+ const currentMeta = this.providerSwapMetadata.get(currentProvider);
770
+ const newMeta = this.providerSwapMetadata.get(newProviderId);
771
+ if (!currentMeta) {
772
+ throw new Error(`Cannot swap: current provider '${currentProvider}' is not registered.`);
773
+ }
774
+ if (!newMeta) {
775
+ throw new Error(`Cannot swap: target provider '${newProviderId}' is not registered.`);
776
+ }
777
+ if (currentMeta.wireFamily &&
778
+ newMeta.wireFamily &&
779
+ currentMeta.wireFamily !== newMeta.wireFamily) {
780
+ throw new Error(`Cannot swap '${currentProvider}' → '${newProviderId}': wireFamily mismatch ` +
781
+ `(${currentMeta.wireFamily} vs ${newMeta.wireFamily}).`);
782
+ }
783
+ const compatible = currentMeta.compatibleProviders;
784
+ if (!compatible.includes(newProviderId)) {
785
+ throw new Error(`Cannot swap '${currentProvider}' → '${newProviderId}': not in compatibleProviders list. ` +
786
+ `Allowed: [${compatible.join(", ") || "none"}].`);
787
+ }
788
+ this.requireEnabledProvider(newProviderId);
789
+ const newClient = this.requireClient(newProviderId);
790
+ const available = await newClient.isAvailable();
791
+ if (!available) {
792
+ throw new Error(`Cannot swap to '${newProviderId}': provider is not available. Please ensure the CLI is installed.`);
793
+ }
794
+ // Cancel any in-flight turn — best effort, do not fail the swap if cancel times out.
795
+ if (this.hasInFlightRun(agentId)) {
796
+ try {
797
+ await this.cancelAgentRun(agentId);
798
+ }
799
+ catch (error) {
800
+ this.logger.warn({ err: error, agentId, currentProvider, newProviderId }, "swapAgentProvider: cancelAgentRun failed, proceeding anyway");
801
+ }
802
+ }
803
+ const refreshedExisting = this.requireSessionAgent(agentId);
804
+ const handle = refreshedExisting.persistence;
805
+ if (!handle) {
806
+ throw new Error(`Cannot swap provider for agent '${agentId}': no persistence handle. ` +
807
+ `Only agents with session persistence can be swapped.`);
808
+ }
809
+ const newPersistenceHandle = {
810
+ ...handle,
811
+ provider: newProviderId,
812
+ };
813
+ // Build new config: copy from existing, override provider + (optional)
814
+ // model/modeId. Inherit everything else (cwd, env, mcp servers, etc.).
815
+ const baseConfig = {
816
+ ...refreshedExisting.config,
817
+ provider: newProviderId,
818
+ ...(overrides?.model !== undefined ? { model: overrides.model ?? undefined } : {}),
819
+ ...(overrides?.modeId !== undefined ? { modeId: overrides.modeId } : {}),
820
+ };
821
+ const { storedConfig, launchConfig } = await this.prepareSessionConfig(baseConfig, agentId);
822
+ const launchContext = await this.buildLaunchContext(agentId, newClient);
823
+ const providerLaunchConfig = this.resolveProviderLaunchConfig(launchConfig, launchContext);
824
+ // Preserve fields we want to carry across the swap.
825
+ const preservedHistoryPrimed = refreshedExisting.historyPrimed;
826
+ const preservedLastUsage = refreshedExisting.lastUsage;
827
+ const preservedLastError = refreshedExisting.lastError;
828
+ const preservedAttention = refreshedExisting.attention;
829
+ const oldSession = refreshedExisting.session;
830
+ const session = await newClient.resumeSession(newPersistenceHandle, providerLaunchConfig, launchContext);
831
+ this.agentStreamCoalescer.flushAndDiscard(agentId);
832
+ this.agents.delete(agentId);
833
+ if (refreshedExisting.unsubscribeSession) {
834
+ refreshedExisting.unsubscribeSession();
835
+ refreshedExisting.unsubscribeSession = null;
836
+ }
837
+ this.foregroundRuns.clearAgent(agentId, refreshedExisting);
838
+ await this.closeReloadedSession(oldSession, agentId);
839
+ const managed = await this.registerSession(session, storedConfig, agentId, {
840
+ labels: refreshedExisting.labels,
841
+ digest: refreshedExisting.digest,
842
+ createdAt: refreshedExisting.createdAt,
843
+ updatedAt: refreshedExisting.updatedAt,
844
+ lastUserMessageAt: refreshedExisting.lastUserMessageAt,
845
+ historyPrimed: preservedHistoryPrimed,
846
+ lastUsage: preservedLastUsage,
847
+ lastError: preservedLastError,
848
+ attention: preservedAttention,
849
+ });
850
+ this.logger.info({ agentId, oldProvider: currentProvider, newProvider: newProviderId }, "swapAgentProvider: completed");
851
+ return managed;
852
+ }
853
+ // Hot-reload an active agent session with config overrides while preserving
854
+ // in-memory timeline state.
855
+ async reloadAgentSession(agentId, overrides, options) {
856
+ let existing = this.requireSessionAgent(agentId);
857
+ if (this.hasInFlightRun(agentId)) {
858
+ await this.cancelAgentRun(agentId);
859
+ existing = this.requireSessionAgent(agentId);
860
+ }
861
+ const rehydrateFromDisk = options?.rehydrateFromDisk ?? false;
862
+ const preservedHistoryPrimed = existing.historyPrimed;
863
+ const preservedLastUsage = existing.lastUsage;
864
+ const preservedLastError = existing.lastError;
865
+ const preservedAttention = existing.attention;
866
+ // `options.persistence` retargets the SAME agent at a different session -- what editing a
867
+ // message needs, since the fork lives at a new sessionId. Defaults to the agent's own
868
+ // handle, which is every other caller (voice, refresh, unarchive).
869
+ // `in` rather than `??`: an explicit null means "start a fresh session", which is a
870
+ // different instruction from "not specified".
871
+ const handle = options && "persistence" in options ? options.persistence : existing.persistence;
872
+ const provider = handle?.provider ?? existing.provider;
873
+ const client = this.requireClient(provider);
874
+ const refreshConfig = {
875
+ ...existing.config,
876
+ ...overrides,
877
+ provider,
878
+ };
879
+ const { storedConfig, launchConfig } = await this.prepareSessionConfig(refreshConfig, agentId);
880
+ const launchContext = await this.buildLaunchContext(agentId, client);
881
+ const providerLaunchConfig = this.resolveProviderLaunchConfig(launchConfig, launchContext);
882
+ const session = handle
883
+ ? await client.resumeSession(handle, providerLaunchConfig, launchContext)
884
+ : await client.createSession(providerLaunchConfig, launchContext);
885
+ this.agentStreamCoalescer.flushAndDiscard(agentId);
886
+ // Remove the existing agent entry before swapping sessions
887
+ this.agents.delete(agentId);
888
+ if (existing.unsubscribeSession) {
889
+ existing.unsubscribeSession();
890
+ existing.unsubscribeSession = null;
891
+ }
892
+ this.foregroundRuns.clearAgent(agentId, existing);
893
+ await this.closeReloadedSession(existing.session, agentId);
894
+ if (rehydrateFromDisk) {
895
+ // Wipe both durable and in-memory timeline so registerSession mints a
896
+ // new epoch and hydrateTimelineFromProvider re-streams the freshly read
897
+ // provider history into an empty timeline.
898
+ await this.deleteCommittedTimeline(agentId);
899
+ this.timelineStore.delete(agentId);
900
+ this.authorshipMarkup?.forget(agentId);
901
+ }
902
+ // Preserve existing labels and timeline during reload.
903
+ return this.registerSession(session, storedConfig, agentId, {
904
+ labels: existing.labels,
905
+ workspaceId: existing.workspaceId,
906
+ digest: existing.digest,
907
+ createdAt: existing.createdAt,
908
+ updatedAt: existing.updatedAt,
909
+ lastUserMessageAt: existing.lastUserMessageAt,
910
+ historyPrimed: rehydrateFromDisk ? false : preservedHistoryPrimed,
911
+ lastUsage: preservedLastUsage,
912
+ lastError: preservedLastError,
913
+ attention: preservedAttention,
914
+ });
915
+ }
916
+ async closeReloadedSession(session, agentId) {
917
+ try {
918
+ const result = await this.waitWithTimeout({
919
+ operation: session.close(),
920
+ timeoutMs: this.rescueTimeouts.reloadSessionCloseMs,
921
+ onLateError: (error) => {
922
+ this.logger.warn({ err: error, agentId }, "Previous session close failed after refresh timeout");
923
+ },
924
+ });
925
+ if (result === "timed_out") {
926
+ this.logger.warn({ agentId, timeoutMs: this.rescueTimeouts.reloadSessionCloseMs }, "Timed out closing previous session during refresh");
927
+ }
928
+ }
929
+ catch (error) {
930
+ this.logger.warn({ err: error, agentId }, "Failed to close previous session during refresh");
931
+ }
932
+ }
933
+ async waitWithTimeout(options) {
934
+ let didTimeOut = false;
935
+ let timer = null;
936
+ const operation = options.operation
937
+ .then(() => "completed")
938
+ .catch((error) => {
939
+ if (didTimeOut) {
940
+ options.onLateError?.(error);
941
+ return "timed_out";
942
+ }
943
+ throw error;
944
+ });
945
+ try {
946
+ return await Promise.race([
947
+ operation,
948
+ new Promise((resolvePromise) => {
949
+ timer = setTimeout(() => {
950
+ didTimeOut = true;
951
+ resolvePromise("timed_out");
952
+ }, options.timeoutMs);
953
+ }),
954
+ ]);
955
+ }
956
+ finally {
957
+ if (timer) {
958
+ clearTimeout(timer);
959
+ }
960
+ }
961
+ }
962
+ async closeAgent(agentId) {
963
+ const agent = this.requireAgent(agentId);
964
+ this.logger.trace({
965
+ agentId,
966
+ provider: agent.provider,
967
+ sessionId: agent.persistence?.sessionId ?? undefined,
968
+ turnId: agent.activeForegroundTurnId ?? undefined,
969
+ lifecycle: agent.lifecycle,
970
+ activeForegroundTurnId: agent.activeForegroundTurnId,
971
+ pendingPermissions: agent.pendingPermissions.size,
972
+ }, "agent.manager.close.start");
973
+ const closedAgent = this.prepareAgentForClosure(agent, "agent closed");
974
+ await agent.session.close();
975
+ this.timelineStore.delete(agentId);
976
+ this.authorshipMarkup?.forget(agentId);
977
+ await this.persistSnapshot(closedAgent);
978
+ this.emitClosedAgent(closedAgent, { persist: false });
979
+ this.logger.trace({
980
+ agentId,
981
+ provider: closedAgent.provider,
982
+ sessionId: closedAgent.persistence?.sessionId ?? undefined,
983
+ }, "agent.manager.close.complete");
984
+ }
985
+ async archiveAgent(agentId) {
986
+ const agent = this.requireAgent(agentId);
987
+ if (!this.registry) {
988
+ throw new Error("Agent storage is not configured");
989
+ }
990
+ await this.registry.applySnapshot(agent, {
991
+ internal: agent.internal,
992
+ });
993
+ const stored = await this.registry.get(agentId);
994
+ if (!stored) {
995
+ throw new Error(`Agent ${agentId} not found in storage after snapshot`);
996
+ }
997
+ const { archivedAt } = await this.markRecordArchived(stored);
998
+ agent.updatedAt = new Date(archivedAt);
999
+ await this.closeAgent(agentId);
1000
+ await this.cascadeArchiveChildren(agentId);
1001
+ return { archivedAt };
1002
+ }
1003
+ // Children created via the MCP `create_agent` tool carry the parent-agent-id
1004
+ // label pointing back at the caller. Archiving the parent cascades to those
1005
+ // children so subagent fleets don't outlive their orchestrator. Detached
1006
+ // handoff agents omit this label, so they stand outside the cascade.
1007
+ async cascadeArchiveChildren(parentAgentId) {
1008
+ const registry = this.registry;
1009
+ if (!registry) {
1010
+ return;
1011
+ }
1012
+ const records = await registry.list();
1013
+ for (const record of records) {
1014
+ if (record.archivedAt) {
1015
+ continue;
1016
+ }
1017
+ if (record.labels?.[PARENT_AGENT_ID_LABEL] !== parentAgentId) {
1018
+ continue;
1019
+ }
1020
+ if (this.agents.has(record.id)) {
1021
+ await this.archiveAgent(record.id);
1022
+ }
1023
+ else {
1024
+ await this.markRecordArchived(record);
1025
+ await this.cascadeArchiveChildren(record.id);
1026
+ }
1027
+ }
1028
+ }
1029
+ async markRecordArchived(record) {
1030
+ const registry = this.requireRegistry();
1031
+ const archivedAt = new Date().toISOString();
1032
+ const archivedRecord = buildArchivedAgentRecord(record, {
1033
+ archivedAt,
1034
+ updatedAt: archivedAt,
1035
+ });
1036
+ await registry.upsert(archivedRecord);
1037
+ await this.archiveNativeSessionBestEffort(record.provider, record.persistence);
1038
+ if (this.agents.has(record.id)) {
1039
+ this.notifyAgentState(record.id);
1040
+ }
1041
+ else if (!archivedRecord.internal) {
1042
+ this.dispatchArchivedStoredAgent(archivedRecord);
1043
+ }
1044
+ await this.fireAgentArchived(record.id);
1045
+ return archivedRecord;
1046
+ }
1047
+ async fireAgentArchived(agentId) {
1048
+ const callback = this.onAgentArchived;
1049
+ if (!callback) {
1050
+ return;
1051
+ }
1052
+ try {
1053
+ await callback(agentId);
1054
+ }
1055
+ catch (error) {
1056
+ this.logger.warn({ err: error, agentId }, "onAgentArchived callback failed");
1057
+ }
1058
+ }
1059
+ dispatchArchivedStoredAgent(record) {
1060
+ const updatedAt = new Date(record.updatedAt);
1061
+ this.dispatch({
1062
+ type: "agent_state",
1063
+ agent: {
1064
+ id: record.id,
1065
+ provider: record.provider,
1066
+ cwd: record.cwd,
1067
+ workspaceId: record.workspaceId,
1068
+ session: null,
1069
+ capabilities: STORED_AGENT_CAPABILITIES,
1070
+ config: buildStoredAgentConfig(record),
1071
+ runtimeInfo: undefined,
1072
+ lifecycle: "closed",
1073
+ createdAt: new Date(record.createdAt),
1074
+ updatedAt,
1075
+ availableModes: [],
1076
+ features: record.features,
1077
+ currentModeId: record.lastModeId ?? null,
1078
+ pendingPermissions: new Map(),
1079
+ bufferedPermissionResolutions: new Map(),
1080
+ inFlightPermissionResponses: new Set(),
1081
+ pendingReplacement: false,
1082
+ activeForegroundTurnId: null,
1083
+ foregroundTurnWaiters: new Set(),
1084
+ finalizedForegroundTurnIds: new Set(),
1085
+ unsubscribeSession: null,
1086
+ persistence: record.persistence ?? null,
1087
+ historyPrimed: true,
1088
+ lastUserMessageAt: record.lastUserMessageAt ? new Date(record.lastUserMessageAt) : null,
1089
+ lastUsage: undefined,
1090
+ lastError: record.lastError ?? undefined,
1091
+ attention: { requiresAttention: false },
1092
+ internal: record.internal,
1093
+ labels: record.labels,
1094
+ digest: record.digest,
1095
+ },
1096
+ });
1097
+ }
1098
+ async setAgentMode(agentId, modeId) {
1099
+ const agent = this.requireSessionAgent(agentId);
1100
+ const notice = (await agent.session.setMode(modeId)) ?? null;
1101
+ const currentMode = (await agent.session.getCurrentMode()) ?? modeId;
1102
+ agent.config.modeId = currentMode ?? undefined;
1103
+ agent.currentModeId = currentMode;
1104
+ // Update runtimeInfo to reflect the new mode
1105
+ if (agent.runtimeInfo) {
1106
+ agent.runtimeInfo = { ...agent.runtimeInfo, modeId: currentMode };
1107
+ }
1108
+ this.touchUpdatedAt(agent);
1109
+ this.emitState(agent);
1110
+ return notice;
1111
+ }
1112
+ async setAgentModel(agentId, modelId) {
1113
+ const agent = this.requireSessionAgent(agentId);
1114
+ const normalizedModelId = typeof modelId === "string" && modelId.trim().length > 0 ? modelId : null;
1115
+ if (agent.session.setModel) {
1116
+ await agent.session.setModel(normalizedModelId);
1117
+ }
1118
+ agent.config.model = normalizedModelId ?? undefined;
1119
+ if (agent.runtimeInfo) {
1120
+ agent.runtimeInfo = { ...agent.runtimeInfo, model: normalizedModelId };
1121
+ }
1122
+ this.touchUpdatedAt(agent);
1123
+ this.emitState(agent);
1124
+ }
1125
+ async setAgentThinkingOption(agentId, thinkingOptionId) {
1126
+ const agent = this.requireSessionAgent(agentId);
1127
+ const normalizedThinkingOptionId = typeof thinkingOptionId === "string" && thinkingOptionId.trim().length > 0
1128
+ ? thinkingOptionId
1129
+ : null;
1130
+ let notice = null;
1131
+ if (agent.session.setThinkingOption) {
1132
+ notice = (await agent.session.setThinkingOption(normalizedThinkingOptionId)) ?? null;
1133
+ }
1134
+ agent.config.thinkingOptionId = normalizedThinkingOptionId ?? undefined;
1135
+ if (agent.runtimeInfo) {
1136
+ agent.runtimeInfo = {
1137
+ ...agent.runtimeInfo,
1138
+ thinkingOptionId: normalizedThinkingOptionId,
1139
+ };
1140
+ }
1141
+ this.touchUpdatedAt(agent);
1142
+ this.emitState(agent);
1143
+ return notice;
1144
+ }
1145
+ /**
1146
+ * Write the agent's durable descriptions (`goal`, `jobToBeDone`) after
1147
+ * creation.
1148
+ *
1149
+ * `requireAgent` and not `requireSessionAgent`: these are pure config that no
1150
+ * provider session ever reads, so demanding a live session would refuse the
1151
+ * edit on exactly the agent most likely to need it, one that is idle between
1152
+ * routine firings.
1153
+ *
1154
+ * Whitespace-only clears the field rather than storing blanks, matching the
1155
+ * create path and `deriveHasSystemPrompt`. Passing `undefined` for a field
1156
+ * leaves it untouched, so a caller can set one without erasing the other.
1157
+ */
1158
+ async setAgentDurableDescriptions(agentId, descriptions) {
1159
+ const agent = this.requireAgent(agentId);
1160
+ if (descriptions.goal !== undefined) {
1161
+ agent.config.goal = descriptions.goal.trim() || undefined;
1162
+ }
1163
+ if (descriptions.jobToBeDone !== undefined) {
1164
+ agent.config.jobToBeDone = descriptions.jobToBeDone.trim() || undefined;
1165
+ }
1166
+ this.touchUpdatedAt(agent);
1167
+ this.emitState(agent);
1168
+ }
1169
+ /**
1170
+ * Write the agent's per-run tool allowlist after creation.
1171
+ *
1172
+ * This is the repair path. Before it existed, an agent created with a bad
1173
+ * allowlist could not run a single tool AND could not be edited back out of
1174
+ * that state through the API, so the only fix was to archive it and create a
1175
+ * new one. `null` and `[]` both clear the list, because paseo spells "every
1176
+ * tool" as no allowlist; a non-empty list restricts.
1177
+ *
1178
+ * `requireAgent` and not `requireSessionAgent`, matching
1179
+ * `setAgentDurableDescriptions`: the allowlist is config the provider reads
1180
+ * when it builds a run, so demanding a live session would refuse the edit on
1181
+ * exactly the agent most likely to need it, one that is idle and locked out.
1182
+ * The new list takes effect on the next run, not mid-run.
1183
+ *
1184
+ * A non-empty list on a provider that cannot enforce one is rejected here for
1185
+ * the same reason `requireToolAllowlistSupport` rejects it at create: storing
1186
+ * it would hand the caller a fence that does not exist. Clearing is always
1187
+ * allowed, whatever the provider.
1188
+ */
1189
+ async setAgentAllowedTools(agentId, allowedTools) {
1190
+ const agent = this.requireAgent(agentId);
1191
+ const rules = normalizeAllowedTools(allowedTools ?? []);
1192
+ if (rules.length > 0) {
1193
+ const client = this.clients.get(agent.config.provider);
1194
+ if (client) {
1195
+ requireToolAllowlistSupport(client, { ...agent.config, allowedTools: rules });
1196
+ }
1197
+ }
1198
+ agent.config.allowedTools = rules.length > 0 ? rules : undefined;
1199
+ this.touchUpdatedAt(agent);
1200
+ this.emitState(agent);
1201
+ }
1202
+ async setAgentFeature(agentId, featureId, value) {
1203
+ const agent = this.requireAgent(agentId);
1204
+ if (!agent.session.setFeature) {
1205
+ throw new Error("Agent session does not support setting features");
1206
+ }
1207
+ await agent.session.setFeature(featureId, value);
1208
+ agent.config.featureValues = {
1209
+ ...agent.config.featureValues,
1210
+ [featureId]: value,
1211
+ };
1212
+ this.touchUpdatedAt(agent);
1213
+ this.emitState(agent);
1214
+ }
1215
+ async setTitle(agentId, title) {
1216
+ const agent = this.requireAgent(agentId);
1217
+ const normalizedTitle = title.trim();
1218
+ if (!normalizedTitle) {
1219
+ return;
1220
+ }
1221
+ if (this.agentsAwaitingInitialSnapshotPersist.has(agent.id) &&
1222
+ this.registry &&
1223
+ (await this.registry.get(agent.id)) === null) {
1224
+ return;
1225
+ }
1226
+ this.touchUpdatedAt(agent);
1227
+ await this.persistSnapshot(agent, { title: normalizedTitle });
1228
+ this.emitState(agent, { persist: false });
1229
+ }
1230
+ async setLabels(agentId, labels) {
1231
+ const agent = this.requireAgent(agentId);
1232
+ await this.writeLabels(agent.id, labels);
1233
+ }
1234
+ /**
1235
+ * The single chokepoint for every label write (JARVIS-V1-SPEC §3.2). Both the
1236
+ * live-agent branch and the detached-record branch flow through here, which is
1237
+ * why the card-move hook lives at this level and not on the public `setLabels`
1238
+ * (that one misses the detached path entirely).
1239
+ */
1240
+ async writeLabels(agentId, patch) {
1241
+ // Only pay for a before-read when the patch could actually move the card.
1242
+ const touchesColumn = Object.prototype.hasOwnProperty.call(patch, KANBAN_LABEL_KEY);
1243
+ const liveAgent = this.agents.get(agentId);
1244
+ if (liveAgent) {
1245
+ const beforeColumn = touchesColumn ? (liveAgent.labels[KANBAN_LABEL_KEY] ?? null) : null;
1246
+ liveAgent.labels = applyLabelPatch(liveAgent.labels, patch);
1247
+ this.touchUpdatedAt(liveAgent);
1248
+ await this.persistSnapshot(liveAgent);
1249
+ this.emitState(liveAgent, { persist: false });
1250
+ if (touchesColumn) {
1251
+ this.cardMoveLog?.record(agentId, beforeColumn, liveAgent.labels[KANBAN_LABEL_KEY] ?? null);
1252
+ }
1253
+ const record = this.registry ? await this.registry.get(agentId) : null;
1254
+ return { record, live: true };
1255
+ }
1256
+ const priorColumn = touchesColumn && this.registry
1257
+ ? ((await this.registry.get(agentId))?.labels?.[KANBAN_LABEL_KEY] ?? null)
1258
+ : null;
1259
+ const nextRecord = await this.writeStoredMetadata(agentId, {
1260
+ labels: patch,
1261
+ });
1262
+ if (touchesColumn) {
1263
+ this.cardMoveLog?.record(agentId, priorColumn, nextRecord.labels?.[KANBAN_LABEL_KEY] ?? null);
1264
+ }
1265
+ return { record: nextRecord, live: false };
1266
+ }
1267
+ async writeStoredMetadata(agentId, patch) {
1268
+ const registry = this.requireRegistry();
1269
+ const record = await registry.get(agentId);
1270
+ if (!record) {
1271
+ throw new Error(`Agent not found: ${agentId}`);
1272
+ }
1273
+ const nextRecord = {
1274
+ ...record,
1275
+ ...(patch.title ? { title: patch.title } : {}),
1276
+ ...(patch.labels ? { labels: applyLabelPatch(record.labels, patch.labels) } : {}),
1277
+ ...(patch.digest ? { digest: patch.digest } : {}),
1278
+ updatedAt: this.nextStoredUpdatedAt(record),
1279
+ };
1280
+ await registry.upsert(nextRecord);
1281
+ return nextRecord;
1282
+ }
1283
+ async detachAgent(agentId) {
1284
+ const registry = this.requireRegistry();
1285
+ const liveAgent = this.agents.get(agentId);
1286
+ if (liveAgent) {
1287
+ const previousParentAgentId = getParentAgentIdFromLabels(liveAgent.labels);
1288
+ if (!previousParentAgentId) {
1289
+ await this.persistSnapshot(liveAgent);
1290
+ const record = await registry.get(agentId);
1291
+ if (!record) {
1292
+ throw new Error(`Agent not found in storage after detach: ${agentId}`);
1293
+ }
1294
+ return { record, live: true, previousParentAgentId: null };
1295
+ }
1296
+ const { record } = await this.writeLabels(agentId, {
1297
+ [PARENT_AGENT_ID_LABEL]: null,
1298
+ });
1299
+ if (!record) {
1300
+ throw new Error(`Agent not found in storage after detach: ${agentId}`);
1301
+ }
1302
+ return { record, live: true, previousParentAgentId };
1303
+ }
1304
+ const record = await registry.get(agentId);
1305
+ if (!record) {
1306
+ throw new Error(`Agent not found: ${agentId}`);
1307
+ }
1308
+ const previousParentAgentId = getParentAgentIdFromLabels(record.labels);
1309
+ if (!previousParentAgentId) {
1310
+ return { record, live: false, previousParentAgentId: null };
1311
+ }
1312
+ const result = await this.writeLabels(agentId, {
1313
+ [PARENT_AGENT_ID_LABEL]: null,
1314
+ });
1315
+ if (!result.record) {
1316
+ throw new Error(`Agent not found in storage after detach: ${agentId}`);
1317
+ }
1318
+ return { record: result.record, live: false, previousParentAgentId };
1319
+ }
1320
+ /**
1321
+ * Replace the session digest wholesale. Callers (the set_session_digest MCP
1322
+ * tool and the daemon digest refresher) compute the merged digest and pass
1323
+ * the full object. See docs/session-digest.md.
1324
+ */
1325
+ async setDigest(agentId, digest) {
1326
+ const agent = this.requireAgent(agentId);
1327
+ agent.digest = digest;
1328
+ // Targeted digest-only persist (mirrors setGeneratedTitle): the digest
1329
+ // refresh runs asynchronously on running→idle, so a full-record
1330
+ // persistSnapshot here would race with and revert a concurrent title/label
1331
+ // write. Updating only the digest field is race-safe. See docs/session-digest.md §5.
1332
+ const registry = this.requireRegistry();
1333
+ const persisted = await registry.setDigest(agentId, digest);
1334
+ agent.updatedAt = new Date(persisted.updatedAt);
1335
+ // Jarvis substrate: mergeDigest overwrites blockers on every derivation, so
1336
+ // without this append the "fourth time waiting on Marco" signal is destroyed
1337
+ // on every idle. Self-reported blockers win over derived ones, matching how
1338
+ // the judge reads them.
1339
+ this.blockerLog?.record(agentId, digest.blockers?.length ? digest.blockers : digest.derivedBlockers);
1340
+ this.emitState(agent, { persist: false });
1341
+ }
1342
+ notifyAgentState(agentId) {
1343
+ const agent = this.agents.get(agentId);
1344
+ if (!agent || agent.internal) {
1345
+ return;
1346
+ }
1347
+ this.touchUpdatedAt(agent);
1348
+ this.emitState(agent);
1349
+ }
1350
+ async clearAgentAttention(agentId) {
1351
+ const agent = this.requireAgent(agentId);
1352
+ if (agent.attention.requiresAttention) {
1353
+ agent.attention = { requiresAttention: false };
1354
+ await this.persistSnapshot(agent);
1355
+ this.emitState(agent, { persist: false });
1356
+ }
1357
+ }
1358
+ async archiveSnapshot(agentId, archivedAt) {
1359
+ const registry = this.requireRegistry();
1360
+ const liveAgent = this.getAgent(agentId);
1361
+ if (liveAgent) {
1362
+ await this.persistSnapshot(liveAgent, {
1363
+ internal: liveAgent.internal,
1364
+ });
1365
+ }
1366
+ const record = await registry.get(agentId);
1367
+ if (!record) {
1368
+ throw new Error(`Agent not found: ${agentId}`);
1369
+ }
1370
+ const nextRecord = buildArchivedAgentRecord(record, { archivedAt });
1371
+ await registry.upsert(nextRecord);
1372
+ await this.archiveNativeSessionBestEffort(record.provider, record.persistence);
1373
+ if (this.agents.has(agentId)) {
1374
+ this.notifyAgentState(agentId);
1375
+ }
1376
+ else if (!nextRecord.internal) {
1377
+ this.dispatchArchivedStoredAgent(nextRecord);
1378
+ }
1379
+ await this.fireAgentArchived(agentId);
1380
+ return nextRecord;
1381
+ }
1382
+ async unarchiveSnapshot(agentId) {
1383
+ const registry = this.requireRegistry();
1384
+ const record = await registry.get(agentId);
1385
+ if (!record || !record.archivedAt) {
1386
+ return false;
1387
+ }
1388
+ await this.unarchiveNativeSession(record.provider, record.persistence);
1389
+ await registry.upsert({
1390
+ ...record,
1391
+ archivedAt: null,
1392
+ updatedAt: new Date().toISOString(),
1393
+ });
1394
+ if (this.getAgent(agentId)) {
1395
+ this.notifyAgentState(agentId);
1396
+ }
1397
+ return true;
1398
+ }
1399
+ async unarchiveSnapshotByHandle(handle) {
1400
+ const registry = this.requireRegistry();
1401
+ const records = await registry.list();
1402
+ const matched = records.find((record) => record.persistence?.provider === handle.provider &&
1403
+ record.persistence?.sessionId === handle.sessionId);
1404
+ if (!matched) {
1405
+ return;
1406
+ }
1407
+ await this.unarchiveSnapshot(matched.id);
1408
+ }
1409
+ async updateAgentMetadata(agentId, updates) {
1410
+ const liveAgent = this.getAgent(agentId);
1411
+ if (liveAgent) {
1412
+ if (updates.title) {
1413
+ await this.setTitle(agentId, updates.title);
1414
+ }
1415
+ if (updates.labels) {
1416
+ await this.writeLabels(agentId, updates.labels);
1417
+ }
1418
+ if (updates.digest) {
1419
+ await this.setDigest(agentId, updates.digest);
1420
+ }
1421
+ return;
1422
+ }
1423
+ await this.writeStoredMetadata(agentId, updates);
1424
+ }
1425
+ async runAgent(agentId, prompt, options) {
1426
+ const events = this.streamAgent(agentId, prompt, options);
1427
+ const timeline = [];
1428
+ let finalText = "";
1429
+ let usage;
1430
+ let canceled = false;
1431
+ for await (const event of events) {
1432
+ if (event.type === "timeline") {
1433
+ timeline.push(event.item);
1434
+ }
1435
+ else if (event.type === "turn_completed") {
1436
+ usage = event.usage;
1437
+ }
1438
+ else if (event.type === "turn_failed") {
1439
+ throw new Error(this.formatTurnFailedMessage(event));
1440
+ }
1441
+ else if (event.type === "turn_canceled") {
1442
+ canceled = true;
1443
+ }
1444
+ }
1445
+ finalText = this.getLastAssistantMessageFromTimeline(timeline) ?? "";
1446
+ const agent = this.requireAgent(agentId);
1447
+ const sessionId = agent.persistence?.sessionId;
1448
+ if (!sessionId) {
1449
+ throw new Error(`Agent ${agentId} has no persistence.sessionId after run completed`);
1450
+ }
1451
+ return {
1452
+ sessionId,
1453
+ finalText,
1454
+ usage,
1455
+ timeline,
1456
+ canceled,
1457
+ };
1458
+ }
1459
+ /**
1460
+ * Try to run a prompt out-of-band — i.e. without allocating a foreground turn
1461
+ * and without canceling any active turn. Returns true when the session
1462
+ * accepted the prompt as a side-effect command (e.g. /goal pause). Events
1463
+ * emitted by the handler flow through dispatchStream so they persist and
1464
+ * broadcast like normal timeline events.
1465
+ */
1466
+ tryRunOutOfBand(agentId, prompt) {
1467
+ const agent = this.requireSessionAgent(agentId);
1468
+ const handler = agent.session.tryHandleOutOfBand?.(prompt);
1469
+ if (!handler) {
1470
+ return false;
1471
+ }
1472
+ const dispatch = (event) => {
1473
+ // Persist timeline items so they show up in fetchAgentTimeline; broadcast
1474
+ // for live subscribers. Other event types are broadcast only.
1475
+ if (event.type === "timeline") {
1476
+ this.touchUpdatedAt(agent);
1477
+ const row = this.recordTimeline(agent.id, event.item);
1478
+ this.dispatchStream(agent.id, event, {
1479
+ seq: row.seq,
1480
+ epoch: this.timelineStore.getEpoch(agent.id),
1481
+ timestamp: row.timestamp,
1482
+ });
1483
+ return;
1484
+ }
1485
+ this.dispatchStream(agent.id, event, {
1486
+ timestamp: new Date().toISOString(),
1487
+ });
1488
+ };
1489
+ void (async () => {
1490
+ try {
1491
+ await handler.run({ emit: dispatch });
1492
+ }
1493
+ catch (error) {
1494
+ const text = error instanceof Error ? error.message : "Out-of-band command failed";
1495
+ dispatch({
1496
+ type: "timeline",
1497
+ provider: agent.provider,
1498
+ item: { type: "assistant_message", text: `[Error] ${text}` },
1499
+ });
1500
+ }
1501
+ })();
1502
+ return true;
1503
+ }
1504
+ async appendTimelineItem(agentId, item) {
1505
+ const agent = this.requireAgent(agentId);
1506
+ this.touchUpdatedAt(agent);
1507
+ const row = this.recordTimeline(agentId, item);
1508
+ this.dispatchStream(agentId, {
1509
+ type: "timeline",
1510
+ item,
1511
+ provider: agent.provider,
1512
+ }, {
1513
+ seq: row.seq,
1514
+ epoch: this.timelineStore.getEpoch(agentId),
1515
+ timestamp: row.timestamp,
1516
+ });
1517
+ await this.persistSnapshot(agent);
1518
+ }
1519
+ async emitLiveTimelineItem(agentId, item) {
1520
+ const agent = this.requireAgent(agentId);
1521
+ this.touchUpdatedAt(agent);
1522
+ this.dispatchStream(agentId, {
1523
+ type: "timeline",
1524
+ item,
1525
+ provider: agent.provider,
1526
+ });
1527
+ }
1528
+ streamAgent(agentId, prompt, options) {
1529
+ const existingAgent = this.requireSessionAgent(agentId);
1530
+ this.logger.trace({
1531
+ agentId,
1532
+ provider: existingAgent.provider,
1533
+ sessionId: existingAgent.persistence?.sessionId ?? undefined,
1534
+ turnId: existingAgent.activeForegroundTurnId ?? undefined,
1535
+ lifecycle: existingAgent.lifecycle,
1536
+ activeForegroundTurnId: existingAgent.activeForegroundTurnId,
1537
+ hasPendingForegroundRun: this.foregroundRuns.hasPendingRun(agentId),
1538
+ promptType: typeof prompt === "string" ? "string" : "structured",
1539
+ hasRunOptions: Boolean(options),
1540
+ }, "agent.manager.stream.request");
1541
+ if (existingAgent.activeForegroundTurnId || this.foregroundRuns.hasPendingRun(agentId)) {
1542
+ this.logger.trace({
1543
+ agentId,
1544
+ provider: existingAgent.provider,
1545
+ sessionId: existingAgent.persistence?.sessionId ?? undefined,
1546
+ turnId: existingAgent.activeForegroundTurnId ?? undefined,
1547
+ lifecycle: existingAgent.lifecycle,
1548
+ hasPendingForegroundRun: this.foregroundRuns.hasPendingRun(agentId),
1549
+ }, "agent.manager.stream.reject");
1550
+ throw new Error(`Agent ${agentId} already has an active run`);
1551
+ }
1552
+ const agent = existingAgent;
1553
+ agent.pendingReplacement = false;
1554
+ agent.lastError = undefined;
1555
+ const pendingRun = this.foregroundRuns.createPendingRun(agentId);
1556
+ const streamForwarder = async function* streamForwarder() {
1557
+ let turnId;
1558
+ let turnStream = null;
1559
+ try {
1560
+ // Attribution must be applied to the prompt BEFORE it goes on the wire;
1561
+ // the ledger below records the same turn but cannot reach the prompt.
1562
+ // No-op unless markup was injected.
1563
+ const attributed = (this.authorshipMarkup?.apply(agentId, prompt) ??
1564
+ prompt);
1565
+ const result = await agent.session.startTurn(attributed, options);
1566
+ turnId = result.turnId;
1567
+ }
1568
+ catch (error) {
1569
+ const errorMsg = error instanceof Error ? error.message : "Failed to start turn";
1570
+ await this.handleStreamEvent(agent, {
1571
+ type: "turn_failed",
1572
+ provider: agent.provider,
1573
+ error: errorMsg,
1574
+ });
1575
+ this.finalizeForegroundTurn(agent);
1576
+ this.foregroundRuns.settlePendingRun(agentId, pendingRun.token);
1577
+ throw error;
1578
+ }
1579
+ pendingRun.started = true;
1580
+ agent.activeForegroundTurnId = turnId;
1581
+ // The only moment the human and the turn coexist server-side. Nothing
1582
+ // downstream can reconstruct who authored this, so stamp it here or the
1583
+ // fact is gone. No-op unless a ledger was injected.
1584
+ this.authorshipLedger?.record({
1585
+ agentId,
1586
+ turnId,
1587
+ sessionId: agent.persistence?.sessionId ?? null,
1588
+ });
1589
+ agent.lifecycle = "running";
1590
+ this.touchUpdatedAt(agent);
1591
+ this.emitState(agent);
1592
+ this.logger.trace({
1593
+ agentId,
1594
+ provider: agent.provider,
1595
+ sessionId: agent.persistence?.sessionId ?? undefined,
1596
+ turnId,
1597
+ lifecycle: agent.lifecycle,
1598
+ activeForegroundTurnId: agent.activeForegroundTurnId,
1599
+ }, "agent.manager.stream.start");
1600
+ turnStream = this.foregroundRuns.createTurnStream(turnId);
1601
+ this.foregroundRuns.addWaiter(agent, turnStream.waiter);
1602
+ try {
1603
+ for await (const event of turnStream.events(isTurnTerminalEvent)) {
1604
+ yield event;
1605
+ }
1606
+ }
1607
+ finally {
1608
+ if (turnStream) {
1609
+ this.foregroundRuns.deleteWaiter(agent, turnStream.waiter);
1610
+ }
1611
+ this.foregroundRuns.settlePendingRun(agentId, pendingRun.token);
1612
+ if (!agent.activeForegroundTurnId) {
1613
+ await this.refreshRuntimeInfo(agent);
1614
+ }
1615
+ }
1616
+ }.call(this);
1617
+ return streamForwarder;
1618
+ }
1619
+ finalizeForegroundTurn(agent, turnId) {
1620
+ const mutableAgent = agent;
1621
+ if (turnId) {
1622
+ this.foregroundRuns.rememberFinalizedTurn(mutableAgent, turnId);
1623
+ }
1624
+ mutableAgent.activeForegroundTurnId = null;
1625
+ const terminalError = mutableAgent.lastError;
1626
+ const shouldHoldBusyForReplacement = mutableAgent.pendingReplacement && !terminalError;
1627
+ let nextLifecycle;
1628
+ if (shouldHoldBusyForReplacement) {
1629
+ nextLifecycle = "running";
1630
+ }
1631
+ else if (terminalError) {
1632
+ nextLifecycle = "error";
1633
+ }
1634
+ else {
1635
+ nextLifecycle = "idle";
1636
+ }
1637
+ mutableAgent.lifecycle = nextLifecycle;
1638
+ const persistenceHandle = mutableAgent.session.describePersistence() ??
1639
+ (mutableAgent.runtimeInfo?.sessionId
1640
+ ? {
1641
+ provider: mutableAgent.provider,
1642
+ sessionId: mutableAgent.runtimeInfo.sessionId,
1643
+ }
1644
+ : null);
1645
+ if (persistenceHandle) {
1646
+ mutableAgent.persistence = attachPersistenceCwd(persistenceHandle, mutableAgent.cwd);
1647
+ }
1648
+ this.logger.trace({
1649
+ agentId: agent.id,
1650
+ provider: agent.provider,
1651
+ sessionId: mutableAgent.persistence?.sessionId ?? undefined,
1652
+ turnId,
1653
+ lifecycle: mutableAgent.lifecycle,
1654
+ terminalError,
1655
+ pendingReplacement: mutableAgent.pendingReplacement,
1656
+ }, "agent.manager.finalize");
1657
+ if (!shouldHoldBusyForReplacement) {
1658
+ this.touchUpdatedAt(mutableAgent);
1659
+ this.emitState(mutableAgent);
1660
+ }
1661
+ }
1662
+ replaceAgentRun(agentId, prompt, options) {
1663
+ const snapshot = this.requireAgent(agentId);
1664
+ if (snapshot.lifecycle !== "running" &&
1665
+ !snapshot.activeForegroundTurnId &&
1666
+ !this.foregroundRuns.hasPendingRun(agentId)) {
1667
+ return this.streamAgent(agentId, prompt, options);
1668
+ }
1669
+ const agent = this.requireSessionAgent(agentId);
1670
+ agent.pendingReplacement = true;
1671
+ agent.lifecycle = "running";
1672
+ this.touchUpdatedAt(agent);
1673
+ this.emitState(agent);
1674
+ return async function* replaceRunForwarder() {
1675
+ try {
1676
+ await this.cancelAgentRun(agentId);
1677
+ const nextRun = this.streamAgent(agentId, prompt, options);
1678
+ for await (const event of nextRun) {
1679
+ yield event;
1680
+ }
1681
+ }
1682
+ catch (error) {
1683
+ const latest = this.agents.get(agentId);
1684
+ if (latest) {
1685
+ const latestActive = latest;
1686
+ latestActive.pendingReplacement = false;
1687
+ if (!latestActive.activeForegroundTurnId && latestActive.lifecycle === "running") {
1688
+ latestActive.lifecycle = "idle";
1689
+ this.touchUpdatedAt(latestActive);
1690
+ this.emitState(latestActive);
1691
+ }
1692
+ }
1693
+ throw error;
1694
+ }
1695
+ }.call(this);
1696
+ }
1697
+ async waitForAgentRunStart(agentId, options) {
1698
+ const snapshot = this.getAgent(agentId);
1699
+ if (!snapshot) {
1700
+ throw new Error(`Agent ${agentId} not found`);
1701
+ }
1702
+ const pendingRun = this.foregroundRuns.getPendingRun(agentId);
1703
+ if ((snapshot.lifecycle === "running" || pendingRun?.started) && !snapshot.pendingReplacement) {
1704
+ return;
1705
+ }
1706
+ if (!snapshot.activeForegroundTurnId && !pendingRun && !snapshot.pendingReplacement) {
1707
+ throw new Error(`Agent ${agentId} has no pending run`);
1708
+ }
1709
+ if (options?.signal?.aborted) {
1710
+ throw createAbortError(options.signal, "wait_for_agent_start aborted");
1711
+ }
1712
+ await new Promise((resolvePromise, reject) => {
1713
+ if (options?.signal?.aborted) {
1714
+ reject(createAbortError(options.signal, "wait_for_agent_start aborted"));
1715
+ return;
1716
+ }
1717
+ let unsubscribe = null;
1718
+ let abortHandler = null;
1719
+ const cleanup = () => {
1720
+ if (unsubscribe) {
1721
+ try {
1722
+ unsubscribe();
1723
+ }
1724
+ catch {
1725
+ // ignore cleanup errors
1726
+ }
1727
+ unsubscribe = null;
1728
+ }
1729
+ if (abortHandler && options?.signal) {
1730
+ try {
1731
+ options.signal.removeEventListener("abort", abortHandler);
1732
+ }
1733
+ catch {
1734
+ // ignore cleanup errors
1735
+ }
1736
+ abortHandler = null;
1737
+ }
1738
+ };
1739
+ const finishOk = () => {
1740
+ cleanup();
1741
+ resolvePromise();
1742
+ };
1743
+ const finishErr = (error) => {
1744
+ cleanup();
1745
+ reject(error);
1746
+ };
1747
+ if (options?.signal) {
1748
+ abortHandler = () => finishErr(createAbortError(options.signal, "wait_for_agent_start aborted"));
1749
+ options.signal.addEventListener("abort", abortHandler, { once: true });
1750
+ }
1751
+ const checkCurrentState = () => {
1752
+ const current = this.getAgent(agentId);
1753
+ if (!current) {
1754
+ finishErr(new Error(`Agent ${agentId} not found`));
1755
+ return true;
1756
+ }
1757
+ const currentPendingRun = this.foregroundRuns.getPendingRun(agentId);
1758
+ if ((current.lifecycle === "running" || currentPendingRun?.started) &&
1759
+ !current.pendingReplacement) {
1760
+ finishOk();
1761
+ return true;
1762
+ }
1763
+ if (current.lifecycle === "error" && !currentPendingRun?.started) {
1764
+ finishErr(new Error(current.lastError ?? `Agent ${agentId} failed to start`));
1765
+ return true;
1766
+ }
1767
+ if (!currentPendingRun && !current.activeForegroundTurnId && !current.pendingReplacement) {
1768
+ finishErr(new Error(`Agent ${agentId} run finished before starting`));
1769
+ return true;
1770
+ }
1771
+ return false;
1772
+ };
1773
+ unsubscribe = this.subscribe((event) => {
1774
+ if (event.type !== "agent_state" || event.agent.id !== agentId) {
1775
+ return;
1776
+ }
1777
+ checkCurrentState();
1778
+ }, { agentId, replayState: false });
1779
+ checkCurrentState();
1780
+ });
1781
+ }
1782
+ async respondToPermission(agentId, requestId, response) {
1783
+ const agent = this.requireAgent(agentId);
1784
+ agent.inFlightPermissionResponses.add(requestId);
1785
+ try {
1786
+ const result = await agent.session.respondToPermission(requestId, response);
1787
+ agent.pendingPermissions.delete(requestId);
1788
+ try {
1789
+ await this.refreshSessionState(agent);
1790
+ }
1791
+ catch {
1792
+ // Ignore refresh errors - state sync after permission approval is best effort.
1793
+ }
1794
+ this.touchUpdatedAt(agent);
1795
+ await this.persistSnapshot(agent);
1796
+ this.emitState(agent);
1797
+ const bufferedResolution = agent.bufferedPermissionResolutions.get(requestId);
1798
+ if (bufferedResolution) {
1799
+ agent.bufferedPermissionResolutions.delete(requestId);
1800
+ this.dispatchStream(agent.id, bufferedResolution, {
1801
+ timestamp: new Date().toISOString(),
1802
+ });
1803
+ }
1804
+ return result;
1805
+ }
1806
+ finally {
1807
+ agent.inFlightPermissionResponses.delete(requestId);
1808
+ agent.bufferedPermissionResolutions.delete(requestId);
1809
+ }
1810
+ }
1811
+ /**
1812
+ * Dismiss a live background shell for an agent. Delegates to the provider
1813
+ * session, which (for Claude Code over PTY) kills the shell inside the CLI
1814
+ * via its own keybinding. Returns false if the provider doesn't support it.
1815
+ */
1816
+ async dismissBackgroundTask(agentId, taskId) {
1817
+ const agent = this.requireSessionAgent(agentId);
1818
+ if (typeof agent.session.dismissBackgroundTask !== "function") {
1819
+ return false;
1820
+ }
1821
+ return agent.session.dismissBackgroundTask(taskId);
1822
+ }
1823
+ /**
1824
+ * Background shells for one agent, or across every live agent when `agentId`
1825
+ * is omitted. Each row carries its owning agent so a cross-agent list renders
1826
+ * without a second lookup. Providers that don't model background shells
1827
+ * contribute nothing.
1828
+ */
1829
+ listBackgroundTasks(agentId) {
1830
+ const candidates = agentId === undefined
1831
+ ? Array.from(this.agents.values()).filter((agent) => !agent.internal)
1832
+ : [this.requireSessionAgent(agentId)];
1833
+ const rows = [];
1834
+ for (const agent of candidates) {
1835
+ if (typeof agent.session?.listBackgroundTasks !== "function") {
1836
+ continue;
1837
+ }
1838
+ for (const task of agent.session.listBackgroundTasks()) {
1839
+ rows.push({
1840
+ agentId: agent.id,
1841
+ agentTitle: agent.config.title ?? null,
1842
+ task,
1843
+ });
1844
+ }
1845
+ }
1846
+ return rows;
1847
+ }
1848
+ /**
1849
+ * Read a background shell's captured output. Returns null when the provider
1850
+ * doesn't model background shells, or the id is unknown to it.
1851
+ */
1852
+ async readBackgroundTaskOutput(agentId, taskId, options) {
1853
+ const agent = this.requireSessionAgent(agentId);
1854
+ if (typeof agent.session.readBackgroundTaskOutput !== "function") {
1855
+ return null;
1856
+ }
1857
+ return agent.session.readBackgroundTaskOutput(taskId, options);
1858
+ }
1859
+ async cancelAgentRun(agentId) {
1860
+ const agent = this.requireSessionAgent(agentId);
1861
+ const pendingRun = this.foregroundRuns.getPendingRun(agentId);
1862
+ const foregroundTurnId = agent.activeForegroundTurnId;
1863
+ const hasForegroundTurn = Boolean(foregroundTurnId);
1864
+ const isAutonomousRunning = agent.lifecycle === "running" && !hasForegroundTurn && !pendingRun;
1865
+ if (!hasForegroundTurn && !isAutonomousRunning && !pendingRun) {
1866
+ return false;
1867
+ }
1868
+ await this.interruptSession(agent.session, agentId);
1869
+ // The interrupt will produce a turn_canceled/turn_failed event via subscribe(),
1870
+ // which flows through the session event dispatcher and settles the foreground turn waiter.
1871
+ // Wait briefly for the event to propagate if there's an active foreground turn.
1872
+ if (foregroundTurnId) {
1873
+ const waiter = Array.from(agent.foregroundTurnWaiters).find((candidate) => candidate.turnId === foregroundTurnId);
1874
+ const timeout = new Promise((resolvePromise) => setTimeout(resolvePromise, 2000));
1875
+ if (waiter) {
1876
+ await Promise.race([waiter.settledPromise, timeout]);
1877
+ }
1878
+ else if (agent.activeForegroundTurnId === foregroundTurnId) {
1879
+ await Promise.race([
1880
+ new Promise((resolvePromise) => {
1881
+ const unsubscribe = this.subscribe((event) => {
1882
+ if (event.type === "agent_state" &&
1883
+ event.agent.id === agentId &&
1884
+ !event.agent.activeForegroundTurnId) {
1885
+ unsubscribe();
1886
+ resolvePromise();
1887
+ }
1888
+ }, { agentId, replayState: false });
1889
+ }),
1890
+ timeout,
1891
+ ]);
1892
+ }
1893
+ // The waiter settling wakes up the streamForwarder generator, but its
1894
+ // finally block (which deletes the pendingForegroundRun) runs asynchronously.
1895
+ // Wait for the pending run to be fully cleaned up so the next streamAgent
1896
+ // call doesn't see a stale entry and reject with "already has an active run".
1897
+ if (pendingRun && !pendingRun.settled) {
1898
+ await Promise.race([pendingRun.settledPromise, timeout]);
1899
+ }
1900
+ }
1901
+ else if (pendingRun) {
1902
+ const timeout = new Promise((resolvePromise) => setTimeout(resolvePromise, 2000));
1903
+ await Promise.race([pendingRun.settledPromise, timeout]);
1904
+ }
1905
+ // If the foreground turn is still stuck after the timeout, force-dispatch a
1906
+ // synthetic turn_canceled so the normal event pipeline cleans up
1907
+ // activeForegroundTurnId, settles waiters, and unblocks the streamForwarder.
1908
+ if (foregroundTurnId && agent.activeForegroundTurnId === foregroundTurnId) {
1909
+ this.logger.warn({ agentId, foregroundTurnId }, "cancelAgentRun: foreground turn still active after timeout, force-canceling");
1910
+ void this.dispatchSessionEvent(agent, {
1911
+ type: "turn_canceled",
1912
+ provider: agent.provider,
1913
+ reason: "interrupted",
1914
+ turnId: foregroundTurnId,
1915
+ });
1916
+ // The synthetic event unblocks the streamForwarder generator, whose finally
1917
+ // block settles the pending foreground run asynchronously. Wait for it.
1918
+ const staleRun = this.foregroundRuns.getPendingRun(agentId);
1919
+ if (staleRun && !staleRun.settled) {
1920
+ await staleRun.settledPromise;
1921
+ }
1922
+ }
1923
+ // Clear any pending permissions that weren't cleaned up by handleStreamEvent.
1924
+ if (agent.pendingPermissions.size > 0) {
1925
+ for (const [requestId] of agent.pendingPermissions) {
1926
+ this.dispatchStream(agent.id, {
1927
+ type: "permission_resolved",
1928
+ provider: agent.provider,
1929
+ requestId,
1930
+ resolution: { behavior: "deny", message: "Interrupted" },
1931
+ }, { timestamp: new Date().toISOString() });
1932
+ }
1933
+ agent.pendingPermissions.clear();
1934
+ this.touchUpdatedAt(agent);
1935
+ this.emitState(agent);
1936
+ }
1937
+ return true;
1938
+ }
1939
+ async interruptSession(session, agentId) {
1940
+ try {
1941
+ const result = await this.waitWithTimeout({
1942
+ operation: session.interrupt(),
1943
+ timeoutMs: this.rescueTimeouts.interruptSessionMs,
1944
+ onLateError: (error) => {
1945
+ this.logger.warn({ err: error, agentId }, "Session interrupt failed after timeout during cancel");
1946
+ },
1947
+ });
1948
+ if (result === "timed_out") {
1949
+ this.logger.warn({ agentId, timeoutMs: this.rescueTimeouts.interruptSessionMs }, "Timed out interrupting session during cancel");
1950
+ }
1951
+ }
1952
+ catch (error) {
1953
+ this.logger.error({ err: error, agentId }, "Failed to interrupt session");
1954
+ }
1955
+ }
1956
+ getPendingPermissions(agentId) {
1957
+ const agent = this.requireSessionAgent(agentId);
1958
+ return Array.from(agent.pendingPermissions.values());
1959
+ }
1960
+ peekPendingPermission(agent) {
1961
+ const iterator = agent.pendingPermissions.values().next();
1962
+ return iterator.done ? null : iterator.value;
1963
+ }
1964
+ /**
1965
+ * Hydrates the timeline from provider history if the agent's durable
1966
+ * timeline is empty (e.g., imported agents that have provider history
1967
+ * on disk but no persisted timeline rows). No-ops if already hydrated.
1968
+ */
1969
+ async hydrateTimelineFromProvider(agentId, options) {
1970
+ const agent = this.requireSessionAgent(agentId);
1971
+ await this.hydrateTimelineFromLegacyProviderHistory(agent, options);
1972
+ }
1973
+ async rewind(agentId, messageId, mode) {
1974
+ const agent = this.requireSessionAgent(agentId);
1975
+ const hadActiveRun = Boolean(agent.activeForegroundTurnId) || this.foregroundRuns.hasPendingRun(agentId);
1976
+ if (hadActiveRun) {
1977
+ await this.cancelAgentRun(agentId);
1978
+ }
1979
+ const lock = this.foregroundRuns.createPendingRun(agentId);
1980
+ try {
1981
+ this.logger.info({ agentId, provider: agent.provider, messageId, mode }, "agent.rewind.start");
1982
+ await invokeRewindCapability(agent.session, { messageId, mode });
1983
+ if (mode !== "files") {
1984
+ await this.hydrateTimelineFromProvider(agentId, {
1985
+ force: true,
1986
+ broadcast: true,
1987
+ });
1988
+ }
1989
+ await this.refreshRuntimeInfo(agent);
1990
+ await this.persistSnapshot(agent);
1991
+ this.logger.info({ agentId, provider: agent.provider, messageId, mode }, "agent.rewind.complete");
1992
+ }
1993
+ catch (error) {
1994
+ this.logger.warn({ err: error, agentId, provider: agent.provider, messageId, mode }, "agent.rewind.failed");
1995
+ throw error;
1996
+ }
1997
+ finally {
1998
+ this.foregroundRuns.settlePendingRun(agentId, lock.token);
1999
+ }
2000
+ }
2001
+ async deleteCommittedTimeline(agentId) {
2002
+ if (!this.durableTimelineStore) {
2003
+ return;
2004
+ }
2005
+ await this.durableTimelineStore.deleteAgent(agentId);
2006
+ }
2007
+ async getLastAssistantMessage(agentId) {
2008
+ const agent = this.agents.get(agentId);
2009
+ if (!agent) {
2010
+ return null;
2011
+ }
2012
+ return await this.getLastAssistantMessageFromStores(agentId);
2013
+ }
2014
+ getLastAssistantMessageFromTimeline(timeline) {
2015
+ return this.getLastAssistantMessageSegmentFromTimeline(timeline)?.text ?? null;
2016
+ }
2017
+ getLastAssistantMessageSegmentFromTimeline(timeline) {
2018
+ // Collect the last contiguous assistant messages (Claude streams chunks)
2019
+ const chunks = [];
2020
+ let startsAtBeginning = false;
2021
+ for (let i = timeline.length - 1; i >= 0; i--) {
2022
+ const item = timeline[i];
2023
+ if (item.type !== "assistant_message") {
2024
+ if (chunks.length) {
2025
+ break;
2026
+ }
2027
+ continue;
2028
+ }
2029
+ chunks.push(item.text);
2030
+ startsAtBeginning = i === 0;
2031
+ }
2032
+ if (!chunks.length) {
2033
+ return null;
2034
+ }
2035
+ return {
2036
+ text: chunks.toReversed().join(""),
2037
+ startsAtBeginning,
2038
+ };
2039
+ }
2040
+ async getLastAssistantMessageFromStores(agentId) {
2041
+ const liveTimeline = this.timelineStore.getItems(agentId);
2042
+ const liveSegment = this.getLastAssistantMessageSegmentFromTimeline(liveTimeline);
2043
+ if (!this.durableTimelineStore) {
2044
+ return liveSegment?.text ?? null;
2045
+ }
2046
+ if (!liveSegment) {
2047
+ return await this.durableTimelineStore.getLastAssistantMessage(agentId);
2048
+ }
2049
+ if (!liveSegment.startsAtBeginning) {
2050
+ return liveSegment.text;
2051
+ }
2052
+ const lastDurableItem = await this.durableTimelineStore.getLastItem(agentId);
2053
+ if (lastDurableItem?.type !== "assistant_message") {
2054
+ return liveSegment.text;
2055
+ }
2056
+ const durableMessage = await this.durableTimelineStore.getLastAssistantMessage(agentId);
2057
+ return durableMessage ? `${durableMessage}${liveSegment.text}` : liveSegment.text;
2058
+ }
2059
+ async getLastItemFromStores(agentId) {
2060
+ const lastLiveItem = this.timelineStore.getLastItem(agentId);
2061
+ if (lastLiveItem) {
2062
+ return lastLiveItem;
2063
+ }
2064
+ if (!this.durableTimelineStore) {
2065
+ return null;
2066
+ }
2067
+ return await this.durableTimelineStore.getLastItem(agentId);
2068
+ }
2069
+ async waitForAgentEvent(agentId, options) {
2070
+ const snapshot = this.getAgent(agentId);
2071
+ if (!snapshot) {
2072
+ throw new Error(`Agent ${agentId} not found`);
2073
+ }
2074
+ const pendingForegroundRun = this.foregroundRuns.getPendingRun(agentId);
2075
+ const hasForegroundTurn = Boolean(snapshot.activeForegroundTurnId) || Boolean(pendingForegroundRun);
2076
+ const immediatePermission = this.peekPendingPermission(snapshot);
2077
+ if (immediatePermission) {
2078
+ return {
2079
+ status: snapshot.lifecycle,
2080
+ permission: immediatePermission,
2081
+ lastMessage: await this.getLastAssistantMessage(agentId),
2082
+ };
2083
+ }
2084
+ const initialStatus = snapshot.lifecycle;
2085
+ const initialBusy = isAgentBusy(initialStatus) || hasForegroundTurn;
2086
+ const waitForActive = options?.waitForActive ?? false;
2087
+ if (!waitForActive && !initialBusy) {
2088
+ return {
2089
+ status: initialStatus,
2090
+ permission: null,
2091
+ lastMessage: await this.getLastAssistantMessage(agentId),
2092
+ };
2093
+ }
2094
+ if (waitForActive && !initialBusy && !hasForegroundTurn) {
2095
+ return {
2096
+ status: initialStatus,
2097
+ permission: null,
2098
+ lastMessage: await this.getLastAssistantMessage(agentId),
2099
+ };
2100
+ }
2101
+ if (options?.signal?.aborted) {
2102
+ throw createAbortError(options.signal, "wait_for_agent aborted");
2103
+ }
2104
+ return await new Promise((resolvePromise, reject) => {
2105
+ // Bug #1 Fix: Check abort signal AGAIN inside Promise constructor
2106
+ // to avoid race condition between pre-Promise check and abort listener registration
2107
+ if (options?.signal?.aborted) {
2108
+ reject(createAbortError(options.signal, "wait_for_agent aborted"));
2109
+ return;
2110
+ }
2111
+ let currentStatus = initialStatus;
2112
+ let hasStarted = isAgentBusy(initialStatus) ||
2113
+ Boolean(snapshot.activeForegroundTurnId) ||
2114
+ Boolean(pendingForegroundRun?.started);
2115
+ let terminalStatusOverride = null;
2116
+ let finished = false;
2117
+ // Bug #3 Fix: Declare unsubscribe and abortHandler upfront so cleanup can reference them
2118
+ let unsubscribe = null;
2119
+ let abortHandler = null;
2120
+ const cleanup = () => {
2121
+ // Clean up subscription
2122
+ if (unsubscribe) {
2123
+ try {
2124
+ unsubscribe();
2125
+ }
2126
+ catch {
2127
+ // ignore cleanup errors
2128
+ }
2129
+ unsubscribe = null;
2130
+ }
2131
+ // Clean up abort listener
2132
+ if (abortHandler && options?.signal) {
2133
+ try {
2134
+ options.signal.removeEventListener("abort", abortHandler);
2135
+ }
2136
+ catch {
2137
+ // ignore cleanup errors
2138
+ }
2139
+ abortHandler = null;
2140
+ }
2141
+ };
2142
+ const finish = (permission) => {
2143
+ if (finished) {
2144
+ return;
2145
+ }
2146
+ finished = true;
2147
+ cleanup();
2148
+ void this.getLastAssistantMessage(agentId)
2149
+ .then((lastMessage) => {
2150
+ resolvePromise({
2151
+ status: currentStatus,
2152
+ permission,
2153
+ lastMessage,
2154
+ });
2155
+ return;
2156
+ })
2157
+ .catch(reject);
2158
+ };
2159
+ // Bug #3 Fix: Set up abort handler BEFORE subscription
2160
+ // to ensure cleanup handlers exist before callback can fire
2161
+ if (options?.signal) {
2162
+ abortHandler = () => {
2163
+ cleanup();
2164
+ reject(createAbortError(options.signal, "wait_for_agent aborted"));
2165
+ };
2166
+ options.signal.addEventListener("abort", abortHandler, { once: true });
2167
+ }
2168
+ // Bug #3 Fix: Now subscribe with cleanup handlers already in place
2169
+ // This prevents race condition if callback fires synchronously with replayState: true
2170
+ unsubscribe = this.subscribe((event) => {
2171
+ if (event.type === "agent_state") {
2172
+ currentStatus = event.agent.lifecycle;
2173
+ const pending = this.peekPendingPermission(event.agent);
2174
+ if (pending) {
2175
+ finish(pending);
2176
+ return;
2177
+ }
2178
+ if (isAgentBusy(event.agent.lifecycle)) {
2179
+ hasStarted = true;
2180
+ return;
2181
+ }
2182
+ if (!waitForActive || hasStarted) {
2183
+ if (terminalStatusOverride) {
2184
+ currentStatus = terminalStatusOverride;
2185
+ }
2186
+ finish(null);
2187
+ }
2188
+ return;
2189
+ }
2190
+ if (event.type === "agent_stream") {
2191
+ if (event.event.type === "permission_requested") {
2192
+ finish(event.event.request);
2193
+ return;
2194
+ }
2195
+ if (event.event.type === "turn_failed") {
2196
+ hasStarted = true;
2197
+ terminalStatusOverride = "error";
2198
+ return;
2199
+ }
2200
+ if (event.event.type === "turn_completed") {
2201
+ hasStarted = true;
2202
+ }
2203
+ if (event.event.type === "turn_canceled") {
2204
+ hasStarted = true;
2205
+ }
2206
+ }
2207
+ }, { agentId, replayState: true });
2208
+ });
2209
+ }
2210
+ async registerSession(session, config, agentId, options) {
2211
+ const resolvedAgentId = validateAgentId(agentId, "registerSession");
2212
+ if (this.agents.has(resolvedAgentId)) {
2213
+ throw new Error(`Agent with id ${resolvedAgentId} already exists`);
2214
+ }
2215
+ const initialPersistedTitle = await this.resolveInitialPersistedTitle(resolvedAgentId, config, options?.initialTitle ?? null);
2216
+ const now = new Date();
2217
+ const { durableTimelineHasRows } = await this.initializeAgentTimelineForRegister({
2218
+ agentId: resolvedAgentId,
2219
+ now,
2220
+ options,
2221
+ });
2222
+ const managed = this.buildManagedAgentForRegister({
2223
+ resolvedAgentId,
2224
+ session,
2225
+ config,
2226
+ now,
2227
+ durableTimelineHasRows,
2228
+ options,
2229
+ });
2230
+ this.agents.set(resolvedAgentId, managed);
2231
+ // Initialize previousStatus to track transitions
2232
+ this.previousStatuses.set(resolvedAgentId, managed.lifecycle);
2233
+ await this.refreshRuntimeInfo(managed, {
2234
+ emit: !options?.publishWhenReady,
2235
+ });
2236
+ await this.persistSnapshot(managed, {
2237
+ title: initialPersistedTitle,
2238
+ });
2239
+ if (!options?.publishWhenReady) {
2240
+ this.emitState(managed, { persist: false });
2241
+ }
2242
+ await this.refreshSessionState(managed, {
2243
+ emit: !options?.publishWhenReady,
2244
+ });
2245
+ managed.lifecycle = "idle";
2246
+ await this.persistSnapshot(managed);
2247
+ this.emitState(managed, { persist: false });
2248
+ this.subscribeToSession(managed);
2249
+ return { ...managed };
2250
+ }
2251
+ async initializeAgentTimelineForRegister(params) {
2252
+ const { agentId, now, options } = params;
2253
+ const explicitTimelineSeed = buildExplicitTimelineSeedForRegister(now, options);
2254
+ const shouldSeedFromDurable = !explicitTimelineSeed &&
2255
+ !this.timelineStore.has(agentId) &&
2256
+ this.durableTimelineStore !== undefined;
2257
+ const durableTimelineSeed = shouldSeedFromDurable
2258
+ ? await this.loadCommittedTimelineSeed(agentId, now)
2259
+ : null;
2260
+ const durableTimelineHasRows = durableTimelineSeed != null && (durableTimelineSeed.nextSeq ?? 1) > 1;
2261
+ const timelineSeed = explicitTimelineSeed ?? durableTimelineSeed;
2262
+ if (timelineSeed || !this.timelineStore.has(agentId)) {
2263
+ this.timelineStore.initialize(agentId, timelineSeed ?? { timestamp: now.toISOString() });
2264
+ }
2265
+ if (options?.timelineRows?.length) {
2266
+ this.enqueueDurableTimelineBulkInsert(agentId, options.timelineRows);
2267
+ }
2268
+ return { durableTimelineHasRows };
2269
+ }
2270
+ buildManagedAgentForRegister(params) {
2271
+ const { resolvedAgentId, session, config, now, durableTimelineHasRows, options } = params;
2272
+ return {
2273
+ id: resolvedAgentId,
2274
+ provider: config.provider,
2275
+ cwd: config.cwd,
2276
+ workspaceId: options?.workspaceId,
2277
+ session,
2278
+ capabilities: session.capabilities,
2279
+ config,
2280
+ runtimeInfo: undefined,
2281
+ lifecycle: "initializing",
2282
+ createdAt: options?.createdAt ?? now,
2283
+ updatedAt: options?.updatedAt ?? now,
2284
+ availableModes: [],
2285
+ currentModeId: null,
2286
+ pendingPermissions: new Map(),
2287
+ bufferedPermissionResolutions: new Map(),
2288
+ inFlightPermissionResponses: new Set(),
2289
+ pendingReplacement: false,
2290
+ activeForegroundTurnId: null,
2291
+ foregroundTurnWaiters: new Set(),
2292
+ finalizedForegroundTurnIds: new Set(),
2293
+ unsubscribeSession: null,
2294
+ persistence: attachPersistenceCwd(options?.persistence ?? session.describePersistence(), config.cwd),
2295
+ historyPrimed: options?.historyPrimed ?? durableTimelineHasRows,
2296
+ lastUserMessageAt: options?.lastUserMessageAt ?? null,
2297
+ lastUsage: options?.lastUsage,
2298
+ lastError: options?.lastError,
2299
+ attention: resolveInitialAttention(options?.attention),
2300
+ internal: config.internal ?? false,
2301
+ labels: options?.labels ?? {},
2302
+ digest: options?.digest,
2303
+ };
2304
+ }
2305
+ async loadCommittedTimelineSeed(agentId, now) {
2306
+ if (!this.durableTimelineStore) {
2307
+ return { timestamp: now.toISOString() };
2308
+ }
2309
+ return {
2310
+ nextSeq: (await this.durableTimelineStore.getLatestCommittedSeq(agentId)) + 1,
2311
+ timestamp: now.toISOString(),
2312
+ };
2313
+ }
2314
+ prepareAgentForClosure(agent, cancelReason) {
2315
+ this.agentStreamCoalescer.flushAndDiscard(agent.id);
2316
+ this.agents.delete(agent.id);
2317
+ this.previousStatuses.delete(agent.id);
2318
+ if (agent.unsubscribeSession) {
2319
+ agent.unsubscribeSession();
2320
+ agent.unsubscribeSession = null;
2321
+ }
2322
+ this.foregroundRuns.cancelWaiters(agent, (turnId) => ({
2323
+ type: "turn_canceled",
2324
+ provider: agent.provider,
2325
+ reason: cancelReason,
2326
+ turnId,
2327
+ }));
2328
+ this.foregroundRuns.settlePendingRun(agent.id);
2329
+ return {
2330
+ ...agent,
2331
+ lifecycle: "closed",
2332
+ session: null,
2333
+ activeForegroundTurnId: null,
2334
+ };
2335
+ }
2336
+ emitClosedAgent(agent, options) {
2337
+ this.emitState(agent, options);
2338
+ }
2339
+ subscribeToSession(agent) {
2340
+ if (agent.unsubscribeSession) {
2341
+ return;
2342
+ }
2343
+ const agentId = agent.id;
2344
+ const unsubscribe = agent.session.subscribe((event) => {
2345
+ this.enqueueSessionEvent(agentId, event);
2346
+ });
2347
+ agent.unsubscribeSession = unsubscribe;
2348
+ }
2349
+ enqueueSessionEvent(agentId, event) {
2350
+ this.logger.trace({
2351
+ agentId,
2352
+ provider: event.provider,
2353
+ sessionId: this.agents.get(agentId)?.persistence?.sessionId ?? undefined,
2354
+ turnId: getAgentStreamEventTurnId(event),
2355
+ event,
2356
+ }, "agent.manager.enqueue");
2357
+ const previous = this.sessionEventTails.get(agentId) ?? Promise.resolve();
2358
+ const next = previous
2359
+ .catch(() => undefined)
2360
+ .then(async () => {
2361
+ const current = this.agents.get(agentId);
2362
+ if (!current) {
2363
+ return;
2364
+ }
2365
+ if (current.session == null) {
2366
+ return;
2367
+ }
2368
+ this.logger.trace({
2369
+ agentId,
2370
+ provider: event.provider,
2371
+ sessionId: current.persistence?.sessionId ?? undefined,
2372
+ turnId: getAgentStreamEventTurnId(event),
2373
+ event,
2374
+ }, "agent.manager.dequeue");
2375
+ await this.dispatchSessionEvent(current, event);
2376
+ return;
2377
+ })
2378
+ .catch((err) => {
2379
+ this.logger.error({ err, agentId, eventType: event.type }, "Failed to process session event");
2380
+ });
2381
+ this.sessionEventTails.set(agentId, next);
2382
+ this.trackBackgroundTask(next);
2383
+ void next.finally(() => {
2384
+ if (this.sessionEventTails.get(agentId) === next) {
2385
+ this.sessionEventTails.delete(agentId);
2386
+ }
2387
+ });
2388
+ }
2389
+ async dispatchSessionEvent(agent, event) {
2390
+ const turnId = getAgentStreamEventTurnId(event);
2391
+ const matchingWaiters = this.foregroundRuns.getMatchingWaiters(agent, turnId);
2392
+ this.logger.trace({
2393
+ agentId: agent.id,
2394
+ provider: event.provider,
2395
+ sessionId: agent.persistence?.sessionId ?? undefined,
2396
+ turnId,
2397
+ matchingWaiterCount: matchingWaiters.length,
2398
+ event,
2399
+ }, "agent.manager.dispatch_session_event");
2400
+ const shouldNotifyWaiters = await this.handleStreamEvent(agent, event);
2401
+ if (!shouldNotifyWaiters) {
2402
+ return;
2403
+ }
2404
+ this.foregroundRuns.notifyWaiters(matchingWaiters, event, {
2405
+ terminal: isTurnTerminalEvent(event),
2406
+ });
2407
+ this.logger.trace({
2408
+ agentId: agent.id,
2409
+ provider: event.provider,
2410
+ sessionId: agent.persistence?.sessionId ?? undefined,
2411
+ turnId,
2412
+ notifiedWaiterCount: matchingWaiters.length,
2413
+ terminal: isTurnTerminalEvent(event),
2414
+ event,
2415
+ }, "agent.manager.notify_waiters");
2416
+ }
2417
+ async resolveInitialPersistedTitle(agentId, config, fallbackTitle) {
2418
+ const existing = await this.registry?.get(agentId);
2419
+ if (existing) {
2420
+ return existing.title ?? null;
2421
+ }
2422
+ const explicitTitle = typeof config.title === "string" && config.title.trim().length > 0
2423
+ ? config.title.trim()
2424
+ : null;
2425
+ return explicitTitle ?? fallbackTitle;
2426
+ }
2427
+ async persistSnapshot(agent, options) {
2428
+ if (!this.registry) {
2429
+ return;
2430
+ }
2431
+ // Don't persist internal agents - they're ephemeral system tasks
2432
+ if (agent.internal) {
2433
+ return;
2434
+ }
2435
+ await this.registry.applySnapshot(agent, options);
2436
+ }
2437
+ requireRegistry() {
2438
+ if (!this.registry) {
2439
+ throw new Error("Agent storage unavailable");
2440
+ }
2441
+ return this.registry;
2442
+ }
2443
+ async refreshSessionState(agent, options) {
2444
+ try {
2445
+ const modes = await agent.session.getAvailableModes();
2446
+ agent.availableModes = modes;
2447
+ }
2448
+ catch {
2449
+ agent.availableModes = [];
2450
+ }
2451
+ try {
2452
+ agent.currentModeId = await agent.session.getCurrentMode();
2453
+ }
2454
+ catch {
2455
+ agent.currentModeId = null;
2456
+ }
2457
+ try {
2458
+ const pending = agent.session.getPendingPermissions();
2459
+ agent.pendingPermissions = new Map(pending.map((request) => [request.id, request]));
2460
+ }
2461
+ catch {
2462
+ agent.pendingPermissions.clear();
2463
+ }
2464
+ this.syncFeaturesFromSession(agent);
2465
+ await this.refreshRuntimeInfo(agent, options);
2466
+ }
2467
+ async refreshRuntimeInfo(agent, options) {
2468
+ try {
2469
+ const newInfo = await agent.session.getRuntimeInfo();
2470
+ const changed = newInfo.model !== agent.runtimeInfo?.model ||
2471
+ newInfo.thinkingOptionId !== agent.runtimeInfo?.thinkingOptionId ||
2472
+ newInfo.sessionId !== agent.runtimeInfo?.sessionId ||
2473
+ newInfo.modeId !== agent.runtimeInfo?.modeId;
2474
+ agent.runtimeInfo = newInfo;
2475
+ if (!agent.persistence && newInfo.sessionId) {
2476
+ agent.persistence = attachPersistenceCwd({ provider: agent.provider, sessionId: newInfo.sessionId }, agent.cwd);
2477
+ }
2478
+ // Emit state if runtimeInfo changed so clients get the updated model
2479
+ if (changed && options?.emit !== false) {
2480
+ this.emitState(agent);
2481
+ }
2482
+ }
2483
+ catch {
2484
+ // Keep existing runtimeInfo if refresh fails.
2485
+ }
2486
+ }
2487
+ async hydrateTimelineFromLegacyProviderHistory(agent, options) {
2488
+ if (agent.historyPrimed && !options?.force) {
2489
+ return;
2490
+ }
2491
+ if (options?.force) {
2492
+ const historyEvents = [];
2493
+ for await (const event of agent.session.streamHistory()) {
2494
+ if (event.type === "timeline") {
2495
+ if (event.item.type === "user_message" && isSystemInjectedEnvelope(event.item.text)) {
2496
+ continue;
2497
+ }
2498
+ historyEvents.push(event);
2499
+ }
2500
+ }
2501
+ this.agentStreamCoalescer.flushAndDiscard(agent.id);
2502
+ await this.deleteCommittedTimeline(agent.id);
2503
+ this.timelineStore.delete(agent.id);
2504
+ this.timelineStore.initialize(agent.id, {
2505
+ timestamp: new Date().toISOString(),
2506
+ });
2507
+ agent.historyPrimed = true;
2508
+ for (const event of historyEvents) {
2509
+ const row = this.recordTimeline(agent.id, event.item, event.timestamp ? { timestamp: event.timestamp } : undefined);
2510
+ if (options?.broadcast) {
2511
+ this.dispatchStream(agent.id, event, {
2512
+ seq: row.seq,
2513
+ epoch: this.timelineStore.getEpoch(agent.id),
2514
+ timestamp: row.timestamp,
2515
+ });
2516
+ }
2517
+ }
2518
+ this.touchUpdatedAt(agent);
2519
+ this.emitState(agent);
2520
+ return;
2521
+ }
2522
+ agent.historyPrimed = true;
2523
+ try {
2524
+ for await (const event of agent.session.streamHistory()) {
2525
+ if (event.type !== "timeline") {
2526
+ continue;
2527
+ }
2528
+ if (event.item.type === "user_message" && isSystemInjectedEnvelope(event.item.text)) {
2529
+ continue;
2530
+ }
2531
+ this.recordTimeline(agent.id, event.item, event.timestamp ? { timestamp: event.timestamp } : undefined);
2532
+ }
2533
+ }
2534
+ catch {
2535
+ // ignore history failures
2536
+ }
2537
+ }
2538
+ notifyForegroundTurnWaiters(agentId, event) {
2539
+ const turnId = getAgentStreamEventTurnId(event);
2540
+ if (turnId == null) {
2541
+ return;
2542
+ }
2543
+ const agent = this.agents.get(agentId);
2544
+ if (!agent) {
2545
+ return;
2546
+ }
2547
+ this.foregroundRuns.notifyAgentWaiters(agent, event);
2548
+ this.logger.trace({
2549
+ agentId,
2550
+ provider: event.provider,
2551
+ sessionId: agent.persistence?.sessionId ?? undefined,
2552
+ turnId,
2553
+ event,
2554
+ }, "agent.manager.notify_waiters.coalesced");
2555
+ }
2556
+ async handleStreamEvent(agent, event, options) {
2557
+ const eventTurnId = getAgentStreamEventTurnId(event);
2558
+ const isForegroundEvent = Boolean(eventTurnId && agent.activeForegroundTurnId === eventTurnId);
2559
+ this.traceHandleStreamEventStart(agent, event, eventTurnId, isForegroundEvent);
2560
+ if (eventTurnId &&
2561
+ isTurnTerminalEvent(event) &&
2562
+ this.foregroundRuns.hasFinalizedTurn(agent, eventTurnId)) {
2563
+ return false;
2564
+ }
2565
+ // Only update timestamp for live events, not history replay
2566
+ if (!options?.fromHistory) {
2567
+ this.touchUpdatedAt(agent);
2568
+ if (this.agentStreamCoalescer.handle(agent.id, event)) {
2569
+ this.traceCoalescerBuffered(agent, event, eventTurnId);
2570
+ return false;
2571
+ }
2572
+ this.agentStreamCoalescer.flushFor(agent.id);
2573
+ }
2574
+ const flags = {
2575
+ shouldDispatchEvent: true,
2576
+ shouldNotifyWaiters: true,
2577
+ };
2578
+ const dispatchPromise = this.dispatchStreamEventByType({
2579
+ agent,
2580
+ event,
2581
+ options,
2582
+ isForegroundEvent,
2583
+ eventTurnId,
2584
+ flags,
2585
+ });
2586
+ if (dispatchPromise) {
2587
+ await dispatchPromise;
2588
+ }
2589
+ if (!options?.fromHistory && isForegroundEvent && isTurnTerminalEvent(event)) {
2590
+ this.finalizeForegroundTurn(agent, eventTurnId);
2591
+ }
2592
+ if (!options?.fromHistory && flags.shouldDispatchEvent) {
2593
+ this.dispatchStream(agent.id, event, {
2594
+ timestamp: new Date().toISOString(),
2595
+ });
2596
+ }
2597
+ this.traceHandleStreamEventEnd(agent, event, eventTurnId, flags);
2598
+ return flags.shouldNotifyWaiters;
2599
+ }
2600
+ traceHandleStreamEventStart(agent, event, turnId, isForegroundEvent) {
2601
+ this.logger.trace({
2602
+ agentId: agent.id,
2603
+ provider: event.provider,
2604
+ sessionId: agent.persistence?.sessionId ?? undefined,
2605
+ turnId,
2606
+ lifecycle: agent.lifecycle,
2607
+ activeForegroundTurnId: agent.activeForegroundTurnId,
2608
+ isForegroundEvent,
2609
+ event,
2610
+ }, "agent.manager.handle_stream_event.start");
2611
+ }
2612
+ traceCoalescerBuffered(agent, event, turnId) {
2613
+ this.logger.trace({
2614
+ agentId: agent.id,
2615
+ provider: event.provider,
2616
+ sessionId: agent.persistence?.sessionId ?? undefined,
2617
+ turnId,
2618
+ event,
2619
+ }, "agent.manager.coalescer.buffer");
2620
+ }
2621
+ traceHandleStreamEventEnd(agent, event, turnId, flags) {
2622
+ this.logger.trace({
2623
+ agentId: agent.id,
2624
+ provider: event.provider,
2625
+ sessionId: agent.persistence?.sessionId ?? undefined,
2626
+ turnId,
2627
+ lifecycle: agent.lifecycle,
2628
+ activeForegroundTurnId: agent.activeForegroundTurnId,
2629
+ shouldDispatchEvent: flags.shouldDispatchEvent,
2630
+ shouldNotifyWaiters: flags.shouldNotifyWaiters,
2631
+ event,
2632
+ }, "agent.manager.handle_stream_event.end");
2633
+ }
2634
+ dispatchStreamEventByType(params) {
2635
+ const { agent, event, options, isForegroundEvent, eventTurnId, flags } = params;
2636
+ switch (event.type) {
2637
+ case "thread_started":
2638
+ this.onStreamThreadStarted(agent);
2639
+ return undefined;
2640
+ case "usage_updated":
2641
+ agent.lastUsage = event.usage;
2642
+ this.emitState(agent);
2643
+ return undefined;
2644
+ case "mode_changed":
2645
+ agent.currentModeId = event.currentModeId;
2646
+ agent.availableModes = event.availableModes;
2647
+ if (agent.runtimeInfo) {
2648
+ agent.runtimeInfo = {
2649
+ ...agent.runtimeInfo,
2650
+ modeId: event.currentModeId,
2651
+ };
2652
+ }
2653
+ flags.shouldDispatchEvent = false;
2654
+ this.emitState(agent);
2655
+ return undefined;
2656
+ case "model_changed":
2657
+ agent.runtimeInfo = event.runtimeInfo;
2658
+ if (!agent.persistence && event.runtimeInfo.sessionId) {
2659
+ agent.persistence = attachPersistenceCwd({
2660
+ provider: agent.provider,
2661
+ sessionId: event.runtimeInfo.sessionId,
2662
+ }, agent.cwd);
2663
+ }
2664
+ agent.currentModeId = event.runtimeInfo.modeId ?? agent.currentModeId;
2665
+ flags.shouldDispatchEvent = false;
2666
+ this.emitState(agent);
2667
+ return undefined;
2668
+ case "thinking_option_changed":
2669
+ if (agent.runtimeInfo) {
2670
+ agent.runtimeInfo = {
2671
+ ...agent.runtimeInfo,
2672
+ thinkingOptionId: event.thinkingOptionId,
2673
+ };
2674
+ }
2675
+ flags.shouldDispatchEvent = false;
2676
+ this.emitState(agent);
2677
+ return undefined;
2678
+ case "timeline":
2679
+ return this.onStreamTimelineEvent({
2680
+ agent,
2681
+ event,
2682
+ options,
2683
+ isForegroundEvent,
2684
+ flags,
2685
+ });
2686
+ case "turn_completed":
2687
+ this.onStreamTurnCompleted({
2688
+ agent,
2689
+ event,
2690
+ eventTurnId,
2691
+ isForegroundEvent,
2692
+ });
2693
+ return undefined;
2694
+ case "turn_failed":
2695
+ return this.onStreamTurnFailed({
2696
+ agent,
2697
+ event,
2698
+ eventTurnId,
2699
+ isForegroundEvent,
2700
+ options,
2701
+ });
2702
+ case "turn_canceled":
2703
+ this.onStreamTurnCanceled({
2704
+ agent,
2705
+ event,
2706
+ eventTurnId,
2707
+ isForegroundEvent,
2708
+ options,
2709
+ });
2710
+ return undefined;
2711
+ case "turn_started":
2712
+ this.onStreamTurnStarted({ agent, eventTurnId, isForegroundEvent });
2713
+ return undefined;
2714
+ case "permission_requested":
2715
+ this.onStreamPermissionRequested(agent, event);
2716
+ return undefined;
2717
+ case "permission_resolved":
2718
+ this.onStreamPermissionResolved({ agent, event, options, flags });
2719
+ return undefined;
2720
+ default:
2721
+ return undefined;
2722
+ }
2723
+ }
2724
+ onStreamThreadStarted(agent) {
2725
+ const previousSessionId = agent.persistence?.sessionId ?? null;
2726
+ const handle = agent.session.describePersistence();
2727
+ if (handle) {
2728
+ agent.persistence = attachPersistenceCwd(handle, agent.cwd);
2729
+ if (agent.persistence?.sessionId !== previousSessionId) {
2730
+ this.emitState(agent);
2731
+ }
2732
+ }
2733
+ void this.refreshRuntimeInfo(agent);
2734
+ }
2735
+ async onStreamTimelineEvent(params) {
2736
+ const { agent, event, options, flags } = params;
2737
+ if (event.item.type === "user_message" && isSystemInjectedEnvelope(event.item.text)) {
2738
+ flags.shouldDispatchEvent = false;
2739
+ flags.shouldNotifyWaiters = false;
2740
+ return;
2741
+ }
2742
+ if (options?.fromHistory) {
2743
+ this.recordTimeline(agent.id, event.item, event.timestamp ? { timestamp: event.timestamp } : undefined);
2744
+ flags.shouldDispatchEvent = false;
2745
+ flags.shouldNotifyWaiters = false;
2746
+ return;
2747
+ }
2748
+ this.recordAndDispatchTimelineItem(agent.id, event.item, event.provider, event.turnId);
2749
+ if (event.item.type === "user_message") {
2750
+ agent.lastUserMessageAt = new Date();
2751
+ this.emitState(agent);
2752
+ }
2753
+ flags.shouldDispatchEvent = false;
2754
+ flags.shouldNotifyWaiters = true;
2755
+ }
2756
+ onStreamTurnCompleted(params) {
2757
+ const { agent, event, eventTurnId, isForegroundEvent } = params;
2758
+ this.logger.trace({
2759
+ agentId: agent.id,
2760
+ provider: agent.provider,
2761
+ sessionId: agent.persistence?.sessionId ?? undefined,
2762
+ turnId: eventTurnId,
2763
+ lifecycle: agent.lifecycle,
2764
+ activeForegroundTurnId: agent.activeForegroundTurnId,
2765
+ }, "agent.manager.turn.completed");
2766
+ agent.lastUsage = event.usage;
2767
+ agent.lastError = undefined;
2768
+ if (!isForegroundEvent && agent.lifecycle !== "idle" && !agent.pendingReplacement) {
2769
+ agent.lifecycle = "idle";
2770
+ this.emitState(agent);
2771
+ }
2772
+ void this.refreshRuntimeInfo(agent);
2773
+ }
2774
+ async onStreamTurnFailed(params) {
2775
+ const { agent, event, eventTurnId, isForegroundEvent, options } = params;
2776
+ this.logger.warn({
2777
+ agentId: agent.id,
2778
+ provider: agent.provider,
2779
+ sessionId: agent.persistence?.sessionId ?? undefined,
2780
+ turnId: eventTurnId,
2781
+ lifecycle: agent.lifecycle,
2782
+ activeForegroundTurnId: agent.activeForegroundTurnId,
2783
+ eventTurnId,
2784
+ error: event.error,
2785
+ code: event.code,
2786
+ diagnostic: event.diagnostic,
2787
+ }, "handleStreamEvent: turn_failed");
2788
+ if (!isForegroundEvent) {
2789
+ agent.lifecycle = "error";
2790
+ }
2791
+ agent.lastError = event.error;
2792
+ await this.appendSystemErrorTimelineMessage(agent, event.provider, this.formatTurnFailedMessage(event), options);
2793
+ this.resolvePendingPermissionsForAgent(agent, event.provider, options, "Turn failed");
2794
+ if (!isForegroundEvent) {
2795
+ this.emitState(agent);
2796
+ }
2797
+ }
2798
+ onStreamTurnCanceled(params) {
2799
+ const { agent, event, eventTurnId, isForegroundEvent, options } = params;
2800
+ this.logger.trace({
2801
+ agentId: agent.id,
2802
+ provider: agent.provider,
2803
+ sessionId: agent.persistence?.sessionId ?? undefined,
2804
+ turnId: eventTurnId,
2805
+ lifecycle: agent.lifecycle,
2806
+ activeForegroundTurnId: agent.activeForegroundTurnId,
2807
+ eventTurnId,
2808
+ }, "agent.manager.turn.canceled");
2809
+ if (!isForegroundEvent && !agent.pendingReplacement) {
2810
+ agent.lifecycle = "idle";
2811
+ }
2812
+ agent.lastError = undefined;
2813
+ this.resolvePendingPermissionsForAgent(agent, event.provider, options, "Interrupted");
2814
+ if (!isForegroundEvent) {
2815
+ this.emitState(agent);
2816
+ }
2817
+ }
2818
+ onStreamTurnStarted(params) {
2819
+ const { agent, eventTurnId, isForegroundEvent } = params;
2820
+ this.logger.trace({
2821
+ agentId: agent.id,
2822
+ provider: agent.provider,
2823
+ sessionId: agent.persistence?.sessionId ?? undefined,
2824
+ turnId: eventTurnId,
2825
+ lifecycle: agent.lifecycle,
2826
+ activeForegroundTurnId: agent.activeForegroundTurnId,
2827
+ }, "agent.manager.turn.started");
2828
+ if (!isForegroundEvent) {
2829
+ agent.lifecycle = "running";
2830
+ this.emitState(agent);
2831
+ }
2832
+ }
2833
+ onStreamPermissionRequested(agent, event) {
2834
+ const hadPendingPermissions = agent.pendingPermissions.size > 0;
2835
+ agent.pendingPermissions.set(event.request.id, event.request);
2836
+ if (!hadPendingPermissions && !agent.internal) {
2837
+ this.broadcastAgentAttention(agent, "permission");
2838
+ }
2839
+ this.emitState(agent);
2840
+ }
2841
+ onStreamPermissionResolved(params) {
2842
+ const { agent, event, options, flags } = params;
2843
+ agent.pendingPermissions.delete(event.requestId);
2844
+ if (!options?.fromHistory && agent.inFlightPermissionResponses.has(event.requestId)) {
2845
+ agent.bufferedPermissionResolutions.set(event.requestId, event);
2846
+ flags.shouldDispatchEvent = false;
2847
+ return;
2848
+ }
2849
+ this.emitState(agent);
2850
+ }
2851
+ resolvePendingPermissionsForAgent(agent, provider, options, message) {
2852
+ for (const [requestId] of agent.pendingPermissions) {
2853
+ agent.pendingPermissions.delete(requestId);
2854
+ if (!options?.fromHistory) {
2855
+ this.dispatchStream(agent.id, {
2856
+ type: "permission_resolved",
2857
+ provider,
2858
+ requestId,
2859
+ resolution: { behavior: "deny", message },
2860
+ });
2861
+ }
2862
+ }
2863
+ }
2864
+ recordAndDispatchTimelineItem(agentId, item, provider, turnId) {
2865
+ const row = this.recordTimeline(agentId, item);
2866
+ const event = {
2867
+ type: "timeline",
2868
+ item,
2869
+ provider,
2870
+ ...(turnId !== undefined ? { turnId } : {}),
2871
+ };
2872
+ this.dispatchStream(agentId, event, {
2873
+ seq: row.seq,
2874
+ epoch: this.timelineStore.getEpoch(agentId),
2875
+ timestamp: row.timestamp,
2876
+ });
2877
+ if (item.type === "tool_call" &&
2878
+ item.status === "completed" &&
2879
+ item.detail?.type === "shell" &&
2880
+ commandMayHaveChangedExternalState(item.detail.command)) {
2881
+ const agent = this.agents.get(agentId);
2882
+ if (agent) {
2883
+ this.onWorkspaceStateMayHaveChanged?.({ cwd: agent.cwd });
2884
+ }
2885
+ }
2886
+ return event;
2887
+ }
2888
+ async appendSystemErrorTimelineMessage(agent, provider, message, options) {
2889
+ if (options?.fromHistory) {
2890
+ return;
2891
+ }
2892
+ const normalized = message.trim();
2893
+ if (!normalized) {
2894
+ return;
2895
+ }
2896
+ const text = `${SYSTEM_ERROR_PREFIX} ${normalized}`;
2897
+ const lastItem = await this.getLastItemFromStores(agent.id);
2898
+ if (lastItem?.type === "assistant_message" && lastItem.text === text) {
2899
+ return;
2900
+ }
2901
+ const item = { type: "assistant_message", text };
2902
+ const row = this.recordTimeline(agent.id, item);
2903
+ this.dispatchStream(agent.id, {
2904
+ type: "timeline",
2905
+ item,
2906
+ provider,
2907
+ }, {
2908
+ seq: row.seq,
2909
+ epoch: this.timelineStore.getEpoch(agent.id),
2910
+ timestamp: row.timestamp,
2911
+ });
2912
+ }
2913
+ formatTurnFailedMessage(event) {
2914
+ const base = event.error.trim();
2915
+ const parts = [base.length > 0 ? base : "Provider run failed"];
2916
+ const code = event.code?.trim();
2917
+ if (code) {
2918
+ parts.push(`code: ${code}`);
2919
+ }
2920
+ const diagnostic = event.diagnostic?.trim();
2921
+ if (diagnostic && diagnostic !== base) {
2922
+ parts.push(diagnostic);
2923
+ }
2924
+ return parts.join("\n\n");
2925
+ }
2926
+ recordTimeline(agentId, item, options) {
2927
+ const row = this.timelineStore.append(agentId, item, options);
2928
+ this.enqueueDurableTimelineAppend(agentId, row);
2929
+ return row;
2930
+ }
2931
+ emitState(agent, options) {
2932
+ // Keep attention as an edge-triggered unread signal, not a level signal.
2933
+ this.checkAndSetAttention(agent);
2934
+ if (options?.persist !== false) {
2935
+ this.enqueueBackgroundPersist(agent);
2936
+ }
2937
+ this.syncFeaturesFromSession(agent);
2938
+ this.logger.trace({
2939
+ agentId: agent.id,
2940
+ provider: agent.provider,
2941
+ sessionId: agent.persistence?.sessionId ?? undefined,
2942
+ turnId: agent.activeForegroundTurnId ?? undefined,
2943
+ lifecycle: agent.lifecycle,
2944
+ activeForegroundTurnId: agent.activeForegroundTurnId,
2945
+ pendingPermissions: agent.pendingPermissions.size,
2946
+ persist: options?.persist !== false,
2947
+ }, "agent.manager.emit_state");
2948
+ this.dispatch({
2949
+ type: "agent_state",
2950
+ agent: { ...agent },
2951
+ });
2952
+ }
2953
+ syncFeaturesFromSession(agent) {
2954
+ if ("session" in agent && agent.session?.features) {
2955
+ agent.features = agent.session.features;
2956
+ }
2957
+ }
2958
+ /**
2959
+ * Live background work owned by this agent: monitors, crons, and backgrounded
2960
+ * shells the provider is still tracking. Mirrors what `agent-projections`
2961
+ * publishes as `activeBackgroundTaskCount`, read through the same optional
2962
+ * hook so providers that do not implement it simply report zero.
2963
+ */
2964
+ getActiveBackgroundTaskCount(agent) {
2965
+ if (!("session" in agent)) {
2966
+ return 0;
2967
+ }
2968
+ return agent.session?.getActiveBackgroundTaskCount?.() ?? 0;
2969
+ }
2970
+ checkAndSetAttention(agent) {
2971
+ const previousStatus = this.previousStatuses.get(agent.id);
2972
+ const currentStatus = agent.lifecycle;
2973
+ // Track the new status
2974
+ this.previousStatuses.set(agent.id, currentStatus);
2975
+ // Skip attention tracking for internal agents
2976
+ if (agent.internal) {
2977
+ return;
2978
+ }
2979
+ // Skip if already requires attention
2980
+ if (agent.attention.requiresAttention) {
2981
+ return;
2982
+ }
2983
+ // Check if agent transitioned from running to idle (finished)
2984
+ if (previousStatus === "running" && currentStatus === "idle") {
2985
+ // ...but "the lifecycle went running -> idle" is NOT the same fact as
2986
+ // "this agent is finished and wants you".
2987
+ //
2988
+ // A monitor tick, a cron firing, or a background shell reporting progress
2989
+ // all WAKE the session: status goes idle -> running, the agent prints a
2990
+ // progress line ("1/12 done, I'll let you know"), the turn ends, and the
2991
+ // lifecycle settles back to idle. Under the old rule that transition set
2992
+ // requiresAttention="finished" on EVERY tick, which lit the Unread chip,
2993
+ // the dock badge and a push notification for output nobody needs to act
2994
+ // on. With several sessions in parallel that made Unread — the one chip
2995
+ // you actually watch — useless.
2996
+ //
2997
+ // So: if the agent still owns armed background work, the turn ending is a
2998
+ // progress beat, not a handoff. Stay quiet and let the bucket derivation
2999
+ // surface it as "pending" (alive, will come back on its own) instead.
3000
+ //
3001
+ // "Stay quiet" means DO NOT PUSH. It does not mean forget. The flag is
3002
+ // recorded either way, and only `broadcastAgentAttention` (push, dock
3003
+ // badge) is withheld, because `deriveAgentStateBucket` already checks
3004
+ // `activeChildCount` BEFORE `requiresAttention` and therefore renders an
3005
+ // agent with armed work as `pending` no matter what the flag says.
3006
+ //
3007
+ // Not setting the flag was a silent data loss. `attention` is
3008
+ // edge-triggered and one-shot (the `requiresAttention` early return
3009
+ // above), and nothing re-runs this check when the background work later
3010
+ // retires - so a suppressed finish was never recoverable and the session
3011
+ // fell to `done` forever. Recording it lets the SAME bucket ladder
3012
+ // promote `pending` to `attention` the moment the last task retires, with
3013
+ // no second trigger needed.
3014
+ //
3015
+ // KNOWN GAP, deliberately named rather than silently accepted: a turn that
3016
+ // ends with the agent asking a real question in PROSE (not a permission
3017
+ // request, which still routes through needs_input and is unaffected) is
3018
+ // also suppressed while background work is armed. Prose questions are not
3019
+ // machine-detectable here. The counter below exists so that gap is
3020
+ // MEASURED rather than assumed — feed it to the Jarvis judge in shadow
3021
+ // mode (PASEO_JARVIS_SHADOW=1) to size the real distribution before
3022
+ // deciding whether it needs rescuing.
3023
+ const activeBackgroundTaskCount = this.getActiveBackgroundTaskCount(agent);
3024
+ // Log the DECISION, not just the suppression. The previous version logged
3025
+ // only the suppressed branch, so "never fired" and "fires correctly, just
3026
+ // rarely" produced byte-identical journals — which is how a broken
3027
+ // suppression survived a release looking healthy. An always-on line makes
3028
+ // the count visible at the exact moment it is read:
3029
+ // journalctl -u paseo.service | grep "finished-attention decision"
3030
+ this.logger.info({
3031
+ agentId: agent.id,
3032
+ activeBackgroundTaskCount,
3033
+ decision: activeBackgroundTaskCount > 0 ? "set-attention-quietly" : "set-attention",
3034
+ hasSession: "session" in agent && agent.session != null,
3035
+ hasGetter: typeof agent.session
3036
+ ?.getActiveBackgroundTaskCount === "function",
3037
+ }, "finished-attention decision");
3038
+ agent.attention = {
3039
+ requiresAttention: true,
3040
+ attentionReason: "finished",
3041
+ attentionTimestamp: new Date(),
3042
+ };
3043
+ if (activeBackgroundTaskCount > 0) {
3044
+ agent.suppressedAttentionCount = (agent.suppressedAttentionCount ?? 0) + 1;
3045
+ // info, not debug: this is the ONLY production signal that the
3046
+ // suppression fired. The daemon logs at level 30 and emits zero debug
3047
+ // lines, so at debug this was unobservable — and an absent log then
3048
+ // looked identical to a working feature. Verify with:
3049
+ // journalctl -u paseo.service | grep "Suppressed finished-attention"
3050
+ this.logger.info({
3051
+ agentId: agent.id,
3052
+ activeBackgroundTaskCount,
3053
+ suppressedAttentionCount: agent.suppressedAttentionCount,
3054
+ }, "Quiet finished-attention: flag recorded, push suppressed while background work is armed");
3055
+ return;
3056
+ }
3057
+ this.broadcastAgentAttention(agent, "finished");
3058
+ return;
3059
+ }
3060
+ // Check if agent entered error state
3061
+ if (previousStatus !== "error" && currentStatus === "error") {
3062
+ agent.attention = {
3063
+ requiresAttention: true,
3064
+ attentionReason: "error",
3065
+ attentionTimestamp: new Date(),
3066
+ };
3067
+ this.broadcastAgentAttention(agent, "error");
3068
+ return;
3069
+ }
3070
+ }
3071
+ enqueueBackgroundPersist(agent) {
3072
+ const task = this.persistSnapshot(agent).catch((err) => {
3073
+ this.logger.error({ err, agentId: agent.id }, "Failed to persist agent snapshot");
3074
+ });
3075
+ this.trackBackgroundTask(task);
3076
+ }
3077
+ enqueueDurableTimelineAppend(agentId, row) {
3078
+ if (!this.durableTimelineStore) {
3079
+ return;
3080
+ }
3081
+ const task = this.durableTimelineStore
3082
+ .bulkInsert(agentId, [row])
3083
+ .then(() => undefined)
3084
+ .catch((err) => {
3085
+ this.logger.error({ err, agentId, seq: row.seq, itemType: row.item.type }, "Failed to append timeline row to durable store");
3086
+ });
3087
+ this.trackBackgroundTask(task);
3088
+ }
3089
+ enqueueDurableTimelineBulkInsert(agentId, rows) {
3090
+ if (!this.durableTimelineStore || rows.length === 0) {
3091
+ return;
3092
+ }
3093
+ const task = this.durableTimelineStore.bulkInsert(agentId, rows).catch((err) => {
3094
+ this.logger.error({ err, agentId, rowCount: rows.length }, "Failed to seed durable timeline store");
3095
+ });
3096
+ this.trackBackgroundTask(task);
3097
+ }
3098
+ trackBackgroundTask(task) {
3099
+ this.backgroundTasks.add(task);
3100
+ void task.finally(() => {
3101
+ this.backgroundTasks.delete(task);
3102
+ });
3103
+ }
3104
+ /**
3105
+ * Flush any background persistence work (best-effort).
3106
+ * Used by daemon shutdown paths to avoid unhandled rejections after cleanup.
3107
+ */
3108
+ async flush() {
3109
+ this.agentStreamCoalescer.flushAll();
3110
+ // Drain tasks, including tasks spawned while awaiting.
3111
+ while (this.backgroundTasks.size > 0) {
3112
+ const pending = Array.from(this.backgroundTasks);
3113
+ await Promise.allSettled(pending);
3114
+ }
3115
+ }
3116
+ broadcastAgentAttention(agent, reason) {
3117
+ if (isDelegatedAgent(agent)) {
3118
+ return;
3119
+ }
3120
+ if (this.attentionListeners.size === 0) {
3121
+ return;
3122
+ }
3123
+ const params = {
3124
+ agentId: agent.id,
3125
+ provider: agent.provider,
3126
+ reason,
3127
+ };
3128
+ for (const listener of this.attentionListeners) {
3129
+ try {
3130
+ listener(params);
3131
+ }
3132
+ catch (err) {
3133
+ this.logger.warn({ err, agentId: agent.id }, "Attention listener threw");
3134
+ }
3135
+ }
3136
+ }
3137
+ dispatchStream(agentId, event, metadata) {
3138
+ const agent = this.agents.get(agentId);
3139
+ this.logger.trace({
3140
+ agentId,
3141
+ provider: event.provider,
3142
+ sessionId: agent?.persistence?.sessionId ?? undefined,
3143
+ turnId: getAgentStreamEventTurnId(event),
3144
+ metadata,
3145
+ event,
3146
+ }, "agent.manager.dispatch_stream");
3147
+ this.dispatch({ type: "agent_stream", agentId, event, ...metadata });
3148
+ }
3149
+ dispatch(event) {
3150
+ for (const subscriber of this.subscribers) {
3151
+ if (subscriber.agentId &&
3152
+ event.type === "agent_stream" &&
3153
+ subscriber.agentId !== event.agentId) {
3154
+ continue;
3155
+ }
3156
+ if (subscriber.agentId &&
3157
+ event.type === "agent_state" &&
3158
+ subscriber.agentId !== event.agent.id) {
3159
+ continue;
3160
+ }
3161
+ // Skip internal agents for global subscribers (those without a specific agentId)
3162
+ if (!subscriber.agentId) {
3163
+ if (event.type === "agent_state" && event.agent.internal) {
3164
+ continue;
3165
+ }
3166
+ if (event.type === "agent_stream") {
3167
+ const agent = this.agents.get(event.agentId);
3168
+ if (agent?.internal) {
3169
+ continue;
3170
+ }
3171
+ }
3172
+ }
3173
+ subscriber.callback(event);
3174
+ }
3175
+ }
3176
+ async normalizeConfig(config, options = {}) {
3177
+ const normalized = { ...config };
3178
+ // Always resolve cwd to absolute path for consistent history file lookup
3179
+ if (normalized.cwd) {
3180
+ normalized.cwd = resolve(normalized.cwd);
3181
+ try {
3182
+ const cwdStats = await stat(normalized.cwd);
3183
+ if (!cwdStats.isDirectory()) {
3184
+ throw new Error(`Working directory is not a directory: ${normalized.cwd}`);
3185
+ }
3186
+ }
3187
+ catch (error) {
3188
+ if (error instanceof Error &&
3189
+ "code" in error &&
3190
+ error.code === "ENOENT") {
3191
+ throw new Error(`Working directory does not exist: ${normalized.cwd}`, { cause: error });
3192
+ }
3193
+ if (error instanceof Error) {
3194
+ throw error;
3195
+ }
3196
+ throw new Error(`Failed to access working directory: ${normalized.cwd}`, { cause: error });
3197
+ }
3198
+ }
3199
+ if (typeof normalized.model === "string") {
3200
+ const trimmed = normalized.model.trim();
3201
+ normalized.model = trimmed.length > 0 && trimmed !== "default" ? trimmed : undefined;
3202
+ }
3203
+ const shouldResolveDefaultModel = options.resolveDefaultModel ?? true;
3204
+ if (shouldResolveDefaultModel && !normalized.model) {
3205
+ const defaultModelId = await this.resolveDefaultModelId(normalized);
3206
+ if (defaultModelId) {
3207
+ normalized.model = defaultModelId;
3208
+ }
3209
+ }
3210
+ if (!normalized.modeId) {
3211
+ try {
3212
+ normalized.modeId =
3213
+ getAgentProviderDefinition(normalized.provider).defaultModeId ?? undefined;
3214
+ }
3215
+ catch {
3216
+ // Unknown provider
3217
+ }
3218
+ }
3219
+ return normalized;
3220
+ }
3221
+ async resolveDefaultModelId(config) {
3222
+ const client = this.clients.get(config.provider);
3223
+ if (!client) {
3224
+ return undefined;
3225
+ }
3226
+ try {
3227
+ const catalog = await client.fetchCatalog({
3228
+ scope: "workspace",
3229
+ cwd: config.cwd,
3230
+ force: false,
3231
+ });
3232
+ return (catalog.models.find((model) => model.isDefault) ?? catalog.models[0])?.id;
3233
+ }
3234
+ catch {
3235
+ // Provider may not support model listing — leave model undefined.
3236
+ return undefined;
3237
+ }
3238
+ }
3239
+ async prepareSessionConfig(config, agentId) {
3240
+ const storedConfig = await this.normalizeConfig(stripInternalPaseoMcpServer(config));
3241
+ const launchConfig = this.applyDaemonAppendSystemPrompt(withRuntimePaseoMcpServer({
3242
+ config: storedConfig,
3243
+ agentId,
3244
+ mcpBaseUrl: this.mcpBaseUrl,
3245
+ mcpAuthToken: this.mcpAuthToken,
3246
+ }));
3247
+ return { storedConfig, launchConfig };
3248
+ }
3249
+ applyDaemonAppendSystemPrompt(config) {
3250
+ const daemonAppendSystemPrompt = this.appendSystemPrompt.trim();
3251
+ const next = { ...config };
3252
+ delete next.daemonAppendSystemPrompt;
3253
+ return daemonAppendSystemPrompt
3254
+ ? {
3255
+ ...next,
3256
+ daemonAppendSystemPrompt,
3257
+ }
3258
+ : next;
3259
+ }
3260
+ async buildLaunchContext(agentId, client, env) {
3261
+ const context = {
3262
+ agentId,
3263
+ env: {
3264
+ ...env,
3265
+ PASEO_AGENT_ID: agentId,
3266
+ },
3267
+ };
3268
+ if (this.paseoToolsEnabled &&
3269
+ client.capabilities.supportsNativePaseoTools &&
3270
+ this.paseoToolCatalogFactory) {
3271
+ context.paseoTools = await this.paseoToolCatalogFactory({
3272
+ callerAgentId: agentId,
3273
+ });
3274
+ }
3275
+ return context;
3276
+ }
3277
+ resolveProviderLaunchConfig(launchConfig, launchContext) {
3278
+ return launchContext.paseoTools ? stripInternalPaseoMcpServer(launchConfig) : launchConfig;
3279
+ }
3280
+ async requireAvailableClient(options) {
3281
+ const client = this.clients.get(options.provider);
3282
+ if (!client) {
3283
+ const configuredProviders = this.getConfiguredProviderIds();
3284
+ throw new Error(`Unknown provider '${options.provider}'. Configured providers: ${formatProviderList(configuredProviders)}.`);
3285
+ }
3286
+ let unavailableReason = null;
3287
+ try {
3288
+ const available = await client.isAvailable();
3289
+ if (available) {
3290
+ return client;
3291
+ }
3292
+ }
3293
+ catch (error) {
3294
+ unavailableReason = error instanceof Error ? error.message : String(error);
3295
+ }
3296
+ const availableProviders = (await this.listProviderAvailability())
3297
+ .filter((entry) => entry.available)
3298
+ .map((entry) => entry.provider);
3299
+ const providerList = formatProviderList(availableProviders);
3300
+ const reason = unavailableReason ? ` Reason: ${unavailableReason}.` : "";
3301
+ throw new Error(`Provider '${options.provider}' is not available.${reason} Available providers: ${providerList}. Use one of those providers, or install/configure '${options.provider}'.`);
3302
+ }
3303
+ requireEnabledProvider(provider) {
3304
+ if (this.providerEnabled.get(provider) === false) {
3305
+ throw new Error(`Provider '${provider}' is disabled`);
3306
+ }
3307
+ }
3308
+ getConfiguredProviderIds() {
3309
+ return Array.from(new Set([...this.providerEnabled.keys(), ...this.clients.keys()]));
3310
+ }
3311
+ requireClient(provider) {
3312
+ const client = this.clients.get(provider);
3313
+ if (!client) {
3314
+ throw new Error(`No client registered for provider '${provider}'`);
3315
+ }
3316
+ return client;
3317
+ }
3318
+ async archiveNativeSessionBestEffort(provider, persistence) {
3319
+ if (!persistence)
3320
+ return;
3321
+ const client = this.clients.get(provider);
3322
+ if (!client?.archiveNativeSession)
3323
+ return;
3324
+ try {
3325
+ await client.archiveNativeSession(persistence);
3326
+ }
3327
+ catch (error) {
3328
+ this.logger.warn({ error, provider, sessionId: persistence.sessionId }, "Failed to archive native session (best-effort)");
3329
+ }
3330
+ }
3331
+ async unarchiveNativeSession(provider, persistence) {
3332
+ if (!persistence)
3333
+ return;
3334
+ const client = this.clients.get(provider);
3335
+ if (!client?.unarchiveNativeSession)
3336
+ return;
3337
+ await client.unarchiveNativeSession(persistence);
3338
+ }
3339
+ requireAgent(id) {
3340
+ const normalizedId = validateAgentId(id, "requireAgent");
3341
+ const agent = this.agents.get(normalizedId);
3342
+ if (!agent) {
3343
+ throw new Error(`Unknown agent '${normalizedId}'`);
3344
+ }
3345
+ return agent;
3346
+ }
3347
+ requireSessionAgent(id) {
3348
+ const agent = this.requireAgent(id);
3349
+ if (agent.session === null) {
3350
+ throw new Error(`Agent '${agent.id}' has no managed session`);
3351
+ }
3352
+ return agent;
3353
+ }
3354
+ }
3355
+ export function commandMayHaveChangedExternalState(command) {
3356
+ const normalized = command.toLowerCase();
3357
+ // Commands that operate on remote state and do NOT trigger local file
3358
+ // watchers. Local git mutations (commit, checkout, merge, rebase, reset,
3359
+ // pull) are already caught by watchers on .git/HEAD and refs/heads/.
3360
+ return (
3361
+ // GitHub PR operations (merge, close, create, edit, comment, review)
3362
+ /\bgh\s+pr\s+(merge|close|create|edit|comment|review)\b/.test(normalized) ||
3363
+ // Pushes to remote — local refs unchanged, but remote state (PR checks,
3364
+ // mergeable status) may shift immediately after.
3365
+ /\bgit\s+push\b/.test(normalized) ||
3366
+ // Fetches update refs/remotes/ which our watchers do not watch, so
3367
+ // ahead/behind counts can drift stale until the next refresh.
3368
+ /\bgit\s+fetch\b/.test(normalized));
3369
+ }
3370
+ //# sourceMappingURL=agent-manager.js.map