@phnx-labs/agents-cli 1.22.38 → 1.22.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (554) hide show
  1. package/CHANGELOG.md +302 -0
  2. package/README.md +111 -70
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.js +46 -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 +260 -0
  8. package/dist/commands/accounts.d.ts +20 -0
  9. package/dist/commands/accounts.js +186 -25
  10. package/dist/commands/apply.d.ts +3 -3
  11. package/dist/commands/apply.js +20 -63
  12. package/dist/commands/browser.js +206 -94
  13. package/dist/commands/budget.d.ts +7 -6
  14. package/dist/commands/budget.js +8 -7
  15. package/dist/commands/cloud.js +17 -20
  16. package/dist/commands/commands.js +1 -1
  17. package/dist/commands/computer-actions.d.ts +1 -35
  18. package/dist/commands/computer-actions.js +13 -181
  19. package/dist/commands/computer.d.ts +28 -3
  20. package/dist/commands/computer.js +93 -65
  21. package/dist/commands/config.js +47 -4
  22. package/dist/commands/cost.d.ts +2 -1
  23. package/dist/commands/cost.js +7 -6
  24. package/dist/commands/daemon.js +151 -4
  25. package/dist/commands/detach.js +1 -1
  26. package/dist/commands/doctor.js +19 -11
  27. package/dist/commands/events.js +1 -1
  28. package/dist/commands/exec.d.ts +2 -50
  29. package/dist/commands/exec.js +161 -216
  30. package/dist/commands/factory.js +1 -1
  31. package/dist/commands/feed.d.ts +2 -2
  32. package/dist/commands/feed.js +9 -12
  33. package/dist/commands/fleet-capture.js +25 -27
  34. package/dist/commands/focus.d.ts +2 -3
  35. package/dist/commands/focus.js +34 -9
  36. package/dist/commands/go.js +15 -5
  37. package/dist/commands/harness.d.ts +3 -3
  38. package/dist/commands/harness.js +53 -5
  39. package/dist/commands/hooks.js +1 -1
  40. package/dist/commands/import.js +2 -2
  41. package/dist/commands/insights.d.ts +5 -5
  42. package/dist/commands/insights.js +15 -9
  43. package/dist/commands/inspect.d.ts +2 -3
  44. package/dist/commands/inspect.js +4 -16
  45. package/dist/commands/logs.d.ts +2 -2
  46. package/dist/commands/logs.js +9 -9
  47. package/dist/commands/mcp.js +2 -2
  48. package/dist/commands/memory.js +1 -1
  49. package/dist/commands/message.d.ts +1 -1
  50. package/dist/commands/message.js +7 -7
  51. package/dist/commands/mine.d.ts +11 -8
  52. package/dist/commands/mine.js +11 -10
  53. package/dist/commands/models.js +1 -1
  54. package/dist/commands/modes.js +1 -1
  55. package/dist/commands/monitors.js +23 -6
  56. package/dist/commands/output.d.ts +7 -6
  57. package/dist/commands/output.js +11 -10
  58. package/dist/commands/packages.js +4 -4
  59. package/dist/commands/perf.js +1 -1
  60. package/dist/commands/permissions.js +49 -32
  61. package/dist/commands/plugins.d.ts +1 -1
  62. package/dist/commands/plugins.js +3 -3
  63. package/dist/commands/profiles.d.ts +6 -9
  64. package/dist/commands/profiles.js +8 -321
  65. package/dist/commands/projects.d.ts +9 -0
  66. package/dist/commands/projects.js +140 -8
  67. package/dist/commands/prune.js +5 -13
  68. package/dist/commands/refresh-rules.js +1 -1
  69. package/dist/commands/repo.d.ts +5 -7
  70. package/dist/commands/repo.js +34 -18
  71. package/dist/commands/resource-view.js +4 -0
  72. package/dist/commands/resume.d.ts +11 -7
  73. package/dist/commands/resume.js +82 -98
  74. package/dist/commands/route.d.ts +12 -0
  75. package/dist/commands/route.js +261 -0
  76. package/dist/commands/routines.d.ts +2 -3
  77. package/dist/commands/routines.js +120 -145
  78. package/dist/commands/rules.js +1 -1
  79. package/dist/commands/run-account-picker.d.ts +1 -1
  80. package/dist/commands/run-account-picker.js +2 -2
  81. package/dist/commands/run-broadcast.d.ts +21 -0
  82. package/dist/commands/run-broadcast.js +89 -0
  83. package/dist/commands/run-cloud.js +1 -1
  84. package/dist/commands/secrets-vault.d.ts +10 -0
  85. package/dist/commands/{login.js → secrets-vault.js} +34 -14
  86. package/dist/commands/secrets.d.ts +4 -4
  87. package/dist/commands/secrets.js +72 -63
  88. package/dist/commands/sessions-backfill.js +1 -1
  89. package/dist/commands/sessions-browser.d.ts +1 -1
  90. package/dist/commands/sessions-browser.js +9 -5
  91. package/dist/commands/sessions-export.js +2 -2
  92. package/dist/commands/sessions-inject.js +4 -5
  93. package/dist/commands/sessions-migrate.js +16 -27
  94. package/dist/commands/sessions-picker.d.ts +13 -0
  95. package/dist/commands/sessions-picker.js +182 -8
  96. package/dist/commands/sessions-resume.d.ts +7 -3
  97. package/dist/commands/sessions-resume.js +81 -33
  98. package/dist/commands/sessions-stats.js +2 -2
  99. package/dist/commands/sessions.d.ts +75 -68
  100. package/dist/commands/sessions.js +142 -180
  101. package/dist/commands/setup-computer.js +1 -1
  102. package/dist/commands/setup-fleet.js +3 -0
  103. package/dist/commands/setup-mine.d.ts +7 -3
  104. package/dist/commands/setup-mine.js +13 -8
  105. package/dist/commands/setup-secrets.js +2 -2
  106. package/dist/commands/setup-watchdog.js +2 -2
  107. package/dist/commands/setup.js +7 -2
  108. package/dist/commands/share.d.ts +65 -0
  109. package/dist/commands/share.js +253 -20
  110. package/dist/commands/skills.js +3 -3
  111. package/dist/commands/snapshot.d.ts +2 -2
  112. package/dist/commands/snapshot.js +9 -9
  113. package/dist/commands/ssh.d.ts +1 -1
  114. package/dist/commands/ssh.js +318 -48
  115. package/dist/commands/subagents.js +1 -1
  116. package/dist/commands/sync.js +24 -9
  117. package/dist/commands/teams.d.ts +2 -2
  118. package/dist/commands/teams.js +9 -18
  119. package/dist/commands/tmux.js +5 -1
  120. package/dist/commands/trash.js +1 -1
  121. package/dist/commands/usage.d.ts +1 -1
  122. package/dist/commands/usage.js +2 -2
  123. package/dist/commands/utils.d.ts +4 -14
  124. package/dist/commands/utils.js +6 -27
  125. package/dist/commands/versions.js +2 -2
  126. package/dist/commands/view.d.ts +9 -77
  127. package/dist/commands/view.js +23 -8
  128. package/dist/commands/watchdog.js +1 -1
  129. package/dist/commands/webhook.js +11 -25
  130. package/dist/commands/workflows.js +1 -1
  131. package/dist/index.js +1 -1
  132. package/dist/lib/account-capabilities.d.ts +39 -0
  133. package/dist/lib/account-capabilities.js +59 -0
  134. package/dist/lib/account-catalog.js +1 -1
  135. package/dist/lib/account-registry.d.ts +66 -0
  136. package/dist/lib/account-registry.js +151 -5
  137. package/dist/lib/{rotate.d.ts → accounting/rotate.d.ts} +4 -4
  138. package/dist/lib/{rotate.js → accounting/rotate.js} +8 -8
  139. package/dist/lib/{usage.d.ts → accounting/usage.d.ts} +4 -4
  140. package/dist/lib/{usage.js → accounting/usage.js} +11 -11
  141. package/dist/lib/agent-spec/provider.js +1 -1
  142. package/dist/lib/agents.d.ts +72 -4
  143. package/dist/lib/agents.js +231 -199
  144. package/dist/lib/answer-router.d.ts +2 -2
  145. package/dist/lib/ask-classifier.d.ts +1 -1
  146. package/dist/lib/ask-classifier.js +1 -1
  147. package/dist/lib/audit/log.js +1 -1
  148. package/dist/lib/auth-health.d.ts +1 -1
  149. package/dist/lib/auth-health.js +2 -2
  150. package/dist/lib/brand.js +1 -1
  151. package/dist/lib/browser/caller-identity.d.ts +28 -0
  152. package/dist/lib/browser/caller-identity.js +156 -0
  153. package/dist/lib/browser/cdp.js +1 -1
  154. package/dist/lib/browser/drivers/ssh.d.ts +1 -1
  155. package/dist/lib/browser/drivers/ssh.js +2 -2
  156. package/dist/lib/browser/hygiene.d.ts +10 -2
  157. package/dist/lib/browser/hygiene.js +7 -4
  158. package/dist/lib/browser/ipc.d.ts +22 -2
  159. package/dist/lib/browser/ipc.js +185 -21
  160. package/dist/lib/browser/profiles.d.ts +67 -3
  161. package/dist/lib/browser/profiles.js +129 -7
  162. package/dist/lib/browser/remote-control.d.ts +2 -2
  163. package/dist/lib/browser/remote-control.js +3 -3
  164. package/dist/lib/browser/runtime-state.d.ts +79 -0
  165. package/dist/lib/browser/runtime-state.js +119 -1
  166. package/dist/lib/browser/service.d.ts +113 -1
  167. package/dist/lib/browser/service.js +454 -40
  168. package/dist/lib/browser/sessions-list.d.ts +2 -1
  169. package/dist/lib/browser/sessions-list.js +4 -13
  170. package/dist/lib/browser/types.d.ts +18 -0
  171. package/dist/lib/budget/config.js +1 -1
  172. package/dist/lib/budget/ledger.js +1 -1
  173. package/dist/lib/byok-usage.js +1 -1
  174. package/dist/lib/capabilities.js +3 -15
  175. package/dist/lib/catchup.d.ts +1 -1
  176. package/dist/lib/catchup.js +1 -1
  177. package/dist/lib/cloud/dispatch.js +1 -1
  178. package/dist/lib/cloud/host.d.ts +3 -3
  179. package/dist/lib/cloud/host.js +5 -5
  180. package/dist/lib/cloud/rush.d.ts +9 -21
  181. package/dist/lib/cloud/rush.js +33 -120
  182. package/dist/lib/cloud/types.d.ts +2 -2
  183. package/dist/lib/commands.js +3 -13
  184. package/dist/lib/computer/actions.d.ts +36 -0
  185. package/dist/lib/computer/actions.js +162 -0
  186. package/dist/lib/computer/dispatch.d.ts +2 -2
  187. package/dist/lib/computer/dispatch.js +2 -2
  188. package/dist/lib/computer/sessions-list.d.ts +3 -3
  189. package/dist/lib/computer/sessions-list.js +2 -2
  190. package/dist/lib/config-keys.d.ts +12 -3
  191. package/dist/lib/config-keys.js +29 -6
  192. package/dist/lib/config-machine-keys.d.ts +4 -2
  193. package/dist/lib/config-machine-keys.js +6 -2
  194. package/dist/lib/crabbox/lease.js +9 -1
  195. package/dist/lib/crabbox/runtimes.d.ts +32 -7
  196. package/dist/lib/crabbox/runtimes.js +72 -30
  197. package/dist/lib/{daemon.d.ts → daemon/daemon.d.ts} +59 -1
  198. package/dist/lib/{daemon.js → daemon/daemon.js} +237 -49
  199. package/dist/lib/daemon-services.d.ts +1 -1
  200. package/dist/lib/daemon-services.js +5 -0
  201. package/dist/lib/daemon-ticks.d.ts +25 -0
  202. package/dist/lib/daemon-ticks.js +31 -1
  203. package/dist/lib/daemon-webhooks.d.ts +102 -0
  204. package/dist/lib/daemon-webhooks.js +210 -0
  205. package/dist/lib/device-config.d.ts +116 -72
  206. package/dist/lib/device-config.js +366 -132
  207. package/dist/lib/devices/config-migration.d.ts +29 -34
  208. package/dist/lib/devices/config-migration.js +209 -130
  209. package/dist/lib/devices/connect.d.ts +2 -2
  210. package/dist/lib/devices/connect.js +2 -2
  211. package/dist/lib/devices/discovery-policy.d.ts +30 -0
  212. package/dist/lib/devices/discovery-policy.js +101 -0
  213. package/dist/lib/devices/fleet-inventory.js +8 -3
  214. package/dist/lib/devices/harness-inventory.d.ts +1 -1
  215. package/dist/lib/devices/harness-inventory.js +12 -3
  216. package/dist/lib/devices/known-hosts.js +1 -1
  217. package/dist/lib/devices/pool.d.ts +61 -0
  218. package/dist/lib/devices/pool.js +83 -0
  219. package/dist/lib/devices/registry.d.ts +1 -1
  220. package/dist/lib/devices/registry.js +1 -1
  221. package/dist/lib/devices/resolve-profile.d.ts +2 -2
  222. package/dist/lib/devices/resolve-profile.js +2 -2
  223. package/dist/lib/devices/resolve-target.d.ts +1 -1
  224. package/dist/lib/devices/resolve-target.js +4 -4
  225. package/dist/lib/devices/self-host.d.ts +1 -1
  226. package/dist/lib/devices/self-host.js +3 -3
  227. package/dist/lib/devices/ssh-config.d.ts +1 -1
  228. package/dist/lib/devices/stats-cache.js +1 -1
  229. package/dist/lib/devices/sync.d.ts +3 -1
  230. package/dist/lib/devices/sync.js +3 -3
  231. package/dist/lib/doctor-diff.js +4 -4
  232. package/dist/lib/drift-sync.js +2 -2
  233. package/dist/lib/drift.js +2 -2
  234. package/dist/lib/event-families.d.ts +1 -1
  235. package/dist/lib/event-stream.d.ts +1 -1
  236. package/dist/lib/event-stream.js +2 -2
  237. package/dist/lib/events-ingest.js +2 -2
  238. package/dist/lib/exec.d.ts +8 -5
  239. package/dist/lib/exec.js +19 -13
  240. package/dist/lib/factory/snapshot.d.ts +1 -1
  241. package/dist/lib/factory/snapshot.js +1 -1
  242. package/dist/lib/{activity.d.ts → feed/activity.d.ts} +1 -1
  243. package/dist/lib/{activity.js → feed/activity.js} +7 -7
  244. package/dist/lib/{events.d.ts → feed/events.d.ts} +2 -2
  245. package/dist/lib/{events.js → feed/events.js} +5 -5
  246. package/dist/lib/{feed.js → feed/feed.js} +4 -4
  247. package/dist/lib/feed-outcome.d.ts +1 -1
  248. package/dist/lib/feed-policy.d.ts +1 -1
  249. package/dist/lib/feed-policy.js +1 -1
  250. package/dist/lib/feed-post.d.ts +1 -1
  251. package/dist/lib/feed-post.js +1 -1
  252. package/dist/lib/feed-ranking.d.ts +1 -1
  253. package/dist/lib/fleet/apply.d.ts +0 -6
  254. package/dist/lib/fleet/apply.js +18 -45
  255. package/dist/lib/fleet/auth-sync.d.ts +16 -35
  256. package/dist/lib/fleet/auth-sync.js +16 -75
  257. package/dist/lib/fleet/capture.js +8 -6
  258. package/dist/lib/fleet/manifest.js +23 -11
  259. package/dist/lib/fleet/types.d.ts +19 -7
  260. package/dist/lib/fleet-cache.d.ts +1 -1
  261. package/dist/lib/fleet-cache.js +1 -1
  262. package/dist/lib/format.d.ts +19 -0
  263. package/dist/lib/format.js +44 -1
  264. package/dist/lib/friction-heuristics.d.ts +1 -1
  265. package/dist/lib/git.d.ts +24 -1
  266. package/dist/lib/git.js +82 -38
  267. package/dist/lib/heal.js +3 -3
  268. package/dist/lib/hooks.d.ts +18 -0
  269. package/dist/lib/hooks.js +113 -1
  270. package/dist/lib/hosts/credentials.d.ts +30 -10
  271. package/dist/lib/hosts/credentials.js +38 -26
  272. package/dist/lib/hosts/dispatch.d.ts +3 -3
  273. package/dist/lib/hosts/dispatch.js +3 -3
  274. package/dist/lib/hosts/option.d.ts +3 -3
  275. package/dist/lib/hosts/option.js +7 -8
  276. package/dist/lib/hosts/passthrough.d.ts +17 -17
  277. package/dist/lib/hosts/passthrough.js +67 -50
  278. package/dist/lib/hosts/providers/devices.d.ts +1 -1
  279. package/dist/lib/hosts/providers/devices.js +1 -1
  280. package/dist/lib/hosts/reconcile.d.ts +1 -1
  281. package/dist/lib/hosts/reconcile.js +1 -1
  282. package/dist/lib/hosts/reconnect.d.ts +1 -1
  283. package/dist/lib/hosts/reconnect.js +2 -2
  284. package/dist/lib/hosts/registry.d.ts +5 -5
  285. package/dist/lib/hosts/registry.js +5 -5
  286. package/dist/lib/hosts/remote-cmd.d.ts +10 -10
  287. package/dist/lib/hosts/remote-cmd.js +25 -18
  288. package/dist/lib/hosts/remote-os.d.ts +4 -4
  289. package/dist/lib/hosts/remote-os.js +4 -4
  290. package/dist/lib/hosts/remote-session-id.d.ts +2 -2
  291. package/dist/lib/hosts/remote-session-id.js +2 -2
  292. package/dist/lib/hosts/routing-flag.d.ts +3 -3
  293. package/dist/lib/hosts/routing-flag.js +4 -5
  294. package/dist/lib/hosts/run-target.d.ts +4 -4
  295. package/dist/lib/hosts/run-target.js +4 -4
  296. package/dist/lib/hosts/session-index.d.ts +2 -2
  297. package/dist/lib/hosts/session-index.js +1 -1
  298. package/dist/lib/hosts/session-marker.d.ts +1 -1
  299. package/dist/lib/hosts/session-marker.js +1 -1
  300. package/dist/lib/hosts/types.d.ts +2 -2
  301. package/dist/lib/hosts/types.js +2 -2
  302. package/dist/lib/import.js +1 -1
  303. package/dist/lib/{migrate.d.ts → installations/migrate.d.ts} +49 -1
  304. package/dist/lib/{migrate.js → installations/migrate.js} +265 -38
  305. package/dist/lib/installations/resolve.js +1 -1
  306. package/dist/lib/installations/strategies.js +1 -1
  307. package/dist/lib/installations/update.js +2 -2
  308. package/dist/lib/{versions.d.ts → installations/versions.d.ts} +12 -3
  309. package/dist/lib/{versions.js → installations/versions.js} +51 -31
  310. package/dist/lib/isolation-boundary-report.js +1 -1
  311. package/dist/lib/linear-projects.d.ts +28 -0
  312. package/dist/lib/linear-projects.js +30 -0
  313. package/dist/lib/loop.js +1 -1
  314. package/dist/lib/mailbox-gc.js +1 -1
  315. package/dist/lib/mailbox.js +1 -1
  316. package/dist/lib/mcp-registry.d.ts +62 -0
  317. package/dist/lib/mcp-registry.js +177 -0
  318. package/dist/lib/mcp.d.ts +5 -0
  319. package/dist/lib/mcp.js +124 -307
  320. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  321. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  322. package/dist/lib/menubar/install-menubar.d.ts +7 -0
  323. package/dist/lib/menubar/install-menubar.js +24 -6
  324. package/dist/lib/menubar/snapshot.d.ts +7 -0
  325. package/dist/lib/menubar/snapshot.js +8 -6
  326. package/dist/lib/models.js +1 -1
  327. package/dist/lib/monitors/config.d.ts +12 -0
  328. package/dist/lib/monitors/config.js +3 -0
  329. package/dist/lib/monitors/dispatch.js +26 -5
  330. package/dist/lib/monitors/engine.js +10 -0
  331. package/dist/lib/monitors/sources/webhook.d.ts +1 -1
  332. package/dist/lib/monitors/state.d.ts +42 -0
  333. package/dist/lib/monitors/state.js +30 -0
  334. package/dist/lib/notify.d.ts +1 -1
  335. package/dist/lib/observe-aliases.d.ts +2 -2
  336. package/dist/lib/observe-aliases.js +2 -11
  337. package/dist/lib/output/git-output.js +2 -2
  338. package/dist/lib/overdue.d.ts +1 -1
  339. package/dist/lib/overdue.js +1 -1
  340. package/dist/lib/permissions-registry.d.ts +65 -0
  341. package/dist/lib/permissions-registry.js +599 -0
  342. package/dist/lib/permissions.d.ts +24 -13
  343. package/dist/lib/permissions.js +52 -271
  344. package/dist/lib/picker.d.ts +16 -0
  345. package/dist/lib/picker.js +33 -3
  346. package/dist/lib/placement.d.ts +1 -1
  347. package/dist/lib/placement.js +4 -4
  348. package/dist/lib/platform/paths.d.ts +8 -0
  349. package/dist/lib/platform/paths.js +11 -0
  350. package/dist/lib/platform/posixpath.js +3 -3
  351. package/dist/lib/{plugin-marketplace.d.ts → plugins/plugin-marketplace.d.ts} +1 -1
  352. package/dist/lib/{plugin-marketplace.js → plugins/plugin-marketplace.js} +2 -2
  353. package/dist/lib/{plugins.d.ts → plugins/plugins.d.ts} +1 -1
  354. package/dist/lib/{plugins.js → plugins/plugins.js} +7 -7
  355. package/dist/lib/{skills.d.ts → plugins/skills.d.ts} +1 -1
  356. package/dist/lib/{skills.js → plugins/skills.js} +7 -7
  357. package/dist/lib/pricing/cost.d.ts +1 -1
  358. package/dist/lib/pricing/cost.js +1 -1
  359. package/dist/lib/profiles-presets.d.ts +1 -1
  360. package/dist/lib/profiles-presets.js +1 -1
  361. package/dist/lib/profiles.js +2 -2
  362. package/dist/lib/project-import.js +4 -1
  363. package/dist/lib/project-launch.d.ts +1 -1
  364. package/dist/lib/project-launch.js +3 -3
  365. package/dist/lib/project-pull.d.ts +128 -0
  366. package/dist/lib/project-pull.js +384 -0
  367. package/dist/lib/project-root.d.ts +2 -2
  368. package/dist/lib/project-root.js +2 -2
  369. package/dist/lib/project-status.js +1 -1
  370. package/dist/lib/projects.d.ts +23 -0
  371. package/dist/lib/projects.js +29 -6
  372. package/dist/lib/refresh.d.ts +12 -1
  373. package/dist/lib/refresh.js +16 -9
  374. package/dist/lib/registry.d.ts +9 -2
  375. package/dist/lib/registry.js +11 -4
  376. package/dist/lib/resources.d.ts +2 -2
  377. package/dist/lib/resources.js +2 -2
  378. package/dist/lib/routers.d.ts +81 -0
  379. package/dist/lib/routers.js +153 -0
  380. package/dist/lib/routine-context.d.ts +1 -0
  381. package/dist/lib/routine-context.js +7 -2
  382. package/dist/lib/routine-notify-owner.d.ts +1 -1
  383. package/dist/lib/routine-notify.d.ts +1 -1
  384. package/dist/lib/routine-notify.js +1 -1
  385. package/dist/lib/routine-process-cleanup.d.ts +1 -1
  386. package/dist/lib/routine-readiness.d.ts +1 -1
  387. package/dist/lib/routine-readiness.js +11 -4
  388. package/dist/lib/routines-placement.d.ts +12 -2
  389. package/dist/lib/routines-placement.js +20 -3
  390. package/dist/lib/routines-project.d.ts +1 -1
  391. package/dist/lib/routines-project.js +1 -1
  392. package/dist/lib/rules/compile.d.ts +1 -0
  393. package/dist/lib/rules/compile.js +10 -2
  394. package/dist/lib/rules/rules.js +1 -1
  395. package/dist/lib/run-notify.js +1 -1
  396. package/dist/lib/runner.d.ts +80 -2
  397. package/dist/lib/runner.js +241 -62
  398. package/dist/lib/sandbox.d.ts +1 -1
  399. package/dist/lib/scheduler.d.ts +1 -1
  400. package/dist/lib/scheduler.js +1 -1
  401. package/dist/lib/{routines.d.ts → scheduling/routines.d.ts} +54 -9
  402. package/dist/lib/{routines.js → scheduling/routines.js} +173 -14
  403. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  404. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  405. package/dist/lib/secrets/agent.js +2 -2
  406. package/dist/lib/secrets/audit.js +1 -1
  407. package/dist/lib/secrets/bundles.d.ts +3 -3
  408. package/dist/lib/secrets/bundles.js +7 -7
  409. package/dist/lib/secrets/index.js +1 -1
  410. package/dist/lib/secrets/list-filter.d.ts +1 -1
  411. package/dist/lib/secrets/list-filter.js +2 -2
  412. package/dist/lib/secrets/push.d.ts +1 -1
  413. package/dist/lib/secrets/push.js +10 -12
  414. package/dist/lib/secrets/remote.d.ts +12 -10
  415. package/dist/lib/secrets/remote.js +21 -14
  416. package/dist/lib/secrets/vault.js +2 -2
  417. package/dist/lib/self-heal/checks/shadowing.js +1 -1
  418. package/dist/lib/self-heal/checks/shims.js +1 -1
  419. package/dist/lib/self-update.d.ts +39 -4
  420. package/dist/lib/self-update.js +78 -25
  421. package/dist/lib/serve/control.d.ts +1 -1
  422. package/dist/lib/serve/control.js +4 -4
  423. package/dist/lib/serve/data.d.ts +1 -1
  424. package/dist/lib/serve/data.js +1 -1
  425. package/dist/lib/serve/stream.js +1 -1
  426. package/dist/lib/service-manifest.d.ts +29 -0
  427. package/dist/lib/service-manifest.js +80 -0
  428. package/dist/lib/session/active.d.ts +59 -7
  429. package/dist/lib/session/active.js +158 -17
  430. package/dist/lib/session/bash-command.js +1 -1
  431. package/dist/lib/session/claude-accounts.d.ts +1 -1
  432. package/dist/lib/session/claude-accounts.js +1 -1
  433. package/dist/lib/session/db.d.ts +10 -2
  434. package/dist/lib/session/db.js +25 -6
  435. package/dist/lib/session/discover.d.ts +77 -0
  436. package/dist/lib/session/discover.js +130 -25
  437. package/dist/lib/session/fork.js +1 -1
  438. package/dist/lib/session/inject.d.ts +1 -1
  439. package/dist/lib/session/insights.d.ts +1 -1
  440. package/dist/lib/session/insights.js +1 -1
  441. package/dist/lib/session/live-metadata.d.ts +15 -0
  442. package/dist/lib/session/live-metadata.js +76 -0
  443. package/dist/lib/session/migrate-targets.d.ts +1 -1
  444. package/dist/lib/session/recovery.d.ts +1 -1
  445. package/dist/lib/session/recovery.js +2 -2
  446. package/dist/lib/session/remote-active.d.ts +10 -1
  447. package/dist/lib/session/remote-active.js +8 -3
  448. package/dist/lib/session/remote-bundle.d.ts +1 -1
  449. package/dist/lib/session/remote-bundle.js +2 -2
  450. package/dist/lib/session/remote-list.d.ts +15 -4
  451. package/dist/lib/session/remote-list.js +40 -3
  452. package/dist/lib/session/remote.d.ts +5 -5
  453. package/dist/lib/session/remote.js +13 -17
  454. package/dist/lib/session/resume-command.d.ts +3 -2
  455. package/dist/lib/session/resume-command.js +4 -3
  456. package/dist/lib/session/resume-owner.d.ts +3 -3
  457. package/dist/lib/session/resume-owner.js +3 -3
  458. package/dist/lib/session/session-cache.d.ts +12 -0
  459. package/dist/lib/session/session-cache.js +2 -0
  460. package/dist/lib/session/shell-programs.js +1 -1
  461. package/dist/lib/session/state.js +5 -5
  462. package/dist/lib/session/team-filter.d.ts +1 -1
  463. package/dist/lib/session/team-filter.js +1 -1
  464. package/dist/lib/session/types.d.ts +3 -3
  465. package/dist/lib/session/width.d.ts +2 -2
  466. package/dist/lib/session/width.js +2 -2
  467. package/dist/lib/share/delete.d.ts +21 -0
  468. package/dist/lib/share/delete.js +42 -0
  469. package/dist/lib/share/publish.d.ts +82 -0
  470. package/dist/lib/share/publish.js +170 -18
  471. package/dist/lib/share/worker-template.js +172 -9
  472. package/dist/lib/shims.js +35 -7
  473. package/dist/lib/smart-launch.d.ts +36 -6
  474. package/dist/lib/smart-launch.js +65 -8
  475. package/dist/lib/snapshot.d.ts +4 -4
  476. package/dist/lib/snapshot.js +2 -2
  477. package/dist/lib/ssh-exec.d.ts +1 -1
  478. package/dist/lib/ssh-exec.js +2 -2
  479. package/dist/lib/ssh-tunnel.d.ts +10 -10
  480. package/dist/lib/ssh-tunnel.js +12 -12
  481. package/dist/lib/staleness/checkers/hooks.d.ts +1 -1
  482. package/dist/lib/staleness/checkers/hooks.js +1 -1
  483. package/dist/lib/staleness/detectors/permissions.js +0 -23
  484. package/dist/lib/staleness/detectors/plugins.js +1 -1
  485. package/dist/lib/staleness/fingerprint.js +1 -1
  486. package/dist/lib/staleness/layers.d.ts +1 -1
  487. package/dist/lib/staleness/layers.js +1 -1
  488. package/dist/lib/staleness/writers/mcp.js +3 -1
  489. package/dist/lib/staleness/writers/plugins.js +1 -1
  490. package/dist/lib/staleness/writers/types.d.ts +8 -0
  491. package/dist/lib/startup/command-registry.d.ts +5 -147
  492. package/dist/lib/startup/command-registry.js +38 -303
  493. package/dist/lib/startup/dev-build.d.ts +0 -21
  494. package/dist/lib/startup/dev-build.js +29 -8
  495. package/dist/lib/state.d.ts +19 -1
  496. package/dist/lib/state.js +120 -51
  497. package/dist/lib/subagents.js +1 -1
  498. package/dist/lib/sync-status.js +1 -1
  499. package/dist/lib/sync-umbrella.d.ts +6 -1
  500. package/dist/lib/sync-umbrella.js +9 -4
  501. package/dist/lib/teams/agents.js +2 -2
  502. package/dist/lib/teams/registry.js +1 -1
  503. package/dist/lib/terminal/backends/vscodium-agent.js +1 -1
  504. package/dist/lib/terminal/engine.js +1 -1
  505. package/dist/lib/terminal/index.d.ts +4 -0
  506. package/dist/lib/terminal/index.js +3 -0
  507. package/dist/lib/terminal/inject.d.ts +2 -2
  508. package/dist/lib/terminal/inject.js +2 -2
  509. package/dist/lib/terminal/transport.js +1 -1
  510. package/dist/lib/tmux/index.d.ts +1 -1
  511. package/dist/lib/tmux/index.js +1 -1
  512. package/dist/lib/tmux/session.d.ts +21 -5
  513. package/dist/lib/tmux/session.js +76 -22
  514. package/dist/lib/triggers/handlers.d.ts +1 -1
  515. package/dist/lib/triggers/handlers.js +2 -2
  516. package/dist/lib/triggers/webhook.d.ts +36 -2
  517. package/dist/lib/triggers/webhook.js +97 -42
  518. package/dist/lib/types.d.ts +18 -6
  519. package/dist/lib/usage-fleet.d.ts +1 -1
  520. package/dist/lib/usage-fleet.js +1 -1
  521. package/dist/lib/usage-refresh.d.ts +1 -1
  522. package/dist/lib/usage-refresh.js +3 -3
  523. package/dist/lib/version-duplicates.js +2 -2
  524. package/dist/lib/view-types.d.ts +56 -0
  525. package/dist/lib/view-types.js +1 -0
  526. package/dist/lib/watchdog/rotate.d.ts +2 -2
  527. package/dist/lib/watchdog/rotate.js +3 -3
  528. package/dist/lib/watchdog/runner.d.ts +2 -3
  529. package/dist/lib/watchdog/runner.js +3 -4
  530. package/dist/lib/workflows.js +1 -1
  531. package/package.json +2 -1
  532. package/scripts/postinstall.js +2 -2
  533. package/dist/commands/bench.d.ts +0 -2
  534. package/dist/commands/bench.js +0 -101
  535. package/dist/commands/cp.d.ts +0 -84
  536. package/dist/commands/cp.js +0 -231
  537. package/dist/commands/login.d.ts +0 -2
  538. package/dist/lib/resources/commands.d.ts +0 -46
  539. package/dist/lib/resources/commands.js +0 -211
  540. package/dist/lib/resources/hooks.d.ts +0 -16
  541. package/dist/lib/resources/hooks.js +0 -153
  542. package/dist/lib/resources/mcp.d.ts +0 -34
  543. package/dist/lib/resources/mcp.js +0 -250
  544. package/dist/lib/resources/memory.d.ts +0 -15
  545. package/dist/lib/resources/memory.js +0 -46
  546. package/dist/lib/resources/permissions.d.ts +0 -13
  547. package/dist/lib/resources/permissions.js +0 -202
  548. package/dist/lib/resources/rules.d.ts +0 -46
  549. package/dist/lib/resources/rules.js +0 -179
  550. package/dist/lib/resources/skills.d.ts +0 -37
  551. package/dist/lib/resources/skills.js +0 -247
  552. package/dist/lib/resources/subagents.d.ts +0 -46
  553. package/dist/lib/resources/subagents.js +0 -202
  554. /package/dist/lib/{feed.d.ts → feed/feed.d.ts} +0 -0
@@ -2,19 +2,20 @@ import * as fs from 'fs';
2
2
  import * as os from 'os';
3
3
  import * as path from 'path';
4
4
  import { BrowserCdpConnectionError, CDPClient, discoverBrowserWsUrl, verifyBrowserIdentity, } from './cdp.js';
5
- import { getProfile, getProfileRuntimeDir, getProfileDownloadsDir, getProfileSessionsDir, getBrowserRuntimeDir, listProfiles, extractConfiguredPort, resolveEndpoint, } from './profiles.js';
5
+ import { getProfile, getProfileRuntimeDir, getProfileDownloadsDir, getProfileSessionsDir, getBrowserRuntimeDir, listProfiles, extractConfiguredPort, resolveEndpoint, parseEndpointUrl, } from './profiles.js';
6
6
  import { killChrome, getRunningChromeInfo, launchBrowser, allocatePort } from './chrome.js';
7
7
  import { connectLocal } from './drivers/local.js';
8
8
  import { connectSSH, shellQuote } from './drivers/ssh.js';
9
9
  import { clearProfileRuntime, listProfileCacheDirs, readProfileRuntimeMeta, isProcessAlive } from './runtime-state.js';
10
10
  import { resolveDomainSkill } from './domain-skills.js';
11
- import { generateTaskId, generateShortId, generateTaskName, } from './types.js';
11
+ import { generateTaskId, generateShortId, } from './types.js';
12
12
  import { reapAbandonedTasks, resolveLiveIdentities, taskOwnerIsGone, } from './hygiene.js';
13
+ import { taskMatchesCaller } from './caller-identity.js';
13
14
  import { getRefs, resolveRefToCoords, describeRefs, healRef } from './refs.js';
14
15
  import { clickAtCoords, hoverAtCoords, scrollAtCoords, typeText, pressKey, focusNode } from './input.js';
15
16
  import { typeEditorText } from './editor.js';
16
17
  import { detectUploadPattern, stageUploadFile, uploadToDropTarget, uploadToFileInput, uploadViaFileChooser, } from './upload.js';
17
- import { emit } from '../events.js';
18
+ import { emit } from '../feed/events.js';
18
19
  import { resolveActor } from '../actor.js';
19
20
  import { recordBrowserSession } from '../session/db.js';
20
21
  import { sshExecAsync } from '../ssh-exec.js';
@@ -238,6 +239,36 @@ async function isConnHealthy(conn, timeoutMs = 1000) {
238
239
  return false;
239
240
  }
240
241
  }
242
+ /** Join error lines so callers get a next command, not a dead-end message. */
243
+ export function actionable(...lines) {
244
+ return lines.filter((l) => l != null && l !== '').join('\n');
245
+ }
246
+ /** Derive a human label from an explicit title or a navigated URL. */
247
+ export function deriveTaskLabel(opts) {
248
+ if (opts.title?.trim())
249
+ return opts.title.trim();
250
+ if (opts.existing && opts.existing !== 'untitled')
251
+ return opts.existing;
252
+ if (opts.url) {
253
+ try {
254
+ const host = new URL(opts.url).hostname.replace(/^www\./, '');
255
+ if (host)
256
+ return host;
257
+ }
258
+ catch {
259
+ /* unparseable */
260
+ }
261
+ }
262
+ return opts.existing ?? 'untitled';
263
+ }
264
+ /**
265
+ * True when `key` is the bare profile name or one of its composite endpoint
266
+ * keys (`name@endpoint`). Used by status/stop so `comet-local` matches
267
+ * `comet-local@endpoint-0`.
268
+ */
269
+ export function connectionKeyMatchesProfile(key, profileName) {
270
+ return key === profileName || key.startsWith(`${profileName}@`) || key.startsWith(`${profileName}.`);
271
+ }
241
272
  /**
242
273
  * Resolve the identity stamped on a task at start: WHO (`owner`) and WHICH run
243
274
  * (`launchId`). The forwarded values come from the caller's own CLI process and
@@ -280,14 +311,20 @@ export class BrowserService {
280
311
  // passed an unknown name. The composite identifier `<profile>@<endpoint>`
281
312
  // is what the connection map + per-profile runtime dirs are keyed on, so
282
313
  // a single YAML profile can run at multiple endpoints concurrently.
314
+ //
315
+ // The YAML profile's bare `name` stays on `profile.name` for status
316
+ // matching; only the connection/runtime key uses the composite.
283
317
  const resolved = resolveEndpoint(profile, opts.endpointName);
284
318
  const composite = `${profileName}@${resolved.name}`;
285
319
  const effectiveProfile = {
286
320
  ...profile,
321
+ // Runtime/connect path key — NOT the bare YAML name. Connections and
322
+ // tasks.json live under this composite so multi-endpoint is safe.
287
323
  name: composite,
288
324
  binary: resolved.binary,
289
325
  targetFilter: resolved.targetFilter,
290
326
  };
327
+ const taskId = generateTaskId();
291
328
  let taskName;
292
329
  if (opts.taskName) {
293
330
  if (this.hasTaskNamed(opts.taskName)) {
@@ -296,9 +333,10 @@ export class BrowserService {
296
333
  taskName = opts.taskName;
297
334
  }
298
335
  else {
299
- taskName = this.generateUniqueTaskName();
336
+ // Address by the short machine id — no word-salad. Status shows `label`.
337
+ taskName = taskId;
300
338
  }
301
- const taskId = generateTaskId();
339
+ const taskLabel = deriveTaskLabel({ title: opts.title, url: opts.url });
302
340
  let conn = this.connections.get(composite);
303
341
  let effectiveProfileName = composite;
304
342
  // If we have a cached connection, confirm it's still usable before any
@@ -344,9 +382,12 @@ export class BrowserService {
344
382
  else if (!conn) {
345
383
  conn = await this.connectProfile(effectiveProfile, resolved.target);
346
384
  conn.profileName = composite;
385
+ conn.bareName = profileName;
347
386
  this.connections.set(composite, conn);
348
387
  await this.applyDefaultDownloadBehavior(conn, composite);
349
388
  }
389
+ if (conn && !conn.bareName)
390
+ conn.bareName = profileName;
350
391
  // Browsers launch with --no-startup-window (session-cookie persistence,
351
392
  // see launchBrowser), so a bare `start` with no --url would otherwise
352
393
  // leave the user staring at a process with zero windows. Recreate the
@@ -374,6 +415,7 @@ export class BrowserService {
374
415
  const task = {
375
416
  id: taskId,
376
417
  name: taskName,
418
+ label: taskLabel,
377
419
  profile: effectiveProfileName,
378
420
  tabs: {},
379
421
  currentTabId: undefined,
@@ -574,9 +616,18 @@ export class BrowserService {
574
616
  return reapAbandonedTasks(this, opts);
575
617
  }
576
618
  async stop(taskName) {
619
+ // Rehydrate from tasks.json when the daemon restarted and lost RAM state.
620
+ try {
621
+ await this.findTask(taskName);
622
+ }
623
+ catch {
624
+ // findTask throws when truly gone; fall through to the miss return.
625
+ }
577
626
  for (const [profileName, conn] of this.connections) {
578
- const task = conn.tasks.get(taskName);
627
+ const task = this.lookupTaskOnConn(conn, taskName);
579
628
  if (task) {
629
+ // Map key may be task.name, not the caller-supplied handle.
630
+ const mapKey = this.taskMapKey(conn, task) ?? taskName;
580
631
  // Get domains from tabs before closing (for history)
581
632
  const domains = new Set();
582
633
  try {
@@ -608,16 +659,16 @@ export class BrowserService {
608
659
  conn.sessionCache.delete(cdpId);
609
660
  }
610
661
  this.invalidateTargetCache(conn);
611
- conn.tasks.delete(taskName);
662
+ conn.tasks.delete(mapKey);
612
663
  await this.saveTaskState(profileName, conn.tasks);
613
- emit('browser.close', { profile: profileName, task: taskName });
664
+ emit('browser.close', { profile: profileName, task: task.name });
614
665
  void import('../analytics/usage-db.js').then(({ recordUsage }) => {
615
666
  recordUsage({
616
667
  kind: 'browser',
617
668
  name: profileName,
618
669
  event: 'close',
619
670
  source: 'browser',
620
- meta: { task: taskName },
671
+ meta: { task: task.name },
621
672
  });
622
673
  }).catch(() => { });
623
674
  if (conn.forkedFrom && conn.tasks.size === 0) {
@@ -669,6 +720,7 @@ export class BrowserService {
669
720
  }
670
721
  async navigate(taskId, url, profileName) {
671
722
  const { conn, task } = await this.findTask(taskId, profileName);
723
+ this.maybeUpdateLabelFromUrl(conn, task, url);
672
724
  // If we have a current tab, navigate in it (reuse)
673
725
  const currentShortId = task.currentTabId;
674
726
  if (currentShortId && task.tabs[currentShortId]) {
@@ -1357,14 +1409,25 @@ export class BrowserService {
1357
1409
  return { path: stageUploadFile(source) };
1358
1410
  }
1359
1411
  async status(profileName) {
1412
+ // Reconnect live browsers after a daemon restart so status is not empty
1413
+ // while tasks.json still holds open work.
1414
+ await this.rehydrateAllFromDisk();
1360
1415
  const seen = new Set();
1361
1416
  const statuses = [];
1362
- const candidates = profileName ? [profileName] : Array.from(this.connections.keys());
1417
+ // Connections are keyed by composite `<profile>@<endpoint>`. A bare
1418
+ // `--profile comet-local` must still list those tasks (same rule as
1419
+ // stopProfile). Match exact key, bareName, and composite/fork prefixes.
1420
+ const candidates = profileName
1421
+ ? [...this.connections.keys()].filter((k) => connectionKeyMatchesProfile(k, profileName) ||
1422
+ this.connections.get(k)?.bareName === profileName)
1423
+ : Array.from(this.connections.keys());
1363
1424
  for (const name of candidates) {
1364
1425
  const status = await this.getProfileStatus(name);
1365
1426
  if (status) {
1366
1427
  statuses.push(status);
1367
1428
  seen.add(name);
1429
+ if (status.name)
1430
+ seen.add(status.name);
1368
1431
  }
1369
1432
  }
1370
1433
  if (!profileName) {
@@ -1372,12 +1435,14 @@ export class BrowserService {
1372
1435
  for (const profile of profiles) {
1373
1436
  if (seen.has(profile.name))
1374
1437
  continue;
1438
+ if ([...seen].some((s) => connectionKeyMatchesProfile(s, profile.name)))
1439
+ continue;
1375
1440
  const reconciled = await this.reconcileFromDisk(profile.name);
1376
1441
  if (reconciled)
1377
1442
  statuses.push(reconciled);
1378
1443
  }
1379
1444
  }
1380
- else if (!seen.has(profileName)) {
1445
+ else if (statuses.length === 0) {
1381
1446
  const reconciled = await this.reconcileFromDisk(profileName);
1382
1447
  if (reconciled)
1383
1448
  statuses.push(reconciled);
@@ -1385,16 +1450,37 @@ export class BrowserService {
1385
1450
  return statuses;
1386
1451
  }
1387
1452
  async reconcileFromDisk(profileName) {
1388
- const info = getRunningChromeInfo(profileName);
1389
- if (!info)
1390
- return null;
1391
- const profile = await getProfile(profileName);
1392
- const tasks = this.loadTaskState(profileName);
1453
+ // Runtime dirs live under the composite (`comet-local@endpoint-0`), not the
1454
+ // bare YAML name. Walk every matching cache dir so bare `status --profile`
1455
+ // sees the same tasks as unscoped `status`.
1456
+ const dirs = listProfileCacheDirs(profileName);
1457
+ if (dirs.length === 0) {
1458
+ // Legacy: non-composite dir named exactly the bare profile.
1459
+ const info = getRunningChromeInfo(profileName);
1460
+ if (!info)
1461
+ return null;
1462
+ return this.profileStatusFromDisk(profileName, profileName, info.port, info.pid);
1463
+ }
1464
+ // Prefer a dir that still has a live browser; fall back to the first.
1465
+ for (const dir of dirs) {
1466
+ const dirName = path.basename(dir);
1467
+ const info = getRunningChromeInfo(dirName);
1468
+ if (!info)
1469
+ continue;
1470
+ return this.profileStatusFromDisk(profileName, dirName, info.port, info.pid);
1471
+ }
1472
+ return null;
1473
+ }
1474
+ async profileStatusFromDisk(displayName, runtimeKey, port, pid) {
1475
+ const bare = displayName.includes('@') ? displayName.split('@')[0] : displayName;
1476
+ const profile = await getProfile(bare);
1477
+ const tasks = this.loadTaskState(runtimeKey);
1393
1478
  const taskStatuses = [];
1394
1479
  for (const [, task] of tasks) {
1395
1480
  taskStatuses.push({
1396
1481
  id: task.id,
1397
1482
  name: task.name,
1483
+ label: task.label ?? task.name,
1398
1484
  tabCount: Object.keys(task.tabs).length,
1399
1485
  currentTabId: task.currentTabId,
1400
1486
  createdAt: task.createdAt,
@@ -1402,11 +1488,11 @@ export class BrowserService {
1402
1488
  }
1403
1489
  const configuredPort = profile ? extractConfiguredPort(profile) : undefined;
1404
1490
  return {
1405
- name: profileName,
1491
+ name: runtimeKey,
1406
1492
  running: true,
1407
- port: info.port,
1408
- pid: info.pid,
1409
- configuredPort: configuredPort !== info.port ? configuredPort : undefined,
1493
+ port,
1494
+ pid,
1495
+ configuredPort: configuredPort !== port ? configuredPort : undefined,
1410
1496
  tasks: taskStatuses,
1411
1497
  };
1412
1498
  }
@@ -2009,18 +2095,143 @@ export class BrowserService {
2009
2095
  }
2010
2096
  hasTaskNamed(name) {
2011
2097
  for (const conn of this.connections.values()) {
2012
- if (conn.tasks.has(name))
2098
+ if (this.lookupTaskOnConn(conn, name))
2013
2099
  return true;
2014
2100
  }
2015
2101
  return false;
2016
2102
  }
2017
- generateUniqueTaskName() {
2018
- for (let attempt = 0; attempt < 8; attempt++) {
2019
- const candidate = generateTaskName();
2020
- if (!this.hasTaskNamed(candidate))
2021
- return candidate;
2103
+ /** Map key for a task on a connection (tasks are keyed by `name`). */
2104
+ taskMapKey(conn, task) {
2105
+ for (const [key, t] of conn.tasks) {
2106
+ if (t === task || t.id === task.id || t.name === task.name)
2107
+ return key;
2022
2108
  }
2023
- throw new Error('Could not generate unique task name after 8 attempts');
2109
+ return undefined;
2110
+ }
2111
+ /** Find a task by map key, id, or name on one connection. */
2112
+ lookupTaskOnConn(conn, handle) {
2113
+ const direct = conn.tasks.get(handle);
2114
+ if (direct)
2115
+ return direct;
2116
+ for (const task of conn.tasks.values()) {
2117
+ if (task.id === handle || task.name === handle)
2118
+ return task;
2119
+ }
2120
+ return undefined;
2121
+ }
2122
+ maybeUpdateLabelFromUrl(conn, task, url) {
2123
+ if (task.label && task.label !== 'untitled')
2124
+ return;
2125
+ const next = deriveTaskLabel({ url, existing: task.label });
2126
+ if (next === task.label)
2127
+ return;
2128
+ task.label = next;
2129
+ void this.saveTaskState(task.profile, conn.tasks).catch(() => { });
2130
+ }
2131
+ /**
2132
+ * Resolve a task for a page/close verb.
2133
+ *
2134
+ * - explicit `task` handle → look up (with disk rehydrate on RAM miss)
2135
+ * - no handle, exactly one live task for this caller → use it
2136
+ * - no handle, multiple for this caller → error listing them + `--task`
2137
+ * - no handle, zero for this caller, createIfMissing → start a new task
2138
+ * - no handle, zero, !createIfMissing → return null (caller reports "nothing to close")
2139
+ */
2140
+ async resolveOrCreateTask(opts) {
2141
+ if (opts.task) {
2142
+ const found = await this.findTask(opts.task, opts.profile);
2143
+ return { ...found, created: false };
2144
+ }
2145
+ // After a daemon restart the connections map is empty while tasks.json still
2146
+ // holds live tasks. Rehydrate before identity matching so done/screenshot
2147
+ // without --task still find the caller's task.
2148
+ await this.rehydrateAllFromDisk();
2149
+ const caller = {
2150
+ sessionId: opts.sessionId,
2151
+ launchId: opts.launchId,
2152
+ };
2153
+ const matches = this.listTasksForCaller(caller);
2154
+ if (matches.length === 1) {
2155
+ const m = matches[0];
2156
+ await this.touchTask(m.conn, m.task);
2157
+ return { conn: m.conn, task: m.task, profileName: m.profileName, created: false };
2158
+ }
2159
+ if (matches.length > 1) {
2160
+ const lines = matches.map((m) => {
2161
+ const ageMs = Date.now() - m.task.createdAt;
2162
+ const age = ageMs < 60_000
2163
+ ? `${Math.round(ageMs / 1000)}s`
2164
+ : `${Math.round(ageMs / 60_000)}m`;
2165
+ const label = m.task.label ?? m.task.name;
2166
+ const url = this.currentUrlHint(m.conn, m.task) ?? '-';
2167
+ return ` ${label} id=${m.task.name} url=${url} age=${age}`;
2168
+ });
2169
+ throw new Error(actionable(`Multiple browser tasks for this session — pass --task <name>:`, ...lines, `Next: agents browser status`));
2170
+ }
2171
+ // Zero matches for this caller.
2172
+ if (!opts.createIfMissing)
2173
+ return null;
2174
+ // Implicit start on the default / named profile.
2175
+ let profileName = opts.profile;
2176
+ if (!profileName) {
2177
+ const { ensureDefaultBrowserProfile } = await import('./profiles.js');
2178
+ const detected = await ensureDefaultBrowserProfile();
2179
+ profileName = detected.name;
2180
+ }
2181
+ const started = await this.start(profileName, {
2182
+ url: opts.url,
2183
+ actor: opts.actor,
2184
+ launchId: opts.launchId,
2185
+ sessionId: opts.sessionId,
2186
+ title: opts.title,
2187
+ });
2188
+ return { ...(await this.findTask(started.name, started.profile)), created: true };
2189
+ }
2190
+ listTasksForCaller(caller) {
2191
+ const out = [];
2192
+ const hasIdentity = !!(caller.sessionId || caller.launchId);
2193
+ for (const [key, conn] of this.connections) {
2194
+ for (const task of conn.tasks.values()) {
2195
+ if (hasIdentity) {
2196
+ if (taskMatchesCaller(task, caller)) {
2197
+ out.push({ conn, task, profileName: conn.profileName ?? key });
2198
+ }
2199
+ }
2200
+ else {
2201
+ // No caller identity: only match tasks that also lack identity
2202
+ // (a human-driven shell). If there is exactly one live task total,
2203
+ // the single-task path still needs that listed — fall through below.
2204
+ if (!task.sessionId && !task.launchId) {
2205
+ out.push({ conn, task, profileName: conn.profileName ?? key });
2206
+ }
2207
+ }
2208
+ }
2209
+ }
2210
+ // No-identity caller with zero unscoped matches: if the daemon holds
2211
+ // exactly one live task that ALSO has no identity (a human-started one),
2212
+ // use it. Never steal a task stamped with another caller's session/launch.
2213
+ if (!hasIdentity && out.length === 0) {
2214
+ const unowned = this.listTasks().filter((t) => !t.task.sessionId && !t.task.launchId);
2215
+ if (unowned.length === 1) {
2216
+ const only = unowned[0];
2217
+ const conn = this.connections.get(only.profile) ??
2218
+ [...this.connections.entries()].find(([, c]) => c.tasks.has(only.task.name) || [...c.tasks.values()].includes(only.task))?.[1];
2219
+ if (conn) {
2220
+ out.push({ conn, task: only.task, profileName: only.profile });
2221
+ }
2222
+ }
2223
+ }
2224
+ return out;
2225
+ }
2226
+ currentUrlHint(conn, task) {
2227
+ const shortId = task.currentTabId;
2228
+ if (!shortId)
2229
+ return undefined;
2230
+ const cdpId = task.tabs[shortId];
2231
+ if (!cdpId)
2232
+ return undefined;
2233
+ const cached = conn.targetCache?.targets.find((t) => t.targetId === cdpId);
2234
+ return cached?.url;
2024
2235
  }
2025
2236
  /**
2026
2237
  * Mark a task as active, so the reaper's idle window measures time since the
@@ -2059,25 +2270,214 @@ export class BrowserService {
2059
2270
  }
2060
2271
  async findTask(taskId, profileName) {
2061
2272
  if (profileName) {
2062
- const conn = this.connections.get(profileName);
2063
- if (!conn) {
2064
- throw new Error(`Profile "${profileName}" not connected`);
2273
+ // Accept bare profile names against composite connection keys.
2274
+ const keys = [...this.connections.keys()].filter((k) => k === profileName ||
2275
+ connectionKeyMatchesProfile(k, profileName) ||
2276
+ this.connections.get(k)?.bareName === profileName);
2277
+ for (const key of keys) {
2278
+ const conn = this.connections.get(key);
2279
+ const task = this.lookupTaskOnConn(conn, taskId);
2280
+ if (task) {
2281
+ await this.touchTask(conn, task);
2282
+ return { conn, task, profileName: conn.profileName ?? key };
2283
+ }
2065
2284
  }
2066
- const task = conn.tasks.get(taskId);
2067
- if (!task) {
2068
- throw new Error(`Task "${taskId}" not found on profile "${profileName}"`);
2285
+ // RAM miss → rehydrate from disk for this profile.
2286
+ const rehydrated = await this.rehydrateTaskFromDisk(taskId, profileName);
2287
+ if (rehydrated) {
2288
+ await this.touchTask(rehydrated.conn, rehydrated.task);
2289
+ return rehydrated;
2069
2290
  }
2070
- await this.touchTask(conn, task);
2071
- return { conn, task, profileName };
2291
+ throw new Error(actionable(`Task "${taskId}" not found on profile "${profileName}".`, `Next: agents browser status --profile ${profileName}`));
2072
2292
  }
2073
2293
  for (const [key, conn] of this.connections) {
2074
- const task = conn.tasks.get(taskId);
2294
+ const task = this.lookupTaskOnConn(conn, taskId);
2075
2295
  if (task) {
2076
2296
  await this.touchTask(conn, task);
2077
2297
  return { conn, task, profileName: conn.profileName ?? key };
2078
2298
  }
2079
2299
  }
2080
- throw new Error(`Task "${taskId}" not found`);
2300
+ // RAM miss after a daemon restart: tasks.json still has the task and
2301
+ // meta.json still has the browser pid/port. Reconnect and adopt.
2302
+ const rehydrated = await this.rehydrateTaskFromDisk(taskId);
2303
+ if (rehydrated) {
2304
+ await this.touchTask(rehydrated.conn, rehydrated.task);
2305
+ return rehydrated;
2306
+ }
2307
+ const live = this.listTasks()
2308
+ .map(({ task }) => task.label ?? task.name)
2309
+ .join(', ');
2310
+ throw new Error(actionable(`Task "${taskId}" not found.`, `Active tasks: ${live || 'none'}`, `It may have been closed by the idle reaper (30 min).`, `Next: agents browser status | agents browser navigate <url>`));
2311
+ }
2312
+ /**
2313
+ * Soft-attach to an already-running browser for a runtime dir.
2314
+ *
2315
+ * Never launches a browser and never clears pid/port files on failure —
2316
+ * `connectProfile` does both, which made `status()` wipe disk state when
2317
+ * CDP was unreachable (CI / post-reaper) and then return an empty list.
2318
+ * Returns null when nothing is speaking CDP so callers can fall through
2319
+ * to disk reconcile.
2320
+ */
2321
+ async attachRunningProfile(dirName, diskTasks) {
2322
+ const bare = dirName.includes('@') ? dirName.split('@')[0] : dirName;
2323
+ const endpointFromKey = dirName.includes('@')
2324
+ ? dirName.slice(dirName.indexOf('@') + 1).split('.')[0]
2325
+ : undefined;
2326
+ const profile = await getProfile(bare);
2327
+ if (!profile)
2328
+ return null;
2329
+ let resolved;
2330
+ try {
2331
+ resolved = resolveEndpoint(profile, endpointFromKey);
2332
+ }
2333
+ catch {
2334
+ return null;
2335
+ }
2336
+ const existingInfo = getRunningChromeInfo(dirName);
2337
+ const parsed = parseEndpointUrl(resolved.target);
2338
+ const port = existingInfo?.port ?? parsed?.port;
2339
+ if (port === undefined)
2340
+ return null;
2341
+ const host = parsed?.host && parsed.host !== 'localhost' ? parsed.host : 'localhost';
2342
+ // ssh:// endpoints need a tunnel; soft rehydrate only handles local CDP.
2343
+ if (resolved.target.startsWith('ssh:'))
2344
+ return null;
2345
+ try {
2346
+ const { wsUrl, browser } = await discoverBrowserWsUrl(port, host, dirName);
2347
+ verifyBrowserIdentity(browser, profile.browser, port, host);
2348
+ const cdp = new CDPClient();
2349
+ await cdp.connect(wsUrl);
2350
+ await this.enableDomains(cdp);
2351
+ const tasks = this.loadTaskState(dirName);
2352
+ for (const [k, t] of diskTasks) {
2353
+ if (!tasks.has(k))
2354
+ tasks.set(k, t);
2355
+ }
2356
+ const conn = {
2357
+ cdp,
2358
+ port,
2359
+ pid: existingInfo?.pid ?? 0,
2360
+ electron: profile.electron,
2361
+ targetFilter: resolved.targetFilter ?? profile.targetFilter,
2362
+ profileName: dirName,
2363
+ bareName: bare,
2364
+ tasks,
2365
+ sessionCache: new Map(),
2366
+ };
2367
+ return conn;
2368
+ }
2369
+ catch {
2370
+ return null;
2371
+ }
2372
+ }
2373
+ /**
2374
+ * Reconnect every profile runtime dir that still has a live browser and
2375
+ * tasks.json entries. Used before identity-based resolution so a daemon
2376
+ * restart does not make the caller's tasks invisible.
2377
+ */
2378
+ async rehydrateAllFromDisk() {
2379
+ const runtimeRoot = getBrowserRuntimeDir();
2380
+ let dirNames = [];
2381
+ try {
2382
+ dirNames = fs.readdirSync(runtimeRoot).filter((d) => {
2383
+ try {
2384
+ return fs.statSync(path.join(runtimeRoot, d)).isDirectory();
2385
+ }
2386
+ catch {
2387
+ return false;
2388
+ }
2389
+ });
2390
+ }
2391
+ catch {
2392
+ return;
2393
+ }
2394
+ for (const dirName of dirNames) {
2395
+ if (this.connections.has(dirName))
2396
+ continue;
2397
+ // Skip non-runtime dirs (e.g. profiles/)
2398
+ if (dirName === 'profiles' || dirName === 'sessions' || dirName === 'exports')
2399
+ continue;
2400
+ const tasks = this.loadTaskState(dirName);
2401
+ if (tasks.size === 0)
2402
+ continue;
2403
+ // Soft attach only — never launch / never clear pid files.
2404
+ const conn = await this.attachRunningProfile(dirName, tasks);
2405
+ if (!conn)
2406
+ continue;
2407
+ this.connections.set(dirName, conn);
2408
+ try {
2409
+ await this.applyDefaultDownloadBehavior(conn, dirName);
2410
+ }
2411
+ catch {
2412
+ // Non-fatal for rehydrate.
2413
+ }
2414
+ }
2415
+ }
2416
+ /**
2417
+ * On a RAM miss, scan profile runtime dirs for a tasks.json entry matching
2418
+ * `taskId`, soft-attach when CDP is still up, and register the connection.
2419
+ * Does not launch browsers or clear runtime files.
2420
+ */
2421
+ async rehydrateTaskFromDisk(taskId, profileHint) {
2422
+ const runtimeRoot = getBrowserRuntimeDir();
2423
+ let dirNames = [];
2424
+ try {
2425
+ dirNames = fs.readdirSync(runtimeRoot).filter((d) => {
2426
+ try {
2427
+ return fs.statSync(path.join(runtimeRoot, d)).isDirectory();
2428
+ }
2429
+ catch {
2430
+ return false;
2431
+ }
2432
+ });
2433
+ }
2434
+ catch {
2435
+ return null;
2436
+ }
2437
+ if (profileHint) {
2438
+ dirNames = dirNames.filter((d) => d === profileHint || connectionKeyMatchesProfile(d, profileHint));
2439
+ }
2440
+ for (const dirName of dirNames) {
2441
+ if (dirName === 'profiles' || dirName === 'sessions' || dirName === 'exports')
2442
+ continue;
2443
+ const tasks = this.loadTaskState(dirName);
2444
+ let found;
2445
+ for (const task of tasks.values()) {
2446
+ if (task.id === taskId || task.name === taskId) {
2447
+ found = task;
2448
+ break;
2449
+ }
2450
+ }
2451
+ // Also allow map-key match
2452
+ if (!found)
2453
+ found = tasks.get(taskId);
2454
+ if (!found)
2455
+ continue;
2456
+ // Already connected under this key?
2457
+ let conn = this.connections.get(dirName);
2458
+ if (!conn) {
2459
+ const attached = await this.attachRunningProfile(dirName, tasks);
2460
+ if (!attached) {
2461
+ // CDP down — cannot rehydrate a live connection; caller will error.
2462
+ continue;
2463
+ }
2464
+ conn = attached;
2465
+ this.connections.set(dirName, conn);
2466
+ try {
2467
+ await this.applyDefaultDownloadBehavior(conn, dirName);
2468
+ }
2469
+ catch {
2470
+ // Non-fatal.
2471
+ }
2472
+ }
2473
+ const task = this.lookupTaskOnConn(conn, taskId) ?? found;
2474
+ // Ensure the rehydrated task is on the connection map.
2475
+ if (!this.lookupTaskOnConn(conn, task.name)) {
2476
+ conn.tasks.set(task.name, task);
2477
+ }
2478
+ return { conn, task, profileName: conn.profileName ?? dirName };
2479
+ }
2480
+ return null;
2081
2481
  }
2082
2482
  async getTabsForTask(cdp, task) {
2083
2483
  const targets = (await cdp.send('Target.getTargets'));
@@ -2096,7 +2496,19 @@ export class BrowserService {
2096
2496
  return tabs;
2097
2497
  }
2098
2498
  async getProfileStatus(profileName) {
2099
- const conn = this.connections.get(profileName);
2499
+ // Exact composite key first; bare name falls through connectionKeyMatches.
2500
+ let conn = this.connections.get(profileName);
2501
+ let resolvedKey = profileName;
2502
+ if (!conn) {
2503
+ for (const [key, c] of this.connections) {
2504
+ if (connectionKeyMatchesProfile(key, profileName) ||
2505
+ c.bareName === profileName) {
2506
+ conn = c;
2507
+ resolvedKey = key;
2508
+ break;
2509
+ }
2510
+ }
2511
+ }
2100
2512
  if (!conn)
2101
2513
  return null;
2102
2514
  // Fetch all targets once for efficiency
@@ -2134,6 +2546,7 @@ export class BrowserService {
2134
2546
  tasks.push({
2135
2547
  id: task.id,
2136
2548
  name: task.name,
2549
+ label: task.label ?? task.name,
2137
2550
  tabCount: Object.keys(task.tabs).length,
2138
2551
  currentTabId: task.currentTabId,
2139
2552
  createdAt: task.createdAt,
@@ -2141,10 +2554,11 @@ export class BrowserService {
2141
2554
  domains: domainSet.size > 0 ? Array.from(domainSet) : undefined,
2142
2555
  });
2143
2556
  }
2144
- const profile = await getProfile(profileName);
2557
+ const bare = conn.bareName ?? (resolvedKey.includes('@') ? resolvedKey.split('@')[0] : resolvedKey);
2558
+ const profile = await getProfile(bare);
2145
2559
  const configuredPort = profile ? extractConfiguredPort(profile) : undefined;
2146
2560
  return {
2147
- name: profileName,
2561
+ name: resolvedKey,
2148
2562
  running: true,
2149
2563
  port: conn.port,
2150
2564
  pid: conn.pid,