@producible/cereworker-browser 26.520.1

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 (46) hide show
  1. package/LICENSE +21 -0
  2. package/dist/backend.d.ts +28 -0
  3. package/dist/backend.d.ts.map +1 -0
  4. package/dist/backend.js +2 -0
  5. package/dist/backend.js.map +1 -0
  6. package/dist/cdp.d.ts +29 -0
  7. package/dist/cdp.d.ts.map +1 -0
  8. package/dist/cdp.js +180 -0
  9. package/dist/cdp.js.map +1 -0
  10. package/dist/extension-backend.d.ts +23 -0
  11. package/dist/extension-backend.d.ts.map +1 -0
  12. package/dist/extension-backend.js +60 -0
  13. package/dist/extension-backend.js.map +1 -0
  14. package/dist/index.d.ts +7 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +6 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/puppeteer.d.ts +31 -0
  19. package/dist/puppeteer.d.ts.map +1 -0
  20. package/dist/puppeteer.js +182 -0
  21. package/dist/puppeteer.js.map +1 -0
  22. package/dist/relay.d.ts +32 -0
  23. package/dist/relay.d.ts.map +1 -0
  24. package/dist/relay.js +171 -0
  25. package/dist/relay.js.map +1 -0
  26. package/dist/relay.test.d.ts +2 -0
  27. package/dist/relay.test.d.ts.map +1 -0
  28. package/dist/relay.test.js +37 -0
  29. package/dist/relay.test.js.map +1 -0
  30. package/dist/tools.d.ts +179 -0
  31. package/dist/tools.d.ts.map +1 -0
  32. package/dist/tools.js +514 -0
  33. package/dist/tools.js.map +1 -0
  34. package/dist/tools.test.d.ts +2 -0
  35. package/dist/tools.test.d.ts.map +1 -0
  36. package/dist/tools.test.js +92 -0
  37. package/dist/tools.test.js.map +1 -0
  38. package/extension/background.js +444 -0
  39. package/extension/icons/icon128.png +0 -0
  40. package/extension/icons/icon16.png +0 -0
  41. package/extension/icons/icon32.png +0 -0
  42. package/extension/icons/icon48.png +0 -0
  43. package/extension/manifest.json +38 -0
  44. package/extension/options.html +34 -0
  45. package/extension/options.js +53 -0
  46. package/package.json +36 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Producible
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,28 @@
1
+ export interface TabInfo {
2
+ id: string;
3
+ title: string;
4
+ url: string;
5
+ active: boolean;
6
+ }
7
+ export interface BrowserCommandOptions {
8
+ abortSignal?: AbortSignal;
9
+ }
10
+ export interface BrowserBackend {
11
+ navigate(url: string, options?: BrowserCommandOptions): Promise<string>;
12
+ getPageText(options?: BrowserCommandOptions): Promise<string>;
13
+ screenshot(path?: string, options?: BrowserCommandOptions): Promise<string>;
14
+ click(selector: string, options?: BrowserCommandOptions): Promise<string>;
15
+ clickByText(text: string, role?: string, options?: BrowserCommandOptions): Promise<string>;
16
+ type(selector: string, text: string, options?: BrowserCommandOptions): Promise<string>;
17
+ evaluate(code: string, options?: BrowserCommandOptions): Promise<string>;
18
+ waitForSelector(selector: string, timeoutMs?: number, options?: BrowserCommandOptions): Promise<string>;
19
+ getPageUrl(options?: BrowserCommandOptions): Promise<string>;
20
+ listTabs(options?: BrowserCommandOptions): Promise<TabInfo[]>;
21
+ switchTab(tabId: string, options?: BrowserCommandOptions): Promise<string>;
22
+ newTab(url?: string, options?: BrowserCommandOptions): Promise<string>;
23
+ closeTab(tabId?: string, options?: BrowserCommandOptions): Promise<string>;
24
+ connect(options?: BrowserCommandOptions): Promise<string>;
25
+ disconnect(): Promise<void>;
26
+ isConnected(): boolean;
27
+ }
28
+ //# sourceMappingURL=backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAE7B,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxE,WAAW,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9D,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5E,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1E,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3F,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzE,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxG,UAAU,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAG7D,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9D,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3E,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAG3E,OAAO,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,WAAW,IAAI,OAAO,CAAC;CACxB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":""}
package/dist/cdp.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ import type { BrowserBackend, BrowserCommandOptions, TabInfo } from './backend.js';
2
+ export interface CdpConnectionOptions {
3
+ port?: number;
4
+ wsEndpoint?: string;
5
+ }
6
+ export declare class CdpBackend implements BrowserBackend {
7
+ private browser;
8
+ private page;
9
+ private options;
10
+ constructor(options?: CdpConnectionOptions);
11
+ private ensureConnected;
12
+ navigate(url: string, _options?: BrowserCommandOptions): Promise<string>;
13
+ getPageText(_options?: BrowserCommandOptions): Promise<string>;
14
+ screenshot(path?: string, _options?: BrowserCommandOptions): Promise<string>;
15
+ click(selector: string, _options?: BrowserCommandOptions): Promise<string>;
16
+ clickByText(text: string, role?: string, _options?: BrowserCommandOptions): Promise<string>;
17
+ type(selector: string, text: string, _options?: BrowserCommandOptions): Promise<string>;
18
+ evaluate(code: string, _options?: BrowserCommandOptions): Promise<string>;
19
+ waitForSelector(selector: string, timeoutMs?: number, _options?: BrowserCommandOptions): Promise<string>;
20
+ getPageUrl(_options?: BrowserCommandOptions): Promise<string>;
21
+ listTabs(_options?: BrowserCommandOptions): Promise<TabInfo[]>;
22
+ switchTab(tabId: string, _options?: BrowserCommandOptions): Promise<string>;
23
+ newTab(url?: string, _options?: BrowserCommandOptions): Promise<string>;
24
+ closeTab(tabId?: string, _options?: BrowserCommandOptions): Promise<string>;
25
+ connect(_options?: BrowserCommandOptions): Promise<string>;
26
+ disconnect(): Promise<void>;
27
+ isConnected(): boolean;
28
+ }
29
+ //# sourceMappingURL=cdp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp.d.ts","sourceRoot":"","sources":["../src/cdp.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEnF,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,UAAW,YAAW,cAAc;IAC/C,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,OAAO,CAAuB;gBAE1B,OAAO,CAAC,EAAE,oBAAoB;YAI5B,eAAe;IAuBvB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAMxE,WAAW,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAO9D,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAO5E,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAU1E,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAiB3F,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAUvF,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzE,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,SAAO,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAUtG,UAAU,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAK7D,QAAQ,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAW9D,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAY3E,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAWvE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAuB3E,OAAO,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAK1D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC,WAAW,IAAI,OAAO;CAGvB"}
package/dist/cdp.js ADDED
@@ -0,0 +1,180 @@
1
+ import puppeteer from 'puppeteer';
2
+ export class CdpBackend {
3
+ browser = null;
4
+ page = null;
5
+ options;
6
+ constructor(options) {
7
+ this.options = options ?? {};
8
+ }
9
+ async ensureConnected() {
10
+ if (this.browser && this.page)
11
+ return { browser: this.browser, page: this.page };
12
+ try {
13
+ let wsEndpoint = this.options.wsEndpoint;
14
+ if (!wsEndpoint) {
15
+ const port = this.options.port ?? 9222;
16
+ const response = await fetch(`http://localhost:${port}/json/version`);
17
+ const data = (await response.json());
18
+ wsEndpoint = data.webSocketDebuggerUrl;
19
+ }
20
+ this.browser = await puppeteer.connect({ browserWSEndpoint: wsEndpoint });
21
+ const pages = await this.browser.pages();
22
+ this.page = pages[0] ?? (await this.browser.newPage());
23
+ return { browser: this.browser, page: this.page };
24
+ }
25
+ catch (err) {
26
+ const msg = err instanceof Error ? err.message : String(err);
27
+ throw new Error(`Cannot connect to Chrome via CDP (${msg}). ` +
28
+ 'Start Chrome with --remote-debugging-port=9222, or use httpFetch/shell tools instead.');
29
+ }
30
+ }
31
+ async navigate(url, _options) {
32
+ const { page } = await this.ensureConnected();
33
+ await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
34
+ return `Navigated to ${page.url()} - Title: ${await page.title()}`;
35
+ }
36
+ async getPageText(_options) {
37
+ const { page } = await this.ensureConnected();
38
+ const text = await page.evaluate(() => document.body.innerText);
39
+ const maxLen = 10000;
40
+ return text.length > maxLen ? text.slice(0, maxLen) + '\n... (truncated)' : text;
41
+ }
42
+ async screenshot(path, _options) {
43
+ const { page } = await this.ensureConnected();
44
+ const filePath = path ?? `/tmp/cereworker-screenshot-${Date.now()}.png`;
45
+ await page.screenshot({ path: filePath, fullPage: false });
46
+ return `Screenshot saved to ${filePath}`;
47
+ }
48
+ async click(selector, _options) {
49
+ const { page } = await this.ensureConnected();
50
+ try {
51
+ await page.click(selector);
52
+ return `Clicked: ${selector}`;
53
+ }
54
+ catch {
55
+ return `Element not found: ${selector}`;
56
+ }
57
+ }
58
+ async clickByText(text, role, _options) {
59
+ const { page } = await this.ensureConnected();
60
+ try {
61
+ const selector = role ? `[role="${role}"]` : 'button, [role="button"], a';
62
+ const clicked = await page.evaluate((sel, txt) => {
63
+ const els = Array.from(document.querySelectorAll(sel));
64
+ for (const el of els) {
65
+ if (el.textContent?.trim() === txt) {
66
+ el.click();
67
+ return true;
68
+ }
69
+ }
70
+ return false;
71
+ }, selector, text);
72
+ return clicked ? `Clicked element with text: "${text}"` : `No clickable element found with text: "${text}"`;
73
+ }
74
+ catch {
75
+ return `No clickable element found with text: "${text}"`;
76
+ }
77
+ }
78
+ async type(selector, text, _options) {
79
+ const { page } = await this.ensureConnected();
80
+ try {
81
+ await page.type(selector, text);
82
+ return `Typed into: ${selector}`;
83
+ }
84
+ catch {
85
+ return `Element not found: ${selector}`;
86
+ }
87
+ }
88
+ async evaluate(code, _options) {
89
+ const { page } = await this.ensureConnected();
90
+ try {
91
+ const result = await page.evaluate(code);
92
+ return String(result ?? '(no result)');
93
+ }
94
+ catch (err) {
95
+ return `Error: ${err instanceof Error ? err.message : String(err)}`;
96
+ }
97
+ }
98
+ async waitForSelector(selector, timeoutMs = 5000, _options) {
99
+ const { page } = await this.ensureConnected();
100
+ try {
101
+ await page.waitForSelector(selector, { timeout: timeoutMs });
102
+ return `Found: ${selector}`;
103
+ }
104
+ catch {
105
+ return `Timeout waiting for: ${selector}`;
106
+ }
107
+ }
108
+ async getPageUrl(_options) {
109
+ const { page } = await this.ensureConnected();
110
+ return page.url();
111
+ }
112
+ async listTabs(_options) {
113
+ const { browser, page } = await this.ensureConnected();
114
+ const pages = await browser.pages();
115
+ return pages.map((p, i) => ({
116
+ id: String(i),
117
+ title: '',
118
+ url: p.url(),
119
+ active: p === page,
120
+ }));
121
+ }
122
+ async switchTab(tabId, _options) {
123
+ const { browser } = await this.ensureConnected();
124
+ const pages = await browser.pages();
125
+ const idx = parseInt(tabId, 10);
126
+ if (isNaN(idx) || idx < 0 || idx >= pages.length) {
127
+ return `Invalid tab id: ${tabId}. Use browserListTabs to see available tabs.`;
128
+ }
129
+ this.page = pages[idx];
130
+ await this.page.bringToFront();
131
+ return `Switched to tab ${idx}: ${this.page.url()}`;
132
+ }
133
+ async newTab(url, _options) {
134
+ const { browser } = await this.ensureConnected();
135
+ const page = await browser.newPage();
136
+ if (url) {
137
+ await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
138
+ }
139
+ this.page = page;
140
+ const pages = await browser.pages();
141
+ return `Opened new tab (${pages.length} total)${url ? `: ${page.url()}` : ''}`;
142
+ }
143
+ async closeTab(tabId, _options) {
144
+ const { browser } = await this.ensureConnected();
145
+ const pages = await browser.pages();
146
+ if (pages.length <= 1)
147
+ return 'Cannot close the last tab.';
148
+ if (tabId !== undefined) {
149
+ const idx = parseInt(tabId, 10);
150
+ if (isNaN(idx) || idx < 0 || idx >= pages.length)
151
+ return `Invalid tab id: ${tabId}`;
152
+ const wasActive = pages[idx] === this.page;
153
+ await pages[idx].close();
154
+ if (wasActive) {
155
+ const remaining = await browser.pages();
156
+ this.page = remaining[remaining.length - 1];
157
+ }
158
+ return `Closed tab ${idx}`;
159
+ }
160
+ await this.page.close();
161
+ const remaining = await browser.pages();
162
+ this.page = remaining[remaining.length - 1];
163
+ return `Closed current tab. Now on: ${this.page.url()}`;
164
+ }
165
+ async connect(_options) {
166
+ const { page } = await this.ensureConnected();
167
+ return `Connected to Chrome via CDP. Current page: ${page.url()}`;
168
+ }
169
+ async disconnect() {
170
+ if (this.browser) {
171
+ this.browser.disconnect();
172
+ this.browser = null;
173
+ this.page = null;
174
+ }
175
+ }
176
+ isConnected() {
177
+ return this.browser !== null && this.browser.connected;
178
+ }
179
+ }
180
+ //# sourceMappingURL=cdp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp.js","sourceRoot":"","sources":["../src/cdp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { BrowserBackend, BrowserCommandOptions, TabInfo } from './backend.js';
2
+ import type { BrowserRelay } from './relay.js';
3
+ export declare class ExtensionBackend implements BrowserBackend {
4
+ private relay;
5
+ constructor(relay: BrowserRelay);
6
+ navigate(url: string, options?: BrowserCommandOptions): Promise<string>;
7
+ getPageText(options?: BrowserCommandOptions): Promise<string>;
8
+ screenshot(path?: string, options?: BrowserCommandOptions): Promise<string>;
9
+ click(selector: string, options?: BrowserCommandOptions): Promise<string>;
10
+ clickByText(text: string, role?: string, options?: BrowserCommandOptions): Promise<string>;
11
+ type(selector: string, text: string, options?: BrowserCommandOptions): Promise<string>;
12
+ evaluate(code: string, options?: BrowserCommandOptions): Promise<string>;
13
+ waitForSelector(selector: string, timeoutMs?: number, options?: BrowserCommandOptions): Promise<string>;
14
+ getPageUrl(options?: BrowserCommandOptions): Promise<string>;
15
+ listTabs(options?: BrowserCommandOptions): Promise<TabInfo[]>;
16
+ switchTab(tabId: string, options?: BrowserCommandOptions): Promise<string>;
17
+ newTab(url?: string, options?: BrowserCommandOptions): Promise<string>;
18
+ closeTab(tabId?: string, options?: BrowserCommandOptions): Promise<string>;
19
+ connect(_options?: BrowserCommandOptions): Promise<string>;
20
+ disconnect(): Promise<void>;
21
+ isConnected(): boolean;
22
+ }
23
+ //# sourceMappingURL=extension-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension-backend.d.ts","sourceRoot":"","sources":["../src/extension-backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,qBAAa,gBAAiB,YAAW,cAAc;IACrD,OAAO,CAAC,KAAK,CAAe;gBAEhB,KAAK,EAAE,YAAY;IAIzB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAIvE,WAAW,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAI7D,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAI3E,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAIzE,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAI1F,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAItF,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAIxE,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,SAAO,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAIrG,UAAU,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAI5D,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAK7D,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAI1E,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAItE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAI1E,OAAO,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAU1D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC,WAAW,IAAI,OAAO;CAGvB"}
@@ -0,0 +1,60 @@
1
+ export class ExtensionBackend {
2
+ relay;
3
+ constructor(relay) {
4
+ this.relay = relay;
5
+ }
6
+ async navigate(url, options) {
7
+ return this.relay.send('navigate', { url }, 30_000, options?.abortSignal);
8
+ }
9
+ async getPageText(options) {
10
+ return this.relay.send('getPageText', undefined, 30_000, options?.abortSignal);
11
+ }
12
+ async screenshot(path, options) {
13
+ return this.relay.send('screenshot', { path }, 30_000, options?.abortSignal);
14
+ }
15
+ async click(selector, options) {
16
+ return this.relay.send('click', { selector }, 30_000, options?.abortSignal);
17
+ }
18
+ async clickByText(text, role, options) {
19
+ return this.relay.send('clickByText', { text, role }, 30_000, options?.abortSignal);
20
+ }
21
+ async type(selector, text, options) {
22
+ return this.relay.send('type', { selector, text }, 30_000, options?.abortSignal);
23
+ }
24
+ async evaluate(code, options) {
25
+ return this.relay.send('evaluate', { code }, 30_000, options?.abortSignal);
26
+ }
27
+ async waitForSelector(selector, timeoutMs = 5000, options) {
28
+ return this.relay.send('waitForSelector', { selector, timeout: timeoutMs }, timeoutMs + 5000, options?.abortSignal);
29
+ }
30
+ async getPageUrl(options) {
31
+ return this.relay.send('getPageUrl', undefined, 30_000, options?.abortSignal);
32
+ }
33
+ async listTabs(options) {
34
+ const result = await this.relay.send('listTabs', undefined, 30_000, options?.abortSignal);
35
+ return JSON.parse(result);
36
+ }
37
+ async switchTab(tabId, options) {
38
+ return this.relay.send('switchTab', { tabId }, 30_000, options?.abortSignal);
39
+ }
40
+ async newTab(url, options) {
41
+ return this.relay.send('newTab', { url }, 30_000, options?.abortSignal);
42
+ }
43
+ async closeTab(tabId, options) {
44
+ return this.relay.send('closeTab', { tabId }, 30_000, options?.abortSignal);
45
+ }
46
+ async connect(_options) {
47
+ if (!this.relay.isExtensionConnected()) {
48
+ throw new Error('Chrome extension not connected. Load the CereWorker extension in Chrome, ' +
49
+ 'configure the relay port and token in extension options, then click the extension icon.');
50
+ }
51
+ return 'Connected to Chrome via extension';
52
+ }
53
+ async disconnect() {
54
+ // Extension stays connected — nothing to tear down from backend side
55
+ }
56
+ isConnected() {
57
+ return this.relay.isExtensionConnected();
58
+ }
59
+ }
60
+ //# sourceMappingURL=extension-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension-backend.js","sourceRoot":"","sources":["../src/extension-backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export type { BrowserBackend, BrowserCommandOptions, TabInfo } from './backend.js';
2
+ export { PuppeteerBackend, type BrowserSession } from './puppeteer.js';
3
+ export { CdpBackend, type CdpConnectionOptions } from './cdp.js';
4
+ export { createBrowserTools, type BrowserTools, type BrowserToolName } from './tools.js';
5
+ export { BrowserRelay, type RelayConfig, type RelayCommand, type RelayResult } from './relay.js';
6
+ export { ExtensionBackend } from './extension-backend.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { PuppeteerBackend } from './puppeteer.js';
2
+ export { CdpBackend } from './cdp.js';
3
+ export { createBrowserTools } from './tools.js';
4
+ export { BrowserRelay } from './relay.js';
5
+ export { ExtensionBackend } from './extension-backend.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAuB,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,UAAU,EAA6B,MAAM,UAAU,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAA2C,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,YAAY,EAAyD,MAAM,YAAY,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { type Browser, type Page } from 'puppeteer';
2
+ import type { BrowserBackend, BrowserCommandOptions, TabInfo } from './backend.js';
3
+ export interface BrowserSession {
4
+ browser: Browser;
5
+ page: Page;
6
+ }
7
+ export declare class PuppeteerBackend implements BrowserBackend {
8
+ private session;
9
+ private headless;
10
+ constructor(options?: {
11
+ headless?: boolean;
12
+ });
13
+ private getSession;
14
+ navigate(url: string, _options?: BrowserCommandOptions): Promise<string>;
15
+ getPageText(_options?: BrowserCommandOptions): Promise<string>;
16
+ screenshot(path?: string, _options?: BrowserCommandOptions): Promise<string>;
17
+ click(selector: string, _options?: BrowserCommandOptions): Promise<string>;
18
+ clickByText(text: string, role?: string, _options?: BrowserCommandOptions): Promise<string>;
19
+ type(selector: string, text: string, _options?: BrowserCommandOptions): Promise<string>;
20
+ evaluate(code: string, _options?: BrowserCommandOptions): Promise<string>;
21
+ waitForSelector(selector: string, timeoutMs?: number, _options?: BrowserCommandOptions): Promise<string>;
22
+ getPageUrl(_options?: BrowserCommandOptions): Promise<string>;
23
+ listTabs(_options?: BrowserCommandOptions): Promise<TabInfo[]>;
24
+ switchTab(tabId: string, _options?: BrowserCommandOptions): Promise<string>;
25
+ newTab(url?: string, _options?: BrowserCommandOptions): Promise<string>;
26
+ closeTab(tabId?: string, _options?: BrowserCommandOptions): Promise<string>;
27
+ connect(_options?: BrowserCommandOptions): Promise<string>;
28
+ disconnect(): Promise<void>;
29
+ isConnected(): boolean;
30
+ }
31
+ //# sourceMappingURL=puppeteer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"puppeteer.d.ts","sourceRoot":"","sources":["../src/puppeteer.ts"],"names":[],"mappings":"AAAA,OAAkB,EAAE,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEnF,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,qBAAa,gBAAiB,YAAW,cAAc;IACrD,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,QAAQ,CAAU;gBAEd,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE;YAI9B,UAAU;IAoBlB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAMxE,WAAW,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAO9D,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAO5E,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAU1E,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAiB3F,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAUvF,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzE,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,SAAO,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAUtG,UAAU,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAK7D,QAAQ,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAW9D,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAa3E,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAavE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IA4B3E,OAAO,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAK1D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAOjC,WAAW,IAAI,OAAO;CAGvB"}
@@ -0,0 +1,182 @@
1
+ import puppeteer from 'puppeteer';
2
+ export class PuppeteerBackend {
3
+ session = null;
4
+ headless;
5
+ constructor(options) {
6
+ this.headless = options?.headless ?? true;
7
+ }
8
+ async getSession() {
9
+ if (this.session)
10
+ return this.session;
11
+ try {
12
+ const browser = await puppeteer.launch({
13
+ headless: this.headless ? 'shell' : false,
14
+ args: ['--no-sandbox', '--disable-setuid-sandbox'],
15
+ });
16
+ const page = await browser.newPage();
17
+ await page.setViewport({ width: 1280, height: 800 });
18
+ this.session = { browser, page };
19
+ return this.session;
20
+ }
21
+ catch (err) {
22
+ const msg = err instanceof Error ? err.message : String(err);
23
+ throw new Error(`No browser available (${msg}). ` +
24
+ 'Use httpFetch/shell tools for API calls, or install Chrome for browser automation.');
25
+ }
26
+ }
27
+ async navigate(url, _options) {
28
+ const s = await this.getSession();
29
+ await s.page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
30
+ return `Navigated to ${s.page.url()} - Title: ${await s.page.title()}`;
31
+ }
32
+ async getPageText(_options) {
33
+ const s = await this.getSession();
34
+ const text = await s.page.evaluate(() => document.body.innerText);
35
+ const maxLen = 10000;
36
+ return text.length > maxLen ? text.slice(0, maxLen) + '\n... (truncated)' : text;
37
+ }
38
+ async screenshot(path, _options) {
39
+ const s = await this.getSession();
40
+ const filePath = path ?? `/tmp/cereworker-screenshot-${Date.now()}.png`;
41
+ await s.page.screenshot({ path: filePath, fullPage: false });
42
+ return `Screenshot saved to ${filePath}`;
43
+ }
44
+ async click(selector, _options) {
45
+ const s = await this.getSession();
46
+ try {
47
+ await s.page.click(selector);
48
+ return `Clicked: ${selector}`;
49
+ }
50
+ catch {
51
+ return `Element not found: ${selector}`;
52
+ }
53
+ }
54
+ async clickByText(text, role, _options) {
55
+ const s = await this.getSession();
56
+ try {
57
+ const selector = role ? `[role="${role}"]` : 'button, [role="button"], a';
58
+ const clicked = await s.page.evaluate((sel, txt) => {
59
+ const els = Array.from(document.querySelectorAll(sel));
60
+ for (const el of els) {
61
+ if (el.textContent?.trim() === txt) {
62
+ el.click();
63
+ return true;
64
+ }
65
+ }
66
+ return false;
67
+ }, selector, text);
68
+ return clicked ? `Clicked element with text: "${text}"` : `No clickable element found with text: "${text}"`;
69
+ }
70
+ catch {
71
+ return `No clickable element found with text: "${text}"`;
72
+ }
73
+ }
74
+ async type(selector, text, _options) {
75
+ const s = await this.getSession();
76
+ try {
77
+ await s.page.type(selector, text);
78
+ return `Typed into: ${selector}`;
79
+ }
80
+ catch {
81
+ return `Element not found: ${selector}`;
82
+ }
83
+ }
84
+ async evaluate(code, _options) {
85
+ const s = await this.getSession();
86
+ try {
87
+ const result = await s.page.evaluate(code);
88
+ return String(result ?? '(no result)');
89
+ }
90
+ catch (err) {
91
+ return `Error: ${err instanceof Error ? err.message : String(err)}`;
92
+ }
93
+ }
94
+ async waitForSelector(selector, timeoutMs = 5000, _options) {
95
+ const s = await this.getSession();
96
+ try {
97
+ await s.page.waitForSelector(selector, { timeout: timeoutMs });
98
+ return `Found: ${selector}`;
99
+ }
100
+ catch {
101
+ return `Timeout waiting for: ${selector}`;
102
+ }
103
+ }
104
+ async getPageUrl(_options) {
105
+ const s = await this.getSession();
106
+ return s.page.url();
107
+ }
108
+ async listTabs(_options) {
109
+ const s = await this.getSession();
110
+ const pages = await s.browser.pages();
111
+ return pages.map((p, i) => ({
112
+ id: String(i),
113
+ title: '', // title() is async, keep lightweight
114
+ url: p.url(),
115
+ active: p === s.page,
116
+ }));
117
+ }
118
+ async switchTab(tabId, _options) {
119
+ const s = await this.getSession();
120
+ const pages = await s.browser.pages();
121
+ const idx = parseInt(tabId, 10);
122
+ if (isNaN(idx) || idx < 0 || idx >= pages.length) {
123
+ return `Invalid tab id: ${tabId}. Use browserListTabs to see available tabs.`;
124
+ }
125
+ s.page = pages[idx];
126
+ this.session = s;
127
+ await s.page.bringToFront();
128
+ return `Switched to tab ${idx}: ${s.page.url()}`;
129
+ }
130
+ async newTab(url, _options) {
131
+ const s = await this.getSession();
132
+ const page = await s.browser.newPage();
133
+ await page.setViewport({ width: 1280, height: 800 });
134
+ if (url) {
135
+ await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 });
136
+ }
137
+ s.page = page;
138
+ this.session = s;
139
+ const pages = await s.browser.pages();
140
+ return `Opened new tab (${pages.length} total)${url ? `: ${page.url()}` : ''}`;
141
+ }
142
+ async closeTab(tabId, _options) {
143
+ const s = await this.getSession();
144
+ const pages = await s.browser.pages();
145
+ if (pages.length <= 1)
146
+ return 'Cannot close the last tab.';
147
+ if (tabId !== undefined) {
148
+ const idx = parseInt(tabId, 10);
149
+ if (isNaN(idx) || idx < 0 || idx >= pages.length) {
150
+ return `Invalid tab id: ${tabId}`;
151
+ }
152
+ await pages[idx].close();
153
+ if (pages[idx] === s.page) {
154
+ const remaining = await s.browser.pages();
155
+ s.page = remaining[remaining.length - 1];
156
+ this.session = s;
157
+ }
158
+ return `Closed tab ${idx}`;
159
+ }
160
+ // Close current tab
161
+ const current = s.page;
162
+ await current.close();
163
+ const remaining = await s.browser.pages();
164
+ s.page = remaining[remaining.length - 1];
165
+ this.session = s;
166
+ return `Closed current tab. Now on: ${s.page.url()}`;
167
+ }
168
+ async connect(_options) {
169
+ const s = await this.getSession();
170
+ return `Browser launched (headless: ${this.headless}). Page: ${s.page.url()}`;
171
+ }
172
+ async disconnect() {
173
+ if (this.session) {
174
+ await this.session.browser.close();
175
+ this.session = null;
176
+ }
177
+ }
178
+ isConnected() {
179
+ return this.session !== null && this.session.browser.connected;
180
+ }
181
+ }
182
+ //# sourceMappingURL=puppeteer.js.map