@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.
Files changed (136) hide show
  1. package/dist/client.d.ts +34 -0
  2. package/dist/client.js +138 -0
  3. package/dist/commandRegistry.d.ts +16 -0
  4. package/dist/commandRegistry.js +21 -0
  5. package/dist/help.d.ts +4 -0
  6. package/dist/help.js +24 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.js +23 -0
  9. package/dist/runCli.d.ts +5 -0
  10. package/dist/runCli.js +170 -0
  11. package/package.json +32 -59
  12. package/INSTALL-CN.md +0 -92
  13. package/INSTALL.md +0 -92
  14. package/LICENSE +0 -21
  15. package/README-CN.md +0 -69
  16. package/README.md +0 -69
  17. package/apps/browserctl/src/commands/a11y-snapshot.ts +0 -20
  18. package/apps/browserctl/src/commands/act.test.ts +0 -71
  19. package/apps/browserctl/src/commands/act.ts +0 -64
  20. package/apps/browserctl/src/commands/command-wrappers.test.ts +0 -688
  21. package/apps/browserctl/src/commands/common.test.ts +0 -87
  22. package/apps/browserctl/src/commands/common.ts +0 -191
  23. package/apps/browserctl/src/commands/console-list.test.ts +0 -102
  24. package/apps/browserctl/src/commands/console-list.ts +0 -108
  25. package/apps/browserctl/src/commands/cookie-clear.ts +0 -18
  26. package/apps/browserctl/src/commands/cookie-get.ts +0 -18
  27. package/apps/browserctl/src/commands/cookie-set.ts +0 -22
  28. package/apps/browserctl/src/commands/dialog-arm.ts +0 -20
  29. package/apps/browserctl/src/commands/dom-query-all.ts +0 -18
  30. package/apps/browserctl/src/commands/dom-query.ts +0 -18
  31. package/apps/browserctl/src/commands/download-trigger.ts +0 -22
  32. package/apps/browserctl/src/commands/download-wait.test.ts +0 -67
  33. package/apps/browserctl/src/commands/download-wait.ts +0 -27
  34. package/apps/browserctl/src/commands/element-screenshot.ts +0 -20
  35. package/apps/browserctl/src/commands/frame-list.ts +0 -16
  36. package/apps/browserctl/src/commands/frame-snapshot.ts +0 -18
  37. package/apps/browserctl/src/commands/har-export.test.ts +0 -112
  38. package/apps/browserctl/src/commands/har-export.ts +0 -120
  39. package/apps/browserctl/src/commands/memory-delete.ts +0 -20
  40. package/apps/browserctl/src/commands/memory-inspect.ts +0 -20
  41. package/apps/browserctl/src/commands/memory-list.ts +0 -90
  42. package/apps/browserctl/src/commands/memory-mode-set.ts +0 -29
  43. package/apps/browserctl/src/commands/memory-purge.ts +0 -16
  44. package/apps/browserctl/src/commands/memory-resolve.ts +0 -56
  45. package/apps/browserctl/src/commands/memory-status.ts +0 -16
  46. package/apps/browserctl/src/commands/memory-ttl-set.ts +0 -28
  47. package/apps/browserctl/src/commands/memory-upsert.ts +0 -142
  48. package/apps/browserctl/src/commands/network-list.test.ts +0 -110
  49. package/apps/browserctl/src/commands/network-list.ts +0 -112
  50. package/apps/browserctl/src/commands/network-wait-for.test.ts +0 -90
  51. package/apps/browserctl/src/commands/network-wait-for.ts +0 -100
  52. package/apps/browserctl/src/commands/profile-list.ts +0 -16
  53. package/apps/browserctl/src/commands/profile-use.ts +0 -18
  54. package/apps/browserctl/src/commands/response-body.ts +0 -24
  55. package/apps/browserctl/src/commands/screenshot.ts +0 -16
  56. package/apps/browserctl/src/commands/session-drop.test.ts +0 -36
  57. package/apps/browserctl/src/commands/session-drop.ts +0 -16
  58. package/apps/browserctl/src/commands/session-list.test.ts +0 -81
  59. package/apps/browserctl/src/commands/session-list.ts +0 -70
  60. package/apps/browserctl/src/commands/snapshot.ts +0 -16
  61. package/apps/browserctl/src/commands/status.ts +0 -10
  62. package/apps/browserctl/src/commands/storage-get.ts +0 -20
  63. package/apps/browserctl/src/commands/storage-set.ts +0 -22
  64. package/apps/browserctl/src/commands/tab-close.ts +0 -20
  65. package/apps/browserctl/src/commands/tab-focus.ts +0 -20
  66. package/apps/browserctl/src/commands/tab-open.ts +0 -19
  67. package/apps/browserctl/src/commands/tabs.ts +0 -13
  68. package/apps/browserctl/src/commands/trace-get.test.ts +0 -61
  69. package/apps/browserctl/src/commands/trace-get.ts +0 -62
  70. package/apps/browserctl/src/commands/upload-arm.ts +0 -26
  71. package/apps/browserctl/src/commands/wait-element.test.ts +0 -80
  72. package/apps/browserctl/src/commands/wait-element.ts +0 -76
  73. package/apps/browserctl/src/commands/wait-text.test.ts +0 -110
  74. package/apps/browserctl/src/commands/wait-text.ts +0 -93
  75. package/apps/browserctl/src/commands/wait-url.test.ts +0 -80
  76. package/apps/browserctl/src/commands/wait-url.ts +0 -76
  77. package/apps/browserctl/src/daemon-client.test.ts +0 -512
  78. package/apps/browserctl/src/daemon-client.ts +0 -632
  79. package/apps/browserctl/src/e2e.test.ts +0 -103
  80. package/apps/browserctl/src/main.dispatch.test.ts +0 -461
  81. package/apps/browserctl/src/main.test.ts +0 -334
  82. package/apps/browserctl/src/main.ts +0 -957
  83. package/apps/browserctl/src/smoke.e2e.test.ts +0 -97
  84. package/apps/browserctl/src/test-port.ts +0 -26
  85. package/apps/browserd/src/bootstrap.ts +0 -432
  86. package/apps/browserd/src/chrome-relay-extension-bridge.test.ts +0 -250
  87. package/apps/browserd/src/chrome-relay-extension-bridge.ts +0 -506
  88. package/apps/browserd/src/container.ts +0 -3088
  89. package/apps/browserd/src/main.test.ts +0 -1522
  90. package/apps/browserd/src/main.ts +0 -7
  91. package/apps/browserd/src/test-port.ts +0 -26
  92. package/apps/browserd/src/tool-matrix.test.ts +0 -887
  93. package/bin/browserctl.cjs +0 -21
  94. package/bin/browserd.cjs +0 -21
  95. package/extensions/chrome-relay/README-CN.md +0 -39
  96. package/extensions/chrome-relay/README.md +0 -39
  97. package/extensions/chrome-relay/background.js +0 -1687
  98. package/extensions/chrome-relay/manifest.json +0 -15
  99. package/extensions/chrome-relay/popup.html +0 -369
  100. package/extensions/chrome-relay/popup.js +0 -972
  101. package/packages/core/src/bootstrap.test.ts +0 -10
  102. package/packages/core/src/driver-registry.test.ts +0 -45
  103. package/packages/core/src/driver-registry.ts +0 -22
  104. package/packages/core/src/driver.ts +0 -47
  105. package/packages/core/src/index.ts +0 -6
  106. package/packages/core/src/navigation-memory.test.ts +0 -259
  107. package/packages/core/src/navigation-memory.ts +0 -360
  108. package/packages/core/src/ref-cache.test.ts +0 -61
  109. package/packages/core/src/ref-cache.ts +0 -28
  110. package/packages/core/src/session-store.test.ts +0 -82
  111. package/packages/core/src/session-store.ts +0 -138
  112. package/packages/core/src/types.ts +0 -9
  113. package/packages/driver-chrome-relay/src/chrome-relay-driver.test.ts +0 -744
  114. package/packages/driver-chrome-relay/src/chrome-relay-driver.ts +0 -2429
  115. package/packages/driver-chrome-relay/src/chrome-relay-extension-runtime.test.ts +0 -264
  116. package/packages/driver-chrome-relay/src/chrome-relay-extension-runtime.ts +0 -521
  117. package/packages/driver-chrome-relay/src/index.ts +0 -26
  118. package/packages/driver-managed/src/index.ts +0 -22
  119. package/packages/driver-managed/src/managed-driver.test.ts +0 -183
  120. package/packages/driver-managed/src/managed-driver.ts +0 -341
  121. package/packages/driver-managed/src/managed-local-driver.test.ts +0 -608
  122. package/packages/driver-managed/src/managed-local-driver.ts +0 -2243
  123. package/packages/driver-remote-cdp/src/index.ts +0 -19
  124. package/packages/driver-remote-cdp/src/remote-cdp-driver.test.ts +0 -727
  125. package/packages/driver-remote-cdp/src/remote-cdp-driver.ts +0 -2264
  126. package/packages/protocol/src/envelope.test.ts +0 -25
  127. package/packages/protocol/src/envelope.ts +0 -31
  128. package/packages/protocol/src/errors.test.ts +0 -17
  129. package/packages/protocol/src/errors.ts +0 -11
  130. package/packages/protocol/src/index.ts +0 -3
  131. package/packages/protocol/src/tools.ts +0 -3
  132. package/packages/transport-mcp-stdio/src/index.ts +0 -3
  133. package/packages/transport-mcp-stdio/src/sdk-server.ts +0 -139
  134. package/packages/transport-mcp-stdio/src/server.test.ts +0 -281
  135. package/packages/transport-mcp-stdio/src/server.ts +0 -183
  136. package/packages/transport-mcp-stdio/src/tool-map.ts +0 -84
@@ -1,10 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- describe("workspace bootstrap", () => {
4
- it("loads test runner", () => {
5
- const state = expect.getState();
6
-
7
- expect(state.currentTestName).toContain("loads test runner");
8
- expect(state.testPath).toContain("bootstrap.test.ts");
9
- });
10
- });
@@ -1,45 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import type { BrowserDriver } from "./driver";
4
- import { DriverRegistry } from "./driver-registry";
5
-
6
- function createDriver(): BrowserDriver {
7
- return {
8
- status: async () => ({ kind: "test" }),
9
- listProfiles: async () => [],
10
- listTabs: async () => [],
11
- openTab: async () => "target:1",
12
- focusTab: async () => {},
13
- closeTab: async () => {},
14
- snapshot: async () => ({ html: "" }),
15
- act: async () => ({ ok: true }),
16
- armUpload: async () => {},
17
- armDialog: async () => {},
18
- waitDownload: async () => ({ path: "download.bin" }),
19
- triggerDownload: async () => {}
20
- };
21
- }
22
-
23
- describe("DriverRegistry", () => {
24
- it("returns a registered driver", () => {
25
- const registry = new DriverRegistry();
26
- const driver = createDriver();
27
-
28
- registry.register("managed", driver);
29
-
30
- expect(registry.get("managed")).toBe(driver);
31
- });
32
-
33
- it("throws when registering a duplicate driver name", () => {
34
- const registry = new DriverRegistry();
35
- registry.register("managed", createDriver());
36
-
37
- expect(() => registry.register("managed", createDriver())).toThrowError("Driver already registered: managed");
38
- });
39
-
40
- it("throws when the requested driver is not registered", () => {
41
- const registry = new DriverRegistry();
42
-
43
- expect(() => registry.get("missing")).toThrowError("Unknown driver: missing");
44
- });
45
- });
@@ -1,22 +0,0 @@
1
- import type { BrowserDriver } from "./driver";
2
-
3
- export class DriverRegistry {
4
- readonly #drivers = new Map<string, BrowserDriver>();
5
-
6
- register(name: string, driver: BrowserDriver): void {
7
- if (this.#drivers.has(name)) {
8
- throw new Error(`Driver already registered: ${name}`);
9
- }
10
-
11
- this.#drivers.set(name, driver);
12
- }
13
-
14
- get(name: string): BrowserDriver {
15
- const driver = this.#drivers.get(name);
16
- if (!driver) {
17
- throw new Error(`Unknown driver: ${name}`);
18
- }
19
-
20
- return driver;
21
- }
22
- }
@@ -1,47 +0,0 @@
1
- import type { ProfileId, TargetId } from "./types";
2
-
3
- export type DriverScalar = string | number | boolean | null;
4
- export type DriverValue = DriverScalar | DriverObject | DriverValue[];
5
- export type DriverObject = { [key: string]: DriverValue };
6
-
7
- export type DriverStatus = DriverObject;
8
- export type DriverSnapshot = DriverObject;
9
- export type DriverActionPayload = DriverObject;
10
- export type DriverActionResult = DriverObject;
11
- export type DriverDownloadResult = DriverObject;
12
- export type DriverScreenshot = DriverObject;
13
-
14
- export type DriverAction<TPayload extends DriverObject = DriverActionPayload> = {
15
- type: string;
16
- payload?: TPayload;
17
- };
18
-
19
- export type BrowserDriverScreenshot<
20
- TScreenshot extends DriverObject = DriverScreenshot
21
- > = {
22
- screenshot(targetId: TargetId, profile?: ProfileId): Promise<TScreenshot>;
23
- };
24
-
25
- export interface BrowserDriver<
26
- TStatus extends DriverObject = DriverStatus,
27
- TSnapshot extends DriverObject = DriverSnapshot,
28
- TAction extends DriverAction = DriverAction,
29
- TActionResult extends DriverObject = DriverActionResult,
30
- TDownload extends DriverObject = DriverDownloadResult
31
- > {
32
- status(): Promise<TStatus>;
33
- listProfiles(): Promise<ProfileId[]>;
34
- listTabs(profile?: ProfileId): Promise<TargetId[]>;
35
-
36
- openTab(url: string, profile?: ProfileId): Promise<TargetId>;
37
- focusTab(targetId: TargetId, profile?: ProfileId): Promise<void>;
38
- closeTab(targetId: TargetId, profile?: ProfileId): Promise<void>;
39
-
40
- snapshot(targetId: TargetId, profile?: ProfileId): Promise<TSnapshot>;
41
- act(action: TAction, targetId: TargetId, profile?: ProfileId): Promise<TActionResult>;
42
-
43
- armUpload(targetId: TargetId, files: string[], profile?: ProfileId): Promise<void>;
44
- armDialog(targetId: TargetId, profile?: ProfileId): Promise<void>;
45
- waitDownload(targetId: TargetId, profile?: ProfileId, path?: string): Promise<TDownload>;
46
- triggerDownload(targetId: TargetId, profile?: ProfileId): Promise<void>;
47
- }
@@ -1,6 +0,0 @@
1
- export * from "./types";
2
- export * from "./session-store";
3
- export * from "./navigation-memory";
4
- export * from "./ref-cache";
5
- export * from "./driver";
6
- export * from "./driver-registry";
@@ -1,259 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { mkdtemp, rm } from "node:fs/promises";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
- import { describe, expect, it } from "vitest";
6
-
7
- import { createNavigationMemoryStore } from "./navigation-memory";
8
-
9
- describe("navigation memory contracts", () => {
10
- it("scopes by domain+profile", async () => {
11
- const store = createNavigationMemoryStore({
12
- path: ":memory:",
13
- now: () => 1_000
14
- });
15
-
16
- await store.upsert({
17
- domain: "forum.example",
18
- profileId: "chrome-relay",
19
- intentKey: "open_profile",
20
- signals: [{ kind: "urlPattern", value: "/u/*" }]
21
- });
22
-
23
- const hit = await store.resolve({
24
- domain: "forum.example",
25
- profileId: "chrome-relay",
26
- intentKey: "open_profile"
27
- });
28
- const missByProfile = await store.resolve({
29
- domain: "forum.example",
30
- profileId: "managed-local",
31
- intentKey: "open_profile"
32
- });
33
- const missByDomain = await store.resolve({
34
- domain: "news.example",
35
- profileId: "chrome-relay",
36
- intentKey: "open_profile"
37
- });
38
-
39
- expect(hit.hit).toBe(true);
40
- expect(hit.entry?.signals).toEqual([{ kind: "urlPattern", value: "/u/*" }]);
41
- expect(missByProfile.hit).toBe(false);
42
- expect(missByDomain.hit).toBe(false);
43
- });
44
-
45
- it("implements the core store API", async () => {
46
- let now = 10_000;
47
- const store = createNavigationMemoryStore({
48
- path: ":memory:",
49
- now: () => now,
50
- ttlDays: 1
51
- });
52
-
53
- const upserted = await store.upsert({
54
- domain: "news.example",
55
- profileId: "chrome-relay",
56
- intentKey: "hot",
57
- signals: [{ kind: "selector", value: "#hot-list" }],
58
- confidence: 0.7
59
- });
60
-
61
- expect(upserted.created).toBe(true);
62
- expect((await store.list())).toHaveLength(1);
63
- expect(await store.inspect(upserted.entry.id)).toMatchObject({
64
- id: upserted.entry.id,
65
- domain: "news.example",
66
- profileId: "chrome-relay",
67
- intentKey: "hot"
68
- });
69
-
70
- await store.setMode("ask");
71
- await store.setTtlDays(0);
72
- expect(store.status()).toMatchObject({
73
- mode: "ask",
74
- ttlDays: 0,
75
- totalEntries: 0
76
- });
77
-
78
- now += 1;
79
- expect(await store.purgeExpired()).toBe(1);
80
- expect(await store.delete(upserted.entry.id)).toBe(false);
81
- expect(await store.list()).toHaveLength(0);
82
- });
83
-
84
- it("keeps task1 store in-memory even when path is set", async () => {
85
- const dirPath = await mkdtemp(join(tmpdir(), "navigation-memory-task1-"));
86
- const filePath = join(dirPath, "navigation-memory.json");
87
-
88
- try {
89
- const store = createNavigationMemoryStore({
90
- path: filePath,
91
- now: () => 1_000
92
- });
93
-
94
- await store.upsert({
95
- domain: "forum.example",
96
- profileId: "chrome-relay",
97
- intentKey: "open_profile",
98
- signals: [{ kind: "urlPattern", value: "/u/*" }]
99
- });
100
-
101
- expect(existsSync(filePath)).toBe(false);
102
- } finally {
103
- await rm(dirPath, { recursive: true, force: true });
104
- }
105
- });
106
-
107
- it("does not revive expired entries when ttl days changes", async () => {
108
- const dayMs = 24 * 60 * 60 * 1000;
109
- let now = 5_000;
110
- const store = createNavigationMemoryStore({
111
- path: ":memory:",
112
- now: () => now,
113
- ttlDays: 1
114
- });
115
-
116
- const upserted = await store.upsert({
117
- domain: "forum.example",
118
- profileId: "chrome-relay",
119
- intentKey: "open_profile",
120
- signals: [{ kind: "selector", value: "#profile-link" }]
121
- });
122
-
123
- now += dayMs + 1;
124
-
125
- const status = await store.setTtlDays(30);
126
- expect(status.totalEntries).toBe(0);
127
- expect(await store.inspect(upserted.entry.id)).toBeUndefined();
128
- });
129
-
130
- it("supports extracted setMode and setTtlDays calls", async () => {
131
- const store = createNavigationMemoryStore({
132
- path: ":memory:"
133
- });
134
-
135
- const { setMode, setTtlDays } = store;
136
-
137
- const modeStatus = await setMode("ask");
138
- expect(modeStatus.mode).toBe("ask");
139
-
140
- const ttlStatus = await setTtlDays(7);
141
- expect(ttlStatus.ttlDays).toBe(7);
142
-
143
- expect(store.status()).toMatchObject({
144
- mode: "ask",
145
- ttlDays: 7
146
- });
147
- });
148
-
149
- it("renews expireAt when resolve hits", async () => {
150
- let now = 10_000;
151
- const dayMs = 24 * 60 * 60 * 1000;
152
- const store = createNavigationMemoryStore({
153
- path: ":memory:",
154
- now: () => now,
155
- ttlDays: 30
156
- });
157
-
158
- const created = await store.upsert({
159
- domain: "news.example",
160
- profileId: "chrome-relay",
161
- intentKey: "hot",
162
- signals: []
163
- });
164
-
165
- const before = await store.inspect(created.entry.id);
166
- now += 60_000;
167
-
168
- const first = await store.resolve({
169
- domain: "news.example",
170
- profileId: "chrome-relay",
171
- intentKey: "hot"
172
- });
173
-
174
- expect(first.hit).toBe(true);
175
- expect(first.entry).toBeDefined();
176
- expect(first.entry!.expireAt).not.toBe(before!.expireAt);
177
- expect(first.entry!.expireAt).toBe(new Date(now + 30 * dayMs).toISOString());
178
-
179
- const inspected = await store.inspect(first.entry!.id);
180
- expect(inspected!.hitCount).toBe(1);
181
- expect(inspected!.expireAt).toBe(first.entry!.expireAt);
182
- });
183
-
184
- it("rejects write when mode=ask and no explicit approval", async () => {
185
- const store = createNavigationMemoryStore({ path: ":memory:", mode: "ask" });
186
-
187
- await expect(
188
- store.upsert({
189
- domain: "forum.example",
190
- profileId: "chrome-relay",
191
- intentKey: "open_profile",
192
- signals: [],
193
- confirmed: false
194
- })
195
- ).rejects.toThrow(/confirmation/i);
196
- });
197
-
198
- it("returns miss and does not mutate entry when mode=off on resolve", async () => {
199
- let now = 10_000;
200
- const store = createNavigationMemoryStore({
201
- path: ":memory:",
202
- now: () => now,
203
- ttlDays: 30
204
- });
205
-
206
- const created = await store.upsert({
207
- domain: "forum.example",
208
- profileId: "chrome-relay",
209
- intentKey: "open_profile",
210
- signals: [{ kind: "selector", value: "#profile-link" }]
211
- });
212
-
213
- const before = await store.inspect(created.entry.id);
214
- await store.setMode("off");
215
- now += 5_000;
216
-
217
- const resolved = await store.resolve({
218
- domain: "forum.example",
219
- profileId: "chrome-relay",
220
- intentKey: "open_profile"
221
- });
222
-
223
- expect(resolved.hit).toBe(false);
224
- expect(resolved.entry).toBeUndefined();
225
-
226
- const after = await store.inspect(created.entry.id);
227
- expect(after).toBeDefined();
228
- expect(after!.hitCount).toBe(before!.hitCount);
229
- expect(after!.lastHitAt).toBe(before!.lastHitAt);
230
- expect(after!.expireAt).toBe(before!.expireAt);
231
- });
232
-
233
- it("does not delete expired entry when mode=off resolve is called", async () => {
234
- const store = createNavigationMemoryStore({
235
- path: ":memory:",
236
- now: () => 10_000,
237
- ttlDays: 0
238
- });
239
-
240
- const created = await store.upsert({
241
- domain: "forum.example",
242
- profileId: "chrome-relay",
243
- intentKey: "open_profile",
244
- signals: [{ kind: "selector", value: "#profile-link" }]
245
- });
246
-
247
- await store.setMode("off");
248
-
249
- const resolved = await store.resolve({
250
- domain: "forum.example",
251
- profileId: "chrome-relay",
252
- intentKey: "open_profile"
253
- });
254
-
255
- expect(resolved.hit).toBe(false);
256
- expect(resolved.entry).toBeUndefined();
257
- expect(await store.delete(created.entry.id)).toBe(true);
258
- });
259
- });