@trenchwork/erosolar 1.1.36 → 1.1.38
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 +219 -170
- package/SECURITY.md +28 -6
- package/agents/engagement-delivery.rules.json +7 -0
- package/agents/variant-research.rules.json +7 -0
- package/dist/bin/erosolar.js +192 -85
- package/dist/bin/erosolar.js.map +1 -1
- package/dist/capabilities/_opsContext.d.ts +65 -1
- package/dist/capabilities/_opsContext.d.ts.map +1 -1
- package/dist/capabilities/_opsContext.js +43 -0
- package/dist/capabilities/_opsContext.js.map +1 -1
- package/dist/capabilities/heliaCapability.d.ts +15 -0
- package/dist/capabilities/heliaCapability.d.ts.map +1 -0
- package/dist/capabilities/heliaCapability.js +34 -0
- package/dist/capabilities/heliaCapability.js.map +1 -0
- package/dist/capabilities/index.d.ts +1 -0
- package/dist/capabilities/index.d.ts.map +1 -1
- package/dist/capabilities/index.js +1 -0
- package/dist/capabilities/index.js.map +1 -1
- package/dist/capabilities/llmRedteamCapability.d.ts.map +1 -1
- package/dist/capabilities/llmRedteamCapability.js +47 -0
- package/dist/capabilities/llmRedteamCapability.js.map +1 -1
- package/dist/core/artifactLog.d.ts +82 -0
- package/dist/core/artifactLog.d.ts.map +1 -0
- package/dist/core/artifactLog.js +224 -0
- package/dist/core/artifactLog.js.map +1 -0
- package/dist/core/artifactStore.d.ts +17 -0
- package/dist/core/artifactStore.d.ts.map +1 -1
- package/dist/core/artifactStore.js +22 -0
- package/dist/core/artifactStore.js.map +1 -1
- package/dist/core/cliTriggerHandlers.d.ts +15 -0
- package/dist/core/cliTriggerHandlers.d.ts.map +1 -0
- package/dist/core/cliTriggerHandlers.js +60 -0
- package/dist/core/cliTriggerHandlers.js.map +1 -0
- package/dist/core/hitl.d.ts +4 -1
- package/dist/core/hitl.d.ts.map +1 -1
- package/dist/core/hitl.js +60 -171
- package/dist/core/hitl.js.map +1 -1
- package/dist/core/portalPresence.d.ts +74 -0
- package/dist/core/portalPresence.d.ts.map +1 -0
- package/dist/core/portalPresence.js +187 -0
- package/dist/core/portalPresence.js.map +1 -0
- package/dist/core/updateChecker.d.ts.map +1 -1
- package/dist/core/updateChecker.js +8 -6
- package/dist/core/updateChecker.js.map +1 -1
- package/dist/headless/interactiveShell.js +23 -0
- package/dist/headless/interactiveShell.js.map +1 -1
- package/dist/plugins/tools/mcp/mcpClient.js +1 -1
- package/dist/plugins/tools/mcp/mcpClient.js.map +1 -1
- package/dist/runtime/node.d.ts.map +1 -1
- package/dist/runtime/node.js +2 -2
- package/dist/runtime/node.js.map +1 -1
- package/dist/runtime/phaseEmitter.d.ts +6 -0
- package/dist/runtime/phaseEmitter.d.ts.map +1 -1
- package/dist/runtime/phaseEmitter.js +0 -0
- package/dist/runtime/phaseEmitter.js.map +1 -1
- package/dist/tools/engagementTools.d.ts.map +1 -1
- package/dist/tools/engagementTools.js +73 -1
- package/dist/tools/engagementTools.js.map +1 -1
- package/dist/tools/heliaControl.d.ts +17 -0
- package/dist/tools/heliaControl.d.ts.map +1 -1
- package/dist/tools/heliaControl.js +108 -2
- package/dist/tools/heliaControl.js.map +1 -1
- package/dist/tools/heliaTools.d.ts +22 -0
- package/dist/tools/heliaTools.d.ts.map +1 -0
- package/dist/tools/heliaTools.js +125 -0
- package/dist/tools/heliaTools.js.map +1 -0
- package/dist/tools/interactionTools.d.ts.map +1 -1
- package/dist/tools/interactionTools.js +31 -15
- package/dist/tools/interactionTools.js.map +1 -1
- package/dist/tools/scheduleTools.d.ts.map +1 -1
- package/dist/tools/scheduleTools.js +5 -2
- package/dist/tools/scheduleTools.js.map +1 -1
- package/dist/tools/webTools.js +1 -1
- package/dist/tools/webTools.js.map +1 -1
- package/dist/ui/ink/AskUserMenu.d.ts +16 -0
- package/dist/ui/ink/AskUserMenu.d.ts.map +1 -0
- package/dist/ui/ink/AskUserMenu.js +85 -0
- package/dist/ui/ink/AskUserMenu.js.map +1 -0
- package/dist/ui/ink/HitlDecisionMenu.d.ts +23 -0
- package/dist/ui/ink/HitlDecisionMenu.d.ts.map +1 -0
- package/dist/ui/ink/HitlDecisionMenu.js +124 -0
- package/dist/ui/ink/HitlDecisionMenu.js.map +1 -0
- package/dist/ui/ink/oneShot.d.ts +33 -0
- package/dist/ui/ink/oneShot.d.ts.map +1 -0
- package/dist/ui/ink/oneShot.js +70 -0
- package/dist/ui/ink/oneShot.js.map +1 -0
- package/dist/utils/heliaClient.d.ts +23 -0
- package/dist/utils/heliaClient.d.ts.map +1 -0
- package/dist/utils/heliaClient.js +79 -0
- package/dist/utils/heliaClient.js.map +1 -0
- package/dist/utils/lambdaClient.d.ts.map +1 -1
- package/dist/utils/lambdaClient.js +9 -0
- package/dist/utils/lambdaClient.js.map +1 -1
- package/dist/utils/statusReporter.d.ts +13 -0
- package/dist/utils/statusReporter.d.ts.map +1 -1
- package/dist/utils/statusReporter.js +26 -0
- package/dist/utils/statusReporter.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -3,17 +3,19 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@trenchwork/erosolar)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
|
|
6
|
-
A multi-provider terminal agent for coding work and authorized
|
|
7
|
-
security research. Default backend is DeepSeek-V4-Pro
|
|
8
|
-
key gated by Erosolar Auth
|
|
9
|
-
Anthropic / OpenAI / Google / xAI / Qwen / Ollama
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
A multi-provider terminal agent for coding work and authorized
|
|
7
|
+
offensive-security research. Default backend is **DeepSeek-V4-Pro**
|
|
8
|
+
via a shared key gated by Erosolar Auth (no key bundled in the npm
|
|
9
|
+
tarball); Anthropic / OpenAI / Google / xAI / Qwen / Ollama are opt-in
|
|
10
|
+
providers with bring-your-own keys.
|
|
11
|
+
|
|
12
|
+
This README documents the **current shipped state** of the CLI — the
|
|
13
|
+
auth-gated boot, profiles, capability surface, MCP integration,
|
|
14
|
+
artifact store, and operational knobs. Examples, "try asking…" hints,
|
|
15
|
+
and onboarding fluff are deliberately absent ([CLAUDE.md](CLAUDE.md)
|
|
16
|
+
is strict about that). Deep technical reference lives in
|
|
17
|
+
[`docs/ENGINEERING.md`](docs/ENGINEERING.md); security model and
|
|
18
|
+
threat boundaries live in [`SECURITY.md`](SECURITY.md).
|
|
17
19
|
|
|
18
20
|
---
|
|
19
21
|
|
|
@@ -23,12 +25,12 @@ toward the end cover architecture and contribution. Examples,
|
|
|
23
25
|
npm install -g @trenchwork/erosolar
|
|
24
26
|
```
|
|
25
27
|
|
|
26
|
-
Two
|
|
28
|
+
Two binaries land on `$PATH` and point at the same entry:
|
|
27
29
|
|
|
28
30
|
- `erosolar` — preferred
|
|
29
31
|
- `trenchwork` — alternate name
|
|
30
32
|
|
|
31
|
-
Node ≥ 20 required
|
|
33
|
+
Node ≥ 20 required.
|
|
32
34
|
|
|
33
35
|
### First-run boot
|
|
34
36
|
|
|
@@ -38,64 +40,47 @@ erosolar
|
|
|
38
40
|
|
|
39
41
|
On first launch the CLI:
|
|
40
42
|
|
|
41
|
-
1.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
page and at the Firestore-rule layer
|
|
43
|
+
1. Opens a browser tab to `https://ero.solar/auth?port=…`. Sign in with
|
|
44
|
+
**Google SSO** (Firebase Auth, project `erosolar-1b0db`). SSO is
|
|
45
|
+
enforced both at the auth page and at the Firestore rule layer
|
|
45
46
|
(`request.auth.token.firebase.sign_in_provider == 'google.com'`).
|
|
46
47
|
2. Stores a Firebase ID token + refresh token at `~/.erosolar/auth.json`
|
|
47
|
-
(`0o600`). The refresh token is long-lived; the ID token
|
|
48
|
-
|
|
48
|
+
(`0o600`). The refresh token is long-lived; the ID token rotates
|
|
49
|
+
automatically before expiry.
|
|
49
50
|
3. **Approval gate.** The CLI checks `approved_users/{your-email}` in
|
|
50
|
-
Firestore. The package ships offsec capabilities (Kali tools
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
is approved.
|
|
51
|
+
Firestore. The package ships offsec capabilities (Kali tools, AFL++,
|
|
52
|
+
gdb, pwntools, Ghidra), so only allowlisted emails can launch. If
|
|
53
|
+
your email isn't approved, the CLI writes a pending request to
|
|
54
|
+
`approval_requests/{uid}` and exits with a clear message — re-run
|
|
55
|
+
once the operator approves.
|
|
56
56
|
4. Fetches the shared DeepSeek API key from Firestore at
|
|
57
|
-
`shared_secrets/deepseek` and writes it into
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
5. Starts the interactive Ink-based shell.
|
|
57
|
+
`shared_secrets/deepseek` and writes it into the process env for the
|
|
58
|
+
duration of the run. **Nothing lands on disk.** Reads are gated to
|
|
59
|
+
authenticated + approved users; writes are admin-only.
|
|
60
|
+
5. Starts the Ink-based interactive shell.
|
|
62
61
|
|
|
63
62
|
### Requesting approval
|
|
64
63
|
|
|
65
|
-
Sign in once via Google SSO. The CLI
|
|
66
|
-
|
|
67
|
-
`approval_requests/{uid}`. The operator reviews the queue and
|
|
68
|
-
adds your email via:
|
|
64
|
+
Sign in once via Google SSO. The CLI files a pending request at
|
|
65
|
+
`approval_requests/{uid}`. The operator reviews and approves with:
|
|
69
66
|
|
|
70
67
|
```sh
|
|
71
68
|
node scripts/approve-user.mjs <your-email>
|
|
72
69
|
```
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
### Approval gate — admin operations
|
|
77
|
-
|
|
78
|
-
Adding a user (uses the Firebase CLI's stored OAuth token; bypasses
|
|
79
|
-
Firestore rules via owner privileges):
|
|
80
|
-
|
|
81
|
-
```sh
|
|
82
|
-
node scripts/approve-user.mjs alice@example.com
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Inspecting pending requests via Firebase Console:
|
|
86
|
-
[Firestore → `approval_requests`](https://console.firebase.google.com/project/erosolar-1b0db/firestore/data/~2Fapproval_requests)
|
|
71
|
+
Re-run `erosolar` after approval is confirmed.
|
|
87
72
|
|
|
88
73
|
### Bring-your-own key
|
|
89
74
|
|
|
90
|
-
If
|
|
91
|
-
|
|
75
|
+
If `DEEPSEEK_API_KEY` is set in env, the Firestore fetch is skipped.
|
|
76
|
+
Resolution order:
|
|
92
77
|
|
|
93
78
|
1. `process.env.DEEPSEEK_API_KEY` (env override always wins)
|
|
94
|
-
2. `~/.erosolar/secrets.json` (set in-CLI via `/key sk-…` or `/secrets`)
|
|
79
|
+
2. `~/.erosolar/secrets.json` (set in-CLI via `/key sk-…` or `/secrets set`)
|
|
95
80
|
3. Firestore `shared_secrets/deepseek` (the post-login fallback)
|
|
96
81
|
|
|
97
|
-
|
|
98
|
-
shared-secrets module
|
|
82
|
+
The same chain applies to `TAVILY_API_KEY` and any provider key the
|
|
83
|
+
shared-secrets module recognises.
|
|
99
84
|
|
|
100
85
|
### Modes
|
|
101
86
|
|
|
@@ -103,7 +88,7 @@ shared-secrets module knows about.
|
|
|
103
88
|
erosolar # interactive
|
|
104
89
|
erosolar -q "explain X" # one-shot, prints answer, exits
|
|
105
90
|
git diff | erosolar # pipe mode — stdin becomes the prompt
|
|
106
|
-
erosolar --profile variant-research "<goal>"
|
|
91
|
+
erosolar --profile variant-research "<goal>"
|
|
107
92
|
erosolar --self-test # provider/auth/capability smoke test
|
|
108
93
|
```
|
|
109
94
|
|
|
@@ -111,45 +96,62 @@ erosolar --self-test # provider/auth/capability smoke test
|
|
|
111
96
|
|
|
112
97
|
## Profiles
|
|
113
98
|
|
|
114
|
-
A **profile** binds a system prompt template, default model
|
|
115
|
-
and a [rulebook](#rulebooks) (a phase-structured guidance document
|
|
116
|
-
|
|
99
|
+
A **profile** binds a system prompt template, default model + provider,
|
|
100
|
+
and a [rulebook](#rulebooks) (a phase-structured guidance document
|
|
101
|
+
inlined into the system prompt). Switch via `--profile <name>` or the
|
|
102
|
+
`EROSOLAR_PROFILE` environment variable. Three profiles ship:
|
|
117
103
|
|
|
118
104
|
### `erosolar-code` (default)
|
|
119
105
|
|
|
120
|
-
General-purpose terminal agent for coding
|
|
121
|
-
`deepseek-v4-pro`, default provider
|
|
122
|
-
inventory
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
HITL, plus any MCP servers you declare in `mcp.json`. Rulebook at
|
|
106
|
+
General-purpose terminal agent for coding, builds, tests, sysadmin,
|
|
107
|
+
package management. Default model `deepseek-v4-pro`, default provider
|
|
108
|
+
`deepseek`. Coding tool inventory only — the offsec capabilities are
|
|
109
|
+
withheld so the model's tool list isn't padded with sqlmap / ROP-search
|
|
110
|
+
in normal sessions. Rulebook:
|
|
126
111
|
[`agents/erosolar-code.rules.json`](agents/erosolar-code.rules.json).
|
|
127
112
|
|
|
128
113
|
### `variant-research`
|
|
129
114
|
|
|
130
115
|
Authorized offsec / vulnerability-research surface. Walks the standard
|
|
131
116
|
n-day-to-0-day pivot: recon → vulnerable+patched binary acquisition →
|
|
132
|
-
patch diff (Ghidra
|
|
133
|
-
|
|
134
|
-
disclosure. Rulebook
|
|
117
|
+
patch diff (Ghidra) → variant search → fuzz campaign (AFL++) → crash
|
|
118
|
+
triage (gdb/pwndbg) → PoC development (pwntools) → coordinated
|
|
119
|
+
disclosure. Rulebook:
|
|
135
120
|
[`agents/variant-research.rules.json`](agents/variant-research.rules.json).
|
|
136
121
|
|
|
137
122
|
The disclosure terminal is **pinned to coordinated channels**
|
|
138
123
|
(HackerOne / Bugcrowd / vendor PSIRT / CERT-CC / internal write-up /
|
|
139
124
|
90-day published advisory). The rulebook contains an explicit
|
|
140
|
-
`vr.r.no_brokerage` rule
|
|
125
|
+
`vr.r.no_brokerage` rule — it is not a vector for selling unreported
|
|
141
126
|
exploits.
|
|
142
127
|
|
|
143
|
-
|
|
144
|
-
target
|
|
145
|
-
|
|
146
|
-
a target portfolio, per-investigation findings dirs, and a disclosure
|
|
147
|
-
log all driven by this profile.
|
|
128
|
+
The companion research workspace is [`Aroxora/patchpivot`](https://github.com/Aroxora/patchpivot)
|
|
129
|
+
(private): target portfolio, per-investigation findings dirs, and a
|
|
130
|
+
disclosure log driven by this profile.
|
|
148
131
|
|
|
149
132
|
```sh
|
|
150
133
|
erosolar --profile variant-research "investigate the patch at <commit-url>"
|
|
151
134
|
```
|
|
152
135
|
|
|
136
|
+
### `engagement-delivery`
|
|
137
|
+
|
|
138
|
+
Sibling of `variant-research` running the same eight-phase VR workflow,
|
|
139
|
+
but the terminal phase delivers to an **authorized engagement
|
|
140
|
+
recipient** — a U.S. government contract / task order, a U.S. defense
|
|
141
|
+
prime under contract, or a published bug-bounty program. The rulebook
|
|
142
|
+
adds an intake phase that requires an active engagement identifier in
|
|
143
|
+
the artifact store before any other phase advances; missing engagement
|
|
144
|
+
id → halt + prompt operator. Rulebook:
|
|
145
|
+
[`agents/engagement-delivery.rules.json`](agents/engagement-delivery.rules.json).
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
erosolar --profile engagement-delivery "<task>"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Both `variant-research` and `engagement-delivery` get the offsec
|
|
152
|
+
capability surface. `erosolar-code` does not. Gating lives in
|
|
153
|
+
`src/runtime/profileGates.ts`.
|
|
154
|
+
|
|
153
155
|
---
|
|
154
156
|
|
|
155
157
|
## Capability surface
|
|
@@ -162,82 +164,92 @@ Capabilities are typed wrappers around external tools, registered in
|
|
|
162
164
|
| Family | Tools |
|
|
163
165
|
|---|---|
|
|
164
166
|
| Filesystem | `Read`, `Write`, `Edit`, `MultiEdit`, `Glob`, `Grep`, `Search` |
|
|
165
|
-
| Process | `Bash` (
|
|
166
|
-
| Git | `git_status`, `git_log`, `git_diff`, `git_show`, `git_blame`, `git_revert
|
|
167
|
+
| Process | `Bash` (bracketed-paste-safe stdin, 1MB stdout cap) |
|
|
168
|
+
| Git | `git_status`, `git_log`, `git_diff`, `git_show`, `git_blame`, `git_revert`, full enhanced-git surface |
|
|
167
169
|
| Memory | `memory_save`, `memory_load`, `memory_list`, `memory_delete` |
|
|
168
|
-
| Planning | `TodoWrite` (state + plan-formatter integration) |
|
|
169
|
-
| Skills | `Skill`, `list_skills` (loads
|
|
170
|
+
| Planning | `TodoWrite` (state + plan-formatter integration), `PlanMode` |
|
|
171
|
+
| Skills | `Skill`, `list_skills` (loads `~/.erosolar/skills/<name>/SKILL.md`) |
|
|
170
172
|
| Web | `WebSearch`, `WebExtract` (Tavily under the hood) |
|
|
171
173
|
| Sub-agent | `spawn_agent`, `agent_status`, `agent_output`, `agent_stop` |
|
|
172
174
|
| Notebook | `NotebookEdit` |
|
|
173
175
|
| HITL | `hitl_decision`, `hitl_approve`, `hitl_choose` |
|
|
176
|
+
| Worktree | `worktree_create`, `worktree_remove`, `worktree_list` |
|
|
177
|
+
| Monitor | `monitor_start`, `monitor_stop` (long-running command observers) |
|
|
178
|
+
| Schedule | `schedule_*`, `trigger_*` (in-session reminders / cron-style triggers) |
|
|
174
179
|
|
|
175
|
-
### Offensive (variant-research /
|
|
180
|
+
### Offensive (variant-research / engagement-delivery only)
|
|
176
181
|
|
|
177
182
|
| Capability | Module | Tools |
|
|
178
183
|
|---|---|---|
|
|
179
184
|
| Kali (network/web) | `kaliCapability.ts` | `kali_sqlmap`, `kali_gobuster`, `kali_ffuf`, `kali_feroxbuster`, `kali_nikto`, `kali_wpscan`, `kali_hydra`, `kali_john`, `kali_hashcat`, `kali_masscan`, `kali_amass`, `kali_subfinder` |
|
|
180
185
|
| Static binary analysis | `binaryAnalysisCapability.ts` | `bin_file`, `bin_strings`, `bin_objdump`, `bin_readelf`, `bin_nm`, `bin_checksec`, `bin_ropgadget`, `bin_radare2_cmd` |
|
|
186
|
+
| Headless Ghidra | `ghidraHeadlessCapability.ts` | `ghidra_analyze`, `ghidra_decompile`, `ghidra_diff` |
|
|
181
187
|
| AFL++ fuzzing | `aflppCapability.ts` | `afl_compile_harness`, `afl_fuzz_start` (detached), `afl_fuzz_status` (auto-registers crashes in artifact store), `afl_fuzz_stop`, `afl_showmap`, `afl_cmin`, `afl_tmin` |
|
|
182
188
|
| Crash triage | `gdbCapability.ts` | `gdb_run_with_input`, `gdb_inspect_at`, `gdb_disassemble` (pwndbg/GEF inherited from `~/.gdbinit`) |
|
|
183
|
-
| Exploit
|
|
189
|
+
| Exploit dev | `pwntoolsCapability.ts` | `pwn_eval`, `pwn_rop_search`, `pwn_packed` |
|
|
184
190
|
|
|
185
191
|
The offsec capabilities are guardrail-free per
|
|
186
|
-
[
|
|
192
|
+
[ero.solar/about](https://ero.solar/about) — the operator authorizes
|
|
187
193
|
their own engagements; the CLI does not validate target/argv. Install
|
|
188
|
-
the underlying binaries via `kali-linux-everything` + `ghidra` on
|
|
189
|
-
|
|
194
|
+
the underlying binaries via `kali-linux-everything` + `ghidra` on
|
|
195
|
+
Kali, or the Kali rolling repo on Debian/Ubuntu.
|
|
190
196
|
|
|
191
197
|
---
|
|
192
198
|
|
|
193
199
|
## MCP servers
|
|
194
200
|
|
|
195
201
|
The CLI auto-loads MCP servers declared in `mcp.json` (or
|
|
196
|
-
`mcp.json.example` as a template).
|
|
197
|
-
|
|
202
|
+
`mcp.json.example` as a template). MCP tools appear in the flat tool
|
|
203
|
+
list with the prefix `mcp__<server>__<tool>`.
|
|
198
204
|
|
|
199
205
|
```json
|
|
200
206
|
{
|
|
201
207
|
"mcpServers": {
|
|
202
|
-
"ghidra": {
|
|
203
|
-
"command": "python3",
|
|
204
|
-
"args": ["-m", "ghidra_mcp"],
|
|
205
|
-
"env": { "GHIDRA_INSTALL_DIR": "/usr/share/ghidra" }
|
|
206
|
-
},
|
|
208
|
+
"ghidra": { "command": "python3", "args": ["-m", "ghidra_mcp"], "env": { "GHIDRA_INSTALL_DIR": "/usr/share/ghidra" } },
|
|
207
209
|
"mcp_kali_server": { "command": "mcp-kali-server", "args": [] },
|
|
208
|
-
"metasploitmcp": { "command": "metasploitmcp",
|
|
209
|
-
"tavily": { "command": "tavily-mcp",
|
|
210
|
+
"metasploitmcp": { "command": "metasploitmcp", "args": [] },
|
|
211
|
+
"tavily": { "command": "tavily-mcp", "args": [] }
|
|
210
212
|
}
|
|
211
213
|
}
|
|
212
214
|
```
|
|
213
215
|
|
|
214
|
-
|
|
215
|
-
`
|
|
216
|
-
|
|
216
|
+
`mcp-kali-server` and `metasploitmcp` ship in `kali-linux-everything`.
|
|
217
|
+
`ghidra-mcp` is a separate `pip install`. `tavily-mcp` is on npm.
|
|
218
|
+
None are required; they're additive.
|
|
217
219
|
|
|
218
220
|
---
|
|
219
221
|
|
|
220
222
|
## Slash commands
|
|
221
223
|
|
|
222
|
-
|
|
224
|
+
Handled before the agent loop sees the input. The set below reflects
|
|
225
|
+
the actual command table (`src/shell/commandRegistry.ts` plus the
|
|
226
|
+
inline matchers in `src/headless/interactiveShell.ts`):
|
|
223
227
|
|
|
224
|
-
| Command | Effect |
|
|
225
|
-
|
|
226
|
-
| `/help` |
|
|
227
|
-
| `/
|
|
228
|
-
| `/
|
|
229
|
-
| `/
|
|
230
|
-
| `/
|
|
231
|
-
| `/auto
|
|
232
|
-
| `/
|
|
233
|
-
| `/
|
|
234
|
-
| `/
|
|
235
|
-
| `/
|
|
236
|
-
| `/revert` |
|
|
237
|
-
| `/
|
|
238
|
-
| `/
|
|
239
|
-
| `/
|
|
240
|
-
| `/
|
|
228
|
+
| Command | Aliases | Effect |
|
|
229
|
+
|---|---|---|
|
|
230
|
+
| `/help` | `/h`, `/?` | Inline help panel |
|
|
231
|
+
| `/model [name]` | `/m` | No arg → picker menu; arg → silent switch (`provider`, `provider model`, `provider/model`, or `model`) |
|
|
232
|
+
| `/providers` | | List configured providers |
|
|
233
|
+
| `/key <sk-…>` | | Save `DEEPSEEK_API_KEY` to `~/.erosolar/secrets.json` |
|
|
234
|
+
| `/secrets [set [name]]` | `/s` | Inspect / set / unset every known provider key |
|
|
235
|
+
| `/auto` | `/continue`, `/loop`, `/dual` | Cycle auto-continue mode (off → on → dual → off) |
|
|
236
|
+
| `/bash <cmd>` | `/sh` | One-shot shell command, bypasses the agent |
|
|
237
|
+
| `/clear` | `/c` | Clear screen, redraw welcome |
|
|
238
|
+
| `/context` | | Refresh workspace context |
|
|
239
|
+
| `/sessions` | | Session management menu |
|
|
240
|
+
| `/revert [confirm]` | | Preview / roll back files modified during the current run |
|
|
241
|
+
| `/tools` | | List active tools |
|
|
242
|
+
| `/mcp` | | MCP server + tool status |
|
|
243
|
+
| `/learn` | | Learning-system status |
|
|
244
|
+
| `/debug [on\|off\|status]` | | Toggle agent-internal debug logging |
|
|
245
|
+
| `/stats` | `/status` | Session token + cost stats |
|
|
246
|
+
| `/keys` | `/shortcuts`, `/kb` | Keyboard shortcuts panel |
|
|
247
|
+
| `/exit` | `/quit`, `/q` | Leave the shell |
|
|
248
|
+
|
|
249
|
+
Profile is selected at boot only — there is no in-session `/profile`
|
|
250
|
+
switch; restart with `--profile <name>` or set `EROSOLAR_PROFILE`.
|
|
251
|
+
HITL is configured per-tool through the capability's `autoPause`
|
|
252
|
+
option (Option+V toggles the equivalent).
|
|
241
253
|
|
|
242
254
|
---
|
|
243
255
|
|
|
@@ -264,13 +276,13 @@ In-shell commands handled before the agent loop sees them:
|
|
|
264
276
|
| `EROSOLAR_HOME` | Override `~/.erosolar` storage root |
|
|
265
277
|
| `EROSOLAR_PROFILE` | Default profile (alternative to `--profile`) |
|
|
266
278
|
| `EROSOLAR_INK_DEBUG=1` | Verbose Ink prompt + state logging on stderr |
|
|
267
|
-
| `<PROFILE>_MODEL` | Per-profile default model override (e.g. `EROSOLAR_CODE_MODEL=claude-opus-4-
|
|
279
|
+
| `<PROFILE>_MODEL` | Per-profile default model override (e.g. `EROSOLAR_CODE_MODEL=claude-opus-4-7`) |
|
|
268
280
|
| `<PROFILE>_PROVIDER` | Per-profile default provider override |
|
|
269
281
|
| `<PROFILE>_SYSTEM_PROMPT` | Per-profile system prompt override |
|
|
270
282
|
| `NO_COLOR`, `FORCE_COLOR` | Standard color toggles |
|
|
271
|
-
| `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `XAI_API_KEY`, `DASHSCOPE_API_KEY`, `OLLAMA_BASE_URL` | Other provider credentials when
|
|
283
|
+
| `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `XAI_API_KEY`, `DASHSCOPE_API_KEY`, `OLLAMA_BASE_URL` | Other provider credentials when those models are selected |
|
|
272
284
|
|
|
273
|
-
###
|
|
285
|
+
### `~/.erosolar/settings.json` (hooks + permissions)
|
|
274
286
|
|
|
275
287
|
The harness reads `~/.erosolar/settings.json` (user) and
|
|
276
288
|
`<workspace>/.erosolar/settings.json` (project) for hooks, allow/deny
|
|
@@ -281,19 +293,24 @@ contract.
|
|
|
281
293
|
|
|
282
294
|
## Variant research workflow
|
|
283
295
|
|
|
284
|
-
The `variant-research`
|
|
285
|
-
reads from its system prompt:
|
|
296
|
+
The `variant-research` and `engagement-delivery` rulebooks drive the
|
|
297
|
+
same eight-phase pivot the LLM reads from its system prompt:
|
|
286
298
|
|
|
287
299
|
| Phase | Intent | Tools |
|
|
288
300
|
|---|---|---|
|
|
289
301
|
| `recon` | Identify target patch / CVE / advisory; record bug-class hypothesis | Tavily / WebSearch |
|
|
290
302
|
| `acquire` | Build vulnerable + patched binaries; persist to artifact store | Bash, Git, `bin_*` |
|
|
291
|
-
| `bindiff` | Diff binaries
|
|
292
|
-
| `variant` | Hunt the same buggy pattern in older versions / forks / siblings | Ghidra
|
|
303
|
+
| `bindiff` | Diff binaries; pull decompiled C of changed functions | Ghidra MCP / `ghidra_*` |
|
|
304
|
+
| `variant` | Hunt the same buggy pattern in older versions / forks / siblings | Ghidra, Grep |
|
|
293
305
|
| `fuzz` | Build harness + run AFL++ campaign as detached job | `afl_*` |
|
|
294
|
-
| `triage` | Classify each crash; correlate to
|
|
295
|
-
| `poc` | Develop minimal reliable PoC
|
|
296
|
-
| `disclose` | Author write-up;
|
|
306
|
+
| `triage` | Classify each crash; correlate to decomp; identify primitive | `gdb_*`, Ghidra |
|
|
307
|
+
| `poc` | Develop minimal reliable PoC reproducing the primitive | `pwn_*` |
|
|
308
|
+
| `disclose` / `deliver` | Author write-up; ship through coordinated / contracted channel | — (rulebook lists allowed channels) |
|
|
309
|
+
|
|
310
|
+
`engagement-delivery` adds a leading `intake` phase that gates the
|
|
311
|
+
workflow on a registered engagement identifier (USG contract / task
|
|
312
|
+
order, defense-prime engagement reference, or published bug-bounty
|
|
313
|
+
program scope).
|
|
297
314
|
|
|
298
315
|
The artifact store is the load-bearing piece: every multi-megabyte
|
|
299
316
|
output (binaries, decompilations, crash corpora) is registered with a
|
|
@@ -301,9 +318,6 @@ sha256 id and tagged. The LLM passes ids around in conversation
|
|
|
301
318
|
instead of pasting blobs into context — without this, a long workflow
|
|
302
319
|
gets summarized away mid-investigation.
|
|
303
320
|
|
|
304
|
-
The companion `patchpivot` repo (separate, private) holds target
|
|
305
|
-
portfolios and per-investigation workspaces.
|
|
306
|
-
|
|
307
321
|
---
|
|
308
322
|
|
|
309
323
|
## Architecture
|
|
@@ -324,28 +338,33 @@ No DAG planner, no ReAct scratchpad. Multi-step planning is implicit
|
|
|
324
338
|
in the LLM's tool calls, guided by the rulebook injected into the
|
|
325
339
|
system prompt. Sub-agents (`spawn_agent` / `agent_status` /
|
|
326
340
|
`agent_output` / `agent_stop`) are the long-task supervisor — anything
|
|
327
|
-
|
|
328
|
-
|
|
341
|
+
running for hours (fuzz campaigns, large recompiles) goes detached and
|
|
342
|
+
the parent polls.
|
|
329
343
|
|
|
330
344
|
### Capability registry
|
|
331
345
|
|
|
332
346
|
Each capability module implements `CapabilityModule` and contributes a
|
|
333
347
|
flat `ToolSuite` to the runtime. Registration happens in
|
|
334
|
-
`src/capabilities/index.ts`. Tools declare JSON Schema parameters
|
|
335
|
-
inputs are validated and coerced via
|
|
336
|
-
|
|
337
|
-
|
|
348
|
+
`src/capabilities/index.ts`. Tools declare JSON Schema parameters;
|
|
349
|
+
inputs are validated and coerced via `src/core/schemaValidator.ts`
|
|
350
|
+
before the handler runs. MCP tools are first-class — same
|
|
351
|
+
`ToolDefinition` shape, `mcp__<server>__` prefix.
|
|
352
|
+
|
|
353
|
+
Profile-based gating (`src/runtime/profileGates.ts`) decides which
|
|
354
|
+
capabilities are mounted. Cowork / productivity capabilities were
|
|
355
|
+
extracted to `~/GitHub/erosolar-cowork` in 2026-05 and are not
|
|
356
|
+
present in this repo (enforced by `test/capability-separation.test.ts`).
|
|
338
357
|
|
|
339
|
-
###
|
|
358
|
+
### Rulebooks
|
|
340
359
|
|
|
341
360
|
A rulebook (`src/contracts/schemas/agent-rules.schema.json`) is a
|
|
342
361
|
phase-structured JSON document with `globalPrinciples`, `phases`, and
|
|
343
|
-
per-step `entryCriteria` / `exitCriteria` / `rules`. The CLI renders
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
`
|
|
362
|
+
per-step `entryCriteria` / `exitCriteria` / `rules`. The CLI renders it
|
|
363
|
+
to markdown and inlines it into the profile's system prompt at boot.
|
|
364
|
+
It is **declarative guidance**, not an enforced state machine — the
|
|
365
|
+
LLM is expected to follow it; nothing in the runtime blocks a phase
|
|
366
|
+
from being skipped. Rule severities (`critical` / `required` /
|
|
367
|
+
`recommended`) influence how strongly the LLM treats them.
|
|
349
368
|
|
|
350
369
|
### Artifact store
|
|
351
370
|
|
|
@@ -361,17 +380,17 @@ compaction.
|
|
|
361
380
|
|
|
362
381
|
`src/core/sharedSecrets.ts` — REST fetch of `shared_secrets/<name>`
|
|
363
382
|
from Firestore using the user's Firebase ID token. Auto-refreshes the
|
|
364
|
-
token if expired. Writes to `process.env`, no on-disk cache (a
|
|
365
|
-
|
|
366
|
-
|
|
383
|
+
token if expired. Writes to `process.env`, no on-disk cache (a rotated
|
|
384
|
+
key shouldn't get stuck stale on a user's machine). Triggered once at
|
|
385
|
+
boot from `src/bin/deepseek.ts` after `requireAuth()`.
|
|
367
386
|
|
|
368
387
|
### Context manager
|
|
369
388
|
|
|
370
389
|
`src/core/contextManager.ts` — token-budget aware sliding window with
|
|
371
390
|
LLM-driven summarization. Defaults: 130k max, 100k target compaction
|
|
372
391
|
trigger, last 10 exchanges always preserved, file-read truncation
|
|
373
|
-
keeps head + tail of large files. Uses
|
|
374
|
-
|
|
392
|
+
keeps head + tail of large files. Uses the profile's default model for
|
|
393
|
+
the summarization pass.
|
|
375
394
|
|
|
376
395
|
### HITL
|
|
377
396
|
|
|
@@ -383,6 +402,31 @@ the LLM (it decides when to ask), not the runtime — there's no
|
|
|
383
402
|
|
|
384
403
|
---
|
|
385
404
|
|
|
405
|
+
## Companion surfaces
|
|
406
|
+
|
|
407
|
+
This monorepo contains the CLI plus three companion surfaces that
|
|
408
|
+
share Erosolar Auth, balance, and the model brain:
|
|
409
|
+
|
|
410
|
+
- **Helia** ([`Erosolar_Browser/`](Erosolar_Browser)) — Electron +
|
|
411
|
+
Chromium browser modeled after ChatGPT Atlas, with a side-panel
|
|
412
|
+
Erosolar agent that has full page context and CDP-driven action
|
|
413
|
+
automation. Cross-platform: macOS (dmg/zip, x64+arm64), Windows
|
|
414
|
+
(NSIS + portable), Linux (AppImage + .deb). Distributed at
|
|
415
|
+
[ero.solar/helia](https://ero.solar/helia) with an S3-manifest
|
|
416
|
+
auto-updater. Current Helia version: `0.1.21`.
|
|
417
|
+
- **Site** ([`site/`](site)) — Firebase-hosted marketing/portal
|
|
418
|
+
(`/about`, `/portal`, `/auth`, `/docs`, `/defense`, `/process`,
|
|
419
|
+
`/audit`, `/admin`, `/npm`, `/helia`).
|
|
420
|
+
- **AWS Lambda backend** ([`aws/lambda/`](aws/lambda)) — single Lambda
|
|
421
|
+
fronted by API Gateway, Stripe checkout, Firestore for state,
|
|
422
|
+
service-account JSON pulled from AWS Secrets Manager. Replaces the
|
|
423
|
+
legacy Cloud Functions deployment; portal + CLI both call into it.
|
|
424
|
+
|
|
425
|
+
Cross-surface PRs are atomic by design. See CLAUDE.md "Monorepo for
|
|
426
|
+
one product, separate repos for different products" for the rule.
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
386
430
|
## Building from source
|
|
387
431
|
|
|
388
432
|
```sh
|
|
@@ -394,38 +438,40 @@ npm test # full jest suite
|
|
|
394
438
|
node dist/bin/erosolar.js --self-test
|
|
395
439
|
```
|
|
396
440
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
from source.
|
|
441
|
+
`pretest` runs the build, and `prepublishOnly` rebuilds before any npm
|
|
442
|
+
publish so the published tarball is always rebuilt from source.
|
|
400
443
|
|
|
401
444
|
### Tests
|
|
402
445
|
|
|
403
446
|
`test/**/*.test.ts` — driven by jest with the config in
|
|
404
|
-
`jest.config.cjs`. Test discipline (per
|
|
447
|
+
`jest.config.cjs`. Test discipline (per CLAUDE.md): real behavior
|
|
405
448
|
end-to-end, no mocks for things the test claims to verify. Tests for
|
|
406
449
|
provider calls require credentials; those are gated by env-var
|
|
407
|
-
presence and skipped (with a clear reason) when absent.
|
|
408
|
-
passing
|
|
450
|
+
presence and skipped (with a clear reason) when absent.
|
|
451
|
+
**Skipped ≠ passing.**
|
|
452
|
+
|
|
453
|
+
A pre-push git hook (`scripts/git-hooks/pre-push`) runs `npm test`
|
|
454
|
+
before every push. Install once per checkout:
|
|
455
|
+
`git config core.hooksPath scripts/git-hooks`. Bypass in an emergency
|
|
456
|
+
with `git push --no-verify`.
|
|
409
457
|
|
|
410
458
|
### Releasing
|
|
411
459
|
|
|
412
460
|
`npm run release` → `scripts/create-release.sh patch` (interactive —
|
|
413
|
-
checks clean git, runs tests, bumps version, builds, publishes,
|
|
414
|
-
|
|
415
|
-
`npm version patch && npm publish --access public`.
|
|
461
|
+
checks clean git, runs tests, bumps version, builds, publishes, tags).
|
|
462
|
+
Non-interactive publishes: `npm version patch && npm publish --access public`.
|
|
416
463
|
|
|
417
464
|
---
|
|
418
465
|
|
|
419
466
|
## Versioning + deprecation policy
|
|
420
467
|
|
|
421
468
|
Semver. Patches add features and fix bugs without API breakage; minor
|
|
422
|
-
bumps signal new public surfaces; major bumps signal breaking
|
|
423
|
-
changes. Dev releases use the `next` dist-tag.
|
|
469
|
+
bumps signal new public surfaces; major bumps signal breaking changes.
|
|
424
470
|
|
|
425
471
|
Versions `1.1.16` → `1.1.19` are **deprecated** — they bundled an
|
|
426
|
-
embedded DeepSeek API key that
|
|
427
|
-
|
|
428
|
-
|
|
472
|
+
embedded DeepSeek API key that has been revoked. Installations on that
|
|
473
|
+
range print an `npm deprecate` warning. Upgrade to ≥ `1.1.20`. The
|
|
474
|
+
shared-key fetch via Firebase Auth replaces the embedded key.
|
|
429
475
|
|
|
430
476
|
---
|
|
431
477
|
|
|
@@ -436,19 +482,22 @@ that range will print an `npm deprecate` warning. Upgrade to ≥
|
|
|
436
482
|
> reference (SSO, allowlist, revocation, profile gating, audit log,
|
|
437
483
|
> threat model, residual risk).
|
|
438
484
|
|
|
439
|
-
|
|
440
485
|
- The CLI is dual-use offensive-security tooling. U.S. classification
|
|
441
|
-
is EAR-controlled (CCL [ECCN 4D004](https://www.federalregister.gov/documents/2021/10/21/2021-22774/information-security-controls-cybersecurity-items)
|
|
442
|
-
|
|
443
|
-
controls apply to international transfer.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
(
|
|
447
|
-
|
|
448
|
-
-
|
|
486
|
+
is EAR-controlled (CCL [ECCN 4D004](https://www.federalregister.gov/documents/2021/10/21/2021-22774/information-security-controls-cybersecurity-items)
|
|
487
|
+
+ 4E001 for development technology). Domestic development and use is
|
|
488
|
+
unrestricted; export controls apply to international transfer. Good-faith
|
|
489
|
+
security research is affirmatively protected by Van Buren (2021), the
|
|
490
|
+
DOJ May-2022 CFAA Charging Policy, and the LOC § 1201 Triennial
|
|
491
|
+
Exemption (2024).
|
|
492
|
+
- `kaliCapability.ts` and the offsec capability surface are
|
|
493
|
+
guardrail-free. Operator authorization is assumed — both legal
|
|
494
|
+
authorization (you have permission to test the target) and ethical
|
|
495
|
+
authorization (the engagement scope covers what you're about to run).
|
|
496
|
+
- Disclosure is pinned. The `variant-research` rulebook's `disclose`
|
|
449
497
|
phase has explicit `vr.r.no_brokerage` and `vr.r.respect_embargo`
|
|
450
498
|
rules. PoCs go to vendor / HackerOne / Bugcrowd / CERT-CC, not to
|
|
451
|
-
brokers.
|
|
499
|
+
brokers. `engagement-delivery` ships only to authorized contracted
|
|
500
|
+
recipients.
|
|
452
501
|
- Secrets handling: the npm package ships zero embedded API keys.
|
|
453
502
|
Keys come from env, user-set local file, or Firestore via Firebase
|
|
454
503
|
Auth (admin-managed). Error messages are sanitized through
|
|
@@ -458,8 +507,8 @@ that range will print an `npm deprecate` warning. Upgrade to ≥
|
|
|
458
507
|
permissions, in an `0o700` directory. Atomic writes prevent
|
|
459
508
|
half-written JSON from breaking subsequent loads.
|
|
460
509
|
|
|
461
|
-
See [`/about`](https://
|
|
462
|
-
including BIS
|
|
510
|
+
See [`/about`](https://ero.solar/about) for the full disclosure
|
|
511
|
+
including BIS links and the relevant rulemaking.
|
|
463
512
|
|
|
464
513
|
---
|
|
465
514
|
|
|
@@ -468,8 +517,8 @@ including BIS / DDTC links and the relevant rulemaking.
|
|
|
468
517
|
- npm: https://www.npmjs.com/package/@trenchwork/erosolar
|
|
469
518
|
- Source: https://github.com/Aroxora/deepseek-coder-cli
|
|
470
519
|
- Companion research workspace: `Aroxora/patchpivot` (private)
|
|
471
|
-
- Helia (
|
|
472
|
-
- Erosolar Auth: https://
|
|
473
|
-
- Project context: https://
|
|
520
|
+
- Helia (browser companion, mac/win/linux): https://ero.solar/helia
|
|
521
|
+
- Erosolar Auth: https://ero.solar/auth
|
|
522
|
+
- Project context: https://ero.solar/about
|
|
474
523
|
|
|
475
524
|
License: MIT (see [LICENSE](LICENSE)).
|