aimux-cli 0.1.16 → 0.1.19

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 (357) hide show
  1. package/README.md +184 -67
  2. package/bin/aimux-dev +10 -0
  3. package/dist/agent-events.js +0 -1
  4. package/dist/agent-output-parser.js +0 -1
  5. package/dist/agent-prompt-delivery.js +0 -1
  6. package/dist/agent-tracker.js +0 -1
  7. package/dist/agent-watcher.js +0 -1
  8. package/dist/alert-display.d.ts +21 -0
  9. package/dist/alert-display.js +85 -0
  10. package/dist/atomic-write.js +0 -1
  11. package/dist/attachment-store.d.ts +0 -7
  12. package/dist/attachment-store.js +2 -87
  13. package/dist/builtin-metadata-watchers.js +4 -5
  14. package/dist/claude-hooks.d.ts +1 -0
  15. package/dist/claude-hooks.js +25 -1
  16. package/dist/config.d.ts +19 -13
  17. package/dist/config.js +28 -15
  18. package/dist/connection-targets.d.ts +8 -0
  19. package/dist/connection-targets.js +27 -0
  20. package/dist/context/compactor.js +0 -1
  21. package/dist/context/context-bridge.js +0 -1
  22. package/dist/context/context-file.js +0 -1
  23. package/dist/context/history.js +0 -1
  24. package/dist/credentials.d.ts +12 -0
  25. package/dist/credentials.js +48 -0
  26. package/dist/daemon.d.ts +23 -0
  27. package/dist/daemon.js +391 -67
  28. package/dist/dashboard/command-spec.js +0 -1
  29. package/dist/dashboard/feedback.js +0 -1
  30. package/dist/dashboard/index.d.ts +13 -10
  31. package/dist/dashboard/index.js +3 -27
  32. package/dist/dashboard/operation-failures.js +0 -1
  33. package/dist/dashboard/order.d.ts +22 -0
  34. package/dist/dashboard/order.js +54 -0
  35. package/dist/dashboard/pending-actions.d.ts +39 -10
  36. package/dist/dashboard/pending-actions.js +166 -37
  37. package/dist/dashboard/quick-jump.d.ts +2 -1
  38. package/dist/dashboard/quick-jump.js +7 -5
  39. package/dist/dashboard/runtime-evidence.js +0 -1
  40. package/dist/dashboard/session-actions.d.ts +4 -4
  41. package/dist/dashboard/session-actions.js +1 -2
  42. package/dist/dashboard/session-registry.d.ts +4 -3
  43. package/dist/dashboard/session-registry.js +16 -51
  44. package/dist/dashboard/sort.js +0 -1
  45. package/dist/dashboard/state.d.ts +1 -1
  46. package/dist/dashboard/state.js +0 -1
  47. package/dist/dashboard/targets.js +0 -1
  48. package/dist/dashboard/ui-state-store.d.ts +16 -1
  49. package/dist/dashboard/ui-state-store.js +73 -3
  50. package/dist/debug-state.d.ts +97 -0
  51. package/dist/debug-state.js +540 -0
  52. package/dist/debug.d.ts +38 -0
  53. package/dist/debug.js +219 -16
  54. package/dist/default-plugins/gh-pr-context.d.ts +2 -1
  55. package/dist/default-plugins/gh-pr-context.js +17 -12
  56. package/dist/default-plugins/transcript-length.js +15 -3
  57. package/dist/fast-control.js +37 -20
  58. package/dist/hotkeys.js +0 -1
  59. package/dist/http-client.js +31 -3
  60. package/dist/key-parser.js +0 -1
  61. package/dist/last-used.js +0 -1
  62. package/dist/local-ui-server.d.ts +22 -0
  63. package/dist/local-ui-server.js +185 -0
  64. package/dist/login-flow.d.ts +7 -0
  65. package/dist/login-flow.js +119 -0
  66. package/dist/main.js +821 -152
  67. package/dist/managed-launch-env.js +14 -1
  68. package/dist/metadata-server.d.ts +36 -36
  69. package/dist/metadata-server.js +638 -138
  70. package/dist/metadata-store.d.ts +4 -1
  71. package/dist/metadata-store.js +30 -3
  72. package/dist/multiplexer/agent-io-methods.d.ts +2 -10
  73. package/dist/multiplexer/agent-io-methods.js +12 -44
  74. package/dist/multiplexer/archives.js +8 -10
  75. package/dist/multiplexer/dashboard-actions-methods.js +0 -1
  76. package/dist/multiplexer/dashboard-control.js +45 -14
  77. package/dist/multiplexer/dashboard-interaction.d.ts +8 -2
  78. package/dist/multiplexer/dashboard-interaction.js +187 -29
  79. package/dist/multiplexer/dashboard-model.d.ts +10 -3
  80. package/dist/multiplexer/dashboard-model.js +417 -36
  81. package/dist/multiplexer/dashboard-ops.d.ts +9 -7
  82. package/dist/multiplexer/dashboard-ops.js +178 -69
  83. package/dist/multiplexer/dashboard-state-methods.d.ts +2 -1
  84. package/dist/multiplexer/dashboard-state-methods.js +3 -3
  85. package/dist/multiplexer/dashboard-tail-methods.d.ts +22 -10
  86. package/dist/multiplexer/dashboard-tail-methods.js +164 -48
  87. package/dist/multiplexer/dashboard-view-methods.d.ts +1 -1
  88. package/dist/multiplexer/dashboard-view-methods.js +23 -9
  89. package/dist/multiplexer/graveyard-view-model.d.ts +9 -1
  90. package/dist/multiplexer/graveyard-view-model.js +39 -1
  91. package/dist/multiplexer/index.d.ts +15 -12
  92. package/dist/multiplexer/index.js +64 -44
  93. package/dist/multiplexer/navigation.js +0 -1
  94. package/dist/multiplexer/notifications.js +107 -25
  95. package/dist/multiplexer/persistence-methods.d.ts +31 -4
  96. package/dist/multiplexer/persistence-methods.js +304 -309
  97. package/dist/multiplexer/runtime-lifecycle-methods.d.ts +8 -10
  98. package/dist/multiplexer/runtime-lifecycle-methods.js +104 -87
  99. package/dist/multiplexer/runtime-state.d.ts +8 -10
  100. package/dist/multiplexer/runtime-state.js +82 -146
  101. package/dist/multiplexer/runtime-sync.d.ts +2 -10
  102. package/dist/multiplexer/runtime-sync.js +3 -19
  103. package/dist/multiplexer/service-state-snapshot.d.ts +2 -4
  104. package/dist/multiplexer/service-state-snapshot.js +4 -52
  105. package/dist/multiplexer/services.d.ts +1 -0
  106. package/dist/multiplexer/services.js +55 -6
  107. package/dist/multiplexer/session-capture.d.ts +1 -0
  108. package/dist/multiplexer/session-capture.js +23 -0
  109. package/dist/multiplexer/session-launch.d.ts +4 -1
  110. package/dist/multiplexer/session-launch.js +152 -64
  111. package/dist/multiplexer/session-runtime-core.d.ts +8 -20
  112. package/dist/multiplexer/session-runtime-core.js +40 -136
  113. package/dist/multiplexer/subscreens.js +10 -4
  114. package/dist/multiplexer/tool-picker.js +0 -1
  115. package/dist/multiplexer/worktree-graveyard.d.ts +0 -1
  116. package/dist/multiplexer/worktree-graveyard.js +15 -17
  117. package/dist/multiplexer/worktrees.js +96 -41
  118. package/dist/notification-context.js +8 -5
  119. package/dist/notifications.js +163 -102
  120. package/dist/notify.d.ts +4 -0
  121. package/dist/notify.js +14 -1
  122. package/dist/orchestration-actions.js +0 -1
  123. package/dist/orchestration-routing.js +0 -1
  124. package/dist/orchestration.js +0 -1
  125. package/dist/osc-notifications.js +0 -1
  126. package/dist/paths.d.ts +32 -7
  127. package/dist/paths.js +82 -59
  128. package/dist/pending-actions.d.ts +5 -0
  129. package/dist/pending-actions.js +13 -0
  130. package/dist/plugin-runtime.js +9 -3
  131. package/dist/project-events.d.ts +1 -10
  132. package/dist/project-events.js +0 -11
  133. package/dist/project-scanner.d.ts +2 -3
  134. package/dist/project-scanner.js +58 -130
  135. package/dist/project-service-manifest.d.ts +1 -3
  136. package/dist/project-service-manifest.js +1 -4
  137. package/dist/recency.js +0 -1
  138. package/dist/recorder.js +0 -1
  139. package/dist/relay-client.d.ts +30 -0
  140. package/dist/relay-client.js +190 -0
  141. package/dist/remote-access.d.ts +16 -0
  142. package/dist/remote-access.js +90 -0
  143. package/dist/runtime-core/exchange-derived.d.ts +2 -0
  144. package/dist/runtime-core/exchange-derived.js +153 -0
  145. package/dist/runtime-core/exchange-import.d.ts +24 -0
  146. package/dist/runtime-core/exchange-import.js +317 -0
  147. package/dist/runtime-core/exchange-store.d.ts +157 -0
  148. package/dist/runtime-core/exchange-store.js +452 -0
  149. package/dist/runtime-core/topology-services.d.ts +38 -0
  150. package/dist/runtime-core/topology-services.js +170 -0
  151. package/dist/runtime-core/topology-sessions.d.ts +52 -0
  152. package/dist/runtime-core/topology-sessions.js +238 -0
  153. package/dist/runtime-core/topology-store.d.ts +171 -0
  154. package/dist/runtime-core/topology-store.js +419 -0
  155. package/dist/runtime-core/topology-worktrees.d.ts +60 -0
  156. package/dist/runtime-core/topology-worktrees.js +199 -0
  157. package/dist/runtime-migration.d.ts +69 -0
  158. package/dist/runtime-migration.js +398 -0
  159. package/dist/session-bootstrap.d.ts +8 -6
  160. package/dist/session-bootstrap.js +51 -159
  161. package/dist/session-runtime.d.ts +2 -0
  162. package/dist/session-runtime.js +1 -1
  163. package/dist/session-semantics.d.ts +12 -4
  164. package/dist/session-semantics.js +14 -1
  165. package/dist/shell-args.js +0 -1
  166. package/dist/shell-hooks.js +32 -11
  167. package/dist/shell-state.d.ts +2 -0
  168. package/dist/shell-state.js +26 -2
  169. package/dist/status-detector.js +0 -1
  170. package/dist/statusline-model.d.ts +10 -2
  171. package/dist/statusline-model.js +106 -31
  172. package/dist/task-workflow.d.ts +6 -9
  173. package/dist/task-workflow.js +37 -85
  174. package/dist/tasks.d.ts +6 -33
  175. package/dist/tasks.js +46 -89
  176. package/dist/team.d.ts +29 -0
  177. package/dist/team.js +40 -1
  178. package/dist/terminal-host.js +0 -1
  179. package/dist/threads.d.ts +6 -35
  180. package/dist/threads.js +89 -99
  181. package/dist/tmux/doctor.js +0 -1
  182. package/dist/tmux/inbox-popup.js +37 -16
  183. package/dist/tmux/runtime-manager.d.ts +3 -0
  184. package/dist/tmux/runtime-manager.js +21 -5
  185. package/dist/tmux/session-transport.js +0 -1
  186. package/dist/tmux/statusline-cache.js +0 -1
  187. package/dist/tmux/statusline.js +49 -10
  188. package/dist/tmux/switcher.js +0 -1
  189. package/dist/tmux/window-open.js +1 -3
  190. package/dist/tool-output-watchers.d.ts +0 -18
  191. package/dist/tool-output-watchers.js +0 -323
  192. package/dist/tui/render/box.js +0 -1
  193. package/dist/tui/render/text.js +0 -1
  194. package/dist/tui/screens/dashboard-renderers.js +37 -26
  195. package/dist/tui/screens/overlay-renderers.d.ts +2 -0
  196. package/dist/tui/screens/overlay-renderers.js +37 -2
  197. package/dist/tui/screens/subscreen-renderers.js +7 -1
  198. package/dist/workflow.js +0 -1
  199. package/dist/worktree.js +17 -1
  200. package/dist-ui/_expo/static/css/web-30453ede1678c16acb08b97e83e8646d.css +1 -0
  201. package/dist-ui/_expo/static/js/web/entry-477c745b2adc79367a4380ecf07d9ff6.js +14620 -0
  202. package/dist-ui/assets/assets/images/icon.a5413dcd2e811c9f2317d01a28118d8a.png +0 -0
  203. package/dist-ui/assets/node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png +0 -0
  204. package/dist-ui/assets/node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png +0 -0
  205. package/dist-ui/assets/node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png +0 -0
  206. package/dist-ui/assets/node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png +0 -0
  207. package/dist-ui/assets/node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png +0 -0
  208. package/dist-ui/assets/node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png +0 -0
  209. package/dist-ui/assets/node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png +0 -0
  210. package/dist-ui/assets/node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png +0 -0
  211. package/dist-ui/assets/node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png +0 -0
  212. package/dist-ui/assets/node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png +0 -0
  213. package/dist-ui/assets/node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png +0 -0
  214. package/dist-ui/assets/node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png +0 -0
  215. package/dist-ui/assets/node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png +0 -0
  216. package/dist-ui/assets/node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png +0 -0
  217. package/dist-ui/assets/node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png +0 -0
  218. package/dist-ui/assets/node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png +0 -0
  219. package/dist-ui/assets/node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png +0 -0
  220. package/dist-ui/assets/node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png +0 -0
  221. package/dist-ui/favicon.ico +0 -0
  222. package/dist-ui/index.html +38 -0
  223. package/dist-ui/metadata.json +1 -0
  224. package/package.json +29 -12
  225. package/dist/agent-events.js.map +0 -1
  226. package/dist/agent-message-parts.d.ts +0 -17
  227. package/dist/agent-message-parts.js +0 -31
  228. package/dist/agent-message-parts.js.map +0 -1
  229. package/dist/agent-output-parser.js.map +0 -1
  230. package/dist/agent-prompt-delivery.js.map +0 -1
  231. package/dist/agent-tracker.js.map +0 -1
  232. package/dist/agent-watcher.js.map +0 -1
  233. package/dist/atomic-write.js.map +0 -1
  234. package/dist/attachment-store.js.map +0 -1
  235. package/dist/builtin-metadata-watchers.js.map +0 -1
  236. package/dist/claude-hooks.js.map +0 -1
  237. package/dist/config.js.map +0 -1
  238. package/dist/context/compactor.js.map +0 -1
  239. package/dist/context/context-bridge.js.map +0 -1
  240. package/dist/context/context-file.js.map +0 -1
  241. package/dist/context/history.js.map +0 -1
  242. package/dist/daemon.js.map +0 -1
  243. package/dist/dashboard/command-spec.js.map +0 -1
  244. package/dist/dashboard/feedback.js.map +0 -1
  245. package/dist/dashboard/index.js.map +0 -1
  246. package/dist/dashboard/operation-failures.js.map +0 -1
  247. package/dist/dashboard/pending-actions.js.map +0 -1
  248. package/dist/dashboard/quick-jump.js.map +0 -1
  249. package/dist/dashboard/runtime-evidence.js.map +0 -1
  250. package/dist/dashboard/session-actions.js.map +0 -1
  251. package/dist/dashboard/session-registry.js.map +0 -1
  252. package/dist/dashboard/sort.js.map +0 -1
  253. package/dist/dashboard/state.js.map +0 -1
  254. package/dist/dashboard/targets.js.map +0 -1
  255. package/dist/dashboard/ui-state-store.js.map +0 -1
  256. package/dist/debug.js.map +0 -1
  257. package/dist/default-plugins/gh-pr-context.js.map +0 -1
  258. package/dist/default-plugins/transcript-length.js.map +0 -1
  259. package/dist/fast-control.js.map +0 -1
  260. package/dist/hotkeys.js.map +0 -1
  261. package/dist/http-client.js.map +0 -1
  262. package/dist/instance-directory.d.ts +0 -32
  263. package/dist/instance-directory.js +0 -82
  264. package/dist/instance-directory.js.map +0 -1
  265. package/dist/instance-registry.d.ts +0 -39
  266. package/dist/instance-registry.js +0 -208
  267. package/dist/instance-registry.js.map +0 -1
  268. package/dist/key-parser.js.map +0 -1
  269. package/dist/last-used.js.map +0 -1
  270. package/dist/main.js.map +0 -1
  271. package/dist/managed-launch-env.js.map +0 -1
  272. package/dist/metadata-server.js.map +0 -1
  273. package/dist/metadata-store.js.map +0 -1
  274. package/dist/multiplexer/agent-io-methods.js.map +0 -1
  275. package/dist/multiplexer/archives.js.map +0 -1
  276. package/dist/multiplexer/dashboard-actions-methods.js.map +0 -1
  277. package/dist/multiplexer/dashboard-control.js.map +0 -1
  278. package/dist/multiplexer/dashboard-interaction.js.map +0 -1
  279. package/dist/multiplexer/dashboard-model.js.map +0 -1
  280. package/dist/multiplexer/dashboard-ops.js.map +0 -1
  281. package/dist/multiplexer/dashboard-state-methods.js.map +0 -1
  282. package/dist/multiplexer/dashboard-tail-methods.js.map +0 -1
  283. package/dist/multiplexer/dashboard-view-methods.js.map +0 -1
  284. package/dist/multiplexer/graveyard-view-model.js.map +0 -1
  285. package/dist/multiplexer/index.js.map +0 -1
  286. package/dist/multiplexer/navigation.js.map +0 -1
  287. package/dist/multiplexer/notifications.js.map +0 -1
  288. package/dist/multiplexer/persistence-methods.js.map +0 -1
  289. package/dist/multiplexer/runtime-lifecycle-methods.js.map +0 -1
  290. package/dist/multiplexer/runtime-state.js.map +0 -1
  291. package/dist/multiplexer/runtime-sync.js.map +0 -1
  292. package/dist/multiplexer/service-state-snapshot.js.map +0 -1
  293. package/dist/multiplexer/services.js.map +0 -1
  294. package/dist/multiplexer/session-actions.d.ts +0 -40
  295. package/dist/multiplexer/session-actions.js +0 -110
  296. package/dist/multiplexer/session-actions.js.map +0 -1
  297. package/dist/multiplexer/session-launch.js.map +0 -1
  298. package/dist/multiplexer/session-runtime-core.js.map +0 -1
  299. package/dist/multiplexer/subscreens.js.map +0 -1
  300. package/dist/multiplexer/tool-picker.js.map +0 -1
  301. package/dist/multiplexer/worktree-graveyard.js.map +0 -1
  302. package/dist/multiplexer/worktrees.js.map +0 -1
  303. package/dist/notification-context.js.map +0 -1
  304. package/dist/notifications.js.map +0 -1
  305. package/dist/notify.js.map +0 -1
  306. package/dist/orchestration-actions.js.map +0 -1
  307. package/dist/orchestration-dispatcher.d.ts +0 -25
  308. package/dist/orchestration-dispatcher.js +0 -59
  309. package/dist/orchestration-dispatcher.js.map +0 -1
  310. package/dist/orchestration-routing.js.map +0 -1
  311. package/dist/orchestration.js.map +0 -1
  312. package/dist/osc-notifications.js.map +0 -1
  313. package/dist/paths.js.map +0 -1
  314. package/dist/plugin-runtime.js.map +0 -1
  315. package/dist/project-events.js.map +0 -1
  316. package/dist/project-scanner.js.map +0 -1
  317. package/dist/project-service-manifest.js.map +0 -1
  318. package/dist/recency.js.map +0 -1
  319. package/dist/recorder.js.map +0 -1
  320. package/dist/session-bootstrap.js.map +0 -1
  321. package/dist/session-input-operations.d.ts +0 -19
  322. package/dist/session-input-operations.js +0 -46
  323. package/dist/session-input-operations.js.map +0 -1
  324. package/dist/session-message-history.d.ts +0 -27
  325. package/dist/session-message-history.js +0 -105
  326. package/dist/session-message-history.js.map +0 -1
  327. package/dist/session-runtime.js.map +0 -1
  328. package/dist/session-semantics.js.map +0 -1
  329. package/dist/shell-args.js.map +0 -1
  330. package/dist/shell-hooks.js.map +0 -1
  331. package/dist/shell-state.js.map +0 -1
  332. package/dist/status-detector.js.map +0 -1
  333. package/dist/statusline-model.js.map +0 -1
  334. package/dist/task-dispatcher.d.ts +0 -64
  335. package/dist/task-dispatcher.js +0 -213
  336. package/dist/task-dispatcher.js.map +0 -1
  337. package/dist/task-workflow.js.map +0 -1
  338. package/dist/tasks.js.map +0 -1
  339. package/dist/team.js.map +0 -1
  340. package/dist/terminal-host.js.map +0 -1
  341. package/dist/threads.js.map +0 -1
  342. package/dist/tmux/doctor.js.map +0 -1
  343. package/dist/tmux/inbox-popup.js.map +0 -1
  344. package/dist/tmux/runtime-manager.js.map +0 -1
  345. package/dist/tmux/session-transport.js.map +0 -1
  346. package/dist/tmux/statusline-cache.js.map +0 -1
  347. package/dist/tmux/statusline.js.map +0 -1
  348. package/dist/tmux/switcher.js.map +0 -1
  349. package/dist/tmux/window-open.js.map +0 -1
  350. package/dist/tool-output-watchers.js.map +0 -1
  351. package/dist/tui/render/box.js.map +0 -1
  352. package/dist/tui/render/text.js.map +0 -1
  353. package/dist/tui/screens/dashboard-renderers.js.map +0 -1
  354. package/dist/tui/screens/overlay-renderers.js.map +0 -1
  355. package/dist/tui/screens/subscreen-renderers.js.map +0 -1
  356. package/dist/workflow.js.map +0 -1
  357. package/dist/worktree.js.map +0 -1
@@ -1,12 +1,15 @@
1
- import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
1
+ import { existsSync } from "node:fs";
2
2
  import { loadConfig } from "../config.js";
3
3
  import { loadMetadataState, updateSessionMetadata } from "../metadata-store.js";
4
- import { getGraveyardPath, getLocalAimuxDir, getStatePath } from "../paths.js";
5
4
  import { isToolInternalWorktree, listWorktrees as listAllWorktrees } from "../worktree.js";
6
5
  import { isDashboardWindowName } from "../tmux/runtime-manager.js";
7
6
  import { TmuxSessionTransport } from "../tmux/session-transport.js";
8
7
  import { markLastUsed } from "../last-used.js";
9
8
  import { listWorktreeGraveyardPaths } from "./worktree-graveyard.js";
9
+ import { getServiceLaunchCommandLine } from "./services.js";
10
+ import { listTopologySessionStates, moveTopologySessionToGraveyard, upsertTopologySession, } from "../runtime-core/topology-sessions.js";
11
+ import { listTopologyServiceStates } from "../runtime-core/topology-services.js";
12
+ const DASHBOARD_BACKGROUND_REFRESH_MS = 2000;
10
13
  function isAvailableWorktreePath(worktreePath, graveyardPaths = listWorktreeGraveyardPaths()) {
11
14
  if (!worktreePath)
12
15
  return true;
@@ -110,41 +113,6 @@ export function startStatusRefresh(host) {
110
113
  return;
111
114
  host.statusInterval = setInterval(() => {
112
115
  let dashboardNeedsRender = false;
113
- if (host.mode === "project-service") {
114
- host.taskDispatcher?.tick(host.sessions.map((s) => s.id));
115
- host.orchestrationDispatcher?.tick(host.sessions.map((s) => s.id));
116
- }
117
- const events = host.taskDispatcher?.drainEvents() ?? [];
118
- for (const ev of events) {
119
- if (ev.type === "assigned") {
120
- host.footerFlash = `⧫ Task assigned → ${ev.sessionId}`;
121
- }
122
- else if (ev.type === "completed") {
123
- host.footerFlash = `✓ Task done by ${ev.sessionId}`;
124
- }
125
- else if (ev.type === "failed") {
126
- host.footerFlash = `✗ Task failed: ${ev.sessionId}`;
127
- }
128
- else if (ev.type === "review_created") {
129
- host.footerFlash = `⧫ Review created: ${ev.description}`;
130
- }
131
- else if (ev.type === "review_approved") {
132
- host.footerFlash = `✓ Review approved: ${ev.description}`;
133
- }
134
- else if (ev.type === "changes_requested") {
135
- host.footerFlash = `↻ Changes requested: ${ev.description}`;
136
- }
137
- host.footerFlashTicks = 3;
138
- dashboardNeedsRender = true;
139
- }
140
- const orchestrationEvents = host.orchestrationDispatcher?.drainEvents() ?? [];
141
- for (const event of orchestrationEvents) {
142
- if (event.type === "message_delivered") {
143
- host.footerFlash = `✉ Message delivered → ${event.sessionId}`;
144
- host.footerFlashTicks = 3;
145
- dashboardNeedsRender = true;
146
- }
147
- }
148
116
  if (host.dashboardFeedback.tickFlashVisibilityChanged()) {
149
117
  dashboardNeedsRender = true;
150
118
  }
@@ -166,7 +134,7 @@ export function startStatusRefresh(host) {
166
134
  if (host.mode === "dashboard") {
167
135
  const now = Date.now();
168
136
  if (now >= host.dashboardNextBackgroundRefreshAt) {
169
- host.dashboardNextBackgroundRefreshAt = now + 5000;
137
+ host.dashboardNextBackgroundRefreshAt = now + DASHBOARD_BACKGROUND_REFRESH_MS;
170
138
  void host.refreshDashboardModelFromService().then((refreshed) => {
171
139
  if (refreshed || dashboardNeedsRender) {
172
140
  host.renderCurrentDashboardView();
@@ -185,45 +153,38 @@ export function stopStatusRefresh(host) {
185
153
  host.statusInterval = null;
186
154
  }
187
155
  }
188
- export function syncSessionsFromState(host, state = host.constructor.loadState()) {
189
- const liveAgentWindows = restoreTmuxSessionsFromState(host, state);
190
- loadOfflineSessions(host, state, liveAgentWindows);
156
+ export function syncSessionsFromTopology(host) {
157
+ const state = host.constructor.loadState();
158
+ const liveAgentWindows = restoreTmuxSessionsFromTopology(host);
159
+ loadOfflineTopologySessions(host, liveAgentWindows);
191
160
  loadOfflineServices(host, state);
192
161
  host.invalidateDesktopStateSnapshot();
193
162
  }
194
- export function loadOfflineSessions(host, state = host.constructor.loadState(), liveAgentWindows = listLiveAgentWindows(host)) {
195
- if (!state || state.sessions.length === 0) {
163
+ export function loadOfflineTopologySessions(host, liveAgentWindows = listLiveAgentWindows(host)) {
164
+ const savedSessions = listTopologySessionStates({ statuses: ["offline"] });
165
+ if (savedSessions.length === 0) {
196
166
  const changed = host.offlineSessions.length > 0;
197
167
  host.offlineSessions = [];
198
168
  return changed;
199
169
  }
200
170
  const liveIds = new Set(liveAgentWindows.map(({ metadata }) => metadata.sessionId));
201
- const liveBackendIds = new Set(liveAgentWindows
202
- .map(({ metadata }) => metadata.backendSessionId)
203
- .filter((value) => Boolean(value)));
204
171
  const ownedIds = new Set();
205
172
  for (const s of host.sessions)
206
173
  ownedIds.add(s.id);
207
- for (const inst of host.getRemoteInstancesSafe()) {
208
- for (const rs of inst.sessions)
209
- ownedIds.add(rs.id);
210
- }
211
174
  const ownedBackendIds = new Set(host.sessions
212
175
  .map((session) => session.backendSessionId)
213
176
  .filter((value) => Boolean(value)));
214
- const nextOfflineSessions = state.sessions
177
+ const nextOfflineSessions = savedSessions
215
178
  .filter((s) => {
216
179
  if (!isIntentionalOfflineSession(s))
217
180
  return false;
218
181
  if (liveIds.has(s.id))
219
182
  return false;
220
- if (s.backendSessionId && liveBackendIds.has(s.backendSessionId))
221
- return false;
222
183
  if (ownedIds.has(s.id))
223
184
  return false;
224
185
  if (s.backendSessionId && ownedBackendIds.has(s.backendSessionId))
225
186
  return false;
226
- if (host.dashboardPendingActions?.get?.(s.id) === "starting")
187
+ if (host.dashboardPendingActions?.getSessionAction?.(s.id) === "starting")
227
188
  return false;
228
189
  if (!isAvailableWorktreePath(s.worktreePath))
229
190
  return false;
@@ -231,19 +192,20 @@ export function loadOfflineSessions(host, state = host.constructor.loadState(),
231
192
  })
232
193
  .map(offlineSessionState);
233
194
  const previousKey = host.offlineSessions
234
- .map((session) => `${session.id}:${session.label ?? ""}:${session.worktreePath ?? ""}`)
195
+ .map((session) => `${session.id}:${session.label ?? ""}:${session.worktreePath ?? ""}:${session.backendSessionId ?? ""}:${JSON.stringify(session.team ?? null)}`)
235
196
  .join("|");
236
197
  const nextKey = nextOfflineSessions
237
- .map((session) => `${session.id}:${session.label ?? ""}:${session.worktreePath ?? ""}`)
198
+ .map((session) => `${session.id}:${session.label ?? ""}:${session.worktreePath ?? ""}:${session.backendSessionId ?? ""}:${JSON.stringify(session.team ?? null)}`)
238
199
  .join("|");
239
200
  host.offlineSessions = nextOfflineSessions;
240
201
  if (host.offlineSessions.length > 0) {
241
- host.debug?.(`loaded ${host.offlineSessions.length} offline session(s) from state.json`, "session");
202
+ host.debug?.(`loaded ${host.offlineSessions.length} offline session(s) from runtime topology`, "session");
242
203
  }
243
204
  return previousKey !== nextKey;
244
205
  }
245
206
  export function loadOfflineServices(host, state = host.constructor.loadState()) {
246
- const savedServices = state?.services ?? [];
207
+ const topologyServices = listTopologyServiceStates({ statuses: ["stopped", "offline"] });
208
+ const savedServices = topologyServices.length > 0 ? topologyServices : (state?.services ?? []);
247
209
  if (savedServices.length === 0) {
248
210
  const changed = host.offlineServices.length > 0;
249
211
  host.offlineServices = [];
@@ -259,7 +221,7 @@ export function loadOfflineServices(host, state = host.constructor.loadState())
259
221
  const nextOfflineServices = savedServices.filter((service) => {
260
222
  if (liveServiceIds.has(service.id))
261
223
  return false;
262
- if (host.dashboardPendingActions?.get?.(service.id) === "starting")
224
+ if (host.dashboardPendingActions?.getServiceAction?.(service.id) === "starting")
263
225
  return false;
264
226
  if (!isAvailableWorktreePath(service.worktreePath))
265
227
  return false;
@@ -288,7 +250,7 @@ export function buildLiveServiceStates(host) {
288
250
  if (seen.has(metadata.sessionId))
289
251
  continue;
290
252
  seen.add(metadata.sessionId);
291
- const launchCommandLine = metadata.command === "shell" ? "" : metadata.args?.[0] === "-lc" ? (metadata.args[1] ?? "") : "";
253
+ const launchCommandLine = metadata.launchCommandLine?.trim() || getServiceLaunchCommandLine(metadata);
292
254
  liveServices.push({
293
255
  id: metadata.sessionId,
294
256
  createdAt: metadata.createdAt,
@@ -301,8 +263,9 @@ export function buildLiveServiceStates(host) {
301
263
  }
302
264
  return liveServices;
303
265
  }
304
- export function restoreTmuxSessionsFromState(host, state = host.constructor.loadState()) {
305
- const savedById = new Map((state?.sessions ?? []).map((session) => [session.id, session]));
266
+ export function restoreTmuxSessionsFromTopology(host) {
267
+ const savedSessions = listTopologySessionStates({ statuses: ["running", "idle", "offline"] });
268
+ const savedById = new Map(savedSessions.map((session) => [session.id, session]));
306
269
  const cols = process.stdout.columns ?? 80;
307
270
  const rows = process.stdout.rows ?? 24;
308
271
  const liveAgentWindows = listLiveAgentWindows(host);
@@ -330,9 +293,8 @@ export function restoreTmuxSessionsFromState(host, state = host.constructor.load
330
293
  if (existing)
331
294
  continue;
332
295
  const transport = new TmuxSessionTransport(metadata.sessionId, metadata.command, target, host.tmuxRuntimeManager, cols, rows);
333
- transport.backendSessionId = metadata.backendSessionId;
334
296
  host.sessionTmuxTargets.set(metadata.sessionId, target);
335
- host.registerManagedSession(transport, metadata.args, metadata.toolConfigKey, metadata.worktreePath, metadata.role, metadata.createdAt ? Date.parse(metadata.createdAt) : undefined);
297
+ host.registerManagedSession(transport, metadata.args, metadata.toolConfigKey, metadata.worktreePath, metadata.role, metadata.createdAt ? Date.parse(metadata.createdAt) : undefined, metadata.team);
336
298
  const saved = savedById.get(metadata.sessionId);
337
299
  const label = metadata.label ?? saved?.label;
338
300
  if (label) {
@@ -343,7 +305,6 @@ export function restoreTmuxSessionsFromState(host, state = host.constructor.load
343
305
  }
344
306
  host.syncTmuxWindowMetadata(metadata.sessionId);
345
307
  }
346
- host.writeSessionsFile?.();
347
308
  host.updateContextWatcherSessions?.();
348
309
  return liveAgentWindows;
349
310
  }
@@ -351,6 +312,7 @@ export function stopSessionToOffline(host, session) {
351
312
  if (host.stoppingSessionIds.has(session.id))
352
313
  return;
353
314
  markLifecycleUsed(host, session.id);
315
+ const backendSessionId = session.backendSessionId;
354
316
  const offlineEntry = {
355
317
  id: session.id,
356
318
  tool: session.command,
@@ -359,16 +321,22 @@ export function stopSessionToOffline(host, session) {
359
321
  args: host.sessionOriginalArgs.get(session.id) ?? [],
360
322
  lifecycle: "offline",
361
323
  createdAt: session.startTime ? new Date(session.startTime).toISOString() : undefined,
362
- backendSessionId: session.backendSessionId,
324
+ backendSessionId,
325
+ team: session.team,
363
326
  worktreePath: host.sessionWorktreePaths.get(session.id),
364
327
  label: host.getSessionLabel(session.id),
365
328
  headline: host.deriveHeadline(session.id),
366
329
  };
367
- if (!host.offlineSessions.some((entry) => entry.id === session.id)) {
330
+ const existingIndex = host.offlineSessions.findIndex((entry) => entry.id === session.id);
331
+ if (existingIndex >= 0) {
332
+ host.offlineSessions[existingIndex] = { ...host.offlineSessions[existingIndex], ...offlineEntry };
333
+ }
334
+ else {
368
335
  host.offlineSessions.push(offlineEntry);
369
336
  }
370
337
  host.stoppingSessionIds.add(session.id);
371
338
  host.startedInDashboard = true;
339
+ upsertTopologySession(offlineEntry, "offline");
372
340
  host.saveState();
373
341
  session.kill();
374
342
  host.debug?.(`stopped session ${session.id} → offline`, "session");
@@ -390,30 +358,18 @@ export function adjustAfterRemove(host, hasWorktrees) {
390
358
  }
391
359
  }
392
360
  }
393
- export function graveyardSession(host, sessionId) {
394
- const session = host.offlineSessions.find((s) => s.id === sessionId);
361
+ export function graveyardSession(host, sessionId, _sessionSeed) {
362
+ const session = host.offlineSessions.find((s) => s.id === sessionId) ??
363
+ listTopologySessionStates({ statuses: ["running", "idle", "offline"] }).find((s) => s.id === sessionId);
395
364
  if (!session)
396
365
  return;
397
366
  markLifecycleUsed(host, sessionId);
398
367
  host.offlineSessions = host.offlineSessions.filter((s) => s.id !== sessionId);
399
- const graveyardPath = getGraveyardPath();
400
- let graveyard = [];
401
- if (existsSync(graveyardPath)) {
402
- try {
403
- graveyard = JSON.parse(readFileSync(graveyardPath, "utf-8"));
404
- }
405
- catch { }
406
- }
407
- graveyard.push({ ...session, id: session.id });
408
- writeFileSync(graveyardPath, JSON.stringify(graveyard, null, 2) + "\n");
409
- const statePath = getStatePath();
410
- if (existsSync(statePath)) {
411
- try {
412
- const state = JSON.parse(readFileSync(statePath, "utf-8"));
413
- state.sessions = state.sessions.filter((s) => s.id !== sessionId);
414
- writeFileSync(statePath, JSON.stringify(state, null, 2) + "\n");
415
- }
416
- catch { }
368
+ moveTopologySessionToGraveyard(sessionId);
369
+ host.invalidateDesktopStateSnapshot?.();
370
+ host.writeStatuslineFile?.();
371
+ if (host.mode === "dashboard") {
372
+ host.renderCurrentDashboardView?.();
417
373
  }
418
374
  host.debug?.(`graveyarded session ${sessionId}`, "session");
419
375
  }
@@ -443,7 +399,6 @@ export function evictZombieSession(host, runtime) {
443
399
  }
444
400
  host.stoppingSessionIds.delete(runtime.id);
445
401
  host.sessionTmuxTargets.delete(runtime.id);
446
- host.writeSessionsFile();
447
402
  host.updateContextWatcherSessions();
448
403
  host.saveState();
449
404
  }
@@ -464,16 +419,20 @@ export function resumeOfflineSession(host, session) {
464
419
  return;
465
420
  const derived = loadMetadataState().sessions[session.id]?.derived;
466
421
  const relaunchFresh = derived?.activity === "error" || derived?.attention === "error";
467
- const useBackendResume = !relaunchFresh && host.sessionBootstrap.canResumeWithBackendSessionId(toolCfg, session.backendSessionId);
422
+ const backendSessionId = session.backendSessionId;
423
+ const useBackendResume = !relaunchFresh && host.sessionBootstrap.canResumeWithBackendSessionId(toolCfg, backendSessionId);
468
424
  let actionArgs;
469
425
  if (useBackendResume) {
470
- actionArgs = toolCfg.resumeArgs.map((a) => a.replace("{sessionId}", session.backendSessionId));
426
+ actionArgs = toolCfg.resumeArgs.map((a) => a.replace("{sessionId}", backendSessionId));
471
427
  }
472
428
  else if (relaunchFresh) {
473
429
  actionArgs = [];
474
430
  }
475
431
  else {
476
- actionArgs = [...(toolCfg.resumeFallback ?? [])];
432
+ // Targeted dashboard restore must never use "latest session" style fallbacks
433
+ // such as Claude --continue or Codex resume --last; those can resurrect the
434
+ // wrong agent after a crash or stale-state mismatch.
435
+ throw new Error(`Cannot restore session "${session.id}" without an exact resumable backend session id for "${session.toolConfigKey}"`);
477
436
  }
478
437
  const args = [...(toolCfg.args ?? []), ...actionArgs];
479
438
  if (relaunchFresh) {
@@ -492,31 +451,42 @@ export function resumeOfflineSession(host, session) {
492
451
  if (preservedLabel) {
493
452
  host.sessionLabels.set(session.id, preservedLabel);
494
453
  }
495
- host.debug?.(`resuming offline session ${session.id} (${relaunchFresh ? "fresh" : useBackendResume ? `backend=${session.backendSessionId ?? "none"}` : "fallback"})`, "session");
496
- host.createSession(session.command, args, toolCfg.preambleFlag, session.toolConfigKey, undefined, undefined, session.worktreePath, useBackendResume ? session.backendSessionId : undefined, session.id, true, !relaunchFresh);
454
+ host.debug?.(`resuming offline session ${session.id} (${relaunchFresh ? "fresh" : useBackendResume ? `backend=${backendSessionId ?? "none"}` : "fallback"})`, "session");
455
+ host.createSession(session.command, args, toolCfg.preambleFlag, session.toolConfigKey, undefined, undefined, session.worktreePath, useBackendResume ? backendSessionId : undefined, session.id, true, useBackendResume, session.team);
456
+ }
457
+ export function recordSessionBackendSessionId(host, sessionId, backendSessionId) {
458
+ const normalizedBackendSessionId = backendSessionId.trim();
459
+ if (!sessionId.trim()) {
460
+ throw new Error("sessionId is required");
461
+ }
462
+ if (!normalizedBackendSessionId) {
463
+ throw new Error("backendSessionId is required");
464
+ }
465
+ const runtime = host.sessions.find((session) => session.id === sessionId);
466
+ const offline = host.offlineSessions.find((session) => session.id === sessionId);
467
+ if (!runtime && !offline) {
468
+ throw new Error(`Agent "${sessionId}" is not managed by this runtime`);
469
+ }
470
+ const existing = runtime?.backendSessionId ?? offline?.backendSessionId;
471
+ if (existing && existing !== normalizedBackendSessionId) {
472
+ throw new Error(`Agent "${sessionId}" already has backend session "${existing}", cannot replace with "${normalizedBackendSessionId}"`);
473
+ }
474
+ const selectedBackendSessionId = existing ?? normalizedBackendSessionId;
475
+ if (runtime) {
476
+ runtime.backendSessionId = selectedBackendSessionId;
477
+ host.syncTmuxWindowMetadata?.(sessionId);
478
+ }
479
+ if (offline) {
480
+ offline.backendSessionId = selectedBackendSessionId;
481
+ }
482
+ host.saveState?.();
483
+ host.invalidateDesktopStateSnapshot?.();
484
+ host.writeStatuslineFile?.();
485
+ return { sessionId, backendSessionId: selectedBackendSessionId };
497
486
  }
498
487
  export function startHeartbeat(host) {
499
488
  host.runtimeSync.startHeartbeat();
500
489
  }
501
- export function handleSessionClaimed(host, sessionId) {
502
- const session = host.sessions.find((s) => s.id === sessionId);
503
- if (!session)
504
- return;
505
- host.debug?.(`session ${sessionId} was claimed by another instance, killing local PTY`, "instance");
506
- session.kill();
507
- const idx = host.sessions.indexOf(session);
508
- if (idx >= 0) {
509
- host.sessions.splice(idx, 1);
510
- host.sessionToolKeys.delete(sessionId);
511
- host.sessionOriginalArgs.delete(sessionId);
512
- host.sessionWorktreePaths.delete(sessionId);
513
- host.sessionTmuxTargets.delete(sessionId);
514
- }
515
- if (host.activeIndex >= host.sessions.length) {
516
- host.activeIndex = Math.max(0, host.sessions.length - 1);
517
- }
518
- host.renderDashboard();
519
- }
520
490
  export function stopHeartbeat(host) {
521
491
  host.runtimeSync.stopHeartbeat();
522
492
  }
@@ -526,40 +496,6 @@ export function startProjectServiceRefresh(host) {
526
496
  export function stopProjectServiceRefresh(host) {
527
497
  host.runtimeSync.stopProjectServiceRefresh();
528
498
  }
529
- export function getRemoteInstancesSafe(host) {
530
- return host.instanceDirectory.getRemoteInstancesSafe(host.instanceId, process.cwd());
531
- }
532
- export function getRemoteOwnedSessionKeys(host) {
533
- return host.instanceDirectory.getRemoteOwnedSessionKeys(host.instanceId, process.cwd());
534
- }
535
- export function getInstanceSessionRefs(host) {
536
- return host.sessions.map((s) => ({
537
- id: s.id,
538
- tool: s.command,
539
- backendSessionId: s.backendSessionId,
540
- worktreePath: host.sessionWorktreePaths.get(s.id),
541
- }));
542
- }
543
- export function writeSessionsFile(host) {
544
- const dir = getLocalAimuxDir();
545
- if (!existsSync(dir))
546
- mkdirSync(dir, { recursive: true });
547
- const localSessions = host.sessions.map((s) => ({
548
- id: s.id,
549
- tool: s.command,
550
- backendSessionId: s.backendSessionId,
551
- worktreePath: host.sessionWorktreePaths.get(s.id),
552
- }));
553
- const data = host.instanceDirectory.buildSessionsFileEntries(localSessions, host.instanceDirectory.getRemoteInstancesSafe(host.instanceId, process.cwd()));
554
- writeFileSync(`${dir}/sessions.json`, JSON.stringify(data, null, 2) + "\n");
555
- }
556
- export function removeSessionsFile() {
557
- try {
558
- unlinkSync(`${getLocalAimuxDir()}/sessions.json`);
559
- }
560
- catch { }
561
- }
562
499
  export function listDesktopWorktrees(_host) {
563
500
  return listAllWorktrees().filter((wt) => !wt.isBare && !isToolInternalWorktree(wt));
564
501
  }
565
- //# sourceMappingURL=runtime-state.js.map
@@ -1,22 +1,14 @@
1
- import type { InstanceDirectory } from "../instance-directory.js";
2
- import type { InstanceSessionRef } from "../instance-registry.js";
3
1
  export declare class MultiplexerRuntimeSync {
4
2
  private readonly deps;
5
3
  private heartbeatInterval;
6
4
  private projectServiceInterval;
7
5
  constructor(deps: {
8
- instanceDirectory: InstanceDirectory;
9
- instanceId: string;
10
6
  cwd: string;
11
7
  getMode: () => "dashboard" | "project-service";
12
- getConfirmedRegistered: () => Set<string>;
13
- setConfirmedRegistered: (value: Set<string>) => void;
14
- getInstanceSessionRefs: () => InstanceSessionRef[];
15
- syncSessionsFromState: () => void;
16
- loadOfflineSessions: () => boolean;
8
+ syncSessionsFromTopology: () => void;
9
+ loadOfflineTopologySessions: () => boolean;
17
10
  renderCurrentDashboardView: () => void;
18
11
  renderDashboard: () => void;
19
- handleSessionClaimed: (sessionId: string) => void;
20
12
  writeStatuslineFile: () => void;
21
13
  });
22
14
  startHeartbeat(): void;
@@ -10,25 +10,10 @@ export class MultiplexerRuntimeSync {
10
10
  return;
11
11
  this.heartbeatInterval = setInterval(() => {
12
12
  if (this.deps.getMode() === "project-service") {
13
- this.deps.syncSessionsFromState();
13
+ this.deps.syncSessionsFromTopology();
14
14
  return;
15
15
  }
16
- let dashboardNeedsRender = false;
17
- const sessions = this.deps.getInstanceSessionRefs();
18
- this.deps.instanceDirectory
19
- .reconcileHeartbeat(this.deps.instanceId, sessions, this.deps.cwd, this.deps.getConfirmedRegistered())
20
- .then((result) => {
21
- for (const id of result.claimedIds) {
22
- this.deps.handleSessionClaimed(id);
23
- dashboardNeedsRender = true;
24
- }
25
- this.deps.setConfirmedRegistered(result.confirmedIds);
26
- if (dashboardNeedsRender && this.deps.getMode() === "dashboard") {
27
- this.deps.renderCurrentDashboardView();
28
- }
29
- })
30
- .catch(() => { });
31
- const offlineChanged = this.deps.loadOfflineSessions();
16
+ const offlineChanged = this.deps.loadOfflineTopologySessions();
32
17
  if (offlineChanged && this.deps.getMode() === "dashboard") {
33
18
  this.deps.renderCurrentDashboardView();
34
19
  }
@@ -44,7 +29,7 @@ export class MultiplexerRuntimeSync {
44
29
  if (this.projectServiceInterval)
45
30
  return;
46
31
  this.projectServiceInterval = setInterval(() => {
47
- this.deps.syncSessionsFromState();
32
+ this.deps.syncSessionsFromTopology();
48
33
  }, 2000);
49
34
  }
50
35
  stopProjectServiceRefresh() {
@@ -54,4 +39,3 @@ export class MultiplexerRuntimeSync {
54
39
  }
55
40
  }
56
41
  }
57
- //# sourceMappingURL=runtime-sync.js.map
@@ -1,14 +1,12 @@
1
1
  import type { TmuxRuntimeManager } from "../tmux/runtime-manager.js";
2
- import type { SavedState, ServiceState, SessionState } from "./index.js";
2
+ import type { SavedState, ServiceState } from "./index.js";
3
3
  export declare function mergeRuntimeSnapshots(state: SavedState | null, snapshots: {
4
- sessions?: SessionState[];
5
4
  services?: ServiceState[];
6
5
  }, cwd: string, savedAt?: string): SavedState;
7
6
  export declare function mergeServiceSnapshots(state: SavedState | null, snapshots: ServiceState[], cwd: string, savedAt?: string): SavedState;
8
- export declare function snapshotProjectAgentWindows(projectRoot: string, tmux: TmuxRuntimeManager): SessionState[];
9
7
  export declare function snapshotProjectServiceWindows(projectRoot: string, tmux: TmuxRuntimeManager): ServiceState[];
10
8
  export declare function persistProjectRuntimeSnapshotsBeforeTmuxStop(projectRoot: string, tmux: TmuxRuntimeManager): {
11
- sessions: SessionState[];
9
+ sessions: [];
12
10
  services: ServiceState[];
13
11
  };
14
12
  export declare function persistProjectServiceSnapshotsBeforeRuntimeStop(projectRoot: string, tmux: TmuxRuntimeManager): ServiceState[];
@@ -2,13 +2,6 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { getStatePath } from "../paths.js";
3
3
  import { buildServiceStateFromMetadata } from "./services.js";
4
4
  import { listWorktreeGraveyardPaths } from "./worktree-graveyard.js";
5
- function sessionStateKey(session) {
6
- return session.backendSessionId ? `backend:${session.backendSessionId}` : `id:${session.id}`;
7
- }
8
- function sanitizeSnapshotSession(session) {
9
- const { tmuxTarget: _tmuxTarget, ...rest } = session;
10
- return { ...rest, lifecycle: "offline" };
11
- }
12
5
  function isAvailableSnapshotWorktree(worktreePath, graveyardPaths = listWorktreeGraveyardPaths()) {
13
6
  if (!worktreePath)
14
7
  return true;
@@ -17,14 +10,6 @@ function isAvailableSnapshotWorktree(worktreePath, graveyardPaths = listWorktree
17
10
  return existsSync(worktreePath);
18
11
  }
19
12
  export function mergeRuntimeSnapshots(state, snapshots, cwd, savedAt = new Date().toISOString()) {
20
- const sessionByKey = new Map();
21
- for (const session of state?.sessions ?? []) {
22
- sessionByKey.set(sessionStateKey(session), session);
23
- }
24
- for (const session of snapshots.sessions ?? []) {
25
- const offline = sanitizeSnapshotSession(session);
26
- sessionByKey.set(sessionStateKey(offline), offline);
27
- }
28
13
  const byId = new Map();
29
14
  for (const service of state?.services ?? []) {
30
15
  byId.set(service.id, service);
@@ -39,43 +24,12 @@ export function mergeRuntimeSnapshots(state, snapshots, cwd, savedAt = new Date(
39
24
  return {
40
25
  savedAt,
41
26
  cwd: state?.cwd ?? cwd,
42
- sessions: [...sessionByKey.values()],
43
27
  services: [...byId.values()],
44
28
  };
45
29
  }
46
30
  export function mergeServiceSnapshots(state, snapshots, cwd, savedAt = new Date().toISOString()) {
47
31
  return mergeRuntimeSnapshots(state, { services: snapshots }, cwd, savedAt);
48
32
  }
49
- export function snapshotProjectAgentWindows(projectRoot, tmux) {
50
- const seen = new Set();
51
- const graveyardPaths = listWorktreeGraveyardPaths();
52
- const snapshots = [];
53
- for (const { target, metadata } of tmux.listProjectManagedWindows(projectRoot)) {
54
- if (metadata.kind !== "agent")
55
- continue;
56
- if (seen.has(metadata.sessionId))
57
- continue;
58
- if (!isAvailableSnapshotWorktree(metadata.worktreePath, graveyardPaths))
59
- continue;
60
- if (tmux.isWindowAlive && !tmux.isWindowAlive(target))
61
- continue;
62
- seen.add(metadata.sessionId);
63
- snapshots.push({
64
- id: metadata.sessionId,
65
- tool: metadata.command,
66
- toolConfigKey: metadata.toolConfigKey ?? metadata.command,
67
- command: metadata.command,
68
- args: metadata.args ?? [],
69
- lifecycle: "offline",
70
- createdAt: metadata.createdAt,
71
- backendSessionId: metadata.backendSessionId,
72
- worktreePath: metadata.worktreePath,
73
- label: metadata.label,
74
- headline: metadata.statusText,
75
- });
76
- }
77
- return snapshots;
78
- }
79
33
  export function snapshotProjectServiceWindows(projectRoot, tmux) {
80
34
  const seen = new Set();
81
35
  const graveyardPaths = listWorktreeGraveyardPaths();
@@ -97,10 +51,9 @@ export function snapshotProjectServiceWindows(projectRoot, tmux) {
97
51
  return snapshots;
98
52
  }
99
53
  export function persistProjectRuntimeSnapshotsBeforeTmuxStop(projectRoot, tmux) {
100
- const sessions = snapshotProjectAgentWindows(projectRoot, tmux);
101
54
  const services = snapshotProjectServiceWindows(projectRoot, tmux);
102
- if (sessions.length === 0 && services.length === 0)
103
- return { sessions, services };
55
+ if (services.length === 0)
56
+ return { sessions: [], services };
104
57
  const statePath = getStatePath();
105
58
  let existing = null;
106
59
  if (existsSync(statePath)) {
@@ -111,11 +64,10 @@ export function persistProjectRuntimeSnapshotsBeforeTmuxStop(projectRoot, tmux)
111
64
  existing = null;
112
65
  }
113
66
  }
114
- const nextState = mergeRuntimeSnapshots(existing, { sessions, services }, projectRoot);
67
+ const nextState = mergeRuntimeSnapshots(existing, { services }, projectRoot);
115
68
  writeFileSync(statePath, JSON.stringify(nextState, null, 2) + "\n");
116
- return { sessions, services };
69
+ return { sessions: [], services };
117
70
  }
118
71
  export function persistProjectServiceSnapshotsBeforeRuntimeStop(projectRoot, tmux) {
119
72
  return persistProjectRuntimeSnapshotsBeforeTmuxStop(projectRoot, tmux).services;
120
73
  }
121
- //# sourceMappingURL=service-state-snapshot.js.map
@@ -11,6 +11,7 @@ export declare function buildServiceStateFromMetadata(serviceId: string, metadat
11
11
  createdAt?: string;
12
12
  worktreePath?: string;
13
13
  label?: string;
14
+ launchCommandLine?: string;
14
15
  }, opts?: {
15
16
  cwd?: string;
16
17
  tmuxTarget?: ServiceState["tmuxTarget"];