@phnx-labs/agents-cli 1.22.41 → 1.22.43

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 (253) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +10 -4
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.js +25 -7
  5. package/dist/cli/command-registry.d.ts +2 -3
  6. package/dist/cli/command-registry.js +4 -8
  7. package/dist/commands/accounts.d.ts +29 -0
  8. package/dist/commands/accounts.js +220 -29
  9. package/dist/commands/alias.d.ts +7 -4
  10. package/dist/commands/alias.js +34 -9
  11. package/dist/commands/auth.d.ts +9 -0
  12. package/dist/commands/auth.js +108 -0
  13. package/dist/commands/browser-sessions-picker.js +42 -62
  14. package/dist/commands/browser.js +30 -38
  15. package/dist/commands/computer-actions.d.ts +1 -1
  16. package/dist/commands/computer-actions.js +1 -1
  17. package/dist/commands/computer-sessions-picker.js +32 -55
  18. package/dist/commands/computer.d.ts +1 -1
  19. package/dist/commands/computer.js +22 -8
  20. package/dist/commands/daemon.js +1 -1
  21. package/dist/commands/doctor.d.ts +5 -3
  22. package/dist/commands/doctor.js +23 -8
  23. package/dist/commands/exec.js +3 -2
  24. package/dist/commands/feed.js +2 -31
  25. package/dist/commands/harness.js +3 -3
  26. package/dist/commands/hooks.js +1 -1
  27. package/dist/commands/import.js +1 -1
  28. package/dist/commands/insights.js +163 -85
  29. package/dist/commands/inspect.js +2 -2
  30. package/dist/commands/mine.js +1 -1
  31. package/dist/commands/monitors.js +1 -1
  32. package/dist/commands/org.d.ts +6 -0
  33. package/dist/commands/org.js +175 -0
  34. package/dist/commands/packages.js +1 -1
  35. package/dist/commands/profiles.js +2 -2
  36. package/dist/commands/prune.js +1 -1
  37. package/dist/commands/routines.js +44 -26
  38. package/dist/commands/run-account-picker.d.ts +19 -0
  39. package/dist/commands/run-account-picker.js +81 -0
  40. package/dist/commands/sessions-picker-factory.d.ts +40 -0
  41. package/dist/commands/sessions-picker-factory.js +67 -0
  42. package/dist/commands/sessions-picker.js +124 -122
  43. package/dist/commands/setup-browser.js +4 -4
  44. package/dist/commands/setup-mine.js +1 -1
  45. package/dist/commands/setup-preferences.js +2 -2
  46. package/dist/commands/setup.js +10 -4
  47. package/dist/commands/snapshot.d.ts +1 -1
  48. package/dist/commands/snapshot.js +4 -4
  49. package/dist/commands/status.d.ts +4 -2
  50. package/dist/commands/status.js +10 -7
  51. package/dist/commands/sync.d.ts +1 -0
  52. package/dist/commands/sync.js +30 -3
  53. package/dist/commands/versions.js +1 -1
  54. package/dist/commands/view.js +7 -1
  55. package/dist/commands/webhook.js +1 -1
  56. package/dist/lib/account-capabilities.d.ts +10 -0
  57. package/dist/lib/account-capabilities.js +34 -0
  58. package/dist/lib/accounting/rotate.d.ts +5 -3
  59. package/dist/lib/accounting/rotate.js +36 -7
  60. package/dist/lib/accounting/usage.d.ts +18 -4
  61. package/dist/lib/accounting/usage.js +138 -27
  62. package/dist/lib/agent-spec/agents.d.ts +584 -0
  63. package/dist/lib/agent-spec/agents.js +3127 -0
  64. package/dist/lib/agent-spec/provider.js +1 -1
  65. package/dist/lib/agents.d.ts +2 -584
  66. package/dist/lib/agents.js +2 -3127
  67. package/dist/lib/browser/drivers/local.d.ts +8 -2
  68. package/dist/lib/browser/drivers/local.js +8 -2
  69. package/dist/lib/browser/drivers/ssh.d.ts +8 -2
  70. package/dist/lib/browser/drivers/ssh.js +10 -4
  71. package/dist/lib/browser/hygiene.d.ts +1 -1
  72. package/dist/lib/browser/hygiene.js +5 -1
  73. package/dist/lib/browser/profiles.d.ts +74 -1
  74. package/dist/lib/browser/profiles.js +114 -5
  75. package/dist/lib/browser/runtime-state.d.ts +11 -5
  76. package/dist/lib/browser/runtime-state.js +13 -9
  77. package/dist/lib/browser/service.d.ts +68 -30
  78. package/dist/lib/browser/service.js +305 -194
  79. package/dist/lib/browser/types.d.ts +95 -3
  80. package/dist/lib/browser/types.js +51 -0
  81. package/dist/lib/catchup.js +1 -1
  82. package/dist/lib/cloud/rush.d.ts +0 -15
  83. package/dist/lib/cloud/rush.js +0 -35
  84. package/dist/lib/computer/actions.d.ts +1 -1
  85. package/dist/lib/computer/actions.js +1 -1
  86. package/dist/lib/{computer-rpc.js → computer/computer-rpc.js} +5 -5
  87. package/dist/lib/computer/dispatch.d.ts +1 -1
  88. package/dist/lib/computer/download.d.ts +1 -1
  89. package/dist/lib/computer/download.js +3 -3
  90. package/dist/lib/{ssh-tunnel.d.ts → computer/ssh-tunnel.d.ts} +1 -1
  91. package/dist/lib/{ssh-tunnel.js → computer/ssh-tunnel.js} +12 -12
  92. package/dist/lib/crabbox/runtimes.d.ts +6 -2
  93. package/dist/lib/crabbox/runtimes.js +21 -5
  94. package/dist/lib/daemon/daemon.js +87 -59
  95. package/dist/lib/{runner.d.ts → daemon/runner.d.ts} +28 -11
  96. package/dist/lib/{runner.js → daemon/runner.js} +143 -123
  97. package/dist/lib/devices/doctor-findings.d.ts +1 -1
  98. package/dist/lib/devices/doctor-findings.js +4 -4
  99. package/dist/lib/devices/fleet-inventory.js +1 -1
  100. package/dist/lib/devices/harness-inventory.js +1 -1
  101. package/dist/lib/devices/health-report.js +1 -1
  102. package/dist/lib/devices/registry.js +4 -22
  103. package/dist/lib/doctor-diff.d.ts +1 -1
  104. package/dist/lib/doctor-diff.js +1 -1
  105. package/dist/lib/drift-sync.d.ts +1 -1
  106. package/dist/lib/drift-sync.js +2 -2
  107. package/dist/lib/drift.d.ts +1 -1
  108. package/dist/lib/drift.js +1 -1
  109. package/dist/lib/entitlement.d.ts +31 -0
  110. package/dist/lib/entitlement.js +137 -0
  111. package/dist/lib/exec.js +52 -205
  112. package/dist/lib/feed/feed.js +2 -8
  113. package/dist/lib/format.d.ts +9 -0
  114. package/dist/lib/format.js +16 -0
  115. package/dist/lib/fs-atomic.d.ts +7 -0
  116. package/dist/lib/fs-atomic.js +9 -0
  117. package/dist/lib/github/pr-mergeable.d.ts +49 -0
  118. package/dist/lib/github/pr-mergeable.js +157 -0
  119. package/dist/lib/github/pr-verdict.d.ts +67 -0
  120. package/dist/lib/github/pr-verdict.js +72 -0
  121. package/dist/lib/harness/adapter.d.ts +161 -0
  122. package/dist/lib/harness/adapter.js +47 -0
  123. package/dist/lib/harness/adapters/claude.d.ts +2 -0
  124. package/dist/lib/harness/adapters/claude.js +110 -0
  125. package/dist/lib/harness/adapters/codex.d.ts +2 -0
  126. package/dist/lib/harness/adapters/codex.js +83 -0
  127. package/dist/lib/harness/adapters/copilot.d.ts +2 -0
  128. package/dist/lib/harness/adapters/copilot.js +23 -0
  129. package/dist/lib/harness/adapters/cursor.d.ts +2 -0
  130. package/dist/lib/harness/adapters/cursor.js +38 -0
  131. package/dist/lib/harness/adapters/droid.d.ts +2 -0
  132. package/dist/lib/harness/adapters/droid.js +17 -0
  133. package/dist/lib/harness/adapters/grok.d.ts +2 -0
  134. package/dist/lib/harness/adapters/grok.js +14 -0
  135. package/dist/lib/harness/adapters/kimi.d.ts +2 -0
  136. package/dist/lib/harness/adapters/kimi.js +49 -0
  137. package/dist/lib/harness/adapters/muse.d.ts +2 -0
  138. package/dist/lib/harness/adapters/muse.js +44 -0
  139. package/dist/lib/harness/adapters/opencode.d.ts +2 -0
  140. package/dist/lib/harness/adapters/opencode.js +14 -0
  141. package/dist/lib/harness/exec-config-version.d.ts +8 -0
  142. package/dist/lib/harness/exec-config-version.js +22 -0
  143. package/dist/lib/harness/index.d.ts +1 -0
  144. package/dist/lib/harness/index.js +34 -0
  145. package/dist/lib/{hooks.d.ts → hooks/install.d.ts} +1 -1
  146. package/dist/lib/{hooks.js → hooks/install.js} +11 -11
  147. package/dist/lib/hosts/passthrough.d.ts +10 -0
  148. package/dist/lib/hosts/passthrough.js +28 -6
  149. package/dist/lib/hosts/session-index.js +1 -1
  150. package/dist/lib/import.js +1 -1
  151. package/dist/lib/installations/index.d.ts +4 -4
  152. package/dist/lib/installations/index.js +3 -4
  153. package/dist/lib/installations/migrate.js +6 -6
  154. package/dist/lib/{shims.d.ts → installations/shims.d.ts} +2 -2
  155. package/dist/lib/{shims.js → installations/shims.js} +13 -115
  156. package/dist/lib/installations/store.d.ts +141 -3
  157. package/dist/lib/installations/store.js +475 -5
  158. package/dist/lib/installations/versions.d.ts +40 -125
  159. package/dist/lib/installations/versions.js +57 -462
  160. package/dist/lib/isolation-boundary-report.d.ts +1 -1
  161. package/dist/lib/isolation-boundary-report.js +1 -1
  162. package/dist/lib/mailbox-gc.js +2 -3
  163. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  164. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  165. package/dist/lib/menubar/install-menubar.js +19 -8
  166. package/dist/lib/monitors/config.d.ts +2 -2
  167. package/dist/lib/monitors/config.js +3 -2
  168. package/dist/lib/monitors/dispatch.d.ts +1 -1
  169. package/dist/lib/monitors/dispatch.js +2 -2
  170. package/dist/lib/monitors/state.d.ts +1 -1
  171. package/dist/lib/origin-machine.d.ts +18 -0
  172. package/dist/lib/origin-machine.js +34 -0
  173. package/dist/lib/perf/db.js +1 -1
  174. package/dist/lib/perf/spool.js +1 -1
  175. package/dist/lib/plugins/plugins.js +1 -1
  176. package/dist/lib/plugins/skills.js +1 -1
  177. package/dist/lib/prix-account.d.ts +158 -0
  178. package/dist/lib/prix-account.js +214 -0
  179. package/dist/lib/profiles.d.ts +7 -0
  180. package/dist/lib/profiles.js +26 -1
  181. package/dist/lib/project-key.js +2 -2
  182. package/dist/lib/project-launch.js +1 -1
  183. package/dist/lib/refresh.js +2 -2
  184. package/dist/lib/resource-inventory.d.ts +1 -1
  185. package/dist/lib/resource-inventory.js +1 -1
  186. package/dist/lib/rules/rules.js +1 -1
  187. package/dist/lib/sandbox.d.ts +24 -0
  188. package/dist/lib/sandbox.js +101 -0
  189. package/dist/lib/scheduling/routines.d.ts +18 -9
  190. package/dist/lib/scheduling/routines.js +17 -9
  191. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  192. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  193. package/dist/lib/secrets/agent.js +9 -1
  194. package/dist/lib/secrets/index.js +1 -1
  195. package/dist/lib/secrets/list-filter.js +1 -1
  196. package/dist/lib/self-heal/checks/hook-runtime.js +1 -1
  197. package/dist/lib/self-heal/checks/path.js +1 -1
  198. package/dist/lib/self-heal/checks/shadowing.js +1 -1
  199. package/dist/lib/self-heal/checks/shims.js +1 -1
  200. package/dist/lib/service-manifest.d.ts +20 -0
  201. package/dist/lib/service-manifest.js +34 -0
  202. package/dist/lib/session/cloud.js +1 -1
  203. package/dist/lib/session/db.js +1 -1
  204. package/dist/lib/session/discover.d.ts +39 -0
  205. package/dist/lib/session/discover.js +3 -3
  206. package/dist/lib/session/fork.js +1 -1
  207. package/dist/lib/session/live-metadata.js +1 -1
  208. package/dist/lib/session/origin-machine.d.ts +1 -18
  209. package/dist/lib/session/origin-machine.js +4 -34
  210. package/dist/lib/session/parse.js +24 -42
  211. package/dist/lib/session/recovery.js +1 -1
  212. package/dist/lib/session/relative-time.d.ts +1 -44
  213. package/dist/lib/session/relative-time.js +4 -120
  214. package/dist/lib/session/remote-list.js +1 -1
  215. package/dist/lib/session/remote.js +2 -2
  216. package/dist/lib/session/short-id.d.ts +1 -17
  217. package/dist/lib/session/short-id.js +4 -20
  218. package/dist/lib/session/width.d.ts +1 -29
  219. package/dist/lib/session/width.js +4 -101
  220. package/dist/lib/snapshot.d.ts +2 -2
  221. package/dist/lib/snapshot.js +1 -1
  222. package/dist/lib/staleness/prune.d.ts +1 -1
  223. package/dist/lib/staleness/prune.js +1 -1
  224. package/dist/lib/staleness/writers/hooks.js +1 -1
  225. package/dist/lib/startup/command-registry.d.ts +4 -1
  226. package/dist/lib/startup/command-registry.js +12 -5
  227. package/dist/lib/teams/agents.js +2 -19
  228. package/dist/lib/teams/parsers.js +20 -26
  229. package/dist/lib/teams/placement-probe.js +1 -1
  230. package/dist/lib/teams/registry.js +2 -21
  231. package/dist/lib/teams/scheduler.js +1 -1
  232. package/dist/lib/text/relative-time.d.ts +44 -0
  233. package/dist/lib/text/relative-time.js +120 -0
  234. package/dist/lib/text/short-id.d.ts +17 -0
  235. package/dist/lib/text/short-id.js +20 -0
  236. package/dist/lib/text/width.d.ts +29 -0
  237. package/dist/lib/text/width.js +101 -0
  238. package/dist/lib/triggers/handlers.d.ts +7 -0
  239. package/dist/lib/triggers/handlers.js +9 -1
  240. package/dist/lib/triggers/webhook.d.ts +1 -0
  241. package/dist/lib/triggers/webhook.js +3 -2
  242. package/dist/lib/uninstall.js +1 -1
  243. package/dist/lib/version.d.ts +9 -2
  244. package/dist/lib/version.js +11 -9
  245. package/dist/lib/view-types.d.ts +4 -0
  246. package/package.json +1 -1
  247. package/dist/commands/tickets.d.ts +0 -2
  248. package/dist/commands/tickets.js +0 -43
  249. package/dist/lib/observe-aliases.d.ts +0 -30
  250. package/dist/lib/observe-aliases.js +0 -38
  251. package/dist/lib/tickets/list.d.ts +0 -53
  252. package/dist/lib/tickets/list.js +0 -153
  253. /package/dist/lib/{computer-rpc.d.ts → computer/computer-rpc.d.ts} +0 -0
@@ -1,8 +1,14 @@
1
1
  import { CDPClient } from '../cdp.js';
2
- import type { BrowserProfile } from '../types.js';
2
+ import type { BrowserProfile, ConnectionKey } from '../types.js';
3
3
  export interface LocalConnection {
4
4
  cdp: CDPClient;
5
5
  port: number;
6
6
  pid: number;
7
7
  }
8
- export declare function connectLocal(endpoint: string, profile: BrowserProfile): Promise<LocalConnection>;
8
+ export declare function connectLocal(endpoint: string, profile: BrowserProfile,
9
+ /**
10
+ * Runtime key (`<profile>@<endpoint>`) the launched browser's user-data-dir,
11
+ * pid, and port files are stored under. Separate from `profile.name`, which
12
+ * stays the bare user-facing name and appears only in messages (RUSH-2709).
13
+ */
14
+ key: ConnectionKey): Promise<LocalConnection>;
@@ -31,7 +31,13 @@ const TUNNEL_PROCESS_NAMES = new Set(['ssh', 'autossh', 'mosh-client', 'socat'])
31
31
  function isTunnelProcess(command) {
32
32
  return TUNNEL_PROCESS_NAMES.has(command.toLowerCase());
33
33
  }
34
- export async function connectLocal(endpoint, profile) {
34
+ export async function connectLocal(endpoint, profile,
35
+ /**
36
+ * Runtime key (`<profile>@<endpoint>`) the launched browser's user-data-dir,
37
+ * pid, and port files are stored under. Separate from `profile.name`, which
38
+ * stays the bare user-facing name and appears only in messages (RUSH-2709).
39
+ */
40
+ key) {
35
41
  const url = new URL(endpoint);
36
42
  if (url.protocol !== 'cdp:') {
37
43
  throw new Error(`Invalid local endpoint: ${endpoint}`);
@@ -91,7 +97,7 @@ export async function connectLocal(endpoint, profile) {
91
97
  const chromeOpts = { ...profile.chrome, viewport: profile.viewport };
92
98
  let launched;
93
99
  try {
94
- launched = await launchBrowser(profile.name, profile.browser, newPort, chromeOpts, profile.secrets, profile.binary, profile.electron === true);
100
+ launched = await launchBrowser(key, profile.browser, newPort, chromeOpts, profile.secrets, profile.binary, profile.electron === true);
95
101
  }
96
102
  catch (launchErr) {
97
103
  const reason = launchErr instanceof Error ? launchErr.message : String(launchErr);
@@ -1,5 +1,5 @@
1
1
  import { CDPClient } from '../cdp.js';
2
- import type { BrowserProfile } from '../types.js';
2
+ import type { BrowserProfile, ConnectionKey } from '../types.js';
3
3
  import { shellQuote } from '../../ssh-exec.js';
4
4
  export { shellQuote };
5
5
  export interface SSHConnection {
@@ -16,7 +16,13 @@ export interface SSHConnection {
16
16
  * strings differ (no `&` backgrounding, no `lsof`, `.exe` instead of `.app`).
17
17
  */
18
18
  export type RemoteOs = 'windows' | 'posix';
19
- export declare function connectSSH(endpoint: string, profile: BrowserProfile): Promise<SSHConnection>;
19
+ export declare function connectSSH(endpoint: string, profile: BrowserProfile,
20
+ /**
21
+ * Runtime key (`<profile>@<endpoint>`) this connection is stored under. It
22
+ * keys the tunnel's runtime record; `profile.name` is the bare, user-facing
23
+ * name and appears only in messages (RUSH-2709).
24
+ */
25
+ key: ConnectionKey): Promise<SSHConnection>;
20
26
  /**
21
27
  * Wrap a PowerShell script as a `-EncodedCommand` invocation. Base64 of the
22
28
  * UTF-16LE bytes is a single quote-free token, so it rides through Node spawn
@@ -11,9 +11,15 @@ export { shellQuote };
11
11
  // The `ssh -L` tunnel spawn is shared with `agents computer --device`; it lives in
12
12
  // the single ssh-tunnel helper. Calling it with no options preserves this
13
13
  // driver's original foreground, stderr-captured behavior exactly.
14
- import { startSSHTunnel } from '../../ssh-tunnel.js';
14
+ import { startSSHTunnel } from '../../computer/ssh-tunnel.js';
15
15
  import { encodePwshBase64 } from '../../pwsh.js';
16
- export async function connectSSH(endpoint, profile) {
16
+ export async function connectSSH(endpoint, profile,
17
+ /**
18
+ * Runtime key (`<profile>@<endpoint>`) this connection is stored under. It
19
+ * keys the tunnel's runtime record; `profile.name` is the bare, user-facing
20
+ * name and appears only in messages (RUSH-2709).
21
+ */
22
+ key) {
17
23
  const url = new URL(endpoint);
18
24
  if (url.protocol !== 'ssh:') {
19
25
  throw new Error(`Invalid SSH endpoint: ${endpoint}`);
@@ -88,7 +94,7 @@ export async function connectSSH(endpoint, profile) {
88
94
  // browser process.
89
95
  const tunnelPid = tunnel.pid ?? 0;
90
96
  if (tunnelPid > 0) {
91
- writeProfileRuntime(profile.name, {
97
+ writeProfileRuntime(key, {
92
98
  pid: 0,
93
99
  port: localPort,
94
100
  command: 'ssh',
@@ -108,7 +114,7 @@ export async function connectSSH(endpoint, profile) {
108
114
  // stays synchronous, and killRemoteBrowser never rejects.
109
115
  killRemoteBrowser(user, host, remoteOs, remotePort).catch(() => { });
110
116
  tunnel.kill();
111
- clearProfileRuntime(profile.name);
117
+ clearProfileRuntime(key);
112
118
  },
113
119
  };
114
120
  }
@@ -1,5 +1,5 @@
1
1
  import { type PidSessionEntry } from '../session/pid-registry.js';
2
- import type { ReapResult, Task } from './types.js';
2
+ import { type ReapResult, type Task } from './types.js';
3
3
  /** Default idle window before an untouched task is reaped. */
4
4
  export declare const DEFAULT_IDLE_MS: number;
5
5
  /**
@@ -28,6 +28,7 @@
28
28
  */
29
29
  import { isPidAlive, isSessionIdLiveOnProcessTable } from '../session/active.js';
30
30
  import { listPidSessionEntries, sessionIdFromLivePid } from '../session/pid-registry.js';
31
+ import { parseConnectionKey } from './types.js';
31
32
  /** Default idle window before an untouched task is reaped. */
32
33
  export const DEFAULT_IDLE_MS = 30 * 60_000;
33
34
  /**
@@ -131,7 +132,10 @@ export async function reapAbandonedTasks(service, opts = {}) {
131
132
  continue;
132
133
  }
133
134
  if (opts.dryRun) {
134
- closed.push({ task: task.name, profile, reason });
135
+ // Report the BARE profile, exactly as the real run does below — `profile`
136
+ // here is the runtime key from `listTasks()`, and printing the two shapes
137
+ // in one column made `gc --dry-run` and `gc` disagree (RUSH-2709).
138
+ closed.push({ task: task.name, profile: parseConnectionKey(profile).profile, reason });
135
139
  continue;
136
140
  }
137
141
  const result = await service.stop(task.name);
@@ -1,6 +1,30 @@
1
1
  import type { BrowserProfile } from './types.js';
2
2
  export type { BrowserProfile } from './types.js';
3
- export declare const DEFAULT_BROWSER_PROFILE_NAME = "default";
3
+ /**
4
+ * Name of the profile `ensureDefaultBrowserProfile` auto-detects and pins.
5
+ *
6
+ * It is `auto-chrome`, NOT `default`, since RUSH-2709: `default` used to be
7
+ * both this concrete profile AND the alias meaning "whatever profile the user
8
+ * configured", so `--profile default` landed on a literal auto-detected Chrome
9
+ * on one command and on the user's configured Comet on another. The alias now
10
+ * lives alone in {@link DEFAULT_PROFILE_ALIAS} and resolves in exactly one
11
+ * place ({@link resolveProfileRef}).
12
+ */
13
+ export declare const DEFAULT_BROWSER_PROFILE_NAME = "auto-chrome";
14
+ /**
15
+ * What older builds named the auto-detected profile. Still honored everywhere:
16
+ * a user whose machine already carries a `default` profile keeps using it (and
17
+ * its running browser + runtime dirs) rather than having a second one created
18
+ * beside it.
19
+ */
20
+ export declare const LEGACY_DEFAULT_BROWSER_PROFILE_NAME = "default";
21
+ /**
22
+ * The reserved ALIAS. `--profile default` (and a `browser.profile` config value
23
+ * of `default`) means "the configured default profile", not a profile called
24
+ * `default` — unless a profile literally named `default` exists, which still
25
+ * wins, so no existing config breaks.
26
+ */
27
+ export declare const DEFAULT_PROFILE_ALIAS = "default";
4
28
  /**
5
29
  * Where a profile is stored, and therefore who sees it:
6
30
  * - `local` — this machine's `devices/<machine>/agents.yaml` (`deviceBrowser`)
@@ -75,6 +99,55 @@ export declare function isProfileLaunchableHere(profile: BrowserProfile): boolea
75
99
  * that no longer exists, or can't launch here, warns and falls through — never a
76
100
  * hard fail.
77
101
  */
102
+ /**
103
+ * The auto-detected profile this machine already carries, under either name —
104
+ * the current `auto-chrome` or the `default` an older build wrote. Callers that
105
+ * ask "is a default profile set up here?" MUST use this rather than probing one
106
+ * name, or a machine that predates the RUSH-2709 rename grows a second one.
107
+ */
108
+ export declare function getAutoDetectedProfile(): Promise<BrowserProfile | null>;
109
+ /**
110
+ * Resolve what a caller typed after `--profile` to a real, BARE profile name.
111
+ * Every command — stop, status, navigate, tab, use, and (through
112
+ * {@link resolveProfileRefForStart}) start — routes through this one function,
113
+ * which is the whole point: before RUSH-2709 only `start` honored the reserved
114
+ * `default` alias, so `--profile default` meant three different profiles across
115
+ * three commands.
116
+ *
117
+ * Order:
118
+ * 1. A profile that literally bears the given name always wins — including
119
+ * one a user genuinely named `default`, which resolves to itself.
120
+ * 2. `default` (the alias) or no argument at all → the configured
121
+ * `browser.profile` for this machine, if it names a profile that exists.
122
+ * 3. → the auto-detected profile ({@link DEFAULT_BROWSER_PROFILE_NAME}), or
123
+ * its legacy `default`-named predecessor when that is what is on disk.
124
+ * 4. Otherwise the input is returned unchanged (so the caller reports its own
125
+ * `Profile "x" not found`), or `undefined` when nothing was passed.
126
+ *
127
+ * It never creates a profile, never warns, and never checks whether the profile
128
+ * can launch HERE. That is deliberate: for most callers `--profile` is a FILTER
129
+ * (`status`, `tasks`, `navigate --task`), where an absent flag means "no filter"
130
+ * and rewriting or warning about the user's config would be wrong. Note the
131
+ * corollary at those call sites — pass a ref only when the user gave one; do not
132
+ * resolve `undefined` into a concrete profile, or an unscoped listing silently
133
+ * becomes a scoped one.
134
+ */
135
+ export declare function resolveProfileRef(ref?: string): Promise<string | undefined>;
136
+ /**
137
+ * `start`'s resolver. Same order as {@link resolveProfileRef} for an explicit
138
+ * name, but the IMPLICIT path (no `--profile`, or the bare `default` alias with
139
+ * no profile of that name) goes through {@link ensureDefaultBrowserProfile} —
140
+ * which additionally verifies the resolved default can launch on THIS machine,
141
+ * warns and falls through when it can't, and regenerates or creates one.
142
+ *
143
+ * `start` is the only command that launches a browser, so it is the only one
144
+ * that may do those things; routing a filter-only command through this would
145
+ * warn about, and rewrite, config the user never asked it to touch.
146
+ *
147
+ * Throws when no profile exists and no supported browser is installed —
148
+ * `ensureDefaultBrowserProfile`'s actionable "install one of …" error.
149
+ */
150
+ export declare function resolveProfileRefForStart(ref?: string): Promise<string>;
78
151
  export declare function ensureDefaultBrowserProfile(): Promise<BrowserProfile>;
79
152
  /**
80
153
  * Compute the LOCAL port a profile will occupy at runtime:
@@ -3,7 +3,31 @@ import { getBrowserRuntimeDir as getBrowserRuntimeDirRoot, readMeta, updateMeta,
3
3
  import { getConfigValue } from '../device-config.js';
4
4
  import { findBrowserPath, findFirstInstalledBrowser, isPortInUse } from './chrome.js';
5
5
  import { DEFAULT_VIEWPORT } from './devices.js';
6
- export const DEFAULT_BROWSER_PROFILE_NAME = 'default';
6
+ /**
7
+ * Name of the profile `ensureDefaultBrowserProfile` auto-detects and pins.
8
+ *
9
+ * It is `auto-chrome`, NOT `default`, since RUSH-2709: `default` used to be
10
+ * both this concrete profile AND the alias meaning "whatever profile the user
11
+ * configured", so `--profile default` landed on a literal auto-detected Chrome
12
+ * on one command and on the user's configured Comet on another. The alias now
13
+ * lives alone in {@link DEFAULT_PROFILE_ALIAS} and resolves in exactly one
14
+ * place ({@link resolveProfileRef}).
15
+ */
16
+ export const DEFAULT_BROWSER_PROFILE_NAME = 'auto-chrome';
17
+ /**
18
+ * What older builds named the auto-detected profile. Still honored everywhere:
19
+ * a user whose machine already carries a `default` profile keeps using it (and
20
+ * its running browser + runtime dirs) rather than having a second one created
21
+ * beside it.
22
+ */
23
+ export const LEGACY_DEFAULT_BROWSER_PROFILE_NAME = 'default';
24
+ /**
25
+ * The reserved ALIAS. `--profile default` (and a `browser.profile` config value
26
+ * of `default`) means "the configured default profile", not a profile called
27
+ * `default` — unless a profile literally named `default` exists, which still
28
+ * wins, so no existing config breaks.
29
+ */
30
+ export const DEFAULT_PROFILE_ALIAS = 'default';
7
31
  /**
8
32
  * True for a profile whose contents only make sense on THIS machine, so it must
9
33
  * live in the per-machine doc rather than the fleet-synced agents.yaml.
@@ -21,7 +45,7 @@ export const DEFAULT_BROWSER_PROFILE_NAME = 'default';
21
45
  * into central from being written back there by {@link updateProfile}.
22
46
  */
23
47
  function isMachineLocalProfile(name) {
24
- return name === DEFAULT_BROWSER_PROFILE_NAME;
48
+ return name === DEFAULT_BROWSER_PROFILE_NAME || name === LEGACY_DEFAULT_BROWSER_PROFILE_NAME;
25
49
  }
26
50
  /**
27
51
  * The device-local configured default profile name (set via
@@ -178,9 +202,86 @@ export function isProfileLaunchableHere(profile) {
178
202
  * that no longer exists, or can't launch here, warns and falls through — never a
179
203
  * hard fail.
180
204
  */
205
+ /**
206
+ * The auto-detected profile this machine already carries, under either name —
207
+ * the current `auto-chrome` or the `default` an older build wrote. Callers that
208
+ * ask "is a default profile set up here?" MUST use this rather than probing one
209
+ * name, or a machine that predates the RUSH-2709 rename grows a second one.
210
+ */
211
+ export async function getAutoDetectedProfile() {
212
+ return ((await getProfile(DEFAULT_BROWSER_PROFILE_NAME)) ??
213
+ (await getProfile(LEGACY_DEFAULT_BROWSER_PROFILE_NAME)));
214
+ }
215
+ /**
216
+ * Resolve what a caller typed after `--profile` to a real, BARE profile name.
217
+ * Every command — stop, status, navigate, tab, use, and (through
218
+ * {@link resolveProfileRefForStart}) start — routes through this one function,
219
+ * which is the whole point: before RUSH-2709 only `start` honored the reserved
220
+ * `default` alias, so `--profile default` meant three different profiles across
221
+ * three commands.
222
+ *
223
+ * Order:
224
+ * 1. A profile that literally bears the given name always wins — including
225
+ * one a user genuinely named `default`, which resolves to itself.
226
+ * 2. `default` (the alias) or no argument at all → the configured
227
+ * `browser.profile` for this machine, if it names a profile that exists.
228
+ * 3. → the auto-detected profile ({@link DEFAULT_BROWSER_PROFILE_NAME}), or
229
+ * its legacy `default`-named predecessor when that is what is on disk.
230
+ * 4. Otherwise the input is returned unchanged (so the caller reports its own
231
+ * `Profile "x" not found`), or `undefined` when nothing was passed.
232
+ *
233
+ * It never creates a profile, never warns, and never checks whether the profile
234
+ * can launch HERE. That is deliberate: for most callers `--profile` is a FILTER
235
+ * (`status`, `tasks`, `navigate --task`), where an absent flag means "no filter"
236
+ * and rewriting or warning about the user's config would be wrong. Note the
237
+ * corollary at those call sites — pass a ref only when the user gave one; do not
238
+ * resolve `undefined` into a concrete profile, or an unscoped listing silently
239
+ * becomes a scoped one.
240
+ */
241
+ export async function resolveProfileRef(ref) {
242
+ if (ref && ref !== DEFAULT_PROFILE_ALIAS) {
243
+ return ref;
244
+ }
245
+ if (ref === DEFAULT_PROFILE_ALIAS && (await getProfile(ref))) {
246
+ // A profile the user literally named `default` outranks the alias.
247
+ return ref;
248
+ }
249
+ const configured = getConfiguredDefaultProfileName();
250
+ if (configured && configured !== DEFAULT_PROFILE_ALIAS && (await getProfile(configured))) {
251
+ return configured;
252
+ }
253
+ if (await getProfile(DEFAULT_BROWSER_PROFILE_NAME))
254
+ return DEFAULT_BROWSER_PROFILE_NAME;
255
+ if (await getProfile(LEGACY_DEFAULT_BROWSER_PROFILE_NAME)) {
256
+ return LEGACY_DEFAULT_BROWSER_PROFILE_NAME;
257
+ }
258
+ return ref;
259
+ }
260
+ /**
261
+ * `start`'s resolver. Same order as {@link resolveProfileRef} for an explicit
262
+ * name, but the IMPLICIT path (no `--profile`, or the bare `default` alias with
263
+ * no profile of that name) goes through {@link ensureDefaultBrowserProfile} —
264
+ * which additionally verifies the resolved default can launch on THIS machine,
265
+ * warns and falls through when it can't, and regenerates or creates one.
266
+ *
267
+ * `start` is the only command that launches a browser, so it is the only one
268
+ * that may do those things; routing a filter-only command through this would
269
+ * warn about, and rewrite, config the user never asked it to touch.
270
+ *
271
+ * Throws when no profile exists and no supported browser is installed —
272
+ * `ensureDefaultBrowserProfile`'s actionable "install one of …" error.
273
+ */
274
+ export async function resolveProfileRefForStart(ref) {
275
+ if (ref && ref !== DEFAULT_PROFILE_ALIAS)
276
+ return ref;
277
+ // A profile the user literally named `default` still outranks the alias.
278
+ if (ref === DEFAULT_PROFILE_ALIAS && (await getProfile(ref)))
279
+ return ref;
280
+ return (await ensureDefaultBrowserProfile()).name;
281
+ }
181
282
  export async function ensureDefaultBrowserProfile() {
182
283
  const configured = getConfiguredDefaultProfileName();
183
- if (configured) {
284
+ if (configured && configured !== DEFAULT_PROFILE_ALIAS) {
184
285
  const chosen = await getProfile(configured);
185
286
  if (chosen && isProfileLaunchableHere(chosen))
186
287
  return chosen;
@@ -191,7 +292,12 @@ export async function ensureDefaultBrowserProfile() {
191
292
  : `warning: configured default browser profile "${configured}" no longer exists; ` +
192
293
  `falling back to auto-detect. Fix with: agents browser use <name> (or --unset)`);
193
294
  }
194
- const existing = await getProfile(DEFAULT_BROWSER_PROFILE_NAME);
295
+ // Prefer whichever auto-detected profile this machine already carries: the
296
+ // current `auto-chrome`, else the `default` an older build wrote. Reusing the
297
+ // legacy one is what keeps a currently-running browser (and its runtime dirs,
298
+ // keyed `default@endpoint-0`) attached after the rename.
299
+ const existing = (await getProfile(DEFAULT_BROWSER_PROFILE_NAME)) ??
300
+ (await getProfile(LEGACY_DEFAULT_BROWSER_PROFILE_NAME));
195
301
  if (existing && isProfileLaunchableHere(existing))
196
302
  return existing;
197
303
  const detected = findFirstInstalledBrowser();
@@ -204,7 +310,10 @@ export async function ensureDefaultBrowserProfile() {
204
310
  }
205
311
  const freePort = await findFreeProfilePort();
206
312
  const profile = {
207
- name: DEFAULT_BROWSER_PROFILE_NAME,
313
+ // Regenerate under the name that is already on disk when there is one, so a
314
+ // stale legacy `default` is repaired in place instead of leaving the user
315
+ // with two auto-detected profiles.
316
+ name: existing?.name ?? DEFAULT_BROWSER_PROFILE_NAME,
208
317
  description: `Auto-detected ${detected.browserType} profile`,
209
318
  browser: detected.browserType,
210
319
  binary: detected.binary,
@@ -1,4 +1,5 @@
1
1
  import { type ProfileScope } from './profiles.js';
2
+ import { type ProfileName } from './types.js';
2
3
  /**
3
4
  * Per-profile runtime files we persist under
4
5
  * `~/.agents/.cache/browser/<composite>/`:
@@ -55,12 +56,16 @@ export declare function clearProfileRuntime(profileName: string): void;
55
56
  */
56
57
  export declare function removeProfileCache(profileName: string): void;
57
58
  /**
58
- * Find every cache directory belonging to a given profile. The composite
59
- * naming (`<name>@<endpoint>`) means a single agents-cli profile can have
60
- * multiple runtime dirs side by side; this finds them all plus the legacy
59
+ * Find every cache directory belonging to a given profile. A runtime dir name
60
+ * IS a connection key (`<name>@<endpoint>[.<fork>]`), so a single agents-cli
61
+ * profile can have several side by side; this finds them all, plus the legacy
61
62
  * non-composite dir from older builds.
63
+ *
64
+ * Membership is decided by {@link keyBelongsToProfile} — the same single rule
65
+ * `status`, `stopProfile`, and `findTask` use (RUSH-2709), so a fork dir is no
66
+ * longer missed here while being matched there.
62
67
  */
63
- export declare function listProfileCacheDirs(profileName: string): string[];
68
+ export declare function listProfileCacheDirs(profileName: ProfileName): string[];
64
69
  /**
65
70
  * `process.kill(pid, 0)` answers "is a process with this id alive?" — but
66
71
  * pid reuse is real on long-uptime machines, and a stale cache pointing
@@ -162,7 +167,8 @@ export declare const PRUNE_REASON_TEXT: Record<PruneReason, string>;
162
167
  * - **in use** — a live browser, SSH tunnel, or open task on any of its dirs.
163
168
  * - **the configured default** — this machine resolves a bare
164
169
  * `agents browser start` to it; removing it breaks that command.
165
- * - **`default`** auto-regenerated by `ensureDefaultBrowserProfile`, so
170
+ * - **the auto-detected profile** (`auto-chrome`, or the `default` an older
171
+ * build wrote) — auto-regenerated by `ensureDefaultBrowserProfile`, so
166
172
  * pruning it is pure churn.
167
173
  * - **fleet-synced** — deleting one removes it from EVERY machine, so it takes
168
174
  * the explicit `includeFleet` opt-in.
@@ -1,7 +1,8 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { execFileSync } from 'child_process';
4
- import { getProfileRuntimeDir, getBrowserRuntimeDir, listProfilesWithScope, getConfiguredDefaultProfileName, isProfileLaunchableHere, deleteProfile, DEFAULT_BROWSER_PROFILE_NAME, } from './profiles.js';
4
+ import { getProfileRuntimeDir, getBrowserRuntimeDir, listProfilesWithScope, getConfiguredDefaultProfileName, isProfileLaunchableHere, deleteProfile, DEFAULT_BROWSER_PROFILE_NAME, LEGACY_DEFAULT_BROWSER_PROFILE_NAME, } from './profiles.js';
5
+ import { keyBelongsToProfile } from './types.js';
5
6
  const PID_FILE = 'pid';
6
7
  const PORT_FILE = 'port';
7
8
  const COMMAND_FILE = 'command';
@@ -106,10 +107,14 @@ export function removeProfileCache(profileName) {
106
107
  catch { /* gone */ }
107
108
  }
108
109
  /**
109
- * Find every cache directory belonging to a given profile. The composite
110
- * naming (`<name>@<endpoint>`) means a single agents-cli profile can have
111
- * multiple runtime dirs side by side; this finds them all plus the legacy
110
+ * Find every cache directory belonging to a given profile. A runtime dir name
111
+ * IS a connection key (`<name>@<endpoint>[.<fork>]`), so a single agents-cli
112
+ * profile can have several side by side; this finds them all, plus the legacy
112
113
  * non-composite dir from older builds.
114
+ *
115
+ * Membership is decided by {@link keyBelongsToProfile} — the same single rule
116
+ * `status`, `stopProfile`, and `findTask` use (RUSH-2709), so a fork dir is no
117
+ * longer missed here while being matched there.
113
118
  */
114
119
  export function listProfileCacheDirs(profileName) {
115
120
  const root = getBrowserRuntimeDir();
@@ -117,9 +122,7 @@ export function listProfileCacheDirs(profileName) {
117
122
  return [];
118
123
  const matches = [];
119
124
  for (const entry of fs.readdirSync(root)) {
120
- if (entry === profileName)
121
- matches.push(path.join(root, entry));
122
- else if (entry.startsWith(`${profileName}@`))
125
+ if (keyBelongsToProfile(entry, profileName))
123
126
  matches.push(path.join(root, entry));
124
127
  }
125
128
  return matches;
@@ -292,7 +295,8 @@ export const PRUNE_REASON_TEXT = {
292
295
  * - **in use** — a live browser, SSH tunnel, or open task on any of its dirs.
293
296
  * - **the configured default** — this machine resolves a bare
294
297
  * `agents browser start` to it; removing it breaks that command.
295
- * - **`default`** auto-regenerated by `ensureDefaultBrowserProfile`, so
298
+ * - **the auto-detected profile** (`auto-chrome`, or the `default` an older
299
+ * build wrote) — auto-regenerated by `ensureDefaultBrowserProfile`, so
296
300
  * pruning it is pure churn.
297
301
  * - **fleet-synced** — deleting one removes it from EVERY machine, so it takes
298
302
  * the explicit `includeFleet` opt-in.
@@ -310,7 +314,7 @@ export function planProfilePrune(profiles, opts = {}) {
310
314
  keep('fleet-synced (pass --fleet to include it)');
311
315
  continue;
312
316
  }
313
- if (name === DEFAULT_BROWSER_PROFILE_NAME) {
317
+ if (name === DEFAULT_BROWSER_PROFILE_NAME || name === LEGACY_DEFAULT_BROWSER_PROFILE_NAME) {
314
318
  keep('the auto-detected default profile');
315
319
  continue;
316
320
  }
@@ -1,6 +1,6 @@
1
1
  import { CDPClient } from './cdp.js';
2
2
  import { type ResolvedDomainSkill } from './domain-skills.js';
3
- import { type Task, type TabInfo, type ProfileStatus, type BrowserType, type HistoricalTask, type ReapResult } from './types.js';
3
+ import { type Task, type TabInfo, type ProfileStatus, type BrowserType, type HistoricalTask, type ReapResult, type ProfileName, type ConnectionKey } from './types.js';
4
4
  import { type ReapOptions } from './hygiene.js';
5
5
  import { type RefOpts, type RefNode } from './refs.js';
6
6
  import type { TargetFilter } from './types.js';
@@ -60,19 +60,15 @@ interface ProfileConnection {
60
60
  /** Raw `url:<v>` / `title:<v>` filter copied from the profile config. */
61
61
  targetFilter?: string;
62
62
  /**
63
- * The composite key this connection is registered under in `this.connections`
64
- * (`<profile>` / `<profile>@<endpoint>` / `<profile>.<fork>`). It is the same
65
- * name used to key the profile's runtime dir, so downloads and session
66
- * captures land under `.cache/browser/<profileName>/`. Set at registration.
63
+ * The runtime key this connection is registered under in `this.connections`
64
+ * (`<profile>@<endpoint>`, plus `.<fork>` for an Electron fork; a bare name
65
+ * for a legacy pre-composite dir). Also keys the profile's runtime dir, so
66
+ * downloads and session captures land under `.cache/browser/<key>/`.
67
67
  */
68
- profileName?: string;
69
- /**
70
- * Bare YAML profile name without the `@<endpoint>` suffix. Kept so
71
- * `status --profile comet-local` matches the composite connection key
72
- * `comet-local@endpoint-0` without prefix-matching wrong browsers.
73
- */
74
- bareName?: string;
75
- forkedFrom?: string;
68
+ key?: ConnectionKey;
69
+ /** The bare, user-facing profile name this connection belongs to. */
70
+ profile?: ProfileName;
71
+ forkedFrom?: ConnectionKey;
76
72
  tasks: Map<string, Task>;
77
73
  windowId?: string;
78
74
  targetCache?: {
@@ -104,12 +100,6 @@ export declare function deriveTaskLabel(opts: {
104
100
  url?: string;
105
101
  existing?: string;
106
102
  }): string;
107
- /**
108
- * True when `key` is the bare profile name or one of its composite endpoint
109
- * keys (`name@endpoint`). Used by status/stop so `comet-local` matches
110
- * `comet-local@endpoint-0`.
111
- */
112
- export declare function connectionKeyMatchesProfile(key: string, profileName: string): boolean;
113
103
  type TargetInfo = {
114
104
  targetId: string;
115
105
  url?: string;
@@ -142,6 +132,12 @@ export declare function resolveTaskIdentity(forwarded: {
142
132
  };
143
133
  export declare class BrowserService {
144
134
  private static readonly SOURCE_PREFIX;
135
+ /**
136
+ * Live browsers, keyed by {@link ConnectionKey} — NOT by profile name. The
137
+ * branded key type is what makes `connections.get(someProfileName)` (the
138
+ * RUSH-2709 miss that made `status --profile <name>` return empty for a
139
+ * running `<name>@endpoint-0`) fail to compile.
140
+ */
145
141
  private connections;
146
142
  private forkingProfiles;
147
143
  private consoleLogs;
@@ -172,7 +168,10 @@ export declare class BrowserService {
172
168
  name: string;
173
169
  tabId?: string;
174
170
  windowId?: string;
175
- profile: string;
171
+ /** BARE profile name — what the caller asked for, never the runtime key. */
172
+ profile: ProfileName;
173
+ /** Runtime key the task actually landed on (`<profile>@<endpoint>`). */
174
+ key: ConnectionKey;
176
175
  skill?: ResolvedDomainSkill;
177
176
  }>;
178
177
  /**
@@ -207,6 +206,25 @@ export declare class BrowserService {
207
206
  * page that has since redirected elsewhere simply does not match, and the
208
207
  * caller opens a tab as before.
209
208
  */
209
+ /** Is this CDP target already registered to any task on the connection? */
210
+ private targetIsClaimed;
211
+ /**
212
+ * The CDP targets a task may CLOSE — its own tabs minus any it merely
213
+ * borrowed. A borrowed tab existed before the task did (see `Task.borrowedTabs`),
214
+ * so closing it would remove something the task never opened.
215
+ */
216
+ private closeableTargetIds;
217
+ /**
218
+ * A page target that `navigate` may take over on a browser which cannot create
219
+ * tabs (Arc). Deliberately narrow: only a tab ALREADY showing the requested URL
220
+ * -- re-showing that document there is what the caller asked for -- or an empty
221
+ * new-tab page. A target any task already owns is left alone. Note the honest
222
+ * limit: reusing a matching tab still RELOADS it, discarding scroll position and
223
+ * unsaved form state. Arc cannot open a tab at all, so some intrusion is
224
+ * unavoidable to show the document; a reload is the smallest one, and the tab is
225
+ * borrowed rather than owned so it is never closed.
226
+ */
227
+ private pickReusableTargetWithoutCreate;
210
228
  private adoptTabShowing;
211
229
  /**
212
230
  * Every live task across every connected profile — the reaper's input
@@ -214,7 +232,7 @@ export declare class BrowserService {
214
232
  * daemon's live state, so callers only read it and act through `stop`.
215
233
  */
216
234
  listTasks(): Array<{
217
- profile: string;
235
+ profile: ConnectionKey;
218
236
  task: Task;
219
237
  }>;
220
238
  /**
@@ -231,13 +249,13 @@ export declare class BrowserService {
231
249
  ok: boolean;
232
250
  profile?: string;
233
251
  }>;
234
- stopProfile(profileName: string): Promise<void>;
235
- navigate(taskId: string, url: string, profileName?: string): Promise<{
252
+ stopProfile(profileRef: ProfileName | ConnectionKey): Promise<void>;
253
+ navigate(taskId: string, url: string, profileRef?: ProfileName | ConnectionKey): Promise<{
236
254
  tabId: string;
237
255
  url: string;
238
256
  created: boolean;
239
257
  }>;
240
- tabAdd(taskId: string, url: string, profileName?: string): Promise<{
258
+ tabAdd(taskId: string, url: string, profileRef?: ProfileName | ConnectionKey): Promise<{
241
259
  tabId: string;
242
260
  url: string;
243
261
  }>;
@@ -253,7 +271,7 @@ export declare class BrowserService {
253
271
  private resolveTabHint;
254
272
  private resolveCurrentTab;
255
273
  private getCdpTargetId;
256
- tabs(taskId?: string, profileName?: string): Promise<TabInfo[]>;
274
+ tabs(taskId?: string, profileRef?: ProfileName | ConnectionKey): Promise<TabInfo[]>;
257
275
  tabClose(taskId: string, tabHint?: string): Promise<void>;
258
276
  evaluate(taskId: string, tabHint: string | undefined, expression: string): Promise<unknown>;
259
277
  screenshot(taskId: string, tabHint?: string, outputPath?: string, quality?: 'compressed' | 'raw'): Promise<{
@@ -335,7 +353,25 @@ export declare class BrowserService {
335
353
  stageUpload(source: string): {
336
354
  path: string;
337
355
  };
338
- status(profileName?: string): Promise<ProfileStatus[]>;
356
+ /**
357
+ * Status for one profile (bare name) or every live profile.
358
+ *
359
+ * `profileName` is a {@link ProfileName} — a BARE name, never a runtime key.
360
+ * Every candidate is selected by the one rule ({@link keyBelongsToProfile}),
361
+ * and a scoped query that finds no live connection falls through to disk, so
362
+ * `status --profile comet-local` reports the LIVE `comet-local@endpoint-0`
363
+ * instead of the empty list it used to return (RUSH-2709).
364
+ */
365
+ status(profileRef?: ProfileName | ConnectionKey): Promise<ProfileStatus[]>;
366
+ /**
367
+ * Rebuild a profile's status from its runtime dirs when no live connection is
368
+ * registered — a daemon that never connected this profile, or a browser
369
+ * started by an earlier daemon.
370
+ *
371
+ * Takes a BARE profile name and walks every runtime key that belongs to it
372
+ * ({@link listProfileCacheDirs}), including the legacy pre-composite dir named
373
+ * exactly the profile.
374
+ */
339
375
  private reconcileFromDisk;
340
376
  private profileStatusFromDisk;
341
377
  setViewport(taskId: string, width: number, height: number, options?: {
@@ -400,9 +436,10 @@ export declare class BrowserService {
400
436
  * already resolved the endpoint and built the `effectiveProfile` with
401
437
  * the per-endpoint binary/targetFilter overrides applied; we just use it.
402
438
  *
403
- * `effectiveProfile.name` is the composite identifier (`<profile>@<endpoint>`)
404
- * so per-endpoint pid/port files don't collide when the same app runs
405
- * locally and remotely at the same time.
439
+ * `key` is the runtime key (`<profile>@<endpoint>`) and is what every on-disk
440
+ * lookup uses, so per-endpoint pid/port files don't collide when the same app
441
+ * runs locally and remotely at the same time. It is a SEPARATE argument
442
+ * because `effectiveProfile.name` stays the bare, user-facing name (RUSH-2709).
406
443
  */
407
444
  private connectProfile;
408
445
  private connectEndpoint;
@@ -443,7 +480,7 @@ export declare class BrowserService {
443
480
  }): Promise<{
444
481
  conn: ProfileConnection;
445
482
  task: Task;
446
- profileName: string;
483
+ key: ConnectionKey;
447
484
  created: boolean;
448
485
  } | null>;
449
486
  private listTasksForCaller;
@@ -491,6 +528,7 @@ export declare class BrowserService {
491
528
  */
492
529
  private rehydrateTaskFromDisk;
493
530
  private getTabsForTask;
531
+ /** Live status for ONE registered connection, addressed by its runtime key. */
494
532
  private getProfileStatus;
495
533
  private getTarget;
496
534
  private getSessionId;