# External tools and dependencies

> Bun and Babel package dependencies, subprocess tools (@electron/asar, prettier, @wakaru/cli, webcrack, source-map-explorer), BSD-style script exit codes, and graceful degradation when binaries are absent.

- Repository: JimLiu/decode-codex
- GitHub: https://github.com/JimLiu/decode-codex
- Human docs: https://grok-wiki.com/public/docs/jimliu-decode-codex-1a3a0c425b33
- Complete Markdown: https://grok-wiki.com/public/docs/jimliu-decode-codex-1a3a0c425b33/llms-full.txt

## Source Files

- `.agents/skills/deobfuscate-javascript/package.json`
- `.agents/skills/deobfuscate-javascript/SKILL.md`
- `.agents/skills/deobfuscate-javascript/scripts/wakaru-normalize.ts`
- `.agents/skills/deobfuscate-javascript/scripts/format.ts`
- `.agents/skills/codex-app-ref-refresh/scripts/refresh-codex-ref.mjs`
- `.agents/skills/deobfuscate-javascript/scripts/sourcemap-check.ts`

---

---
title: "External tools and dependencies"
description: "Bun and Babel package dependencies, subprocess tools (@electron/asar, prettier, @wakaru/cli, webcrack, source-map-explorer), BSD-style script exit codes, and graceful degradation when binaries are absent."
---

decode-codex splits toolchain ownership across two agent skills: **codex-app-ref-refresh** runs on **Node.js** and shells out to **`npx`** for `@electron/asar` and Prettier; **deobfuscate-javascript** runs on **Bun** with in-process **Babel** libraries and thin wrappers that probe optional subprocess CLIs (`@wakaru/cli`, Prettier) before falling back to passthrough behavior so the core rename/polish path never hard-depends on network-fetched binaries.

## Runtime stack

| Layer | Skill | Runtime | Installed deps |
| ----- | ----- | ------- | -------------- |
| Refresh | `codex-app-ref-refresh` | Node.js (`node refresh-codex-ref.mjs`) | None — tools fetched on demand via `npx -y` |
| Deobfuscate | `deobfuscate-javascript` | Bun (`bun scripts/<name>.ts`) | Babel packages in skill `package.json` |

<Note>
Run `bun install` once inside `.agents/skills/deobfuscate-javascript/` before invoking deobfuscation scripts. The refresh skill has no `package.json`; it only needs Node.js and network access for `npx`.
</Note>

### Bun and Babel (`deobfuscate-javascript/package.json`)

All mechanical AST work — parse, traverse, generate, type-aware transforms in Stage 1–3 — runs in-process via Babel. These are the only runtime dependencies declared in the skill manifest:

| Package | Role |
| ------- | ---- |
| `@babel/parser` | Parse minified/obfuscated JS into ASTs |
| `@babel/traverse` | Walk and rewrite bindings, imports, JSX-runtime calls |
| `@babel/generator` | Emit readable code between pipeline steps |
| `@babel/types` | AST node builders and guards |

Dev dependencies (`bun-types`, `@types/babel__*`) support TypeScript scripts and `bun test`. **External CLIs are intentionally absent from `package.json`** — they are invoked as subprocesses through wrapper scripts or direct `npx` calls.

## Subprocess tools

External binaries are **not** `bun install` targets. The skill adopts them via `npx`, a global install on `PATH`, or a dedicated wrapper that pins versions and degrades when unavailable.

```text
  codex-app-ref-refresh                    deobfuscate-javascript
  ─────────────────────                    ──────────────────────
  Node.js                                  Bun + Babel (in-process)
       │                                        │
       ├─ npx @electron/asar extract            ├─ scripts/format.ts ──► prettier (PATH → bunx → npx)
       └─ npx prettier --write                  ├─ scripts/wakaru-normalize.ts ──► wakaru / npx @wakaru/cli@1.5.0
                                                ├─ npx webcrack (direct, webpack pre-split)
                                                └─ npx source-map-explorer (direct, sourcemap recovery)
```

### Tool reference

| Tool | Invoked by | When | Version / resolution |
| ---- | ---------- | ---- | -------------------- |
| `@electron/asar` | `refresh-codex-ref.mjs` | Extract `Codex.app/Contents/Resources/app.asar` into `./ref` | `npx -y @electron/asar extract <asar> <refDir>` — unpinned, fetched on demand |
| Prettier | `refresh-codex-ref.mjs`, `scripts/format.ts`, `quality-gate.ts --check-format` | Format extracted JS/CSS; format deliverables; optional gate check | Refresh: `npx -y prettier`. Deobfuscate: `prettier` on `PATH` → `bunx prettier` → `npx prettier` |
| `@wakaru/cli` | `scripts/wakaru-normalize.ts` | Pre-rename mechanical normalization (classes, async/await, optional chaining, destructuring, enums) | Pinned `@wakaru/cli@1.5.0`; global `wakaru` preferred over `npx` |
| `webcrack` | Agent / workflow docs (`npx webcrack`) | Pre-split webpack/browserify bundles ≥ 500 KB or `id:(e,t,n)=>{}` module maps | Direct `npx webcrack <file> -o <out-dir>/` — no wrapper |
| `source-map-explorer` | Agent after `sourcemap-check.ts` | Recover original sources when a usable `.map` exists — higher fidelity than rename | Direct `npx source-map-explorer <input.js>` — no wrapper |

<Warning>
`webcrack` and `source-map-explorer` have no graceful-degradation wrappers. If `npx` cannot fetch or launch them, the agent must fall back manually (feed the original file into `extract.ts`, or hand-decode `sourcesContent`).
</Warning>

### `@electron/asar` and Prettier (refresh skill)

`refresh-codex-ref.mjs` chains three steps: delete `./ref`, extract with `@electron/asar`, then format every `.js`/`.css` under `ref` (skipping `ref/node_modules`). Prettier runs with `--ignore-path /dev/null` so gitignored `ref/` is still formatted — the same trap that affects restore deliverables under gitignored `restored/`.

<ParamField body="CODEX_APP_ASAR" type="string">
Override the default asar path `/Applications/Codex.app/Contents/Resources/app.asar`.
</ParamField>

<ParamField body="--dry-run" type="boolean">
Print resolved workspace, asar, and target paths without deleting or extracting.
</ParamField>

<ParamField body="--skip-format" type="boolean">
Extract only; skip Prettier. Use only when the user explicitly wants raw minified output.
</ParamField>

The refresh script uses a simple **0 / 1** exit model: `0` on success (including dry-run), `1` on any error (missing asar, unsafe `./ref` path, subprocess failure, Prettier verification failure after three passes). It does not use BSD usage code `64`.

### Prettier (`scripts/format.ts`)

`format.ts` is the stable entry point for deliverable formatting. It wraps Prettier with gitignore-aware defaults:

- Directories default to glob `**/*.{ts,tsx,js,jsx,mjs,cjs}`.
- `--ignore-path .prettierignore` — **not** `.gitignore` — so gitignored `restored/` files are actually formatted.
- Runner resolution: `prettier` on `PATH` (offline-safe) → `bunx prettier` → `npx prettier`.

<ParamField body="--check" type="boolean">
Run `prettier --check` instead of `--write`; non-zero exit when formatting would change files.
</ParamField>

<ParamField body="--glob" type="string">
Limit which files under a directory Prettier touches.
</ParamField>

Unlike wakaru, `format.ts` does **not** passthrough on failure — a missing target exits `1`, and Prettier errors propagate the subprocess exit code.

### `@wakaru/cli` (`scripts/wakaru-normalize.ts`)

Wakaru is a Rust transpiler/minifier decompiler. The wrapper pins `WAKARU_VERSION = "1.5.0"` and resolves the runner as:

1. Global `wakaru` on `PATH`
2. `npx --yes @wakaru/cli@1.5.0`

<ParamField body="--level" type="string" default="standard">
`minimal` | `standard` | `aggressive` — aggressiveness of mechanical recovery.
</ParamField>

<ParamField body="--unpack" type="string">
`auto` | `strict` or bare `--unpack` — split a **single** scope-hoisted bundle into modules. Never use on an already-split chunk tree.
</ParamField>

<ParamField body="--dce" type="boolean" default={false}>
Dead-code elimination — opt-in only; can drop side-effecting code.
</ParamField>

<ParamField body="--source-map" type="string" short="m">
Pass a sourcemap for identifier recovery and import dedup.
</ParamField>

Readable tier runs wakaru **default-on** after sourcemap-check and Stage 1 (if obfuscated), before `extract.ts`. Skip entirely when a usable `.map` exists — sourcemap recovery wins. Deep/full mode runs wakaru per chunk body only, never with `--unpack` on a split tree.

### `webcrack` (direct `npx`)

Use when input is one giant webpack-shaped bundle. Output lands under a workspace directory (e.g. `$WS/webcracked/modules/`); each module then follows the single-file restore flow. webcrack is webpack-shaped — Rollup/esbuild/Vite flat ESM usually passes through unchanged; use [multi-export-bundle](/page-multi-export-bundle) or wakaru `--unpack` for those shapes instead.

### `source-map-explorer` (direct `npx`)

`sourcemap-check.ts` is always Step 0. When it reports `✓ sourcemap detected`, stop the rename pipeline and recover originals:

```bash
npx source-map-explorer ref/webview/assets/some-chunk-XXXX.js
```

This preserves original variable names, comments, and file structure that Stage 1 + Stage 2 cannot reconstruct. Running wakaru or Stage 1 **after** committing to sourcemap recovery invalidates byte offsets the map indexes.

## BSD-style exit codes

All `deobfuscate-javascript` scripts share a common exit vocabulary so shell pipelines and orchestrators can branch predictably:

| Code | Meaning | Typical scripts |
| ---- | ------- | ----------------- |
| `0` | Success | All scripts |
| `1` | I/O error — missing input, write failure, gate failure | `extract.ts`, `format.ts`, `quality-gate.ts`, `sourcemap-check.ts` (no map found) |
| `2` | JavaScript parse error | `extract.ts`, `smart-rename.ts`, `wakaru-normalize.ts` (wakaru parse failure) |
| `64` | Usage error — missing arg, unknown flag, bad option value | CLI entrypoints across `scripts/*.ts` |

### Domain-specific extensions

| Code | Meaning | Script |
| ---- | ------- | ------ |
| `1` (informational) | No recoverable sourcemap — proceed with rename pipeline | `sourcemap-check.ts` |
| `3` | Suspicious entry — likely a transitive vendor leaf, not the app root | `check-entry.ts` |
| `75` | Lock contention — another agent holds the file-stage lock | `ledger.ts` (`EX_LOCKED`) |

<Info>
`sourcemap-check.ts` exiting `1` when no map is found is **not** a hard failure — it signals "continue with extract/rename." `check-entry.ts` exiting `3` **is** actionable: switch to the `index.html` script root or a high fan-out `app-main-*` chunk before building the import graph.
</Info>

### Wakaru exit mapping

| Condition | Exit | Output file |
| --------- | ---- | ----------- |
| Binary unavailable (`which` finds neither `wakaru` nor `npx`) | `0`, `skipped: true` | Passthrough copy of input |
| Runner spawn fails (ENOENT, offline `npx` fetch) | `0`, `skipped: true` | Passthrough copy |
| Wakaru runs but parse fails | `2` | Passthrough copy (pipeline may continue) |
| Success | `0` | Wakaru-transformed output |

Stderr carries the skip note: `wakaru unavailable — skipping mechanical normalization, continuing with original`.

## Graceful degradation

The skill distinguishes **hard dependencies** (Bun + Babel — pipeline stops without them) from **optional accelerators** (external CLIs — pipeline continues with reduced fidelity).

```mermaid
sequenceDiagram
  participant Agent
  participant WakaruWrap as wakaru-normalize.ts
  participant Wakaru as @wakaru/cli
  participant Next as extract.ts

  Agent->>WakaruWrap: normalize input → normalized.js
  alt binary on PATH or npx reachable
    WakaruWrap->>Wakaru: spawn with pinned @1.5.0
    Wakaru-->>WakaruWrap: transformed JS
    WakaruWrap-->>Agent: exit 0, skipped=false
  else unavailable or spawn failure
    WakaruWrap->>WakaruWrap: copyFileSync passthrough
    WakaruWrap-->>Agent: exit 0, skipped=true + stderr note
  else wakaru parse error
    WakaruWrap->>WakaruWrap: passthrough copy
    WakaruWrap-->>Agent: exit 2 + stderr
  end
  Agent->>Next: always reads normalized.js
```

| Surface | Missing tool behavior | Pipeline impact |
| ------- | --------------------- | --------------- |
| `wakaru-normalize.ts` | Passthrough copy, exit `0`, stderr note | Rename starts from less-normalized input; more hand-fixes |
| `format.ts` | Tries `PATH` → `bunx` → `npx`; fails if all unreachable | Promotion/gate may report unformatted deliverables |
| `quality-gate.ts --check-format` | Soft-skip — advisory stderr, no `unformatted` issues | Gate passes format dimension when Prettier cannot run |
| `unpack.ts --no-eval` | Exit `0`, input unchanged, `evalRefused: true` | Packed layers remain; agent must unpack manually |
| `refresh-codex-ref.mjs` | Hard fail exit `1` if `npx` or asar missing | `./ref` not created — fix Node/network before deobfuscation |

<Check>
Every wrapper that degrades still **writes the expected output path** (`normalized.js`, formatted deliverable target) so the next pipeline step never blocks on a missing file. Wakaru and unpack follow this contract; refresh does not — it fails fast because unreadable minified `ref/` blocks all downstream work.
</Check>

### Adopting new tools

When extending the skill:

- **JS/Babel library** → add to `package.json`, run `bun install`, import in scripts.
- **External binary** (Rust/Go CLI) → do **not** add to `package.json`; create a thin wrapper modeled on `format.ts` or `wakaru-normalize.ts`: probe `PATH`, fall back to pinned `npx`, degrade gracefully, document under external tools.

## First-time setup

<Steps>
<Step title="Install runtimes">
Install **Node.js** (refresh skill) and **Bun** (deobfuscate skill). macOS with Codex.app at `/Applications/Codex.app` is required for the default asar path.
</Step>

<Step title="Install Babel deps">
```bash
cd .agents/skills/deobfuscate-javascript
bun install
```
</Step>

<Step title="Optional: prefetch external CLIs">
For offline runs, install globals or ensure `npx` cache is warm:
```bash
npm install -g prettier @wakaru/cli@1.5.0
# webcrack and source-map-explorer: npx on demand
```
</Step>

<Step title="Verify toolchain">
```bash
node .agents/skills/codex-app-ref-refresh/scripts/refresh-codex-ref.mjs --dry-run
bun .agents/skills/deobfuscate-javascript/scripts/wakaru-normalize.ts --help 2>&1 | head -1
bun .agents/skills/deobfuscate-javascript/scripts/format.ts --help 2>&1 | head -1
```
</Step>
</Steps>

## Troubleshooting

<AccordionGroup>
<Accordion title="wakaru skipped but I expected normalization">
Check stderr for `wakaru unavailable` or `could not be launched`. Install `@wakaru/cli@1.5.0` globally or ensure `npx` has network access. The pipeline still produces `normalized.js` as a copy of the input — compare file hashes to confirm skip vs transform.
</Accordion>

<Accordion title="Prettier says all files use Prettier code style but nothing changed">
Prettier 3 honors `.gitignore` by default. On gitignored `ref/` or `restored/`, use `scripts/format.ts` (pins `--ignore-path .prettierignore`) or pass `--ignore-path /dev/null` when invoking Prettier directly — the refresh script already does this.
</Accordion>

<Accordion title="check-entry exits 3">
The discovered or supplied entry is a transitive vendor leaf (small local fan-out, imported by many siblings). Re-run discovery from `index.html` or pick a high fan-out `app-main-*` / `app-shell-*` chunk before `build-import-graph.ts`.
</Accordion>

<Accordion title="quality-gate --check-format silently passes unformatted files">
When Prettier is unreachable, the gate soft-skips with `[quality-gate] prettier --check could not run …; skipping format check`. Install Prettier and re-run with `--check-format`, or run `bun scripts/format.ts <target>` first.
</Accordion>

<Accordion title="webcrack left the bundle unsplit">
Input is likely Rollup/esbuild/Vite ESM, not webpack module-id shape. Feed the original file into `extract.ts` directly, or try wakaru `--unpack` on a **single** bundle only.
</Accordion>
</AccordionGroup>

## Related pages

<CardGroup>
<Card title="Installation" href="/installation">
Prerequisites and first-time `bun install` inside the deobfuscate skill directory.
</Card>
<Card title="Refresh script reference" href="/refresh-script-reference">
`refresh-codex-ref.mjs` flags, `CODEX_APP_ASAR`, Prettier verification passes, and completion log lines.
</Card>
<Card title="Stage 2 scripts" href="/stage-2-scripts">
`sourcemap-check`, `wakaru-normalize`, `format`, and `polish` CLI signatures and ordering.
</Card>
<Card title="Pipeline caveats" href="/pipeline-caveats">
Prettier gitignore traps, wakaru caveats, sourcemap precedence, and recovery steps.
</Card>
</CardGroup>
