dbg-cli 0.3.0

A universal debugger CLI that lets AI agents observe runtime state instead of guessing from source code
Documentation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>dbg demo</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body {
    background: #1e1e2e;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  }
  h1 {
    color: #cdd6f4;
    font-size: 1.4rem;
    margin-bottom: 1rem;
  }
  #term {
    background: #282a36;
    border-radius: 8px;
    padding: 16px;
    max-width: 760px;
    width: 95%;
    min-height: 420px;
    font-family: "SF Mono", "Cascadia Code", "Fira Code", "JetBrains Mono", Menlo, Consolas, monospace;
    font-size: 13px;
    line-height: 1.5;
    color: #f8f8f2;
    white-space: pre-wrap;
    word-break: break-all;
    overflow: hidden;
  }
  #controls {
    margin-top: 12px;
    display: flex;
    gap: 8px;
  }
  #controls button {
    background: #44475a;
    color: #f8f8f2;
    border: none;
    border-radius: 4px;
    padding: 6px 16px;
    font-size: 13px;
    cursor: pointer;
  }
  #controls button:hover { background: #6272a4; }
  .c-reset { color: #f8f8f2; }
  .c-bold { font-weight: bold; }
  .c-dim { opacity: 0.6; }
  .c-fg-red { color: #ff5555; }
  .c-fg-green { color: #50fa7b; }
  .c-fg-yellow { color: #f1fa8c; }
  .c-fg-blue { color: #6272a4; }
  .c-fg-magenta { color: #ff79c6; }
  .c-fg-cyan { color: #8be9fd; }
  .c-fg-white { color: #f8f8f2; }
  .c-bold.c-fg-red { color: #ff6e6e; }
  .c-bold.c-fg-green { color: #69ff94; }
  .c-bold.c-fg-yellow { color: #ffffa5; }
  .c-bold.c-fg-magenta { color: #ff92df; }
  .c-bold.c-fg-cyan { color: #a4ffff; }
</style>
</head>
<body>
  <h1>dbg: agent debugging in 30 seconds</h1>
  <div id="term"></div>
  <div id="controls">
    <button onclick="replay()">Replay</button>
  </div>
<script>
var CAST = [
[0.0,"o","\x1b[1;35m>\x1b[0m "],
[0.6,"o","T"],[0.65,"o","h"],[0.7,"o","e"],[0.73,"o"," "],
[0.78,"o","f"],[0.82,"o","u"],[0.85,"o","n"],[0.88,"o","c"],
[0.91,"o","t"],[0.94,"o","i"],[0.97,"o","o"],[1.0,"o","n"],
[1.03,"o"," "],[1.08,"o","i"],[1.11,"o","n"],[1.14,"o"," "],
[1.17,"o","/"],[1.2,"o","t"],[1.23,"o","m"],[1.26,"o","p"],
[1.29,"o","/"],[1.32,"o","c"],[1.35,"o","r"],[1.38,"o","a"],
[1.41,"o","s"],[1.44,"o","h"],[1.47,"o","."],[1.5,"o","p"],
[1.53,"o","y"],[1.56,"o"," "],[1.59,"o","c"],[1.62,"o","r"],
[1.65,"o","a"],[1.68,"o","s"],[1.71,"o","h"],[1.74,"o","e"],
[1.77,"o","s"],[1.8,"o","."],[1.83,"o"," "],[1.86,"o","D"],
[1.89,"o","e"],[1.92,"o","b"],[1.95,"o","u"],[1.98,"o","g"],
[2.01,"o"," "],[2.04,"o","i"],[2.07,"o","t"],[2.1,"o","."],
[2.5,"o","\r\n"],
[3.0,"o","\r\n"],
[3.1,"o","\x1b[2m  \u2570\u2500 \x1b[0m\x1b[2mRead /tmp/crash.py\x1b[0m\r\n"],
[3.4,"o","\r\n"],
[3.5,"o","  The file accesses \x1b[1mx[5]\x1b[0m on a list. Let me start a debug session to inspect\r\n"],
[3.6,"o","  the runtime state and find the exact failure.\r\n"],
[4.0,"o","\r\n"],
[4.1,"o","\x1b[2m  \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg start python /tmp/crash.py\x1b[0m\r\n"],
[4.4,"o","\x1b[2m     \x1b[0mtarget: /tmp/crash.py\r\n"],
[4.8,"o","\r\n"],
[4.9,"o","\x1b[2m  \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg break /tmp/crash.py:1\x1b[0m\r\n"],
[5.2,"o","\x1b[2m     \x1b[0mBreakpoint 1 at /tmp/crash.py:1\r\n"],
[5.6,"o","\r\n"],
[5.7,"o","\x1b[2m  \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg run\x1b[0m\r\n"],
[6.0,"o","\x1b[2m     \x1b[0m> /tmp/crash.py(1)<module>()\r\n"],
[6.1,"o","\x1b[2m     \x1b[0m-> x = [1,2,3]; print(x[5])\r\n"],
[6.5,"o","\r\n"],
[6.6,"o","  Hit the breakpoint. Let me step into the crash.\r\n"],
[7.0,"o","\r\n"],
[7.1,"o","\x1b[2m  \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg step\x1b[0m\r\n"],
[7.4,"o","\x1b[2m     \x1b[0m\x1b[1;31mIndexError: list index out of range\x1b[0m\r\n"],
[7.5,"o","\x1b[2m     \x1b[0m> /tmp/crash.py(1)<module>()\r\n"],
[7.6,"o","\x1b[2m     \x1b[0m-> x = [1,2,3]; print(x[5])\r\n"],
[8.0,"o","\r\n"],
[8.1,"o","  IndexError. Let me inspect the variable to confirm the root cause.\r\n"],
[8.5,"o","\r\n"],
[8.6,"o","\x1b[2m  \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg \"print(x)\"\x1b[0m\r\n"],
[8.9,"o","\x1b[2m     \x1b[0m[1, 2, 3]\r\n"],
[9.3,"o","\r\n"],
[9.4,"o","\x1b[2m  \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg \"print(len(x))\"\x1b[0m\r\n"],
[9.7,"o","\x1b[2m     \x1b[0m3\r\n"],
[10.1,"o","\r\n"],
[10.2,"o","  \x1b[1mRoot cause:\x1b[0m \x1b[33mx\x1b[0m has 3 elements (indices 0\u20132), but the code accesses \x1b[33mx[5]\x1b[0m.\r\n"],
[10.4,"o","  Fix: change \x1b[33mx[5]\x1b[0m to a valid index, or add a bounds check.\r\n"],
[10.8,"o","\r\n"],
[10.9,"o","\x1b[2m  \u2570\u2500 \x1b[0m\x1b[1;36mBash\x1b[0m \x1b[2mdbg kill\x1b[0m\r\n"],
[11.2,"o","\x1b[2m     \x1b[0mstopped\r\n"],
[11.6,"o","\r\n"],
[11.7,"o","\x1b[1;35m>\x1b[0m "],
[13.0,"o",""]
];

var FG_COLORS = {30:'',31:'red',32:'green',33:'yellow',34:'blue',35:'magenta',36:'cyan',37:'white'};

function ansiToHtml(str) {
  var result = '';
  var bold = false, dim = false, fg = '';
  var i = 0;
  while (i < str.length) {
    if (str[i] === '\x1b' && str[i+1] === '[') {
      var j = i + 2;
      while (j < str.length && str[j] !== 'm') j++;
      var codes = str.substring(i+2, j).split(';');
      for (var k = 0; k < codes.length; k++) {
        var c = parseInt(codes[k]);
        if (c === 0) { bold = false; dim = false; fg = ''; }
        else if (c === 1) bold = true;
        else if (c === 2) dim = true;
        else if (c >= 30 && c <= 37) fg = FG_COLORS[c] || '';
      }
      i = j + 1;
      var cls = [];
      if (bold) cls.push('c-bold');
      if (dim) cls.push('c-dim');
      if (fg) cls.push('c-fg-' + fg);
      result += '</span><span class="' + cls.join(' ') + '">';
    } else if (str[i] === '\r') {
      i++;
    } else if (str[i] === '<') {
      result += '&lt;'; i++;
    } else if (str[i] === '>') {
      result += '&gt;'; i++;
    } else if (str[i] === '&') {
      result += '&amp;'; i++;
    } else {
      result += str[i]; i++;
    }
  }
  return result;
}

var term = document.getElementById('term');
var timers = [];

function replay() {
  for (var i = 0; i < timers.length; i++) clearTimeout(timers[i]);
  timers = [];
  term.innerHTML = '<span>';
  for (var i = 0; i < CAST.length; i++) {
    (function(entry) {
      timers.push(setTimeout(function() {
        term.innerHTML = term.innerHTML + ansiToHtml(entry[2]);
        term.scrollTop = term.scrollHeight;
      }, entry[0] * 1000));
    })(CAST[i]);
  }
}

replay();
</script>
</body>
</html>