@moxxy/cli 0.14.1 → 0.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +332 -28
- package/dist/bin.js.map +1 -1
- package/dist/sidecar.js +26 -2
- package/dist/sidecar.js.map +1 -1
- package/package.json +2 -2
package/dist/sidecar.js
CHANGED
|
@@ -139,7 +139,7 @@ async function launchWithAutoInstall(browserType, which, headless) {
|
|
|
139
139
|
}
|
|
140
140
|
async function launchOnce(browserType, headless) {
|
|
141
141
|
const browser = await browserType.launch({ headless });
|
|
142
|
-
const context = await browser.newContext();
|
|
142
|
+
const context = await browser.newContext({ deviceScaleFactor: 2 });
|
|
143
143
|
await installNavigationSsrfGuard(context);
|
|
144
144
|
const page = await context.newPage();
|
|
145
145
|
return { browser, context, page };
|
|
@@ -272,7 +272,7 @@ async function dispatchInner(state2, req) {
|
|
|
272
272
|
}
|
|
273
273
|
case "frame": {
|
|
274
274
|
const h = await ensurePlaywright(state2, {});
|
|
275
|
-
const buf = await h.page.screenshot({ type: "jpeg", quality:
|
|
275
|
+
const buf = await h.page.screenshot({ type: "jpeg", quality: 70 });
|
|
276
276
|
const vp = h.page.viewportSize() ?? { width: 1280, height: 720 };
|
|
277
277
|
return {
|
|
278
278
|
id: req.id,
|
|
@@ -336,6 +336,30 @@ async function dispatchInner(state2, req) {
|
|
|
336
336
|
await h.page.mouse.wheel(0, dy ?? 0);
|
|
337
337
|
return { id: req.id, ok: true };
|
|
338
338
|
}
|
|
339
|
+
case "zoom": {
|
|
340
|
+
const { factor } = req.params ?? {};
|
|
341
|
+
const f = Number.isFinite(factor) ? Math.min(5, Math.max(0.25, factor)) : 1;
|
|
342
|
+
const h = await ensurePlaywright(state2, {});
|
|
343
|
+
await h.page.evaluate(`document.documentElement.style.zoom=String(${f})`);
|
|
344
|
+
return { id: req.id, ok: true };
|
|
345
|
+
}
|
|
346
|
+
case "capture": {
|
|
347
|
+
const { x, y, width, height } = req.params ?? {};
|
|
348
|
+
if (![x, y, width, height].every((n) => Number.isFinite(n)) || width < 1 || height < 1) {
|
|
349
|
+
throw badParams("x, y, width, height must be finite; width/height positive");
|
|
350
|
+
}
|
|
351
|
+
const h = await ensurePlaywright(state2, {});
|
|
352
|
+
const buf = await h.page.screenshot({ type: "png", clip: { x, y, width, height } });
|
|
353
|
+
return { id: req.id, ok: true, result: { mediaType: "image/png", base64: buf.toString("base64") } };
|
|
354
|
+
}
|
|
355
|
+
case "pick": {
|
|
356
|
+
const { x, y } = req.params ?? {};
|
|
357
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) throw badParams("x and y must be finite numbers");
|
|
358
|
+
const h = await ensurePlaywright(state2, {});
|
|
359
|
+
const expr = `(() => { const x=${x}, y=${y}; const el=document.elementFromPoint(x,y); if(!el) return null; const sel=(e)=>{ if(e.id) return '#'+CSS.escape(e.id); const p=[]; let n=e; while(n && n.nodeType===1 && n!==document.body){ let s=n.tagName.toLowerCase(); if(n.classList && n.classList.length) s+='.'+Array.from(n.classList).slice(0,2).map(c=>CSS.escape(c)).join('.'); const par=n.parentElement; if(par){ const same=Array.from(par.children).filter(c=>c.tagName===n.tagName); if(same.length>1) s+=':nth-of-type('+(same.indexOf(n)+1)+')'; } p.unshift(s); n=n.parentElement; } return p.join(' > '); }; return { selector: sel(el), tag: el.tagName.toLowerCase(), text: (el.textContent||'').replace(/\\s+/g,' ').trim().slice(0,140) }; })()`;
|
|
360
|
+
const info = await h.page.evaluate(expr);
|
|
361
|
+
return { id: req.id, ok: true, result: info };
|
|
362
|
+
}
|
|
339
363
|
case "eval": {
|
|
340
364
|
const h = await ensurePlaywright(state2, {});
|
|
341
365
|
const { expression } = req.params ?? {};
|
package/dist/sidecar.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../plugin-browser/src/ssrf-guard.ts","../../plugin-browser/src/sidecar/types.ts","../../plugin-browser/src/sidecar/install.ts","../../plugin-browser/src/sidecar/dispatch.ts","../../plugin-browser/src/sidecar.ts"],"names":["dnsLookup","state","text"],"mappings":"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","file":"sidecar.js","sourcesContent":["import { isIP } from 'node:net';\nimport { lookup as dnsLookup } from 'node:dns/promises';\n\n/**\n * Shared SSRF guard for every model-drivable navigation/fetch path in this\n * plugin: `web_fetch` (initial URL + every redirect hop), `browser_session`'s\n * goto (parent side), the sidecar's goto dispatch (child-process side), and\n * the sidecar's in-page navigation interceptor.\n *\n * Blocks non-HTTP(S) schemes, loopback (incl. `localhost`/`*.localhost`),\n * 0.0.0.0/8, RFC-1918 private ranges, link-local 169.254/16 (incl. the\n * 169.254.169.254 cloud metadata endpoint), CGNAT 100.64/10, multicast/\n * reserved, and IPv6 loopback/link-local/unique-local (+ v4-mapped). Hostnames\n * are resolved so an internal DNS name (or rebinding) can't smuggle a private\n * target past the literal-IP checks.\n *\n * NOTE: deliberately NO `@moxxy/sdk` import. The Playwright sidecar — a\n * separate child process whose bundle must stay free of non-builtin deps —\n * imports this module too. Parent-side callers wrap `SsrfBlockedError` into\n * `MoxxyError` themselves.\n */\n\n/** Thrown for every guard rejection (bad scheme, private/loopback target, unparseable URL). */\nexport class SsrfBlockedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SsrfBlockedError';\n }\n}\n\nexport type DnsResolver = (host: string) => Promise<ReadonlyArray<string>>;\nconst defaultResolver: DnsResolver = async (host) =>\n (await dnsLookup(host, { all: true })).map((a) => a.address);\nlet resolver: DnsResolver = defaultResolver;\n\n/** Test seam: override DNS resolution so SSRF tests stay hermetic. Pass null to reset. */\nexport function setSsrfDnsResolver(fn: DnsResolver | null): void {\n resolver = fn ?? defaultResolver;\n}\n\nfunction isBlockedIpv4(ip: string): boolean {\n const parts = ip.split('.').map((p) => Number(p));\n if (parts.length !== 4 || parts.some((p) => !Number.isInteger(p) || p < 0 || p > 255)) return true;\n const [a, b] = parts as [number, number, number, number];\n if (a === 0) return true; // 0.0.0.0/8 \"this host\"\n if (a === 127) return true; // loopback\n if (a === 10) return true; // private\n if (a === 172 && b >= 16 && b <= 31) return true; // private\n if (a === 192 && b === 168) return true; // private\n if (a === 169 && b === 254) return true; // link-local incl. 169.254.169.254 metadata\n if (a === 100 && b >= 64 && b <= 127) return true; // CGNAT 100.64/10\n if (a >= 224) return true; // multicast / reserved\n return false;\n}\n\nfunction isBlockedIpv6(ip: string): boolean {\n const addr = ip.toLowerCase().replace(/^\\[|\\]$/g, '').split('%')[0]!; // strip zone id\n if (addr === '::1' || addr === '::') return true; // loopback / unspecified\n if (addr.startsWith('fe80')) return true; // link-local\n if (addr.startsWith('fc') || addr.startsWith('fd')) return true; // unique-local fc00::/7\n const v4mapped = addr.match(/^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/);\n if (v4mapped) return isBlockedIpv4(v4mapped[1]!);\n return false;\n}\n\nexport function isBlockedIp(ip: string): boolean {\n const kind = isIP(ip);\n if (kind === 4) return isBlockedIpv4(ip);\n if (kind === 6) return isBlockedIpv6(ip);\n return true; // not a parseable IP → block\n}\n\n/**\n * Reject `raw` unless it is an http(s) URL whose host is (and resolves to)\n * a public address. `label` prefixes the error message so each caller's\n * rejections stay attributable (e.g. \"web_fetch\", \"browser_session\").\n *\n * Returns the vetted resolved addresses so callers can PIN the subsequent\n * connection to exactly what was checked (closing the DNS-rebinding TOCTOU\n * where the guard resolves one answer and the fetch independently resolves\n * another — see web-fetch's pinned undici dispatcher). Returns `null` when\n * there is nothing to pin: the host is already an IP literal (vetted above,\n * no DNS involved) or resolution failed (fail-open — a name the guard can't\n * resolve, the fetch's identical system resolver can't reach either).\n */\nexport async function assertPublicUrl(\n raw: string,\n label = 'request',\n): Promise<ReadonlyArray<string> | null> {\n let u: URL;\n try {\n u = new URL(raw);\n } catch {\n throw new SsrfBlockedError(`${label}: invalid URL: ${raw}`);\n }\n if (u.protocol !== 'http:' && u.protocol !== 'https:') {\n throw new SsrfBlockedError(`${label}: refusing non-HTTP(S) scheme \"${u.protocol}\"`);\n }\n const host = u.hostname.replace(/^\\[|\\]$/g, '');\n if (host === 'localhost' || host.endsWith('.localhost')) {\n throw new SsrfBlockedError(`${label}: refusing to fetch loopback host \"${host}\"`);\n }\n if (isIP(host)) {\n if (isBlockedIp(host))\n throw new SsrfBlockedError(`${label}: refusing private/loopback address \"${host}\"`);\n return null;\n }\n // Resolve the name and block if it maps to a private range (internal name or\n // DNS rebinding). Fail OPEN on resolution error: a name we can't resolve here\n // the subsequent fetch can't reach either, so it's no SSRF vector.\n let addrs: ReadonlyArray<string>;\n try {\n addrs = await resolver(host);\n } catch {\n return null;\n }\n for (const addr of addrs) {\n if (isBlockedIp(addr)) {\n throw new SsrfBlockedError(\n `${label}: host \"${host}\" resolves to a private/loopback address (${addr})`,\n );\n }\n }\n return addrs;\n}\n","export type BrowserKind = 'chromium' | 'firefox' | 'webkit';\n\nexport type ErrorKind =\n | 'init'\n | 'needs-install' // the `playwright` npm package itself isn't installed yet\n | 'navigation'\n | 'runtime'\n | 'timeout'\n | 'unknown';\n\nexport interface Req {\n readonly id: string;\n readonly method: string;\n readonly params?: Record<string, unknown>;\n}\n\nexport interface Ok {\n readonly id: string;\n readonly ok: true;\n readonly result?: unknown;\n /** One-shot human-readable note (e.g. \"Auto-installed Chromium\"). */\n readonly notice?: string;\n}\n\nexport interface Err {\n readonly id: string;\n readonly ok: false;\n readonly error: { message: string; kind: ErrorKind };\n}\n\nexport type Reply = Ok | Err;\n\nexport interface BrowserType {\n launch(opts: {\n headless: boolean;\n }): Promise<{ close(): Promise<void>; newContext(): Promise<unknown> }>;\n}\n\nexport interface PageHandle {\n goto(url: string, opts?: unknown): Promise<unknown>;\n click(selector: string, opts?: unknown): Promise<void>;\n fill(selector: string, value: string, opts?: unknown): Promise<void>;\n textContent(selector: string): Promise<string | null>;\n content(): Promise<string>;\n screenshot(opts?: unknown): Promise<Buffer>;\n evaluate(fn: string): Promise<unknown>;\n url(): string;\n close(): Promise<void>;\n // Coordinate-based input + viewport control for the live browser surface\n // (loosely typed — the real Playwright Page provides all of these).\n viewportSize(): { width: number; height: number } | null;\n setViewportSize(size: { width: number; height: number }): Promise<void>;\n goBack(opts?: unknown): Promise<unknown>;\n goForward(opts?: unknown): Promise<unknown>;\n reload(opts?: unknown): Promise<unknown>;\n readonly mouse: {\n move(x: number, y: number, opts?: unknown): Promise<void>;\n click(x: number, y: number, opts?: unknown): Promise<void>;\n wheel(dx: number, dy: number): Promise<void>;\n };\n readonly keyboard: {\n press(key: string): Promise<void>;\n type(text: string): Promise<void>;\n };\n}\n\n/** Minimal slice of Playwright's `Request` used by the navigation SSRF guard. */\nexport interface RouteRequest {\n url(): string;\n isNavigationRequest(): boolean;\n}\n\n/** Minimal slice of Playwright's `Route` used by the navigation SSRF guard. */\nexport interface RouteHandle {\n request(): RouteRequest;\n abort(errorCode?: string): Promise<void>;\n continue(): Promise<void>;\n}\n\nexport interface PlaywrightHandle {\n // Loosely typed so we can avoid importing the playwright types at compile time —\n // they're an optional peer dependency.\n readonly browser: { close(): Promise<void> };\n readonly context: {\n newPage(): Promise<unknown>;\n close(): Promise<void>;\n /** Optional because the type is a loose projection; real Playwright contexts always have it. */\n route?(pattern: string, handler: (route: RouteHandle) => Promise<void> | void): Promise<void>;\n };\n readonly page: PageHandle;\n}\n\nexport function errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * An error carrying a typed {@link ErrorKind} so the dispatch layer can map it\n * onto the wire reply's `error.kind` without poking an untyped `kind` property\n * onto a bare `Error`.\n */\nexport class SidecarError extends Error {\n constructor(\n message: string,\n readonly kind: ErrorKind,\n ) {\n super(message);\n this.name = 'SidecarError';\n }\n}\n\nexport function badParams(msg: string): SidecarError {\n return new SidecarError(msg, 'runtime');\n}\n","/**\n * Playwright lifecycle: import, launch, and one-shot auto-install of the\n * per-browser binary. Keeps the dispatch layer free of node:child_process\n * + Playwright-import noise.\n */\n\nimport { spawn } from 'node:child_process';\nimport { assertPublicUrl } from '../ssrf-guard.js';\nimport { SidecarError } from './types.js';\nimport type { BrowserKind, BrowserType, PageHandle, PlaywrightHandle } from './types.js';\n\nexport interface LaunchResult {\n handle: PlaywrightHandle;\n /** Set when the browser binary was auto-downloaded during this launch. */\n installNotice: string | null;\n}\n\nexport async function importPlaywright(): Promise<{\n chromium: BrowserType;\n firefox: BrowserType;\n webkit: BrowserType;\n}> {\n try {\n return (await import('playwright')) as never;\n } catch (err) {\n const underlying = err instanceof Error ? err.message : String(err);\n // Distinguish \"the npm package isn't installed\" (recoverable — the surface\n // can offer a one-click install, see `installPlaywrightPackage`) from any\n // other import failure. The `kind` rides the JSON-RPC reply so the browser\n // surface shows an \"Install\" affordance instead of a dead-end error.\n throw new SidecarError(\n `Playwright is not installed. Run \\`pnpm add playwright\\` (or \\`npm i playwright\\`) and then \\`npx playwright install\\` in the moxxy install dir.\\n` +\n `Underlying: ${underlying}`,\n isModuleNotFound(underlying) ? 'needs-install' : 'init',\n );\n }\n}\n\n/** True when an import failure is \"the `playwright` package can't be found\"\n * (vs. a load/runtime error inside an installed package). */\nfunction isModuleNotFound(message: string): boolean {\n return (\n /cannot find (package|module) ['\"]?playwright/i.test(message) ||\n /ERR_MODULE_NOT_FOUND/i.test(message) ||\n /failed to resolve ['\"]?playwright/i.test(message)\n );\n}\n\nexport interface InstallPlaywrightOptions {\n /** Directory whose `node_modules` should receive `playwright` — the CLI\n * install root (e.g. `<userData>/cli`). `npm` runs with this as its cwd. */\n readonly rootDir: string;\n /** Which browser engine binary to download after the npm package lands. */\n readonly browser?: BrowserKind;\n /** Per-line progress (npm/npx stdout+stderr) for streaming to the UI. */\n readonly onProgress?: (line: string) => void;\n readonly signal?: AbortSignal;\n}\n\n/**\n * Install the `playwright` npm package into `rootDir`, then download the browser\n * engine binary — the two halves the desktop browser surface needs. Driven by\n * the surface AFTER the user consents (the download is ~200MB). Streams progress\n * via `onProgress`; resolves on success, rejects with the failing step's output.\n *\n * Lives next to {@link importPlaywright} (which reports the `needs-install` that\n * triggers this) but is invoked in the RUNNER process — `rootDir`'s node_modules\n * is the one the sidecar later imports `playwright` from.\n */\nexport async function installPlaywrightPackage(opts: InstallPlaywrightOptions): Promise<void> {\n const which = opts.browser ?? 'chromium';\n opts.onProgress?.(`Installing the playwright npm package into ${opts.rootDir}…`);\n await runProcess('npm', ['install', '--no-fund', '--no-audit', 'playwright'], opts);\n opts.onProgress?.(`Downloading the ${which} browser engine (~150MB, one-time)…`);\n await runProcess('npx', ['playwright', 'install', which], opts);\n opts.onProgress?.('Playwright installed.');\n}\n\n/** Spawn a child, forward its output to `onProgress`, resolve on exit-0. */\nfunction runProcess(cmd: string, args: string[], opts: InstallPlaywrightOptions): Promise<void> {\n return new Promise((resolve, reject) => {\n if (opts.signal?.aborted) return reject(new Error('install aborted'));\n const child = spawn(cmd, args, { cwd: opts.rootDir, stdio: ['ignore', 'pipe', 'pipe'] });\n let tail = '';\n const onChunk = (chunk: Buffer): void => {\n const text = chunk.toString('utf8');\n for (const line of text.split(/\\r?\\n/)) if (line.trim()) opts.onProgress?.(line);\n tail = (tail + text).slice(-4000);\n };\n child.stdout.on('data', onChunk);\n child.stderr.on('data', onChunk);\n const onAbort = (): void => {\n child.kill();\n };\n opts.signal?.addEventListener('abort', onAbort, { once: true });\n child.once('error', (err) => {\n opts.signal?.removeEventListener('abort', onAbort);\n reject(err);\n });\n child.once('close', (code) => {\n opts.signal?.removeEventListener('abort', onAbort);\n if (code === 0) resolve();\n else\n reject(\n new Error(`\\`${cmd} ${args.join(' ')}\\` failed (exit ${code}): ${tail.trim() || '(no output)'}`),\n );\n });\n });\n}\n\n/**\n * Try to launch the browser. If the binary isn't downloaded yet\n * (Playwright distinguishes the npm install from the per-browser\n * binary download), run `npx playwright install <which>` once and\n * retry. The install can take 30s–2min on the first run depending on\n * connection; we surface progress on stderr (parent forwards to the\n * logger) and return a one-shot notice for the first tool response.\n */\nexport async function launchWithAutoInstall(\n browserType: BrowserType,\n which: BrowserKind,\n headless: boolean,\n): Promise<LaunchResult> {\n try {\n return { handle: await launchOnce(browserType, headless), installNotice: null };\n } catch (err) {\n if (!isMissingBrowserError(err)) throw err;\n process.stderr.write(\n `moxxy-browser: ${which} binary missing, running \\`npx playwright install ${which}\\` ` +\n `(one-time, ~150MB). This may take a minute…\\n`,\n );\n try {\n await runPlaywrightInstall(which);\n } catch (installErr) {\n const msg = installErr instanceof Error ? installErr.message : String(installErr);\n throw new SidecarError(\n `Playwright browser auto-install failed: ${msg}. ` +\n `Run \\`npx playwright install ${which}\\` manually in the moxxy dir.`,\n 'init',\n );\n }\n process.stderr.write(`moxxy-browser: install complete, retrying launch\\n`);\n return {\n handle: await launchOnce(browserType, headless),\n installNotice: `Auto-installed Playwright ${which} browser (~150MB, one-time).`,\n };\n }\n}\n\nasync function launchOnce(browserType: BrowserType, headless: boolean): Promise<PlaywrightHandle> {\n const browser = await browserType.launch({ headless });\n const context = (await browser.newContext()) as PlaywrightHandle['context'];\n await installNavigationSsrfGuard(context);\n const page = (await context.newPage()) as unknown as PageHandle;\n return { browser, context, page };\n}\n\n/**\n * Block navigations to private/loopback origins for the lifetime of the\n * context. The goto RPC is validated in the parent AND in dispatch, but a\n * page reached via a legitimate public goto can then redirect or\n * script-navigate itself to e.g. http://169.254.169.254/ — those navigations\n * never pass through the RPC layer, so we intercept them here. Navigation\n * requests (top-level + iframes, which covers HTTP redirect hops too) go\n * through the same `assertPublicUrl` guard as web_fetch; everything else is\n * passed through untouched so ordinary page loads don't pay a DNS round-trip\n * per subresource.\n *\n * Residual risk (also stated in the browser_session tool description):\n * SUBRESOURCE requests (img/fetch/script) from a loaded page are NOT\n * filtered. The browser's same-origin policy stops the page reading those\n * responses, but blind request side effects against internal services remain\n * possible. Filtering every request was judged disproportionate for now.\n */\nasync function installNavigationSsrfGuard(context: PlaywrightHandle['context']): Promise<void> {\n if (typeof context.route !== 'function') return; // loose projection: tolerate stubs without route()\n await context.route('**/*', async (route) => {\n const request = route.request();\n if (!request.isNavigationRequest()) return route.continue();\n try {\n await assertPublicUrl(request.url(), 'browser_session navigation');\n } catch {\n return route.abort('blockedbyclient');\n }\n return route.continue();\n });\n}\n\nfunction isMissingBrowserError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n // Playwright's \"Executable doesn't exist at …\" launch error fires\n // when the npm package is installed but the per-browser binary\n // hasn't been downloaded. The message stays stable across versions.\n return /Executable doesn'?t exist at/i.test(err.message);\n}\n\n/**\n * Run `npx playwright install <which>` and stream its output to the\n * sidecar's stderr so the operator can watch progress. Resolves on\n * exit-0; rejects with the tail of stderr otherwise.\n */\nfunction runPlaywrightInstall(which: BrowserKind): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn('npx', ['playwright', 'install', which], {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stderrTail = '';\n child.stdout.on('data', (chunk: Buffer) => process.stderr.write(chunk));\n child.stderr.on('data', (chunk: Buffer) => {\n process.stderr.write(chunk);\n stderrTail += chunk.toString('utf8');\n if (stderrTail.length > 4000) stderrTail = stderrTail.slice(-4000);\n });\n child.once('error', (err) => reject(err));\n child.once('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`exit ${code}: ${stderrTail.trim() || '(no stderr)'}`));\n });\n });\n}\n","/**\n * JSON-RPC dispatch table for the sidecar. Each `method` here corresponds\n * one-to-one with the wire-format methods documented in `sidecar.ts`.\n */\n\nimport { assertPublicUrl } from '../ssrf-guard.js';\nimport { importPlaywright, launchWithAutoInstall } from './install.js';\nimport {\n badParams,\n errMsg,\n SidecarError,\n type BrowserKind,\n type PlaywrightHandle,\n type Reply,\n type Req,\n} from './types.js';\n\nexport interface SidecarState {\n handle: PlaywrightHandle | null;\n /**\n * Set after a successful auto-install of browser binaries so the next\n * tool result can carry a `notice` letting the user/model know the\n * one-time download happened. Cleared once the notice has been\n * delivered (handed to the reply once, then forgotten).\n */\n pendingInstallNotice: string | null;\n}\n\nasync function ensurePlaywright(\n state: SidecarState,\n opts: { browser?: BrowserKind; headless?: boolean },\n): Promise<PlaywrightHandle> {\n if (state.handle) return state.handle;\n const pw = await importPlaywright();\n const which = opts.browser ?? 'chromium';\n const browserType = pw[which];\n const { handle, installNotice } = await launchWithAutoInstall(browserType, which, opts.headless ?? true);\n state.handle = handle;\n if (installNotice) state.pendingInstallNotice = installNotice;\n return state.handle;\n}\n\nexport async function teardown(state: SidecarState): Promise<void> {\n if (!state.handle) return;\n try {\n await state.handle.context.close();\n await state.handle.browser.close();\n } catch {\n /* ignore */\n }\n state.handle = null;\n}\n\nexport async function dispatch(state: SidecarState, req: Req): Promise<Reply> {\n try {\n return await dispatchInner(state, req);\n } catch (err) {\n return {\n id: req.id,\n ok: false,\n error: { message: errMsg(err), kind: err instanceof SidecarError ? err.kind : 'unknown' },\n };\n }\n}\n\nasync function dispatchInner(state: SidecarState, req: Req): Promise<Reply> {\n switch (req.method) {\n case 'init': {\n const opts = (req.params ?? {}) as { browser?: BrowserKind; headless?: boolean };\n await ensurePlaywright(state, opts);\n return { id: req.id, ok: true, result: { ready: true } };\n }\n case 'goto': {\n const { url, waitUntil, timeoutMs } = (req.params ?? {}) as {\n url: string;\n waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';\n timeoutMs?: number;\n };\n if (!url) throw badParams('url is required');\n // Defence-in-depth: the parent already runs the full SSRF guard before\n // sending this RPC, but the sidecar is a distinct process driven over\n // JSON-RPC, so re-check here rather than trust the caller to have\n // validated. Blocks file:// / javascript: schemes AND loopback/private/\n // link-local (incl. 169.254.169.254 metadata)/CGNAT targets, resolving\n // hostnames. Runs BEFORE ensurePlaywright so a blocked URL never\n // launches (or auto-installs) a browser.\n try {\n await assertPublicUrl(url, 'goto');\n } catch (err) {\n return { id: req.id, ok: false, error: { message: errMsg(err), kind: 'navigation' } };\n }\n const h = await ensurePlaywright(state, {});\n try {\n await h.page.goto(url, { waitUntil: waitUntil ?? 'domcontentloaded', timeout: timeoutMs ?? 30_000 });\n } catch (err) {\n return { id: req.id, ok: false, error: { message: errMsg(err), kind: 'navigation' } };\n }\n return { id: req.id, ok: true, result: { url: h.page.url() } };\n }\n case 'click': {\n const h = await ensurePlaywright(state, {});\n const { selector, timeoutMs } = (req.params ?? {}) as { selector: string; timeoutMs?: number };\n if (!selector) throw badParams('selector is required');\n await h.page.click(selector, { timeout: timeoutMs ?? 10_000 });\n return { id: req.id, ok: true };\n }\n case 'fill': {\n const h = await ensurePlaywright(state, {});\n const { selector, value, timeoutMs } = (req.params ?? {}) as {\n selector: string;\n value: string;\n timeoutMs?: number;\n };\n if (!selector) throw badParams('selector is required');\n await h.page.fill(selector, value ?? '', { timeout: timeoutMs ?? 10_000 });\n return { id: req.id, ok: true };\n }\n case 'text': {\n const h = await ensurePlaywright(state, {});\n const { selector } = (req.params ?? {}) as { selector?: string };\n if (selector) {\n const text = await h.page.textContent(selector);\n return { id: req.id, ok: true, result: text ?? '' };\n }\n // Whole-document text via evaluate\n const text = (await h.page.evaluate('document.body ? document.body.innerText : \"\"')) as string;\n return { id: req.id, ok: true, result: text };\n }\n case 'html': {\n const h = await ensurePlaywright(state, {});\n const html = await h.page.content();\n return { id: req.id, ok: true, result: html };\n }\n case 'screenshot': {\n const h = await ensurePlaywright(state, {});\n const { fullPage } = (req.params ?? {}) as { fullPage?: boolean };\n const buf = await h.page.screenshot({ fullPage: fullPage ?? false });\n return { id: req.id, ok: true, result: { mediaType: 'image/png', base64: buf.toString('base64') } };\n }\n case 'frame': {\n // Combined live-view frame for the browser SURFACE: a JPEG screenshot\n // plus the current url + viewport size, so the renderer can map clicks\n // back onto the page. One round-trip per frame.\n const h = await ensurePlaywright(state, {});\n const buf = await h.page.screenshot({ type: 'jpeg', quality: 55 });\n const vp = h.page.viewportSize() ?? { width: 1280, height: 720 };\n return {\n id: req.id,\n ok: true,\n result: {\n mediaType: 'image/jpeg',\n base64: buf.toString('base64'),\n url: h.page.url(),\n width: vp.width,\n height: vp.height,\n },\n };\n }\n case 'mouse': {\n const { x, y, count } = (req.params ?? {}) as { x: number; y: number; count?: number };\n // Parity with `key`/`eval`: validate before launching/driving the page so\n // a malformed surface message (missing/NaN coords) surfaces a clean\n // `badParams` instead of an opaque Playwright throw from click(undefined).\n if (!Number.isFinite(x) || !Number.isFinite(y)) throw badParams('x and y must be finite numbers');\n const h = await ensurePlaywright(state, {});\n await h.page.mouse.click(x, y, { clickCount: Math.min(3, Math.max(1, count ?? 1)) });\n return { id: req.id, ok: true, result: { url: h.page.url() } };\n }\n case 'mousemove': {\n // Hover: drives the page's pointer so :hover styles / tooltips render in\n // the polled frame. Cheap; the surface throttles how often it sends these.\n const { x, y } = (req.params ?? {}) as { x: number; y: number };\n if (!Number.isFinite(x) || !Number.isFinite(y)) throw badParams('x and y must be finite numbers');\n const h = await ensurePlaywright(state, {});\n await h.page.mouse.move(x, y);\n return { id: req.id, ok: true };\n }\n case 'setviewport': {\n // Resize the page to the pane so the live view fills the container instead\n // of being letterboxed at the default 1280×720.\n const { width, height } = (req.params ?? {}) as { width: number; height: number };\n if (!Number.isFinite(width) || !Number.isFinite(height) || width < 1 || height < 1) {\n throw badParams('width and height must be positive finite numbers');\n }\n const h = await ensurePlaywright(state, {});\n await h.page.setViewportSize({ width: Math.round(width), height: Math.round(height) });\n return { id: req.id, ok: true };\n }\n case 'back':\n case 'forward':\n case 'reload': {\n const h = await ensurePlaywright(state, {});\n try {\n if (req.method === 'back') await h.page.goBack();\n else if (req.method === 'forward') await h.page.goForward();\n else await h.page.reload();\n } catch (err) {\n // No history to go to is not an error worth failing the surface over.\n return { id: req.id, ok: false, error: { message: errMsg(err), kind: 'navigation' } };\n }\n return { id: req.id, ok: true, result: { url: h.page.url() } };\n }\n case 'key': {\n const h = await ensurePlaywright(state, {});\n const { key } = (req.params ?? {}) as { key: string };\n if (!key) throw badParams('key is required');\n // A single printable char is typed (inserts it); a named key is pressed.\n if (key.length === 1) await h.page.keyboard.type(key);\n else await h.page.keyboard.press(key);\n return { id: req.id, ok: true };\n }\n case 'scroll': {\n const h = await ensurePlaywright(state, {});\n const { dy } = (req.params ?? {}) as { dy: number };\n await h.page.mouse.wheel(0, dy ?? 0);\n return { id: req.id, ok: true };\n }\n case 'eval': {\n const h = await ensurePlaywright(state, {});\n const { expression } = (req.params ?? {}) as { expression: string };\n if (!expression) throw badParams('expression is required');\n const value = await h.page.evaluate(expression);\n return { id: req.id, ok: true, result: value };\n }\n case 'url': {\n const h = await ensurePlaywright(state, {});\n return { id: req.id, ok: true, result: h.page.url() };\n }\n case 'close': {\n await teardown(state);\n return { id: req.id, ok: true };\n }\n default:\n return {\n id: req.id,\n ok: false,\n error: { message: `unknown method: ${req.method}`, kind: 'runtime' },\n };\n }\n}\n","#!/usr/bin/env node\n/**\n * Playwright sidecar — owns a single browser context. Speaks newline-delimited\n * JSON-RPC over stdio so the parent (`browser_session` tool) doesn't load\n * Playwright into its own process. Crash isolation, lazy install: the parent\n * only spawns this when the heavy tier is actually needed.\n *\n * Wire format (one line per message):\n * { \"id\": \"uuid\", \"method\": \"goto\"|\"click\"|\"fill\"|\"text\"|\"html\"|\"screenshot\"|\"eval\"|\"close\", \"params\": {...} }\n * { \"id\": \"uuid\", \"ok\": true, \"result\": ... }\n * { \"id\": \"uuid\", \"ok\": false, \"error\": { \"message\": \"...\", \"kind\": \"init\"|\"navigation\"|\"runtime\"|\"timeout\" } }\n *\n * Run with `node dist/sidecar.js` (the package's `bin` entry is\n * `moxxy-browser-sidecar`). Parent terminates by closing stdin or sending\n * `{method:'close'}`.\n */\n\nimport * as readline from 'node:readline';\nimport { fileURLToPath } from 'node:url';\nimport { dispatch, teardown, type SidecarState } from './sidecar/dispatch.js';\nimport { errMsg, type Reply, type Req } from './sidecar/types.js';\n\nconst state: SidecarState = { handle: null, pendingInstallNotice: null };\n\nfunction write(reply: Reply): void {\n // Drain the install-notice flag into the first reply that goes out\n // after the install completed, then clear it. Errors get the notice\n // too — sometimes the launch retry surfaces a different problem and\n // the user still wants to know we tried to install.\n if (state.pendingInstallNotice) {\n if (reply.ok) {\n reply = { ...reply, notice: state.pendingInstallNotice };\n } else {\n reply = {\n ...reply,\n error: {\n ...reply.error,\n message: `${state.pendingInstallNotice} Then: ${reply.error.message}`,\n },\n };\n }\n state.pendingInstallNotice = null;\n }\n process.stdout.write(JSON.stringify(reply) + '\\n');\n}\n\n/**\n * Tears down the browser context AND exits the process. Used both by\n * the explicit `close` RPC path and the parent-loss / stdin-close\n * paths so all cleanup goes through one routine.\n */\nasync function shutdownAndExit(code: number): Promise<void> {\n await teardown(state);\n process.exit(code);\n}\n\n/**\n * Parent watchdog: if the moxxy process that spawned this sidecar\n * disappears (crash, SIGKILL, terminal hangup), there's no stdin EOF\n * to rely on — orphan Chromium would keep running and chew CPU/memory\n * until the user notices. Poll the parent PID every few seconds and\n * self-terminate when it goes away.\n *\n * `process.kill(pid, 0)` is the POSIX trick for \"does this PID\n * exist?\" — no signal is actually delivered. Throws ESRCH when the\n * process is gone (or EPERM when it exists but we can't signal it —\n * still alive, so don't treat as gone).\n */\nfunction startParentWatchdog(): void {\n const parentPid = process.ppid;\n if (!parentPid || parentPid <= 1) return; // already orphaned (init), nothing to watch\n const interval = setInterval(() => {\n try {\n process.kill(parentPid, 0);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ESRCH') {\n clearInterval(interval);\n void shutdownAndExit(0);\n }\n // EPERM means the process exists but we can't signal it — still alive.\n }\n }, 2000);\n interval.unref?.(); // never block the event loop from exiting\n}\n\nlet queue: Promise<void> = Promise.resolve();\n\n/**\n * Parse one input line and chain its dispatch onto the serial request queue.\n * `out` is the sink for replies (real run: {@link write}; tests inject a stub).\n * Exported so a test can drive the queue without spinning up the whole stdio\n * loop. Returns the queue tail so callers can await it.\n *\n * The `.catch` on the chained link is load-bearing: a throw from `out` (e.g. a\n * broken stdout pipe) would otherwise reject `queue` permanently and strand\n * EVERY subsequent request, since each link chains off the previous one.\n * Swallow it here — after emitting a best-effort error reply — so the next\n * request still serves.\n */\nexport function enqueueLine(line: string, out: (reply: Reply) => void): Promise<void> {\n if (!line.trim()) return queue;\n let req: Req;\n try {\n req = JSON.parse(line) as Req;\n } catch {\n out({ id: 'unknown', ok: false, error: { message: 'invalid JSON', kind: 'runtime' } });\n return queue;\n }\n if (!req.id || !req.method) {\n out({\n id: req.id ?? 'unknown',\n ok: false,\n error: { message: 'request requires { id, method }', kind: 'runtime' },\n });\n return queue;\n }\n // Sequentially serve requests on the single page. Parent can pipeline by\n // sending more requests; we serialize them inside the sidecar so a goto\n // doesn't race a click.\n queue = queue\n .then(async () => {\n const reply = await dispatch(state, req);\n out(reply);\n })\n .catch((err) => {\n try {\n out({ id: req.id, ok: false, error: { message: errMsg(err), kind: 'runtime' } });\n } catch {\n /* stdout is gone too — nothing left to do but keep the queue alive */\n }\n });\n return queue;\n}\n\nasync function main(): Promise<void> {\n startParentWatchdog();\n const rl = readline.createInterface({ input: process.stdin });\n rl.on('line', (line) => {\n void enqueueLine(line, write);\n });\n rl.once('close', () => {\n void shutdownAndExit(0);\n });\n // Defensive: if our stdout pipe breaks (parent died mid-write), Node\n // would otherwise throw an uncaught EPIPE on the next write. Treat\n // it as a signal to clean up gracefully instead.\n process.stdout.on('error', (err) => {\n if ((err as NodeJS.ErrnoException).code === 'EPIPE') {\n void shutdownAndExit(0);\n }\n });\n}\n\n// Auto-run only when executed as the bin script — not when imported (tests).\nif (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {\n main().catch((err) => {\n process.stderr.write(`sidecar fatal: ${errMsg(err)}\\n`);\n void shutdownAndExit(1);\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../plugin-browser/src/ssrf-guard.ts","../../plugin-browser/src/sidecar/types.ts","../../plugin-browser/src/sidecar/install.ts","../../plugin-browser/src/sidecar/dispatch.ts","../../plugin-browser/src/sidecar.ts"],"names":["dnsLookup","state","text"],"mappings":"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","file":"sidecar.js","sourcesContent":["import { isIP } from 'node:net';\nimport { lookup as dnsLookup } from 'node:dns/promises';\n\n/**\n * Shared SSRF guard for every model-drivable navigation/fetch path in this\n * plugin: `web_fetch` (initial URL + every redirect hop), `browser_session`'s\n * goto (parent side), the sidecar's goto dispatch (child-process side), and\n * the sidecar's in-page navigation interceptor.\n *\n * Blocks non-HTTP(S) schemes, loopback (incl. `localhost`/`*.localhost`),\n * 0.0.0.0/8, RFC-1918 private ranges, link-local 169.254/16 (incl. the\n * 169.254.169.254 cloud metadata endpoint), CGNAT 100.64/10, multicast/\n * reserved, and IPv6 loopback/link-local/unique-local (+ v4-mapped). Hostnames\n * are resolved so an internal DNS name (or rebinding) can't smuggle a private\n * target past the literal-IP checks.\n *\n * NOTE: deliberately NO `@moxxy/sdk` import. The Playwright sidecar — a\n * separate child process whose bundle must stay free of non-builtin deps —\n * imports this module too. Parent-side callers wrap `SsrfBlockedError` into\n * `MoxxyError` themselves.\n */\n\n/** Thrown for every guard rejection (bad scheme, private/loopback target, unparseable URL). */\nexport class SsrfBlockedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SsrfBlockedError';\n }\n}\n\nexport type DnsResolver = (host: string) => Promise<ReadonlyArray<string>>;\nconst defaultResolver: DnsResolver = async (host) =>\n (await dnsLookup(host, { all: true })).map((a) => a.address);\nlet resolver: DnsResolver = defaultResolver;\n\n/** Test seam: override DNS resolution so SSRF tests stay hermetic. Pass null to reset. */\nexport function setSsrfDnsResolver(fn: DnsResolver | null): void {\n resolver = fn ?? defaultResolver;\n}\n\nfunction isBlockedIpv4(ip: string): boolean {\n const parts = ip.split('.').map((p) => Number(p));\n if (parts.length !== 4 || parts.some((p) => !Number.isInteger(p) || p < 0 || p > 255)) return true;\n const [a, b] = parts as [number, number, number, number];\n if (a === 0) return true; // 0.0.0.0/8 \"this host\"\n if (a === 127) return true; // loopback\n if (a === 10) return true; // private\n if (a === 172 && b >= 16 && b <= 31) return true; // private\n if (a === 192 && b === 168) return true; // private\n if (a === 169 && b === 254) return true; // link-local incl. 169.254.169.254 metadata\n if (a === 100 && b >= 64 && b <= 127) return true; // CGNAT 100.64/10\n if (a >= 224) return true; // multicast / reserved\n return false;\n}\n\nfunction isBlockedIpv6(ip: string): boolean {\n const addr = ip.toLowerCase().replace(/^\\[|\\]$/g, '').split('%')[0]!; // strip zone id\n if (addr === '::1' || addr === '::') return true; // loopback / unspecified\n if (addr.startsWith('fe80')) return true; // link-local\n if (addr.startsWith('fc') || addr.startsWith('fd')) return true; // unique-local fc00::/7\n const v4mapped = addr.match(/^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/);\n if (v4mapped) return isBlockedIpv4(v4mapped[1]!);\n return false;\n}\n\nexport function isBlockedIp(ip: string): boolean {\n const kind = isIP(ip);\n if (kind === 4) return isBlockedIpv4(ip);\n if (kind === 6) return isBlockedIpv6(ip);\n return true; // not a parseable IP → block\n}\n\n/**\n * Reject `raw` unless it is an http(s) URL whose host is (and resolves to)\n * a public address. `label` prefixes the error message so each caller's\n * rejections stay attributable (e.g. \"web_fetch\", \"browser_session\").\n *\n * Returns the vetted resolved addresses so callers can PIN the subsequent\n * connection to exactly what was checked (closing the DNS-rebinding TOCTOU\n * where the guard resolves one answer and the fetch independently resolves\n * another — see web-fetch's pinned undici dispatcher). Returns `null` when\n * there is nothing to pin: the host is already an IP literal (vetted above,\n * no DNS involved) or resolution failed (fail-open — a name the guard can't\n * resolve, the fetch's identical system resolver can't reach either).\n */\nexport async function assertPublicUrl(\n raw: string,\n label = 'request',\n): Promise<ReadonlyArray<string> | null> {\n let u: URL;\n try {\n u = new URL(raw);\n } catch {\n throw new SsrfBlockedError(`${label}: invalid URL: ${raw}`);\n }\n if (u.protocol !== 'http:' && u.protocol !== 'https:') {\n throw new SsrfBlockedError(`${label}: refusing non-HTTP(S) scheme \"${u.protocol}\"`);\n }\n const host = u.hostname.replace(/^\\[|\\]$/g, '');\n if (host === 'localhost' || host.endsWith('.localhost')) {\n throw new SsrfBlockedError(`${label}: refusing to fetch loopback host \"${host}\"`);\n }\n if (isIP(host)) {\n if (isBlockedIp(host))\n throw new SsrfBlockedError(`${label}: refusing private/loopback address \"${host}\"`);\n return null;\n }\n // Resolve the name and block if it maps to a private range (internal name or\n // DNS rebinding). Fail OPEN on resolution error: a name we can't resolve here\n // the subsequent fetch can't reach either, so it's no SSRF vector.\n let addrs: ReadonlyArray<string>;\n try {\n addrs = await resolver(host);\n } catch {\n return null;\n }\n for (const addr of addrs) {\n if (isBlockedIp(addr)) {\n throw new SsrfBlockedError(\n `${label}: host \"${host}\" resolves to a private/loopback address (${addr})`,\n );\n }\n }\n return addrs;\n}\n","export type BrowserKind = 'chromium' | 'firefox' | 'webkit';\n\nexport type ErrorKind =\n | 'init'\n | 'needs-install' // the `playwright` npm package itself isn't installed yet\n | 'navigation'\n | 'runtime'\n | 'timeout'\n | 'unknown';\n\nexport interface Req {\n readonly id: string;\n readonly method: string;\n readonly params?: Record<string, unknown>;\n}\n\nexport interface Ok {\n readonly id: string;\n readonly ok: true;\n readonly result?: unknown;\n /** One-shot human-readable note (e.g. \"Auto-installed Chromium\"). */\n readonly notice?: string;\n}\n\nexport interface Err {\n readonly id: string;\n readonly ok: false;\n readonly error: { message: string; kind: ErrorKind };\n}\n\nexport type Reply = Ok | Err;\n\nexport interface BrowserType {\n launch(opts: {\n headless: boolean;\n }): Promise<{ close(): Promise<void>; newContext(opts?: unknown): Promise<unknown> }>;\n}\n\nexport interface PageHandle {\n goto(url: string, opts?: unknown): Promise<unknown>;\n click(selector: string, opts?: unknown): Promise<void>;\n fill(selector: string, value: string, opts?: unknown): Promise<void>;\n textContent(selector: string): Promise<string | null>;\n content(): Promise<string>;\n screenshot(opts?: unknown): Promise<Buffer>;\n evaluate(fn: string): Promise<unknown>;\n url(): string;\n close(): Promise<void>;\n // Coordinate-based input + viewport control for the live browser surface\n // (loosely typed — the real Playwright Page provides all of these).\n viewportSize(): { width: number; height: number } | null;\n setViewportSize(size: { width: number; height: number }): Promise<void>;\n goBack(opts?: unknown): Promise<unknown>;\n goForward(opts?: unknown): Promise<unknown>;\n reload(opts?: unknown): Promise<unknown>;\n readonly mouse: {\n move(x: number, y: number, opts?: unknown): Promise<void>;\n click(x: number, y: number, opts?: unknown): Promise<void>;\n wheel(dx: number, dy: number): Promise<void>;\n };\n readonly keyboard: {\n press(key: string): Promise<void>;\n type(text: string): Promise<void>;\n };\n}\n\n/** Minimal slice of Playwright's `Request` used by the navigation SSRF guard. */\nexport interface RouteRequest {\n url(): string;\n isNavigationRequest(): boolean;\n}\n\n/** Minimal slice of Playwright's `Route` used by the navigation SSRF guard. */\nexport interface RouteHandle {\n request(): RouteRequest;\n abort(errorCode?: string): Promise<void>;\n continue(): Promise<void>;\n}\n\nexport interface PlaywrightHandle {\n // Loosely typed so we can avoid importing the playwright types at compile time —\n // they're an optional peer dependency.\n readonly browser: { close(): Promise<void> };\n readonly context: {\n newPage(): Promise<unknown>;\n close(): Promise<void>;\n /** Optional because the type is a loose projection; real Playwright contexts always have it. */\n route?(pattern: string, handler: (route: RouteHandle) => Promise<void> | void): Promise<void>;\n };\n readonly page: PageHandle;\n}\n\nexport function errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * An error carrying a typed {@link ErrorKind} so the dispatch layer can map it\n * onto the wire reply's `error.kind` without poking an untyped `kind` property\n * onto a bare `Error`.\n */\nexport class SidecarError extends Error {\n constructor(\n message: string,\n readonly kind: ErrorKind,\n ) {\n super(message);\n this.name = 'SidecarError';\n }\n}\n\nexport function badParams(msg: string): SidecarError {\n return new SidecarError(msg, 'runtime');\n}\n","/**\n * Playwright lifecycle: import, launch, and one-shot auto-install of the\n * per-browser binary. Keeps the dispatch layer free of node:child_process\n * + Playwright-import noise.\n */\n\nimport { spawn } from 'node:child_process';\nimport { assertPublicUrl } from '../ssrf-guard.js';\nimport { SidecarError } from './types.js';\nimport type { BrowserKind, BrowserType, PageHandle, PlaywrightHandle } from './types.js';\n\nexport interface LaunchResult {\n handle: PlaywrightHandle;\n /** Set when the browser binary was auto-downloaded during this launch. */\n installNotice: string | null;\n}\n\nexport async function importPlaywright(): Promise<{\n chromium: BrowserType;\n firefox: BrowserType;\n webkit: BrowserType;\n}> {\n try {\n return (await import('playwright')) as never;\n } catch (err) {\n const underlying = err instanceof Error ? err.message : String(err);\n // Distinguish \"the npm package isn't installed\" (recoverable — the surface\n // can offer a one-click install, see `installPlaywrightPackage`) from any\n // other import failure. The `kind` rides the JSON-RPC reply so the browser\n // surface shows an \"Install\" affordance instead of a dead-end error.\n throw new SidecarError(\n `Playwright is not installed. Run \\`pnpm add playwright\\` (or \\`npm i playwright\\`) and then \\`npx playwright install\\` in the moxxy install dir.\\n` +\n `Underlying: ${underlying}`,\n isModuleNotFound(underlying) ? 'needs-install' : 'init',\n );\n }\n}\n\n/** True when an import failure is \"the `playwright` package can't be found\"\n * (vs. a load/runtime error inside an installed package). */\nfunction isModuleNotFound(message: string): boolean {\n return (\n /cannot find (package|module) ['\"]?playwright/i.test(message) ||\n /ERR_MODULE_NOT_FOUND/i.test(message) ||\n /failed to resolve ['\"]?playwright/i.test(message)\n );\n}\n\nexport interface InstallPlaywrightOptions {\n /** Directory whose `node_modules` should receive `playwright` — the CLI\n * install root (e.g. `<userData>/cli`). `npm` runs with this as its cwd. */\n readonly rootDir: string;\n /** Which browser engine binary to download after the npm package lands. */\n readonly browser?: BrowserKind;\n /** Per-line progress (npm/npx stdout+stderr) for streaming to the UI. */\n readonly onProgress?: (line: string) => void;\n readonly signal?: AbortSignal;\n}\n\n/**\n * Install the `playwright` npm package into `rootDir`, then download the browser\n * engine binary — the two halves the desktop browser surface needs. Driven by\n * the surface AFTER the user consents (the download is ~200MB). Streams progress\n * via `onProgress`; resolves on success, rejects with the failing step's output.\n *\n * Lives next to {@link importPlaywright} (which reports the `needs-install` that\n * triggers this) but is invoked in the RUNNER process — `rootDir`'s node_modules\n * is the one the sidecar later imports `playwright` from.\n */\nexport async function installPlaywrightPackage(opts: InstallPlaywrightOptions): Promise<void> {\n const which = opts.browser ?? 'chromium';\n opts.onProgress?.(`Installing the playwright npm package into ${opts.rootDir}…`);\n await runProcess('npm', ['install', '--no-fund', '--no-audit', 'playwright'], opts);\n opts.onProgress?.(`Downloading the ${which} browser engine (~150MB, one-time)…`);\n await runProcess('npx', ['playwright', 'install', which], opts);\n opts.onProgress?.('Playwright installed.');\n}\n\n/** Spawn a child, forward its output to `onProgress`, resolve on exit-0. */\nfunction runProcess(cmd: string, args: string[], opts: InstallPlaywrightOptions): Promise<void> {\n return new Promise((resolve, reject) => {\n if (opts.signal?.aborted) return reject(new Error('install aborted'));\n const child = spawn(cmd, args, { cwd: opts.rootDir, stdio: ['ignore', 'pipe', 'pipe'] });\n let tail = '';\n const onChunk = (chunk: Buffer): void => {\n const text = chunk.toString('utf8');\n for (const line of text.split(/\\r?\\n/)) if (line.trim()) opts.onProgress?.(line);\n tail = (tail + text).slice(-4000);\n };\n child.stdout.on('data', onChunk);\n child.stderr.on('data', onChunk);\n const onAbort = (): void => {\n child.kill();\n };\n opts.signal?.addEventListener('abort', onAbort, { once: true });\n child.once('error', (err) => {\n opts.signal?.removeEventListener('abort', onAbort);\n reject(err);\n });\n child.once('close', (code) => {\n opts.signal?.removeEventListener('abort', onAbort);\n if (code === 0) resolve();\n else\n reject(\n new Error(`\\`${cmd} ${args.join(' ')}\\` failed (exit ${code}): ${tail.trim() || '(no output)'}`),\n );\n });\n });\n}\n\n/**\n * Try to launch the browser. If the binary isn't downloaded yet\n * (Playwright distinguishes the npm install from the per-browser\n * binary download), run `npx playwright install <which>` once and\n * retry. The install can take 30s–2min on the first run depending on\n * connection; we surface progress on stderr (parent forwards to the\n * logger) and return a one-shot notice for the first tool response.\n */\nexport async function launchWithAutoInstall(\n browserType: BrowserType,\n which: BrowserKind,\n headless: boolean,\n): Promise<LaunchResult> {\n try {\n return { handle: await launchOnce(browserType, headless), installNotice: null };\n } catch (err) {\n if (!isMissingBrowserError(err)) throw err;\n process.stderr.write(\n `moxxy-browser: ${which} binary missing, running \\`npx playwright install ${which}\\` ` +\n `(one-time, ~150MB). This may take a minute…\\n`,\n );\n try {\n await runPlaywrightInstall(which);\n } catch (installErr) {\n const msg = installErr instanceof Error ? installErr.message : String(installErr);\n throw new SidecarError(\n `Playwright browser auto-install failed: ${msg}. ` +\n `Run \\`npx playwright install ${which}\\` manually in the moxxy dir.`,\n 'init',\n );\n }\n process.stderr.write(`moxxy-browser: install complete, retrying launch\\n`);\n return {\n handle: await launchOnce(browserType, headless),\n installNotice: `Auto-installed Playwright ${which} browser (~150MB, one-time).`,\n };\n }\n}\n\nasync function launchOnce(browserType: BrowserType, headless: boolean): Promise<PlaywrightHandle> {\n const browser = await browserType.launch({ headless });\n // deviceScaleFactor: 2 so the live-view / region screenshots are captured at\n // Retina density — a 1× capture upscaled into a HiDPI pane is what made the\n // surface look blurry. Costs ~2× the screenshot bytes; worth it for crisp text.\n const context = (await browser.newContext({ deviceScaleFactor: 2 })) as PlaywrightHandle['context'];\n await installNavigationSsrfGuard(context);\n const page = (await context.newPage()) as unknown as PageHandle;\n return { browser, context, page };\n}\n\n/**\n * Block navigations to private/loopback origins for the lifetime of the\n * context. The goto RPC is validated in the parent AND in dispatch, but a\n * page reached via a legitimate public goto can then redirect or\n * script-navigate itself to e.g. http://169.254.169.254/ — those navigations\n * never pass through the RPC layer, so we intercept them here. Navigation\n * requests (top-level + iframes, which covers HTTP redirect hops too) go\n * through the same `assertPublicUrl` guard as web_fetch; everything else is\n * passed through untouched so ordinary page loads don't pay a DNS round-trip\n * per subresource.\n *\n * Residual risk (also stated in the browser_session tool description):\n * SUBRESOURCE requests (img/fetch/script) from a loaded page are NOT\n * filtered. The browser's same-origin policy stops the page reading those\n * responses, but blind request side effects against internal services remain\n * possible. Filtering every request was judged disproportionate for now.\n */\nasync function installNavigationSsrfGuard(context: PlaywrightHandle['context']): Promise<void> {\n if (typeof context.route !== 'function') return; // loose projection: tolerate stubs without route()\n await context.route('**/*', async (route) => {\n const request = route.request();\n if (!request.isNavigationRequest()) return route.continue();\n try {\n await assertPublicUrl(request.url(), 'browser_session navigation');\n } catch {\n return route.abort('blockedbyclient');\n }\n return route.continue();\n });\n}\n\nfunction isMissingBrowserError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n // Playwright's \"Executable doesn't exist at …\" launch error fires\n // when the npm package is installed but the per-browser binary\n // hasn't been downloaded. The message stays stable across versions.\n return /Executable doesn'?t exist at/i.test(err.message);\n}\n\n/**\n * Run `npx playwright install <which>` and stream its output to the\n * sidecar's stderr so the operator can watch progress. Resolves on\n * exit-0; rejects with the tail of stderr otherwise.\n */\nfunction runPlaywrightInstall(which: BrowserKind): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn('npx', ['playwright', 'install', which], {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stderrTail = '';\n child.stdout.on('data', (chunk: Buffer) => process.stderr.write(chunk));\n child.stderr.on('data', (chunk: Buffer) => {\n process.stderr.write(chunk);\n stderrTail += chunk.toString('utf8');\n if (stderrTail.length > 4000) stderrTail = stderrTail.slice(-4000);\n });\n child.once('error', (err) => reject(err));\n child.once('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`exit ${code}: ${stderrTail.trim() || '(no stderr)'}`));\n });\n });\n}\n","/**\n * JSON-RPC dispatch table for the sidecar. Each `method` here corresponds\n * one-to-one with the wire-format methods documented in `sidecar.ts`.\n */\n\nimport { assertPublicUrl } from '../ssrf-guard.js';\nimport { importPlaywright, launchWithAutoInstall } from './install.js';\nimport {\n badParams,\n errMsg,\n SidecarError,\n type BrowserKind,\n type PlaywrightHandle,\n type Reply,\n type Req,\n} from './types.js';\n\nexport interface SidecarState {\n handle: PlaywrightHandle | null;\n /**\n * Set after a successful auto-install of browser binaries so the next\n * tool result can carry a `notice` letting the user/model know the\n * one-time download happened. Cleared once the notice has been\n * delivered (handed to the reply once, then forgotten).\n */\n pendingInstallNotice: string | null;\n}\n\nasync function ensurePlaywright(\n state: SidecarState,\n opts: { browser?: BrowserKind; headless?: boolean },\n): Promise<PlaywrightHandle> {\n if (state.handle) return state.handle;\n const pw = await importPlaywright();\n const which = opts.browser ?? 'chromium';\n const browserType = pw[which];\n const { handle, installNotice } = await launchWithAutoInstall(browserType, which, opts.headless ?? true);\n state.handle = handle;\n if (installNotice) state.pendingInstallNotice = installNotice;\n return state.handle;\n}\n\nexport async function teardown(state: SidecarState): Promise<void> {\n if (!state.handle) return;\n try {\n await state.handle.context.close();\n await state.handle.browser.close();\n } catch {\n /* ignore */\n }\n state.handle = null;\n}\n\nexport async function dispatch(state: SidecarState, req: Req): Promise<Reply> {\n try {\n return await dispatchInner(state, req);\n } catch (err) {\n return {\n id: req.id,\n ok: false,\n error: { message: errMsg(err), kind: err instanceof SidecarError ? err.kind : 'unknown' },\n };\n }\n}\n\nasync function dispatchInner(state: SidecarState, req: Req): Promise<Reply> {\n switch (req.method) {\n case 'init': {\n const opts = (req.params ?? {}) as { browser?: BrowserKind; headless?: boolean };\n await ensurePlaywright(state, opts);\n return { id: req.id, ok: true, result: { ready: true } };\n }\n case 'goto': {\n const { url, waitUntil, timeoutMs } = (req.params ?? {}) as {\n url: string;\n waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';\n timeoutMs?: number;\n };\n if (!url) throw badParams('url is required');\n // Defence-in-depth: the parent already runs the full SSRF guard before\n // sending this RPC, but the sidecar is a distinct process driven over\n // JSON-RPC, so re-check here rather than trust the caller to have\n // validated. Blocks file:// / javascript: schemes AND loopback/private/\n // link-local (incl. 169.254.169.254 metadata)/CGNAT targets, resolving\n // hostnames. Runs BEFORE ensurePlaywright so a blocked URL never\n // launches (or auto-installs) a browser.\n try {\n await assertPublicUrl(url, 'goto');\n } catch (err) {\n return { id: req.id, ok: false, error: { message: errMsg(err), kind: 'navigation' } };\n }\n const h = await ensurePlaywright(state, {});\n try {\n await h.page.goto(url, { waitUntil: waitUntil ?? 'domcontentloaded', timeout: timeoutMs ?? 30_000 });\n } catch (err) {\n return { id: req.id, ok: false, error: { message: errMsg(err), kind: 'navigation' } };\n }\n return { id: req.id, ok: true, result: { url: h.page.url() } };\n }\n case 'click': {\n const h = await ensurePlaywright(state, {});\n const { selector, timeoutMs } = (req.params ?? {}) as { selector: string; timeoutMs?: number };\n if (!selector) throw badParams('selector is required');\n await h.page.click(selector, { timeout: timeoutMs ?? 10_000 });\n return { id: req.id, ok: true };\n }\n case 'fill': {\n const h = await ensurePlaywright(state, {});\n const { selector, value, timeoutMs } = (req.params ?? {}) as {\n selector: string;\n value: string;\n timeoutMs?: number;\n };\n if (!selector) throw badParams('selector is required');\n await h.page.fill(selector, value ?? '', { timeout: timeoutMs ?? 10_000 });\n return { id: req.id, ok: true };\n }\n case 'text': {\n const h = await ensurePlaywright(state, {});\n const { selector } = (req.params ?? {}) as { selector?: string };\n if (selector) {\n const text = await h.page.textContent(selector);\n return { id: req.id, ok: true, result: text ?? '' };\n }\n // Whole-document text via evaluate\n const text = (await h.page.evaluate('document.body ? document.body.innerText : \"\"')) as string;\n return { id: req.id, ok: true, result: text };\n }\n case 'html': {\n const h = await ensurePlaywright(state, {});\n const html = await h.page.content();\n return { id: req.id, ok: true, result: html };\n }\n case 'screenshot': {\n const h = await ensurePlaywright(state, {});\n const { fullPage } = (req.params ?? {}) as { fullPage?: boolean };\n const buf = await h.page.screenshot({ fullPage: fullPage ?? false });\n return { id: req.id, ok: true, result: { mediaType: 'image/png', base64: buf.toString('base64') } };\n }\n case 'frame': {\n // Combined live-view frame for the browser SURFACE: a JPEG screenshot\n // plus the current url + viewport size, so the renderer can map clicks\n // back onto the page. One round-trip per frame.\n const h = await ensurePlaywright(state, {});\n // quality 70 (was 55) + the context's deviceScaleFactor:2 = legible text in\n // the live view. Reports the CSS viewport size (the image is 2× that) so the\n // renderer keeps mapping clicks in CSS coords.\n const buf = await h.page.screenshot({ type: 'jpeg', quality: 70 });\n const vp = h.page.viewportSize() ?? { width: 1280, height: 720 };\n return {\n id: req.id,\n ok: true,\n result: {\n mediaType: 'image/jpeg',\n base64: buf.toString('base64'),\n url: h.page.url(),\n width: vp.width,\n height: vp.height,\n },\n };\n }\n case 'mouse': {\n const { x, y, count } = (req.params ?? {}) as { x: number; y: number; count?: number };\n // Parity with `key`/`eval`: validate before launching/driving the page so\n // a malformed surface message (missing/NaN coords) surfaces a clean\n // `badParams` instead of an opaque Playwright throw from click(undefined).\n if (!Number.isFinite(x) || !Number.isFinite(y)) throw badParams('x and y must be finite numbers');\n const h = await ensurePlaywright(state, {});\n await h.page.mouse.click(x, y, { clickCount: Math.min(3, Math.max(1, count ?? 1)) });\n return { id: req.id, ok: true, result: { url: h.page.url() } };\n }\n case 'mousemove': {\n // Hover: drives the page's pointer so :hover styles / tooltips render in\n // the polled frame. Cheap; the surface throttles how often it sends these.\n const { x, y } = (req.params ?? {}) as { x: number; y: number };\n if (!Number.isFinite(x) || !Number.isFinite(y)) throw badParams('x and y must be finite numbers');\n const h = await ensurePlaywright(state, {});\n await h.page.mouse.move(x, y);\n return { id: req.id, ok: true };\n }\n case 'setviewport': {\n // Resize the page to the pane so the live view fills the container instead\n // of being letterboxed at the default 1280×720.\n const { width, height } = (req.params ?? {}) as { width: number; height: number };\n if (!Number.isFinite(width) || !Number.isFinite(height) || width < 1 || height < 1) {\n throw badParams('width and height must be positive finite numbers');\n }\n const h = await ensurePlaywright(state, {});\n await h.page.setViewportSize({ width: Math.round(width), height: Math.round(height) });\n return { id: req.id, ok: true };\n }\n case 'back':\n case 'forward':\n case 'reload': {\n const h = await ensurePlaywright(state, {});\n try {\n if (req.method === 'back') await h.page.goBack();\n else if (req.method === 'forward') await h.page.goForward();\n else await h.page.reload();\n } catch (err) {\n // No history to go to is not an error worth failing the surface over.\n return { id: req.id, ok: false, error: { message: errMsg(err), kind: 'navigation' } };\n }\n return { id: req.id, ok: true, result: { url: h.page.url() } };\n }\n case 'key': {\n const h = await ensurePlaywright(state, {});\n const { key } = (req.params ?? {}) as { key: string };\n if (!key) throw badParams('key is required');\n // A single printable char is typed (inserts it); a named key is pressed.\n if (key.length === 1) await h.page.keyboard.type(key);\n else await h.page.keyboard.press(key);\n return { id: req.id, ok: true };\n }\n case 'scroll': {\n const h = await ensurePlaywright(state, {});\n const { dy } = (req.params ?? {}) as { dy: number };\n await h.page.mouse.wheel(0, dy ?? 0);\n return { id: req.id, ok: true };\n }\n case 'zoom': {\n // Page zoom for the surface (⌘+/⌘−). CSS `zoom` is the cheapest faithful\n // way to scale a screenshot-streamed page; clamped to a sane range.\n const { factor } = (req.params ?? {}) as { factor: number };\n const f = Number.isFinite(factor) ? Math.min(5, Math.max(0.25, factor)) : 1;\n const h = await ensurePlaywright(state, {});\n await h.page.evaluate(`document.documentElement.style.zoom=String(${f})`);\n return { id: req.id, ok: true };\n }\n case 'capture': {\n // Sharp PNG of a region the user dragged — attached to the chat composer so\n // the agent SEES the area (\"change this to …\"). Coords are CSS px; the\n // context's deviceScaleFactor:2 makes the PNG 2× → crisp.\n const { x, y, width, height } = (req.params ?? {}) as {\n x: number;\n y: number;\n width: number;\n height: number;\n };\n if (![x, y, width, height].every((n) => Number.isFinite(n)) || width < 1 || height < 1) {\n throw badParams('x, y, width, height must be finite; width/height positive');\n }\n const h = await ensurePlaywright(state, {});\n const buf = await h.page.screenshot({ type: 'png', clip: { x, y, width, height } });\n return { id: req.id, ok: true, result: { mediaType: 'image/png', base64: buf.toString('base64') } };\n }\n case 'pick': {\n // Identify the element at (x,y) so the user can hand it to the agent\n // (\"change this XXX to YYY\"). Returns a best-effort CSS selector + a short\n // text snippet; the agent's browser_session tool can act on the selector.\n const { x, y } = (req.params ?? {}) as { x: number; y: number };\n if (!Number.isFinite(x) || !Number.isFinite(y)) throw badParams('x and y must be finite numbers');\n const h = await ensurePlaywright(state, {});\n const expr =\n `(() => { const x=${x}, y=${y}; const el=document.elementFromPoint(x,y);` +\n ` if(!el) return null;` +\n ` const sel=(e)=>{ if(e.id) return '#'+CSS.escape(e.id); const p=[]; let n=e;` +\n ` while(n && n.nodeType===1 && n!==document.body){ let s=n.tagName.toLowerCase();` +\n ` if(n.classList && n.classList.length) s+='.'+Array.from(n.classList).slice(0,2).map(c=>CSS.escape(c)).join('.');` +\n ` const par=n.parentElement; if(par){ const same=Array.from(par.children).filter(c=>c.tagName===n.tagName);` +\n ` if(same.length>1) s+=':nth-of-type('+(same.indexOf(n)+1)+')'; } p.unshift(s); n=n.parentElement; }` +\n ` return p.join(' > '); };` +\n ` return { selector: sel(el), tag: el.tagName.toLowerCase(), text: (el.textContent||'').replace(/\\\\s+/g,' ').trim().slice(0,140) }; })()`;\n const info = await h.page.evaluate(expr);\n return { id: req.id, ok: true, result: info };\n }\n case 'eval': {\n const h = await ensurePlaywright(state, {});\n const { expression } = (req.params ?? {}) as { expression: string };\n if (!expression) throw badParams('expression is required');\n const value = await h.page.evaluate(expression);\n return { id: req.id, ok: true, result: value };\n }\n case 'url': {\n const h = await ensurePlaywright(state, {});\n return { id: req.id, ok: true, result: h.page.url() };\n }\n case 'close': {\n await teardown(state);\n return { id: req.id, ok: true };\n }\n default:\n return {\n id: req.id,\n ok: false,\n error: { message: `unknown method: ${req.method}`, kind: 'runtime' },\n };\n }\n}\n","#!/usr/bin/env node\n/**\n * Playwright sidecar — owns a single browser context. Speaks newline-delimited\n * JSON-RPC over stdio so the parent (`browser_session` tool) doesn't load\n * Playwright into its own process. Crash isolation, lazy install: the parent\n * only spawns this when the heavy tier is actually needed.\n *\n * Wire format (one line per message):\n * { \"id\": \"uuid\", \"method\": \"goto\"|\"click\"|\"fill\"|\"text\"|\"html\"|\"screenshot\"|\"eval\"|\"close\", \"params\": {...} }\n * { \"id\": \"uuid\", \"ok\": true, \"result\": ... }\n * { \"id\": \"uuid\", \"ok\": false, \"error\": { \"message\": \"...\", \"kind\": \"init\"|\"navigation\"|\"runtime\"|\"timeout\" } }\n *\n * Run with `node dist/sidecar.js` (the package's `bin` entry is\n * `moxxy-browser-sidecar`). Parent terminates by closing stdin or sending\n * `{method:'close'}`.\n */\n\nimport * as readline from 'node:readline';\nimport { fileURLToPath } from 'node:url';\nimport { dispatch, teardown, type SidecarState } from './sidecar/dispatch.js';\nimport { errMsg, type Reply, type Req } from './sidecar/types.js';\n\nconst state: SidecarState = { handle: null, pendingInstallNotice: null };\n\nfunction write(reply: Reply): void {\n // Drain the install-notice flag into the first reply that goes out\n // after the install completed, then clear it. Errors get the notice\n // too — sometimes the launch retry surfaces a different problem and\n // the user still wants to know we tried to install.\n if (state.pendingInstallNotice) {\n if (reply.ok) {\n reply = { ...reply, notice: state.pendingInstallNotice };\n } else {\n reply = {\n ...reply,\n error: {\n ...reply.error,\n message: `${state.pendingInstallNotice} Then: ${reply.error.message}`,\n },\n };\n }\n state.pendingInstallNotice = null;\n }\n process.stdout.write(JSON.stringify(reply) + '\\n');\n}\n\n/**\n * Tears down the browser context AND exits the process. Used both by\n * the explicit `close` RPC path and the parent-loss / stdin-close\n * paths so all cleanup goes through one routine.\n */\nasync function shutdownAndExit(code: number): Promise<void> {\n await teardown(state);\n process.exit(code);\n}\n\n/**\n * Parent watchdog: if the moxxy process that spawned this sidecar\n * disappears (crash, SIGKILL, terminal hangup), there's no stdin EOF\n * to rely on — orphan Chromium would keep running and chew CPU/memory\n * until the user notices. Poll the parent PID every few seconds and\n * self-terminate when it goes away.\n *\n * `process.kill(pid, 0)` is the POSIX trick for \"does this PID\n * exist?\" — no signal is actually delivered. Throws ESRCH when the\n * process is gone (or EPERM when it exists but we can't signal it —\n * still alive, so don't treat as gone).\n */\nfunction startParentWatchdog(): void {\n const parentPid = process.ppid;\n if (!parentPid || parentPid <= 1) return; // already orphaned (init), nothing to watch\n const interval = setInterval(() => {\n try {\n process.kill(parentPid, 0);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ESRCH') {\n clearInterval(interval);\n void shutdownAndExit(0);\n }\n // EPERM means the process exists but we can't signal it — still alive.\n }\n }, 2000);\n interval.unref?.(); // never block the event loop from exiting\n}\n\nlet queue: Promise<void> = Promise.resolve();\n\n/**\n * Parse one input line and chain its dispatch onto the serial request queue.\n * `out` is the sink for replies (real run: {@link write}; tests inject a stub).\n * Exported so a test can drive the queue without spinning up the whole stdio\n * loop. Returns the queue tail so callers can await it.\n *\n * The `.catch` on the chained link is load-bearing: a throw from `out` (e.g. a\n * broken stdout pipe) would otherwise reject `queue` permanently and strand\n * EVERY subsequent request, since each link chains off the previous one.\n * Swallow it here — after emitting a best-effort error reply — so the next\n * request still serves.\n */\nexport function enqueueLine(line: string, out: (reply: Reply) => void): Promise<void> {\n if (!line.trim()) return queue;\n let req: Req;\n try {\n req = JSON.parse(line) as Req;\n } catch {\n out({ id: 'unknown', ok: false, error: { message: 'invalid JSON', kind: 'runtime' } });\n return queue;\n }\n if (!req.id || !req.method) {\n out({\n id: req.id ?? 'unknown',\n ok: false,\n error: { message: 'request requires { id, method }', kind: 'runtime' },\n });\n return queue;\n }\n // Sequentially serve requests on the single page. Parent can pipeline by\n // sending more requests; we serialize them inside the sidecar so a goto\n // doesn't race a click.\n queue = queue\n .then(async () => {\n const reply = await dispatch(state, req);\n out(reply);\n })\n .catch((err) => {\n try {\n out({ id: req.id, ok: false, error: { message: errMsg(err), kind: 'runtime' } });\n } catch {\n /* stdout is gone too — nothing left to do but keep the queue alive */\n }\n });\n return queue;\n}\n\nasync function main(): Promise<void> {\n startParentWatchdog();\n const rl = readline.createInterface({ input: process.stdin });\n rl.on('line', (line) => {\n void enqueueLine(line, write);\n });\n rl.once('close', () => {\n void shutdownAndExit(0);\n });\n // Defensive: if our stdout pipe breaks (parent died mid-write), Node\n // would otherwise throw an uncaught EPIPE on the next write. Treat\n // it as a signal to clean up gracefully instead.\n process.stdout.on('error', (err) => {\n if ((err as NodeJS.ErrnoException).code === 'EPIPE') {\n void shutdownAndExit(0);\n }\n });\n}\n\n// Auto-run only when executed as the bin script — not when imported (tests).\nif (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {\n main().catch((err) => {\n process.stderr.write(`sidecar fatal: ${errMsg(err)}\\n`);\n void shutdownAndExit(1);\n });\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moxxy/cli",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.3",
|
|
4
4
|
"description": "moxxy command-line binary. Subcommand dispatcher consuming the moxxy SDK.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"moxxy",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"zod": "^3.24.0",
|
|
53
|
-
"@moxxy/sdk": "0.
|
|
53
|
+
"@moxxy/sdk": "0.15.0"
|
|
54
54
|
},
|
|
55
55
|
"optionalDependencies": {
|
|
56
56
|
"@napi-rs/keyring": "^1.3.0",
|