agent-dbg 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/cdp/client.ts CHANGED
@@ -54,6 +54,14 @@ export class CdpClient {
54
54
  });
55
55
  }
56
56
 
57
+ /**
58
+ * Send an untyped CDP/WebKit command. Use this for protocol methods
59
+ * not in the devtools-protocol typings (e.g. WebKit Inspector commands).
60
+ */
61
+ async sendRaw(method: string, params?: Record<string, unknown>): Promise<unknown> {
62
+ return this.send(method as CdpCommand, params as never);
63
+ }
64
+
57
65
  async send<T extends CdpCommand>(
58
66
  method: T,
59
67
  ...params: ProtocolMapping.Commands[T]["paramsType"]
@@ -111,13 +119,65 @@ export class CdpClient {
111
119
  }
112
120
  }
113
121
 
122
+ /**
123
+ * Wait for a single occurrence of a CDP event.
124
+ * Resolves with the event params, rejects on timeout.
125
+ */
126
+ waitFor<T extends CdpEventName>(
127
+ event: T,
128
+ opts?: { timeoutMs?: number; filter?: (...args: ProtocolMapping.Events[T]) => boolean },
129
+ ): Promise<ProtocolMapping.Events[T][0]>;
130
+ waitFor(
131
+ event: string,
132
+ opts?: { timeoutMs?: number; filter?: (params: unknown) => boolean },
133
+ ): Promise<unknown>;
134
+ // biome-ignore lint/suspicious/noExplicitAny: Implementation signature accepts both typed and untyped filter functions
135
+ waitFor(event: string, opts?: { timeoutMs?: number; filter?: (...args: any[]) => boolean }): Promise<unknown> {
136
+ const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
137
+ const filter = opts?.filter;
138
+
139
+ return new Promise<unknown>((resolve, reject) => {
140
+ const handler: AnyHandler = (params: unknown) => {
141
+ if (filter && !filter(params)) return;
142
+ cleanup();
143
+ resolve(params);
144
+ };
145
+
146
+ const timer = setTimeout(() => {
147
+ cleanup();
148
+ reject(new Error(`waitFor timed out: ${event} (after ${timeoutMs}ms)`));
149
+ }, timeoutMs);
150
+
151
+ const cleanup = () => {
152
+ clearTimeout(timer);
153
+ this.off(event, handler);
154
+ };
155
+
156
+ this.on(event, handler);
157
+ });
158
+ }
159
+
160
+ /** Set of successfully enabled CDP domain names (e.g. "Debugger", "Runtime") */
161
+ enabledDomains = new Set<string>();
162
+
114
163
  async enableDomains(): Promise<void> {
115
- await Promise.all([
116
- this.send("Debugger.enable"),
117
- this.send("Runtime.enable"),
118
- this.send("Profiler.enable"),
119
- this.send("HeapProfiler.enable"),
120
- ]);
164
+ // Required domains — these must succeed
165
+ await Promise.all([this.send("Debugger.enable"), this.send("Runtime.enable")]);
166
+ this.enabledDomains.add("Debugger");
167
+ this.enabledDomains.add("Runtime");
168
+
169
+ // Optional domains — may not be supported (e.g. Bun/JavaScriptCore)
170
+ const optional = ["Profiler", "HeapProfiler"] as const;
171
+ await Promise.allSettled(
172
+ optional.map(async (domain) => {
173
+ try {
174
+ await this.send(`${domain}.enable` as any);
175
+ this.enabledDomains.add(domain);
176
+ } catch {
177
+ // Domain not supported — skip silently
178
+ }
179
+ }),
180
+ );
121
181
  }
122
182
 
123
183
  async runIfWaitingForDebugger(): Promise<void> {
@@ -183,6 +243,7 @@ export class CdpClient {
183
243
  const response = parsed as CdpResponse;
184
244
  const method = this.sentMethods.get(response.id) ?? "unknown";
185
245
  this.sentMethods.delete(response.id);
246
+
186
247
  this.logger?.logResponse(response.id, method, response.result, response.error);
187
248
 
188
249
  const pending = this.pending.get(response.id);
@@ -0,0 +1,58 @@
1
+ import type { CdpClient } from "./client.ts";
2
+ import type { JSC } from "./jsc-protocol.js";
3
+
4
+ type JscCommand = keyof JSC.RequestMap & keyof JSC.ResponseMap;
5
+ type JscEvent = keyof JSC.EventMap;
6
+
7
+ /**
8
+ * Typed wrapper around CdpClient for WebKit Inspector Protocol (JSC) commands.
9
+ * Exposes `.cdp` for shared CDP commands (Debugger.resume, Runtime.evaluate, etc.).
10
+ */
11
+ export class JscClient {
12
+ constructor(readonly cdp: CdpClient) {}
13
+
14
+ async send<T extends JscCommand>(
15
+ method: T,
16
+ ...args: Record<string, never> extends JSC.RequestMap[T]
17
+ ? [JSC.RequestMap[T]?]
18
+ : [JSC.RequestMap[T]]
19
+ ): Promise<JSC.ResponseMap[T]> {
20
+ const params = args[0] as Record<string, unknown> | undefined;
21
+ return this.cdp.sendRaw(method, params) as Promise<JSC.ResponseMap[T]>;
22
+ }
23
+
24
+ on<T extends JscEvent>(event: T, handler: (params: JSC.EventMap[T]) => void): void;
25
+ on(event: string, handler: (params: unknown) => void): void;
26
+ on(event: string, handler: (params: unknown) => void): void {
27
+ this.cdp.on(event, handler);
28
+ }
29
+
30
+ off<T extends JscEvent>(event: T, handler: (params: JSC.EventMap[T]) => void): void;
31
+ off(event: string, handler: (params: unknown) => void): void;
32
+ off(event: string, handler: (params: unknown) => void): void {
33
+ this.cdp.off(event, handler);
34
+ }
35
+
36
+ waitFor<T extends JscEvent>(
37
+ event: T,
38
+ opts?: { timeoutMs?: number; filter?: (params: JSC.EventMap[T]) => boolean },
39
+ ): Promise<JSC.EventMap[T]>;
40
+ waitFor(
41
+ event: string,
42
+ opts?: { timeoutMs?: number; filter?: (params: unknown) => boolean },
43
+ ): Promise<unknown>;
44
+ waitFor(
45
+ event: string,
46
+ opts?: { timeoutMs?: number; filter?: (params: unknown) => boolean },
47
+ ): Promise<unknown> {
48
+ return this.cdp.waitFor(event, opts);
49
+ }
50
+
51
+ disconnect(): void {
52
+ this.cdp.disconnect();
53
+ }
54
+
55
+ get connected(): boolean {
56
+ return this.cdp.connected;
57
+ }
58
+ }