@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.
- package/CHANGELOG.md +235 -0
- package/dist/bootstrap.js +4 -11
- package/dist/commands/browser.d.ts +52 -70
- package/dist/commands/browser.js +192 -3562
- package/dist/commands/daemon.d.ts +39 -2
- package/dist/commands/daemon.js +72 -73
- package/dist/commands/events.js +1 -1
- package/dist/commands/exec.js +53 -1
- package/dist/commands/repo.js +13 -49
- package/dist/commands/route.js +5 -5
- package/dist/commands/routines.js +39 -12
- package/dist/commands/sessions-render.d.ts +1 -1
- package/dist/commands/sessions-render.js +0 -1
- package/dist/commands/sessions.test-fixture.d.ts +0 -1
- package/dist/commands/sessions.test-fixture.js +0 -37
- package/dist/commands/setup-browser.d.ts +17 -12
- package/dist/commands/setup-browser.js +52 -87
- package/dist/commands/setup-preferences.d.ts +0 -17
- package/dist/commands/setup-preferences.js +18 -49
- package/dist/commands/setup.js +9 -9
- package/dist/commands/ssh.js +10 -1
- package/dist/commands/sync.js +6 -44
- package/dist/commands/teams.js +0 -1
- package/dist/commands/update.d.ts +19 -0
- package/dist/commands/update.js +34 -6
- package/dist/commands/view.d.ts +12 -1
- package/dist/commands/view.js +47 -2
- package/dist/index.js +107 -26
- package/dist/lib/account-capabilities.js +0 -2
- package/dist/lib/account-catalog.d.ts +38 -0
- package/dist/lib/account-catalog.js +110 -26
- package/dist/lib/account-provider-registry.js +1 -1
- package/dist/lib/account-registry.d.ts +1 -1
- package/dist/lib/account-registry.js +36 -2
- package/dist/lib/accounting/rotate.js +22 -8
- package/dist/lib/accounting/usage-ingest.d.ts +6 -1
- package/dist/lib/accounting/usage-ingest.js +115 -45
- package/dist/lib/accounting/usage-sync.d.ts +134 -31
- package/dist/lib/accounting/usage-sync.js +227 -66
- package/dist/lib/accounting/usage.d.ts +16 -3
- package/dist/lib/accounting/usage.js +26 -8
- package/dist/lib/accounts/slots.d.ts +8 -0
- package/dist/lib/accounts/slots.js +17 -0
- package/dist/lib/add-dir.js +0 -1
- package/dist/lib/agent-cli-commands.js +0 -1
- package/dist/lib/agent-spec/agents.d.ts +6 -7
- package/dist/lib/agent-spec/agents.js +6 -60
- package/dist/lib/auth-health.d.ts +69 -1
- package/dist/lib/auth-health.js +133 -4
- package/dist/lib/browser/context.d.ts +82 -0
- package/dist/lib/browser/context.js +88 -0
- package/dist/lib/browser/paths.d.ts +25 -0
- package/dist/lib/browser/paths.js +51 -0
- package/dist/lib/browser/record.d.ts +38 -0
- package/dist/lib/browser/record.js +57 -0
- package/dist/lib/browser/sessions-list.js +1 -2
- package/dist/lib/browser-client.d.ts +158 -0
- package/dist/lib/browser-client.js +234 -0
- package/dist/lib/channels/owner-sink.d.ts +1 -18
- package/dist/lib/channels/owner-sink.js +29 -82
- package/dist/lib/channels/providers/rush.d.ts +7 -7
- package/dist/lib/channels/providers/rush.js +127 -57
- package/dist/lib/claude-statusline.d.ts +1 -1
- package/dist/lib/claude-statusline.js +15 -3
- package/dist/lib/commands.js +1 -1
- package/dist/lib/crabbox/lease.js +1 -1
- package/dist/lib/crabbox/runtimes.js +1 -3
- package/dist/lib/daemon/account-state-daemon-service.js +1 -0
- package/dist/lib/daemon/auth-sync-service.d.ts +21 -18
- package/dist/lib/daemon/auth-sync-service.js +37 -43
- package/dist/lib/daemon/daemon.d.ts +25 -14
- package/dist/lib/daemon/daemon.js +92 -154
- package/dist/lib/daemon/runner.d.ts +2 -2
- package/dist/lib/daemon/runner.js +32 -9
- package/dist/lib/daemon/self-update-service.d.ts +35 -34
- package/dist/lib/daemon/self-update-service.js +40 -36
- package/dist/lib/daemon/service.d.ts +12 -8
- package/dist/lib/daemon/supervisor.d.ts +65 -54
- package/dist/lib/daemon/supervisor.js +136 -171
- package/dist/lib/daemon/testdata/process-view-start.js +5 -2
- package/dist/lib/daemon/usage-sync-service.d.ts +21 -30
- package/dist/lib/daemon/usage-sync-service.js +46 -78
- package/dist/lib/daemon-health.d.ts +22 -5
- package/dist/lib/daemon-health.js +47 -3
- package/dist/lib/daemon-services.d.ts +1 -1
- package/dist/lib/daemon-services.js +0 -10
- package/dist/lib/daemon-ticks.js +4 -2
- package/dist/lib/devices/doctor-findings.js +8 -11
- package/dist/lib/devices/harness-inventory.js +14 -5
- package/dist/lib/exec-account-home.js +5 -0
- package/dist/lib/exec.js +0 -11
- package/dist/lib/feed/events.js +0 -1
- package/dist/lib/feed/tool-activity.js +5 -2
- package/dist/lib/fleet-shared-state.d.ts +45 -0
- package/dist/lib/fleet-shared-state.js +78 -9
- package/dist/lib/fs-atomic.js +25 -0
- package/dist/lib/harness-auth-capabilities.js +0 -1
- package/dist/lib/helper-versions.js +1 -1
- package/dist/lib/hooks/cache.d.ts +7 -0
- package/dist/lib/hooks/cache.js +27 -2
- package/dist/lib/hooks/install.js +7 -1
- package/dist/lib/hosts/ready.d.ts +38 -8
- package/dist/lib/hosts/ready.js +62 -14
- package/dist/lib/installations/active-check.d.ts +27 -0
- package/dist/lib/installations/active-check.js +61 -0
- package/dist/lib/installations/migrate.js +6 -3
- package/dist/lib/installations/shims.js +9 -7
- package/dist/lib/installations/update.js +21 -15
- package/dist/lib/installations/versions.js +12 -1
- package/dist/lib/manifest.js +1 -1
- package/dist/lib/models.js +0 -2
- package/dist/lib/open-url.js +28 -54
- package/dist/lib/profiles.js +0 -2
- package/dist/lib/refresh.js +1 -1
- package/dist/lib/routine-readiness.d.ts +35 -0
- package/dist/lib/routine-readiness.js +74 -16
- package/dist/lib/rules/compile.js +6 -0
- package/dist/lib/sandbox.js +0 -2
- package/dist/lib/secrets-policy.d.ts +89 -11
- package/dist/lib/secrets-policy.js +175 -28
- package/dist/lib/session/db.d.ts +1 -1
- package/dist/lib/session/db.js +65 -18
- package/dist/lib/session/discover.js +1 -283
- package/dist/lib/session/mirror.d.ts +4 -3
- package/dist/lib/session/mirror.js +4 -3
- package/dist/lib/session/parse.d.ts +0 -2
- package/dist/lib/session/parse.js +1 -138
- package/dist/lib/session/throughput.d.ts +1 -3
- package/dist/lib/session/throughput.js +0 -20
- package/dist/lib/session/types.d.ts +2 -2
- package/dist/lib/session/types.js +2 -2
- package/dist/lib/sessions-client.d.ts +60 -1
- package/dist/lib/sessions-client.js +227 -4
- package/dist/lib/setup-tool-status.js +5 -10
- package/dist/lib/signin-badge.d.ts +3 -2
- package/dist/lib/signin-badge.js +6 -3
- package/dist/lib/smart-launch.js +4 -1
- package/dist/lib/staleness/detectors/commands.d.ts +1 -1
- package/dist/lib/staleness/detectors/hooks.d.ts +1 -1
- package/dist/lib/staleness/detectors/mcp.d.ts +1 -1
- package/dist/lib/staleness/detectors/permissions.d.ts +1 -1
- package/dist/lib/staleness/detectors/plugins.d.ts +1 -1
- package/dist/lib/staleness/detectors/rules.d.ts +1 -1
- package/dist/lib/staleness/detectors/skills.d.ts +1 -1
- package/dist/lib/staleness/detectors/subagents.d.ts +1 -1
- package/dist/lib/staleness/detectors/workflows.d.ts +1 -1
- package/dist/lib/staleness/writers/commands.d.ts +1 -1
- package/dist/lib/staleness/writers/hooks.d.ts +1 -1
- package/dist/lib/staleness/writers/mcp.d.ts +1 -1
- package/dist/lib/staleness/writers/permissions.d.ts +1 -1
- package/dist/lib/staleness/writers/plugins.d.ts +1 -1
- package/dist/lib/staleness/writers/rules.d.ts +1 -1
- package/dist/lib/staleness/writers/skills.d.ts +1 -1
- package/dist/lib/staleness/writers/sources.js +5 -0
- package/dist/lib/staleness/writers/subagents.d.ts +1 -1
- package/dist/lib/staleness/writers/workflows.d.ts +1 -1
- package/dist/lib/state.d.ts +6 -4
- package/dist/lib/state.js +7 -17
- package/dist/lib/teams/parsers.d.ts +1 -1
- package/dist/lib/teams/parsers.js +1 -136
- package/dist/lib/teams/placement-probe.js +50 -15
- package/dist/lib/teams/scheduler.d.ts +7 -0
- package/dist/lib/types.d.ts +10 -1
- package/dist/lib/types.js +1 -1
- package/dist/lib/view-types.d.ts +32 -0
- package/dist/lib/watchdog/read.js +0 -1
- package/dist/lib/watchdog/rotate.js +1 -2
- package/dist/lib/watchdog/runner.js +2 -2
- package/dist/lib/watchdog/watchdog.d.ts +1 -1
- package/dist/lib/watchdog/watchdogTail.js +0 -31
- package/package.json +1 -1
- package/scripts/postinstall.js +8 -8
- package/dist/browser.d.ts +0 -2
- package/dist/browser.js +0 -17
- package/dist/commands/browser-picker.d.ts +0 -18
- package/dist/commands/browser-picker.js +0 -97
- package/dist/lib/browser/arc-discovery.d.ts +0 -52
- package/dist/lib/browser/arc-discovery.js +0 -197
- package/dist/lib/browser/arc-dom.d.ts +0 -14
- package/dist/lib/browser/arc-dom.js +0 -121
- package/dist/lib/browser/caller-identity.d.ts +0 -40
- package/dist/lib/browser/caller-identity.js +0 -175
- package/dist/lib/browser/cdp.d.ts +0 -51
- package/dist/lib/browser/cdp.js +0 -254
- package/dist/lib/browser/chrome.d.ts +0 -141
- package/dist/lib/browser/chrome.js +0 -704
- package/dist/lib/browser/chromium-discovery.d.ts +0 -28
- package/dist/lib/browser/chromium-discovery.js +0 -96
- package/dist/lib/browser/devices.d.ts +0 -34
- package/dist/lib/browser/devices.js +0 -61
- package/dist/lib/browser/domain-skills.d.ts +0 -71
- package/dist/lib/browser/domain-skills.js +0 -195
- package/dist/lib/browser/drivers/arc.d.ts +0 -40
- package/dist/lib/browser/drivers/arc.js +0 -276
- package/dist/lib/browser/drivers/firefox.d.ts +0 -99
- package/dist/lib/browser/drivers/firefox.js +0 -377
- package/dist/lib/browser/drivers/local.d.ts +0 -55
- package/dist/lib/browser/drivers/local.js +0 -266
- package/dist/lib/browser/drivers/ssh.d.ts +0 -120
- package/dist/lib/browser/drivers/ssh.js +0 -467
- package/dist/lib/browser/editor.d.ts +0 -3
- package/dist/lib/browser/editor.js +0 -50
- package/dist/lib/browser/ffmpeg.d.ts +0 -12
- package/dist/lib/browser/ffmpeg.js +0 -184
- package/dist/lib/browser/firefox-discovery.d.ts +0 -69
- package/dist/lib/browser/firefox-discovery.js +0 -162
- package/dist/lib/browser/har.d.ts +0 -85
- package/dist/lib/browser/har.js +0 -77
- package/dist/lib/browser/hygiene.d.ts +0 -97
- package/dist/lib/browser/hygiene.js +0 -153
- package/dist/lib/browser/index.d.ts +0 -5
- package/dist/lib/browser/index.js +0 -5
- package/dist/lib/browser/input.d.ts +0 -7
- package/dist/lib/browser/input.js +0 -92
- package/dist/lib/browser/ipc.d.ts +0 -204
- package/dist/lib/browser/ipc.js +0 -1453
- package/dist/lib/browser/login-detection.d.ts +0 -87
- package/dist/lib/browser/login-detection.js +0 -274
- package/dist/lib/browser/profiles.d.ts +0 -422
- package/dist/lib/browser/profiles.js +0 -1157
- package/dist/lib/browser/refs.d.ts +0 -89
- package/dist/lib/browser/refs.js +0 -191
- package/dist/lib/browser/registry.d.ts +0 -70
- package/dist/lib/browser/registry.js +0 -252
- package/dist/lib/browser/remote-control.d.ts +0 -59
- package/dist/lib/browser/remote-control.js +0 -85
- package/dist/lib/browser/resolve-target.d.ts +0 -66
- package/dist/lib/browser/resolve-target.js +0 -264
- package/dist/lib/browser/runtime-state.d.ts +0 -291
- package/dist/lib/browser/runtime-state.js +0 -584
- package/dist/lib/browser/secret-ref.d.ts +0 -10
- package/dist/lib/browser/secret-ref.js +0 -14
- package/dist/lib/browser/service.d.ts +0 -812
- package/dist/lib/browser/service.js +0 -4693
- package/dist/lib/browser/stream.d.ts +0 -17
- package/dist/lib/browser/stream.js +0 -72
- package/dist/lib/browser/task-index.d.ts +0 -78
- package/dist/lib/browser/task-index.js +0 -199
- package/dist/lib/browser/types.d.ts +0 -647
- package/dist/lib/browser/types.js +0 -61
- package/dist/lib/browser/upload.d.ts +0 -29
- package/dist/lib/browser/upload.js +0 -298
- package/dist/lib/daemon/browser-ipc-service.d.ts +0 -20
- package/dist/lib/daemon/browser-ipc-service.js +0 -46
- package/dist/lib/daemon/browser-task-reap-service.d.ts +0 -14
- package/dist/lib/daemon/browser-task-reap-service.js +0 -26
- package/dist/lib/fleet-shared-repo-sync.d.ts +0 -55
- package/dist/lib/fleet-shared-repo-sync.js +0 -490
package/dist/lib/browser/cdp.js
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
// The `ws` client, NOT the platform (undici) WebSocket: undici enforces a
|
|
2
|
-
// non-configurable max decompressed message size, and a CDP response carrying
|
|
3
|
-
// a base64 screenshot of a content-rich page blows past it — the socket dies
|
|
4
|
-
// with code 1006 ("Max decompressed message size exceeded") while the command
|
|
5
|
-
// is pending. `ws` offers no permessage-deflate by default and takes an
|
|
6
|
-
// explicit payload cap. (Reproduced live against a remote Edge over
|
|
7
|
-
// `browser --device`: fresh blank newtab passed, reused content-rich newtab
|
|
8
|
-
// failed on every Page.captureScreenshot.)
|
|
9
|
-
import WSWebSocket from 'ws';
|
|
10
|
-
const pipeTransports = new Map();
|
|
11
|
-
export function registerPipeTransport(transport) {
|
|
12
|
-
const id = `pipe://${process.pid}/${pipeTransports.size + 1}`;
|
|
13
|
-
pipeTransports.set(id, transport);
|
|
14
|
-
return id;
|
|
15
|
-
}
|
|
16
|
-
export class CDPClient {
|
|
17
|
-
ws = null;
|
|
18
|
-
pipe = null;
|
|
19
|
-
pipeBuffer = Buffer.alloc(0);
|
|
20
|
-
transport = null;
|
|
21
|
-
messageId = 0;
|
|
22
|
-
pending = new Map();
|
|
23
|
-
eventHandlers = new Map();
|
|
24
|
-
pipeDataHandler = null;
|
|
25
|
-
pipeErrorHandler = null;
|
|
26
|
-
pipeCloseHandler = null;
|
|
27
|
-
async connect(endpoint) {
|
|
28
|
-
if (endpoint.startsWith('pipe://')) {
|
|
29
|
-
const transport = pipeTransports.get(endpoint);
|
|
30
|
-
if (!transport) {
|
|
31
|
-
throw new Error('CDP pipe transport is not available in this process');
|
|
32
|
-
}
|
|
33
|
-
pipeTransports.delete(endpoint);
|
|
34
|
-
this.connectPipe(transport);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
return new Promise((resolve, reject) => {
|
|
38
|
-
this.ws = new WSWebSocket(endpoint, { maxPayload: 256 * 1024 * 1024 });
|
|
39
|
-
this.transport = 'websocket';
|
|
40
|
-
this.ws.onopen = () => resolve();
|
|
41
|
-
this.ws.onerror = () => reject(new Error('WebSocket error'));
|
|
42
|
-
this.ws.onclose = () => this.handleClose();
|
|
43
|
-
this.ws.onmessage = (ev) => this.handleMessage(String(ev.data));
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
connectPipe(transport) {
|
|
47
|
-
this.pipe = transport;
|
|
48
|
-
this.transport = 'pipe';
|
|
49
|
-
this.pipeBuffer = Buffer.alloc(0);
|
|
50
|
-
this.pipeDataHandler = (chunk) => this.handlePipeData(chunk);
|
|
51
|
-
this.pipeErrorHandler = (err) => this.handleClose(err);
|
|
52
|
-
this.pipeCloseHandler = () => this.handleClose();
|
|
53
|
-
transport.read.on('data', this.pipeDataHandler);
|
|
54
|
-
transport.read.on('error', this.pipeErrorHandler);
|
|
55
|
-
transport.read.on('close', this.pipeCloseHandler);
|
|
56
|
-
transport.write.on('error', this.pipeErrorHandler);
|
|
57
|
-
transport.write.on('close', this.pipeCloseHandler);
|
|
58
|
-
}
|
|
59
|
-
async send(method, params, sessionId) {
|
|
60
|
-
if (!this.isOpen) {
|
|
61
|
-
// Reached when the underlying browser was killed externally between
|
|
62
|
-
// the daemon establishing the connection and a CDP call going out.
|
|
63
|
-
// The service-layer healthcheck normally catches this on the next
|
|
64
|
-
// `start`, so seeing this in the wild means a request landed against
|
|
65
|
-
// an in-flight conn that just died — tell the user how to recover.
|
|
66
|
-
throw new Error('CDP connection not open — the browser was likely closed externally. ' +
|
|
67
|
-
'Run `agents browser stop --profile <name>` (or restart the daemon) and try again.');
|
|
68
|
-
}
|
|
69
|
-
const id = ++this.messageId;
|
|
70
|
-
const message = sessionId
|
|
71
|
-
? JSON.stringify({ id, method, params, sessionId })
|
|
72
|
-
: JSON.stringify({ id, method, params });
|
|
73
|
-
return new Promise((resolve, reject) => {
|
|
74
|
-
this.pending.set(id, { resolve: resolve, reject });
|
|
75
|
-
if (this.transport === 'pipe') {
|
|
76
|
-
this.pipe.write.write(message + '\0');
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
this.ws.send(message);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
on(event, handler) {
|
|
84
|
-
if (!this.eventHandlers.has(event)) {
|
|
85
|
-
this.eventHandlers.set(event, new Set());
|
|
86
|
-
}
|
|
87
|
-
this.eventHandlers.get(event).add(handler);
|
|
88
|
-
}
|
|
89
|
-
off(event, handler) {
|
|
90
|
-
this.eventHandlers.get(event)?.delete(handler);
|
|
91
|
-
}
|
|
92
|
-
close() {
|
|
93
|
-
if (this.ws) {
|
|
94
|
-
this.ws.close();
|
|
95
|
-
this.ws = null;
|
|
96
|
-
}
|
|
97
|
-
if (this.pipe) {
|
|
98
|
-
if (this.pipeDataHandler)
|
|
99
|
-
this.pipe.read.off('data', this.pipeDataHandler);
|
|
100
|
-
if (this.pipeErrorHandler) {
|
|
101
|
-
this.pipe.read.off('error', this.pipeErrorHandler);
|
|
102
|
-
this.pipe.write.off('error', this.pipeErrorHandler);
|
|
103
|
-
}
|
|
104
|
-
if (this.pipeCloseHandler) {
|
|
105
|
-
this.pipe.read.off('close', this.pipeCloseHandler);
|
|
106
|
-
this.pipe.write.off('close', this.pipeCloseHandler);
|
|
107
|
-
}
|
|
108
|
-
this.pipe.write.end();
|
|
109
|
-
this.pipe = null;
|
|
110
|
-
}
|
|
111
|
-
this.transport = null;
|
|
112
|
-
}
|
|
113
|
-
get connected() {
|
|
114
|
-
return ((this.ws !== null && this.ws.readyState === WSWebSocket.OPEN) ||
|
|
115
|
-
(this.pipe !== null && !this.pipe.write.destroyed));
|
|
116
|
-
}
|
|
117
|
-
get isOpen() {
|
|
118
|
-
return this.connected;
|
|
119
|
-
}
|
|
120
|
-
handlePipeData(chunk) {
|
|
121
|
-
this.pipeBuffer = Buffer.concat([this.pipeBuffer, chunk]);
|
|
122
|
-
let idx = this.pipeBuffer.indexOf(0);
|
|
123
|
-
while (idx !== -1) {
|
|
124
|
-
const frame = this.pipeBuffer.subarray(0, idx).toString('utf8');
|
|
125
|
-
this.pipeBuffer = this.pipeBuffer.subarray(idx + 1);
|
|
126
|
-
if (frame.length > 0)
|
|
127
|
-
this.handleMessage(frame);
|
|
128
|
-
idx = this.pipeBuffer.indexOf(0);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
handleMessage(data) {
|
|
132
|
-
const msg = JSON.parse(data);
|
|
133
|
-
if ('id' in msg) {
|
|
134
|
-
const pending = this.pending.get(msg.id);
|
|
135
|
-
if (pending) {
|
|
136
|
-
this.pending.delete(msg.id);
|
|
137
|
-
if ('error' in msg) {
|
|
138
|
-
pending.reject(new Error(msg.error.message || 'CDP error'));
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
pending.resolve(msg.result);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
else if ('method' in msg) {
|
|
146
|
-
const handlers = this.eventHandlers.get(msg.method);
|
|
147
|
-
if (handlers) {
|
|
148
|
-
for (const handler of handlers) {
|
|
149
|
-
handler(msg.params || {}, msg.sessionId);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
handleClose(err) {
|
|
155
|
-
for (const pending of this.pending.values()) {
|
|
156
|
-
pending.reject(err ?? new Error('CDP connection closed'));
|
|
157
|
-
}
|
|
158
|
-
this.pending.clear();
|
|
159
|
-
this.ws = null;
|
|
160
|
-
this.pipe = null;
|
|
161
|
-
this.transport = null;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
export class BrowserCdpConnectionError extends Error {
|
|
165
|
-
port;
|
|
166
|
-
profileName;
|
|
167
|
-
host;
|
|
168
|
-
constructor(port, profileName = '<name>', host = 'localhost') {
|
|
169
|
-
super(formatBrowserCdpConnectionError(port, profileName, host));
|
|
170
|
-
this.port = port;
|
|
171
|
-
this.profileName = profileName;
|
|
172
|
-
this.host = host;
|
|
173
|
-
this.name = 'BrowserCdpConnectionError';
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
export function formatBrowserCdpConnectionError(port, profileName = '<name>', host = 'localhost') {
|
|
177
|
-
const target = host === 'localhost' || host === '127.0.0.1'
|
|
178
|
-
? `port ${port}`
|
|
179
|
-
: `${host}:${port}`;
|
|
180
|
-
return [
|
|
181
|
-
`Could not connect to Chrome on ${target}.`,
|
|
182
|
-
`- Is Chrome running with --remote-debugging-port=${port}?`,
|
|
183
|
-
`- Try: agents browser start --profile ${profileName}`,
|
|
184
|
-
].join('\n');
|
|
185
|
-
}
|
|
186
|
-
export async function discoverBrowserWsUrl(port, host = 'localhost', profileName = '<name>') {
|
|
187
|
-
// Node's fetch has no default timeout — a port that ACKs the TCP connect
|
|
188
|
-
// but never sends an HTTP response will hang here indefinitely. Bound the
|
|
189
|
-
// discovery probe so the caller can surface an actionable error in seconds,
|
|
190
|
-
// not minutes.
|
|
191
|
-
const controller = new AbortController();
|
|
192
|
-
const timer = setTimeout(() => controller.abort(), 3000);
|
|
193
|
-
let response;
|
|
194
|
-
try {
|
|
195
|
-
response = await fetch(`http://${host}:${port}/json/version`, { signal: controller.signal });
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
throw new BrowserCdpConnectionError(port, profileName, host);
|
|
199
|
-
}
|
|
200
|
-
finally {
|
|
201
|
-
clearTimeout(timer);
|
|
202
|
-
}
|
|
203
|
-
if (!response.ok) {
|
|
204
|
-
throw new BrowserCdpConnectionError(port, profileName, host);
|
|
205
|
-
}
|
|
206
|
-
const data = (await response.json());
|
|
207
|
-
const browserField = data.Browser || data.Product || '';
|
|
208
|
-
return {
|
|
209
|
-
wsUrl: data.webSocketDebuggerUrl,
|
|
210
|
-
browser: normalizeBrowserName(browserField),
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
export function normalizeBrowserName(s) {
|
|
214
|
-
if (!s)
|
|
215
|
-
return 'unknown';
|
|
216
|
-
return s.split('/')[0].trim().toLowerCase().replace(/\s+/g, '-');
|
|
217
|
-
}
|
|
218
|
-
export function verifyBrowserIdentity(reported, expected, port, host = 'localhost') {
|
|
219
|
-
if (expected === 'custom')
|
|
220
|
-
return;
|
|
221
|
-
if (reported === 'unknown')
|
|
222
|
-
return;
|
|
223
|
-
const matches = {
|
|
224
|
-
chrome: ['chrome', 'google-chrome', 'headlesschrome'],
|
|
225
|
-
chromium: ['chromium', 'headlesschrome', 'chrome'],
|
|
226
|
-
// Comet reports itself as plain "Chrome/<version>" in /json/version — it
|
|
227
|
-
// doesn't override the Chromium branding. Accept chrome here so attaching
|
|
228
|
-
// to a Comet instance doesn't trip a false "identity mismatch".
|
|
229
|
-
comet: ['comet', 'chrome'],
|
|
230
|
-
// Arc reports itself as plain "Chrome/<version>" in /json/version (verified
|
|
231
|
-
// live: Arc 1.15x → "Chrome/151"), so accept chrome to avoid a false
|
|
232
|
-
// identity mismatch when attaching to a real Arc.
|
|
233
|
-
arc: ['arc', 'chrome'],
|
|
234
|
-
brave: ['brave', 'brave-browser', 'chrome'],
|
|
235
|
-
// Windows/Chromium Edge reports its /json/version "Browser" field as
|
|
236
|
-
// "Edg/<version>" (the `Edg` token, not `Edge`), which normalizeBrowserName
|
|
237
|
-
// reduces to "edg". Accept it so attaching to a real Edge doesn't trip a
|
|
238
|
-
// false identity mismatch (the profile enum only allows "edge").
|
|
239
|
-
edge: ['edge', 'edg', 'microsoft-edge', 'msedge', 'chrome'],
|
|
240
|
-
};
|
|
241
|
-
const accepted = matches[expected] || [expected];
|
|
242
|
-
if (accepted.includes(reported))
|
|
243
|
-
return;
|
|
244
|
-
const target = host === 'localhost' || host === '127.0.0.1' ? `port ${port}` : `${host}:${port}`;
|
|
245
|
-
throw new Error(`Browser identity mismatch: profile expects "${expected}" but ${target} is serving "${reported}". ` +
|
|
246
|
-
`Stop the running browser (e.g. \`pkill -f ${reported}\`) or update the profile to browser=${reported}, then retry.`);
|
|
247
|
-
}
|
|
248
|
-
export async function listTargets(port, host = 'localhost') {
|
|
249
|
-
const response = await fetch(`http://${host}:${port}/json`);
|
|
250
|
-
if (!response.ok) {
|
|
251
|
-
throw new Error(`Failed to list targets: ${response.status}`);
|
|
252
|
-
}
|
|
253
|
-
return response.json();
|
|
254
|
-
}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import type { ChromeOptions } from './types.js';
|
|
2
|
-
import type { BrowserType } from './types.js';
|
|
3
|
-
/**
|
|
4
|
-
* True when `binaryPath` is a shebang script rather than a native browser
|
|
5
|
-
* executable. The Linux distro launchers (`/usr/bin/brave-browser`, …) are such
|
|
6
|
-
* scripts; `launchBrowser` can't drive one over `--remote-debugging-pipe` (see
|
|
7
|
-
* resolveBrowserBinary). `profiles doctor` uses this to flag a profile whose
|
|
8
|
-
* binary resolves to a wrapper we couldn't unwrap. Shebang scripts are a
|
|
9
|
-
* Linux/Unix concept — returns false on Windows/macOS app bundles.
|
|
10
|
-
*/
|
|
11
|
-
export declare function isLauncherScript(binaryPath: string): boolean;
|
|
12
|
-
export declare function resolveBrowserBinary(binaryPath: string): string;
|
|
13
|
-
export declare function findBrowserPath(browserType: BrowserType, customBinary?: string): string;
|
|
14
|
-
/**
|
|
15
|
-
* Walk the per-platform priority list and return the first browser that's
|
|
16
|
-
* actually installed on disk. Returns null if none of them are present.
|
|
17
|
-
*
|
|
18
|
-
* This is the auto-pick the `agents browser start` command uses when the user
|
|
19
|
-
* doesn't pass `--profile`. The intent matches "use whatever's preinstalled,"
|
|
20
|
-
* but constrained to Chromium-family binaries so CDP works without a new
|
|
21
|
-
* driver layer.
|
|
22
|
-
*/
|
|
23
|
-
export declare function findFirstInstalledBrowser(platform?: string): {
|
|
24
|
-
browserType: BrowserType;
|
|
25
|
-
binary: string;
|
|
26
|
-
} | null;
|
|
27
|
-
/**
|
|
28
|
-
* List every installed Chromium-family browser on this machine, in the platform
|
|
29
|
-
* priority order. Used by `agents setup browser` to offer a pick when more than
|
|
30
|
-
* one is present. Returns [] if none are installed.
|
|
31
|
-
*/
|
|
32
|
-
export declare function listInstalledBrowsers(platform?: string): {
|
|
33
|
-
browserType: BrowserType;
|
|
34
|
-
binary: string;
|
|
35
|
-
}[];
|
|
36
|
-
export interface LaunchResult {
|
|
37
|
-
pid: number;
|
|
38
|
-
port: number;
|
|
39
|
-
wsUrl: string;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* The process that holds a Chromium user-data dir, read from the `SingletonLock`
|
|
43
|
-
* symlink Chromium keeps inside the dir on macOS and Linux (`<host>-<pid>`,
|
|
44
|
-
* PHNX-4042). A live pid means a browser already owns that store: a launch on it
|
|
45
|
-
* would only hand its arguments to the running instance and the requested debug
|
|
46
|
-
* port would never bind. Windows keeps no lock file, so this reports null there
|
|
47
|
-
* and `launchBrowser` catches the hand-off by the child's early exit instead.
|
|
48
|
-
*/
|
|
49
|
-
export declare function storeOccupant(userDataDir: string): {
|
|
50
|
-
pid: number;
|
|
51
|
-
} | null;
|
|
52
|
-
/**
|
|
53
|
-
* The relaunch that makes a browser holding `userDataDir` attachable: the
|
|
54
|
-
* ownership guard reads `--user-data-dir` off the running process, so the
|
|
55
|
-
* owner's normal launch (no flag) can never be verified.
|
|
56
|
-
*/
|
|
57
|
-
export declare function storeRelaunchCommand(browserType: BrowserType, port: number, userDataDir: string, profileDirectory?: string): string;
|
|
58
|
-
/**
|
|
59
|
-
* Resolve a browser-profile secrets bundle into an env map for the child, or an
|
|
60
|
-
* EMPTY map when the bundle is absent, locked, or otherwise unreadable — never a
|
|
61
|
-
* throw and never a prompt. Injecting profile secrets on launch is a BACKGROUND
|
|
62
|
-
* read (the agent is spawning the browser, not a human at a Touch ID sheet), so
|
|
63
|
-
* the read is `agentOnly` (SEC-13: never pop biometry on its own): a `never`/no-ACL
|
|
64
|
-
* or broker-held bundle resolves silently; a locked `hold`/`always` bundle throws,
|
|
65
|
-
* and we swallow it so the launch proceeds without those secrets (an agent that
|
|
66
|
-
* needs them can `agents secrets unlock <bundle>`). Exported so the no-prompt
|
|
67
|
-
* behavior is testable on the real keychain path without spawning a browser.
|
|
68
|
-
*/
|
|
69
|
-
export declare function resolveProfileSecretsEnv(secrets?: string): Promise<Record<string, string>>;
|
|
70
|
-
export declare function launchBrowser(profileName: string, browserType: BrowserType, port: number, options?: ChromeOptions, secrets?: string, customBinary?: string, isElectron?: boolean): Promise<LaunchResult>;
|
|
71
|
-
export declare function killChrome(pid: number): void;
|
|
72
|
-
export declare function getRunningChromeInfo(profileName: string): {
|
|
73
|
-
pid: number;
|
|
74
|
-
port: number;
|
|
75
|
-
} | null;
|
|
76
|
-
/**
|
|
77
|
-
* Prepare `<userDataDir>/Default/Preferences` before launch.
|
|
78
|
-
*
|
|
79
|
-
* Two concerns, one write:
|
|
80
|
-
* - First launch (file absent): stamp the agents-cli profile name so
|
|
81
|
-
* Chromium's UI shows "<profile>" instead of its default "Person 1".
|
|
82
|
-
* Cosmetic; existing files keep whatever Chrome wrote in the meantime.
|
|
83
|
-
* - Every launch (when `persistSessionCookies`): pin
|
|
84
|
-
* `session.restore_on_startup: 1` ("continue where you left off").
|
|
85
|
-
* Chromium purges memory-only session cookies at startup UNLESS this
|
|
86
|
-
* preference says the session will be restored — it keys the purge off
|
|
87
|
-
* the pref, not off tabs actually reopening. Sites like idealista issue
|
|
88
|
-
* login cookies with `expires=-1`, so without this every browser restart
|
|
89
|
-
* silently logs the profile out. The visible tab-restore side effect is
|
|
90
|
-
* suppressed separately via `--no-startup-window` (see launchBrowser).
|
|
91
|
-
*
|
|
92
|
-
* Runs only while the browser is down (called before spawn), so Chromium
|
|
93
|
-
* can't overwrite the patch on exit. Best-effort: a malformed existing file
|
|
94
|
-
* is left untouched (Chromium recovers its own state better than we can),
|
|
95
|
-
* and any I/O hiccup is silently ignored.
|
|
96
|
-
*/
|
|
97
|
-
export declare function ensureProfilePreferences(userDataDir: string, profileName: string, persistSessionCookies: boolean): void;
|
|
98
|
-
/**
|
|
99
|
-
* Is a TCP port currently bound? `lsof` on POSIX, `netstat -ano` on Windows
|
|
100
|
-
* (lsof doesn't exist there). Returns false on any tooling error so port
|
|
101
|
-
* allocation degrades to "assume free" rather than throwing.
|
|
102
|
-
*
|
|
103
|
-
* Exported as the canonical cross-platform probe — `findFreeProfilePort`
|
|
104
|
-
* (profiles.ts) must use this rather than shelling out to lsof directly,
|
|
105
|
-
* or every port scans as free on Windows.
|
|
106
|
-
*/
|
|
107
|
-
export declare function isPortInUse(port: number): boolean;
|
|
108
|
-
export declare function allocatePort(): number;
|
|
109
|
-
/**
|
|
110
|
-
* Read the `--user-data-dir` a running browser process was launched with, by
|
|
111
|
-
* inspecting its command line (PHNX-3967). This is the ownership signal the
|
|
112
|
-
* attach-only guard uses to tell the credentialed canonical browser apart from a
|
|
113
|
-
* foreign port-squatter serving CDP on the same port (e.g. a logged-out
|
|
114
|
-
* `/tmp/...` Comet). Returns null when the pid is gone, exposes no
|
|
115
|
-
* `--user-data-dir`, or the platform probe fails.
|
|
116
|
-
*
|
|
117
|
-
* POSIX: `ps -ww -o command=` (full, un-truncated argv). Windows: the
|
|
118
|
-
* `CommandLine` from `Win32_Process` via PowerShell. The value is captured up to
|
|
119
|
-
* the next ` --<flag>` (or end of line) so a data dir that itself contains a
|
|
120
|
-
* space is not truncated at the space.
|
|
121
|
-
*/
|
|
122
|
-
export declare function getProcessUserDataDir(pid: number): string | null;
|
|
123
|
-
/**
|
|
124
|
-
* Extract the `--user-data-dir` value from a browser command line. Handles both
|
|
125
|
-
* `--user-data-dir=<path>` and `--user-data-dir <path>` and stops the value at
|
|
126
|
-
* the next ` --<flag>` so a path containing spaces survives. Exported for unit
|
|
127
|
-
* testing without a live process.
|
|
128
|
-
*/
|
|
129
|
-
export declare function parseUserDataDirFromCommandLine(cmdline: string): string | null;
|
|
130
|
-
interface PortOccupant {
|
|
131
|
-
pid: number;
|
|
132
|
-
command: string;
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Identify the process listening on a TCP port. Returns null when nothing is bound.
|
|
136
|
-
* Used for clearer error messages when a profile's configured port is taken by a
|
|
137
|
-
* non-debug process (e.g. Comet running without --remote-debugging-port).
|
|
138
|
-
* `lsof` on POSIX; `netstat -ano` + `tasklist` on Windows.
|
|
139
|
-
*/
|
|
140
|
-
export declare function getPortOccupant(port: number): PortOccupant | null;
|
|
141
|
-
export {};
|