[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CHV9E7JV1S3A2AB2C61ZET":3,"skill-same:01M6CHV9E7JV1S3A2AB2C61ZET":81},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":30,"publishedAt":46,"linkOnly":47,"markdownContent":48,"markdownBody":49,"frontMatter":50,"refName":54,"commitSha":55,"skillDirectory":56,"forksCount":57,"repositoryHtmlUrl":58,"repositoryHomepageUrl":6,"ownerHtmlUrl":59,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":60,"install":61,"resources":74},"01M6CHV9E7JV1S3A2AB2C61ZET","dbg",null,"Debug Node.js processes and automate browser pages using the dbg stateless CLI debugger. Use when investigating runtime bugs, inspecting variables and call stacks, analyzing object state, or automating browser testing. Every call is one command in, one response out — built for AI agents and automation.","douglance\u002Fdbg","douglance","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F4741454?v=4","01M6CHV0887PTZP4ACB8QF8VXT","01M6CHV0CJMK4BTFMZ6SAGYX92",6,"MIT","https:\u002F\u002Fgithub.com\u002Fdouglance\u002Fdbg\u002Fblob\u002Fmain\u002Fskills\u002Fdbg\u002FSKILL.md",[17,22,25],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":26,"categoryName":27,"taxonomyType":28,"taxonomyTypeDesc":29},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[5,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],"testing","cli","ai agents","automation","debug","state","browser","browser testing","analyzing","debugger","js","automate","node","command","use","2026-11-10 10:12:30",false,"---\nname: dbg\ndescription: Debug Node.js processes and automate browser pages using the dbg stateless CLI debugger. Use when investigating runtime bugs, inspecting variables and call stacks, analyzing object state, or automating browser testing. Every call is one command in, one response out — built for AI agents and automation.\ncontext: fork\nlicense: MIT\nmetadata:\n  author: douglance\n  version: 0.4.0\n---\n\n# dbg - Stateless Debugger & Browser Automation\n\nDebug Node.js processes and native apps programmatically. Every `dbg` invocation is stateless: one command in, one response out, exit. A background daemon holds the CDP\u002FDAP connection between calls.\n\n## When to Use\n\n- User reports a bug or unexpected behavior in Node.js code\n- Need to inspect runtime state, variables, or call stacks\n- Investigating why code fails at a specific line\n- Analyzing object properties or prototype chains\n- Diagnosing slow CDP calls or flaky connections\n- Need post-hoc analysis of debugger session history\n- **Browser debugging**: console errors, network failures, DOM inspection\n- **Browser automation**: navigate, click, type, screenshot\n- **Performance testing**: network throttling, device emulation, coverage\n- **API mocking**: intercept network requests with custom responses\n\n## Commands\n\n### Start a Session\n\n```sh\ndbg open \u003Cport|host:port>       # attach to --inspect process\ndbg run \"node \u003Cfile>\"           # spawn with --inspect-brk, connect\n```\n\n### Set Breakpoints\n\n```sh\ndbg b \u003Cfile>:\u003Cline>                  # set breakpoint\ndbg b \u003Cfile>:\u003Cline> --if \"\u003Ccond>\"    # conditional breakpoint\ndbg bl                               # list all breakpoints\ndbg db \u003Cid>                          # delete breakpoint\n```\n\n### Taps (Logpoints)\n\nA tap is a never-pausing conditioned breakpoint that logs an expression each\ntime the line runs — instrument code without editing it or stopping execution.\nWorks on browser AND node (V8 inspector) sessions.\n\n```sh\ndbg tap add src\u002FCart.tsx:42 \"user.id\"   # log user.id whenever line 42 runs (1-based)\ndbg tap add app.js:3 \"doubled\" --url \"app\\\\.js\"  # --url overrides the file-suffix regex (bundles)\ndbg tap list                            # all taps (id, file, line, expr, url_regex)\ndbg tap hits \u003Cid> --tail 20             # the most-recent values this tap captured\ndbg tap rm \u003Cid>                         # remove the tap + its CDP breakpoint\ndbg q \"SELECT ts, value FROM tap_hits WHERE tap_id = \u003Cid>\"\n```\n\n`tap add` echoes the RESOLVED location (\"armed on \u003Curl>:\u003Cline>\") or \"arms on\nscript load\" when no matching script is loaded yet — never silently pending. The\n`__dbg_tap:` console sentinel is routed to `tap_hits` and suppressed from the\nuser-facing console, `after` consoleDelta, `dbg why`, and the timeline.\n\n### Flows (Record and Replay)\n\nFlows record user actions on the active visual recorder page and replay them\nwith trusted CDP input, per-step readiness gates, captures, console verdicts,\nand diff-vs-last-run data.\n\n```sh\ndbg record http:\u002F\u002Flocalhost:3000\ndbg flow record checkout\ndbg flow stop\ndbg flow run checkout --step-timeout 5000\ndbg flow list\ndbg flow show checkout\ndbg q \"SELECT * FROM flow_run_steps\"\n```\n\nSelector capture prefers unique `#id`, then `[data-testid]`, then a unique\ntag\u002Fclass selector, then a full `nth-of-type` fallback path.\nScroll-only flows are valid: recording a user scroll or `window.scrollTo(...)`\npersists a `scroll` step and replays it against static `file:\u002F\u002F` reports as\nwell as app pages.\n\nUse `dbg` for CDP-backed debugger state, flight-recorder verdicts, SQL tables,\nand replayable flows. The CLI package installs `@douglance\u002Fplay` as a normal\ndependency, so general Playwright-runner workflows with durable named sessions,\naccessibility snapshots, and smart selector helpers are available without\ndepending on ad hoc global setup.\n\n### Control Execution\n\n```sh\ndbg c                           # continue (blocks until next pause)\ndbg n                           # step over\ndbg s                           # step into\ndbg o                           # step out\ndbg pause                       # pause execution\ndbg status                      # check connection\u002Fpause state\n```\n\n### Inspect State (SQL)\n\n```sh\ndbg q \"SELECT * FROM frames\"\ndbg q \"SELECT name, type, value FROM vars WHERE frame_id = 0\"\ndbg q \"SELECT * FROM scripts WHERE file LIKE '%\u003Cpattern>%'\"\ndbg q \"SELECT name, value FROM props WHERE object_id = '\u003Cid>'\"\ndbg q \"SELECT * FROM console\"\ndbg q \"SELECT * FROM exceptions\"\n```\n\nSQL syntax: `SELECT [cols | *] FROM \u003Ctable> [WHERE ...] [ORDER BY col [ASC|DESC]] [LIMIT n]`\n\nWHERE operators: `=`, `!=`, `\u003C`, `>`, `\u003C=`, `>=`, `LIKE`, `AND`, `OR`, `()`\n\n### Evaluate and View Source\n\n```sh\ndbg e \"\u003Cexpression>\"            # evaluate, bare value output\ndbg src                         # source around current location\ndbg src \u003Cfile> \u003Cstart> \u003Cend>    # specific line range\n```\n\n### Diagnostics\n\n```sh\ndbg trace                       # recent CDP send\u002Frecv with latency\ndbg trace 50                    # limit to 50 messages\ndbg health                      # probe target, report latency (ms)\ndbg reconnect                   # reconnect to last websocket URL\n```\n\n### Session Lifecycle\n\n```sh\ndbg restart                     # respawn, reconnect, restore breakpoints\ndbg close                       # disconnect (kills target if started via run)\n```\n\n### Multi-Session (Frontend + Backend)\n\n```sh\ndbg run \"node server.ts\"                             # auto-named s0\ndbg open 9229 be                                     # positional name (backend)\ndbg open 9222 fe --type page                        # named \"fe\", targets browser tab\ndbg b server.ts:42 --session be                      # breakpoint on backend\ndbg navigate \"http:\u002F\u002Flocalhost:3000\u002Flogin\" --session fe\ndbg q \"SELECT * FROM console WHERE type = 'error'\" --session fe\ndbg q \"SELECT * FROM vars\" --session be\n```\n\n### Browser Navigation\n\n```sh\ndbg navigate \u003Curl>                     # go to URL\ndbg navigate reload                    # reload current page\ndbg navigate back                      # go back in history\ndbg navigate forward                   # go forward in history\n```\n\n### Browser Interaction\n\n```sh\ndbg click \"\u003Cselector>\"                 # click element by CSS selector\ndbg type \"\u003Cselector>\" \"\u003Ctext>\"         # type into element\ndbg select \"\u003Cselector>\" \"\u003Cvalue>\"      # select dropdown option\ndbg screenshot                         # capture PNG (returns base64)\ndbg screenshot \u002Ftmp\u002Fpage.png           # save to file\n```\n\n### Browser Query Tables\n\n```sh\ndbg q \"SELECT method, url, status FROM network WHERE status >= 400\"\ndbg q \"SELECT * FROM dom WHERE selector = 'h1'\"\ndbg q \"SELECT * FROM cookies\"\ndbg q \"SELECT key, value FROM storage WHERE type = 'local'\"\ndbg q \"SELECT * FROM performance\"\ndbg q \"SELECT * FROM console WHERE type = 'error'\"\n```\n\n### Network Mocking\n\n```sh\ndbg mock \"\u002Fapi\u002Fusers\" '{\"users\":[]}'              # intercept with mock response\ndbg mock \"\u002Fapi\u002Fdata\" '{}' --status 500             # mock error response\ndbg unmock \"\u002Fapi\u002Fusers\"                            # remove specific mock\ndbg unmock                                         # clear all mocks\n```\n\n### Device Emulation & Throttling\n\n```sh\ndbg emulate iphone-14                  # emulate iPhone 14 (390x844)\ndbg emulate ipad                       # emulate iPad (810x1080)\ndbg emulate pixel-7                    # emulate Pixel 7\ndbg emulate reset                      # reset to default\n\ndbg throttle 3g                        # simulate 3G network\ndbg throttle slow-3g                   # simulate slow 3G\ndbg throttle offline                   # simulate offline\ndbg throttle off                       # disable throttling\n```\n\n### Code Coverage\n\n```sh\ndbg coverage start                     # begin tracking JS + CSS usage\n# ... interact with the page ...\ndbg coverage stop\ndbg q \"SELECT url, used_pct FROM coverage ORDER BY used_pct ASC\"\n```\n\n### Visual Flight Recorder (record → edit → after)\n\n```sh\ndbg record http:\u002F\u002Flocalhost:3000     # daemon launches headless Chrome, keeps recording\ndbg record http:\u002F\u002Flocalhost:3000 --viewport 1280x720   # WxH or preset (desktop|tablet|mobile)\ndbg mark before-fix                  # stamp a named epoch (auto-epochs happen on edit bursts)\n# ... edit code; saved files + vite HMR modules annotate captures automatically ...\ndbg after --json                     # capture now, diff vs anchor: pixels + component blame\n                                     #   + style deltas + new console\u002Fnetwork errors + report.html\ndbg after --at mark:before-fix       # explicit anchors: capture:\u003Cid> | mark:\u003Cname> | time:\u003Cts|10m> | file:\u003Cpath>\ndbg after --perf-budget lcp=2500,cls=0.1   # perfDelta (ΔLCP\u002FΔCLS\u002Fbundle); nonzero exit on breach (--skip-perf to omit)\ndbg why                              # blame the most recent error → ranked edit\u002Fepoch\u002Fcommit\u002Fprompt\ndbg why \"coupon\"                     # blame the most recent error whose text contains \"coupon\"\ndbg timeline                         # filmstrip HTML of every capture with annotations\ndbg replay \u003CcaptureId>               # restore a capture's URL\u002Fscroll in the recorder page\ndbg record --status                  # captureCount, epochCount, lastCaptureTs\ndbg record --stop                    # end recording, kill managed Chrome\n```\n\n`dbg after --json` returns `pair` (diffPercent, diffPixels, clusters), `regions`\n(diff clusters blamed to React component names, or tag.class on non-React pages;\n`causal: true` when the component's file was just edited), `styleChanges`\n(computed-style deltas like `padding-top: 8px → 40px`), `consoleDelta` \u002F\n`exceptionDelta` \u002F `networkDelta`, and `reportPath` (self-contained HTML with\nside-by-side \u002F wipe \u002F onion-skin \u002F diff-overlay views). Add `--open` for humans.\n\n**Verdict sections (Plan V)** — `dbg after` also returns:\n- `networkDiff` — requests grouped by method + normalized URL pattern (numeric\n  ids \u002F uuids collapsed to `:id`), classified `added` \u002F `removed` \u002F\n  `statusChanged` \u002F `durationDelta` (anchor window vs after window).\n- `stateChanges` — added\u002Fremoved\u002Fchanged local & sessionStorage keys\n  (JSON-parsed values), from the per-capture `state_snapshots`.\n- `a11yNew` — accessibility issues present in the after capture but not the\n  anchor (five rules: missing alt, control\u002Fbutton without name, control without\n  label, duplicate landmark, missing document title).\n- `perfDelta` (Plan X) — ΔLCP, ΔCLS (new layout shift during flows), new\n  longtask count, ΔJSHeap, Δbundle_bytes, and interaction count\u002Fmax-duration.\n  Sourced from a buffered `PerformanceObserver` (LCP\u002FCLS\u002Flongtask\u002Fpaint\u002Fevent)\n  plus a per-capture `Performance.getMetrics` subset (`JSHeapUsedSize`,\n  `JSHeapTotalSize`, `Nodes`, `Documents`, `JSEventListeners`, `LayoutCount`,\n  `RecalcStyleCount`) and a per-nav Script\u002FStylesheet `bundle_bytes` total.\n  `nav_id` increments per main-frame navigation observed by the daemon; entries\n  are stamped with the nav_id current at receipt. The recorder loop is HMR-alive\n  (not reload-heavy), so CLS\u002FLCP are per-hard-nav — they reset only on real\n  document navigations. Rows land in the `perf_samples` table.\n\n`dbg why [substring]` walks the substrate back from the target error to ranked\ncauses and returns a `why` verdict + one-line `answer`, e.g. *\"'Cannot read x of\nundefined' first seen …, 2.1s after you saved src\u002FCart.tsx (epoch 4:\n'before-fix', prompt: 'add coupon field')\"*. Ranking = edit recency +\nfile-in-stack-trace bonus; plus the enclosing epoch, nearest commit, and active\nagent prompt. Reads errors from the **persisted** event store, so it works after\n`record --stop` (subject to the events TTL).\n\nEach `after` section is individually skippable to stay fast: `--skip-network`,\n`--skip-state`, `--skip-a11y`, `--skip-perf` (measured `after` ≈ 220ms with all\non — perfDelta is pure store reads and adds no CDP round-trip to `after`, so no\nbudget bump was needed; the only cold cost is one `Performance.getMetrics` call\nper capture, best-effort and parallel to snapshot work).\n`--perf-budget lcp=2500,cls=0.1` fails (nonzero exit) when the after-side delta\nbreaches a budget (keys: `lcp`, `cls`, `longtask`, `jsheap`, `bundle`).\n\n### Deliberate Captures (shoot)\n\n```sh\ndbg shoot http:\u002F\u002Flocalhost:3000 --selector \"#nav\" --states hover,focus\ndbg shoot src\u002FButton.tsx --props '{\"variant\":\"primary\"}'   # esbuild harness renders\n                                     # the component with YOUR react-dom at #dbg-root\ndbg shoot http:\u002F\u002Flocalhost:3000 --viewport mobile --full-page\ndbg shoot http:\u002F\u002Flocalhost:3000 --out screenshots\u002F --name nav-check\n```\n\nViewport presets: `desktop` (1280x800), `tablet` (768x1024), `mobile` (390x844),\nor any `WxH`. Each state produces its own PNG under `.dbg\u002Fshots\u002F` (base name for\nthe default state, `name@hover.png` etc. for forced states); shots also land as\n`captures` rows under session `shoot`. prefers-reduced-motion is emulated so\nanimations don't pollute pixels. For Storybook, shoot the story URL directly\n(e.g. `dbg shoot 'http:\u002F\u002Flocalhost:6006\u002Fiframe.html?id=button--primary'`).\n\n### Apple Device \u002F Simulator (iOS, tvOS, watchOS, visionOS)\n\n```sh\ndbg devices                            # list all devices + simulators\ndbg devices --platform ios             # filter by platform\ndbg apps \u003Cdevice-id>                   # list installed apps on a device\ndbg attach com.example.myapp           # attach to running app\ndbg attach com.example.myapp --launch  # launch app then attach\ndbg attach com.example.myapp --device sim:\"iPhone 15\" --launch\ndbg attach com.example.myapp --device device:\u003Cudid> --launch\n```\n\nOn physical devices, if attach fails without `--launch`, dbg automatically retries with `--launch`. After a `--launch` attach, dbg auto-continues past dyld into app code (lands at `main`).\n\n### Native Debug (LLDB Sessions)\n\n```sh\ndbg attach-lldb .\u002Fa.out                # launch local binary via lldb-dap\ndbg registers                          # show CPU registers\ndbg memory \u003Caddr> \u003Clen>                # read process memory\ndbg disasm                             # disassemble at current location\ndbg disasm \u003Caddr>                      # disassemble at specific address\n```\n\nNote: `registers` on physical devices returns a friendly error instead of crashing the session if the adapter disconnects.\n\n### Target Management\n\n```sh\ndbg targets 9222                       # list all debuggable tabs\ndbg open 9222 --type page              # connect to first page target\ndbg open 9222 --target \u003Cid>            # connect to specific tab\n```\n\n## Virtual Tables\n\n### Debugger State\n\n| Table | Description | Required Filter |\n|---|---|---|\n| `frames` | Call stack | — |\n| `scopes` | Scope chains | — |\n| `vars` | Variables (frame 0, skips global) | — |\n| `this` | `this` binding per frame | — |\n| `props` | Object properties | `object_id` |\n| `proto` | Prototype chain | `object_id` |\n| `breakpoints` | All breakpoints | — |\n| `scripts` | Loaded scripts | — |\n| `source` | Source lines | `file` or `script_id` |\n| `console` | Console messages | — |\n| `exceptions` | Thrown exceptions | — |\n| `async_frames` | Async stack traces | — |\n| `listeners` | Event listeners | `object_id` |\n\n### Event Log\n\n| Table | Description |\n|---|---|\n| `events` | Raw event log (daemon, CDP, connections) |\n| `cdp` \u002F `cdp_messages` | CDP messages with direction and latency |\n| `connections` | Connection lifecycle (connect, disconnect, reconnect) |\n| `events_stream` | CDP event-stream debug view (stream\u002Fphase\u002Fseverity classification, windowing, coalescing) |\n\nEvent log queries:\n\n```sh\ndbg q \"SELECT direction, method, latency_ms FROM cdp ORDER BY id DESC LIMIT 20\"\ndbg q \"SELECT method, latency_ms FROM cdp WHERE latency_ms > 100\"\ndbg q \"SELECT ts, event, session_id FROM connections\"\ndbg q \"SELECT ts, stream, severity, method, entity, summary FROM events_stream ORDER BY ts DESC LIMIT 120\"\ndbg q \"SELECT ts, stream, severity, method, summary FROM events_stream WHERE include = 'errors' ORDER BY ts DESC LIMIT 80\"\ndbg q \"SELECT ts, stream, method, summary FROM events_stream WHERE detail = 'full' AND window_ms = 5000 ORDER BY ts DESC LIMIT 200\"\n```\n\n> Note: the `timeline` name now refers to the unified cross-source stream (see\n> **Unified Timeline** below). The CDP event-stream view was renamed to\n> `events_stream`; its schema and behavior are unchanged.\n\nEvent-backed tables (`events`, `cdp`, `connections`, `events_stream`, `timeline`) can be queried even when no debug session is active.\n\n#### Native Tables (LLDB\u002FDAP Sessions)\n\n| Table | Description | Required Filter |\n|---|---|---|\n| `registers` | CPU register values | — |\n| `memory` | Process memory bytes | `address`, `length` |\n| `disassembly` | Disassembled instructions | `address` |\n| `threads` | Active threads | — |\n| `modules` | Loaded modules\u002Flibraries | — |\n| `watchpoints` | Hardware watchpoints | — |\n| `signals` | Signal information | — |\n\n## Browser Tables\n\n| Table | Description | Required Filter |\n|---|---|---|\n| `network` | HTTP requests\u002Fresponses | — |\n| `network_headers` | Request\u002Fresponse headers | `request_id` |\n| `network_body` | Response body content | `request_id` |\n| `page_events` | Page lifecycle events | — |\n| `dom` | DOM elements by selector | `selector` |\n| `styles` | Computed CSS styles | `node_id` |\n| `performance` | Performance metrics | — |\n| `cookies` | Browser cookies | — |\n| `storage` | localStorage\u002FsessionStorage | `type` (local\u002Fsession) |\n| `ws_frames` | WebSocket messages | — |\n| `coverage` | JS\u002FCSS code coverage | — |\n\nBrowser table queries:\n\n```sh\ndbg q \"SELECT method, url, status, duration_ms FROM network\"\ndbg q \"SELECT name, value FROM network_headers WHERE request_id = '\u003Cid>'\"\ndbg q \"SELECT body FROM network_body WHERE request_id = '\u003Cid>'\"\ndbg q \"SELECT node_id, tag, text FROM dom WHERE selector = '.error'\"\ndbg q \"SELECT name, value FROM styles WHERE node_id = 42\"\ndbg q \"SELECT name, value FROM cookies WHERE domain LIKE '%example%'\"\ndbg q \"SELECT key, value FROM storage WHERE type = 'local'\"\n```\n\n## Recorder & Dev Tables\n\nEvery development signal is stored on one **epoch-milliseconds** timeline (UTC\n`ts` INTEGER across every table), so screenshots, file edits, git commits, and\nagent history all join on `ts` directly.\n\n| Table | Description | Source |\n|---|---|---|\n| `captures` | Screenshot capture metadata (url, hash, epoch_id, tier) | recorder store |\n| `epochs` | Epoch markers (auto on edit bursts, or named via `dbg mark`) | recorder store |\n| `diffs` | `dbg after` pixel-diff results | recorder store |\n| `regions` | Blamed diff clusters (`diff_id`) | recorder store |\n| `edits` | **First-class file-edit stream** — one row per fs-watch event (`ts`, `path`, `epoch_id`, `session_id`), tagged with the current epoch | recorder store |\n| `state_snapshots` | Per-capture local\u002FsessionStorage dump (`capture_id`, `kind`, `data` JSON) | recorder store |\n| `a11y_issues` | Per-capture accessibility issues (`capture_id`, `rule`, `selector`, `detail`) | recorder store |\n| `taps` | Logpoints (`id`, `session_id`, `file`, `line`, `expr`, `url_regex`, `enabled`) | debug store |\n| `tap_hits` | Each tap fire (`tap_id`, `ts`, `value`) | debug store |\n| `flows` | Recorded user flows (`id`, `ts`, `name`, `url`, `session_id`) | recorder store |\n| `flow_steps` | Recorded flow actions (`flow_id`, `idx`, `kind`, `selector`, `fallback_path`, `value`) | recorder store |\n| `flow_runs` | Flow replay summaries (`status`, `steps_total`, `steps_passed`) | recorder store |\n| `flow_run_steps` | Per-step replay verdicts (`status`, `capture_id`, `error`, `diff_percent`) | recorder store |\n| `commits` | `git log` (hash, short_hash, ts, author, summary, files); default repo = cwd, override `WHERE repo = '\u002Fabs'` (500 most recent) | git |\n| `agent_prompts` | Claude Code prompts (`ts`, `display`, `project`); default-scoped to cwd, `WHERE project = '\u003Cslug>'` widens | `~\u002F.claude\u002Fhistory.jsonl` |\n| `agent_sessions` | Per-session transcript summaries (`ts_first`, `ts_last`, `title`, `message_count`) | `~\u002F.claude\u002Fprojects\u002F\u003Cslug>` |\n| `timeline` | **Unified union** over all of the above | union |\n\n`dbg q` threads your shell's cwd to the daemon, so `commits` \u002F `agent_prompts` \u002F\n`agent_sessions` scope to *your* project, not the daemon's.\n\n### Unified Timeline\n\n`timeline` is a single ts-ordered union (columns: `ts`, `kind`, `session_id`,\n`label`, `ref_id`, `detail`). `kind` ∈ `capture` (label=url) · `mark`\u002F`epoch` ·\n`edit` (label=path) · `error` \u002F `exception` (label=text) · `netfail`\n(label=`method url status`) · `commit` (label=summary, ref_id=short_hash) ·\n`prompt` (label=first 120 chars) · `diff`. It defaults to the **last 24h**\nunless a `WHERE` constrains `ts`.\n\nMulti-table joins, `BETWEEN`, `GROUP BY`, and aliases now run as **real SQL**:\nqueries that reference more than one table (or that the single-table engine\ncan't parse) are materialized into an in-memory SQLite DB and executed there.\n\n```sh\n# 1. Causal chain — which prompt caused the edit that produced an error\ndbg q \"SELECT p.display, e.path, c.url, x.label\n       FROM agent_prompts p\n       JOIN edits e ON e.ts BETWEEN p.ts AND p.ts + 600000\n       JOIN captures c ON c.ts BETWEEN e.ts AND e.ts + 30000\n       JOIN timeline x ON x.kind = 'error' AND x.ts BETWEEN e.ts AND e.ts + 5000\n       ORDER BY e.ts\"\n\n# 2. Errors within 5s of each edit\ndbg q \"SELECT e.path, e.ts, t.label\n       FROM edits e\n       JOIN timeline t ON t.kind = 'error' AND t.ts BETWEEN e.ts AND e.ts + 5000\n       ORDER BY e.ts\"\n\n# 3. Commits with no subsequent capture (shipped but never re-recorded)\ndbg q \"SELECT c.short_hash, c.summary\n       FROM commits c\n       WHERE (SELECT COUNT(*) FROM captures cap WHERE cap.ts > c.ts) = 0\"\n```\n\n**Cold-scan costs:** `commits` shells out to `git log` (~50–150ms). `agent_prompts`\nreads one JSONL file (~100ms cold). `agent_sessions` scans a project's transcript\ndir — ~0.7s cold on a large history, ~50ms warm (results are cached by\npath+mtime+size). `edits` \u002F `captures` \u002F `epochs` \u002F `diffs` are indexed store\nreads (sub-ms). `dbg timeline` HTML now interleaves commit + prompt chips between\nframe cards by `ts`.\n\n> Network failures ride the timeline as the `netfail` kind, reconstructed from\n> the raw events table (whose `ts` is wall-clock epoch-ms at receipt — not CDP's\n> monotonic `Network.*.timestamp`), so they honor the unified `ts` contract.\n\n## Output Format\n\n- **TOON** (compact, token-efficient) by default for every command\n- **JSON**: `dbg q \"SELECT * FROM frames\" --json` (or `--format json`)\n- `--format toon|json|yaml|md|jsonl` picks the encoding explicitly\n- Flow commands return a structured object (`status: paused`, `file`, `line`, `function`)\n- **Exit 0** success, **1** error. Parse stdout, check exit code.\n\n## Object Drill-Down Pattern\n\n```sh\n# 1. Get object_id from variables\ndbg q \"SELECT name, object_id FROM vars WHERE name = 'config'\"\n\n# 2. Inspect its properties\ndbg q \"SELECT name, type, value FROM props WHERE object_id = '\u003Cid>'\"\n\n# 3. Keep drilling into nested objects\ndbg q \"SELECT name, value FROM props WHERE object_id = '\u003Cchild_id>'\"\n```\n\n## Example Workflow\n\n```sh\n# Scenario: Function returns unexpected value\ndbg run \"node app.ts\"\ndbg b app.ts:42\ndbg c\ndbg q \"SELECT name, type, value FROM vars WHERE frame_id = 0\"\ndbg e \"config.settings\"\ndbg q \"SELECT id, function, file, line FROM frames LIMIT 5\"\ndbg n\ndbg q \"SELECT name, value FROM vars WHERE name = 'result'\"\ndbg close\n```\n\n## Browser Debug Loop\n\n```sh\n# Scenario: Login page is broken\ndbg open 9222 --type page\ndbg navigate \"http:\u002F\u002Flocalhost:3000\u002Flogin\"\ndbg q \"SELECT type, text FROM console WHERE type = 'error'\" --json\ndbg q \"SELECT method, status, url FROM network WHERE status >= 400\" --json\ndbg q \"SELECT node_id, text FROM dom WHERE selector = '.error-message'\" --json\n# ... identify and fix the bug in code ...\ndbg navigate reload\ndbg q \"SELECT * FROM console WHERE type = 'error'\" --json\ndbg screenshot \u002Ftmp\u002Flogin-fixed.png\n# Verify: zero errors, page renders correctly\ndbg close\n```\n\n## Environment Variables\n\n| Variable | Default | Description |\n|---|---|---|\n| `DBG_SOCK` | `\u002Ftmp\u002Fdbg.sock` | Unix socket path for daemon communication |\n| `DBG_EVENTS_DB` | `\u002Ftmp\u002Fdbg-events.db` | SQLite event store path (set a persistent path to keep history across runs) |\n\n## Postmortem Timeline Workflow\n\n```sh\n# Keep one persistent event DB for repeated runs\nexport DBG_EVENTS_DB=\"$HOME\u002F.dbg\u002Fhistory.db\"\n\n# Run dbg workflows as usual (open\u002Frun\u002Fnavigate\u002Fetc.)\n# Later, even with no active session:\ndbg q \"SELECT ts, stream, severity, method, summary FROM timeline ORDER BY ts DESC LIMIT 200\"\ndbg q \"SELECT ts, method, error FROM cdp WHERE error != '' ORDER BY ts DESC LIMIT 100\"\n```\n\n## Native Device Debug Loop\n\n```sh\n# Scenario: Debug an iOS app on a physical device\ndbg devices --platform ios\ndbg apps \u003Cdevice-id>\ndbg attach com.example.myapp               # auto-retries with --launch if needed\n# Now paused in app code (main), not dyld\ndbg b ViewController.swift:42\ndbg c\ndbg q \"SELECT name, value FROM vars WHERE frame_id = 0\"\ndbg n\ndbg e \"self.viewModel.state\"\ndbg close\n```\n\n## Visual Before\u002FAfter Loop (agents)\n\nThe recorder gives every code edit a visual paper trail — no window, no human:\n\n```sh\ndbg record http:\u002F\u002Flocalhost:3000     # 1. start recording (background, headless)\ndbg mark attempt-1                   # 2. stamp where you are\n# 3. edit code — file saves and HMR updates annotate captures automatically\ndbg after --json                     # 4. verdict: pixel diff % + blamed components\n                                     #    + style deltas + new errors, in one JSON\n# 5. iterate; when done, show report.html to the human (dbg after --open)\ndbg record --stop\n```\n\n\"Before\" always exists retroactively: the anchor defaults to the last capture\nat the newest epoch, so you can edit first and ask questions later.\n\nPerformance: sub-second after-verdicts are the design target, so poll freely.\nCI-enforced budgets (test\u002Fperf.test.ts): record cold start \u003C 4s, mark \u003C 500ms,\nafter \u003C 1.5s, timeline \u003C 1s, shoot \u003C 5s, mutation → capture row \u003C 1.5s.\n\nThe `dbg after --json` verdict shape:\n\n```json\n{\n  \"ok\": true,\n  \"pair\": { \"name\": \"capture 1 → capture 3\", \"baseline\": {\"captureId\": 1, \"ts\": 0},\n            \"after\": {\"captureId\": 3, \"ts\": 0}, \"diffPercent\": 27.8,\n            \"diffPixels\": 133588, \"dimensionsChanged\": false, \"clusters\": 2 },\n  \"regions\": [ { \"box\": {\"x\": 8, \"y\": 61, \"w\": 480, \"h\": 280},\n                 \"label\": \"ColorCard\", \"component\": \"ColorCard\",\n                 \"file\": null, \"causal\": true } ],\n  \"styleChanges\": [ { \"selector\": \"div.color-card\", \"prop\": \"padding-top\",\n                      \"before\": \"8px\", \"after\": \"40px\" } ],\n  \"consoleDelta\": { \"new\": [ {\"type\": \"error\", \"text\": \"boom\", \"ts\": 0} ] },\n  \"exceptionDelta\": { \"new\": [] },\n  \"networkDelta\": { \"failed\": [] },\n  \"reportPath\": \".dbg\u002Frecordings\u002Freport.html\"\n}\n```\n\nRetention: capture history is bounded — metadata rows are kept forever, but\npixels decay oldest-first once past the budgets (200 full frames \u002F 100MB per\nsession; `--max-frames`, `--max-bytes`). Decayed frames become ≤320px thumbs,\nthen metadata-only (`captures.tier` = 'full'|'thumb'|'meta'). Epoch anchors,\ndiff baselines, and the newest capture never decay, so `dbg after` anchors\nstay diffable; a decayed `--at` anchor returns an error suggesting the nearest\nfull capture. Raw CDP `events` rows expire after 30 minutes (most-recent 50k\nkept; `--events-ttl`). Check usage with `dbg record --status` (diskBytes,\nfullFrames\u002FthumbFrames\u002FmetaFrames, eventsRows).\n\nRecorder SQL tables (join them with `console`, `network`, etc.):\n\n```sh\ndbg q \"SELECT ts, changed_files, hmr_modules, epoch_id FROM captures\"  # visual git log\ndbg q \"SELECT id, ts, name, auto FROM epochs\"                          # marks + edit bursts\ndbg q \"SELECT name, diff_percent, report_path FROM diffs\"              # every after verdict\ndbg q \"SELECT diff_id, component, causal FROM regions\"                 # who changed the pixels\n```\n\n## Tips\n\n- Every `dbg` call is independent — no session to manage\n- Breakpoints persist across `dbg restart`\n- Use SQL WHERE clauses to filter large result sets\n- `dbg trace` shows CDP\u002FDAP latency to diagnose slow operations\n- `dbg health` quickly verifies the target is responsive\n- `dbg reconnect` recovers from dropped websocket connections\n- For browser pages, use `dbg open \u003Cport> --type page` to skip Node.js targets\n- `dbg targets \u003Cport>` lists all available tabs — use `--target \u003Cid>` for specific ones\n- Network mocks survive page reload (Fetch domain stays enabled)\n- Screenshot returns base64 PNG — agents can \"see\" the page\n- Combine DOM queries + screenshots for both structural and visual verification\n- Physical device attach auto-retries with `--launch` if needed\n- After `--launch`, dbg auto-continues past dyld to `main`\n- `registers` on physical devices fails gracefully (no session crash)\n\n## Success Criteria\n\n- Root cause identified and documented\n- Relevant variables, stack frames, or object state captured\n- Fix validated by re-running with breakpoints at the fix point\n","# dbg - Stateless Debugger & Browser Automation\n\nDebug Node.js processes and native apps programmatically. Every `dbg` invocation is stateless: one command in, one response out, exit. A background daemon holds the CDP\u002FDAP connection between calls.\n\n## When to Use\n\n- User reports a bug or unexpected behavior in Node.js code\n- Need to inspect runtime state, variables, or call stacks\n- Investigating why code fails at a specific line\n- Analyzing object properties or prototype chains\n- Diagnosing slow CDP calls or flaky connections\n- Need post-hoc analysis of debugger session history\n- **Browser debugging**: console errors, network failures, DOM inspection\n- **Browser automation**: navigate, click, type, screenshot\n- **Performance testing**: network throttling, device emulation, coverage\n- **API mocking**: intercept network requests with custom responses\n\n## Commands\n\n### Start a Session\n\n```sh\ndbg open \u003Cport|host:port>       # attach to --inspect process\ndbg run \"node \u003Cfile>\"           # spawn with --inspect-brk, connect\n```\n\n### Set Breakpoints\n\n```sh\ndbg b \u003Cfile>:\u003Cline>                  # set breakpoint\ndbg b \u003Cfile>:\u003Cline> --if \"\u003Ccond>\"    # conditional breakpoint\ndbg bl                               # list all breakpoints\ndbg db \u003Cid>                          # delete breakpoint\n```\n\n### Taps (Logpoints)\n\nA tap is a never-pausing conditioned breakpoint that logs an expression each\ntime the line runs — instrument code without editing it or stopping execution.\nWorks on browser AND node (V8 inspector) sessions.\n\n```sh\ndbg tap add src\u002FCart.tsx:42 \"user.id\"   # log user.id whenever line 42 runs (1-based)\ndbg tap add app.js:3 \"doubled\" --url \"app\\\\.js\"  # --url overrides the file-suffix regex (bundles)\ndbg tap list                            # all taps (id, file, line, expr, url_regex)\ndbg tap hits \u003Cid> --tail 20             # the most-recent values this tap captured\ndbg tap rm \u003Cid>                         # remove the tap + its CDP breakpoint\ndbg q \"SELECT ts, value FROM tap_hits WHERE tap_id = \u003Cid>\"\n```\n\n`tap add` echoes the RESOLVED location (\"armed on \u003Curl>:\u003Cline>\") or \"arms on\nscript load\" when no matching script is loaded yet — never silently pending. The\n`__dbg_tap:` console sentinel is routed to `tap_hits` and suppressed from the\nuser-facing console, `after` consoleDelta, `dbg why`, and the timeline.\n\n### Flows (Record and Replay)\n\nFlows record user actions on the active visual recorder page and replay them\nwith trusted CDP input, per-step readiness gates, captures, console verdicts,\nand diff-vs-last-run data.\n\n```sh\ndbg record http:\u002F\u002Flocalhost:3000\ndbg flow record checkout\ndbg flow stop\ndbg flow run checkout --step-timeout 5000\ndbg flow list\ndbg flow show checkout\ndbg q \"SELECT * FROM flow_run_steps\"\n```\n\nSelector capture prefers unique `#id`, then `[data-testid]`, then a unique\ntag\u002Fclass selector, then a full `nth-of-type` fallback path.\nScroll-only flows are valid: recording a user scroll or `window.scrollTo(...)`\npersists a `scroll` step and replays it against static `file:\u002F\u002F` reports as\nwell as app pages.\n\nUse `dbg` for CDP-backed debugger state, flight-recorder verdicts, SQL tables,\nand replayable flows. The CLI package installs `@douglance\u002Fplay` as a normal\ndependency, so general Playwright-runner workflows with durable named sessions,\naccessibility snapshots, and smart selector helpers are available without\ndepending on ad hoc global setup.\n\n### Control Execution\n\n```sh\ndbg c                           # continue (blocks until next pause)\ndbg n                           # step over\ndbg s                           # step into\ndbg o                           # step out\ndbg pause                       # pause execution\ndbg status                      # check connection\u002Fpause state\n```\n\n### Inspect State (SQL)\n\n```sh\ndbg q \"SELECT * FROM frames\"\ndbg q \"SELECT name, type, value FROM vars WHERE frame_id = 0\"\ndbg q \"SELECT * FROM scripts WHERE file LIKE '%\u003Cpattern>%'\"\ndbg q \"SELECT name, value FROM props WHERE object_id = '\u003Cid>'\"\ndbg q \"SELECT * FROM console\"\ndbg q \"SELECT * FROM exceptions\"\n```\n\nSQL syntax: `SELECT [cols | *] FROM \u003Ctable> [WHERE ...] [ORDER BY col [ASC|DESC]] [LIMIT n]`\n\nWHERE operators: `=`, `!=`, `\u003C`, `>`, `\u003C=`, `>=`, `LIKE`, `AND`, `OR`, `()`\n\n### Evaluate and View Source\n\n```sh\ndbg e \"\u003Cexpression>\"            # evaluate, bare value output\ndbg src                         # source around current location\ndbg src \u003Cfile> \u003Cstart> \u003Cend>    # specific line range\n```\n\n### Diagnostics\n\n```sh\ndbg trace                       # recent CDP send\u002Frecv with latency\ndbg trace 50                    # limit to 50 messages\ndbg health                      # probe target, report latency (ms)\ndbg reconnect                   # reconnect to last websocket URL\n```\n\n### Session Lifecycle\n\n```sh\ndbg restart                     # respawn, reconnect, restore breakpoints\ndbg close                       # disconnect (kills target if started via run)\n```\n\n### Multi-Session (Frontend + Backend)\n\n```sh\ndbg run \"node server.ts\"                             # auto-named s0\ndbg open 9229 be                                     # positional name (backend)\ndbg open 9222 fe --type page                        # named \"fe\", targets browser tab\ndbg b server.ts:42 --session be                      # breakpoint on backend\ndbg navigate \"http:\u002F\u002Flocalhost:3000\u002Flogin\" --session fe\ndbg q \"SELECT * FROM console WHERE type = 'error'\" --session fe\ndbg q \"SELECT * FROM vars\" --session be\n```\n\n### Browser Navigation\n\n```sh\ndbg navigate \u003Curl>                     # go to URL\ndbg navigate reload                    # reload current page\ndbg navigate back                      # go back in history\ndbg navigate forward                   # go forward in history\n```\n\n### Browser Interaction\n\n```sh\ndbg click \"\u003Cselector>\"                 # click element by CSS selector\ndbg type \"\u003Cselector>\" \"\u003Ctext>\"         # type into element\ndbg select \"\u003Cselector>\" \"\u003Cvalue>\"      # select dropdown option\ndbg screenshot                         # capture PNG (returns base64)\ndbg screenshot \u002Ftmp\u002Fpage.png           # save to file\n```\n\n### Browser Query Tables\n\n```sh\ndbg q \"SELECT method, url, status FROM network WHERE status >= 400\"\ndbg q \"SELECT * FROM dom WHERE selector = 'h1'\"\ndbg q \"SELECT * FROM cookies\"\ndbg q \"SELECT key, value FROM storage WHERE type = 'local'\"\ndbg q \"SELECT * FROM performance\"\ndbg q \"SELECT * FROM console WHERE type = 'error'\"\n```\n\n### Network Mocking\n\n```sh\ndbg mock \"\u002Fapi\u002Fusers\" '{\"users\":[]}'              # intercept with mock response\ndbg mock \"\u002Fapi\u002Fdata\" '{}' --status 500             # mock error response\ndbg unmock \"\u002Fapi\u002Fusers\"                            # remove specific mock\ndbg unmock                                         # clear all mocks\n```\n\n### Device Emulation & Throttling\n\n```sh\ndbg emulate iphone-14                  # emulate iPhone 14 (390x844)\ndbg emulate ipad                       # emulate iPad (810x1080)\ndbg emulate pixel-7                    # emulate Pixel 7\ndbg emulate reset                      # reset to default\n\ndbg throttle 3g                        # simulate 3G network\ndbg throttle slow-3g                   # simulate slow 3G\ndbg throttle offline                   # simulate offline\ndbg throttle off                       # disable throttling\n```\n\n### Code Coverage\n\n```sh\ndbg coverage start                     # begin tracking JS + CSS usage\n# ... interact with the page ...\ndbg coverage stop\ndbg q \"SELECT url, used_pct FROM coverage ORDER BY used_pct ASC\"\n```\n\n### Visual Flight Recorder (record → edit → after)\n\n```sh\ndbg record http:\u002F\u002Flocalhost:3000     # daemon launches headless Chrome, keeps recording\ndbg record http:\u002F\u002Flocalhost:3000 --viewport 1280x720   # WxH or preset (desktop|tablet|mobile)\ndbg mark before-fix                  # stamp a named epoch (auto-epochs happen on edit bursts)\n# ... edit code; saved files + vite HMR modules annotate captures automatically ...\ndbg after --json                     # capture now, diff vs anchor: pixels + component blame\n                                     #   + style deltas + new console\u002Fnetwork errors + report.html\ndbg after --at mark:before-fix       # explicit anchors: capture:\u003Cid> | mark:\u003Cname> | time:\u003Cts|10m> | file:\u003Cpath>\ndbg after --perf-budget lcp=2500,cls=0.1   # perfDelta (ΔLCP\u002FΔCLS\u002Fbundle); nonzero exit on breach (--skip-perf to omit)\ndbg why                              # blame the most recent error → ranked edit\u002Fepoch\u002Fcommit\u002Fprompt\ndbg why \"coupon\"                     # blame the most recent error whose text contains \"coupon\"\ndbg timeline                         # filmstrip HTML of every capture with annotations\ndbg replay \u003CcaptureId>               # restore a capture's URL\u002Fscroll in the recorder page\ndbg record --status                  # captureCount, epochCount, lastCaptureTs\ndbg record --stop                    # end recording, kill managed Chrome\n```\n\n`dbg after --json` returns `pair` (diffPercent, diffPixels, clusters), `regions`\n(diff clusters blamed to React component names, or tag.class on non-React pages;\n`causal: true` when the component's file was just edited), `styleChanges`\n(computed-style deltas like `padding-top: 8px → 40px`), `consoleDelta` \u002F\n`exceptionDelta` \u002F `networkDelta`, and `reportPath` (self-contained HTML with\nside-by-side \u002F wipe \u002F onion-skin \u002F diff-overlay views). Add `--open` for humans.\n\n**Verdict sections (Plan V)** — `dbg after` also returns:\n- `networkDiff` — requests grouped by method + normalized URL pattern (numeric\n  ids \u002F uuids collapsed to `:id`), classified `added` \u002F `removed` \u002F\n  `statusChanged` \u002F `durationDelta` (anchor window vs after window).\n- `stateChanges` — added\u002Fremoved\u002Fchanged local & sessionStorage keys\n  (JSON-parsed values), from the per-capture `state_snapshots`.\n- `a11yNew` — accessibility issues present in the after capture but not the\n  anchor (five rules: missing alt, control\u002Fbutton without name, control without\n  label, duplicate landmark, missing document title).\n- `perfDelta` (Plan X) — ΔLCP, ΔCLS (new layout shift during flows), new\n  longtask count, ΔJSHeap, Δbundle_bytes, and interaction count\u002Fmax-duration.\n  Sourced from a buffered `PerformanceObserver` (LCP\u002FCLS\u002Flongtask\u002Fpaint\u002Fevent)\n  plus a per-capture `Performance.getMetrics` subset (`JSHeapUsedSize`,\n  `JSHeapTotalSize`, `Nodes`, `Documents`, `JSEventListeners`, `LayoutCount`,\n  `RecalcStyleCount`) and a per-nav Script\u002FStylesheet `bundle_bytes` total.\n  `nav_id` increments per main-frame navigation observed by the daemon; entries\n  are stamped with the nav_id current at receipt. The recorder loop is HMR-alive\n  (not reload-heavy), so CLS\u002FLCP are per-hard-nav — they reset only on real\n  document navigations. Rows land in the `perf_samples` table.\n\n`dbg why [substring]` walks the substrate back from the target error to ranked\ncauses and returns a `why` verdict + one-line `answer`, e.g. *\"'Cannot read x of\nundefined' first seen …, 2.1s after you saved src\u002FCart.tsx (epoch 4:\n'before-fix', prompt: 'add coupon field')\"*. Ranking = edit recency +\nfile-in-stack-trace bonus; plus the enclosing epoch, nearest commit, and active\nagent prompt. Reads errors from the **persisted** event store, so it works after\n`record --stop` (subject to the events TTL).\n\nEach `after` section is individually skippable to stay fast: `--skip-network`,\n`--skip-state`, `--skip-a11y`, `--skip-perf` (measured `after` ≈ 220ms with all\non — perfDelta is pure store reads and adds no CDP round-trip to `after`, so no\nbudget bump was needed; the only cold cost is one `Performance.getMetrics` call\nper capture, best-effort and parallel to snapshot work).\n`--perf-budget lcp=2500,cls=0.1` fails (nonzero exit) when the after-side delta\nbreaches a budget (keys: `lcp`, `cls`, `longtask`, `jsheap`, `bundle`).\n\n### Deliberate Captures (shoot)\n\n```sh\ndbg shoot http:\u002F\u002Flocalhost:3000 --selector \"#nav\" --states hover,focus\ndbg shoot src\u002FButton.tsx --props '{\"variant\":\"primary\"}'   # esbuild harness renders\n                                     # the component with YOUR react-dom at #dbg-root\ndbg shoot http:\u002F\u002Flocalhost:3000 --viewport mobile --full-page\ndbg shoot http:\u002F\u002Flocalhost:3000 --out screenshots\u002F --name nav-check\n```\n\nViewport presets: `desktop` (1280x800), `tablet` (768x1024), `mobile` (390x844),\nor any `WxH`. Each state produces its own PNG under `.dbg\u002Fshots\u002F` (base name for\nthe default state, `name@hover.png` etc. for forced states); shots also land as\n`captures` rows under session `shoot`. prefers-reduced-motion is emulated so\nanimations don't pollute pixels. For Storybook, shoot the story URL directly\n(e.g. `dbg shoot 'http:\u002F\u002Flocalhost:6006\u002Fiframe.html?id=button--primary'`).\n\n### Apple Device \u002F Simulator (iOS, tvOS, watchOS, visionOS)\n\n```sh\ndbg devices                            # list all devices + simulators\ndbg devices --platform ios             # filter by platform\ndbg apps \u003Cdevice-id>                   # list installed apps on a device\ndbg attach com.example.myapp           # attach to running app\ndbg attach com.example.myapp --launch  # launch app then attach\ndbg attach com.example.myapp --device sim:\"iPhone 15\" --launch\ndbg attach com.example.myapp --device device:\u003Cudid> --launch\n```\n\nOn physical devices, if attach fails without `--launch`, dbg automatically retries with `--launch`. After a `--launch` attach, dbg auto-continues past dyld into app code (lands at `main`).\n\n### Native Debug (LLDB Sessions)\n\n```sh\ndbg attach-lldb .\u002Fa.out                # launch local binary via lldb-dap\ndbg registers                          # show CPU registers\ndbg memory \u003Caddr> \u003Clen>                # read process memory\ndbg disasm                             # disassemble at current location\ndbg disasm \u003Caddr>                      # disassemble at specific address\n```\n\nNote: `registers` on physical devices returns a friendly error instead of crashing the session if the adapter disconnects.\n\n### Target Management\n\n```sh\ndbg targets 9222                       # list all debuggable tabs\ndbg open 9222 --type page              # connect to first page target\ndbg open 9222 --target \u003Cid>            # connect to specific tab\n```\n\n## Virtual Tables\n\n### Debugger State\n\n| Table | Description | Required Filter |\n|---|---|---|\n| `frames` | Call stack | — |\n| `scopes` | Scope chains | — |\n| `vars` | Variables (frame 0, skips global) | — |\n| `this` | `this` binding per frame | — |\n| `props` | Object properties | `object_id` |\n| `proto` | Prototype chain | `object_id` |\n| `breakpoints` | All breakpoints | — |\n| `scripts` | Loaded scripts | — |\n| `source` | Source lines | `file` or `script_id` |\n| `console` | Console messages | — |\n| `exceptions` | Thrown exceptions | — |\n| `async_frames` | Async stack traces | — |\n| `listeners` | Event listeners | `object_id` |\n\n### Event Log\n\n| Table | Description |\n|---|---|\n| `events` | Raw event log (daemon, CDP, connections) |\n| `cdp` \u002F `cdp_messages` | CDP messages with direction and latency |\n| `connections` | Connection lifecycle (connect, disconnect, reconnect) |\n| `events_stream` | CDP event-stream debug view (stream\u002Fphase\u002Fseverity classification, windowing, coalescing) |\n\nEvent log queries:\n\n```sh\ndbg q \"SELECT direction, method, latency_ms FROM cdp ORDER BY id DESC LIMIT 20\"\ndbg q \"SELECT method, latency_ms FROM cdp WHERE latency_ms > 100\"\ndbg q \"SELECT ts, event, session_id FROM connections\"\ndbg q \"SELECT ts, stream, severity, method, entity, summary FROM events_stream ORDER BY ts DESC LIMIT 120\"\ndbg q \"SELECT ts, stream, severity, method, summary FROM events_stream WHERE include = 'errors' ORDER BY ts DESC LIMIT 80\"\ndbg q \"SELECT ts, stream, method, summary FROM events_stream WHERE detail = 'full' AND window_ms = 5000 ORDER BY ts DESC LIMIT 200\"\n```\n\n> Note: the `timeline` name now refers to the unified cross-source stream (see\n> **Unified Timeline** below). The CDP event-stream view was renamed to\n> `events_stream`; its schema and behavior are unchanged.\n\nEvent-backed tables (`events`, `cdp`, `connections`, `events_stream`, `timeline`) can be queried even when no debug session is active.\n\n#### Native Tables (LLDB\u002FDAP Sessions)\n\n| Table | Description | Required Filter |\n|---|---|---|\n| `registers` | CPU register values | — |\n| `memory` | Process memory bytes | `address`, `length` |\n| `disassembly` | Disassembled instructions | `address` |\n| `threads` | Active threads | — |\n| `modules` | Loaded modules\u002Flibraries | — |\n| `watchpoints` | Hardware watchpoints | — |\n| `signals` | Signal information | — |\n\n## Browser Tables\n\n| Table | Description | Required Filter |\n|---|---|---|\n| `network` | HTTP requests\u002Fresponses | — |\n| `network_headers` | Request\u002Fresponse headers | `request_id` |\n| `network_body` | Response body content | `request_id` |\n| `page_events` | Page lifecycle events | — |\n| `dom` | DOM elements by selector | `selector` |\n| `styles` | Computed CSS styles | `node_id` |\n| `performance` | Performance metrics | — |\n| `cookies` | Browser cookies | — |\n| `storage` | localStorage\u002FsessionStorage | `type` (local\u002Fsession) |\n| `ws_frames` | WebSocket messages | — |\n| `coverage` | JS\u002FCSS code coverage | — |\n\nBrowser table queries:\n\n```sh\ndbg q \"SELECT method, url, status, duration_ms FROM network\"\ndbg q \"SELECT name, value FROM network_headers WHERE request_id = '\u003Cid>'\"\ndbg q \"SELECT body FROM network_body WHERE request_id = '\u003Cid>'\"\ndbg q \"SELECT node_id, tag, text FROM dom WHERE selector = '.error'\"\ndbg q \"SELECT name, value FROM styles WHERE node_id = 42\"\ndbg q \"SELECT name, value FROM cookies WHERE domain LIKE '%example%'\"\ndbg q \"SELECT key, value FROM storage WHERE type = 'local'\"\n```\n\n## Recorder & Dev Tables\n\nEvery development signal is stored on one **epoch-milliseconds** timeline (UTC\n`ts` INTEGER across every table), so screenshots, file edits, git commits, and\nagent history all join on `ts` directly.\n\n| Table | Description | Source |\n|---|---|---|\n| `captures` | Screenshot capture metadata (url, hash, epoch_id, tier) | recorder store |\n| `epochs` | Epoch markers (auto on edit bursts, or named via `dbg mark`) | recorder store |\n| `diffs` | `dbg after` pixel-diff results | recorder store |\n| `regions` | Blamed diff clusters (`diff_id`) | recorder store |\n| `edits` | **First-class file-edit stream** — one row per fs-watch event (`ts`, `path`, `epoch_id`, `session_id`), tagged with the current epoch | recorder store |\n| `state_snapshots` | Per-capture local\u002FsessionStorage dump (`capture_id`, `kind`, `data` JSON) | recorder store |\n| `a11y_issues` | Per-capture accessibility issues (`capture_id`, `rule`, `selector`, `detail`) | recorder store |\n| `taps` | Logpoints (`id`, `session_id`, `file`, `line`, `expr`, `url_regex`, `enabled`) | debug store |\n| `tap_hits` | Each tap fire (`tap_id`, `ts`, `value`) | debug store |\n| `flows` | Recorded user flows (`id`, `ts`, `name`, `url`, `session_id`) | recorder store |\n| `flow_steps` | Recorded flow actions (`flow_id`, `idx`, `kind`, `selector`, `fallback_path`, `value`) | recorder store |\n| `flow_runs` | Flow replay summaries (`status`, `steps_total`, `steps_passed`) | recorder store |\n| `flow_run_steps` | Per-step replay verdicts (`status`, `capture_id`, `error`, `diff_percent`) | recorder store |\n| `commits` | `git log` (hash, short_hash, ts, author, summary, files); default repo = cwd, override `WHERE repo = '\u002Fabs'` (500 most recent) | git |\n| `agent_prompts` | Claude Code prompts (`ts`, `display`, `project`); default-scoped to cwd, `WHERE project = '\u003Cslug>'` widens | `~\u002F.claude\u002Fhistory.jsonl` |\n| `agent_sessions` | Per-session transcript summaries (`ts_first`, `ts_last`, `title`, `message_count`) | `~\u002F.claude\u002Fprojects\u002F\u003Cslug>` |\n| `timeline` | **Unified union** over all of the above | union |\n\n`dbg q` threads your shell's cwd to the daemon, so `commits` \u002F `agent_prompts` \u002F\n`agent_sessions` scope to *your* project, not the daemon's.\n\n### Unified Timeline\n\n`timeline` is a single ts-ordered union (columns: `ts`, `kind`, `session_id`,\n`label`, `ref_id`, `detail`). `kind` ∈ `capture` (label=url) · `mark`\u002F`epoch` ·\n`edit` (label=path) · `error` \u002F `exception` (label=text) · `netfail`\n(label=`method url status`) · `commit` (label=summary, ref_id=short_hash) ·\n`prompt` (label=first 120 chars) · `diff`. It defaults to the **last 24h**\nunless a `WHERE` constrains `ts`.\n\nMulti-table joins, `BETWEEN`, `GROUP BY`, and aliases now run as **real SQL**:\nqueries that reference more than one table (or that the single-table engine\ncan't parse) are materialized into an in-memory SQLite DB and executed there.\n\n```sh\n# 1. Causal chain — which prompt caused the edit that produced an error\ndbg q \"SELECT p.display, e.path, c.url, x.label\n       FROM agent_prompts p\n       JOIN edits e ON e.ts BETWEEN p.ts AND p.ts + 600000\n       JOIN captures c ON c.ts BETWEEN e.ts AND e.ts + 30000\n       JOIN timeline x ON x.kind = 'error' AND x.ts BETWEEN e.ts AND e.ts + 5000\n       ORDER BY e.ts\"\n\n# 2. Errors within 5s of each edit\ndbg q \"SELECT e.path, e.ts, t.label\n       FROM edits e\n       JOIN timeline t ON t.kind = 'error' AND t.ts BETWEEN e.ts AND e.ts + 5000\n       ORDER BY e.ts\"\n\n# 3. Commits with no subsequent capture (shipped but never re-recorded)\ndbg q \"SELECT c.short_hash, c.summary\n       FROM commits c\n       WHERE (SELECT COUNT(*) FROM captures cap WHERE cap.ts > c.ts) = 0\"\n```\n\n**Cold-scan costs:** `commits` shells out to `git log` (~50–150ms). `agent_prompts`\nreads one JSONL file (~100ms cold). `agent_sessions` scans a project's transcript\ndir — ~0.7s cold on a large history, ~50ms warm (results are cached by\npath+mtime+size). `edits` \u002F `captures` \u002F `epochs` \u002F `diffs` are indexed store\nreads (sub-ms). `dbg timeline` HTML now interleaves commit + prompt chips between\nframe cards by `ts`.\n\n> Network failures ride the timeline as the `netfail` kind, reconstructed from\n> the raw events table (whose `ts` is wall-clock epoch-ms at receipt — not CDP's\n> monotonic `Network.*.timestamp`), so they honor the unified `ts` contract.\n\n## Output Format\n\n- **TOON** (compact, token-efficient) by default for every command\n- **JSON**: `dbg q \"SELECT * FROM frames\" --json` (or `--format json`)\n- `--format toon|json|yaml|md|jsonl` picks the encoding explicitly\n- Flow commands return a structured object (`status: paused`, `file`, `line`, `function`)\n- **Exit 0** success, **1** error. Parse stdout, check exit code.\n\n## Object Drill-Down Pattern\n\n```sh\n# 1. Get object_id from variables\ndbg q \"SELECT name, object_id FROM vars WHERE name = 'config'\"\n\n# 2. Inspect its properties\ndbg q \"SELECT name, type, value FROM props WHERE object_id = '\u003Cid>'\"\n\n# 3. Keep drilling into nested objects\ndbg q \"SELECT name, value FROM props WHERE object_id = '\u003Cchild_id>'\"\n```\n\n## Example Workflow\n\n```sh\n# Scenario: Function returns unexpected value\ndbg run \"node app.ts\"\ndbg b app.ts:42\ndbg c\ndbg q \"SELECT name, type, value FROM vars WHERE frame_id = 0\"\ndbg e \"config.settings\"\ndbg q \"SELECT id, function, file, line FROM frames LIMIT 5\"\ndbg n\ndbg q \"SELECT name, value FROM vars WHERE name = 'result'\"\ndbg close\n```\n\n## Browser Debug Loop\n\n```sh\n# Scenario: Login page is broken\ndbg open 9222 --type page\ndbg navigate \"http:\u002F\u002Flocalhost:3000\u002Flogin\"\ndbg q \"SELECT type, text FROM console WHERE type = 'error'\" --json\ndbg q \"SELECT method, status, url FROM network WHERE status >= 400\" --json\ndbg q \"SELECT node_id, text FROM dom WHERE selector = '.error-message'\" --json\n# ... identify and fix the bug in code ...\ndbg navigate reload\ndbg q \"SELECT * FROM console WHERE type = 'error'\" --json\ndbg screenshot \u002Ftmp\u002Flogin-fixed.png\n# Verify: zero errors, page renders correctly\ndbg close\n```\n\n## Environment Variables\n\n| Variable | Default | Description |\n|---|---|---|\n| `DBG_SOCK` | `\u002Ftmp\u002Fdbg.sock` | Unix socket path for daemon communication |\n| `DBG_EVENTS_DB` | `\u002Ftmp\u002Fdbg-events.db` | SQLite event store path (set a persistent path to keep history across runs) |\n\n## Postmortem Timeline Workflow\n\n```sh\n# Keep one persistent event DB for repeated runs\nexport DBG_EVENTS_DB=\"$HOME\u002F.dbg\u002Fhistory.db\"\n\n# Run dbg workflows as usual (open\u002Frun\u002Fnavigate\u002Fetc.)\n# Later, even with no active session:\ndbg q \"SELECT ts, stream, severity, method, summary FROM timeline ORDER BY ts DESC LIMIT 200\"\ndbg q \"SELECT ts, method, error FROM cdp WHERE error != '' ORDER BY ts DESC LIMIT 100\"\n```\n\n## Native Device Debug Loop\n\n```sh\n# Scenario: Debug an iOS app on a physical device\ndbg devices --platform ios\ndbg apps \u003Cdevice-id>\ndbg attach com.example.myapp               # auto-retries with --launch if needed\n# Now paused in app code (main), not dyld\ndbg b ViewController.swift:42\ndbg c\ndbg q \"SELECT name, value FROM vars WHERE frame_id = 0\"\ndbg n\ndbg e \"self.viewModel.state\"\ndbg close\n```\n\n## Visual Before\u002FAfter Loop (agents)\n\nThe recorder gives every code edit a visual paper trail — no window, no human:\n\n```sh\ndbg record http:\u002F\u002Flocalhost:3000     # 1. start recording (background, headless)\ndbg mark attempt-1                   # 2. stamp where you are\n# 3. edit code — file saves and HMR updates annotate captures automatically\ndbg after --json                     # 4. verdict: pixel diff % + blamed components\n                                     #    + style deltas + new errors, in one JSON\n# 5. iterate; when done, show report.html to the human (dbg after --open)\ndbg record --stop\n```\n\n\"Before\" always exists retroactively: the anchor defaults to the last capture\nat the newest epoch, so you can edit first and ask questions later.\n\nPerformance: sub-second after-verdicts are the design target, so poll freely.\nCI-enforced budgets (test\u002Fperf.test.ts): record cold start \u003C 4s, mark \u003C 500ms,\nafter \u003C 1.5s, timeline \u003C 1s, shoot \u003C 5s, mutation → capture row \u003C 1.5s.\n\nThe `dbg after --json` verdict shape:\n\n```json\n{\n  \"ok\": true,\n  \"pair\": { \"name\": \"capture 1 → capture 3\", \"baseline\": {\"captureId\": 1, \"ts\": 0},\n            \"after\": {\"captureId\": 3, \"ts\": 0}, \"diffPercent\": 27.8,\n            \"diffPixels\": 133588, \"dimensionsChanged\": false, \"clusters\": 2 },\n  \"regions\": [ { \"box\": {\"x\": 8, \"y\": 61, \"w\": 480, \"h\": 280},\n                 \"label\": \"ColorCard\", \"component\": \"ColorCard\",\n                 \"file\": null, \"causal\": true } ],\n  \"styleChanges\": [ { \"selector\": \"div.color-card\", \"prop\": \"padding-top\",\n                      \"before\": \"8px\", \"after\": \"40px\" } ],\n  \"consoleDelta\": { \"new\": [ {\"type\": \"error\", \"text\": \"boom\", \"ts\": 0} ] },\n  \"exceptionDelta\": { \"new\": [] },\n  \"networkDelta\": { \"failed\": [] },\n  \"reportPath\": \".dbg\u002Frecordings\u002Freport.html\"\n}\n```\n\nRetention: capture history is bounded — metadata rows are kept forever, but\npixels decay oldest-first once past the budgets (200 full frames \u002F 100MB per\nsession; `--max-frames`, `--max-bytes`). Decayed frames become ≤320px thumbs,\nthen metadata-only (`captures.tier` = 'full'|'thumb'|'meta'). Epoch anchors,\ndiff baselines, and the newest capture never decay, so `dbg after` anchors\nstay diffable; a decayed `--at` anchor returns an error suggesting the nearest\nfull capture. Raw CDP `events` rows expire after 30 minutes (most-recent 50k\nkept; `--events-ttl`). Check usage with `dbg record --status` (diskBytes,\nfullFrames\u002FthumbFrames\u002FmetaFrames, eventsRows).\n\nRecorder SQL tables (join them with `console`, `network`, etc.):\n\n```sh\ndbg q \"SELECT ts, changed_files, hmr_modules, epoch_id FROM captures\"  # visual git log\ndbg q \"SELECT id, ts, name, auto FROM epochs\"                          # marks + edit bursts\ndbg q \"SELECT name, diff_percent, report_path FROM diffs\"              # every after verdict\ndbg q \"SELECT diff_id, component, causal FROM regions\"                 # who changed the pixels\n```\n\n## Tips\n\n- Every `dbg` call is independent — no session to manage\n- Breakpoints persist across `dbg restart`\n- Use SQL WHERE clauses to filter large result sets\n- `dbg trace` shows CDP\u002FDAP latency to diagnose slow operations\n- `dbg health` quickly verifies the target is responsive\n- `dbg reconnect` recovers from dropped websocket connections\n- For browser pages, use `dbg open \u003Cport> --type page` to skip Node.js targets\n- `dbg targets \u003Cport>` lists all available tabs — use `--target \u003Cid>` for specific ones\n- Network mocks survive page reload (Fetch domain stays enabled)\n- Screenshot returns base64 PNG — agents can \"see\" the page\n- Combine DOM queries + screenshots for both structural and visual verification\n- Physical device attach auto-retries with `--launch` if needed\n- After `--launch`, dbg auto-continues past dyld to `main`\n- `registers` on physical devices fails gracefully (no session crash)\n\n## Success Criteria\n\n- Root cause identified and documented\n- Relevant variables, stack frames, or object state captured\n- Fix validated by re-running with breakpoints at the fix point\n",{"name":5,"context":51,"license":14,"metadata":52,"description":7},"fork",{"author":9,"version":53},"0.4.0","main","be748465e0f6b08c881307d42ca2c674e4d27eb3","skills\u002Fdbg",0,"https:\u002F\u002Fgithub.com\u002Fdouglance\u002Fdbg","https:\u002F\u002Fgithub.com\u002Fdouglance","2026-07-08 22:14:09",{"source":8,"skillName":5,"commands":62,"prompt":72,"zipAvailable":73},[63,66,69],{"tool":64,"command":65},"npx","npx skills add douglance\u002Fdbg --skill dbg",{"tool":67,"command":68},"bunx","bunx skills add douglance\u002Fdbg --skill dbg",{"tool":70,"command":71},"pnpm","pnpm dlx skills add douglance\u002Fdbg --skill dbg","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdouglance\u002Fdbg\u002Fblob\u002Fmain\u002Fskills\u002Fdbg\u002FSKILL.md",true,[75],{"path":76,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":79,"sourceHtmlUrl":80},"references\u002Ftables.md","REFERENCE","参考文档",12794,"https:\u002F\u002Fgithub.com\u002Fdouglance\u002Fdbg\u002Fblob\u002Fmain\u002Fskills\u002Fdbg\u002Freferences\u002Ftables.md",[82,107,112],{"skillNo":83,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":88,"publishedAt":46},"01M6CHV68A3AAMMRNP13H9GC4Y","but","Commit, push, branch, and manage version control with GitButler. Use for: commit my changes, check what changed, create a PR, push my branch, view diff, create branches, stage files, edit commit history, squash commits, amend commits, undo commits, pull requests, merge, stash work. Replaces git - use 'but' instead of git commit, git status, git push, git checkout, git add, git diff, git branch, git rebase, git stash, git merge. Covers all git, version control, and source control operations.","https:\u002F\u002Fgithub.com\u002Fdouglance\u002Fdbg\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fgitbutler\u002FSKILL.md",[],[84,89,90,91,92,93,94,95,96,97,98,45,99,100,101,102,103,104,105,106],"pull","git commit","push","team","commits","squash","git push","history","branch","view","version","diff","files","manage","git branch","git merge","pr","commit",{"skillNo":108,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":111,"publishedAt":46},"01M6CHV4V3KGJN2HNYW25WBCD0","https:\u002F\u002Fgithub.com\u002Fdouglance\u002Fdbg\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fdbg\u002FSKILL.md",[],[5],{"skillNo":113,"name":114,"nameZh":6,"description":115,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":116,"categories":117,"keywords":118,"publishedAt":46},"01M6CHV28JYJDS261WZ273WVD0","dbg-dev","Develop, test, and debug the dbg stateless CLI debugger. Build workflow, architecture, self-debugging patterns, and contributor guidance.","https:\u002F\u002Fgithub.com\u002Fdouglance\u002Fdbg\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fdbg-dev\u002FSKILL.md",[],[119,120,32,121,122,123,124,40,125,126,35,127,128,129],"dev","dbg dev","patterns","build","guidance","develop","build workflow","debugging","architecture","test","workflow"]