diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 83218a6392..8d6bea208e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -244,15 +244,41 @@ jobs:
if: github.event_name == 'push' || needs.changes.outputs.package == 'true'
strategy:
fail-fast: false
+ max-parallel: 2
matrix:
- os: [ubuntu-latest, macos-14]
+ include:
+ - os: ubuntu-latest
+ platform: linux
+ architecture: x64
+ - os: ubuntu-24.04-arm
+ platform: linux
+ architecture: arm64
+ - os: macos-14
+ platform: darwin
+ architecture: arm64
+ - os: macos-15-intel
+ platform: darwin
+ architecture: x64
runs-on: ${{ matrix.os }}
+ timeout-minutes: 20
+ env:
+ NODE_OPTIONS: "--max-old-space-size=1024"
+ UV_THREADPOOL_SIZE: "2"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
+ - name: Verify native runtime identity
+ env:
+ EXPECTED_CI_PLATFORM: ${{ matrix.platform }}
+ EXPECTED_CI_ARCHITECTURE: ${{ matrix.architecture }}
+ run: >-
+ node -e "const assert = require('node:assert/strict');
+ assert.equal(process.platform, process.env.EXPECTED_CI_PLATFORM);
+ assert.equal(process.arch, process.env.EXPECTED_CI_ARCHITECTURE);
+ console.log(JSON.stringify({ platform: process.platform, architecture: process.arch, node: process.version }));"
- run: npm ci
- uses: actions/download-artifact@v4
with:
@@ -318,16 +344,44 @@ jobs:
if: github.event_name == 'push' || needs.changes.outputs.code == 'true'
strategy:
fail-fast: false
+ max-parallel: 2
matrix:
- os: [ubuntu-latest, windows-latest]
+ include:
+ - os: ubuntu-latest
+ platform: linux
+ architecture: x64
+ - os: ubuntu-24.04-arm
+ platform: linux
+ architecture: arm64
+ - os: macos-14
+ platform: darwin
+ architecture: arm64
+ - os: macos-15-intel
+ platform: darwin
+ architecture: x64
+ - os: windows-latest
+ platform: win32
+ architecture: x64
runs-on: ${{ matrix.os }}
timeout-minutes: 10
+ env:
+ NODE_OPTIONS: "--max-old-space-size=1024"
+ UV_THREADPOOL_SIZE: "2"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
+ - name: Verify native runtime identity
+ env:
+ EXPECTED_CI_PLATFORM: ${{ matrix.platform }}
+ EXPECTED_CI_ARCHITECTURE: ${{ matrix.architecture }}
+ run: >-
+ node -e "const assert = require('node:assert/strict');
+ assert.equal(process.platform, process.env.EXPECTED_CI_PLATFORM);
+ assert.equal(process.arch, process.env.EXPECTED_CI_ARCHITECTURE);
+ console.log(JSON.stringify({ platform: process.platform, architecture: process.arch, node: process.version }));"
- run: npm ci
- name: Verify real Node Inspector discovery and observation
run: npm run verify:inspector
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
new file mode 100644
index 0000000000..dde66fcf48
--- /dev/null
+++ b/.github/workflows/pages.yml
@@ -0,0 +1,63 @@
+name: Documentation site
+
+on:
+ push:
+ branches: [main]
+ paths:
+ - "docs/**"
+ - "package.json"
+ - "package-lock.json"
+ - ".nvmrc"
+ - ".github/workflows/pages.yml"
+ pull_request:
+ branches: [main]
+ paths:
+ - "docs/**"
+ - "package.json"
+ - "package-lock.json"
+ - ".nvmrc"
+ - ".github/workflows/pages.yml"
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+concurrency:
+ group: pages-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
+
+env:
+ HUSKY: "0"
+
+jobs:
+ build:
+ name: Build documentation
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version-file: .nvmrc
+ cache: npm
+ - run: npm ci
+ - run: npm run docs:build
+ - uses: actions/upload-pages-artifact@v4
+ if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
+ with:
+ path: docs/.vitepress/dist
+
+ deploy:
+ name: Publish documentation
+ if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
+ needs: build
+ runs-on: ubuntu-latest
+ permissions:
+ pages: write
+ id-token: write
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - uses: actions/configure-pages@v5
+ - uses: actions/deploy-pages@v4
+ id: deployment
diff --git a/.github/workflows/real-javascript-recovery.yml b/.github/workflows/real-javascript-recovery.yml
index ca84669f94..7076a29cde 100644
--- a/.github/workflows/real-javascript-recovery.yml
+++ b/.github/workflows/real-javascript-recovery.yml
@@ -5,10 +5,10 @@ on:
paths:
- ".github/workflows/real-javascript-recovery.yml"
- "src/javascript/recovery/**"
- - "src/domain/javascript*.ts"
- - "src/application/JavaScriptRecovery*.ts"
+ - "src/domain/javascript/**"
+ - "src/application/javascript/JavaScriptRecovery*.ts"
- "src/composition/javascriptRecovery.ts"
- - "src/contracts/javascriptRecoveryToolContracts.ts"
+ - "src/contracts/javascript/javascriptRecoveryToolContracts.ts"
- "src/cli/javascriptRecoveryCommands.ts"
- "src/cli/javascriptApplicationAnalysis.ts"
- "src/server/registerJavaScriptRecoveryTool.ts"
@@ -22,8 +22,7 @@ on:
- "scripts/rea.mjs"
- "src/process/**"
- "src/artifacts/SafeOutputTree.ts"
- - "scripts/verify-javascript-recovery.mjs"
- - "scripts/lib/javascript-recovery-*.mjs"
+ - "scripts/verify/javascript/recovery.mjs"
- "scripts/fixtures/javascript-recovery/**"
- "third_party/wakaru"
- "package.json"
diff --git a/.github/workflows/real-web-source-map.yml b/.github/workflows/real-web-source-map.yml
new file mode 100644
index 0000000000..e58764a36c
--- /dev/null
+++ b/.github/workflows/real-web-source-map.yml
@@ -0,0 +1,50 @@
+name: Real website source-map verification
+on:
+ pull_request:
+ paths:
+ - ".github/workflows/real-web-source-map.yml"
+ - "scripts/verify-browser-source-maps.mjs"
+ - "scripts/lib/browser-source-map-e2e.mjs"
+ - "scripts/fixtures/browser-source-map-site.mjs"
+ - "src/javascript/sourceMaps/**"
+ - "src/browser/assets/**"
+ - "src/domain/webSource*.ts"
+ - "src/domain/webScript*.ts"
+ - "src/application/WebSourceLocation*.ts"
+ - "src/application/ValidateSelectedWebScript.ts"
+ - "src/composition/webSourceLocations.ts"
+ - "src/server/registerWebSourceLocationTool.ts"
+ - "src/server/createServer.ts"
+ - "src/contracts/webScriptToolContracts.ts"
+ - "src/process/**"
+ - "src/cli/webSourceLocationCommands.ts"
+ - "src/cli.ts"
+ - "src/artifacts/readStableArtifact.ts"
+ - "package.json"
+ - "package-lock.json"
+ workflow_dispatch:
+permissions:
+ contents: read
+concurrency:
+ group: real-web-source-map-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
+env:
+ HUSKY: "0"
+jobs:
+ real-web-source-map:
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 24
+ cache: npm
+ - run: npm ci
+ - name: Install the pinned compiler into an isolated fixture directory
+ run: npm install --prefix "$RUNNER_TEMP/rea-web-source-map-compiler" --no-audit --no-fund --package-lock=false esbuild@0.25.10
+ - run: npm run verify:browser:source-maps
+ env:
+ REA_BROWSER_EXECUTABLE: /usr/bin/google-chrome
+ REA_BROWSER_NO_SANDBOX: "true"
+ REA_WEB_SOURCE_MAP_COMPILER: ${{ runner.temp }}/rea-web-source-map-compiler/node_modules/esbuild/lib/main.js
diff --git a/.github/workflows/website-pages.yml b/.github/workflows/website-pages.yml
new file mode 100644
index 0000000000..3967a89e47
--- /dev/null
+++ b/.github/workflows/website-pages.yml
@@ -0,0 +1,44 @@
+name: Publish REA website
+
+on:
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+concurrency:
+ group: website-pages
+ cancel-in-progress: false
+
+jobs:
+ prepare:
+ if: github.ref == 'refs/heads/main'
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions:
+ contents: read
+ pages: read
+ steps:
+ - name: Check out the repository
+ uses: actions/checkout@v4
+ - name: Configure Pages
+ uses: actions/configure-pages@v5
+ - name: Upload the website
+ uses: actions/upload-pages-artifact@v4
+ with:
+ path: website/public
+
+ deploy:
+ needs: prepare
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions:
+ pages: write
+ id-token: write
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Publish to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
index 8396bc653e..e699d15fd1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,6 +37,7 @@ coverage/
test-results.xml
.turbo/
.cache/
+docs/.vitepress/cache/
# OS
.DS_Store
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 731cd2cdc5..07b182bd24 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -26,6 +26,22 @@ worktrees. After a package, lockfile, or managed-skill version change, run
Keep dependencies flowing inward through the existing domain, contracts, provider, application, server, and adapter layers. Parse unknown values at process and protocol boundaries, model expected failures with `Result`, and preserve the canonical tool inventory defined by `TOOL_CONTRACTS` unless a deliberate contract change updates every verifier, generated catalog artifact, and snapshot. Keep tool discovery complete and report capability- and session-scoped availability through `binary_session`.
+## Documentation website
+
+The VitePress site uses the Markdown files in `docs/` and deploys to
+. Run `npm run docs:dev` for live editing,
+`npm run docs:build` to check the production build and links, and
+`npm run docs:preview` to preview that build at `/rea/`.
+
+Site navigation lives in `docs/.vitepress/config.ts`. Keep links to guides
+relative so they work on GitHub and the website; link to repository files
+outside `docs/` using their full GitHub URLs. Generated reference documents
+still use `npm run docs:generate`; `docs:build` only builds the website.
+
+The documentation workflow builds pull requests and deploys changes on `main`.
+The repository's **Settings → Pages → Build and deployment → Source** must be
+set to **GitHub Actions** before the first deployment.
+
## Development feedback and PR verification
For an ordinary edit, run the relevant regression and cached static checks:
diff --git a/README.md b/README.md
index 441f2485e7..2bf765f54d 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@
-[Quick start](#quick-start) · [Current status](#current-status) · [Investigation model](#the-investigation-model) · [Tool catalog](#tool-catalog-for-investigation) · [Roadmap](#roadmap) · [How it works](#how-it-works)
+[Documentation](https://morluto.github.io/rea/) · [Quick start](#quick-start) · [Current status](#current-status) · [Investigation model](#the-investigation-model) · [Tool catalog](#tool-catalog-for-investigation) · [Roadmap](#roadmap) · [How it works](#how-it-works)
npx rea-agents setup
@@ -163,7 +163,7 @@ Deep native binary analysis requires [Hopper](https://www.hopperapp.com/), [Ghid
Firmware region inspection and explicit extraction use caller-supplied Binwalk and Unblob on Linux. See [Firmware analysis](docs/firmware-analysis.md) for setup, provenance, resource limits and native handoff.
-Static APK analysis uses a separately supplied headless JADX JAR and Java, with no emulator or APK execution. See [Android analysis](docs/android-analysis.md) for setup, CLI/MCP operations, coverage and public test fixtures. Authenticated IPA inventory Evidence can be projected with [Apple application analysis](docs/apple-application-analysis.md).
+Static APK analysis uses a separately supplied headless JADX JAR and a full JDK, with no emulator or APK execution. See [Android analysis](docs/android-analysis.md) for setup, CLI/MCP operations, coverage and public test fixtures. Authenticated IPA inventory Evidence can be projected with [Apple application analysis](docs/apple-application-analysis.md).
Repository main and npm 4.1.0 include experimental Windows x64 Ghidra support for native x86-64 PE applications on local NTFS, with bundled Job Object, private-DACL, and path-admission controls. Check the [release boundary](docs/installation.md#released-package-and-main) before expecting this from an older npm package. See [Windows Ghidra P0](docs/windows-ghidra-p0.md) for prerequisites and verified scope.
@@ -411,7 +411,7 @@ See [native investigation](docs/native-investigation.md) for keyed archives, ins
| Browser observation | 9 | page structure, network metadata, scripts, source maps, WebMCP discovery, screenshots, and capture comparisons |
| Electron analysis | 5 | renderer observation, static app mapping, and static/runtime reconciliation |
| JavaScript runtime | 2 | Node/Electron Inspector target discovery, script locations, and execution-context events |
-| Application workflows | 12 | captured website script export; Android/Apple inventory projections; cross-layer feature traces, build comparisons, historical source mapping, static return-shape comparison, and reconstruction checks |
+| Application workflows | 13 | captured website script export; Android/Apple inventory projections; cross-layer feature traces, build comparisons, historical source mapping, static return-shape comparison, and reconstruction checks |
| Workspace and observation | 21 | sessions, evidence bundles, navigation context, process/artifact/function comparisons, and open-question tracking |
The public interface describes what the agent is trying to learn. Providers decide how to answer. macOS utilities handle common semantic inspection without launching Hopper; Hopper handles deeper native analysis; the process harness records direct behavioral captures.
@@ -420,7 +420,7 @@ The public interface describes what the agent is trying to learn. Providers deci
REA supports native application, JavaScript, Electron, .NET, and browser investigation on macOS and Linux. Individual tools have platform and runtime prerequisites. `rea capabilities` and `rea providers` describe the binary-session providers and auxiliary operations; they are not an inventory of every browser, Android, or application workflow. Use the connected MCP tool list and `binary_session` tool availability for the full MCP surface, and the relevant guide for each tool's prerequisites. Repository main can be ahead of [the npm release](docs/installation.md#released-package-and-main).
-Static Android APK inspection is verified on Linux with headless JADX; see [Android analysis](docs/android-analysis.md) for its separate prerequisites and coverage.
+Static Android APK inspection supports Linux and macOS; the current metadata bridge is verified on macOS arm64 with headless JADX; see [Android analysis](docs/android-analysis.md) for its separate prerequisites and coverage.
- **Native binaries:** Open Mach-O, ELF, PE, and Mac `.app` targets through a selected deep provider. Hopper and Ghidra cover broad inventory and function analysis; the IDA adapter supplies its documented read-only function/string operations. Hopper also accepts `.hop` databases and supports annotations.
- **Packages and resources:** Inspect directories, ZIP, APK, IPA, ASAR, plists, compiled Interface Builder files, and Apple asset catalogs. Artifact requests name the input and requested extraction or traversal directly; macOS DMG traversal also requires the host's native mounting support.
@@ -436,6 +436,11 @@ Static Android APK inspection is verified on Linux with headless JADX; see [Andr
`rea trace-web-module-imports`, preserving query/fragment identity and optional
import-map context. Requires caller-supplied Chromium via
`REA_BROWSER_EXECUTABLE`; see [module relationships](docs/website-module-trace.md).
+
+- **Source locations:** Trace one retained website script point through a selected
+ local source map with `rea trace-web-source-location`. See
+ [captured website source locations](docs/web-source-location.md) for byte
+ identities, embedded original content and coverage limits.
Recover readable modules from selected local bundles with
`recover_javascript_sources` / `rea recover-javascript-sources`, then pass
the returned `analysis_input` to static analysis. This optional Linux x64
diff --git a/README_ar.md b/README_ar.md
index 0b68890e8a..364f80b06a 100644
--- a/README_ar.md
+++ b/README_ar.md
@@ -223,7 +223,7 @@ rea setup
| مراقبة المتصفح | 9 | بنية الصفحات وبيانات الشبكة والبرامج النصية وخرائط المصدر واكتشاف WebMCP والصور ومقارنة الالتقاط |
| تحليل Electron | 5 | مراقبة العارضين وخريطة التطبيق الثابتة والمواءمة بين نتائج الثبات والتشغيل |
| وقت تشغيل JavaScript | 2 | اكتشاف أهداف Node/Electron Inspector ومواضع البرامج وأحداث سياقات التنفيذ |
-| سير عمل التطبيقات | 12 | تصدير النصوص البرمجية الملتقطة، تتبع الميزات عبر الطبقات ومقارنة الإصدارات ومواءمة المصدر التاريخي ومقارنة أشكال القيم المعادة والتحقق من إعادة الإنشاء |
+| سير عمل التطبيقات | 13 | تصدير النصوص البرمجية الملتقطة، تتبع الميزات عبر الطبقات ومقارنة الإصدارات ومواءمة المصدر التاريخي ومقارنة أشكال القيم المعادة والتحقق من إعادة الإنشاء |
| مساحة العمل والملاحظة | 21 | الجلسات وحزم الأدلة وسياق التنقل ومقارنة العمليات والمخرجات والدوال وتسجيل الأسئلة غير المحسومة |
## خطة العمل
diff --git a/README_ja.md b/README_ja.md
index 3fabfe2b35..1dd94db2c4 100644
--- a/README_ja.md
+++ b/README_ja.md
@@ -212,7 +212,7 @@ REA は手順 1〜5 のバイナリ解析を処理し、手順 6 はエージェ
| ブラウザー観察 | 9 | ページ構成、ネットワークメタデータ、スクリプト、ソースマップ、WebMCP 検出、スクリーンショット、キャプチャ比較 |
| Electron 解析 | 5 | レンダラー観察、静的アプリマッピング、静的/実行時結果の対応付け |
| JavaScript 実行時 | 2 | Node/Electron Inspector 対象の検出、スクリプト位置、実行コンテキストイベント |
-| アプリワークフロー | 12 | 取得した Web スクリプトのエクスポート、層をまたぐ機能トレース、ビルド比較、履歴ソース対応、静的戻り値形状の比較、再実装検証 |
+| アプリワークフロー | 13 | 取得した Web スクリプトのエクスポート、層をまたぐ機能トレース、ビルド比較、履歴ソース対応、静的戻り値形状の比較、再実装検証 |
| ワークスペースと観察 | 21 | セッション、証跡バンドル、ナビゲーション文脈、プロセス・成果物・関数比較、未解決事項の記録 |
## ロードマップ
diff --git a/README_ko.md b/README_ko.md
index 19b58bd294..916540d14b 100644
--- a/README_ko.md
+++ b/README_ko.md
@@ -213,7 +213,7 @@ REA는 1–5단계의 바이너리 분석을 처리합니다. 6단계는 에이
| 브라우저 관찰 | 9 | 페이지 구조, 네트워크 메타데이터, 스크립트, 소스 맵, WebMCP 탐색, 스크린샷, 캡처 비교 |
| Electron 분석 | 5 | 렌더러 관찰, 정적 앱 매핑, 정적·런타임 결과 연결 |
| JavaScript 런타임 | 2 | Node/Electron Inspector 대상 탐색, 스크립트 위치, 실행 컨텍스트 이벤트 |
-| 앱 워크플로 | 12 | 캡처한 웹 스크립트 내보내기, 계층 간 기능 추적, 빌드 비교, 히스토리 소스 매핑, 정적 반환 구조 비교, 재구현 검증 |
+| 앱 워크플로 | 13 | 캡처한 웹 스크립트 내보내기, 계층 간 기능 추적, 빌드 비교, 히스토리 소스 매핑, 정적 반환 구조 비교, 재구현 검증 |
| 작업 공간과 관찰 | 21 | 세션, 근거 번들, 탐색 컨텍스트, 프로세스·아티팩트·함수 비교, 미해결 항목 기록 |
## 로드맵
diff --git a/README_zh.md b/README_zh.md
index 4495802602..9052768463 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -212,7 +212,7 @@ REA 负责第 1–5 步中的二进制分析。第 6 步由智能体使用其常
| 浏览器观察 | 9 | 页面结构、网络元数据、脚本、来源映射、WebMCP 发现、截图与捕获比较 |
| Electron 分析 | 5 | 渲染进程观察、静态应用映射、静态/运行时结果关联 |
| JavaScript 运行时 | 2 | Node/Electron Inspector 目标发现、脚本位置与执行上下文事件 |
-| 应用工作流 | 12 | 捕获的网站脚本导出、跨层功能追踪、构建比较、历史源码映射、静态返回结构比较与重建验证 |
+| 应用工作流 | 13 | 捕获的网站脚本导出、跨层功能追踪、构建比较、历史源码映射、静态返回结构比较与重建验证 |
| 工作区与观察 | 21 | 会话、证据包、导航上下文、进程/产物/函数比较与待解决问题跟踪 |
## 路线图
diff --git a/bridge/android/ReaJadxBridge.java b/bridge/android/ReaJadxBridge.java
new file mode 100644
index 0000000000..51ac0f7032
--- /dev/null
+++ b/bridge/android/ReaJadxBridge.java
@@ -0,0 +1,247 @@
+import com.atxx.jhmcp.*;
+import com.google.gson.*;
+import io.modelcontextprotocol.kotlin.sdk.server.*;
+import io.modelcontextprotocol.kotlin.sdk.types.*;
+import jadx.api.*;
+import jadx.core.dex.nodes.*;
+import java.io.PrintStream;
+import java.util.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.stream.Collectors;
+import kotlin.Unit;
+import kotlin.coroutines.EmptyCoroutineContext;
+import kotlinx.coroutines.BuildersKt;
+import kotlinx.io.CoreKt;
+import kotlinx.io.JvmCoreKt;
+import kotlinx.serialization.json.JsonObject;
+
+/** REA-owned metadata boundary for the unmodified jadx-headless-mcp 0.7.1 JAR. */
+class ReaJadxBridge {
+ private static final Gson JSON = new Gson();
+ private final SessionHolder holder;
+ private JadxSession indexedSession;
+ private Map> classes = Map.of();
+
+ private record MethodSnapshot(String name, String shortId, Map summary) {}
+ private record ClassSnapshot(JavaClass node, List methods, Map summary) {}
+
+ private ReaJadxBridge(SessionHolder holder) { this.holder = holder; }
+
+ private static CallToolResult text(String value, boolean failed) {
+ return new CallToolResult(List.of(new TextContent(value, null, null)), failed, null, null);
+ }
+
+ private static CallToolResult json(Object value) { return text(JSON.toJson(value), false); }
+
+ private static String string(JsonObject args, String name) {
+ JsonElement value = JsonParser.parseString(args.toString()).getAsJsonObject().get(name);
+ if (value == null || !value.isJsonPrimitive() || !value.getAsJsonPrimitive().isString())
+ throw new IllegalArgumentException(name + " must be a string");
+ return value.getAsString();
+ }
+
+ private static int integer(JsonObject args, String name, int fallback) {
+ JsonElement value = JsonParser.parseString(args.toString()).getAsJsonObject().get(name);
+ if (value == null) return fallback;
+ if (!value.isJsonPrimitive() || !value.getAsJsonPrimitive().isNumber())
+ throw new IllegalArgumentException(name + " must be a nonnegative integer");
+ try {
+ int result = value.getAsBigDecimal().intValueExact();
+ if (result < 0) throw new ArithmeticException();
+ return result;
+ } catch (ArithmeticException error) {
+ throw new IllegalArgumentException(name + " must be a nonnegative integer", error);
+ }
+ }
+
+ private JadxSession session() {
+ JadxSession current = holder.current();
+ if (current == null) throw new IllegalArgumentException("No APK loaded");
+ return current;
+ }
+
+ private ClassSnapshot selected(JsonObject args) {
+ JadxSession current = session();
+ if (indexedSession != current) {
+ Map> index = new LinkedHashMap<>();
+ if (!current.getClasses().isEmpty()) {
+ JadxDecompiler decompiler = current.getClasses().get(0).getClassNode().root().getDecompiler();
+ // JavaClass.getMethods/getFields/getInnerClasses all load code. Raw nodes do not.
+ // Snapshot every identity before code generation can rewrite aliases or members.
+ for (JavaClass cls : decompiler.getClassesWithInners()) {
+ ClassNode node = cls.getClassNode();
+ List ordered = new ArrayList<>(node.getMethods());
+ ordered.sort(Comparator.comparing(MethodNode::getAlias));
+ List methods = ordered.stream().map(method -> {
+ String name = method.getAlias();
+ String signature = name + "(" + method.getArgTypes().stream()
+ .map(Object::toString).collect(Collectors.joining(", "))
+ + "): " + method.getReturnType().toString();
+ return new MethodSnapshot(name, method.getMethodInfo().getShortId(), Map.of(
+ "name", name, "signature", signature,
+ "is_constructor", method.isConstructor(), "def_pos", 0));
+ }).toList();
+ List