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/.claude/skills/agent-dbg/SKILL.md +44 -14
- package/.claude/skills/agent-dbg/references/commands.md +4 -0
- package/README.md +65 -29
- package/dist/main.js +362 -98
- package/package.json +3 -3
- package/src/cdp/client.ts +67 -6
- package/src/cdp/jsc-client.ts +58 -0
- package/src/cdp/jsc-protocol.d.ts +2807 -0
- package/src/daemon/adapters/bun-adapter.ts +190 -0
- package/src/daemon/adapters/index.ts +13 -0
- package/src/daemon/adapters/node-adapter.ts +121 -0
- package/src/daemon/runtime-adapter.ts +50 -0
- package/src/daemon/session-blackbox.ts +2 -6
- package/src/daemon/session-breakpoints.ts +64 -53
- package/src/daemon/session-inspection.ts +2 -2
- package/src/daemon/session-state.ts +1 -1
- package/src/daemon/session.ts +46 -44
- package/src/formatter/source.ts +6 -2
- package/tests/fixtures/bun-simple.js +12 -0
- package/tests/integration/bun-launch.test.ts +135 -0
- package/tests/unit/cdp-client.test.ts +134 -10
- package/tests/unit/jsc-client.test.ts +165 -0
- package/demo/DEMO.md +0 -71
- package/demo/order-processor.js +0 -35
- package/tests/fixtures/dap/hello +0 -0
- package/tests/fixtures/dap/hello.dSYM/Contents/Info.plist +0 -20
- package/tests/fixtures/dap/hello.dSYM/Contents/Resources/DWARF/hello +0 -0
- package/tests/fixtures/dap/hello.dSYM/Contents/Resources/Relocations/aarch64/hello.yml +0 -5
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
+
}
|