@phnx-labs/agents-cli 1.22.46 → 1.22.49

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 (348) hide show
  1. package/CHANGELOG.md +663 -0
  2. package/LICENSE +102 -182
  3. package/README.md +96 -49
  4. package/dist/bootstrap.js +4 -2
  5. package/dist/cli/command-registry.d.ts +2 -1
  6. package/dist/cli/command-registry.js +6 -2
  7. package/dist/commands/accounts.d.ts +58 -0
  8. package/dist/commands/accounts.js +243 -25
  9. package/dist/commands/artifacts.js +7 -6
  10. package/dist/commands/attach.js +1 -1
  11. package/dist/commands/auth.js +7 -5
  12. package/dist/commands/browser-sessions-picker.js +9 -7
  13. package/dist/commands/browser.js +711 -62
  14. package/dist/commands/config.d.ts +0 -1
  15. package/dist/commands/config.js +26 -24
  16. package/dist/commands/cost.d.ts +1 -1
  17. package/dist/commands/daemon.d.ts +21 -0
  18. package/dist/commands/daemon.js +147 -12
  19. package/dist/commands/detach.d.ts +13 -0
  20. package/dist/commands/detach.js +11 -8
  21. package/dist/commands/exec.js +107 -53
  22. package/dist/commands/feed-watch.d.ts +2 -0
  23. package/dist/commands/feed-watch.js +28 -0
  24. package/dist/commands/feed.js +27 -0
  25. package/dist/commands/feedback.js +3 -19
  26. package/dist/commands/focus.d.ts +14 -0
  27. package/dist/commands/focus.js +48 -5
  28. package/dist/commands/go.d.ts +3 -0
  29. package/dist/commands/go.js +16 -3
  30. package/dist/commands/insights.d.ts +1 -1
  31. package/dist/commands/insights.js +2 -2
  32. package/dist/commands/inspect.js +2 -2
  33. package/dist/commands/lease.d.ts +1 -1
  34. package/dist/commands/lease.js +7 -6
  35. package/dist/commands/mailboxes.js +4 -3
  36. package/dist/commands/menubar.js +11 -4
  37. package/dist/commands/projects.d.ts +16 -1
  38. package/dist/commands/projects.js +58 -64
  39. package/dist/commands/resume.js +1 -1
  40. package/dist/commands/route.js +4 -4
  41. package/dist/commands/routines.js +4 -3
  42. package/dist/commands/run-broadcast.d.ts +1 -1
  43. package/dist/commands/run-broadcast.js +1 -1
  44. package/dist/commands/sessions-picker-factory.d.ts +2 -1
  45. package/dist/commands/sessions-picker-factory.js +1 -1
  46. package/dist/commands/sessions-picker.d.ts +22 -0
  47. package/dist/commands/sessions-picker.js +48 -9
  48. package/dist/commands/sessions-stop.d.ts +24 -0
  49. package/dist/commands/sessions-stop.js +66 -0
  50. package/dist/commands/sessions-trace.d.ts +82 -0
  51. package/dist/commands/sessions-trace.js +387 -0
  52. package/dist/commands/sessions.js +5 -0
  53. package/dist/commands/setup-secrets.js +23 -0
  54. package/dist/commands/share.d.ts +20 -5
  55. package/dist/commands/share.js +152 -52
  56. package/dist/commands/ssh.d.ts +15 -0
  57. package/dist/commands/ssh.js +243 -18
  58. package/dist/commands/teams.js +34 -2
  59. package/dist/commands/traces.d.ts +2 -0
  60. package/dist/commands/traces.js +184 -0
  61. package/dist/commands/view.d.ts +2 -0
  62. package/dist/commands/view.js +32 -62
  63. package/dist/commands/watchdog.js +9 -14
  64. package/dist/index.d.ts +1 -0
  65. package/dist/index.js +5 -0
  66. package/dist/lib/account-capabilities.d.ts +4 -0
  67. package/dist/lib/account-capabilities.js +13 -9
  68. package/dist/lib/account-registry.d.ts +2 -0
  69. package/dist/lib/account-registry.js +30 -2
  70. package/dist/lib/accounting/rotate.d.ts +9 -0
  71. package/dist/lib/accounting/rotate.js +12 -2
  72. package/dist/lib/accounting/usage.d.ts +84 -6
  73. package/dist/lib/accounting/usage.js +293 -75
  74. package/dist/lib/agent-modes.js +29 -1
  75. package/dist/lib/agent-spec/agents.d.ts +4 -3
  76. package/dist/lib/agent-spec/agents.js +25 -15
  77. package/dist/lib/analytics/mix-commands.d.ts +1 -1
  78. package/dist/lib/analytics/mix-commands.js +2 -2
  79. package/dist/lib/auth-health.d.ts +13 -3
  80. package/dist/lib/auth-health.js +50 -8
  81. package/dist/lib/browser/devices.d.ts +19 -0
  82. package/dist/lib/browser/devices.js +23 -0
  83. package/dist/lib/browser/drivers/ssh.d.ts +16 -2
  84. package/dist/lib/browser/drivers/ssh.js +36 -9
  85. package/dist/lib/browser/ipc.d.ts +1 -1
  86. package/dist/lib/browser/ipc.js +40 -9
  87. package/dist/lib/browser/profiles.d.ts +104 -65
  88. package/dist/lib/browser/profiles.js +277 -165
  89. package/dist/lib/browser/registry.d.ts +39 -0
  90. package/dist/lib/browser/registry.js +149 -0
  91. package/dist/lib/browser/remote-control.d.ts +28 -2
  92. package/dist/lib/browser/remote-control.js +35 -3
  93. package/dist/lib/browser/resolve-target.d.ts +68 -0
  94. package/dist/lib/browser/resolve-target.js +250 -0
  95. package/dist/lib/browser/runtime-state.d.ts +44 -11
  96. package/dist/lib/browser/runtime-state.js +98 -15
  97. package/dist/lib/browser/service.d.ts +65 -9
  98. package/dist/lib/browser/service.js +196 -61
  99. package/dist/lib/browser/sessions-list.d.ts +1 -3
  100. package/dist/lib/browser/sessions-list.js +3 -16
  101. package/dist/lib/browser/task-index.d.ts +70 -0
  102. package/dist/lib/browser/task-index.js +180 -0
  103. package/dist/lib/browser/types.d.ts +12 -1
  104. package/dist/lib/byok-usage.js +2 -2
  105. package/dist/lib/claude-statusline.d.ts +29 -0
  106. package/dist/lib/claude-statusline.js +139 -0
  107. package/dist/lib/cloud/host.d.ts +1 -1
  108. package/dist/lib/cloud/host.js +1 -1
  109. package/dist/lib/cloud/rush.js +1 -1
  110. package/dist/lib/codex-policy.d.ts +11 -1
  111. package/dist/lib/codex-policy.js +20 -5
  112. package/dist/lib/computer/computer-rpc.js +2 -2
  113. package/dist/lib/computer/download.d.ts +15 -15
  114. package/dist/lib/computer/download.js +35 -98
  115. package/dist/lib/computer/ssh-tunnel.d.ts +0 -3
  116. package/dist/lib/computer/ssh-tunnel.js +12 -22
  117. package/dist/lib/config-keys.d.ts +6 -11
  118. package/dist/lib/config-keys.js +18 -19
  119. package/dist/lib/crabbox/cli.d.ts +1 -1
  120. package/dist/lib/crabbox/cli.js +2 -2
  121. package/dist/lib/crabbox/lease.d.ts +9 -0
  122. package/dist/lib/crabbox/lease.js +70 -15
  123. package/dist/lib/crabbox/runtimes.js +1 -1
  124. package/dist/lib/daemon/account-state-daemon-service.d.ts +16 -0
  125. package/dist/lib/daemon/account-state-daemon-service.js +26 -0
  126. package/dist/lib/daemon/browser-ipc-service.d.ts +20 -0
  127. package/dist/lib/daemon/browser-ipc-service.js +46 -0
  128. package/dist/lib/daemon/daemon.d.ts +3 -0
  129. package/dist/lib/daemon/daemon.js +212 -444
  130. package/dist/lib/daemon/device-probe-service.d.ts +26 -0
  131. package/dist/lib/daemon/device-probe-service.js +47 -0
  132. package/dist/lib/daemon/keychain-reap-service.d.ts +17 -0
  133. package/dist/lib/daemon/keychain-reap-service.js +32 -0
  134. package/dist/lib/daemon/monitor-engine-service.d.ts +22 -0
  135. package/dist/lib/daemon/monitor-engine-service.js +29 -0
  136. package/dist/lib/daemon/runner.js +15 -2
  137. package/dist/lib/daemon/secrets-broker-service.d.ts +20 -0
  138. package/dist/lib/daemon/secrets-broker-service.js +66 -0
  139. package/dist/lib/daemon/self-heal-service.d.ts +27 -0
  140. package/dist/lib/daemon/self-heal-service.js +48 -0
  141. package/dist/lib/daemon/service.d.ts +102 -0
  142. package/dist/lib/daemon/service.js +98 -0
  143. package/dist/lib/daemon/session-index-service.d.ts +22 -0
  144. package/dist/lib/daemon/session-index-service.js +40 -0
  145. package/dist/lib/daemon/state-dir-check-service.d.ts +43 -0
  146. package/dist/lib/daemon/state-dir-check-service.js +63 -0
  147. package/dist/lib/daemon/supervisor.d.ts +87 -0
  148. package/dist/lib/daemon/supervisor.js +298 -0
  149. package/dist/lib/daemon/watchdog-service.d.ts +19 -0
  150. package/dist/lib/daemon/watchdog-service.js +40 -0
  151. package/dist/lib/daemon-health.d.ts +15 -0
  152. package/dist/lib/daemon-health.js +29 -5
  153. package/dist/lib/daemon-services.d.ts +8 -1
  154. package/dist/lib/daemon-services.js +55 -0
  155. package/dist/lib/daemon-ticks.d.ts +13 -2
  156. package/dist/lib/daemon-ticks.js +22 -20
  157. package/dist/lib/device-config.d.ts +25 -10
  158. package/dist/lib/device-config.js +90 -39
  159. package/dist/lib/devices/config-migration.d.ts +7 -0
  160. package/dist/lib/devices/config-migration.js +67 -3
  161. package/dist/lib/devices/health.d.ts +27 -2
  162. package/dist/lib/devices/health.js +39 -9
  163. package/dist/lib/devices/interactive-host.d.ts +15 -0
  164. package/dist/lib/devices/interactive-host.js +53 -0
  165. package/dist/lib/devices/registry.d.ts +61 -4
  166. package/dist/lib/devices/registry.js +94 -38
  167. package/dist/lib/devices/stats-cache.d.ts +26 -0
  168. package/dist/lib/devices/stats-cache.js +59 -7
  169. package/dist/lib/devices/worker-pick.d.ts +48 -0
  170. package/dist/lib/devices/worker-pick.js +113 -0
  171. package/dist/lib/exec.d.ts +70 -14
  172. package/dist/lib/exec.js +110 -38
  173. package/dist/lib/feed/answer.d.ts +29 -0
  174. package/dist/lib/feed/answer.js +145 -0
  175. package/dist/lib/feed/attention.d.ts +83 -0
  176. package/dist/lib/feed/attention.js +0 -0
  177. package/dist/lib/feed/feed.d.ts +109 -0
  178. package/dist/lib/feed/feed.js +154 -3
  179. package/dist/lib/feed/pr-status.d.ts +14 -0
  180. package/dist/lib/feed/pr-status.js +47 -0
  181. package/dist/lib/feed/watch.d.ts +59 -0
  182. package/dist/lib/feed/watch.js +180 -0
  183. package/dist/lib/fleet/capture.js +6 -0
  184. package/dist/lib/fleet/remote-login.js +8 -3
  185. package/dist/lib/fleet/types.d.ts +17 -0
  186. package/dist/lib/harness/adapter.d.ts +11 -0
  187. package/dist/lib/harness/adapters/claude.js +38 -24
  188. package/dist/lib/harness/adapters/codex.js +2 -4
  189. package/dist/lib/harness/adapters/cursor.js +8 -11
  190. package/dist/lib/helper-download.d.ts +108 -0
  191. package/dist/lib/helper-download.js +194 -0
  192. package/dist/lib/helper-versions.d.ts +52 -0
  193. package/dist/lib/helper-versions.js +58 -0
  194. package/dist/lib/hooks/cache.js +19 -0
  195. package/dist/lib/hooks/install.js +2 -2
  196. package/dist/lib/hooks/match.d.ts +3 -0
  197. package/dist/lib/hooks/match.js +25 -0
  198. package/dist/lib/hosts/credentials.d.ts +1 -1
  199. package/dist/lib/hosts/credentials.js +1 -1
  200. package/dist/lib/hosts/dispatch.d.ts +7 -1
  201. package/dist/lib/hosts/dispatch.js +24 -5
  202. package/dist/lib/hosts/passthrough.d.ts +8 -15
  203. package/dist/lib/hosts/passthrough.js +35 -16
  204. package/dist/lib/hosts/providers/devices.d.ts +1 -1
  205. package/dist/lib/hosts/providers/devices.js +1 -1
  206. package/dist/lib/hosts/reconnect.d.ts +179 -21
  207. package/dist/lib/hosts/reconnect.js +266 -45
  208. package/dist/lib/hosts/registry.js +7 -0
  209. package/dist/lib/installations/migrate.d.ts +4 -5
  210. package/dist/lib/installations/migrate.js +6 -7
  211. package/dist/lib/installations/shims.d.ts +1 -1
  212. package/dist/lib/installations/shims.js +23 -13
  213. package/dist/lib/installations/versions.js +25 -2
  214. package/dist/lib/linear-autoclose.d.ts +1 -1
  215. package/dist/lib/linear-autoclose.js +1 -1
  216. package/dist/lib/loop.d.ts +2 -2
  217. package/dist/lib/loop.js +1 -1
  218. package/dist/lib/menubar/download-menubar.d.ts +47 -0
  219. package/dist/lib/menubar/download-menubar.js +60 -0
  220. package/dist/lib/menubar/install-menubar.d.ts +44 -7
  221. package/dist/lib/menubar/install-menubar.js +105 -23
  222. package/dist/lib/menubar/notify-desktop.d.ts +3 -3
  223. package/dist/lib/menubar/notify-desktop.js +6 -6
  224. package/dist/lib/model-tiers.d.ts +1 -1
  225. package/dist/lib/open-url.d.ts +60 -2
  226. package/dist/lib/open-url.js +167 -12
  227. package/dist/lib/project-probe.d.ts +1 -1
  228. package/dist/lib/project-probe.js +1 -1
  229. package/dist/lib/project-pull.d.ts +1 -1
  230. package/dist/lib/project-pull.js +2 -2
  231. package/dist/lib/projects.d.ts +1 -1
  232. package/dist/lib/projects.js +1 -1
  233. package/dist/lib/refresh-coordinator.d.ts +1 -1
  234. package/dist/lib/refresh-coordinator.js +1 -1
  235. package/dist/lib/sandbox.js +6 -7
  236. package/dist/lib/secrets/download-keychain.d.ts +47 -0
  237. package/dist/lib/secrets/download-keychain.js +70 -0
  238. package/dist/lib/secrets/install-helper.d.ts +20 -1
  239. package/dist/lib/secrets/install-helper.js +44 -3
  240. package/dist/lib/session/active.d.ts +67 -0
  241. package/dist/lib/session/active.js +86 -2
  242. package/dist/lib/session/db.d.ts +11 -1
  243. package/dist/lib/session/db.js +142 -8
  244. package/dist/lib/session/discover.d.ts +23 -1
  245. package/dist/lib/session/discover.js +44 -10
  246. package/dist/lib/session/highlights.d.ts +49 -1
  247. package/dist/lib/session/highlights.js +95 -0
  248. package/dist/lib/session/host-link.d.ts +16 -2
  249. package/dist/lib/session/host-link.js +7 -1
  250. package/dist/lib/session/parse.js +33 -1
  251. package/dist/lib/session/prompt.d.ts +35 -0
  252. package/dist/lib/session/prompt.js +56 -0
  253. package/dist/lib/session/remote/remote-list.d.ts +9 -0
  254. package/dist/lib/session/remote/remote-list.js +19 -2
  255. package/dist/lib/session/remote/watch.d.ts +1 -1
  256. package/dist/lib/session/remote/watch.js +17 -3
  257. package/dist/lib/session/render.js +7 -3
  258. package/dist/lib/session/session-cache.d.ts +53 -0
  259. package/dist/lib/session/session-cache.js +93 -1
  260. package/dist/lib/session/state.js +1 -1
  261. package/dist/lib/session/tool-calls.d.ts +2 -0
  262. package/dist/lib/session/tool-calls.js +1 -1
  263. package/dist/lib/session/trajectory-compare.d.ts +47 -0
  264. package/dist/lib/session/trajectory-compare.js +116 -0
  265. package/dist/lib/session/trajectory-html.d.ts +19 -0
  266. package/dist/lib/session/trajectory-html.js +770 -0
  267. package/dist/lib/session/trajectory-lineage.d.ts +92 -0
  268. package/dist/lib/session/trajectory-lineage.js +195 -0
  269. package/dist/lib/session/trajectory-text.d.ts +37 -0
  270. package/dist/lib/session/trajectory-text.js +284 -0
  271. package/dist/lib/session/trajectory.d.ts +102 -0
  272. package/dist/lib/session/trajectory.js +384 -0
  273. package/dist/lib/session/types.d.ts +15 -0
  274. package/dist/lib/sha256-asset.d.ts +26 -0
  275. package/dist/lib/sha256-asset.js +41 -0
  276. package/dist/lib/share/backend.d.ts +95 -0
  277. package/dist/lib/share/backend.js +139 -0
  278. package/dist/lib/share/delete.d.ts +6 -2
  279. package/dist/lib/share/delete.js +8 -9
  280. package/dist/lib/share/html.d.ts +22 -0
  281. package/dist/lib/share/html.js +88 -0
  282. package/dist/lib/share/provision.d.ts +18 -4
  283. package/dist/lib/share/provision.js +38 -4
  284. package/dist/lib/share/publish.d.ts +39 -15
  285. package/dist/lib/share/publish.js +55 -26
  286. package/dist/lib/share/worker-template.js +171 -11
  287. package/dist/lib/sqlite.js +16 -3
  288. package/dist/lib/ssh-exec.d.ts +65 -0
  289. package/dist/lib/ssh-exec.js +120 -4
  290. package/dist/lib/startup/command-registry.d.ts +3 -1
  291. package/dist/lib/startup/command-registry.js +6 -3
  292. package/dist/lib/startup/dev-build.js +3 -3
  293. package/dist/lib/state.d.ts +2 -2
  294. package/dist/lib/state.js +11 -5
  295. package/dist/lib/subagents-registry.js +1 -1
  296. package/dist/lib/teams/agents.js +9 -0
  297. package/dist/lib/terminal/index.d.ts +1 -1
  298. package/dist/lib/terminal/inject.d.ts +19 -0
  299. package/dist/lib/terminal/inject.js +19 -9
  300. package/dist/lib/terminal/types.d.ts +1 -1
  301. package/dist/lib/terminal/types.js +1 -1
  302. package/dist/lib/tmux/orphan-reap.js +1 -1
  303. package/dist/lib/tmux/session.d.ts +46 -13
  304. package/dist/lib/tmux/session.js +204 -27
  305. package/dist/lib/traces/backend.d.ts +29 -0
  306. package/dist/lib/traces/backend.js +46 -0
  307. package/dist/lib/traces/classify.d.ts +52 -0
  308. package/dist/lib/traces/classify.js +72 -0
  309. package/dist/lib/traces/config.d.ts +10 -0
  310. package/dist/lib/traces/config.js +2 -0
  311. package/dist/lib/traces/provision.d.ts +19 -0
  312. package/dist/lib/traces/provision.js +30 -0
  313. package/dist/lib/traces/sync.d.ts +150 -0
  314. package/dist/lib/traces/sync.js +447 -0
  315. package/dist/lib/traces/worker-template.d.ts +4 -0
  316. package/dist/lib/traces/worker-template.js +159 -0
  317. package/dist/lib/types.d.ts +34 -19
  318. package/dist/lib/types.js +14 -0
  319. package/dist/lib/usage-backoff.d.ts +2 -1
  320. package/dist/lib/usage-backoff.js +60 -19
  321. package/dist/lib/usage-refresh.d.ts +18 -4
  322. package/dist/lib/usage-refresh.js +68 -19
  323. package/dist/lib/watchdog/log.d.ts +1 -1
  324. package/dist/lib/watchdog/log.js +1 -1
  325. package/dist/lib/watchdog/runner.d.ts +36 -45
  326. package/dist/lib/watchdog/runner.js +150 -119
  327. package/dist/lib/watchdog/service.d.ts +0 -1
  328. package/dist/lib/watchdog/service.js +0 -1
  329. package/dist/lib/watchdog/watchdog-agent.d.ts +38 -0
  330. package/dist/lib/watchdog/watchdog-agent.js +59 -0
  331. package/dist/lib/watchdog/watchdog.d.ts +11 -2
  332. package/dist/lib/watchdog/watchdog.js +37 -104
  333. package/dist/lib/workflows.d.ts +1 -1
  334. package/package.json +5 -7
  335. package/dist/commands/usage.d.ts +0 -27
  336. package/dist/commands/usage.js +0 -96
  337. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  338. package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +0 -24
  339. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  340. package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
  341. package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +0 -128
  342. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  343. package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -24
  344. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  345. package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +0 -123
  346. package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
  347. package/dist/lib/usage-fleet.d.ts +0 -32
  348. package/dist/lib/usage-fleet.js +0 -125
@@ -22,7 +22,7 @@ import { terminalWidth, stringWidth } from '../lib/session/width.js';
22
22
  import { itemPicker } from '../lib/picker.js';
23
23
  import { createMemoryCache } from '../lib/memory-cache.js';
24
24
  import { classifyFileChanges, changeCounts, toolHistogram, detectTestResult } from '../lib/session/digest.js';
25
- import { extractArtifacts, extractHooks, extractLinks, extractRepos, extractSkills } from '../lib/session/highlights.js';
25
+ import { extractArtifacts, extractHooks, extractLinks, extractRepos, extractSkills, harnessTracksBackgroundShells, isBackgroundShellStart, isSubAgentTool, } from '../lib/session/highlights.js';
26
26
  import { getSessionPlugins, readSessionPreviewCache, writeSessionPreviewCache, readSessionContent, readArchivedSessionPreview } from '../lib/session/db.js';
27
27
  /** A session whose transcript FILE is on another machine (folded in over the
28
28
  * live cross-machine fan-out): its `filePath` is on that peer's disk, so the
@@ -222,6 +222,10 @@ export function sanitizeRemoteDigest(raw) {
222
222
  planFile: str(d.planFile),
223
223
  todos,
224
224
  subAgentCount: num(d.subAgentCount),
225
+ // optNum, not num: a peer's JSON is untrusted, and the undefined-vs-0
226
+ // distinction is load-bearing here — num() would coerce a malformed value
227
+ // to 0, which reads as "scanned, none running".
228
+ backgroundShellCount: optNum(d.backgroundShellCount),
225
229
  toolTags: strList(d.toolTags),
226
230
  changes,
227
231
  dirs: strList(d.dirs),
@@ -472,6 +476,37 @@ function formatHeader(session, events) {
472
476
  * machine — far too much for a pane that repaints as the cursor moves. The line
473
477
  * names the command that does report them instead.
474
478
  */
479
+ /**
480
+ * The "what did this session leave running" segments of the Doing line.
481
+ *
482
+ * Prefers a DERIVED count (fresh, from the transcript the caller just parsed)
483
+ * and falls back to the PERSISTED column, which is what lets a remote/unindexed
484
+ * row — rendered from `SessionMeta` alone, with no events — show fan-out at all.
485
+ * That fallback is the whole reason the counts are columns (RUSH-3091/3095).
486
+ *
487
+ * A count of 0 or undefined renders NOTHING. Both are real states — "scanned,
488
+ * none found" and "this harness cannot report it" — and a literal "0 background
489
+ * shells" would assert "nothing is running" for a harness that simply does not
490
+ * record them.
491
+ *
492
+ * Wording is "left behind", not "running": a transcript records a start and
493
+ * never a death (see extractBackgroundShells).
494
+ */
495
+ export function formatFanOut(session, derived) {
496
+ // DERIVED wins when the caller has one. It is computed from the transcript as
497
+ // it stands right now, whereas the persisted column is only as fresh as the
498
+ // last scan — for a live session those disagree within seconds. The persisted
499
+ // value is the fallback that makes a remote/unindexed row (no events, so no
500
+ // derived value) render at all, which is the whole reason it is a column.
501
+ const subAgents = derived?.subAgentCount ?? session.subAgentCount ?? 0;
502
+ const shells = derived?.backgroundShellCount ?? session.backgroundShellCount ?? 0;
503
+ const out = [];
504
+ if (subAgents > 0)
505
+ out.push(chalk.gray(`${subAgents} sub-agent${subAgents === 1 ? '' : 's'}`));
506
+ if (shells > 0)
507
+ out.push(chalk.gray(`${shells} background shell${shells === 1 ? '' : 's'}`));
508
+ return out;
509
+ }
475
510
  export function formatTeamLineage(session) {
476
511
  const origin = session.teamOrigin;
477
512
  if (origin) {
@@ -505,7 +540,7 @@ function formatMetaOnlyBody(session) {
505
540
  }
506
541
  const compact = formatTodoCompact(session.todos);
507
542
  const teamLine = formatTeamLineage(session);
508
- const doing = [compact ? chalk.white(compact) : '', teamLine].filter(Boolean);
543
+ const doing = [compact ? chalk.white(compact) : '', teamLine, ...formatFanOut(session)].filter(Boolean);
509
544
  if (doing.length) {
510
545
  lines.push(verbLabel('Doing') + doing.join(DOT));
511
546
  }
@@ -630,6 +665,12 @@ export function buildSessionPreviewDigest(events, session) {
630
665
  /** Latest checklist from the transcript (Claude TodoWrite / Codex update_plan). */
631
666
  let latestTodos;
632
667
  let subAgentCount = 0;
668
+ // undefined, not 0, when the harness records no background-shell concept —
669
+ // formatFanOut renders absence for both, but conflating them here would let a
670
+ // later consumer read "0 shells" as a positive "none running" claim.
671
+ let backgroundShellCount = harnessTracksBackgroundShells(session.agent)
672
+ ? 0
673
+ : undefined;
633
674
  const toolTags = new Set();
634
675
  // usedBrowser/usedComputer are computed at scan time from a sessionId-scoped
635
676
  // events-log read (session/db.ts detectToolUsage), NOT a transcript regex —
@@ -658,6 +699,8 @@ export function buildSessionPreviewDigest(events, session) {
658
699
  }
659
700
  if (isSubAgentTool(tool, command))
660
701
  subAgentCount++;
702
+ if (backgroundShellCount !== undefined && isBackgroundShellStart(event))
703
+ backgroundShellCount++;
661
704
  const p = event.path || event.args?.file_path || event.args?.path || '';
662
705
  if (['Read', 'read_file', 'view_file', 'cat_file', 'get_file'].includes(tool) && p) {
663
706
  filesRead.add(p);
@@ -700,6 +743,7 @@ export function buildSessionPreviewDigest(events, session) {
700
743
  planFile,
701
744
  todos,
702
745
  subAgentCount,
746
+ backgroundShellCount,
703
747
  toolTags: [...toolTags],
704
748
  changes: chg,
705
749
  dirs: directoriesTouched(session, events, changes),
@@ -722,7 +766,7 @@ function verbLabel(v) {
722
766
  return chalk.cyan(v.padEnd(VERB_GUTTER)) + ' ';
723
767
  }
724
768
  function formatCompactPreview(digest, session, events) {
725
- const { firstUser, lastAssistant, filesRead, toolCalls, planFile, todos, subAgentCount, toolTags, changes: chg, dirs, repos, artifacts, skills, plugins, hooks, links, errorCount, firstError, toolHistogram: hist, test, } = digest;
769
+ const { firstUser, lastAssistant, filesRead, toolCalls, planFile, todos, subAgentCount, backgroundShellCount, toolTags, changes: chg, dirs, repos, artifacts, skills, plugins, hooks, links, errorCount, firstError, toolHistogram: hist, test, } = digest;
726
770
  const lines = [];
727
771
  const termWidth = process.stdout.columns || 80;
728
772
  const valueWidth = termWidth - VERB_GUTTER - 5;
@@ -740,7 +784,7 @@ function formatCompactPreview(digest, session, events) {
740
784
  const doing = [
741
785
  compact ? chalk.white(compact) : '',
742
786
  teamLine,
743
- subAgentCount ? chalk.gray(`${subAgentCount} sub-agent${subAgentCount === 1 ? '' : 's'}`) : '',
787
+ ...formatFanOut(session, { subAgentCount, backgroundShellCount }),
744
788
  ].filter(Boolean);
745
789
  if (doing.length) {
746
790
  lines.push(verbLabel('Doing') + doing.join(DOT));
@@ -854,11 +898,6 @@ function classifySessionTool(tool, command) {
854
898
  tags.push('computer');
855
899
  return tags;
856
900
  }
857
- function isSubAgentTool(tool, command) {
858
- if (/^(Agent|Task)$/i.test(tool))
859
- return true;
860
- return /\b(?:agents|ag)\b[^\n;&|]*\b(?:run|cloud\s+run|teams\s+(?:add|start))\b/.test(command);
861
- }
862
901
  /**
863
902
  * Unique directories the session touched, compact and human-readable.
864
903
  * Prefer `session.recentDirectoriesTouched` — the scan records it on the row, so
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `agents sessions stop <id>` — end a live agent session outright: stop its
3
+ * interactive process and tear down its tmux/mux session, so the session becomes
4
+ * done/closed rather than an orphaned idle background process.
5
+ *
6
+ * The lifecycle sibling of `detach` that does NOT resume headless. `detach`
7
+ * backgrounds a still-wanted agent (stop the terminal, keep it working); `stop`
8
+ * is for when the work is over — the agent's editor tab was closed, or you want
9
+ * it gone. Both reuse the same live-session resolution and the same
10
+ * `stopInteractive` teardown (tmux `kill-session`, else SIGTERM→SIGKILL the pid),
11
+ * so a session killed here reaps its helpers exactly as `detach` does before it
12
+ * resumes.
13
+ *
14
+ * The primary caller is AGI EXT: when a user genuinely closes an agent tab
15
+ * (Cmd+W), the extension runs this so the underlying agent + its mux are shut
16
+ * down instead of being left running detached (the "Cmd+W orphans an idle
17
+ * session" bug). A window RELOAD does NOT call this — the extension distinguishes
18
+ * the two via `terminal.exitStatus.reason` and only a real user close tears down.
19
+ */
20
+ import type { Command } from 'commander';
21
+ export declare function registerSessionsStopCommand(program: Command): void;
22
+ export declare function stopSessionAction(id: string, opts?: {
23
+ local?: boolean;
24
+ }): Promise<void>;
@@ -0,0 +1,66 @@
1
+ import chalk from 'chalk';
2
+ import { gatherLiveTargets } from './go.js';
3
+ import { resolveDetachTarget, resolveOne } from './detach-core.js';
4
+ import { stopInteractive } from './detach.js';
5
+ import { runOnPeer } from '../lib/session/remote-list.js';
6
+ import { setHelpSections } from '../lib/help.js';
7
+ export function registerSessionsStopCommand(program) {
8
+ const cmd = program
9
+ .command('stop')
10
+ .argument('<id>', 'Short or full id of the live session to stop')
11
+ .option('--local', 'Only this machine (skip the cross-host sweep)')
12
+ .description('Stop a live agent outright — end its process and tear down its tmux/mux session')
13
+ .action(async (id, opts) => {
14
+ await stopSessionAction(id, opts);
15
+ });
16
+ setHelpSections(cmd, {
17
+ examples: `
18
+ # Stop a live session by a short id prefix
19
+ agents sessions stop 4b2f1a9c
20
+
21
+ # Only look on this machine (skip the fleet sweep)
22
+ agents sessions stop 4b2f1a9c --local
23
+ `,
24
+ notes: `
25
+ stop ENDS the session; it does not background it. To keep an agent working
26
+ unattended instead, use \`agents sessions detach <id>\`, and bring it back
27
+ with \`agents sessions resume <id>\`.
28
+
29
+ A session that lives on another machine is stopped THERE over SSH — its pid
30
+ and tmux socket only mean something where it actually runs.
31
+ `,
32
+ });
33
+ }
34
+ export async function stopSessionAction(id, opts = {}) {
35
+ const { self, activeById } = await gatherLiveTargets(!!opts.local, { includeCloud: true });
36
+ const resolved = resolveOne(activeById, id);
37
+ if ('error' in resolved) {
38
+ console.error(chalk.red(resolved.error));
39
+ process.exitCode = 1;
40
+ return;
41
+ }
42
+ const s = resolved;
43
+ const target = resolveDetachTarget(s, self);
44
+ // Cloud/team/id-less sessions have their own lifecycles — refuse rather than
45
+ // half-stopping one from here (same boundary `detach` enforces).
46
+ if (target.kind === 'refuse') {
47
+ console.error(chalk.red(target.reason));
48
+ process.exitCode = 1;
49
+ return;
50
+ }
51
+ const short = target.sessionId.slice(0, 8);
52
+ // A session on another host: its pid/tmux socket only mean something where it
53
+ // runs, so stop it THERE over SSH — never kill locally. Mirrors detach/focus.
54
+ if (target.kind === 'remote') {
55
+ console.log(chalk.gray(`${short} lives on ${target.machine} — stopping it there over SSH…`));
56
+ const rc = await runOnPeer(['sessions', 'stop', target.sessionId, '--local'], target.machine);
57
+ if (rc === 'no-target') {
58
+ console.error(chalk.red(`Can't reach ${target.machine} to stop ${short}.`));
59
+ process.exitCode = 1;
60
+ }
61
+ return;
62
+ }
63
+ // Local: end the interactive process and tear down its tmux/mux session.
64
+ await stopInteractive(s);
65
+ console.log(chalk.green(`■ Stopped ${s.kind} ${short}`) + chalk.gray(' — process ended, session closed.'));
66
+ }
@@ -0,0 +1,82 @@
1
+ import type { Command } from 'commander';
2
+ import type { SessionTrajectory } from '../lib/session/trajectory.js';
3
+ import type { TrajectoryComparison, TrajectoryDivergence, TrajectorySummary } from '../lib/session/trajectory-compare.js';
4
+ import type { TrajectoryStep } from '../lib/session/trajectory.js';
5
+ import type { LineageEdge, LineageNode, SessionLineage } from '../lib/session/trajectory-lineage.js';
6
+ /** Versioned envelope emitted by `--json` — the stable contract for consumers. */
7
+ export declare const SESSIONS_TRACE_SCHEMA_VERSION = 1;
8
+ /** The `diff` block of a `layout: 'compare'` envelope — everything but the two full trajectories, which already ride `sessions`. */
9
+ export interface SessionsTraceDiffEnvelope {
10
+ divergence?: TrajectoryDivergence;
11
+ added: TrajectoryStep[];
12
+ removed: TrajectoryStep[];
13
+ summaryA: TrajectorySummary;
14
+ summaryB: TrajectorySummary;
15
+ truncatedA: number;
16
+ truncatedB: number;
17
+ }
18
+ /** The `lineage` block of a `layout: 'lineage'` envelope — the delegation graph. */
19
+ export interface SessionsTraceLineageEnvelope {
20
+ rootId: string;
21
+ nodes: LineageNode[];
22
+ edges: LineageEdge[];
23
+ teams: string[];
24
+ unresolvedParentIds: string[];
25
+ }
26
+ /** The `--json` envelope: the versioned contract for the ext / triaging agents. */
27
+ export interface SessionsTraceEnvelope {
28
+ schemaVersion: typeof SESSIONS_TRACE_SCHEMA_VERSION;
29
+ kind: 'sessions-trace';
30
+ layout: 'single' | 'compare' | 'lineage';
31
+ sessions: SessionTrajectory[];
32
+ diff?: SessionsTraceDiffEnvelope;
33
+ lineage?: SessionsTraceLineageEnvelope;
34
+ }
35
+ /** Build the versioned `--json` envelope for a single-session trajectory. */
36
+ export declare function buildTraceEnvelope(models: SessionTrajectory[]): SessionsTraceEnvelope;
37
+ /** Build the versioned `--json` envelope for a two-session compare. */
38
+ export declare function buildCompareTraceEnvelope(cmp: TrajectoryComparison): SessionsTraceEnvelope;
39
+ /**
40
+ * Build the versioned `--json` envelope for a lineage. `sessions` carries the
41
+ * ROOT's trajectory only: the graph's own numbers come from the indexed session
42
+ * rows, so a consumer pays one transcript parse instead of one per teammate —
43
+ * `agents sessions trace <child>` is how you get a child's full trajectory.
44
+ */
45
+ export declare function buildLineageTraceEnvelope(lineage: SessionLineage, rootTrajectory: SessionTrajectory): SessionsTraceEnvelope;
46
+ interface TraceOptions {
47
+ html?: boolean;
48
+ text?: boolean;
49
+ json?: boolean;
50
+ output?: string;
51
+ open?: boolean;
52
+ errorsOnly?: boolean;
53
+ redact?: boolean;
54
+ all?: boolean;
55
+ since?: string;
56
+ limit?: string;
57
+ agent?: string;
58
+ compare?: boolean;
59
+ tree?: boolean;
60
+ }
61
+ export type RenderFormat = 'html' | 'text' | 'json';
62
+ /**
63
+ * Pick the rendering by audience: explicit `--html/--text/--json` win; otherwise
64
+ * a person at a TTY gets the visual HTML and a piped/headless caller (an agent)
65
+ * gets the compact text trajectory.
66
+ */
67
+ export declare function chooseFormat(options: TraceOptions, isTTY: boolean): RenderFormat;
68
+ /**
69
+ * Decide the trace layout from what the user TYPED (`selectorCount`) vs what
70
+ * those selectors RESOLVED to (`resolvedCount`). Keyed on selector count so a
71
+ * single content-search selector that happens to match two sessions never
72
+ * silently becomes a compare — every unsupported combination fails loud with a
73
+ * clear message. Pure, so the boundaries are unit-tested without the command.
74
+ */
75
+ export declare function decideTraceLayout(options: Pick<TraceOptions, 'tree' | 'compare'>, selectorCount: number, resolvedCount: number): 'single' | 'compare' | 'lineage';
76
+ /** Attach the trace behaviour to a command node (canonical or top-level alias). */
77
+ export declare function configureTraceCommand(cmd: Command): Command;
78
+ /** Canonical `agents sessions trace <selectors...>`. */
79
+ export declare function registerSessionsTraceCommand(sessionsCmd: Command): void;
80
+ /** Top-level alias `agents trace <selectors...>` (mirrors `agents insights`). */
81
+ export declare function registerTraceCommand(program: Command): void;
82
+ export {};