agent-dbg 0.1.2 → 0.1.3

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.
@@ -17,7 +17,9 @@
17
17
  "Bash(grep:*)",
18
18
  "Bash(npm view:*)",
19
19
  "Bash(find:*)",
20
- "Bash(xargs sed:*)"
20
+ "Bash(xargs sed:*)",
21
+ "Bash(ps:*)",
22
+ "Bash(ls:*)"
21
23
  ]
22
24
  }
23
25
  }
@@ -20,6 +20,8 @@ description: >
20
20
  ```bash
21
21
  # 1. Launch with breakpoint at first line
22
22
  agent-dbg launch --brk node app.js
23
+ # Or attach to a running node process with the --inspect flag
24
+ agent-dbg attach 9229
23
25
 
24
26
  # 2. Set breakpoints at suspicious locations
25
27
  agent-dbg break src/handler.ts:42
@@ -111,7 +111,8 @@ agent-dbg exceptions --since 3 # Last 3 exceptions
111
111
  ## Breakpoints
112
112
 
113
113
  ```bash
114
- agent-dbg break <file>:<line> # Set breakpoint
114
+ agent-dbg break <file>:<line> # Set breakpoint
115
+ agent-dbg break <file>:<line>:<column> # Set breakpoint
115
116
  agent-dbg break src/app.ts:42 --condition "x > 10" # Conditional
116
117
  agent-dbg break src/app.ts:42 --hit-count 5 # Break on Nth hit
117
118
  agent-dbg break src/app.ts:42 --continue # Log but don't pause
package/bun.lock ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 1,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "ndbg",
7
+ "dependencies": {
8
+ "@jridgewell/trace-mapping": "^0.3.31",
9
+ "zod": "^4.0.0",
10
+ },
11
+ "devDependencies": {
12
+ "@biomejs/biome": "^2.3.14",
13
+ "@types/bun": "latest",
14
+ "devtools-protocol": "^0.0.1581282",
15
+ },
16
+ "peerDependencies": {
17
+ "typescript": "^5",
18
+ },
19
+ },
20
+ },
21
+ "packages": {
22
+ "@biomejs/biome": ["@biomejs/biome@2.3.14", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.14", "@biomejs/cli-darwin-x64": "2.3.14", "@biomejs/cli-linux-arm64": "2.3.14", "@biomejs/cli-linux-arm64-musl": "2.3.14", "@biomejs/cli-linux-x64": "2.3.14", "@biomejs/cli-linux-x64-musl": "2.3.14", "@biomejs/cli-win32-arm64": "2.3.14", "@biomejs/cli-win32-x64": "2.3.14" }, "bin": { "biome": "bin/biome" } }, "sha512-QMT6QviX0WqXJCaiqVMiBUCr5WRQ1iFSjvOLoTk6auKukJMvnMzWucXpwZB0e8F00/1/BsS9DzcKgWH+CLqVuA=="],
23
+
24
+ "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UJGPpvWJMkLxSRtpCAKfKh41Q4JJXisvxZL8ChN1eNW3m/WlPFJ6EFDCE7YfUb4XS8ZFi3C1dFpxUJ0Ety5n+A=="],
25
+
26
+ "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-PNkLNQG6RLo8lG7QoWe/hhnMxJIt1tEimoXpGQjwS/dkdNiKBLPv4RpeQl8o3s1OKI3ZOR5XPiYtmbGGHAOnLA=="],
27
+
28
+ "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-KT67FKfzIw6DNnUNdYlBg+eU24Go3n75GWK6NwU4+yJmDYFe9i/MjiI+U/iEzKvo0g7G7MZqoyrhIYuND2w8QQ=="],
29
+
30
+ "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-LInRbXhYujtL3sH2TMCH/UBwJZsoGwfQjBrMfl84CD4hL/41C/EU5mldqf1yoFpsI0iPWuU83U+nB2TUUypWeg=="],
31
+
32
+ "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-ZsZzQsl9U+wxFrGGS4f6UxREUlgHwmEfu1IrXlgNFrNnd5Th6lIJr8KmSzu/+meSa9f4rzFrbEW9LBBA6ScoMA=="],
33
+
34
+ "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-KQU7EkbBBuHPW3/rAcoiVmhlPtDSGOGRPv9js7qJVpYTzjQmVR+C9Rfcz+ti8YCH+zT1J52tuBybtP4IodjxZQ=="],
35
+
36
+ "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-+IKYkj/pUBbnRf1G1+RlyA3LWiDgra1xpS7H2g4BuOzzRbRB+hmlw0yFsLprHhbbt7jUzbzAbAjK/Pn0FDnh1A=="],
37
+
38
+ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.14", "", { "os": "win32", "cpu": "x64" }, "sha512-oizCjdyQ3WJEswpb3Chdngeat56rIdSYK12JI3iI11Mt5T5EXcZ7WLuowzEaFPNJ3zmOQFliMN8QY1Pi+qsfdQ=="],
39
+
40
+ "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
41
+
42
+ "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
43
+
44
+ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
45
+
46
+ "@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="],
47
+
48
+ "@types/node": ["@types/node@25.2.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ=="],
49
+
50
+ "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="],
51
+
52
+ "devtools-protocol": ["devtools-protocol@0.0.1581282", "", {}, "sha512-nv7iKtNZQshSW2hKzYNr46nM/Cfh5SEvE2oV0/SEGgc9XupIY5ggf84Cz8eJIkBce7S3bmTAauFD6aysMpnqsQ=="],
53
+
54
+ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
55
+
56
+ "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
57
+
58
+ "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
59
+ }
60
+ }
package/dist/main.js CHANGED
@@ -12,6 +12,72 @@ var __export = (target, all) => {
12
12
  };
13
13
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
14
14
 
15
+ // src/daemon/logger.ts
16
+ import { appendFileSync, writeFileSync } from "fs";
17
+
18
+ class DaemonLogger {
19
+ logPath;
20
+ constructor(logPath) {
21
+ this.logPath = logPath;
22
+ writeFileSync(logPath, "");
23
+ }
24
+ info(event, message, data) {
25
+ this.write("info", event, message, data);
26
+ }
27
+ warn(event, message, data) {
28
+ this.write("warn", event, message, data);
29
+ }
30
+ error(event, message, data) {
31
+ this.write("error", event, message, data);
32
+ }
33
+ debug(event, message, data) {
34
+ this.write("debug", event, message, data);
35
+ }
36
+ clear() {
37
+ writeFileSync(this.logPath, "");
38
+ }
39
+ write(level, event, message, data) {
40
+ const entry = { ts: Date.now(), level, event, message };
41
+ if (data !== undefined) {
42
+ entry.data = data;
43
+ }
44
+ appendFileSync(this.logPath, `${JSON.stringify(entry)}
45
+ `);
46
+ }
47
+ }
48
+ var init_logger = () => {};
49
+
50
+ // src/daemon/paths.ts
51
+ import { existsSync, mkdirSync } from "fs";
52
+ import { join } from "path";
53
+ function getSocketDir() {
54
+ const xdgRuntime = process.env.XDG_RUNTIME_DIR;
55
+ if (xdgRuntime) {
56
+ return join(xdgRuntime, "agent-dbg");
57
+ }
58
+ const tmpdir = process.env.TMPDIR || "/tmp";
59
+ return join(tmpdir, `agent-dbg-${process.getuid?.() ?? 0}`);
60
+ }
61
+ function getSocketPath(session) {
62
+ return join(getSocketDir(), `${session}.sock`);
63
+ }
64
+ function getLockPath(session) {
65
+ return join(getSocketDir(), `${session}.lock`);
66
+ }
67
+ function getLogPath(session) {
68
+ return join(getSocketDir(), `${session}.cdp.log`);
69
+ }
70
+ function getDaemonLogPath(session) {
71
+ return join(getSocketDir(), `${session}.daemon.log`);
72
+ }
73
+ function ensureSocketDir() {
74
+ const dir = getSocketDir();
75
+ if (!existsSync(dir)) {
76
+ mkdirSync(dir, { recursive: true });
77
+ }
78
+ }
79
+ var init_paths = () => {};
80
+
15
81
  // node_modules/@zod/core/dist/esm/core.js
16
82
  function $constructor(name, initializer) {
17
83
  class _ {
@@ -6308,36 +6374,8 @@ var init_messages = __esm(() => {
6308
6374
  DaemonResponseSchema = exports_external.union([SuccessResponse, ErrorResponse]);
6309
6375
  });
6310
6376
 
6311
- // src/daemon/paths.ts
6312
- import { existsSync, mkdirSync } from "fs";
6313
- import { join } from "path";
6314
- function getSocketDir() {
6315
- const xdgRuntime = process.env.XDG_RUNTIME_DIR;
6316
- if (xdgRuntime) {
6317
- return join(xdgRuntime, "agent-dbg");
6318
- }
6319
- const tmpdir = process.env.TMPDIR || "/tmp";
6320
- return join(tmpdir, `agent-dbg-${process.getuid?.() ?? 0}`);
6321
- }
6322
- function getSocketPath(session) {
6323
- return join(getSocketDir(), `${session}.sock`);
6324
- }
6325
- function getLockPath(session) {
6326
- return join(getSocketDir(), `${session}.lock`);
6327
- }
6328
- function getLogPath(session) {
6329
- return join(getSocketDir(), `${session}.cdp.log`);
6330
- }
6331
- function ensureSocketDir() {
6332
- const dir = getSocketDir();
6333
- if (!existsSync(dir)) {
6334
- mkdirSync(dir, { recursive: true });
6335
- }
6336
- }
6337
- var init_paths = () => {};
6338
-
6339
6377
  // src/daemon/server.ts
6340
- import { existsSync as existsSync2, unlinkSync, writeFileSync } from "fs";
6378
+ import { existsSync as existsSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
6341
6379
 
6342
6380
  class DaemonServer {
6343
6381
  session;
@@ -6347,11 +6385,13 @@ class DaemonServer {
6347
6385
  listener = null;
6348
6386
  socketPath;
6349
6387
  lockPath;
6388
+ logger;
6350
6389
  constructor(session, options) {
6351
6390
  this.session = session;
6352
6391
  this.idleTimeout = options.idleTimeout;
6353
6392
  this.socketPath = getSocketPath(session);
6354
6393
  this.lockPath = getLockPath(session);
6394
+ this.logger = options.logger ?? null;
6355
6395
  }
6356
6396
  onRequest(handler) {
6357
6397
  this.handler = handler;
@@ -6368,7 +6408,7 @@ class DaemonServer {
6368
6408
  if (existsSync2(this.socketPath)) {
6369
6409
  unlinkSync(this.socketPath);
6370
6410
  }
6371
- writeFileSync(this.lockPath, String(process.pid));
6411
+ writeFileSync2(this.lockPath, String(process.pid));
6372
6412
  const server = this;
6373
6413
  this.listener = Bun.listen({
6374
6414
  unix: this.socketPath,
@@ -6389,6 +6429,7 @@ class DaemonServer {
6389
6429
  },
6390
6430
  close() {},
6391
6431
  error(_socket, error3) {
6432
+ server.logger?.error("socket.error", error3.message);
6392
6433
  console.error(`[daemon] socket error: ${error3.message}`);
6393
6434
  }
6394
6435
  }
@@ -6457,6 +6498,7 @@ class DaemonServer {
6457
6498
  }
6458
6499
  if (this.idleTimeout > 0) {
6459
6500
  this.idleTimer = setTimeout(() => {
6501
+ this.logger?.info("daemon.idle", `Idle timeout reached (${this.idleTimeout}s), shutting down`);
6460
6502
  this.stop();
6461
6503
  }, this.idleTimeout * 1000);
6462
6504
  }
@@ -6647,14 +6689,14 @@ class CdpClient {
6647
6689
  var DEFAULT_TIMEOUT_MS = 30000;
6648
6690
 
6649
6691
  // src/cdp/logger.ts
6650
- import { appendFileSync, writeFileSync as writeFileSync2 } from "fs";
6692
+ import { appendFileSync as appendFileSync2, writeFileSync as writeFileSync3 } from "fs";
6651
6693
 
6652
6694
  class CdpLogger {
6653
6695
  logPath;
6654
6696
  pending = new Map;
6655
6697
  constructor(logPath) {
6656
6698
  this.logPath = logPath;
6657
- writeFileSync2(logPath, "");
6699
+ writeFileSync3(logPath, "");
6658
6700
  }
6659
6701
  logSend(id, method, params) {
6660
6702
  this.pending.set(id, { method, sentAt: Date.now() });
@@ -6687,14 +6729,14 @@ class CdpLogger {
6687
6729
  this.append(entry);
6688
6730
  }
6689
6731
  clear() {
6690
- writeFileSync2(this.logPath, "");
6732
+ writeFileSync3(this.logPath, "");
6691
6733
  }
6692
6734
  append(entry) {
6693
- appendFileSync(this.logPath, `${JSON.stringify(entry)}
6735
+ appendFileSync2(this.logPath, `${JSON.stringify(entry)}
6694
6736
  `);
6695
6737
  }
6696
6738
  }
6697
- var init_logger = () => {};
6739
+ var init_logger2 = () => {};
6698
6740
 
6699
6741
  // src/formatter/values.ts
6700
6742
  function truncate(str, max) {
@@ -9040,10 +9082,12 @@ class DebugSession {
9040
9082
  launchCommand = null;
9041
9083
  launchOptions = null;
9042
9084
  cdpLogger;
9043
- constructor(session) {
9085
+ daemonLogger;
9086
+ constructor(session, options) {
9044
9087
  this.session = session;
9045
9088
  ensureSocketDir();
9046
9089
  this.cdpLogger = new CdpLogger(getLogPath(session));
9090
+ this.daemonLogger = options?.daemonLogger ?? new DaemonLogger(getDaemonLogPath(session));
9047
9091
  }
9048
9092
  async launch(command, options = {}) {
9049
9093
  if (this.state !== "idle") {
@@ -9062,13 +9106,20 @@ class DebugSession {
9062
9106
  const spawnArgs = [runtime, inspectFlag, ...rest];
9063
9107
  const proc = Bun.spawn(spawnArgs, {
9064
9108
  stdin: "ignore",
9065
- stdout: "pipe",
9109
+ stdout: "ignore",
9066
9110
  stderr: "pipe"
9067
9111
  });
9068
9112
  this.childProcess = proc;
9113
+ this.daemonLogger.info("child.spawn", `Spawned process pid=${proc.pid}`, {
9114
+ pid: proc.pid,
9115
+ command: spawnArgs
9116
+ });
9069
9117
  this.monitorProcessExit(proc);
9070
9118
  const wsUrl = await this.readInspectorUrl(proc.stderr);
9071
9119
  this.wsUrl = wsUrl;
9120
+ this.daemonLogger.info("inspector.detected", `Inspector URL: ${wsUrl}`, {
9121
+ wsUrl
9122
+ });
9072
9123
  await this.connectCdp(wsUrl);
9073
9124
  if (brk) {
9074
9125
  await this.waitForBrkPause();
@@ -9382,8 +9433,10 @@ class DebugSession {
9382
9433
  }
9383
9434
  }
9384
9435
  async connectCdp(wsUrl) {
9436
+ this.daemonLogger.debug("cdp.connecting", `Connecting to ${wsUrl}`);
9385
9437
  const cdp = await CdpClient.connect(wsUrl, this.cdpLogger);
9386
9438
  this.cdp = cdp;
9439
+ this.daemonLogger.info("cdp.connected", `CDP connected to ${wsUrl}`);
9387
9440
  this.setupCdpEventHandlers(cdp);
9388
9441
  await cdp.enableDomains();
9389
9442
  if (this.blackboxPatterns.length > 0) {
@@ -9490,7 +9543,11 @@ class DebugSession {
9490
9543
  });
9491
9544
  }
9492
9545
  monitorProcessExit(proc) {
9493
- proc.exited.then(() => {
9546
+ proc.exited.then((exitCode) => {
9547
+ this.daemonLogger.info("child.exit", `Process exited with code ${exitCode ?? "unknown"}`, {
9548
+ pid: proc.pid,
9549
+ exitCode: exitCode ?? null
9550
+ });
9494
9551
  this.childProcess = null;
9495
9552
  if (this.cdp) {
9496
9553
  this.cdp.disconnect();
@@ -9499,7 +9556,10 @@ class DebugSession {
9499
9556
  this.state = "idle";
9500
9557
  this.pauseInfo = null;
9501
9558
  this.onProcessExit?.();
9502
- }).catch(() => {
9559
+ }).catch((err) => {
9560
+ this.daemonLogger.error("child.exit.error", `Error waiting for process exit: ${err}`, {
9561
+ pid: proc.pid
9562
+ });
9503
9563
  this.childProcess = null;
9504
9564
  this.state = "idle";
9505
9565
  this.pauseInfo = null;
@@ -9518,16 +9578,22 @@ class DebugSession {
9518
9578
  if (done) {
9519
9579
  break;
9520
9580
  }
9521
- accumulated += decoder.decode(value, { stream: true });
9581
+ const chunk = decoder.decode(value, { stream: true });
9582
+ accumulated += chunk;
9583
+ this.daemonLogger.debug("child.stderr", chunk.trimEnd());
9522
9584
  const match = INSPECTOR_URL_REGEX.exec(accumulated);
9523
9585
  if (match?.[1]) {
9524
9586
  clearTimeout(timeout);
9525
- reader.releaseLock();
9587
+ this.drainReader(reader);
9526
9588
  return match[1];
9527
9589
  }
9528
9590
  }
9529
9591
  } catch {}
9530
9592
  clearTimeout(timeout);
9593
+ this.daemonLogger.error("inspector.failed", "Failed to detect inspector URL", {
9594
+ stderr: accumulated.slice(0, 2000),
9595
+ timeoutMs: INSPECTOR_TIMEOUT_MS
9596
+ });
9531
9597
  throw new Error(`Failed to detect inspector URL within ${INSPECTOR_TIMEOUT_MS}ms. Stderr: ${accumulated.slice(0, 500)}`);
9532
9598
  }
9533
9599
  async discoverWsUrl(port) {
@@ -9552,12 +9618,22 @@ class DebugSession {
9552
9618
  }
9553
9619
  return wsUrl;
9554
9620
  }
9621
+ drainReader(reader) {
9622
+ const pump = () => {
9623
+ reader.read().then(({ done }) => {
9624
+ if (!done)
9625
+ pump();
9626
+ }).catch(() => {});
9627
+ };
9628
+ pump();
9629
+ }
9555
9630
  }
9556
9631
  var INSPECTOR_URL_REGEX, INSPECTOR_TIMEOUT_MS = 5000;
9557
9632
  var init_session = __esm(() => {
9558
- init_logger();
9633
+ init_logger2();
9559
9634
  init_ref_table();
9560
9635
  init_resolver();
9636
+ init_logger();
9561
9637
  init_paths();
9562
9638
  init_session_inspection();
9563
9639
  init_session_mutation();
@@ -9567,8 +9643,10 @@ var init_session = __esm(() => {
9567
9643
 
9568
9644
  // src/daemon/entry.ts
9569
9645
  var exports_entry = {};
9570
- var daemonIdx, session, timeout = 300, timeoutIdx, server, debugSession;
9646
+ var daemonIdx, session, timeout = 300, timeoutIdx, daemonLogger, server, debugSession;
9571
9647
  var init_entry = __esm(async () => {
9648
+ init_logger();
9649
+ init_paths();
9572
9650
  init_server();
9573
9651
  init_session();
9574
9652
  daemonIdx = process.argv.indexOf("--daemon");
@@ -9587,8 +9665,15 @@ var init_entry = __esm(async () => {
9587
9665
  }
9588
9666
  }
9589
9667
  }
9590
- server = new DaemonServer(session, { idleTimeout: timeout });
9591
- debugSession = new DebugSession(session);
9668
+ ensureSocketDir();
9669
+ daemonLogger = new DaemonLogger(getDaemonLogPath(session));
9670
+ daemonLogger.info("daemon.start", `Daemon starting for session "${session}"`, {
9671
+ pid: process.pid,
9672
+ session,
9673
+ timeout
9674
+ });
9675
+ server = new DaemonServer(session, { idleTimeout: timeout, logger: daemonLogger });
9676
+ debugSession = new DebugSession(session, { daemonLogger });
9592
9677
  server.onRequest(async (req) => {
9593
9678
  switch (req.cmd) {
9594
9679
  case "ping":
@@ -9790,7 +9875,7 @@ var init_registry = __esm(() => {
9790
9875
  });
9791
9876
 
9792
9877
  // src/daemon/client.ts
9793
- import { existsSync as existsSync3, readdirSync } from "fs";
9878
+ import { existsSync as existsSync3, readFileSync, readdirSync, unlinkSync as unlinkSync2 } from "fs";
9794
9879
 
9795
9880
  class DaemonClient {
9796
9881
  session;
@@ -9890,12 +9975,28 @@ class DaemonClient {
9890
9975
  if (!existsSync3(socketPath)) {
9891
9976
  return false;
9892
9977
  }
9978
+ const lockPath = getLockPath(session2);
9979
+ if (!existsSync3(lockPath)) {
9980
+ return false;
9981
+ }
9893
9982
  try {
9983
+ const pid = parseInt(readFileSync(lockPath, "utf-8"), 10);
9984
+ if (Number.isNaN(pid))
9985
+ return false;
9986
+ process.kill(pid, 0);
9894
9987
  return true;
9895
9988
  } catch {
9896
9989
  return false;
9897
9990
  }
9898
9991
  }
9992
+ static cleanStaleFiles(session2) {
9993
+ const socketPath = getSocketPath(session2);
9994
+ const lockPath = getLockPath(session2);
9995
+ if (existsSync3(socketPath))
9996
+ unlinkSync2(socketPath);
9997
+ if (existsSync3(lockPath))
9998
+ unlinkSync2(lockPath);
9999
+ }
9899
10000
  static async isAlive(session2) {
9900
10001
  const socketPath = getSocketPath(session2);
9901
10002
  if (!existsSync3(socketPath)) {
@@ -9925,7 +10026,7 @@ var init_client = __esm(() => {
9925
10026
  });
9926
10027
 
9927
10028
  // src/daemon/spawn.ts
9928
- import { existsSync as existsSync4 } from "fs";
10029
+ import { existsSync as existsSync4, openSync } from "fs";
9929
10030
  async function spawnDaemon(session2, options = {}) {
9930
10031
  const socketPath = getSocketPath(session2);
9931
10032
  const spawnArgs = [];
@@ -9940,11 +10041,13 @@ async function spawnDaemon(session2, options = {}) {
9940
10041
  if (options.timeout !== undefined) {
9941
10042
  spawnArgs.push("--timeout", String(options.timeout));
9942
10043
  }
10044
+ ensureSocketDir();
10045
+ const logFd = openSync(getDaemonLogPath(session2), "a");
9943
10046
  const proc = Bun.spawn(spawnArgs, {
9944
10047
  detached: true,
9945
10048
  stdin: "ignore",
9946
- stdout: "ignore",
9947
- stderr: "ignore"
10049
+ stdout: logFd,
10050
+ stderr: logFd
9948
10051
  });
9949
10052
  proc.unref();
9950
10053
  const deadline = Date.now() + SPAWN_TIMEOUT_MS;
@@ -9956,8 +10059,15 @@ async function spawnDaemon(session2, options = {}) {
9956
10059
  }
9957
10060
  throw new Error(`Daemon for session "${session2}" failed to start within ${SPAWN_TIMEOUT_MS}ms`);
9958
10061
  }
10062
+ async function ensureDaemon(session2, options) {
10063
+ if (DaemonClient.isRunning(session2))
10064
+ return;
10065
+ DaemonClient.cleanStaleFiles(session2);
10066
+ await spawnDaemon(session2, options);
10067
+ }
9959
10068
  var POLL_INTERVAL_MS = 50, SPAWN_TIMEOUT_MS = 5000;
9960
10069
  var init_spawn = __esm(() => {
10070
+ init_client();
9961
10071
  init_paths();
9962
10072
  });
9963
10073
 
@@ -10001,9 +10111,7 @@ var init_launch = __esm(() => {
10001
10111
  console.error(" -> Try: agent-dbg launch --brk node app.js");
10002
10112
  return 1;
10003
10113
  }
10004
- if (!DaemonClient.isRunning(session2)) {
10005
- await spawnDaemon(session2, { timeout: timeout2 });
10006
- }
10114
+ await ensureDaemon(session2, { timeout: timeout2 });
10007
10115
  const client = new DaemonClient(session2);
10008
10116
  const response = await client.request("launch", { command, brk, port });
10009
10117
  if (!response.ok) {
@@ -10049,7 +10157,7 @@ var init_attach = __esm(() => {
10049
10157
  return 1;
10050
10158
  }
10051
10159
  const timeout2 = typeof args.flags.timeout === "string" ? parseInt(args.flags.timeout, 10) : undefined;
10052
- await spawnDaemon(session2, { timeout: timeout2 });
10160
+ await ensureDaemon(session2, { timeout: timeout2 });
10053
10161
  const client = new DaemonClient(session2);
10054
10162
  const response = await client.request("attach", { target });
10055
10163
  if (!response.ok) {
@@ -12006,7 +12114,13 @@ function formatLogEntry(entry) {
12006
12114
  const summary = summarizer ? summarizer(entry) : summarizeParams(entry);
12007
12115
  return `${time3} <- ${entry.method}${summary ? ` ${summary}` : ""}`;
12008
12116
  }
12009
- var eventSummarizers, responseSummarizers;
12117
+ function formatDaemonLogEntry(entry) {
12118
+ const time3 = `[${formatTime(entry.ts)}]`;
12119
+ const level = levelColors[entry.level] ?? entry.level.toUpperCase();
12120
+ const data = entry.data ? ` ${truncate2(JSON.stringify(entry.data), 120)}` : "";
12121
+ return `${time3} ${level} ${entry.event}: ${entry.message}${data}`;
12122
+ }
12123
+ var eventSummarizers, responseSummarizers, levelColors;
12010
12124
  var init_logs = __esm(() => {
12011
12125
  eventSummarizers = {
12012
12126
  "Debugger.scriptParsed": (e) => {
@@ -12063,6 +12177,12 @@ var init_logs = __esm(() => {
12063
12177
  return `breakpointId=${r.breakpointId}`;
12064
12178
  }
12065
12179
  };
12180
+ levelColors = {
12181
+ info: "INFO ",
12182
+ warn: "WARN ",
12183
+ error: "ERROR",
12184
+ debug: "DEBUG"
12185
+ };
12066
12186
  });
12067
12187
 
12068
12188
  // src/commands/logs.ts
@@ -12070,13 +12190,25 @@ var exports_logs = {};
12070
12190
  import {
12071
12191
  closeSync,
12072
12192
  existsSync as existsSync5,
12073
- openSync,
12074
- readFileSync,
12193
+ openSync as openSync2,
12194
+ readFileSync as readFileSync2,
12075
12195
  readSync,
12076
12196
  watch,
12077
- writeFileSync as writeFileSync3
12197
+ writeFileSync as writeFileSync4
12078
12198
  } from "fs";
12079
- function parseEntries(text) {
12199
+ function parseCdpEntries(text) {
12200
+ const entries = [];
12201
+ for (const line of text.split(`
12202
+ `)) {
12203
+ if (!line.trim())
12204
+ continue;
12205
+ try {
12206
+ entries.push(JSON.parse(line));
12207
+ } catch {}
12208
+ }
12209
+ return entries;
12210
+ }
12211
+ function parseDaemonEntries(text) {
12080
12212
  const entries = [];
12081
12213
  for (const line of text.split(`
12082
12214
  `)) {
@@ -12091,7 +12223,10 @@ function parseEntries(text) {
12091
12223
  function filterByDomain(entries, domain) {
12092
12224
  return entries.filter((e) => e.method.startsWith(`${domain}.`));
12093
12225
  }
12094
- function printEntries(entries, json2) {
12226
+ function filterByLevel(entries, level) {
12227
+ return entries.filter((e) => e.level === level);
12228
+ }
12229
+ function printCdpEntries(entries, json2) {
12095
12230
  for (const entry of entries) {
12096
12231
  if (json2) {
12097
12232
  console.log(JSON.stringify(entry));
@@ -12100,37 +12235,56 @@ function printEntries(entries, json2) {
12100
12235
  }
12101
12236
  }
12102
12237
  }
12238
+ function printDaemonEntries(entries, json2) {
12239
+ for (const entry of entries) {
12240
+ if (json2) {
12241
+ console.log(JSON.stringify(entry));
12242
+ } else {
12243
+ console.log(formatDaemonLogEntry(entry));
12244
+ }
12245
+ }
12246
+ }
12103
12247
  var init_logs2 = __esm(() => {
12104
12248
  init_registry();
12105
12249
  init_paths();
12106
12250
  init_logs();
12107
12251
  registerCommand("logs", async (args) => {
12108
12252
  const session2 = args.global.session;
12109
- const logPath = getLogPath(session2);
12253
+ const isDaemon = args.flags.daemon === true;
12254
+ const logPath = isDaemon ? getDaemonLogPath(session2) : getLogPath(session2);
12110
12255
  if (args.flags.clear === true) {
12111
12256
  if (existsSync5(logPath)) {
12112
- writeFileSync3(logPath, "");
12113
- console.log("Log cleared");
12257
+ writeFileSync4(logPath, "");
12258
+ console.log(`${isDaemon ? "Daemon log" : "Log"} cleared`);
12114
12259
  } else {
12115
- console.log("No log file to clear");
12260
+ console.log(`No ${isDaemon ? "daemon " : ""}log file to clear`);
12116
12261
  }
12117
12262
  return 0;
12118
12263
  }
12119
12264
  if (!existsSync5(logPath)) {
12120
- console.error(`No log file for session "${session2}"`);
12265
+ console.error(`No ${isDaemon ? "daemon " : ""}log file for session "${session2}"`);
12121
12266
  console.error(" -> Try: agent-dbg launch --brk node app.js");
12122
12267
  return 1;
12123
12268
  }
12124
12269
  const isJson = args.global.json;
12125
12270
  const domain = typeof args.flags.domain === "string" ? args.flags.domain : undefined;
12271
+ const level = typeof args.flags.level === "string" ? args.flags.level : undefined;
12126
12272
  const limit = typeof args.flags.limit === "string" ? parseInt(args.flags.limit, 10) : 50;
12127
12273
  const follow = args.flags.follow === true;
12128
- const content = readFileSync(logPath, "utf-8");
12129
- let entries = parseEntries(content);
12130
- if (domain)
12131
- entries = filterByDomain(entries, domain);
12132
- const sliced = follow ? entries : entries.slice(-limit);
12133
- printEntries(sliced, isJson);
12274
+ const content = readFileSync2(logPath, "utf-8");
12275
+ if (isDaemon) {
12276
+ let entries = parseDaemonEntries(content);
12277
+ if (level)
12278
+ entries = filterByLevel(entries, level);
12279
+ const sliced = follow ? entries : entries.slice(-limit);
12280
+ printDaemonEntries(sliced, isJson);
12281
+ } else {
12282
+ let entries = parseCdpEntries(content);
12283
+ if (domain)
12284
+ entries = filterByDomain(entries, domain);
12285
+ const sliced = follow ? entries : entries.slice(-limit);
12286
+ printCdpEntries(sliced, isJson);
12287
+ }
12134
12288
  if (!follow)
12135
12289
  return 0;
12136
12290
  let offset = Buffer.byteLength(content, "utf-8");
@@ -12140,15 +12294,22 @@ var init_logs2 = __esm(() => {
12140
12294
  const size = Bun.file(logPath).size;
12141
12295
  if (size <= offset)
12142
12296
  return;
12143
- const fd = openSync(logPath, "r");
12297
+ const fd = openSync2(logPath, "r");
12144
12298
  const buf = Buffer.alloc(size - offset);
12145
12299
  readSync(fd, buf, 0, buf.length, offset);
12146
12300
  closeSync(fd);
12147
12301
  offset = size;
12148
- let newEntries = parseEntries(buf.toString("utf-8"));
12149
- if (domain)
12150
- newEntries = filterByDomain(newEntries, domain);
12151
- printEntries(newEntries, isJson);
12302
+ if (isDaemon) {
12303
+ let newEntries = parseDaemonEntries(buf.toString("utf-8"));
12304
+ if (level)
12305
+ newEntries = filterByLevel(newEntries, level);
12306
+ printDaemonEntries(newEntries, isJson);
12307
+ } else {
12308
+ let newEntries = parseCdpEntries(buf.toString("utf-8"));
12309
+ if (domain)
12310
+ newEntries = filterByDomain(newEntries, domain);
12311
+ printCdpEntries(newEntries, isJson);
12312
+ }
12152
12313
  } catch {}
12153
12314
  };
12154
12315
  watcher = watch(logPath, () => {