@oharness/engine 0.7.0 → 0.8.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 (72) hide show
  1. package/dist/agent/agent.d.ts +72 -0
  2. package/dist/agent/agent.js +114 -1
  3. package/dist/agent/agent.js.map +1 -1
  4. package/dist/agent/permissions.js +8 -0
  5. package/dist/agent/permissions.js.map +1 -1
  6. package/dist/browser/cdp.d.ts +75 -0
  7. package/dist/browser/cdp.js +136 -0
  8. package/dist/browser/cdp.js.map +1 -0
  9. package/dist/browser/chrome.d.ts +19 -0
  10. package/dist/browser/chrome.js +306 -0
  11. package/dist/browser/chrome.js.map +1 -0
  12. package/dist/browser/extension.d.ts +35 -0
  13. package/dist/browser/extension.js +297 -0
  14. package/dist/browser/extension.js.map +1 -0
  15. package/dist/browser/host-manifest.d.ts +78 -0
  16. package/dist/browser/host-manifest.js +166 -0
  17. package/dist/browser/host-manifest.js.map +1 -0
  18. package/dist/browser/host.d.ts +27 -0
  19. package/dist/browser/host.js +311 -0
  20. package/dist/browser/host.js.map +1 -0
  21. package/dist/browser/index.d.ts +26 -0
  22. package/dist/browser/index.js +15 -0
  23. package/dist/browser/index.js.map +1 -0
  24. package/dist/browser/login-import.d.ts +98 -0
  25. package/dist/browser/login-import.js +244 -0
  26. package/dist/browser/login-import.js.map +1 -0
  27. package/dist/browser/plugin.d.ts +109 -0
  28. package/dist/browser/plugin.js +22 -0
  29. package/dist/browser/plugin.js.map +1 -0
  30. package/dist/browser/presence.d.ts +29 -0
  31. package/dist/browser/presence.js +54 -0
  32. package/dist/browser/presence.js.map +1 -0
  33. package/dist/browser/provider.d.ts +17 -0
  34. package/dist/browser/provider.js +13 -0
  35. package/dist/browser/provider.js.map +1 -0
  36. package/dist/browser/screencast.d.ts +42 -0
  37. package/dist/browser/screencast.js +99 -0
  38. package/dist/browser/screencast.js.map +1 -0
  39. package/dist/browser/session.d.ts +320 -0
  40. package/dist/browser/session.js +837 -0
  41. package/dist/browser/session.js.map +1 -0
  42. package/dist/browser/snapshot.d.ts +49 -0
  43. package/dist/browser/snapshot.js +145 -0
  44. package/dist/browser/snapshot.js.map +1 -0
  45. package/dist/browser/socket.d.ts +15 -0
  46. package/dist/browser/socket.js +32 -0
  47. package/dist/browser/socket.js.map +1 -0
  48. package/dist/browser/target.d.ts +112 -0
  49. package/dist/browser/target.js +20 -0
  50. package/dist/browser/target.js.map +1 -0
  51. package/dist/browser/tools.d.ts +3 -0
  52. package/dist/browser/tools.js +537 -0
  53. package/dist/browser/tools.js.map +1 -0
  54. package/dist/config.d.ts +14 -0
  55. package/dist/config.js.map +1 -1
  56. package/dist/core/errors.d.ts +12 -0
  57. package/dist/core/errors.js +14 -1
  58. package/dist/core/errors.js.map +1 -1
  59. package/dist/harness.d.ts +49 -0
  60. package/dist/harness.js +97 -1
  61. package/dist/harness.js.map +1 -1
  62. package/dist/index.d.ts +1 -0
  63. package/dist/index.js +1 -0
  64. package/dist/index.js.map +1 -1
  65. package/dist/providers/piai.js +7 -2
  66. package/dist/providers/piai.js.map +1 -1
  67. package/dist/tools/define.d.ts +1 -0
  68. package/dist/tools/define.js +3 -0
  69. package/dist/tools/define.js.map +1 -1
  70. package/dist/tools/types.d.ts +11 -0
  71. package/dist/tools/types.js.map +1 -1
  72. package/package.json +2 -2
@@ -0,0 +1,244 @@
1
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { BrowserError } from "../core/errors.js";
4
+ import { userPath } from "../paths.js";
5
+ /** A page's localStorage can be large; the import is for sign-in, not caches. */
6
+ const LOCAL_STORAGE_LIMIT = 5 * 1024 * 1024;
7
+ /**
8
+ * The site a URL or typed domain names: lower-case host, `www.` dropped so
9
+ * `github.com` and `www.github.com` are one choice in the dialog.
10
+ */
11
+ export function normalizeSite(input) {
12
+ const raw = input.trim().toLowerCase();
13
+ if (!raw)
14
+ return undefined;
15
+ let host;
16
+ try {
17
+ host = new URL(/^[a-z][a-z0-9+.-]*:\/\//.test(raw) ? raw : `https://${raw}`).hostname;
18
+ }
19
+ catch {
20
+ return undefined;
21
+ }
22
+ host = host.replace(/^\.+/, "").replace(/\.$/, "");
23
+ if (!host || /\s/.test(host))
24
+ return undefined;
25
+ // A bare label ("com", "localhost") would match every cookie under it.
26
+ if (!host.includes(".") && host !== "localhost")
27
+ return undefined;
28
+ return host.startsWith("www.") ? host.slice(4) : host;
29
+ }
30
+ /** Whether a host belongs to a site: the site itself or any subdomain of it. */
31
+ export function hostInSite(host, site) {
32
+ const value = host.toLowerCase().replace(/^\.+/, "");
33
+ return value === site || value.endsWith(`.${site}`);
34
+ }
35
+ /**
36
+ * Whether a cookie is part of signing in to `site`.
37
+ *
38
+ * Its own and its subdomains' cookies, and the parent domain's too: signing in
39
+ * to `mail.example.com` often lives in a cookie set on `.example.com`. A public
40
+ * suffix can never carry a cookie, so the parent walk cannot reach `.com`.
41
+ */
42
+ export function cookieInSite(domain, site) {
43
+ const value = domain.toLowerCase().replace(/^\.+/, "");
44
+ if (!value)
45
+ return false;
46
+ return value === site || value.endsWith(`.${site}`) || site.endsWith(`.${value}`);
47
+ }
48
+ /** The http(s) sites open in a browser, grouped the way the dialog lists them. */
49
+ export function groupSites(tabs) {
50
+ const sites = new Map();
51
+ for (const tab of tabs) {
52
+ let parsed;
53
+ try {
54
+ parsed = new URL(tab.url);
55
+ }
56
+ catch {
57
+ continue;
58
+ }
59
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:")
60
+ continue;
61
+ const site = normalizeSite(parsed.hostname);
62
+ if (!site)
63
+ continue;
64
+ const existing = sites.get(site);
65
+ if (existing) {
66
+ existing.tabs++;
67
+ continue;
68
+ }
69
+ sites.set(site, { site, url: parsed.href, ...(tab.title ? { title: tab.title } : {}), tabs: 1 });
70
+ }
71
+ return [...sites.values()];
72
+ }
73
+ /** Which browser the extension lives in, for the dialog. Older extensions cannot say. */
74
+ export async function externalBrowserName(target) {
75
+ const described = await target.describe?.().catch(() => undefined);
76
+ return described?.name || "Chrome";
77
+ }
78
+ async function tabInfos(target) {
79
+ if (target.pageInfos)
80
+ return target.pageInfos();
81
+ const pages = await target.pages();
82
+ return Promise.all(pages.map(async (page) => ({ id: page.id, url: await evaluateString(page, "location.href") })));
83
+ }
84
+ export async function listExternalSites(target) {
85
+ return groupSites(await tabInfos(target));
86
+ }
87
+ /**
88
+ * Read one site's cookies and localStorage from the external browser.
89
+ *
90
+ * Cookies come from the browser-wide store, so any attached tab can answer;
91
+ * localStorage only exists inside a page of its own origin, so it is read from
92
+ * the site's open tabs and is simply absent for a site with none.
93
+ */
94
+ export async function readSiteLoginState(target, site) {
95
+ const infos = await tabInfos(target);
96
+ const web = infos.filter((info) => /^https?:/i.test(info.url));
97
+ const matching = web.filter((info) => {
98
+ try {
99
+ return hostInSite(new URL(info.url).hostname, site);
100
+ }
101
+ catch {
102
+ return false;
103
+ }
104
+ });
105
+ const reader = matching[0] ?? web[0];
106
+ if (!reader)
107
+ throw new BrowserError(`open ${site} in your browser first, so its sign-in can be read`);
108
+ const readerPage = await pageFor(target, reader.id);
109
+ if (!readerPage)
110
+ throw new BrowserError("the browser tab closed before it could be read");
111
+ const cookies = (await readCookies(readerPage, matching.map((info) => info.url).concat(`https://${site}/`, `http://${site}/`)))
112
+ .filter((cookie) => typeof cookie["domain"] === "string" && cookieInSite(cookie["domain"], site))
113
+ .flatMap((cookie) => {
114
+ const param = cookieParam(cookie);
115
+ return param ? [param] : [];
116
+ });
117
+ const origins = [];
118
+ const seen = new Set();
119
+ let budget = LOCAL_STORAGE_LIMIT;
120
+ for (const info of matching) {
121
+ const origin = new URL(info.url).origin;
122
+ if (seen.has(origin))
123
+ continue;
124
+ seen.add(origin);
125
+ const page = info.id === reader.id ? readerPage : await pageFor(target, info.id);
126
+ if (!page)
127
+ continue;
128
+ const entries = await readLocalStorage(page).catch(() => []);
129
+ const kept = [];
130
+ for (const entry of entries) {
131
+ const size = entry[0].length + entry[1].length;
132
+ if (size > budget)
133
+ continue;
134
+ budget -= size;
135
+ kept.push(entry);
136
+ }
137
+ origins.push({ origin, url: info.url, localStorage: kept });
138
+ }
139
+ return { site, cookies, origins };
140
+ }
141
+ async function pageFor(target, id) {
142
+ if (target.pageById)
143
+ return target.pageById(id);
144
+ return (await target.pages()).find((page) => page.id === id);
145
+ }
146
+ async function readCookies(page, urls) {
147
+ const pick = (result) => Array.isArray(result["cookies"])
148
+ ? result["cookies"].filter((cookie) => typeof cookie === "object" && cookie !== null)
149
+ : [];
150
+ // Every cookie, so a subdomain's is not missed; the per-URL form is the
151
+ // fallback for a relay that refuses the browser-wide call.
152
+ try {
153
+ return pick(await page.send("Network.getAllCookies"));
154
+ }
155
+ catch {
156
+ return pick(await page.send("Network.getCookies", { urls: [...new Set(urls)] }));
157
+ }
158
+ }
159
+ async function readLocalStorage(page) {
160
+ const result = await page.send("Runtime.evaluate", {
161
+ expression: "JSON.stringify(Object.entries(localStorage))",
162
+ returnByValue: true,
163
+ });
164
+ const value = (result["result"] ?? {})["value"];
165
+ if (typeof value !== "string")
166
+ return [];
167
+ const parsed = JSON.parse(value);
168
+ return Array.isArray(parsed)
169
+ ? parsed.flatMap((entry) => Array.isArray(entry) && typeof entry[0] === "string" && typeof entry[1] === "string"
170
+ ? [[entry[0], entry[1]]]
171
+ : [])
172
+ : [];
173
+ }
174
+ async function evaluateString(page, expression) {
175
+ const result = await page.send("Runtime.evaluate", { expression, returnByValue: true });
176
+ return String((result["result"] ?? {})["value"] ?? "");
177
+ }
178
+ /**
179
+ * A read cookie, rewritten as one `Network.setCookies` will store identically.
180
+ *
181
+ * A host-only cookie is reported with a bare domain, and passing that back as
182
+ * `domain` would widen it to every subdomain (and make a `__Host-` cookie
183
+ * invalid). So host-only cookies are set by `url`, domain cookies by `domain`.
184
+ * Partitioning and source-port fields are left out: their shapes differ across
185
+ * Chromium versions, and the embedded one rejects what it does not know.
186
+ */
187
+ export function cookieParam(cookie) {
188
+ const { name, value, domain } = cookie;
189
+ if (typeof name !== "string" || typeof value !== "string" || typeof domain !== "string" || !domain)
190
+ return undefined;
191
+ const cookiePath = typeof cookie["path"] === "string" && cookie["path"] ? cookie["path"] : "/";
192
+ const secure = cookie["secure"] === true;
193
+ const param = { name, value, path: cookiePath, secure };
194
+ if (domain.startsWith("."))
195
+ param["domain"] = domain;
196
+ else
197
+ param["url"] = `${secure ? "https" : "http"}://${domain}${cookiePath}`;
198
+ if (cookie["httpOnly"] === true)
199
+ param["httpOnly"] = true;
200
+ if (cookie["sameSite"] === "Strict" || cookie["sameSite"] === "Lax" || cookie["sameSite"] === "None") {
201
+ param["sameSite"] = cookie["sameSite"];
202
+ }
203
+ // A session cookie reads as -1; leaving `expires` out keeps it one.
204
+ if (cookie["session"] !== true && typeof cookie["expires"] === "number" && cookie["expires"] > 0) {
205
+ param["expires"] = cookie["expires"];
206
+ }
207
+ if (cookie["priority"] === "Low" || cookie["priority"] === "Medium" || cookie["priority"] === "High") {
208
+ param["priority"] = cookie["priority"];
209
+ }
210
+ return param;
211
+ }
212
+ /**
213
+ * Sites the person already answered for — imported, or told the suggestion to
214
+ * go away. The built-in profile is shared and persistent, so the answer is too:
215
+ * asking again in the next conversation would be asking the same question.
216
+ */
217
+ export class LoginImportMemory {
218
+ file;
219
+ loaded;
220
+ constructor(file = userPath("browser-import.json")) {
221
+ this.file = file;
222
+ }
223
+ sites() {
224
+ this.loaded ??= readFile(this.file, "utf8")
225
+ .then((text) => {
226
+ const parsed = JSON.parse(text);
227
+ return new Set(Array.isArray(parsed.quiet) ? parsed.quiet.filter((site) => typeof site === "string") : []);
228
+ })
229
+ .catch(() => new Set());
230
+ return this.loaded;
231
+ }
232
+ async has(site) {
233
+ return (await this.sites()).has(site);
234
+ }
235
+ async add(site) {
236
+ const sites = await this.sites();
237
+ if (sites.has(site))
238
+ return;
239
+ sites.add(site);
240
+ await mkdir(path.dirname(this.file), { recursive: true });
241
+ await writeFile(this.file, `${JSON.stringify({ quiet: [...sites].sort() }, null, 2)}\n`, "utf8").catch(() => { });
242
+ }
243
+ }
244
+ //# sourceMappingURL=login-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-import.js","sourceRoot":"","sources":["../../src/browser/login-import.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ import type { Logger } from "../util/logger.ts";
2
+ import type { Tool } from "../tools/types.ts";
3
+ import type { BrowserSessionOptions } from "./session.ts";
4
+ import type { BrowserProviderPlugin } from "./provider.ts";
5
+ import type { ExternalSite, ImportedSite } from "./login-import.ts";
6
+ import type { BrowserInputEvent, FrameOptions } from "./target.ts";
7
+ /** Host-facing surface; custom feature plugins need not subclass BrowserSession. */
8
+ export interface BrowserUseSession {
9
+ readonly running: boolean;
10
+ /** Called once when the eager tool façade is assigned to its first conversation. */
11
+ bind(sessionId: string): void;
12
+ state(): {
13
+ running: boolean;
14
+ origin?: string;
15
+ presentation?: "stream" | "native";
16
+ /** The browser in use now. */
17
+ mode?: "builtin" | "extension";
18
+ /** Which browsers the session may use. */
19
+ policy?: "auto" | "builtin" | "extension";
20
+ };
21
+ viewport(): Promise<{
22
+ width: number;
23
+ height: number;
24
+ } | undefined>;
25
+ url(): Promise<string>;
26
+ frames(opts?: FrameOptions): AsyncIterable<Buffer>;
27
+ forward(event: BrowserInputEvent): Promise<void>;
28
+ navigate(url: string): Promise<{
29
+ url: string;
30
+ status?: number;
31
+ }>;
32
+ reload(): Promise<{
33
+ url: string;
34
+ }>;
35
+ /** Tabs visible to the Browser pane. Optional for third-party feature plugins. */
36
+ paneTabs?(): Promise<Array<{
37
+ id: string;
38
+ url: string;
39
+ title?: string;
40
+ active: boolean;
41
+ mine?: false;
42
+ }>>;
43
+ /** Hand one of the person's own tabs to this conversation, at their request. */
44
+ adoptYourTab?(id: string): Promise<{
45
+ id: string;
46
+ url: string;
47
+ }>;
48
+ /** Make a tab the one used by both the tools and the Browser pane. */
49
+ selectPaneTab?(id: string): Promise<{
50
+ id: string;
51
+ url: string;
52
+ }>;
53
+ /** Close one tab, releasing the browser target when it was the last one. */
54
+ closePaneTab?(id: string): Promise<{
55
+ closed: string;
56
+ active?: string;
57
+ running: boolean;
58
+ }>;
59
+ close(): Promise<void>;
60
+ /** Name the conversation this browser works for; see BrowserTargetContext.label. */
61
+ setLabel?(label: () => string | undefined): void;
62
+ /** Move to the other browser; the next call opens it. Optional for third-party feature plugins. */
63
+ setMode?(mode: "auto" | "builtin" | "extension"): Promise<void>;
64
+ /** The external browser and the sites it has open. Lists tabs; attaches to none. */
65
+ loginImportSources?(): Promise<{
66
+ browser: string;
67
+ sites: ExternalSite[];
68
+ current?: string;
69
+ }>;
70
+ /** Person-confirmed only: copy these sites' sign-in into the built-in profile. */
71
+ importLogin?(sites: readonly string[]): Promise<{
72
+ browser: string;
73
+ imported: ImportedSite[];
74
+ migrated: boolean;
75
+ url?: string;
76
+ }>;
77
+ /** A site the built-in browser is on that the external browser has open too. Never blocks. */
78
+ loginImportSuggestion?(): {
79
+ site: string;
80
+ browser: string;
81
+ } | undefined;
82
+ dismissLoginImport?(site: string): Promise<void>;
83
+ }
84
+ export interface BrowserUseSessionContext {
85
+ sessionId?: string;
86
+ mode: "auto" | "builtin" | "extension";
87
+ logger?: Logger;
88
+ label?: () => string | undefined;
89
+ cwd?: string;
90
+ }
91
+ /**
92
+ * Complete project-level Browser Use feature plugin.
93
+ *
94
+ * This is not an agent-installed plugin. The Harness host loads one feature
95
+ * implementation, then asks it for a session and its tools. Keeping these two
96
+ * operations together means another implementation can replace the entire
97
+ * Browser Use stack rather than only swapping the browser executable.
98
+ */
99
+ export interface BrowserUsePlugin {
100
+ readonly id: string;
101
+ createSession(context: BrowserUseSessionContext): BrowserUseSession;
102
+ tools(session: BrowserUseSession): Tool[];
103
+ }
104
+ export interface DefaultBrowserUsePluginOptions {
105
+ providers?: readonly BrowserProviderPlugin[];
106
+ /** Compatibility seam for older embedders and focused tests. */
107
+ target?: BrowserSessionOptions["target"];
108
+ }
109
+ export declare function createBrowserUsePlugin(opts?: DefaultBrowserUsePluginOptions): BrowserUsePlugin;
@@ -0,0 +1,22 @@
1
+ import { BrowserSession } from "./session.js";
2
+ import { createBrowserTools } from "./tools.js";
3
+ export function createBrowserUsePlugin(opts = {}) {
4
+ return {
5
+ id: "browser-use",
6
+ createSession(context) {
7
+ const session = new BrowserSession({
8
+ ...(opts.target ? { target: opts.target } : {}),
9
+ ...(opts.providers ? { providers: opts.providers } : {}),
10
+ mode: context.mode,
11
+ ...(context.logger ? { logger: context.logger } : {}),
12
+ ...(context.label ? { label: context.label } : {}),
13
+ ...(context.cwd ? { cwd: context.cwd } : {}),
14
+ });
15
+ if (context.sessionId)
16
+ session.bind(context.sessionId);
17
+ return session;
18
+ },
19
+ tools: (session) => createBrowserTools(session),
20
+ };
21
+ }
22
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/browser/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA2EhD,MAAM,UAAU,sBAAsB,CAAC,OAAuC,EAAE;IAC9E,OAAO;QACL,EAAE,EAAE,aAAa;QACjB,aAAa,CAAC,OAAO;YACnB,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC;gBACjC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/C,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxD,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrD,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClD,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC7C,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,SAAS;gBAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACvD,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,kBAAkB,CAAC,OAAyB,CAAC;KAClE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Telling the browser extension where this OHarness is.
3
+ *
4
+ * The extension's side panel shows this process's own page, which lives at a
5
+ * port chosen at startup and opens only with a token made for this run. The
6
+ * extension cannot find either on its own, and the token is never written to
7
+ * disk — so a server says where it is, over the same local socket the
8
+ * extension's native host already listens on, and the host tells the
9
+ * extension. Nothing here leaves the machine.
10
+ *
11
+ * The host exists only while the browser is open, and a new one starts each
12
+ * time the extension's worker restarts. So this keeps trying, on a backoff,
13
+ * and registers again with every host it reaches. None of it keeps the
14
+ * process alive: a server that is otherwise done exits whether or not a
15
+ * browser was ever there to hear about it.
16
+ */
17
+ export interface PresenceInfo {
18
+ /** Where the page is, without the token. */
19
+ url: string;
20
+ token: string;
21
+ /** Which kind of OHarness, so the extension can prefer the desktop app. */
22
+ kind: "desktop" | "web";
23
+ }
24
+ export interface Presence {
25
+ close(): void;
26
+ }
27
+ export declare function announcePresence(info: PresenceInfo, opts?: {
28
+ socketPath?: string;
29
+ }): Presence;
@@ -0,0 +1,54 @@
1
+ import { connect } from "node:net";
2
+ import { extensionSocketPath } from "./socket.js";
3
+ /** Seconds between attempts to reach a host: quick at first, patient after. */
4
+ const BACKOFF = [1, 2, 5, 10, 30];
5
+ export function announcePresence(info, opts = {}) {
6
+ const socketPath = opts.socketPath ?? extensionSocketPath();
7
+ let socket;
8
+ let timer;
9
+ let attempt = 0;
10
+ let closed = false;
11
+ const retry = () => {
12
+ if (closed || timer)
13
+ return;
14
+ const seconds = BACKOFF[Math.min(attempt, BACKOFF.length - 1)];
15
+ attempt += 1;
16
+ timer = setTimeout(() => {
17
+ timer = undefined;
18
+ open();
19
+ }, seconds * 1000);
20
+ timer.unref?.();
21
+ };
22
+ const open = () => {
23
+ if (closed)
24
+ return;
25
+ const current = connect(socketPath);
26
+ socket = current;
27
+ current.unref();
28
+ current.on("connect", () => {
29
+ attempt = 0;
30
+ current.write(`${JSON.stringify({ t: "register", pid: process.pid, ...info })}\n`);
31
+ });
32
+ // Replies and the other harnesses' traffic are none of this connection's
33
+ // business; reading them keeps the socket from backing up.
34
+ current.on("data", () => { });
35
+ current.on("error", () => { });
36
+ current.on("close", () => {
37
+ if (socket === current)
38
+ socket = undefined;
39
+ retry();
40
+ });
41
+ };
42
+ open();
43
+ return {
44
+ close() {
45
+ closed = true;
46
+ if (timer)
47
+ clearTimeout(timer);
48
+ timer = undefined;
49
+ socket?.destroy();
50
+ socket = undefined;
51
+ },
52
+ };
53
+ }
54
+ //# sourceMappingURL=presence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presence.js","sourceRoot":"","sources":["../../src/browser/presence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AA+BlD,+EAA+E;AAC/E,MAAM,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAElC,MAAM,UAAU,gBAAgB,CAAC,IAAkB,EAAE,OAAgC,EAAE;IACrF,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,mBAAmB,EAAE,CAAC;IAC5D,IAAI,MAA0B,CAAC;IAC/B,IAAI,KAAiC,CAAC;IACtC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,IAAI,MAAM,IAAI,KAAK;YAAE,OAAO;QAC5B,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAE,CAAC;QAChE,OAAO,IAAI,CAAC,CAAC;QACb,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YACtB,KAAK,GAAG,SAAS,CAAC;YAClB,IAAI,EAAE,CAAC;QACT,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;QACnB,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IAClB,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,GAAS,EAAE;QACtB,IAAI,MAAM;YAAE,OAAO;QACnB,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QACpC,MAAM,GAAG,OAAO,CAAC;QACjB,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YACzB,OAAO,GAAG,CAAC,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;QACrF,CAAC,CAAC,CAAC;QACH,yEAAyE;QACzE,2DAA2D;QAC3D,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC7B,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC9B,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACvB,IAAI,MAAM,KAAK,OAAO;gBAAE,MAAM,GAAG,SAAS,CAAC;YAC3C,KAAK,EAAE,CAAC;QACV,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,IAAI,EAAE,CAAC;IACP,OAAO;QACL,KAAK;YACH,MAAM,GAAG,IAAI,CAAC;YACd,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,KAAK,GAAG,SAAS,CAAC;YAClB,MAAM,EAAE,OAAO,EAAE,CAAC;YAClB,MAAM,GAAG,SAAS,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { BrowserTargetFactory } from "./target.ts";
2
+ import type { Logger } from "../util/logger.ts";
3
+ /** A replaceable browser runtime used by the Browser Use feature plugin. */
4
+ export interface BrowserProviderPlugin {
5
+ readonly id: string;
6
+ readonly mode: "builtin" | "extension";
7
+ readonly createTarget: BrowserTargetFactory;
8
+ }
9
+ export declare function builtinBrowserProvider(opts?: {
10
+ headless?: boolean;
11
+ logger?: Logger;
12
+ }): BrowserProviderPlugin;
13
+ export declare function extensionBrowserProvider(): BrowserProviderPlugin;
14
+ export declare function browserProviderFor(mode: "builtin" | "extension", providers?: readonly BrowserProviderPlugin[], opts?: {
15
+ headless?: boolean;
16
+ logger?: Logger;
17
+ }): BrowserProviderPlugin;
@@ -0,0 +1,13 @@
1
+ import { launchChrome } from "./chrome.js";
2
+ import { extensionTarget } from "./extension.js";
3
+ export function builtinBrowserProvider(opts = {}) {
4
+ return { id: "chromium", mode: "builtin", createTarget: () => launchChrome(opts) };
5
+ }
6
+ export function extensionBrowserProvider() {
7
+ return { id: "chrome-extension", mode: "extension", createTarget: (context) => extensionTarget(undefined, context) };
8
+ }
9
+ export function browserProviderFor(mode, providers = [], opts = {}) {
10
+ return providers.find((provider) => provider.mode === mode) ??
11
+ (mode === "extension" ? extensionBrowserProvider() : builtinBrowserProvider(opts));
12
+ }
13
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/browser/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAWjD,MAAM,UAAU,sBAAsB,CAAC,OAAgD,EAAE;IACvF,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,OAAO,EAAE,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;AACvH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,IAA6B,EAC7B,YAA8C,EAAE,EAChD,OAAgD,EAAE;IAElD,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC;QACzD,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,wBAAwB,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC;AACvF,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type { FrameOptions } from "./target.ts";
2
+ /**
3
+ * One screencast, however many people are watching it.
4
+ *
5
+ * Three things go wrong with the obvious implementation — start a screencast
6
+ * per consumer, stop it when that consumer leaves — and all three are silent.
7
+ *
8
+ * A still page produces no frames. Chrome sends one when the screencast starts
9
+ * and then only on damage, so a viewer who opens the pane on a page that is not
10
+ * moving waits forever on a blank rectangle, with the protocol reporting
11
+ * success throughout. So the last frame is kept and handed to whoever arrives
12
+ * next, and if there has never been one a screenshot is taken to seed it.
13
+ *
14
+ * Starting a second screencast on a page that already has one does not give the
15
+ * new consumer its own initial frame, so the second viewer of a still page saw
16
+ * nothing at all.
17
+ *
18
+ * And stopping is global: the first consumer to leave used to call
19
+ * `Page.stopScreencast`, which ends the stream for everyone still watching. So
20
+ * the start and the stop are refcounted here, and the CDP calls happen only at
21
+ * the edges.
22
+ */
23
+ interface CdpPage {
24
+ send(method: string, params?: Record<string, unknown>): Promise<Record<string, unknown>>;
25
+ on(event: string, handler: (params: Record<string, unknown>) => void): () => void;
26
+ }
27
+ export declare class ScreencastHub {
28
+ private readonly page;
29
+ private readonly subscribers;
30
+ private detach?;
31
+ private last?;
32
+ constructor(page: CdpPage);
33
+ /** The most recent frame, for a viewer that has just arrived. */
34
+ private seed;
35
+ private start;
36
+ private stop;
37
+ /** Newest frame only: a viewer behind wants the current picture, not a queue. */
38
+ frames(opts?: FrameOptions): AsyncIterable<Buffer>;
39
+ /** The page went away; every watcher ends rather than waiting on it. */
40
+ close(): void;
41
+ }
42
+ export {};