@flrande/browserctl 0.5.0-dev.22.1 → 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 -59
- 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 -512
- 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 -1522
- 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,142 +0,0 @@
|
|
|
1
|
-
import { callDaemonTool } from "../daemon-client";
|
|
2
|
-
import { buildToolArguments, parseCommandContext, requirePositionalArg } from "./common";
|
|
3
|
-
|
|
4
|
-
export type MemoryUpsertCommandResult = Record<string, unknown>;
|
|
5
|
-
|
|
6
|
-
type MemoryUpsertOptions = {
|
|
7
|
-
profileId?: string;
|
|
8
|
-
signals: unknown[];
|
|
9
|
-
confidence?: number;
|
|
10
|
-
confirmed?: boolean;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
function requireOptionValue(tokens: string[], index: number, optionName: string): string {
|
|
14
|
-
const value = tokens[index + 1];
|
|
15
|
-
if (value === undefined || value.startsWith("--")) {
|
|
16
|
-
throw new Error(`Missing value for ${optionName}.`);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return value;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function parseNumber(value: string, optionName: string): number {
|
|
23
|
-
const parsed = Number(value);
|
|
24
|
-
if (!Number.isFinite(parsed)) {
|
|
25
|
-
throw new Error(`${optionName} must be a valid number.`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return parsed;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function parseBoolean(value: string, optionName: string): boolean {
|
|
32
|
-
const normalizedValue = value.trim().toLowerCase();
|
|
33
|
-
if (normalizedValue === "true") {
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (normalizedValue === "false") {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
throw new Error(`${optionName} must be true or false when provided with a value.`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function parseSignalsJson(value: string): unknown[] {
|
|
45
|
-
let parsedValue: unknown;
|
|
46
|
-
try {
|
|
47
|
-
parsedValue = JSON.parse(value);
|
|
48
|
-
} catch (error) {
|
|
49
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
50
|
-
throw new Error(`Invalid JSON for --signals-json: ${message}`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (!Array.isArray(parsedValue)) {
|
|
54
|
-
throw new Error("--signals-json must decode to a JSON array.");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return parsedValue;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function parseUpsertOptions(tokens: string[]): MemoryUpsertOptions {
|
|
61
|
-
let profileId: string | undefined;
|
|
62
|
-
let signals: unknown[] | undefined;
|
|
63
|
-
let confidence: number | undefined;
|
|
64
|
-
let confirmed: boolean | undefined;
|
|
65
|
-
|
|
66
|
-
for (let index = 0; index < tokens.length; index += 1) {
|
|
67
|
-
const token = tokens[index];
|
|
68
|
-
if (token === "--profile-id") {
|
|
69
|
-
const value = requireOptionValue(tokens, index, "--profile-id");
|
|
70
|
-
|
|
71
|
-
const trimmedValue = value.trim();
|
|
72
|
-
if (trimmedValue.length === 0) {
|
|
73
|
-
throw new Error("--profile-id must be a non-empty string.");
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
profileId = trimmedValue;
|
|
77
|
-
index += 1;
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (token === "--signals-json") {
|
|
82
|
-
const value = requireOptionValue(tokens, index, "--signals-json");
|
|
83
|
-
|
|
84
|
-
signals = parseSignalsJson(value);
|
|
85
|
-
index += 1;
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (token === "--confidence") {
|
|
90
|
-
const value = requireOptionValue(tokens, index, "--confidence");
|
|
91
|
-
|
|
92
|
-
confidence = parseNumber(value, "--confidence");
|
|
93
|
-
index += 1;
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (token === "--confirmed") {
|
|
98
|
-
const maybeValue = tokens[index + 1];
|
|
99
|
-
if (maybeValue === undefined || maybeValue.startsWith("--")) {
|
|
100
|
-
confirmed = true;
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
confirmed = parseBoolean(maybeValue, "--confirmed");
|
|
105
|
-
index += 1;
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
throw new Error(`Unknown memory-upsert option: ${token}`);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (signals === undefined) {
|
|
113
|
-
throw new Error("Missing value for --signals-json.");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return {
|
|
117
|
-
signals,
|
|
118
|
-
...(profileId !== undefined ? { profileId } : {}),
|
|
119
|
-
...(confidence !== undefined ? { confidence } : {}),
|
|
120
|
-
...(confirmed !== undefined ? { confirmed } : {})
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export async function runMemoryUpsertCommand(args: string[]): Promise<MemoryUpsertCommandResult> {
|
|
125
|
-
const context = parseCommandContext(args);
|
|
126
|
-
const domain = requirePositionalArg(context, 0, "domain");
|
|
127
|
-
const intentKey = requirePositionalArg(context, 1, "intentKey");
|
|
128
|
-
const options = parseUpsertOptions(context.positional.slice(2));
|
|
129
|
-
const profileId = options.profileId ?? context.profile ?? "default";
|
|
130
|
-
|
|
131
|
-
return await callDaemonTool<MemoryUpsertCommandResult>(
|
|
132
|
-
"browser.memory.upsert",
|
|
133
|
-
buildToolArguments(context, {
|
|
134
|
-
domain,
|
|
135
|
-
profileId,
|
|
136
|
-
intentKey,
|
|
137
|
-
signals: options.signals,
|
|
138
|
-
...(options.confidence !== undefined ? { confidence: options.confidence } : {}),
|
|
139
|
-
...(options.confirmed !== undefined ? { confirmed: options.confirmed } : {})
|
|
140
|
-
})
|
|
141
|
-
);
|
|
142
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const { callDaemonToolMock } = vi.hoisted(() => ({
|
|
4
|
-
callDaemonToolMock: vi.fn()
|
|
5
|
-
}));
|
|
6
|
-
|
|
7
|
-
vi.mock("../daemon-client", () => ({
|
|
8
|
-
callDaemonTool: callDaemonToolMock
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
import { runNetworkListCommand } from "./network-list";
|
|
12
|
-
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
callDaemonToolMock.mockReset();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
describe("runNetworkListCommand", () => {
|
|
18
|
-
it("forwards filter options", async () => {
|
|
19
|
-
callDaemonToolMock.mockResolvedValue({ ok: true });
|
|
20
|
-
|
|
21
|
-
await runNetworkListCommand([
|
|
22
|
-
"target:1",
|
|
23
|
-
"--url-contains",
|
|
24
|
-
"/api/",
|
|
25
|
-
"--method",
|
|
26
|
-
"post",
|
|
27
|
-
"--status",
|
|
28
|
-
"201",
|
|
29
|
-
"--since",
|
|
30
|
-
"2026-01-01T00:00:00.000Z",
|
|
31
|
-
"--limit",
|
|
32
|
-
"50"
|
|
33
|
-
]);
|
|
34
|
-
|
|
35
|
-
expect(callDaemonToolMock).toHaveBeenCalledTimes(1);
|
|
36
|
-
expect(callDaemonToolMock).toHaveBeenCalledWith("browser.network.list", {
|
|
37
|
-
sessionId: "cli:local",
|
|
38
|
-
targetId: "target:1",
|
|
39
|
-
urlContains: "/api/",
|
|
40
|
-
method: "POST",
|
|
41
|
-
status: 201,
|
|
42
|
-
since: "2026-01-01T00:00:00.000Z",
|
|
43
|
-
limit: 50
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it.each([
|
|
48
|
-
{
|
|
49
|
-
label: "--url-contains",
|
|
50
|
-
args: ["target:1", "--url-contains"],
|
|
51
|
-
message: "Missing value for --url-contains."
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
label: "--method",
|
|
55
|
-
args: ["target:1", "--method"],
|
|
56
|
-
message: "Missing value for --method."
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
label: "--status",
|
|
60
|
-
args: ["target:1", "--status"],
|
|
61
|
-
message: "Missing value for --status."
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
label: "--since",
|
|
65
|
-
args: ["target:1", "--since"],
|
|
66
|
-
message: "Missing value for --since."
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
label: "--limit",
|
|
70
|
-
args: ["target:1", "--limit"],
|
|
71
|
-
message: "Missing value for --limit."
|
|
72
|
-
}
|
|
73
|
-
])("throws when $label is missing a value", async ({ args, message }) => {
|
|
74
|
-
await expect(runNetworkListCommand(args)).rejects.toThrow(message);
|
|
75
|
-
expect(callDaemonToolMock).not.toHaveBeenCalled();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it.each([
|
|
79
|
-
{
|
|
80
|
-
label: "empty --url-contains",
|
|
81
|
-
args: ["target:1", "--url-contains", " "],
|
|
82
|
-
message: "--url-contains must be a non-empty string."
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
label: "status <= 0",
|
|
86
|
-
args: ["target:1", "--status", "0"],
|
|
87
|
-
message: "--status must be a positive integer."
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
label: "status non-strict integer text",
|
|
91
|
-
args: ["target:1", "--status", "200ok"],
|
|
92
|
-
message: "--status must be a positive integer."
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
label: "limit <= 0",
|
|
96
|
-
args: ["target:1", "--limit", "0"],
|
|
97
|
-
message: "--limit must be a positive integer."
|
|
98
|
-
}
|
|
99
|
-
])("throws on invalid option value: $label", async ({ args, message }) => {
|
|
100
|
-
await expect(runNetworkListCommand(args)).rejects.toThrow(message);
|
|
101
|
-
expect(callDaemonToolMock).not.toHaveBeenCalled();
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it("throws on unknown option token", async () => {
|
|
105
|
-
await expect(runNetworkListCommand(["target:1", "--unknown"]))
|
|
106
|
-
.rejects.toThrow("Unknown network-list option: --unknown");
|
|
107
|
-
|
|
108
|
-
expect(callDaemonToolMock).not.toHaveBeenCalled();
|
|
109
|
-
});
|
|
110
|
-
});
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { callDaemonTool } from "../daemon-client";
|
|
2
|
-
import { buildToolArguments, parseCommandContext, requirePositionalArg } from "./common";
|
|
3
|
-
|
|
4
|
-
export type NetworkListCommandResult = Record<string, unknown>;
|
|
5
|
-
|
|
6
|
-
function parsePositiveInteger(value: string, optionName: string): number {
|
|
7
|
-
const normalized = value.trim();
|
|
8
|
-
if (!/^[1-9]\d*$/.test(normalized)) {
|
|
9
|
-
throw new Error(`${optionName} must be a positive integer.`);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return Number.parseInt(normalized, 10);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function parseNetworkListOptions(tokens: string[]): {
|
|
16
|
-
urlContains?: string;
|
|
17
|
-
method?: string;
|
|
18
|
-
status?: number;
|
|
19
|
-
since?: string;
|
|
20
|
-
limit?: number;
|
|
21
|
-
} {
|
|
22
|
-
let urlContains: string | undefined;
|
|
23
|
-
let method: string | undefined;
|
|
24
|
-
let status: number | undefined;
|
|
25
|
-
let since: string | undefined;
|
|
26
|
-
let limit: number | undefined;
|
|
27
|
-
|
|
28
|
-
for (let index = 0; index < tokens.length; index += 1) {
|
|
29
|
-
const token = tokens[index];
|
|
30
|
-
if (token === "--url-contains") {
|
|
31
|
-
const value = tokens[index + 1];
|
|
32
|
-
if (value === undefined) {
|
|
33
|
-
throw new Error("Missing value for --url-contains.");
|
|
34
|
-
}
|
|
35
|
-
const trimmed = value.trim();
|
|
36
|
-
if (trimmed.length === 0) {
|
|
37
|
-
throw new Error("--url-contains must be a non-empty string.");
|
|
38
|
-
}
|
|
39
|
-
urlContains = trimmed;
|
|
40
|
-
index += 1;
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (token === "--method") {
|
|
45
|
-
const value = tokens[index + 1];
|
|
46
|
-
if (value === undefined) {
|
|
47
|
-
throw new Error("Missing value for --method.");
|
|
48
|
-
}
|
|
49
|
-
method = value.trim().toUpperCase();
|
|
50
|
-
index += 1;
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (token === "--status") {
|
|
55
|
-
const value = tokens[index + 1];
|
|
56
|
-
if (value === undefined) {
|
|
57
|
-
throw new Error("Missing value for --status.");
|
|
58
|
-
}
|
|
59
|
-
status = parsePositiveInteger(value, "--status");
|
|
60
|
-
index += 1;
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (token === "--since") {
|
|
65
|
-
const value = tokens[index + 1];
|
|
66
|
-
if (value === undefined) {
|
|
67
|
-
throw new Error("Missing value for --since.");
|
|
68
|
-
}
|
|
69
|
-
const trimmed = value.trim();
|
|
70
|
-
if (trimmed.length === 0) {
|
|
71
|
-
throw new Error("--since must be a non-empty ISO timestamp.");
|
|
72
|
-
}
|
|
73
|
-
since = trimmed;
|
|
74
|
-
index += 1;
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (token === "--limit") {
|
|
79
|
-
const value = tokens[index + 1];
|
|
80
|
-
if (value === undefined) {
|
|
81
|
-
throw new Error("Missing value for --limit.");
|
|
82
|
-
}
|
|
83
|
-
limit = parsePositiveInteger(value, "--limit");
|
|
84
|
-
index += 1;
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
throw new Error(`Unknown network-list option: ${token}`);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
...(urlContains !== undefined ? { urlContains } : {}),
|
|
93
|
-
...(method !== undefined ? { method } : {}),
|
|
94
|
-
...(status !== undefined ? { status } : {}),
|
|
95
|
-
...(since !== undefined ? { since } : {}),
|
|
96
|
-
...(limit !== undefined ? { limit } : {})
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export async function runNetworkListCommand(args: string[]): Promise<NetworkListCommandResult> {
|
|
101
|
-
const context = parseCommandContext(args);
|
|
102
|
-
const targetId = requirePositionalArg(context, 0, "targetId");
|
|
103
|
-
const options = parseNetworkListOptions(context.positional.slice(1));
|
|
104
|
-
|
|
105
|
-
return await callDaemonTool<NetworkListCommandResult>(
|
|
106
|
-
"browser.network.list",
|
|
107
|
-
buildToolArguments(context, {
|
|
108
|
-
targetId,
|
|
109
|
-
...options
|
|
110
|
-
})
|
|
111
|
-
);
|
|
112
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const { callDaemonToolMock } = vi.hoisted(() => ({
|
|
4
|
-
callDaemonToolMock: vi.fn()
|
|
5
|
-
}));
|
|
6
|
-
|
|
7
|
-
vi.mock("../daemon-client", () => ({
|
|
8
|
-
callDaemonTool: callDaemonToolMock
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
import { runNetworkWaitForCommand } from "./network-wait-for";
|
|
12
|
-
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
callDaemonToolMock.mockReset();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
describe("runNetworkWaitForCommand", () => {
|
|
18
|
-
it("supports positional timeout shorthand", async () => {
|
|
19
|
-
callDaemonToolMock.mockResolvedValue({ ok: true });
|
|
20
|
-
|
|
21
|
-
await runNetworkWaitForCommand(["target:1", "/api", "2500"]);
|
|
22
|
-
|
|
23
|
-
expect(callDaemonToolMock).toHaveBeenCalledTimes(1);
|
|
24
|
-
expect(callDaemonToolMock).toHaveBeenCalledWith("browser.network.waitFor", {
|
|
25
|
-
sessionId: "cli:local",
|
|
26
|
-
targetId: "target:1",
|
|
27
|
-
urlPattern: "/api",
|
|
28
|
-
timeoutMs: 2500
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it.each([
|
|
33
|
-
{
|
|
34
|
-
label: "--method",
|
|
35
|
-
args: ["target:1", "/api", "--method"],
|
|
36
|
-
message: "Missing value for --method."
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
label: "--status",
|
|
40
|
-
args: ["target:1", "/api", "--status"],
|
|
41
|
-
message: "Missing value for --status."
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
label: "--timeout-ms",
|
|
45
|
-
args: ["target:1", "/api", "--timeout-ms"],
|
|
46
|
-
message: "Missing value for --timeout-ms."
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
label: "--poll-ms",
|
|
50
|
-
args: ["target:1", "/api", "--poll-ms"],
|
|
51
|
-
message: "Missing value for --poll-ms."
|
|
52
|
-
}
|
|
53
|
-
])("throws when $label is missing a value", async ({ args, message }) => {
|
|
54
|
-
await expect(runNetworkWaitForCommand(args)).rejects.toThrow(message);
|
|
55
|
-
expect(callDaemonToolMock).not.toHaveBeenCalled();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it.each([
|
|
59
|
-
{
|
|
60
|
-
label: "status <= 0",
|
|
61
|
-
args: ["target:1", "/api", "--status", "0"],
|
|
62
|
-
message: "--status must be a positive integer."
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
label: "timeout <= 0",
|
|
66
|
-
args: ["target:1", "/api", "--timeout-ms", "-10"],
|
|
67
|
-
message: "--timeout-ms must be a positive integer."
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
label: "poll <= 0",
|
|
71
|
-
args: ["target:1", "/api", "--poll-ms", "0"],
|
|
72
|
-
message: "--poll-ms must be a positive integer."
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
label: "positional timeout <= 0",
|
|
76
|
-
args: ["target:1", "/api", "0"],
|
|
77
|
-
message: "timeoutMs must be a positive integer."
|
|
78
|
-
}
|
|
79
|
-
])("throws on non-positive numeric option: $label", async ({ args, message }) => {
|
|
80
|
-
await expect(runNetworkWaitForCommand(args)).rejects.toThrow(message);
|
|
81
|
-
expect(callDaemonToolMock).not.toHaveBeenCalled();
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it("throws on unknown option token", async () => {
|
|
85
|
-
await expect(runNetworkWaitForCommand(["target:1", "/api", "1200", "--unknown"]))
|
|
86
|
-
.rejects.toThrow("Unknown network-wait-for option: --unknown");
|
|
87
|
-
|
|
88
|
-
expect(callDaemonToolMock).not.toHaveBeenCalled();
|
|
89
|
-
});
|
|
90
|
-
});
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { callDaemonTool } from "../daemon-client";
|
|
2
|
-
import { buildToolArguments, parseCommandContext, requirePositionalArg } from "./common";
|
|
3
|
-
|
|
4
|
-
export type NetworkWaitForCommandResult = Record<string, unknown>;
|
|
5
|
-
|
|
6
|
-
function parsePositiveInteger(value: string, optionName: string): number {
|
|
7
|
-
const parsed = Number.parseInt(value, 10);
|
|
8
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
9
|
-
throw new Error(`${optionName} must be a positive integer.`);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return parsed;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function parseNetworkWaitOptions(tokens: string[]): {
|
|
16
|
-
method?: string;
|
|
17
|
-
status?: number;
|
|
18
|
-
timeoutMs?: number;
|
|
19
|
-
pollMs?: number;
|
|
20
|
-
} {
|
|
21
|
-
let method: string | undefined;
|
|
22
|
-
let status: number | undefined;
|
|
23
|
-
let timeoutMs: number | undefined;
|
|
24
|
-
let pollMs: number | undefined;
|
|
25
|
-
|
|
26
|
-
for (let index = 0; index < tokens.length; index += 1) {
|
|
27
|
-
const token = tokens[index];
|
|
28
|
-
if (token === "--method") {
|
|
29
|
-
const value = tokens[index + 1];
|
|
30
|
-
if (value === undefined) {
|
|
31
|
-
throw new Error("Missing value for --method.");
|
|
32
|
-
}
|
|
33
|
-
method = value.trim().toUpperCase();
|
|
34
|
-
index += 1;
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (token === "--status") {
|
|
39
|
-
const value = tokens[index + 1];
|
|
40
|
-
if (value === undefined) {
|
|
41
|
-
throw new Error("Missing value for --status.");
|
|
42
|
-
}
|
|
43
|
-
status = parsePositiveInteger(value, "--status");
|
|
44
|
-
index += 1;
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (token === "--timeout-ms") {
|
|
49
|
-
const value = tokens[index + 1];
|
|
50
|
-
if (value === undefined) {
|
|
51
|
-
throw new Error("Missing value for --timeout-ms.");
|
|
52
|
-
}
|
|
53
|
-
timeoutMs = parsePositiveInteger(value, "--timeout-ms");
|
|
54
|
-
index += 1;
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (token === "--poll-ms") {
|
|
59
|
-
const value = tokens[index + 1];
|
|
60
|
-
if (value === undefined) {
|
|
61
|
-
throw new Error("Missing value for --poll-ms.");
|
|
62
|
-
}
|
|
63
|
-
pollMs = parsePositiveInteger(value, "--poll-ms");
|
|
64
|
-
index += 1;
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (timeoutMs === undefined) {
|
|
69
|
-
timeoutMs = parsePositiveInteger(token, "timeoutMs");
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
throw new Error(`Unknown network-wait-for option: ${token}`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
...(method !== undefined ? { method } : {}),
|
|
78
|
-
...(status !== undefined ? { status } : {}),
|
|
79
|
-
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
80
|
-
...(pollMs !== undefined ? { pollMs } : {})
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export async function runNetworkWaitForCommand(
|
|
85
|
-
args: string[]
|
|
86
|
-
): Promise<NetworkWaitForCommandResult> {
|
|
87
|
-
const context = parseCommandContext(args);
|
|
88
|
-
const targetId = requirePositionalArg(context, 0, "targetId");
|
|
89
|
-
const urlPattern = requirePositionalArg(context, 1, "urlPattern");
|
|
90
|
-
const options = parseNetworkWaitOptions(context.positional.slice(2));
|
|
91
|
-
|
|
92
|
-
return await callDaemonTool<NetworkWaitForCommandResult>(
|
|
93
|
-
"browser.network.waitFor",
|
|
94
|
-
buildToolArguments(context, {
|
|
95
|
-
targetId,
|
|
96
|
-
urlPattern,
|
|
97
|
-
...options
|
|
98
|
-
})
|
|
99
|
-
);
|
|
100
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { callDaemonTool } from "../daemon-client";
|
|
2
|
-
import { buildToolArguments, parseCommandContext } from "./common";
|
|
3
|
-
|
|
4
|
-
export type ProfileListCommandResult = {
|
|
5
|
-
driver: string;
|
|
6
|
-
profiles: string[];
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export async function runProfileListCommand(args: string[] = []): Promise<ProfileListCommandResult> {
|
|
10
|
-
const context = parseCommandContext(args);
|
|
11
|
-
|
|
12
|
-
return await callDaemonTool<ProfileListCommandResult>(
|
|
13
|
-
"browser.profile.list",
|
|
14
|
-
buildToolArguments(context)
|
|
15
|
-
);
|
|
16
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { callDaemonTool } from "../daemon-client";
|
|
2
|
-
import { buildToolArguments, parseCommandContext, requirePositionalArg } from "./common";
|
|
3
|
-
|
|
4
|
-
export type ProfileUseCommandResult = {
|
|
5
|
-
profile: string;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export async function runProfileUseCommand(args: string[]): Promise<ProfileUseCommandResult> {
|
|
9
|
-
const context = parseCommandContext(args);
|
|
10
|
-
const profile = requirePositionalArg(context, 0, "profile");
|
|
11
|
-
|
|
12
|
-
return await callDaemonTool<ProfileUseCommandResult>(
|
|
13
|
-
"browser.profile.use",
|
|
14
|
-
buildToolArguments(context, {
|
|
15
|
-
profile
|
|
16
|
-
})
|
|
17
|
-
);
|
|
18
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { callDaemonTool } from "../daemon-client";
|
|
2
|
-
import { buildToolArguments, parseCommandContext, requirePositionalArg } from "./common";
|
|
3
|
-
|
|
4
|
-
export type ResponseBodyCommandResult = {
|
|
5
|
-
driver: string;
|
|
6
|
-
targetId: string;
|
|
7
|
-
requestId: string;
|
|
8
|
-
body: string;
|
|
9
|
-
encoding: string;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export async function runResponseBodyCommand(args: string[]): Promise<ResponseBodyCommandResult> {
|
|
13
|
-
const context = parseCommandContext(args);
|
|
14
|
-
const targetId = requirePositionalArg(context, 0, "targetId");
|
|
15
|
-
const requestId = requirePositionalArg(context, 1, "requestId");
|
|
16
|
-
|
|
17
|
-
return await callDaemonTool<ResponseBodyCommandResult>(
|
|
18
|
-
"browser.network.responseBody",
|
|
19
|
-
buildToolArguments(context, {
|
|
20
|
-
targetId,
|
|
21
|
-
requestId
|
|
22
|
-
})
|
|
23
|
-
);
|
|
24
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { callDaemonTool } from "../daemon-client";
|
|
2
|
-
import { buildToolArguments, parseCommandContext, requirePositionalArg } from "./common";
|
|
3
|
-
|
|
4
|
-
export type ScreenshotCommandResult = Record<string, unknown>;
|
|
5
|
-
|
|
6
|
-
export async function runScreenshotCommand(args: string[]): Promise<ScreenshotCommandResult> {
|
|
7
|
-
const context = parseCommandContext(args);
|
|
8
|
-
const targetId = requirePositionalArg(context, 0, "targetId");
|
|
9
|
-
|
|
10
|
-
return await callDaemonTool<ScreenshotCommandResult>(
|
|
11
|
-
"browser.screenshot",
|
|
12
|
-
buildToolArguments(context, {
|
|
13
|
-
targetId
|
|
14
|
-
})
|
|
15
|
-
);
|
|
16
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const { callDaemonToolMock } = vi.hoisted(() => ({
|
|
4
|
-
callDaemonToolMock: vi.fn()
|
|
5
|
-
}));
|
|
6
|
-
|
|
7
|
-
vi.mock("../daemon-client", () => ({
|
|
8
|
-
callDaemonTool: callDaemonToolMock
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
import { runSessionDropCommand } from "./session-drop";
|
|
12
|
-
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
callDaemonToolMock.mockReset();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
describe("runSessionDropCommand", () => {
|
|
18
|
-
it("forwards session id to drop", async () => {
|
|
19
|
-
callDaemonToolMock.mockResolvedValue({ ok: true });
|
|
20
|
-
|
|
21
|
-
await runSessionDropCommand(["tenant-a:task-1"]);
|
|
22
|
-
|
|
23
|
-
expect(callDaemonToolMock).toHaveBeenCalledTimes(1);
|
|
24
|
-
expect(callDaemonToolMock).toHaveBeenCalledWith("browser.session.drop", {
|
|
25
|
-
sessionId: "cli:local",
|
|
26
|
-
sessionIdToDelete: "tenant-a:task-1"
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("throws when session id is missing", async () => {
|
|
31
|
-
await expect(runSessionDropCommand([])).rejects.toThrow(
|
|
32
|
-
"Missing required argument: sessionId."
|
|
33
|
-
);
|
|
34
|
-
expect(callDaemonToolMock).not.toHaveBeenCalled();
|
|
35
|
-
});
|
|
36
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { callDaemonTool } from "../daemon-client";
|
|
2
|
-
import { buildToolArguments, parseCommandContext, requirePositionalArg } from "./common";
|
|
3
|
-
|
|
4
|
-
export type SessionDropCommandResult = Record<string, unknown>;
|
|
5
|
-
|
|
6
|
-
export async function runSessionDropCommand(args: string[]): Promise<SessionDropCommandResult> {
|
|
7
|
-
const context = parseCommandContext(args);
|
|
8
|
-
const sessionIdToDelete = requirePositionalArg(context, 0, "sessionId");
|
|
9
|
-
|
|
10
|
-
return await callDaemonTool<SessionDropCommandResult>(
|
|
11
|
-
"browser.session.drop",
|
|
12
|
-
buildToolArguments(context, {
|
|
13
|
-
sessionIdToDelete
|
|
14
|
-
})
|
|
15
|
-
);
|
|
16
|
-
}
|