[PR #2093] feat(javascript-recovery): add jsbeautify as a caller-supplied recovery engine #5022

Open
opened 2026-10-31 00:58:33 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2093
Author: @coleleavitt
Created: 10/12/2026
Status: 🔄 Open

Base: main ← Head: pr/jsbeautify-recovery-engine


📝 Commits (10+)

  • e0f5193 feat(javascript-recovery): add jsbeautify as a caller-supplied recovery engine
  • ae6f216 docs(javascript-recovery): follow the jsbeautify repository rename
  • eb98293 docs(javascript-recovery): cite jsbeautify commits from its public history
  • 188452c docs(javascript-recovery): cite jsbeautify commit 9949993
  • b19fd10 fix(javascript-recovery): merge main and enforce recovery boundaries
  • 3a5f943 fix(javascript-recovery): bound retained and published recovery output
  • d48e68f fix(javascript-recovery): preserve engine and output identities
  • 33ec469 chore: merge captured main into PR #2093
  • d9b29d0 fix(javascript-recovery): revalidate consumed snapshots and catalog identity
  • 2faac39 fix(javascript-recovery): bind bounded jsbeautify results

📊 Changes

37 files changed (+2214 additions, -516 deletions)

View changed files

📝 .agents/skills/reverse-engineer-anything/references/javascript-applications.md (+2 -1)
📝 THIRD_PARTY_NOTICES.md (+1 -0)
📝 docs/javascript-recovery.md (+64 -3)
📝 scripts/lib/catalog-builders.mjs (+5 -0)
📝 scripts/lib/catalog-core.mjs (+1 -0)
📝 src/application/CapabilityInventory.test.ts (+18 -0)
📝 src/application/CapabilityInventory.ts (+36 -1)
📝 src/application/javascript/JavaScriptRecoveryPort.ts (+4 -0)
📝 src/application/javascript/JavaScriptRecoveryService.test.ts (+8 -3)
📝 src/application/javascript/JavaScriptRecoveryService.ts (+1 -0)
📝 src/cli/javascriptRecoveryCommands.ts (+7 -0)
📝 src/composition/javascriptRecovery.ts (+7 -4)
📝 src/contracts/javascript/javascriptRecoveryToolContracts.ts (+9 -1)
📝 src/domain/javascript/javascriptRecovery.ts (+9 -2)
➕ src/javascript/recovery/JsBeautifyEngine.ts (+482 -0)
➕ src/javascript/recovery/JsBeautifyModuleNames.ts (+112 -0)
➕ src/javascript/recovery/JsBeautifyRelease.ts (+35 -0)
➕ src/javascript/recovery/RecoveryCommand.test.ts (+293 -0)
➕ src/javascript/recovery/RecoveryCommand.ts (+229 -0)
➕ src/javascript/recovery/RecoveryEngine.ts (+74 -0)

...and 17 more files

📄 Description

Branch: pr/jsbeautify-recovery-engine (base: origin/main b3dec005b, independent of the other two PRs)

Commit:

  • e0f51933e feat(javascript-recovery): add jsbeautify as a caller-supplied recovery engine

Problem

recover_javascript_sources only runs Wakaru. Wakaru unpacks webpack/Browserify module
graphs, but it does not deobfuscate single-file bundles such as esbuild/Bun output,
javascript-obfuscator string arrays, or Akamai BMP scripts. For the Grok Bot Electron app,
the main-process bundles (dist/electron-main/main-app.cjs, 2.4 MB esbuild) had to be
beautified outside REA (jsbeautify -s 2, see REA_REPORT §"Citation conventions"), so the
readable copy had no REA provenance (original path, SHA-256, byte range) and could not be
offered back to analyze_javascript_application.

The provider lifecycle (owned process runner, input snapshots, staging inventory,
publication, cleanup retention) was written for Wakaru only, so a second engine would have
duplicated it.

What changed

  • recover_javascript_sources (MCP and rea recover-javascript-sources --engine) gains
    engine: "wakaru" | "jsbeautify", default wakaru. Existing calls are unchanged.
  • jsbeautify runs a caller-supplied jsbeautify binary (REA_JSBEAUTIFY_COMMAND,
    absolute path, Linux) on each selected file whole:
    • rewrite_level: minimal formats only, standard adds --deobfuscate,
      aggressive adds --rename-vars;
    • .cjs/.mjs inputs keep their parse goal;
    • a file is published only when the tool exits 0 and, when deobfuscating, both
      generated-output re-parse checks (phases 19.6 and 21.5) are reported; otherwise it is a
      validity-gate warning and the result is partial;
    • each module keeps its original path, SHA-256 and whole-file byte range; the recovered
      tree is offered as analysis_input;
    • detected_formats follows the tool's per-detector <name> check: detected lines
      (esbuild, Bun, webpack, Turbopack, Akamai BMP, Angular).
  • The Wakaru-specific lifecycle becomes RecoveryEngine (RecoveryProvider,
    RecoveryCommand, RecoveryFiles) with per-engine limits. Wakaru keeps its limits and
    behaviour; WakaruProvider is renamed RecoveryProvider, WakaruCommand.test.ts
    becomes RecoveryCommand.test.ts.
  • jsbeautify limits: 8 GiB address-space ceiling, 300 s deadline, 256 MiB output, 64 MiB
    per diagnostic stream. Builds before jsbeautify 9949993 reserve a worker stack of
    2 KiB per input byte regardless of RLIMIT_AS (the 2.4 MB bundle peaks at 0.33 GB RSS
    but aborts below 3 GiB); later builds cap the stack at a quarter of the limit.
  • Capability inventory and session tool availability enable recovery when
    REA_JSBEAUTIFY_COMMAND is an absolute path on Linux. Docs: docs/javascript-recovery.md,
    skill reference.

Breaking changes

None. engine is optional and defaults to wakaru.

Verification

Run on this branch alone (rebased on origin/main b3dec005b):

  • npm run check — pass (typecheck, lint, format, knip, metadata, architecture guards).
  • npm run test:changed -- --base origin/main — 33 files, 525 tests passed.
  • npm run test:focused -- tests/boundary/javascript-recovery/jsbeautifyRecovery.test.ts tests/boundary/javascript-recovery/wakaruCommandConfiguration.test.ts tests/boundary/javascript-recovery/wakaruIntegration.test.ts tests/boundary/mcp/javascriptRecoveryMcp.test.ts tests/evaluation/moduleBoundaries.test.ts
    — 5 files, 157 tests passed.
  • Real provider (Linux x64, jsbeautify 0.1.0+f0d6795, util-linux prlimit):
    • rea recover-javascript-sources …/electron-main/main-app.cjs <out> --engine jsbeautify --json
      → status: complete, 1/1 module, detected_formats: ["esbuild"], 5.2 s wall,
      325 MB peak RSS (CLI process).
    • preload.cjs + --additional-path preload-webview.cjs → complete, 2/2 modules,
      detected_formats: [] (neither is an esbuild/webpack/Turbopack bundle), 0.8 s.

Not run: Wakaru real-provider lane (no Wakaru install on this host; Wakaru code paths are
covered by the existing boundary tests above). macOS/Windows: the engine is Linux-only.

Limitations

  • jsbeautify output proves syntax (re-parse), not runtime equivalence;
    runtime_equivalence stays unknown.
  • One module per input file: jsbeautify does not split bundles into modules.
  • Linux only (the address-space limit uses prlimit).

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/2093 **Author:** [@coleleavitt](https://github.com/coleleavitt) **Created:** 10/12/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `pr/jsbeautify-recovery-engine` --- ### 📝 Commits (10+) - [`e0f5193`](https://github.com/morluto/rea/commit/e0f51933ef32a5164cdc8eae15b5a219e6cad4a0) feat(javascript-recovery): add jsbeautify as a caller-supplied recovery engine - [`ae6f216`](https://github.com/morluto/rea/commit/ae6f216cf3c891eed3794626e5c36ce378fb1d50) docs(javascript-recovery): follow the jsbeautify repository rename - [`eb98293`](https://github.com/morluto/rea/commit/eb9829373e79b87f73365d5e480397bda83868e6) docs(javascript-recovery): cite jsbeautify commits from its public history - [`188452c`](https://github.com/morluto/rea/commit/188452c799d58c5921856a7e43689a82ef6d514b) docs(javascript-recovery): cite jsbeautify commit 9949993 - [`b19fd10`](https://github.com/morluto/rea/commit/b19fd1063fa2fdb814dcf77867a3955333f7f277) fix(javascript-recovery): merge main and enforce recovery boundaries - [`3a5f943`](https://github.com/morluto/rea/commit/3a5f943f076ca3849ecf7992b83521020f9b2b4c) fix(javascript-recovery): bound retained and published recovery output - [`d48e68f`](https://github.com/morluto/rea/commit/d48e68f0ecae63f00b8dcac9a5275e878c13f07a) fix(javascript-recovery): preserve engine and output identities - [`33ec469`](https://github.com/morluto/rea/commit/33ec469e5440f2a97f5984400c2d3082db28fcb5) chore: merge captured main into PR #2093 - [`d9b29d0`](https://github.com/morluto/rea/commit/d9b29d0a838cf2a00a87322fe48206c8e2c597c6) fix(javascript-recovery): revalidate consumed snapshots and catalog identity - [`2faac39`](https://github.com/morluto/rea/commit/2faac396869df9fb949eeaa74f5da22f78ab36ad) fix(javascript-recovery): bind bounded jsbeautify results ### 📊 Changes **37 files changed** (+2214 additions, -516 deletions) <details> <summary>View changed files</summary> 📝 `.agents/skills/reverse-engineer-anything/references/javascript-applications.md` (+2 -1) 📝 `THIRD_PARTY_NOTICES.md` (+1 -0) 📝 `docs/javascript-recovery.md` (+64 -3) 📝 `scripts/lib/catalog-builders.mjs` (+5 -0) 📝 `scripts/lib/catalog-core.mjs` (+1 -0) 📝 `src/application/CapabilityInventory.test.ts` (+18 -0) 📝 `src/application/CapabilityInventory.ts` (+36 -1) 📝 `src/application/javascript/JavaScriptRecoveryPort.ts` (+4 -0) 📝 `src/application/javascript/JavaScriptRecoveryService.test.ts` (+8 -3) 📝 `src/application/javascript/JavaScriptRecoveryService.ts` (+1 -0) 📝 `src/cli/javascriptRecoveryCommands.ts` (+7 -0) 📝 `src/composition/javascriptRecovery.ts` (+7 -4) 📝 `src/contracts/javascript/javascriptRecoveryToolContracts.ts` (+9 -1) 📝 `src/domain/javascript/javascriptRecovery.ts` (+9 -2) ➕ `src/javascript/recovery/JsBeautifyEngine.ts` (+482 -0) ➕ `src/javascript/recovery/JsBeautifyModuleNames.ts` (+112 -0) ➕ `src/javascript/recovery/JsBeautifyRelease.ts` (+35 -0) ➕ `src/javascript/recovery/RecoveryCommand.test.ts` (+293 -0) ➕ `src/javascript/recovery/RecoveryCommand.ts` (+229 -0) ➕ `src/javascript/recovery/RecoveryEngine.ts` (+74 -0) _...and 17 more files_ </details> ### 📄 Description Branch: `pr/jsbeautify-recovery-engine` (base: `origin/main` b3dec005b, independent of the other two PRs) Commit: - e0f51933e feat(javascript-recovery): add jsbeautify as a caller-supplied recovery engine ## Problem `recover_javascript_sources` only runs Wakaru. Wakaru unpacks webpack/Browserify module graphs, but it does not deobfuscate single-file bundles such as esbuild/Bun output, javascript-obfuscator string arrays, or Akamai BMP scripts. For the Grok Bot Electron app, the main-process bundles (`dist/electron-main/main-app.cjs`, 2.4 MB esbuild) had to be beautified outside REA (`jsbeautify -s 2`, see REA_REPORT §"Citation conventions"), so the readable copy had no REA provenance (original path, SHA-256, byte range) and could not be offered back to `analyze_javascript_application`. The provider lifecycle (owned process runner, input snapshots, staging inventory, publication, cleanup retention) was written for Wakaru only, so a second engine would have duplicated it. ## What changed - `recover_javascript_sources` (MCP and `rea recover-javascript-sources --engine`) gains `engine: "wakaru" | "jsbeautify"`, default `wakaru`. Existing calls are unchanged. - `jsbeautify` runs a caller-supplied jsbeautify binary (`REA_JSBEAUTIFY_COMMAND`, absolute path, Linux) on each selected file whole: - `rewrite_level: minimal` formats only, `standard` adds `--deobfuscate`, `aggressive` adds `--rename-vars`; - `.cjs`/`.mjs` inputs keep their parse goal; - a file is published only when the tool exits 0 and, when deobfuscating, both generated-output re-parse checks (phases 19.6 and 21.5) are reported; otherwise it is a validity-gate warning and the result is `partial`; - each module keeps its original path, SHA-256 and whole-file byte range; the recovered tree is offered as `analysis_input`; - `detected_formats` follows the tool's per-detector `<name> check: detected` lines (esbuild, Bun, webpack, Turbopack, Akamai BMP, Angular). - The Wakaru-specific lifecycle becomes `RecoveryEngine` (`RecoveryProvider`, `RecoveryCommand`, `RecoveryFiles`) with per-engine limits. Wakaru keeps its limits and behaviour; `WakaruProvider` is renamed `RecoveryProvider`, `WakaruCommand.test.ts` becomes `RecoveryCommand.test.ts`. - jsbeautify limits: 8 GiB address-space ceiling, 300 s deadline, 256 MiB output, 64 MiB per diagnostic stream. Builds before jsbeautify `9949993` reserve a worker stack of 2 KiB per input byte regardless of `RLIMIT_AS` (the 2.4 MB bundle peaks at 0.33 GB RSS but aborts below 3 GiB); later builds cap the stack at a quarter of the limit. - Capability inventory and session tool availability enable recovery when `REA_JSBEAUTIFY_COMMAND` is an absolute path on Linux. Docs: `docs/javascript-recovery.md`, skill reference. ## Breaking changes None. `engine` is optional and defaults to `wakaru`. ## Verification Run on this branch alone (rebased on `origin/main` b3dec005b): - `npm run check` — pass (typecheck, lint, format, knip, metadata, architecture guards). - `npm run test:changed -- --base origin/main` — 33 files, 525 tests passed. - `npm run test:focused -- tests/boundary/javascript-recovery/jsbeautifyRecovery.test.ts tests/boundary/javascript-recovery/wakaruCommandConfiguration.test.ts tests/boundary/javascript-recovery/wakaruIntegration.test.ts tests/boundary/mcp/javascriptRecoveryMcp.test.ts tests/evaluation/moduleBoundaries.test.ts` — 5 files, 157 tests passed. - Real provider (Linux x64, jsbeautify `0.1.0+f0d6795`, util-linux `prlimit`): - `rea recover-javascript-sources …/electron-main/main-app.cjs <out> --engine jsbeautify --json` → `status: complete`, 1/1 module, `detected_formats: ["esbuild"]`, 5.2 s wall, 325 MB peak RSS (CLI process). - `preload.cjs` + `--additional-path preload-webview.cjs` → `complete`, 2/2 modules, `detected_formats: []` (neither is an esbuild/webpack/Turbopack bundle), 0.8 s. Not run: Wakaru real-provider lane (no Wakaru install on this host; Wakaru code paths are covered by the existing boundary tests above). macOS/Windows: the engine is Linux-only. ## Limitations - jsbeautify output proves syntax (re-parse), not runtime equivalence; `runtime_equivalence` stays `unknown`. - One module per input file: jsbeautify does not split bundles into modules. - Linux only (the address-space limit uses `prlimit`). --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5022
No description provided.