@phnx-labs/agents-cli 1.22.39 → 1.22.41

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 (569) hide show
  1. package/CHANGELOG.md +316 -0
  2. package/README.md +116 -70
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.js +45 -27
  5. package/dist/browser.js +2 -2
  6. package/dist/cli/command-registry.d.ts +135 -0
  7. package/dist/cli/command-registry.js +259 -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.d.ts +15 -0
  13. package/dist/commands/browser.js +318 -131
  14. package/dist/commands/budget.d.ts +7 -6
  15. package/dist/commands/budget.js +8 -7
  16. package/dist/commands/cloud.js +17 -20
  17. package/dist/commands/commands.js +1 -1
  18. package/dist/commands/computer-actions.d.ts +1 -35
  19. package/dist/commands/computer-actions.js +13 -181
  20. package/dist/commands/computer.d.ts +28 -3
  21. package/dist/commands/computer.js +93 -65
  22. package/dist/commands/config.js +16 -3
  23. package/dist/commands/cost.d.ts +2 -1
  24. package/dist/commands/cost.js +7 -6
  25. package/dist/commands/daemon.js +151 -4
  26. package/dist/commands/detach.js +1 -1
  27. package/dist/commands/doctor.js +19 -11
  28. package/dist/commands/events.js +1 -1
  29. package/dist/commands/exec.d.ts +2 -50
  30. package/dist/commands/exec.js +160 -215
  31. package/dist/commands/factory.js +1 -1
  32. package/dist/commands/feed.d.ts +2 -2
  33. package/dist/commands/feed.js +12 -23
  34. package/dist/commands/fleet-capture.js +25 -27
  35. package/dist/commands/focus.d.ts +2 -3
  36. package/dist/commands/focus.js +34 -9
  37. package/dist/commands/go.js +15 -5
  38. package/dist/commands/harness.d.ts +3 -3
  39. package/dist/commands/harness.js +53 -5
  40. package/dist/commands/hooks.js +1 -1
  41. package/dist/commands/import.js +2 -2
  42. package/dist/commands/insights.d.ts +5 -5
  43. package/dist/commands/insights.js +15 -9
  44. package/dist/commands/inspect.d.ts +2 -3
  45. package/dist/commands/inspect.js +4 -16
  46. package/dist/commands/logs.d.ts +2 -2
  47. package/dist/commands/logs.js +9 -9
  48. package/dist/commands/mcp.js +2 -2
  49. package/dist/commands/memory.js +1 -1
  50. package/dist/commands/message.d.ts +1 -1
  51. package/dist/commands/message.js +7 -7
  52. package/dist/commands/mine.d.ts +11 -8
  53. package/dist/commands/mine.js +11 -10
  54. package/dist/commands/models.js +1 -1
  55. package/dist/commands/modes.js +1 -1
  56. package/dist/commands/monitors.js +23 -6
  57. package/dist/commands/output.d.ts +7 -6
  58. package/dist/commands/output.js +11 -10
  59. package/dist/commands/packages.js +4 -4
  60. package/dist/commands/perf.js +1 -1
  61. package/dist/commands/permissions.js +49 -32
  62. package/dist/commands/plugins.d.ts +1 -1
  63. package/dist/commands/plugins.js +3 -3
  64. package/dist/commands/profiles.d.ts +6 -9
  65. package/dist/commands/profiles.js +8 -321
  66. package/dist/commands/projects.d.ts +9 -0
  67. package/dist/commands/projects.js +140 -8
  68. package/dist/commands/prune.js +5 -13
  69. package/dist/commands/refresh-rules.js +1 -1
  70. package/dist/commands/repo.d.ts +5 -7
  71. package/dist/commands/repo.js +34 -18
  72. package/dist/commands/resource-view.js +4 -0
  73. package/dist/commands/resume.d.ts +11 -7
  74. package/dist/commands/resume.js +82 -98
  75. package/dist/commands/route.d.ts +12 -0
  76. package/dist/commands/route.js +261 -0
  77. package/dist/commands/routines.d.ts +2 -3
  78. package/dist/commands/routines.js +120 -145
  79. package/dist/commands/rules.js +1 -1
  80. package/dist/commands/run-account-picker.d.ts +1 -1
  81. package/dist/commands/run-account-picker.js +2 -2
  82. package/dist/commands/run-broadcast.d.ts +21 -0
  83. package/dist/commands/run-broadcast.js +89 -0
  84. package/dist/commands/run-cloud.js +1 -1
  85. package/dist/commands/secrets-vault.d.ts +10 -0
  86. package/dist/commands/{login.js → secrets-vault.js} +34 -14
  87. package/dist/commands/secrets.d.ts +4 -4
  88. package/dist/commands/secrets.js +158 -159
  89. package/dist/commands/sessions-backfill.js +1 -1
  90. package/dist/commands/sessions-browser.d.ts +1 -1
  91. package/dist/commands/sessions-browser.js +9 -5
  92. package/dist/commands/sessions-export.js +2 -2
  93. package/dist/commands/sessions-inject.js +4 -5
  94. package/dist/commands/sessions-migrate.js +16 -27
  95. package/dist/commands/sessions-picker.d.ts +14 -0
  96. package/dist/commands/sessions-picker.js +209 -13
  97. package/dist/commands/sessions-resume.d.ts +7 -3
  98. package/dist/commands/sessions-resume.js +81 -33
  99. package/dist/commands/sessions-share.d.ts +25 -0
  100. package/dist/commands/sessions-share.js +166 -0
  101. package/dist/commands/sessions-stats.js +2 -2
  102. package/dist/commands/sessions.d.ts +75 -68
  103. package/dist/commands/sessions.js +144 -180
  104. package/dist/commands/setup-browser.js +1 -1
  105. package/dist/commands/setup-computer.js +1 -1
  106. package/dist/commands/setup-fleet.js +3 -0
  107. package/dist/commands/setup-mine.d.ts +7 -3
  108. package/dist/commands/setup-mine.js +13 -8
  109. package/dist/commands/setup-preferences.js +2 -2
  110. package/dist/commands/setup-secrets.js +2 -2
  111. package/dist/commands/setup-watchdog.js +2 -2
  112. package/dist/commands/setup.js +7 -2
  113. package/dist/commands/share.d.ts +65 -0
  114. package/dist/commands/share.js +253 -20
  115. package/dist/commands/skills.js +3 -3
  116. package/dist/commands/snapshot.d.ts +2 -2
  117. package/dist/commands/snapshot.js +9 -9
  118. package/dist/commands/ssh.d.ts +1 -1
  119. package/dist/commands/ssh.js +186 -64
  120. package/dist/commands/subagents.js +1 -1
  121. package/dist/commands/sync.js +24 -9
  122. package/dist/commands/teams.d.ts +2 -2
  123. package/dist/commands/teams.js +9 -18
  124. package/dist/commands/tmux.js +5 -1
  125. package/dist/commands/trash.js +1 -1
  126. package/dist/commands/usage.d.ts +1 -1
  127. package/dist/commands/usage.js +2 -2
  128. package/dist/commands/utils.d.ts +4 -14
  129. package/dist/commands/utils.js +6 -27
  130. package/dist/commands/versions.js +2 -2
  131. package/dist/commands/view.d.ts +9 -77
  132. package/dist/commands/view.js +23 -8
  133. package/dist/commands/watchdog.js +1 -1
  134. package/dist/commands/webhook.js +25 -34
  135. package/dist/commands/workflows.js +1 -1
  136. package/dist/index.js +1 -1
  137. package/dist/lib/account-capabilities.d.ts +39 -0
  138. package/dist/lib/account-capabilities.js +59 -0
  139. package/dist/lib/account-catalog.js +1 -1
  140. package/dist/lib/account-registry.d.ts +66 -0
  141. package/dist/lib/account-registry.js +151 -5
  142. package/dist/lib/{rotate.d.ts → accounting/rotate.d.ts} +4 -4
  143. package/dist/lib/{rotate.js → accounting/rotate.js} +8 -8
  144. package/dist/lib/{usage.d.ts → accounting/usage.d.ts} +4 -4
  145. package/dist/lib/{usage.js → accounting/usage.js} +11 -11
  146. package/dist/lib/agent-spec/provider.js +1 -1
  147. package/dist/lib/agents.d.ts +72 -4
  148. package/dist/lib/agents.js +231 -199
  149. package/dist/lib/answer-router.d.ts +2 -2
  150. package/dist/lib/ask-classifier.d.ts +1 -1
  151. package/dist/lib/ask-classifier.js +1 -1
  152. package/dist/lib/audit/log.js +1 -1
  153. package/dist/lib/auth-health.d.ts +1 -1
  154. package/dist/lib/auth-health.js +2 -2
  155. package/dist/lib/brand.js +1 -1
  156. package/dist/lib/browser/caller-identity.d.ts +28 -0
  157. package/dist/lib/browser/caller-identity.js +156 -0
  158. package/dist/lib/browser/cdp.js +5 -1
  159. package/dist/lib/browser/chrome.js +12 -1
  160. package/dist/lib/browser/drivers/ssh.d.ts +1 -1
  161. package/dist/lib/browser/drivers/ssh.js +3 -2
  162. package/dist/lib/browser/hygiene.d.ts +10 -2
  163. package/dist/lib/browser/hygiene.js +7 -4
  164. package/dist/lib/browser/ipc.d.ts +22 -2
  165. package/dist/lib/browser/ipc.js +185 -21
  166. package/dist/lib/browser/profiles.d.ts +69 -5
  167. package/dist/lib/browser/profiles.js +135 -13
  168. package/dist/lib/browser/remote-control.d.ts +2 -2
  169. package/dist/lib/browser/remote-control.js +3 -3
  170. package/dist/lib/browser/runtime-state.d.ts +79 -0
  171. package/dist/lib/browser/runtime-state.js +119 -1
  172. package/dist/lib/browser/service.d.ts +137 -2
  173. package/dist/lib/browser/service.js +492 -54
  174. package/dist/lib/browser/sessions-list.d.ts +2 -1
  175. package/dist/lib/browser/sessions-list.js +4 -13
  176. package/dist/lib/browser/types.d.ts +19 -1
  177. package/dist/lib/budget/config.js +1 -1
  178. package/dist/lib/budget/ledger.js +1 -1
  179. package/dist/lib/byok-usage.js +1 -1
  180. package/dist/lib/capabilities.js +3 -15
  181. package/dist/lib/catchup.d.ts +1 -1
  182. package/dist/lib/catchup.js +1 -1
  183. package/dist/lib/cloud/dispatch.js +1 -1
  184. package/dist/lib/cloud/host.d.ts +3 -3
  185. package/dist/lib/cloud/host.js +5 -5
  186. package/dist/lib/cloud/rush.d.ts +9 -21
  187. package/dist/lib/cloud/rush.js +33 -120
  188. package/dist/lib/cloud/types.d.ts +2 -2
  189. package/dist/lib/commands.js +3 -13
  190. package/dist/lib/computer/actions.d.ts +36 -0
  191. package/dist/lib/computer/actions.js +162 -0
  192. package/dist/lib/computer/dispatch.d.ts +2 -2
  193. package/dist/lib/computer/dispatch.js +2 -2
  194. package/dist/lib/computer/sessions-list.d.ts +3 -3
  195. package/dist/lib/computer/sessions-list.js +2 -2
  196. package/dist/lib/config-keys.d.ts +2 -1
  197. package/dist/lib/config-keys.js +8 -4
  198. package/dist/lib/config-machine-keys.d.ts +4 -2
  199. package/dist/lib/config-machine-keys.js +5 -2
  200. package/dist/lib/crabbox/lease.js +9 -1
  201. package/dist/lib/crabbox/runtimes.d.ts +32 -7
  202. package/dist/lib/crabbox/runtimes.js +72 -30
  203. package/dist/lib/{daemon.d.ts → daemon/daemon.d.ts} +59 -1
  204. package/dist/lib/{daemon.js → daemon/daemon.js} +237 -49
  205. package/dist/lib/daemon-services.d.ts +1 -1
  206. package/dist/lib/daemon-services.js +5 -0
  207. package/dist/lib/daemon-ticks.d.ts +25 -0
  208. package/dist/lib/daemon-ticks.js +31 -1
  209. package/dist/lib/daemon-webhooks.d.ts +104 -0
  210. package/dist/lib/daemon-webhooks.js +215 -0
  211. package/dist/lib/device-config.d.ts +85 -75
  212. package/dist/lib/device-config.js +280 -142
  213. package/dist/lib/devices/config-migration.d.ts +29 -34
  214. package/dist/lib/devices/config-migration.js +209 -130
  215. package/dist/lib/devices/connect.d.ts +2 -2
  216. package/dist/lib/devices/connect.js +2 -2
  217. package/dist/lib/devices/discovery-policy.d.ts +30 -0
  218. package/dist/lib/devices/discovery-policy.js +101 -0
  219. package/dist/lib/devices/fleet-inventory.js +8 -3
  220. package/dist/lib/devices/harness-inventory.d.ts +1 -1
  221. package/dist/lib/devices/harness-inventory.js +12 -3
  222. package/dist/lib/devices/known-hosts.js +1 -1
  223. package/dist/lib/devices/pool.d.ts +10 -5
  224. package/dist/lib/devices/pool.js +5 -7
  225. package/dist/lib/devices/registry.d.ts +1 -1
  226. package/dist/lib/devices/registry.js +1 -1
  227. package/dist/lib/devices/resolve-profile.d.ts +2 -2
  228. package/dist/lib/devices/resolve-profile.js +2 -2
  229. package/dist/lib/devices/resolve-target.d.ts +1 -1
  230. package/dist/lib/devices/resolve-target.js +4 -4
  231. package/dist/lib/devices/self-host.d.ts +1 -1
  232. package/dist/lib/devices/self-host.js +3 -3
  233. package/dist/lib/devices/ssh-config.d.ts +1 -1
  234. package/dist/lib/devices/stats-cache.js +1 -1
  235. package/dist/lib/devices/sync.d.ts +3 -1
  236. package/dist/lib/devices/sync.js +3 -3
  237. package/dist/lib/doctor-diff.js +4 -4
  238. package/dist/lib/drift-sync.js +2 -2
  239. package/dist/lib/drift.js +2 -2
  240. package/dist/lib/event-families.d.ts +1 -1
  241. package/dist/lib/event-stream.d.ts +1 -1
  242. package/dist/lib/event-stream.js +2 -2
  243. package/dist/lib/events-ingest.js +2 -2
  244. package/dist/lib/exec.d.ts +4 -4
  245. package/dist/lib/exec.js +11 -11
  246. package/dist/lib/factory/snapshot.d.ts +1 -1
  247. package/dist/lib/factory/snapshot.js +1 -1
  248. package/dist/lib/{activity.d.ts → feed/activity.d.ts} +1 -1
  249. package/dist/lib/{activity.js → feed/activity.js} +7 -7
  250. package/dist/lib/{events.d.ts → feed/events.d.ts} +2 -2
  251. package/dist/lib/{events.js → feed/events.js} +5 -5
  252. package/dist/lib/{feed.js → feed/feed.js} +4 -4
  253. package/dist/lib/feed-outcome.d.ts +1 -1
  254. package/dist/lib/feed-policy.d.ts +1 -1
  255. package/dist/lib/feed-policy.js +1 -1
  256. package/dist/lib/feed-post.d.ts +1 -1
  257. package/dist/lib/feed-post.js +1 -1
  258. package/dist/lib/feed-ranking.d.ts +1 -1
  259. package/dist/lib/fleet/apply.d.ts +0 -6
  260. package/dist/lib/fleet/apply.js +18 -45
  261. package/dist/lib/fleet/auth-sync.d.ts +16 -35
  262. package/dist/lib/fleet/auth-sync.js +16 -75
  263. package/dist/lib/fleet/capture.js +8 -6
  264. package/dist/lib/fleet/manifest.js +23 -11
  265. package/dist/lib/fleet/types.d.ts +19 -7
  266. package/dist/lib/fleet-cache.d.ts +1 -1
  267. package/dist/lib/fleet-cache.js +1 -1
  268. package/dist/lib/format.d.ts +19 -0
  269. package/dist/lib/format.js +44 -1
  270. package/dist/lib/friction-heuristics.d.ts +1 -1
  271. package/dist/lib/git.d.ts +24 -1
  272. package/dist/lib/git.js +82 -38
  273. package/dist/lib/heal.js +3 -3
  274. package/dist/lib/hooks.d.ts +18 -0
  275. package/dist/lib/hooks.js +113 -1
  276. package/dist/lib/hosts/credentials.d.ts +30 -10
  277. package/dist/lib/hosts/credentials.js +38 -26
  278. package/dist/lib/hosts/dispatch.d.ts +3 -3
  279. package/dist/lib/hosts/dispatch.js +3 -3
  280. package/dist/lib/hosts/option.d.ts +3 -3
  281. package/dist/lib/hosts/option.js +7 -8
  282. package/dist/lib/hosts/passthrough.d.ts +17 -17
  283. package/dist/lib/hosts/passthrough.js +67 -50
  284. package/dist/lib/hosts/providers/devices.d.ts +1 -1
  285. package/dist/lib/hosts/providers/devices.js +1 -1
  286. package/dist/lib/hosts/reconcile.d.ts +1 -1
  287. package/dist/lib/hosts/reconcile.js +1 -1
  288. package/dist/lib/hosts/reconnect.d.ts +1 -1
  289. package/dist/lib/hosts/reconnect.js +2 -2
  290. package/dist/lib/hosts/registry.d.ts +5 -5
  291. package/dist/lib/hosts/registry.js +5 -5
  292. package/dist/lib/hosts/remote-cmd.d.ts +10 -10
  293. package/dist/lib/hosts/remote-cmd.js +25 -18
  294. package/dist/lib/hosts/remote-os.d.ts +4 -4
  295. package/dist/lib/hosts/remote-os.js +4 -4
  296. package/dist/lib/hosts/remote-session-id.d.ts +2 -2
  297. package/dist/lib/hosts/remote-session-id.js +2 -2
  298. package/dist/lib/hosts/routing-flag.d.ts +3 -3
  299. package/dist/lib/hosts/routing-flag.js +4 -5
  300. package/dist/lib/hosts/run-target.d.ts +4 -4
  301. package/dist/lib/hosts/run-target.js +4 -4
  302. package/dist/lib/hosts/session-index.d.ts +2 -2
  303. package/dist/lib/hosts/session-index.js +1 -1
  304. package/dist/lib/hosts/session-marker.d.ts +1 -1
  305. package/dist/lib/hosts/session-marker.js +1 -1
  306. package/dist/lib/hosts/types.d.ts +2 -2
  307. package/dist/lib/hosts/types.js +2 -2
  308. package/dist/lib/import.js +1 -1
  309. package/dist/lib/{migrate.d.ts → installations/migrate.d.ts} +13 -1
  310. package/dist/lib/{migrate.js → installations/migrate.js} +160 -40
  311. package/dist/lib/installations/resolve.js +1 -1
  312. package/dist/lib/installations/strategies.js +1 -1
  313. package/dist/lib/installations/update.js +2 -2
  314. package/dist/lib/{versions.d.ts → installations/versions.d.ts} +12 -3
  315. package/dist/lib/{versions.js → installations/versions.js} +51 -31
  316. package/dist/lib/isolation-boundary-report.js +1 -1
  317. package/dist/lib/linear-projects.d.ts +28 -0
  318. package/dist/lib/linear-projects.js +30 -0
  319. package/dist/lib/loop.js +1 -1
  320. package/dist/lib/mailbox-gc.js +1 -1
  321. package/dist/lib/mailbox.js +1 -1
  322. package/dist/lib/mcp-registry.d.ts +62 -0
  323. package/dist/lib/mcp-registry.js +177 -0
  324. package/dist/lib/mcp.d.ts +5 -0
  325. package/dist/lib/mcp.js +124 -307
  326. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  327. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  328. package/dist/lib/menubar/install-menubar.d.ts +7 -0
  329. package/dist/lib/menubar/install-menubar.js +24 -6
  330. package/dist/lib/menubar/snapshot.d.ts +7 -0
  331. package/dist/lib/menubar/snapshot.js +8 -6
  332. package/dist/lib/models.js +1 -1
  333. package/dist/lib/monitors/config.d.ts +12 -0
  334. package/dist/lib/monitors/config.js +3 -0
  335. package/dist/lib/monitors/dispatch.js +26 -5
  336. package/dist/lib/monitors/engine.js +10 -0
  337. package/dist/lib/monitors/sources/webhook.d.ts +1 -1
  338. package/dist/lib/monitors/state.d.ts +42 -0
  339. package/dist/lib/monitors/state.js +30 -0
  340. package/dist/lib/notify.d.ts +1 -1
  341. package/dist/lib/observe-aliases.d.ts +3 -3
  342. package/dist/lib/observe-aliases.js +3 -21
  343. package/dist/lib/output/git-output.js +2 -2
  344. package/dist/lib/overdue.d.ts +1 -1
  345. package/dist/lib/overdue.js +1 -1
  346. package/dist/lib/permissions-registry.d.ts +65 -0
  347. package/dist/lib/permissions-registry.js +599 -0
  348. package/dist/lib/permissions.d.ts +24 -13
  349. package/dist/lib/permissions.js +52 -271
  350. package/dist/lib/picker.d.ts +16 -0
  351. package/dist/lib/picker.js +33 -3
  352. package/dist/lib/placement.d.ts +1 -1
  353. package/dist/lib/placement.js +4 -4
  354. package/dist/lib/platform/paths.d.ts +8 -0
  355. package/dist/lib/platform/paths.js +11 -0
  356. package/dist/lib/platform/posixpath.js +3 -3
  357. package/dist/lib/{plugin-marketplace.d.ts → plugins/plugin-marketplace.d.ts} +1 -1
  358. package/dist/lib/{plugin-marketplace.js → plugins/plugin-marketplace.js} +2 -2
  359. package/dist/lib/{plugins.d.ts → plugins/plugins.d.ts} +1 -1
  360. package/dist/lib/{plugins.js → plugins/plugins.js} +7 -7
  361. package/dist/lib/{skills.d.ts → plugins/skills.d.ts} +1 -1
  362. package/dist/lib/{skills.js → plugins/skills.js} +7 -7
  363. package/dist/lib/pricing/cost.d.ts +1 -1
  364. package/dist/lib/pricing/cost.js +1 -1
  365. package/dist/lib/profiles-presets.d.ts +1 -1
  366. package/dist/lib/profiles-presets.js +1 -1
  367. package/dist/lib/profiles.js +2 -2
  368. package/dist/lib/project-import.js +4 -1
  369. package/dist/lib/project-key.js +7 -0
  370. package/dist/lib/project-launch.d.ts +1 -1
  371. package/dist/lib/project-launch.js +3 -3
  372. package/dist/lib/project-pull.d.ts +128 -0
  373. package/dist/lib/project-pull.js +384 -0
  374. package/dist/lib/project-root.d.ts +2 -2
  375. package/dist/lib/project-root.js +2 -2
  376. package/dist/lib/project-status.js +1 -1
  377. package/dist/lib/projects.d.ts +23 -0
  378. package/dist/lib/projects.js +29 -6
  379. package/dist/lib/refresh.d.ts +12 -1
  380. package/dist/lib/refresh.js +16 -9
  381. package/dist/lib/registry.d.ts +9 -2
  382. package/dist/lib/registry.js +11 -4
  383. package/dist/lib/resources.d.ts +2 -2
  384. package/dist/lib/resources.js +2 -2
  385. package/dist/lib/routers.d.ts +81 -0
  386. package/dist/lib/routers.js +153 -0
  387. package/dist/lib/routine-context.d.ts +1 -0
  388. package/dist/lib/routine-context.js +7 -2
  389. package/dist/lib/routine-notify-owner.d.ts +1 -1
  390. package/dist/lib/routine-notify.d.ts +1 -1
  391. package/dist/lib/routine-notify.js +1 -1
  392. package/dist/lib/routine-process-cleanup.d.ts +1 -1
  393. package/dist/lib/routine-readiness.d.ts +1 -1
  394. package/dist/lib/routine-readiness.js +11 -4
  395. package/dist/lib/routines-placement.d.ts +12 -2
  396. package/dist/lib/routines-placement.js +20 -3
  397. package/dist/lib/routines-project.d.ts +1 -1
  398. package/dist/lib/routines-project.js +1 -1
  399. package/dist/lib/rules/compile.d.ts +1 -0
  400. package/dist/lib/rules/compile.js +10 -2
  401. package/dist/lib/rules/rules.js +1 -1
  402. package/dist/lib/run-notify.js +1 -1
  403. package/dist/lib/runner.d.ts +80 -2
  404. package/dist/lib/runner.js +261 -67
  405. package/dist/lib/sandbox.d.ts +1 -1
  406. package/dist/lib/scheduler.d.ts +1 -1
  407. package/dist/lib/scheduler.js +1 -1
  408. package/dist/lib/{routines.d.ts → scheduling/routines.d.ts} +54 -9
  409. package/dist/lib/{routines.js → scheduling/routines.js} +173 -14
  410. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  411. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  412. package/dist/lib/secrets/agent.js +2 -2
  413. package/dist/lib/secrets/audit.js +1 -1
  414. package/dist/lib/secrets/bundles.d.ts +4 -4
  415. package/dist/lib/secrets/bundles.js +8 -8
  416. package/dist/lib/secrets/headless.d.ts +16 -0
  417. package/dist/lib/secrets/headless.js +21 -0
  418. package/dist/lib/secrets/index.js +1 -1
  419. package/dist/lib/secrets/list-filter.d.ts +1 -1
  420. package/dist/lib/secrets/list-filter.js +2 -2
  421. package/dist/lib/secrets/push.d.ts +1 -1
  422. package/dist/lib/secrets/push.js +10 -12
  423. package/dist/lib/secrets/remote.d.ts +21 -17
  424. package/dist/lib/secrets/remote.js +39 -23
  425. package/dist/lib/secrets/vault.js +2 -2
  426. package/dist/lib/self-heal/checks/shadowing.js +1 -1
  427. package/dist/lib/self-heal/checks/shims.js +1 -1
  428. package/dist/lib/self-update.d.ts +39 -4
  429. package/dist/lib/self-update.js +78 -25
  430. package/dist/lib/serve/control.d.ts +1 -1
  431. package/dist/lib/serve/control.js +4 -4
  432. package/dist/lib/serve/data.d.ts +1 -1
  433. package/dist/lib/serve/data.js +1 -1
  434. package/dist/lib/serve/stream.js +1 -1
  435. package/dist/lib/service-manifest.d.ts +29 -0
  436. package/dist/lib/service-manifest.js +80 -0
  437. package/dist/lib/session/active.d.ts +59 -7
  438. package/dist/lib/session/active.js +158 -17
  439. package/dist/lib/session/bash-command.js +1 -1
  440. package/dist/lib/session/claude-accounts.d.ts +1 -1
  441. package/dist/lib/session/claude-accounts.js +1 -1
  442. package/dist/lib/session/db.d.ts +10 -2
  443. package/dist/lib/session/db.js +25 -6
  444. package/dist/lib/session/discover.d.ts +77 -0
  445. package/dist/lib/session/discover.js +130 -25
  446. package/dist/lib/session/fork.js +1 -1
  447. package/dist/lib/session/inject.d.ts +1 -1
  448. package/dist/lib/session/insights.d.ts +1 -1
  449. package/dist/lib/session/insights.js +1 -1
  450. package/dist/lib/session/live-metadata.d.ts +15 -0
  451. package/dist/lib/session/live-metadata.js +76 -0
  452. package/dist/lib/session/migrate-targets.d.ts +1 -1
  453. package/dist/lib/session/recovery.d.ts +1 -1
  454. package/dist/lib/session/recovery.js +2 -2
  455. package/dist/lib/session/remote-active.d.ts +10 -1
  456. package/dist/lib/session/remote-active.js +8 -3
  457. package/dist/lib/session/remote-bundle.d.ts +1 -1
  458. package/dist/lib/session/remote-bundle.js +2 -2
  459. package/dist/lib/session/remote-list.d.ts +15 -4
  460. package/dist/lib/session/remote-list.js +40 -3
  461. package/dist/lib/session/remote.d.ts +5 -5
  462. package/dist/lib/session/remote.js +13 -17
  463. package/dist/lib/session/resume-command.d.ts +3 -2
  464. package/dist/lib/session/resume-command.js +4 -3
  465. package/dist/lib/session/resume-owner.d.ts +3 -3
  466. package/dist/lib/session/resume-owner.js +3 -3
  467. package/dist/lib/session/session-cache.d.ts +12 -0
  468. package/dist/lib/session/session-cache.js +2 -0
  469. package/dist/lib/session/share-html.d.ts +55 -0
  470. package/dist/lib/session/share-html.js +319 -0
  471. package/dist/lib/session/shell-programs.js +1 -1
  472. package/dist/lib/session/state.js +5 -5
  473. package/dist/lib/session/team-filter.d.ts +1 -1
  474. package/dist/lib/session/team-filter.js +1 -1
  475. package/dist/lib/session/types.d.ts +3 -3
  476. package/dist/lib/session/width.d.ts +2 -2
  477. package/dist/lib/session/width.js +2 -2
  478. package/dist/lib/settings-manifest.d.ts +2 -0
  479. package/dist/lib/settings-manifest.js +81 -3
  480. package/dist/lib/share/delete.d.ts +21 -0
  481. package/dist/lib/share/delete.js +42 -0
  482. package/dist/lib/share/publish.d.ts +120 -0
  483. package/dist/lib/share/publish.js +243 -18
  484. package/dist/lib/share/worker-template.js +172 -9
  485. package/dist/lib/shims.js +35 -7
  486. package/dist/lib/smart-launch.d.ts +4 -4
  487. package/dist/lib/smart-launch.js +6 -4
  488. package/dist/lib/snapshot.d.ts +4 -4
  489. package/dist/lib/snapshot.js +2 -2
  490. package/dist/lib/ssh-exec.d.ts +1 -1
  491. package/dist/lib/ssh-exec.js +2 -2
  492. package/dist/lib/ssh-tunnel.d.ts +10 -10
  493. package/dist/lib/ssh-tunnel.js +12 -12
  494. package/dist/lib/staleness/checkers/hooks.d.ts +1 -1
  495. package/dist/lib/staleness/checkers/hooks.js +1 -1
  496. package/dist/lib/staleness/detectors/permissions.js +0 -23
  497. package/dist/lib/staleness/detectors/plugins.js +1 -1
  498. package/dist/lib/staleness/fingerprint.js +1 -1
  499. package/dist/lib/staleness/layers.d.ts +1 -1
  500. package/dist/lib/staleness/layers.js +1 -1
  501. package/dist/lib/staleness/writers/mcp.js +3 -1
  502. package/dist/lib/staleness/writers/plugins.js +1 -1
  503. package/dist/lib/staleness/writers/types.d.ts +8 -0
  504. package/dist/lib/startup/command-registry.d.ts +6 -147
  505. package/dist/lib/startup/command-registry.js +40 -303
  506. package/dist/lib/startup/dev-build.d.ts +0 -21
  507. package/dist/lib/startup/dev-build.js +29 -8
  508. package/dist/lib/state.d.ts +19 -1
  509. package/dist/lib/state.js +120 -51
  510. package/dist/lib/subagents.js +1 -1
  511. package/dist/lib/sync-status.js +1 -1
  512. package/dist/lib/sync-umbrella.d.ts +6 -1
  513. package/dist/lib/sync-umbrella.js +9 -4
  514. package/dist/lib/teams/agents.js +2 -2
  515. package/dist/lib/teams/registry.js +1 -1
  516. package/dist/lib/terminal/backends/vscodium-agent.js +1 -1
  517. package/dist/lib/terminal/engine.js +1 -1
  518. package/dist/lib/terminal/index.d.ts +4 -0
  519. package/dist/lib/terminal/index.js +3 -0
  520. package/dist/lib/terminal/inject.d.ts +2 -2
  521. package/dist/lib/terminal/inject.js +2 -2
  522. package/dist/lib/terminal/transport.js +1 -1
  523. package/dist/lib/tmux/index.d.ts +1 -1
  524. package/dist/lib/tmux/index.js +1 -1
  525. package/dist/lib/tmux/session.d.ts +21 -5
  526. package/dist/lib/tmux/session.js +76 -22
  527. package/dist/lib/triggers/handlers.d.ts +38 -3
  528. package/dist/lib/triggers/handlers.js +58 -7
  529. package/dist/lib/triggers/webhook.d.ts +113 -5
  530. package/dist/lib/triggers/webhook.js +223 -44
  531. package/dist/lib/types.d.ts +19 -7
  532. package/dist/lib/usage-fleet.d.ts +1 -1
  533. package/dist/lib/usage-fleet.js +1 -1
  534. package/dist/lib/usage-refresh.d.ts +1 -1
  535. package/dist/lib/usage-refresh.js +3 -3
  536. package/dist/lib/version-duplicates.js +2 -2
  537. package/dist/lib/view-types.d.ts +56 -0
  538. package/dist/lib/view-types.js +1 -0
  539. package/dist/lib/watchdog/rotate.d.ts +2 -2
  540. package/dist/lib/watchdog/rotate.js +3 -3
  541. package/dist/lib/watchdog/runner.d.ts +2 -3
  542. package/dist/lib/watchdog/runner.js +3 -4
  543. package/dist/lib/workflows.js +1 -1
  544. package/dist/lib/wrap.d.ts +33 -0
  545. package/dist/lib/wrap.js +70 -0
  546. package/package.json +2 -1
  547. package/scripts/postinstall.js +2 -2
  548. package/dist/commands/bench.d.ts +0 -2
  549. package/dist/commands/bench.js +0 -101
  550. package/dist/commands/cp.d.ts +0 -84
  551. package/dist/commands/cp.js +0 -231
  552. package/dist/commands/login.d.ts +0 -2
  553. package/dist/lib/resources/commands.d.ts +0 -46
  554. package/dist/lib/resources/commands.js +0 -211
  555. package/dist/lib/resources/hooks.d.ts +0 -16
  556. package/dist/lib/resources/hooks.js +0 -153
  557. package/dist/lib/resources/mcp.d.ts +0 -34
  558. package/dist/lib/resources/mcp.js +0 -250
  559. package/dist/lib/resources/memory.d.ts +0 -15
  560. package/dist/lib/resources/memory.js +0 -46
  561. package/dist/lib/resources/permissions.d.ts +0 -13
  562. package/dist/lib/resources/permissions.js +0 -202
  563. package/dist/lib/resources/rules.d.ts +0 -46
  564. package/dist/lib/resources/rules.js +0 -179
  565. package/dist/lib/resources/skills.d.ts +0 -37
  566. package/dist/lib/resources/skills.js +0 -247
  567. package/dist/lib/resources/subagents.d.ts +0 -46
  568. package/dist/lib/resources/subagents.js +0 -202
  569. /package/dist/lib/{feed.d.ts → feed/feed.d.ts} +0 -0
@@ -81,7 +81,7 @@ export declare function sessionMatchesQuery(s: SessionMeta, query: string): bool
81
81
  * `--print-cmd`.
82
82
  */
83
83
  export declare function browserFilterToArgv(f: BrowserFilter, query?: string): string[];
84
- /** Normalize a `--host`/`--device` token (`alias`, `user@host`, `host.domain`) to
84
+ /** Normalize a `--device`/`--device` token (`alias`, `user@host`, `host.domain`) to
85
85
  * the canonical machine id the rows carry in `.machine`, so a flag seed matches
86
86
  * (the `d` hotkey already cycles canonical ids). Mirrors sessions.ts `hostToken`. */
87
87
  export declare function normalizeDeviceSeed(host: string | undefined): string | undefined;
@@ -16,12 +16,12 @@ import { dynamicPicker } from '../lib/picker.js';
16
16
  import { isSessionTrackedAgent } from '../lib/session/types.js';
17
17
  import { discoverSessions } from '../lib/session/discover.js';
18
18
  import { gatherRemoteList } from '../lib/session/remote-list.js';
19
- import { resolveVersionAliasLoose } from '../lib/versions.js';
19
+ import { resolveVersionAliasLoose } from '../lib/installations/versions.js';
20
20
  import { AGENTS } from '../lib/agents.js';
21
21
  import { enrichTeamOrigins, safeTeamText, shouldShowTeamSessions } from '../lib/session/team-filter.js';
22
22
  import { listBookmarks, toggleBookmark } from '../lib/session/bookmarks.js';
23
23
  import { machineId, normalizeHost } from '../lib/session/sync/config.js';
24
- import { buildPreview } from './sessions-picker.js';
24
+ import { buildPreview, setRemotePreviewRepaint } from './sessions-picker.js';
25
25
  import { formatPickerLabel, pickerColumnsFor, ticketLabel, mergeLocalFirst, gatherActiveSessions, liveHostLabel, LIVE_ROW_PREFIX, cleanPreview, handlePickedSession, shouldIncludeLocal, remoteHostsToDial, matchesTeam, formatLiveStatusHeadline, isRunningLiveSession, matchesLiveStatus, parseAgentFilter, resolveRoutineName, } from './sessions.js';
26
26
  /**
27
27
  * Complete a seed into the filter the picker actually runs on.
@@ -164,7 +164,7 @@ export function browserFilterToArgv(f, query = '') {
164
164
  a.push(JSON.stringify(q));
165
165
  return a;
166
166
  }
167
- /** Normalize a `--host`/`--device` token (`alias`, `user@host`, `host.domain`) to
167
+ /** Normalize a `--device`/`--device` token (`alias`, `user@host`, `host.domain`) to
168
168
  * the canonical machine id the rows carry in `.machine`, so a flag seed matches
169
169
  * (the `d` hotkey already cycles canonical ids). Mirrors sessions.ts `hostToken`. */
170
170
  export function normalizeDeviceSeed(host) {
@@ -253,7 +253,7 @@ function copyToClipboard(text) {
253
253
  * The live index is fetched separately/lazily — it's the slow part and only the
254
254
  * running filter needs it, so a bare browse stays instant.
255
255
  *
256
- * `hosts` is the explicit `--host`/`--device` scope (if any): it restricts which
256
+ * `hosts` is the explicit `--device`/`--device` scope (if any): it restricts which
257
257
  * peers are dialed and whether local is included, honoring the flag's "scope,
258
258
  * not add" contract instead of always sweeping the whole fleet. */
259
259
  async function fetchRawPool(f, self, local, hosts, fixedFilters = false) {
@@ -699,6 +699,9 @@ export async function runSessionBrowser(initial = {}, opts = {}) {
699
699
  const body = buildPreview(s);
700
700
  return headline ? `${headline}\n${body}` : body;
701
701
  },
702
+ // A remote row's digest arrives over SSH after the pane painted — this is
703
+ // what lets its completion swap the metadata card for the full preview.
704
+ registerPreviewRepaint: setRemotePreviewRepaint,
702
705
  headerFor: (f) => unreachable.length > 0
703
706
  ? `${headerFor(f)} · ${chalk.yellow(`${unreachable.join(', ')}: unreachable`)}`
704
707
  : headerFor(f),
@@ -741,7 +744,8 @@ export async function runSessionBrowser(initial = {}, opts = {}) {
741
744
  }
742
745
  return undefined;
743
746
  },
744
- });
747
+ // A late digest fetch must not poke a closed prompt.
748
+ }).finally(() => setRemotePreviewRepaint(undefined));
745
749
  if (!picked)
746
750
  return;
747
751
  if (picked.action === 'focus') {
@@ -196,7 +196,7 @@ export function r2ExportGateError(g, isConfigured) {
196
196
  if (!g.toR2)
197
197
  return null;
198
198
  if (g.host && g.host.length > 0) {
199
- return "--to-r2 backs up THIS machine's sessions; it cannot be combined with --host.";
199
+ return "--to-r2 backs up THIS machine's sessions; it cannot be combined with --device.";
200
200
  }
201
201
  if (!isConfigured) {
202
202
  return ('R2 backup is not configured: the r2.backups secrets bundle is missing or locked.\n' +
@@ -266,7 +266,7 @@ export function resolveR2BackupKey() {
266
266
  */
267
267
  async function runRemoteExport(g, selectors, command) {
268
268
  if (g.encrypt) {
269
- process.stderr.write(chalk.yellow('Note: --encrypt is ignored with --host (the SSH stream is already encrypted). Encrypt a local bundle instead.\n'));
269
+ process.stderr.write(chalk.yellow('Note: --encrypt is ignored with --device (the SSH stream is already encrypted). Encrypt a local bundle instead.\n'));
270
270
  }
271
271
  const { bundles, errors } = await pullBundlesFromHosts(g.host, forwardExportArgs(g, selectors, command));
272
272
  for (const e of errors)
@@ -14,8 +14,7 @@
14
14
  */
15
15
  import chalk from 'chalk';
16
16
  import { getActiveSessions } from '../lib/session/active.js';
17
- import { resolveInjectTargetForSession } from '../lib/terminal/resolve.js';
18
- import { injectIntoTerminal } from '../lib/terminal/index.js';
17
+ import { injectIntoTerminal, resolveInjectTargetForSession } from '../lib/terminal/index.js';
19
18
  import { setHelpSections } from '../lib/help.js';
20
19
  /** Resolve a session id (short or full) to an addressable terminal target, via the
21
20
  * same resolver the watchdog uses so both agree on what is reachable. */
@@ -56,7 +55,7 @@ async function runInject(sessionId, text, options) {
56
55
  enter: options.enter !== false,
57
56
  combined: options.combined,
58
57
  socket: options.socket,
59
- host: options.host,
58
+ host: options.device,
60
59
  });
61
60
  if (options.json) {
62
61
  console.log(JSON.stringify(res));
@@ -78,7 +77,7 @@ export function registerSessionsInjectCommand(sessionsCmd) {
78
77
  .option('--pane <id>', 'Target a tmux pane id directly (e.g. %3), skipping session lookup')
79
78
  .option('--pty <id>', 'Target an agents-pty session id directly, skipping session lookup')
80
79
  .option('--socket <path>', 'tmux socket path (defaults to the session/shared socket)')
81
- .option('--host <target>', 'Deliver on a remote host over SSH (tmux/AppleScript backends)')
80
+ .option('--device <target>', 'Deliver on a remote device over SSH (tmux/AppleScript backends)')
82
81
  .option('--no-enter', 'Send only the text, without a trailing Enter')
83
82
  .option('--combined', 'Fuse text + Enter into ONE write (default: two writes, Ink-TUI safe)')
84
83
  .option('--json', 'Output the InjectResult as JSON');
@@ -99,7 +98,7 @@ export function registerSessionsInjectCommand(sessionsCmd) {
99
98
  - A session is addressable by id when it resolves to a precise split —
100
99
  tmux, iTerm, a VSCodium/Cursor/VS Code integrated terminal, or a pty
101
100
  (resolveInjectTargetForSession). Use --pane/--pty for direct targeting.
102
- - Built on the Terminal Engine (src/lib/terminal): --host runs the tmux /
101
+ - Built on the Terminal Engine (src/lib/terminal): --device runs the tmux /
103
102
  AppleScript spec over the same SSH transport the launch engine uses.
104
103
  `,
105
104
  });
@@ -15,7 +15,7 @@
15
15
  * - ship the transcript with the SAME bundle pipeline as
16
16
  * `sessions export --stdout | sessions import -`, over `sshExec`;
17
17
  * - resume on the target through the SAME `openSurfaces({ backend:'tmux', host })`
18
- * path `sessions resume --host` uses;
18
+ * path `sessions resume --device` uses;
19
19
  * - only AFTER the target's prompt is confirmed live, kill the source tmux
20
20
  * session (`killSession`). --keep skips the kill (copy, not move).
21
21
  *
@@ -33,9 +33,7 @@ import { getActiveSessions } from '../lib/session/active.js';
33
33
  import { discoverSessions, resolveSessionById } from '../lib/session/discover.js';
34
34
  import { buildResumeCommand } from './sessions.js';
35
35
  import { injectTargetFromReplyRail } from '../lib/session/inject.js';
36
- import { injectIntoTerminal } from '../lib/terminal/index.js';
37
- import { iLoginShell } from '../lib/terminal/shell.js';
38
- import { shellQuote as quoteArg } from '../lib/terminal/quote.js';
36
+ import { injectIntoTerminal, iLoginShell, shellQuote as quoteArg } from '../lib/terminal/index.js';
39
37
  import { killSession } from '../lib/tmux/session.js';
40
38
  import { getDefaultSocketPath } from '../lib/tmux/paths.js';
41
39
  import { listAllHosts, resolveHost } from '../lib/hosts/registry.js';
@@ -57,7 +55,7 @@ export function registerSessionsMigrateCommand(sessionsCmd) {
57
55
  .alias('relocate')
58
56
  .description('Relocate a running session onto another machine (fleet worker, device, or ephemeral box), then stop the source here.')
59
57
  .option('--auto', 'Pick the best target host automatically (idle fleet worker preferred)')
60
- .option('--host <name>', 'Explicit target: an enrolled host, a device, or a warm ephemeral box slug')
58
+ .option('--device <name>', 'Explicit target: an enrolled host, device, or a warm ephemeral box slug')
61
59
  .option('--lease', 'Provision a fresh ephemeral crabbox box as the target')
62
60
  .option('--mode <mode>', 'rehydrate (default: the target agent reads the transported transcript) or resume (best-effort native --resume)', 'rehydrate')
63
61
  .option('--keep', 'Copy, not move — do NOT stop the source after resuming on the target')
@@ -68,13 +66,13 @@ export function registerSessionsMigrateCommand(sessionsCmd) {
68
66
  agents sessions migrate --auto
69
67
 
70
68
  # Move a specific session onto a named host
71
- agents sessions migrate a1b2c3d4 --host yosemite-s1
69
+ agents sessions migrate a1b2c3d4 --device yosemite-s1
72
70
 
73
71
  # Spin up a fresh ephemeral box and move onto it
74
72
  agents sessions migrate --lease
75
73
 
76
74
  # Copy (don't stop the source), letting the agent wrap up its own dirty tree
77
- agents sessions migrate --host box-a --keep --agent-wrapup
75
+ agents sessions migrate --device box-a --keep --agent-wrapup
78
76
  `,
79
77
  notes: `
80
78
  - Without a [session-id], migrate resolves the session running in THIS tmux pane ($TMUX_PANE).
@@ -87,17 +85,8 @@ export function registerSessionsMigrateCommand(sessionsCmd) {
87
85
  - Every migrate appends to the ledger — see 'agents sessions migrations' for where each session went.
88
86
  `,
89
87
  });
90
- cmd.action(async (sessionId, options, command) => {
91
- // commander 15: the parent `sessions` command owns a global `-H, --host` (the
92
- // listing fan-out), which shadows this subcommand's own --host — the value
93
- // lands in the merged globals, not `options.host`. Read it from there so
94
- // `agents sessions migrate --host <name>` binds.
95
- const globals = command.optsWithGlobals();
96
- const hosts = Array.isArray(globals.host) ? globals.host : globals.host ? [globals.host] : [];
97
- if (hosts.length > 1) {
98
- console.error(chalk.yellow(`Multiple --host values given; migrating to the first (${hosts[0]}).`));
99
- }
100
- await sessionsMigrateAction(sessionId, { ...options, host: hosts[0] });
88
+ cmd.action(async (sessionId, options) => {
89
+ await sessionsMigrateAction(sessionId, options);
101
90
  });
102
91
  }
103
92
  function fail(message) {
@@ -141,7 +130,7 @@ function statsByName() {
141
130
  const cache = readStatsCache();
142
131
  return new Map(Object.entries(cache));
143
132
  }
144
- /** Enumerate + rank targets, honoring --host / --auto / --lease. */
133
+ /** Enumerate + rank targets, honoring --device / --auto / --lease. */
145
134
  async function resolveTarget(options, source) {
146
135
  const selfHostname = os.hostname();
147
136
  const ctx = {
@@ -162,17 +151,17 @@ async function resolveTarget(options, source) {
162
151
  warm = []; // crabbox not configured — fleet-only targets
163
152
  }
164
153
  const stats = statsByName();
165
- if (options.host) {
154
+ if (options.device) {
166
155
  // Explicit target: a fleet host/device, or a warm box slug.
167
- const box = warm.find((b) => b.slug === options.host);
156
+ const box = warm.find((b) => b.slug === options.device);
168
157
  if (box) {
169
158
  return { name: box.slug, kind: 'ephemeral', os: 'linux', headroom: 'unknown', box };
170
159
  }
171
- const host = await resolveHost(options.host);
160
+ const host = await resolveHost(options.device);
172
161
  if (!host)
173
- fail(`No host, device, or warm box named "${options.host}".`);
162
+ fail(`No host, device, or warm box named "${options.device}".`);
174
163
  if (host.name.toLowerCase() === selfHostname.toLowerCase()) {
175
- fail(`"${options.host}" is this machine — migrate needs a different target.`);
164
+ fail(`"${options.device}" is this machine — migrate needs a different target.`);
176
165
  }
177
166
  return { name: host.name, kind: 'fleet', os: host.os, headroom: 'unknown', host };
178
167
  }
@@ -186,7 +175,7 @@ async function resolveTarget(options, source) {
186
175
  }
187
176
  // Interactive: rank the candidates and let the user pick.
188
177
  if (!isInteractiveTerminal()) {
189
- fail('Pass --auto, --host <name>, or --lease to choose a target (no interactive picker without a tty).');
178
+ fail('Pass --auto, --device <name>, or --lease to choose a target (no interactive picker without a tty).');
190
179
  }
191
180
  const ranked = rankTargets(enumerateTargets(hosts, warm, stats, ctx), ctx);
192
181
  if (ranked.length === 0) {
@@ -447,7 +436,7 @@ export function buildMigrateResumeCommands(opts) {
447
436
  }
448
437
  /**
449
438
  * Resume the session on the target through the SAME host path as
450
- * `sessions resume --host` (tmux backend). Returns true when the resume launched.
439
+ * `sessions resume --device` (tmux backend). Returns true when the resume launched.
451
440
  */
452
441
  async function resumeOnTarget(sshTarget, source, remoteCwd, mode) {
453
442
  const command = mode === 'resume' ? buildResumeCommand(source) : rehydrateCommand(source);
@@ -459,7 +448,7 @@ async function resumeOnTarget(sshTarget, source, remoteCwd, mode) {
459
448
  // box has none ("no server running"), so we create the session (and thus the
460
449
  // server) directly with `new-session -d`, mirroring the local `createSession`
461
450
  // helper (remain-on-exit keeps the pane inspectable if the agent exits), over
462
- // the same SSH transport as `sessions resume --host`.
451
+ // the same SSH transport as `sessions resume --device`.
463
452
  //
464
453
  // Each argv element is quoted BEFORE the zsh -ilc wrapper so a command that
465
454
  // carries spaces or backticks (the rehydrate prompt) reaches the agent as one
@@ -1,4 +1,5 @@
1
1
  import type { SessionEvent, SessionMeta, TodoProgress } from '../lib/session/types.js';
2
+ import { fetchPeerPreviewDigest } from '../lib/session/remote-list.js';
2
3
  import { classifyFileChanges, changeCounts, toolHistogram, detectTestResult } from '../lib/session/digest.js';
3
4
  import { extractArtifacts, extractHooks, extractLinks, extractSkills } from '../lib/session/highlights.js';
4
5
  /**
@@ -32,6 +33,18 @@ export interface SessionPickerConfig {
32
33
  /** Lines the caller printed above the prompt (hidden-session footer). */
33
34
  linesAbovePrompt?: number;
34
35
  }
36
+ export declare function setRemotePreviewRepaint(repaint?: () => void): void;
37
+ export declare function setPeerDigestFetcherForTest(fetcher?: typeof fetchPeerPreviewDigest): void;
38
+ export declare function clearRemoteDigestCacheForTest(): void;
39
+ /**
40
+ * Validate + scrub a peer-supplied preview digest before any of it reaches this
41
+ * terminal. Peer JSON is untrusted at this boundary — the same rule
42
+ * `sanitizeMeta` applies to fan-out rows — so every string is stripped of
43
+ * terminal escapes and every list re-shaped field by field. Anything that
44
+ * doesn't look like the v1 digest is rejected, so a version-skewed peer
45
+ * degrades to the metadata card instead of a corrupted pane.
46
+ */
47
+ export declare function sanitizeRemoteDigest(raw: unknown): SessionPreviewDigest | undefined;
35
48
  export declare function clearPreviewMemoryCacheForTest(): void;
36
49
  export declare function loadSessionPreviewDigest(session: SessionMeta): {
37
50
  digest?: SessionPreviewDigest;
@@ -106,5 +119,6 @@ export declare function buildSessionPreviewDigest(events: SessionEvent[], sessio
106
119
  export declare function directoriesTouched(session: SessionMeta, events: SessionEvent[], changes: ReturnType<typeof classifyFileChanges>): string[];
107
120
  /** Relativize a file path to its parent dir, short enough for one preview line. */
108
121
  export declare function relativizeDir(filePath: string, cwd?: string): string | undefined;
122
+ export declare function renderLastResponse(content: string, maxLines?: number, width?: number): string[];
109
123
  /** Show an interactive session picker and return the selected session with its action (resume or view). */
110
124
  export declare function sessionPicker(config: SessionPickerConfig): Promise<PickedSession | null>;
@@ -9,6 +9,7 @@ import fs from 'node:fs';
9
9
  import path from 'node:path';
10
10
  import chalk from 'chalk';
11
11
  import { truncate, humanDuration } from '../lib/format.js';
12
+ import { fetchPeerPreviewDigest } from '../lib/session/remote-list.js';
12
13
  import { parseSession, sanitizeForTerminal, SNAPSHOT_TODO_TOOLS } from '../lib/session/parse.js';
13
14
  import { safeTeamText } from '../lib/session/team-filter.js';
14
15
  import { cleanSessionPrompt, extractSessionTopic, isSyntheticUserMessage } from '../lib/session/prompt.js';
@@ -16,6 +17,8 @@ import { linkPath, linkUrl, relativeToCwd, shortenModel } from '../lib/session/r
16
17
  import { linearIssueUrl } from '../lib/session/linear.js';
17
18
  import { extractTodoProgress, WORKTREE_RE } from '../lib/session/state.js';
18
19
  import { renderMarkdown } from '../lib/markdown.js';
20
+ import { wrapToWidth } from '../lib/wrap.js';
21
+ import { terminalWidth, stringWidth } from '../lib/session/width.js';
19
22
  import { itemPicker } from '../lib/picker.js';
20
23
  import { createMemoryCache } from '../lib/memory-cache.js';
21
24
  import { classifyFileChanges, changeCounts, toolHistogram, detectTestResult } from '../lib/session/digest.js';
@@ -23,9 +26,10 @@ import { extractArtifacts, extractHooks, extractLinks, extractRepos, extractSkil
23
26
  import { getSessionPlugins, readSessionPreviewCache, writeSessionPreviewCache, readSessionContent, readArchivedSessionPreview } from '../lib/session/db.js';
24
27
  /** A session whose transcript FILE is on another machine (folded in over the
25
28
  * live cross-machine fan-out): its `filePath` is on that peer's disk, so the
26
- * preview can't parse it locally — it shows metadata + a "resume there" note
27
- * instead. Keys off `_remote`, not the machine tag, so locally-readable synced
28
- * mirrors still parse their file normally.
29
+ * preview can't parse it locally — it fetches the peer's digest over SSH and
30
+ * shows metadata + a "resume there" note until that lands. Keys off `_remote`,
31
+ * not the machine tag, so locally-readable synced mirrors still parse their
32
+ * file normally.
29
33
  *
30
34
  * This is the READ rule and only the read rule. Whether a session may be
31
35
  * RESUMED here is a different question with a different answer — a mirror is
@@ -106,6 +110,155 @@ const previewCache = createMemoryCache({
106
110
  max: 256,
107
111
  ttlMs: 5 * 60_000,
108
112
  });
113
+ const remoteDigestCache = createMemoryCache({
114
+ max: 256,
115
+ ttlMs: 5 * 60_000,
116
+ });
117
+ function remoteDigestKey(sessionId, machine) {
118
+ return `${machine}:${sessionId}`;
119
+ }
120
+ /**
121
+ * The open picker's repaint trigger. The peer fetch resolves while the pane is
122
+ * already painted, so completion has to nudge the picker into re-rendering —
123
+ * pickers register their trigger here (via `registerPreviewRepaint`) and clear
124
+ * it when they close, making a late fetch after close a no-op.
125
+ */
126
+ let remotePreviewRepaint;
127
+ export function setRemotePreviewRepaint(repaint) {
128
+ remotePreviewRepaint = repaint;
129
+ }
130
+ /** Seam for tests: the real fetcher opens an SSH connection to the peer. */
131
+ let peerDigestFetcher = fetchPeerPreviewDigest;
132
+ export function setPeerDigestFetcherForTest(fetcher) {
133
+ peerDigestFetcher = fetcher ?? fetchPeerPreviewDigest;
134
+ }
135
+ export function clearRemoteDigestCacheForTest() {
136
+ remoteDigestCache.clear();
137
+ }
138
+ /**
139
+ * Look up (or start fetching) the peer digest for a remote row. Returns the
140
+ * current entry synchronously — `buildPreview` renders whatever state exists
141
+ * now, and the fetch's completion repaints the pane through the registered
142
+ * trigger.
143
+ */
144
+ function remoteDigestForPreview(session, machine) {
145
+ const key = remoteDigestKey(session.id, machine);
146
+ const existing = remoteDigestCache.get(key);
147
+ if (existing)
148
+ return existing;
149
+ const pending = { state: 'pending' };
150
+ remoteDigestCache.set(key, pending);
151
+ void peerDigestFetcher(session.id, machine)
152
+ .then((raw) => {
153
+ const digest = sanitizeRemoteDigest(raw);
154
+ remoteDigestCache.set(key, digest ? { state: 'ready', digest } : { state: 'failed' });
155
+ })
156
+ .catch(() => {
157
+ remoteDigestCache.set(key, { state: 'failed' });
158
+ })
159
+ .then(() => remotePreviewRepaint?.());
160
+ return pending;
161
+ }
162
+ /**
163
+ * Validate + scrub a peer-supplied preview digest before any of it reaches this
164
+ * terminal. Peer JSON is untrusted at this boundary — the same rule
165
+ * `sanitizeMeta` applies to fan-out rows — so every string is stripped of
166
+ * terminal escapes and every list re-shaped field by field. Anything that
167
+ * doesn't look like the v1 digest is rejected, so a version-skewed peer
168
+ * degrades to the metadata card instead of a corrupted pane.
169
+ */
170
+ export function sanitizeRemoteDigest(raw) {
171
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
172
+ return undefined;
173
+ const d = raw;
174
+ if (d.schemaVersion !== 1)
175
+ return undefined;
176
+ const str = (v) => (typeof v === 'string' ? sanitizeForTerminal(v) : '');
177
+ const optStr = (v) => (typeof v === 'string' ? sanitizeForTerminal(v) : undefined);
178
+ const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
179
+ const optNum = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : undefined);
180
+ const strList = (v) => Array.isArray(v) ? v.filter((x) => typeof x === 'string').map(sanitizeForTerminal) : [];
181
+ const objList = (v, map) => Array.isArray(v)
182
+ ? v.flatMap((x) => {
183
+ if (!x || typeof x !== 'object' || Array.isArray(x))
184
+ return [];
185
+ const mapped = map(x);
186
+ return mapped === undefined ? [] : [mapped];
187
+ })
188
+ : [];
189
+ let todos;
190
+ if (d.todos && typeof d.todos === 'object' && !Array.isArray(d.todos)) {
191
+ const t = d.todos;
192
+ const items = objList(t.items, (it) => {
193
+ const content = str(it.content ?? it.text);
194
+ if (!content)
195
+ return undefined;
196
+ const status = it.status === 'completed' || it.status === 'in_progress' ? it.status : 'pending';
197
+ return { content, status, activeForm: optStr(it.activeForm) };
198
+ });
199
+ todos = { items, done: num(t.done), total: num(t.total), activeForm: optStr(t.activeForm) };
200
+ }
201
+ const changes = d.changes && typeof d.changes === 'object' && !Array.isArray(d.changes)
202
+ ? {
203
+ created: num(d.changes.created),
204
+ modified: num(d.changes.modified),
205
+ deleted: num(d.changes.deleted),
206
+ }
207
+ : { created: 0, modified: 0, deleted: 0 };
208
+ let test;
209
+ if (d.test && typeof d.test === 'object' && !Array.isArray(d.test)) {
210
+ const t = d.test;
211
+ const runner = str(t.runner);
212
+ if (runner) {
213
+ test = { runner, ok: t.ok === true, ts: num(t.ts), passed: optNum(t.passed), failed: optNum(t.failed) };
214
+ }
215
+ }
216
+ return {
217
+ schemaVersion: 1,
218
+ firstUser: str(d.firstUser),
219
+ lastAssistant: str(d.lastAssistant),
220
+ filesRead: num(d.filesRead),
221
+ toolCalls: num(d.toolCalls),
222
+ planFile: str(d.planFile),
223
+ todos,
224
+ subAgentCount: num(d.subAgentCount),
225
+ toolTags: strList(d.toolTags),
226
+ changes,
227
+ dirs: strList(d.dirs),
228
+ repos: strList(d.repos),
229
+ artifacts: objList(d.artifacts, (a) => {
230
+ const p = str(a.path);
231
+ const basename = str(a.basename);
232
+ if (!p || !basename)
233
+ return undefined;
234
+ const bucket = a.bucket === 'artifacts' || a.bucket === 'plans' || a.bucket === 'reports' ? a.bucket : 'docs';
235
+ return { path: p, basename, bucket };
236
+ }),
237
+ skills: objList(d.skills, (s) => {
238
+ const name = str(s.name);
239
+ return name ? { name, count: num(s.count) } : undefined;
240
+ }),
241
+ plugins: strList(d.plugins),
242
+ hooks: objList(d.hooks, (h) => {
243
+ const name = str(h.name);
244
+ return name ? { name, event: optStr(h.event), count: num(h.count), failed: num(h.failed) } : undefined;
245
+ }),
246
+ links: objList(d.links, (l) => {
247
+ const url = str(l.url);
248
+ const label = str(l.label);
249
+ // Only http(s) URLs render as OSC 8 hyperlinks — anything else a peer
250
+ // sends (file:, a bare payload) is dropped rather than linkified.
251
+ return /^https?:\/\//.test(url) && label ? { kind: 'other', url, label } : undefined;
252
+ }),
253
+ errorCount: num(d.errorCount),
254
+ firstError: optStr(d.firstError),
255
+ toolHistogram: objList(d.toolHistogram, (h) => {
256
+ const tool = str(h.tool);
257
+ return tool ? { tool, count: num(h.count) } : undefined;
258
+ }),
259
+ test,
260
+ };
261
+ }
109
262
  function previewCacheKey(session, remote) {
110
263
  let fileStamp = '';
111
264
  if (!remote && session.filePath) {
@@ -117,10 +270,16 @@ function previewCacheKey(session, remote) {
117
270
  fileStamp = 'missing';
118
271
  }
119
272
  }
273
+ // A remote row's rendered pane depends on the fetched digest's state
274
+ // (none → pending → ready/failed), so the state rides the key — otherwise the
275
+ // memoized metadata-only card would keep serving after the digest arrived.
276
+ const remoteDigestState = remote
277
+ ? remoteDigestCache.get(remoteDigestKey(session.id, remote))?.state ?? 'none'
278
+ : '';
120
279
  // The transcript stamp invalidates derived activity. Metadata that can change
121
280
  // independently (label/ticket/PR/live scanner enrichment) also rides the key.
122
281
  return JSON.stringify([
123
- remote ?? '', session.id, fileStamp, session.lastActivity, session.label,
282
+ remote ?? '', remoteDigestState, session.id, fileStamp, session.lastActivity, session.label,
124
283
  session.topic, session.ticketId, session.prUrl, session.messageCount,
125
284
  session.tokenCount, session.model, session.todos, session.plan,
126
285
  session.recentDirectoriesTouched, session.skillsUsed,
@@ -181,13 +340,26 @@ export function buildPreview(session) {
181
340
  return cached;
182
341
  const safe = sanitizeMeta(session);
183
342
  // Remote session: the transcript is on the peer's disk, so there is nothing to
184
- // parse here. Show the metadata header (agent, cwd, msgs, tokens all carried
185
- // over in the fan-out) plus where it lives and how to open it.
343
+ // parse here. Fetch the peer's already-computed digest over SSH (kicked off on
344
+ // first render; the pane repaints when it lands) and render the same compact
345
+ // preview a local row gets. Until it arrives — or when the peer can't answer —
346
+ // show the metadata header (agent, cwd, msgs, tokens — all carried over in the
347
+ // fan-out) plus where it lives and how to open it.
186
348
  if (remote) {
187
349
  const note = ' ' + chalk.gray(`on `) + chalk.bold.white(remote)
188
350
  + chalk.gray(` — enter to resume there, or space then enter to read it over SSH`);
351
+ const entry = remoteDigestForPreview(session, remote);
352
+ if (entry.state === 'ready') {
353
+ const body = formatCompactPreview(entry.digest, safe);
354
+ const output = [formatHeader(safe, []), '', note, body].filter(Boolean).join('\n');
355
+ previewCache.set(cacheKey, output);
356
+ return output;
357
+ }
358
+ const fetching = entry.state === 'pending'
359
+ ? ' ' + chalk.gray(`fetching preview from ${remote} over SSH…`)
360
+ : '';
189
361
  const metaBody = formatMetaOnlyBody(safe);
190
- const output = [formatHeader(safe, []), '', note, metaBody].filter(Boolean).join('\n');
362
+ const output = [formatHeader(safe, []), '', note, fetching, metaBody].filter(Boolean).join('\n');
191
363
  previewCache.set(cacheKey, output);
192
364
  return output;
193
365
  }
@@ -265,8 +437,6 @@ function formatHeader(session, events) {
265
437
  if (totalTokens !== undefined) {
266
438
  line3.push(chalk.bold.white(formatTokens(totalTokens)) + chalk.gray(' tokens'));
267
439
  }
268
- if (session.label)
269
- line3.push(chalk.white(session.label));
270
440
  if (session.filePath)
271
441
  line3.push(chalk.gray(linkPath(session.filePath, session.id)));
272
442
  else
@@ -282,7 +452,19 @@ function formatHeader(session, events) {
282
452
  const label = session.prNumber ? `PR#${session.prNumber}` : 'PR';
283
453
  line4.push(chalk.blue(linkUrl(session.prUrl, label)));
284
454
  }
455
+ // Lead with the session's human title: `session.label` — an agent-generated
456
+ // name / `/rename`, else the `--name` launch handle. NOT `session.topic`: the
457
+ // topic is the derived first-prompt, already shown on the `Prompt:` line, so
458
+ // using it here too would print the same text twice. Unlabelled sessions keep
459
+ // that `Prompt:` line as their topic indicator and simply lead with the agent
460
+ // line. Wrapped to the pane (the header sits at column 0, full terminal width);
461
+ // nothing renders when there is no label.
462
+ const title = (session.label || '').trim();
463
+ const titleLines = title
464
+ ? wrapToWidth(title, terminalWidth()).map(l => chalk.bold.white(l))
465
+ : [];
285
466
  return [
467
+ ...titleLines,
286
468
  line1.join(DOT),
287
469
  line2.join(DOT),
288
470
  line3.join(DOT),
@@ -651,7 +833,9 @@ function formatCompactPreview(digest, session) {
651
833
  }
652
834
  if (lastAssistant) {
653
835
  const maxLines = todosRendered.length > 0 || compact ? LAST_RESPONSE_MAX_LINES_WITH_TODOS : LAST_RESPONSE_MAX_LINES;
654
- const rendered = renderLastResponse(lastAssistant, maxLines);
836
+ // Content sits at column 4 (outer body indent + the ' ' prefix below), so
837
+ // wrap it to the pane minus that indent.
838
+ const rendered = renderLastResponse(lastAssistant, maxLines, terminalWidth() - 4);
655
839
  if (rendered.length > 0) {
656
840
  lines.push('');
657
841
  lines.push(chalk.cyan('Last response:'));
@@ -829,7 +1013,7 @@ export function relativizeDir(filePath, cwd) {
829
1013
  dir = parts.slice(-3).join('/');
830
1014
  return dir || undefined;
831
1015
  }
832
- function renderLastResponse(content, maxLines = LAST_RESPONSE_MAX_LINES) {
1016
+ export function renderLastResponse(content, maxLines = LAST_RESPONSE_MAX_LINES, width = terminalWidth()) {
833
1017
  const cleaned = stripTags(content).trim();
834
1018
  if (!cleaned)
835
1019
  return [];
@@ -840,7 +1024,15 @@ function renderLastResponse(content, maxLines = LAST_RESPONSE_MAX_LINES) {
840
1024
  catch {
841
1025
  rendered = cleaned;
842
1026
  }
843
- const all = rendered.replace(/\s+$/, '').split('\n');
1027
+ // `marked-terminal` runs with `reflowText` off, so a paragraph with no hard
1028
+ // breaks renders as one long line that overflows the pane. Wrap any line whose
1029
+ // VISIBLE width exceeds the budget; leave lines that already fit untouched so
1030
+ // rendered-markdown indentation (lists, code blocks) is preserved. The text is
1031
+ // ANSI-coloured, so width is measured with `stringWidth`, never `String.length`.
1032
+ const all = rendered
1033
+ .replace(/\s+$/, '')
1034
+ .split('\n')
1035
+ .flatMap(line => (stringWidth(line) <= width ? [line] : wrapToWidth(line, width)));
844
1036
  // Drop leading/trailing empty lines
845
1037
  while (all.length && !all[0].trim())
846
1038
  all.shift();
@@ -895,13 +1087,17 @@ export async function sessionPicker(config) {
895
1087
  filter: config.filter,
896
1088
  labelFor: config.labelFor,
897
1089
  buildPreview,
1090
+ // A remote row's digest arrives over SSH after the pane painted — this is
1091
+ // what lets its completion swap the metadata card for the full preview.
1092
+ registerPreviewRepaint: setRemotePreviewRepaint,
898
1093
  shortIdFor: (s) => s.shortId,
899
1094
  pageSize: config.pageSize,
900
1095
  initialSearch: config.initialSearch,
901
1096
  emptyMessage: 'No sessions match.',
902
1097
  enterHint: config.enterHint ?? 'resume',
903
1098
  linesAbovePrompt: config.linesAbovePrompt,
904
- });
1099
+ // A late digest fetch must not poke a closed prompt.
1100
+ }).finally(() => setRemotePreviewRepaint(undefined));
905
1101
  if (!picked)
906
1102
  return null;
907
1103
  return { session: picked.item, action: 'resume' };
@@ -1,15 +1,16 @@
1
1
  import type { Command } from 'commander';
2
2
  import { type SessionMeta } from '../lib/session/types.js';
3
3
  import { type Backend, type EngineContext, type Packing } from '../lib/terminal/index.js';
4
+ import { type StrictResumeOptions } from './resume.js';
4
5
  /** Opening more than this many live sessions at once asks for confirmation first. */
5
6
  export declare const CONFIRM_THRESHOLD = 5;
6
- export interface ResumeOptions {
7
+ export interface ResumeOptions extends StrictResumeOptions {
7
8
  agent?: string;
8
9
  all?: boolean;
9
10
  teams?: boolean;
10
11
  since?: string;
11
12
  limit?: string;
12
- host?: string;
13
+ device?: string;
13
14
  iterm?: boolean;
14
15
  ghostty?: boolean;
15
16
  tmux?: boolean;
@@ -24,12 +25,15 @@ export declare function registerSessionsResumeCommand(sessionsCmd: Command): voi
24
25
  /** IDs and tmux aliases are actions, not picker search text. Human phrases keep
25
26
  * the existing pre-filtered picker, while an explicit identity resumes directly. */
26
27
  export declare function isDirectResumeSelector(query: string): boolean;
27
- /** Re-enter through the top-level command so fleet routing and harness policy
28
+ /** Re-enter through sessions resume so fleet routing and harness policy
28
29
  * stay centralized. The child inherits this terminal for a real interactive resume. */
29
30
  export declare function resumeSelectorInPlace(selector: string): Promise<void>;
30
31
  /** Direct identities use focus as the lifecycle dispatcher: it rechecks the
31
32
  * live fleet, attaches a healthy pane, and falls through to `agents resume`
32
33
  * only when the process is no longer attachable. */
34
+ /** True when `sessions resume <id> --attach-only|--local` must go through
35
+ * `sessions focus` instead of `runStrictResume` (which can fork a copy). */
36
+ export declare function resumeUsesLifecycleDispatch(query: string | undefined, prompt: string | undefined, options: Pick<ResumeOptions, 'attachOnly' | 'local' | 'mode' | 'interactive' | 'headless' | 'here'>): boolean;
33
37
  export declare function dispatchSessionLifecycleInPlace(selector: string, hosts?: string[], attachOnly?: boolean, local?: boolean): Promise<void>;
34
38
  export declare function buildSessionLifecycleArgs(selector: string, hosts?: string[], attachOnly?: boolean, local?: boolean): string[];
35
39
  export declare function resolveResumePacking(options: Pick<ResumeOptions, 'splits'>): Packing;