pentesting 0.43.0 → 0.44.1
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/dist/main.js +430 -378
- package/dist/prompts/base.md +34 -2
- package/dist/prompts/ctf-mode.md +1 -1
- package/dist/prompts/recon.md +3 -3
- package/dist/prompts/strategist-system.md +254 -22
- package/dist/prompts/strategy.md +8 -2
- package/dist/prompts/techniques/lateral.md +1 -1
- package/dist/prompts/techniques/network-svc.md +3 -3
- package/dist/prompts/vuln.md +2 -2
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -10,7 +10,6 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
10
10
|
import { render } from "ink";
|
|
11
11
|
import { Command } from "commander";
|
|
12
12
|
import chalk from "chalk";
|
|
13
|
-
import gradient from "gradient-string";
|
|
14
13
|
|
|
15
14
|
// src/platform/tui/app.tsx
|
|
16
15
|
import { useState as useState4, useCallback as useCallback4, useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
@@ -307,14 +306,12 @@ var ORPHAN_PROCESS_NAMES = [
|
|
|
307
306
|
"dnsspoof",
|
|
308
307
|
"tcpdump",
|
|
309
308
|
"tshark",
|
|
310
|
-
"socat"
|
|
311
|
-
"nc",
|
|
312
|
-
"python"
|
|
309
|
+
"socat"
|
|
313
310
|
];
|
|
314
311
|
|
|
315
312
|
// src/shared/constants/agent.ts
|
|
316
313
|
var APP_NAME = "Pentest AI";
|
|
317
|
-
var APP_VERSION = "0.
|
|
314
|
+
var APP_VERSION = "0.44.1";
|
|
318
315
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
319
316
|
var LLM_ROLES = {
|
|
320
317
|
SYSTEM: "system",
|
|
@@ -342,6 +339,146 @@ var SENSITIVE_INPUT_TYPES = [
|
|
|
342
339
|
INPUT_TYPES.CREDENTIAL
|
|
343
340
|
];
|
|
344
341
|
|
|
342
|
+
// src/shared/utils/time-strategy.ts
|
|
343
|
+
var PHASE_RATIOS = {
|
|
344
|
+
/** Sprint ends at 25% of total time */
|
|
345
|
+
SPRINT_END: 0.25,
|
|
346
|
+
/** Exploit phase ends at 50% of total time */
|
|
347
|
+
EXPLOIT_END: 0.5,
|
|
348
|
+
/** Creative phase ends at 75% of total time */
|
|
349
|
+
CREATIVE_END: 0.75
|
|
350
|
+
// Harvest: 75%-100%
|
|
351
|
+
};
|
|
352
|
+
var DEFAULT_DURATION_SEC = 86400;
|
|
353
|
+
var MIN_DURATION_SEC = 300;
|
|
354
|
+
var MAX_DURATION_SEC = 604800;
|
|
355
|
+
var MS_PER_SEC = 1e3;
|
|
356
|
+
function getSessionDurationMs() {
|
|
357
|
+
const envValue = process.env.PENTEST_DURATION;
|
|
358
|
+
if (envValue) {
|
|
359
|
+
const parsed = parseInt(envValue, 10);
|
|
360
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
361
|
+
const clamped = Math.max(MIN_DURATION_SEC, Math.min(MAX_DURATION_SEC, parsed));
|
|
362
|
+
return clamped * MS_PER_SEC;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return DEFAULT_DURATION_SEC * MS_PER_SEC;
|
|
366
|
+
}
|
|
367
|
+
function computeDeadline(startedAt) {
|
|
368
|
+
return startedAt + getSessionDurationMs();
|
|
369
|
+
}
|
|
370
|
+
function formatDuration(totalSec) {
|
|
371
|
+
if (totalSec <= 0) return "0s";
|
|
372
|
+
const h = Math.floor(totalSec / 3600);
|
|
373
|
+
const m = Math.floor(totalSec % 3600 / 60);
|
|
374
|
+
const s = Math.floor(totalSec % 60);
|
|
375
|
+
if (h > 0 && m > 0) return `${h}h${m}m`;
|
|
376
|
+
if (h > 0) return `${h}h`;
|
|
377
|
+
if (m > 0 && s > 0) return `${m}m${s}s`;
|
|
378
|
+
if (m > 0) return `${m}m`;
|
|
379
|
+
return `${s}s`;
|
|
380
|
+
}
|
|
381
|
+
function getTimeAdaptiveStrategy(elapsedMs, deadlineMs) {
|
|
382
|
+
let totalMs;
|
|
383
|
+
let remainingMs;
|
|
384
|
+
if (deadlineMs > 0) {
|
|
385
|
+
remainingMs = Math.max(0, deadlineMs - Date.now());
|
|
386
|
+
totalMs = elapsedMs + remainingMs;
|
|
387
|
+
} else {
|
|
388
|
+
totalMs = getSessionDurationMs();
|
|
389
|
+
remainingMs = Math.max(0, totalMs - elapsedMs);
|
|
390
|
+
}
|
|
391
|
+
if (totalMs <= 0) totalMs = 1;
|
|
392
|
+
const progress = Math.min(1, elapsedMs / totalMs);
|
|
393
|
+
const remainingSec = Math.floor(remainingMs / MS_PER_SEC);
|
|
394
|
+
const totalDurationSec = Math.floor(totalMs / MS_PER_SEC);
|
|
395
|
+
const elapsedStr = formatDuration(Math.floor(elapsedMs / MS_PER_SEC));
|
|
396
|
+
const remainStr = formatDuration(remainingSec);
|
|
397
|
+
const totalStr = formatDuration(totalDurationSec);
|
|
398
|
+
const pctStr = `${Math.floor(progress * 100)}%`;
|
|
399
|
+
if (progress >= PHASE_RATIOS.CREATIVE_END) {
|
|
400
|
+
return {
|
|
401
|
+
phase: "harvest",
|
|
402
|
+
label: "HARVEST",
|
|
403
|
+
urgency: "critical",
|
|
404
|
+
progress,
|
|
405
|
+
totalDurationSec,
|
|
406
|
+
remainingSec,
|
|
407
|
+
directive: [
|
|
408
|
+
`\u{1F3C1} HARVEST MODE [${pctStr} elapsed, ${remainStr} of ${totalStr} remaining]:`,
|
|
409
|
+
"- STOP exploring new attack vectors. Exploit what you HAVE.",
|
|
410
|
+
"- Submit ALL discovered flags immediately",
|
|
411
|
+
"- Check obvious flag locations: /root/flag.txt, user.txt, env vars, DB tables",
|
|
412
|
+
"- Re-check previously accessed systems for missed flags/proof",
|
|
413
|
+
"- Collect and record ALL evidence and proof files",
|
|
414
|
+
"- Write final report with all findings",
|
|
415
|
+
"- Credential spray ALL discovered creds on ALL remaining services",
|
|
416
|
+
remainingSec <= 300 ? "- \u26A0\uFE0F FINAL 5 MINUTES \u2014 submit everything NOW, stop all scans" : "- Focus on highest-confidence paths only"
|
|
417
|
+
].join("\n")
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
if (progress >= PHASE_RATIOS.EXPLOIT_END) {
|
|
421
|
+
return {
|
|
422
|
+
phase: "creative",
|
|
423
|
+
label: "CREATIVE",
|
|
424
|
+
urgency: "high",
|
|
425
|
+
progress,
|
|
426
|
+
totalDurationSec,
|
|
427
|
+
remainingSec,
|
|
428
|
+
directive: [
|
|
429
|
+
`\u{1F52C} CREATIVE MODE [${pctStr} elapsed, ${remainStr} of ${totalStr} remaining]:`,
|
|
430
|
+
"- Try advanced techniques: chained exploits, custom tools, race conditions",
|
|
431
|
+
"- Binary analysis for SUID/custom binaries, kernel exploits for privesc",
|
|
432
|
+
"- Protocol-level attacks: SMB relay, Kerberoasting, ADCS abuse",
|
|
433
|
+
'- Search for latest bypasses: web_search("{defense} bypass {year}")',
|
|
434
|
+
"- If stuck >5min on any vector, SWITCH immediately",
|
|
435
|
+
"- Start preparing evidence collection for final phase",
|
|
436
|
+
"- If all targets are compromised \u2192 skip to harvest immediately"
|
|
437
|
+
].join("\n")
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
if (progress >= PHASE_RATIOS.SPRINT_END) {
|
|
441
|
+
return {
|
|
442
|
+
phase: "exploit",
|
|
443
|
+
label: "EXPLOIT",
|
|
444
|
+
urgency: "medium",
|
|
445
|
+
progress,
|
|
446
|
+
totalDurationSec,
|
|
447
|
+
remainingSec,
|
|
448
|
+
directive: [
|
|
449
|
+
`\u{1F3AF} EXPLOIT MODE [${pctStr} elapsed, ${remainStr} of ${totalStr} remaining]:`,
|
|
450
|
+
"- Concentrate on discovered vectors with highest success probability",
|
|
451
|
+
"- Run parallel exploitation attempts on multiple targets",
|
|
452
|
+
"- Search for CVE PoCs for every identified service+version",
|
|
453
|
+
"- Chain: credentials \u2192 spray everywhere, LFI \u2192 config \u2192 DB creds",
|
|
454
|
+
"- Keep background scans running for new targets",
|
|
455
|
+
"- Time-box each vector: 10min max then switch",
|
|
456
|
+
"- If all vectors exhausted early \u2192 move to creative techniques immediately"
|
|
457
|
+
].join("\n")
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
phase: "sprint",
|
|
462
|
+
label: "SPRINT",
|
|
463
|
+
urgency: "low",
|
|
464
|
+
progress,
|
|
465
|
+
totalDurationSec,
|
|
466
|
+
remainingSec,
|
|
467
|
+
directive: [
|
|
468
|
+
`\u26A1 SPRINT MODE [${pctStr} elapsed, ${remainStr} of ${totalStr} remaining]:`,
|
|
469
|
+
"- RustScan first for fast port discovery \u2192 then nmap -Pn -sV -sC on found ports",
|
|
470
|
+
"- ALWAYS use nmap -Pn (no exceptions \u2014 firewalls block ICMP)",
|
|
471
|
+
"- Run ALL scans in parallel (rustscan, nmap UDP, web fuzzing, CVE search)",
|
|
472
|
+
"- Try default/weak credentials on every discovered service IMMEDIATELY",
|
|
473
|
+
"- Check for exposed files (.env, .git, backup.sql, phpinfo)",
|
|
474
|
+
"- Anonymous access: FTP, SMB null session, Redis no auth, MongoDB",
|
|
475
|
+
"- OSINT: web_search for target intel, shodan, github repos",
|
|
476
|
+
"- Goal: Maximum attack surface discovery + instant wins",
|
|
477
|
+
"- \u26A1 If recon completes early \u2192 ATTACK IMMEDIATELY, do not wait for this phase to end"
|
|
478
|
+
].join("\n")
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
345
482
|
// src/shared/utils/id.ts
|
|
346
483
|
var ID_DEFAULT_RADIX = 36;
|
|
347
484
|
var ID_DEFAULT_LENGTH = 6;
|
|
@@ -2027,7 +2164,7 @@ async function cleanupAllProcesses() {
|
|
|
2027
2164
|
backgroundProcesses.clear();
|
|
2028
2165
|
for (const name of ORPHAN_PROCESS_NAMES) {
|
|
2029
2166
|
try {
|
|
2030
|
-
execSync2(`pkill -
|
|
2167
|
+
execSync2(`pkill -x "${name}" 2>/dev/null || true`, { stdio: "ignore", timeout: SYSTEM_LIMITS.PROCESS_OP_TIMEOUT_MS });
|
|
2031
2168
|
} catch {
|
|
2032
2169
|
}
|
|
2033
2170
|
}
|
|
@@ -2652,6 +2789,22 @@ var AttackGraph = class {
|
|
|
2652
2789
|
if (nodeCount >= GRAPH_LIMITS.ASCII_MAX_NODES) break;
|
|
2653
2790
|
const sIcon = statusIcons[node.status] || "?";
|
|
2654
2791
|
const fail = node.status === NODE_STATUS.FAILED && node.failReason ? ` \u2014 ${node.failReason}` : "";
|
|
2792
|
+
let detail = "";
|
|
2793
|
+
if (type === NODE_TYPE.CREDENTIAL) {
|
|
2794
|
+
const source = node.data.source ? ` (from: ${node.data.source})` : "";
|
|
2795
|
+
detail = source;
|
|
2796
|
+
} else if (type === NODE_TYPE.VULNERABILITY) {
|
|
2797
|
+
const sev = node.data.severity ? ` [${String(node.data.severity).toUpperCase()}]` : "";
|
|
2798
|
+
const exploit = node.data.hasExploit ? " [EXPLOIT]" : "";
|
|
2799
|
+
const target = node.data.target ? ` \u2192 ${node.data.target}` : "";
|
|
2800
|
+
detail = `${sev}${exploit}${target}`;
|
|
2801
|
+
} else if (type === NODE_TYPE.ACCESS) {
|
|
2802
|
+
const via = node.data.via ? ` via ${node.data.via}` : "";
|
|
2803
|
+
detail = via;
|
|
2804
|
+
} else if (type === NODE_TYPE.SERVICE) {
|
|
2805
|
+
const ver = node.data.version ? ` (${node.data.version})` : "";
|
|
2806
|
+
detail = ver;
|
|
2807
|
+
}
|
|
2655
2808
|
const outEdges = this.edges.filter((e) => e.from === node.id);
|
|
2656
2809
|
const edgeStr = outEdges.length > 0 ? ` \u2192 ${outEdges.map((e) => {
|
|
2657
2810
|
const target = this.nodes.get(e.to);
|
|
@@ -2659,10 +2812,19 @@ var AttackGraph = class {
|
|
|
2659
2812
|
const eStatus = e.status === EDGE_STATUS.FAILED ? " \u2717" : e.status === EDGE_STATUS.SUCCEEDED ? " \u2713" : "";
|
|
2660
2813
|
return `${eName}${eStatus}`;
|
|
2661
2814
|
}).join(", ")}` : "";
|
|
2662
|
-
lines.push(`\u2502 ${sIcon} ${node.label}${fail}${edgeStr}`);
|
|
2815
|
+
lines.push(`\u2502 ${sIcon} ${node.label}${detail}${fail}${edgeStr}`);
|
|
2663
2816
|
nodeCount++;
|
|
2664
2817
|
}
|
|
2665
2818
|
}
|
|
2819
|
+
const succeededNodes = Array.from(this.nodes.values()).filter((n) => n.status === NODE_STATUS.SUCCEEDED);
|
|
2820
|
+
if (succeededNodes.length > 0) {
|
|
2821
|
+
lines.push(`\u2502`);
|
|
2822
|
+
lines.push(`\u251C\u2500\u2500\u2500 Exploited \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524`);
|
|
2823
|
+
for (const n of succeededNodes) {
|
|
2824
|
+
const via = n.data.via ? ` via ${n.data.via}` : "";
|
|
2825
|
+
lines.push(`\u2502 \u25CF ${n.label}${via}`);
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2666
2828
|
const stats = this.getStats();
|
|
2667
2829
|
lines.push(`\u2502`);
|
|
2668
2830
|
lines.push(`\u251C\u2500\u2500\u2500 Summary \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524`);
|
|
@@ -3183,6 +3345,7 @@ var SharedState = class {
|
|
|
3183
3345
|
// ─── Improvement #7: Dynamic Technique Library ────────────────
|
|
3184
3346
|
dynamicTechniques = new DynamicTechniqueLibrary();
|
|
3185
3347
|
constructor() {
|
|
3348
|
+
const now = Date.now();
|
|
3186
3349
|
this.data = {
|
|
3187
3350
|
engagement: null,
|
|
3188
3351
|
targets: /* @__PURE__ */ new Map(),
|
|
@@ -3196,8 +3359,10 @@ var SharedState = class {
|
|
|
3196
3359
|
ctfMode: true,
|
|
3197
3360
|
// CTF mode ON by default
|
|
3198
3361
|
flags: [],
|
|
3199
|
-
startedAt:
|
|
3200
|
-
|
|
3362
|
+
startedAt: now,
|
|
3363
|
+
// Auto-configure from PENTEST_DURATION env (seconds).
|
|
3364
|
+
// Defaults to 24h if not set. Can be overridden via setDeadline().
|
|
3365
|
+
deadlineAt: computeDeadline(now),
|
|
3201
3366
|
challengeAnalysis: null
|
|
3202
3367
|
};
|
|
3203
3368
|
}
|
|
@@ -3206,6 +3371,7 @@ var SharedState = class {
|
|
|
3206
3371
|
* Used by /clear command to start a fresh session without recreating the agent.
|
|
3207
3372
|
*/
|
|
3208
3373
|
reset() {
|
|
3374
|
+
const now = Date.now();
|
|
3209
3375
|
this.data = {
|
|
3210
3376
|
engagement: null,
|
|
3211
3377
|
targets: /* @__PURE__ */ new Map(),
|
|
@@ -3218,8 +3384,8 @@ var SharedState = class {
|
|
|
3218
3384
|
missionChecklist: [],
|
|
3219
3385
|
ctfMode: true,
|
|
3220
3386
|
flags: [],
|
|
3221
|
-
startedAt:
|
|
3222
|
-
deadlineAt:
|
|
3387
|
+
startedAt: now,
|
|
3388
|
+
deadlineAt: computeDeadline(now),
|
|
3223
3389
|
challengeAnalysis: null
|
|
3224
3390
|
};
|
|
3225
3391
|
this.attackGraph.reset();
|
|
@@ -3404,24 +3570,28 @@ var SharedState = class {
|
|
|
3404
3570
|
if (this.data.deadlineAt === 0) return 0;
|
|
3405
3571
|
return Math.max(0, this.data.deadlineAt - Date.now());
|
|
3406
3572
|
}
|
|
3407
|
-
/** Get time status string for prompt injection */
|
|
3573
|
+
/** Get time status string for prompt injection (ratio-based, aligned with PHASE_RATIOS) */
|
|
3408
3574
|
getTimeStatus() {
|
|
3409
3575
|
const elapsed = this.getElapsedMs();
|
|
3410
3576
|
const mins = Math.floor(elapsed / 6e4);
|
|
3411
3577
|
let status = `\u23F1 Elapsed: ${mins}min`;
|
|
3412
3578
|
if (this.data.deadlineAt > 0) {
|
|
3413
3579
|
const remainingMs = this.getRemainingMs();
|
|
3580
|
+
const totalMs = elapsed + remainingMs;
|
|
3581
|
+
const progress = totalMs > 0 ? elapsed / totalMs : 1;
|
|
3414
3582
|
const remainingMins = Math.floor(remainingMs / 6e4);
|
|
3415
|
-
if (
|
|
3583
|
+
if (remainingMs <= 0) {
|
|
3416
3584
|
status += " | \u26A0\uFE0F TIME IS UP \u2014 submit any flags you have NOW";
|
|
3417
|
-
} else if (
|
|
3585
|
+
} else if (progress >= 0.95) {
|
|
3418
3586
|
status += ` | \u{1F534} ${remainingMins}min LEFT \u2014 FINAL PUSH: submit flags, check obvious locations, env vars, DBs`;
|
|
3419
|
-
} else if (
|
|
3420
|
-
status += ` | \u{1F7E1} ${remainingMins}min LEFT \u2014 wrap up
|
|
3421
|
-
} else if (
|
|
3422
|
-
status += ` | \u{1F7E0} ${remainingMins}min LEFT \u2014
|
|
3587
|
+
} else if (progress >= 0.75) {
|
|
3588
|
+
status += ` | \u{1F7E1} ${remainingMins}min LEFT \u2014 HARVEST: wrap up, collect evidence, submit flags`;
|
|
3589
|
+
} else if (progress >= 0.5) {
|
|
3590
|
+
status += ` | \u{1F7E0} ${remainingMins}min LEFT \u2014 CREATIVE: advanced techniques, switch if stuck`;
|
|
3591
|
+
} else if (progress >= 0.25) {
|
|
3592
|
+
status += ` | \u{1F535} ${remainingMins}min LEFT \u2014 EXPLOIT: focus on discovered vectors`;
|
|
3423
3593
|
} else {
|
|
3424
|
-
status += ` | \u{1F7E2} ${remainingMins}min remaining`;
|
|
3594
|
+
status += ` | \u{1F7E2} ${remainingMins}min remaining \u2014 SPRINT: recon + quick wins`;
|
|
3425
3595
|
}
|
|
3426
3596
|
}
|
|
3427
3597
|
return status;
|
|
@@ -4912,26 +5082,31 @@ Detail: ${detail}
|
|
|
4912
5082
|
},
|
|
4913
5083
|
{
|
|
4914
5084
|
name: TOOL_NAMES.ADD_FINDING,
|
|
4915
|
-
description:
|
|
5085
|
+
description: `Add a security finding with full details.
|
|
5086
|
+
ALWAYS provide: description (HOW you exploited it, step-by-step), evidence (actual command output proving success), and attackPattern (MITRE ATT&CK tactic).
|
|
5087
|
+
Findings without evidence are marked as UNVERIFIED and have low credibility.`,
|
|
4916
5088
|
parameters: {
|
|
4917
|
-
title: { type: "string", description:
|
|
5089
|
+
title: { type: "string", description: 'Concise finding title (e.g., "Path Traversal via /download endpoint")' },
|
|
4918
5090
|
severity: { type: "string", description: "Severity: critical, high, medium, low, info" },
|
|
4919
|
-
affected: { type: "array", items: { type: "string" }, description:
|
|
5091
|
+
affected: { type: "array", items: { type: "string" }, description: 'Affected host:port or URLs (e.g., ["ctf.example.com:443/download"])' },
|
|
5092
|
+
description: { type: "string", description: "Detailed description: what the vulnerability is, how you exploited it step-by-step, what access it gives, and the impact. Include credentials found, methods used, and exploitation chain." },
|
|
5093
|
+
evidence: { type: "array", items: { type: "string" }, description: 'Actual command outputs proving the finding (e.g., ["curl output showing /etc/passwd", "uid=0(root) gid=0(root)"]). Copy real output here.' },
|
|
4920
5094
|
attackPattern: { type: "string", description: "MITRE ATT&CK tactic: initial_access, execution, persistence, privilege_escalation, defense_evasion, credential_access, discovery, lateral_movement, collection, exfiltration, command_and_control, impact" }
|
|
4921
5095
|
},
|
|
4922
|
-
required: ["title", "severity"],
|
|
5096
|
+
required: ["title", "severity", "description", "evidence"],
|
|
4923
5097
|
execute: async (p) => {
|
|
4924
5098
|
const evidence = p.evidence || [];
|
|
4925
5099
|
const title = p.title;
|
|
4926
5100
|
const severity = p.severity;
|
|
4927
5101
|
const affected = p.affected || [];
|
|
5102
|
+
const description = p.description || "";
|
|
4928
5103
|
const validation = validateFinding(evidence, severity);
|
|
4929
5104
|
state.addFinding({
|
|
4930
5105
|
id: generateId(AGENT_LIMITS.ID_RADIX, AGENT_LIMITS.ID_LENGTH),
|
|
4931
5106
|
title,
|
|
4932
5107
|
severity,
|
|
4933
5108
|
affected,
|
|
4934
|
-
description
|
|
5109
|
+
description,
|
|
4935
5110
|
evidence,
|
|
4936
5111
|
isVerified: validation.isVerified,
|
|
4937
5112
|
remediation: "",
|
|
@@ -8686,6 +8861,11 @@ var NETWORK_ERROR_CODES = {
|
|
|
8686
8861
|
ENOTFOUND: "ENOTFOUND",
|
|
8687
8862
|
CONNECT_TIMEOUT: "UND_ERR_CONNECT_TIMEOUT"
|
|
8688
8863
|
};
|
|
8864
|
+
var TRANSIENT_NETWORK_ERRORS = [
|
|
8865
|
+
NETWORK_ERROR_CODES.ECONNRESET,
|
|
8866
|
+
NETWORK_ERROR_CODES.ETIMEDOUT,
|
|
8867
|
+
NETWORK_ERROR_CODES.ENOTFOUND
|
|
8868
|
+
];
|
|
8689
8869
|
var LLMError = class extends Error {
|
|
8690
8870
|
/** Structured error information */
|
|
8691
8871
|
errorInfo;
|
|
@@ -8696,8 +8876,11 @@ var LLMError = class extends Error {
|
|
|
8696
8876
|
}
|
|
8697
8877
|
};
|
|
8698
8878
|
function classifyError(error) {
|
|
8879
|
+
if (error === null || error === void 0) {
|
|
8880
|
+
return { type: LLM_ERROR_TYPES.UNKNOWN, message: String(error), isRetryable: false, suggestedAction: "Analyze error" };
|
|
8881
|
+
}
|
|
8699
8882
|
const e = error;
|
|
8700
|
-
const statusCode = e
|
|
8883
|
+
const statusCode = e?.status || e?.statusCode;
|
|
8701
8884
|
const errorMessage = e?.error?.error?.message || e?.error?.message || e?.message || String(error);
|
|
8702
8885
|
if (statusCode === HTTP_STATUS.RATE_LIMIT || errorMessage.toLowerCase().includes("rate limit")) {
|
|
8703
8886
|
return { type: LLM_ERROR_TYPES.RATE_LIMIT, message: errorMessage, statusCode, isRetryable: true, suggestedAction: "Wait and retry" };
|
|
@@ -8708,7 +8891,7 @@ function classifyError(error) {
|
|
|
8708
8891
|
if (statusCode === HTTP_STATUS.BAD_REQUEST) {
|
|
8709
8892
|
return { type: LLM_ERROR_TYPES.INVALID_REQUEST, message: errorMessage, statusCode, isRetryable: false, suggestedAction: "Modify request" };
|
|
8710
8893
|
}
|
|
8711
|
-
if (e.code
|
|
8894
|
+
if (e.code && TRANSIENT_NETWORK_ERRORS.includes(e.code)) {
|
|
8712
8895
|
return { type: LLM_ERROR_TYPES.NETWORK_ERROR, message: errorMessage, isRetryable: true, suggestedAction: "Check network" };
|
|
8713
8896
|
}
|
|
8714
8897
|
if (errorMessage.toLowerCase().includes("timeout") || e.code === NETWORK_ERROR_CODES.CONNECT_TIMEOUT) {
|
|
@@ -10317,100 +10500,6 @@ var INITIAL_TASKS = {
|
|
|
10317
10500
|
RECON: "Initial reconnaissance and target discovery"
|
|
10318
10501
|
};
|
|
10319
10502
|
|
|
10320
|
-
// src/shared/utils/time-strategy.ts
|
|
10321
|
-
var TIME_CONSTANTS = {
|
|
10322
|
-
/** Milliseconds per minute */
|
|
10323
|
-
MS_PER_MINUTE: 6e4,
|
|
10324
|
-
/** Minutes threshold for sprint-to-exploit switch (no deadline mode) */
|
|
10325
|
-
SPRINT_MINUTES: 10,
|
|
10326
|
-
/** Deadline percentage thresholds for phase transitions */
|
|
10327
|
-
PHASE_SPRINT: 0.25,
|
|
10328
|
-
PHASE_EXPLOIT: 0.5,
|
|
10329
|
-
PHASE_CREATIVE: 0.75
|
|
10330
|
-
};
|
|
10331
|
-
function getTimeAdaptiveStrategy(elapsedMs, deadlineMs) {
|
|
10332
|
-
if (deadlineMs === 0) {
|
|
10333
|
-
const mins = Math.floor(elapsedMs / TIME_CONSTANTS.MS_PER_MINUTE);
|
|
10334
|
-
if (mins < TIME_CONSTANTS.SPRINT_MINUTES) {
|
|
10335
|
-
return {
|
|
10336
|
-
phase: "sprint",
|
|
10337
|
-
label: "SPRINT",
|
|
10338
|
-
urgency: "low",
|
|
10339
|
-
directive: `\u26A1 SPRINT MODE (${mins}min elapsed): Parallel reconnaissance. Full port scan + service enumeration + default credentials. Attack immediately on any finding.`
|
|
10340
|
-
};
|
|
10341
|
-
}
|
|
10342
|
-
return {
|
|
10343
|
-
phase: "exploit",
|
|
10344
|
-
label: "EXPLOIT",
|
|
10345
|
-
urgency: "low",
|
|
10346
|
-
directive: `\u{1F3AF} EXPLOIT MODE (${mins}min elapsed): Focus on discovered vectors. Chain findings. Build custom tools if needed.`
|
|
10347
|
-
};
|
|
10348
|
-
}
|
|
10349
|
-
const totalMs = deadlineMs - (deadlineMs > Date.now() ? Date.now() - elapsedMs : 0);
|
|
10350
|
-
const remainingMs = Math.max(0, deadlineMs - Date.now());
|
|
10351
|
-
const pct = totalMs > 0 ? 1 - remainingMs / totalMs : 1;
|
|
10352
|
-
const remainingMins = Math.floor(remainingMs / TIME_CONSTANTS.MS_PER_MINUTE);
|
|
10353
|
-
if (pct < TIME_CONSTANTS.PHASE_SPRINT) {
|
|
10354
|
-
return {
|
|
10355
|
-
phase: "sprint",
|
|
10356
|
-
label: "SPRINT",
|
|
10357
|
-
urgency: "low",
|
|
10358
|
-
directive: [
|
|
10359
|
-
`\u26A1 SPRINT MODE (${remainingMins}min remaining):`,
|
|
10360
|
-
"- Run ALL scans in parallel (nmap TCP/UDP, web fuzzing, CVE search)",
|
|
10361
|
-
"- Try default/weak credentials on every discovered service IMMEDIATELY",
|
|
10362
|
-
"- Check for exposed files (.env, .git, backup.sql, phpinfo)",
|
|
10363
|
-
"- Anonymous access: FTP, SMB null session, Redis no auth, MongoDB",
|
|
10364
|
-
"- Goal: Maximum attack surface discovery + instant wins"
|
|
10365
|
-
].join("\n")
|
|
10366
|
-
};
|
|
10367
|
-
}
|
|
10368
|
-
if (pct < TIME_CONSTANTS.PHASE_EXPLOIT) {
|
|
10369
|
-
return {
|
|
10370
|
-
phase: "exploit",
|
|
10371
|
-
label: "EXPLOIT",
|
|
10372
|
-
urgency: "medium",
|
|
10373
|
-
directive: [
|
|
10374
|
-
`\u{1F3AF} EXPLOIT MODE (${remainingMins}min remaining):`,
|
|
10375
|
-
"- Concentrate on discovered vectors with highest success probability",
|
|
10376
|
-
"- Run parallel exploitation attempts on multiple targets",
|
|
10377
|
-
"- Search for CVE PoCs for every identified service+version",
|
|
10378
|
-
"- Chain: credentials \u2192 spray everywhere, LFI \u2192 config \u2192 DB creds",
|
|
10379
|
-
"- Keep background scans running for new targets"
|
|
10380
|
-
].join("\n")
|
|
10381
|
-
};
|
|
10382
|
-
}
|
|
10383
|
-
if (pct < TIME_CONSTANTS.PHASE_CREATIVE) {
|
|
10384
|
-
return {
|
|
10385
|
-
phase: "creative",
|
|
10386
|
-
label: "CREATIVE",
|
|
10387
|
-
urgency: "high",
|
|
10388
|
-
directive: [
|
|
10389
|
-
`\u{1F52C} CREATIVE MODE (${remainingMins}min remaining):`,
|
|
10390
|
-
"- Try advanced techniques: chained exploits, custom tools, race conditions",
|
|
10391
|
-
"- Binary analysis for SUID/custom binaries, kernel exploits for privesc",
|
|
10392
|
-
"- Protocol-level attacks: SMB relay, Kerberoasting, ADCS abuse",
|
|
10393
|
-
'- Search for latest bypasses: web_search("{defense} bypass 2025")',
|
|
10394
|
-
"- If stuck >5min on any vector, SWITCH immediately"
|
|
10395
|
-
].join("\n")
|
|
10396
|
-
};
|
|
10397
|
-
}
|
|
10398
|
-
return {
|
|
10399
|
-
phase: "harvest",
|
|
10400
|
-
label: "HARVEST",
|
|
10401
|
-
urgency: "critical",
|
|
10402
|
-
directive: [
|
|
10403
|
-
`\u{1F3C1} HARVEST MODE (${remainingMins}min remaining \u2014 FINAL PUSH):`,
|
|
10404
|
-
"- STOP exploring new vectors. Focus on what you HAVE.",
|
|
10405
|
-
"- Submit ALL discovered flags immediately",
|
|
10406
|
-
"- Check obvious flag locations: /root/flag.txt, env vars, DB tables",
|
|
10407
|
-
"- Re-check previously accessed systems for missed flags",
|
|
10408
|
-
"- Collect and record ALL evidence and proof files",
|
|
10409
|
-
"- Write final report with all findings"
|
|
10410
|
-
].join("\n")
|
|
10411
|
-
};
|
|
10412
|
-
}
|
|
10413
|
-
|
|
10414
10503
|
// src/shared/constants/service-ports.ts
|
|
10415
10504
|
var SERVICE_PORTS = {
|
|
10416
10505
|
SSH: 22,
|
|
@@ -10960,12 +11049,13 @@ var STRATEGIST_LIMITS = {
|
|
|
10960
11049
|
* Full state can be 20K+; Strategist needs summary, not everything. */
|
|
10961
11050
|
MAX_INPUT_CHARS: 15e3,
|
|
10962
11051
|
/** Maximum characters for the Strategist's response.
|
|
10963
|
-
* WHY: Directives should be terse and actionable (~
|
|
10964
|
-
*
|
|
10965
|
-
MAX_OUTPUT_CHARS:
|
|
11052
|
+
* WHY: Directives should be terse and actionable (~800-1500 tokens).
|
|
11053
|
+
* Enhanced format includes SITUATION, priorities, EXHAUSTED, and SEARCH ORDERS. */
|
|
11054
|
+
MAX_OUTPUT_CHARS: 5e3,
|
|
10966
11055
|
/** Maximum lines in the directive output.
|
|
10967
|
-
* WHY: Forces concise, prioritized directives
|
|
10968
|
-
|
|
11056
|
+
* WHY: Forces concise, prioritized directives while allowing
|
|
11057
|
+
* structured format (priorities + exhausted + search orders). */
|
|
11058
|
+
MAX_DIRECTIVE_LINES: 60
|
|
10969
11059
|
};
|
|
10970
11060
|
|
|
10971
11061
|
// src/agents/strategist.ts
|
|
@@ -11134,11 +11224,14 @@ NOTE: This directive is from ${age}min ago (Strategist call failed this turn). V
|
|
|
11134
11224
|
this.totalCalls = 0;
|
|
11135
11225
|
}
|
|
11136
11226
|
};
|
|
11137
|
-
var FALLBACK_SYSTEM_PROMPT = `You are
|
|
11138
|
-
Analyze the
|
|
11139
|
-
|
|
11140
|
-
|
|
11141
|
-
|
|
11227
|
+
var FALLBACK_SYSTEM_PROMPT = `You are an elite autonomous penetration testing STRATEGIST \u2014 a red team tactical commander.
|
|
11228
|
+
Analyze the engagement state and issue precise attack orders for the execution agent.
|
|
11229
|
+
Format: SITUATION line, numbered PRIORITY items with ACTION/SEARCH/SUCCESS/FALLBACK/CHAIN fields, EXHAUSTED list, and SEARCH ORDERS.
|
|
11230
|
+
Be surgically specific: name exact tools, commands, parameters, and wordlists. The agent copy-pastes your commands.
|
|
11231
|
+
Include mandatory web_search directives for every unknown service/version.
|
|
11232
|
+
Detect stalls (repeated failures, no progress) and force completely different attack vectors.
|
|
11233
|
+
Chain every finding: "If X works \u2192 immediately do Y \u2192 which enables Z."
|
|
11234
|
+
Maximum 50 lines. Zero preamble. Direct imperatives only. Never repeat failed approaches.`;
|
|
11142
11235
|
|
|
11143
11236
|
// src/agents/main-agent.ts
|
|
11144
11237
|
var MainAgent = class extends CoreAgent {
|
|
@@ -11319,7 +11412,7 @@ var AgentFactory = class {
|
|
|
11319
11412
|
};
|
|
11320
11413
|
|
|
11321
11414
|
// src/platform/tui/utils/format.ts
|
|
11322
|
-
var
|
|
11415
|
+
var formatDuration2 = (ms) => {
|
|
11323
11416
|
const totalSec = ms / 1e3;
|
|
11324
11417
|
if (totalSec < 60) return `${totalSec.toFixed(1)}s`;
|
|
11325
11418
|
const minutes = Math.floor(totalSec / 60);
|
|
@@ -11333,7 +11426,7 @@ var formatTokens = (count) => {
|
|
|
11333
11426
|
};
|
|
11334
11427
|
var formatMeta = (ms, tokens) => {
|
|
11335
11428
|
const parts = [];
|
|
11336
|
-
if (ms > 0) parts.push(
|
|
11429
|
+
if (ms > 0) parts.push(formatDuration2(ms));
|
|
11337
11430
|
if (tokens > 0) parts.push(`\u2191 ${formatTokens(tokens)} tokens`);
|
|
11338
11431
|
return parts.length > 0 ? `(${parts.join(" \xB7 ")})` : "";
|
|
11339
11432
|
};
|
|
@@ -11367,135 +11460,74 @@ var formatInlineStatus = () => {
|
|
|
11367
11460
|
import { useState, useRef, useCallback } from "react";
|
|
11368
11461
|
|
|
11369
11462
|
// src/shared/constants/theme.ts
|
|
11463
|
+
var HEX = {
|
|
11464
|
+
primary: "#FF968A",
|
|
11465
|
+
pink: "#FFAEAE",
|
|
11466
|
+
peach: "#FFC5BF"
|
|
11467
|
+
};
|
|
11468
|
+
var COLORS = {
|
|
11469
|
+
// Primary accent - coral/salmon (ANSI 210 is light coral)
|
|
11470
|
+
primary: "ansi256(210)",
|
|
11471
|
+
// Pastel pink (ANSI 217 is light pink)
|
|
11472
|
+
pink: "ansi256(217)",
|
|
11473
|
+
// Pastel peach (ANSI 216 is light salmon)
|
|
11474
|
+
peach: "ansi256(216)",
|
|
11475
|
+
// Warning yellow (ANSI 222 is light goldenrod)
|
|
11476
|
+
yellow: "ansi256(222)",
|
|
11477
|
+
// Orange (ANSI 215)
|
|
11478
|
+
orange: "ansi256(215)",
|
|
11479
|
+
// Bright white for main text
|
|
11480
|
+
white: "white",
|
|
11481
|
+
// Light gray for secondary text (ANSI 252 is light gray)
|
|
11482
|
+
gray: "ansi256(252)",
|
|
11483
|
+
// Bright red for errors
|
|
11484
|
+
red: "red"
|
|
11485
|
+
};
|
|
11370
11486
|
var THEME = {
|
|
11371
|
-
|
|
11487
|
+
...COLORS,
|
|
11372
11488
|
bg: {
|
|
11373
11489
|
primary: "#050505",
|
|
11374
|
-
// Deepest black
|
|
11375
|
-
secondary: "#0a0c10",
|
|
11376
|
-
// Dark void
|
|
11377
|
-
tertiary: "#0f172a",
|
|
11378
|
-
// Slate dark
|
|
11379
|
-
elevated: "#1e293b",
|
|
11380
|
-
// Bright slate
|
|
11381
11490
|
input: "#020617"
|
|
11382
|
-
// Midnight
|
|
11383
11491
|
},
|
|
11384
|
-
// Text colors
|
|
11385
11492
|
text: {
|
|
11386
|
-
primary:
|
|
11387
|
-
//
|
|
11388
|
-
secondary:
|
|
11389
|
-
//
|
|
11390
|
-
muted:
|
|
11391
|
-
//
|
|
11392
|
-
accent:
|
|
11393
|
-
//
|
|
11394
|
-
highlight: "#ffffff"
|
|
11395
|
-
// Pure white
|
|
11493
|
+
primary: COLORS.white,
|
|
11494
|
+
// AI responses - main text
|
|
11495
|
+
secondary: COLORS.gray,
|
|
11496
|
+
// Secondary info
|
|
11497
|
+
muted: COLORS.gray,
|
|
11498
|
+
// Metadata, hints
|
|
11499
|
+
accent: COLORS.gray
|
|
11500
|
+
// Very subtle
|
|
11396
11501
|
},
|
|
11397
|
-
// Status colors (deep blue-focused)
|
|
11398
11502
|
status: {
|
|
11399
|
-
success:
|
|
11400
|
-
//
|
|
11401
|
-
warning:
|
|
11402
|
-
//
|
|
11403
|
-
error:
|
|
11404
|
-
//
|
|
11405
|
-
|
|
11406
|
-
//
|
|
11407
|
-
running: "#1e40af",
|
|
11408
|
-
// Blue 800 (AI activity)
|
|
11409
|
-
pending: "#64748b"
|
|
11410
|
-
// Slate
|
|
11503
|
+
success: COLORS.gray,
|
|
11504
|
+
// Keep it subtle
|
|
11505
|
+
warning: COLORS.yellow,
|
|
11506
|
+
// Pastel yellow
|
|
11507
|
+
error: COLORS.red,
|
|
11508
|
+
// Bright red for errors
|
|
11509
|
+
running: COLORS.gray
|
|
11510
|
+
// Processing indicator
|
|
11411
11511
|
},
|
|
11412
|
-
// Severity colors
|
|
11413
|
-
semantic: {
|
|
11414
|
-
critical: "#7f1d1d",
|
|
11415
|
-
// Dark red
|
|
11416
|
-
high: "#ef4444",
|
|
11417
|
-
// Red
|
|
11418
|
-
medium: "#f97316",
|
|
11419
|
-
// Orange
|
|
11420
|
-
low: "#eab308",
|
|
11421
|
-
// Yellow
|
|
11422
|
-
info: "#1d4ed8"
|
|
11423
|
-
// Blue 700
|
|
11424
|
-
},
|
|
11425
|
-
// Border colors
|
|
11426
11512
|
border: {
|
|
11427
|
-
|
|
11428
|
-
|
|
11429
|
-
|
|
11430
|
-
error:
|
|
11431
|
-
success: "#22c55e"
|
|
11432
|
-
},
|
|
11433
|
-
// Phase colors (deep blue-focused)
|
|
11434
|
-
phase: {
|
|
11435
|
-
recon: "#94a3b8",
|
|
11436
|
-
enum: "#1d4ed8",
|
|
11437
|
-
// Blue 700 (phase indicator)
|
|
11438
|
-
vuln: "#f59e0b",
|
|
11439
|
-
exploit: "#ef4444",
|
|
11440
|
-
privesc: "#8b5cf6",
|
|
11441
|
-
persist: "#22c55e",
|
|
11442
|
-
report: "#64748b"
|
|
11513
|
+
// ANSI 241 is a medium slate gray for borders
|
|
11514
|
+
default: "ansi256(241)",
|
|
11515
|
+
focus: COLORS.primary,
|
|
11516
|
+
error: COLORS.red
|
|
11443
11517
|
},
|
|
11444
|
-
// Accent colors (NO cyan/teal - pure blue palette)
|
|
11445
|
-
accent: {
|
|
11446
|
-
pink: "#f472b6",
|
|
11447
|
-
rose: "#fb7185",
|
|
11448
|
-
fuchsia: "#e879f9",
|
|
11449
|
-
purple: "#a78bfa",
|
|
11450
|
-
violet: "#8b5cf6",
|
|
11451
|
-
indigo: "#818cf8",
|
|
11452
|
-
blue: "#1d4ed8",
|
|
11453
|
-
// Blue 700 - primary accent
|
|
11454
|
-
emerald: "#34d399",
|
|
11455
|
-
green: "#4ade80",
|
|
11456
|
-
lime: "#a3e635",
|
|
11457
|
-
yellow: "#facc15",
|
|
11458
|
-
amber: "#fbbf24",
|
|
11459
|
-
orange: "#fb923c",
|
|
11460
|
-
red: "#f87171"
|
|
11461
|
-
},
|
|
11462
|
-
// Gradients (deep blue-focused)
|
|
11463
11518
|
gradient: {
|
|
11464
|
-
|
|
11465
|
-
|
|
11466
|
-
// Blue 500
|
|
11467
|
-
"#3584f4",
|
|
11468
|
-
"#2f86f2",
|
|
11469
|
-
"#2988f0",
|
|
11470
|
-
"#238aee",
|
|
11471
|
-
"#1d8cec",
|
|
11472
|
-
// Mid blue
|
|
11473
|
-
"#1d7ad8",
|
|
11474
|
-
"#1d78c6",
|
|
11475
|
-
"#1d76b4",
|
|
11476
|
-
"#1d74a2",
|
|
11477
|
-
"#1e40af"
|
|
11478
|
-
// Blue 800
|
|
11479
|
-
],
|
|
11480
|
-
danger: ["#ef4444", "#7f1d1d"],
|
|
11481
|
-
success: ["#22c55e", "#14532d"],
|
|
11482
|
-
gold: ["#f59e0b", "#78350f"],
|
|
11483
|
-
royal: ["#818cf8", "#312e81"]
|
|
11519
|
+
// Hex colors required for gradient-string
|
|
11520
|
+
cyber: [HEX.primary, HEX.pink, HEX.peach]
|
|
11484
11521
|
},
|
|
11485
|
-
|
|
11486
|
-
spinner: "#3b82f6",
|
|
11487
|
-
// Blue 500
|
|
11488
|
-
// Identity color (branded accent - deep blue)
|
|
11489
|
-
identity: "#1d4ed8"
|
|
11490
|
-
// Blue 700
|
|
11522
|
+
spinner: COLORS.primary
|
|
11491
11523
|
};
|
|
11492
11524
|
var ASCII_BANNER = `
|
|
11493
|
-
|
|
11494
|
-
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11525
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
11526
|
+
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
|
|
11527
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557
|
|
11528
|
+
\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551
|
|
11529
|
+
\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
|
|
11530
|
+
\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D
|
|
11499
11531
|
`;
|
|
11500
11532
|
var ICONS = {
|
|
11501
11533
|
// Status
|
|
@@ -11509,7 +11541,7 @@ var ICONS = {
|
|
|
11509
11541
|
target: "\u25C8",
|
|
11510
11542
|
// Diamond for target
|
|
11511
11543
|
scan: "\u25CE",
|
|
11512
|
-
exploit: "\
|
|
11544
|
+
exploit: "\u2607",
|
|
11513
11545
|
shell: "\u276F",
|
|
11514
11546
|
// Progress
|
|
11515
11547
|
pending: "\u25CB",
|
|
@@ -11521,9 +11553,9 @@ var ICONS = {
|
|
|
11521
11553
|
medium: "\u25C7",
|
|
11522
11554
|
low: "\u25E6",
|
|
11523
11555
|
// Security
|
|
11524
|
-
lock: "\
|
|
11525
|
-
unlock: "\
|
|
11526
|
-
key: "\
|
|
11556
|
+
lock: "\u22A1",
|
|
11557
|
+
unlock: "\u2B1A",
|
|
11558
|
+
key: "\u26B7",
|
|
11527
11559
|
flag: "\u2691",
|
|
11528
11560
|
// Simple flag
|
|
11529
11561
|
pwned: "\u25C8"
|
|
@@ -11573,14 +11605,22 @@ var TUI_DISPLAY_LIMITS = {
|
|
|
11573
11605
|
};
|
|
11574
11606
|
var MESSAGE_STYLES = {
|
|
11575
11607
|
colors: {
|
|
11576
|
-
user: THEME.
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11608
|
+
user: THEME.white,
|
|
11609
|
+
// User input - bright white
|
|
11610
|
+
assistant: THEME.white,
|
|
11611
|
+
// AI response - white
|
|
11612
|
+
ai: THEME.white,
|
|
11613
|
+
// AI response - white
|
|
11614
|
+
system: THEME.gray,
|
|
11615
|
+
// System - light gray
|
|
11616
|
+
error: THEME.red,
|
|
11617
|
+
// Errors - red
|
|
11618
|
+
tool: THEME.gray,
|
|
11619
|
+
// Tool commands - light gray
|
|
11620
|
+
result: THEME.gray,
|
|
11621
|
+
// Tool results - light gray
|
|
11622
|
+
status: THEME.primary
|
|
11623
|
+
// Status - pastel red accent
|
|
11584
11624
|
},
|
|
11585
11625
|
prefixes: {
|
|
11586
11626
|
user: "\u276F",
|
|
@@ -11641,21 +11681,9 @@ var useAgentState = () => {
|
|
|
11641
11681
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
11642
11682
|
const [currentStatus, setCurrentStatus] = useState("");
|
|
11643
11683
|
const [elapsedTime, setElapsedTime] = useState(0);
|
|
11644
|
-
const [retryState, setRetryState] = useState({
|
|
11645
|
-
isRetrying: false,
|
|
11646
|
-
attempt: 0,
|
|
11647
|
-
maxRetries: 0,
|
|
11648
|
-
delayMs: 0,
|
|
11649
|
-
error: "",
|
|
11650
|
-
countdown: 0
|
|
11651
|
-
});
|
|
11684
|
+
const [retryState, setRetryState] = useState({ status: "idle" });
|
|
11652
11685
|
const [currentTokens, setCurrentTokens] = useState(0);
|
|
11653
|
-
const [inputRequest, setInputRequest] = useState({
|
|
11654
|
-
isActive: false,
|
|
11655
|
-
prompt: "",
|
|
11656
|
-
isPassword: false,
|
|
11657
|
-
resolve: null
|
|
11658
|
-
});
|
|
11686
|
+
const [inputRequest, setInputRequest] = useState({ status: "inactive" });
|
|
11659
11687
|
const [stats, setStats] = useState({ phase: DEFAULTS.INIT_PHASE, targets: 0, findings: 0, todo: 0 });
|
|
11660
11688
|
const lastResponseMetaRef = useRef(null);
|
|
11661
11689
|
const startTimeRef = useRef(0);
|
|
@@ -11796,7 +11824,7 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11796
11824
|
const isPassword = /password|passphrase/i.test(p);
|
|
11797
11825
|
const inputType = /sudo/i.test(p) ? "sudo_password" : isPassword ? "password" : "text";
|
|
11798
11826
|
setInputRequest({
|
|
11799
|
-
|
|
11827
|
+
status: "active",
|
|
11800
11828
|
prompt: p.trim(),
|
|
11801
11829
|
isPassword,
|
|
11802
11830
|
inputType,
|
|
@@ -11810,7 +11838,7 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11810
11838
|
const isPassword = hiddenTypes.includes(request.type);
|
|
11811
11839
|
const displayPrompt = buildCredentialPrompt(request);
|
|
11812
11840
|
setInputRequest({
|
|
11813
|
-
|
|
11841
|
+
status: "active",
|
|
11814
11842
|
prompt: displayPrompt,
|
|
11815
11843
|
isPassword,
|
|
11816
11844
|
inputType: request.type,
|
|
@@ -11891,7 +11919,7 @@ function handleRetry(e, addMessage, setRetryState, retryCountdownRef, retryCount
|
|
|
11891
11919
|
const retryNum = retryCountRef.current;
|
|
11892
11920
|
addMessage("system", `\u27F3 Retry #${retryNum} \xB7 ${e.data.error} \xB7 waiting ${delaySec}s...`);
|
|
11893
11921
|
setRetryState({
|
|
11894
|
-
|
|
11922
|
+
status: "retrying",
|
|
11895
11923
|
attempt: retryNum,
|
|
11896
11924
|
maxRetries: e.data.maxRetries,
|
|
11897
11925
|
delayMs: e.data.delayMs,
|
|
@@ -11903,10 +11931,10 @@ function handleRetry(e, addMessage, setRetryState, retryCountdownRef, retryCount
|
|
|
11903
11931
|
retryCountdownRef.current = setInterval(() => {
|
|
11904
11932
|
remaining -= 1;
|
|
11905
11933
|
if (remaining <= 0) {
|
|
11906
|
-
setRetryState(
|
|
11934
|
+
setRetryState({ status: "idle" });
|
|
11907
11935
|
if (retryCountdownRef.current) clearInterval(retryCountdownRef.current);
|
|
11908
11936
|
} else {
|
|
11909
|
-
setRetryState((prev) =>
|
|
11937
|
+
setRetryState((prev) => prev.status === "retrying" ? { ...prev, countdown: remaining } : prev);
|
|
11910
11938
|
}
|
|
11911
11939
|
}, 1e3);
|
|
11912
11940
|
}
|
|
@@ -12001,9 +12029,9 @@ var useAgent = (shouldAutoApprove, target) => {
|
|
|
12001
12029
|
inputRequestRef.current = inputRequest;
|
|
12002
12030
|
const cancelInputRequest = useCallback2(() => {
|
|
12003
12031
|
const ir = inputRequestRef.current;
|
|
12004
|
-
if (ir.
|
|
12032
|
+
if (ir.status === "active") {
|
|
12005
12033
|
ir.resolve(null);
|
|
12006
|
-
setInputRequest({
|
|
12034
|
+
setInputRequest({ status: "inactive" });
|
|
12007
12035
|
addMessage("system", "Input cancelled");
|
|
12008
12036
|
}
|
|
12009
12037
|
}, [setInputRequest, addMessage]);
|
|
@@ -12045,7 +12073,7 @@ import { Box as Box2, Text as Text2, Static } from "ink";
|
|
|
12045
12073
|
// src/platform/tui/components/inline-status.tsx
|
|
12046
12074
|
import { Box, Text } from "ink";
|
|
12047
12075
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12048
|
-
function
|
|
12076
|
+
function formatDuration3(ms) {
|
|
12049
12077
|
const seconds = Math.floor(ms / 1e3);
|
|
12050
12078
|
if (seconds < 60) return `${seconds}s`;
|
|
12051
12079
|
const minutes = Math.floor(seconds / 60);
|
|
@@ -12057,43 +12085,43 @@ function formatDuration2(ms) {
|
|
|
12057
12085
|
}
|
|
12058
12086
|
function getRoleColor(role) {
|
|
12059
12087
|
const roleColors = {
|
|
12060
|
-
listener: THEME.
|
|
12061
|
-
active_shell: THEME.
|
|
12062
|
-
server: THEME.
|
|
12063
|
-
sniffer: THEME.
|
|
12064
|
-
spoofer: THEME.
|
|
12065
|
-
proxy: THEME.
|
|
12066
|
-
callback: THEME.
|
|
12067
|
-
background: THEME.
|
|
12088
|
+
listener: THEME.primary,
|
|
12089
|
+
active_shell: THEME.primary,
|
|
12090
|
+
server: THEME.gray,
|
|
12091
|
+
sniffer: THEME.yellow,
|
|
12092
|
+
spoofer: THEME.yellow,
|
|
12093
|
+
proxy: THEME.primary,
|
|
12094
|
+
callback: THEME.primary,
|
|
12095
|
+
background: THEME.gray
|
|
12068
12096
|
};
|
|
12069
|
-
return roleColors[role] || THEME.
|
|
12097
|
+
return roleColors[role] || THEME.gray;
|
|
12070
12098
|
}
|
|
12071
12099
|
function StatusIndicator({ running, exitCode }) {
|
|
12072
12100
|
if (running) {
|
|
12073
|
-
return /* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12101
|
+
return /* @__PURE__ */ jsxs(Text, { color: THEME.primary, children: [
|
|
12074
12102
|
ICONS.running,
|
|
12075
12103
|
" "
|
|
12076
12104
|
] });
|
|
12077
12105
|
}
|
|
12078
12106
|
if (exitCode === 0) {
|
|
12079
|
-
return /* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12107
|
+
return /* @__PURE__ */ jsxs(Text, { color: THEME.gray, children: [
|
|
12080
12108
|
ICONS.success,
|
|
12081
12109
|
" "
|
|
12082
12110
|
] });
|
|
12083
12111
|
}
|
|
12084
|
-
return /* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12112
|
+
return /* @__PURE__ */ jsxs(Text, { color: THEME.red, children: [
|
|
12085
12113
|
ICONS.error,
|
|
12086
12114
|
" "
|
|
12087
12115
|
] });
|
|
12088
12116
|
}
|
|
12089
12117
|
function ProcessRow({ proc, compact }) {
|
|
12090
|
-
const duration =
|
|
12118
|
+
const duration = formatDuration3(proc.durationMs);
|
|
12091
12119
|
const port = proc.listeningPort ? `:${proc.listeningPort}` : "";
|
|
12092
12120
|
const purpose = proc.purpose || proc.description || "";
|
|
12093
12121
|
const truncatedPurpose = compact && purpose.length > TUI_DISPLAY_LIMITS.purposeMaxLength ? purpose.slice(0, TUI_DISPLAY_LIMITS.purposeTruncated) + "..." : purpose;
|
|
12094
12122
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
12095
12123
|
/* @__PURE__ */ jsx(StatusIndicator, { running: proc.running, exitCode: proc.exitCode }),
|
|
12096
|
-
/* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12124
|
+
/* @__PURE__ */ jsxs(Text, { color: THEME.gray, children: [
|
|
12097
12125
|
"[",
|
|
12098
12126
|
proc.id,
|
|
12099
12127
|
"]"
|
|
@@ -12103,14 +12131,14 @@ function ProcessRow({ proc, compact }) {
|
|
|
12103
12131
|
proc.role,
|
|
12104
12132
|
port
|
|
12105
12133
|
] }),
|
|
12106
|
-
/* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12134
|
+
/* @__PURE__ */ jsxs(Text, { color: THEME.gray, children: [
|
|
12107
12135
|
" (",
|
|
12108
12136
|
duration,
|
|
12109
12137
|
")"
|
|
12110
12138
|
] }),
|
|
12111
12139
|
truncatedPurpose && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12112
|
-
/* @__PURE__ */ jsx(Text, { color: THEME.
|
|
12113
|
-
/* @__PURE__ */ jsx(Text, { color: THEME.
|
|
12140
|
+
/* @__PURE__ */ jsx(Text, { color: THEME.gray, children: " - " }),
|
|
12141
|
+
/* @__PURE__ */ jsx(Text, { color: THEME.gray, children: truncatedPurpose })
|
|
12114
12142
|
] })
|
|
12115
12143
|
] });
|
|
12116
12144
|
}
|
|
@@ -12121,18 +12149,18 @@ var InlineStatus = ({
|
|
|
12121
12149
|
compact = true
|
|
12122
12150
|
}) => {
|
|
12123
12151
|
if (processes.length === 0 && zombies.length === 0) {
|
|
12124
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: THEME.
|
|
12152
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: THEME.gray, children: "\u2022 No active background processes" }) });
|
|
12125
12153
|
}
|
|
12126
12154
|
const running = processes.filter((p) => p.running);
|
|
12127
12155
|
const stopped = processes.filter((p) => !p.running);
|
|
12128
12156
|
const healthColor = {
|
|
12129
|
-
healthy: THEME.
|
|
12130
|
-
warning: THEME.
|
|
12131
|
-
critical: THEME.
|
|
12157
|
+
healthy: THEME.gray,
|
|
12158
|
+
warning: THEME.yellow,
|
|
12159
|
+
critical: THEME.red
|
|
12132
12160
|
}[health];
|
|
12133
12161
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
12134
12162
|
running.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
12135
|
-
/* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12163
|
+
/* @__PURE__ */ jsxs(Text, { color: THEME.gray, bold: true, children: [
|
|
12136
12164
|
ICONS.running,
|
|
12137
12165
|
" Active (",
|
|
12138
12166
|
running.length,
|
|
@@ -12141,46 +12169,46 @@ var InlineStatus = ({
|
|
|
12141
12169
|
running.map((proc) => /* @__PURE__ */ jsx(ProcessRow, { proc, compact }, proc.id))
|
|
12142
12170
|
] }),
|
|
12143
12171
|
stopped.length > 0 && !compact && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: running.length > 0 ? 1 : 0, children: [
|
|
12144
|
-
/* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12172
|
+
/* @__PURE__ */ jsxs(Text, { color: THEME.gray, children: [
|
|
12145
12173
|
ICONS.completed,
|
|
12146
12174
|
" Completed (",
|
|
12147
12175
|
stopped.length,
|
|
12148
12176
|
")"
|
|
12149
12177
|
] }),
|
|
12150
12178
|
stopped.slice(0, TUI_DISPLAY_LIMITS.maxStoppedProcesses).map((proc) => /* @__PURE__ */ jsx(ProcessRow, { proc, compact }, proc.id)),
|
|
12151
|
-
stopped.length > TUI_DISPLAY_LIMITS.maxStoppedProcesses && /* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12179
|
+
stopped.length > TUI_DISPLAY_LIMITS.maxStoppedProcesses && /* @__PURE__ */ jsxs(Text, { color: THEME.gray, children: [
|
|
12152
12180
|
" ... and ",
|
|
12153
12181
|
stopped.length - TUI_DISPLAY_LIMITS.maxStoppedProcesses,
|
|
12154
12182
|
" more"
|
|
12155
12183
|
] })
|
|
12156
12184
|
] }),
|
|
12157
12185
|
zombies.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
12158
|
-
/* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12186
|
+
/* @__PURE__ */ jsxs(Text, { color: THEME.yellow, children: [
|
|
12159
12187
|
ICONS.warning,
|
|
12160
12188
|
" Zombie Processes (",
|
|
12161
12189
|
zombies.length,
|
|
12162
12190
|
")"
|
|
12163
12191
|
] }),
|
|
12164
12192
|
zombies.map((z) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
12165
|
-
/* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12193
|
+
/* @__PURE__ */ jsxs(Text, { color: THEME.red, children: [
|
|
12166
12194
|
" ",
|
|
12167
12195
|
ICONS.error,
|
|
12168
12196
|
" "
|
|
12169
12197
|
] }),
|
|
12170
|
-
/* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12198
|
+
/* @__PURE__ */ jsxs(Text, { color: THEME.gray, children: [
|
|
12171
12199
|
"[",
|
|
12172
12200
|
z.processId,
|
|
12173
12201
|
"] "
|
|
12174
12202
|
] }),
|
|
12175
|
-
/* @__PURE__ */ jsxs(Text, { color: THEME.
|
|
12203
|
+
/* @__PURE__ */ jsxs(Text, { color: THEME.yellow, children: [
|
|
12176
12204
|
z.orphanedChildren.length,
|
|
12177
12205
|
" orphaned children"
|
|
12178
12206
|
] })
|
|
12179
12207
|
] }, z.processId)),
|
|
12180
|
-
/* @__PURE__ */ jsx(Text, { color: THEME.
|
|
12208
|
+
/* @__PURE__ */ jsx(Text, { color: THEME.gray, children: " Run /cleanup to terminate" })
|
|
12181
12209
|
] }),
|
|
12182
12210
|
/* @__PURE__ */ jsxs(Box, { marginTop: running.length > 0 ? 1 : 0, children: [
|
|
12183
|
-
/* @__PURE__ */ jsx(Text, { color: THEME.
|
|
12211
|
+
/* @__PURE__ */ jsx(Text, { color: THEME.gray, children: "Health: " }),
|
|
12184
12212
|
/* @__PURE__ */ jsx(Text, { color: healthColor, bold: true, children: health.toUpperCase() })
|
|
12185
12213
|
] })
|
|
12186
12214
|
] });
|
|
@@ -12234,7 +12262,7 @@ import { useState as useState3, useEffect as useEffect3, memo as memo2 } from "r
|
|
|
12234
12262
|
import { Text as Text3 } from "ink";
|
|
12235
12263
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
12236
12264
|
var FRAMES = ["\u2669", "\u266A", "\u266B", "\u266C", "\u266B", "\u266A"];
|
|
12237
|
-
var INTERVAL =
|
|
12265
|
+
var INTERVAL = 120;
|
|
12238
12266
|
var MusicSpinner = memo2(({ color }) => {
|
|
12239
12267
|
const [index, setIndex] = useState3(0);
|
|
12240
12268
|
useEffect3(() => {
|
|
@@ -12260,29 +12288,29 @@ var StatusDisplay = memo3(({
|
|
|
12260
12288
|
};
|
|
12261
12289
|
const meta = formatMeta(elapsedTime * 1e3, currentTokens);
|
|
12262
12290
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 0, children: [
|
|
12263
|
-
retryState.
|
|
12264
|
-
/* @__PURE__ */ jsx4(Text4, { color: THEME.
|
|
12265
|
-
/* @__PURE__ */ jsxs3(Text4, { color: THEME.
|
|
12291
|
+
retryState.status === "retrying" && /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
|
|
12292
|
+
/* @__PURE__ */ jsx4(Text4, { color: THEME.yellow, children: /* @__PURE__ */ jsx4(MusicSpinner, { color: THEME.yellow }) }),
|
|
12293
|
+
/* @__PURE__ */ jsxs3(Text4, { color: THEME.yellow, children: [
|
|
12266
12294
|
" \u27F3 Retry #",
|
|
12267
12295
|
retryState.attempt
|
|
12268
12296
|
] }),
|
|
12269
|
-
/* @__PURE__ */ jsxs3(Text4, { color: THEME.
|
|
12297
|
+
/* @__PURE__ */ jsxs3(Text4, { color: THEME.gray, children: [
|
|
12270
12298
|
" \xB7 ",
|
|
12271
12299
|
truncateError(retryState.error)
|
|
12272
12300
|
] }),
|
|
12273
|
-
/* @__PURE__ */ jsxs3(Text4, { color: THEME.
|
|
12301
|
+
/* @__PURE__ */ jsxs3(Text4, { color: THEME.primary, bold: true, children: [
|
|
12274
12302
|
" \xB7 ",
|
|
12275
12303
|
retryState.countdown,
|
|
12276
12304
|
"s"
|
|
12277
12305
|
] })
|
|
12278
12306
|
] }),
|
|
12279
|
-
isProcessing &&
|
|
12280
|
-
/* @__PURE__ */ jsx4(Text4, { color: THEME.
|
|
12281
|
-
/* @__PURE__ */ jsxs3(Text4, { color: THEME.
|
|
12307
|
+
isProcessing && retryState.status !== "retrying" && /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
|
|
12308
|
+
/* @__PURE__ */ jsx4(Text4, { color: THEME.primary, children: /* @__PURE__ */ jsx4(MusicSpinner, { color: THEME.primary }) }),
|
|
12309
|
+
/* @__PURE__ */ jsxs3(Text4, { color: THEME.gray, children: [
|
|
12282
12310
|
" ",
|
|
12283
12311
|
currentStatus || "Processing"
|
|
12284
12312
|
] }),
|
|
12285
|
-
/* @__PURE__ */ jsxs3(Text4, { color: THEME.
|
|
12313
|
+
/* @__PURE__ */ jsxs3(Text4, { color: THEME.gray, children: [
|
|
12286
12314
|
" ",
|
|
12287
12315
|
meta
|
|
12288
12316
|
] })
|
|
@@ -12325,25 +12353,28 @@ var ChatInput = memo4(({
|
|
|
12325
12353
|
const onChangeRef = useRef3(onChange);
|
|
12326
12354
|
onChangeRef.current = onChange;
|
|
12327
12355
|
useInput(useCallback3((_input, key) => {
|
|
12328
|
-
if (inputRequestRef.current.
|
|
12356
|
+
if (inputRequestRef.current.status === "active") return;
|
|
12329
12357
|
if (key.tab && isSlashModeRef.current && !hasArgsRef.current && suggestionsRef.current.length > 0) {
|
|
12330
12358
|
const best = suggestionsRef.current[0];
|
|
12331
12359
|
const argsHint = best.args ? " " : "";
|
|
12332
|
-
|
|
12360
|
+
const completed = `/${best.name}${argsHint}`;
|
|
12361
|
+
onChangeRef.current("");
|
|
12362
|
+
setTimeout(() => onChangeRef.current(completed), 0);
|
|
12333
12363
|
}
|
|
12334
12364
|
}, []));
|
|
12335
12365
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
12336
|
-
|
|
12366
|
+
/* @__PURE__ */ jsx5(
|
|
12337
12367
|
Box4,
|
|
12338
12368
|
{
|
|
12339
12369
|
flexDirection: "column",
|
|
12340
|
-
borderStyle: "single",
|
|
12341
|
-
borderColor: THEME.border.default,
|
|
12342
|
-
paddingX: 1,
|
|
12370
|
+
borderStyle: showPreview ? "single" : void 0,
|
|
12371
|
+
borderColor: showPreview ? THEME.border.default : void 0,
|
|
12372
|
+
paddingX: showPreview ? 1 : 0,
|
|
12343
12373
|
marginBottom: 0,
|
|
12344
|
-
|
|
12374
|
+
height: showPreview ? void 0 : 0,
|
|
12375
|
+
children: showPreview && suggestions.map((cmd, i) => {
|
|
12345
12376
|
const isFirst = i === 0;
|
|
12346
|
-
const nameColor = isFirst ? THEME.
|
|
12377
|
+
const nameColor = isFirst ? THEME.white : THEME.gray;
|
|
12347
12378
|
const aliasText = cmd.alias ? ` /${cmd.alias}` : "";
|
|
12348
12379
|
const argsText = cmd.args ? ` ${cmd.args}` : "";
|
|
12349
12380
|
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
@@ -12351,13 +12382,13 @@ var ChatInput = memo4(({
|
|
|
12351
12382
|
"/",
|
|
12352
12383
|
cmd.name
|
|
12353
12384
|
] }),
|
|
12354
|
-
/* @__PURE__ */ jsx5(Text5, { color: THEME.
|
|
12355
|
-
aliasText && /* @__PURE__ */ jsx5(Text5, { color: THEME.
|
|
12356
|
-
/* @__PURE__ */ jsxs4(Text5, { color: THEME.
|
|
12385
|
+
/* @__PURE__ */ jsx5(Text5, { color: THEME.gray, children: argsText }),
|
|
12386
|
+
aliasText && /* @__PURE__ */ jsx5(Text5, { color: THEME.gray, children: aliasText }),
|
|
12387
|
+
/* @__PURE__ */ jsxs4(Text5, { color: THEME.gray, children: [
|
|
12357
12388
|
" \u2014 ",
|
|
12358
12389
|
cmd.description
|
|
12359
12390
|
] }),
|
|
12360
|
-
isFirst && /* @__PURE__ */ jsx5(Text5, { color: THEME.
|
|
12391
|
+
isFirst && /* @__PURE__ */ jsx5(Text5, { color: THEME.primary, children: " [Tab]" })
|
|
12361
12392
|
] }, cmd.name);
|
|
12362
12393
|
})
|
|
12363
12394
|
}
|
|
@@ -12366,11 +12397,11 @@ var ChatInput = memo4(({
|
|
|
12366
12397
|
Box4,
|
|
12367
12398
|
{
|
|
12368
12399
|
borderStyle: "single",
|
|
12369
|
-
borderColor: inputRequest.
|
|
12400
|
+
borderColor: inputRequest.status === "active" ? THEME.yellow : THEME.border.default,
|
|
12370
12401
|
paddingX: 1,
|
|
12371
|
-
children: inputRequest.
|
|
12372
|
-
/* @__PURE__ */ jsx5(Text5, { color: THEME.
|
|
12373
|
-
/* @__PURE__ */ jsxs4(Text5, { color: THEME.
|
|
12402
|
+
children: inputRequest.status === "active" ? /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
12403
|
+
/* @__PURE__ */ jsx5(Text5, { color: THEME.yellow, children: "[auth]" }),
|
|
12404
|
+
/* @__PURE__ */ jsxs4(Text5, { color: THEME.gray, children: [
|
|
12374
12405
|
" ",
|
|
12375
12406
|
inputRequest.prompt
|
|
12376
12407
|
] }),
|
|
@@ -12385,7 +12416,7 @@ var ChatInput = memo4(({
|
|
|
12385
12416
|
}
|
|
12386
12417
|
)
|
|
12387
12418
|
] }) : /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
12388
|
-
/* @__PURE__ */ jsx5(Text5, { color: THEME.
|
|
12419
|
+
/* @__PURE__ */ jsx5(Text5, { color: THEME.primary, children: "\u25B8" }),
|
|
12389
12420
|
/* @__PURE__ */ jsx5(Text5, { children: " " }),
|
|
12390
12421
|
/* @__PURE__ */ jsx5(
|
|
12391
12422
|
TextInput,
|
|
@@ -12425,26 +12456,26 @@ var Footer = memo5(({ phase, targets, findings, todo, elapsedTime, isProcessing
|
|
|
12425
12456
|
justifyContent: "space-between",
|
|
12426
12457
|
children: [
|
|
12427
12458
|
/* @__PURE__ */ jsxs5(Box5, { gap: 2, children: [
|
|
12428
|
-
/* @__PURE__ */ jsxs5(Text6, { color: THEME.
|
|
12459
|
+
/* @__PURE__ */ jsxs5(Text6, { color: THEME.gray, children: [
|
|
12429
12460
|
"Phase: ",
|
|
12430
|
-
/* @__PURE__ */ jsx6(Text6, { color: THEME.
|
|
12461
|
+
/* @__PURE__ */ jsx6(Text6, { color: THEME.white, children: phase })
|
|
12431
12462
|
] }),
|
|
12432
|
-
/* @__PURE__ */ jsxs5(Text6, { color: THEME.
|
|
12463
|
+
/* @__PURE__ */ jsxs5(Text6, { color: THEME.gray, children: [
|
|
12433
12464
|
"Targets: ",
|
|
12434
|
-
/* @__PURE__ */ jsx6(Text6, { color: THEME.
|
|
12465
|
+
/* @__PURE__ */ jsx6(Text6, { color: THEME.white, children: targets })
|
|
12435
12466
|
] }),
|
|
12436
|
-
/* @__PURE__ */ jsxs5(Text6, { color: THEME.
|
|
12467
|
+
/* @__PURE__ */ jsxs5(Text6, { color: THEME.gray, children: [
|
|
12437
12468
|
"Findings: ",
|
|
12438
|
-
/* @__PURE__ */ jsx6(Text6, { color: THEME.
|
|
12469
|
+
/* @__PURE__ */ jsx6(Text6, { color: THEME.white, children: findings })
|
|
12439
12470
|
] }),
|
|
12440
|
-
/* @__PURE__ */ jsxs5(Text6, { color: THEME.
|
|
12471
|
+
/* @__PURE__ */ jsxs5(Text6, { color: THEME.gray, children: [
|
|
12441
12472
|
"Tasks: ",
|
|
12442
|
-
/* @__PURE__ */ jsx6(Text6, { color: THEME.
|
|
12473
|
+
/* @__PURE__ */ jsx6(Text6, { color: THEME.white, children: todo })
|
|
12443
12474
|
] })
|
|
12444
12475
|
] }),
|
|
12445
12476
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
12446
|
-
/* @__PURE__ */ jsx6(Text6, { color: isProcessing ? THEME.
|
|
12447
|
-
/* @__PURE__ */ jsx6(Text6, { color: THEME.
|
|
12477
|
+
/* @__PURE__ */ jsx6(Text6, { color: isProcessing ? THEME.primary : THEME.gray, children: isProcessing ? "Running " : "Idle " }),
|
|
12478
|
+
/* @__PURE__ */ jsx6(Text6, { color: THEME.white, children: formatElapsed(elapsedTime) })
|
|
12448
12479
|
] })
|
|
12449
12480
|
]
|
|
12450
12481
|
}
|
|
@@ -12485,7 +12516,7 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
12485
12516
|
inputRequestRef.current = inputRequest;
|
|
12486
12517
|
const handleExit = useCallback4(() => {
|
|
12487
12518
|
const ir = inputRequestRef.current;
|
|
12488
|
-
if (ir.
|
|
12519
|
+
if (ir.status === "active") ir.resolve(null);
|
|
12489
12520
|
cleanupAllProcesses().catch(() => {
|
|
12490
12521
|
});
|
|
12491
12522
|
exit();
|
|
@@ -12549,8 +12580,29 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
12549
12580
|
addMessage("system", "No findings.");
|
|
12550
12581
|
break;
|
|
12551
12582
|
}
|
|
12552
|
-
|
|
12553
|
-
findings.forEach((f) =>
|
|
12583
|
+
const findingLines = [`\u2500\u2500\u2500 ${findings.length} Findings \u2500\u2500\u2500`, ""];
|
|
12584
|
+
findings.forEach((f, i) => {
|
|
12585
|
+
const verified = f.isVerified ? `[${ICONS.success}] Verified` : `[${ICONS.warning}] Unverified`;
|
|
12586
|
+
const atk = f.attackPattern ? ` | ATT&CK: ${f.attackPattern}` : "";
|
|
12587
|
+
findingLines.push(`[${i + 1}] [${f.severity.toUpperCase()}] ${f.title}`);
|
|
12588
|
+
findingLines.push(` ${verified}${atk}`);
|
|
12589
|
+
if (f.affected.length > 0) {
|
|
12590
|
+
findingLines.push(` Affected: ${f.affected.join(", ")}`);
|
|
12591
|
+
}
|
|
12592
|
+
if (f.description) {
|
|
12593
|
+
findingLines.push(` ${f.description}`);
|
|
12594
|
+
}
|
|
12595
|
+
if (f.evidence.length > 0) {
|
|
12596
|
+
findingLines.push(` Evidence:`);
|
|
12597
|
+
f.evidence.slice(0, 3).forEach((e) => {
|
|
12598
|
+
const preview = e.length > 120 ? e.slice(0, 120) + "..." : e;
|
|
12599
|
+
findingLines.push(` \u25B8 ${preview}`);
|
|
12600
|
+
});
|
|
12601
|
+
if (f.evidence.length > 3) findingLines.push(` ... +${f.evidence.length - 3} more`);
|
|
12602
|
+
}
|
|
12603
|
+
findingLines.push("");
|
|
12604
|
+
});
|
|
12605
|
+
addMessage("system", findingLines.join("\n"));
|
|
12554
12606
|
break;
|
|
12555
12607
|
case UI_COMMANDS.ASSETS:
|
|
12556
12608
|
case UI_COMMANDS.ASSETS_SHORT:
|
|
@@ -12614,17 +12666,17 @@ ${procData.stdout || "(no output)"}
|
|
|
12614
12666
|
}, [addMessage, executeTask, handleCommand]);
|
|
12615
12667
|
const handleSecretSubmit = useCallback4((value) => {
|
|
12616
12668
|
const ir = inputRequestRef.current;
|
|
12617
|
-
if (
|
|
12669
|
+
if (ir.status !== "active") return;
|
|
12618
12670
|
const displayText = ir.isPassword ? "\u2022".repeat(value.length) : value;
|
|
12619
12671
|
const promptLabel = ir.prompt || "Input";
|
|
12620
12672
|
addMessage("system", `\u21B3 ${promptLabel} ${displayText}`);
|
|
12621
12673
|
ir.resolve(value);
|
|
12622
|
-
setInputRequest({
|
|
12674
|
+
setInputRequest({ status: "inactive" });
|
|
12623
12675
|
setSecretInput("");
|
|
12624
12676
|
}, [addMessage, setInputRequest]);
|
|
12625
12677
|
useInput2(useCallback4((ch, key) => {
|
|
12626
12678
|
if (key.escape) {
|
|
12627
|
-
if (inputRequestRef.current.
|
|
12679
|
+
if (inputRequestRef.current.status === "active") cancelInputRequest();
|
|
12628
12680
|
else if (isProcessingRef.current) abort();
|
|
12629
12681
|
}
|
|
12630
12682
|
if (key.ctrl && ch === "c") handleExit();
|
|
@@ -12711,9 +12763,9 @@ program.command("interactive", { isDefault: true }).alias("i").description("Star
|
|
|
12711
12763
|
const opts = program.opts();
|
|
12712
12764
|
const skipPermissions = opts.dangerouslySkipPermissions || false;
|
|
12713
12765
|
console.clear();
|
|
12714
|
-
console.log(
|
|
12766
|
+
console.log(chalk.hex(THEME.primary)(ASCII_BANNER));
|
|
12715
12767
|
console.log(
|
|
12716
|
-
" " + chalk.hex(THEME.text.secondary)(`v${APP_VERSION}`) + chalk.hex(THEME.text.muted)(" \u2502 ") + chalk.hex(THEME.
|
|
12768
|
+
" " + chalk.hex(THEME.text.secondary)(`v${APP_VERSION}`) + chalk.hex(THEME.text.muted)(" \u2502 ") + chalk.hex(THEME.primary)("Type /help for commands") + "\n"
|
|
12717
12769
|
);
|
|
12718
12770
|
if (skipPermissions) {
|
|
12719
12771
|
console.log(chalk.hex(THEME.status.error)("[!] WARNING: Running with --dangerously-skip-permissions"));
|
|
@@ -12733,11 +12785,11 @@ program.command("interactive", { isDefault: true }).alias("i").description("Star
|
|
|
12733
12785
|
program.command("run <objective>").alias("r").description("Run a single objective and exit").option("-o, --output <file>", "Output file for results").option("--max-steps <n>", "Maximum number of steps", String(CLI_DEFAULT.MAX_STEPS)).action(async (objective, options) => {
|
|
12734
12786
|
const opts = program.opts();
|
|
12735
12787
|
const skipPermissions = opts.dangerouslySkipPermissions || false;
|
|
12736
|
-
console.log(
|
|
12788
|
+
console.log(chalk.hex(THEME.primary)(ASCII_BANNER));
|
|
12737
12789
|
if (skipPermissions) {
|
|
12738
12790
|
console.log(chalk.hex(THEME.status.error)("[!] WARNING: Running with --dangerously-skip-permissions\n"));
|
|
12739
12791
|
}
|
|
12740
|
-
console.log(chalk.hex(THEME.
|
|
12792
|
+
console.log(chalk.hex(THEME.primary)(`[target] Objective: ${objective}
|
|
12741
12793
|
`));
|
|
12742
12794
|
const agent = AgentFactory.createMainAgent(skipPermissions);
|
|
12743
12795
|
if (skipPermissions) {
|
|
@@ -12759,7 +12811,7 @@ program.command("run <objective>").alias("r").description("Run a single objectiv
|
|
|
12759
12811
|
if (options.output) {
|
|
12760
12812
|
const fs = await import("fs/promises");
|
|
12761
12813
|
await fs.writeFile(options.output, JSON.stringify({ result: result2 }, null, 2));
|
|
12762
|
-
console.log(chalk.hex(THEME.
|
|
12814
|
+
console.log(chalk.hex(THEME.primary)(`
|
|
12763
12815
|
[+] Report saved to: ${options.output}`));
|
|
12764
12816
|
}
|
|
12765
12817
|
await shutdown(0);
|
|
@@ -12773,8 +12825,8 @@ program.command("run <objective>").alias("r").description("Run a single objectiv
|
|
|
12773
12825
|
program.command("scan <target>").description("Quick scan a target").option("-s, --scan-type <type>", `Scan type (${CLI_SCAN_TYPES.join("|")})`, CLI_DEFAULT.SCAN_TYPE).option("-p, --ports <ports>", "Specific ports to scan").action(async (target, options) => {
|
|
12774
12826
|
const opts = program.opts();
|
|
12775
12827
|
const skipPermissions = opts.dangerouslySkipPermissions || false;
|
|
12776
|
-
console.log(
|
|
12777
|
-
console.log(chalk.hex(THEME.
|
|
12828
|
+
console.log(chalk.hex(THEME.primary)(ASCII_BANNER));
|
|
12829
|
+
console.log(chalk.hex(THEME.primary)(`
|
|
12778
12830
|
[scan] Target: ${target} (${options.scanType})
|
|
12779
12831
|
`));
|
|
12780
12832
|
const agent = AgentFactory.createMainAgent(skipPermissions);
|
|
@@ -12796,11 +12848,11 @@ program.command("scan <target>").description("Quick scan a target").option("-s,
|
|
|
12796
12848
|
}
|
|
12797
12849
|
});
|
|
12798
12850
|
program.command("help-extended").description("Show extended help with examples").action(() => {
|
|
12799
|
-
console.log(
|
|
12851
|
+
console.log(chalk.hex(THEME.primary)(ASCII_BANNER));
|
|
12800
12852
|
console.log(`
|
|
12801
|
-
${chalk.hex(THEME.
|
|
12853
|
+
${chalk.hex(THEME.primary)(APP_NAME + " - Autonomous Penetration Testing AI")}
|
|
12802
12854
|
|
|
12803
|
-
${chalk.hex(THEME.status.warning)("Usage:")}
|
|
12855
|
+
${chalk.hex(THEME.status.warning)("Usage:")}
|
|
12804
12856
|
|
|
12805
12857
|
${chalk.hex(THEME.status.success)("$ pentesting")} Start interactive mode
|
|
12806
12858
|
${chalk.hex(THEME.status.success)("$ pentesting -t 192.168.1.1")} Start with target
|
|
@@ -12808,24 +12860,24 @@ ${chalk.hex(THEME.status.warning)("Usage:")}
|
|
|
12808
12860
|
|
|
12809
12861
|
${chalk.hex(THEME.status.warning)("Commands:")}
|
|
12810
12862
|
|
|
12811
|
-
${chalk.hex(THEME.
|
|
12812
|
-
${chalk.hex(THEME.
|
|
12813
|
-
${chalk.hex(THEME.
|
|
12863
|
+
${chalk.hex(THEME.primary)("pentesting")} Interactive TUI mode
|
|
12864
|
+
${chalk.hex(THEME.primary)("pentesting run <objective>")} Run single objective
|
|
12865
|
+
${chalk.hex(THEME.primary)("pentesting scan <target>")} Quick scan target
|
|
12814
12866
|
|
|
12815
12867
|
${chalk.hex(THEME.status.warning)("Options:")}
|
|
12816
12868
|
|
|
12817
|
-
${chalk.hex(THEME.
|
|
12818
|
-
${chalk.hex(THEME.
|
|
12819
|
-
${chalk.hex(THEME.
|
|
12869
|
+
${chalk.hex(THEME.primary)("--dangerously-skip-permissions")} Skip all permission prompts
|
|
12870
|
+
${chalk.hex(THEME.primary)("-t, --target <ip>")} Set target
|
|
12871
|
+
${chalk.hex(THEME.primary)("-o, --output <file>")} Save results to file
|
|
12820
12872
|
|
|
12821
12873
|
${chalk.hex(THEME.status.warning)("Interactive Commands:")}
|
|
12822
12874
|
|
|
12823
|
-
${chalk.hex(THEME.
|
|
12824
|
-
${chalk.hex(THEME.
|
|
12825
|
-
${chalk.hex(THEME.
|
|
12826
|
-
${chalk.hex(THEME.
|
|
12827
|
-
${chalk.hex(THEME.
|
|
12828
|
-
${chalk.hex(THEME.
|
|
12875
|
+
${chalk.hex(THEME.primary)("/target <ip>")} Set target
|
|
12876
|
+
${chalk.hex(THEME.primary)("/start")} Start autonomous mode
|
|
12877
|
+
${chalk.hex(THEME.primary)("/config")} Manage configuration
|
|
12878
|
+
${chalk.hex(THEME.primary)("/hint <text>")} Provide hint
|
|
12879
|
+
${chalk.hex(THEME.primary)("/findings")} Show findings
|
|
12880
|
+
${chalk.hex(THEME.primary)("/reset")} Reset session
|
|
12829
12881
|
|
|
12830
12882
|
${chalk.hex(THEME.status.warning)("Examples:")}
|
|
12831
12883
|
|
|
@@ -12840,9 +12892,9 @@ ${chalk.hex(THEME.status.warning)("Examples:")}
|
|
|
12840
12892
|
|
|
12841
12893
|
${chalk.hex(THEME.status.warning)("Environment:")}
|
|
12842
12894
|
|
|
12843
|
-
${chalk.hex(THEME.
|
|
12844
|
-
${chalk.hex(THEME.
|
|
12845
|
-
${chalk.hex(THEME.
|
|
12895
|
+
${chalk.hex(THEME.primary)("PENTEST_API_KEY")} Required - LLM API key
|
|
12896
|
+
${chalk.hex(THEME.primary)("PENTEST_BASE_URL")} Optional - AI API base URL
|
|
12897
|
+
${chalk.hex(THEME.primary)("PENTEST_MODEL")} Optional - Model override
|
|
12846
12898
|
`);
|
|
12847
12899
|
});
|
|
12848
12900
|
program.parse();
|