debug-that 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +5 -1
  2. package/dist/main.js +487 -63
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Debugger CLI built for AI agents. Fast, token-efficient, no fluff.
4
4
 
5
+ <p align="center">
6
+ <img src="docs/demo-2x.gif" alt="debug-that demo" />
7
+ </p>
8
+
5
9
  **Why?** Agents waste tokens on print-debugging. A real debugger gives precise state inspection in minimal output — variables, stack, breakpoints — all via short `@ref` handles.
6
10
 
7
11
  Inspired by Vercel's [agent-browser](https://github.com/vercel-labs/agent-browser) CLI — the same `@ref` concept, applied to debugging instead of browsing.
@@ -15,7 +19,7 @@ Inspired by Vercel's [agent-browser](https://github.com/vercel-labs/agent-browse
15
19
  | Bun | JavaScript / TypeScript | Supported | WebKit Inspector (JSC) |
16
20
  | LLDB | C / C++ / Rust / Swift | Supported | DAP (Debug Adapter Protocol) |
17
21
  | Deno | JavaScript / TypeScript | Planned | V8 Inspector (CDP) |
18
- | Python (debugpy) | Python | Planned | DAP |
22
+ | Python (debugpy) | Python | Supported | DAP |
19
23
  | Go (delve) | Go | Planned | DAP |
20
24
  | Java (JDWP) | Java / Kotlin | Planned | DAP |
21
25
 
package/dist/main.js CHANGED
@@ -13,6 +13,9 @@ var __export = (target, all) => {
13
13
  };
14
14
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
15
15
 
16
+ // src/constants.ts
17
+ var REQUEST_TIMEOUT_MS = 30000, INSPECTOR_TIMEOUT_MS = 5000, SPAWN_TIMEOUT_MS = 5000, SPAWN_POLL_INTERVAL_MS = 50, BRK_PAUSE_TIMEOUT_MS = 2000, MAX_INTERNAL_PAUSE_SKIPS = 5, STATE_WAIT_TIMEOUT_MS = 5000, PAUSE_WAITER_TIMEOUT_MS = 30000, MAX_BUFFERED_MESSAGES = 1000, BUFFER_TRIM_BATCH = 100, MAX_SOURCE_LINE_WIDTH = 120, INITIALIZED_TIMEOUT_MS = 1e4, MAX_REQUEST_SIZE = 1048576;
18
+
16
19
  // src/refs/ref-table.ts
17
20
  class RefTable {
18
21
  entries = new Map;
@@ -108,9 +111,6 @@ var init_ref_table = __esm(() => {
108
111
  };
109
112
  });
110
113
 
111
- // src/constants.ts
112
- var REQUEST_TIMEOUT_MS = 30000, INSPECTOR_TIMEOUT_MS = 5000, SPAWN_TIMEOUT_MS = 5000, SPAWN_POLL_INTERVAL_MS = 50, BRK_PAUSE_TIMEOUT_MS = 2000, MAX_INTERNAL_PAUSE_SKIPS = 5, STATE_WAIT_TIMEOUT_MS = 5000, PAUSE_WAITER_TIMEOUT_MS = 30000, MAX_BUFFERED_MESSAGES = 1000, BUFFER_TRIM_BATCH = 100, MAX_SOURCE_LINE_WIDTH = 120, MAX_REQUEST_SIZE = 1048576;
113
-
114
114
  // src/dap/client.ts
115
115
  class DapClient {
116
116
  proc;
@@ -325,6 +325,12 @@ function resolveAdapterCommand(runtime) {
325
325
  }
326
326
  case "codelldb":
327
327
  return ["codelldb", "--port", "0"];
328
+ case "python":
329
+ case "debugpy": {
330
+ const py3 = Bun.spawnSync(["which", "python3"]);
331
+ const pyBin = py3.exitCode === 0 ? "python3" : "python";
332
+ return [pyBin, "-m", "debugpy.adapter"];
333
+ }
328
334
  default:
329
335
  return [runtime];
330
336
  }
@@ -368,8 +374,14 @@ class DapSession {
368
374
  stopOnEntry: options.brk ?? true,
369
375
  cwd: process.cwd()
370
376
  };
371
- await this.dap.send("launch", launchArgs);
377
+ if (this._runtime === "python" || this._runtime === "debugpy") {
378
+ launchArgs.console = "internalConsole";
379
+ launchArgs.justMyCode = false;
380
+ }
381
+ const launchPromise = this.dap.send("launch", launchArgs);
382
+ await this.waitForInitialized();
372
383
  await this.dap.send("configurationDone");
384
+ await launchPromise;
373
385
  if (options.brk !== false) {
374
386
  await this.waitForStop(5000);
375
387
  }
@@ -393,8 +405,10 @@ class DapSession {
393
405
  await this.initializeAdapter();
394
406
  const pid = parseInt(target, 10);
395
407
  const attachArgs = Number.isNaN(pid) ? { program: target, waitFor: true } : { pid };
396
- await this.dap.send("attach", attachArgs);
408
+ const attachPromise = this.dap.send("attach", attachArgs);
409
+ await this.waitForInitialized();
397
410
  await this.dap.send("configurationDone");
411
+ await attachPromise;
398
412
  await this.waitForStop(5000).catch(() => {});
399
413
  if (this._state === "idle") {
400
414
  this._state = "running";
@@ -433,12 +447,12 @@ class DapSession {
433
447
  async continue() {
434
448
  this.requireConnected();
435
449
  this.requirePaused();
436
- const waiter = this.createStoppedWaiter(30000);
437
- await this.getDap().send("continue", { threadId: this._threadId });
438
450
  this._state = "running";
439
451
  this._pauseInfo = null;
440
452
  this._stackFrames = [];
441
453
  this.refs.clearVolatile();
454
+ const waiter = this.createStoppedWaiter(30000);
455
+ await this.getDap().send("continue", { threadId: this._threadId });
442
456
  await waiter;
443
457
  if (this.isPaused())
444
458
  await this.fetchStackTrace();
@@ -446,12 +460,12 @@ class DapSession {
446
460
  async step(mode) {
447
461
  this.requireConnected();
448
462
  this.requirePaused();
449
- const waiter = this.createStoppedWaiter(30000);
450
- const command = mode === "into" ? "stepIn" : mode === "out" ? "stepOut" : "next";
451
- await this.getDap().send(command, { threadId: this._threadId });
452
463
  this._state = "running";
453
464
  this._pauseInfo = null;
454
465
  this.refs.clearVolatile();
466
+ const waiter = this.createStoppedWaiter(30000);
467
+ const command = mode === "into" ? "stepIn" : mode === "out" ? "stepOut" : "next";
468
+ await this.getDap().send(command, { threadId: this._threadId });
455
469
  await waiter;
456
470
  if (this.isPaused())
457
471
  await this.fetchStackTrace();
@@ -1097,6 +1111,21 @@ class DapSession {
1097
1111
  };
1098
1112
  });
1099
1113
  }
1114
+ async waitForInitialized() {
1115
+ const dap = this.getDap();
1116
+ return new Promise((resolve, reject) => {
1117
+ const timer = setTimeout(() => {
1118
+ dap.off("initialized", handler);
1119
+ reject(new Error("Timed out waiting for DAP initialized event"));
1120
+ }, INITIALIZED_TIMEOUT_MS);
1121
+ const handler = () => {
1122
+ clearTimeout(timer);
1123
+ dap.off("initialized", handler);
1124
+ resolve();
1125
+ };
1126
+ dap.on("initialized", handler);
1127
+ });
1128
+ }
1100
1129
  async waitForStop(timeoutMs) {
1101
1130
  if (!this.isPaused()) {
1102
1131
  await this.createStoppedWaiter(timeoutMs);
@@ -11017,7 +11046,7 @@ class DebugSession {
11017
11046
  if (match?.[1]) {
11018
11047
  clearTimeout(timeout);
11019
11048
  this.drainReader(reader);
11020
- return match[1];
11049
+ return match[1].replace(ANSI_RE, "");
11021
11050
  }
11022
11051
  }
11023
11052
  } catch {}
@@ -11062,7 +11091,7 @@ class DebugSession {
11062
11091
  pump();
11063
11092
  }
11064
11093
  }
11065
- var INSPECTOR_URL_REGEX;
11094
+ var INSPECTOR_URL_REGEX, ESC, ANSI_RE;
11066
11095
  var init_session2 = __esm(() => {
11067
11096
  init_client2();
11068
11097
  init_logger2();
@@ -11077,6 +11106,8 @@ var init_session2 = __esm(() => {
11077
11106
  init_session_mutation();
11078
11107
  init_session_state();
11079
11108
  INSPECTOR_URL_REGEX = /(?:Debugger listening on\s+)?(wss?:\/\/\S+)/;
11109
+ ESC = String.fromCharCode(27);
11110
+ ANSI_RE = new RegExp(`${ESC}\\[[0-9;]*m`, "g");
11080
11111
  });
11081
11112
 
11082
11113
  // src/daemon/entry.ts
@@ -11871,6 +11902,306 @@ var init_status = __esm(() => {
11871
11902
  });
11872
11903
  });
11873
11904
 
11905
+ // src/formatter/color.ts
11906
+ function c(color, text) {
11907
+ return `${color}${text}${RESET}`;
11908
+ }
11909
+ function shouldEnableColor(explicitFlag) {
11910
+ if (explicitFlag)
11911
+ return true;
11912
+ if (process.env.NO_COLOR !== undefined)
11913
+ return false;
11914
+ if (process.env.FORCE_COLOR !== undefined)
11915
+ return true;
11916
+ if (process.env.DBG_COLOR === "1" || process.env.DBG_COLOR === "true")
11917
+ return true;
11918
+ return false;
11919
+ }
11920
+ function detectLanguage(url2) {
11921
+ const dot = url2.lastIndexOf(".");
11922
+ if (dot === -1)
11923
+ return "unknown";
11924
+ return EXT_MAP[url2.slice(dot)] ?? "unknown";
11925
+ }
11926
+ function getKeywords(lang) {
11927
+ switch (lang) {
11928
+ case "js":
11929
+ return { keywords: JS_KEYWORDS, constants: JS_CONSTANTS };
11930
+ case "py":
11931
+ return { keywords: PY_KEYWORDS, constants: PY_CONSTANTS };
11932
+ case "c":
11933
+ return { keywords: C_KEYWORDS, constants: C_CONSTANTS };
11934
+ default:
11935
+ return { keywords: new Set, constants: new Set };
11936
+ }
11937
+ }
11938
+ function getRegex(lang) {
11939
+ switch (lang) {
11940
+ case "js":
11941
+ return new RegExp(JS_LINE_RE.source, JS_LINE_RE.flags);
11942
+ case "py":
11943
+ return new RegExp(PY_LINE_RE.source, PY_LINE_RE.flags);
11944
+ case "c":
11945
+ return new RegExp(C_LINE_RE.source, C_LINE_RE.flags);
11946
+ default:
11947
+ return new RegExp(JS_LINE_RE.source, JS_LINE_RE.flags);
11948
+ }
11949
+ }
11950
+ function tokenizeLine(line, lang) {
11951
+ if (lang === "unknown")
11952
+ return [{ text: line }];
11953
+ const { keywords, constants } = getKeywords(lang);
11954
+ const re = getRegex(lang);
11955
+ const tokens = [];
11956
+ for (let match = re.exec(line);match !== null; match = re.exec(line)) {
11957
+ const [full, comment, str, num, word] = match;
11958
+ if (comment) {
11959
+ tokens.push({ text: comment, color: ansi.gray });
11960
+ } else if (str) {
11961
+ tokens.push({ text: str, color: ansi.green });
11962
+ } else if (num) {
11963
+ tokens.push({ text: num, color: ansi.yellow });
11964
+ } else if (word) {
11965
+ if (keywords.has(word)) {
11966
+ tokens.push({ text: word, color: ansi.blue });
11967
+ } else if (constants.has(word)) {
11968
+ tokens.push({ text: word, color: ansi.yellow });
11969
+ } else if (word[0] === word[0]?.toUpperCase() && /^[A-Z]/.test(word)) {
11970
+ tokens.push({ text: word, color: ansi.cyan });
11971
+ } else {
11972
+ tokens.push({ text: word });
11973
+ }
11974
+ } else {
11975
+ tokens.push({ text: full });
11976
+ }
11977
+ }
11978
+ return tokens;
11979
+ }
11980
+ function highlightLine(line, lang) {
11981
+ const tokens = tokenizeLine(line, lang);
11982
+ return tokens.map((t) => t.color ? c(t.color, t.text) : t.text).join("");
11983
+ }
11984
+ var ESC2 = "\x1B[", RESET, ansi, EXT_MAP, JS_KEYWORDS, JS_CONSTANTS, PY_KEYWORDS, PY_CONSTANTS, C_KEYWORDS, C_CONSTANTS, JS_LINE_RE, PY_LINE_RE, C_LINE_RE;
11985
+ var init_color = __esm(() => {
11986
+ RESET = `${ESC2}0m`;
11987
+ ansi = {
11988
+ reset: RESET,
11989
+ bold: `${ESC2}1m`,
11990
+ dim: `${ESC2}2m`,
11991
+ italic: `${ESC2}3m`,
11992
+ underline: `${ESC2}4m`,
11993
+ red: `${ESC2}31m`,
11994
+ green: `${ESC2}32m`,
11995
+ yellow: `${ESC2}33m`,
11996
+ blue: `${ESC2}34m`,
11997
+ magenta: `${ESC2}35m`,
11998
+ cyan: `${ESC2}36m`,
11999
+ white: `${ESC2}37m`,
12000
+ gray: `${ESC2}90m`,
12001
+ brightRed: `${ESC2}91m`,
12002
+ brightGreen: `${ESC2}92m`,
12003
+ brightYellow: `${ESC2}93m`,
12004
+ brightBlue: `${ESC2}94m`,
12005
+ brightMagenta: `${ESC2}95m`,
12006
+ brightCyan: `${ESC2}96m`
12007
+ };
12008
+ EXT_MAP = {
12009
+ ".js": "js",
12010
+ ".mjs": "js",
12011
+ ".cjs": "js",
12012
+ ".ts": "js",
12013
+ ".mts": "js",
12014
+ ".cts": "js",
12015
+ ".tsx": "js",
12016
+ ".jsx": "js",
12017
+ ".py": "py",
12018
+ ".pyw": "py",
12019
+ ".c": "c",
12020
+ ".cpp": "c",
12021
+ ".cc": "c",
12022
+ ".cxx": "c",
12023
+ ".h": "c",
12024
+ ".hpp": "c",
12025
+ ".rs": "c",
12026
+ ".go": "c",
12027
+ ".java": "c",
12028
+ ".swift": "c",
12029
+ ".m": "c"
12030
+ };
12031
+ JS_KEYWORDS = new Set([
12032
+ "async",
12033
+ "await",
12034
+ "break",
12035
+ "case",
12036
+ "catch",
12037
+ "class",
12038
+ "const",
12039
+ "continue",
12040
+ "debugger",
12041
+ "default",
12042
+ "delete",
12043
+ "do",
12044
+ "else",
12045
+ "export",
12046
+ "extends",
12047
+ "finally",
12048
+ "for",
12049
+ "from",
12050
+ "function",
12051
+ "if",
12052
+ "import",
12053
+ "in",
12054
+ "instanceof",
12055
+ "let",
12056
+ "new",
12057
+ "of",
12058
+ "return",
12059
+ "static",
12060
+ "super",
12061
+ "switch",
12062
+ "this",
12063
+ "throw",
12064
+ "try",
12065
+ "typeof",
12066
+ "var",
12067
+ "void",
12068
+ "while",
12069
+ "with",
12070
+ "yield",
12071
+ "type",
12072
+ "interface",
12073
+ "enum",
12074
+ "as",
12075
+ "implements",
12076
+ "declare",
12077
+ "readonly",
12078
+ "abstract",
12079
+ "override"
12080
+ ]);
12081
+ JS_CONSTANTS = new Set(["true", "false", "null", "undefined", "NaN", "Infinity"]);
12082
+ PY_KEYWORDS = new Set([
12083
+ "and",
12084
+ "as",
12085
+ "assert",
12086
+ "async",
12087
+ "await",
12088
+ "break",
12089
+ "class",
12090
+ "continue",
12091
+ "def",
12092
+ "del",
12093
+ "elif",
12094
+ "else",
12095
+ "except",
12096
+ "finally",
12097
+ "for",
12098
+ "from",
12099
+ "global",
12100
+ "if",
12101
+ "import",
12102
+ "in",
12103
+ "is",
12104
+ "lambda",
12105
+ "nonlocal",
12106
+ "not",
12107
+ "or",
12108
+ "pass",
12109
+ "raise",
12110
+ "return",
12111
+ "try",
12112
+ "while",
12113
+ "with",
12114
+ "yield"
12115
+ ]);
12116
+ PY_CONSTANTS = new Set(["True", "False", "None"]);
12117
+ C_KEYWORDS = new Set([
12118
+ "auto",
12119
+ "break",
12120
+ "case",
12121
+ "char",
12122
+ "const",
12123
+ "continue",
12124
+ "default",
12125
+ "do",
12126
+ "double",
12127
+ "else",
12128
+ "enum",
12129
+ "extern",
12130
+ "float",
12131
+ "for",
12132
+ "goto",
12133
+ "if",
12134
+ "inline",
12135
+ "int",
12136
+ "long",
12137
+ "register",
12138
+ "return",
12139
+ "short",
12140
+ "signed",
12141
+ "sizeof",
12142
+ "static",
12143
+ "struct",
12144
+ "switch",
12145
+ "typedef",
12146
+ "union",
12147
+ "unsigned",
12148
+ "void",
12149
+ "volatile",
12150
+ "while",
12151
+ "class",
12152
+ "namespace",
12153
+ "template",
12154
+ "typename",
12155
+ "public",
12156
+ "private",
12157
+ "protected",
12158
+ "virtual",
12159
+ "override",
12160
+ "final",
12161
+ "new",
12162
+ "delete",
12163
+ "throw",
12164
+ "try",
12165
+ "catch",
12166
+ "using",
12167
+ "nullptr",
12168
+ "fn",
12169
+ "let",
12170
+ "mut",
12171
+ "pub",
12172
+ "impl",
12173
+ "trait",
12174
+ "self",
12175
+ "Self",
12176
+ "match",
12177
+ "mod",
12178
+ "use",
12179
+ "crate",
12180
+ "where",
12181
+ "async",
12182
+ "await",
12183
+ "move",
12184
+ "ref",
12185
+ "unsafe",
12186
+ "func",
12187
+ "package",
12188
+ "import",
12189
+ "var",
12190
+ "type",
12191
+ "range",
12192
+ "defer",
12193
+ "chan",
12194
+ "select",
12195
+ "go",
12196
+ "map",
12197
+ "interface"
12198
+ ]);
12199
+ C_CONSTANTS = new Set(["true", "false", "NULL", "nullptr", "nil"]);
12200
+ JS_LINE_RE = /(\/\/.*$|\/\*.*?\*\/)|("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)|((?<!\w)(?:0[xXoObB][\da-fA-F_]+|\d[\d_]*(?:\.[\d_]*)?(?:[eE][+-]?\d+)?n?)(?!\w))|([a-zA-Z_$][\w$]*)|(.)/g;
12201
+ PY_LINE_RE = /(#.*$)|("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|"""[\s\S]*?"""|'''[\s\S]*?''')|((?<!\w)(?:0[xXoObB][\da-fA-F_]+|\d[\d_]*(?:\.[\d_]*)?(?:[eE][+-]?\d+)?)(?!\w))|([a-zA-Z_][\w]*)|(.)/g;
12202
+ C_LINE_RE = /(\/\/.*$|\/\*.*?\*\/)|("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)')|((?<!\w)(?:0[xXoObB][\da-fA-F_]+|\d[\d_]*(?:\.[\d_]*)?(?:[eE][+-]?\d+)?[fFlLuU]*)(?!\w))|([a-zA-Z_][\w]*)|(.)/g;
12203
+ });
12204
+
11874
12205
  // src/formatter/source.ts
11875
12206
  function trimLine(content, column) {
11876
12207
  const col = column !== undefined ? column - 1 : undefined;
@@ -11898,9 +12229,11 @@ function trimLine(content, column) {
11898
12229
  const adjustedCaret = col !== undefined ? col - start + (hasPrefix ? 1 : 0) : undefined;
11899
12230
  return { text: `${prefix}${content.slice(start, end)}${suffix}`, caretOffset: adjustedCaret };
11900
12231
  }
11901
- function formatSource(lines) {
12232
+ function formatSource(lines, opts) {
11902
12233
  if (lines.length === 0)
11903
12234
  return "";
12235
+ const color = opts?.color ?? false;
12236
+ const lang = opts?.language ?? "unknown";
11904
12237
  const maxLineNum = Math.max(...lines.map((l) => l.lineNumber));
11905
12238
  const numWidth = String(maxLineNum).length;
11906
12239
  const result = [];
@@ -11915,20 +12248,36 @@ function formatSource(lines) {
11915
12248
  marker = " \u25CF";
11916
12249
  }
11917
12250
  const trimmed = line.isCurrent ? trimLine(line.content, line.currentColumn) : trimLine(line.content);
11918
- result.push(`${marker} ${num}\u2502${trimmed.text}`);
12251
+ let coloredMarker = marker;
12252
+ let coloredNum = num;
12253
+ let coloredContent = trimmed.text;
12254
+ if (color) {
12255
+ if (line.isCurrent) {
12256
+ coloredMarker = c(ansi.brightYellow, marker);
12257
+ } else if (line.hasBreakpoint) {
12258
+ coloredMarker = c(ansi.red, marker);
12259
+ }
12260
+ coloredNum = c(ansi.gray, num);
12261
+ coloredContent = highlightLine(trimmed.text, lang);
12262
+ }
12263
+ result.push(`${coloredMarker} ${coloredNum}\u2502${coloredContent}`);
11919
12264
  if (line.isCurrent && trimmed.caretOffset !== undefined && trimmed.caretOffset >= 0) {
11920
12265
  const gutter = " ".repeat(numWidth + 4);
11921
12266
  const indent = trimmed.text.slice(0, trimmed.caretOffset).replace(/[^\t]/g, " ");
11922
- result.push(`${gutter}${indent}^`);
12267
+ const caret = color ? c(ansi.brightYellow, "^") : "^";
12268
+ result.push(`${gutter}${indent}${caret}`);
11923
12269
  }
11924
12270
  }
11925
12271
  return result.join(`
11926
12272
  `);
11927
12273
  }
11928
- var init_source = () => {};
12274
+ var init_source = __esm(() => {
12275
+ init_color();
12276
+ });
11929
12277
 
11930
12278
  // src/formatter/stack.ts
11931
- function formatStack(frames) {
12279
+ function formatStack(frames, opts) {
12280
+ const color = opts?.color ?? false;
11932
12281
  const outputLines = [];
11933
12282
  const segments = [];
11934
12283
  let i = 0;
@@ -11959,28 +12308,34 @@ function formatStack(frames) {
11959
12308
  for (const seg of segments) {
11960
12309
  if ("blackboxedCount" in seg) {
11961
12310
  const label = seg.blackboxedCount === 1 ? "\u250A ... 1 framework frame (blackboxed)" : `\u250A ... ${seg.blackboxedCount} framework frames (blackboxed)`;
11962
- outputLines.push(label);
12311
+ outputLines.push(color ? c(ansi.gray, label) : label);
11963
12312
  continue;
11964
12313
  }
11965
12314
  const frame = seg;
11966
12315
  if (frame.isAsync) {
11967
- outputLines.push("\u250A async gap");
12316
+ const gap = "\u250A async gap";
12317
+ outputLines.push(color ? c(ansi.gray, gap) : gap);
11968
12318
  }
11969
12319
  const ref = frame.ref.padEnd(maxRefLen);
11970
12320
  const name = frame.functionName.padEnd(maxNameLen);
11971
12321
  const file2 = shortPath(frame.file);
11972
12322
  const loc = frame.column !== undefined ? `${file2}:${frame.line}:${frame.column}` : `${file2}:${frame.line}`;
11973
- outputLines.push(`${ref} ${name} ${loc}`);
12323
+ if (color) {
12324
+ outputLines.push(`${c(ansi.gray, ref)} ${c(ansi.yellow, name)} ${c(ansi.gray, loc)}`);
12325
+ } else {
12326
+ outputLines.push(`${ref} ${name} ${loc}`);
12327
+ }
11974
12328
  }
11975
12329
  return outputLines.join(`
11976
12330
  `);
11977
12331
  }
11978
12332
  var init_stack = __esm(() => {
12333
+ init_color();
11979
12334
  init_path();
11980
12335
  });
11981
12336
 
11982
12337
  // src/formatter/variables.ts
11983
- function formatGroup(vars) {
12338
+ function formatGroup(vars, color) {
11984
12339
  if (vars.length === 0)
11985
12340
  return "";
11986
12341
  const maxRefLen = Math.max(...vars.map((v) => v.ref.length));
@@ -11988,13 +12343,17 @@ function formatGroup(vars) {
11988
12343
  return vars.map((v) => {
11989
12344
  const ref = v.ref.padEnd(maxRefLen);
11990
12345
  const name = v.name.padEnd(maxNameLen);
12346
+ if (color) {
12347
+ return `${c(ansi.gray, ref)} ${c(ansi.cyan, name)} ${v.value}`;
12348
+ }
11991
12349
  return `${ref} ${name} ${v.value}`;
11992
12350
  }).join(`
11993
12351
  `);
11994
12352
  }
11995
- function formatVariables(vars) {
12353
+ function formatVariables(vars, opts) {
11996
12354
  if (vars.length === 0)
11997
12355
  return "";
12356
+ const color = opts?.color ?? false;
11998
12357
  const scopeOrder = [];
11999
12358
  const groups = new Map;
12000
12359
  for (const v of vars) {
@@ -12008,7 +12367,7 @@ function formatVariables(vars) {
12008
12367
  group.push(v);
12009
12368
  }
12010
12369
  if (scopeOrder.length === 1) {
12011
- return formatGroup(vars);
12370
+ return formatGroup(vars, color);
12012
12371
  }
12013
12372
  const sections = [];
12014
12373
  for (const scope of scopeOrder) {
@@ -12016,8 +12375,9 @@ function formatVariables(vars) {
12016
12375
  if (!group || group.length === 0)
12017
12376
  continue;
12018
12377
  const label = SCOPE_LABELS[scope] ?? scope;
12019
- sections.push(`${label}:
12020
- ${formatGroup(group)}`);
12378
+ const header = color ? c(ansi.bold, `${label}:`) : `${label}:`;
12379
+ sections.push(`${header}
12380
+ ${formatGroup(group, color)}`);
12021
12381
  }
12022
12382
  return sections.join(`
12023
12383
 
@@ -12025,6 +12385,7 @@ ${formatGroup(group)}`);
12025
12385
  }
12026
12386
  var SCOPE_LABELS;
12027
12387
  var init_variables = __esm(() => {
12388
+ init_color();
12028
12389
  SCOPE_LABELS = {
12029
12390
  local: "Locals",
12030
12391
  module: "Module",
@@ -12039,7 +12400,8 @@ var init_variables = __esm(() => {
12039
12400
  });
12040
12401
 
12041
12402
  // src/commands/print-state.ts
12042
- function printState(data) {
12403
+ function printState(data, opts) {
12404
+ const color = opts?.color ?? false;
12043
12405
  if (data.status !== "paused") {
12044
12406
  const icon = data.status === "running" ? "\u25B6" : "\u25CB";
12045
12407
  const label = data.status === "running" ? "Running" : "Idle";
@@ -12047,27 +12409,43 @@ function printState(data) {
12047
12409
  const desc = data.lastException.description ?? data.lastException.text;
12048
12410
  const firstLine = desc.split(`
12049
12411
  `)[0] ?? desc;
12050
- console.log(`${icon} ${label} (crashed)`);
12051
- console.log(` ${firstLine}`);
12052
- console.log(" -> Try: dbg exceptions");
12412
+ if (color) {
12413
+ console.log(`${c(ansi.yellow, icon)} ${label} ${c(ansi.red, "(crashed)")}`);
12414
+ console.log(` ${c(ansi.red, firstLine)}`);
12415
+ console.log(` ${c(ansi.cyan, "-> Try:")} dbg exceptions`);
12416
+ } else {
12417
+ console.log(`${icon} ${label} (crashed)`);
12418
+ console.log(` ${firstLine}`);
12419
+ console.log(" -> Try: dbg exceptions");
12420
+ }
12053
12421
  } else {
12054
- console.log(`${icon} ${label}`);
12422
+ if (color) {
12423
+ const coloredIcon = data.status === "running" ? c(ansi.green, icon) : c(ansi.gray, icon);
12424
+ console.log(`${coloredIcon} ${label}`);
12425
+ } else {
12426
+ console.log(`${icon} ${label}`);
12427
+ }
12055
12428
  }
12056
12429
  return;
12057
12430
  }
12058
12431
  const loc = data.location ? `${shortPath(data.location.url)}:${data.location.line}${data.location.column !== undefined ? `:${data.location.column}` : ""}` : "unknown";
12059
12432
  const reason = data.reason ?? "unknown";
12060
- console.log(`\u23F8 Paused at ${loc} (${reason})`);
12433
+ if (color) {
12434
+ console.log(`${c(ansi.brightYellow, "\u23F8")} Paused at ${c(ansi.cyan, loc)} ${c(ansi.gray, `(${reason})`)}`);
12435
+ } else {
12436
+ console.log(`\u23F8 Paused at ${loc} (${reason})`);
12437
+ }
12438
+ const lang = data.location?.url ? detectLanguage(data.location.url) : "unknown";
12061
12439
  if (data.source?.lines) {
12062
12440
  console.log("");
12063
- console.log("Source:");
12441
+ console.log(color ? c(ansi.bold, "Source:") : "Source:");
12064
12442
  const sourceLines = data.source.lines.map((l) => ({
12065
12443
  lineNumber: l.line,
12066
12444
  content: l.text,
12067
12445
  isCurrent: l.current,
12068
12446
  currentColumn: l.current ? data.location?.column : undefined
12069
12447
  }));
12070
- console.log(formatSource(sourceLines));
12448
+ console.log(formatSource(sourceLines, { color, language: lang }));
12071
12449
  }
12072
12450
  if (data.vars) {
12073
12451
  console.log("");
@@ -12077,21 +12455,21 @@ function printState(data) {
12077
12455
  value: v.value,
12078
12456
  scope: v.scope
12079
12457
  }));
12080
- const formatted = formatVariables(vars);
12458
+ const formatted = formatVariables(vars, { color });
12081
12459
  if (formatted) {
12082
12460
  const scopes = new Set(vars.map((v) => v.scope ?? "local"));
12083
12461
  if (scopes.size <= 1) {
12084
- console.log("Locals:");
12462
+ console.log(color ? c(ansi.bold, "Locals:") : "Locals:");
12085
12463
  }
12086
12464
  console.log(formatted);
12087
12465
  } else {
12088
- console.log("Locals:");
12466
+ console.log(color ? c(ansi.bold, "Locals:") : "Locals:");
12089
12467
  console.log(" (none)");
12090
12468
  }
12091
12469
  }
12092
12470
  if (data.stack) {
12093
12471
  console.log("");
12094
- console.log("Stack:");
12472
+ console.log(color ? c(ansi.bold, "Stack:") : "Stack:");
12095
12473
  const frames = data.stack.map((f) => ({
12096
12474
  ref: f.ref,
12097
12475
  functionName: f.functionName,
@@ -12100,14 +12478,19 @@ function printState(data) {
12100
12478
  column: f.column,
12101
12479
  isAsync: f.isAsync
12102
12480
  }));
12103
- console.log(formatStack(frames));
12481
+ console.log(formatStack(frames, { color }));
12104
12482
  }
12105
12483
  if (data.breakpointCount !== undefined) {
12106
12484
  console.log("");
12107
- console.log(`Breakpoints: ${data.breakpointCount} active`);
12485
+ if (color) {
12486
+ console.log(`Breakpoints: ${c(ansi.yellow, String(data.breakpointCount))} active`);
12487
+ } else {
12488
+ console.log(`Breakpoints: ${data.breakpointCount} active`);
12489
+ }
12108
12490
  }
12109
12491
  }
12110
12492
  var init_print_state = __esm(() => {
12493
+ init_color();
12111
12494
  init_path();
12112
12495
  init_source();
12113
12496
  init_stack();
@@ -12119,6 +12502,7 @@ var exports_state = {};
12119
12502
  var init_state = __esm(() => {
12120
12503
  init_registry();
12121
12504
  init_client3();
12505
+ init_color();
12122
12506
  init_print_state();
12123
12507
  registerCommand("state", async (args) => {
12124
12508
  const session2 = args.global.session;
@@ -12164,7 +12548,7 @@ var init_state = __esm(() => {
12164
12548
  console.log(JSON.stringify(data, null, 2));
12165
12549
  return 0;
12166
12550
  }
12167
- printState(data);
12551
+ printState(data, { color: shouldEnableColor(args.global.color) });
12168
12552
  return 0;
12169
12553
  });
12170
12554
  });
@@ -12174,6 +12558,7 @@ var exports_continue = {};
12174
12558
  var init_continue = __esm(() => {
12175
12559
  init_registry();
12176
12560
  init_client3();
12561
+ init_color();
12177
12562
  init_print_state();
12178
12563
  registerCommand("continue", async (args) => {
12179
12564
  const session2 = args.global.session;
@@ -12194,7 +12579,7 @@ var init_continue = __esm(() => {
12194
12579
  if (args.global.json) {
12195
12580
  console.log(JSON.stringify(data, null, 2));
12196
12581
  } else {
12197
- printState(data);
12582
+ printState(data, { color: shouldEnableColor(args.global.color) });
12198
12583
  }
12199
12584
  return 0;
12200
12585
  });
@@ -12205,6 +12590,7 @@ var exports_step = {};
12205
12590
  var init_step = __esm(() => {
12206
12591
  init_registry();
12207
12592
  init_client3();
12593
+ init_color();
12208
12594
  init_print_state();
12209
12595
  registerCommand("step", async (args) => {
12210
12596
  const session2 = args.global.session;
@@ -12227,7 +12613,7 @@ var init_step = __esm(() => {
12227
12613
  if (args.global.json) {
12228
12614
  console.log(JSON.stringify(data, null, 2));
12229
12615
  } else {
12230
- printState(data);
12616
+ printState(data, { color: shouldEnableColor(args.global.color) });
12231
12617
  }
12232
12618
  return 0;
12233
12619
  });
@@ -12238,6 +12624,7 @@ var exports_pause = {};
12238
12624
  var init_pause = __esm(() => {
12239
12625
  init_registry();
12240
12626
  init_client3();
12627
+ init_color();
12241
12628
  init_print_state();
12242
12629
  registerCommand("pause", async (args) => {
12243
12630
  const session2 = args.global.session;
@@ -12258,7 +12645,7 @@ var init_pause = __esm(() => {
12258
12645
  if (args.global.json) {
12259
12646
  console.log(JSON.stringify(data, null, 2));
12260
12647
  } else {
12261
- printState(data);
12648
+ printState(data, { color: shouldEnableColor(args.global.color) });
12262
12649
  }
12263
12650
  return 0;
12264
12651
  });
@@ -12304,6 +12691,7 @@ var exports_run_to = {};
12304
12691
  var init_run_to = __esm(() => {
12305
12692
  init_registry();
12306
12693
  init_client3();
12694
+ init_color();
12307
12695
  init_print_state();
12308
12696
  registerCommand("run-to", async (args) => {
12309
12697
  const session2 = args.global.session;
@@ -12337,7 +12725,7 @@ var init_run_to = __esm(() => {
12337
12725
  if (args.global.json) {
12338
12726
  console.log(JSON.stringify(data, null, 2));
12339
12727
  } else {
12340
- printState(data);
12728
+ printState(data, { color: shouldEnableColor(args.global.color) });
12341
12729
  }
12342
12730
  return 0;
12343
12731
  });
@@ -12348,6 +12736,7 @@ var exports_break = {};
12348
12736
  var init_break = __esm(() => {
12349
12737
  init_registry();
12350
12738
  init_client3();
12739
+ init_color();
12351
12740
  init_path();
12352
12741
  registerCommand("break", async (args) => {
12353
12742
  const session2 = args.global.session;
@@ -12412,8 +12801,13 @@ var init_break = __esm(() => {
12412
12801
  if (args.global.json) {
12413
12802
  console.log(JSON.stringify(data2, null, 2));
12414
12803
  } else {
12804
+ const color = shouldEnableColor(args.global.color);
12415
12805
  const loc = `${shortPath(data2.location.url)}:${data2.location.line}`;
12416
- console.log(`${data2.ref} set at ${loc} (log: ${logTemplate})`);
12806
+ if (color) {
12807
+ console.log(`${c(ansi.magenta, data2.ref)} set at ${c(ansi.cyan, loc)} (log: ${logTemplate})`);
12808
+ } else {
12809
+ console.log(`${data2.ref} set at ${loc} (log: ${logTemplate})`);
12810
+ }
12417
12811
  }
12418
12812
  return 0;
12419
12813
  }
@@ -12438,15 +12832,27 @@ var init_break = __esm(() => {
12438
12832
  if (args.global.json) {
12439
12833
  console.log(JSON.stringify(data, null, 2));
12440
12834
  } else {
12835
+ const color = shouldEnableColor(args.global.color);
12441
12836
  const loc = `${shortPath(data.location.url)}:${data.location.line}`;
12442
- let msg = `${data.ref} set at ${loc}`;
12443
- if (condition) {
12444
- msg += ` (condition: ${condition})`;
12445
- }
12446
- if (hitCount) {
12447
- msg += ` (hit-count: ${hitCount})`;
12837
+ if (color) {
12838
+ let msg = `${c(ansi.magenta, data.ref)} set at ${c(ansi.cyan, loc)}`;
12839
+ if (condition) {
12840
+ msg += ` ${c(ansi.gray, `(condition: ${condition})`)}`;
12841
+ }
12842
+ if (hitCount) {
12843
+ msg += ` ${c(ansi.gray, `(hit-count: ${hitCount})`)}`;
12844
+ }
12845
+ console.log(msg);
12846
+ } else {
12847
+ let msg = `${data.ref} set at ${loc}`;
12848
+ if (condition) {
12849
+ msg += ` (condition: ${condition})`;
12850
+ }
12851
+ if (hitCount) {
12852
+ msg += ` (hit-count: ${hitCount})`;
12853
+ }
12854
+ console.log(msg);
12448
12855
  }
12449
- console.log(msg);
12450
12856
  }
12451
12857
  if (shouldContinue) {
12452
12858
  const contResponse = await client.request("continue");
@@ -12544,6 +12950,7 @@ var exports_break_ls = {};
12544
12950
  var init_break_ls = __esm(() => {
12545
12951
  init_registry();
12546
12952
  init_client3();
12953
+ init_color();
12547
12954
  init_path();
12548
12955
  registerCommand("break-ls", async (args) => {
12549
12956
  const session2 = args.global.session;
@@ -12564,22 +12971,37 @@ var init_break_ls = __esm(() => {
12564
12971
  if (args.global.json) {
12565
12972
  console.log(JSON.stringify(data, null, 2));
12566
12973
  } else {
12974
+ const color = shouldEnableColor(args.global.color);
12567
12975
  if (data.length === 0) {
12568
12976
  console.log("No breakpoints or logpoints set");
12569
12977
  } else {
12570
12978
  for (const bp of data) {
12571
12979
  const loc = `${shortPath(bp.url)}:${bp.line}`;
12572
- let line = `${bp.ref} ${loc}`;
12573
- if (bp.type === "LP" && bp.template) {
12574
- line += ` (log: ${bp.template})`;
12575
- }
12576
- if (bp.condition) {
12577
- line += ` [condition: ${bp.condition}]`;
12578
- }
12579
- if (bp.hitCount) {
12580
- line += ` [hit-count: ${bp.hitCount}]`;
12980
+ if (color) {
12981
+ let line = `${c(ansi.magenta, bp.ref)} ${c(ansi.cyan, loc)}`;
12982
+ if (bp.type === "LP" && bp.template) {
12983
+ line += ` ${c(ansi.green, `(log: ${bp.template})`)}`;
12984
+ }
12985
+ if (bp.condition) {
12986
+ line += ` ${c(ansi.gray, `[condition: ${bp.condition}]`)}`;
12987
+ }
12988
+ if (bp.hitCount) {
12989
+ line += ` ${c(ansi.gray, `[hit-count: ${bp.hitCount}]`)}`;
12990
+ }
12991
+ console.log(line);
12992
+ } else {
12993
+ let line = `${bp.ref} ${loc}`;
12994
+ if (bp.type === "LP" && bp.template) {
12995
+ line += ` (log: ${bp.template})`;
12996
+ }
12997
+ if (bp.condition) {
12998
+ line += ` [condition: ${bp.condition}]`;
12999
+ }
13000
+ if (bp.hitCount) {
13001
+ line += ` [hit-count: ${bp.hitCount}]`;
13002
+ }
13003
+ console.log(line);
12581
13004
  }
12582
- console.log(line);
12583
13005
  }
12584
13006
  }
12585
13007
  }
@@ -12688,6 +13110,7 @@ var exports_source = {};
12688
13110
  var init_source2 = __esm(() => {
12689
13111
  init_registry();
12690
13112
  init_client3();
13113
+ init_color();
12691
13114
  init_path();
12692
13115
  init_source();
12693
13116
  registerCommand("source", async (args) => {
@@ -12723,13 +13146,14 @@ var init_source2 = __esm(() => {
12723
13146
  console.log(JSON.stringify(data, null, 2));
12724
13147
  return 0;
12725
13148
  }
13149
+ const color = shouldEnableColor(args.global.color);
12726
13150
  console.log(`Source: ${shortPath(data.url)}`);
12727
13151
  const sourceLines = data.lines.map((l) => ({
12728
13152
  lineNumber: l.line,
12729
13153
  content: l.text,
12730
13154
  isCurrent: l.current
12731
13155
  }));
12732
- console.log(formatSource(sourceLines));
13156
+ console.log(formatSource(sourceLines, { color, language: detectLanguage(data.url) }));
12733
13157
  return 0;
12734
13158
  });
12735
13159
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "debug-that",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Node.js Debugger CLI for AI Agents",
5
5
  "license": "MIT",
6
6
  "author": "Theodo Group",