dsh-plugin-rea 1.0.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,255 +2,255 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/dsh-plugin-rea?style=flat-square&color=cb3837)](https://www.npmjs.com/package/dsh-plugin-rea)
4
4
 
5
- 把 **[REA — Reverse Engineer Anything](https://github.com/morluto/rea)** 接入 **DeepSeek Harness (dsh)**:
6
- 一个**纯配置型 Cordis bundle**,复用官方 MCP 客户端插件 `@deepseek-ai/dsh-mcp-client`,
7
- 把本机已安装的 `rea mcp`(stdio)注册成原生工具。装载后模型直接拥有 `mcp__rea__*` 工具。
8
-
9
- > **与上游的关系(重要)**
10
- > 本仓库是**第三方适配封装,不是 REA 项目的组成部分**,也不包含 REA 的任何源码,
11
- > 更不由 REA 作者维护。它只做一件事:向 dsh 的配置组合里插入一条指向你本机 `rea` 安装的 MCP 服务器记录。
12
- > - 上游项目:**REA — Reverse Engineer Anything** — <https://github.com/morluto/rea>(MIT)
13
- > - 上游文档:<https://github.com/morluto/rea#what-you-can-analyze> · [中文](https://github.com/morluto/rea/blob/main/README_zh.md#可以分析什么) · 站点 <https://rea.tools/>
14
- > - 上游 npm 包:`rea-agents`
15
- > - 本插件仓库:**<https://github.com/czcdr/dsh-plugin-rea>** · npm:`dsh-plugin-rea`
16
- > - 问题反馈:REA 本身的问题请提到上游;本插件的问题提到 [本仓库 Issues](https://github.com/czcdr/dsh-plugin-rea/issues)。
17
-
18
- ---
19
-
20
- ![dsh-plugin-rea:会话经官方 MCP 客户端行调用本机 rea mcp,再把 Evidence 带回会话](assets/screenshot-1.png)
21
-
22
- ## English
23
-
24
- **What it does.** This plugin performs **no reverse engineering itself**. It connects the upstream REA
25
- MCP server to DeepSeek Harness, so the tools REA ships become callable in a session as
26
- `mcp__rea__*`.
27
-
28
- In upstream's own words, REA is *"one MCP for reverse engineering across binaries, applications, and
29
- runtime behavior"* — *"see a feature you like. Understand how it works, down to the binary level."* It
30
- *connects your agent to tools for inspecting native binaries, JavaScript and Electron apps, .NET
31
- assemblies, and websites*; analysis runs locally, and results include the evidence and limitations
32
- behind each conclusion. Native analysis can use an existing Hopper, Ghidra, or IDA installation, and
33
- static JavaScript analysis needs no native engine.
34
-
35
- Upstream's own coverage list (`README.md#what-you-can-analyze`): native binaries — pseudocode,
36
- assembly, strings, symbols, calls and references; JavaScript/Electron apps — modules, imports, source
37
- maps, routes, IPC; websites — page structure, scripts, network observations, screenshots; .NET
38
- assemblies; Android APKs; Android devices over adb; JEB projects; Android resources; firmware;
39
- packages and assets; process behavior; plus offline ELF layout, EVM bytecode, recorded Linux crashes
40
- and saved network captures.
41
-
42
- **What this plugin adds.** Exactly two things: it registers that MCP server into DSH's tool layer
43
- under the `mcp__rea__*` names, and it lets the engine environment (`GHIDRA_INSTALL_DIR`, …) be scoped
44
- to that MCP child process instead of the whole harness.
45
-
46
- **What it can and cannot do.** The analysis is upstream's; this section only restates upstream's own
47
- contract so expectations are right.
5
+ **English** · [简体中文](README.zh-CN.md)
6
+
7
+ Brings the upstream **[REA — Reverse Engineer Anything](https://github.com/morluto/rea)** MCP server into
8
+ **DeepSeek Harness** (dsh), so its tools show up in a session as `mcp__rea__*`.
9
+
10
+ ![dsh-plugin-rea: the session calls the official MCP client row, which launches the bundle's shim; the shim starts the provisioned REA and the Evidence comes back](assets/screenshot-1.png)
11
+
12
+ > **This is the 2.x line, and `main` is it.** The all-in-one variant: it provisions the runtime (Node, the REA
13
+ > CLI, a JDK, Ghidra) and then wires the row itself. The original configuration-only adapter — 1.x, which
14
+ > assumed you had installed Node, `rea-agents` and Ghidra yourself — is preserved on the
15
+ > [`v1` branch](https://github.com/czcdr/dsh-plugin-rea/tree/v1) and on npm as `dsh-plugin-rea@1.0.6`.
16
+ > The two lines are compared in [Two lines: 1.x and 2.x](#two-lines-1x-and-2x).
17
+
18
+ ## What this is
19
+
20
+ A **Cordis bundle with a provisioning layer**. `package.json` declares `dsh.bundle.patch`, and that patch
21
+ inserts one row of the official MCP client plugin (`@deepseek-ai/dsh-mcp-client`). The row launches
22
+ `bin/rea-shim.mjs` with the running Node executable; the shim reads the machine-local state that
23
+ `scripts/setup.mjs` wrote and starts the REA CLI it provisioned. There is no analysis code here, and the
24
+ published patch contains no machine path.
25
+
26
+ > **Third-party adapter.** This repository is not part of REA, ships none of REA's code, and is not
27
+ > maintained by REA's authors. It composes one configuration row and fetches upstream's own releases.
28
+ > Upstream: [github.com/morluto/rea](https://github.com/morluto/rea) (MIT) ·
29
+ > [docs](https://github.com/morluto/rea#what-you-can-analyze) ·
30
+ > [rea.tools](https://rea.tools/) · npm package `rea-agents`.
31
+ > REA's own problems go to its tracker; **this plugin's** problems go to
32
+ > [this repository's issues](https://github.com/czcdr/dsh-plugin-rea/issues).
33
+
34
+ **It adds exactly three things:** the tool registration under the `mcp__rea__*` names, the per-machine
35
+ engine environment (`GHIDRA_INSTALL_DIR`, `JAVA_HOME`, `REA_ADB_PATH`, `REA_APKTOOL_COMMAND`,
36
+ `REA_JADX_MCP_JAR`, `REA_BROWSER_EXECUTABLE`, …) scoped to that MCP child instead of the whole harness, and
37
+ the provisioning that puts those components on disk.
38
+
39
+ ## What it can and cannot do
40
+
41
+ The analysis is upstream's; this section only restates upstream's own contract so expectations are right.
48
42
 
49
43
  - **It cannot recover complete source code.** For native binaries upstream returns *pseudocode and
50
- assembly*, for Android APKs *decompiled methods*, for JEB units *pseudocode*, and for
51
- JavaScript/Electron *modules and their relations*. Upstream's tool contract states the pseudocode
52
- "is decompiler output, not original source and not text-equivalent" to another provider's output.
53
- - Not recoverable in practice: original identifier names, types, comments, macros and template
54
- expansion, build scripts and assets. Optimisation (inlining, reordering), symbol stripping,
55
- obfuscation, packing and VM protection only make the output worse.
56
- - Every result carries **confidence and limitations** (`observed` / `derived` / `inferred`, plus an
57
- explicit limitations list). Read them as evidence, never as recovered source.
44
+ assembly*, for Android APKs *decompiled methods*, for JEB units *pseudocode*, and for JavaScript/Electron
45
+ *modules and their relations*. Upstream's tool contract states the pseudocode "is decompiler output, not
46
+ original source and not text-equivalent" to another provider's output.
47
+ - Not recoverable in practice: original identifier names, types, comments, macros and template expansion,
48
+ build scripts and assets. Optimisation (inlining, reordering), symbol stripping, obfuscation, packing and
49
+ VM protection only make the output worse.
50
+ - Every result carries **confidence and limitations** (`observed` / `derived` / `inferred`, plus an explicit
51
+ limitations list). Read them as evidence, never as recovered source.
58
52
  - Good for: understanding behaviour, locating an implementation, interoperability and compatible
59
- re-implementation, security review, migration reference. To obtain actual source code, use the
60
- legitimate route — the upstream repository, vendor authorisation, or the vendor's own SDK.
53
+ re-implementation, security review, migration reference. To obtain actual source code, use the legitimate
54
+ route — the upstream repository, vendor authorisation, or the vendor's own SDK.
61
55
 
62
- **Verified against** (author's machine, 2026-10-12/13):
56
+ **What provisioning cannot buy you.** These are upstream host gates, not settings this plugin forgot:
63
57
 
64
- | Component | Version |
58
+ | Capability | Gate |
65
59
  |---|---|
66
- | REA (`rea-agents`) | **6.4.0** |
67
- | DeepSeek Harness | desktop runtime **0.2.0-rc.2**, with its bundled dsh CLI 0.1.7-rc.2 |
68
- | `@deepseek-ai/dsh-mcp-client` (row provider) | bundled by the harness; npm latest `0.0.1-rc.1` |
69
- | Ghidra | 12.1.4 (REA currently accepts 12.1.x) |
70
- | Node.js | 24.21.0 (REA engines: `^22.19.0 \|\| ^24.11.0 \|\| >=26.0.0`) |
71
- | Host | Windows 11 x64 |
60
+ | Hopper provider | macOS only |
61
+ | IDA provider | needs your own IDA and `REA_IDA_MCP_CONFIG`; REA never launches IDA |
62
+ | firmware `binwalk` / `unblob` | Linux only |
63
+ | Wakaru JS recovery, pwntools ELF/recorded-crash paths | Linux x64 only |
64
+ | pwndbg / gdb core context | Linux, macOS |
65
+ | native mitmproxy captures | Linux (`REA_MITMDUMP_COMMAND`); HAR needs no engine |
66
+ | Apple toolchain (Mach-O, plist, asset catalog, LLDB) | macOS only |
67
+ | `capture_process_scenario` | Linux/macOS PTY |
68
+ | apktool (Android resource decoding) | available only when `REA_APKTOOL_COMMAND` points at something Node can **execute directly**: upstream `execFile`s that command without a shell, and Windows cannot execute a `.bat`/`.cmd` that way (EINVAL). This bundle wires the official `apktool.bat` as upstream documents, so on Windows the launcher reports no version and the capability stays unavailable; JADX (a jar) is unaffected |
69
+
70
+ ## Two lines: 1.x and 2.x
71
+
72
+ | | **2.x** — this line, `main` | **1.x** — [`v1`](https://github.com/czcdr/dsh-plugin-rea/tree/v1) |
73
+ |---|---|---|
74
+ | What it is | the adapter **plus provisioning**: it prepares Node, the REA CLI, a JDK and Ghidra, then wires the row | configuration-only adapter: one MCP row pointing at a `rea` you installed yourself |
75
+ | What you need first | nothing for the runtime — provisioning fetches what is missing (with `--reuse` it adopts an existing Ghidra/JDK instead) | Node.js on REA's engines, `npm i -g rea-agents`, and Ghidra 12.1.x for native analysis |
76
+ | First run | run `scripts/setup.mjs` (or the bootstrap) once, then restart dsh | nothing to run |
77
+ | The row launches | the running Node executable plus `<DSH_HOME>/plugins/rea-bundle/bin/rea-shim.mjs`, which reads that machine's state | `cmd.exe /c rea mcp` on Windows, `rea mcp` on macOS/Linux |
78
+ | Machine state | `<DSH_HOME>/plugins/rea-bundle/` — `bundle.json`, `vendor/`, `cache/` | your own REA and Ghidra installs |
79
+ | Install | `dsh plugin --profile <profile> add dsh-plugin-rea` (npm `latest` ≥ 2.0.0) | `… add dsh-plugin-rea@1.0.6`, or `github:czcdr/dsh-plugin-rea#v1.0.6` |
80
+
81
+ Both lines ship the **same patch shape** — one `insert` row of `@deepseek-ai/dsh-mcp-client` — and offer the
82
+ same `mcp__rea__*` surface; they differ in who prepares the runtime. Moving from 1.x to 2.x takes two
83
+ commands: see [Upgrading from 1.x](#upgrading-from-1x).
84
+
85
+ ## Install
86
+
87
+ **Nothing to install first.** On a bare Windows x64 machine:
72
88
 
73
- The shipped row was exercised live: `list_documents` answered through the `cmd.exe` form, and
74
- `open_binary` completed with the `ghidra` provider while the engine directory came only from a
75
- profile-level override.
76
-
77
- **Prerequisites.** Node.js (a version REA accepts) and the REA CLI installed globally
78
- (`npm i -g rea-agents`). For native analysis, Ghidra 12.1.x (Hopper / IDA are alternatives under
79
- their own licences). Static JavaScript/Electron and .NET analysis need no engine.
89
+ ```
90
+ powershell -ExecutionPolicy Bypass -File scripts\rea-bundle-bootstrap.ps1 -Reuse
91
+ ```
80
92
 
81
- **Install.**
93
+ `-Reuse` adopts a Ghidra/JDK you already have; omit it to download both (about 775 MB from the official
94
+ releases, checksum-verified). Then install the plugin for your profile:
82
95
 
83
96
  ```
84
- dsh plugin --profile <profile> add github:czcdr/dsh-plugin-rea
85
- # or, from npm:
86
97
  dsh plugin --profile <profile> add dsh-plugin-rea
98
+ # or pin this release instead of tracking npm latest:
99
+ dsh plugin --profile <profile> add github:czcdr/dsh-plugin-rea#v2.0.0
87
100
  ```
88
101
 
89
- A prebuilt tarball is attached to [Releases](https://github.com/czcdr/dsh-plugin-rea/releases)
90
- (version-free asset name, so the link keeps resolving).
91
-
92
- **Configure — usually nothing.** The shipped row carries **no machine-specific path**:
102
+ > **On an Electron host (the DeepSeek Harness desktop app) the profile is owned by the application.**
103
+ > `dsh plugin --profile desktop …` is refused by the CLI (`profile "desktop" is managed exclusively by
104
+ > the Electron application`) — install or update through the in-app plugin manager instead. The CLI form
105
+ > above is for a profile you created yourself with the CLI under another name.
93
106
 
94
- - Windows: `command: cmd.exe`, `args: ['/c', 'rea', 'mcp']` — the npm shim is a `.cmd`, so a shell is
95
- required.
96
- - macOS/Linux: `command: rea`, `args: ['mcp']` — see
97
- [`examples/cordis.patch.posix.yml`](examples/cordis.patch.posix.yml).
107
+ If Node is already installed, you can skip the bootstrap and run provisioning directly:
98
108
 
99
- The only optional piece is the analysis engine. REA reads `GHIDRA_INSTALL_DIR` from its environment,
100
- so either:
109
+ ```
110
+ node scripts/setup.mjs --reuse # or --dry-run to see the plan first
111
+ ```
101
112
 
102
- 1. set it as an **OS-level environment variable** and (re)start the harness, or
103
- 2. pin it for the MCP child only — see
104
- [`examples/cordis.patch.with-env.yml`](examples/cordis.patch.with-env.yml).
113
+ Installing the plugin **first** also works, but it takes two steps. The row resolves to
114
+ `<DSH_HOME>/plugins/rea-bundle/bin/rea-shim.mjs`, and that file is created by setup — so until the first
115
+ provisioning run the row exits with `MODULE_NOT_FOUND`, and nothing is there to start a background
116
+ provisioning (the harness itself is unaffected: `failOnStartupError: false` is deliberate). Run
117
+ `node scripts/setup.mjs` once; from then on the shim is in place, and every later missing state is picked up
118
+ by the shim itself, which provisions in the background.
105
119
 
106
- Either way the variable reaches REA without any literal path: the client hands the parent
107
- environment to the child (minus names that look like secrets), and the patch dialect evaluates
108
- `!!js` expressions, so `GHIDRA_INSTALL_DIR: !!js process.env.GHIDRA_INSTALL_DIR` also works.
120
+ ## Configure — nothing
109
121
 
110
- **Keep machine-specific values out of the plugin.** Override the row from your own profile's
111
- `cordis.patch.yml` (id-targeted config override). That file is machine-local and never published:
122
+ The shipped row carries **no machine path**:
112
123
 
113
124
  ```yaml
114
- - id: mcp-rea
115
- config:
116
- env:
117
- GHIDRA_INSTALL_DIR: '<your Ghidra 12.1.x directory>'
125
+ - insert:
126
+ - id: mcp-rea
127
+ name: '@deepseek-ai/dsh-mcp-client'
128
+ config:
129
+ serverName: rea
130
+ transport: stdio
131
+ command: !!js process.execPath
132
+ args:
133
+ - !!js "(process.env.DSH_HOME && process.env.DSH_HOME.trim() !== '' ? process.env.DSH_HOME : (process.env.USERPROFILE || process.env.HOME || '') + '/.dsh') + '/plugins/rea-bundle/bin/rea-shim.mjs'"
134
+ - mcp
135
+ env:
136
+ ELECTRON_RUN_AS_NODE: '1'
137
+ failOnStartupError: false
118
138
  ```
119
139
 
120
- Only one row may use `serverName: rea` in a profile.
140
+ Three details in that row are load-bearing, and all three were bugs first:
121
141
 
122
- **Verify.** Ask for a `mcp__rea__*` call — `binary_session` reports the engine checks
123
- (`configuration` / `installation` / `headless` / `native_decompiler` / `java`), all of which should be
124
- `ok: true`. Then `open_binary` a PE, `binary_overview`, and `procedure_pseudo_code`.
142
+ - **The `!!js` scalar is quoted.** A bare scalar containing `? ` and `: ` is not one scalar: YAML reads it as an explicit key/value pair, so the loader receives a *mapping* where an expression belongs. Measured against the harness's own dialect (`JSON_SCHEMA` plus the `!!js` type from `app.asar`), the unquoted form made `args[0]` into `{"[object Object]": "..."}` — an object the row cannot launch with. Quoting removes the ambiguity, and the JS string literals inside then use single quotes.
143
+ - **Forward slashes, never backslashes.** A single-quoted YAML scalar keeps `\` literal, and JavaScript then consumes it: `'\plugins'` is not a path but the BEL control character, `'\rea-bundle'` becomes a carriage return and `'\bin'` a backspace — the path is destroyed silently. Forward slashes work on Windows and on POSIX.
144
+ - **The `DSH_HOME` fallback is `<home>/.dsh`, not `<home>`.** The shim, `setup.mjs` and `bootstrap.ps1` all resolve an unset `DSH_HOME` to `<home>/.dsh/...`; a fallback that stopped one level higher made the row point at a file provisioning never writes — invisible on any machine where `DSH_HOME` happens to be set.
145
+ - **No `path`/`require` in a `!!js` expression**: `ctx` is the loader scope, so the DSH_HOME fallback is written as plain concatenation.
146
+
147
+ `npm run bundle:audit` enforces the first three: it evaluates this exact expression with `DSH_HOME` unset, empty and set, and rejects a bare scalar that YAML would read as a mapping.
125
148
 
126
- **Scope and caveats.** REA exposes 170+ tools at 6.4.0, so every session's tool list grows; the row
127
- sets `failOnStartupError: false` so a missing REA never blocks harness startup. Some REA tools launch
128
- processes, write files and access the network — DSH's permission policy applies. Analyse only
129
- artifacts you are authorized to inspect.
130
-
131
- **Updating — two independent things, both manual.**
132
-
133
- - **This plugin** never updates itself. Installed from a plugin market? Update it **in that market**.
134
- Installed from a local `file:` checkout? Overwrite the directory and install it again. Updating REA
135
- below does **not** update this plugin, and updating this plugin does not touch REA.
136
- - **Upstream REA**: `npm i -g rea-agents@latest`. Its `bin` entry (`scripts/rea.mjs`) is stable across
137
- releases, so this needs no change here.
138
- - **Ghidra** is version-gated by REA (12.1.x today): update REA first, then check that it accepts a
139
- newer Ghidra.
140
- - **DeepSeek Harness**: a harness upgrade may change the MCP client's config schema — inspect the row
141
- with `Config.listConfigs name=@deepseek-ai/dsh-mcp-client` and adjust the field names.
142
-
143
- `check-updates.ps1` (Windows PowerShell) reports the state of all four at once, and
144
- `.github/workflows/validate.yml` enforces the bundle's shape — including "the shipped patch must not
145
- contain a machine-specific path" — in CI.
146
-
147
- **License.** MIT (this adapter). REA is MIT and owned by its authors; Ghidra is Apache-2.0 and owned
148
- by the NSA. No upstream code is redistributed here.
149
-
150
- ---
151
-
152
- ## 中文
153
-
154
- **作用。** 本插件**自身不做任何逆向分析**。它把上游 REA 的 MCP 服务接入 DeepSeek Harness,
155
- 让 REA 提供的那套工具在会话里变成可直接调用的 `mcp__rea__*`。
156
-
157
- 按上游自述,REA 是「**通过一个 MCP 服务,逆向分析二进制文件、应用程序和运行时行为**」——
158
- 「看到喜欢的功能,弄清它的工作原理,深入到二进制层面」。它「将智能体连接到分析工具,用于检查
159
- 原生二进制文件、JavaScript 和 Electron 应用、.NET 程序集以及网站」;分析在本机运行,结果包含
160
- 支撑各项结论的证据和相关限制。原生分析可以使用已有的 Hopper、Ghidra 或 IDA,静态 JavaScript 分析
161
- 不需要原生引擎。
162
-
163
- 上游列出的可分析目标(原文见 [README_zh.md#可以分析什么](https://github.com/morluto/rea/blob/main/README_zh.md#可以分析什么)):
164
- 原生二进制文件——伪代码、汇编、字符串、符号、调用和引用;JavaScript / Electron——模块、导入、
165
- source map、路由与 IPC;网站——页面结构、脚本、网络观察结果与截图;.NET 程序集;Android APK;
166
- Android 设备(adb);JEB 项目;Android 资源;固件;软件包与资源;进程行为;以及离线 ELF 布局、
167
- EVM 字节码、已记录的 Linux 崩溃与已保存的网络捕获。
168
-
169
- **本插件在此之上只增加两件事**:把该 MCP 服务注册进 DSH 的工具层(工具名 `mcp__rea__*`),
170
- 以及让引擎环境变量(`GHIDRA_INSTALL_DIR` 等)只作用于这个 MCP 子进程,而不是整个 harness。
171
-
172
- **能做什么、不能做什么(重要)。** 分析能力由上游提供;这里只复述上游自己的契约,避免预期错位。
173
-
174
- - **无法完整还原源代码。** 上游对原生二进制返回的是**伪代码与汇编**,对 Android APK 返回
175
- **反编译的方法**,对 JEB 单元返回**伪代码**,对 JavaScript/Electron 返回**模块及其关系**。
176
- 上游的工具契约明确写着:伪代码是反编译器输出,**不是原始源码**,且与其他提供方的输出
177
- **不保证文本等价**。
178
- - 实践中不可恢复的内容:原始标识符命名、类型、注释、宏与模板展开、构建脚本与资源;
179
- 优化(内联、指令重排)、去符号(strip)、混淆、加壳与 VM 保护只会让可读性更差。
180
- - 每条结论都自带**置信度与限制**(`observed` / `derived` / `inferred`,另有 limitations 列表):
181
- 请把它们当作证据使用,而不要当作"已还原的源码"。
182
- - 适合做:理解行为、定位实现、互操作与兼容实现、安全审计、迁移参考。
183
- **要拿到真正的源码,请走正规渠道**——上游代码仓库、厂商授权,或厂商自己的 SDK。
184
-
185
- **已验证版本**(作者机器,2026-10-12/13):REA `6.4.0`、DeepSeek Harness 桌面运行时 `0.2.0-rc.2`
186
- (自带 dsh CLI `0.1.7-rc.2`)、Ghidra `12.1.4`、Node `24.21.0`、Windows 11 x64。行提供方
187
- `@deepseek-ai/dsh-mcp-client` 由 harness 自带(npm 最新 `0.0.1-rc.1`)。发布用的这一行**实测跑通过**:
188
- `list_documents` 在 `cmd.exe` 形式下正常应答,`open_binary` 走 `ghidra` 提供方成功,
189
- 而引擎目录仅来自本机 profile 覆盖。
190
-
191
- **前置条件。** 满足 REA 要求的 Node;全局安装 REA(`npm i -g rea-agents`)。原生分析需要
192
- Ghidra 12.1.x(Hopper / IDA 为替代方案,各自需授权);静态 JavaScript/Electron 与 .NET 分析
193
- 不需要引擎。
194
-
195
- **安装。**
149
+ `ELECTRON_RUN_AS_NODE` only matters if the harness itself runs on Electron; it is harmless for a plain Node host, and stating it explicitly beats relying on it surviving the child-env scrub.
150
+
151
+ `command` is the running Node executable and `args[0]` is computed from `DSH_HOME`, so the same patch works
152
+ on Windows, macOS and Linux without a PATH entry. Everything machine-specific lives in
153
+ `<DSH_HOME>/plugins/rea-bundle/bundle.json`, written by setup and readable with:
196
154
 
197
155
  ```
198
- dsh plugin --profile <profile> add github:czcdr/dsh-plugin-rea
199
- # 或从 npm 安装:
200
- dsh plugin --profile <profile> add dsh-plugin-rea
156
+ node bin/rea-shim.mjs --shim-status # resolved paths, versions, verification state
157
+ node bin/rea-shim.mjs --shim-print-env # the environment the MCP child will see
201
158
  ```
202
159
 
203
- [Releases](https://github.com/czcdr/dsh-plugin-rea/releases) 附带预构建 tarball(资产名不带版本号,
204
- 链接不会失效)。
160
+ Both commands answer with the same bundle whether you run them from the plugin directory (the checkout copy)
161
+ or from `<DSH_HOME>/plugins/rea-bundle` (the mirrored copy): the checkout resolves the location by the same
162
+ rule setup uses, while the mirror uses its own position — it cannot rely on `DSH_HOME`, which the harness
163
+ strips from an MCP child's environment.
205
164
 
206
- **配置——通常什么都不用改。** 发布出去的那一行**不含任何机器相关路径**:
165
+ Setting `REA_BUNDLE_AUTO_PROVISION=0` disables the first-run background provisioning.
207
166
 
208
- - Windows:`command: cmd.exe`、`args: ['/c', 'rea', 'mcp']` —— npm 的 shim 是 `.cmd`,必须经 shell。
209
- - macOS/Linux:`command: rea`、`args: ['mcp']` —— 见
210
- [`examples/cordis.patch.posix.yml`](examples/cordis.patch.posix.yml)。
167
+ To pin a different launch command on this machine (for example your own globally installed `rea`), override
168
+ the row from the profile's own `cordis.patch.yml` — that file is machine-local and never published. Only one
169
+ row may use `serverName: rea` in a profile.
211
170
 
212
- 唯一可选的是分析引擎。REA 从环境读取 `GHIDRA_INSTALL_DIR`,二选一:
171
+ ## Verify
213
172
 
214
- 1. 设为**系统级环境变量**,然后重启 harness(让 MCP 子进程继承);
215
- 2. 只为这个 MCP 子进程指定 —— 见
216
- [`examples/cordis.patch.with-env.yml`](examples/cordis.patch.with-env.yml)。
173
+ Ask for a `mcp__rea__*` call — `binary_session` reports the engine checks
174
+ (`configuration` / `installation` / `headless` / `native_decompiler` / `java`), all of which should be
175
+ `ok: true`. Then `open_binary` a PE, `binary_overview`, and `procedure_pseudo_code`.
217
176
 
218
- 两种方式都不需要在插件里写死路径:客户端会把父进程环境传给子进程(只剔除名字像密钥的变量),
219
- 而补丁方言支持 `!!js` 表达式,所以 `GHIDRA_INSTALL_DIR: !!js process.env.GHIDRA_INSTALL_DIR`
220
- 同样可用。
177
+ Provisioning itself ends with two probes: `rea doctor --json` (reported, with unmet checks named) and the
178
+ exact shim launch the MCP row will use.
221
179
 
222
- **机器相关值不要写进插件。** 用你自己的 profile `cordis.patch.yml` **按 id 覆盖**这一行即可;
223
- 该文件只在你本机、永不随插件发布:
180
+ ## Verified against
224
181
 
225
- ```yaml
226
- - id: mcp-rea
227
- config:
228
- env:
229
- GHIDRA_INSTALL_DIR: '<你的 Ghidra 12.1.x 目录>'
230
- ```
182
+ Author's machine, 2026-10-13 / 14:
231
183
 
232
- 同一 profile 内 `serverName: rea` 只能有一条记录。
184
+ | Component | Version |
185
+ |---|---|
186
+ | REA (`rea-agents`) | **6.4.0** (170 tools) |
187
+ | DeepSeek Harness | desktop runtime **0.2.0-rc.2**, with its bundled dsh CLI 0.1.7-rc.2 |
188
+ | `@deepseek-ai/dsh-mcp-client` (row provider) | bundled by the harness |
189
+ | Ghidra | 12.1.4 |
190
+ | JDK | Temurin 21 (provisioned) / Microsoft OpenJDK 25.0.4 (adopted) |
191
+ | Node.js | 24.21.0 (REA engines: `^22.19.0 \|\| ^24.11.0 \|\| >=26.0.0`) |
192
+ | Host | Windows 11 x64 (build 26200) |
193
+
194
+ Exercised live: a clean `setup.mjs --reuse` run reached `setup complete`; an MCP `initialize` handshake
195
+ **through the shim with no `rea` on PATH** answered `serverInfo {name: rea, version: 6.4.0}`; and the whole
196
+ chain ran under the real desktop host — its own Electron binary launched
197
+ `<DSH_HOME>/plugins/rea-bundle/bin/rea-shim.mjs mcp`, the shim started the **vendored** REA, and a live tool
198
+ call reported `path_source: environment` for a path only that machine's `bundle.json` knows.
233
199
 
234
- **验证。** 调用任一 `mcp__rea__*` 工具:`binary_session` 会给出引擎检查项
235
- (configuration / installation / headless / native_decompiler / java),应全部 `ok: true`;
236
- 随后 `open_binary` 打开一个 PE → `binary_overview` → `procedure_pseudo_code`。
200
+ Not exercised end to end here, and therefore not claimed: the ~775 MB JDK + Ghidra download branch (planned
201
+ by `--dry-run`, but this machine adopted its existing installs with `--reuse`), and first runs on
202
+ macOS/Linux.
237
203
 
238
- **范围与注意。** REA 在 6.4.0 暴露 170+ 个工具,注入后每个会话的工具列表都会变大;行内设置
239
- `failOnStartupError: false`,因此 REA 缺失也不会阻塞 harness 启动。部分 REA 工具会启动进程、
240
- 写文件、访问网络,按 DSH 的权限策略执行。请仅分析你已获得授权的目标。
204
+ ## Scope and caveats
241
205
 
242
- **更新:两件事,且都要手动。**
206
+ - REA exposes 170 tools at 6.4.0, so every session's tool list grows.
207
+ - Provisioning is honest about checksums: where a vendor publishes one it is pinned and verified; where none
208
+ exists (jadx-headless-mcp, the apktool wrapper, Android platform-tools, the rolling "latest" URLs) the
209
+ hash is **measured once and recorded**, and later drift is reported rather than silently accepted.
210
+ `bundle.json` lists which components are in that state under `unverifiedChecksums`.
211
+ - Downloads are slow on some networks (measured 0.35–0.54 MiB/s from the GitHub release CDN here, so Ghidra
212
+ alone takes ~25–45 min). Fetching is resumable: the cache is kept and re-verified, and a killed run
213
+ continues instead of restarting.
214
+ - Some REA tools launch processes, write files and access the network — DSH's permission policy applies.
215
+ Analyse only artifacts you are authorized to inspect.
216
+ - `scripts/setup.mjs` runs `npm install` for the REA CLI with `--ignore-scripts`: the published tarball
217
+ carries no `node_modules`, so a dependency closure must be resolved, and package lifecycle scripts are
218
+ skipped on purpose during provisioning.
243
219
 
244
- - **本插件**不会自动更新。**从插件市场安装的,就在市场里更新**;本地 `file:` 目录方式安装的,
245
- 覆盖目录后在插件管理器里重装。下面更新 REA **不会**更新本插件,反过来也一样。
246
- - **上游 REA**:用 `npm i -g rea-agents@latest` 更新。它的 `bin` 入口(`scripts/rea.mjs`)
247
- 跨版本稳定,所以本插件无需改动。
248
- - **Ghidra**:受 REA 版本门槛限制(当前 12.1.x),先升 REA,再确认它接受新版 Ghidra。
249
- - **DeepSeek Harness**:升级可能改变 MCP 客户端配置结构,用
250
- `Config.listConfigs name=@deepseek-ai/dsh-mcp-client` 看该行 schema 并调整字段名。
220
+ ## Updating — three independent things
251
221
 
252
- `check-updates.ps1`(Windows PowerShell)会把上述四项一次跑完;
253
- `.github/workflows/validate.yml` 在 CI 里守住 bundle 的形状(含「发布物不得含机器路径」这一条)。
222
+ ### Upgrading from 1.x
223
+
224
+ Install 2.x, then run provisioning **once** before restarting dsh:
225
+
226
+ ```
227
+ node scripts/setup.mjs # or: powershell -File scripts\rea-bundle-bootstrap.ps1 -Reuse
228
+ ```
254
229
 
255
- **许可。** 本适配器为 MIT;REA 为 MIT,版权归其作者;Ghidra 为 Apache-2.0,版权归 NSA。
256
- 本仓库不再分发上游代码。
230
+ Why it matters: the 1.x row launched `rea mcp` from PATH, while the 2.x row launches
231
+ `<DSH_HOME>/plugins/rea-bundle/bin/rea-shim.mjs` — a file only `setup.mjs` creates. Upgrade and restart
232
+ without provisioning and that row exits with `MODULE_NOT_FOUND`: the harness stays up
233
+ (`failOnStartupError: false` is deliberate), but the `mcp__rea__*` tools are gone and you get **no
234
+ remediation message**, because the shim that prints one does not exist yet. After the setup run they are
235
+ back on the next start.
236
+
237
+ - **This plugin** never updates itself. Installed from a market? Update it there. Installed from a `file:`
238
+ checkout? Overwrite the directory and reinstall.
239
+ - **Upgrading from `2.0.0-bundle.1`**: that release mirrored the shim and `setup.mjs` but not the manifest,
240
+ and recorded nothing about the plugin checkout, so a bundle it provisioned cannot repair itself — its
241
+ background provisioning dies on the missing manifest, invisibly, and its own lock suppresses retries for
242
+ six hours. Re-run `node scripts/setup.mjs` **from the plugin directory** once; it re-mirrors all three
243
+ files and writes the record that lets later runs find the checkout. `check-updates.ps1` reports this state.
244
+ - **Provisioned components**: re-run `node scripts/setup.mjs`; it re-verifies what is on disk and only
245
+ fetches what is missing or wrong. Pins live in `manifest/bundle.manifest.json`.
246
+ - **Upstream REA / Ghidra**: update the pins in the manifest, then re-run setup. REA version-gates Ghidra
247
+ (12.1.x today), so update REA first.
248
+
249
+ `check-updates.ps1` (Windows PowerShell) reports the state of all of these at once.
250
+
251
+ ## License
252
+
253
+ MIT (this adapter). REA is MIT and owned by its authors; Ghidra is Apache-2.0 and owned by the NSA; Temurin
254
+ is GPLv2+CE; Node.js is MIT; apktool, jadx-headless-mcp and Android platform-tools keep their own licences.
255
+ **No upstream code or binary is redistributed in this package** — provisioning fetches each component from
256
+ its official source.