agent-dbg 0.1.3 → 0.1.4
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/settings.local.json +27 -1
- package/TODO.md +299 -0
- package/demo/DEMO.md +71 -0
- package/demo/order-processor.js +35 -0
- package/dist/main.js +1250 -187
- package/package.json +3 -1
- package/src/commands/attach.ts +2 -1
- package/src/commands/break-fn.ts +41 -0
- package/src/commands/launch.ts +2 -1
- package/src/daemon/client.ts +1 -1
- package/src/daemon/entry.ts +83 -45
- package/src/daemon/server.ts +67 -34
- package/src/daemon/session-breakpoints.ts +2 -1
- package/src/daemon/session-mutation.ts +1 -0
- package/src/daemon/session.ts +7 -5
- package/src/daemon/spawn.ts +21 -5
- package/src/dap/client.ts +252 -0
- package/src/dap/session.ts +1151 -0
- package/src/main.ts +1 -0
- package/src/protocol/messages.ts +12 -0
- package/tests/fixtures/dap/hello +0 -0
- package/tests/fixtures/dap/hello.c +8 -0
- package/tests/fixtures/dap/hello.dSYM/Contents/Info.plist +20 -0
- package/tests/fixtures/dap/hello.dSYM/Contents/Resources/DWARF/hello +0 -0
- package/tests/fixtures/dap/hello.dSYM/Contents/Resources/Relocations/aarch64/hello.yml +5 -0
- package/tests/fixtures/hotpatch-active-fn.js +7 -0
- package/tests/integration/daemon-logging.test.ts +8 -9
- package/tests/integration/mutation.test.ts +33 -0
- package/tests/unit/daemon-logger.test.ts +2 -2
- package/bun.lock +0 -60
package/dist/main.js
CHANGED
|
@@ -12,6 +12,1049 @@ var __export = (target, all) => {
|
|
|
12
12
|
};
|
|
13
13
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
14
14
|
|
|
15
|
+
// src/refs/ref-table.ts
|
|
16
|
+
class RefTable {
|
|
17
|
+
entries = new Map;
|
|
18
|
+
counters = {
|
|
19
|
+
v: 1,
|
|
20
|
+
f: 0,
|
|
21
|
+
o: 1,
|
|
22
|
+
BP: 1,
|
|
23
|
+
LP: 1,
|
|
24
|
+
HS: 1
|
|
25
|
+
};
|
|
26
|
+
addVar(remoteId, name, meta) {
|
|
27
|
+
return this.add("v", remoteId, name, meta);
|
|
28
|
+
}
|
|
29
|
+
addFrame(remoteId, name, meta) {
|
|
30
|
+
return this.add("f", remoteId, name, meta);
|
|
31
|
+
}
|
|
32
|
+
addObject(remoteId, name, meta) {
|
|
33
|
+
return this.add("o", remoteId, name, meta);
|
|
34
|
+
}
|
|
35
|
+
addBreakpoint(remoteId, meta) {
|
|
36
|
+
return this.add("BP", remoteId, undefined, meta);
|
|
37
|
+
}
|
|
38
|
+
addLogpoint(remoteId, meta) {
|
|
39
|
+
return this.add("LP", remoteId, undefined, meta);
|
|
40
|
+
}
|
|
41
|
+
addHeapSnapshot(remoteId, meta) {
|
|
42
|
+
return this.add("HS", remoteId, undefined, meta);
|
|
43
|
+
}
|
|
44
|
+
resolve(ref) {
|
|
45
|
+
return this.entries.get(ref);
|
|
46
|
+
}
|
|
47
|
+
resolveId(ref) {
|
|
48
|
+
return this.entries.get(ref)?.remoteId;
|
|
49
|
+
}
|
|
50
|
+
clearVolatile() {
|
|
51
|
+
for (const [key, entry] of this.entries) {
|
|
52
|
+
if (entry.type === "v" || entry.type === "f") {
|
|
53
|
+
this.entries.delete(key);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
this.counters.v = 1;
|
|
57
|
+
this.counters.f = 0;
|
|
58
|
+
}
|
|
59
|
+
clearObjects() {
|
|
60
|
+
for (const [key, entry] of this.entries) {
|
|
61
|
+
if (entry.type === "o") {
|
|
62
|
+
this.entries.delete(key);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
this.counters.o = 1;
|
|
66
|
+
}
|
|
67
|
+
clearAll() {
|
|
68
|
+
this.entries.clear();
|
|
69
|
+
this.counters = { v: 1, f: 0, o: 1, BP: 1, LP: 1, HS: 1 };
|
|
70
|
+
}
|
|
71
|
+
list(type) {
|
|
72
|
+
const result = [];
|
|
73
|
+
for (const entry of this.entries.values()) {
|
|
74
|
+
if (entry.type === type) {
|
|
75
|
+
result.push(entry);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
remove(ref) {
|
|
81
|
+
return this.entries.delete(ref);
|
|
82
|
+
}
|
|
83
|
+
add(type, remoteId, name, meta) {
|
|
84
|
+
const num = this.counters[type];
|
|
85
|
+
this.counters[type] = num + 1;
|
|
86
|
+
const ref = `${PREFIXES[type]}${num}`;
|
|
87
|
+
const entry = { ref, type, remoteId };
|
|
88
|
+
if (name !== undefined) {
|
|
89
|
+
entry.name = name;
|
|
90
|
+
}
|
|
91
|
+
if (meta !== undefined) {
|
|
92
|
+
entry.meta = meta;
|
|
93
|
+
}
|
|
94
|
+
this.entries.set(ref, entry);
|
|
95
|
+
return ref;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
var PREFIXES;
|
|
99
|
+
var init_ref_table = __esm(() => {
|
|
100
|
+
PREFIXES = {
|
|
101
|
+
v: "@v",
|
|
102
|
+
f: "@f",
|
|
103
|
+
o: "@o",
|
|
104
|
+
BP: "BP#",
|
|
105
|
+
LP: "LP#",
|
|
106
|
+
HS: "HS#"
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// src/dap/client.ts
|
|
111
|
+
class DapClient {
|
|
112
|
+
proc;
|
|
113
|
+
nextSeq = 1;
|
|
114
|
+
pending = new Map;
|
|
115
|
+
listeners = new Map;
|
|
116
|
+
isConnected = false;
|
|
117
|
+
buffer = "";
|
|
118
|
+
constructor(proc) {
|
|
119
|
+
this.proc = proc;
|
|
120
|
+
this.isConnected = true;
|
|
121
|
+
this.readLoop();
|
|
122
|
+
this.drainStderr();
|
|
123
|
+
}
|
|
124
|
+
static spawn(command) {
|
|
125
|
+
const [cmd, ...args] = command;
|
|
126
|
+
if (!cmd) {
|
|
127
|
+
throw new Error("DapClient.spawn: command array must not be empty");
|
|
128
|
+
}
|
|
129
|
+
const proc = Bun.spawn([cmd, ...args], {
|
|
130
|
+
stdin: "pipe",
|
|
131
|
+
stdout: "pipe",
|
|
132
|
+
stderr: "pipe"
|
|
133
|
+
});
|
|
134
|
+
return new DapClient(proc);
|
|
135
|
+
}
|
|
136
|
+
async send(command, args) {
|
|
137
|
+
if (!this.isConnected) {
|
|
138
|
+
throw new Error("DAP client is not connected");
|
|
139
|
+
}
|
|
140
|
+
const seq = this.nextSeq++;
|
|
141
|
+
const request = {
|
|
142
|
+
seq,
|
|
143
|
+
type: "request",
|
|
144
|
+
command
|
|
145
|
+
};
|
|
146
|
+
if (args !== undefined) {
|
|
147
|
+
request.arguments = args;
|
|
148
|
+
}
|
|
149
|
+
return new Promise((resolve, reject) => {
|
|
150
|
+
const timer = setTimeout(() => {
|
|
151
|
+
this.pending.delete(seq);
|
|
152
|
+
reject(new Error(`DAP request timed out: ${command} (seq=${seq})`));
|
|
153
|
+
}, DEFAULT_TIMEOUT_MS);
|
|
154
|
+
this.pending.set(seq, { resolve, reject, timer });
|
|
155
|
+
this.writeMessage(request);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
on(event, handler) {
|
|
159
|
+
let handlers = this.listeners.get(event);
|
|
160
|
+
if (!handlers) {
|
|
161
|
+
handlers = new Set;
|
|
162
|
+
this.listeners.set(event, handlers);
|
|
163
|
+
}
|
|
164
|
+
handlers.add(handler);
|
|
165
|
+
}
|
|
166
|
+
off(event, handler) {
|
|
167
|
+
const handlers = this.listeners.get(event);
|
|
168
|
+
if (handlers) {
|
|
169
|
+
handlers.delete(handler);
|
|
170
|
+
if (handlers.size === 0) {
|
|
171
|
+
this.listeners.delete(event);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
disconnect() {
|
|
176
|
+
if (!this.isConnected) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
this.isConnected = false;
|
|
180
|
+
const error = new Error("DAP client disconnected");
|
|
181
|
+
for (const [id, pending] of this.pending) {
|
|
182
|
+
clearTimeout(pending.timer);
|
|
183
|
+
pending.reject(error);
|
|
184
|
+
this.pending.delete(id);
|
|
185
|
+
}
|
|
186
|
+
this.listeners.clear();
|
|
187
|
+
try {
|
|
188
|
+
this.proc.stdin.end();
|
|
189
|
+
} catch {}
|
|
190
|
+
try {
|
|
191
|
+
this.proc.kill();
|
|
192
|
+
} catch {}
|
|
193
|
+
}
|
|
194
|
+
get connected() {
|
|
195
|
+
return this.isConnected;
|
|
196
|
+
}
|
|
197
|
+
get pid() {
|
|
198
|
+
return this.proc.pid;
|
|
199
|
+
}
|
|
200
|
+
writeMessage(msg) {
|
|
201
|
+
const json = JSON.stringify(msg);
|
|
202
|
+
const header = `Content-Length: ${Buffer.byteLength(json, "utf-8")}\r
|
|
203
|
+
\r
|
|
204
|
+
`;
|
|
205
|
+
try {
|
|
206
|
+
this.proc.stdin.write(header + json);
|
|
207
|
+
} catch {
|
|
208
|
+
this.isConnected = false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async readLoop() {
|
|
212
|
+
const reader = this.proc.stdout.getReader();
|
|
213
|
+
const decoder = new TextDecoder;
|
|
214
|
+
try {
|
|
215
|
+
while (this.isConnected) {
|
|
216
|
+
const { done, value } = await reader.read();
|
|
217
|
+
if (done)
|
|
218
|
+
break;
|
|
219
|
+
this.buffer += decoder.decode(value, { stream: true });
|
|
220
|
+
this.processBuffer();
|
|
221
|
+
}
|
|
222
|
+
} catch {} finally {
|
|
223
|
+
this.isConnected = false;
|
|
224
|
+
const error = new Error("DAP adapter process terminated");
|
|
225
|
+
for (const [id, pending] of this.pending) {
|
|
226
|
+
clearTimeout(pending.timer);
|
|
227
|
+
pending.reject(error);
|
|
228
|
+
this.pending.delete(id);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
processBuffer() {
|
|
233
|
+
while (true) {
|
|
234
|
+
const headerEnd = this.buffer.indexOf(`\r
|
|
235
|
+
\r
|
|
236
|
+
`);
|
|
237
|
+
if (headerEnd === -1)
|
|
238
|
+
return;
|
|
239
|
+
const header = this.buffer.slice(0, headerEnd);
|
|
240
|
+
const match = /Content-Length:\s*(\d+)/i.exec(header);
|
|
241
|
+
if (!match?.[1]) {
|
|
242
|
+
this.buffer = this.buffer.slice(headerEnd + 4);
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const contentLength = parseInt(match[1], 10);
|
|
246
|
+
const bodyStart = headerEnd + 4;
|
|
247
|
+
const bodyEnd = bodyStart + contentLength;
|
|
248
|
+
if (this.buffer.length < bodyEnd)
|
|
249
|
+
return;
|
|
250
|
+
const body = this.buffer.slice(bodyStart, bodyEnd);
|
|
251
|
+
this.buffer = this.buffer.slice(bodyEnd);
|
|
252
|
+
this.handleMessage(body);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
handleMessage(data) {
|
|
256
|
+
let parsed;
|
|
257
|
+
try {
|
|
258
|
+
parsed = JSON.parse(data);
|
|
259
|
+
} catch {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (parsed.type === "response") {
|
|
263
|
+
const response = parsed;
|
|
264
|
+
const pending = this.pending.get(response.request_seq);
|
|
265
|
+
if (!pending)
|
|
266
|
+
return;
|
|
267
|
+
this.pending.delete(response.request_seq);
|
|
268
|
+
clearTimeout(pending.timer);
|
|
269
|
+
if (!response.success) {
|
|
270
|
+
pending.reject(new Error(`DAP error (${response.command}): ${response.message ?? "unknown error"}`));
|
|
271
|
+
} else {
|
|
272
|
+
pending.resolve(response);
|
|
273
|
+
}
|
|
274
|
+
} else if (parsed.type === "event") {
|
|
275
|
+
const event = parsed;
|
|
276
|
+
const handlers = this.listeners.get(event.event);
|
|
277
|
+
if (handlers) {
|
|
278
|
+
for (const handler of handlers) {
|
|
279
|
+
handler(event.body);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async drainStderr() {
|
|
285
|
+
const reader = this.proc.stderr.getReader();
|
|
286
|
+
try {
|
|
287
|
+
while (true) {
|
|
288
|
+
const { done } = await reader.read();
|
|
289
|
+
if (done)
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
} catch {}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
var DEFAULT_TIMEOUT_MS = 30000;
|
|
296
|
+
|
|
297
|
+
// src/dap/session.ts
|
|
298
|
+
function resolveAdapterCommand(runtime) {
|
|
299
|
+
switch (runtime) {
|
|
300
|
+
case "lldb":
|
|
301
|
+
case "lldb-dap": {
|
|
302
|
+
const brewPath = "/opt/homebrew/opt/llvm/bin/lldb-dap";
|
|
303
|
+
return [brewPath];
|
|
304
|
+
}
|
|
305
|
+
case "codelldb":
|
|
306
|
+
return ["codelldb", "--port", "0"];
|
|
307
|
+
default:
|
|
308
|
+
return [runtime];
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
class DapSession {
|
|
313
|
+
dap = null;
|
|
314
|
+
refs = new RefTable;
|
|
315
|
+
_state = "idle";
|
|
316
|
+
_pauseInfo = null;
|
|
317
|
+
_session;
|
|
318
|
+
_runtime;
|
|
319
|
+
_startTime = Date.now();
|
|
320
|
+
_threadId = 1;
|
|
321
|
+
_stackFrames = [];
|
|
322
|
+
_consoleMessages = [];
|
|
323
|
+
_exceptionEntries = [];
|
|
324
|
+
capabilities = {};
|
|
325
|
+
breakpoints = new Map;
|
|
326
|
+
allBreakpoints = [];
|
|
327
|
+
functionBreakpoints = [];
|
|
328
|
+
stoppedWaiter = null;
|
|
329
|
+
_stackFetchPromise = null;
|
|
330
|
+
constructor(session, runtime) {
|
|
331
|
+
this._session = session;
|
|
332
|
+
this._runtime = runtime;
|
|
333
|
+
}
|
|
334
|
+
async launch(command, options = {}) {
|
|
335
|
+
if (this._state !== "idle") {
|
|
336
|
+
throw new Error("Session already has an active debug target");
|
|
337
|
+
}
|
|
338
|
+
const adapterCmd = resolveAdapterCommand(this._runtime);
|
|
339
|
+
this.dap = DapClient.spawn(adapterCmd);
|
|
340
|
+
this.setupEventHandlers();
|
|
341
|
+
await this.initializeAdapter();
|
|
342
|
+
const program = options.program ?? command[0];
|
|
343
|
+
const programArgs = options.args ?? command.slice(1);
|
|
344
|
+
const launchArgs = {
|
|
345
|
+
program,
|
|
346
|
+
args: programArgs,
|
|
347
|
+
stopOnEntry: options.brk ?? true,
|
|
348
|
+
cwd: process.cwd()
|
|
349
|
+
};
|
|
350
|
+
await this.dap.send("launch", launchArgs);
|
|
351
|
+
await this.dap.send("configurationDone");
|
|
352
|
+
if (options.brk !== false) {
|
|
353
|
+
await this.waitForStop(5000);
|
|
354
|
+
}
|
|
355
|
+
const result = {
|
|
356
|
+
pid: this.dap.pid,
|
|
357
|
+
wsUrl: `dap://${this._runtime}`,
|
|
358
|
+
paused: this.isPaused()
|
|
359
|
+
};
|
|
360
|
+
if (this._pauseInfo) {
|
|
361
|
+
result.pauseInfo = this._pauseInfo;
|
|
362
|
+
}
|
|
363
|
+
return result;
|
|
364
|
+
}
|
|
365
|
+
async attach(target) {
|
|
366
|
+
if (this._state !== "idle") {
|
|
367
|
+
throw new Error("Session already has an active debug target");
|
|
368
|
+
}
|
|
369
|
+
const adapterCmd = resolveAdapterCommand(this._runtime);
|
|
370
|
+
this.dap = DapClient.spawn(adapterCmd);
|
|
371
|
+
this.setupEventHandlers();
|
|
372
|
+
await this.initializeAdapter();
|
|
373
|
+
const pid = parseInt(target, 10);
|
|
374
|
+
const attachArgs = Number.isNaN(pid) ? { program: target, waitFor: true } : { pid };
|
|
375
|
+
await this.dap.send("attach", attachArgs);
|
|
376
|
+
await this.dap.send("configurationDone");
|
|
377
|
+
await this.waitForStop(5000).catch(() => {});
|
|
378
|
+
if (this._state === "idle") {
|
|
379
|
+
this._state = "running";
|
|
380
|
+
}
|
|
381
|
+
return { wsUrl: `dap://${this._runtime}/${target}` };
|
|
382
|
+
}
|
|
383
|
+
getStatus() {
|
|
384
|
+
return {
|
|
385
|
+
session: this._session,
|
|
386
|
+
state: this._state,
|
|
387
|
+
pid: this.dap?.pid,
|
|
388
|
+
wsUrl: this.dap ? `dap://${this._runtime}` : undefined,
|
|
389
|
+
pauseInfo: this._pauseInfo ?? undefined,
|
|
390
|
+
uptime: Math.floor((Date.now() - this._startTime) / 1000),
|
|
391
|
+
scriptCount: 0
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
async stop() {
|
|
395
|
+
if (this.dap) {
|
|
396
|
+
try {
|
|
397
|
+
await this.dap.send("disconnect", { terminateDebuggee: true });
|
|
398
|
+
} catch {}
|
|
399
|
+
this.dap.disconnect();
|
|
400
|
+
this.dap = null;
|
|
401
|
+
}
|
|
402
|
+
this._state = "idle";
|
|
403
|
+
this._pauseInfo = null;
|
|
404
|
+
this._stackFrames = [];
|
|
405
|
+
this.refs.clearAll();
|
|
406
|
+
this.breakpoints.clear();
|
|
407
|
+
this.allBreakpoints = [];
|
|
408
|
+
this.functionBreakpoints = [];
|
|
409
|
+
this._consoleMessages = [];
|
|
410
|
+
this._exceptionEntries = [];
|
|
411
|
+
}
|
|
412
|
+
async continue() {
|
|
413
|
+
this.requireConnected();
|
|
414
|
+
this.requirePaused();
|
|
415
|
+
const waiter = this.createStoppedWaiter(30000);
|
|
416
|
+
await this.getDap().send("continue", { threadId: this._threadId });
|
|
417
|
+
this._state = "running";
|
|
418
|
+
this._pauseInfo = null;
|
|
419
|
+
this._stackFrames = [];
|
|
420
|
+
this.refs.clearVolatile();
|
|
421
|
+
await waiter;
|
|
422
|
+
if (this.isPaused())
|
|
423
|
+
await this.fetchStackTrace();
|
|
424
|
+
}
|
|
425
|
+
async step(mode) {
|
|
426
|
+
this.requireConnected();
|
|
427
|
+
this.requirePaused();
|
|
428
|
+
const waiter = this.createStoppedWaiter(30000);
|
|
429
|
+
const command = mode === "into" ? "stepIn" : mode === "out" ? "stepOut" : "next";
|
|
430
|
+
await this.getDap().send(command, { threadId: this._threadId });
|
|
431
|
+
this._state = "running";
|
|
432
|
+
this._pauseInfo = null;
|
|
433
|
+
this.refs.clearVolatile();
|
|
434
|
+
await waiter;
|
|
435
|
+
if (this.isPaused())
|
|
436
|
+
await this.fetchStackTrace();
|
|
437
|
+
}
|
|
438
|
+
async pause() {
|
|
439
|
+
this.requireConnected();
|
|
440
|
+
if (this._state !== "running") {
|
|
441
|
+
throw new Error("Cannot pause: target is not running");
|
|
442
|
+
}
|
|
443
|
+
const waiter = this.createStoppedWaiter(5000);
|
|
444
|
+
await this.getDap().send("pause", { threadId: this._threadId });
|
|
445
|
+
await waiter;
|
|
446
|
+
if (this.isPaused())
|
|
447
|
+
await this.fetchStackTrace();
|
|
448
|
+
}
|
|
449
|
+
async setBreakpoint(file, line, options) {
|
|
450
|
+
this.requireConnected();
|
|
451
|
+
const entry = {
|
|
452
|
+
ref: "",
|
|
453
|
+
file,
|
|
454
|
+
line,
|
|
455
|
+
condition: options?.condition,
|
|
456
|
+
hitCondition: options?.hitCount ? String(options.hitCount) : undefined,
|
|
457
|
+
verified: false
|
|
458
|
+
};
|
|
459
|
+
let fileBreakpoints = this.breakpoints.get(file);
|
|
460
|
+
if (!fileBreakpoints) {
|
|
461
|
+
fileBreakpoints = [];
|
|
462
|
+
this.breakpoints.set(file, fileBreakpoints);
|
|
463
|
+
}
|
|
464
|
+
fileBreakpoints.push(entry);
|
|
465
|
+
this.allBreakpoints.push(entry);
|
|
466
|
+
const ref = this.refs.addBreakpoint(`dap-bp:${file}:${line}`, {
|
|
467
|
+
file,
|
|
468
|
+
line
|
|
469
|
+
});
|
|
470
|
+
entry.ref = ref;
|
|
471
|
+
await this.syncFileBreakpoints(file);
|
|
472
|
+
return {
|
|
473
|
+
ref,
|
|
474
|
+
location: { url: file, line: entry.actualLine ?? line }
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
async removeBreakpoint(ref) {
|
|
478
|
+
this.requireConnected();
|
|
479
|
+
const entry = this.allBreakpoints.find((bp) => bp.ref === ref);
|
|
480
|
+
if (!entry) {
|
|
481
|
+
throw new Error(`Unknown breakpoint ref: ${ref}`);
|
|
482
|
+
}
|
|
483
|
+
const fileBreakpoints = this.breakpoints.get(entry.file);
|
|
484
|
+
if (fileBreakpoints) {
|
|
485
|
+
const idx = fileBreakpoints.indexOf(entry);
|
|
486
|
+
if (idx !== -1)
|
|
487
|
+
fileBreakpoints.splice(idx, 1);
|
|
488
|
+
if (fileBreakpoints.length === 0) {
|
|
489
|
+
this.breakpoints.delete(entry.file);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
const allIdx = this.allBreakpoints.indexOf(entry);
|
|
493
|
+
if (allIdx !== -1)
|
|
494
|
+
this.allBreakpoints.splice(allIdx, 1);
|
|
495
|
+
this.refs.remove(ref);
|
|
496
|
+
await this.syncFileBreakpoints(entry.file);
|
|
497
|
+
}
|
|
498
|
+
async removeAllBreakpoints() {
|
|
499
|
+
this.requireConnected();
|
|
500
|
+
const files = [...this.breakpoints.keys()];
|
|
501
|
+
this.breakpoints.clear();
|
|
502
|
+
this.allBreakpoints = [];
|
|
503
|
+
this.functionBreakpoints = [];
|
|
504
|
+
for (const entry of this.refs.list("BP")) {
|
|
505
|
+
this.refs.remove(entry.ref);
|
|
506
|
+
}
|
|
507
|
+
for (const file of files) {
|
|
508
|
+
await this.getDap().send("setBreakpoints", {
|
|
509
|
+
source: { path: file },
|
|
510
|
+
breakpoints: []
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
await this.getDap().send("setFunctionBreakpoints", { breakpoints: [] });
|
|
514
|
+
}
|
|
515
|
+
listBreakpoints() {
|
|
516
|
+
const fileBps = this.allBreakpoints.map((bp) => ({
|
|
517
|
+
ref: bp.ref,
|
|
518
|
+
type: "BP",
|
|
519
|
+
url: bp.file,
|
|
520
|
+
line: bp.actualLine ?? bp.line,
|
|
521
|
+
condition: bp.condition
|
|
522
|
+
}));
|
|
523
|
+
const fnBps = this.functionBreakpoints.map((bp) => ({
|
|
524
|
+
ref: bp.ref,
|
|
525
|
+
type: "BP",
|
|
526
|
+
url: bp.name,
|
|
527
|
+
line: 0,
|
|
528
|
+
condition: bp.condition
|
|
529
|
+
}));
|
|
530
|
+
return [...fileBps, ...fnBps];
|
|
531
|
+
}
|
|
532
|
+
async setFunctionBreakpoint(name, options) {
|
|
533
|
+
this.requireConnected();
|
|
534
|
+
const entry = {
|
|
535
|
+
ref: "",
|
|
536
|
+
name,
|
|
537
|
+
condition: options?.condition,
|
|
538
|
+
hitCondition: options?.hitCount ? String(options.hitCount) : undefined,
|
|
539
|
+
verified: false
|
|
540
|
+
};
|
|
541
|
+
this.functionBreakpoints.push(entry);
|
|
542
|
+
const ref = this.refs.addBreakpoint(`dap-fn:${name}`, {
|
|
543
|
+
file: name,
|
|
544
|
+
line: 0
|
|
545
|
+
});
|
|
546
|
+
entry.ref = ref;
|
|
547
|
+
await this.syncFunctionBreakpoints();
|
|
548
|
+
return { ref };
|
|
549
|
+
}
|
|
550
|
+
async removeFunctionBreakpoint(ref) {
|
|
551
|
+
this.requireConnected();
|
|
552
|
+
const idx = this.functionBreakpoints.findIndex((bp) => bp.ref === ref);
|
|
553
|
+
if (idx === -1) {
|
|
554
|
+
throw new Error(`Unknown function breakpoint ref: ${ref}`);
|
|
555
|
+
}
|
|
556
|
+
this.functionBreakpoints.splice(idx, 1);
|
|
557
|
+
this.refs.remove(ref);
|
|
558
|
+
await this.syncFunctionBreakpoints();
|
|
559
|
+
}
|
|
560
|
+
async syncFunctionBreakpoints() {
|
|
561
|
+
const dapBps = this.functionBreakpoints.map((bp) => ({
|
|
562
|
+
name: bp.name,
|
|
563
|
+
condition: bp.condition,
|
|
564
|
+
hitCondition: bp.hitCondition
|
|
565
|
+
}));
|
|
566
|
+
const response = await this.getDap().send("setFunctionBreakpoints", {
|
|
567
|
+
breakpoints: dapBps
|
|
568
|
+
});
|
|
569
|
+
const body = response.body;
|
|
570
|
+
const resultBps = body?.breakpoints ?? [];
|
|
571
|
+
for (let i = 0;i < this.functionBreakpoints.length; i++) {
|
|
572
|
+
const entry = this.functionBreakpoints[i];
|
|
573
|
+
const result = resultBps[i];
|
|
574
|
+
if (entry && result) {
|
|
575
|
+
entry.verified = result.verified ?? false;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
async eval(expression, options = {}) {
|
|
580
|
+
this.requireConnected();
|
|
581
|
+
this.requirePaused();
|
|
582
|
+
await this.ensureStack();
|
|
583
|
+
const frameId = this.resolveFrameId(options.frame);
|
|
584
|
+
const response = await this.getDap().send("evaluate", {
|
|
585
|
+
expression,
|
|
586
|
+
frameId,
|
|
587
|
+
context: "repl"
|
|
588
|
+
});
|
|
589
|
+
const body = response.body;
|
|
590
|
+
const remoteId = body.variablesReference > 0 ? String(body.variablesReference) : `eval:${Date.now()}`;
|
|
591
|
+
const ref = this.refs.addVar(remoteId, expression);
|
|
592
|
+
return {
|
|
593
|
+
ref,
|
|
594
|
+
type: body.type ?? "unknown",
|
|
595
|
+
value: body.result,
|
|
596
|
+
objectId: body.variablesReference > 0 ? String(body.variablesReference) : undefined
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
async getVars(options = {}) {
|
|
600
|
+
this.requireConnected();
|
|
601
|
+
this.requirePaused();
|
|
602
|
+
await this.ensureStack();
|
|
603
|
+
const frameId = this.resolveFrameId(options.frame);
|
|
604
|
+
const scopesResponse = await this.getDap().send("scopes", { frameId });
|
|
605
|
+
const scopes = scopesResponse.body.scopes;
|
|
606
|
+
const result = [];
|
|
607
|
+
const scopesToFetch = options.allScopes ? scopes : scopes.filter((s) => !s.expensive).slice(0, 2);
|
|
608
|
+
for (const scope of scopesToFetch) {
|
|
609
|
+
const varsResponse = await this.getDap().send("variables", {
|
|
610
|
+
variablesReference: scope.variablesReference
|
|
611
|
+
});
|
|
612
|
+
const variables = varsResponse.body.variables;
|
|
613
|
+
for (const v of variables) {
|
|
614
|
+
if (options.names && !options.names.includes(v.name))
|
|
615
|
+
continue;
|
|
616
|
+
const remoteId = v.variablesReference > 0 ? String(v.variablesReference) : `var:${v.name}:${Date.now()}`;
|
|
617
|
+
const ref = this.refs.addVar(remoteId, v.name);
|
|
618
|
+
result.push({
|
|
619
|
+
ref,
|
|
620
|
+
name: v.name,
|
|
621
|
+
type: v.type ?? "unknown",
|
|
622
|
+
value: v.value
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return result;
|
|
627
|
+
}
|
|
628
|
+
async getProps(ref, _options = {}) {
|
|
629
|
+
this.requireConnected();
|
|
630
|
+
const remoteId = this.refs.resolveId(ref);
|
|
631
|
+
if (!remoteId) {
|
|
632
|
+
throw new Error(`Unknown ref: ${ref}`);
|
|
633
|
+
}
|
|
634
|
+
const variablesReference = parseInt(remoteId, 10);
|
|
635
|
+
if (Number.isNaN(variablesReference) || variablesReference <= 0) {
|
|
636
|
+
return [];
|
|
637
|
+
}
|
|
638
|
+
const response = await this.getDap().send("variables", { variablesReference });
|
|
639
|
+
const variables = response.body.variables;
|
|
640
|
+
return variables.map((v) => {
|
|
641
|
+
const childRemoteId = v.variablesReference > 0 ? String(v.variablesReference) : `prop:${v.name}:${Date.now()}`;
|
|
642
|
+
const childRef = v.variablesReference > 0 ? this.refs.addVar(childRemoteId, v.name) : undefined;
|
|
643
|
+
return {
|
|
644
|
+
ref: childRef,
|
|
645
|
+
name: v.name,
|
|
646
|
+
type: v.type ?? "unknown",
|
|
647
|
+
value: v.value,
|
|
648
|
+
isOwn: true
|
|
649
|
+
};
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
getStack(_options = {}) {
|
|
653
|
+
return this._stackFrames.map((frame) => {
|
|
654
|
+
const ref = this.refs.addFrame(String(frame.id), frame.name);
|
|
655
|
+
return {
|
|
656
|
+
ref,
|
|
657
|
+
functionName: frame.name,
|
|
658
|
+
file: frame.file ?? "<unknown>",
|
|
659
|
+
line: frame.line,
|
|
660
|
+
column: frame.column > 0 ? frame.column : undefined
|
|
661
|
+
};
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
async getSource(options = {}) {
|
|
665
|
+
const file = options.file ?? this._pauseInfo?.url;
|
|
666
|
+
if (!file) {
|
|
667
|
+
throw new Error("No source file available. Specify a file path.");
|
|
668
|
+
}
|
|
669
|
+
let content;
|
|
670
|
+
try {
|
|
671
|
+
content = await Bun.file(file).text();
|
|
672
|
+
} catch {
|
|
673
|
+
throw new Error(`Cannot read source file: ${file}`);
|
|
674
|
+
}
|
|
675
|
+
const allLines = content.split(`
|
|
676
|
+
`);
|
|
677
|
+
const currentLine = this._pauseInfo?.line;
|
|
678
|
+
const windowSize = options.lines ?? 10;
|
|
679
|
+
let startLine;
|
|
680
|
+
let endLine;
|
|
681
|
+
if (options.all) {
|
|
682
|
+
startLine = 1;
|
|
683
|
+
endLine = allLines.length;
|
|
684
|
+
} else if (currentLine !== undefined) {
|
|
685
|
+
startLine = Math.max(1, currentLine - windowSize);
|
|
686
|
+
endLine = Math.min(allLines.length, currentLine + windowSize);
|
|
687
|
+
} else {
|
|
688
|
+
startLine = 1;
|
|
689
|
+
endLine = Math.min(allLines.length, windowSize * 2);
|
|
690
|
+
}
|
|
691
|
+
const lines = [];
|
|
692
|
+
for (let i = startLine;i <= endLine; i++) {
|
|
693
|
+
const lineObj = {
|
|
694
|
+
line: i,
|
|
695
|
+
text: allLines[i - 1] ?? ""
|
|
696
|
+
};
|
|
697
|
+
if (currentLine !== undefined && i === currentLine) {
|
|
698
|
+
lineObj.current = true;
|
|
699
|
+
}
|
|
700
|
+
lines.push(lineObj);
|
|
701
|
+
}
|
|
702
|
+
return { url: file, lines };
|
|
703
|
+
}
|
|
704
|
+
async buildState(options = {}) {
|
|
705
|
+
if (this.isPaused())
|
|
706
|
+
await this.ensureStack();
|
|
707
|
+
const snapshot = {
|
|
708
|
+
status: this._state
|
|
709
|
+
};
|
|
710
|
+
if (this._state === "paused" && this._pauseInfo) {
|
|
711
|
+
snapshot.reason = this._pauseInfo.reason;
|
|
712
|
+
if (this._pauseInfo.url && this._pauseInfo.line !== undefined) {
|
|
713
|
+
snapshot.location = {
|
|
714
|
+
url: this._pauseInfo.url,
|
|
715
|
+
line: this._pauseInfo.line,
|
|
716
|
+
column: this._pauseInfo.column
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
if (this._state === "paused" && options.code !== false) {
|
|
721
|
+
try {
|
|
722
|
+
const source = await this.getSource({ lines: options.lines });
|
|
723
|
+
snapshot.source = source;
|
|
724
|
+
} catch {}
|
|
725
|
+
}
|
|
726
|
+
if (this._state === "paused" && (options.vars !== false || !options.compact)) {
|
|
727
|
+
try {
|
|
728
|
+
const vars = await this.getVars({ frame: options.frame, allScopes: options.allScopes });
|
|
729
|
+
snapshot.vars = vars.map((v) => ({
|
|
730
|
+
ref: v.ref,
|
|
731
|
+
name: v.name,
|
|
732
|
+
value: v.value,
|
|
733
|
+
scope: "local"
|
|
734
|
+
}));
|
|
735
|
+
} catch {}
|
|
736
|
+
}
|
|
737
|
+
if (this._state === "paused" && options.stack !== false) {
|
|
738
|
+
try {
|
|
739
|
+
snapshot.stack = this.getStack();
|
|
740
|
+
} catch {}
|
|
741
|
+
}
|
|
742
|
+
if (options.breakpoints !== false) {
|
|
743
|
+
snapshot.breakpointCount = this.allBreakpoints.length;
|
|
744
|
+
}
|
|
745
|
+
return snapshot;
|
|
746
|
+
}
|
|
747
|
+
getConsoleMessages(options = {}) {
|
|
748
|
+
let msgs = this._consoleMessages;
|
|
749
|
+
if (options.level) {
|
|
750
|
+
msgs = msgs.filter((m) => m.level === options.level);
|
|
751
|
+
}
|
|
752
|
+
if (options.since !== undefined) {
|
|
753
|
+
const since = options.since;
|
|
754
|
+
msgs = msgs.filter((m) => m.timestamp >= since);
|
|
755
|
+
}
|
|
756
|
+
if (options.clear) {
|
|
757
|
+
this._consoleMessages = [];
|
|
758
|
+
}
|
|
759
|
+
return msgs;
|
|
760
|
+
}
|
|
761
|
+
getExceptions(options = {}) {
|
|
762
|
+
let entries = this._exceptionEntries;
|
|
763
|
+
if (options.since !== undefined) {
|
|
764
|
+
const since = options.since;
|
|
765
|
+
entries = entries.filter((e) => e.timestamp >= since);
|
|
766
|
+
}
|
|
767
|
+
return entries;
|
|
768
|
+
}
|
|
769
|
+
async setLogpoint(_file, _line, _template, _options) {
|
|
770
|
+
throw new Error("Logpoints are not supported in DAP mode. Use breakpoints with conditions instead.");
|
|
771
|
+
}
|
|
772
|
+
async setExceptionPause(mode) {
|
|
773
|
+
this.requireConnected();
|
|
774
|
+
const available = this.capabilities.exceptionBreakpointFilters ?? [];
|
|
775
|
+
const filterIds = available.map((f) => f.filter);
|
|
776
|
+
let filters;
|
|
777
|
+
if (mode === "none") {
|
|
778
|
+
filters = [];
|
|
779
|
+
} else if (mode === "all") {
|
|
780
|
+
filters = filterIds;
|
|
781
|
+
} else {
|
|
782
|
+
filters = filterIds.filter((id) => id.includes(mode));
|
|
783
|
+
if (filters.length === 0)
|
|
784
|
+
filters = filterIds;
|
|
785
|
+
}
|
|
786
|
+
await this.getDap().send("setExceptionBreakpoints", { filters });
|
|
787
|
+
}
|
|
788
|
+
async toggleBreakpoint(_ref) {
|
|
789
|
+
throw new Error("Breakpoint toggling is not yet supported in DAP mode. Use break-rm and break.");
|
|
790
|
+
}
|
|
791
|
+
async getBreakableLocations(_file, _startLine, _endLine) {
|
|
792
|
+
throw new Error("Breakable locations are not supported in DAP mode.");
|
|
793
|
+
}
|
|
794
|
+
async hotpatch(_file, _source, _options) {
|
|
795
|
+
throw new Error("Hot-patching is not supported in DAP mode.");
|
|
796
|
+
}
|
|
797
|
+
async searchInScripts(_query, _options) {
|
|
798
|
+
throw new Error("Script search is not supported in DAP mode. Use your shell to search source files.");
|
|
799
|
+
}
|
|
800
|
+
async setVariable(varName, value, options = {}) {
|
|
801
|
+
this.requireConnected();
|
|
802
|
+
this.requirePaused();
|
|
803
|
+
await this.ensureStack();
|
|
804
|
+
const frameId = this.resolveFrameId(options.frame);
|
|
805
|
+
const scopesResponse = await this.getDap().send("scopes", { frameId });
|
|
806
|
+
const scopes = scopesResponse.body.scopes;
|
|
807
|
+
for (const scope of scopes) {
|
|
808
|
+
try {
|
|
809
|
+
const response = await this.getDap().send("setVariable", {
|
|
810
|
+
variablesReference: scope.variablesReference,
|
|
811
|
+
name: varName,
|
|
812
|
+
value
|
|
813
|
+
});
|
|
814
|
+
const body = response.body;
|
|
815
|
+
return { name: varName, newValue: body.value, type: body.type ?? "unknown" };
|
|
816
|
+
} catch {}
|
|
817
|
+
}
|
|
818
|
+
throw new Error(`Variable "${varName}" not found in any scope`);
|
|
819
|
+
}
|
|
820
|
+
async setReturnValue(_value) {
|
|
821
|
+
throw new Error("Setting return values is not supported in DAP mode.");
|
|
822
|
+
}
|
|
823
|
+
async restartFrame(_frameRef) {
|
|
824
|
+
throw new Error("Frame restart is not supported in DAP mode.");
|
|
825
|
+
}
|
|
826
|
+
async runTo(_file, _line) {
|
|
827
|
+
throw new Error("Run-to-location is not yet supported in DAP mode. Set a breakpoint and continue.");
|
|
828
|
+
}
|
|
829
|
+
getScripts(_filter) {
|
|
830
|
+
return [];
|
|
831
|
+
}
|
|
832
|
+
async addBlackbox(_patterns) {
|
|
833
|
+
throw new Error("Blackboxing is not supported in DAP mode.");
|
|
834
|
+
}
|
|
835
|
+
listBlackbox() {
|
|
836
|
+
return [];
|
|
837
|
+
}
|
|
838
|
+
async removeBlackbox(_patterns) {
|
|
839
|
+
throw new Error("Blackboxing is not supported in DAP mode.");
|
|
840
|
+
}
|
|
841
|
+
async restart() {
|
|
842
|
+
throw new Error("Restart is not yet supported in DAP mode. Use stop + launch.");
|
|
843
|
+
}
|
|
844
|
+
get sourceMapResolver() {
|
|
845
|
+
return {
|
|
846
|
+
findScriptForSource: () => null,
|
|
847
|
+
getInfo: () => null,
|
|
848
|
+
getAllInfos: () => [],
|
|
849
|
+
setDisabled: () => {}
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
isPaused() {
|
|
853
|
+
return this._state === "paused";
|
|
854
|
+
}
|
|
855
|
+
async ensureStack() {
|
|
856
|
+
if (this.isPaused() && this._stackFrames.length === 0) {
|
|
857
|
+
await this.fetchStackTrace();
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
getDap() {
|
|
861
|
+
if (!this.dap || !this.dap.connected) {
|
|
862
|
+
throw new Error("Not connected to a debug adapter. Use launch or attach first.");
|
|
863
|
+
}
|
|
864
|
+
return this.dap;
|
|
865
|
+
}
|
|
866
|
+
requireConnected() {
|
|
867
|
+
this.getDap();
|
|
868
|
+
}
|
|
869
|
+
requirePaused() {
|
|
870
|
+
if (!this.isPaused()) {
|
|
871
|
+
throw new Error("Target is not paused. Use pause or wait for a breakpoint.");
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
async initializeAdapter() {
|
|
875
|
+
const response = await this.getDap().send("initialize", {
|
|
876
|
+
adapterID: this._runtime,
|
|
877
|
+
clientID: "agent-dbg",
|
|
878
|
+
clientName: "agent-dbg",
|
|
879
|
+
linesStartAt1: true,
|
|
880
|
+
columnsStartAt1: true,
|
|
881
|
+
pathFormat: "path",
|
|
882
|
+
supportsVariableType: true
|
|
883
|
+
});
|
|
884
|
+
this.capabilities = response.body ?? {};
|
|
885
|
+
}
|
|
886
|
+
setupEventHandlers() {
|
|
887
|
+
const dap = this.getDap();
|
|
888
|
+
dap.on("stopped", (body) => {
|
|
889
|
+
const event = body;
|
|
890
|
+
this._state = "paused";
|
|
891
|
+
if (event.threadId !== undefined) {
|
|
892
|
+
this._threadId = event.threadId;
|
|
893
|
+
}
|
|
894
|
+
this._pauseInfo = {
|
|
895
|
+
reason: event.reason
|
|
896
|
+
};
|
|
897
|
+
if (this.stoppedWaiter) {
|
|
898
|
+
this.stoppedWaiter.resolve();
|
|
899
|
+
this.stoppedWaiter = null;
|
|
900
|
+
} else {
|
|
901
|
+
this.fetchStackTrace().catch(() => {});
|
|
902
|
+
}
|
|
903
|
+
});
|
|
904
|
+
dap.on("continued", (_body) => {
|
|
905
|
+
this._state = "running";
|
|
906
|
+
this._pauseInfo = null;
|
|
907
|
+
this._stackFrames = [];
|
|
908
|
+
this.refs.clearVolatile();
|
|
909
|
+
});
|
|
910
|
+
dap.on("terminated", (_body) => {
|
|
911
|
+
this._state = "idle";
|
|
912
|
+
this._pauseInfo = null;
|
|
913
|
+
this._stackFrames = [];
|
|
914
|
+
this.stoppedWaiter?.resolve();
|
|
915
|
+
this.stoppedWaiter = null;
|
|
916
|
+
});
|
|
917
|
+
dap.on("exited", (_body) => {
|
|
918
|
+
this._state = "idle";
|
|
919
|
+
this._pauseInfo = null;
|
|
920
|
+
this.stoppedWaiter?.resolve();
|
|
921
|
+
this.stoppedWaiter = null;
|
|
922
|
+
});
|
|
923
|
+
dap.on("output", (body) => {
|
|
924
|
+
const event = body;
|
|
925
|
+
const category = event.category ?? "console";
|
|
926
|
+
if (category === "stdout" || category === "console") {
|
|
927
|
+
this._consoleMessages.push({
|
|
928
|
+
timestamp: Date.now(),
|
|
929
|
+
level: "log",
|
|
930
|
+
text: event.output.trimEnd(),
|
|
931
|
+
url: event.source?.path,
|
|
932
|
+
line: event.line
|
|
933
|
+
});
|
|
934
|
+
} else if (category === "stderr") {
|
|
935
|
+
this._consoleMessages.push({
|
|
936
|
+
timestamp: Date.now(),
|
|
937
|
+
level: "error",
|
|
938
|
+
text: event.output.trimEnd(),
|
|
939
|
+
url: event.source?.path,
|
|
940
|
+
line: event.line
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
if (this._consoleMessages.length > 1000) {
|
|
944
|
+
this._consoleMessages.shift();
|
|
945
|
+
}
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
async fetchStackTrace() {
|
|
949
|
+
if (this._stackFetchPromise) {
|
|
950
|
+
await this._stackFetchPromise;
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
this._stackFetchPromise = this._fetchStackTraceImpl();
|
|
954
|
+
try {
|
|
955
|
+
await this._stackFetchPromise;
|
|
956
|
+
} finally {
|
|
957
|
+
this._stackFetchPromise = null;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
async _fetchStackTraceImpl() {
|
|
961
|
+
if (!this.dap || this._state !== "paused")
|
|
962
|
+
return;
|
|
963
|
+
try {
|
|
964
|
+
const response = await this.dap.send("stackTrace", {
|
|
965
|
+
threadId: this._threadId,
|
|
966
|
+
startFrame: 0,
|
|
967
|
+
levels: 50
|
|
968
|
+
});
|
|
969
|
+
const body = response.body;
|
|
970
|
+
this._stackFrames = body.stackFrames.map((f) => ({
|
|
971
|
+
id: f.id,
|
|
972
|
+
name: f.name,
|
|
973
|
+
file: f.source?.path ?? f.source?.name,
|
|
974
|
+
line: f.line,
|
|
975
|
+
column: f.column
|
|
976
|
+
}));
|
|
977
|
+
const topFrame = this._stackFrames[0];
|
|
978
|
+
if (topFrame && this._pauseInfo) {
|
|
979
|
+
this._pauseInfo.url = topFrame.file;
|
|
980
|
+
this._pauseInfo.line = topFrame.line;
|
|
981
|
+
this._pauseInfo.column = topFrame.column > 0 ? topFrame.column : undefined;
|
|
982
|
+
this._pauseInfo.callFrameCount = this._stackFrames.length;
|
|
983
|
+
}
|
|
984
|
+
} catch {}
|
|
985
|
+
}
|
|
986
|
+
resolveFrameId(frameRef) {
|
|
987
|
+
if (!frameRef) {
|
|
988
|
+
const topFrame = this._stackFrames[0];
|
|
989
|
+
if (!topFrame) {
|
|
990
|
+
throw new Error("No stack frames available");
|
|
991
|
+
}
|
|
992
|
+
return topFrame.id;
|
|
993
|
+
}
|
|
994
|
+
const remoteId = this.refs.resolveId(frameRef);
|
|
995
|
+
if (!remoteId) {
|
|
996
|
+
throw new Error(`Unknown frame ref: ${frameRef}`);
|
|
997
|
+
}
|
|
998
|
+
return parseInt(remoteId, 10);
|
|
999
|
+
}
|
|
1000
|
+
async syncFileBreakpoints(file) {
|
|
1001
|
+
const entries = this.breakpoints.get(file) ?? [];
|
|
1002
|
+
const dapBreakpoints = entries.map((bp) => {
|
|
1003
|
+
const sbp = { line: bp.line };
|
|
1004
|
+
if (bp.condition)
|
|
1005
|
+
sbp.condition = bp.condition;
|
|
1006
|
+
if (bp.hitCondition)
|
|
1007
|
+
sbp.hitCondition = bp.hitCondition;
|
|
1008
|
+
return sbp;
|
|
1009
|
+
});
|
|
1010
|
+
const response = await this.getDap().send("setBreakpoints", {
|
|
1011
|
+
source: { path: file },
|
|
1012
|
+
breakpoints: dapBreakpoints
|
|
1013
|
+
});
|
|
1014
|
+
const body = response.body;
|
|
1015
|
+
for (let i = 0;i < entries.length && i < body.breakpoints.length; i++) {
|
|
1016
|
+
const bp = body.breakpoints[i];
|
|
1017
|
+
const entry = entries[i];
|
|
1018
|
+
if (bp && entry) {
|
|
1019
|
+
entry.dapId = bp.id;
|
|
1020
|
+
entry.verified = bp.verified;
|
|
1021
|
+
entry.actualLine = bp.line ?? entry.line;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
createStoppedWaiter(timeoutMs) {
|
|
1026
|
+
return new Promise((resolve, reject) => {
|
|
1027
|
+
const timer = setTimeout(() => {
|
|
1028
|
+
this.stoppedWaiter = null;
|
|
1029
|
+
resolve();
|
|
1030
|
+
}, timeoutMs);
|
|
1031
|
+
this.stoppedWaiter = {
|
|
1032
|
+
resolve: () => {
|
|
1033
|
+
clearTimeout(timer);
|
|
1034
|
+
this.stoppedWaiter = null;
|
|
1035
|
+
resolve();
|
|
1036
|
+
},
|
|
1037
|
+
reject: (e) => {
|
|
1038
|
+
clearTimeout(timer);
|
|
1039
|
+
this.stoppedWaiter = null;
|
|
1040
|
+
reject(e);
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
async waitForStop(timeoutMs) {
|
|
1046
|
+
if (!this.isPaused()) {
|
|
1047
|
+
await this.createStoppedWaiter(timeoutMs);
|
|
1048
|
+
}
|
|
1049
|
+
if (this.isPaused() && this._stackFrames.length === 0) {
|
|
1050
|
+
await this.fetchStackTrace();
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
var init_session = __esm(() => {
|
|
1055
|
+
init_ref_table();
|
|
1056
|
+
});
|
|
1057
|
+
|
|
15
1058
|
// src/daemon/logger.ts
|
|
16
1059
|
import { appendFileSync, writeFileSync } from "fs";
|
|
17
1060
|
|
|
@@ -6101,7 +7144,7 @@ var init_esm2 = __esm(() => {
|
|
|
6101
7144
|
});
|
|
6102
7145
|
|
|
6103
7146
|
// src/protocol/messages.ts
|
|
6104
|
-
var PingRequest, LaunchRequest, AttachRequest, StatusRequest, StateRequest, ContinueRequest, StepRequest, PauseRequest, RunToRequest, BreakRequest, BreakRmRequest, BreakLsRequest, LogpointRequest, CatchRequest, SourceRequest, ScriptsRequest, StackRequest, SearchRequest, ConsoleRequest, ExceptionsRequest, EvalRequest, VarsRequest, PropsRequest, BlackboxRequest, BlackboxLsRequest, BlackboxRmRequest, SetRequest, SetReturnRequest, HotpatchRequest, BreakToggleRequest, BreakableRequest, RestartFrameRequest, SourcemapRequest, SourcemapDisableRequest, RestartRequest, StopRequest, DaemonRequestSchema, SuccessResponse, ErrorResponse, DaemonResponseSchema;
|
|
7147
|
+
var PingRequest, LaunchRequest, AttachRequest, StatusRequest, StateRequest, ContinueRequest, StepRequest, PauseRequest, RunToRequest, BreakRequest, BreakFnRequest, BreakRmRequest, BreakLsRequest, LogpointRequest, CatchRequest, SourceRequest, ScriptsRequest, StackRequest, SearchRequest, ConsoleRequest, ExceptionsRequest, EvalRequest, VarsRequest, PropsRequest, BlackboxRequest, BlackboxLsRequest, BlackboxRmRequest, SetRequest, SetReturnRequest, HotpatchRequest, BreakToggleRequest, BreakableRequest, RestartFrameRequest, SourcemapRequest, SourcemapDisableRequest, RestartRequest, StopRequest, DaemonRequestSchema, SuccessResponse, ErrorResponse, DaemonResponseSchema;
|
|
6105
7148
|
var init_messages = __esm(() => {
|
|
6106
7149
|
init_esm2();
|
|
6107
7150
|
PingRequest = exports_external.object({ cmd: exports_external.literal("ping") });
|
|
@@ -6110,13 +7153,15 @@ var init_messages = __esm(() => {
|
|
|
6110
7153
|
args: exports_external.object({
|
|
6111
7154
|
command: exports_external.array(exports_external.string()),
|
|
6112
7155
|
brk: exports_external.optional(exports_external.boolean()),
|
|
6113
|
-
port: exports_external.optional(exports_external.number())
|
|
7156
|
+
port: exports_external.optional(exports_external.number()),
|
|
7157
|
+
runtime: exports_external.optional(exports_external.string())
|
|
6114
7158
|
})
|
|
6115
7159
|
});
|
|
6116
7160
|
AttachRequest = exports_external.object({
|
|
6117
7161
|
cmd: exports_external.literal("attach"),
|
|
6118
7162
|
args: exports_external.object({
|
|
6119
|
-
target: exports_external.string()
|
|
7163
|
+
target: exports_external.string(),
|
|
7164
|
+
runtime: exports_external.optional(exports_external.string())
|
|
6120
7165
|
})
|
|
6121
7166
|
});
|
|
6122
7167
|
StatusRequest = exports_external.object({ cmd: exports_external.literal("status") });
|
|
@@ -6157,7 +7202,15 @@ var init_messages = __esm(() => {
|
|
|
6157
7202
|
line: exports_external.number(),
|
|
6158
7203
|
condition: exports_external.optional(exports_external.string()),
|
|
6159
7204
|
hitCount: exports_external.optional(exports_external.number()),
|
|
6160
|
-
urlRegex: exports_external.optional(exports_external.string())
|
|
7205
|
+
urlRegex: exports_external.optional(exports_external.string()),
|
|
7206
|
+
column: exports_external.optional(exports_external.number())
|
|
7207
|
+
})
|
|
7208
|
+
});
|
|
7209
|
+
BreakFnRequest = exports_external.object({
|
|
7210
|
+
cmd: exports_external.literal("break-fn"),
|
|
7211
|
+
args: exports_external.object({
|
|
7212
|
+
name: exports_external.string(),
|
|
7213
|
+
condition: exports_external.optional(exports_external.string())
|
|
6161
7214
|
})
|
|
6162
7215
|
});
|
|
6163
7216
|
BreakRmRequest = exports_external.object({
|
|
@@ -6335,6 +7388,7 @@ var init_messages = __esm(() => {
|
|
|
6335
7388
|
PauseRequest,
|
|
6336
7389
|
RunToRequest,
|
|
6337
7390
|
BreakRequest,
|
|
7391
|
+
BreakFnRequest,
|
|
6338
7392
|
BreakRmRequest,
|
|
6339
7393
|
BreakLsRequest,
|
|
6340
7394
|
LogpointRequest,
|
|
@@ -6414,7 +7468,7 @@ class DaemonServer {
|
|
|
6414
7468
|
unix: this.socketPath,
|
|
6415
7469
|
socket: {
|
|
6416
7470
|
open(socket) {
|
|
6417
|
-
socket.data = { buffer: "" };
|
|
7471
|
+
socket.data = { buffer: "", pendingWrite: null, pendingOffset: 0 };
|
|
6418
7472
|
server.resetIdleTimer();
|
|
6419
7473
|
},
|
|
6420
7474
|
data(socket, data) {
|
|
@@ -6427,6 +7481,9 @@ class DaemonServer {
|
|
|
6427
7481
|
socket.data.buffer = socket.data.buffer.slice(newlineIdx + 1);
|
|
6428
7482
|
server.handleMessage(socket, line);
|
|
6429
7483
|
},
|
|
7484
|
+
drain(socket) {
|
|
7485
|
+
server.flushPending(socket);
|
|
7486
|
+
},
|
|
6430
7487
|
close() {},
|
|
6431
7488
|
error(_socket, error3) {
|
|
6432
7489
|
server.logger?.error("socket.error", error3.message);
|
|
@@ -6436,60 +7493,69 @@ class DaemonServer {
|
|
|
6436
7493
|
});
|
|
6437
7494
|
this.resetIdleTimer();
|
|
6438
7495
|
}
|
|
7496
|
+
flushPending(socket) {
|
|
7497
|
+
const data = socket.data;
|
|
7498
|
+
if (!data.pendingWrite)
|
|
7499
|
+
return;
|
|
7500
|
+
while (data.pendingOffset < data.pendingWrite.length) {
|
|
7501
|
+
const written = socket.write(data.pendingWrite.subarray(data.pendingOffset));
|
|
7502
|
+
if (written === 0) {
|
|
7503
|
+
return;
|
|
7504
|
+
}
|
|
7505
|
+
data.pendingOffset += written;
|
|
7506
|
+
}
|
|
7507
|
+
data.pendingWrite = null;
|
|
7508
|
+
data.pendingOffset = 0;
|
|
7509
|
+
socket.end();
|
|
7510
|
+
}
|
|
7511
|
+
sendResponse(socket, response) {
|
|
7512
|
+
const payload = Buffer.from(`${JSON.stringify(response)}
|
|
7513
|
+
`);
|
|
7514
|
+
const written = socket.write(payload);
|
|
7515
|
+
if (written < payload.length) {
|
|
7516
|
+
socket.data.pendingWrite = payload;
|
|
7517
|
+
socket.data.pendingOffset = written;
|
|
7518
|
+
} else {
|
|
7519
|
+
socket.end();
|
|
7520
|
+
}
|
|
7521
|
+
}
|
|
6439
7522
|
handleMessage(socket, line) {
|
|
6440
7523
|
let json2;
|
|
6441
7524
|
try {
|
|
6442
7525
|
json2 = JSON.parse(line);
|
|
6443
7526
|
} catch {
|
|
6444
|
-
|
|
6445
|
-
ok: false,
|
|
6446
|
-
error: "Invalid JSON"
|
|
6447
|
-
};
|
|
6448
|
-
socket.write(`${JSON.stringify(errResponse)}
|
|
6449
|
-
`);
|
|
6450
|
-
socket.end();
|
|
7527
|
+
this.sendResponse(socket, { ok: false, error: "Invalid JSON" });
|
|
6451
7528
|
return;
|
|
6452
7529
|
}
|
|
6453
7530
|
const parsed = DaemonRequestSchema.safeParse(json2);
|
|
6454
7531
|
if (!parsed.success) {
|
|
6455
7532
|
const obj = json2;
|
|
6456
7533
|
const cmd = obj && typeof obj === "object" && typeof obj.cmd === "string" ? obj.cmd : undefined;
|
|
6457
|
-
|
|
7534
|
+
this.sendResponse(socket, cmd ? {
|
|
6458
7535
|
ok: false,
|
|
6459
7536
|
error: `Unknown command: ${cmd}`,
|
|
6460
7537
|
suggestion: "-> Try: agent-dbg --help"
|
|
6461
7538
|
} : {
|
|
6462
7539
|
ok: false,
|
|
6463
7540
|
error: "Invalid request: must have { cmd: string, args: object }"
|
|
6464
|
-
};
|
|
6465
|
-
socket.write(`${JSON.stringify(errResponse)}
|
|
6466
|
-
`);
|
|
6467
|
-
socket.end();
|
|
7541
|
+
});
|
|
6468
7542
|
return;
|
|
6469
7543
|
}
|
|
6470
7544
|
const request = parsed.data;
|
|
6471
7545
|
if (!this.handler) {
|
|
6472
|
-
|
|
7546
|
+
this.sendResponse(socket, {
|
|
6473
7547
|
ok: false,
|
|
6474
7548
|
error: "No request handler registered"
|
|
6475
|
-
};
|
|
6476
|
-
socket.write(`${JSON.stringify(errResponse)}
|
|
6477
|
-
`);
|
|
6478
|
-
socket.end();
|
|
7549
|
+
});
|
|
6479
7550
|
return;
|
|
6480
7551
|
}
|
|
6481
7552
|
this.handler(request).then((response) => {
|
|
6482
|
-
|
|
6483
|
-
`);
|
|
6484
|
-
socket.end();
|
|
7553
|
+
this.sendResponse(socket, response);
|
|
6485
7554
|
}).catch((err) => {
|
|
6486
|
-
|
|
7555
|
+
this.sendResponse(socket, {
|
|
6487
7556
|
ok: false,
|
|
6488
7557
|
error: err instanceof Error ? err.message : String(err)
|
|
6489
|
-
};
|
|
6490
|
-
socket.write(`${JSON.stringify(errResponse)}
|
|
6491
|
-
`);
|
|
6492
|
-
socket.end();
|
|
7558
|
+
});
|
|
6493
7559
|
});
|
|
6494
7560
|
}
|
|
6495
7561
|
resetIdleTimer() {
|
|
@@ -6582,7 +7648,7 @@ class CdpClient {
|
|
|
6582
7648
|
this.pending.delete(id);
|
|
6583
7649
|
this.sentMethods.delete(id);
|
|
6584
7650
|
reject(new Error(`CDP request timed out: ${method} (id=${id})`));
|
|
6585
|
-
},
|
|
7651
|
+
}, DEFAULT_TIMEOUT_MS2);
|
|
6586
7652
|
this.pending.set(id, { resolve, reject, timer });
|
|
6587
7653
|
this.ws.send(JSON.stringify(request));
|
|
6588
7654
|
});
|
|
@@ -6686,7 +7752,7 @@ class CdpClient {
|
|
|
6686
7752
|
}
|
|
6687
7753
|
}
|
|
6688
7754
|
}
|
|
6689
|
-
var
|
|
7755
|
+
var DEFAULT_TIMEOUT_MS2 = 30000;
|
|
6690
7756
|
|
|
6691
7757
|
// src/cdp/logger.ts
|
|
6692
7758
|
import { appendFileSync as appendFileSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
@@ -6943,101 +8009,6 @@ function formatValue(obj, maxLen = 80) {
|
|
|
6943
8009
|
return truncate(obj.description ?? String(obj.value ?? obj.type), maxLen);
|
|
6944
8010
|
}
|
|
6945
8011
|
|
|
6946
|
-
// src/refs/ref-table.ts
|
|
6947
|
-
class RefTable {
|
|
6948
|
-
entries = new Map;
|
|
6949
|
-
counters = {
|
|
6950
|
-
v: 1,
|
|
6951
|
-
f: 0,
|
|
6952
|
-
o: 1,
|
|
6953
|
-
BP: 1,
|
|
6954
|
-
LP: 1,
|
|
6955
|
-
HS: 1
|
|
6956
|
-
};
|
|
6957
|
-
addVar(remoteId, name, meta) {
|
|
6958
|
-
return this.add("v", remoteId, name, meta);
|
|
6959
|
-
}
|
|
6960
|
-
addFrame(remoteId, name, meta) {
|
|
6961
|
-
return this.add("f", remoteId, name, meta);
|
|
6962
|
-
}
|
|
6963
|
-
addObject(remoteId, name, meta) {
|
|
6964
|
-
return this.add("o", remoteId, name, meta);
|
|
6965
|
-
}
|
|
6966
|
-
addBreakpoint(remoteId, meta) {
|
|
6967
|
-
return this.add("BP", remoteId, undefined, meta);
|
|
6968
|
-
}
|
|
6969
|
-
addLogpoint(remoteId, meta) {
|
|
6970
|
-
return this.add("LP", remoteId, undefined, meta);
|
|
6971
|
-
}
|
|
6972
|
-
addHeapSnapshot(remoteId, meta) {
|
|
6973
|
-
return this.add("HS", remoteId, undefined, meta);
|
|
6974
|
-
}
|
|
6975
|
-
resolve(ref) {
|
|
6976
|
-
return this.entries.get(ref);
|
|
6977
|
-
}
|
|
6978
|
-
resolveId(ref) {
|
|
6979
|
-
return this.entries.get(ref)?.remoteId;
|
|
6980
|
-
}
|
|
6981
|
-
clearVolatile() {
|
|
6982
|
-
for (const [key, entry] of this.entries) {
|
|
6983
|
-
if (entry.type === "v" || entry.type === "f") {
|
|
6984
|
-
this.entries.delete(key);
|
|
6985
|
-
}
|
|
6986
|
-
}
|
|
6987
|
-
this.counters.v = 1;
|
|
6988
|
-
this.counters.f = 0;
|
|
6989
|
-
}
|
|
6990
|
-
clearObjects() {
|
|
6991
|
-
for (const [key, entry] of this.entries) {
|
|
6992
|
-
if (entry.type === "o") {
|
|
6993
|
-
this.entries.delete(key);
|
|
6994
|
-
}
|
|
6995
|
-
}
|
|
6996
|
-
this.counters.o = 1;
|
|
6997
|
-
}
|
|
6998
|
-
clearAll() {
|
|
6999
|
-
this.entries.clear();
|
|
7000
|
-
this.counters = { v: 1, f: 0, o: 1, BP: 1, LP: 1, HS: 1 };
|
|
7001
|
-
}
|
|
7002
|
-
list(type) {
|
|
7003
|
-
const result = [];
|
|
7004
|
-
for (const entry of this.entries.values()) {
|
|
7005
|
-
if (entry.type === type) {
|
|
7006
|
-
result.push(entry);
|
|
7007
|
-
}
|
|
7008
|
-
}
|
|
7009
|
-
return result;
|
|
7010
|
-
}
|
|
7011
|
-
remove(ref) {
|
|
7012
|
-
return this.entries.delete(ref);
|
|
7013
|
-
}
|
|
7014
|
-
add(type, remoteId, name, meta) {
|
|
7015
|
-
const num = this.counters[type];
|
|
7016
|
-
this.counters[type] = num + 1;
|
|
7017
|
-
const ref = `${PREFIXES[type]}${num}`;
|
|
7018
|
-
const entry = { ref, type, remoteId };
|
|
7019
|
-
if (name !== undefined) {
|
|
7020
|
-
entry.name = name;
|
|
7021
|
-
}
|
|
7022
|
-
if (meta !== undefined) {
|
|
7023
|
-
entry.meta = meta;
|
|
7024
|
-
}
|
|
7025
|
-
this.entries.set(ref, entry);
|
|
7026
|
-
return ref;
|
|
7027
|
-
}
|
|
7028
|
-
}
|
|
7029
|
-
var PREFIXES;
|
|
7030
|
-
var init_ref_table = __esm(() => {
|
|
7031
|
-
PREFIXES = {
|
|
7032
|
-
v: "@v",
|
|
7033
|
-
f: "@f",
|
|
7034
|
-
o: "@o",
|
|
7035
|
-
BP: "BP#",
|
|
7036
|
-
LP: "LP#",
|
|
7037
|
-
HS: "HS#"
|
|
7038
|
-
};
|
|
7039
|
-
});
|
|
7040
|
-
|
|
7041
8012
|
// node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
|
|
7042
8013
|
function decodeInteger(reader, relative) {
|
|
7043
8014
|
let value = 0;
|
|
@@ -8861,7 +9832,8 @@ async function hotpatch(session, file2, newSource, options = {}) {
|
|
|
8861
9832
|
}
|
|
8862
9833
|
const setSourceParams = {
|
|
8863
9834
|
scriptId,
|
|
8864
|
-
scriptSource: newSource
|
|
9835
|
+
scriptSource: newSource,
|
|
9836
|
+
allowTopFrameEditing: true
|
|
8865
9837
|
};
|
|
8866
9838
|
if (options.dryRun) {
|
|
8867
9839
|
setSourceParams.dryRun = true;
|
|
@@ -9629,7 +10601,7 @@ class DebugSession {
|
|
|
9629
10601
|
}
|
|
9630
10602
|
}
|
|
9631
10603
|
var INSPECTOR_URL_REGEX, INSPECTOR_TIMEOUT_MS = 5000;
|
|
9632
|
-
var
|
|
10604
|
+
var init_session2 = __esm(() => {
|
|
9633
10605
|
init_logger2();
|
|
9634
10606
|
init_ref_table();
|
|
9635
10607
|
init_resolver();
|
|
@@ -9643,12 +10615,19 @@ var init_session = __esm(() => {
|
|
|
9643
10615
|
|
|
9644
10616
|
// src/daemon/entry.ts
|
|
9645
10617
|
var exports_entry = {};
|
|
9646
|
-
|
|
10618
|
+
function isDapRuntime(runtime) {
|
|
10619
|
+
return runtime !== undefined && runtime !== "node";
|
|
10620
|
+
}
|
|
10621
|
+
function activeSession() {
|
|
10622
|
+
return dapSession ?? cdpSession;
|
|
10623
|
+
}
|
|
10624
|
+
var daemonIdx, session, timeout = 300, timeoutIdx, daemonLogger, server, cdpSession, dapSession = null;
|
|
9647
10625
|
var init_entry = __esm(async () => {
|
|
10626
|
+
init_session();
|
|
9648
10627
|
init_logger();
|
|
9649
10628
|
init_paths();
|
|
9650
10629
|
init_server();
|
|
9651
|
-
|
|
10630
|
+
init_session2();
|
|
9652
10631
|
daemonIdx = process.argv.indexOf("--daemon");
|
|
9653
10632
|
session = daemonIdx !== -1 ? process.argv[daemonIdx + 1] : process.argv[2];
|
|
9654
10633
|
if (!session) {
|
|
@@ -9673,52 +10652,62 @@ var init_entry = __esm(async () => {
|
|
|
9673
10652
|
timeout
|
|
9674
10653
|
});
|
|
9675
10654
|
server = new DaemonServer(session, { idleTimeout: timeout, logger: daemonLogger });
|
|
9676
|
-
|
|
10655
|
+
cdpSession = new DebugSession(session, { daemonLogger });
|
|
9677
10656
|
server.onRequest(async (req) => {
|
|
9678
10657
|
switch (req.cmd) {
|
|
9679
10658
|
case "ping":
|
|
9680
10659
|
return { ok: true, data: "pong" };
|
|
9681
10660
|
case "launch": {
|
|
9682
|
-
const { command, brk = true, port } = req.args;
|
|
9683
|
-
|
|
10661
|
+
const { command, brk = true, port, runtime } = req.args;
|
|
10662
|
+
if (isDapRuntime(runtime)) {
|
|
10663
|
+
dapSession = new DapSession(session, runtime);
|
|
10664
|
+
const result2 = await dapSession.launch(command, { brk });
|
|
10665
|
+
return { ok: true, data: result2 };
|
|
10666
|
+
}
|
|
10667
|
+
const result = await cdpSession.launch(command, { brk, port });
|
|
9684
10668
|
return { ok: true, data: result };
|
|
9685
10669
|
}
|
|
9686
10670
|
case "attach": {
|
|
9687
|
-
const { target } = req.args;
|
|
9688
|
-
|
|
10671
|
+
const { target, runtime } = req.args;
|
|
10672
|
+
if (isDapRuntime(runtime)) {
|
|
10673
|
+
dapSession = new DapSession(session, runtime);
|
|
10674
|
+
const result2 = await dapSession.attach(target);
|
|
10675
|
+
return { ok: true, data: result2 };
|
|
10676
|
+
}
|
|
10677
|
+
const result = await cdpSession.attach(target);
|
|
9689
10678
|
return { ok: true, data: result };
|
|
9690
10679
|
}
|
|
9691
10680
|
case "status":
|
|
9692
|
-
return { ok: true, data:
|
|
10681
|
+
return { ok: true, data: activeSession().getStatus() };
|
|
9693
10682
|
case "state": {
|
|
9694
|
-
const stateResult = await
|
|
10683
|
+
const stateResult = await activeSession().buildState(req.args);
|
|
9695
10684
|
return { ok: true, data: stateResult };
|
|
9696
10685
|
}
|
|
9697
10686
|
case "continue": {
|
|
9698
|
-
await
|
|
9699
|
-
const stateAfter = await
|
|
10687
|
+
await activeSession().continue();
|
|
10688
|
+
const stateAfter = await activeSession().buildState();
|
|
9700
10689
|
return { ok: true, data: stateAfter };
|
|
9701
10690
|
}
|
|
9702
10691
|
case "step": {
|
|
9703
10692
|
const { mode = "over" } = req.args;
|
|
9704
|
-
await
|
|
9705
|
-
const stateAfter = await
|
|
10693
|
+
await activeSession().step(mode);
|
|
10694
|
+
const stateAfter = await activeSession().buildState();
|
|
9706
10695
|
return { ok: true, data: stateAfter };
|
|
9707
10696
|
}
|
|
9708
10697
|
case "pause": {
|
|
9709
|
-
await
|
|
9710
|
-
const stateAfter = await
|
|
10698
|
+
await activeSession().pause();
|
|
10699
|
+
const stateAfter = await activeSession().buildState();
|
|
9711
10700
|
return { ok: true, data: stateAfter };
|
|
9712
10701
|
}
|
|
9713
10702
|
case "run-to": {
|
|
9714
10703
|
const { file: file2, line } = req.args;
|
|
9715
|
-
await
|
|
9716
|
-
const stateAfter = await
|
|
10704
|
+
await activeSession().runTo(file2, line);
|
|
10705
|
+
const stateAfter = await activeSession().buildState();
|
|
9717
10706
|
return { ok: true, data: stateAfter };
|
|
9718
10707
|
}
|
|
9719
10708
|
case "break": {
|
|
9720
10709
|
const { file: file2, line, condition, hitCount, urlRegex: urlRegex2, column } = req.args;
|
|
9721
|
-
const bpResult = await
|
|
10710
|
+
const bpResult = await activeSession().setBreakpoint(file2, line, {
|
|
9722
10711
|
condition,
|
|
9723
10712
|
hitCount,
|
|
9724
10713
|
urlRegex: urlRegex2,
|
|
@@ -9726,20 +10715,35 @@ var init_entry = __esm(async () => {
|
|
|
9726
10715
|
});
|
|
9727
10716
|
return { ok: true, data: bpResult };
|
|
9728
10717
|
}
|
|
10718
|
+
case "break-fn": {
|
|
10719
|
+
const session2 = activeSession();
|
|
10720
|
+
if (!("setFunctionBreakpoint" in session2)) {
|
|
10721
|
+
return {
|
|
10722
|
+
ok: false,
|
|
10723
|
+
error: "Function breakpoints are only supported with DAP runtimes (e.g. --runtime lldb)",
|
|
10724
|
+
suggestion: "Use 'break <file>:<line>' for CDP sessions"
|
|
10725
|
+
};
|
|
10726
|
+
}
|
|
10727
|
+
const { name, condition } = req.args;
|
|
10728
|
+
const bpResult = await session2.setFunctionBreakpoint(name, {
|
|
10729
|
+
condition
|
|
10730
|
+
});
|
|
10731
|
+
return { ok: true, data: bpResult };
|
|
10732
|
+
}
|
|
9729
10733
|
case "break-rm": {
|
|
9730
10734
|
const { ref } = req.args;
|
|
9731
10735
|
if (ref === "all") {
|
|
9732
|
-
await
|
|
10736
|
+
await activeSession().removeAllBreakpoints();
|
|
9733
10737
|
return { ok: true, data: "all removed" };
|
|
9734
10738
|
}
|
|
9735
|
-
await
|
|
10739
|
+
await activeSession().removeBreakpoint(ref);
|
|
9736
10740
|
return { ok: true, data: "removed" };
|
|
9737
10741
|
}
|
|
9738
10742
|
case "break-ls":
|
|
9739
|
-
return { ok: true, data:
|
|
10743
|
+
return { ok: true, data: activeSession().listBreakpoints() };
|
|
9740
10744
|
case "logpoint": {
|
|
9741
10745
|
const { file: file2, line, template, condition, maxEmissions } = req.args;
|
|
9742
|
-
const lpResult = await
|
|
10746
|
+
const lpResult = await activeSession().setLogpoint(file2, line, template, {
|
|
9743
10747
|
condition,
|
|
9744
10748
|
maxEmissions
|
|
9745
10749
|
});
|
|
@@ -9747,114 +10751,115 @@ var init_entry = __esm(async () => {
|
|
|
9747
10751
|
}
|
|
9748
10752
|
case "catch": {
|
|
9749
10753
|
const { mode } = req.args;
|
|
9750
|
-
await
|
|
10754
|
+
await activeSession().setExceptionPause(mode);
|
|
9751
10755
|
return { ok: true, data: mode };
|
|
9752
10756
|
}
|
|
9753
10757
|
case "source": {
|
|
9754
|
-
const sourceResult = await
|
|
10758
|
+
const sourceResult = await activeSession().getSource(req.args);
|
|
9755
10759
|
return { ok: true, data: sourceResult };
|
|
9756
10760
|
}
|
|
9757
10761
|
case "scripts": {
|
|
9758
10762
|
const { filter } = req.args;
|
|
9759
|
-
const scriptsResult =
|
|
10763
|
+
const scriptsResult = activeSession().getScripts(filter);
|
|
9760
10764
|
return { ok: true, data: scriptsResult };
|
|
9761
10765
|
}
|
|
9762
10766
|
case "stack": {
|
|
9763
|
-
const stackResult =
|
|
10767
|
+
const stackResult = activeSession().getStack(req.args);
|
|
9764
10768
|
return { ok: true, data: stackResult };
|
|
9765
10769
|
}
|
|
9766
10770
|
case "search": {
|
|
9767
10771
|
const { query, ...searchOptions } = req.args;
|
|
9768
|
-
const searchResult = await
|
|
10772
|
+
const searchResult = await activeSession().searchInScripts(query, searchOptions);
|
|
9769
10773
|
return { ok: true, data: searchResult };
|
|
9770
10774
|
}
|
|
9771
10775
|
case "console": {
|
|
9772
|
-
const consoleResult =
|
|
10776
|
+
const consoleResult = activeSession().getConsoleMessages(req.args);
|
|
9773
10777
|
return { ok: true, data: consoleResult };
|
|
9774
10778
|
}
|
|
9775
10779
|
case "exceptions": {
|
|
9776
|
-
const exceptionsResult =
|
|
10780
|
+
const exceptionsResult = activeSession().getExceptions(req.args);
|
|
9777
10781
|
return { ok: true, data: exceptionsResult };
|
|
9778
10782
|
}
|
|
9779
10783
|
case "eval": {
|
|
9780
10784
|
const { expression, ...evalOptions } = req.args;
|
|
9781
|
-
const evalResult = await
|
|
10785
|
+
const evalResult = await activeSession().eval(expression, evalOptions);
|
|
9782
10786
|
return { ok: true, data: evalResult };
|
|
9783
10787
|
}
|
|
9784
10788
|
case "vars": {
|
|
9785
|
-
const varsResult = await
|
|
10789
|
+
const varsResult = await activeSession().getVars(req.args);
|
|
9786
10790
|
return { ok: true, data: varsResult };
|
|
9787
10791
|
}
|
|
9788
10792
|
case "props": {
|
|
9789
10793
|
const { ref, ...propsOptions } = req.args;
|
|
9790
|
-
const propsResult = await
|
|
10794
|
+
const propsResult = await activeSession().getProps(ref, propsOptions);
|
|
9791
10795
|
return { ok: true, data: propsResult };
|
|
9792
10796
|
}
|
|
9793
10797
|
case "blackbox": {
|
|
9794
10798
|
const { patterns } = req.args;
|
|
9795
|
-
const result = await
|
|
10799
|
+
const result = await activeSession().addBlackbox(patterns);
|
|
9796
10800
|
return { ok: true, data: result };
|
|
9797
10801
|
}
|
|
9798
10802
|
case "blackbox-ls": {
|
|
9799
|
-
return { ok: true, data:
|
|
10803
|
+
return { ok: true, data: activeSession().listBlackbox() };
|
|
9800
10804
|
}
|
|
9801
10805
|
case "blackbox-rm": {
|
|
9802
10806
|
const { patterns } = req.args;
|
|
9803
|
-
const result = await
|
|
10807
|
+
const result = await activeSession().removeBlackbox(patterns);
|
|
9804
10808
|
return { ok: true, data: result };
|
|
9805
10809
|
}
|
|
9806
10810
|
case "set": {
|
|
9807
10811
|
const { name, value, frame } = req.args;
|
|
9808
|
-
const result = await
|
|
10812
|
+
const result = await activeSession().setVariable(name, value, { frame });
|
|
9809
10813
|
return { ok: true, data: result };
|
|
9810
10814
|
}
|
|
9811
10815
|
case "set-return": {
|
|
9812
10816
|
const { value } = req.args;
|
|
9813
|
-
const result = await
|
|
10817
|
+
const result = await activeSession().setReturnValue(value);
|
|
9814
10818
|
return { ok: true, data: result };
|
|
9815
10819
|
}
|
|
9816
10820
|
case "hotpatch": {
|
|
9817
10821
|
const { file: file2, source, dryRun } = req.args;
|
|
9818
|
-
const result = await
|
|
10822
|
+
const result = await activeSession().hotpatch(file2, source, { dryRun });
|
|
9819
10823
|
return { ok: true, data: result };
|
|
9820
10824
|
}
|
|
9821
10825
|
case "break-toggle": {
|
|
9822
10826
|
const { ref } = req.args;
|
|
9823
|
-
const toggleResult = await
|
|
10827
|
+
const toggleResult = await activeSession().toggleBreakpoint(ref);
|
|
9824
10828
|
return { ok: true, data: toggleResult };
|
|
9825
10829
|
}
|
|
9826
10830
|
case "breakable": {
|
|
9827
10831
|
const { file: file2, startLine, endLine } = req.args;
|
|
9828
|
-
const breakableResult = await
|
|
10832
|
+
const breakableResult = await activeSession().getBreakableLocations(file2, startLine, endLine);
|
|
9829
10833
|
return { ok: true, data: breakableResult };
|
|
9830
10834
|
}
|
|
9831
10835
|
case "restart-frame": {
|
|
9832
10836
|
const { frameRef } = req.args;
|
|
9833
|
-
const restartResult = await
|
|
10837
|
+
const restartResult = await activeSession().restartFrame(frameRef);
|
|
9834
10838
|
return { ok: true, data: restartResult };
|
|
9835
10839
|
}
|
|
9836
10840
|
case "sourcemap": {
|
|
9837
10841
|
const { file: smFile } = req.args;
|
|
9838
10842
|
if (smFile) {
|
|
9839
|
-
const match =
|
|
10843
|
+
const match = activeSession().sourceMapResolver.findScriptForSource(smFile);
|
|
9840
10844
|
if (match) {
|
|
9841
|
-
const info =
|
|
10845
|
+
const info = activeSession().sourceMapResolver.getInfo(match.scriptId);
|
|
9842
10846
|
return { ok: true, data: info ? [info] : [] };
|
|
9843
10847
|
}
|
|
9844
10848
|
return { ok: true, data: [] };
|
|
9845
10849
|
}
|
|
9846
|
-
return { ok: true, data:
|
|
10850
|
+
return { ok: true, data: activeSession().sourceMapResolver.getAllInfos() };
|
|
9847
10851
|
}
|
|
9848
10852
|
case "sourcemap-disable": {
|
|
9849
|
-
|
|
10853
|
+
activeSession().sourceMapResolver.setDisabled(true);
|
|
9850
10854
|
return { ok: true, data: "disabled" };
|
|
9851
10855
|
}
|
|
9852
10856
|
case "restart": {
|
|
9853
|
-
const result = await
|
|
10857
|
+
const result = await activeSession().restart();
|
|
9854
10858
|
return { ok: true, data: result };
|
|
9855
10859
|
}
|
|
9856
10860
|
case "stop":
|
|
9857
|
-
await
|
|
10861
|
+
await activeSession().stop();
|
|
10862
|
+
dapSession = null;
|
|
9858
10863
|
setTimeout(() => {
|
|
9859
10864
|
server.stop();
|
|
9860
10865
|
process.exit(0);
|
|
@@ -9875,7 +10880,7 @@ var init_registry = __esm(() => {
|
|
|
9875
10880
|
});
|
|
9876
10881
|
|
|
9877
10882
|
// src/daemon/client.ts
|
|
9878
|
-
import { existsSync as existsSync3,
|
|
10883
|
+
import { existsSync as existsSync3, readdirSync, readFileSync, unlinkSync as unlinkSync2 } from "fs";
|
|
9879
10884
|
|
|
9880
10885
|
class DaemonClient {
|
|
9881
10886
|
session;
|
|
@@ -9895,9 +10900,9 @@ class DaemonClient {
|
|
|
9895
10900
|
const timer = setTimeout(() => {
|
|
9896
10901
|
if (!settled) {
|
|
9897
10902
|
settled = true;
|
|
9898
|
-
reject(new Error(`Request timed out after ${
|
|
10903
|
+
reject(new Error(`Request timed out after ${DEFAULT_TIMEOUT_MS3}ms`));
|
|
9899
10904
|
}
|
|
9900
|
-
},
|
|
10905
|
+
}, DEFAULT_TIMEOUT_MS3);
|
|
9901
10906
|
Bun.connect({
|
|
9902
10907
|
unix: socketPath,
|
|
9903
10908
|
socket: {
|
|
@@ -10019,20 +11024,20 @@ class DaemonClient {
|
|
|
10019
11024
|
return files.filter((f) => f.endsWith(".sock")).map((f) => f.slice(0, -5));
|
|
10020
11025
|
}
|
|
10021
11026
|
}
|
|
10022
|
-
var
|
|
11027
|
+
var DEFAULT_TIMEOUT_MS3 = 30000;
|
|
10023
11028
|
var init_client = __esm(() => {
|
|
10024
11029
|
init_messages();
|
|
10025
11030
|
init_paths();
|
|
10026
11031
|
});
|
|
10027
11032
|
|
|
10028
11033
|
// src/daemon/spawn.ts
|
|
10029
|
-
import { existsSync as existsSync4, openSync } from "fs";
|
|
11034
|
+
import { existsSync as existsSync4, openSync, readFileSync as readFileSync2 } from "fs";
|
|
10030
11035
|
async function spawnDaemon(session2, options = {}) {
|
|
10031
11036
|
const socketPath = getSocketPath(session2);
|
|
10032
11037
|
const spawnArgs = [];
|
|
10033
11038
|
const execPath = process.execPath;
|
|
10034
11039
|
const scriptPath = process.argv[1];
|
|
10035
|
-
if (scriptPath && scriptPath.endsWith(".ts")) {
|
|
11040
|
+
if (scriptPath && (scriptPath.endsWith(".ts") || scriptPath.endsWith(".js"))) {
|
|
10036
11041
|
spawnArgs.push(execPath, "run", scriptPath);
|
|
10037
11042
|
} else {
|
|
10038
11043
|
spawnArgs.push(execPath);
|
|
@@ -10057,7 +11062,24 @@ async function spawnDaemon(session2, options = {}) {
|
|
|
10057
11062
|
}
|
|
10058
11063
|
await Bun.sleep(POLL_INTERVAL_MS);
|
|
10059
11064
|
}
|
|
10060
|
-
|
|
11065
|
+
const logPath = getDaemonLogPath(session2);
|
|
11066
|
+
let logTail = "";
|
|
11067
|
+
try {
|
|
11068
|
+
const log = readFileSync2(logPath, "utf-8");
|
|
11069
|
+
const lines = log.trimEnd().split(`
|
|
11070
|
+
`);
|
|
11071
|
+
logTail = lines.slice(-20).join(`
|
|
11072
|
+
`);
|
|
11073
|
+
} catch {}
|
|
11074
|
+
const details = [
|
|
11075
|
+
`Daemon for session "${session2}" failed to start within ${SPAWN_TIMEOUT_MS}ms`,
|
|
11076
|
+
`Spawn command: ${spawnArgs.join(" ")}`,
|
|
11077
|
+
`Socket path: ${socketPath}`,
|
|
11078
|
+
logTail ? `Daemon log (last 20 lines):
|
|
11079
|
+
${logTail}` : `No daemon log at ${logPath}`
|
|
11080
|
+
].join(`
|
|
11081
|
+
`);
|
|
11082
|
+
throw new Error(details);
|
|
10061
11083
|
}
|
|
10062
11084
|
async function ensureDaemon(session2, options) {
|
|
10063
11085
|
if (DaemonClient.isRunning(session2))
|
|
@@ -10105,6 +11127,7 @@ var init_launch = __esm(() => {
|
|
|
10105
11127
|
const brk = args.flags.brk === true;
|
|
10106
11128
|
const port = typeof args.flags.port === "string" ? parseInt(args.flags.port, 10) : undefined;
|
|
10107
11129
|
const timeout2 = typeof args.flags.timeout === "string" ? parseInt(args.flags.timeout, 10) : undefined;
|
|
11130
|
+
const runtime = typeof args.flags.runtime === "string" ? args.flags.runtime : undefined;
|
|
10108
11131
|
const command = args.subcommand ? [args.subcommand, ...args.positionals] : [...args.positionals];
|
|
10109
11132
|
if (command.length === 0) {
|
|
10110
11133
|
console.error("No command specified");
|
|
@@ -10113,7 +11136,7 @@ var init_launch = __esm(() => {
|
|
|
10113
11136
|
}
|
|
10114
11137
|
await ensureDaemon(session2, { timeout: timeout2 });
|
|
10115
11138
|
const client = new DaemonClient(session2);
|
|
10116
|
-
const response = await client.request("launch", { command, brk, port });
|
|
11139
|
+
const response = await client.request("launch", { command, brk, port, runtime });
|
|
10117
11140
|
if (!response.ok) {
|
|
10118
11141
|
console.error(`${response.error}`);
|
|
10119
11142
|
if (response.suggestion)
|
|
@@ -10146,6 +11169,7 @@ var init_attach = __esm(() => {
|
|
|
10146
11169
|
registerCommand("attach", async (args) => {
|
|
10147
11170
|
const session2 = args.global.session;
|
|
10148
11171
|
const target = args.subcommand ?? args.positionals[0];
|
|
11172
|
+
const runtime = typeof args.flags.runtime === "string" ? args.flags.runtime : undefined;
|
|
10149
11173
|
if (!target) {
|
|
10150
11174
|
console.error("No target specified");
|
|
10151
11175
|
console.error(" -> Try: agent-dbg attach <ws-url | port>");
|
|
@@ -10159,7 +11183,7 @@ var init_attach = __esm(() => {
|
|
|
10159
11183
|
const timeout2 = typeof args.flags.timeout === "string" ? parseInt(args.flags.timeout, 10) : undefined;
|
|
10160
11184
|
await ensureDaemon(session2, { timeout: timeout2 });
|
|
10161
11185
|
const client = new DaemonClient(session2);
|
|
10162
|
-
const response = await client.request("attach", { target });
|
|
11186
|
+
const response = await client.request("attach", { target, runtime });
|
|
10163
11187
|
if (!response.ok) {
|
|
10164
11188
|
console.error(`${response.error}`);
|
|
10165
11189
|
if (response.suggestion)
|
|
@@ -10919,6 +11943,44 @@ var init_break = __esm(() => {
|
|
|
10919
11943
|
});
|
|
10920
11944
|
});
|
|
10921
11945
|
|
|
11946
|
+
// src/commands/break-fn.ts
|
|
11947
|
+
var exports_break_fn = {};
|
|
11948
|
+
var init_break_fn = __esm(() => {
|
|
11949
|
+
init_registry();
|
|
11950
|
+
init_client();
|
|
11951
|
+
registerCommand("break-fn", async (args) => {
|
|
11952
|
+
const session2 = args.global.session;
|
|
11953
|
+
if (!DaemonClient.isRunning(session2)) {
|
|
11954
|
+
console.error(`No active session "${session2}"`);
|
|
11955
|
+
console.error(" -> Try: agent-dbg launch --brk --runtime lldb ./program");
|
|
11956
|
+
return 1;
|
|
11957
|
+
}
|
|
11958
|
+
const name = args.subcommand;
|
|
11959
|
+
if (!name) {
|
|
11960
|
+
console.error("Usage: agent-dbg break-fn <function-name>");
|
|
11961
|
+
console.error(" Example: agent-dbg break-fn __assert_rtn");
|
|
11962
|
+
console.error(" Example: agent-dbg break-fn 'yoga::Style::operator=='");
|
|
11963
|
+
return 1;
|
|
11964
|
+
}
|
|
11965
|
+
const condition = typeof args.flags.condition === "string" ? args.flags.condition : undefined;
|
|
11966
|
+
const client = new DaemonClient(session2);
|
|
11967
|
+
const response = await client.request("break-fn", { name, condition });
|
|
11968
|
+
if (!response.ok) {
|
|
11969
|
+
console.error(`${response.error}`);
|
|
11970
|
+
if (response.suggestion)
|
|
11971
|
+
console.error(` ${response.suggestion}`);
|
|
11972
|
+
return 1;
|
|
11973
|
+
}
|
|
11974
|
+
const data = response.data;
|
|
11975
|
+
if (args.global.json) {
|
|
11976
|
+
console.log(JSON.stringify(data, null, 2));
|
|
11977
|
+
} else {
|
|
11978
|
+
console.log(`${data.ref} fn:${name}`);
|
|
11979
|
+
}
|
|
11980
|
+
return 0;
|
|
11981
|
+
});
|
|
11982
|
+
});
|
|
11983
|
+
|
|
10922
11984
|
// src/commands/break-rm.ts
|
|
10923
11985
|
var exports_break_rm = {};
|
|
10924
11986
|
var init_break_rm = __esm(() => {
|
|
@@ -12191,7 +13253,7 @@ import {
|
|
|
12191
13253
|
closeSync,
|
|
12192
13254
|
existsSync as existsSync5,
|
|
12193
13255
|
openSync as openSync2,
|
|
12194
|
-
readFileSync as
|
|
13256
|
+
readFileSync as readFileSync3,
|
|
12195
13257
|
readSync,
|
|
12196
13258
|
watch,
|
|
12197
13259
|
writeFileSync as writeFileSync4
|
|
@@ -12271,7 +13333,7 @@ var init_logs2 = __esm(() => {
|
|
|
12271
13333
|
const level = typeof args.flags.level === "string" ? args.flags.level : undefined;
|
|
12272
13334
|
const limit = typeof args.flags.limit === "string" ? parseInt(args.flags.limit, 10) : 50;
|
|
12273
13335
|
const follow = args.flags.follow === true;
|
|
12274
|
-
const content =
|
|
13336
|
+
const content = readFileSync3(logPath, "utf-8");
|
|
12275
13337
|
if (isDaemon) {
|
|
12276
13338
|
let entries = parseDaemonEntries(content);
|
|
12277
13339
|
if (level)
|
|
@@ -12630,6 +13692,7 @@ if (process.argv.includes("--daemon")) {
|
|
|
12630
13692
|
await Promise.resolve().then(() => (init_pause(), exports_pause));
|
|
12631
13693
|
await Promise.resolve().then(() => (init_run_to(), exports_run_to));
|
|
12632
13694
|
await Promise.resolve().then(() => (init_break(), exports_break));
|
|
13695
|
+
await Promise.resolve().then(() => (init_break_fn(), exports_break_fn));
|
|
12633
13696
|
await Promise.resolve().then(() => (init_break_rm(), exports_break_rm));
|
|
12634
13697
|
await Promise.resolve().then(() => (init_break_ls(), exports_break_ls));
|
|
12635
13698
|
await Promise.resolve().then(() => (init_logpoint(), exports_logpoint));
|