@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
@@ -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,47 @@ 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
+ /**
247
+ * Arc answers `Browser.getVersion` (so a connection succeeds) but exposes zero
248
+ * CDP page targets via every discovery method and CRASHES when a new tab is
249
+ * requested via `Target.createTarget` (verified live, PR #2778). It is therefore
250
+ * not drivable. This is the single clear, actionable error every tab-creating
251
+ * path throws instead of crashing the user's Arc window.
252
+ */
253
+ export function arcNotDrivableError(profileName) {
254
+ const scope = profileName ? ` (profile "${profileName}")` : '';
255
+ return new Error(actionable(`Browser "arc"${scope} is not drivable: Arc exposes no CDP page targets and`, 'crashes when a new tab is requested, so `agents browser` cannot control it.', 'Use a Chromium-family browser instead — Comet, Chrome, Chromium, or Brave:', ' agents browser profiles create <name> --browser comet'));
256
+ }
257
+ /** Derive a human label from an explicit title or a navigated URL. */
258
+ export function deriveTaskLabel(opts) {
259
+ if (opts.title?.trim())
260
+ return opts.title.trim();
261
+ if (opts.existing && opts.existing !== 'untitled')
262
+ return opts.existing;
263
+ if (opts.url) {
264
+ try {
265
+ const host = new URL(opts.url).hostname.replace(/^www\./, '');
266
+ if (host)
267
+ return host;
268
+ }
269
+ catch {
270
+ /* unparseable */
271
+ }
272
+ }
273
+ return opts.existing ?? 'untitled';
274
+ }
275
+ /**
276
+ * True when `key` is the bare profile name or one of its composite endpoint
277
+ * keys (`name@endpoint`). Used by status/stop so `comet-local` matches
278
+ * `comet-local@endpoint-0`.
279
+ */
280
+ export function connectionKeyMatchesProfile(key, profileName) {
281
+ return key === profileName || key.startsWith(`${profileName}@`) || key.startsWith(`${profileName}.`);
282
+ }
241
283
  /**
242
284
  * Resolve the identity stamped on a task at start: WHO (`owner`) and WHICH run
243
285
  * (`launchId`). The forwarded values come from the caller's own CLI process and
@@ -280,14 +322,20 @@ export class BrowserService {
280
322
  // passed an unknown name. The composite identifier `<profile>@<endpoint>`
281
323
  // is what the connection map + per-profile runtime dirs are keyed on, so
282
324
  // a single YAML profile can run at multiple endpoints concurrently.
325
+ //
326
+ // The YAML profile's bare `name` stays on `profile.name` for status
327
+ // matching; only the connection/runtime key uses the composite.
283
328
  const resolved = resolveEndpoint(profile, opts.endpointName);
284
329
  const composite = `${profileName}@${resolved.name}`;
285
330
  const effectiveProfile = {
286
331
  ...profile,
332
+ // Runtime/connect path key — NOT the bare YAML name. Connections and
333
+ // tasks.json live under this composite so multi-endpoint is safe.
287
334
  name: composite,
288
335
  binary: resolved.binary,
289
336
  targetFilter: resolved.targetFilter,
290
337
  };
338
+ const taskId = generateTaskId();
291
339
  let taskName;
292
340
  if (opts.taskName) {
293
341
  if (this.hasTaskNamed(opts.taskName)) {
@@ -296,9 +344,10 @@ export class BrowserService {
296
344
  taskName = opts.taskName;
297
345
  }
298
346
  else {
299
- taskName = this.generateUniqueTaskName();
347
+ // Address by the short machine id — no word-salad. Status shows `label`.
348
+ taskName = taskId;
300
349
  }
301
- const taskId = generateTaskId();
350
+ const taskLabel = deriveTaskLabel({ title: opts.title, url: opts.url });
302
351
  let conn = this.connections.get(composite);
303
352
  let effectiveProfileName = composite;
304
353
  // If we have a cached connection, confirm it's still usable before any
@@ -344,9 +393,12 @@ export class BrowserService {
344
393
  else if (!conn) {
345
394
  conn = await this.connectProfile(effectiveProfile, resolved.target);
346
395
  conn.profileName = composite;
396
+ conn.bareName = profileName;
347
397
  this.connections.set(composite, conn);
348
398
  await this.applyDefaultDownloadBehavior(conn, composite);
349
399
  }
400
+ if (conn && !conn.bareName)
401
+ conn.bareName = profileName;
350
402
  // Browsers launch with --no-startup-window (session-cookie persistence,
351
403
  // see launchBrowser), so a bare `start` with no --url would otherwise
352
404
  // leave the user staring at a process with zero windows. Recreate the
@@ -363,9 +415,9 @@ export class BrowserService {
363
415
  if (!opts.url && !conn.electron) {
364
416
  const { targetInfos } = (await conn.cdp.send('Target.getTargets'));
365
417
  if (!targetInfos.some((t) => t.type === 'page')) {
366
- const created = (await conn.cdp.send('Target.createTarget', {
418
+ const created = await this.createPageTarget(conn, {
367
419
  url: 'about:blank',
368
- }));
420
+ });
369
421
  startupBlankTargetId = created.targetId;
370
422
  this.invalidateTargetCache(conn);
371
423
  }
@@ -374,6 +426,7 @@ export class BrowserService {
374
426
  const task = {
375
427
  id: taskId,
376
428
  name: taskName,
429
+ label: taskLabel,
377
430
  profile: effectiveProfileName,
378
431
  tabs: {},
379
432
  currentTabId: undefined,
@@ -443,10 +496,7 @@ export class BrowserService {
443
496
  let tabId;
444
497
  if (opts.url && !conn.electron) {
445
498
  const adopted = opts.fresh ? undefined : await this.adoptTabShowing(conn, opts.url);
446
- const targetId = adopted ??
447
- (await conn.cdp.send('Target.createTarget', {
448
- url: opts.url,
449
- })).targetId;
499
+ const targetId = adopted ?? (await this.createPageTarget(conn, { url: opts.url })).targetId;
450
500
  const shortId = generateShortId();
451
501
  task.tabs[shortId] = targetId;
452
502
  task.currentTabId = shortId;
@@ -574,9 +624,18 @@ export class BrowserService {
574
624
  return reapAbandonedTasks(this, opts);
575
625
  }
576
626
  async stop(taskName) {
627
+ // Rehydrate from tasks.json when the daemon restarted and lost RAM state.
628
+ try {
629
+ await this.findTask(taskName);
630
+ }
631
+ catch {
632
+ // findTask throws when truly gone; fall through to the miss return.
633
+ }
577
634
  for (const [profileName, conn] of this.connections) {
578
- const task = conn.tasks.get(taskName);
635
+ const task = this.lookupTaskOnConn(conn, taskName);
579
636
  if (task) {
637
+ // Map key may be task.name, not the caller-supplied handle.
638
+ const mapKey = this.taskMapKey(conn, task) ?? taskName;
580
639
  // Get domains from tabs before closing (for history)
581
640
  const domains = new Set();
582
641
  try {
@@ -608,16 +667,16 @@ export class BrowserService {
608
667
  conn.sessionCache.delete(cdpId);
609
668
  }
610
669
  this.invalidateTargetCache(conn);
611
- conn.tasks.delete(taskName);
670
+ conn.tasks.delete(mapKey);
612
671
  await this.saveTaskState(profileName, conn.tasks);
613
- emit('browser.close', { profile: profileName, task: taskName });
672
+ emit('browser.close', { profile: profileName, task: task.name });
614
673
  void import('../analytics/usage-db.js').then(({ recordUsage }) => {
615
674
  recordUsage({
616
675
  kind: 'browser',
617
676
  name: profileName,
618
677
  event: 'close',
619
678
  source: 'browser',
620
- meta: { task: taskName },
679
+ meta: { task: task.name },
621
680
  });
622
681
  }).catch(() => { });
623
682
  if (conn.forkedFrom && conn.tasks.size === 0) {
@@ -669,6 +728,7 @@ export class BrowserService {
669
728
  }
670
729
  async navigate(taskId, url, profileName) {
671
730
  const { conn, task } = await this.findTask(taskId, profileName);
731
+ this.maybeUpdateLabelFromUrl(conn, task, url);
672
732
  // If we have a current tab, navigate in it (reuse)
673
733
  const currentShortId = task.currentTabId;
674
734
  if (currentShortId && task.tabs[currentShortId]) {
@@ -695,9 +755,7 @@ export class BrowserService {
695
755
  return { tabId: shortId, url, created: true };
696
756
  }
697
757
  // Chrome: create new tab
698
- const result = (await conn.cdp.send('Target.createTarget', {
699
- url,
700
- }));
758
+ const result = await this.createPageTarget(conn, { url });
701
759
  const shortId = generateShortId();
702
760
  task.tabs[shortId] = result.targetId;
703
761
  task.currentTabId = shortId;
@@ -711,9 +769,7 @@ export class BrowserService {
711
769
  if (conn.electron) {
712
770
  throw new Error('Electron apps do not support opening additional tabs');
713
771
  }
714
- const result = (await conn.cdp.send('Target.createTarget', {
715
- url,
716
- }));
772
+ const result = await this.createPageTarget(conn, { url });
717
773
  const shortId = generateShortId();
718
774
  task.tabs[shortId] = result.targetId;
719
775
  task.currentTabId = shortId; // new tab becomes current
@@ -1357,14 +1413,25 @@ export class BrowserService {
1357
1413
  return { path: stageUploadFile(source) };
1358
1414
  }
1359
1415
  async status(profileName) {
1416
+ // Reconnect live browsers after a daemon restart so status is not empty
1417
+ // while tasks.json still holds open work.
1418
+ await this.rehydrateAllFromDisk();
1360
1419
  const seen = new Set();
1361
1420
  const statuses = [];
1362
- const candidates = profileName ? [profileName] : Array.from(this.connections.keys());
1421
+ // Connections are keyed by composite `<profile>@<endpoint>`. A bare
1422
+ // `--profile comet-local` must still list those tasks (same rule as
1423
+ // stopProfile). Match exact key, bareName, and composite/fork prefixes.
1424
+ const candidates = profileName
1425
+ ? [...this.connections.keys()].filter((k) => connectionKeyMatchesProfile(k, profileName) ||
1426
+ this.connections.get(k)?.bareName === profileName)
1427
+ : Array.from(this.connections.keys());
1363
1428
  for (const name of candidates) {
1364
1429
  const status = await this.getProfileStatus(name);
1365
1430
  if (status) {
1366
1431
  statuses.push(status);
1367
1432
  seen.add(name);
1433
+ if (status.name)
1434
+ seen.add(status.name);
1368
1435
  }
1369
1436
  }
1370
1437
  if (!profileName) {
@@ -1372,12 +1439,14 @@ export class BrowserService {
1372
1439
  for (const profile of profiles) {
1373
1440
  if (seen.has(profile.name))
1374
1441
  continue;
1442
+ if ([...seen].some((s) => connectionKeyMatchesProfile(s, profile.name)))
1443
+ continue;
1375
1444
  const reconciled = await this.reconcileFromDisk(profile.name);
1376
1445
  if (reconciled)
1377
1446
  statuses.push(reconciled);
1378
1447
  }
1379
1448
  }
1380
- else if (!seen.has(profileName)) {
1449
+ else if (statuses.length === 0) {
1381
1450
  const reconciled = await this.reconcileFromDisk(profileName);
1382
1451
  if (reconciled)
1383
1452
  statuses.push(reconciled);
@@ -1385,16 +1454,37 @@ export class BrowserService {
1385
1454
  return statuses;
1386
1455
  }
1387
1456
  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);
1457
+ // Runtime dirs live under the composite (`comet-local@endpoint-0`), not the
1458
+ // bare YAML name. Walk every matching cache dir so bare `status --profile`
1459
+ // sees the same tasks as unscoped `status`.
1460
+ const dirs = listProfileCacheDirs(profileName);
1461
+ if (dirs.length === 0) {
1462
+ // Legacy: non-composite dir named exactly the bare profile.
1463
+ const info = getRunningChromeInfo(profileName);
1464
+ if (!info)
1465
+ return null;
1466
+ return this.profileStatusFromDisk(profileName, profileName, info.port, info.pid);
1467
+ }
1468
+ // Prefer a dir that still has a live browser; fall back to the first.
1469
+ for (const dir of dirs) {
1470
+ const dirName = path.basename(dir);
1471
+ const info = getRunningChromeInfo(dirName);
1472
+ if (!info)
1473
+ continue;
1474
+ return this.profileStatusFromDisk(profileName, dirName, info.port, info.pid);
1475
+ }
1476
+ return null;
1477
+ }
1478
+ async profileStatusFromDisk(displayName, runtimeKey, port, pid) {
1479
+ const bare = displayName.includes('@') ? displayName.split('@')[0] : displayName;
1480
+ const profile = await getProfile(bare);
1481
+ const tasks = this.loadTaskState(runtimeKey);
1393
1482
  const taskStatuses = [];
1394
1483
  for (const [, task] of tasks) {
1395
1484
  taskStatuses.push({
1396
1485
  id: task.id,
1397
1486
  name: task.name,
1487
+ label: task.label ?? task.name,
1398
1488
  tabCount: Object.keys(task.tabs).length,
1399
1489
  currentTabId: task.currentTabId,
1400
1490
  createdAt: task.createdAt,
@@ -1402,11 +1492,11 @@ export class BrowserService {
1402
1492
  }
1403
1493
  const configuredPort = profile ? extractConfiguredPort(profile) : undefined;
1404
1494
  return {
1405
- name: profileName,
1495
+ name: runtimeKey,
1406
1496
  running: true,
1407
- port: info.port,
1408
- pid: info.pid,
1409
- configuredPort: configuredPort !== info.port ? configuredPort : undefined,
1497
+ port,
1498
+ pid,
1499
+ configuredPort: configuredPort !== port ? configuredPort : undefined,
1410
1500
  tasks: taskStatuses,
1411
1501
  };
1412
1502
  }
@@ -1843,6 +1933,7 @@ export class BrowserService {
1843
1933
  port,
1844
1934
  pid,
1845
1935
  electron: true,
1936
+ browserType: profile.browser,
1846
1937
  targetFilter: profile.targetFilter,
1847
1938
  profileName: forkName,
1848
1939
  forkedFrom: profile.name,
@@ -1877,6 +1968,7 @@ export class BrowserService {
1877
1968
  port: existingInfo.port,
1878
1969
  pid: existingInfo.pid,
1879
1970
  electron: effectiveProfile.electron,
1971
+ browserType: effectiveProfile.browser,
1880
1972
  targetFilter: effectiveProfile.targetFilter,
1881
1973
  tasks,
1882
1974
  sessionCache: new Map(),
@@ -1908,6 +2000,7 @@ export class BrowserService {
1908
2000
  port: conn.port,
1909
2001
  pid: conn.pid,
1910
2002
  electron: profile.electron,
2003
+ browserType: profile.browser,
1911
2004
  targetFilter: profile.targetFilter,
1912
2005
  tasks: conn.pid === 0 ? this.loadTaskState(profile.name) : new Map(),
1913
2006
  sessionCache: new Map(),
@@ -1921,6 +2014,7 @@ export class BrowserService {
1921
2014
  port: conn.port,
1922
2015
  pid: conn.pid,
1923
2016
  electron: profile.electron,
2017
+ browserType: profile.browser,
1924
2018
  targetFilter: profile.targetFilter,
1925
2019
  tasks: new Map(),
1926
2020
  sessionCache: new Map(),
@@ -1942,6 +2036,7 @@ export class BrowserService {
1942
2036
  port: 0,
1943
2037
  pid: 0,
1944
2038
  electron: profile.electron,
2039
+ browserType: profile.browser,
1945
2040
  targetFilter: profile.targetFilter,
1946
2041
  tasks: this.loadTaskState(profile.name),
1947
2042
  sessionCache: new Map(),
@@ -1959,6 +2054,7 @@ export class BrowserService {
1959
2054
  port,
1960
2055
  pid: 0,
1961
2056
  electron: profile.electron,
2057
+ browserType: profile.browser,
1962
2058
  targetFilter: profile.targetFilter,
1963
2059
  tasks: this.loadTaskState(profile.name),
1964
2060
  sessionCache: new Map(),
@@ -1969,6 +2065,19 @@ export class BrowserService {
1969
2065
  async enableDomains(cdp) {
1970
2066
  await cdp.send('Target.setDiscoverTargets', { discover: true });
1971
2067
  }
2068
+ /**
2069
+ * The single path that opens a new CDP page/window target. It exists so the
2070
+ * Arc guard lives in exactly one place: `Target.createTarget` crashes Arc
2071
+ * (verified, PR #2778), so an Arc connection throws a clear, actionable error
2072
+ * here instead of every call site re-checking. Every drivable Chromium-family
2073
+ * browser goes straight through.
2074
+ */
2075
+ async createPageTarget(conn, params) {
2076
+ if (conn.browserType === 'arc') {
2077
+ throw arcNotDrivableError(conn.bareName ?? conn.profileName);
2078
+ }
2079
+ return (await conn.cdp.send('Target.createTarget', params));
2080
+ }
1972
2081
  async getOrCreateWindow(conn) {
1973
2082
  // Already have a window for this profile?
1974
2083
  if (conn.windowId) {
@@ -2000,27 +2109,152 @@ export class BrowserService {
2000
2109
  `Available page targets:\n${candidates || ' (none)'}`);
2001
2110
  }
2002
2111
  // First ever use - create window
2003
- const result = (await conn.cdp.send('Target.createTarget', {
2112
+ const result = await this.createPageTarget(conn, {
2004
2113
  url: 'about:blank',
2005
2114
  newWindow: true,
2006
- }));
2115
+ });
2007
2116
  conn.windowId = result.targetId;
2008
2117
  return result.targetId;
2009
2118
  }
2010
2119
  hasTaskNamed(name) {
2011
2120
  for (const conn of this.connections.values()) {
2012
- if (conn.tasks.has(name))
2121
+ if (this.lookupTaskOnConn(conn, name))
2013
2122
  return true;
2014
2123
  }
2015
2124
  return false;
2016
2125
  }
2017
- generateUniqueTaskName() {
2018
- for (let attempt = 0; attempt < 8; attempt++) {
2019
- const candidate = generateTaskName();
2020
- if (!this.hasTaskNamed(candidate))
2021
- return candidate;
2126
+ /** Map key for a task on a connection (tasks are keyed by `name`). */
2127
+ taskMapKey(conn, task) {
2128
+ for (const [key, t] of conn.tasks) {
2129
+ if (t === task || t.id === task.id || t.name === task.name)
2130
+ return key;
2022
2131
  }
2023
- throw new Error('Could not generate unique task name after 8 attempts');
2132
+ return undefined;
2133
+ }
2134
+ /** Find a task by map key, id, or name on one connection. */
2135
+ lookupTaskOnConn(conn, handle) {
2136
+ const direct = conn.tasks.get(handle);
2137
+ if (direct)
2138
+ return direct;
2139
+ for (const task of conn.tasks.values()) {
2140
+ if (task.id === handle || task.name === handle)
2141
+ return task;
2142
+ }
2143
+ return undefined;
2144
+ }
2145
+ maybeUpdateLabelFromUrl(conn, task, url) {
2146
+ if (task.label && task.label !== 'untitled')
2147
+ return;
2148
+ const next = deriveTaskLabel({ url, existing: task.label });
2149
+ if (next === task.label)
2150
+ return;
2151
+ task.label = next;
2152
+ void this.saveTaskState(task.profile, conn.tasks).catch(() => { });
2153
+ }
2154
+ /**
2155
+ * Resolve a task for a page/close verb.
2156
+ *
2157
+ * - explicit `task` handle → look up (with disk rehydrate on RAM miss)
2158
+ * - no handle, exactly one live task for this caller → use it
2159
+ * - no handle, multiple for this caller → error listing them + `--task`
2160
+ * - no handle, zero for this caller, createIfMissing → start a new task
2161
+ * - no handle, zero, !createIfMissing → return null (caller reports "nothing to close")
2162
+ */
2163
+ async resolveOrCreateTask(opts) {
2164
+ if (opts.task) {
2165
+ const found = await this.findTask(opts.task, opts.profile);
2166
+ return { ...found, created: false };
2167
+ }
2168
+ // After a daemon restart the connections map is empty while tasks.json still
2169
+ // holds live tasks. Rehydrate before identity matching so done/screenshot
2170
+ // without --task still find the caller's task.
2171
+ await this.rehydrateAllFromDisk();
2172
+ const caller = {
2173
+ sessionId: opts.sessionId,
2174
+ launchId: opts.launchId,
2175
+ };
2176
+ const matches = this.listTasksForCaller(caller);
2177
+ if (matches.length === 1) {
2178
+ const m = matches[0];
2179
+ await this.touchTask(m.conn, m.task);
2180
+ return { conn: m.conn, task: m.task, profileName: m.profileName, created: false };
2181
+ }
2182
+ if (matches.length > 1) {
2183
+ const lines = matches.map((m) => {
2184
+ const ageMs = Date.now() - m.task.createdAt;
2185
+ const age = ageMs < 60_000
2186
+ ? `${Math.round(ageMs / 1000)}s`
2187
+ : `${Math.round(ageMs / 60_000)}m`;
2188
+ const label = m.task.label ?? m.task.name;
2189
+ const url = this.currentUrlHint(m.conn, m.task) ?? '-';
2190
+ return ` ${label} id=${m.task.name} url=${url} age=${age}`;
2191
+ });
2192
+ throw new Error(actionable(`Multiple browser tasks for this session — pass --task <name>:`, ...lines, `Next: agents browser status`));
2193
+ }
2194
+ // Zero matches for this caller.
2195
+ if (!opts.createIfMissing)
2196
+ return null;
2197
+ // Implicit start on the default / named profile.
2198
+ let profileName = opts.profile;
2199
+ if (!profileName) {
2200
+ const { ensureDefaultBrowserProfile } = await import('./profiles.js');
2201
+ const detected = await ensureDefaultBrowserProfile();
2202
+ profileName = detected.name;
2203
+ }
2204
+ const started = await this.start(profileName, {
2205
+ url: opts.url,
2206
+ actor: opts.actor,
2207
+ launchId: opts.launchId,
2208
+ sessionId: opts.sessionId,
2209
+ title: opts.title,
2210
+ });
2211
+ return { ...(await this.findTask(started.name, started.profile)), created: true };
2212
+ }
2213
+ listTasksForCaller(caller) {
2214
+ const out = [];
2215
+ const hasIdentity = !!(caller.sessionId || caller.launchId);
2216
+ for (const [key, conn] of this.connections) {
2217
+ for (const task of conn.tasks.values()) {
2218
+ if (hasIdentity) {
2219
+ if (taskMatchesCaller(task, caller)) {
2220
+ out.push({ conn, task, profileName: conn.profileName ?? key });
2221
+ }
2222
+ }
2223
+ else {
2224
+ // No caller identity: only match tasks that also lack identity
2225
+ // (a human-driven shell). If there is exactly one live task total,
2226
+ // the single-task path still needs that listed — fall through below.
2227
+ if (!task.sessionId && !task.launchId) {
2228
+ out.push({ conn, task, profileName: conn.profileName ?? key });
2229
+ }
2230
+ }
2231
+ }
2232
+ }
2233
+ // No-identity caller with zero unscoped matches: if the daemon holds
2234
+ // exactly one live task that ALSO has no identity (a human-started one),
2235
+ // use it. Never steal a task stamped with another caller's session/launch.
2236
+ if (!hasIdentity && out.length === 0) {
2237
+ const unowned = this.listTasks().filter((t) => !t.task.sessionId && !t.task.launchId);
2238
+ if (unowned.length === 1) {
2239
+ const only = unowned[0];
2240
+ const conn = this.connections.get(only.profile) ??
2241
+ [...this.connections.entries()].find(([, c]) => c.tasks.has(only.task.name) || [...c.tasks.values()].includes(only.task))?.[1];
2242
+ if (conn) {
2243
+ out.push({ conn, task: only.task, profileName: only.profile });
2244
+ }
2245
+ }
2246
+ }
2247
+ return out;
2248
+ }
2249
+ currentUrlHint(conn, task) {
2250
+ const shortId = task.currentTabId;
2251
+ if (!shortId)
2252
+ return undefined;
2253
+ const cdpId = task.tabs[shortId];
2254
+ if (!cdpId)
2255
+ return undefined;
2256
+ const cached = conn.targetCache?.targets.find((t) => t.targetId === cdpId);
2257
+ return cached?.url;
2024
2258
  }
2025
2259
  /**
2026
2260
  * Mark a task as active, so the reaper's idle window measures time since the
@@ -2059,25 +2293,215 @@ export class BrowserService {
2059
2293
  }
2060
2294
  async findTask(taskId, profileName) {
2061
2295
  if (profileName) {
2062
- const conn = this.connections.get(profileName);
2063
- if (!conn) {
2064
- throw new Error(`Profile "${profileName}" not connected`);
2296
+ // Accept bare profile names against composite connection keys.
2297
+ const keys = [...this.connections.keys()].filter((k) => k === profileName ||
2298
+ connectionKeyMatchesProfile(k, profileName) ||
2299
+ this.connections.get(k)?.bareName === profileName);
2300
+ for (const key of keys) {
2301
+ const conn = this.connections.get(key);
2302
+ const task = this.lookupTaskOnConn(conn, taskId);
2303
+ if (task) {
2304
+ await this.touchTask(conn, task);
2305
+ return { conn, task, profileName: conn.profileName ?? key };
2306
+ }
2065
2307
  }
2066
- const task = conn.tasks.get(taskId);
2067
- if (!task) {
2068
- throw new Error(`Task "${taskId}" not found on profile "${profileName}"`);
2308
+ // RAM miss → rehydrate from disk for this profile.
2309
+ const rehydrated = await this.rehydrateTaskFromDisk(taskId, profileName);
2310
+ if (rehydrated) {
2311
+ await this.touchTask(rehydrated.conn, rehydrated.task);
2312
+ return rehydrated;
2069
2313
  }
2070
- await this.touchTask(conn, task);
2071
- return { conn, task, profileName };
2314
+ throw new Error(actionable(`Task "${taskId}" not found on profile "${profileName}".`, `Next: agents browser status --profile ${profileName}`));
2072
2315
  }
2073
2316
  for (const [key, conn] of this.connections) {
2074
- const task = conn.tasks.get(taskId);
2317
+ const task = this.lookupTaskOnConn(conn, taskId);
2075
2318
  if (task) {
2076
2319
  await this.touchTask(conn, task);
2077
2320
  return { conn, task, profileName: conn.profileName ?? key };
2078
2321
  }
2079
2322
  }
2080
- throw new Error(`Task "${taskId}" not found`);
2323
+ // RAM miss after a daemon restart: tasks.json still has the task and
2324
+ // meta.json still has the browser pid/port. Reconnect and adopt.
2325
+ const rehydrated = await this.rehydrateTaskFromDisk(taskId);
2326
+ if (rehydrated) {
2327
+ await this.touchTask(rehydrated.conn, rehydrated.task);
2328
+ return rehydrated;
2329
+ }
2330
+ const live = this.listTasks()
2331
+ .map(({ task }) => task.label ?? task.name)
2332
+ .join(', ');
2333
+ 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>`));
2334
+ }
2335
+ /**
2336
+ * Soft-attach to an already-running browser for a runtime dir.
2337
+ *
2338
+ * Never launches a browser and never clears pid/port files on failure —
2339
+ * `connectProfile` does both, which made `status()` wipe disk state when
2340
+ * CDP was unreachable (CI / post-reaper) and then return an empty list.
2341
+ * Returns null when nothing is speaking CDP so callers can fall through
2342
+ * to disk reconcile.
2343
+ */
2344
+ async attachRunningProfile(dirName, diskTasks) {
2345
+ const bare = dirName.includes('@') ? dirName.split('@')[0] : dirName;
2346
+ const endpointFromKey = dirName.includes('@')
2347
+ ? dirName.slice(dirName.indexOf('@') + 1).split('.')[0]
2348
+ : undefined;
2349
+ const profile = await getProfile(bare);
2350
+ if (!profile)
2351
+ return null;
2352
+ let resolved;
2353
+ try {
2354
+ resolved = resolveEndpoint(profile, endpointFromKey);
2355
+ }
2356
+ catch {
2357
+ return null;
2358
+ }
2359
+ const existingInfo = getRunningChromeInfo(dirName);
2360
+ const parsed = parseEndpointUrl(resolved.target);
2361
+ const port = existingInfo?.port ?? parsed?.port;
2362
+ if (port === undefined)
2363
+ return null;
2364
+ const host = parsed?.host && parsed.host !== 'localhost' ? parsed.host : 'localhost';
2365
+ // ssh:// endpoints need a tunnel; soft rehydrate only handles local CDP.
2366
+ if (resolved.target.startsWith('ssh:'))
2367
+ return null;
2368
+ try {
2369
+ const { wsUrl, browser } = await discoverBrowserWsUrl(port, host, dirName);
2370
+ verifyBrowserIdentity(browser, profile.browser, port, host);
2371
+ const cdp = new CDPClient();
2372
+ await cdp.connect(wsUrl);
2373
+ await this.enableDomains(cdp);
2374
+ const tasks = this.loadTaskState(dirName);
2375
+ for (const [k, t] of diskTasks) {
2376
+ if (!tasks.has(k))
2377
+ tasks.set(k, t);
2378
+ }
2379
+ const conn = {
2380
+ cdp,
2381
+ port,
2382
+ pid: existingInfo?.pid ?? 0,
2383
+ electron: profile.electron,
2384
+ browserType: profile.browser,
2385
+ targetFilter: resolved.targetFilter ?? profile.targetFilter,
2386
+ profileName: dirName,
2387
+ bareName: bare,
2388
+ tasks,
2389
+ sessionCache: new Map(),
2390
+ };
2391
+ return conn;
2392
+ }
2393
+ catch {
2394
+ return null;
2395
+ }
2396
+ }
2397
+ /**
2398
+ * Reconnect every profile runtime dir that still has a live browser and
2399
+ * tasks.json entries. Used before identity-based resolution so a daemon
2400
+ * restart does not make the caller's tasks invisible.
2401
+ */
2402
+ async rehydrateAllFromDisk() {
2403
+ const runtimeRoot = getBrowserRuntimeDir();
2404
+ let dirNames = [];
2405
+ try {
2406
+ dirNames = fs.readdirSync(runtimeRoot).filter((d) => {
2407
+ try {
2408
+ return fs.statSync(path.join(runtimeRoot, d)).isDirectory();
2409
+ }
2410
+ catch {
2411
+ return false;
2412
+ }
2413
+ });
2414
+ }
2415
+ catch {
2416
+ return;
2417
+ }
2418
+ for (const dirName of dirNames) {
2419
+ if (this.connections.has(dirName))
2420
+ continue;
2421
+ // Skip non-runtime dirs (e.g. profiles/)
2422
+ if (dirName === 'profiles' || dirName === 'sessions' || dirName === 'exports')
2423
+ continue;
2424
+ const tasks = this.loadTaskState(dirName);
2425
+ if (tasks.size === 0)
2426
+ continue;
2427
+ // Soft attach only — never launch / never clear pid files.
2428
+ const conn = await this.attachRunningProfile(dirName, tasks);
2429
+ if (!conn)
2430
+ continue;
2431
+ this.connections.set(dirName, conn);
2432
+ try {
2433
+ await this.applyDefaultDownloadBehavior(conn, dirName);
2434
+ }
2435
+ catch {
2436
+ // Non-fatal for rehydrate.
2437
+ }
2438
+ }
2439
+ }
2440
+ /**
2441
+ * On a RAM miss, scan profile runtime dirs for a tasks.json entry matching
2442
+ * `taskId`, soft-attach when CDP is still up, and register the connection.
2443
+ * Does not launch browsers or clear runtime files.
2444
+ */
2445
+ async rehydrateTaskFromDisk(taskId, profileHint) {
2446
+ const runtimeRoot = getBrowserRuntimeDir();
2447
+ let dirNames = [];
2448
+ try {
2449
+ dirNames = fs.readdirSync(runtimeRoot).filter((d) => {
2450
+ try {
2451
+ return fs.statSync(path.join(runtimeRoot, d)).isDirectory();
2452
+ }
2453
+ catch {
2454
+ return false;
2455
+ }
2456
+ });
2457
+ }
2458
+ catch {
2459
+ return null;
2460
+ }
2461
+ if (profileHint) {
2462
+ dirNames = dirNames.filter((d) => d === profileHint || connectionKeyMatchesProfile(d, profileHint));
2463
+ }
2464
+ for (const dirName of dirNames) {
2465
+ if (dirName === 'profiles' || dirName === 'sessions' || dirName === 'exports')
2466
+ continue;
2467
+ const tasks = this.loadTaskState(dirName);
2468
+ let found;
2469
+ for (const task of tasks.values()) {
2470
+ if (task.id === taskId || task.name === taskId) {
2471
+ found = task;
2472
+ break;
2473
+ }
2474
+ }
2475
+ // Also allow map-key match
2476
+ if (!found)
2477
+ found = tasks.get(taskId);
2478
+ if (!found)
2479
+ continue;
2480
+ // Already connected under this key?
2481
+ let conn = this.connections.get(dirName);
2482
+ if (!conn) {
2483
+ const attached = await this.attachRunningProfile(dirName, tasks);
2484
+ if (!attached) {
2485
+ // CDP down — cannot rehydrate a live connection; caller will error.
2486
+ continue;
2487
+ }
2488
+ conn = attached;
2489
+ this.connections.set(dirName, conn);
2490
+ try {
2491
+ await this.applyDefaultDownloadBehavior(conn, dirName);
2492
+ }
2493
+ catch {
2494
+ // Non-fatal.
2495
+ }
2496
+ }
2497
+ const task = this.lookupTaskOnConn(conn, taskId) ?? found;
2498
+ // Ensure the rehydrated task is on the connection map.
2499
+ if (!this.lookupTaskOnConn(conn, task.name)) {
2500
+ conn.tasks.set(task.name, task);
2501
+ }
2502
+ return { conn, task, profileName: conn.profileName ?? dirName };
2503
+ }
2504
+ return null;
2081
2505
  }
2082
2506
  async getTabsForTask(cdp, task) {
2083
2507
  const targets = (await cdp.send('Target.getTargets'));
@@ -2096,7 +2520,19 @@ export class BrowserService {
2096
2520
  return tabs;
2097
2521
  }
2098
2522
  async getProfileStatus(profileName) {
2099
- const conn = this.connections.get(profileName);
2523
+ // Exact composite key first; bare name falls through connectionKeyMatches.
2524
+ let conn = this.connections.get(profileName);
2525
+ let resolvedKey = profileName;
2526
+ if (!conn) {
2527
+ for (const [key, c] of this.connections) {
2528
+ if (connectionKeyMatchesProfile(key, profileName) ||
2529
+ c.bareName === profileName) {
2530
+ conn = c;
2531
+ resolvedKey = key;
2532
+ break;
2533
+ }
2534
+ }
2535
+ }
2100
2536
  if (!conn)
2101
2537
  return null;
2102
2538
  // Fetch all targets once for efficiency
@@ -2134,6 +2570,7 @@ export class BrowserService {
2134
2570
  tasks.push({
2135
2571
  id: task.id,
2136
2572
  name: task.name,
2573
+ label: task.label ?? task.name,
2137
2574
  tabCount: Object.keys(task.tabs).length,
2138
2575
  currentTabId: task.currentTabId,
2139
2576
  createdAt: task.createdAt,
@@ -2141,10 +2578,11 @@ export class BrowserService {
2141
2578
  domains: domainSet.size > 0 ? Array.from(domainSet) : undefined,
2142
2579
  });
2143
2580
  }
2144
- const profile = await getProfile(profileName);
2581
+ const bare = conn.bareName ?? (resolvedKey.includes('@') ? resolvedKey.split('@')[0] : resolvedKey);
2582
+ const profile = await getProfile(bare);
2145
2583
  const configuredPort = profile ? extractConfiguredPort(profile) : undefined;
2146
2584
  return {
2147
- name: profileName,
2585
+ name: resolvedKey,
2148
2586
  running: true,
2149
2587
  port: conn.port,
2150
2588
  pid: conn.pid,