@canaryai/cli 0.2.14 → 0.2.16

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 (49) hide show
  1. package/dist/{chunk-ZQF72UTG.js → chunk-MKE3V6GC.js} +2 -2
  2. package/dist/{chunk-4A4G5KTC.js → chunk-N7L7AH6L.js} +48 -23
  3. package/dist/chunk-N7L7AH6L.js.map +1 -0
  4. package/dist/{chunk-6IAPGYZQ.js → chunk-WOVAMA3N.js} +328 -8
  5. package/dist/chunk-WOVAMA3N.js.map +1 -0
  6. package/dist/{chunk-BOS2YLKH.js → chunk-XSOKWWRV.js} +2 -2
  7. package/dist/chunk-XSOKWWRV.js.map +1 -0
  8. package/dist/{debug-workflow-DIQZDFMN.js → debug-workflow-J645OPCM.js} +4 -4
  9. package/dist/{docs-CSVSGIGW.js → docs-FORYHZVU.js} +13 -7
  10. package/dist/docs-FORYHZVU.js.map +1 -0
  11. package/dist/{feature-flag-BIPFVVNC.js → feature-flag-7BD3NT6G.js} +2 -2
  12. package/dist/index.js +11 -11
  13. package/dist/{init-BTDX5N6P.js → init-JHZ3OWKQ.js} +7 -6
  14. package/dist/init-JHZ3OWKQ.js.map +1 -0
  15. package/dist/{issues-EWVB52CA.js → issues-LYAJOKGM.js} +4 -3
  16. package/dist/issues-LYAJOKGM.js.map +1 -0
  17. package/dist/{knobs-VYABZESR.js → knobs-QUJQ4NWV.js} +2 -2
  18. package/dist/{list-RCPYLS36.js → list-2L2NGCSF.js} +2 -2
  19. package/dist/{local-ZPVM4BXX.js → local-45POWSFC.js} +5 -5
  20. package/dist/{local-browser-WV4IH2DU.js → local-browser-K5S2FBJ2.js} +3 -3
  21. package/dist/{login-W4GXV3VA.js → login-ZKF6GONZ.js} +3 -3
  22. package/dist/{mcp-YER5GQG7.js → mcp-PCIBK4LR.js} +4 -4
  23. package/dist/{record-KRS2PHMW.js → record-OGUYMAHJ.js} +3 -3
  24. package/dist/{session-CLWAVJ2K.js → session-VWBTOWHC.js} +33 -7
  25. package/dist/session-VWBTOWHC.js.map +1 -0
  26. package/dist/{src-WLOHOI6P.js → src-VOM4WIB3.js} +2 -2
  27. package/dist/{start-CNNQUP5I.js → start-QMTRNSYD.js} +3 -3
  28. package/dist/{workflow-XXL4H5R4.js → workflow-U2NK4YED.js} +2 -2
  29. package/package.json +1 -1
  30. package/dist/chunk-4A4G5KTC.js.map +0 -1
  31. package/dist/chunk-6IAPGYZQ.js.map +0 -1
  32. package/dist/chunk-BOS2YLKH.js.map +0 -1
  33. package/dist/docs-CSVSGIGW.js.map +0 -1
  34. package/dist/init-BTDX5N6P.js.map +0 -1
  35. package/dist/issues-EWVB52CA.js.map +0 -1
  36. package/dist/session-CLWAVJ2K.js.map +0 -1
  37. /package/dist/{chunk-ZQF72UTG.js.map → chunk-MKE3V6GC.js.map} +0 -0
  38. /package/dist/{debug-workflow-DIQZDFMN.js.map → debug-workflow-J645OPCM.js.map} +0 -0
  39. /package/dist/{feature-flag-BIPFVVNC.js.map → feature-flag-7BD3NT6G.js.map} +0 -0
  40. /package/dist/{knobs-VYABZESR.js.map → knobs-QUJQ4NWV.js.map} +0 -0
  41. /package/dist/{list-RCPYLS36.js.map → list-2L2NGCSF.js.map} +0 -0
  42. /package/dist/{local-ZPVM4BXX.js.map → local-45POWSFC.js.map} +0 -0
  43. /package/dist/{local-browser-WV4IH2DU.js.map → local-browser-K5S2FBJ2.js.map} +0 -0
  44. /package/dist/{login-W4GXV3VA.js.map → login-ZKF6GONZ.js.map} +0 -0
  45. /package/dist/{mcp-YER5GQG7.js.map → mcp-PCIBK4LR.js.map} +0 -0
  46. /package/dist/{record-KRS2PHMW.js.map → record-OGUYMAHJ.js.map} +0 -0
  47. /package/dist/{src-WLOHOI6P.js.map → src-VOM4WIB3.js.map} +0 -0
  48. /package/dist/{start-CNNQUP5I.js.map → start-QMTRNSYD.js.map} +0 -0
  49. /package/dist/{workflow-XXL4H5R4.js.map → workflow-U2NK4YED.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
2
2
  import {
3
3
  PlaywrightClient
4
- } from "./chunk-6IAPGYZQ.js";
4
+ } from "./chunk-WOVAMA3N.js";
5
5
 
6
6
  // src/local-browser/host.ts
7
7
  var HEARTBEAT_INTERVAL_MS = 3e4;
@@ -384,4 +384,4 @@ var LocalBrowserHost = class {
384
384
  export {
385
385
  LocalBrowserHost
386
386
  };
387
- //# sourceMappingURL=chunk-ZQF72UTG.js.map
387
+ //# sourceMappingURL=chunk-MKE3V6GC.js.map
@@ -26,19 +26,54 @@ function isProcessAlive(pid) {
26
26
  return false;
27
27
  }
28
28
  }
29
- async function daemonFetch(port, method, path2, body) {
29
+ var DAEMON_REQUEST_TIMEOUT_MS = 3e4;
30
+ var DAEMON_FETCH_MAX_RETRIES = 2;
31
+ function isConnectionError(err) {
32
+ if (err instanceof TypeError && err.message === "fetch failed") return true;
33
+ const cause = err?.cause;
34
+ if (cause?.code === "UND_ERR_SOCKET") return true;
35
+ if (cause?.code === "ECONNREFUSED") return true;
36
+ if (cause?.code === "ECONNRESET") return true;
37
+ return false;
38
+ }
39
+ async function daemonFetchOnce(port, method, path2, body) {
30
40
  const url = `http://127.0.0.1:${port}${path2}`;
31
41
  const res = await fetch(url, {
32
42
  method,
33
- headers: body ? { "Content-Type": "application/json" } : void 0,
34
- body: body ? JSON.stringify(body) : void 0
43
+ headers: {
44
+ ...body ? { "Content-Type": "application/json" } : void 0,
45
+ Connection: "close"
46
+ },
47
+ body: body ? JSON.stringify(body) : void 0,
48
+ signal: AbortSignal.timeout(DAEMON_REQUEST_TIMEOUT_MS)
35
49
  });
36
50
  return res.json();
37
51
  }
52
+ async function daemonFetchWithRetry(method, path2, body) {
53
+ let port = await ensureDaemon();
54
+ let lastError;
55
+ for (let attempt = 0; attempt <= DAEMON_FETCH_MAX_RETRIES; attempt++) {
56
+ try {
57
+ return await daemonFetchOnce(port, method, path2, body);
58
+ } catch (err) {
59
+ lastError = err;
60
+ if (!isConnectionError(err) || attempt === DAEMON_FETCH_MAX_RETRIES) {
61
+ throw err;
62
+ }
63
+ try {
64
+ await fs.unlink(PIDFILE_PATH);
65
+ } catch {
66
+ }
67
+ port = await ensureDaemon();
68
+ }
69
+ }
70
+ throw lastError;
71
+ }
38
72
  async function healthCheck(port) {
39
73
  try {
40
74
  const res = await fetch(`http://127.0.0.1:${port}/health`, {
41
- signal: AbortSignal.timeout(2e3)
75
+ signal: AbortSignal.timeout(2e3),
76
+ headers: { Connection: "close" }
42
77
  });
43
78
  return res.ok;
44
79
  } catch {
@@ -113,41 +148,31 @@ async function ensureDaemon() {
113
148
  throw new Error("Daemon failed to become healthy after spawn");
114
149
  }
115
150
  async function createSession(params) {
116
- const port = await ensureDaemon();
117
- return daemonFetch(port, "POST", "/sessions", params);
151
+ return daemonFetchWithRetry("POST", "/sessions", params);
118
152
  }
119
153
  async function listSessions() {
120
- const port = await ensureDaemon();
121
- return daemonFetch(port, "GET", "/sessions");
154
+ return daemonFetchWithRetry("GET", "/sessions");
122
155
  }
123
156
  async function getSession(sessionId) {
124
- const port = await ensureDaemon();
125
- return daemonFetch(port, "GET", `/sessions/${sessionId}`);
157
+ return daemonFetchWithRetry("GET", `/sessions/${sessionId}`);
126
158
  }
127
159
  async function deleteSession(sessionId) {
128
- const port = await ensureDaemon();
129
- return daemonFetch(port, "DELETE", `/sessions/${sessionId}`);
160
+ return daemonFetchWithRetry("DELETE", `/sessions/${sessionId}`);
130
161
  }
131
162
  async function deleteAllSessions() {
132
- const port = await ensureDaemon();
133
- return daemonFetch(port, "DELETE", "/sessions");
163
+ return daemonFetchWithRetry("DELETE", "/sessions");
134
164
  }
135
165
  async function swapSessionContext(sessionId, params) {
136
- const port = await ensureDaemon();
137
- return daemonFetch(port, "POST", `/sessions/${sessionId}/swap-context`, params);
166
+ return daemonFetchWithRetry("POST", `/sessions/${sessionId}/swap-context`, params);
138
167
  }
139
168
  async function getSessionStorageState(sessionId) {
140
- const port = await ensureDaemon();
141
- return daemonFetch(
142
- port,
169
+ return daemonFetchWithRetry(
143
170
  "GET",
144
171
  `/sessions/${sessionId}/storage-state`
145
172
  );
146
173
  }
147
174
  async function callTool(sessionId, toolName, args) {
148
- const port = await ensureDaemon();
149
- return daemonFetch(
150
- port,
175
+ return daemonFetchWithRetry(
151
176
  "POST",
152
177
  `/sessions/${sessionId}/tools/${toolName}`,
153
178
  args
@@ -191,4 +216,4 @@ export {
191
216
  callTool,
192
217
  resolveTargetSession
193
218
  };
194
- //# sourceMappingURL=chunk-4A4G5KTC.js.map
219
+ //# sourceMappingURL=chunk-N7L7AH6L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/session/daemon-client.ts"],"sourcesContent":["/**\n * Daemon client — HTTP client for the session daemon.\n *\n * Handles pidfile read/write, stale PID detection, auto-start,\n * and provides typed HTTP helpers for daemon communication.\n *\n * @module\n */\n\nimport { spawn } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type {\n DaemonState,\n DaemonResponse,\n SessionInfo,\n CreateSessionRequest,\n SwapContextRequest,\n ToolResponse,\n StorageStateResponse,\n} from './types.js';\n\nconst PIDFILE_DIR = path.join(os.homedir(), '.config', 'canary-cli');\nconst PIDFILE_PATH = path.join(PIDFILE_DIR, 'daemon.json');\nconst HEALTH_POLL_INTERVAL_MS = 100;\nconst HEALTH_POLL_TIMEOUT_MS = 15_000;\n\n/* ── Pidfile helpers ─────────────────────────────────────────────────── */\n\nasync function readPidfile(): Promise<DaemonState | null> {\n try {\n const content = await fs.readFile(PIDFILE_PATH, 'utf-8');\n return JSON.parse(content) as DaemonState;\n } catch {\n return null;\n }\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nconst DAEMON_REQUEST_TIMEOUT_MS = 30_000;\nconst DAEMON_FETCH_MAX_RETRIES = 2;\n\n/* ── HTTP helpers ────────────────────────────────────────────────────── */\n\nfunction isConnectionError(err: unknown): boolean {\n if (err instanceof TypeError && err.message === 'fetch failed') return true;\n const cause = (err as { cause?: { code?: string } })?.cause;\n if (cause?.code === 'UND_ERR_SOCKET') return true;\n if (cause?.code === 'ECONNREFUSED') return true;\n if (cause?.code === 'ECONNRESET') return true;\n return false;\n}\n\nasync function daemonFetchOnce(\n port: number,\n method: string,\n path: string,\n body?: unknown\n): Promise<unknown> {\n const url = `http://127.0.0.1:${port}${path}`;\n const res = await fetch(url, {\n method,\n headers: {\n ...(body ? { 'Content-Type': 'application/json' } : undefined),\n Connection: 'close',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: AbortSignal.timeout(DAEMON_REQUEST_TIMEOUT_MS),\n });\n return res.json();\n}\n\n/**\n * Fetch from daemon with retry. On connection errors (daemon died or\n * idle-exited between ensureDaemon and the request), re-ensure the\n * daemon and retry up to DAEMON_FETCH_MAX_RETRIES times.\n */\nasync function daemonFetchWithRetry(\n method: string,\n path: string,\n body?: unknown\n): Promise<unknown> {\n let port = await ensureDaemon();\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= DAEMON_FETCH_MAX_RETRIES; attempt++) {\n try {\n return await daemonFetchOnce(port, method, path, body);\n } catch (err) {\n lastError = err;\n if (!isConnectionError(err) || attempt === DAEMON_FETCH_MAX_RETRIES) {\n throw err;\n }\n // Daemon likely died — clean up stale pidfile and re-ensure\n try {\n await fs.unlink(PIDFILE_PATH);\n } catch {\n // ignore\n }\n port = await ensureDaemon();\n }\n }\n\n throw lastError;\n}\n\nasync function healthCheck(port: number): Promise<boolean> {\n try {\n const res = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: AbortSignal.timeout(2000),\n headers: { Connection: 'close' },\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\n/* ── Auto-start ──────────────────────────────────────────────────────── */\n\nasync function spawnDaemon(): Promise<number> {\n // Resolve the canary CLI entry point\n // In source: this file is src/session/daemon-client.ts → ../index.ts\n // In dist: this file is dist/chunk-*.js → ./index.js (flat)\n const dir = path.dirname(new URL(import.meta.url).pathname);\n const candidates = [\n path.resolve(dir, '..', 'index.ts'), // source layout\n path.resolve(dir, 'index.js'), // dist layout (flat)\n path.resolve(dir, '..', 'index.js'), // fallback\n ];\n const cliEntry = candidates.find((p) => existsSync(p));\n if (!cliEntry) {\n throw new Error(`Cannot find CLI entry point. Searched: ${candidates.join(', ')}`);\n }\n\n const child = spawn(process.execPath, [cliEntry, 'session', 'daemon'], {\n detached: true,\n stdio: ['ignore', 'pipe', 'ignore'],\n env: { ...process.env },\n });\n\n child.unref();\n\n // Wait for \"DAEMON_READY:<port>\" on stdout\n return new Promise<number>((resolve, reject) => {\n let output = '';\n const timeout = setTimeout(() => {\n reject(new Error('Daemon startup timed out'));\n }, HEALTH_POLL_TIMEOUT_MS);\n\n child.stdout!.on('data', (data: Buffer) => {\n output += data.toString();\n const match = output.match(/DAEMON_READY:(\\d+)/);\n if (match) {\n clearTimeout(timeout);\n child.stdout!.destroy(); // Release the pipe so the CLI process can exit\n resolve(parseInt(match[1], 10));\n }\n });\n\n child.on('error', (err) => {\n clearTimeout(timeout);\n reject(err);\n });\n\n child.on('exit', (code) => {\n clearTimeout(timeout);\n if (!output.includes('DAEMON_READY')) {\n reject(new Error(`Daemon exited with code ${code} before becoming ready`));\n }\n });\n });\n}\n\n/* ── Public API ──────────────────────────────────────────────────────── */\n\n/**\n * Ensure the daemon is running and return its port.\n * Starts the daemon if needed, cleans up stale pidfiles.\n */\nasync function ensureDaemon(): Promise<number> {\n const state = await readPidfile();\n\n if (state) {\n if (isProcessAlive(state.pid)) {\n // Verify it actually responds\n if (await healthCheck(state.port)) {\n return state.port;\n }\n }\n // Stale pidfile — clean up\n try {\n await fs.unlink(PIDFILE_PATH);\n } catch {\n // ignore\n }\n }\n\n // Spawn new daemon\n const port = await spawnDaemon();\n\n // Poll until healthy\n const deadline = Date.now() + HEALTH_POLL_TIMEOUT_MS;\n while (Date.now() < deadline) {\n if (await healthCheck(port)) return port;\n await new Promise((r) => setTimeout(r, HEALTH_POLL_INTERVAL_MS));\n }\n\n throw new Error('Daemon failed to become healthy after spawn');\n}\n\n/* ── Session operations ──────────────────────────────────────────────── */\n\nexport async function createSession(\n params: CreateSessionRequest\n): Promise<DaemonResponse<SessionInfo>> {\n return daemonFetchWithRetry('POST', '/sessions', params) as Promise<\n DaemonResponse<SessionInfo>\n >;\n}\n\nexport async function listSessions(): Promise<DaemonResponse<SessionInfo[]>> {\n return daemonFetchWithRetry('GET', '/sessions') as Promise<DaemonResponse<SessionInfo[]>>;\n}\n\nexport async function getSession(sessionId: string): Promise<DaemonResponse<SessionInfo>> {\n return daemonFetchWithRetry('GET', `/sessions/${sessionId}`) as Promise<\n DaemonResponse<SessionInfo>\n >;\n}\n\nexport async function deleteSession(sessionId: string): Promise<DaemonResponse> {\n return daemonFetchWithRetry('DELETE', `/sessions/${sessionId}`) as Promise<DaemonResponse>;\n}\n\nexport async function deleteAllSessions(): Promise<DaemonResponse> {\n return daemonFetchWithRetry('DELETE', '/sessions') as Promise<DaemonResponse>;\n}\n\nexport async function swapSessionContext(\n sessionId: string,\n params: SwapContextRequest\n): Promise<DaemonResponse<SessionInfo>> {\n return daemonFetchWithRetry('POST', `/sessions/${sessionId}/swap-context`, params) as Promise<\n DaemonResponse<SessionInfo>\n >;\n}\n\nexport async function getSessionStorageState(sessionId: string): Promise<StorageStateResponse> {\n return daemonFetchWithRetry(\n 'GET',\n `/sessions/${sessionId}/storage-state`\n ) as Promise<StorageStateResponse>;\n}\n\nexport async function callTool(\n sessionId: string,\n toolName: string,\n args: Record<string, unknown>\n): Promise<ToolResponse> {\n return daemonFetchWithRetry(\n 'POST',\n `/sessions/${sessionId}/tools/${toolName}`,\n args\n ) as Promise<ToolResponse>;\n}\n\n/**\n * Resolve the target session for a command.\n * If there's exactly one session, auto-targets it.\n * If a sessionId or name is provided, looks it up.\n */\nexport async function resolveTargetSession(sessionIdOrName?: string): Promise<SessionInfo> {\n const result = await listSessions();\n if (!result.ok || !result.data) {\n throw new Error('Failed to list sessions');\n }\n const sessions = result.data;\n\n if (sessions.length === 0) {\n throw new Error('No active sessions. Start one with: canary session start');\n }\n\n if (sessionIdOrName) {\n const match = sessions.find((s) => s.id === sessionIdOrName || s.name === sessionIdOrName);\n if (!match) {\n throw new Error(\n `Session \"${sessionIdOrName}\" not found. Active sessions: ${sessions.map((s) => s.id).join(', ')}`\n );\n }\n return match;\n }\n\n if (sessions.length === 1) {\n return sessions[0];\n }\n\n throw new Error(\n `Multiple sessions active. Specify one with --session:\\n${sessions.map((s) => ` ${s.id} (${s.name})`).join('\\n')}`\n );\n}\n"],"mappings":";;;AASA,SAAS,aAAa;AACtB,OAAO,QAAQ;AACf,SAAS,kBAAkB;AAC3B,OAAO,UAAU;AACjB,OAAO,QAAQ;AAWf,IAAM,cAAc,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW,YAAY;AACnE,IAAM,eAAe,KAAK,KAAK,aAAa,aAAa;AACzD,IAAM,0BAA0B;AAChC,IAAM,yBAAyB;AAI/B,eAAe,cAA2C;AACxD,MAAI;AACF,UAAM,UAAU,MAAM,GAAG,SAAS,cAAc,OAAO;AACvD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAe,KAAsB;AAC5C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,IAAM,4BAA4B;AAClC,IAAM,2BAA2B;AAIjC,SAAS,kBAAkB,KAAuB;AAChD,MAAI,eAAe,aAAa,IAAI,YAAY,eAAgB,QAAO;AACvE,QAAM,QAAS,KAAuC;AACtD,MAAI,OAAO,SAAS,iBAAkB,QAAO;AAC7C,MAAI,OAAO,SAAS,eAAgB,QAAO;AAC3C,MAAI,OAAO,SAAS,aAAc,QAAO;AACzC,SAAO;AACT;AAEA,eAAe,gBACb,MACA,QACAA,OACA,MACkB;AAClB,QAAM,MAAM,oBAAoB,IAAI,GAAGA,KAAI;AAC3C,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B;AAAA,IACA,SAAS;AAAA,MACP,GAAI,OAAO,EAAE,gBAAgB,mBAAmB,IAAI;AAAA,MACpD,YAAY;AAAA,IACd;AAAA,IACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,IACpC,QAAQ,YAAY,QAAQ,yBAAyB;AAAA,EACvD,CAAC;AACD,SAAO,IAAI,KAAK;AAClB;AAOA,eAAe,qBACb,QACAA,OACA,MACkB;AAClB,MAAI,OAAO,MAAM,aAAa;AAC9B,MAAI;AAEJ,WAAS,UAAU,GAAG,WAAW,0BAA0B,WAAW;AACpE,QAAI;AACF,aAAO,MAAM,gBAAgB,MAAM,QAAQA,OAAM,IAAI;AAAA,IACvD,SAAS,KAAK;AACZ,kBAAY;AACZ,UAAI,CAAC,kBAAkB,GAAG,KAAK,YAAY,0BAA0B;AACnE,cAAM;AAAA,MACR;AAEA,UAAI;AACF,cAAM,GAAG,OAAO,YAAY;AAAA,MAC9B,QAAQ;AAAA,MAER;AACA,aAAO,MAAM,aAAa;AAAA,IAC5B;AAAA,EACF;AAEA,QAAM;AACR;AAEA,eAAe,YAAY,MAAgC;AACzD,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,oBAAoB,IAAI,WAAW;AAAA,MACzD,QAAQ,YAAY,QAAQ,GAAI;AAAA,MAChC,SAAS,EAAE,YAAY,QAAQ;AAAA,IACjC,CAAC;AACD,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,eAAe,cAA+B;AAI5C,QAAM,MAAM,KAAK,QAAQ,IAAI,IAAI,YAAY,GAAG,EAAE,QAAQ;AAC1D,QAAM,aAAa;AAAA,IACjB,KAAK,QAAQ,KAAK,MAAM,UAAU;AAAA;AAAA,IAClC,KAAK,QAAQ,KAAK,UAAU;AAAA;AAAA,IAC5B,KAAK,QAAQ,KAAK,MAAM,UAAU;AAAA;AAAA,EACpC;AACA,QAAM,WAAW,WAAW,KAAK,CAAC,MAAM,WAAW,CAAC,CAAC;AACrD,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,0CAA0C,WAAW,KAAK,IAAI,CAAC,EAAE;AAAA,EACnF;AAEA,QAAM,QAAQ,MAAM,QAAQ,UAAU,CAAC,UAAU,WAAW,QAAQ,GAAG;AAAA,IACrE,UAAU;AAAA,IACV,OAAO,CAAC,UAAU,QAAQ,QAAQ;AAAA,IAClC,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,EACxB,CAAC;AAED,QAAM,MAAM;AAGZ,SAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,QAAI,SAAS;AACb,UAAM,UAAU,WAAW,MAAM;AAC/B,aAAO,IAAI,MAAM,0BAA0B,CAAC;AAAA,IAC9C,GAAG,sBAAsB;AAEzB,UAAM,OAAQ,GAAG,QAAQ,CAAC,SAAiB;AACzC,gBAAU,KAAK,SAAS;AACxB,YAAM,QAAQ,OAAO,MAAM,oBAAoB;AAC/C,UAAI,OAAO;AACT,qBAAa,OAAO;AACpB,cAAM,OAAQ,QAAQ;AACtB,gBAAQ,SAAS,MAAM,CAAC,GAAG,EAAE,CAAC;AAAA,MAChC;AAAA,IACF,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,mBAAa,OAAO;AACpB,aAAO,GAAG;AAAA,IACZ,CAAC;AAED,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,mBAAa,OAAO;AACpB,UAAI,CAAC,OAAO,SAAS,cAAc,GAAG;AACpC,eAAO,IAAI,MAAM,2BAA2B,IAAI,wBAAwB,CAAC;AAAA,MAC3E;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAQA,eAAe,eAAgC;AAC7C,QAAM,QAAQ,MAAM,YAAY;AAEhC,MAAI,OAAO;AACT,QAAI,eAAe,MAAM,GAAG,GAAG;AAE7B,UAAI,MAAM,YAAY,MAAM,IAAI,GAAG;AACjC,eAAO,MAAM;AAAA,MACf;AAAA,IACF;AAEA,QAAI;AACF,YAAM,GAAG,OAAO,YAAY;AAAA,IAC9B,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,OAAO,MAAM,YAAY;AAG/B,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,QAAI,MAAM,YAAY,IAAI,EAAG,QAAO;AACpC,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAAA,EACjE;AAEA,QAAM,IAAI,MAAM,6CAA6C;AAC/D;AAIA,eAAsB,cACpB,QACsC;AACtC,SAAO,qBAAqB,QAAQ,aAAa,MAAM;AAGzD;AAEA,eAAsB,eAAuD;AAC3E,SAAO,qBAAqB,OAAO,WAAW;AAChD;AAEA,eAAsB,WAAW,WAAyD;AACxF,SAAO,qBAAqB,OAAO,aAAa,SAAS,EAAE;AAG7D;AAEA,eAAsB,cAAc,WAA4C;AAC9E,SAAO,qBAAqB,UAAU,aAAa,SAAS,EAAE;AAChE;AAEA,eAAsB,oBAA6C;AACjE,SAAO,qBAAqB,UAAU,WAAW;AACnD;AAEA,eAAsB,mBACpB,WACA,QACsC;AACtC,SAAO,qBAAqB,QAAQ,aAAa,SAAS,iBAAiB,MAAM;AAGnF;AAEA,eAAsB,uBAAuB,WAAkD;AAC7F,SAAO;AAAA,IACL;AAAA,IACA,aAAa,SAAS;AAAA,EACxB;AACF;AAEA,eAAsB,SACpB,WACA,UACA,MACuB;AACvB,SAAO;AAAA,IACL;AAAA,IACA,aAAa,SAAS,UAAU,QAAQ;AAAA,IACxC;AAAA,EACF;AACF;AAOA,eAAsB,qBAAqB,iBAAgD;AACzF,QAAM,SAAS,MAAM,aAAa;AAClC,MAAI,CAAC,OAAO,MAAM,CAAC,OAAO,MAAM;AAC9B,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AACA,QAAM,WAAW,OAAO;AAExB,MAAI,SAAS,WAAW,GAAG;AACzB,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AAEA,MAAI,iBAAiB;AACnB,UAAM,QAAQ,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,mBAAmB,EAAE,SAAS,eAAe;AACzF,QAAI,CAAC,OAAO;AACV,YAAM,IAAI;AAAA,QACR,YAAY,eAAe,iCAAiC,SAAS,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA,MAClG;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,SAAS,CAAC;AAAA,EACnB;AAEA,QAAM,IAAI;AAAA,IACR;AAAA,EAA0D,SAAS,IAAI,CAAC,MAAM,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA,EACnH;AACF;","names":["path"]}
@@ -39388,6 +39388,189 @@ function sortMatchesByContext(matches) {
39388
39388
  });
39389
39389
  }
39390
39390
 
39391
+ // ../browser-core/src/snapshot-formatter-content.ts
39392
+ var MAX_CONTEXT_ANNOTATIONS = 5;
39393
+ var MIN_CONTENT_CARD_RUN = 1;
39394
+ var MAX_CONTENT_CARD_CHILDREN = 6;
39395
+ var MIN_CONTENT_CARD_CHILDREN = 2;
39396
+ function isContextAnnotation(element) {
39397
+ if (element.role !== "paragraph" && element.role !== "generic") return false;
39398
+ if (isClickableByAttribute(element)) return false;
39399
+ if (INTERACTIVE_ROLES.has(element.role)) return false;
39400
+ if (hasInteractiveDescendants(element)) return false;
39401
+ const text = getAnnotationText(element);
39402
+ if (!text || text.length < 3 || text.length > 200) return false;
39403
+ return true;
39404
+ }
39405
+ function getAnnotationText(element) {
39406
+ const direct = getElementText(element);
39407
+ if (direct && direct.trim().length >= 3) return direct.trim();
39408
+ const parts = [];
39409
+ for (const child of element.children) {
39410
+ if (TEXT_CARRYING_ROLES.has(child.role)) {
39411
+ const childText = getElementText(child);
39412
+ if (childText?.trim()) {
39413
+ parts.push(childText.trim());
39414
+ }
39415
+ }
39416
+ }
39417
+ const composed = parts.join(" | ");
39418
+ return composed.length >= 3 ? composed : void 0;
39419
+ }
39420
+ function collectContextAnnotations(siblings) {
39421
+ const annotations = [];
39422
+ for (const sib of siblings) {
39423
+ if (annotations.length >= MAX_CONTEXT_ANNOTATIONS) break;
39424
+ if (extractCardTexts(sib) !== null) continue;
39425
+ if (isContextAnnotation(sib)) {
39426
+ const text = getAnnotationText(sib);
39427
+ if (text) {
39428
+ annotations.push(text);
39429
+ }
39430
+ }
39431
+ }
39432
+ return annotations;
39433
+ }
39434
+ function extractCardTexts(element) {
39435
+ if (isClickableByAttribute(element)) return null;
39436
+ if (INTERACTIVE_ROLES.has(element.role)) return null;
39437
+ if (hasInteractiveDescendants(element)) return null;
39438
+ const texts = [];
39439
+ collectCardTexts(element, texts, 0);
39440
+ if (texts.length < MIN_CONTENT_CARD_CHILDREN || texts.length > MAX_CONTENT_CARD_CHILDREN) {
39441
+ return null;
39442
+ }
39443
+ return texts;
39444
+ }
39445
+ function collectCardTexts(element, texts, depth) {
39446
+ if (depth > 2) return;
39447
+ for (const child of element.children) {
39448
+ if (TEXT_CARRYING_ROLES.has(child.role) || child.role === "listitem") {
39449
+ const text = getElementText(child);
39450
+ if (text && text.trim().length >= 2) {
39451
+ texts.push(text.trim());
39452
+ } else {
39453
+ collectCardTexts(child, texts, depth + 1);
39454
+ }
39455
+ }
39456
+ }
39457
+ }
39458
+ function detectContentCardRun(siblings, startIndex) {
39459
+ const cards = [];
39460
+ let endIndex = startIndex;
39461
+ for (let i = startIndex; i < siblings.length; i++) {
39462
+ const sib = siblings[i];
39463
+ const texts = extractCardTexts(sib);
39464
+ if (!texts) break;
39465
+ cards.push({ ref: sib.ref || "", texts });
39466
+ endIndex = i + 1;
39467
+ }
39468
+ if (cards.length < MIN_CONTENT_CARD_RUN) return null;
39469
+ return { cards, endIndex };
39470
+ }
39471
+ var DAY_ABBREVIATIONS = /* @__PURE__ */ new Set([
39472
+ "S",
39473
+ "M",
39474
+ "T",
39475
+ "W",
39476
+ "F",
39477
+ "Su",
39478
+ "Mo",
39479
+ "Tu",
39480
+ "We",
39481
+ "Th",
39482
+ "Fr",
39483
+ "Sa",
39484
+ "Sun",
39485
+ "Mon",
39486
+ "Tue",
39487
+ "Wed",
39488
+ "Thu",
39489
+ "Fri",
39490
+ "Sat"
39491
+ ]);
39492
+ function detectDatepicker(element) {
39493
+ const kids = element.children;
39494
+ if (kids.length < 35) return null;
39495
+ let headerStart = -1;
39496
+ for (let i = 0; i <= kids.length - 7; i++) {
39497
+ if (isDayHeaderRun(kids, i)) {
39498
+ headerStart = i;
39499
+ break;
39500
+ }
39501
+ }
39502
+ if (headerStart === -1) return null;
39503
+ const dayHeaders = kids.slice(headerStart, headerStart + 7).map((k) => {
39504
+ const text = getElementText(k);
39505
+ return text?.trim() ?? "";
39506
+ });
39507
+ const dayCells = [];
39508
+ for (let i = headerStart + 7; i < kids.length; i++) {
39509
+ const child = kids[i];
39510
+ const text = getElementText(child)?.trim();
39511
+ if (!text) continue;
39512
+ const num = parseInt(text, 10);
39513
+ if (isNaN(num) || num < 1 || num > 31 || String(num) !== text) break;
39514
+ dayCells.push({
39515
+ ref: child.ref || "",
39516
+ dayNumber: num,
39517
+ isSelected: isActiveElement(child) || child.rawLine.includes("[aria-selected=true]")
39518
+ });
39519
+ }
39520
+ if (dayCells.length < 28 || dayCells.length > 42) return null;
39521
+ const weeks = [];
39522
+ for (let i = 0; i < dayCells.length; i += 7) {
39523
+ const weekDays = dayCells.slice(i, i + 7).map((cell) => ({
39524
+ ref: cell.ref,
39525
+ dayNumber: cell.dayNumber,
39526
+ isSelected: cell.isSelected
39527
+ }));
39528
+ weeks.push({ days: weekDays });
39529
+ }
39530
+ return {
39531
+ ref: element.ref || "",
39532
+ dayHeaders,
39533
+ weeks
39534
+ };
39535
+ }
39536
+ function isDayHeaderRun(kids, startIndex) {
39537
+ for (let i = startIndex; i < startIndex + 7; i++) {
39538
+ const child = kids[i];
39539
+ if (isClickableByAttribute(child)) return false;
39540
+ const text = getElementText(child)?.trim();
39541
+ if (!text || !DAY_ABBREVIATIONS.has(text)) return false;
39542
+ }
39543
+ return true;
39544
+ }
39545
+ function formatContextAnnotations(annotations, indent) {
39546
+ const indentStr = " ".repeat(indent + 1);
39547
+ return annotations.map((text) => `${indentStr}context: "${text}"`);
39548
+ }
39549
+ function formatContentCards(cards, indent) {
39550
+ const indentStr = " ".repeat(indent + 1);
39551
+ const lines = [];
39552
+ lines.push(`${indentStr}Content:`);
39553
+ for (const card of cards) {
39554
+ const refPart = card.ref ? `[${card.ref}] ` : "";
39555
+ lines.push(`${indentStr} ${refPart}${card.texts.join(" \xB7 ")}`);
39556
+ }
39557
+ return lines;
39558
+ }
39559
+ function formatDatepicker(info, indent) {
39560
+ const indentStr = " ".repeat(indent + 1);
39561
+ const lines = [];
39562
+ lines.push(`${indentStr}Calendar (${info.dayHeaders.join(" ")}):`);
39563
+ for (let wi = 0; wi < info.weeks.length; wi++) {
39564
+ const week = info.weeks[wi];
39565
+ const dayCells = week.days.map((d) => {
39566
+ const selected = d.isSelected ? "*" : "";
39567
+ return `[${d.ref}]${d.dayNumber}${selected}`;
39568
+ });
39569
+ lines.push(`${indentStr} ${dayCells.join(" ")}`);
39570
+ }
39571
+ return lines;
39572
+ }
39573
+
39391
39574
  // ../browser-core/src/snapshot-formatter-sections.ts
39392
39575
  var FIELD_LABEL_TEXT_ROLES = /* @__PURE__ */ new Set([
39393
39576
  "generic",
@@ -39627,15 +39810,23 @@ function formatElement(element, options) {
39627
39810
  attributes: normalizedAttributes
39628
39811
  };
39629
39812
  }
39813
+ function containsNavigation(section) {
39814
+ for (const sub of section.subsections) {
39815
+ if (sub.role === "navigation") return true;
39816
+ if (containsNavigation(sub)) return true;
39817
+ }
39818
+ return false;
39819
+ }
39630
39820
  function shouldCollapse(section) {
39631
39821
  if (section.containsActive) return false;
39632
39822
  if (section.hasSearchMatch) return false;
39633
- if (section.isBackground) return true;
39634
39823
  if (section.role === "dialog" || section.role === "alertdialog") return false;
39635
39824
  if (section.role === "navigation" || section.role === "menubar" || section.role === "menu")
39636
39825
  return false;
39637
39826
  if (section.role === "banner") return false;
39638
39827
  if (section.role === "form") return false;
39828
+ if (containsNavigation(section)) return false;
39829
+ if (section.isBackground) return true;
39639
39830
  if (section.elementCount >= MIN_ELEMENTS_TO_COLLAPSE) return true;
39640
39831
  return false;
39641
39832
  }
@@ -39713,6 +39904,50 @@ function collectInteractiveElements(element, elements, subsections, depth, inher
39713
39904
  return;
39714
39905
  }
39715
39906
  const kids = element.children;
39907
+ const datepickerResult = detectDatepicker(element);
39908
+ if (datepickerResult) {
39909
+ const annotations = collectContextAnnotations(kids);
39910
+ subsections.push({
39911
+ heading: "Calendar",
39912
+ ref: datepickerResult.ref,
39913
+ role: "generic",
39914
+ level: 4,
39915
+ elements: [],
39916
+ subsections: [],
39917
+ collapsed: false,
39918
+ containsActive: false,
39919
+ isBackground: false,
39920
+ isFocused: false,
39921
+ elementCount: datepickerResult.weeks.reduce((sum, w) => sum + w.days.length, 0),
39922
+ datepickerInfo: datepickerResult,
39923
+ contextAnnotations: annotations.length > 0 ? annotations : void 0
39924
+ });
39925
+ return;
39926
+ }
39927
+ const cardRun = detectContentCardRun(kids, 0);
39928
+ if (cardRun) {
39929
+ const annotations = collectContextAnnotations(kids);
39930
+ subsections.push({
39931
+ heading: "Content",
39932
+ ref: element.ref || "",
39933
+ role: "generic",
39934
+ level: 4,
39935
+ elements: [],
39936
+ subsections: [],
39937
+ collapsed: false,
39938
+ containsActive: false,
39939
+ isBackground: false,
39940
+ isFocused: false,
39941
+ elementCount: cardRun.cards.length,
39942
+ contentCards: cardRun.cards,
39943
+ contextAnnotations: annotations.length > 0 ? annotations : void 0
39944
+ });
39945
+ for (let ki = cardRun.endIndex; ki < kids.length; ki++) {
39946
+ const child = kids[ki];
39947
+ collectInteractiveElements(child, elements, subsections, depth + 1, inheritedFieldLabel);
39948
+ }
39949
+ return;
39950
+ }
39716
39951
  for (let ki = 0; ki < kids.length; ki++) {
39717
39952
  const child = kids[ki];
39718
39953
  if (isVisualHeading(child, kids, ki)) {
@@ -39771,6 +40006,44 @@ function buildSection(element, depth) {
39771
40006
  if (gridInfo) {
39772
40007
  return buildGridSection(element);
39773
40008
  }
40009
+ const datepickerResult = detectDatepicker(element);
40010
+ if (datepickerResult) {
40011
+ const annotations = collectContextAnnotations(element.children);
40012
+ return {
40013
+ ref: element.ref || "",
40014
+ role: element.role,
40015
+ heading: element.text || "Calendar",
40016
+ level: 0,
40017
+ elements: [],
40018
+ subsections: [],
40019
+ containsActive: false,
40020
+ collapsed: false,
40021
+ isBackground: false,
40022
+ isFocused: false,
40023
+ elementCount: datepickerResult.weeks.reduce((sum, w) => sum + w.days.length, 0),
40024
+ datepickerInfo: datepickerResult,
40025
+ contextAnnotations: annotations.length > 0 ? annotations : void 0
40026
+ };
40027
+ }
40028
+ const cardRun = detectContentCardRun(element.children, 0);
40029
+ if (cardRun) {
40030
+ const annotations = collectContextAnnotations(element.children);
40031
+ return {
40032
+ ref: element.ref || "",
40033
+ role: element.role,
40034
+ heading: element.text || "Content",
40035
+ level: 0,
40036
+ elements: [],
40037
+ subsections: [],
40038
+ containsActive: false,
40039
+ collapsed: false,
40040
+ isBackground: false,
40041
+ isFocused: false,
40042
+ elementCount: cardRun.cards.length,
40043
+ contentCards: cardRun.cards,
40044
+ contextAnnotations: annotations.length > 0 ? annotations : void 0
40045
+ };
40046
+ }
39774
40047
  const isHeading = element.role === "heading";
39775
40048
  const isStructural = STRUCTURAL_ROLES.has(element.role);
39776
40049
  if (isHeading && !element.text?.trim() && element.children.length === 0) {
@@ -39881,8 +40154,19 @@ function buildSection(element, depth) {
39881
40154
  function markBackgroundSections(sections) {
39882
40155
  const hasActiveSibling = sections.some((s) => s.containsActive);
39883
40156
  if (hasActiveSibling) {
39884
- for (const section of sections) {
40157
+ let lastActiveIndex = -1;
40158
+ for (let i = sections.length - 1; i >= 0; i--) {
40159
+ if (sections[i].containsActive) {
40160
+ lastActiveIndex = i;
40161
+ break;
40162
+ }
40163
+ }
40164
+ for (let i = 0; i < sections.length; i++) {
40165
+ const section = sections[i];
39885
40166
  if (!section.containsActive) {
40167
+ if (DIALOG_ROLES.has(section.role) && i > lastActiveIndex) {
40168
+ continue;
40169
+ }
39886
40170
  section.isBackground = true;
39887
40171
  section.collapsed = shouldCollapse(section);
39888
40172
  }
@@ -40098,6 +40382,26 @@ function formatSectionOutput(section, indent, showCollapsed) {
40098
40382
  }
40099
40383
  const indentStr = " ".repeat(indent);
40100
40384
  const lines = [];
40385
+ if (section.datepickerInfo) {
40386
+ const headingPrefix2 = section.level > 0 ? "#".repeat(Math.min(section.level + 2, 6)) + " " : "";
40387
+ const refPart2 = section.ref ? ` [${section.ref}]` : "";
40388
+ lines.push(`${indentStr}${headingPrefix2}${section.heading}${refPart2}`);
40389
+ if (section.contextAnnotations) {
40390
+ lines.push(...formatContextAnnotations(section.contextAnnotations, indent));
40391
+ }
40392
+ lines.push(...formatDatepicker(section.datepickerInfo, indent));
40393
+ return lines.join("\n");
40394
+ }
40395
+ if (section.contentCards && section.contentCards.length > 0) {
40396
+ const headingPrefix2 = section.level > 0 ? "#".repeat(Math.min(section.level + 2, 6)) + " " : "";
40397
+ const refPart2 = section.ref ? ` [${section.ref}]` : "";
40398
+ lines.push(`${indentStr}${headingPrefix2}${section.heading}${refPart2}`);
40399
+ if (section.contextAnnotations) {
40400
+ lines.push(...formatContextAnnotations(section.contextAnnotations, indent));
40401
+ }
40402
+ lines.push(...formatContentCards(section.contentCards, indent));
40403
+ return lines.join("\n");
40404
+ }
40101
40405
  const headingPrefix = section.level > 0 ? "#".repeat(Math.min(section.level + 2, 6)) + " " : "";
40102
40406
  const refPart = section.ref ? ` [${section.ref}]` : "";
40103
40407
  const focusedPart = section.isFocused ? " [FOCUSED]" : "";
@@ -40106,6 +40410,9 @@ function formatSectionOutput(section, indent, showCollapsed) {
40106
40410
  lines.push(
40107
40411
  `${indentStr}${headingPrefix}${section.heading}${refPart}${focusedPart}${backgroundPart}${activePart}`
40108
40412
  );
40413
+ if (section.contextAnnotations) {
40414
+ lines.push(...formatContextAnnotations(section.contextAnnotations, indent));
40415
+ }
40109
40416
  if (section.collapsed && !showCollapsed) {
40110
40417
  if (section.isBackground) {
40111
40418
  if (section.ref) {
@@ -45743,7 +46050,8 @@ var PlaywrightClient = class _PlaywrightClient {
45743
46050
  highlightInteractions,
45744
46051
  cursorOverlay,
45745
46052
  extraHTTPHeaders,
45746
- httpCredentials
46053
+ httpCredentials,
46054
+ proxy
45747
46055
  } = options;
45748
46056
  const resolvedBrowserMode = browserMode ?? "headless";
45749
46057
  const resolvedViewport = viewport ?? DEFAULT_VIEWPORT;
@@ -45757,7 +46065,8 @@ var PlaywrightClient = class _PlaywrightClient {
45757
46065
  highlightInteractions,
45758
46066
  cursorOverlay,
45759
46067
  extraHTTPHeaders,
45760
- httpCredentials
46068
+ httpCredentials,
46069
+ proxy
45761
46070
  };
45762
46071
  this.storageStatePath = storageStatePath;
45763
46072
  this.pageClosedIntentionally = false;
@@ -45861,7 +46170,8 @@ var PlaywrightClient = class _PlaywrightClient {
45861
46170
  stealth,
45862
46171
  extensions,
45863
46172
  extraHTTPHeaders,
45864
- httpCredentials
46173
+ httpCredentials,
46174
+ proxy
45865
46175
  }),
45866
46176
  {
45867
46177
  logger: this.logger,
@@ -46042,7 +46352,8 @@ var PlaywrightClient = class _PlaywrightClient {
46042
46352
  stealth,
46043
46353
  extensions,
46044
46354
  extraHTTPHeaders,
46045
- httpCredentials
46355
+ httpCredentials,
46356
+ proxy
46046
46357
  } = options;
46047
46358
  const resolvedViewport = viewport ?? DEFAULT_VIEWPORT;
46048
46359
  const useStealthMode = stealth === true || typeof stealth === "object" && stealth.enabled;
@@ -46077,6 +46388,13 @@ var PlaywrightClient = class _PlaywrightClient {
46077
46388
  contextOptions.httpCredentials = httpCredentials;
46078
46389
  this.logger.info("[DirectPlaywright] HTTP Basic Authentication configured");
46079
46390
  }
46391
+ if (proxy) {
46392
+ this.logger.info("[DirectPlaywright] Proxy configured", {
46393
+ server: proxy.server.replace(/\/\/[^@]+@/, "//***@"),
46394
+ bypass: proxy.bypass,
46395
+ hasAuth: !!(proxy.username && proxy.password)
46396
+ });
46397
+ }
46080
46398
  if (storageStatePath) {
46081
46399
  try {
46082
46400
  await fs4.access(storageStatePath);
@@ -46119,6 +46437,7 @@ var PlaywrightClient = class _PlaywrightClient {
46119
46437
  // We use --headless=new in args for extension support
46120
46438
  args,
46121
46439
  ...executablePath ? { executablePath } : {},
46440
+ ...proxy ? { proxy } : {},
46122
46441
  ...contextOptions
46123
46442
  }),
46124
46443
  3e4,
@@ -46130,7 +46449,8 @@ var PlaywrightClient = class _PlaywrightClient {
46130
46449
  chromiumLauncher.launch({
46131
46450
  headless: browserMode === "headless",
46132
46451
  args,
46133
- ...executablePath ? { executablePath } : {}
46452
+ ...executablePath ? { executablePath } : {},
46453
+ ...proxy ? { proxy } : {}
46134
46454
  }),
46135
46455
  3e4,
46136
46456
  "[DirectPlaywright] chromium.launch"
@@ -49243,4 +49563,4 @@ playwright-extra/dist/index.esm.js:
49243
49563
  * @license MIT
49244
49564
  *)
49245
49565
  */
49246
- //# sourceMappingURL=chunk-6IAPGYZQ.js.map
49566
+ //# sourceMappingURL=chunk-WOVAMA3N.js.map