@moxxy/plugin-browser 0.27.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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/dist/browser-session.d.ts +43 -0
  3. package/dist/browser-session.d.ts.map +1 -0
  4. package/dist/browser-session.js +500 -0
  5. package/dist/browser-session.js.map +1 -0
  6. package/dist/browser-surface.d.ts +3 -0
  7. package/dist/browser-surface.d.ts.map +1 -0
  8. package/dist/browser-surface.js +255 -0
  9. package/dist/browser-surface.js.map +1 -0
  10. package/dist/html-extract.d.ts +20 -0
  11. package/dist/html-extract.d.ts.map +1 -0
  12. package/dist/html-extract.js +122 -0
  13. package/dist/html-extract.js.map +1 -0
  14. package/dist/index.d.ts +10 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +24 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/sidecar/dispatch.d.ts +18 -0
  19. package/dist/sidecar/dispatch.d.ts.map +1 -0
  20. package/dist/sidecar/dispatch.js +294 -0
  21. package/dist/sidecar/dispatch.js.map +1 -0
  22. package/dist/sidecar/install.d.ts +37 -0
  23. package/dist/sidecar/install.d.ts.map +1 -0
  24. package/dist/sidecar/install.js +242 -0
  25. package/dist/sidecar/install.js.map +1 -0
  26. package/dist/sidecar/types.d.ts +97 -0
  27. package/dist/sidecar/types.d.ts.map +1 -0
  28. package/dist/sidecar/types.js +20 -0
  29. package/dist/sidecar/types.js.map +1 -0
  30. package/dist/sidecar.d.ts +31 -0
  31. package/dist/sidecar.d.ts.map +1 -0
  32. package/dist/sidecar.js +165 -0
  33. package/dist/sidecar.js.map +1 -0
  34. package/dist/ssrf-guard.d.ts +43 -0
  35. package/dist/ssrf-guard.d.ts.map +1 -0
  36. package/dist/ssrf-guard.js +164 -0
  37. package/dist/ssrf-guard.js.map +1 -0
  38. package/dist/web-fetch.d.ts +23 -0
  39. package/dist/web-fetch.d.ts.map +1 -0
  40. package/dist/web-fetch.js +253 -0
  41. package/dist/web-fetch.js.map +1 -0
  42. package/package.json +74 -0
  43. package/src/browser-session.test.ts +333 -0
  44. package/src/browser-session.ts +567 -0
  45. package/src/browser-surface.test.ts +367 -0
  46. package/src/browser-surface.ts +275 -0
  47. package/src/html-extract.ts +152 -0
  48. package/src/index.ts +35 -0
  49. package/src/sidecar/dispatch.test.ts +313 -0
  50. package/src/sidecar/dispatch.ts +314 -0
  51. package/src/sidecar/install.ts +283 -0
  52. package/src/sidecar/types.test.ts +26 -0
  53. package/src/sidecar/types.ts +114 -0
  54. package/src/sidecar.test.ts +57 -0
  55. package/src/sidecar.ts +167 -0
  56. package/src/ssrf-guard.test.ts +109 -0
  57. package/src/ssrf-guard.ts +165 -0
  58. package/src/web-fetch.test.ts +305 -0
  59. package/src/web-fetch.ts +311 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Moxxy (moxxy.ai)
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,43 @@
1
+ export interface BrowserSessionDeps {
2
+ /**
3
+ * Override the sidecar script path. Default: resolved next to this file
4
+ * (i.e., the `dist/sidecar.js` shipped in the same package).
5
+ */
6
+ readonly sidecarPath?: string;
7
+ /**
8
+ * Spawn override (test seam). When set, the tool will call this instead
9
+ * of `child_process.spawn` — useful for fake sidecars.
10
+ */
11
+ readonly spawnFn?: (sidecarPath: string) => SidecarStream;
12
+ /**
13
+ * Per-call timeout override (test seam). Defaults to
14
+ * {@link DEFAULT_CALL_TIMEOUT_MS}. A hung sidecar op is rejected after this.
15
+ */
16
+ readonly callTimeoutMs?: number;
17
+ }
18
+ export interface SidecarStream {
19
+ readonly stdin: NodeJS.WritableStream;
20
+ readonly stdout: NodeJS.ReadableStream;
21
+ readonly stderr?: NodeJS.ReadableStream;
22
+ kill(signal?: NodeJS.Signals): boolean;
23
+ once(event: 'exit', listener: (code: number | null) => void): void;
24
+ }
25
+ /** The sidecar-supplied error tag (see {@link Sidecar.handleLine}); 'needs-install'
26
+ * means the `playwright` npm package isn't present yet. */
27
+ export declare function sidecarErrorKind(err: unknown): string | undefined;
28
+ /**
29
+ * The directory whose `node_modules` the sidecar imports `playwright` from — the
30
+ * CLI install root (e.g. `<userData>/cli`). Found by walking up from the sidecar
31
+ * file to the nearest `node_modules` ancestor and returning ITS parent. Falls
32
+ * back to the sidecar's own dir if no `node_modules` is on the path (dev/tests).
33
+ */
34
+ export declare function resolveBrowserInstallRoot(deps?: BrowserSessionDeps): string;
35
+ export declare function buildBrowserSessionTool(deps?: BrowserSessionDeps): import("@moxxy/sdk").ToolDef;
36
+ /**
37
+ * Call a method on the shared sidecar (used by the browser SURFACE so it drives
38
+ * the SAME page the `browser_session` tool does — agent + user share one page).
39
+ */
40
+ export declare function browserSidecarCall(method: string, params?: Record<string, unknown>, deps?: BrowserSessionDeps): Promise<unknown>;
41
+ /** Closes the singleton sidecar — wired to plugin `onShutdown`. */
42
+ export declare function closeBrowserSidecar(): Promise<void>;
43
+ //# sourceMappingURL=browser-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-session.d.ts","sourceRoot":"","sources":["../src/browser-session.ts"],"names":[],"mappings":"AA4DA,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,aAAa,CAAC;IAC1D;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IACxC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IACvC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC;CACpE;AA4UD;4DAC4D;AAC5D,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAEjE;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAU3E;AASD,wBAAgB,uBAAuB,CAAC,IAAI,CAAC,EAAE,kBAAkB,gCAkGhE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,IAAI,CAAC,EAAE,kBAAkB,GACxB,OAAO,CAAC,OAAO,CAAC,CAElB;AAED,mEAAmE;AACnE,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMzD"}
@@ -0,0 +1,500 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { randomUUID } from 'node:crypto';
3
+ import * as path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { MoxxyError, defineTool, z } from '@moxxy/sdk';
6
+ import { assertPublicUrl, SsrfBlockedError } from './ssrf-guard.js';
7
+ const actionSchema = z.union([
8
+ z.object({
9
+ kind: z.literal('goto'),
10
+ // `z.string().url()` accepts file:// and javascript: URLs, which would be
11
+ // forwarded verbatim to Playwright `page.goto`. This refine is only a fast
12
+ // schema-level scheme check; the full SSRF guard (loopback/private/
13
+ // link-local/metadata IPs, DNS resolution — same `assertPublicUrl` as
14
+ // web_fetch) runs in the handler before the RPC AND again inside the
15
+ // sidecar's goto dispatch.
16
+ url: z.string().url().refine((u) => /^https?:\/\//i.test(u), 'only http(s) URLs allowed'),
17
+ waitUntil: z.enum(['load', 'domcontentloaded', 'networkidle']).optional(),
18
+ timeoutMs: z.number().int().positive().max(120_000).optional(),
19
+ }),
20
+ z.object({
21
+ kind: z.literal('click'),
22
+ selector: z.string().min(1),
23
+ timeoutMs: z.number().int().positive().max(60_000).optional(),
24
+ }),
25
+ z.object({
26
+ kind: z.literal('fill'),
27
+ selector: z.string().min(1),
28
+ value: z.string(),
29
+ timeoutMs: z.number().int().positive().max(60_000).optional(),
30
+ }),
31
+ z.object({ kind: z.literal('text'), selector: z.string().optional() }),
32
+ z.object({ kind: z.literal('html') }),
33
+ z.object({ kind: z.literal('screenshot'), fullPage: z.boolean().optional() }),
34
+ z.object({ kind: z.literal('eval'), expression: z.string().min(1) }),
35
+ z.object({ kind: z.literal('url') }),
36
+ ]);
37
+ /**
38
+ * Parent-side per-call ceiling. A wedged sidecar op (an `eval` running
39
+ * `while(true){}`, a screenshot on a hung renderer) never replies and the
40
+ * sidecar process stays alive, so without a parent timeout the pending entry —
41
+ * and every request queued behind it — would hang forever (the surface poll's
42
+ * inFlight guard then latches and the live view silently freezes). 90s is
43
+ * comfortably above the longest legitimate in-sidecar timeout (goto's 120s is
44
+ * the only one above, and it is bounded inside the sidecar; surface frame polls
45
+ * are sub-second). Exceeding it rejects THIS call only — the shared sidecar and
46
+ * any healthy concurrent calls are untouched (a late reply is ignored).
47
+ */
48
+ const DEFAULT_CALL_TIMEOUT_MS = 150_000;
49
+ /** Hard ceiling on queued requests so a wedged head can't let the parent pile
50
+ * up unbounded pending entries (e.g. 3/s surface polls behind a stuck op). */
51
+ const MAX_PENDING = 256;
52
+ /**
53
+ * Cap the parent's hand-rolled stdout line buffer. A sidecar (or a process
54
+ * spoofing the JSON-RPC channel) that emits a very long line with no newline
55
+ * would otherwise grow this string without limit, copying it on every chunk
56
+ * (O(n^2) + unbounded memory in the runner). 96MB comfortably fits the largest
57
+ * legitimate single line — a base64 full-page PNG at deviceScaleFactor 2 — while
58
+ * still bounding a runaway. On overflow we drop the buffer and log a protocol
59
+ * error rather than OOM the runner.
60
+ */
61
+ const MAX_STDOUT_BUFFER = 96 * 1024 * 1024;
62
+ /** stderr is human-readable status only — a much smaller cap is plenty. */
63
+ const MAX_STDERR_BUFFER = 1 * 1024 * 1024;
64
+ /**
65
+ * Coerce a sidecar reply into an object so we can attach `notice`.
66
+ * Wraps primitives + strings; pass-through for objects.
67
+ */
68
+ function wrapResult(value) {
69
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
70
+ return value;
71
+ }
72
+ return { result: value };
73
+ }
74
+ class Sidecar {
75
+ sidecarPath;
76
+ spawnFn;
77
+ callTimeoutMs;
78
+ child = null;
79
+ buffer = '';
80
+ pending = new Map();
81
+ startError = null;
82
+ /** Listeners for sidecar stderr lines — used by callers that want
83
+ * install-progress feedback in their own logger/UI. A Set (not a single
84
+ * slot) so concurrent browser_session calls don't clobber each other. */
85
+ stderrListeners = new Set();
86
+ /** Last few sidecar stderr lines, kept so the `exit` handler can put the
87
+ * ACTUAL failure (e.g. "Cannot find module …" or Playwright's "Executable
88
+ * doesn't exist, run npx playwright install") into the error instead of a
89
+ * bare `code=1` the caller can't act on. */
90
+ recentStderr = [];
91
+ constructor(sidecarPath, spawnFn, callTimeoutMs = DEFAULT_CALL_TIMEOUT_MS) {
92
+ this.sidecarPath = sidecarPath;
93
+ this.spawnFn = spawnFn;
94
+ this.callTimeoutMs = callTimeoutMs;
95
+ }
96
+ /** Subscribe to sidecar stderr lines. Returns an unsubscribe function. */
97
+ onStderr(fn) {
98
+ this.stderrListeners.add(fn);
99
+ return () => this.stderrListeners.delete(fn);
100
+ }
101
+ async ensure() {
102
+ if (this.child)
103
+ return;
104
+ if (this.startError)
105
+ throw this.startError;
106
+ try {
107
+ this.child = this.spawnFn(this.sidecarPath);
108
+ }
109
+ catch (err) {
110
+ this.startError = err instanceof Error ? err : new Error(String(err));
111
+ throw this.startError;
112
+ }
113
+ this.child.stdout.setEncoding?.('utf8');
114
+ this.child.stdout.on('data', (chunk) => {
115
+ this.buffer += typeof chunk === 'string' ? chunk : chunk.toString('utf8');
116
+ let nl;
117
+ while ((nl = this.buffer.indexOf('\n')) !== -1) {
118
+ const line = this.buffer.slice(0, nl);
119
+ this.buffer = this.buffer.slice(nl + 1);
120
+ if (line.trim())
121
+ this.handleLine(line);
122
+ }
123
+ // A single line with no newline that exceeds the cap is malformed/hostile
124
+ // protocol output. Drop it (and any partial accumulation) rather than let
125
+ // the runner grow unbounded; the in-flight call that expected its reply
126
+ // will hit its per-call timeout.
127
+ if (this.buffer.length > MAX_STDOUT_BUFFER) {
128
+ this.recentStderr.push(`[moxxy] dropped ${this.buffer.length} bytes of un-delimited sidecar stdout (> ${MAX_STDOUT_BUFFER} cap)`);
129
+ this.buffer = '';
130
+ }
131
+ });
132
+ // Forward sidecar stderr line-by-line. The sidecar uses stderr
133
+ // for install progress ("downloading chromium…") and other
134
+ // human-readable status; callers wire `onStderr` to surface it.
135
+ let stderrBuf = '';
136
+ this.child.stderr?.on?.('data', (chunk) => {
137
+ stderrBuf += typeof chunk === 'string' ? chunk : chunk.toString('utf8');
138
+ let nl;
139
+ while ((nl = stderrBuf.indexOf('\n')) !== -1) {
140
+ const line = stderrBuf.slice(0, nl);
141
+ stderrBuf = stderrBuf.slice(nl + 1);
142
+ if (line.trim()) {
143
+ this.recentStderr.push(line);
144
+ if (this.recentStderr.length > 24)
145
+ this.recentStderr.shift();
146
+ for (const fn of this.stderrListeners)
147
+ fn(line);
148
+ }
149
+ }
150
+ // Bound a runaway no-newline stderr stream too (it feeds the error tail,
151
+ // so keep only the most recent bytes rather than drop wholesale).
152
+ if (stderrBuf.length > MAX_STDERR_BUFFER)
153
+ stderrBuf = stderrBuf.slice(-MAX_STDERR_BUFFER);
154
+ });
155
+ this.child.once('exit', (code) => {
156
+ // Surface whatever the sidecar printed before dying — that's where the
157
+ // real reason lives (missing module, Playwright not installed, etc.).
158
+ const tail = this.recentStderr.slice(-8).join('\n').trim();
159
+ const err = new MoxxyError({
160
+ code: 'INTERNAL',
161
+ message: `browser sidecar exited unexpectedly (code=${code ?? 'null'})` +
162
+ (tail ? `:\n${tail}` : ' (no stderr captured)'),
163
+ });
164
+ for (const [, p] of this.pending)
165
+ p.reject(err);
166
+ this.pending.clear();
167
+ this.child = null;
168
+ });
169
+ }
170
+ handleLine(line) {
171
+ let reply;
172
+ try {
173
+ reply = JSON.parse(line);
174
+ }
175
+ catch {
176
+ return; // ignore garbage
177
+ }
178
+ const p = reply.id ? this.pending.get(reply.id) : undefined;
179
+ if (!p || !reply.id)
180
+ return;
181
+ this.pending.delete(reply.id);
182
+ if (reply.ok) {
183
+ // Attach the optional sidecar-supplied notice (e.g. "Auto-installed
184
+ // Chromium") so the tool's caller can surface it to the user. Wrap
185
+ // primitive results in `{ result, notice }` so the shape stays
186
+ // useful regardless of what the original call returned.
187
+ if (reply.notice) {
188
+ p.resolve({ ...wrapResult(reply.result), notice: reply.notice });
189
+ }
190
+ else {
191
+ p.resolve(reply.result);
192
+ }
193
+ }
194
+ else {
195
+ // Carry the sidecar's typed `kind` on the rejected error so the surface
196
+ // can tell "playwright not installed" (offer an Install button) apart from
197
+ // a generic failure. MoxxyError doesn't model it, so attach it as a tag.
198
+ const err = new MoxxyError({ code: 'INTERNAL', message: reply.error?.message ?? 'sidecar error' });
199
+ if (reply.error?.kind)
200
+ err.sidecarKind = reply.error.kind;
201
+ p.reject(err);
202
+ }
203
+ }
204
+ async call(method, params = {}, signal) {
205
+ await this.ensure();
206
+ if (!this.child)
207
+ throw new MoxxyError({ code: 'INTERNAL', message: 'sidecar not running' });
208
+ if (signal?.aborted)
209
+ throw new MoxxyError({ code: 'NETWORK_ABORTED', message: 'browser_session aborted' });
210
+ // Bound the pending map: a wedged sidecar head + chatty caller (surface
211
+ // polls) must not let the parent accumulate pending entries without limit.
212
+ if (this.pending.size >= MAX_PENDING) {
213
+ throw new MoxxyError({
214
+ code: 'INTERNAL',
215
+ message: `browser sidecar busy (${this.pending.size} requests in flight)`,
216
+ });
217
+ }
218
+ const id = randomUUID();
219
+ const req = { id, method, params };
220
+ return new Promise((resolve, reject) => {
221
+ // Per-call timeout: a sidecar op that never replies (hung eval/screenshot)
222
+ // would otherwise strand this pending entry — and the serial queue behind
223
+ // it — indefinitely. On expiry, drop the entry and reject THIS call only;
224
+ // a late reply is then ignored (id no longer in `pending`).
225
+ const timer = setTimeout(() => {
226
+ if (this.pending.delete(id)) {
227
+ cleanup();
228
+ reject(new MoxxyError({
229
+ code: 'INTERNAL',
230
+ message: `browser_session "${method}" timed out after ${this.callTimeoutMs}ms`,
231
+ }));
232
+ }
233
+ }, this.callTimeoutMs);
234
+ timer.unref?.();
235
+ // Abort cancels ONLY this pending call (rejects its promise); it does
236
+ // NOT kill the shared singleton sidecar, which other concurrent calls
237
+ // depend on. A late reply for this id is then ignored (not in `pending`).
238
+ const onAbort = () => {
239
+ if (this.pending.delete(id)) {
240
+ cleanup();
241
+ reject(new MoxxyError({ code: 'NETWORK_ABORTED', message: 'browser_session aborted' }));
242
+ }
243
+ };
244
+ const cleanup = () => {
245
+ clearTimeout(timer);
246
+ signal?.removeEventListener('abort', onAbort);
247
+ };
248
+ this.pending.set(id, {
249
+ resolve: (v) => {
250
+ cleanup();
251
+ resolve(v);
252
+ },
253
+ reject: (e) => {
254
+ cleanup();
255
+ reject(e);
256
+ },
257
+ });
258
+ signal?.addEventListener('abort', onAbort, { once: true });
259
+ try {
260
+ this.child.stdin.write(JSON.stringify(req) + '\n');
261
+ }
262
+ catch (err) {
263
+ this.pending.delete(id);
264
+ cleanup();
265
+ reject(err instanceof Error ? err : new Error(String(err)));
266
+ }
267
+ });
268
+ }
269
+ async close() {
270
+ if (!this.child)
271
+ return;
272
+ const child = this.child;
273
+ try {
274
+ await this.call('close');
275
+ }
276
+ catch {
277
+ /* ignore */
278
+ }
279
+ // Wait briefly for a clean exit, escalating SIGTERM → SIGKILL so a wedged
280
+ // sidecar (or a detached Chromium ignoring SIGTERM) can't survive as an
281
+ // orphan after session shutdown.
282
+ await new Promise((resolve) => {
283
+ let settled = false;
284
+ let timer;
285
+ const done = () => {
286
+ if (settled)
287
+ return;
288
+ settled = true;
289
+ if (timer)
290
+ clearTimeout(timer);
291
+ resolve();
292
+ };
293
+ // Arm the SIGKILL escalation BEFORE killing, so a synchronous `exit`
294
+ // (e.g. the test fake) finds `timer` already assigned when `done` runs.
295
+ timer = setTimeout(() => {
296
+ try {
297
+ child.kill('SIGKILL');
298
+ }
299
+ catch {
300
+ /* ignore */
301
+ }
302
+ done();
303
+ }, 2000);
304
+ timer.unref?.();
305
+ child.once('exit', () => done());
306
+ try {
307
+ child.kill('SIGTERM');
308
+ }
309
+ catch {
310
+ done();
311
+ }
312
+ });
313
+ this.child = null;
314
+ }
315
+ }
316
+ /** Module-level singleton: one sidecar per process. */
317
+ let SIDECAR_INSTANCE = null;
318
+ /** The deps the live singleton was created with, so a later caller passing
319
+ * DIFFERENT deps (silently ignored) is made visible rather than a footgun. */
320
+ let SIDECAR_DEPS;
321
+ /**
322
+ * Resolve the shared, process-wide sidecar, creating it on first use.
323
+ *
324
+ * IMPORTANT: `deps` (sidecarPath / spawnFn) are honored ONLY on the FIRST call
325
+ * that creates the singleton. The tool handler and the surface each call this
326
+ * with their own `deps`; whichever runs first wins, and any later caller's
327
+ * `deps` are silently ignored — both production builds pass the same opts so
328
+ * they agree. A test that wants a distinct spawn override must therefore call
329
+ * {@link closeBrowserSidecar} first to reset the singleton, otherwise it will
330
+ * bind against whatever spawn was installed by an earlier call.
331
+ *
332
+ * When a later caller passes deps that DIFFER from the live singleton's we emit
333
+ * a warning (the binding stays the original's) so the silent-ignore is visible
334
+ * — the proper fix is a per-owner registry, tracked in needsFollowup.
335
+ */
336
+ function getSidecar(deps) {
337
+ if (SIDECAR_INSTANCE) {
338
+ if (deps &&
339
+ (deps.sidecarPath !== SIDECAR_DEPS?.sidecarPath || deps.spawnFn !== SIDECAR_DEPS?.spawnFn)) {
340
+ console.warn('[moxxy/plugin-browser] getSidecar called with deps that differ from the live singleton; ' +
341
+ 'they are ignored. Call closeBrowserSidecar() first to rebind.');
342
+ }
343
+ return SIDECAR_INSTANCE;
344
+ }
345
+ const sidecarPath = deps?.sidecarPath ?? defaultSidecarPath();
346
+ const spawnFn = deps?.spawnFn ?? defaultSpawn;
347
+ SIDECAR_INSTANCE = new Sidecar(sidecarPath, spawnFn, deps?.callTimeoutMs ?? DEFAULT_CALL_TIMEOUT_MS);
348
+ SIDECAR_DEPS = deps;
349
+ return SIDECAR_INSTANCE;
350
+ }
351
+ /** Resolve to the sidecar JS file shipped alongside this module. */
352
+ function defaultSidecarPath() {
353
+ const here = path.dirname(fileURLToPath(import.meta.url));
354
+ return path.join(here, 'sidecar.js');
355
+ }
356
+ /** The sidecar-supplied error tag (see {@link Sidecar.handleLine}); 'needs-install'
357
+ * means the `playwright` npm package isn't present yet. */
358
+ export function sidecarErrorKind(err) {
359
+ return err?.sidecarKind;
360
+ }
361
+ /**
362
+ * The directory whose `node_modules` the sidecar imports `playwright` from — the
363
+ * CLI install root (e.g. `<userData>/cli`). Found by walking up from the sidecar
364
+ * file to the nearest `node_modules` ancestor and returning ITS parent. Falls
365
+ * back to the sidecar's own dir if no `node_modules` is on the path (dev/tests).
366
+ */
367
+ export function resolveBrowserInstallRoot(deps) {
368
+ const start = deps?.sidecarPath ?? defaultSidecarPath();
369
+ let dir = path.dirname(start);
370
+ for (let i = 0; i < 12; i += 1) {
371
+ if (path.basename(dir) === 'node_modules')
372
+ return path.dirname(dir);
373
+ const parent = path.dirname(dir);
374
+ if (parent === dir)
375
+ break;
376
+ dir = parent;
377
+ }
378
+ return path.dirname(start);
379
+ }
380
+ function defaultSpawn(scriptPath) {
381
+ const child = spawn(process.execPath, [scriptPath], {
382
+ stdio: ['pipe', 'pipe', 'pipe'],
383
+ });
384
+ return child;
385
+ }
386
+ export function buildBrowserSessionTool(deps) {
387
+ return defineTool({
388
+ name: 'browser_session',
389
+ description: 'Drive a real browser (Playwright). Use for pages that need JS execution, clicks, form fills, or screenshots. For simple GETs prefer web_fetch (no extra deps). Calls within a session share one page. ' +
390
+ 'Navigation is restricted to public http(s) origins: goto URLs and top-level/iframe navigations (including redirects) to loopback, private (RFC-1918), link-local/metadata, or CGNAT addresses are blocked. ' +
391
+ 'The `eval` action runs ARBITRARY JavaScript in the loaded page context (full DOM/cookie/localStorage access, can drive same-origin requests) — set MOXXY_BROWSER_DISABLE_EVAL=1 to disable in-page scripting while keeping navigation/click/fill. ' +
392
+ 'Residual risk: by default subresource requests (img/fetch/script) issued by a loaded page are NOT filtered, so a hostile page can still send blind requests at internal services; set MOXXY_BROWSER_FILTER_SUBRESOURCES=1 to filter those too.',
393
+ inputSchema: z.object({
394
+ action: actionSchema,
395
+ }),
396
+ permission: { action: 'prompt' },
397
+ // Honest capability surface: browser_session spawns the Playwright sidecar
398
+ // (a child process) which drives a real browser to arbitrary hosts and may
399
+ // auto-install browser binaries into Playwright's cache on first use. The
400
+ // `eval` action additionally executes ARBITRARY in-page JavaScript (DOM /
401
+ // cookie / localStorage access of the loaded site) — gate it with
402
+ // MOXXY_BROWSER_DISABLE_EVAL=1 to keep navigation/click/fill but forbid
403
+ // scripting. Modeled on the Bash tool's declaration — these caps are
404
+ // advisory until @moxxy/plugin-security is enabled, at which point an
405
+ // isolator enforces them.
406
+ isolation: {
407
+ capabilities: {
408
+ subprocess: true,
409
+ net: { mode: 'any' },
410
+ // Sidecar may download/unpack browser binaries into the Playwright cache.
411
+ fs: { read: ['$cwd/**', '/tmp/**'], write: ['$cwd/**', '/tmp/**'] },
412
+ env: ['PATH', 'HOME', 'USER', 'PLAYWRIGHT_BROWSERS_PATH'],
413
+ timeMs: 120_000,
414
+ },
415
+ },
416
+ async handler({ action }, ctx) {
417
+ const sidecar = getSidecar(deps);
418
+ // Surface install-progress lines (and any other sidecar status writes)
419
+ // through this call's logger — visible in verbose mode and the event log
420
+ // ("downloading chromium…") instead of an apparently-hung turn. onStderr
421
+ // now supports concurrent subscribers and returns an unsubscribe.
422
+ const offStderr = sidecar.onStderr((line) => ctx.logger.info('browser_session', { line }));
423
+ // Per-call abort: pass ctx.signal so an abort cancels THIS call's RPC,
424
+ // rather than calling sidecar.close() which would tear down the shared
425
+ // singleton (and every other concurrent browser_session) on the bus.
426
+ const call = (method, params = {}) => sidecar.call(method, params, ctx.signal);
427
+ try {
428
+ switch (action.kind) {
429
+ case 'goto':
430
+ // Parent-side SSRF guard — the same assertPublicUrl web_fetch uses
431
+ // (loopback/private/link-local/metadata blocked, hostname resolved).
432
+ // The sidecar re-checks in its goto dispatch (defence in depth, it
433
+ // is a separate process) and intercepts in-page navigations.
434
+ try {
435
+ // fail-closed on the browser path: Chromium resolves names itself,
436
+ // so an unresolvable-here name must not be handed to the sidecar.
437
+ await assertPublicUrl(action.url, 'browser_session', { failClosed: true });
438
+ }
439
+ catch (err) {
440
+ if (err instanceof SsrfBlockedError) {
441
+ throw new MoxxyError({ code: 'INTERNAL', message: err.message });
442
+ }
443
+ throw err;
444
+ }
445
+ return await call('goto', {
446
+ url: action.url,
447
+ waitUntil: action.waitUntil,
448
+ timeoutMs: action.timeoutMs,
449
+ });
450
+ case 'click':
451
+ return await call('click', { selector: action.selector, timeoutMs: action.timeoutMs });
452
+ case 'fill':
453
+ return await call('fill', {
454
+ selector: action.selector,
455
+ value: action.value,
456
+ timeoutMs: action.timeoutMs,
457
+ });
458
+ case 'text':
459
+ return await call('text', { selector: action.selector });
460
+ case 'html':
461
+ return await call('html');
462
+ case 'screenshot':
463
+ return await call('screenshot', { fullPage: action.fullPage });
464
+ case 'eval':
465
+ // Deployment opt-out: in-page scripting can exfiltrate the loaded
466
+ // site's DOM/cookies/storage, so allow disabling it while keeping
467
+ // navigation/click/fill.
468
+ if (process.env.MOXXY_BROWSER_DISABLE_EVAL === '1') {
469
+ throw new MoxxyError({
470
+ code: 'INTERNAL',
471
+ message: 'browser_session eval is disabled (MOXXY_BROWSER_DISABLE_EVAL=1)',
472
+ });
473
+ }
474
+ return await call('eval', { expression: action.expression });
475
+ case 'url':
476
+ return await call('url');
477
+ }
478
+ }
479
+ finally {
480
+ offStderr();
481
+ }
482
+ },
483
+ });
484
+ }
485
+ /**
486
+ * Call a method on the shared sidecar (used by the browser SURFACE so it drives
487
+ * the SAME page the `browser_session` tool does — agent + user share one page).
488
+ */
489
+ export function browserSidecarCall(method, params = {}, deps) {
490
+ return getSidecar(deps).call(method, params);
491
+ }
492
+ /** Closes the singleton sidecar — wired to plugin `onShutdown`. */
493
+ export async function closeBrowserSidecar() {
494
+ if (SIDECAR_INSTANCE) {
495
+ await SIDECAR_INSTANCE.close();
496
+ SIDECAR_INSTANCE = null;
497
+ SIDECAR_DEPS = undefined;
498
+ }
499
+ }
500
+ //# sourceMappingURL=browser-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-session.js","sourceRoot":"","sources":["../src/browser-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type BrowserSessionDeps } from './browser-session.js';
2
+ export declare function buildBrowserSurface(deps?: BrowserSessionDeps): import("@moxxy/sdk").SurfaceDef;
3
+ //# sourceMappingURL=browser-surface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-surface.d.ts","sourceRoot":"","sources":["../src/browser-surface.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AA4C9B,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,kBAAkB,mCA+N5D"}