@phnx-labs/agents-cli 1.22.117 → 1.22.118

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 (248) hide show
  1. package/CHANGELOG.md +235 -0
  2. package/dist/bootstrap.js +4 -11
  3. package/dist/commands/browser.d.ts +52 -70
  4. package/dist/commands/browser.js +192 -3562
  5. package/dist/commands/daemon.d.ts +39 -2
  6. package/dist/commands/daemon.js +72 -73
  7. package/dist/commands/events.js +1 -1
  8. package/dist/commands/exec.js +53 -1
  9. package/dist/commands/repo.js +13 -49
  10. package/dist/commands/route.js +5 -5
  11. package/dist/commands/routines.js +39 -12
  12. package/dist/commands/sessions-render.d.ts +1 -1
  13. package/dist/commands/sessions-render.js +0 -1
  14. package/dist/commands/sessions.test-fixture.d.ts +0 -1
  15. package/dist/commands/sessions.test-fixture.js +0 -37
  16. package/dist/commands/setup-browser.d.ts +17 -12
  17. package/dist/commands/setup-browser.js +52 -87
  18. package/dist/commands/setup-preferences.d.ts +0 -17
  19. package/dist/commands/setup-preferences.js +18 -49
  20. package/dist/commands/setup.js +9 -9
  21. package/dist/commands/ssh.js +10 -1
  22. package/dist/commands/sync.js +6 -44
  23. package/dist/commands/teams.js +0 -1
  24. package/dist/commands/update.d.ts +19 -0
  25. package/dist/commands/update.js +34 -6
  26. package/dist/commands/view.d.ts +12 -1
  27. package/dist/commands/view.js +47 -2
  28. package/dist/index.js +107 -26
  29. package/dist/lib/account-capabilities.js +0 -2
  30. package/dist/lib/account-catalog.d.ts +38 -0
  31. package/dist/lib/account-catalog.js +110 -26
  32. package/dist/lib/account-provider-registry.js +1 -1
  33. package/dist/lib/account-registry.d.ts +1 -1
  34. package/dist/lib/account-registry.js +36 -2
  35. package/dist/lib/accounting/rotate.js +22 -8
  36. package/dist/lib/accounting/usage-ingest.d.ts +6 -1
  37. package/dist/lib/accounting/usage-ingest.js +115 -45
  38. package/dist/lib/accounting/usage-sync.d.ts +134 -31
  39. package/dist/lib/accounting/usage-sync.js +227 -66
  40. package/dist/lib/accounting/usage.d.ts +16 -3
  41. package/dist/lib/accounting/usage.js +26 -8
  42. package/dist/lib/accounts/slots.d.ts +8 -0
  43. package/dist/lib/accounts/slots.js +17 -0
  44. package/dist/lib/add-dir.js +0 -1
  45. package/dist/lib/agent-cli-commands.js +0 -1
  46. package/dist/lib/agent-spec/agents.d.ts +6 -7
  47. package/dist/lib/agent-spec/agents.js +6 -60
  48. package/dist/lib/auth-health.d.ts +69 -1
  49. package/dist/lib/auth-health.js +133 -4
  50. package/dist/lib/browser/context.d.ts +82 -0
  51. package/dist/lib/browser/context.js +88 -0
  52. package/dist/lib/browser/paths.d.ts +25 -0
  53. package/dist/lib/browser/paths.js +51 -0
  54. package/dist/lib/browser/record.d.ts +38 -0
  55. package/dist/lib/browser/record.js +57 -0
  56. package/dist/lib/browser/sessions-list.js +1 -2
  57. package/dist/lib/browser-client.d.ts +158 -0
  58. package/dist/lib/browser-client.js +234 -0
  59. package/dist/lib/channels/owner-sink.d.ts +1 -18
  60. package/dist/lib/channels/owner-sink.js +29 -82
  61. package/dist/lib/channels/providers/rush.d.ts +7 -7
  62. package/dist/lib/channels/providers/rush.js +127 -57
  63. package/dist/lib/claude-statusline.d.ts +1 -1
  64. package/dist/lib/claude-statusline.js +15 -3
  65. package/dist/lib/commands.js +1 -1
  66. package/dist/lib/crabbox/lease.js +1 -1
  67. package/dist/lib/crabbox/runtimes.js +1 -3
  68. package/dist/lib/daemon/account-state-daemon-service.js +1 -0
  69. package/dist/lib/daemon/auth-sync-service.d.ts +21 -18
  70. package/dist/lib/daemon/auth-sync-service.js +37 -43
  71. package/dist/lib/daemon/daemon.d.ts +25 -14
  72. package/dist/lib/daemon/daemon.js +92 -154
  73. package/dist/lib/daemon/runner.d.ts +2 -2
  74. package/dist/lib/daemon/runner.js +32 -9
  75. package/dist/lib/daemon/self-update-service.d.ts +35 -34
  76. package/dist/lib/daemon/self-update-service.js +40 -36
  77. package/dist/lib/daemon/service.d.ts +12 -8
  78. package/dist/lib/daemon/supervisor.d.ts +65 -54
  79. package/dist/lib/daemon/supervisor.js +136 -171
  80. package/dist/lib/daemon/testdata/process-view-start.js +5 -2
  81. package/dist/lib/daemon/usage-sync-service.d.ts +21 -30
  82. package/dist/lib/daemon/usage-sync-service.js +46 -78
  83. package/dist/lib/daemon-health.d.ts +22 -5
  84. package/dist/lib/daemon-health.js +47 -3
  85. package/dist/lib/daemon-services.d.ts +1 -1
  86. package/dist/lib/daemon-services.js +0 -10
  87. package/dist/lib/daemon-ticks.js +4 -2
  88. package/dist/lib/devices/doctor-findings.js +8 -11
  89. package/dist/lib/devices/harness-inventory.js +14 -5
  90. package/dist/lib/exec-account-home.js +5 -0
  91. package/dist/lib/exec.js +0 -11
  92. package/dist/lib/feed/events.js +0 -1
  93. package/dist/lib/feed/tool-activity.js +5 -2
  94. package/dist/lib/fleet-shared-state.d.ts +45 -0
  95. package/dist/lib/fleet-shared-state.js +78 -9
  96. package/dist/lib/fs-atomic.js +25 -0
  97. package/dist/lib/harness-auth-capabilities.js +0 -1
  98. package/dist/lib/helper-versions.js +1 -1
  99. package/dist/lib/hooks/cache.d.ts +7 -0
  100. package/dist/lib/hooks/cache.js +27 -2
  101. package/dist/lib/hooks/install.js +7 -1
  102. package/dist/lib/hosts/ready.d.ts +38 -8
  103. package/dist/lib/hosts/ready.js +62 -14
  104. package/dist/lib/installations/active-check.d.ts +27 -0
  105. package/dist/lib/installations/active-check.js +61 -0
  106. package/dist/lib/installations/migrate.js +6 -3
  107. package/dist/lib/installations/shims.js +9 -7
  108. package/dist/lib/installations/update.js +21 -15
  109. package/dist/lib/installations/versions.js +12 -1
  110. package/dist/lib/manifest.js +1 -1
  111. package/dist/lib/models.js +0 -2
  112. package/dist/lib/open-url.js +28 -54
  113. package/dist/lib/profiles.js +0 -2
  114. package/dist/lib/refresh.js +1 -1
  115. package/dist/lib/routine-readiness.d.ts +35 -0
  116. package/dist/lib/routine-readiness.js +74 -16
  117. package/dist/lib/rules/compile.js +6 -0
  118. package/dist/lib/sandbox.js +0 -2
  119. package/dist/lib/secrets-policy.d.ts +89 -11
  120. package/dist/lib/secrets-policy.js +175 -28
  121. package/dist/lib/session/db.d.ts +1 -1
  122. package/dist/lib/session/db.js +65 -18
  123. package/dist/lib/session/discover.js +1 -283
  124. package/dist/lib/session/mirror.d.ts +4 -3
  125. package/dist/lib/session/mirror.js +4 -3
  126. package/dist/lib/session/parse.d.ts +0 -2
  127. package/dist/lib/session/parse.js +1 -138
  128. package/dist/lib/session/throughput.d.ts +1 -3
  129. package/dist/lib/session/throughput.js +0 -20
  130. package/dist/lib/session/types.d.ts +2 -2
  131. package/dist/lib/session/types.js +2 -2
  132. package/dist/lib/sessions-client.d.ts +60 -1
  133. package/dist/lib/sessions-client.js +227 -4
  134. package/dist/lib/setup-tool-status.js +5 -10
  135. package/dist/lib/signin-badge.d.ts +3 -2
  136. package/dist/lib/signin-badge.js +6 -3
  137. package/dist/lib/smart-launch.js +4 -1
  138. package/dist/lib/staleness/detectors/commands.d.ts +1 -1
  139. package/dist/lib/staleness/detectors/hooks.d.ts +1 -1
  140. package/dist/lib/staleness/detectors/mcp.d.ts +1 -1
  141. package/dist/lib/staleness/detectors/permissions.d.ts +1 -1
  142. package/dist/lib/staleness/detectors/plugins.d.ts +1 -1
  143. package/dist/lib/staleness/detectors/rules.d.ts +1 -1
  144. package/dist/lib/staleness/detectors/skills.d.ts +1 -1
  145. package/dist/lib/staleness/detectors/subagents.d.ts +1 -1
  146. package/dist/lib/staleness/detectors/workflows.d.ts +1 -1
  147. package/dist/lib/staleness/writers/commands.d.ts +1 -1
  148. package/dist/lib/staleness/writers/hooks.d.ts +1 -1
  149. package/dist/lib/staleness/writers/mcp.d.ts +1 -1
  150. package/dist/lib/staleness/writers/permissions.d.ts +1 -1
  151. package/dist/lib/staleness/writers/plugins.d.ts +1 -1
  152. package/dist/lib/staleness/writers/rules.d.ts +1 -1
  153. package/dist/lib/staleness/writers/skills.d.ts +1 -1
  154. package/dist/lib/staleness/writers/sources.js +5 -0
  155. package/dist/lib/staleness/writers/subagents.d.ts +1 -1
  156. package/dist/lib/staleness/writers/workflows.d.ts +1 -1
  157. package/dist/lib/state.d.ts +6 -4
  158. package/dist/lib/state.js +7 -17
  159. package/dist/lib/teams/parsers.d.ts +1 -1
  160. package/dist/lib/teams/parsers.js +1 -136
  161. package/dist/lib/teams/placement-probe.js +50 -15
  162. package/dist/lib/teams/scheduler.d.ts +7 -0
  163. package/dist/lib/types.d.ts +10 -1
  164. package/dist/lib/types.js +1 -1
  165. package/dist/lib/view-types.d.ts +32 -0
  166. package/dist/lib/watchdog/read.js +0 -1
  167. package/dist/lib/watchdog/rotate.js +1 -2
  168. package/dist/lib/watchdog/runner.js +2 -2
  169. package/dist/lib/watchdog/watchdog.d.ts +1 -1
  170. package/dist/lib/watchdog/watchdogTail.js +0 -31
  171. package/package.json +1 -1
  172. package/scripts/postinstall.js +8 -8
  173. package/dist/browser.d.ts +0 -2
  174. package/dist/browser.js +0 -17
  175. package/dist/commands/browser-picker.d.ts +0 -18
  176. package/dist/commands/browser-picker.js +0 -97
  177. package/dist/lib/browser/arc-discovery.d.ts +0 -52
  178. package/dist/lib/browser/arc-discovery.js +0 -197
  179. package/dist/lib/browser/arc-dom.d.ts +0 -14
  180. package/dist/lib/browser/arc-dom.js +0 -121
  181. package/dist/lib/browser/caller-identity.d.ts +0 -40
  182. package/dist/lib/browser/caller-identity.js +0 -175
  183. package/dist/lib/browser/cdp.d.ts +0 -51
  184. package/dist/lib/browser/cdp.js +0 -254
  185. package/dist/lib/browser/chrome.d.ts +0 -141
  186. package/dist/lib/browser/chrome.js +0 -704
  187. package/dist/lib/browser/chromium-discovery.d.ts +0 -28
  188. package/dist/lib/browser/chromium-discovery.js +0 -96
  189. package/dist/lib/browser/devices.d.ts +0 -34
  190. package/dist/lib/browser/devices.js +0 -61
  191. package/dist/lib/browser/domain-skills.d.ts +0 -71
  192. package/dist/lib/browser/domain-skills.js +0 -195
  193. package/dist/lib/browser/drivers/arc.d.ts +0 -40
  194. package/dist/lib/browser/drivers/arc.js +0 -276
  195. package/dist/lib/browser/drivers/firefox.d.ts +0 -99
  196. package/dist/lib/browser/drivers/firefox.js +0 -377
  197. package/dist/lib/browser/drivers/local.d.ts +0 -55
  198. package/dist/lib/browser/drivers/local.js +0 -266
  199. package/dist/lib/browser/drivers/ssh.d.ts +0 -120
  200. package/dist/lib/browser/drivers/ssh.js +0 -467
  201. package/dist/lib/browser/editor.d.ts +0 -3
  202. package/dist/lib/browser/editor.js +0 -50
  203. package/dist/lib/browser/ffmpeg.d.ts +0 -12
  204. package/dist/lib/browser/ffmpeg.js +0 -184
  205. package/dist/lib/browser/firefox-discovery.d.ts +0 -69
  206. package/dist/lib/browser/firefox-discovery.js +0 -162
  207. package/dist/lib/browser/har.d.ts +0 -85
  208. package/dist/lib/browser/har.js +0 -77
  209. package/dist/lib/browser/hygiene.d.ts +0 -97
  210. package/dist/lib/browser/hygiene.js +0 -153
  211. package/dist/lib/browser/index.d.ts +0 -5
  212. package/dist/lib/browser/index.js +0 -5
  213. package/dist/lib/browser/input.d.ts +0 -7
  214. package/dist/lib/browser/input.js +0 -92
  215. package/dist/lib/browser/ipc.d.ts +0 -204
  216. package/dist/lib/browser/ipc.js +0 -1453
  217. package/dist/lib/browser/login-detection.d.ts +0 -87
  218. package/dist/lib/browser/login-detection.js +0 -274
  219. package/dist/lib/browser/profiles.d.ts +0 -422
  220. package/dist/lib/browser/profiles.js +0 -1157
  221. package/dist/lib/browser/refs.d.ts +0 -89
  222. package/dist/lib/browser/refs.js +0 -191
  223. package/dist/lib/browser/registry.d.ts +0 -70
  224. package/dist/lib/browser/registry.js +0 -252
  225. package/dist/lib/browser/remote-control.d.ts +0 -59
  226. package/dist/lib/browser/remote-control.js +0 -85
  227. package/dist/lib/browser/resolve-target.d.ts +0 -66
  228. package/dist/lib/browser/resolve-target.js +0 -264
  229. package/dist/lib/browser/runtime-state.d.ts +0 -291
  230. package/dist/lib/browser/runtime-state.js +0 -584
  231. package/dist/lib/browser/secret-ref.d.ts +0 -10
  232. package/dist/lib/browser/secret-ref.js +0 -14
  233. package/dist/lib/browser/service.d.ts +0 -812
  234. package/dist/lib/browser/service.js +0 -4693
  235. package/dist/lib/browser/stream.d.ts +0 -17
  236. package/dist/lib/browser/stream.js +0 -72
  237. package/dist/lib/browser/task-index.d.ts +0 -78
  238. package/dist/lib/browser/task-index.js +0 -199
  239. package/dist/lib/browser/types.d.ts +0 -647
  240. package/dist/lib/browser/types.js +0 -61
  241. package/dist/lib/browser/upload.d.ts +0 -29
  242. package/dist/lib/browser/upload.js +0 -298
  243. package/dist/lib/daemon/browser-ipc-service.d.ts +0 -20
  244. package/dist/lib/daemon/browser-ipc-service.js +0 -46
  245. package/dist/lib/daemon/browser-task-reap-service.d.ts +0 -14
  246. package/dist/lib/daemon/browser-task-reap-service.js +0 -26
  247. package/dist/lib/fleet-shared-repo-sync.d.ts +0 -55
  248. package/dist/lib/fleet-shared-repo-sync.js +0 -490
@@ -1,812 +0,0 @@
1
- import { CDPClient } from './cdp.js';
2
- import { type DeviceProbe } from './resolve-target.js';
3
- import { type ResolvedDomainSkill } from './domain-skills.js';
4
- import { type Task, type TabInfo, type ProfileTabInfo, type ProfileStatus, type BrowserType, type HistoricalTask, type ReapResult, type ProfileName, type ConnectionKey } from './types.js';
5
- import { type ReapOptions } from './hygiene.js';
6
- import { type RefOpts, type RefNode } from './refs.js';
7
- import type { TargetFilter, PageOpenResult, ArcNativeProfileIdentity, FirefoxProfileIdentity } from './types.js';
8
- import { FirefoxBiDiClient } from './drivers/firefox.js';
9
- type UploadMode = 'auto' | 'input' | 'drop' | 'chooser';
10
- export declare function resolveScreenshotOutputPath(outputPath: string | undefined, automaticPath: string): string;
11
- /**
12
- * Parse a `targetFilter` string into its kind + value, or return `null`
13
- * when the input is missing or malformed. Filter syntax:
14
- * - `url:<substring>` — picks the first page target whose URL contains the substring
15
- * - `title:<substring>` — picks the first page target whose title contains the substring
16
- *
17
- * The match is case-insensitive on both sides because Electron apps
18
- * frequently lowercase or title-case their target metadata in unpredictable ways.
19
- */
20
- export declare function parseTargetFilter(filter: string | undefined): TargetFilter | null;
21
- /**
22
- * Choose the CDP page target that represents the visible UI.
23
- *
24
- * Order:
25
- * 1. If `filter` is set and parseable, narrow to page targets matching it
26
- * (case-insensitive substring). Among matches, prefer one that is not in
27
- * `INVISIBLE_URL_PATTERNS` — this is the tiebreaker that makes a coarse
28
- * filter like `url:https://www.canva.com/` skip the background service
29
- * (`https://www.canva.com/_desktop-background-service` *also* matches the
30
- * substring). If every match is invisible, return the first match so the
31
- * caller still gets something rather than silently falling through.
32
- * An explicit filter that finds *no* match returns `undefined` — callers
33
- * should surface this as an error rather than create an orphan window.
34
- * 2. If `filter` is unset (or unparseable), apply the skip-invisible heuristic
35
- * across all page targets.
36
- * 3. As a last resort, return the first page target.
37
- */
38
- export declare function pickWindowTarget<T extends {
39
- type: string;
40
- url?: string;
41
- title?: string;
42
- }>(targets: T[], filter: string | undefined): T | undefined;
43
- /**
44
- * Parse a `--since`/`--until` value. Accepts ISO-8601 absolute timestamps
45
- * or relative offsets like `30s`, `5m`, `2h`, `1d`.
46
- */
47
- export declare function parseSinceUntil(s: string): Date;
48
- export declare function readNewestMatchingRemoteFileCommand(dir: string, prefix: string, tailLines: number): string;
49
- export declare function readNewestMatchingFile(dir: string, prefix: string, tailLines: number): string;
50
- interface BaseProfileConnection {
51
- port: number;
52
- pid: number;
53
- electron?: boolean;
54
- /**
55
- * The profile's declared browser family. Load-bearing for Arc: Arc answers
56
- * `Browser.getVersion` and DOES expose CDP page targets it honors `Page.navigate`
57
- * on, but CRASHES on `Target.createTarget` (verified live, PR #2778), so any
58
- * tab-CREATING path must refuse and drive an EXISTING tab instead rather than
59
- * crash the user's Arc. See `createPageTarget` / `pickReusableTargetWithoutCreate`.
60
- */
61
- browserType?: BrowserType;
62
- /** Raw `url:<v>` / `title:<v>` filter copied from the profile config. */
63
- targetFilter?: string;
64
- /**
65
- * The runtime key this connection is registered under in `this.connections`
66
- * (`<profile>@<endpoint>`, plus `.<fork>` for an Electron fork; a bare name
67
- * for a legacy pre-composite dir). Also keys the profile's runtime dir, so
68
- * downloads and session captures land under `.cache/browser/<key>/`.
69
- */
70
- key?: ConnectionKey;
71
- /** The bare, user-facing profile name this connection belongs to. */
72
- profile?: ProfileName;
73
- forkedFrom?: ConnectionKey;
74
- tasks: Map<string, Task>;
75
- windowId?: string;
76
- targetCache?: {
77
- targets: TargetInfo[];
78
- ts: number;
79
- };
80
- sessionCache: Map<string, string>;
81
- /**
82
- * Connection-specific teardown (e.g. killing the SSH tunnel for an ssh://
83
- * profile). Must be called whenever the connection is removed from
84
- * `this.connections`, otherwise the tunnel leaks across daemon restarts
85
- * and hijacks future `cdp://127.0.0.1:N` profiles on the same local port.
86
- */
87
- cleanup?: () => void;
88
- }
89
- interface CdpProfileConnection extends BaseProfileConnection {
90
- /** Omitted only by legacy/in-process callers; absence means the CDP path. */
91
- backend?: 'cdp';
92
- cdp: CDPClient;
93
- }
94
- interface ArcProfileConnection extends BaseProfileConnection {
95
- backend: 'arc-native';
96
- browserType: 'arc';
97
- arcProfile: ArcNativeProfileIdentity;
98
- }
99
- /**
100
- * A Firefox connection driven over WebDriver BiDi (PHNX-4043). No CDP socket:
101
- * `bidi` is the live BiDi client, and `firefoxProfile` is the discovered
102
- * profile identity. Task tab ids map to BiDi browsing-context ids.
103
- */
104
- interface FirefoxProfileConnection extends BaseProfileConnection {
105
- backend: 'bidi';
106
- browserType: 'firefox';
107
- bidi: FirefoxBiDiClient;
108
- firefoxProfile: FirefoxProfileIdentity;
109
- /** The BiDi session id from `session.new`. */
110
- sessionId: string;
111
- /** Absolute Firefox profile directory this connection is bound to. */
112
- profileDir: string;
113
- }
114
- type ProfileConnection = CdpProfileConnection | ArcProfileConnection | FirefoxProfileConnection;
115
- /** Join error lines so callers get a next command, not a dead-end message. */
116
- export declare function actionable(...lines: string[]): string;
117
- /**
118
- * Arc DOES expose CDP page targets and honors `Page.navigate` on the ones the
119
- * user already has open (measured live against Arc: 33 targets, PR #2786), so
120
- * agents browser drives an attached Arc by reusing existing tabs. What it CANNOT
121
- * survive is `Target.createTarget` — opening a brand-new tab crashes the user's
122
- * Arc window (verified live, PR #2778). Tab creation is the one CDP-only op that
123
- * fails clearly here (PHNX-2399): every tab-creating path throws this actionable
124
- * error instead of crashing Arc, and steers the caller to reuse an existing
125
- * tab/Space (via `--target-filter`) or to a Chromium-family browser for new tabs.
126
- */
127
- export declare function arcNotDrivableError(profileName?: string): Error;
128
- /** Derive a human label from an explicit title or a navigated URL. */
129
- export declare function deriveTaskLabel(opts: {
130
- title?: string;
131
- url?: string;
132
- existing?: string;
133
- }): string;
134
- type TargetInfo = {
135
- targetId: string;
136
- url?: string;
137
- title?: string;
138
- };
139
- /** Describes a ref that was re-resolved from a drifted integer via its cached descriptor. */
140
- interface HealInfo {
141
- from: number;
142
- to: number;
143
- role: string;
144
- name: string;
145
- }
146
- /**
147
- * Resolve the identity stamped on a task at start: WHO (`owner`) and WHICH run
148
- * (`launchId`). The forwarded values come from the caller's own CLI process and
149
- * are authoritative — the browser daemon is shared and long-lived, so resolving
150
- * the actor daemon-side (the RUSH-2020 bug) mis-attributes every task to the
151
- * daemon's owner. `resolveLocalActor` is consulted ONLY when no actor was
152
- * forwarded (a CLI that predates the field, mid-rollout) — never to override a
153
- * forwarded one.
154
- */
155
- export declare function resolveTaskIdentity(forwarded: {
156
- actor?: string;
157
- launchId?: string;
158
- sessionId?: string;
159
- }, resolveLocalActor: () => string): {
160
- owner: string;
161
- launchId?: string;
162
- sessionId?: string;
163
- };
164
- interface StartOptions {
165
- taskName?: string;
166
- url?: string;
167
- endpointName?: string;
168
- skipDomainSkill?: boolean;
169
- /** Always open a new tab, skipping the abandoned-task reclaim. */
170
- fresh?: boolean;
171
- /** Caller identity, forwarded from the CLI (see IPCRequest.actor/launchId). */
172
- actor?: string;
173
- launchId?: string;
174
- /** Calling agent session, forwarded from the CLI (see IPCRequest.sessionId). */
175
- sessionId?: string;
176
- /** Whether the CALLER was dispatched here by a fleet `--device` hop. */
177
- fleetRemote?: boolean;
178
- /** Explicit human label (`--title`). */
179
- title?: string;
180
- /** Injected reachability probe — production uses ssh; tests pass a fake. */
181
- probe?: DeviceProbe;
182
- }
183
- interface StartResult {
184
- task: string;
185
- name: string;
186
- tabId?: string;
187
- windowId?: string;
188
- /** BARE profile name — what the caller asked for, never the runtime key. */
189
- profile: ProfileName;
190
- /** Runtime key the task actually landed on (`<profile>@<device>`). */
191
- key: ConnectionKey;
192
- /** Device the daemon connected to. */
193
- device: string;
194
- /** Set when the daemon picked a remote declaring device. */
195
- picked?: string;
196
- skill?: ResolvedDomainSkill;
197
- /** A same-name start that matched an existing task and reused it (PHNX-2399). */
198
- reused?: boolean;
199
- /**
200
- * The actual page operation the URL open performed (PHNX-2399), or undefined
201
- * when start opened no URL. Carries created/refreshed/message truthfully:
202
- * a fresh tab is `created`, a same-URL owned-tab reopen is `refreshed`, an
203
- * adopted abandoned tab or a no-op reuse is neither.
204
- */
205
- firstOpen?: PageOpenResult;
206
- }
207
- export declare function arcCreateMarker(): string;
208
- export declare function isArcCreateMarker(url: string): boolean;
209
- export declare class BrowserService {
210
- private static readonly SOURCE_PREFIX;
211
- /**
212
- * Live browsers, keyed by {@link ConnectionKey} — NOT by profile name. The
213
- * branded key type is what makes `connections.get(someProfileName)` (the
214
- * RUSH-2709 miss that made `status --profile <name>` return empty for a
215
- * running `<name>@<device>`) fail to compile. Keys are `<profile>@<device>`
216
- * (legacy leftover `<profile>@endpoint-N` dirs are still recognized).
217
- */
218
- private connections;
219
- private forkingProfiles;
220
- private consoleLogs;
221
- private pageErrors;
222
- private networkRequests;
223
- private pendingDownloads;
224
- private enabledSessions;
225
- /** Profile -> when a `touchTask` last persisted tasks.json for it. */
226
- private lastTouchPersist;
227
- /** Coalescing window for the `touchTask` write. See {@link touchTask}. */
228
- private static readonly TOUCH_PERSIST_INTERVAL_MS;
229
- /**
230
- * Serialization chains for the reopen/create critical section (PHNX-2399).
231
- * Nothing else serializes IPC requests — `BrowserIPCServer` registers a
232
- * per-connection `socket.on('data', async …)` that Node never awaits — so two
233
- * concurrent `navigate`/`tab-add` requests, or two concurrent first-use
234
- * creates for one caller, race the "is this URL already open?" lookup and each
235
- * open a duplicate tab. Each key funnels its section through a promise chain so
236
- * the second request sees the first's tab and refreshes it in place.
237
- *
238
- * Keys are DISJOINT by concern so a nested call can never wait on a lock its
239
- * own outer frame holds: task-scoped work keys on `task:<key>:<name>`, first-
240
- * use creation keys on `create:<callerId>`. `start()`'s Arc/Electron branch
241
- * calls `navigate()` (a `task:` key) while the create path holds a `create:`
242
- * key — different namespaces, so no re-entrant deadlock.
243
- */
244
- private critical;
245
- /**
246
- * Run `fn` mutually exclusive against every other call sharing `key`. The
247
- * chain never rejects (each link swallows its own settlement) so one failed
248
- * section cannot wedge the queue; `fn`'s own result/throw is returned to THIS
249
- * caller unchanged. The map entry is dropped once its tail settles with no
250
- * newer waiter, so idle tasks/callers don't accumulate.
251
- */
252
- private runExclusive;
253
- /**
254
- * The task's OWN tabs (excluding borrowed ones — a borrowed tab predates the
255
- * task, see {@link Task.borrowedTabs}) that are still live in the browser AND
256
- * whose current document canonically equals `url`. Deliberately scoped to THIS
257
- * task: it is neither {@link adoptTabShowing} (reclaims OTHER abandoned tasks'
258
- * tabs) nor {@link pickReusableTargetWithoutCreate} (borrows a USER tab on Arc)
259
- * — the same-task reopen contract only ever touches a tab the task itself owns.
260
- * A registered id with no live target (a tab closed out from under us) is
261
- * skipped, so a stale mapping never masquerades as a reopenable tab.
262
- */
263
- private findOwnedTabShowing;
264
- /**
265
- * Same-task reopen (PHNX-2399): the requested URL is already live in a tab this
266
- * task owns, so RELOAD that same tab and keep its ids rather than opening a
267
- * duplicate. Returns the retained short id, or undefined when no owned tab
268
- * shows the URL (the caller then falls through to its normal navigate/create
269
- * semantics — that no-match split is intentional and preserved).
270
- *
271
- * A real `Page.reload` is issued; a failed reload THROWS rather than reporting
272
- * a phantom refresh (a stale target was already excluded by
273
- * {@link findOwnedTabShowing}). The tab is marked current WITHOUT
274
- * `Target.activateTarget` — reopen must not steal window focus.
275
- */
276
- private reopenOwnedTab;
277
- start(profileName: string, opts?: StartOptions): Promise<StartResult>;
278
- private startBody;
279
- /**
280
- * Reclaim a live page already showing `url` from an ABANDONED task, instead
281
- * of opening a second copy of the same page (RUSH-2622). Returns its CDP
282
- * targetId, or undefined when there is nothing safe to reclaim.
283
- *
284
- * "Safe" is narrow on purpose, because both of the wider readings close a tab
285
- * somebody is using:
286
- *
287
- * - An UNOWNED matching page is NOT taken. No task claims it, which most
288
- * often means the user opened it themselves — and adopting it would make
289
- * this task's `done` close the user's tab.
290
- * - A page owned by a LIVE task is NOT taken. Stealing it would leave that
291
- * agent's `screenshot`/`click` throwing "No tabs open for this task", its
292
- * `navigate` silently opening the duplicate this feature exists to
293
- * prevent, and any in-flight recording truncated when the new owner calls
294
- * `done`.
295
- *
296
- * What is left is exactly the pile-up case: a page held by a task whose owner
297
- * is provably gone. Liveness uses the reaper's own predicate
298
- * (`taskOwnerIsGone`), so "dead" has one definition in this codebase rather
299
- * than two that can drift. A task the reaper cannot prove dead keeps its tab
300
- * and is closed later by the idle rule instead.
301
- *
302
- * Reclaiming transfers rather than shares: two tasks holding one targetId
303
- * means the first `done` closes the other's tab. `start --fresh` skips this
304
- * path entirely.
305
- *
306
- * URLs are compared canonically (`new URL(...).href`), so a requested
307
- * `https://example.com` matches the `https://example.com/` Chrome reports. A
308
- * page that has since redirected elsewhere simply does not match, and the
309
- * caller opens a tab as before.
310
- */
311
- /** Is this CDP target already registered to any task on the connection? */
312
- private targetIsClaimed;
313
- /**
314
- * The CDP targets a task may CLOSE — its own tabs minus any it merely
315
- * borrowed. A borrowed tab existed before the task did (see `Task.borrowedTabs`),
316
- * so closing it would remove something the task never opened.
317
- */
318
- private closeableTargetIds;
319
- /**
320
- * A page target that `navigate` may take over on a browser which cannot create
321
- * tabs (Arc). Deliberately narrow: only a tab ALREADY showing the requested URL
322
- * -- re-showing that document there is what the caller asked for -- or an empty
323
- * new-tab page. A target any task already owns is left alone. Note the honest
324
- * limit: reusing a matching tab still RELOADS it, discarding scroll position and
325
- * unsaved form state. Arc cannot open a tab at all, so some intrusion is
326
- * unavoidable to show the document; a reload is the smallest one, and the tab is
327
- * borrowed rather than owned so it is never closed.
328
- */
329
- private pickReusableTargetWithoutCreate;
330
- private adoptTabShowing;
331
- /**
332
- * Every live task across every connected profile — the reaper's input
333
- * (`hygiene.ts`). A read-only view: mutating a returned `Task` mutates the
334
- * daemon's live state, so callers only read it and act through `stop`.
335
- */
336
- listTasks(): Array<{
337
- profile: ConnectionKey;
338
- task: Task;
339
- }>;
340
- /**
341
- * Close tasks whose owning agent session is gone, or that have sat untouched
342
- * past the idle window. The entry point the daemon's periodic tick and
343
- * `agents browser prune` both call; the policy lives in `hygiene.ts`.
344
- */
345
- reapAbandoned(opts?: ReapOptions): Promise<ReapResult>;
346
- stop(taskName: string): Promise<{
347
- ok: boolean;
348
- profile?: string;
349
- }>;
350
- done(taskName: string): Promise<{
351
- ok: boolean;
352
- profile?: string;
353
- }>;
354
- stopProfile(profileRef: ProfileName | ConnectionKey, opts?: {
355
- fleetRemote?: boolean;
356
- actor?: string;
357
- }): Promise<void>;
358
- navigate(taskId: string, url: string, profileRef?: ProfileName | ConnectionKey): Promise<{
359
- tabId: string;
360
- url: string;
361
- created: boolean;
362
- refreshed: boolean;
363
- message?: string;
364
- }>;
365
- private navigateLocked;
366
- tabAdd(taskId: string, url: string, profileRef?: ProfileName | ConnectionKey): Promise<{
367
- tabId: string;
368
- url: string;
369
- created: boolean;
370
- refreshed: boolean;
371
- message?: string;
372
- }>;
373
- private tabAddLocked;
374
- tabFocus(taskId: string, tabHint: string): Promise<{
375
- tabId: string;
376
- }>;
377
- tabList(taskId: string): Promise<Array<{
378
- id: string;
379
- url: string;
380
- title: string;
381
- current: boolean;
382
- }>>;
383
- /**
384
- * Every top-level tab open in the task's profile browser, the owner's tabs
385
- * included (`agents browser tabs --all`). Read-only: nothing is focused,
386
- * navigated, or closed. A tab an agents-cli task owns carries that task's
387
- * name and short id (so it can be addressed); any other tab carries the
388
- * browser's own id and no task. Same rows on every backend.
389
- */
390
- profileTabs(taskId: string): Promise<ProfileTabInfo[]>;
391
- private resolveTabHint;
392
- private resolveCurrentTab;
393
- private getCdpTargetId;
394
- tabs(taskId?: string, profileRef?: ProfileName | ConnectionKey): Promise<TabInfo[]>;
395
- tabClose(taskId: string, tabHint?: string): Promise<void>;
396
- evaluate(taskId: string, tabHint: string | undefined, expression: string): Promise<unknown>;
397
- screenshot(taskId: string, tabHint?: string, outputPath?: string, quality?: 'compressed' | 'raw'): Promise<{
398
- path: string;
399
- bytes: number;
400
- width: number;
401
- height: number;
402
- }>;
403
- /**
404
- * Export the current tab as a PDF via CDP `Page.printToPDF`. Reuses the
405
- * screenshot session + tab resolution so `--tab`, path sandboxing, and the
406
- * auto-path (`sessions/<task>/<ts>.pdf`) all behave identically to
407
- * `screenshot`. `printBackground: true` matches Chrome's default print flow
408
- * — without it, dark-mode pages render on a blank sheet.
409
- */
410
- printToPdf(taskId: string, tabHint?: string, outputPath?: string): Promise<{
411
- path: string;
412
- bytes: number;
413
- }>;
414
- private recordings;
415
- recordStart(taskId: string, tabHint?: string, opts?: {
416
- fps?: number;
417
- duration?: number;
418
- maxMb?: number;
419
- }): Promise<{
420
- path: string;
421
- fps: number;
422
- durationCapSec: number;
423
- maxMb: number;
424
- }>;
425
- recordStop(taskId: string, reason?: 'manual' | 'duration-cap' | 'size-cap'): Promise<{
426
- path: string;
427
- bytes: number;
428
- durationMs: number;
429
- reason: string;
430
- }>;
431
- recordStatus(taskId: string): Promise<{
432
- recording: boolean;
433
- path?: string;
434
- elapsedMs?: number;
435
- }>;
436
- refs(taskId: string, tabHint?: string, opts?: RefOpts): Promise<{
437
- refs: string;
438
- nodeMap: Map<number, RefNode>;
439
- }>;
440
- /** Record the last ref listing (descriptors + opts) for a tab into state. */
441
- private cacheRefDescriptors;
442
- /**
443
- * Re-resolve a caller-supplied ref against a freshly-built node map, healing
444
- * it back to the right element when the integer ref has drifted since the
445
- * cached `refs` listing. Shared by `click` and `type` so both self-heal
446
- * identically. Returns the ref to act on plus, when a heal occurred, the
447
- * {@link HealInfo} to surface. Throws when the cached element is gone.
448
- */
449
- private resolveHealedRef;
450
- click(taskId: string, ref: number, tabHint?: string): Promise<{
451
- healed?: HealInfo;
452
- }>;
453
- /**
454
- * Click raw viewport coordinates, bypassing ref resolution entirely. Backs
455
- * `browser click --at X,Y` — the escape hatch when the accessibility tree
456
- * exposes no usable ref (canvas apps, custom-drawn UI) and the caller has
457
- * located the target from a screenshot.
458
- */
459
- clickAt(taskId: string, x: number, y: number, tabHint?: string): Promise<void>;
460
- type(taskId: string, ref: number, text: string, tabHint?: string, clear?: boolean): Promise<void>;
461
- press(taskId: string, key: string, tabHint?: string): Promise<void>;
462
- hover(taskId: string, ref: number, tabHint?: string): Promise<void>;
463
- scroll(taskId: string, deltaX: number, deltaY: number, atX?: number, atY?: number, tabHint?: string): Promise<void>;
464
- upload(taskId: string, files: string[], options: {
465
- ref?: number;
466
- trigger?: number;
467
- mode?: UploadMode;
468
- tabHint?: string;
469
- timeout?: number;
470
- }): Promise<{
471
- mode: 'input' | 'drop' | 'chooser';
472
- }>;
473
- stageUpload(source: string): {
474
- path: string;
475
- };
476
- /**
477
- * Status for one profile (bare name) or every live profile.
478
- *
479
- * `profileName` is a {@link ProfileName} — a BARE name, never a runtime key.
480
- * Every candidate is selected by the one rule ({@link keyBelongsToProfile}),
481
- * and a scoped query that finds no live connection falls through to disk, so
482
- * `status --profile comet-local` reports the LIVE `comet-local@<device>`
483
- * (and leftover `comet-local@endpoint-0` dirs) instead of the empty list
484
- * it used to return (RUSH-2709).
485
- */
486
- status(profileRef?: ProfileName | ConnectionKey): Promise<ProfileStatus[]>;
487
- /**
488
- * Rebuild a profile's status from its runtime dirs when no live connection is
489
- * registered — a daemon that never connected this profile, or a browser
490
- * started by an earlier daemon.
491
- *
492
- * Takes a BARE profile name and walks every runtime key that belongs to it
493
- * ({@link listProfileCacheDirs}), including the legacy pre-composite dir named
494
- * exactly the profile.
495
- */
496
- private reconcileFromDisk;
497
- private profileStatusFromDisk;
498
- setViewport(taskId: string, width: number, height: number, options?: {
499
- mobile?: boolean;
500
- deviceScaleFactor?: number;
501
- tabHint?: string;
502
- }): Promise<void>;
503
- setDevice(taskId: string, deviceName: string, tabHint?: string): Promise<void>;
504
- private enableRuntimeForSession;
505
- getConsoleLogs(taskId: string, options?: {
506
- level?: string;
507
- clear?: boolean;
508
- tabHint?: string;
509
- }): Promise<import('./types.js').ConsoleEntry[]>;
510
- getErrors(taskId: string, options?: {
511
- clear?: boolean;
512
- tabHint?: string;
513
- }): Promise<import('./types.js').ErrorEntry[]>;
514
- private enableNetworkForSession;
515
- getNetworkRequests(taskId: string, options?: {
516
- filter?: string;
517
- clear?: boolean;
518
- tabHint?: string;
519
- }): Promise<import('./types.js').NetworkRequest[]>;
520
- getResponseBody(taskId: string, urlPattern: string, options?: {
521
- timeout?: number;
522
- maxChars?: number;
523
- tabHint?: string;
524
- }): Promise<string>;
525
- getAppLogs(taskId: string, opts: {
526
- lines?: number;
527
- level?: string;
528
- filter?: string;
529
- message?: string;
530
- source?: string;
531
- since?: string;
532
- until?: string;
533
- }): Promise<any[]>;
534
- wait(taskId: string, type: 'time' | 'selector' | 'url' | 'function' | 'load', value: string | number, options?: {
535
- timeout?: number;
536
- tabHint?: string;
537
- }): Promise<void>;
538
- /**
539
- * Point the browser's default download destination at the profile's downloads
540
- * dir, browser-global, at connect time. Without this a download the agent never
541
- * explicitly routed (`browser download --path`) falls to Chromium's own default
542
- * — for an attached user browser, wherever that browser was last configured,
543
- * which is how downloads used to escape into random locations. Sent on the root
544
- * session (no sessionId) so every current and future tab inherits it. Best
545
- * effort: a remote CDP endpoint that doesn't expose the Browser domain must not
546
- * fail the whole connect.
547
- */
548
- private applyDefaultDownloadBehavior;
549
- setDownloadPath(taskId: string, downloadPath?: string, tabHint?: string): Promise<string>;
550
- waitForDownload(taskId: string, timeout?: number): Promise<string>;
551
- private findTaskBySession;
552
- shutdown(): Promise<void>;
553
- private findAvailableFork;
554
- private forkElectronProfile;
555
- /**
556
- * Connect to a profile at a specific endpoint preset. The caller has
557
- * already resolved the endpoint and built the `effectiveProfile` with
558
- * the per-endpoint binary/targetFilter overrides applied; we just use it.
559
- *
560
- * `key` is the runtime key (`<profile>@<device>`) and is what every on-disk
561
- * lookup uses. It is a SEPARATE argument because `effectiveProfile.name`
562
- * stays the bare, user-facing name (RUSH-2709).
563
- */
564
- private connectProfile;
565
- private connectEndpoint;
566
- private enableDomains;
567
- /**
568
- * The single path that opens a new CDP page/window target. It exists so the
569
- * Arc guard lives in exactly one place: `Target.createTarget` crashes Arc
570
- * (verified, PR #2778), so an Arc connection throws a clear, actionable error
571
- * here instead of every call site re-checking. Every drivable Chromium-family
572
- * browser goes straight through.
573
- */
574
- private createPageTarget;
575
- private getOrCreateWindow;
576
- private hasTaskNamed;
577
- /** The (connection, task) a handle names anywhere, or undefined. */
578
- private findTaskByHandle;
579
- /**
580
- * Same-name `start --task <name>` retry (PHNX-2399). When a task by that name
581
- * already exists this REUSES it — reopening the URL in the same tab (same id,
582
- * a real reload, the `Tab already open—refreshed` note) — but only after
583
- * proving it is genuinely the same task: same bare profile, same endpoint, and
584
- * a matching caller identity. A mismatch on any of those is a real conflict and
585
- * throws, so a different caller/profile/endpoint can never silently acquire
586
- * another task. Serialized by the `namedstart:` lock in {@link start}.
587
- */
588
- private retryNamedStart;
589
- /** Map key for a task on a connection (tasks are keyed by `name`). */
590
- private taskMapKey;
591
- /** Find a task by map key, id, or name on one connection. */
592
- private lookupTaskOnConn;
593
- private maybeUpdateLabelFromUrl;
594
- /**
595
- * Resolve a task for a page/close verb.
596
- *
597
- * - explicit `task` handle → look up (with disk rehydrate on RAM miss)
598
- * - no handle, exactly one live task for this caller → use it
599
- * - no handle, multiple for this caller → error listing them + `--task`
600
- * - no handle, zero for this caller, createIfMissing → start a new task
601
- * - no handle, zero, !createIfMissing → return null (caller reports "nothing to close")
602
- */
603
- resolveOrCreateTask(opts: {
604
- /** Whether the CALLER was dispatched here by a fleet `--device` hop. */
605
- fleetRemote?: boolean;
606
- task?: string;
607
- profile?: string;
608
- actor?: string;
609
- launchId?: string;
610
- sessionId?: string;
611
- createIfMissing: boolean;
612
- title?: string;
613
- url?: string;
614
- }): Promise<{
615
- conn: ProfileConnection;
616
- task: Task;
617
- key: ConnectionKey;
618
- created: boolean;
619
- picked?: string;
620
- device?: string;
621
- /**
622
- * When this call CREATED the task by starting a browser on `opts.url`, the
623
- * page operation `start` already performed on that URL. The owning IPC
624
- * handler reports it truthfully (adopt → created:false, Arc reuse →
625
- * created:false, fresh tab → created:true) instead of re-running the
626
- * navigate/tab-add (a duplicate execution) and assuming a create (PHNX-2399).
627
- */
628
- firstOpen?: PageOpenResult;
629
- } | null>;
630
- private resolveOrCreateByIdentity;
631
- private listTasksForCaller;
632
- private currentUrlHint;
633
- /**
634
- * Mark a task as active, so the reaper's idle window measures time since the
635
- * last real use rather than time since `start` (RUSH-2622).
636
- *
637
- * Called from `findTask` — the single funnel every task-scoped operation
638
- * resolves through — rather than from each of the ~26 call sites, so a new
639
- * action added later cannot forget to stamp it.
640
- *
641
- * The in-memory stamp is what the reaper reads: it runs inside the same
642
- * daemon that owns these `Task` objects. The write to tasks.json exists only
643
- * so a daemon RESTART does not inherit a stale stamp and reap a task an agent
644
- * has been clicking through for the last half hour — `click`, `type`,
645
- * `evaluate`, and `screenshot` never call `saveTaskState` on their own, so
646
- * without this the on-disk stamp would sit at the last navigation. It is
647
- * coalesced to at most one write per profile per minute so a screenshot loop
648
- * does not become a write loop; the resulting on-disk stamp trails by at most
649
- * a minute, well inside the 30-minute idle window.
650
- */
651
- private touchTask;
652
- private prepareTask;
653
- private findTask;
654
- /**
655
- * Soft-attach to an already-running browser for a runtime dir.
656
- *
657
- * Never launches a browser and never clears pid/port files on failure —
658
- * `connectProfile` does both, which made `status()` wipe disk state when
659
- * CDP was unreachable (CI / post-reaper) and then return an empty list.
660
- * Returns null when nothing is speaking CDP so callers can fall through
661
- * to disk reconcile.
662
- */
663
- private attachRunningProfile;
664
- /**
665
- * Reconnect every profile runtime dir that still has a live browser and
666
- * tasks.json entries. Used before identity-based resolution so a daemon
667
- * restart does not make the caller's tasks invisible.
668
- */
669
- /**
670
- * Register a freshly-rehydrated connection, unless a concurrent rehydrate won
671
- * the race and already registered one for this key. `attachRunningProfile`
672
- * awaits an ssh-tunnel spawn / CDP connect, so two commands landing right
673
- * after a daemon restart can each build a connection for the same key; the
674
- * loser must be released instead of silently overwriting the winner (whose
675
- * `cleanup` would then never run).
676
- *
677
- * The subtlety is the SSH tunnel: when the loser's `connectSSH` landed after
678
- * the winner's tunnel had already bound the local port, `isOwnTunnel` makes it
679
- * **reuse** that same OS process (`drivers/ssh.ts`) — so both connections carry
680
- * the same `pid`/`port`. Calling the loser's `cleanup()` then does
681
- * `tunnel.kill()` on the SHARED process and breaks the winner's live CDP. So
682
- * when the loser shares the winner's tunnel we close ONLY the loser's own CDP
683
- * socket and leave the tunnel to the winner; only a loser that spawned its own
684
- * distinct tunnel gets the full `cleanup()` (else it would leak). Returns the
685
- * winning connection to use.
686
- */
687
- private registerRehydratedConnection;
688
- private rehydrateAllFromDisk;
689
- /**
690
- * On a RAM miss, scan profile runtime dirs for a tasks.json entry matching
691
- * `taskId`, soft-attach when CDP is still up, and register the connection.
692
- * Does not launch browsers or clear runtime files.
693
- */
694
- private rehydrateTaskFromDisk;
695
- private getTabsForTask;
696
- /** Live status for ONE registered connection, addressed by its runtime key. */
697
- private getProfileStatus;
698
- private getTarget;
699
- private getSessionId;
700
- private invalidateTargetCache;
701
- private saveTaskState;
702
- private loadTaskState;
703
- private saveToHistory;
704
- /**
705
- * The cached connection for `key`, or undefined — evicting it first if the
706
- * browser died underneath us.
707
- *
708
- * A browser killed externally (Cmd-Q, crash, a user clearing the profile by
709
- * hand) leaves a closed WebSocket in the map. Without this the next
710
- * `cdp.send` throws "CDP connection not open" and there is no recovery short
711
- * of killing the daemon.
712
- */
713
- private reuseHealthyConnection;
714
- /**
715
- * Reuse a live connection for this profile: the new `<name>@<device>` key
716
- * first, then any leftover `<name>@endpoint-N` key still in the map so a
717
- * browser started before the key collapse is not abandoned.
718
- */
719
- private reuseProfileConnection;
720
- /**
721
- * Bind a task to the profile's Space in the visible Arc window that holds it.
722
- * The Space is the profile (PHNX-2399); only its live window id is looked up.
723
- */
724
- private resolveArcSpace;
725
- private requireArcTask;
726
- private reconcileArcCreateIntents;
727
- private createArcOwnedTab;
728
- private navigateArcNative;
729
- /**
730
- * Execute JavaScript in a native Arc tab. Sync JS only, isolated world —
731
- * async/promise evaluation fails honestly with an AppleScript error.
732
- */
733
- private evaluateArcNative;
734
- /**
735
- * Resolve a task's owned Arc tabs against one shared snapshot of every
736
- * window/space/tab, rather than asking Arc per tab as `listArcTaskTabs` does.
737
- *
738
- * Same ownership rule as the live path — `requireArcTask`, then the recorded
739
- * ref must be present in its original window and Space. The snapshot changes
740
- * how often Arc is asked, never what counts as owned. Actions keep the live
741
- * path, because a snapshot can go stale before it is acted on.
742
- */
743
- private listArcTaskTabsFromSnapshot;
744
- private listArcTaskTabs;
745
- /**
746
- * Close native Arc tabs owned by a task. Only closes tabs the task created
747
- * (not borrowed ones). Never kills Arc. Identifies tabs only by stable ids in
748
- * the original window and Space.
749
- */
750
- private closeArcNativeTabs;
751
- /** The BiDi browsing-context id a task owns for `shortId`. */
752
- private firefoxContext;
753
- /** The context ids currently live in this Firefox (a killed tab drops out). */
754
- private firefoxLiveContexts;
755
- /**
756
- * Same-task reopen for Firefox (mirrors {@link reopenOwnedTab}): the URL is
757
- * already live in one of this task's own tabs → reload THAT tab in place and
758
- * keep its id, rather than opening a duplicate. Borrowed tabs are excluded —
759
- * Firefox never borrows, but the guard keeps parity. Returns the retained
760
- * short id, or undefined when nothing matches.
761
- */
762
- private reopenOwnedFirefoxTab;
763
- private navigateFirefox;
764
- private evaluateFirefox;
765
- private listFirefoxTaskTabs;
766
- /**
767
- * Close every non-borrowed tab a Firefox task owns. Never kills the Firefox
768
- * process (that is `stopProfile`'s job) — a killed browser would take the
769
- * user's other tabs with it. A tab already gone is skipped.
770
- */
771
- private closeFirefoxTabs;
772
- /**
773
- * Viewport-center coordinates of a selector-addressed element in a Firefox
774
- * tab, scrolled into view first — the (x, y) `input.performActions` clicks.
775
- * Throws when the element is gone or has zero size (off-screen / display:none).
776
- */
777
- private firefoxRefCoords;
778
- /**
779
- * Screenshot a Firefox tab over BiDi. Same output contract as the CDP path:
780
- * `raw` is a pixel-faithful PNG; the default is JPEG iteratively downscaled
781
- * under 100 KB so chat-injected screenshots stay token-cheap.
782
- */
783
- private screenshotFirefox;
784
- /** Connect a profile at `target`, register it under `key`, and arm downloads. */
785
- private openConnection;
786
- /**
787
- * Open a tab for a HUMAN to read, bound to no task.
788
- *
789
- * That is the entire difference from {@link start}, and it is the point. The
790
- * abandoned-task reaper closes a task's tabs when the calling session dies or
791
- * after the idle window, but it "deliberately never touches a tab that is not
792
- * in `task.tabs`" (hygiene.ts) — so a viewer tab must not be in one, or the
793
- * artifact the user is reading vanishes when the agent that rendered it exits.
794
- *
795
- * Consequently `stop`/`done` do not close it either, which is correct: it is
796
- * the user's tab now.
797
- */
798
- showUrl(profileName: ProfileName, url: string, opts?: {
799
- endpointName?: string;
800
- fleetRemote?: boolean;
801
- actor?: string;
802
- probe?: DeviceProbe;
803
- }): Promise<{
804
- profile: ProfileName;
805
- key: ConnectionKey;
806
- tabId: string;
807
- device: string;
808
- picked?: string;
809
- }>;
810
- getHistory(limit?: number): Promise<HistoricalTask[]>;
811
- }
812
- export {};