@flrande/browserctl 0.5.0 → 0.6.0
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/dist/client.d.ts +34 -0
- package/dist/client.js +138 -0
- package/dist/commandRegistry.d.ts +16 -0
- package/dist/commandRegistry.js +21 -0
- package/dist/help.d.ts +4 -0
- package/dist/help.js +24 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +23 -0
- package/dist/runCli.d.ts +5 -0
- package/dist/runCli.js +170 -0
- package/package.json +32 -57
- package/INSTALL-CN.md +0 -92
- package/INSTALL.md +0 -92
- package/LICENSE +0 -21
- package/README-CN.md +0 -69
- package/README.md +0 -69
- package/apps/browserctl/src/commands/a11y-snapshot.ts +0 -20
- package/apps/browserctl/src/commands/act.test.ts +0 -71
- package/apps/browserctl/src/commands/act.ts +0 -64
- package/apps/browserctl/src/commands/command-wrappers.test.ts +0 -688
- package/apps/browserctl/src/commands/common.test.ts +0 -87
- package/apps/browserctl/src/commands/common.ts +0 -191
- package/apps/browserctl/src/commands/console-list.test.ts +0 -102
- package/apps/browserctl/src/commands/console-list.ts +0 -108
- package/apps/browserctl/src/commands/cookie-clear.ts +0 -18
- package/apps/browserctl/src/commands/cookie-get.ts +0 -18
- package/apps/browserctl/src/commands/cookie-set.ts +0 -22
- package/apps/browserctl/src/commands/dialog-arm.ts +0 -20
- package/apps/browserctl/src/commands/dom-query-all.ts +0 -18
- package/apps/browserctl/src/commands/dom-query.ts +0 -18
- package/apps/browserctl/src/commands/download-trigger.ts +0 -22
- package/apps/browserctl/src/commands/download-wait.test.ts +0 -67
- package/apps/browserctl/src/commands/download-wait.ts +0 -27
- package/apps/browserctl/src/commands/element-screenshot.ts +0 -20
- package/apps/browserctl/src/commands/frame-list.ts +0 -16
- package/apps/browserctl/src/commands/frame-snapshot.ts +0 -18
- package/apps/browserctl/src/commands/har-export.test.ts +0 -112
- package/apps/browserctl/src/commands/har-export.ts +0 -120
- package/apps/browserctl/src/commands/memory-delete.ts +0 -20
- package/apps/browserctl/src/commands/memory-inspect.ts +0 -20
- package/apps/browserctl/src/commands/memory-list.ts +0 -90
- package/apps/browserctl/src/commands/memory-mode-set.ts +0 -29
- package/apps/browserctl/src/commands/memory-purge.ts +0 -16
- package/apps/browserctl/src/commands/memory-resolve.ts +0 -56
- package/apps/browserctl/src/commands/memory-status.ts +0 -16
- package/apps/browserctl/src/commands/memory-ttl-set.ts +0 -28
- package/apps/browserctl/src/commands/memory-upsert.ts +0 -142
- package/apps/browserctl/src/commands/network-list.test.ts +0 -110
- package/apps/browserctl/src/commands/network-list.ts +0 -112
- package/apps/browserctl/src/commands/network-wait-for.test.ts +0 -90
- package/apps/browserctl/src/commands/network-wait-for.ts +0 -100
- package/apps/browserctl/src/commands/profile-list.ts +0 -16
- package/apps/browserctl/src/commands/profile-use.ts +0 -18
- package/apps/browserctl/src/commands/response-body.ts +0 -24
- package/apps/browserctl/src/commands/screenshot.ts +0 -16
- package/apps/browserctl/src/commands/session-drop.test.ts +0 -36
- package/apps/browserctl/src/commands/session-drop.ts +0 -16
- package/apps/browserctl/src/commands/session-list.test.ts +0 -81
- package/apps/browserctl/src/commands/session-list.ts +0 -70
- package/apps/browserctl/src/commands/snapshot.ts +0 -16
- package/apps/browserctl/src/commands/status.ts +0 -10
- package/apps/browserctl/src/commands/storage-get.ts +0 -20
- package/apps/browserctl/src/commands/storage-set.ts +0 -22
- package/apps/browserctl/src/commands/tab-close.ts +0 -20
- package/apps/browserctl/src/commands/tab-focus.ts +0 -20
- package/apps/browserctl/src/commands/tab-open.ts +0 -19
- package/apps/browserctl/src/commands/tabs.ts +0 -13
- package/apps/browserctl/src/commands/trace-get.test.ts +0 -61
- package/apps/browserctl/src/commands/trace-get.ts +0 -62
- package/apps/browserctl/src/commands/upload-arm.ts +0 -26
- package/apps/browserctl/src/commands/wait-element.test.ts +0 -80
- package/apps/browserctl/src/commands/wait-element.ts +0 -76
- package/apps/browserctl/src/commands/wait-text.test.ts +0 -110
- package/apps/browserctl/src/commands/wait-text.ts +0 -93
- package/apps/browserctl/src/commands/wait-url.test.ts +0 -80
- package/apps/browserctl/src/commands/wait-url.ts +0 -76
- package/apps/browserctl/src/daemon-client.test.ts +0 -253
- package/apps/browserctl/src/daemon-client.ts +0 -632
- package/apps/browserctl/src/e2e.test.ts +0 -103
- package/apps/browserctl/src/main.dispatch.test.ts +0 -461
- package/apps/browserctl/src/main.test.ts +0 -334
- package/apps/browserctl/src/main.ts +0 -957
- package/apps/browserctl/src/smoke.e2e.test.ts +0 -97
- package/apps/browserctl/src/test-port.ts +0 -26
- package/apps/browserd/src/bootstrap.ts +0 -432
- package/apps/browserd/src/chrome-relay-extension-bridge.test.ts +0 -250
- package/apps/browserd/src/chrome-relay-extension-bridge.ts +0 -506
- package/apps/browserd/src/container.ts +0 -3088
- package/apps/browserd/src/main.test.ts +0 -1436
- package/apps/browserd/src/main.ts +0 -7
- package/apps/browserd/src/test-port.ts +0 -26
- package/apps/browserd/src/tool-matrix.test.ts +0 -887
- package/bin/browserctl.cjs +0 -21
- package/bin/browserd.cjs +0 -21
- package/extensions/chrome-relay/README-CN.md +0 -39
- package/extensions/chrome-relay/README.md +0 -39
- package/extensions/chrome-relay/background.js +0 -1687
- package/extensions/chrome-relay/manifest.json +0 -15
- package/extensions/chrome-relay/popup.html +0 -369
- package/extensions/chrome-relay/popup.js +0 -972
- package/packages/core/src/bootstrap.test.ts +0 -10
- package/packages/core/src/driver-registry.test.ts +0 -45
- package/packages/core/src/driver-registry.ts +0 -22
- package/packages/core/src/driver.ts +0 -47
- package/packages/core/src/index.ts +0 -6
- package/packages/core/src/navigation-memory.test.ts +0 -259
- package/packages/core/src/navigation-memory.ts +0 -360
- package/packages/core/src/ref-cache.test.ts +0 -61
- package/packages/core/src/ref-cache.ts +0 -28
- package/packages/core/src/session-store.test.ts +0 -82
- package/packages/core/src/session-store.ts +0 -138
- package/packages/core/src/types.ts +0 -9
- package/packages/driver-chrome-relay/src/chrome-relay-driver.test.ts +0 -744
- package/packages/driver-chrome-relay/src/chrome-relay-driver.ts +0 -2429
- package/packages/driver-chrome-relay/src/chrome-relay-extension-runtime.test.ts +0 -264
- package/packages/driver-chrome-relay/src/chrome-relay-extension-runtime.ts +0 -521
- package/packages/driver-chrome-relay/src/index.ts +0 -26
- package/packages/driver-managed/src/index.ts +0 -22
- package/packages/driver-managed/src/managed-driver.test.ts +0 -183
- package/packages/driver-managed/src/managed-driver.ts +0 -341
- package/packages/driver-managed/src/managed-local-driver.test.ts +0 -608
- package/packages/driver-managed/src/managed-local-driver.ts +0 -2243
- package/packages/driver-remote-cdp/src/index.ts +0 -19
- package/packages/driver-remote-cdp/src/remote-cdp-driver.test.ts +0 -727
- package/packages/driver-remote-cdp/src/remote-cdp-driver.ts +0 -2264
- package/packages/protocol/src/envelope.test.ts +0 -25
- package/packages/protocol/src/envelope.ts +0 -31
- package/packages/protocol/src/errors.test.ts +0 -17
- package/packages/protocol/src/errors.ts +0 -11
- package/packages/protocol/src/index.ts +0 -3
- package/packages/protocol/src/tools.ts +0 -3
- package/packages/transport-mcp-stdio/src/index.ts +0 -3
- package/packages/transport-mcp-stdio/src/sdk-server.ts +0 -139
- package/packages/transport-mcp-stdio/src/server.test.ts +0 -281
- package/packages/transport-mcp-stdio/src/server.ts +0 -183
- package/packages/transport-mcp-stdio/src/tool-map.ts +0 -84
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { stopDaemon } from "./daemon-client";
|
|
4
|
-
import { EXIT_CODES, runCli } from "./main";
|
|
5
|
-
import { reserveLoopbackPort } from "./test-port";
|
|
6
|
-
|
|
7
|
-
const TEST_SESSION_ID = "session:e2e";
|
|
8
|
-
let testDaemonPort = 0;
|
|
9
|
-
|
|
10
|
-
function createIoCapture() {
|
|
11
|
-
const state = {
|
|
12
|
-
stdout: "",
|
|
13
|
-
stderr: ""
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
return {
|
|
17
|
-
state,
|
|
18
|
-
io: {
|
|
19
|
-
stdout: {
|
|
20
|
-
write(content: string) {
|
|
21
|
-
state.stdout += content;
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
stderr: {
|
|
25
|
-
write(content: string) {
|
|
26
|
-
state.stderr += content;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function parseJsonLine(state: { stdout: string }): Record<string, unknown> {
|
|
34
|
-
return JSON.parse(state.stdout.trim()) as Record<string, unknown>;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
beforeEach(async () => {
|
|
38
|
-
testDaemonPort = await reserveLoopbackPort();
|
|
39
|
-
process.env.BROWSERCTL_DAEMON_PORT = String(testDaemonPort);
|
|
40
|
-
process.env.BROWSERD_MANAGED_LOCAL_ENABLED = "false";
|
|
41
|
-
process.env.BROWSERD_DEFAULT_DRIVER = "managed";
|
|
42
|
-
process.env.BROWSERD_CHROME_RELAY_MODE = "cdp";
|
|
43
|
-
await stopDaemon(testDaemonPort);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
afterEach(async () => {
|
|
47
|
-
await stopDaemon(testDaemonPort);
|
|
48
|
-
delete process.env.BROWSERCTL_DAEMON_PORT;
|
|
49
|
-
delete process.env.BROWSERD_MANAGED_LOCAL_ENABLED;
|
|
50
|
-
delete process.env.BROWSERD_DEFAULT_DRIVER;
|
|
51
|
-
delete process.env.BROWSERD_CHROME_RELAY_MODE;
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
describe("browserctl e2e", () => {
|
|
55
|
-
it("reuses daemon state across multiple commands in the same session", async () => {
|
|
56
|
-
const startCapture = createIoCapture();
|
|
57
|
-
const startExitCode = await runCli(["daemon-start", "--json"], startCapture.io);
|
|
58
|
-
|
|
59
|
-
expect(startExitCode).toBe(EXIT_CODES.OK);
|
|
60
|
-
const startPayload = parseJsonLine(startCapture.state);
|
|
61
|
-
expect(startPayload.ok).toBe(true);
|
|
62
|
-
const startData = startPayload.data as Record<string, unknown>;
|
|
63
|
-
expect(startData.running).toBe(true);
|
|
64
|
-
expect(startData.port).toBe(testDaemonPort);
|
|
65
|
-
|
|
66
|
-
const openCapture = createIoCapture();
|
|
67
|
-
const openExitCode = await runCli(
|
|
68
|
-
["tab-open", "--session", TEST_SESSION_ID, "https://example.com", "--json"],
|
|
69
|
-
openCapture.io
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
expect(openExitCode).toBe(EXIT_CODES.OK);
|
|
73
|
-
const openPayload = parseJsonLine(openCapture.state);
|
|
74
|
-
expect(openPayload.ok).toBe(true);
|
|
75
|
-
const openData = openPayload.data as Record<string, unknown>;
|
|
76
|
-
expect(openData.driver).toBe("managed");
|
|
77
|
-
const targetId = openData.targetId;
|
|
78
|
-
expect(typeof targetId).toBe("string");
|
|
79
|
-
|
|
80
|
-
const listCapture = createIoCapture();
|
|
81
|
-
const listExitCode = await runCli(["tabs", "--session", TEST_SESSION_ID, "--json"], listCapture.io);
|
|
82
|
-
|
|
83
|
-
expect(listExitCode).toBe(EXIT_CODES.OK);
|
|
84
|
-
const listPayload = parseJsonLine(listCapture.state);
|
|
85
|
-
expect(listPayload.ok).toBe(true);
|
|
86
|
-
const listData = listPayload.data as { tabs: string[] };
|
|
87
|
-
expect(listData.tabs).toContain(targetId);
|
|
88
|
-
|
|
89
|
-
const consoleCapture = createIoCapture();
|
|
90
|
-
const consoleExitCode = await runCli(
|
|
91
|
-
["console-list", "--session", TEST_SESSION_ID, String(targetId), "--json"],
|
|
92
|
-
consoleCapture.io
|
|
93
|
-
);
|
|
94
|
-
expect(consoleExitCode).toBe(EXIT_CODES.OK);
|
|
95
|
-
const consolePayload = parseJsonLine(consoleCapture.state);
|
|
96
|
-
expect(consolePayload.ok).toBe(true);
|
|
97
|
-
expect(consolePayload.data).toMatchObject({
|
|
98
|
-
driver: "managed",
|
|
99
|
-
targetId,
|
|
100
|
-
entries: []
|
|
101
|
-
});
|
|
102
|
-
}, 20_000);
|
|
103
|
-
});
|
|
@@ -1,461 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
import * as a11ySnapshotCommand from "./commands/a11y-snapshot";
|
|
4
|
-
import * as consoleListCommand from "./commands/console-list";
|
|
5
|
-
import * as cookieClearCommand from "./commands/cookie-clear";
|
|
6
|
-
import * as cookieGetCommand from "./commands/cookie-get";
|
|
7
|
-
import * as cookieSetCommand from "./commands/cookie-set";
|
|
8
|
-
import * as daemonClient from "./daemon-client";
|
|
9
|
-
import * as dialogArmCommand from "./commands/dialog-arm";
|
|
10
|
-
import * as domQueryAllCommand from "./commands/dom-query-all";
|
|
11
|
-
import * as domQueryCommand from "./commands/dom-query";
|
|
12
|
-
import * as downloadTriggerCommand from "./commands/download-trigger";
|
|
13
|
-
import * as downloadWaitCommand from "./commands/download-wait";
|
|
14
|
-
import * as elementScreenshotCommand from "./commands/element-screenshot";
|
|
15
|
-
import * as frameListCommand from "./commands/frame-list";
|
|
16
|
-
import * as frameSnapshotCommand from "./commands/frame-snapshot";
|
|
17
|
-
import * as harExportCommand from "./commands/har-export";
|
|
18
|
-
import * as networkListCommand from "./commands/network-list";
|
|
19
|
-
import * as networkWaitForCommand from "./commands/network-wait-for";
|
|
20
|
-
import * as profileListCommand from "./commands/profile-list";
|
|
21
|
-
import * as profileUseCommand from "./commands/profile-use";
|
|
22
|
-
import * as responseBodyCommand from "./commands/response-body";
|
|
23
|
-
import * as sessionDropCommand from "./commands/session-drop";
|
|
24
|
-
import * as sessionListCommand from "./commands/session-list";
|
|
25
|
-
import * as snapshotCommand from "./commands/snapshot";
|
|
26
|
-
import * as storageGetCommand from "./commands/storage-get";
|
|
27
|
-
import * as storageSetCommand from "./commands/storage-set";
|
|
28
|
-
import * as tabCloseCommand from "./commands/tab-close";
|
|
29
|
-
import * as tabFocusCommand from "./commands/tab-focus";
|
|
30
|
-
import * as tabOpenCommand from "./commands/tab-open";
|
|
31
|
-
import * as traceGetCommand from "./commands/trace-get";
|
|
32
|
-
import * as uploadArmCommand from "./commands/upload-arm";
|
|
33
|
-
import * as waitElementCommand from "./commands/wait-element";
|
|
34
|
-
import * as waitTextCommand from "./commands/wait-text";
|
|
35
|
-
import * as waitUrlCommand from "./commands/wait-url";
|
|
36
|
-
import { EXIT_CODES, runCli } from "./main";
|
|
37
|
-
|
|
38
|
-
function createIoCapture() {
|
|
39
|
-
const state = {
|
|
40
|
-
stdout: "",
|
|
41
|
-
stderr: ""
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
state,
|
|
46
|
-
io: {
|
|
47
|
-
stdout: {
|
|
48
|
-
write(content: string) {
|
|
49
|
-
state.stdout += content;
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
stderr: {
|
|
53
|
-
write(content: string) {
|
|
54
|
-
state.stderr += content;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const ORIGINAL_BROWSERCTL_AUTH_TOKEN = process.env.BROWSERCTL_AUTH_TOKEN;
|
|
62
|
-
const ORIGINAL_BROWSERCTL_BROWSER = process.env.BROWSERCTL_BROWSER;
|
|
63
|
-
|
|
64
|
-
type DispatchCase = {
|
|
65
|
-
command: string;
|
|
66
|
-
commandArgs: string[];
|
|
67
|
-
moduleRef: Record<string, unknown>;
|
|
68
|
-
handlerName: string;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
type MemoryDispatchCase = {
|
|
72
|
-
command: string;
|
|
73
|
-
commandArgs: string[];
|
|
74
|
-
expectedTool: string;
|
|
75
|
-
expectedArgs: Record<string, unknown>;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const COMMAND_DISPATCH_CASES: DispatchCase[] = [
|
|
79
|
-
{
|
|
80
|
-
command: "a11y-snapshot",
|
|
81
|
-
commandArgs: ["target:1"],
|
|
82
|
-
moduleRef: a11ySnapshotCommand as unknown as Record<string, unknown>,
|
|
83
|
-
handlerName: "runA11ySnapshotCommand"
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
command: "console-list",
|
|
87
|
-
commandArgs: ["target:1"],
|
|
88
|
-
moduleRef: consoleListCommand as unknown as Record<string, unknown>,
|
|
89
|
-
handlerName: "runConsoleListCommand"
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
command: "cookie-clear",
|
|
93
|
-
commandArgs: ["target:1"],
|
|
94
|
-
moduleRef: cookieClearCommand as unknown as Record<string, unknown>,
|
|
95
|
-
handlerName: "runCookieClearCommand"
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
command: "cookie-get",
|
|
99
|
-
commandArgs: ["target:1"],
|
|
100
|
-
moduleRef: cookieGetCommand as unknown as Record<string, unknown>,
|
|
101
|
-
handlerName: "runCookieGetCommand"
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
command: "cookie-set",
|
|
105
|
-
commandArgs: ["target:1", "sid", "abc"],
|
|
106
|
-
moduleRef: cookieSetCommand as unknown as Record<string, unknown>,
|
|
107
|
-
handlerName: "runCookieSetCommand"
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
command: "dialog-arm",
|
|
111
|
-
commandArgs: ["target:1"],
|
|
112
|
-
moduleRef: dialogArmCommand as unknown as Record<string, unknown>,
|
|
113
|
-
handlerName: "runDialogArmCommand"
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
command: "dom-query",
|
|
117
|
-
commandArgs: ["target:1", "#root"],
|
|
118
|
-
moduleRef: domQueryCommand as unknown as Record<string, unknown>,
|
|
119
|
-
handlerName: "runDomQueryCommand"
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
command: "dom-query-all",
|
|
123
|
-
commandArgs: ["target:1", ".item"],
|
|
124
|
-
moduleRef: domQueryAllCommand as unknown as Record<string, unknown>,
|
|
125
|
-
handlerName: "runDomQueryAllCommand"
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
command: "download-trigger",
|
|
129
|
-
commandArgs: ["target:1"],
|
|
130
|
-
moduleRef: downloadTriggerCommand as unknown as Record<string, unknown>,
|
|
131
|
-
handlerName: "runDownloadTriggerCommand"
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
command: "download-wait",
|
|
135
|
-
commandArgs: ["target:1"],
|
|
136
|
-
moduleRef: downloadWaitCommand as unknown as Record<string, unknown>,
|
|
137
|
-
handlerName: "runDownloadWaitCommand"
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
command: "element-screenshot",
|
|
141
|
-
commandArgs: ["target:1", "#hero"],
|
|
142
|
-
moduleRef: elementScreenshotCommand as unknown as Record<string, unknown>,
|
|
143
|
-
handlerName: "runElementScreenshotCommand"
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
command: "frame-list",
|
|
147
|
-
commandArgs: ["target:1"],
|
|
148
|
-
moduleRef: frameListCommand as unknown as Record<string, unknown>,
|
|
149
|
-
handlerName: "runFrameListCommand"
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
command: "frame-snapshot",
|
|
153
|
-
commandArgs: ["target:1", "frame:0"],
|
|
154
|
-
moduleRef: frameSnapshotCommand as unknown as Record<string, unknown>,
|
|
155
|
-
handlerName: "runFrameSnapshotCommand"
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
command: "har-export",
|
|
159
|
-
commandArgs: ["target:1"],
|
|
160
|
-
moduleRef: harExportCommand as unknown as Record<string, unknown>,
|
|
161
|
-
handlerName: "runHarExportCommand"
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
command: "network-list",
|
|
165
|
-
commandArgs: ["target:1"],
|
|
166
|
-
moduleRef: networkListCommand as unknown as Record<string, unknown>,
|
|
167
|
-
handlerName: "runNetworkListCommand"
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
command: "network-wait-for",
|
|
171
|
-
commandArgs: ["target:1", "/api", "1000"],
|
|
172
|
-
moduleRef: networkWaitForCommand as unknown as Record<string, unknown>,
|
|
173
|
-
handlerName: "runNetworkWaitForCommand"
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
command: "profile-list",
|
|
177
|
-
commandArgs: [],
|
|
178
|
-
moduleRef: profileListCommand as unknown as Record<string, unknown>,
|
|
179
|
-
handlerName: "runProfileListCommand"
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
command: "profile-use",
|
|
183
|
-
commandArgs: ["managed"],
|
|
184
|
-
moduleRef: profileUseCommand as unknown as Record<string, unknown>,
|
|
185
|
-
handlerName: "runProfileUseCommand"
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
command: "response-body",
|
|
189
|
-
commandArgs: ["target:1", "request:1"],
|
|
190
|
-
moduleRef: responseBodyCommand as unknown as Record<string, unknown>,
|
|
191
|
-
handlerName: "runResponseBodyCommand"
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
command: "session-drop",
|
|
195
|
-
commandArgs: ["tenant-a:job-1"],
|
|
196
|
-
moduleRef: sessionDropCommand as unknown as Record<string, unknown>,
|
|
197
|
-
handlerName: "runSessionDropCommand"
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
command: "session-list",
|
|
201
|
-
commandArgs: ["--tenant", "ops", "--limit", "10"],
|
|
202
|
-
moduleRef: sessionListCommand as unknown as Record<string, unknown>,
|
|
203
|
-
handlerName: "runSessionListCommand"
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
command: "snapshot",
|
|
207
|
-
commandArgs: ["target:1"],
|
|
208
|
-
moduleRef: snapshotCommand as unknown as Record<string, unknown>,
|
|
209
|
-
handlerName: "runSnapshotCommand"
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
command: "storage-get",
|
|
213
|
-
commandArgs: ["target:1", "local", "theme"],
|
|
214
|
-
moduleRef: storageGetCommand as unknown as Record<string, unknown>,
|
|
215
|
-
handlerName: "runStorageGetCommand"
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
command: "storage-set",
|
|
219
|
-
commandArgs: ["target:1", "local", "theme", "dark"],
|
|
220
|
-
moduleRef: storageSetCommand as unknown as Record<string, unknown>,
|
|
221
|
-
handlerName: "runStorageSetCommand"
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
command: "tab-close",
|
|
225
|
-
commandArgs: ["target:1"],
|
|
226
|
-
moduleRef: tabCloseCommand as unknown as Record<string, unknown>,
|
|
227
|
-
handlerName: "runTabCloseCommand"
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
command: "tab-focus",
|
|
231
|
-
commandArgs: ["target:1"],
|
|
232
|
-
moduleRef: tabFocusCommand as unknown as Record<string, unknown>,
|
|
233
|
-
handlerName: "runTabFocusCommand"
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
command: "tab-open",
|
|
237
|
-
commandArgs: ["https://example.com"],
|
|
238
|
-
moduleRef: tabOpenCommand as unknown as Record<string, unknown>,
|
|
239
|
-
handlerName: "runTabOpenCommand"
|
|
240
|
-
},
|
|
241
|
-
{
|
|
242
|
-
command: "trace-get",
|
|
243
|
-
commandArgs: ["--limit", "10"],
|
|
244
|
-
moduleRef: traceGetCommand as unknown as Record<string, unknown>,
|
|
245
|
-
handlerName: "runTraceGetCommand"
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
command: "wait-element",
|
|
249
|
-
commandArgs: ["target:1", "#root", "1500"],
|
|
250
|
-
moduleRef: waitElementCommand as unknown as Record<string, unknown>,
|
|
251
|
-
handlerName: "runWaitElementCommand"
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
command: "wait-text",
|
|
255
|
-
commandArgs: ["target:1", "ready"],
|
|
256
|
-
moduleRef: waitTextCommand as unknown as Record<string, unknown>,
|
|
257
|
-
handlerName: "runWaitTextCommand"
|
|
258
|
-
},
|
|
259
|
-
{
|
|
260
|
-
command: "wait-url",
|
|
261
|
-
commandArgs: ["target:1", "/dashboard"],
|
|
262
|
-
moduleRef: waitUrlCommand as unknown as Record<string, unknown>,
|
|
263
|
-
handlerName: "runWaitUrlCommand"
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
command: "upload-arm",
|
|
267
|
-
commandArgs: ["target:1", "upload.txt"],
|
|
268
|
-
moduleRef: uploadArmCommand as unknown as Record<string, unknown>,
|
|
269
|
-
handlerName: "runUploadArmCommand"
|
|
270
|
-
}
|
|
271
|
-
];
|
|
272
|
-
|
|
273
|
-
const MEMORY_DISPATCH_CASES: MemoryDispatchCase[] = [
|
|
274
|
-
{
|
|
275
|
-
command: "memory-status",
|
|
276
|
-
commandArgs: [],
|
|
277
|
-
expectedTool: "browser.memory.status",
|
|
278
|
-
expectedArgs: {
|
|
279
|
-
sessionId: "cli:local"
|
|
280
|
-
}
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
command: "memory-mode-set",
|
|
284
|
-
commandArgs: ["ask"],
|
|
285
|
-
expectedTool: "browser.memory.mode.set",
|
|
286
|
-
expectedArgs: {
|
|
287
|
-
sessionId: "cli:local",
|
|
288
|
-
mode: "ask"
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
{
|
|
292
|
-
command: "memory-resolve",
|
|
293
|
-
commandArgs: ["forum.example", "open_profile"],
|
|
294
|
-
expectedTool: "browser.memory.resolve",
|
|
295
|
-
expectedArgs: {
|
|
296
|
-
sessionId: "cli:local",
|
|
297
|
-
domain: "forum.example",
|
|
298
|
-
profileId: "default",
|
|
299
|
-
intentKey: "open_profile"
|
|
300
|
-
}
|
|
301
|
-
},
|
|
302
|
-
{
|
|
303
|
-
command: "memory-upsert",
|
|
304
|
-
commandArgs: [
|
|
305
|
-
"forum.example",
|
|
306
|
-
"open_profile",
|
|
307
|
-
"--signals-json",
|
|
308
|
-
"[{\"kind\":\"urlPattern\",\"value\":\"/profile\"}]",
|
|
309
|
-
"--confidence",
|
|
310
|
-
"0.9",
|
|
311
|
-
"--confirmed"
|
|
312
|
-
],
|
|
313
|
-
expectedTool: "browser.memory.upsert",
|
|
314
|
-
expectedArgs: {
|
|
315
|
-
sessionId: "cli:local",
|
|
316
|
-
domain: "forum.example",
|
|
317
|
-
profileId: "default",
|
|
318
|
-
intentKey: "open_profile",
|
|
319
|
-
signals: [{ kind: "urlPattern", value: "/profile" }],
|
|
320
|
-
confidence: 0.9,
|
|
321
|
-
confirmed: true
|
|
322
|
-
}
|
|
323
|
-
},
|
|
324
|
-
{
|
|
325
|
-
command: "memory-list",
|
|
326
|
-
commandArgs: ["--domain", "forum.example", "--profile-id", "managed", "--intent-key", "open_profile"],
|
|
327
|
-
expectedTool: "browser.memory.list",
|
|
328
|
-
expectedArgs: {
|
|
329
|
-
sessionId: "cli:local",
|
|
330
|
-
domain: "forum.example",
|
|
331
|
-
profileId: "managed",
|
|
332
|
-
intentKey: "open_profile"
|
|
333
|
-
}
|
|
334
|
-
},
|
|
335
|
-
{
|
|
336
|
-
command: "memory-inspect",
|
|
337
|
-
commandArgs: ["memory:1"],
|
|
338
|
-
expectedTool: "browser.memory.inspect",
|
|
339
|
-
expectedArgs: {
|
|
340
|
-
sessionId: "cli:local",
|
|
341
|
-
id: "memory:1"
|
|
342
|
-
}
|
|
343
|
-
},
|
|
344
|
-
{
|
|
345
|
-
command: "memory-delete",
|
|
346
|
-
commandArgs: ["memory:1"],
|
|
347
|
-
expectedTool: "browser.memory.delete",
|
|
348
|
-
expectedArgs: {
|
|
349
|
-
sessionId: "cli:local",
|
|
350
|
-
id: "memory:1"
|
|
351
|
-
}
|
|
352
|
-
},
|
|
353
|
-
{
|
|
354
|
-
command: "memory-purge",
|
|
355
|
-
commandArgs: [],
|
|
356
|
-
expectedTool: "browser.memory.purge",
|
|
357
|
-
expectedArgs: {
|
|
358
|
-
sessionId: "cli:local"
|
|
359
|
-
}
|
|
360
|
-
},
|
|
361
|
-
{
|
|
362
|
-
command: "memory-ttl-set",
|
|
363
|
-
commandArgs: ["7"],
|
|
364
|
-
expectedTool: "browser.memory.ttl.set",
|
|
365
|
-
expectedArgs: {
|
|
366
|
-
sessionId: "cli:local",
|
|
367
|
-
ttlDays: 7
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
];
|
|
371
|
-
|
|
372
|
-
afterEach(() => {
|
|
373
|
-
vi.restoreAllMocks();
|
|
374
|
-
if (ORIGINAL_BROWSERCTL_AUTH_TOKEN === undefined) {
|
|
375
|
-
delete process.env.BROWSERCTL_AUTH_TOKEN;
|
|
376
|
-
} else {
|
|
377
|
-
process.env.BROWSERCTL_AUTH_TOKEN = ORIGINAL_BROWSERCTL_AUTH_TOKEN;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
if (ORIGINAL_BROWSERCTL_BROWSER === undefined) {
|
|
381
|
-
delete process.env.BROWSERCTL_BROWSER;
|
|
382
|
-
} else {
|
|
383
|
-
process.env.BROWSERCTL_BROWSER = ORIGINAL_BROWSERCTL_BROWSER;
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
beforeEach(() => {
|
|
388
|
-
delete process.env.BROWSERCTL_AUTH_TOKEN;
|
|
389
|
-
delete process.env.BROWSERCTL_BROWSER;
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
describe("cli dispatch matrix", () => {
|
|
393
|
-
it.each(COMMAND_DISPATCH_CASES)(
|
|
394
|
-
"dispatches $command to $handlerName",
|
|
395
|
-
async ({ command, commandArgs, moduleRef, handlerName }) => {
|
|
396
|
-
const handler = moduleRef[handlerName] as ((args: string[]) => Promise<unknown>) | undefined;
|
|
397
|
-
if (typeof handler !== "function") {
|
|
398
|
-
throw new Error(`Expected ${handlerName} to be a function.`);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const handlerSpy = vi.spyOn(moduleRef as Record<string, (...args: unknown[]) => unknown>, handlerName)
|
|
402
|
-
.mockResolvedValue({ ok: true });
|
|
403
|
-
const { io, state } = createIoCapture();
|
|
404
|
-
|
|
405
|
-
const exitCode = await runCli([command, ...commandArgs], io);
|
|
406
|
-
|
|
407
|
-
expect(exitCode).toBe(EXIT_CODES.OK);
|
|
408
|
-
expect(state.stderr).toBe("");
|
|
409
|
-
expect(state.stdout).toMatch(new RegExp(`^${command}: `));
|
|
410
|
-
expect(handlerSpy).toHaveBeenCalledTimes(1);
|
|
411
|
-
expect(handlerSpy).toHaveBeenCalledWith(commandArgs);
|
|
412
|
-
}
|
|
413
|
-
);
|
|
414
|
-
|
|
415
|
-
it("dispatches daemon-stop through daemon client", async () => {
|
|
416
|
-
const stopSpy = vi.spyOn(daemonClient, "stopDaemon").mockResolvedValue({
|
|
417
|
-
stopped: true,
|
|
418
|
-
port: 41337,
|
|
419
|
-
pid: 12345
|
|
420
|
-
});
|
|
421
|
-
const { io, state } = createIoCapture();
|
|
422
|
-
|
|
423
|
-
const exitCode = await runCli(["daemon-stop", "--json"], io);
|
|
424
|
-
|
|
425
|
-
expect(exitCode).toBe(EXIT_CODES.OK);
|
|
426
|
-
expect(stopSpy).toHaveBeenCalledTimes(1);
|
|
427
|
-
expect(JSON.parse(state.stdout)).toEqual({
|
|
428
|
-
ok: true,
|
|
429
|
-
command: "daemon-stop",
|
|
430
|
-
data: {
|
|
431
|
-
stopped: true,
|
|
432
|
-
port: 41337,
|
|
433
|
-
pid: 12345
|
|
434
|
-
}
|
|
435
|
-
});
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
it.each(MEMORY_DISPATCH_CASES)(
|
|
439
|
-
"dispatches $command to $expectedTool",
|
|
440
|
-
async ({ command, commandArgs, expectedTool, expectedArgs }) => {
|
|
441
|
-
const callDaemonToolSpy = vi.spyOn(daemonClient, "callDaemonTool").mockResolvedValue({
|
|
442
|
-
ok: true
|
|
443
|
-
});
|
|
444
|
-
const { io, state } = createIoCapture();
|
|
445
|
-
|
|
446
|
-
const exitCode = await runCli([command, ...commandArgs, "--json"], io);
|
|
447
|
-
|
|
448
|
-
expect(exitCode).toBe(EXIT_CODES.OK);
|
|
449
|
-
expect(state.stderr).toBe("");
|
|
450
|
-
expect(callDaemonToolSpy).toHaveBeenCalledTimes(1);
|
|
451
|
-
expect(callDaemonToolSpy).toHaveBeenCalledWith(expectedTool, expectedArgs);
|
|
452
|
-
expect(JSON.parse(state.stdout)).toEqual({
|
|
453
|
-
ok: true,
|
|
454
|
-
command,
|
|
455
|
-
data: {
|
|
456
|
-
ok: true
|
|
457
|
-
}
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
);
|
|
461
|
-
});
|