executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
reverse-engineer-jsReverse-engineer minified or obfuscated JavaScript bundles. Primary tool: humanify (humanifyjs) — uses an LLM to rename mangled identifiers back to meaningful names. Default model: gemini-3.8-flash. Use when the user says 'deobfuscate this bundle', 'humanify this', 'rename minified vars', 'reverse engineer this JS', 'what does bundle.js do', or is working i…
Independent GitHub snapshot · Automated classification · Original documentation governs
og/ or modules/ folder fed by humanify. Covers humanify CLI invocation, the pseudo-TTY workaround for cursorTo crashes, single-module extraction from a bundle, and chaining with beautifiers."LLM-assisted deobfuscation of minified / mangled JavaScript using humanifyjs plus surrounding tooling for extracting and reintegrating modules.
| Tool | Purpose | When |
|---|---|---|
humanifyjs (npx) | Rename mangled vars/functions via LLM | Mangled but already valid JS |
prettier / js-beautify | Reformat single-line minified code | Before humanify, if needed |
webcrack | Unpack webpack / browserify bundles into per-module files | When bundle is one big file |
| Source-map sleuthing | // # sourceMappingURL=... may exist next to the bundle | Always check first — beats LLM rename |
Always check for a sourcemap (bundle.js.map or sourceMappingURL comment in the file) before spending tokens on humanify. If found, original sources are recoverable for free.
Use Gemini unless the user says otherwise:
npx humanifyjs gemini -m "gemini-3.8-flash" -o <outputDir> <inputFile>
Requires GEMINI_API_KEY in env (the project's root .env is the usual place).
Other backends:
# OpenAI
npx humanifyjs openai --apiKey="$OPENAI_API_KEY" --model gpt-4.1-mini bundle.js
# Local (slower, free)
npx humanifyjs local bundle.js
humanify calls process.stdout.cursorTo(...) for its progress bar. In Claude Code / CI / piped contexts, stdout is not a TTY and the call crashes with TypeError: process.stdout.cursorTo is not a function.
Wrap the call in script -q /dev/null:
script -q /dev/null npx humanifyjs gemini -m "gemini-3.8-flash" -o "$OUT" "$IN"
(macOS/BSD script syntax. On Linux: script -qc "<cmd>" /dev/null.)
humanify always writes its result as <outputDir>/deobfuscated.js regardless of input filename. Don't expect module_1234.js in → module_1234.js out.
humanify processes top-level declarations sequentially with one LLM call each. A 5 MB bundle can take 30+ minutes. Strategies:
webcrack first if the bundle is webpackedgemini-3.8-flash is the default here; on a very large bundle a lite variant (gemini-3.5-flash-lite) cuts the per-declaration cost, at some accuracy cost on dense codeBefore any rewrite, copy the pristine bundle to archive/bundle.original.js. humanify is non-deterministic and you may want to re-run with a different model.
When the bundle is small (<500 KB) or you have time:
mkdir -p archive out
cp bundle.js archive/bundle.original.js
script -q /dev/null npx humanifyjs gemini \
-m "gemini-3.8-flash" \
-o out bundle.js
# result: out/deobfuscated.js
Then optionally run prettier --write out/deobfuscated.js for nicer formatting.
Common in fxhash / generative-art bundles: a single bundle contains many id: (params) => { ... } modules and you only want to humanify a few interesting ones.
<id>: (e, t, n) => { opener.}.(e, t, n) => { <body> } to a temp file. humanify needs valid top-level code.script -q /dev/null npx humanifyjs gemini -m "gemini-3.8-flash" -o "$OUT" "$IN".(e, t, n) => { ... } shell back off the result.modules/module_<id>_<name>.js, replace the body in the bundle with a stub like <id>: (e, t, n) => { window.DEOBF[<id>](e, t, n); }.If the project already has a scripts/deobfuscate.js (or similar), reuse it — the brace-counting / string-escape logic is finicky enough that re-deriving it for each new bundle is a waste. A typical script: takes a numeric module ID, extracts the body from bundle.js, runs humanify on the wrapped function, unwraps, and writes modules/module_<id>_<name>.js.
When dealing with a webpack bundle, webcrack splits modules cleanly before humanify even runs:
npx webcrack bundle.js -o webcracked/
# Then humanify each module of interest:
script -q /dev/null npx humanifyjs gemini \
-m "gemini-3.8-flash" \
-o humanified webcracked/modules/123.js
User says: "humanify the bundle.js in this fxhash project"
Actions:
head -c 4096 bundle.js | tail -c 200 — look for sourceMappingURL. None? Continue.GEMINI_API_KEY in .env. Source it: set -a; source .env; set +a.mkdir -p archive && cp bundle.js archive/bundle.original.js.mkdir -p out && script -q /dev/null npx humanifyjs gemini -m "gemini-3.8-flash" -o out bundle.js.npx prettier --write out/deobfuscated.js.Result: out/deobfuscated.js with renamed vars, ready to read.
User says: "Deobfuscate module 3658 from og/bundle.js, name it treeGenerator"
Actions:
scripts/deobfuscate.js), run it: node scripts/deobfuscate.js 3658 treeGenerator.(e, t, n) => { ... }, run humanify with script -q /dev/null, unwrap, save to modules/module_3658_treeGenerator.js, stub the bundle.Result: New file in modules/ with a readable version of the function; bundle.js shrunk by stubbing.
cursorTo is not a functionUser says: "humanify just dies immediately"
Diagnosis: Non-TTY stdout (this is the default in Claude Code's bash tool).
Fix: Re-run wrapped in script -q /dev/null <cmd> (macOS) or script -qc "<cmd>" /dev/null (Linux).
cursorTo is not a functionCause: stdout is not a TTY. Fix: wrap in script -q /dev/null.
GEMINI_API_KEY not setCause: humanify reads from process env, not from the project .env automatically. Fix: set -a; source .env; set +a in the same shell, or pass inline: GEMINI_API_KEY=... npx humanifyjs gemini ....
Cause: humanify only renames identifiers it considers mangled (short, single-letter). Already-readable code is left alone. Fix: confirm the input is actually obfuscated; if names like useState survive that's expected, not a bug.
Cause: large file, many top-level functions → many sequential LLM calls. Fix: switch to local backend for free local rename, or extract a single module (Workflow B) instead of the whole bundle.
Cause: big bundle, sequential per-function calls. Fix: pre-split with webcrack, or only humanify the modules you actually need.
deobfuscated.jsCause: humanify writes to a fixed filename. A failed second run will pick up the previous good output. Fix: rm -f $OUT/deobfuscated.js before each run.