agentleFS
berekvolgyipeterberekvolgyipeter/dotclaude/skills/ts-debug/SKILL.md

ts-debug

Skill2 starsChanged 18 days agoMITView on GitHub

TypeScript/Node debugging expert. Use when the user needs to debug, profile, or trace TypeScript or Node.js code — e.g. "how do I debug this", "find the memory leak", "why is this slow", "add a breakpoint", "profile this function", "why won't the process exit".

1 other project uses a version of this.

Adopted by

Most recently taken up by

  • Other versions1 project uses a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 1

    1. tstelzer/skills★ 1same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository9 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 2 are distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Not sure what's wrong? Start with the Node inspector — step through the code and observe.

    line 8
  2. Very specific:

    Every Node flag above is stock — no build step, no loader, no dependency.

    line 19
  3. Very specific:

    Explain the fit in one sentence: before showing usage — e.g.

    line 25
  4. Distinctive:

    Import it when the investigation starts and delete the import when it ends.

    line 141
  5. Very specific:

    Use console.dir to replace ad-hoc console.log debugging when output is hard to read — nested objects collapsed to [Object], truncated …

    line 145

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

TypeScript Debugging

Not sure what's wrong? Start with the Node inspector — step through the code and observe. Once you can characterize the problem (slow, leaking memory, hanging), switch to the matching profiler.

ProblemTool
Need to step through execution interactivelynode --inspect-brk + Chrome DevTools or VS Code
Need to step through a failing testvitest --inspect-brk --no-file-parallelism
Which function is slow, and where does the time go?node --cpu-prof, read as a flame chart in DevTools
Investigating memory growth or leaksnode --heap-prof, then v8.writeHeapSnapshot()
Process won't exit or hangs after work is doneprocess.getActiveResourcesInfo(), escalating to why-is-node-running for the creation stacks
Hard to read debug output (nested objects, long arrays)console.dir(value, { depth: null })

Every Node flag above is stock — no build step, no loader, no dependency. why-is-node-running is the single gap worth a package: the built-in process.getActiveResourcesInfo() names the handle types holding the loop open but not where they were created. Run scripts/setup.sh to add it.

Behavioral Rules

  • Lock the bug with a failing test once reproduced — before patching incorrect behavior, capture the faulty behavior as a regression test (through the public interface where one exists), so the fix is verified and the bug can't silently regress; skip this for pure performance or memory investigations, where a test through the public interface is rarely the right artifact
  • Suggest only one tool per problem — don't list all options and ask the user to choose
  • Explain the fit in one sentence before showing usage — e.g. "Since the process hangs after the work finishes, why-is-node-running is the right tool here."
  • Prefer the inspector as the default for general debugging; only reach for profilers when the problem is clearly performance- or memory-related
  • Reach for a built-in before a dependency — adding a package to a project mid-investigation is a cost the user pays forever, so justify it
  • Run the TypeScript source, not the build — stack frames and breakpoints land on the right lines with no source maps; only a compiled node dist/… run needs --enable-source-maps
  • Place the debugger statement just before the suspect line, not at the top of the function
  • Debug tests in a single worker — --no-file-parallelism, otherwise breakpoints land in a worker thread the debugger isn't attached to
  • Never leave instrumentation in production code paths — debugger statements, why-is-node-running dumps, and heap-snapshot calls must be removed before deploying

Running TypeScript directly

node file.ts erases type annotations in place and runs the result — no build step, no loader, no source maps. Because types are blanked rather than removed, every line number in a stack trace matches the source file exactly.

This runs unflagged on Node 22.18+ and 23.6+. Check node --version before recommending it: on anything older the same command needs --experimental-strip-types, and the whole table above assumes the source runs directly.

Type stripping only erases; it refuses TypeScript that has to emit runtime code:

SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode

enum and namespace are the two that come up in practice. Rewriting them into erasable syntax (a const object, a plain module) is the durable fix — the escape hatch that used to cover them, --experimental-transform-types, was removed in Node 26. When rewriting isn't on the table, run the file through tsx instead.

Native execution also ignores paths in tsconfig — if a project maps import aliases, they won't resolve.

Tool Reference

Node inspector

Pauses on the first line and waits for a debugger to attach on port 9229. Open chrome://inspect in Chrome, or attach VS Code to the running process.

node --inspect-brk src/index.ts                      # TypeScript source
node --inspect-brk --enable-source-maps dist/index.js # compiled output

Set breakpoints in the DevTools/VS Code UI, or in code:

export function transfer(amount: number): void {
  debugger; // execution pauses here when an inspector is attached
  applyTransfer(amount);
}

VS Code attach configuration:

{
  "name": "Attach to process",
  "type": "node",
  "request": "attach",
  "port": 9229,
  "skipFiles": ["<node_internals>/**", "${workspaceFolder}/node_modules/**"]
}

Tip: inspector.open(9229, undefined, true) from node:inspector activates the inspector at runtime — use it when the interesting state only exists after startup.

vitest --inspect-brk

Debug a failing test the same way, with tests forced onto the main thread so breakpoints are hit.

pnpm exec vitest --inspect-brk --no-file-parallelism tests/index.test.ts

node --cpu-prof

CPU profiler. Writes a .cpuprofile to the working directory; load it in the Chrome DevTools Performance tab, which renders it both as a flame chart (where time goes across the call tree) and as a sortable function list (which single function is hot).

node --cpu-prof src/index.ts
# → CPU.<date>.<time>.<pid>.<tid>.<seq>.cpuprofile

Narrow the output with --cpu-prof-dir and --cpu-prof-name.

node --heap-prof + heap snapshots

--heap-prof shows which allocation sites the memory came from; a heap snapshot shows what is still retained. Use the profile to find the allocator, the snapshot to find the retainer.

node --heap-prof src/index.ts
# → Heap.<date>.<time>.<pid>.<tid>.<seq>.heapprofile
import v8 from "node:v8";

v8.writeHeapSnapshot("./before.heapsnapshot");
await runWorkload();
v8.writeHeapSnapshot("./after.heapsnapshot");

Load both .heapsnapshot files in the Chrome DevTools Memory tab and compare them to see what survived.

process.getActiveResourcesInfo (built-in)

The zero-dependency first look at a process that won't exit. Returns the types of the handles and requests keeping the event loop alive:

console.log(process.getActiveResourcesInfo()); // [ 'Timeout' ]

Often that's enough — a lone 'Timeout' or 'TTYWrap' points straight at the culprit. When the type alone doesn't identify which one, reach for the stacks.

why-is-node-running

Dumps the open handles and requests with the stack trace of where each was created — the part getActiveResourcesInfo() can't give you.

import whyIsNodeRunning from "why-is-node-running";

setTimeout(() => whyIsNodeRunning(), 5000); // prints every active handle with its stack

Import it when the investigation starts and delete the import when it ends.

console.dir

Use console.dir to replace ad-hoc console.log debugging when output is hard to read — nested objects collapsed to [Object], truncated arrays. It's not a debugger; use it when the problem is visibility of data, not stepping through logic.

console.dir(someNestedValue, { depth: null, colors: true });

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.