@petukhovart/agent-view 0.9.2 → 0.10.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 (62) hide show
  1. package/.claude-plugin/plugin.json +21 -21
  2. package/LICENSE +21 -21
  3. package/README.md +26 -1
  4. package/dist/adapters/browser.d.ts.map +1 -1
  5. package/dist/adapters/browser.js +2 -2
  6. package/dist/adapters/browser.js.map +1 -1
  7. package/dist/adapters/electron.d.ts.map +1 -1
  8. package/dist/adapters/electron.js +2 -2
  9. package/dist/adapters/electron.js.map +1 -1
  10. package/dist/adapters/target-filter.d.ts +11 -0
  11. package/dist/adapters/target-filter.d.ts.map +1 -0
  12. package/dist/adapters/target-filter.js +19 -0
  13. package/dist/adapters/target-filter.js.map +1 -0
  14. package/dist/adapters/tauri.d.ts +2 -5
  15. package/dist/adapters/tauri.d.ts.map +1 -1
  16. package/dist/adapters/tauri.js +2 -13
  17. package/dist/adapters/tauri.js.map +1 -1
  18. package/dist/cdp/network-stream.d.ts +27 -0
  19. package/dist/cdp/network-stream.d.ts.map +1 -0
  20. package/dist/cdp/network-stream.js +336 -0
  21. package/dist/cdp/network-stream.js.map +1 -0
  22. package/dist/cdp/transport.d.ts.map +1 -1
  23. package/dist/cdp/transport.js +167 -8
  24. package/dist/cdp/transport.js.map +1 -1
  25. package/dist/cdp/types.d.ts +187 -0
  26. package/dist/cdp/types.d.ts.map +1 -1
  27. package/dist/cdp/types.js +55 -0
  28. package/dist/cdp/types.js.map +1 -1
  29. package/dist/cli/commands/network.d.ts +19 -0
  30. package/dist/cli/commands/network.d.ts.map +1 -0
  31. package/dist/cli/commands/network.js +55 -0
  32. package/dist/cli/commands/network.js.map +1 -0
  33. package/dist/cli/index.js +23 -1
  34. package/dist/cli/index.js.map +1 -1
  35. package/dist/config/manager.d.ts.map +1 -1
  36. package/dist/config/manager.js +6 -0
  37. package/dist/config/manager.js.map +1 -1
  38. package/dist/config/types.d.ts +8 -0
  39. package/dist/config/types.d.ts.map +1 -1
  40. package/dist/inspectors/network/index.d.ts +19 -0
  41. package/dist/inspectors/network/index.d.ts.map +1 -0
  42. package/dist/inspectors/network/index.js +169 -0
  43. package/dist/inspectors/network/index.js.map +1 -0
  44. package/dist/server/server.d.ts +12 -0
  45. package/dist/server/server.d.ts.map +1 -1
  46. package/dist/server/server.js +193 -18
  47. package/dist/server/server.js.map +1 -1
  48. package/package.json +9 -8
  49. package/skills/verify/SKILL.md +319 -292
  50. package/skills/verify-recipe/SKILL.md +286 -286
  51. package/dist/cdp/console-stream.d.ts +0 -35
  52. package/dist/cdp/console-stream.d.ts.map +0 -1
  53. package/dist/cdp/console-stream.js +0 -103
  54. package/dist/cdp/console-stream.js.map +0 -1
  55. package/dist/inspectors/dom.d.ts +0 -17
  56. package/dist/inspectors/dom.d.ts.map +0 -1
  57. package/dist/inspectors/dom.js +0 -131
  58. package/dist/inspectors/dom.js.map +0 -1
  59. package/dist/inspectors/scene/pixi.d.ts +0 -3
  60. package/dist/inspectors/scene/pixi.d.ts.map +0 -1
  61. package/dist/inspectors/scene/pixi.js +0 -52
  62. package/dist/inspectors/scene/pixi.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/inspectors/network/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAuBtE,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,UAAU,EAAE,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AA8BD,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,mBAAmB,EAAE,EAC9B,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C,iBAAiB,CA+BnB;AAWD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,mBAAmB,EAC1B,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAClC,MAAM,CAuFR"}
@@ -0,0 +1,169 @@
1
+ import { NetworkEntryState, NetworkResourceType, WebSocketOpcode, WebSocketDirection } from '../../cdp/types.js';
2
+ const SENSITIVE_HEADERS = new Set([
3
+ 'authorization',
4
+ 'cookie',
5
+ 'set-cookie',
6
+ 'x-api-key',
7
+ 'x-auth-token',
8
+ 'proxy-authorization',
9
+ 'x-csrf-token',
10
+ 'x-xsrf-token',
11
+ ]);
12
+ const OPCODE_NAMES = {
13
+ [WebSocketOpcode.Text]: 'text',
14
+ [WebSocketOpcode.Binary]: 'binary',
15
+ [WebSocketOpcode.Close]: 'close',
16
+ [WebSocketOpcode.Ping]: 'ping',
17
+ [WebSocketOpcode.Pong]: 'pong',
18
+ [WebSocketOpcode.Continuation]: 'continuation',
19
+ };
20
+ function entryMethod(entry) {
21
+ if (entry.isWebSocket || entry.resourceType === NetworkResourceType.WebSocket)
22
+ return 'WS';
23
+ if (entry.isEventSource || entry.resourceType === NetworkResourceType.EventSource)
24
+ return 'SSE';
25
+ return entry.method ?? 'GET';
26
+ }
27
+ function entryStatus(entry) {
28
+ if (entry.state === NetworkEntryState.Complete)
29
+ return String(entry.status ?? '');
30
+ if (entry.state === NetworkEntryState.Pending)
31
+ return 'pending';
32
+ return 'FAILED';
33
+ }
34
+ function entryTiming(entry) {
35
+ const isWs = entry.isWebSocket || entry.resourceType === NetworkResourceType.WebSocket;
36
+ const isSse = entry.isEventSource || entry.resourceType === NetworkResourceType.EventSource;
37
+ if (isWs || isSse) {
38
+ const count = entry.frames?.length ?? 0;
39
+ return `(${count} frames)`;
40
+ }
41
+ if (entry.state === NetworkEntryState.Complete && entry.totalMs !== undefined) {
42
+ return `${entry.totalMs}ms`;
43
+ }
44
+ return '';
45
+ }
46
+ export function formatNetworkList(entries, opts) {
47
+ if (entries.length === 0)
48
+ return { text: '(no network activity)', refs: [], nextRef: opts.startRef };
49
+ const refs = entries.map((entry, i) => ({
50
+ ref: opts.startRef + i,
51
+ targetId: entry.targetId,
52
+ requestId: entry.requestId,
53
+ }));
54
+ const nextRef = opts.startRef + entries.length;
55
+ const allLines = entries.map((entry, i) => {
56
+ const ref = opts.startRef + i;
57
+ const method = entryMethod(entry);
58
+ const status = entryStatus(entry);
59
+ const type = entry.resourceType;
60
+ const timing = entryTiming(entry);
61
+ const parts = [`[req=${ref}]`, method, status, type, entry.url];
62
+ if (timing)
63
+ parts.push(timing);
64
+ return parts.join(' ');
65
+ });
66
+ let text;
67
+ if (opts.maxLines !== undefined && allLines.length > opts.maxLines) {
68
+ const visible = allLines.slice(0, opts.maxLines - 1);
69
+ const hidden = allLines.length - visible.length;
70
+ text = [...visible, `… ${hidden} more requests`].join('\n');
71
+ }
72
+ else {
73
+ text = allLines.join('\n');
74
+ }
75
+ return { text, refs, nextRef };
76
+ }
77
+ function redactHeaders(headers, rawHeaders) {
78
+ return Object.entries(headers)
79
+ .map(([k, v]) => {
80
+ const val = !rawHeaders && SENSITIVE_HEADERS.has(k.toLowerCase()) ? '[redacted]' : v;
81
+ return ` ${k}: ${val}`;
82
+ })
83
+ .join('\n');
84
+ }
85
+ export function formatNetworkDetail(entry, opts = {}) {
86
+ const rawHeaders = opts.rawHeaders ?? false;
87
+ const isWs = entry.isWebSocket || entry.resourceType === NetworkResourceType.WebSocket;
88
+ const isSse = entry.isEventSource || entry.resourceType === NetworkResourceType.EventSource;
89
+ const lines = [];
90
+ if (isWs || isSse) {
91
+ const proto = isWs ? 'WS' : 'SSE';
92
+ lines.push(`${proto} ${entry.url}`);
93
+ if (entry.state === NetworkEntryState.Failed) {
94
+ lines.push(`FAILED${entry.errorText ? ': ' + entry.errorText : ''}`);
95
+ }
96
+ else {
97
+ lines.push(entry.state);
98
+ }
99
+ if (entry.frames && entry.frames.length > 0) {
100
+ for (const frame of entry.frames) {
101
+ const arrow = frame.direction === WebSocketDirection.Sent ? '↑' : '↓';
102
+ const opName = OPCODE_NAMES[frame.opcode] ?? String(frame.opcode);
103
+ const time = new Date(frame.ts).toISOString().slice(11, 19);
104
+ let payload;
105
+ if (frame.terminal === 'closed') {
106
+ payload = 'closed';
107
+ }
108
+ else if (frame.terminal === 'error') {
109
+ payload = `error: ${frame.errorMessage ?? ''}`;
110
+ }
111
+ else if (frame.binary) {
112
+ payload = `[binary ${frame.size}B]`;
113
+ }
114
+ else {
115
+ payload = frame.payload ?? '';
116
+ }
117
+ lines.push(`${arrow} ${opName} ${frame.size}B ${time} ${payload}`);
118
+ }
119
+ }
120
+ return lines.join('\n');
121
+ }
122
+ lines.push(`${entry.method ?? 'GET'} ${entry.url}`);
123
+ if (entry.state === NetworkEntryState.Pending) {
124
+ lines.push('pending');
125
+ }
126
+ else if (entry.state === NetworkEntryState.Failed) {
127
+ lines.push(`FAILED${entry.errorText ? ': ' + entry.errorText : ''}`);
128
+ }
129
+ else {
130
+ lines.push(`→ ${entry.status ?? ''} ${entry.statusText ?? ''}`.trimEnd());
131
+ }
132
+ const timingParts = [];
133
+ if (entry.ttfbMs !== undefined)
134
+ timingParts.push(`ttfb ${entry.ttfbMs}ms`);
135
+ if (entry.totalMs !== undefined)
136
+ timingParts.push(`total ${entry.totalMs}ms`);
137
+ if (timingParts.length > 0)
138
+ lines.push(`timing: ${timingParts.join(' ')}`);
139
+ if (entry.requestHeaders && Object.keys(entry.requestHeaders).length > 0) {
140
+ lines.push('request headers:');
141
+ lines.push(redactHeaders(entry.requestHeaders, rawHeaders));
142
+ }
143
+ if (entry.responseHeaders && Object.keys(entry.responseHeaders).length > 0) {
144
+ lines.push('response headers:');
145
+ lines.push(redactHeaders(entry.responseHeaders, rawHeaders));
146
+ }
147
+ if (entry.requestBody !== undefined) {
148
+ lines.push('request body:');
149
+ const body = entry.requestBody;
150
+ if (body.length > 4096) {
151
+ lines.push(body.slice(0, 4096));
152
+ lines.push(`… ${body.length - 4096} more bytes`);
153
+ }
154
+ else {
155
+ lines.push(body);
156
+ }
157
+ }
158
+ if (entry.responseBody !== undefined) {
159
+ lines.push('response body:');
160
+ if (entry.responseBody.binary) {
161
+ lines.push(`[binary ${entry.responseBody.size} bytes]`);
162
+ }
163
+ else {
164
+ lines.push(entry.responseBody.text);
165
+ }
166
+ }
167
+ return lines.join('\n');
168
+ }
169
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/inspectors/network/index.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,9 @@ export declare class AgentViewServer {
19
19
  private domTextCache;
20
20
  private axTreeCache;
21
21
  private consoleStream;
22
+ private networkStream;
23
+ private networkRefs;
24
+ private networkNextRef;
22
25
  private token;
23
26
  private activeWatches;
24
27
  private readonly handlers;
@@ -34,6 +37,12 @@ export declare class AgentViewServer {
34
37
  private getRuntimeSession;
35
38
  private handleDiscover;
36
39
  private handleLaunch;
40
+ /**
41
+ * Connect+attach NetworkStream to every page/iframe target. Idempotent per target.
42
+ * Recreates the stream with config-tuned capacity/captureBody while it is still empty,
43
+ * mirroring the consoleStream pattern.
44
+ */
45
+ private ensureNetworkAttached;
37
46
  private handleDom;
38
47
  private findByFilter;
39
48
  private handleClick;
@@ -50,6 +59,9 @@ export declare class AgentViewServer {
50
59
  private handleEval;
51
60
  private handleWatchStreaming;
52
61
  private handleConsole;
62
+ private handleNetwork;
63
+ private renderNetworkList;
64
+ private followNetwork;
53
65
  private handleStop;
54
66
  private shutdown;
55
67
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAaA,OAAO,EAKL,KAAK,WAAW,EAEhB,KAAK,UAAU,EAGhB,MAAM,iBAAiB,CAAA;AAmDxB,KAAK,YAAY,GACb;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtC,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIzG;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA6B5F;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAaxD;AAMD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,aAAa,CAA0B;IAE/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAe2D;IAEpF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA0C;IAC5E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2F;IAEnH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5B,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,YAAY;YAmBN,cAAc;YAwCd,aAAa;YAMb,aAAa;YA0Bb,cAAc;YAad,iBAAiB;YAgBjB,cAAc;YASd,YAAY;YA+BZ,SAAS;YAmDT,YAAY;YAqGZ,WAAW;YA6CX,UAAU;YAwBV,gBAAgB;YA0BhB,UAAU;YAqCV,UAAU;YA+BV,uBAAuB;YAYvB,gBAAgB;YAuBhB,WAAW;YA2CX,UAAU;YAsCV,aAAa;YASb,aAAa;YA2Bb,UAAU;YAwCV,oBAAoB;YAsFpB,aAAa;YA2Hb,UAAU;YAKV,QAAQ;CAgBvB;AAID,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAOjG"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAcA,OAAO,EAKL,KAAK,WAAW,EAEhB,KAAK,UAAU,EAGhB,MAAM,iBAAiB,CAAA;AAyDxB,KAAK,YAAY,GACb;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtC,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIzG;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA6B5F;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAaxD;AAMD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,WAAW,CAA6D;IAChF,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,aAAa,CAA0B;IAE/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAgB2D;IAEpF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA0C;IAC5E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2F;IAEnH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5B,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,YAAY;YAmBN,cAAc;YAwCd,aAAa;YAMb,aAAa;YA0Bb,cAAc;YAad,iBAAiB;YAgBjB,cAAc;YASd,YAAY;IAmC1B;;;;OAIG;YACW,qBAAqB;YAiBrB,SAAS;YAmDT,YAAY;YAqGZ,WAAW;YA6CX,UAAU;YAwBV,gBAAgB;YA0BhB,UAAU;YAqCV,UAAU;YA+BV,uBAAuB;YAYvB,gBAAgB;YAuBhB,WAAW;YA2CX,UAAU;YAsCV,aAAa;YASb,aAAa;YA2Bb,UAAU;YAwCV,oBAAoB;YAsFpB,aAAa;YA2Hb,aAAa;IA0D3B,OAAO,CAAC,iBAAiB;YAQX,aAAa;YA2Cb,UAAU;YAKV,QAAQ;CAiBvB;AAID,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAOjG"}
@@ -5,6 +5,7 @@ import { homedir, tmpdir } from 'node:os';
5
5
  import { join, resolve } from 'node:path';
6
6
  import { mkdirSync } from 'node:fs';
7
7
  import { getAdapter } from '../adapters/registry.js';
8
+ import { isAppTarget } from '../adapters/target-filter.js';
8
9
  import { formatAccessibilityTree, countAccessibilityNodes, diffDomText } from '../inspectors/dom/index.js';
9
10
  import { getSceneGraph, getRawScene, diffScenes } from '../inspectors/scene/index.js';
10
11
  import { RefStore } from './ref-store.js';
@@ -14,6 +15,9 @@ import { RuntimeType, WebGLEngine, ServerErrorCode } from '../types.js';
14
15
  import { TargetType, ConsoleLevel, EvaluationError, MouseButton, } from '../cdp/types.js';
15
16
  import { listSupportedTargets, connectToRuntime } from '../cdp/transport.js';
16
17
  import { ConsoleStream } from '../cdp/_tests/console-stream.js';
18
+ import { NetworkStream } from '../cdp/network-stream.js';
19
+ import { formatNetworkList, formatNetworkDetail } from '../inspectors/network/index.js';
20
+ import { NetworkResourceType } from '../cdp/types.js';
17
21
  import { AxTreeCache } from '../cdp/ax-cache.js';
18
22
  import { WatchSession } from './watch-session.js';
19
23
  import { StopReason, WATCH_MIN_INTERVAL_MS } from '../inspectors/watch/index.js';
@@ -27,6 +31,9 @@ const TOKEN_DIR = join(homedir(), '.agent-view');
27
31
  const TOKEN_PATH = join(TOKEN_DIR, 'token');
28
32
  const EVAL_OUTPUT_CAP = 64 * 1024;
29
33
  const DEFAULT_CONSOLE_TARGETS = [TargetType.Page, TargetType.SharedWorker, TargetType.ServiceWorker];
34
+ const DEFAULT_NETWORK_BUFFER = 200;
35
+ const DEFAULT_NETWORK_MAX_LINES = 50;
36
+ const NETWORK_PAGE_TARGETS = new Set([TargetType.Page, TargetType.Iframe]);
30
37
  const RUNTIME_ONLY_TARGETS = new Set([
31
38
  TargetType.SharedWorker,
32
39
  TargetType.ServiceWorker,
@@ -64,23 +71,23 @@ export function resolveDepth(filter, explicit) {
64
71
  }
65
72
  export async function textContentFallback(conn, filter) {
66
73
  const safeFilter = JSON.stringify(filter);
67
- const js = `(() => {
68
- const q = ${safeFilter};
69
- const results = [];
70
- for (const el of document.querySelectorAll('body *')) {
71
- if (results.length >= 5) break;
72
- const directText = Array.from(el.childNodes)
73
- .filter(n => n.nodeType === Node.TEXT_NODE)
74
- .map(n => n.textContent.trim())
75
- .join(' ');
76
- if (directText.toLowerCase().includes(q.toLowerCase()) && el.offsetParent !== null) {
77
- const id = el.id ? '#' + el.id : '';
78
- const cls = el.className && typeof el.className === 'string' && el.className.trim()
79
- ? '.' + el.className.trim().split(/\\s+/)[0] : '';
80
- results.push(el.tagName.toLowerCase() + id + cls);
81
- }
82
- }
83
- return results.length ? results.join(', ') : null;
74
+ const js = `(() => {
75
+ const q = ${safeFilter};
76
+ const results = [];
77
+ for (const el of document.querySelectorAll('body *')) {
78
+ if (results.length >= 5) break;
79
+ const directText = Array.from(el.childNodes)
80
+ .filter(n => n.nodeType === Node.TEXT_NODE)
81
+ .map(n => n.textContent.trim())
82
+ .join(' ');
83
+ if (directText.toLowerCase().includes(q.toLowerCase()) && el.offsetParent !== null) {
84
+ const id = el.id ? '#' + el.id : '';
85
+ const cls = el.className && typeof el.className === 'string' && el.className.trim()
86
+ ? '.' + el.className.trim().split(/\\s+/)[0] : '';
87
+ results.push(el.tagName.toLowerCase() + id + cls);
88
+ }
89
+ }
90
+ return results.length ? results.join(', ') : null;
84
91
  })()`;
85
92
  const result = await conn.evaluate(js);
86
93
  if (!result || typeof result !== 'string') {
@@ -113,6 +120,9 @@ export class AgentViewServer {
113
120
  domTextCache = new Map();
114
121
  axTreeCache = new AxTreeCache();
115
122
  consoleStream = new ConsoleStream();
123
+ networkStream = new NetworkStream();
124
+ networkRefs = new Map();
125
+ networkNextRef = 1;
116
126
  token = '';
117
127
  activeWatches = new Set();
118
128
  handlers = {
@@ -129,6 +139,7 @@ export class AgentViewServer {
129
139
  targets: (req) => this.handleTargets(req),
130
140
  eval: (req) => this.handleEval(req),
131
141
  console: (req) => this.handleConsole(req),
142
+ network: (req) => this.handleNetwork(req),
132
143
  stop: () => this.handleStop(),
133
144
  };
134
145
  streamingCommands = new Set(['watch']);
@@ -287,6 +298,7 @@ export class AgentViewServer {
287
298
  return { ok: false, error: 'Launch command does not match project config' };
288
299
  }
289
300
  if (await isRunning(req.port)) {
301
+ await this.ensureNetworkAttached(req, config).catch(() => { });
290
302
  return { ok: true, data: 'Application already running' };
291
303
  }
292
304
  try {
@@ -303,8 +315,34 @@ export class AgentViewServer {
303
315
  }
304
316
  throw err;
305
317
  }
318
+ // Eager attach (ADR 0002): start capture the moment the app is ready, so page-load
319
+ // traffic is not missed. Best-effort — a launch must not fail on a capture hiccup.
320
+ await this.ensureNetworkAttached(req, config).catch(() => { });
306
321
  return { ok: true, data: 'Application launched and ready' };
307
322
  }
323
+ /**
324
+ * Connect+attach NetworkStream to every page/iframe target. Idempotent per target.
325
+ * Recreates the stream with config-tuned capacity/captureBody while it is still empty,
326
+ * mirroring the consoleStream pattern.
327
+ */
328
+ async ensureNetworkAttached(req, config) {
329
+ if (this.networkStream.attachedCount === 0) {
330
+ this.networkStream = new NetworkStream({
331
+ capacity: config?.networkBufferSize ?? DEFAULT_NETWORK_BUFFER,
332
+ captureBody: config?.captureBody ?? false,
333
+ });
334
+ }
335
+ const all = await listSupportedTargets(req.port);
336
+ for (const t of all) {
337
+ if (!NETWORK_PAGE_TARGETS.has(t.type))
338
+ continue;
339
+ try {
340
+ const session = await this.getPageSession(req, t.id);
341
+ await this.networkStream.attach(session);
342
+ }
343
+ catch { /* a single unreachable target shouldn't abort capture */ }
344
+ }
345
+ }
308
346
  async handleDom(req) {
309
347
  const { targetId } = await this.resolveWindow(req);
310
348
  const conn = await this.getPageSession(req, targetId);
@@ -689,7 +727,7 @@ export class AgentViewServer {
689
727
  }
690
728
  return found;
691
729
  }
692
- const firstPage = allTargets.find(t => t.type === TargetType.Page);
730
+ const firstPage = allTargets.find(isAppTarget) ?? allTargets.find(t => t.type === TargetType.Page);
693
731
  if (!firstPage)
694
732
  throw new Error('No page targets found.');
695
733
  return firstPage;
@@ -926,6 +964,97 @@ export class AgentViewServer {
926
964
  });
927
965
  return { ok: true, data: formatConsoleMessages(messages) };
928
966
  }
967
+ async handleNetwork(req) {
968
+ const cwd = argStr(req.args, 'cwd');
969
+ const config = cwd ? readConfig(resolve(cwd)) : null;
970
+ await this.ensureNetworkAttached(req, config);
971
+ let resolvedTargetId;
972
+ const targetQuery = argStr(req.args, 'target') ?? argStr(req.args, 'window');
973
+ if (targetQuery) {
974
+ const all = await listSupportedTargets(req.port);
975
+ const resolved = findTargetByIdOrSubstring(all, targetQuery);
976
+ if (!resolved) {
977
+ return { ok: false, error: `Target not found: "${targetQuery}". Run \`agent-view targets\` for the full list.` };
978
+ }
979
+ resolvedTargetId = resolved.id;
980
+ }
981
+ const reqN = argNum(req.args, 'req');
982
+ if (reqN !== undefined) {
983
+ const ref = this.networkRefs.get(reqN);
984
+ if (!ref) {
985
+ return { ok: false, error: `Invalid req: ${reqN}. Run \`agent-view network\` to get fresh handles.` };
986
+ }
987
+ const entry = this.networkStream.getEntry(ref.targetId, ref.requestId);
988
+ if (!entry) {
989
+ return { ok: false, error: `Request ${reqN} is no longer buffered (evicted or app restarted).` };
990
+ }
991
+ return { ok: true, data: formatNetworkDetail(entry, { rawHeaders: argBool(req.args, 'rawHeaders') ?? false }) };
992
+ }
993
+ if (argBool(req.args, 'clear')) {
994
+ this.networkStream.clear(resolvedTargetId);
995
+ return { ok: true, data: 'Network buffer cleared' };
996
+ }
997
+ const filter = {
998
+ targetId: resolvedTargetId,
999
+ since: argNum(req.args, 'since'),
1000
+ url: argStr(req.args, 'url'),
1001
+ method: parseMethodFilter(argStrArray(req.args, 'method')),
1002
+ type: parseTypeFilter(argStrArray(req.args, 'type')),
1003
+ ...parseStatusFilter(argStrArray(req.args, 'status')),
1004
+ };
1005
+ const maxLines = argNum(req.args, 'maxLines') ?? DEFAULT_NETWORK_MAX_LINES;
1006
+ const follow = argBool(req.args, 'follow') ?? false;
1007
+ const untilPattern = argStr(req.args, 'until');
1008
+ if (untilPattern && !follow) {
1009
+ return { ok: false, error: '--until requires --follow' };
1010
+ }
1011
+ if (follow) {
1012
+ return this.followNetwork(req, filter, maxLines, untilPattern);
1013
+ }
1014
+ const entries = this.networkStream.drain(filter);
1015
+ return { ok: true, data: this.renderNetworkList(entries, maxLines) };
1016
+ }
1017
+ renderNetworkList(entries, maxLines) {
1018
+ const { text, refs, nextRef } = formatNetworkList(entries, { startRef: this.networkNextRef, maxLines });
1019
+ this.networkRefs.clear();
1020
+ for (const r of refs)
1021
+ this.networkRefs.set(r.ref, { targetId: r.targetId, requestId: r.requestId });
1022
+ this.networkNextRef = nextRef;
1023
+ return text;
1024
+ }
1025
+ async followNetwork(req, filter, maxLines, untilPattern) {
1026
+ const timeoutSec = argNum(req.args, 'timeout') ?? 10;
1027
+ const matcher = untilPattern ? buildMatcher(untilPattern) : null;
1028
+ const matchText = (e) => `${e.method ?? (e.isWebSocket ? 'WS' : e.isEventSource ? 'SSE' : '')} ${e.status ?? e.state} ${e.url}`;
1029
+ if (matcher) {
1030
+ const pre = this.networkStream.drain(filter);
1031
+ const hit = pre.findIndex(e => matcher(matchText(e)));
1032
+ if (hit !== -1)
1033
+ return { ok: true, data: this.renderNetworkList(pre.slice(0, hit + 1), maxLines) };
1034
+ }
1035
+ const matched = await new Promise((resolveFollow) => {
1036
+ const dispose = matcher
1037
+ ? this.networkStream.subscribe(() => {
1038
+ const cur = this.networkStream.drain(filter);
1039
+ if (cur.some(e => matcher(matchText(e)))) {
1040
+ clearTimeout(timer);
1041
+ dispose();
1042
+ resolveFollow(true);
1043
+ }
1044
+ })
1045
+ : () => { };
1046
+ const timer = setTimeout(() => {
1047
+ dispose();
1048
+ resolveFollow(false);
1049
+ }, timeoutSec * 1000);
1050
+ timer.unref?.();
1051
+ });
1052
+ if (matcher && !matched) {
1053
+ return { ok: false, error: `Timeout: pattern not seen in ${timeoutSec}s` };
1054
+ }
1055
+ const entries = this.networkStream.drain(filter);
1056
+ return { ok: true, data: this.renderNetworkList(entries, maxLines) };
1057
+ }
929
1058
  async handleStop() {
930
1059
  setTimeout(() => this.shutdown(), 100);
931
1060
  return { ok: true, data: 'Server stopping' };
@@ -938,6 +1067,7 @@ export class AgentViewServer {
938
1067
  }
939
1068
  await unlink(TOKEN_PATH).catch(() => { });
940
1069
  this.consoleStream.detach();
1070
+ this.networkStream.detach();
941
1071
  for (const cached of this.connections.values()) {
942
1072
  try {
943
1073
  await cached.session.close();
@@ -974,6 +1104,51 @@ function parseLevelFilter(levels) {
974
1104
  }
975
1105
  return set.size > 0 ? set : undefined;
976
1106
  }
1107
+ function parseMethodFilter(methods) {
1108
+ if (!methods || methods.length === 0)
1109
+ return undefined;
1110
+ const set = new Set(methods.map(m => m.trim().toUpperCase()).filter(Boolean));
1111
+ return set.size > 0 ? set : undefined;
1112
+ }
1113
+ function parseTypeFilter(types) {
1114
+ if (!types || types.length === 0)
1115
+ return undefined;
1116
+ const valid = Object.values(NetworkResourceType);
1117
+ const set = new Set();
1118
+ for (const t of types) {
1119
+ const lower = t.trim().toLowerCase();
1120
+ if (valid.includes(lower))
1121
+ set.add(lower);
1122
+ }
1123
+ return set.size > 0 ? set : undefined;
1124
+ }
1125
+ function parseStatusFilter(tokens) {
1126
+ if (!tokens || tokens.length === 0)
1127
+ return {};
1128
+ const classes = new Set();
1129
+ const codes = new Set();
1130
+ let includeFailed = false;
1131
+ for (const tok of tokens) {
1132
+ const t = tok.trim().toLowerCase();
1133
+ if (t === 'failed' || t === 'fail') {
1134
+ includeFailed = true;
1135
+ continue;
1136
+ }
1137
+ const classMatch = /^([1-5])xx$/.exec(t);
1138
+ if (classMatch) {
1139
+ classes.add(Number(classMatch[1]));
1140
+ continue;
1141
+ }
1142
+ const n = Number(t);
1143
+ if (Number.isInteger(n) && n >= 100 && n <= 599)
1144
+ codes.add(n);
1145
+ }
1146
+ return {
1147
+ statusClasses: classes.size > 0 ? classes : undefined,
1148
+ statusCodes: codes.size > 0 ? codes : undefined,
1149
+ includeFailed: includeFailed ? true : undefined,
1150
+ };
1151
+ }
977
1152
  function buildMatcher(pattern) {
978
1153
  const regexMatch = /^\/(.+)\/([gimsuy]*)$/.exec(pattern);
979
1154
  if (regexMatch) {