litclaude-ai 0.2.2

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 (156) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/LICENSE +21 -0
  3. package/README.md +369 -0
  4. package/README_ko-KR.md +374 -0
  5. package/RELEASE_CHECKLIST.md +165 -0
  6. package/bin/litclaude-ai.js +643 -0
  7. package/cover.png +0 -0
  8. package/docs/agents.md +67 -0
  9. package/docs/hooks.md +134 -0
  10. package/docs/lsp.md +40 -0
  11. package/docs/migration.md +209 -0
  12. package/docs/workflow-compatibility-audit.md +119 -0
  13. package/generate_cover.py +123 -0
  14. package/package.json +48 -0
  15. package/plugins/litclaude/.claude-plugin/plugin.json +25 -0
  16. package/plugins/litclaude/.lsp.json +13 -0
  17. package/plugins/litclaude/.mcp.json +9 -0
  18. package/plugins/litclaude/agents/boulder-executor.md +12 -0
  19. package/plugins/litclaude/agents/librarian-researcher.md +15 -0
  20. package/plugins/litclaude/agents/oracle-verifier.md +16 -0
  21. package/plugins/litclaude/agents/prometheus-planner.md +13 -0
  22. package/plugins/litclaude/agents/qa-runner.md +16 -0
  23. package/plugins/litclaude/agents/quality-reviewer.md +17 -0
  24. package/plugins/litclaude/bin/litclaude-hook.js +110 -0
  25. package/plugins/litclaude/bin/litclaude-hud.js +271 -0
  26. package/plugins/litclaude/bin/litclaude-lsp-doctor.js +15 -0
  27. package/plugins/litclaude/bin/litclaude-mcp.js +70 -0
  28. package/plugins/litclaude/commands/deep-interview.md +21 -0
  29. package/plugins/litclaude/commands/dynamic-workflow.md +36 -0
  30. package/plugins/litclaude/commands/lit-loop.md +40 -0
  31. package/plugins/litclaude/commands/lit-plan.md +35 -0
  32. package/plugins/litclaude/commands/litgoal.md +30 -0
  33. package/plugins/litclaude/commands/review-work.md +35 -0
  34. package/plugins/litclaude/commands/start-work.md +36 -0
  35. package/plugins/litclaude/hooks/hooks.json +54 -0
  36. package/plugins/litclaude/lib/context-pressure.mjs +25 -0
  37. package/plugins/litclaude/lib/hud-accent-palette.mjs +58 -0
  38. package/plugins/litclaude/lib/litgoal/cli.mjs +266 -0
  39. package/plugins/litclaude/lib/litgoal/ledger.mjs +16 -0
  40. package/plugins/litclaude/lib/litgoal/paths.mjs +7 -0
  41. package/plugins/litclaude/lib/litgoal/state.mjs +67 -0
  42. package/plugins/litclaude/lib/mutated-file-paths.mjs +63 -0
  43. package/plugins/litclaude/lib/start-work-continuation.mjs +99 -0
  44. package/plugins/litclaude/lib/workflow-check.mjs +83 -0
  45. package/plugins/litclaude/skills/ai-slop-remover/SKILL.md +142 -0
  46. package/plugins/litclaude/skills/comment-checker/SKILL.md +55 -0
  47. package/plugins/litclaude/skills/debugging/SKILL.md +70 -0
  48. package/plugins/litclaude/skills/debugging/references/methodology/00-setup.md +108 -0
  49. package/plugins/litclaude/skills/debugging/references/methodology/02-investigate.md +126 -0
  50. package/plugins/litclaude/skills/debugging/references/methodology/04-oracle-triple.md +106 -0
  51. package/plugins/litclaude/skills/debugging/references/methodology/05-escalate.md +69 -0
  52. package/plugins/litclaude/skills/debugging/references/methodology/06-fix.md +116 -0
  53. package/plugins/litclaude/skills/debugging/references/methodology/08-qa.md +94 -0
  54. package/plugins/litclaude/skills/debugging/references/methodology/09-cleanup.md +164 -0
  55. package/plugins/litclaude/skills/debugging/references/methodology/partial-runtime-evidence.md +228 -0
  56. package/plugins/litclaude/skills/debugging/references/runtimes/bundled-js-binary.md +415 -0
  57. package/plugins/litclaude/skills/debugging/references/runtimes/go.md +252 -0
  58. package/plugins/litclaude/skills/debugging/references/runtimes/native-binary.md +484 -0
  59. package/plugins/litclaude/skills/debugging/references/runtimes/node.md +260 -0
  60. package/plugins/litclaude/skills/debugging/references/runtimes/python.md +248 -0
  61. package/plugins/litclaude/skills/debugging/references/runtimes/rust.md +234 -0
  62. package/plugins/litclaude/skills/debugging/references/tools/ghidra.md +212 -0
  63. package/plugins/litclaude/skills/debugging/references/tools/playwright-cli.md +194 -0
  64. package/plugins/litclaude/skills/debugging/references/tools/pwndbg.md +263 -0
  65. package/plugins/litclaude/skills/debugging/references/tools/pwntools.md +265 -0
  66. package/plugins/litclaude/skills/deep-interview/SKILL.md +323 -0
  67. package/plugins/litclaude/skills/deep-interview/scripts/render_progress.py +193 -0
  68. package/plugins/litclaude/skills/frontend-ui-ux/SKILL.md +62 -0
  69. package/plugins/litclaude/skills/lit-loop/SKILL.md +144 -0
  70. package/plugins/litclaude/skills/lit-plan/SKILL.md +125 -0
  71. package/plugins/litclaude/skills/litgoal/SKILL.md +219 -0
  72. package/plugins/litclaude/skills/lsp/SKILL.md +63 -0
  73. package/plugins/litclaude/skills/programming/SKILL.md +106 -0
  74. package/plugins/litclaude/skills/programming/references/go/README.md +90 -0
  75. package/plugins/litclaude/skills/programming/references/go/backend-stack.md +641 -0
  76. package/plugins/litclaude/skills/programming/references/go/bootstrap.md +328 -0
  77. package/plugins/litclaude/skills/programming/references/go/bubbletea-v2.md +360 -0
  78. package/plugins/litclaude/skills/programming/references/go/cobra-stack.md +468 -0
  79. package/plugins/litclaude/skills/programming/references/go/concurrency.md +362 -0
  80. package/plugins/litclaude/skills/programming/references/go/data-modeling.md +329 -0
  81. package/plugins/litclaude/skills/programming/references/go/error-handling.md +359 -0
  82. package/plugins/litclaude/skills/programming/references/go/golangci-strict.md +236 -0
  83. package/plugins/litclaude/skills/programming/references/go/grpc-connect.md +375 -0
  84. package/plugins/litclaude/skills/programming/references/go/libraries.md +337 -0
  85. package/plugins/litclaude/skills/programming/references/go/one-liners.md +202 -0
  86. package/plugins/litclaude/skills/programming/references/go/sqlc-pgx.md +471 -0
  87. package/plugins/litclaude/skills/programming/references/go/testing.md +467 -0
  88. package/plugins/litclaude/skills/programming/references/go/type-patterns.md +298 -0
  89. package/plugins/litclaude/skills/programming/references/python/README.md +314 -0
  90. package/plugins/litclaude/skills/programming/references/python/async-anyio.md +442 -0
  91. package/plugins/litclaude/skills/programming/references/python/data-modeling.md +233 -0
  92. package/plugins/litclaude/skills/programming/references/python/data-processing.md +133 -0
  93. package/plugins/litclaude/skills/programming/references/python/error-handling.md +218 -0
  94. package/plugins/litclaude/skills/programming/references/python/fastapi-stack.md +316 -0
  95. package/plugins/litclaude/skills/programming/references/python/httpx2-optimization.md +360 -0
  96. package/plugins/litclaude/skills/programming/references/python/libraries.md +307 -0
  97. package/plugins/litclaude/skills/programming/references/python/one-liners.md +268 -0
  98. package/plugins/litclaude/skills/programming/references/python/orjson-stack.md +378 -0
  99. package/plugins/litclaude/skills/programming/references/python/pydantic-ai.md +285 -0
  100. package/plugins/litclaude/skills/programming/references/python/pyproject-strict.md +232 -0
  101. package/plugins/litclaude/skills/programming/references/python/textual-tui.md +201 -0
  102. package/plugins/litclaude/skills/programming/references/python/type-patterns.md +176 -0
  103. package/plugins/litclaude/skills/programming/references/rust/README.md +317 -0
  104. package/plugins/litclaude/skills/programming/references/rust/async-tokio.md +299 -0
  105. package/plugins/litclaude/skills/programming/references/rust/axum-stack.md +467 -0
  106. package/plugins/litclaude/skills/programming/references/rust/cargo-strict.md +317 -0
  107. package/plugins/litclaude/skills/programming/references/rust/clap-stack.md +409 -0
  108. package/plugins/litclaude/skills/programming/references/rust/concurrency.md +375 -0
  109. package/plugins/litclaude/skills/programming/references/rust/libraries.md +439 -0
  110. package/plugins/litclaude/skills/programming/references/rust/one-liners.md +291 -0
  111. package/plugins/litclaude/skills/programming/references/rust/proptest-insta.md +429 -0
  112. package/plugins/litclaude/skills/programming/references/rust/type-state.md +354 -0
  113. package/plugins/litclaude/skills/programming/references/rust/unsafe-discipline.md +250 -0
  114. package/plugins/litclaude/skills/programming/references/rust/zero-cost-safety.md +527 -0
  115. package/plugins/litclaude/skills/programming/references/rust-ub/README.md +289 -0
  116. package/plugins/litclaude/skills/programming/references/rust-ub/miri-sanitizers-loom.md +411 -0
  117. package/plugins/litclaude/skills/programming/references/rust-ub/ub-taxonomy.md +269 -0
  118. package/plugins/litclaude/skills/programming/references/typescript/README.md +195 -0
  119. package/plugins/litclaude/skills/programming/references/typescript/backend-hono.md +672 -0
  120. package/plugins/litclaude/skills/programming/references/typescript/bootstrap.md +199 -0
  121. package/plugins/litclaude/skills/programming/references/typescript/data-modeling.md +202 -0
  122. package/plugins/litclaude/skills/programming/references/typescript/error-handling.md +169 -0
  123. package/plugins/litclaude/skills/programming/references/typescript/tsconfig-strict.md +152 -0
  124. package/plugins/litclaude/skills/programming/references/typescript/type-patterns.md +196 -0
  125. package/plugins/litclaude/skills/programming/scripts/go/check-no-excuse-rules.sh +173 -0
  126. package/plugins/litclaude/skills/programming/scripts/go/new-project.py +138 -0
  127. package/plugins/litclaude/skills/programming/scripts/go/templates/.editorconfig +13 -0
  128. package/plugins/litclaude/skills/programming/scripts/go/templates/.golangci.yml +95 -0
  129. package/plugins/litclaude/skills/programming/scripts/go/templates/AGENTS.md.tmpl +24 -0
  130. package/plugins/litclaude/skills/programming/scripts/go/templates/README.md.tmpl +12 -0
  131. package/plugins/litclaude/skills/programming/scripts/go/templates/Taskfile.yml +40 -0
  132. package/plugins/litclaude/skills/programming/scripts/go/templates/ci.yml +37 -0
  133. package/plugins/litclaude/skills/programming/scripts/go/templates/config.go +24 -0
  134. package/plugins/litclaude/skills/programming/scripts/go/templates/gitignore +15 -0
  135. package/plugins/litclaude/skills/programming/scripts/go/templates/main.go.tmpl +22 -0
  136. package/plugins/litclaude/skills/programming/scripts/go/templates/run.go +15 -0
  137. package/plugins/litclaude/skills/programming/scripts/python/check-no-excuse-rules.py +687 -0
  138. package/plugins/litclaude/skills/programming/scripts/python/new-project.py +172 -0
  139. package/plugins/litclaude/skills/programming/scripts/python/new-script.py +116 -0
  140. package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.py +296 -0
  141. package/plugins/litclaude/skills/programming/scripts/rust/check-no-excuse-rules.sh +158 -0
  142. package/plugins/litclaude/skills/programming/scripts/rust/new-project.py +175 -0
  143. package/plugins/litclaude/skills/programming/scripts/typescript/check-no-excuse-rules.ts +282 -0
  144. package/plugins/litclaude/skills/programming/scripts/typescript/new-project.ts +177 -0
  145. package/plugins/litclaude/skills/refactor/SKILL.md +73 -0
  146. package/plugins/litclaude/skills/remove-ai-slops/SKILL.md +52 -0
  147. package/plugins/litclaude/skills/review-work/SKILL.md +331 -0
  148. package/plugins/litclaude/skills/rules/SKILL.md +66 -0
  149. package/plugins/litclaude/skills/start-work/SKILL.md +132 -0
  150. package/scripts/audit-plan-checkboxes.mjs +37 -0
  151. package/scripts/doctor.mjs +41 -0
  152. package/scripts/inspect-agent-tools.mjs +27 -0
  153. package/scripts/postinstall.mjs +50 -0
  154. package/scripts/qa-claude-plugin-smoke.sh +60 -0
  155. package/scripts/qa-portable-install.sh +136 -0
  156. package/scripts/validate-plugin.mjs +72 -0
@@ -0,0 +1,260 @@
1
+ # Node.js / tsx / ts-node / Bun / Deno Debugging
2
+
3
+ Covers Node 18+, tsx, ts-node, Bun, Deno. Launch recipes, inspector protocol usage, the `node inspect` CLI, and the **tsx source-map silent-failure** that costs people days.
4
+
5
+ ---
6
+
7
+ ## Environment detection (Phase 0)
8
+
9
+ ```bash
10
+ node --version
11
+ cat package.json | head -40
12
+
13
+ # Which JS runtime launches the app? (order them; the first match wins)
14
+ ls node_modules/.bin/tsx 2>/dev/null && echo 'has tsx'
15
+ ls node_modules/.bin/ts-node 2>/dev/null && echo 'has ts-node'
16
+ ls node_modules/.bin/vitest 2>/dev/null && echo 'has vitest'
17
+ which bun 2>/dev/null && bun --version
18
+ which deno 2>/dev/null && deno --version
19
+
20
+ # Source-map situation
21
+ grep -E '"sourceMap"|"inlineSources"' tsconfig.json 2>/dev/null
22
+ grep -l '//# sourceMappingURL' dist/*.js 2>/dev/null | head -3
23
+
24
+ # Debug-relevant ports
25
+ lsof -iTCP:9229 -sTCP:LISTEN -nP 2>/dev/null
26
+ lsof -iTCP:9230 -sTCP:LISTEN -nP 2>/dev/null
27
+ ```
28
+
29
+ ---
30
+
31
+ ## 🚨 The tsx + `node inspect` CLI silent-failure (READ THIS)
32
+
33
+ `tsx` transpiles each `.ts` file on the fly and emits an inline source map. V8 Inspector registers the module with its `.ts` path (so it shows up in the debugger's `scripts` list), **but the `node inspect` CLI REPL does not resolve source-map line numbers reliably**. Setting `sb('session.ts', 285)` will show a "pending" breakpoint that **never fires even after the module loads**.
34
+
35
+ The breakpoint list will happily display it, so you think it's set. It isn't.
36
+
37
+ ### Three reliable workarounds
38
+
39
+ | Workaround | When to use | Downside |
40
+ |---|---|---|
41
+ | **`debugger;` statement in source** | You can edit the source, CLI required | Requires source edit + revert |
42
+ | **Chrome DevTools GUI** (`chrome://inspect`) | CLI not required, faster iteration | Not usable if user specifically asked for CLI |
43
+ | **Debug the built `dist/` JS** | Source maps are working end-to-end | Requires `npm run build` on every source change |
44
+
45
+ The `debugger;` statement is the most reliable. Journal the edit — revert at Phase 9.
46
+
47
+ ---
48
+
49
+ ## Launch recipes by runtime
50
+
51
+ ### Node (plain JS / compiled TS)
52
+
53
+ ```bash
54
+ # Break on first line, wait for debugger to attach
55
+ node --inspect-brk=9229 dist/index.js
56
+
57
+ # Attach immediately, don't block startup — pair with debugger; statements
58
+ node --inspect=9229 dist/index.js
59
+
60
+ # Wait for debugger to attach, THEN run (new in Node 20.15+)
61
+ node --inspect-wait=9229 dist/index.js
62
+
63
+ # Source maps in stack traces (always a good idea in debug builds)
64
+ node --enable-source-maps --inspect dist/index.js
65
+ ```
66
+
67
+ ### tsx
68
+
69
+ ```bash
70
+ # The tsx runner is --import-compatible, so these work:
71
+ node --inspect-brk=9229 --import tsx index.ts
72
+ node --inspect=9229 --import tsx index.ts
73
+
74
+ # If user prefers invoking tsx directly, this also works but is less explicit:
75
+ NODE_OPTIONS='--inspect-brk=9229' npx tsx index.ts
76
+
77
+ # ⚠️ tsx watch + inspector = inspector reloads per file change
78
+ # Debug without watch:
79
+ node --inspect=9229 --import tsx index.ts # (no `watch`)
80
+ ```
81
+
82
+ ### ts-node (legacy but still encountered)
83
+
84
+ ```bash
85
+ node --inspect-brk -r ts-node/register src/index.ts
86
+ # ESM (ts-node's ESM loader is fragile — if possible, migrate to tsx):
87
+ node --inspect --loader ts-node/esm src/index.ts
88
+ ```
89
+
90
+ ### Bun (WebKit Inspector Protocol, NOT V8)
91
+
92
+ ```bash
93
+ bun --inspect src/index.ts # opens debug.bun.sh URL
94
+ bun --inspect-brk src/index.ts # break on start
95
+ bun --inspect-wait src/index.ts # wait for attach
96
+ bun test --inspect-brk # debug test runner
97
+ ```
98
+
99
+ **Critical**: Bun uses WebKit Inspector Protocol, not V8. `chrome://inspect` cannot connect directly. Use `debug.bun.sh` or the (currently buggy, per Bun docs) VS Code extension.
100
+
101
+ ### Deno (native V8, Chrome DevTools / VS Code compatible)
102
+
103
+ ```bash
104
+ deno run --inspect-brk --allow-all src/main.ts
105
+ deno test --inspect-brk --filter "auth"
106
+ ```
107
+
108
+ Deno is the smoothest TS debugging experience — native V8 inspector, no source-map workarounds.
109
+
110
+ ### Vitest
111
+
112
+ ```bash
113
+ # Single worker required — inspector can't attach to multiple workers
114
+ vitest --inspect-brk --no-file-parallelism
115
+ vitest --inspect-brk --browser --no-file-parallelism # browser mode
116
+ ```
117
+
118
+ Without `--no-file-parallelism`, breakpoints won't fire because the process Vitest spawns workers in isn't the one listening on the inspector port.
119
+
120
+ ---
121
+
122
+ ## Attaching with `node inspect` CLI
123
+
124
+ ```bash
125
+ node inspect 127.0.0.1:9229 # attach to an existing --inspect process
126
+ ```
127
+
128
+ Core commands at the `debug>` prompt:
129
+
130
+ ```
131
+ cont, c resume until next break / debugger;
132
+ next, n step over
133
+ step, s step into
134
+ out, o step out
135
+ pause pause a running process
136
+ bt backtrace
137
+ scripts list all modules V8 has loaded (incl. tsx-transpiled .ts)
138
+ sb(N) set breakpoint at line N of current file
139
+ sb('file', N) set breakpoint at line N of matching file (⚠️ unreliable with tsx)
140
+ sb(func) set breakpoint at function reference
141
+ cb(N), cb('file', N) clear breakpoint
142
+ breakpoints list breakpoints (shows pending ones, doesn't tell you they'll never fire)
143
+ watch('expr') persistent watch expression
144
+ watchers show watchers
145
+ exec('expr') evaluate expression in paused frame's scope
146
+ repl drop into full REPL with frame's scope
147
+ restart restart the debuggee
148
+ kill kill the debuggee
149
+ ```
150
+
151
+ **`exec('expr')` is the most powerful tool in this CLI** — it evaluates any JS in the paused frame and returns the value. Use it heavily.
152
+
153
+ ---
154
+
155
+ ## `exec()` patterns that resolve hypotheses fast
156
+
157
+ At a breakpoint, these queries resolve most LLM / agent / async bugs in one line each:
158
+
159
+ ```js
160
+ // Agent / LLM state
161
+ exec('this.agent.state.messages.length')
162
+ exec('this.agent.state.messages.map(m => m.role)')
163
+ exec('JSON.stringify(this.agent.state.messages.at(-1)).substring(0, 500)')
164
+ exec('this.agent.state.messages.at(-1).errorMessage') // silent-error sentinel
165
+ exec('this.agent.state.messages.at(-1).stopReason')
166
+ exec('JSON.stringify(this.agent.state.usage)') // undefined / all-zero = failed call
167
+ exec('this.agent.state.model.baseUrl') // catch hardcoded vs env-var
168
+
169
+ // Env / config at runtime
170
+ exec('process.env.RELEVANT_VAR')
171
+ exec('Object.keys(process.env).filter(k => k.startsWith("ANTHROPIC"))')
172
+ exec('this.config')
173
+
174
+ // Async / timing
175
+ exec('Date.now() - this._turnStartedAt')
176
+ exec('this._activePromises?.size')
177
+
178
+ // HTTP request/response in-flight
179
+ exec('JSON.stringify(req.body).length')
180
+ exec('res.statusCode')
181
+ exec('res.headersSent')
182
+
183
+ // What's actually running
184
+ exec('process.version')
185
+ exec('process.cwd()')
186
+ exec('process.argv')
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Silent-failure patterns in Node
192
+
193
+ These are the patterns that most commonly look like success but aren't. Always check when a response is "too fast" or "too empty":
194
+
195
+ | Signal | What it means |
196
+ |---|---|
197
+ | HTTP 200 + `content: ""` | Silent error swallowed |
198
+ | HTTP 200 + response in <1s for an LLM call | Too fast for a real Claude/GPT call; something short-circuited |
199
+ | `usage: { totalTokens: 0 }` | LLM SDK returned a stub without making the call |
200
+ | `stopReason: "error" + content: []` | SDK packaged an error into a "success" message |
201
+ | Unhandled promise rejection with no log | Caller forgot to `await`, or `.catch(() => {})` |
202
+ | `try { await x(); } catch {}` | Error eaten, no log |
203
+ | `void somePromise()` | Explicit opt-out of error propagation; often a bug |
204
+ | Callback-style API where callback never fires | Error happened before callback scheduled |
205
+ | Handler returns `res.json(...)` twice | Second call is silent on some Express versions |
206
+
207
+ When you find one, add a temporary `console.error('[DEBUG]', ...)` to make it loud — journal it, revert at Phase 9.
208
+
209
+ ---
210
+
211
+ ## tmux session layout (two sessions, one purpose each)
212
+
213
+ ```bash
214
+ # Long-running inspected process
215
+ tmux new-session -d -s debug-server -c "$PWD"
216
+ tmux send-keys -t debug-server 'node --inspect=9229 --import tsx index.ts' Enter
217
+
218
+ # Interactive debugger client (separate pane for readability)
219
+ tmux new-session -d -s debug-client -c "$PWD"
220
+ tmux send-keys -t debug-client 'node inspect 127.0.0.1:9229' Enter
221
+
222
+ # Non-blocking pane inspection from the outside
223
+ tmux capture-pane -p -t debug-server -S -50
224
+ ```
225
+
226
+ Journal both session names. Kill both at Phase 9:
227
+
228
+ ```bash
229
+ tmux kill-session -t debug-server
230
+ tmux kill-session -t debug-client
231
+ ```
232
+
233
+ ---
234
+
235
+ ## When to abandon the CLI and switch to Chrome DevTools
236
+
237
+ The user's preference for CLI is valid and should be respected. But you may recommend a switch in one short sentence if ANY of these hold:
238
+
239
+ - You hit source-map resolution failures (`sb('file', line)` not firing) AND the fix is time-sensitive
240
+ - You need to watch many values simultaneously (GUI watch panel is faster to scan)
241
+ - You're stepping through async-heavy code where CLI step semantics get murky across microtask boundaries
242
+
243
+ Phrase as a note, not a request: "I can push through with `debugger;` statements in CLI. If we hit three or more of these in a row, switching to `chrome://inspect` GUI would cut cycle time in half — your call."
244
+
245
+ ---
246
+
247
+ ## Phase 9 cleanup specifics
248
+
249
+ ```bash
250
+ # Revert source-level debug statements
251
+ git diff | grep -E '(debugger;|console\.log\(.*DEBUG|\[ARBITER-DEBUG|\[DEBUG)'
252
+ # Revert any matching files:
253
+ git checkout <file>
254
+
255
+ # Kill inspector-attached processes
256
+ pkill -f 'node --inspect' || true
257
+ pkill -f 'bun --inspect' || true
258
+ pkill -f 'deno.*--inspect' || true
259
+ lsof -iTCP:9229 -sTCP:LISTEN -nP 2>/dev/null
260
+ ```
@@ -0,0 +1,248 @@
1
+ # Python Debugging
2
+
3
+ Covers CPython 3.9+, pytest, asyncio, Django, FastAPI. Setup commands, attach mechanisms, state-query patterns, gotchas, silent-failure signatures.
4
+
5
+ ---
6
+
7
+ ## Environment detection (Phase 0)
8
+
9
+ ```bash
10
+ # Which Python will actually run the code?
11
+ which python; which python3
12
+ python --version
13
+
14
+ # Is there a project env manager in play?
15
+ ls poetry.lock uv.lock Pipfile.lock requirements*.txt .python-version 2>/dev/null
16
+
17
+ # Installed debuggers / profilers in this env?
18
+ python -c 'import pdb, sys; print("pdb", "built-in"); print("python", sys.executable)'
19
+ pip list 2>/dev/null | grep -iE '^(ipdb|pudb|debugpy|py-spy|memray|rich)\s'
20
+
21
+ # asyncio debug mode available?
22
+ python -c 'import asyncio; print(asyncio.__version__)'
23
+ ```
24
+
25
+ **Wrapper gotchas** (these change how flags propagate):
26
+
27
+ - `poetry run python ...` — args after `python` are fine; args before `poetry run` go to poetry, not python
28
+ - `uv run python ...` — similar; prefer `uv run -- python -X dev` if flags collide
29
+ - `pipenv run` — same story
30
+ - `./manage.py <cmd>` (Django) — shebang resolution; make sure it points to the right venv
31
+ - `pytest` — loads `conftest.py` at collection; breakpoints inside collection need `pytest --pdb-trace` not `--pdb`
32
+
33
+ ---
34
+
35
+ ## The four ways to attach
36
+
37
+ | Method | When to use | Command |
38
+ |---|---|---|
39
+ | **`breakpoint()` inline** (Python 3.7+) | You can edit the source and restart. Most reliable. | Add `breakpoint()` to source. Run normally. It invokes `pdb` by default. |
40
+ | **`python -m pdb <script>`** | No source edit desired. Breaks on entry. | `python -m pdb script.py arg1` |
41
+ | **post-mortem `pdb.pm()`** | Exception already happened, you want to inspect state | In an exception-caught REPL: `import pdb; pdb.pm()` after the exception propagates |
42
+ | **debugpy (remote / IDE)** | IDE attach, remote host, containerized process | `python -m debugpy --listen 5678 --wait-for-client script.py` then attach from VS Code / PyCharm |
43
+
44
+ ### Prefer `ipdb` or `pudb` over plain `pdb` when available
45
+
46
+ - **ipdb** — drop-in replacement with tab completion, syntax highlighting. `pip install ipdb`, then `PYTHONBREAKPOINT=ipdb.set_trace` or use `import ipdb; ipdb.set_trace()`.
47
+ - **pudb** — full-screen TUI debugger, much faster to navigate stack/locals. `pip install pudb`, then `PYTHONBREAKPOINT=pudb.set_trace`.
48
+
49
+ ### Control `breakpoint()` globally
50
+
51
+ ```bash
52
+ # Use ipdb instead of pdb
53
+ export PYTHONBREAKPOINT=ipdb.set_trace
54
+
55
+ # Disable all breakpoint() calls (useful to ship without removing them)
56
+ export PYTHONBREAKPOINT=0
57
+ ```
58
+
59
+ **Journal this env var** — unset at Phase 9.
60
+
61
+ ---
62
+
63
+ ## pdb / ipdb essentials
64
+
65
+ At a `(Pdb)` or `ipdb>` prompt:
66
+
67
+ ```
68
+ l list source around current line
69
+ ll list whole function
70
+ s step into
71
+ n step over (next)
72
+ r step out (return)
73
+ c continue
74
+ b list breakpoints
75
+ b <line> breakpoint at line
76
+ b <func> breakpoint at function
77
+ cl <n> clear breakpoint n
78
+ w where (backtrace)
79
+ u / d move up/down the stack
80
+ a args of current frame
81
+ p <expr> print expression
82
+ pp <expr> pretty-print
83
+ !<stmt> execute Python statement (e.g. !x = 5)
84
+ interact drop into a full Python REPL with current frame's locals
85
+ q quit (aborts the program)
86
+ ```
87
+
88
+ **`interact` is underused** — it gives you a full IPython-esque REPL with all locals available. Faster than typing `p` for 20 things.
89
+
90
+ ---
91
+
92
+ ## pytest-specific debugging
93
+
94
+ ```bash
95
+ # Enter pdb on first failure
96
+ pytest --pdb
97
+
98
+ # Enter pdb at the START of each test (not on failure)
99
+ pytest --trace
100
+
101
+ # Run only the failing test, with -s to show print output
102
+ pytest --pdb -x -s path/to/test.py::test_name
103
+
104
+ # Collect-time debugging (for problems in conftest.py / fixture setup)
105
+ pytest --pdb-trace
106
+
107
+ # Disable capture for this test (so breakpoint prompt is visible)
108
+ pytest -s
109
+ ```
110
+
111
+ **Common failure**: `breakpoint()` hangs inside a pytest test — that's because pytest captures stdout/stderr by default. Always add `-s` when debugging with breakpoints inside pytest.
112
+
113
+ ---
114
+
115
+ ## asyncio gotchas
116
+
117
+ Async is where most Python debug sessions go sideways. Know these before attaching.
118
+
119
+ ### Breakpoints inside coroutines
120
+
121
+ `breakpoint()` works inside an async function, but stepping into another coroutine from `pdb` is awkward. Two techniques:
122
+
123
+ ```python
124
+ async def handler():
125
+ result = await some_async_fn() # add breakpoint ABOVE, not inside, when possible
126
+ breakpoint()
127
+ return result
128
+ ```
129
+
130
+ Inside the breakpoint, to inspect a coroutine without actually advancing time:
131
+ ```
132
+ !import asyncio
133
+ !loop = asyncio.get_event_loop()
134
+ !task = asyncio.ensure_future(some_async_fn())
135
+ # Now inspect task state, don't await it
136
+ p task
137
+ ```
138
+
139
+ ### PYTHONASYNCIODEBUG
140
+
141
+ Enable before running the process:
142
+
143
+ ```bash
144
+ PYTHONASYNCIODEBUG=1 python script.py
145
+ ```
146
+
147
+ Surfaces: coroutines that were never awaited, slow callbacks, unhandled task exceptions. **Always turn this on** if the bug is timing- or async-related.
148
+
149
+ ### `asyncio.gather` swallows the first exception
150
+
151
+ By default, `asyncio.gather(t1, t2)` raises the first exception and cancels the rest. If you need all exceptions, use `gather(..., return_exceptions=True)`.
152
+
153
+ ### Unhandled task exceptions are silent
154
+
155
+ ```python
156
+ async def main():
157
+ task = asyncio.create_task(broken_coroutine())
158
+ # If task raises and we never await it, the exception is eaten at gc time
159
+ await asyncio.sleep(10)
160
+ ```
161
+
162
+ To catch these, set `loop.set_exception_handler(...)` or upgrade to Python 3.12+ which warns louder by default.
163
+
164
+ ---
165
+
166
+ ## debugpy — remote / IDE / container attach
167
+
168
+ Listen and wait for attach:
169
+
170
+ ```bash
171
+ python -m debugpy --listen 0.0.0.0:5678 --wait-for-client script.py
172
+ ```
173
+
174
+ Attach from VS Code:
175
+ ```json
176
+ // .vscode/launch.json
177
+ {
178
+ "name": "attach",
179
+ "type": "python",
180
+ "request": "attach",
181
+ "connect": { "host": "localhost", "port": 5678 }
182
+ }
183
+ ```
184
+
185
+ Inside the code, programmatic attach point:
186
+ ```python
187
+ import debugpy
188
+ debugpy.listen(5678)
189
+ debugpy.wait_for_client() # blocks until attached
190
+ debugpy.breakpoint() # programmatic breakpoint
191
+ ```
192
+
193
+ **Journal**: the port (5678) and the listener file — unset at Phase 9.
194
+
195
+ ---
196
+
197
+ ## Sampling profilers for "why is it slow / stuck"
198
+
199
+ When the problem is performance or a hang (not a crash), don't attach pdb — it alters timing. Use a sampling profiler that attaches to the running process:
200
+
201
+ ```bash
202
+ # py-spy — production-safe, zero code change, works on running process
203
+ py-spy top --pid <pid> # live top-like view
204
+ py-spy record -o profile.svg --pid <pid> # flamegraph
205
+ py-spy dump --pid <pid> # stack traces of all threads right now
206
+
207
+ # memray — memory allocation tracking
208
+ memray run script.py
209
+ memray flamegraph output.bin
210
+ memray stats output.bin
211
+ ```
212
+
213
+ `py-spy dump` on a stuck process is often enough to find the hung call — no breakpoints needed.
214
+
215
+ ---
216
+
217
+ ## Silent-failure patterns in Python
218
+
219
+ Add these to Phase 8's silent-failure check:
220
+
221
+ | Pattern | Why it's silent |
222
+ |---|---|
223
+ | `except Exception: pass` or `except: pass` | Catches and discards every error including KeyboardInterrupt |
224
+ | `logging.exception(...)` in a logger with no handlers | "Logs" but actually writes nowhere |
225
+ | `asyncio.create_task(coro)` without storing the task | Task GC'd before completion, exception swallowed |
226
+ | `return x.get("key")` where key is missing | Returns None silently, caller often doesn't check |
227
+ | `subprocess.run(..., check=False)` with ignored returncode | Non-zero exit treated as success |
228
+ | Django `transaction.atomic()` inside a broader `except` | Rolls back silently |
229
+ | `contextlib.suppress(Exception)` | Explicit silencer; easy to leave wider than intended |
230
+ | `queue.get(block=False)` with `except queue.Empty: pass` | Polling that silently drops the work |
231
+
232
+ ---
233
+
234
+ ## Phase 9 cleanup specifics
235
+
236
+ ```bash
237
+ # Remove breakpoint() / ipdb / pudb lines from source
238
+ git diff | grep -E '(breakpoint\(\)|import ipdb|import pudb|import pdb; pdb\.set_trace)'
239
+ # If the above has output, revert those files:
240
+ git checkout <file>
241
+
242
+ # Unset the global breakpoint override
243
+ unset PYTHONBREAKPOINT
244
+
245
+ # Kill any leftover debugpy listeners
246
+ pkill -f 'debugpy' || true
247
+ lsof -iTCP:5678 -sTCP:LISTEN -nP 2>/dev/null # confirm free
248
+ ```