@trenchwork/erosolar 1.1.33 → 1.1.35

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.
@@ -1,7 +1,3 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Alias entrypoint for erosolar-cli.
4
- * Delegates to the main deepseek binary to keep build outputs in sync.
5
- */
6
- import './deepseek.js';
2
+ export {};
7
3
  //# sourceMappingURL=erosolar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"erosolar.d.ts","sourceRoot":"","sources":["../../src/bin/erosolar.ts"],"names":[],"mappings":";AACA;;;GAGG;AACH,OAAO,eAAe,CAAC"}
1
+ {"version":3,"file":"erosolar.d.ts","sourceRoot":"","sources":["../../src/bin/erosolar.ts"],"names":[],"mappings":""}
@@ -1,7 +1,358 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Alias entrypoint for erosolar-cli.
4
- * Delegates to the main deepseek binary to keep build outputs in sync.
3
+ * Erosolar (a.k.a. Trenchwork) — single CLI entry point.
4
+ *
5
+ * The npm `bin` map publishes two names — `erosolar` and `trenchwork` —
6
+ * both pointing at this file. There is no `deepseek` entry point any
7
+ * longer; the historical name was retired 2026-05-09 to keep the brand
8
+ * surface a single name pair. The interactive shell uses Ink only.
5
9
  */
6
- import './deepseek.js';
10
+ import { reportStatus, reportStatusError } from '../utils/statusReporter.js';
11
+ import { track } from '../utils/analytics.js';
12
+ // Fast path: handle --version, --help, --key before any heavy imports.
13
+ const rawArgs = process.argv.slice(2);
14
+ /**
15
+ * Extract `--profile NAME` or `--profile=NAME` from argv. Used by the
16
+ * approval gate to check profile-specific authorization before the
17
+ * profile manifest is loaded.
18
+ */
19
+ function pickProfileArg(args) {
20
+ const idx = args.findIndex((a) => a === '--profile');
21
+ if (idx >= 0) {
22
+ const next = args[idx + 1];
23
+ if (next && !next.startsWith('-'))
24
+ return next;
25
+ }
26
+ const eq = args.find((a) => a.startsWith('--profile='));
27
+ if (eq)
28
+ return eq.slice('--profile='.length);
29
+ return undefined;
30
+ }
31
+ // Best-effort, non-blocking analytics ping. Never throws, never awaited.
32
+ const subcommand = rawArgs[0]?.startsWith('-') ? '(flags)' : (rawArgs[0] || 'default');
33
+ track('cli_invoked', { subcommand, arg_count: rawArgs.length });
34
+ // Handle --key to set API key (simple path that works reliably).
35
+ const keyIndex = rawArgs.findIndex(arg => arg === '--key' || arg.startsWith('--key='));
36
+ if (keyIndex !== -1) {
37
+ let keyValue;
38
+ const arg = rawArgs[keyIndex];
39
+ if (arg?.startsWith('--key=')) {
40
+ keyValue = arg.slice(6);
41
+ }
42
+ else if (rawArgs[keyIndex + 1] && !rawArgs[keyIndex + 1]?.startsWith('-')) {
43
+ keyValue = rawArgs[keyIndex + 1];
44
+ }
45
+ if (keyValue) {
46
+ import('node:fs').then(fs => {
47
+ import('node:path').then(path => {
48
+ import('node:os').then(os => {
49
+ const secretDir = path.join(os.homedir(), '.erosolar');
50
+ const secretFile = path.join(secretDir, 'secrets.json');
51
+ try {
52
+ fs.mkdirSync(secretDir, { recursive: true });
53
+ const existing = fs.existsSync(secretFile)
54
+ ? JSON.parse(fs.readFileSync(secretFile, 'utf-8'))
55
+ : {};
56
+ existing['DEEPSEEK_API_KEY'] = keyValue;
57
+ fs.writeFileSync(secretFile, JSON.stringify(existing, null, 2) + '\n');
58
+ console.log('✓ DEEPSEEK_API_KEY saved to ~/.erosolar/secrets.json');
59
+ process.exit(0);
60
+ }
61
+ catch (err) {
62
+ reportStatus(`Failed to save key: ${err instanceof Error ? err.message : err}`);
63
+ process.exit(1);
64
+ }
65
+ });
66
+ });
67
+ });
68
+ }
69
+ else {
70
+ reportStatus('Usage: erosolar --key YOUR_API_KEY');
71
+ process.exit(1);
72
+ }
73
+ }
74
+ else if (rawArgs.includes('--version') || rawArgs.includes('-v')) {
75
+ import('node:fs').then(fs => {
76
+ import('node:path').then(path => {
77
+ import('node:url').then(url => {
78
+ try {
79
+ const __filename = url.fileURLToPath(import.meta.url);
80
+ const pkgPath = path.resolve(path.dirname(__filename), '../../package.json');
81
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
82
+ console.log(`erosolar v${pkg.version || '0.0.0'}`);
83
+ }
84
+ catch {
85
+ console.log('erosolar (version unknown)');
86
+ }
87
+ process.exit(0);
88
+ });
89
+ });
90
+ });
91
+ }
92
+ else if (rawArgs.includes('--help') || rawArgs.includes('-h')) {
93
+ console.log(`
94
+ erosolar — AI-powered offsec / coding assistant (a.k.a. trenchwork)
95
+
96
+ Usage: erosolar [options] [prompt]
97
+
98
+ Modes:
99
+ erosolar Start the unified Ink interactive shell
100
+ erosolar "prompt" Start with an initial prompt
101
+
102
+ Options:
103
+ -v, --version Show version
104
+ -h, --help Show this help
105
+ --key KEY Set the model provider API key
106
+ --profile NAME Profile (erosolar-code | variant-research |
107
+ engagement-delivery)
108
+ --self-test Run self-tests
109
+
110
+ Subcommands:
111
+ erosolar offsec install Install kali / AFL++ / gdb / pwntools binaries
112
+ erosolar helia <verb> Control the local Helia browser companion
113
+
114
+ In-shell tools (offsec profiles):
115
+ HuntStart Scaffold engagement+target+finding for a target
116
+ (URL / file path / github.com/owner/repo) in one
117
+ tool call. Findings sync live to
118
+ https://trenchwork.org/portal.
119
+
120
+ Environment:
121
+ DEEPSEEK_API_KEY Model provider API key (or use --key to set)
122
+ `);
123
+ process.exit(0);
124
+ }
125
+ else if (rawArgs[0] === 'helia') {
126
+ // Local-only utility: control the Helia browser running on this same
127
+ // machine via its 127.0.0.1:59998 HTTP API. No Erosolar account login
128
+ // required, no pairing token to copy — the CLI reads Helia's token
129
+ // file directly from ~/Library/Application Support/Helia/pairing-token
130
+ // (or the equivalent on Windows / Linux).
131
+ void runHeliaCommand(rawArgs.slice(1)).catch((err) => {
132
+ reportStatusError(err);
133
+ process.exit(1);
134
+ });
135
+ }
136
+ else if (rawArgs[0] === 'offsec') {
137
+ // Cross-platform offsec self-bootstrap. `erosolar offsec install`
138
+ // walks the BinaryRequirement manifest, installs missing binaries
139
+ // for the operator's OS via apt / brew / winget / pipx / npm / cargo
140
+ // / go / gem (whichever has a recipe). Tools without a native path
141
+ // on this OS are skipped with a pointer to WSL2 / Docker — no
142
+ // forced Kali install on macOS or Windows.
143
+ void (async () => {
144
+ const { runOffsecCommand } = await import('../cli/offsecInstall.js');
145
+ const code = await runOffsecCommand(rawArgs.slice(1));
146
+ process.exit(code);
147
+ })().catch((err) => { reportStatusError(err); process.exit(1); });
148
+ }
149
+ else {
150
+ void main();
151
+ }
152
+ async function runHeliaCommand(args) {
153
+ const { heliaControl } = await import('../tools/heliaControl.js');
154
+ const verb = args[0] || 'ping';
155
+ const usage = `Usage: erosolar helia <verb> [args]
156
+
157
+ Verbs:
158
+ ping Check Helia is running, print version
159
+ tabs List open tabs (id / title / url / active)
160
+ open [url] Open a new tab (blank → homepage)
161
+ close <id> Close tab by id
162
+ switch <id> Switch to tab by id
163
+ reload [id] Reload active tab (or specific id)
164
+ navigate <url> Navigate active tab to URL
165
+ context Read active tab's URL / title / text / headings
166
+ prompt <text> Inject text into Helia's sidebar agent
167
+ focus Bring Helia window to the front
168
+ sidebar Open the Erosolar side panel
169
+ token Print path to the pairing-token file
170
+ `;
171
+ try {
172
+ let result;
173
+ switch (verb) {
174
+ case 'ping': {
175
+ const r = await heliaControl.ping();
176
+ if (!r) {
177
+ console.error('Helia is not running on this machine (no response on http://127.0.0.1:59998).');
178
+ process.exit(2);
179
+ }
180
+ result = r;
181
+ break;
182
+ }
183
+ case 'token':
184
+ result = { path: heliaControl.tokenPath() };
185
+ break;
186
+ case 'tabs':
187
+ result = await heliaControl.tabs();
188
+ break;
189
+ case 'open':
190
+ result = await heliaControl.openTab(args[1]);
191
+ break;
192
+ case 'close':
193
+ if (!args[1]) {
194
+ console.error(usage);
195
+ process.exit(1);
196
+ }
197
+ result = await heliaControl.closeTab(args[1]);
198
+ break;
199
+ case 'switch':
200
+ if (!args[1]) {
201
+ console.error(usage);
202
+ process.exit(1);
203
+ }
204
+ result = await heliaControl.switchTab(args[1]);
205
+ break;
206
+ case 'reload':
207
+ result = await heliaControl.reload(args[1]);
208
+ break;
209
+ case 'navigate':
210
+ case 'nav':
211
+ if (!args[1]) {
212
+ console.error(usage);
213
+ process.exit(1);
214
+ }
215
+ result = await heliaControl.navigate(args[1]);
216
+ break;
217
+ case 'context':
218
+ result = await heliaControl.pageContext();
219
+ break;
220
+ case 'prompt': {
221
+ const text = args.slice(1).join(' ');
222
+ if (!text) {
223
+ console.error(usage);
224
+ process.exit(1);
225
+ }
226
+ result = await heliaControl.prompt(text);
227
+ break;
228
+ }
229
+ case 'focus':
230
+ result = await heliaControl.focus();
231
+ break;
232
+ case 'sidebar':
233
+ result = await heliaControl.openSidebar();
234
+ break;
235
+ case '--help':
236
+ case '-h':
237
+ case 'help':
238
+ console.log(usage);
239
+ process.exit(0);
240
+ default:
241
+ console.error(`Unknown helia verb: ${verb}\n\n${usage}`);
242
+ process.exit(1);
243
+ }
244
+ console.log(JSON.stringify(result, null, 2));
245
+ process.exit(0);
246
+ }
247
+ catch (err) {
248
+ const msg = err instanceof Error ? err.message : String(err);
249
+ console.error(`helia ${verb}: ${msg}`);
250
+ process.exit(1);
251
+ }
252
+ }
253
+ async function main() {
254
+ // Require authentication before continuing.
255
+ const { requireAuth } = await import('../core/auth.js');
256
+ await requireAuth();
257
+ // Approved-users gate. The CLI carries offsec tooling, so every
258
+ // launch checks the signed-in email against the Firestore allowlist
259
+ // at `approved_users/{email}`. Misses get a request doc written for
260
+ // the operator to review, then the CLI refuses to start. SSO is
261
+ // also enforced at the Firestore-rule layer (sign_in_provider ==
262
+ // 'google.com'), so a non-SSO token can't even read the doc.
263
+ // The check also enforces:
264
+ // - revocation: `revoked: true` on the doc denies access even if
265
+ // `approved: true` (faster than removing the doc — preserves
266
+ // the audit trail of who held access when).
267
+ // - profile gating: `profiles_allowed: ['variant-research', ...]`
268
+ // restricts which agent profiles a user can launch. Missing
269
+ // field = permissive (backward compat). New approvals default
270
+ // to `['erosolar-code']` only.
271
+ const requestedProfile = pickProfileArg(rawArgs) ?? process.env['EROSOLAR_PROFILE'] ?? 'erosolar-code';
272
+ const { checkApproval, requestApproval } = await import('../core/userApproval.js');
273
+ const approval = await checkApproval(requestedProfile);
274
+ if (!approval.approved) {
275
+ process.stderr.write('\n');
276
+ process.stderr.write('Access denied — this account is not authorized.\n');
277
+ process.stderr.write(` Email: ${approval.email ?? '(no email on token — SSO required)'}\n`);
278
+ process.stderr.write(` Profile: ${requestedProfile}\n`);
279
+ process.stderr.write(` Reason: ${approval.reason ?? 'unknown'}\n\n`);
280
+ if (approval.email && approval.uid && !approval.revoked) {
281
+ const req = await requestApproval();
282
+ if (req.ok) {
283
+ process.stderr.write('A request has been recorded. The administrator will review it.\n');
284
+ process.stderr.write('You can re-run `erosolar` once the approval lands.\n');
285
+ }
286
+ else {
287
+ process.stderr.write(`Could not file approval request: ${req.reason}\n`);
288
+ }
289
+ }
290
+ else if (approval.revoked) {
291
+ process.stderr.write('Revoked accounts cannot file new requests. Contact the operator directly.\n');
292
+ }
293
+ process.exit(1);
294
+ }
295
+ // Hydrate shared provider keys from Firestore. Runs after requireAuth
296
+ // + checkApproval so a valid Firebase ID token is already on disk
297
+ // and the user is on the allowlist. If the user has their own
298
+ // DEEPSEEK_API_KEY in env or saved via /secrets, this is a no-op;
299
+ // otherwise it fetches the org-managed key from
300
+ // shared_secrets/deepseek (Firestore-rule-gated by auth) and writes
301
+ // it into process.env before any provider is constructed. The CLI
302
+ // ships zero embedded keys.
303
+ const { prefetchAllSharedSecrets } = await import('../core/sharedSecrets.js');
304
+ await prefetchAllSharedSecrets();
305
+ // Project tracking. Idempotently upserts `projects/{projectId}`
306
+ // (id = sha256(workingDir).slice(0, 12)) and writes the
307
+ // session-start row with the project FK. The session id is
308
+ // surfaced via the EROSOLAR_SESSION_ID env so the interactive
309
+ // shell can patch session-end fields on clean exit.
310
+ const { registerProject, writeSessionStart } = await import('../core/projectTracker.js');
311
+ const projectResult = await registerProject(process.cwd());
312
+ process.env['EROSOLAR_PROJECT_ID'] = projectResult.context.projectId;
313
+ const cliVersion = process.env['npm_package_version'] || 'unknown';
314
+ const cliModel = process.env[`${requestedProfile.toUpperCase().replace(/[^A-Z0-9]/g, '_')}_MODEL`] || 'default';
315
+ const sessionStart = await writeSessionStart({
316
+ profile: requestedProfile,
317
+ model: cliModel,
318
+ version: cliVersion,
319
+ platform: process.platform,
320
+ project: projectResult.context,
321
+ });
322
+ if (sessionStart.ok && sessionStart.sessionId) {
323
+ process.env['EROSOLAR_SESSION_ID'] = sessionStart.sessionId;
324
+ }
325
+ // Mirror the active profile + model + platform to the Remote
326
+ // Operations Center so the portal's "Profile" pill shows what the
327
+ // CLI is currently running. Fire-and-forget; a failed call never
328
+ // blocks startup.
329
+ void (async () => {
330
+ try {
331
+ const { callLambda } = await import('../utils/lambdaClient.js');
332
+ await callLambda('cliProfileSet', {
333
+ profile: requestedProfile,
334
+ model: cliModel,
335
+ version: cliVersion,
336
+ platform: process.platform,
337
+ projectId: projectResult.context.projectId,
338
+ });
339
+ }
340
+ catch (_) { /* portal mirror is fire-and-forget */ }
341
+ })();
342
+ // Force color support for TTY terminals.
343
+ if (process.stdout.isTTY && !process.env['NO_COLOR']) {
344
+ process.env['FORCE_COLOR'] = process.env['FORCE_COLOR'] ?? '1';
345
+ }
346
+ // Self-test mode.
347
+ if (rawArgs.includes('--self-test')) {
348
+ const { runSelfTest } = await import('./selfTest.js');
349
+ runSelfTest().then((success) => process.exit(success ? 0 : 1)).catch(() => process.exit(1));
350
+ return;
351
+ }
352
+ const { runInteractiveShell } = await import('../headless/interactiveShell.js');
353
+ runInteractiveShell({ argv: rawArgs }).catch((error) => {
354
+ reportStatusError(error);
355
+ process.exit(1);
356
+ });
357
+ }
7
358
  //# sourceMappingURL=erosolar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"erosolar.js","sourceRoot":"","sources":["../../src/bin/erosolar.ts"],"names":[],"mappings":";AACA;;;GAGG;AACH,OAAO,eAAe,CAAC"}
1
+ {"version":3,"file":"erosolar.js","sourceRoot":"","sources":["../../src/bin/erosolar.ts"],"names":[],"mappings":"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"}
@@ -212,12 +212,10 @@ class InteractiveShell {
212
212
  profile;
213
213
  profileConfig;
214
214
  workingDir;
215
- // The shell holds an `IPromptController`-shaped value so the same
216
- // call sites work whether we picked the legacy renderer or the Ink
217
- // adapter (selected by EROSOLAR_INK=1, see createPromptController).
218
- // Using `any` here keeps existing call signatures unchanged — the
219
- // interface declares the same surface but TS would otherwise insist
220
- // we touch every call site to declare nullability.
215
+ // Always an InkPromptController instance (Ink is the only renderer
216
+ // the legacy PromptController was removed 2026-05-09). The `any`
217
+ // keeps call sites unchanged across the IPromptController surface
218
+ // without forcing every caller to declare nullability up-front.
221
219
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
222
220
  promptController = null;
223
221
  isProcessing = false;
@@ -301,12 +299,9 @@ class InteractiveShell {
301
299
  this.pendingPrompts.push(prompt);
302
300
  }
303
301
  async run() {
304
- // Factory-driven construction: `EROSOLAR_INK=1` picks the Ink-backed
305
- // controller (src/ui/ink/InkPromptController.ts), otherwise the
306
- // legacy PromptController. Both implement the same surface so
307
- // every call site below is unchanged. Dynamic import keeps the
308
- // legacy path's cold-start free of the React/Ink parse cost when
309
- // the env flag is unset.
302
+ // Ink is the only renderer; createPromptController always returns
303
+ // an InkPromptController. The dynamic import keeps the React + Ink
304
+ // parse cost off the cold-start path of `--version` / `--help` etc.
310
305
  const { createPromptController } = await import('../ui/ink/InkPromptController.js');
311
306
  this.promptController = await createPromptController(stdin, stdout, {
312
307
  onSubmit: (text) => this.handleSubmit(text),