agent-web-interface 4.5.0 → 4.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +35 -34
  2. package/dist/src/browser/browser-session-config.d.ts.map +1 -1
  3. package/dist/src/browser/browser-session-config.js +1 -0
  4. package/dist/src/browser/browser-session-config.js.map +1 -1
  5. package/dist/src/browser/ensure-browser.d.ts.map +1 -1
  6. package/dist/src/browser/ensure-browser.js +34 -9
  7. package/dist/src/browser/ensure-browser.js.map +1 -1
  8. package/dist/src/browser/page-network-recorder.d.ts +95 -0
  9. package/dist/src/browser/page-network-recorder.d.ts.map +1 -0
  10. package/dist/src/browser/page-network-recorder.js +306 -0
  11. package/dist/src/browser/page-network-recorder.js.map +1 -0
  12. package/dist/src/browser/session-manager.d.ts.map +1 -1
  13. package/dist/src/browser/session-manager.js +47 -3
  14. package/dist/src/browser/session-manager.js.map +1 -1
  15. package/dist/src/server/tool-result-handler.d.ts.map +1 -1
  16. package/dist/src/server/tool-result-handler.js +19 -1
  17. package/dist/src/server/tool-result-handler.js.map +1 -1
  18. package/dist/src/session/session-controller.d.ts +1 -0
  19. package/dist/src/session/session-controller.d.ts.map +1 -1
  20. package/dist/src/session/session-controller.js +3 -0
  21. package/dist/src/session/session-controller.js.map +1 -1
  22. package/dist/src/tools/browser-tools.d.ts +1 -0
  23. package/dist/src/tools/browser-tools.d.ts.map +1 -1
  24. package/dist/src/tools/browser-tools.js +2 -0
  25. package/dist/src/tools/browser-tools.js.map +1 -1
  26. package/dist/src/tools/index.d.ts +2 -0
  27. package/dist/src/tools/index.d.ts.map +1 -1
  28. package/dist/src/tools/index.js +3 -0
  29. package/dist/src/tools/index.js.map +1 -1
  30. package/dist/src/tools/navigation-tools.d.ts.map +1 -1
  31. package/dist/src/tools/navigation-tools.js +14 -9
  32. package/dist/src/tools/navigation-tools.js.map +1 -1
  33. package/dist/src/tools/network-tools.d.ts +10 -0
  34. package/dist/src/tools/network-tools.d.ts.map +1 -0
  35. package/dist/src/tools/network-tools.js +117 -0
  36. package/dist/src/tools/network-tools.js.map +1 -0
  37. package/dist/src/tools/tool-context.types.d.ts +6 -0
  38. package/dist/src/tools/tool-context.types.d.ts.map +1 -1
  39. package/dist/src/tools/tool-registration.d.ts +1 -1
  40. package/dist/src/tools/tool-registration.d.ts.map +1 -1
  41. package/dist/src/tools/tool-registration.js +16 -1
  42. package/dist/src/tools/tool-registration.js.map +1 -1
  43. package/dist/src/tools/tool-schemas.d.ts +93 -3
  44. package/dist/src/tools/tool-schemas.d.ts.map +1 -1
  45. package/dist/src/tools/tool-schemas.js +115 -6
  46. package/dist/src/tools/tool-schemas.js.map +1 -1
  47. package/dist/vitest.config.js +1 -1
  48. package/dist/vitest.config.js.map +1 -1
  49. package/dist/vitest.integration.config.d.ts +3 -0
  50. package/dist/vitest.integration.config.d.ts.map +1 -0
  51. package/dist/vitest.integration.config.js +11 -0
  52. package/dist/vitest.integration.config.js.map +1 -0
  53. package/package.json +14 -3
package/README.md CHANGED
@@ -100,8 +100,6 @@ Example workflows include:
100
100
  - Handling login and consent flows
101
101
  - Performing multi-step UI interactions with lower token usage
102
102
 
103
- See the `examples/` directory for concrete agent workflows.
104
-
105
103
  ---
106
104
 
107
105
  ## Claude Code
@@ -110,33 +108,30 @@ See the `examples/` directory for concrete agent workflows.
110
108
  # Basic (auto-launches browser)
111
109
  claude mcp add agent-web-interface -- npx agent-web-interface@latest
112
110
 
113
- # With auto-connect to your Chrome profile
114
- claude mcp add agent-web-interface -- npx agent-web-interface@latest --autoConnect
115
-
116
- # Headless mode
117
- claude mcp add agent-web-interface -- npx agent-web-interface@latest --headless
111
+ # With auto-connect to your Chrome profile (set via env var)
112
+ claude mcp add agent-web-interface -e AWI_CDP_URL=http://localhost:9222 -- npx agent-web-interface@latest
118
113
  ```
119
114
 
120
115
  ---
121
116
 
122
117
  ## CLI Arguments
123
118
 
124
- The server accepts the following arguments to configure browser initialization:
119
+ The server accepts transport-level arguments only. Browser configuration is per-session via the `navigate` tool.
125
120
 
126
- | Argument | Description | Default |
127
- | ------------------------ | --------------------------------------------------------------- | ---------------- |
128
- | `--headless=true\|false` | Run browser in headless mode | `false` |
129
- | `--browserUrl` | HTTP endpoint to connect to existing browser | - |
130
- | `--wsEndpoint` | WebSocket endpoint to connect to existing browser | - |
131
- | `--autoConnect` | Auto-connect to Chrome 144+ via DevToolsActivePort | `false` |
132
- | `--isolated` | Use isolated temp profile instead of persistent | `false` |
133
- | `--userDataDir` | Chrome user data directory | Platform default |
134
- | `--channel` | Chrome channel (chrome, chrome-canary, chrome-beta, chrome-dev) | `chrome` |
135
- | `--executablePath` | Path to Chrome executable | - |
121
+ | Argument | Description | Default |
122
+ | ------------- | --------------------------------- | ------- |
123
+ | `--transport` | Transport mode: `stdio` or `http` | `stdio` |
124
+ | `--port` | Port for HTTP transport | `3000` |
136
125
 
137
- ### Automatic Browser Initialization
126
+ ### Browser Session Configuration
138
127
 
139
- The browser is automatically launched or connected on the first tool call. No explicit initialization is needed.
128
+ Browser initialization is automatic on the first tool call. The `navigate` tool accepts optional parameters to configure the session:
129
+
130
+ | Parameter | Description | Default |
131
+ | -------------- | -------------------------------------------------- | ------- |
132
+ | `headless` | Run browser in headless mode | `false` |
133
+ | `isolated` | Use an isolated temp profile instead of persistent | `false` |
134
+ | `auto_connect` | Auto-connect to Chrome 144+ via DevToolsActivePort | `false` |
140
135
 
141
136
  Examples:
142
137
 
@@ -144,14 +139,11 @@ Examples:
144
139
  # Auto-launch visible browser (default)
145
140
  npx agent-web-interface
146
141
 
147
- # Launch headless browser
148
- npx agent-web-interface --headless
149
-
150
- # Auto-connect to Chrome with remote debugging enabled
151
- npx agent-web-interface --autoConnect
142
+ # HTTP transport mode
143
+ npx agent-web-interface --transport http --port 8080
152
144
 
153
- # Connect to specific endpoint
154
- npx agent-web-interface --browserUrl http://localhost:9222
145
+ # Connect to existing CDP endpoint via env var
146
+ AWI_CDP_URL=http://localhost:9222 npx agent-web-interface
155
147
  ```
156
148
 
157
149
  ---
@@ -162,14 +154,17 @@ To connect with your bookmarks, extensions, and logged-in sessions:
162
154
 
163
155
  1. Navigate to `chrome://inspect/#remote-debugging` in Chrome
164
156
  2. Enable remote debugging and allow the connection
165
- 3. Use `--autoConnect` CLI argument
157
+ 3. Use the `auto_connect` parameter on the `navigate` tool, or set `AWI_CDP_URL`
166
158
 
167
159
  ```json
168
160
  {
169
161
  "mcpServers": {
170
162
  "agent-web-interface": {
171
163
  "command": "npx",
172
- "args": ["agent-web-interface@latest", "--autoConnect"]
164
+ "args": ["agent-web-interface@latest"],
165
+ "env": {
166
+ "AWI_CDP_URL": "http://localhost:9222"
167
+ }
173
168
  }
174
169
  }
175
170
  }
@@ -179,11 +174,17 @@ To connect with your bookmarks, extensions, and logged-in sessions:
179
174
 
180
175
  ## Environment Variables
181
176
 
182
- | Variable | Description | Default |
183
- | ------------------ | -------------------------------------------------- | ----------- |
184
- | `AWI_TRIM_REGIONS` | Set to `false` to disable region trimming globally | `true` |
185
- | `CEF_BRIDGE_HOST` | CDP host for browser connection | `127.0.0.1` |
186
- | `CEF_BRIDGE_PORT` | CDP port for browser connection | `9223` |
177
+ | Variable | Description | Default |
178
+ | ------------------ | -------------------------------------------------------- | ----------- |
179
+ | `AWI_CDP_URL` | CDP endpoint (http or ws) to connect to existing browser | - |
180
+ | `AWI_TRIM_REGIONS` | Set to `false` to disable region trimming globally | `true` |
181
+ | `TRANSPORT` | Transport mode override (`http`) | - |
182
+ | `HTTP_HOST` | Host for HTTP transport | `127.0.0.1` |
183
+ | `HTTP_PORT` | Port for HTTP transport | `3000` |
184
+ | `LOG_LEVEL` | Logging level | `info` |
185
+ | `CEF_BRIDGE_HOST` | CDP host for CEF bridge connection | `127.0.0.1` |
186
+ | `CEF_BRIDGE_PORT` | CDP port for CEF bridge connection | `9223` |
187
+ | `CHROME_PATH` | Path to Chrome executable (multi-tenant) | - |
187
188
 
188
189
  ---
189
190
 
@@ -1 +1 @@
1
- {"version":3,"file":"browser-session-config.d.ts","sourceRoot":"","sources":["../../../src/browser/browser-session-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,yDAAyD;IACzD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,oBAAoB,CAK3D"}
1
+ {"version":3,"file":"browser-session-config.d.ts","sourceRoot":"","sources":["../../../src/browser/browser-session-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,yDAAyD;IACzD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,oBAAoB,CAM3D"}
@@ -19,6 +19,7 @@ export function defaultBrowserConfig() {
19
19
  return {
20
20
  headless: false,
21
21
  isolated: false,
22
+ autoConnect: true,
22
23
  };
23
24
  }
24
25
  //# sourceMappingURL=browser-session-config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser-session-config.js","sourceRoot":"","sources":["../../../src/browser/browser-session-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAmBH;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,KAAK;KAChB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"browser-session-config.js","sourceRoot":"","sources":["../../../src/browser/browser-session-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAmBH;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,IAAI;KAClB,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ensure-browser.d.ts","sourceRoot":"","sources":["../../../src/browser/ensure-browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AASxE;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,IAAI,CAAC,CA6Df"}
1
+ {"version":3,"file":"ensure-browser.d.ts","sourceRoot":"","sources":["../../../src/browser/ensure-browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AASxE;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAwFf"}
@@ -38,24 +38,37 @@ export async function ensureBrowserReady(session, config) {
38
38
  }
39
39
  // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- empty string must be falsy
40
40
  const cdpUrl = process.env.AWI_CDP_URL?.trim() || undefined;
41
- const shouldConnect = !!(cdpUrl ?? config.autoConnect);
42
- if (shouldConnect) {
43
- logger.info('Lazy browser initialization triggered', { mode: 'connect' });
41
+ // Explicit CDP URL connect only, no fallback to launch
42
+ if (cdpUrl) {
43
+ logger.info('Lazy browser initialization triggered', { mode: 'connect', cdpUrl });
44
44
  try {
45
- await session.connect({
46
- endpointUrl: cdpUrl,
47
- autoConnect: config.autoConnect,
48
- });
45
+ await session.connect({ endpointUrl: cdpUrl });
49
46
  logger.info('Browser initialized successfully', { mode: 'connect' });
50
47
  }
51
48
  catch (error) {
49
+ const msg = extractErrorMessage(error);
52
50
  logger.error('Browser initialization failed', error instanceof Error ? error : undefined, {
53
51
  mode: 'connect',
54
52
  });
55
- throw error;
53
+ throw new Error(`Failed to connect to CDP endpoint (${cdpUrl}): ${msg}. ` +
54
+ 'Try removing AWI_CDP_URL to auto-connect to a running Chrome, or launch a new browser with auto_connect=false.');
56
55
  }
57
56
  return;
58
57
  }
58
+ // Auto-connect: try connecting to an existing Chrome first, fall back to launch
59
+ if (config.autoConnect) {
60
+ logger.info('Attempting auto-connect to existing Chrome');
61
+ try {
62
+ await session.connect({ autoConnect: true });
63
+ logger.info('Auto-connected to existing Chrome');
64
+ return;
65
+ }
66
+ catch (error) {
67
+ logger.info('Auto-connect failed, falling back to launch', {
68
+ error: extractErrorMessage(error),
69
+ });
70
+ }
71
+ }
59
72
  // Launch mode — try reconnecting to an existing browser first (persistent profiles only)
60
73
  const profileDir = config.isolated ? undefined : DEFAULT_USER_DATA_DIR;
61
74
  if (profileDir && (await hasPortFile(profileDir)) && (await tryReconnect(session, profileDir))) {
@@ -76,11 +89,23 @@ export async function ensureBrowserReady(session, config) {
76
89
  if (profileDir && isProfileLockError(error) && (await tryReconnect(session, profileDir))) {
77
90
  return;
78
91
  }
92
+ const msg = extractErrorMessage(error);
79
93
  logger.error('Browser initialization failed', error instanceof Error ? error : undefined, {
80
94
  mode: 'launch',
81
95
  headless: config.headless,
82
96
  });
83
- throw error;
97
+ const suggestions = [];
98
+ if (!config.headless) {
99
+ suggestions.push('try headless=true if no display is available');
100
+ }
101
+ if (!config.isolated) {
102
+ suggestions.push('try isolated=true to use a fresh profile');
103
+ }
104
+ if (config.headless) {
105
+ suggestions.push('try headless=false to launch a visible browser');
106
+ }
107
+ const hint = suggestions.length > 0 ? ` Suggestions: ${suggestions.join('; ')}.` : '';
108
+ throw new Error(`Failed to launch browser: ${msg}.${hint}`);
84
109
  }
85
110
  }
86
111
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ensure-browser.js","sourceRoot":"","sources":["../../../src/browser/ensure-browser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ensure-browser.js","sourceRoot":"","sources":["../../../src/browser/ensure-browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAC;AAElE,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;AAE3B,6FAA6F;AAC7F,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAuB,EACvB,MAA4B;IAE5B,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;QACxB,OAAO;IACT,CAAC;IAED,MAAM,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAClD,IAAI,OAAO,CAAC,eAAe,KAAK,YAAY,IAAI,eAAe,EAAE,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;QACrD,MAAM,eAAe,CAAC;QACtB,OAAO;IACT,CAAC;IAED,sGAAsG;IACtG,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;IAE5D,yDAAyD;IACzD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,uCAAuC,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;QAClF,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,kCAAkC,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACvE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;YACvC,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAAE;gBACxF,IAAI,EAAE,SAAS;aAChB,CAAC,CAAC;YACH,MAAM,IAAI,KAAK,CACb,sCAAsC,MAAM,MAAM,GAAG,IAAI;gBACvD,gHAAgH,CACnH,CAAC;QACJ,CAAC;QACD,OAAO;IACT,CAAC;IAED,gFAAgF;IAChF,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC1D,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7C,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;YACjD,OAAO;QACT,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,6CAA6C,EAAE;gBACzD,KAAK,EAAE,mBAAmB,CAAC,KAAK,CAAC;aAClC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,yFAAyF;IACzF,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,qBAAqB,CAAC;IAEvE,IAAI,UAAU,IAAI,CAAC,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,YAAY,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC;QAC/F,OAAO;IACT,CAAC;IAED,uBAAuB;IACvB,MAAM,CAAC,IAAI,CAAC,uCAAuC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IACzE,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,MAAM,CAAC;YACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,KAAK;YAClC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,KAAK;SACnC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,kCAAkC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,6EAA6E;QAC7E,+DAA+D;QAC/D,IAAI,UAAU,IAAI,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,YAAY,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC;YACzF,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAAE;YACxF,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,CAAC,CAAC;QACH,MAAM,WAAW,GAAa,EAAE,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,WAAW,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,WAAW,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACpB,WAAW,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;QACrE,CAAC;QACD,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,WAAW,CAAC,UAAkB;IAC3C,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACzF,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,YAAY,CAAC,OAAuB,EAAE,UAAkB;IACrE,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,OAAO,CAAC;YACpB,WAAW,EAAE,IAAI;YACjB,WAAW,EAAE,UAAU;YACvB,cAAc,EAAE,IAAI;YACpB,OAAO,EAAE,oBAAoB;SAC9B,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,OAAO,CAAC,sCAAsC,EAAE;YACrD,KAAK,EAAE,mBAAmB,CAAC,KAAK,CAAC;SAClC,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,KAAc;IACxC,MAAM,GAAG,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACvC,OAAO,mDAAmD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvE,CAAC"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Page Network Recorder
3
+ *
4
+ * Records network request/response details per page for the
5
+ * list_network_calls and search_network_calls tools.
6
+ *
7
+ * Uses Puppeteer page events (request, requestfinished, requestfailed)
8
+ * to capture entries. Memory-bounded via a ring buffer with
9
+ * configurable max entries.
10
+ *
11
+ * Follows the same lifecycle pattern as PageNetworkTracker:
12
+ * attach() → markNavigation() → detach()
13
+ */
14
+ import type { Page } from 'puppeteer-core';
15
+ export interface NetworkEntry {
16
+ id: number;
17
+ url: string;
18
+ method: string;
19
+ resource_type: string;
20
+ is_navigation: boolean;
21
+ request_headers: Record<string, string>;
22
+ post_data: string | null;
23
+ started_at: number;
24
+ status: number | null;
25
+ status_text: string | null;
26
+ response_headers: Record<string, string> | null;
27
+ mime_type: string | null;
28
+ duration_ms: number | null;
29
+ failed: boolean;
30
+ failure_text: string | null;
31
+ navigation_id: number;
32
+ }
33
+ export interface NetworkFilter {
34
+ url_pattern?: string;
35
+ url_regex?: boolean;
36
+ method?: string;
37
+ resource_type?: string;
38
+ status_min?: number;
39
+ status_max?: number;
40
+ failed_only?: boolean;
41
+ }
42
+ export interface NetworkQueryResult {
43
+ entries: NetworkEntry[];
44
+ total: number;
45
+ }
46
+ /**
47
+ * Records network request/response details for a single page.
48
+ *
49
+ * Uses a ring buffer (fixed-size array with head pointer) for O(1)
50
+ * insertion and eviction instead of Array.shift().
51
+ */
52
+ export declare class PageNetworkRecorder {
53
+ private buffer;
54
+ private head;
55
+ private count;
56
+ private nextId;
57
+ private navigationId;
58
+ private maxEntries;
59
+ private page;
60
+ private generation;
61
+ private currentGeneration;
62
+ /** Map from HTTPRequest to NetworkEntry for response correlation */
63
+ private pending;
64
+ private onRequest;
65
+ private onRequestFinished;
66
+ private onRequestFailed;
67
+ constructor(maxEntries?: number);
68
+ attach(page: Page): void;
69
+ detach(): void;
70
+ markNavigation(): void;
71
+ getEntries(filter?: NetworkFilter, offset?: number, limit?: number): NetworkQueryResult;
72
+ search(urlPattern: string, isRegex?: boolean, filter?: NetworkFilter, limit?: number): NetworkQueryResult;
73
+ clear(): void;
74
+ getStats(): {
75
+ total: number;
76
+ pending: number;
77
+ failed: number;
78
+ by_resource_type: Record<string, number>;
79
+ };
80
+ isAttached(): boolean;
81
+ /** Iterate entries in insertion order (oldest first). */
82
+ private iterEntries;
83
+ /** Compile a URL regex once, with a safety check for pathological patterns. */
84
+ private compileUrlRegex;
85
+ private applyFilter;
86
+ /** Add an entry, evicting the oldest if at capacity. O(1). */
87
+ private addEntry;
88
+ private pickHeaders;
89
+ private createAndAttachHandlers;
90
+ private removeHandlers;
91
+ }
92
+ export declare function getOrCreateRecorder(page: Page, maxEntries?: number): PageNetworkRecorder;
93
+ export declare function removeRecorder(page: Page): void;
94
+ export declare function hasRecorder(page: Page): boolean;
95
+ //# sourceMappingURL=page-network-recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-network-recorder.d.ts","sourceRoot":"","sources":["../../../src/browser/page-network-recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,306 @@
1
+ /**
2
+ * Page Network Recorder
3
+ *
4
+ * Records network request/response details per page for the
5
+ * list_network_calls and search_network_calls tools.
6
+ *
7
+ * Uses Puppeteer page events (request, requestfinished, requestfailed)
8
+ * to capture entries. Memory-bounded via a ring buffer with
9
+ * configurable max entries.
10
+ *
11
+ * Follows the same lifecycle pattern as PageNetworkTracker:
12
+ * attach() → markNavigation() → detach()
13
+ */
14
+ /** Maximum post data size to store (bytes) */
15
+ const MAX_POST_DATA_SIZE = 2048;
16
+ /** Default maximum number of entries to retain */
17
+ const DEFAULT_MAX_ENTRIES = 1000;
18
+ /** Headers worth keeping on requests */
19
+ const KEPT_REQUEST_HEADERS = new Set([
20
+ 'content-type',
21
+ 'accept',
22
+ 'content-length',
23
+ 'x-requested-with',
24
+ ]);
25
+ /** Headers worth keeping on responses */
26
+ const KEPT_RESPONSE_HEADERS = new Set([
27
+ 'content-type',
28
+ 'content-length',
29
+ 'cache-control',
30
+ 'location',
31
+ ]);
32
+ /**
33
+ * Records network request/response details for a single page.
34
+ *
35
+ * Uses a ring buffer (fixed-size array with head pointer) for O(1)
36
+ * insertion and eviction instead of Array.shift().
37
+ */
38
+ export class PageNetworkRecorder {
39
+ // Ring buffer: fixed-size array, head points to oldest entry
40
+ buffer;
41
+ head = 0;
42
+ count = 0;
43
+ nextId = 1;
44
+ navigationId = 0;
45
+ maxEntries;
46
+ page = null;
47
+ generation = 0;
48
+ currentGeneration = 0;
49
+ /** Map from HTTPRequest to NetworkEntry for response correlation */
50
+ pending = new Map();
51
+ onRequest = null;
52
+ onRequestFinished = null;
53
+ onRequestFailed = null;
54
+ constructor(maxEntries = DEFAULT_MAX_ENTRIES) {
55
+ this.maxEntries = maxEntries;
56
+ this.buffer = new Array(maxEntries).fill(null);
57
+ }
58
+ attach(page) {
59
+ if (this.page) {
60
+ this.detach();
61
+ }
62
+ this.page = page;
63
+ this.generation++;
64
+ this.currentGeneration = this.generation;
65
+ this.createAndAttachHandlers(page);
66
+ }
67
+ detach() {
68
+ if (this.page) {
69
+ this.removeHandlers(this.page);
70
+ }
71
+ this.onRequest = null;
72
+ this.onRequestFinished = null;
73
+ this.onRequestFailed = null;
74
+ this.page = null;
75
+ this.pending.clear();
76
+ }
77
+ markNavigation() {
78
+ this.navigationId++;
79
+ this.generation++;
80
+ this.currentGeneration = this.generation;
81
+ this.pending.clear();
82
+ if (this.page) {
83
+ this.removeHandlers(this.page);
84
+ this.createAndAttachHandlers(this.page);
85
+ }
86
+ }
87
+ getEntries(filter, offset = 0, limit = 25) {
88
+ const filtered = this.applyFilter(filter);
89
+ return {
90
+ total: filtered.length,
91
+ entries: filtered.slice(offset, offset + limit),
92
+ };
93
+ }
94
+ search(urlPattern, isRegex = false, filter, limit = 25) {
95
+ const combinedFilter = {
96
+ ...filter,
97
+ url_pattern: urlPattern,
98
+ url_regex: isRegex,
99
+ };
100
+ const filtered = this.applyFilter(combinedFilter);
101
+ return { total: filtered.length, entries: filtered.slice(0, limit) };
102
+ }
103
+ clear() {
104
+ this.buffer = new Array(this.maxEntries).fill(null);
105
+ this.head = 0;
106
+ this.count = 0;
107
+ this.pending.clear();
108
+ this.nextId = 1;
109
+ }
110
+ getStats() {
111
+ let pendingCount = 0;
112
+ let failedCount = 0;
113
+ const byType = {};
114
+ for (const entry of this.iterEntries()) {
115
+ if (entry.status === null && !entry.failed)
116
+ pendingCount++;
117
+ if (entry.failed)
118
+ failedCount++;
119
+ byType[entry.resource_type] = (byType[entry.resource_type] ?? 0) + 1;
120
+ }
121
+ return {
122
+ total: this.count,
123
+ pending: pendingCount,
124
+ failed: failedCount,
125
+ by_resource_type: byType,
126
+ };
127
+ }
128
+ isAttached() {
129
+ return this.page !== null;
130
+ }
131
+ // --- Private methods ---
132
+ /** Iterate entries in insertion order (oldest first). */
133
+ *iterEntries() {
134
+ for (let i = 0; i < this.count; i++) {
135
+ const idx = (this.head + i) % this.maxEntries;
136
+ const entry = this.buffer[idx];
137
+ if (entry)
138
+ yield entry;
139
+ }
140
+ }
141
+ /** Compile a URL regex once, with a safety check for pathological patterns. */
142
+ compileUrlRegex(pattern) {
143
+ try {
144
+ return new RegExp(pattern);
145
+ }
146
+ catch {
147
+ return null;
148
+ }
149
+ }
150
+ applyFilter(filter) {
151
+ if (!filter)
152
+ return Array.from(this.iterEntries());
153
+ // Pre-compile regex once instead of per-entry
154
+ let urlRegex = null;
155
+ if (filter.url_pattern && filter.url_regex) {
156
+ urlRegex = this.compileUrlRegex(filter.url_pattern);
157
+ }
158
+ const results = [];
159
+ for (const e of this.iterEntries()) {
160
+ if (filter.method && e.method.toUpperCase() !== filter.method.toUpperCase())
161
+ continue;
162
+ if (filter.resource_type && e.resource_type !== filter.resource_type)
163
+ continue;
164
+ if (filter.status_min != null && (e.status === null || e.status < filter.status_min))
165
+ continue;
166
+ if (filter.status_max != null && (e.status === null || e.status > filter.status_max))
167
+ continue;
168
+ if (filter.failed_only && !e.failed)
169
+ continue;
170
+ if (filter.url_pattern) {
171
+ if (urlRegex) {
172
+ if (!urlRegex.test(e.url))
173
+ continue;
174
+ }
175
+ else if (filter.url_regex) {
176
+ // Regex compilation failed — fall back to substring
177
+ if (!e.url.includes(filter.url_pattern))
178
+ continue;
179
+ }
180
+ else {
181
+ if (!e.url.includes(filter.url_pattern))
182
+ continue;
183
+ }
184
+ }
185
+ results.push(e);
186
+ }
187
+ return results;
188
+ }
189
+ /** Add an entry, evicting the oldest if at capacity. O(1). */
190
+ addEntry(entry) {
191
+ if (this.count >= this.maxEntries) {
192
+ // Overwrite oldest entry at head
193
+ this.buffer[this.head] = entry;
194
+ this.head = (this.head + 1) % this.maxEntries;
195
+ // No need to clean up pending — evicted entries that are still pending
196
+ // will simply not be found in the pending Map lookup (harmless no-op)
197
+ }
198
+ else {
199
+ const idx = (this.head + this.count) % this.maxEntries;
200
+ this.buffer[idx] = entry;
201
+ this.count++;
202
+ }
203
+ }
204
+ pickHeaders(headers, kept) {
205
+ const result = {};
206
+ for (const key of Object.keys(headers)) {
207
+ if (kept.has(key.toLowerCase())) {
208
+ result[key.toLowerCase()] = headers[key];
209
+ }
210
+ }
211
+ return result;
212
+ }
213
+ createAndAttachHandlers(page) {
214
+ const gen = this.currentGeneration;
215
+ this.onRequest = (req) => {
216
+ if (this.currentGeneration !== gen)
217
+ return;
218
+ if (req.resourceType() === 'websocket')
219
+ return;
220
+ let postData = req.postData() ?? null;
221
+ if (postData && postData.length > MAX_POST_DATA_SIZE) {
222
+ postData = postData.slice(0, MAX_POST_DATA_SIZE) + '…[truncated]';
223
+ }
224
+ const entry = {
225
+ id: this.nextId++,
226
+ url: req.url(),
227
+ method: req.method(),
228
+ resource_type: req.resourceType(),
229
+ is_navigation: req.isNavigationRequest(),
230
+ request_headers: this.pickHeaders(req.headers(), KEPT_REQUEST_HEADERS),
231
+ post_data: postData,
232
+ started_at: Date.now(),
233
+ status: null,
234
+ status_text: null,
235
+ response_headers: null,
236
+ mime_type: null,
237
+ duration_ms: null,
238
+ failed: false,
239
+ failure_text: null,
240
+ navigation_id: this.navigationId,
241
+ };
242
+ this.addEntry(entry);
243
+ this.pending.set(req, entry);
244
+ };
245
+ this.onRequestFinished = (req) => {
246
+ if (this.currentGeneration !== gen)
247
+ return;
248
+ const entry = this.pending.get(req);
249
+ if (!entry)
250
+ return;
251
+ this.pending.delete(req);
252
+ const response = req.response();
253
+ if (response) {
254
+ entry.status = response.status();
255
+ entry.status_text = response.statusText();
256
+ entry.response_headers = this.pickHeaders(response.headers(), KEPT_RESPONSE_HEADERS);
257
+ const ct = response.headers()['content-type'];
258
+ entry.mime_type = ct ? ct.split(';')[0].trim() : null;
259
+ }
260
+ entry.duration_ms = Date.now() - entry.started_at;
261
+ };
262
+ this.onRequestFailed = (req) => {
263
+ if (this.currentGeneration !== gen)
264
+ return;
265
+ const entry = this.pending.get(req);
266
+ if (!entry)
267
+ return;
268
+ this.pending.delete(req);
269
+ entry.failed = true;
270
+ entry.failure_text = req.failure()?.errorText ?? null;
271
+ entry.duration_ms = Date.now() - entry.started_at;
272
+ };
273
+ page.on('request', this.onRequest);
274
+ page.on('requestfinished', this.onRequestFinished);
275
+ page.on('requestfailed', this.onRequestFailed);
276
+ }
277
+ removeHandlers(page) {
278
+ if (this.onRequest)
279
+ page.off('request', this.onRequest);
280
+ if (this.onRequestFinished)
281
+ page.off('requestfinished', this.onRequestFinished);
282
+ if (this.onRequestFailed)
283
+ page.off('requestfailed', this.onRequestFailed);
284
+ }
285
+ }
286
+ // --- Global Registry ---
287
+ const recorders = new WeakMap();
288
+ export function getOrCreateRecorder(page, maxEntries) {
289
+ let recorder = recorders.get(page);
290
+ if (!recorder) {
291
+ recorder = new PageNetworkRecorder(maxEntries);
292
+ recorders.set(page, recorder);
293
+ }
294
+ return recorder;
295
+ }
296
+ export function removeRecorder(page) {
297
+ const recorder = recorders.get(page);
298
+ if (recorder) {
299
+ recorder.detach();
300
+ recorders.delete(page);
301
+ }
302
+ }
303
+ export function hasRecorder(page) {
304
+ return recorders.has(page);
305
+ }
306
+ //# sourceMappingURL=page-network-recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-network-recorder.js","sourceRoot":"","sources":["../../../src/browser/page-network-recorder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,8CAA8C;AAC9C,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,kDAAkD;AAClD,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC,wCAAwC;AACxC,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,cAAc;IACd,QAAQ;IACR,gBAAgB;IAChB,kBAAkB;CACnB,CAAC,CAAC;AAEH,yCAAyC;AACzC,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACpC,cAAc;IACd,gBAAgB;IAChB,eAAe;IACf,UAAU;CACX,CAAC,CAAC;AAoCH;;;;;GAKG;AACH,MAAM,OAAO,mBAAmB;IAC9B,6DAA6D;IACrD,MAAM,CAA0B;IAChC,IAAI,GAAG,CAAC,CAAC;IACT,KAAK,GAAG,CAAC,CAAC;IACV,MAAM,GAAG,CAAC,CAAC;IACX,YAAY,GAAG,CAAC,CAAC;IACjB,UAAU,CAAS;IACnB,IAAI,GAAgB,IAAI,CAAC;IACzB,UAAU,GAAG,CAAC,CAAC;IACf,iBAAiB,GAAG,CAAC,CAAC;IAE9B,oEAAoE;IAC5D,OAAO,GAAG,IAAI,GAAG,EAA6B,CAAC;IAE/C,SAAS,GAAwC,IAAI,CAAC;IACtD,iBAAiB,GAAwC,IAAI,CAAC;IAC9D,eAAe,GAAwC,IAAI,CAAC;IAEpE,YAAY,UAAU,GAAG,mBAAmB;QAC1C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAsB,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,CAAC,IAAU;QACf,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,UAAU,CAAC;QAEzC,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAC9B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,cAAc;QACZ,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,UAAU,CAAC;QACzC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAErB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,UAAU,CAAC,MAAsB,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,EAAE;QACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO;YACL,KAAK,EAAE,QAAQ,CAAC,MAAM;YACtB,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;SAChD,CAAC;IACJ,CAAC;IAED,MAAM,CACJ,UAAkB,EAClB,OAAO,GAAG,KAAK,EACf,MAAsB,EACtB,KAAK,GAAG,EAAE;QAEV,MAAM,cAAc,GAAkB;YACpC,GAAG,MAAM;YACT,WAAW,EAAE,UAAU;YACvB,SAAS,EAAE,OAAO;SACnB,CAAC;QACF,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QAClD,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;IACvE,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAsB,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzE,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAClB,CAAC;IAED,QAAQ;QAMN,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,MAAM,MAAM,GAA2B,EAAE,CAAC;QAE1C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvC,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM;gBAAE,YAAY,EAAE,CAAC;YAC3D,IAAI,KAAK,CAAC,MAAM;gBAAE,WAAW,EAAE,CAAC;YAChC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACvE,CAAC;QAED,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,YAAY;YACrB,MAAM,EAAE,WAAW;YACnB,gBAAgB,EAAE,MAAM;SACzB,CAAC;IACJ,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;IAC5B,CAAC;IAED,0BAA0B;IAE1B,yDAAyD;IACjD,CAAC,WAAW;QAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,KAAK;gBAAE,MAAM,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IAED,+EAA+E;IACvE,eAAe,CAAC,OAAe;QACrC,IAAI,CAAC;YACH,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,MAAsB;QACxC,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAEnD,8CAA8C;QAC9C,IAAI,QAAQ,GAAkB,IAAI,CAAC;QACnC,IAAI,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YAC3C,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACnC,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE;gBAAE,SAAS;YACtF,IAAI,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC,aAAa,KAAK,MAAM,CAAC,aAAa;gBAAE,SAAS;YAC/E,IAAI,MAAM,CAAC,UAAU,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC;gBAClF,SAAS;YACX,IAAI,MAAM,CAAC,UAAU,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC;gBAClF,SAAS;YACX,IAAI,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,MAAM;gBAAE,SAAS;YAC9C,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;gBACvB,IAAI,QAAQ,EAAE,CAAC;oBACb,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;wBAAE,SAAS;gBACtC,CAAC;qBAAM,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;oBAC5B,oDAAoD;oBACpD,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC;wBAAE,SAAS;gBACpD,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC;wBAAE,SAAS;gBACpD,CAAC;YACH,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,8DAA8D;IACtD,QAAQ,CAAC,KAAmB;QAClC,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAClC,iCAAiC;YACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;YAC/B,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YAC9C,uEAAuE;YACvE,sEAAsE;QACxE,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YACvD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACzB,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,OAA+B,EAAE,IAAiB;QACpE,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACvC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;gBAChC,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,uBAAuB,CAAC,IAAU;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC;QAEnC,IAAI,CAAC,SAAS,GAAG,CAAC,GAAgB,EAAE,EAAE;YACpC,IAAI,IAAI,CAAC,iBAAiB,KAAK,GAAG;gBAAE,OAAO;YAC3C,IAAI,GAAG,CAAC,YAAY,EAAE,KAAK,WAAW;gBAAE,OAAO;YAE/C,IAAI,QAAQ,GAAG,GAAG,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC;YACtC,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;gBACrD,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,kBAAkB,CAAC,GAAG,cAAc,CAAC;YACpE,CAAC;YAED,MAAM,KAAK,GAAiB;gBAC1B,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE;gBACjB,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE;gBACpB,aAAa,EAAE,GAAG,CAAC,YAAY,EAAE;gBACjC,aAAa,EAAE,GAAG,CAAC,mBAAmB,EAAE;gBACxC,eAAe,EAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,oBAAoB,CAAC;gBACtE,SAAS,EAAE,QAAQ;gBACnB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;gBACtB,MAAM,EAAE,IAAI;gBACZ,WAAW,EAAE,IAAI;gBACjB,gBAAgB,EAAE,IAAI;gBACtB,SAAS,EAAE,IAAI;gBACf,WAAW,EAAE,IAAI;gBACjB,MAAM,EAAE,KAAK;gBACb,YAAY,EAAE,IAAI;gBAClB,aAAa,EAAE,IAAI,CAAC,YAAY;aACjC,CAAC;YAEF,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACrB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC,CAAC;QAEF,IAAI,CAAC,iBAAiB,GAAG,CAAC,GAAgB,EAAE,EAAE;YAC5C,IAAI,IAAI,CAAC,iBAAiB,KAAK,GAAG;gBAAE,OAAO;YAE3C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAEzB,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;YAChC,IAAI,QAAQ,EAAE,CAAC;gBACb,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACjC,KAAK,CAAC,WAAW,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC;gBAC1C,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,qBAAqB,CAAC,CAAC;gBACrF,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,cAAc,CAAC,CAAC;gBAC9C,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACxD,CAAC;YACD,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC;QACpD,CAAC,CAAC;QAEF,IAAI,CAAC,eAAe,GAAG,CAAC,GAAgB,EAAE,EAAE;YAC1C,IAAI,IAAI,CAAC,iBAAiB,KAAK,GAAG;gBAAE,OAAO;YAE3C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAEzB,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;YACpB,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC,OAAO,EAAE,EAAE,SAAS,IAAI,IAAI,CAAC;YACtD,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC;QACpD,CAAC,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACnD,IAAI,CAAC,EAAE,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IACjD,CAAC;IAEO,cAAc,CAAC,IAAU;QAC/B,IAAI,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACxD,IAAI,IAAI,CAAC,iBAAiB;YAAE,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAChF,IAAI,IAAI,CAAC,eAAe;YAAE,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IAC5E,CAAC;CACF;AAED,0BAA0B;AAE1B,MAAM,SAAS,GAAG,IAAI,OAAO,EAA6B,CAAC;AAE3D,MAAM,UAAU,mBAAmB,CAAC,IAAU,EAAE,UAAmB;IACjE,IAAI,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,QAAQ,GAAG,IAAI,mBAAmB,CAAC,UAAU,CAAC,CAAC;QAC/C,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAU;IACvC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,MAAM,EAAE,CAAC;QAClB,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAU;IACpC,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC"}