@phnx-labs/agents-cli 1.22.39 → 1.22.40

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 (554) hide show
  1. package/CHANGELOG.md +294 -0
  2. package/README.md +111 -70
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.js +45 -26
  5. package/dist/browser.js +2 -2
  6. package/dist/cli/command-registry.d.ts +135 -0
  7. package/dist/cli/command-registry.js +260 -0
  8. package/dist/commands/accounts.d.ts +20 -0
  9. package/dist/commands/accounts.js +186 -25
  10. package/dist/commands/apply.d.ts +3 -3
  11. package/dist/commands/apply.js +20 -63
  12. package/dist/commands/browser.js +206 -94
  13. package/dist/commands/budget.d.ts +7 -6
  14. package/dist/commands/budget.js +8 -7
  15. package/dist/commands/cloud.js +17 -20
  16. package/dist/commands/commands.js +1 -1
  17. package/dist/commands/computer-actions.d.ts +1 -35
  18. package/dist/commands/computer-actions.js +13 -181
  19. package/dist/commands/computer.d.ts +28 -3
  20. package/dist/commands/computer.js +93 -65
  21. package/dist/commands/config.js +16 -3
  22. package/dist/commands/cost.d.ts +2 -1
  23. package/dist/commands/cost.js +7 -6
  24. package/dist/commands/daemon.js +151 -4
  25. package/dist/commands/detach.js +1 -1
  26. package/dist/commands/doctor.js +19 -11
  27. package/dist/commands/events.js +1 -1
  28. package/dist/commands/exec.d.ts +2 -50
  29. package/dist/commands/exec.js +160 -215
  30. package/dist/commands/factory.js +1 -1
  31. package/dist/commands/feed.d.ts +2 -2
  32. package/dist/commands/feed.js +9 -12
  33. package/dist/commands/fleet-capture.js +25 -27
  34. package/dist/commands/focus.d.ts +2 -3
  35. package/dist/commands/focus.js +34 -9
  36. package/dist/commands/go.js +15 -5
  37. package/dist/commands/harness.d.ts +3 -3
  38. package/dist/commands/harness.js +53 -5
  39. package/dist/commands/hooks.js +1 -1
  40. package/dist/commands/import.js +2 -2
  41. package/dist/commands/insights.d.ts +5 -5
  42. package/dist/commands/insights.js +15 -9
  43. package/dist/commands/inspect.d.ts +2 -3
  44. package/dist/commands/inspect.js +4 -16
  45. package/dist/commands/logs.d.ts +2 -2
  46. package/dist/commands/logs.js +9 -9
  47. package/dist/commands/mcp.js +2 -2
  48. package/dist/commands/memory.js +1 -1
  49. package/dist/commands/message.d.ts +1 -1
  50. package/dist/commands/message.js +7 -7
  51. package/dist/commands/mine.d.ts +11 -8
  52. package/dist/commands/mine.js +11 -10
  53. package/dist/commands/models.js +1 -1
  54. package/dist/commands/modes.js +1 -1
  55. package/dist/commands/monitors.js +23 -6
  56. package/dist/commands/output.d.ts +7 -6
  57. package/dist/commands/output.js +11 -10
  58. package/dist/commands/packages.js +4 -4
  59. package/dist/commands/perf.js +1 -1
  60. package/dist/commands/permissions.js +49 -32
  61. package/dist/commands/plugins.d.ts +1 -1
  62. package/dist/commands/plugins.js +3 -3
  63. package/dist/commands/profiles.d.ts +6 -9
  64. package/dist/commands/profiles.js +8 -321
  65. package/dist/commands/projects.d.ts +9 -0
  66. package/dist/commands/projects.js +140 -8
  67. package/dist/commands/prune.js +5 -13
  68. package/dist/commands/refresh-rules.js +1 -1
  69. package/dist/commands/repo.d.ts +5 -7
  70. package/dist/commands/repo.js +34 -18
  71. package/dist/commands/resource-view.js +4 -0
  72. package/dist/commands/resume.d.ts +11 -7
  73. package/dist/commands/resume.js +82 -98
  74. package/dist/commands/route.d.ts +12 -0
  75. package/dist/commands/route.js +261 -0
  76. package/dist/commands/routines.d.ts +2 -3
  77. package/dist/commands/routines.js +120 -145
  78. package/dist/commands/rules.js +1 -1
  79. package/dist/commands/run-account-picker.d.ts +1 -1
  80. package/dist/commands/run-account-picker.js +2 -2
  81. package/dist/commands/run-broadcast.d.ts +21 -0
  82. package/dist/commands/run-broadcast.js +89 -0
  83. package/dist/commands/run-cloud.js +1 -1
  84. package/dist/commands/secrets-vault.d.ts +10 -0
  85. package/dist/commands/{login.js → secrets-vault.js} +34 -14
  86. package/dist/commands/secrets.d.ts +4 -4
  87. package/dist/commands/secrets.js +72 -63
  88. package/dist/commands/sessions-backfill.js +1 -1
  89. package/dist/commands/sessions-browser.d.ts +1 -1
  90. package/dist/commands/sessions-browser.js +9 -5
  91. package/dist/commands/sessions-export.js +2 -2
  92. package/dist/commands/sessions-inject.js +4 -5
  93. package/dist/commands/sessions-migrate.js +16 -27
  94. package/dist/commands/sessions-picker.d.ts +13 -0
  95. package/dist/commands/sessions-picker.js +182 -8
  96. package/dist/commands/sessions-resume.d.ts +7 -3
  97. package/dist/commands/sessions-resume.js +81 -33
  98. package/dist/commands/sessions-stats.js +2 -2
  99. package/dist/commands/sessions.d.ts +75 -68
  100. package/dist/commands/sessions.js +142 -180
  101. package/dist/commands/setup-computer.js +1 -1
  102. package/dist/commands/setup-fleet.js +3 -0
  103. package/dist/commands/setup-mine.d.ts +7 -3
  104. package/dist/commands/setup-mine.js +13 -8
  105. package/dist/commands/setup-secrets.js +2 -2
  106. package/dist/commands/setup-watchdog.js +2 -2
  107. package/dist/commands/setup.js +7 -2
  108. package/dist/commands/share.d.ts +65 -0
  109. package/dist/commands/share.js +253 -20
  110. package/dist/commands/skills.js +3 -3
  111. package/dist/commands/snapshot.d.ts +2 -2
  112. package/dist/commands/snapshot.js +9 -9
  113. package/dist/commands/ssh.d.ts +1 -1
  114. package/dist/commands/ssh.js +186 -64
  115. package/dist/commands/subagents.js +1 -1
  116. package/dist/commands/sync.js +24 -9
  117. package/dist/commands/teams.d.ts +2 -2
  118. package/dist/commands/teams.js +9 -18
  119. package/dist/commands/tmux.js +5 -1
  120. package/dist/commands/trash.js +1 -1
  121. package/dist/commands/usage.d.ts +1 -1
  122. package/dist/commands/usage.js +2 -2
  123. package/dist/commands/utils.d.ts +4 -14
  124. package/dist/commands/utils.js +6 -27
  125. package/dist/commands/versions.js +2 -2
  126. package/dist/commands/view.d.ts +9 -77
  127. package/dist/commands/view.js +23 -8
  128. package/dist/commands/watchdog.js +1 -1
  129. package/dist/commands/webhook.js +11 -25
  130. package/dist/commands/workflows.js +1 -1
  131. package/dist/index.js +1 -1
  132. package/dist/lib/account-capabilities.d.ts +39 -0
  133. package/dist/lib/account-capabilities.js +59 -0
  134. package/dist/lib/account-catalog.js +1 -1
  135. package/dist/lib/account-registry.d.ts +66 -0
  136. package/dist/lib/account-registry.js +151 -5
  137. package/dist/lib/{rotate.d.ts → accounting/rotate.d.ts} +4 -4
  138. package/dist/lib/{rotate.js → accounting/rotate.js} +8 -8
  139. package/dist/lib/{usage.d.ts → accounting/usage.d.ts} +4 -4
  140. package/dist/lib/{usage.js → accounting/usage.js} +11 -11
  141. package/dist/lib/agent-spec/provider.js +1 -1
  142. package/dist/lib/agents.d.ts +72 -4
  143. package/dist/lib/agents.js +231 -199
  144. package/dist/lib/answer-router.d.ts +2 -2
  145. package/dist/lib/ask-classifier.d.ts +1 -1
  146. package/dist/lib/ask-classifier.js +1 -1
  147. package/dist/lib/audit/log.js +1 -1
  148. package/dist/lib/auth-health.d.ts +1 -1
  149. package/dist/lib/auth-health.js +2 -2
  150. package/dist/lib/brand.js +1 -1
  151. package/dist/lib/browser/caller-identity.d.ts +28 -0
  152. package/dist/lib/browser/caller-identity.js +156 -0
  153. package/dist/lib/browser/cdp.js +1 -1
  154. package/dist/lib/browser/drivers/ssh.d.ts +1 -1
  155. package/dist/lib/browser/drivers/ssh.js +2 -2
  156. package/dist/lib/browser/hygiene.d.ts +10 -2
  157. package/dist/lib/browser/hygiene.js +7 -4
  158. package/dist/lib/browser/ipc.d.ts +22 -2
  159. package/dist/lib/browser/ipc.js +185 -21
  160. package/dist/lib/browser/profiles.d.ts +67 -3
  161. package/dist/lib/browser/profiles.js +129 -7
  162. package/dist/lib/browser/remote-control.d.ts +2 -2
  163. package/dist/lib/browser/remote-control.js +3 -3
  164. package/dist/lib/browser/runtime-state.d.ts +79 -0
  165. package/dist/lib/browser/runtime-state.js +119 -1
  166. package/dist/lib/browser/service.d.ts +113 -1
  167. package/dist/lib/browser/service.js +454 -40
  168. package/dist/lib/browser/sessions-list.d.ts +2 -1
  169. package/dist/lib/browser/sessions-list.js +4 -13
  170. package/dist/lib/browser/types.d.ts +18 -0
  171. package/dist/lib/budget/config.js +1 -1
  172. package/dist/lib/budget/ledger.js +1 -1
  173. package/dist/lib/byok-usage.js +1 -1
  174. package/dist/lib/capabilities.js +3 -15
  175. package/dist/lib/catchup.d.ts +1 -1
  176. package/dist/lib/catchup.js +1 -1
  177. package/dist/lib/cloud/dispatch.js +1 -1
  178. package/dist/lib/cloud/host.d.ts +3 -3
  179. package/dist/lib/cloud/host.js +5 -5
  180. package/dist/lib/cloud/rush.d.ts +9 -21
  181. package/dist/lib/cloud/rush.js +33 -120
  182. package/dist/lib/cloud/types.d.ts +2 -2
  183. package/dist/lib/commands.js +3 -13
  184. package/dist/lib/computer/actions.d.ts +36 -0
  185. package/dist/lib/computer/actions.js +162 -0
  186. package/dist/lib/computer/dispatch.d.ts +2 -2
  187. package/dist/lib/computer/dispatch.js +2 -2
  188. package/dist/lib/computer/sessions-list.d.ts +3 -3
  189. package/dist/lib/computer/sessions-list.js +2 -2
  190. package/dist/lib/config-keys.d.ts +2 -1
  191. package/dist/lib/config-keys.js +8 -4
  192. package/dist/lib/config-machine-keys.d.ts +4 -2
  193. package/dist/lib/config-machine-keys.js +5 -2
  194. package/dist/lib/crabbox/lease.js +9 -1
  195. package/dist/lib/crabbox/runtimes.d.ts +32 -7
  196. package/dist/lib/crabbox/runtimes.js +72 -30
  197. package/dist/lib/{daemon.d.ts → daemon/daemon.d.ts} +59 -1
  198. package/dist/lib/{daemon.js → daemon/daemon.js} +237 -49
  199. package/dist/lib/daemon-services.d.ts +1 -1
  200. package/dist/lib/daemon-services.js +5 -0
  201. package/dist/lib/daemon-ticks.d.ts +25 -0
  202. package/dist/lib/daemon-ticks.js +31 -1
  203. package/dist/lib/daemon-webhooks.d.ts +102 -0
  204. package/dist/lib/daemon-webhooks.js +210 -0
  205. package/dist/lib/device-config.d.ts +85 -75
  206. package/dist/lib/device-config.js +279 -141
  207. package/dist/lib/devices/config-migration.d.ts +29 -34
  208. package/dist/lib/devices/config-migration.js +209 -130
  209. package/dist/lib/devices/connect.d.ts +2 -2
  210. package/dist/lib/devices/connect.js +2 -2
  211. package/dist/lib/devices/discovery-policy.d.ts +30 -0
  212. package/dist/lib/devices/discovery-policy.js +101 -0
  213. package/dist/lib/devices/fleet-inventory.js +8 -3
  214. package/dist/lib/devices/harness-inventory.d.ts +1 -1
  215. package/dist/lib/devices/harness-inventory.js +12 -3
  216. package/dist/lib/devices/known-hosts.js +1 -1
  217. package/dist/lib/devices/pool.d.ts +10 -5
  218. package/dist/lib/devices/pool.js +5 -7
  219. package/dist/lib/devices/registry.d.ts +1 -1
  220. package/dist/lib/devices/registry.js +1 -1
  221. package/dist/lib/devices/resolve-profile.d.ts +2 -2
  222. package/dist/lib/devices/resolve-profile.js +2 -2
  223. package/dist/lib/devices/resolve-target.d.ts +1 -1
  224. package/dist/lib/devices/resolve-target.js +4 -4
  225. package/dist/lib/devices/self-host.d.ts +1 -1
  226. package/dist/lib/devices/self-host.js +3 -3
  227. package/dist/lib/devices/ssh-config.d.ts +1 -1
  228. package/dist/lib/devices/stats-cache.js +1 -1
  229. package/dist/lib/devices/sync.d.ts +3 -1
  230. package/dist/lib/devices/sync.js +3 -3
  231. package/dist/lib/doctor-diff.js +4 -4
  232. package/dist/lib/drift-sync.js +2 -2
  233. package/dist/lib/drift.js +2 -2
  234. package/dist/lib/event-families.d.ts +1 -1
  235. package/dist/lib/event-stream.d.ts +1 -1
  236. package/dist/lib/event-stream.js +2 -2
  237. package/dist/lib/events-ingest.js +2 -2
  238. package/dist/lib/exec.d.ts +4 -4
  239. package/dist/lib/exec.js +11 -11
  240. package/dist/lib/factory/snapshot.d.ts +1 -1
  241. package/dist/lib/factory/snapshot.js +1 -1
  242. package/dist/lib/{activity.d.ts → feed/activity.d.ts} +1 -1
  243. package/dist/lib/{activity.js → feed/activity.js} +7 -7
  244. package/dist/lib/{events.d.ts → feed/events.d.ts} +2 -2
  245. package/dist/lib/{events.js → feed/events.js} +5 -5
  246. package/dist/lib/{feed.js → feed/feed.js} +4 -4
  247. package/dist/lib/feed-outcome.d.ts +1 -1
  248. package/dist/lib/feed-policy.d.ts +1 -1
  249. package/dist/lib/feed-policy.js +1 -1
  250. package/dist/lib/feed-post.d.ts +1 -1
  251. package/dist/lib/feed-post.js +1 -1
  252. package/dist/lib/feed-ranking.d.ts +1 -1
  253. package/dist/lib/fleet/apply.d.ts +0 -6
  254. package/dist/lib/fleet/apply.js +18 -45
  255. package/dist/lib/fleet/auth-sync.d.ts +16 -35
  256. package/dist/lib/fleet/auth-sync.js +16 -75
  257. package/dist/lib/fleet/capture.js +8 -6
  258. package/dist/lib/fleet/manifest.js +23 -11
  259. package/dist/lib/fleet/types.d.ts +19 -7
  260. package/dist/lib/fleet-cache.d.ts +1 -1
  261. package/dist/lib/fleet-cache.js +1 -1
  262. package/dist/lib/format.d.ts +19 -0
  263. package/dist/lib/format.js +44 -1
  264. package/dist/lib/friction-heuristics.d.ts +1 -1
  265. package/dist/lib/git.d.ts +24 -1
  266. package/dist/lib/git.js +82 -38
  267. package/dist/lib/heal.js +3 -3
  268. package/dist/lib/hooks.d.ts +18 -0
  269. package/dist/lib/hooks.js +113 -1
  270. package/dist/lib/hosts/credentials.d.ts +30 -10
  271. package/dist/lib/hosts/credentials.js +38 -26
  272. package/dist/lib/hosts/dispatch.d.ts +3 -3
  273. package/dist/lib/hosts/dispatch.js +3 -3
  274. package/dist/lib/hosts/option.d.ts +3 -3
  275. package/dist/lib/hosts/option.js +7 -8
  276. package/dist/lib/hosts/passthrough.d.ts +17 -17
  277. package/dist/lib/hosts/passthrough.js +67 -50
  278. package/dist/lib/hosts/providers/devices.d.ts +1 -1
  279. package/dist/lib/hosts/providers/devices.js +1 -1
  280. package/dist/lib/hosts/reconcile.d.ts +1 -1
  281. package/dist/lib/hosts/reconcile.js +1 -1
  282. package/dist/lib/hosts/reconnect.d.ts +1 -1
  283. package/dist/lib/hosts/reconnect.js +2 -2
  284. package/dist/lib/hosts/registry.d.ts +5 -5
  285. package/dist/lib/hosts/registry.js +5 -5
  286. package/dist/lib/hosts/remote-cmd.d.ts +10 -10
  287. package/dist/lib/hosts/remote-cmd.js +25 -18
  288. package/dist/lib/hosts/remote-os.d.ts +4 -4
  289. package/dist/lib/hosts/remote-os.js +4 -4
  290. package/dist/lib/hosts/remote-session-id.d.ts +2 -2
  291. package/dist/lib/hosts/remote-session-id.js +2 -2
  292. package/dist/lib/hosts/routing-flag.d.ts +3 -3
  293. package/dist/lib/hosts/routing-flag.js +4 -5
  294. package/dist/lib/hosts/run-target.d.ts +4 -4
  295. package/dist/lib/hosts/run-target.js +4 -4
  296. package/dist/lib/hosts/session-index.d.ts +2 -2
  297. package/dist/lib/hosts/session-index.js +1 -1
  298. package/dist/lib/hosts/session-marker.d.ts +1 -1
  299. package/dist/lib/hosts/session-marker.js +1 -1
  300. package/dist/lib/hosts/types.d.ts +2 -2
  301. package/dist/lib/hosts/types.js +2 -2
  302. package/dist/lib/import.js +1 -1
  303. package/dist/lib/{migrate.d.ts → installations/migrate.d.ts} +13 -1
  304. package/dist/lib/{migrate.js → installations/migrate.js} +160 -40
  305. package/dist/lib/installations/resolve.js +1 -1
  306. package/dist/lib/installations/strategies.js +1 -1
  307. package/dist/lib/installations/update.js +2 -2
  308. package/dist/lib/{versions.d.ts → installations/versions.d.ts} +12 -3
  309. package/dist/lib/{versions.js → installations/versions.js} +51 -31
  310. package/dist/lib/isolation-boundary-report.js +1 -1
  311. package/dist/lib/linear-projects.d.ts +28 -0
  312. package/dist/lib/linear-projects.js +30 -0
  313. package/dist/lib/loop.js +1 -1
  314. package/dist/lib/mailbox-gc.js +1 -1
  315. package/dist/lib/mailbox.js +1 -1
  316. package/dist/lib/mcp-registry.d.ts +62 -0
  317. package/dist/lib/mcp-registry.js +177 -0
  318. package/dist/lib/mcp.d.ts +5 -0
  319. package/dist/lib/mcp.js +124 -307
  320. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  321. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  322. package/dist/lib/menubar/install-menubar.d.ts +7 -0
  323. package/dist/lib/menubar/install-menubar.js +24 -6
  324. package/dist/lib/menubar/snapshot.d.ts +7 -0
  325. package/dist/lib/menubar/snapshot.js +8 -6
  326. package/dist/lib/models.js +1 -1
  327. package/dist/lib/monitors/config.d.ts +12 -0
  328. package/dist/lib/monitors/config.js +3 -0
  329. package/dist/lib/monitors/dispatch.js +26 -5
  330. package/dist/lib/monitors/engine.js +10 -0
  331. package/dist/lib/monitors/sources/webhook.d.ts +1 -1
  332. package/dist/lib/monitors/state.d.ts +42 -0
  333. package/dist/lib/monitors/state.js +30 -0
  334. package/dist/lib/notify.d.ts +1 -1
  335. package/dist/lib/observe-aliases.d.ts +2 -2
  336. package/dist/lib/observe-aliases.js +2 -11
  337. package/dist/lib/output/git-output.js +2 -2
  338. package/dist/lib/overdue.d.ts +1 -1
  339. package/dist/lib/overdue.js +1 -1
  340. package/dist/lib/permissions-registry.d.ts +65 -0
  341. package/dist/lib/permissions-registry.js +599 -0
  342. package/dist/lib/permissions.d.ts +24 -13
  343. package/dist/lib/permissions.js +52 -271
  344. package/dist/lib/picker.d.ts +16 -0
  345. package/dist/lib/picker.js +33 -3
  346. package/dist/lib/placement.d.ts +1 -1
  347. package/dist/lib/placement.js +4 -4
  348. package/dist/lib/platform/paths.d.ts +8 -0
  349. package/dist/lib/platform/paths.js +11 -0
  350. package/dist/lib/platform/posixpath.js +3 -3
  351. package/dist/lib/{plugin-marketplace.d.ts → plugins/plugin-marketplace.d.ts} +1 -1
  352. package/dist/lib/{plugin-marketplace.js → plugins/plugin-marketplace.js} +2 -2
  353. package/dist/lib/{plugins.d.ts → plugins/plugins.d.ts} +1 -1
  354. package/dist/lib/{plugins.js → plugins/plugins.js} +7 -7
  355. package/dist/lib/{skills.d.ts → plugins/skills.d.ts} +1 -1
  356. package/dist/lib/{skills.js → plugins/skills.js} +7 -7
  357. package/dist/lib/pricing/cost.d.ts +1 -1
  358. package/dist/lib/pricing/cost.js +1 -1
  359. package/dist/lib/profiles-presets.d.ts +1 -1
  360. package/dist/lib/profiles-presets.js +1 -1
  361. package/dist/lib/profiles.js +2 -2
  362. package/dist/lib/project-import.js +4 -1
  363. package/dist/lib/project-launch.d.ts +1 -1
  364. package/dist/lib/project-launch.js +3 -3
  365. package/dist/lib/project-pull.d.ts +128 -0
  366. package/dist/lib/project-pull.js +384 -0
  367. package/dist/lib/project-root.d.ts +2 -2
  368. package/dist/lib/project-root.js +2 -2
  369. package/dist/lib/project-status.js +1 -1
  370. package/dist/lib/projects.d.ts +23 -0
  371. package/dist/lib/projects.js +29 -6
  372. package/dist/lib/refresh.d.ts +12 -1
  373. package/dist/lib/refresh.js +16 -9
  374. package/dist/lib/registry.d.ts +9 -2
  375. package/dist/lib/registry.js +11 -4
  376. package/dist/lib/resources.d.ts +2 -2
  377. package/dist/lib/resources.js +2 -2
  378. package/dist/lib/routers.d.ts +81 -0
  379. package/dist/lib/routers.js +153 -0
  380. package/dist/lib/routine-context.d.ts +1 -0
  381. package/dist/lib/routine-context.js +7 -2
  382. package/dist/lib/routine-notify-owner.d.ts +1 -1
  383. package/dist/lib/routine-notify.d.ts +1 -1
  384. package/dist/lib/routine-notify.js +1 -1
  385. package/dist/lib/routine-process-cleanup.d.ts +1 -1
  386. package/dist/lib/routine-readiness.d.ts +1 -1
  387. package/dist/lib/routine-readiness.js +11 -4
  388. package/dist/lib/routines-placement.d.ts +12 -2
  389. package/dist/lib/routines-placement.js +20 -3
  390. package/dist/lib/routines-project.d.ts +1 -1
  391. package/dist/lib/routines-project.js +1 -1
  392. package/dist/lib/rules/compile.d.ts +1 -0
  393. package/dist/lib/rules/compile.js +10 -2
  394. package/dist/lib/rules/rules.js +1 -1
  395. package/dist/lib/run-notify.js +1 -1
  396. package/dist/lib/runner.d.ts +80 -2
  397. package/dist/lib/runner.js +241 -62
  398. package/dist/lib/sandbox.d.ts +1 -1
  399. package/dist/lib/scheduler.d.ts +1 -1
  400. package/dist/lib/scheduler.js +1 -1
  401. package/dist/lib/{routines.d.ts → scheduling/routines.d.ts} +54 -9
  402. package/dist/lib/{routines.js → scheduling/routines.js} +173 -14
  403. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  404. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  405. package/dist/lib/secrets/agent.js +2 -2
  406. package/dist/lib/secrets/audit.js +1 -1
  407. package/dist/lib/secrets/bundles.d.ts +3 -3
  408. package/dist/lib/secrets/bundles.js +7 -7
  409. package/dist/lib/secrets/index.js +1 -1
  410. package/dist/lib/secrets/list-filter.d.ts +1 -1
  411. package/dist/lib/secrets/list-filter.js +2 -2
  412. package/dist/lib/secrets/push.d.ts +1 -1
  413. package/dist/lib/secrets/push.js +10 -12
  414. package/dist/lib/secrets/remote.d.ts +12 -10
  415. package/dist/lib/secrets/remote.js +21 -14
  416. package/dist/lib/secrets/vault.js +2 -2
  417. package/dist/lib/self-heal/checks/shadowing.js +1 -1
  418. package/dist/lib/self-heal/checks/shims.js +1 -1
  419. package/dist/lib/self-update.d.ts +39 -4
  420. package/dist/lib/self-update.js +78 -25
  421. package/dist/lib/serve/control.d.ts +1 -1
  422. package/dist/lib/serve/control.js +4 -4
  423. package/dist/lib/serve/data.d.ts +1 -1
  424. package/dist/lib/serve/data.js +1 -1
  425. package/dist/lib/serve/stream.js +1 -1
  426. package/dist/lib/service-manifest.d.ts +29 -0
  427. package/dist/lib/service-manifest.js +80 -0
  428. package/dist/lib/session/active.d.ts +59 -7
  429. package/dist/lib/session/active.js +158 -17
  430. package/dist/lib/session/bash-command.js +1 -1
  431. package/dist/lib/session/claude-accounts.d.ts +1 -1
  432. package/dist/lib/session/claude-accounts.js +1 -1
  433. package/dist/lib/session/db.d.ts +10 -2
  434. package/dist/lib/session/db.js +25 -6
  435. package/dist/lib/session/discover.d.ts +77 -0
  436. package/dist/lib/session/discover.js +130 -25
  437. package/dist/lib/session/fork.js +1 -1
  438. package/dist/lib/session/inject.d.ts +1 -1
  439. package/dist/lib/session/insights.d.ts +1 -1
  440. package/dist/lib/session/insights.js +1 -1
  441. package/dist/lib/session/live-metadata.d.ts +15 -0
  442. package/dist/lib/session/live-metadata.js +76 -0
  443. package/dist/lib/session/migrate-targets.d.ts +1 -1
  444. package/dist/lib/session/recovery.d.ts +1 -1
  445. package/dist/lib/session/recovery.js +2 -2
  446. package/dist/lib/session/remote-active.d.ts +10 -1
  447. package/dist/lib/session/remote-active.js +8 -3
  448. package/dist/lib/session/remote-bundle.d.ts +1 -1
  449. package/dist/lib/session/remote-bundle.js +2 -2
  450. package/dist/lib/session/remote-list.d.ts +15 -4
  451. package/dist/lib/session/remote-list.js +40 -3
  452. package/dist/lib/session/remote.d.ts +5 -5
  453. package/dist/lib/session/remote.js +13 -17
  454. package/dist/lib/session/resume-command.d.ts +3 -2
  455. package/dist/lib/session/resume-command.js +4 -3
  456. package/dist/lib/session/resume-owner.d.ts +3 -3
  457. package/dist/lib/session/resume-owner.js +3 -3
  458. package/dist/lib/session/session-cache.d.ts +12 -0
  459. package/dist/lib/session/session-cache.js +2 -0
  460. package/dist/lib/session/shell-programs.js +1 -1
  461. package/dist/lib/session/state.js +5 -5
  462. package/dist/lib/session/team-filter.d.ts +1 -1
  463. package/dist/lib/session/team-filter.js +1 -1
  464. package/dist/lib/session/types.d.ts +3 -3
  465. package/dist/lib/session/width.d.ts +2 -2
  466. package/dist/lib/session/width.js +2 -2
  467. package/dist/lib/share/delete.d.ts +21 -0
  468. package/dist/lib/share/delete.js +42 -0
  469. package/dist/lib/share/publish.d.ts +82 -0
  470. package/dist/lib/share/publish.js +170 -18
  471. package/dist/lib/share/worker-template.js +172 -9
  472. package/dist/lib/shims.js +35 -7
  473. package/dist/lib/smart-launch.d.ts +4 -4
  474. package/dist/lib/smart-launch.js +6 -4
  475. package/dist/lib/snapshot.d.ts +4 -4
  476. package/dist/lib/snapshot.js +2 -2
  477. package/dist/lib/ssh-exec.d.ts +1 -1
  478. package/dist/lib/ssh-exec.js +2 -2
  479. package/dist/lib/ssh-tunnel.d.ts +10 -10
  480. package/dist/lib/ssh-tunnel.js +12 -12
  481. package/dist/lib/staleness/checkers/hooks.d.ts +1 -1
  482. package/dist/lib/staleness/checkers/hooks.js +1 -1
  483. package/dist/lib/staleness/detectors/permissions.js +0 -23
  484. package/dist/lib/staleness/detectors/plugins.js +1 -1
  485. package/dist/lib/staleness/fingerprint.js +1 -1
  486. package/dist/lib/staleness/layers.d.ts +1 -1
  487. package/dist/lib/staleness/layers.js +1 -1
  488. package/dist/lib/staleness/writers/mcp.js +3 -1
  489. package/dist/lib/staleness/writers/plugins.js +1 -1
  490. package/dist/lib/staleness/writers/types.d.ts +8 -0
  491. package/dist/lib/startup/command-registry.d.ts +5 -147
  492. package/dist/lib/startup/command-registry.js +38 -303
  493. package/dist/lib/startup/dev-build.d.ts +0 -21
  494. package/dist/lib/startup/dev-build.js +29 -8
  495. package/dist/lib/state.d.ts +19 -1
  496. package/dist/lib/state.js +120 -51
  497. package/dist/lib/subagents.js +1 -1
  498. package/dist/lib/sync-status.js +1 -1
  499. package/dist/lib/sync-umbrella.d.ts +6 -1
  500. package/dist/lib/sync-umbrella.js +9 -4
  501. package/dist/lib/teams/agents.js +2 -2
  502. package/dist/lib/teams/registry.js +1 -1
  503. package/dist/lib/terminal/backends/vscodium-agent.js +1 -1
  504. package/dist/lib/terminal/engine.js +1 -1
  505. package/dist/lib/terminal/index.d.ts +4 -0
  506. package/dist/lib/terminal/index.js +3 -0
  507. package/dist/lib/terminal/inject.d.ts +2 -2
  508. package/dist/lib/terminal/inject.js +2 -2
  509. package/dist/lib/terminal/transport.js +1 -1
  510. package/dist/lib/tmux/index.d.ts +1 -1
  511. package/dist/lib/tmux/index.js +1 -1
  512. package/dist/lib/tmux/session.d.ts +21 -5
  513. package/dist/lib/tmux/session.js +76 -22
  514. package/dist/lib/triggers/handlers.d.ts +1 -1
  515. package/dist/lib/triggers/handlers.js +2 -2
  516. package/dist/lib/triggers/webhook.d.ts +36 -2
  517. package/dist/lib/triggers/webhook.js +97 -42
  518. package/dist/lib/types.d.ts +18 -6
  519. package/dist/lib/usage-fleet.d.ts +1 -1
  520. package/dist/lib/usage-fleet.js +1 -1
  521. package/dist/lib/usage-refresh.d.ts +1 -1
  522. package/dist/lib/usage-refresh.js +3 -3
  523. package/dist/lib/version-duplicates.js +2 -2
  524. package/dist/lib/view-types.d.ts +56 -0
  525. package/dist/lib/view-types.js +1 -0
  526. package/dist/lib/watchdog/rotate.d.ts +2 -2
  527. package/dist/lib/watchdog/rotate.js +3 -3
  528. package/dist/lib/watchdog/runner.d.ts +2 -3
  529. package/dist/lib/watchdog/runner.js +3 -4
  530. package/dist/lib/workflows.js +1 -1
  531. package/package.json +2 -1
  532. package/scripts/postinstall.js +2 -2
  533. package/dist/commands/bench.d.ts +0 -2
  534. package/dist/commands/bench.js +0 -101
  535. package/dist/commands/cp.d.ts +0 -84
  536. package/dist/commands/cp.js +0 -231
  537. package/dist/commands/login.d.ts +0 -2
  538. package/dist/lib/resources/commands.d.ts +0 -46
  539. package/dist/lib/resources/commands.js +0 -211
  540. package/dist/lib/resources/hooks.d.ts +0 -16
  541. package/dist/lib/resources/hooks.js +0 -153
  542. package/dist/lib/resources/mcp.d.ts +0 -34
  543. package/dist/lib/resources/mcp.js +0 -250
  544. package/dist/lib/resources/memory.d.ts +0 -15
  545. package/dist/lib/resources/memory.js +0 -46
  546. package/dist/lib/resources/permissions.d.ts +0 -13
  547. package/dist/lib/resources/permissions.js +0 -202
  548. package/dist/lib/resources/rules.d.ts +0 -46
  549. package/dist/lib/resources/rules.js +0 -179
  550. package/dist/lib/resources/skills.d.ts +0 -37
  551. package/dist/lib/resources/skills.js +0 -247
  552. package/dist/lib/resources/subagents.d.ts +0 -46
  553. package/dist/lib/resources/subagents.js +0 -202
  554. /package/dist/lib/{feed.d.ts → feed/feed.d.ts} +0 -0
@@ -34,7 +34,7 @@ import { costOfUsage, costOfUsageNoCache } from '../pricing/index.js';
34
34
  import { machineForSessionFile } from './origin-machine.js';
35
35
  export { machineForSessionFile } from './origin-machine.js';
36
36
  import { mapBounded } from '../concurrency.js';
37
- import { getDB, getScanStampByPath, getScanStampsForPaths, getParserStatesForPaths, getDirLedgerForPaths, recordDirScans, recordScans, syncLabels, seedLabelsFromNames, syncTopics, upsertSessionsBatch, querySessions, countSessions, ftsSearch, tryClaimScan, releaseScan, cacheLinearProject, } from './db.js';
37
+ import { getDB, getScanStampByPath, getScanStampsForPaths, getParserStatesForPaths, getDirLedgerForPaths, recordDirScans, recordScans, syncLabels, seedLabelsFromNames, syncTopics, upsertSessionsBatch, querySessions, countSessions, ftsSearch, tryClaimScan, releaseScan, scanInProgressByLivePid, cacheLinearProject, } from './db.js';
38
38
  import { buildRunNameMap } from './run-names.js';
39
39
  import { resolveLinearApiKey } from '../linear-cache.js';
40
40
  import { ToolCallCollector, collectClaudeToolCalls, collectCodexToolCalls, } from './tool-calls.js';
@@ -142,6 +142,12 @@ function dirLedgerDisabled() {
142
142
  return v === '1' || v === 'true';
143
143
  }
144
144
  let cachedOpenClawWorkspaces = null;
145
+ /** Max time a `waitForScan` repair waits for a concurrent scan to settle. */
146
+ const WAIT_FOR_SCAN_TIMEOUT_MS = 2_000;
147
+ const WAIT_FOR_SCAN_POLL_MS = 100;
148
+ function sleep(ms) {
149
+ return new Promise(resolve => setTimeout(resolve, ms));
150
+ }
145
151
  const cachedAgentVersions = new Map();
146
152
  /**
147
153
  * Discover sessions. Scans only files whose (mtime, size) have changed since
@@ -154,31 +160,81 @@ const cachedAgentVersions = new Map();
154
160
  * TTL, no external lock files needed.
155
161
  */
156
162
  export async function discoverSessions(options) {
163
+ const { claimed } = await scanSessionsIncremental({
164
+ agent: options?.agent,
165
+ onProgress: options?.onProgress,
166
+ });
167
+ if (!claimed && options?.waitForScan) {
168
+ // Lost the single-flight claim to another live process (a foreground
169
+ // `agents sessions*` or the daemon's index warm). Rather than return the
170
+ // pre-scan snapshot that just missed, wait (bounded) for that scan to finish
171
+ // so the read below reflects what it wrote (RUSH-2682 cold-miss repair).
172
+ await waitForScanToSettle();
173
+ }
174
+ return queryIndexedSessions(options, {
175
+ skipExistenceCheck: options?.skipExistenceCheck ?? false,
176
+ });
177
+ }
178
+ /**
179
+ * The write half of {@link discoverSessions}: claim the single-flight scan slot,
180
+ * incrementally index this host's transcript dirs, and report what was parsed.
181
+ *
182
+ * Split out so a caller that only wants the index refreshed — the daemon's warm
183
+ * tick — can run it WITHOUT the listing query `discoverSessions` ends with. That
184
+ * query is not free: it applies a cwd filter, runs the `archived_at`-writing
185
+ * existence check, and can issue a Linear fetch, none of which index anything
186
+ * (RUSH-2691). Keeping one implementation here is also what stops the tick and
187
+ * the foreground path from drifting apart.
188
+ */
189
+ export async function scanSessionsIncremental(options) {
157
190
  // Touch the DB so the schema is ready and connection is cached for this run.
158
191
  getDB();
159
192
  const agents = options?.agent ? [options.agent] : SESSION_AGENTS;
160
193
  const onProgress = options?.onProgress;
161
- if (tryClaimScan(process.pid)) {
162
- try {
163
- // Bounded + staggered instead of a single Promise.all: scanning every
164
- // agent's dotfile dir (~/.claude, ~/.codex, ~/.gemini, …) simultaneously
165
- // reads to behavioral EDR (CrowdStrike Falcon) as a ransomware-style bulk
166
- // file-enumeration sweep. Same dirs, same results — just not all at once.
167
- await scanAgentsBounded(agents, agent => dispatchAgentScan(agent, onProgress));
168
- await scanAgentsBounded(agents, agent => scanRoutineArchivesIncremental(agent, onProgress));
169
- // Seed labels from `agents run --name` handles onto the freshly-scanned
170
- // rows by id. Runs AFTER the per-agent scans (which applied agent-generated
171
- // titles via syncLabels), so a real title always wins and the seed only
172
- // backfills sessions that would otherwise be unnamed.
173
- seedLabelsFromNames(buildRunNameMap());
174
- }
175
- finally {
176
- releaseScan(process.pid);
177
- }
194
+ if (!tryClaimScan(process.pid))
195
+ return { claimed: false, scanned: 0 };
196
+ // `parsed` climbs monotonically within one scanner run, so the last value per
197
+ // (phase, agent) is that scanner's total. Phase-keyed because the dotfile scan
198
+ // and the routine-archive scan both report under the same agent id.
199
+ const parsedByPhaseAgent = new Map();
200
+ const track = (phase) => (p) => {
201
+ parsedByPhaseAgent.set(`${phase}\0${p.agent}`, p.parsed);
202
+ onProgress?.(p);
203
+ };
204
+ try {
205
+ // Bounded + staggered instead of a single Promise.all: scanning every
206
+ // agent's dotfile dir (~/.claude, ~/.codex, ~/.gemini, …) simultaneously
207
+ // reads to behavioral EDR (CrowdStrike Falcon) as a ransomware-style bulk
208
+ // file-enumeration sweep. Same dirs, same results — just not all at once.
209
+ await scanAgentsBounded(agents, agent => dispatchAgentScan(agent, track('dotfiles')));
210
+ await scanAgentsBounded(agents, agent => scanRoutineArchivesIncremental(agent, track('routines')));
211
+ // Seed labels from `agents run --name` handles onto the freshly-scanned
212
+ // rows by id. Runs AFTER the per-agent scans (which applied agent-generated
213
+ // titles via syncLabels), so a real title always wins and the seed only
214
+ // backfills sessions that would otherwise be unnamed.
215
+ seedLabelsFromNames(buildRunNameMap());
178
216
  }
179
- return queryIndexedSessions(options, {
180
- skipExistenceCheck: options?.skipExistenceCheck ?? false,
181
- });
217
+ finally {
218
+ releaseScan(process.pid);
219
+ }
220
+ let scanned = 0;
221
+ for (const n of parsedByPhaseAgent.values())
222
+ scanned += n;
223
+ return { claimed: true, scanned };
224
+ }
225
+ /**
226
+ * Poll until no live process holds the scan claim, or the bound elapses
227
+ * (RUSH-2682). Bounded so a wedged/slow scan can never hang a foreground preview.
228
+ * Exported for the cold-miss repair test.
229
+ */
230
+ export async function waitForScanToSettle(timeoutMs = WAIT_FOR_SCAN_TIMEOUT_MS, pollMs = WAIT_FOR_SCAN_POLL_MS) {
231
+ const deadline = Date.now() + timeoutMs;
232
+ while (scanInProgressByLivePid()) {
233
+ if (Date.now() >= deadline)
234
+ return false;
235
+ await sleep(pollMs);
236
+ }
237
+ return true;
182
238
  }
183
239
  /** Read the current SQLite snapshot without scanning or parsing transcript files. */
184
240
  export async function queryIndexedSessions(options, indexedOptions = {}) {
@@ -202,6 +258,38 @@ export async function queryIndexedSessions(options, indexedOptions = {}) {
202
258
  }
203
259
  return scopeToManaged(sessions, agents, options);
204
260
  }
261
+ /**
262
+ * Resolve a full-or-partial session id against the LOCAL SQLite index only.
263
+ *
264
+ * A plain WAL read through `queryIndexedSessions` — same origin-machine
265
+ * attribution and managed scoping every indexed read gets — with NO incremental
266
+ * discovery scan (so none of `tryClaimScan`/`releaseScan`'s `BEGIN IMMEDIATE`
267
+ * writer lock) and NO fleet SSH fan-out. This is the crash-restart storm path
268
+ * (RUSH-2477): dozens of `sessions resume <id>` at once for a known local id must
269
+ * each be a cheap read, never a writer-lock contender or a dial into the
270
+ * not-yet-up tailnet. Exact id first, then prefix (matching `findSessionsById`),
271
+ * so a complete id never also drags in its prefix siblings. Returns `[]` on a
272
+ * genuine local miss, leaving the caller to fall back to the fleet resolver.
273
+ *
274
+ * The existence check is left ON (`skipExistenceCheck: false`), exactly as the old
275
+ * `discoverSessions` path and `findSessionsById` do (RUSH-2436): it KEEPS a
276
+ * file-gone session whose user turns still live in `session_text` (flagged
277
+ * archived) and SUPPRESSES a contentless phantom — so a phantom id misses here and
278
+ * falls through to the fleet resolver, instead of resolving to a row with no real
279
+ * transcript to resume. For a present transcript — the storm's actual case, since
280
+ * the crashed tabs' files are on disk — the check does no writes, so the lock-free
281
+ * guarantee holds; it only writes to (un)archive a genuinely missing or resurrected
282
+ * file, which is not the 20-at-once resume path.
283
+ */
284
+ export async function resolveIndexedSessionById(idQuery) {
285
+ const q = idQuery.trim();
286
+ if (!q)
287
+ return [];
288
+ const exact = await queryIndexedSessions({ all: true, unbounded: true, idExact: q }, { resolveLinear: false, skipExistenceCheck: false });
289
+ if (exact.length > 0)
290
+ return exact;
291
+ return queryIndexedSessions({ all: true, unbounded: true, idPrefix: q }, { resolveLinear: false, skipExistenceCheck: false });
292
+ }
205
293
  const linearProjectCache = new Map();
206
294
  async function resolveLinearProjects(sessions) {
207
295
  const apiKey = resolveLinearApiKey();
@@ -310,8 +398,8 @@ function dispatchAgentScan(agent, onProgress) {
310
398
  case 'codex': return scanCodexIncremental(onProgress);
311
399
  case 'gemini': return scanGeminiIncremental(onProgress);
312
400
  case 'antigravity': return scanAntigravityIncremental(onProgress);
313
- case 'opencode': return scanOpenCodeIncremental();
314
- case 'openclaw': return scanOpenClawIncremental();
401
+ case 'opencode': return scanOpenCodeIncremental(onProgress);
402
+ case 'openclaw': return scanOpenClawIncremental(onProgress);
315
403
  case 'rush': return scanRushIncremental(onProgress);
316
404
  case 'hermes': return scanHermesIncremental(onProgress);
317
405
  case 'kimi': return scanKimiIncremental(onProgress);
@@ -418,6 +506,8 @@ function buildQueryOptions(options, agents, opts) {
418
506
  skipExistenceCheck: options?.skipExistenceCheck,
419
507
  skill: options?.skill,
420
508
  plugin: options?.plugin,
509
+ idExact: options?.idExact,
510
+ idPrefix: options?.idPrefix,
421
511
  };
422
512
  }
423
513
  /**
@@ -1940,7 +2030,7 @@ function openCodeSessionStamp(times, bytes, dbScan) {
1940
2030
  return { fileMtimeMs: known.length === 0 ? 0 : Math.floor(Math.max(...known)), fileSize: size };
1941
2031
  }
1942
2032
  /** Scan OpenCode sessions from its SQLite database when the DB file has changed. */
1943
- async function scanOpenCodeIncremental() {
2033
+ async function scanOpenCodeIncremental(onProgress) {
1944
2034
  if (!fs.existsSync(OPENCODE_DB))
1945
2035
  return;
1946
2036
  const stat = safeStatSync(OPENCODE_DB);
@@ -2135,6 +2225,12 @@ async function scanOpenCodeIncremental() {
2135
2225
  entries.push({ meta, content: topic || '', scan });
2136
2226
  }
2137
2227
  upsertSessionsBatch(entries);
2228
+ // Report what this scan indexed. OpenCode is one SQLite DB rather than N
2229
+ // transcript files, so the whole batch lands as a single progress emit —
2230
+ // enough for the daemon's warm tick to count it (RUSH-2691); without it a
2231
+ // tick whose only changed sessions were OpenCode's reported 0 and logged
2232
+ // nothing, the same silent-success class this tick exists to remove.
2233
+ onProgress?.({ agent: 'opencode', parsed: entries.length, total: entries.length });
2138
2234
  // Stamp the OpenCode DB itself so we can short-circuit on the next run.
2139
2235
  recordScans([{ filePath: OPENCODE_DB, scan: currentScan }]);
2140
2236
  }
@@ -2154,7 +2250,7 @@ async function scanOpenCodeIncremental() {
2154
2250
  // OpenClaw
2155
2251
  // ---------------------------------------------------------------------------
2156
2252
  /** Scan active OpenClaw channels and cron jobs via the openclaw CLI. */
2157
- async function scanOpenClawIncremental() {
2253
+ async function scanOpenClawIncremental(onProgress) {
2158
2254
  // Check if openclaw is installed — silently skip if not. `which` is POSIX-only
2159
2255
  // (Windows resolves PATH with `where`), so a bare `which` throws ENOENT on every
2160
2256
  // Windows run and silently disabled the entire OpenClaw scan there — its sessions
@@ -2247,6 +2343,15 @@ async function scanOpenClawIncremental() {
2247
2343
  /* cron command failed */
2248
2344
  }
2249
2345
  upsertSessionsBatch(entries);
2346
+ // Deliberately NO onProgress emit, unlike every other scanner (RUSH-2691).
2347
+ // This one cannot report a delta: its gate is a 60s TTL (not a store stamp),
2348
+ // `scan` above stamps a fresh `now` on every entry every run, and `entries` is
2349
+ // the CURRENT INVENTORY — running channels plus cron jobs — rebuilt from
2350
+ // scratch each pass. Emitting entries.length would report "how many openclaw
2351
+ // things exist", re-counted every 60s forever, which is a worse lie than
2352
+ // silence: the warm tick's number means "transcripts parsed this scan". Giving
2353
+ // OpenClaw a real per-entry stamp is tracked separately; until then it
2354
+ // contributes 0 and the docblock on IncrementalScanResult says so.
2250
2355
  db.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES ('openclaw_last_scan_ms', ?)`).run(String(Date.now()));
2251
2356
  }
2252
2357
  /** Incrementally re-scan changed Rush session files and upsert into the DB. */
@@ -80,7 +80,7 @@ export function forkSession(source, opts = {}) {
80
80
  // Label sidecar (seeds the DB label; survives rescans until an agent title
81
81
  // supersedes it), mirroring `agents run --name`.
82
82
  recordRunName({ sessionId: newId, name: label, agent: source.agent, cwd: source.cwd });
83
- // Register the new session so it resolves immediately (by `agents resume`,
83
+ // Register the new session so it resolves immediately (by `agents sessions resume`,
84
84
  // `agents sessions`, etc.) without waiting for the next scan.
85
85
  const stamp = opts.now ?? new Date().toISOString();
86
86
  const meta = {
@@ -9,7 +9,7 @@
9
9
  * engine stays agnostic of how a target was discovered.
10
10
  */
11
11
  import type { ReplyRail } from './provenance.js';
12
- import type { InjectTarget } from '../terminal/inject.js';
12
+ import type { InjectTarget } from '../terminal/index.js';
13
13
  /**
14
14
  * Map a session's `ReplyRail` to an engine `InjectTarget`. Today only tmux rails
15
15
  * are externally addressable (provenance.ts:143-149); a null rail yields null and
@@ -2,7 +2,7 @@
2
2
  * Behavioural facets of a coding session, and the cross-session rollup built from them.
3
3
  *
4
4
  * This is the engine behind `agents insights`. It answers "how do you work" rather than
5
- * "what did you spend" (`agents cost`) or "what shipped" (`agents output`), and it is
5
+ * "what did you spend" (`agents insights cost`) or "what shipped" (`agents insights output`), and it is
6
6
  * the only surface that splits any of it by the account that produced the work.
7
7
  *
8
8
  * Everything here is a pure function of a parsed `SessionEvent[]`, so it is testable
@@ -2,7 +2,7 @@
2
2
  * Behavioural facets of a coding session, and the cross-session rollup built from them.
3
3
  *
4
4
  * This is the engine behind `agents insights`. It answers "how do you work" rather than
5
- * "what did you spend" (`agents cost`) or "what shipped" (`agents output`), and it is
5
+ * "what did you spend" (`agents insights cost`) or "what shipped" (`agents insights output`), and it is
6
6
  * the only surface that splits any of it by the account that produced the work.
7
7
  *
8
8
  * Everything here is a pure function of a parsed `SessionEvent[]`, so it is testable
@@ -0,0 +1,15 @@
1
+ import { type SessionMeta } from './types.js';
2
+ import type { ActiveSession } from './active.js';
3
+ /**
4
+ * Reshape one live `ActiveSession` into a `SessionMeta` candidate for the id
5
+ * resolver. Returns `null` for a row that cannot back a durable session — no
6
+ * `sessionId`, or a `kind` that is not a session-tracked harness (cloud/team
7
+ * rows without a real agent transcript). Pure: the caller supplies `self` (the
8
+ * local machine id) and `nowMs` so the row is deterministic and testable.
9
+ */
10
+ export declare function activeSessionToSessionMeta(active: ActiveSession, self: string, nowMs: number): SessionMeta | null;
11
+ /**
12
+ * Map every eligible live session to a `SessionMeta` candidate. Ineligible rows
13
+ * (no id, non-agent kind) are dropped. Order follows the input.
14
+ */
15
+ export declare function liveSessionMetas(active: ActiveSession[], self: string, nowMs: number): SessionMeta[];
@@ -0,0 +1,76 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Live-registry → SessionMeta bridge (RUSH-2682)
3
+ // ---------------------------------------------------------------------------
4
+ //
5
+ // A session the live registry (`getActiveSessions`) already knows about can be
6
+ // minutes ahead of the transcript index on the SAME box: indexing is lazy and
7
+ // only runs inside `discoverSessions`, so a session this machine JUST started is
8
+ // "running" in `agents sessions --active` while `agents sessions preview <id>`
9
+ // answers "No session matching" until an unrelated `agents sessions*` call
10
+ // happens to scan (measured 7.6 min blind on zion, agents-cli 1.22.39).
11
+ //
12
+ // This module converts a running `ActiveSession` into a `SessionMeta` candidate
13
+ // so the id resolver behind `preview` / `resume` / `focus` can resolve and render
14
+ // a running session with no transcript row yet, instead of claiming it does not
15
+ // exist. It parses no transcript and renders nothing — it only reshapes process
16
+ // state the live registry already computed. When the transcript IS on disk, the
17
+ // synthesized row carries its path, so the downstream `buildPreview` renders the
18
+ // real digest; otherwise it renders the header + a "not indexed here" note.
19
+ import { deriveShortId } from './short-id.js';
20
+ import { isSessionTrackedAgent } from './types.js';
21
+ /**
22
+ * Reshape one live `ActiveSession` into a `SessionMeta` candidate for the id
23
+ * resolver. Returns `null` for a row that cannot back a durable session — no
24
+ * `sessionId`, or a `kind` that is not a session-tracked harness (cloud/team
25
+ * rows without a real agent transcript). Pure: the caller supplies `self` (the
26
+ * local machine id) and `nowMs` so the row is deterministic and testable.
27
+ */
28
+ export function activeSessionToSessionMeta(active, self, nowMs) {
29
+ const id = active.sessionId;
30
+ if (!id)
31
+ return null;
32
+ if (!isSessionTrackedAgent(active.kind))
33
+ return null;
34
+ const startedMs = active.startedAtMs ?? nowMs;
35
+ const lastMs = active.lastActivityMs ?? startedMs;
36
+ return {
37
+ id,
38
+ shortId: deriveShortId(id),
39
+ agent: active.kind,
40
+ timestamp: new Date(startedMs).toISOString(),
41
+ lastActivity: new Date(lastMs).toISOString(),
42
+ // An empty file path is honest — a just-created session may have no
43
+ // transcript on disk yet, and `buildPreview` renders the header + a live
44
+ // note for that case rather than trying to parse a missing file.
45
+ filePath: active.sessionFile ?? '',
46
+ cwd: active.cwd,
47
+ project: active.project ?? undefined,
48
+ label: active.label,
49
+ topic: active.topic,
50
+ version: active.version,
51
+ messageCount: undefined,
52
+ // The row runs HERE — the local live registry is machine-local, so a match
53
+ // resolves without an SSH hop back to a peer.
54
+ machine: active.machine ?? self,
55
+ ticketId: active.ticket?.id,
56
+ prUrl: active.pr?.url,
57
+ prNumber: active.pr?.number,
58
+ worktreeSlug: active.worktree?.slug,
59
+ gitBranch: active.worktree?.branch,
60
+ origin: active.origin,
61
+ routineName: active.routineName,
62
+ };
63
+ }
64
+ /**
65
+ * Map every eligible live session to a `SessionMeta` candidate. Ineligible rows
66
+ * (no id, non-agent kind) are dropped. Order follows the input.
67
+ */
68
+ export function liveSessionMetas(active, self, nowMs) {
69
+ const out = [];
70
+ for (const a of active) {
71
+ const meta = activeSessionToSessionMeta(a, self, nowMs);
72
+ if (meta)
73
+ out.push(meta);
74
+ }
75
+ return out;
76
+ }
@@ -18,7 +18,7 @@ import type { DeviceStats, Headroom } from '../devices/health.js';
18
18
  import type { CrabboxBox } from '../crabbox/cli.js';
19
19
  /** A machine the current session could be relocated onto. */
20
20
  export interface MigrateTarget {
21
- /** The `--host` value: a host/device name, or a warm box slug for ephemeral. */
21
+ /** The `--device` value: a host/device name, or a warm box slug for ephemeral. */
22
22
  name: string;
23
23
  /** Where the target comes from — a fleet host/device, or a warm crabbox box. */
24
24
  kind: 'fleet' | 'ephemeral';
@@ -1,4 +1,4 @@
1
- import { type RotateCandidate } from '../rotate.js';
1
+ import { type RotateCandidate } from '../accounting/rotate.js';
2
2
  import type { AgentId } from '../types.js';
3
3
  import type { SessionMeta } from './types.js';
4
4
  export type SessionRecoveryTarget = {
@@ -4,8 +4,8 @@ import { AGENTS, agentConfigDirName } from '../agents.js';
4
4
  import { isSelfHost } from '../devices/self-host.js';
5
5
  import { nativeResume } from '../exec.js';
6
6
  import { machineId, normalizeHost } from '../machine-id.js';
7
- import { collectRunCandidates, formatNoHealthyAccountError, pickBalancedCandidate, readinessFromCandidate, } from '../rotate.js';
8
- import { getVersionHomePath } from '../versions.js';
7
+ import { collectRunCandidates, formatNoHealthyAccountError, pickBalancedCandidate, readinessFromCandidate, } from '../accounting/rotate.js';
8
+ import { getVersionHomePath } from '../installations/versions.js';
9
9
  export class SessionRecoveryError extends Error {
10
10
  constructor(message) {
11
11
  super(message);
@@ -19,10 +19,19 @@ export interface RemoteActiveResult {
19
19
  sessions: ActiveSession[];
20
20
  /** How many peer machines we attempted to reach (drives the empty-fleet tip). */
21
21
  deviceCount: number;
22
+ /**
23
+ * Peer device names that were unreachable, timed out, or lacked the CLI —
24
+ * distinct from a peer that answered with zero sessions. Named so an empty
25
+ * fleet-wide result can say WHICH peers went unheard rather than reading
26
+ * identical to "the fleet is genuinely idle" (RUSH-2507).
27
+ */
28
+ skipped: string[];
29
+ /** True when the device list itself could not be loaded — no peer was even attempted. */
30
+ discoveryFailed: boolean;
22
31
  }
23
32
  /**
24
33
  * Gather active sessions from other machines. With an explicit `hosts` list
25
- * (from `--host`), fan out to exactly those. Otherwise sweep the registered,
34
+ * (from `--device`), fan out to exactly those. Otherwise sweep the registered,
26
35
  * online devices from `ag devices`, excluding this machine and any without an
27
36
  * address. Results from all peers run in parallel and are flattened.
28
37
  * `opts.quiet` suppresses the per-device stderr line for callers that report
@@ -7,7 +7,7 @@
7
7
  * it came from so the renderer can bucket by computer.
8
8
  *
9
9
  * Peers are the registered, online devices from `ag devices` (or an explicit
10
- * `--host` list). `--local` on the remote invocation is critical: it stops the
10
+ * `--device` list). `--local` on the remote invocation is critical: it stops the
11
11
  * peer from fanning out to *its* devices, so the sweep never recurses.
12
12
  *
13
13
  * A dead or slow host is skipped with a stderr note, never fatal — one asleep
@@ -67,7 +67,7 @@ export function parseRemoteActive(stdout, machine) {
67
67
  }
68
68
  /**
69
69
  * Gather active sessions from other machines. With an explicit `hosts` list
70
- * (from `--host`), fan out to exactly those. Otherwise sweep the registered,
70
+ * (from `--device`), fan out to exactly those. Otherwise sweep the registered,
71
71
  * online devices from `ag devices`, excluding this machine and any without an
72
72
  * address. Results from all peers run in parallel and are flattened.
73
73
  * `opts.quiet` suppresses the per-device stderr line for callers that report
@@ -81,5 +81,10 @@ export async function gatherRemoteActive(hosts, opts) {
81
81
  parse: parseRemoteActive,
82
82
  quiet: opts?.quiet,
83
83
  });
84
- return { sessions: result.items, deviceCount: result.deviceCount };
84
+ return {
85
+ sessions: result.items,
86
+ deviceCount: result.deviceCount,
87
+ skipped: result.skipped,
88
+ discoveryFailed: result.discoveryFailed,
89
+ };
85
90
  }
@@ -7,6 +7,6 @@ export interface RemotePullResult {
7
7
  * Run `agents sessions export …exportArgs --stdout` on each host and parse the
8
8
  * streamed bundle. A host that fails (unreachable, remote error, bad output) is
9
9
  * collected in `errors` and skipped — one asleep peer never aborts the pull.
10
- * `exportArgs` must NOT contain --host (the remote export runs for itself only).
10
+ * `exportArgs` must NOT contain --device (the remote export runs for itself only).
11
11
  */
12
12
  export declare function pullBundlesFromHosts(hosts: string[], exportArgs: string[]): Promise<RemotePullResult>;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Multi-device session transfer over the EXISTING SSH fleet transport
3
- * (RUSH-1712) — no R2, no daemon. `agents sessions export --host <h>` and
3
+ * (RUSH-1712) — no R2, no daemon. `agents sessions export --device <h>` and
4
4
  * `agents sessions import --from-host <h>` both run `agents sessions export
5
5
  * … --stdout` ON the peer and stream the bundle back over the same SSH path the
6
6
  * cross-machine listing already uses (resolveExplicitTargets + ssh-exec), then
@@ -31,7 +31,7 @@ function remoteAgentsCommand(args, os) {
31
31
  * Run `agents sessions export …exportArgs --stdout` on each host and parse the
32
32
  * streamed bundle. A host that fails (unreachable, remote error, bad output) is
33
33
  * collected in `errors` and skipped — one asleep peer never aborts the pull.
34
- * `exportArgs` must NOT contain --host (the remote export runs for itself only).
34
+ * `exportArgs` must NOT contain --device (the remote export runs for itself only).
35
35
  */
36
36
  export async function pullBundlesFromHosts(hosts, exportArgs) {
37
37
  const targets = await resolveExplicitTargets(hosts);
@@ -60,7 +60,7 @@ export interface RemoteListResult {
60
60
  export declare function isAutomaticSessionPeer(d: DeviceProfile, self: string): boolean;
61
61
  /**
62
62
  * Gather listing sessions from other machines. With an explicit `hosts` list
63
- * (from `--host`), fan out to exactly those. Otherwise sweep the registered,
63
+ * (from `--device`), fan out to exactly those. Otherwise sweep the registered,
64
64
  * online devices from `ag devices`, excluding this machine and any without an
65
65
  * address. `forwardedArgs` are the caller's own sessions args (query + filters,
66
66
  * already `--json`) so every peer returns the same slice this machine asked for.
@@ -113,22 +113,33 @@ export declare function resolvePeerTarget(machine: string): Promise<{
113
113
  target: string;
114
114
  os?: string;
115
115
  } | undefined>;
116
+ /**
117
+ * Fetch one remote session's preview digest from its owning peer — the data
118
+ * behind the picker pane for a `_remote` row, whose transcript file this
119
+ * machine cannot parse. Runs the peer's own `agents sessions preview <id>
120
+ * --local --json` (the same envelope `agents sessions preview` already
121
+ * delegates to for a remote id) and returns its `preview` object, verbatim and
122
+ * UNSANITIZED — the caller owns scrubbing peer-supplied strings before any of
123
+ * them reach a TTY. Undefined on every failure: unregistered machine, SSH
124
+ * error, timeout, version-skewed peer with no `--json` preview envelope.
125
+ */
126
+ export declare function fetchPeerPreviewDigest(sessionId: string, machine: string, timeoutMs?: number): Promise<unknown | undefined>;
116
127
  /**
117
128
  * Run `agents <args>` ON a peer over SSH, attached to this terminal (inherited
118
129
  * stdio). `args` is the full arg vector after the binary — callers pass e.g.
119
130
  * `['sessions', id, '--markdown']` or `['sessions', 'resume', id]`. Used when a
120
131
  * picked session lives on another machine: its transcript and agent binary are
121
132
  * there, so both reading (no TTY) and resuming (TTY) must execute on the peer —
122
- * not via a local `--host` hop, which would discover locally and dead-end for a
133
+ * not via a local `--device` hop, which would discover locally and dead-end for a
123
134
  * session that exists only on the peer. Resolves 'no-target' when the machine
124
135
  * isn't a dialable registered device; the caller surfaces a clear message.
125
136
  *
126
137
  * `opts.env` adds variables to the remote command. It deliberately does NOT
127
- * carry `AGENTS_FLEET_REMOTE` the way the `--host` passthrough does: that marker
138
+ * carry `AGENTS_FLEET_REMOTE` the way the `--device` passthrough does: that marker
128
139
  * gates consent-sensitive actions on the far side
129
140
  * (lib/browser/remote-control.ts), and a resumed agent is a long-lived session
130
141
  * that would inherit it for its whole life — `agents browser start` inside it
131
- * would then be refused as a cross-machine drive. A one-shot `--host` command
142
+ * would then be refused as a cross-machine drive. A one-shot `--device` command
132
143
  * can carry the marker; a session cannot.
133
144
  */
134
145
  export declare function runOnPeer(args: string[], machine: string, opts?: {
@@ -523,22 +523,59 @@ export async function resolvePeerTarget(machine) {
523
523
  }
524
524
  return undefined;
525
525
  }
526
+ /** Interactive ceiling for a picker-driven peer preview fetch. Tighter than the
527
+ * fan-out's 60s: the user is arrowing through rows, and a peer that can't
528
+ * answer a one-session digest in this window should degrade to the metadata
529
+ * card rather than hold a "fetching…" pane open. */
530
+ const PEER_PREVIEW_TIMEOUT_MS = 15_000;
531
+ /**
532
+ * Fetch one remote session's preview digest from its owning peer — the data
533
+ * behind the picker pane for a `_remote` row, whose transcript file this
534
+ * machine cannot parse. Runs the peer's own `agents sessions preview <id>
535
+ * --local --json` (the same envelope `agents sessions preview` already
536
+ * delegates to for a remote id) and returns its `preview` object, verbatim and
537
+ * UNSANITIZED — the caller owns scrubbing peer-supplied strings before any of
538
+ * them reach a TTY. Undefined on every failure: unregistered machine, SSH
539
+ * error, timeout, version-skewed peer with no `--json` preview envelope.
540
+ */
541
+ export async function fetchPeerPreviewDigest(sessionId, machine, timeoutMs = PEER_PREVIEW_TIMEOUT_MS) {
542
+ const peer = await resolvePeerTarget(machine);
543
+ if (!peer)
544
+ return undefined;
545
+ const cmd = remoteListCommand(['sessions', 'preview', sessionId, '--local', '--json'], peer.os);
546
+ const capture = await sshCapture(peer.target, cmd, timeoutMs);
547
+ if (capture.code !== 0)
548
+ return undefined;
549
+ let parsed;
550
+ try {
551
+ parsed = JSON.parse(stripClixml(capture.stdout));
552
+ }
553
+ catch {
554
+ return undefined;
555
+ }
556
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
557
+ return undefined;
558
+ const preview = parsed.preview;
559
+ if (!preview || typeof preview !== 'object' || Array.isArray(preview))
560
+ return undefined;
561
+ return preview;
562
+ }
526
563
  /**
527
564
  * Run `agents <args>` ON a peer over SSH, attached to this terminal (inherited
528
565
  * stdio). `args` is the full arg vector after the binary — callers pass e.g.
529
566
  * `['sessions', id, '--markdown']` or `['sessions', 'resume', id]`. Used when a
530
567
  * picked session lives on another machine: its transcript and agent binary are
531
568
  * there, so both reading (no TTY) and resuming (TTY) must execute on the peer —
532
- * not via a local `--host` hop, which would discover locally and dead-end for a
569
+ * not via a local `--device` hop, which would discover locally and dead-end for a
533
570
  * session that exists only on the peer. Resolves 'no-target' when the machine
534
571
  * isn't a dialable registered device; the caller surfaces a clear message.
535
572
  *
536
573
  * `opts.env` adds variables to the remote command. It deliberately does NOT
537
- * carry `AGENTS_FLEET_REMOTE` the way the `--host` passthrough does: that marker
574
+ * carry `AGENTS_FLEET_REMOTE` the way the `--device` passthrough does: that marker
538
575
  * gates consent-sensitive actions on the far side
539
576
  * (lib/browser/remote-control.ts), and a resumed agent is a long-lived session
540
577
  * that would inherit it for its whole life — `agents browser start` inside it
541
- * would then be refused as a cross-machine drive. A one-shot `--host` command
578
+ * would then be refused as a cross-machine drive. A one-shot `--device` command
542
579
  * can carry the marker; a session cannot.
543
580
  */
544
581
  export async function runOnPeer(args, machine, opts = {}) {
@@ -6,11 +6,11 @@
6
6
  */
7
7
  export declare function shellQuote(s: string): string;
8
8
  /**
9
- * Strip the `--host`/`-H` flag (and its value) from a raw `agents sessions` argv,
9
+ * Strip the `--device`/`-D` flag (and its value) from a raw `agents sessions` argv,
10
10
  * leaving the args to forward to the remote unchanged. The remote runs the same
11
11
  * binary, so every other flag (`--since`, `--last`, `--json`, query, …) carries
12
- * over for free. Handles every form commander accepts: `--host h`, `--host=h`,
13
- * `-H h`, `-H=h`, and the glued short form `-Hh`.
12
+ * over for free. Handles every form commander accepts: `--device h`, `--device=h`,
13
+ * `-D h`, `-D=h`, and the glued short form `-Dh`.
14
14
  *
15
15
  * @param argv full process argv; the sessions args begin at index 2
16
16
  * (`[runtime, script, 'sessions', ...]`).
@@ -20,9 +20,9 @@ export declare function buildForwardedArgs(argv: string[], hosts?: Set<string>):
20
20
  * Force a forwarded `agents sessions` listing to span the peer's WHOLE index.
21
21
  *
22
22
  * A remote listing runs in the peer's SSH-login cwd — its home dir — and the
23
- * default listing is silently cwd-scoped, so `sessions --host box` reads as
23
+ * default listing is silently cwd-scoped, so `sessions --device box` reads as
24
24
  * empty even when the box's index is full (`No sessions found for /home/<user>`).
25
- * Across SSH a peer's cwd is meaningless, so `--host` defaults to `--all`
25
+ * Across SSH a peer's cwd is meaningless, so `--device` defaults to `--all`
26
26
  * (whole-index) scope. This only drops the *cwd* narrowing — an explicit path
27
27
  * query, `--project`, `--since`, or `--agent` filter still narrows on top, and
28
28
  * a query that looks like a path takes precedence over `--all` on the remote.