pentesting 0.7.41 → 0.7.44
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 +30 -1
- package/dist/index.js +319 -91
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -189,7 +189,20 @@ Complete
|
|
|
189
189
|
|
|
190
190
|
---
|
|
191
191
|
|
|
192
|
-
## 🤖
|
|
192
|
+
## 🤖 Agentic System (Dual Architecture)
|
|
193
|
+
|
|
194
|
+
### YAML-Based Agents (Primary)
|
|
195
|
+
New agents defined in `src/agents/specs/*.yaml` with auto-switching:
|
|
196
|
+
|
|
197
|
+
| YAML Agent | Phase | Description |
|
|
198
|
+
|------------|-------|-------------|
|
|
199
|
+
| `recon` | RECON, SCAN | Information gathering, port scanning |
|
|
200
|
+
| `web` | ENUM | Web application security, OWASP Top 10 |
|
|
201
|
+
| `exploit` | VULN, EXPLOIT | CVE research, exploit execution |
|
|
202
|
+
| `privesc` | PRIVESC, PIVOT, PERSIST | Privilege escalation techniques |
|
|
203
|
+
| `crypto` | EXFIL | Hash cracking, encryption analysis |
|
|
204
|
+
|
|
205
|
+
### Built-in Agents (Fallback)
|
|
193
206
|
|
|
194
207
|
| Agent | Specialty |
|
|
195
208
|
|-------|-----------|
|
|
@@ -203,6 +216,22 @@ Complete
|
|
|
203
216
|
| `attack-architect` | Attack strategy planning |
|
|
204
217
|
| `finding-reviewer` | Vulnerability validation |
|
|
205
218
|
|
|
219
|
+
### Agent Orchestration Flow
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
User Request → AutonomousHackingAgent
|
|
223
|
+
↓
|
|
224
|
+
Phase Change Detected (RECON → SCAN → ENUM → ...)
|
|
225
|
+
↓
|
|
226
|
+
autoSwitchAgentForPhase(phaseId)
|
|
227
|
+
├── Try YAML Agent First (SpecOrchestrator)
|
|
228
|
+
└── Fallback to Builtin Agent
|
|
229
|
+
↓
|
|
230
|
+
System Prompt = Base + Agent-Specific Instructions
|
|
231
|
+
↓
|
|
232
|
+
LLM Call with Specialized Context
|
|
233
|
+
```
|
|
234
|
+
|
|
206
235
|
---
|
|
207
236
|
|
|
208
237
|
## ⚙️ Configuration
|
package/dist/index.js
CHANGED
|
@@ -2440,7 +2440,7 @@ var HookExecutor = class extends EventEmitter {
|
|
|
2440
2440
|
}
|
|
2441
2441
|
// Execute single hook
|
|
2442
2442
|
async executeHook(hook, context) {
|
|
2443
|
-
return new Promise((
|
|
2443
|
+
return new Promise((resolve2) => {
|
|
2444
2444
|
const timeout = hook.timeout || 1e4;
|
|
2445
2445
|
let command = hook.command;
|
|
2446
2446
|
if (command.startsWith("./")) {
|
|
@@ -2479,7 +2479,7 @@ var HookExecutor = class extends EventEmitter {
|
|
|
2479
2479
|
decision = "modify";
|
|
2480
2480
|
reason = output.split("MODIFY:")[1]?.split("\n")[0]?.trim() || "";
|
|
2481
2481
|
}
|
|
2482
|
-
|
|
2482
|
+
resolve2({
|
|
2483
2483
|
success: code === 0,
|
|
2484
2484
|
output,
|
|
2485
2485
|
decision,
|
|
@@ -2487,7 +2487,7 @@ var HookExecutor = class extends EventEmitter {
|
|
|
2487
2487
|
});
|
|
2488
2488
|
});
|
|
2489
2489
|
proc.on("error", (error) => {
|
|
2490
|
-
|
|
2490
|
+
resolve2({
|
|
2491
2491
|
success: false,
|
|
2492
2492
|
output: error.message,
|
|
2493
2493
|
decision: "proceed"
|
|
@@ -2545,7 +2545,7 @@ var MCPClient = class extends EventEmitter2 {
|
|
|
2545
2545
|
}
|
|
2546
2546
|
// Start MCP server
|
|
2547
2547
|
async connect() {
|
|
2548
|
-
return new Promise((
|
|
2548
|
+
return new Promise((resolve2, reject) => {
|
|
2549
2549
|
const { command, args, env } = this.config;
|
|
2550
2550
|
this.process = spawn3(command, args || [], {
|
|
2551
2551
|
env: { ...process.env, ...env },
|
|
@@ -2576,7 +2576,7 @@ var MCPClient = class extends EventEmitter2 {
|
|
|
2576
2576
|
this.process.on("spawn", () => {
|
|
2577
2577
|
this.connected = true;
|
|
2578
2578
|
this.emit("connected", { server: this.serverName });
|
|
2579
|
-
|
|
2579
|
+
resolve2();
|
|
2580
2580
|
});
|
|
2581
2581
|
this.process.on("close", (code) => {
|
|
2582
2582
|
this.connected = false;
|
|
@@ -2596,8 +2596,8 @@ var MCPClient = class extends EventEmitter2 {
|
|
|
2596
2596
|
method,
|
|
2597
2597
|
params
|
|
2598
2598
|
};
|
|
2599
|
-
return new Promise((
|
|
2600
|
-
this.pendingRequests.set(id, { resolve, reject });
|
|
2599
|
+
return new Promise((resolve2, reject) => {
|
|
2600
|
+
this.pendingRequests.set(id, { resolve: resolve2, reject });
|
|
2601
2601
|
const line = JSON.stringify(request) + "\n";
|
|
2602
2602
|
this.process.stdin.write(line, (error) => {
|
|
2603
2603
|
if (error) {
|
|
@@ -2947,11 +2947,11 @@ var ApprovalManager = class extends EventEmitter3 {
|
|
|
2947
2947
|
};
|
|
2948
2948
|
this.pendingRequests.set(request.id, request);
|
|
2949
2949
|
this.emit(APPROVAL_EVENT.REQUEST, request);
|
|
2950
|
-
return new Promise((
|
|
2950
|
+
return new Promise((resolve2) => {
|
|
2951
2951
|
const timeout = setTimeout(() => {
|
|
2952
2952
|
this.pendingRequests.delete(request.id);
|
|
2953
2953
|
this.emit(APPROVAL_EVENT.TIMEOUT, request.id);
|
|
2954
|
-
|
|
2954
|
+
resolve2("deny");
|
|
2955
2955
|
}, this.defaultTimeout);
|
|
2956
2956
|
const responseHandler = (response) => {
|
|
2957
2957
|
if (response.requestId === request.id) {
|
|
@@ -2969,7 +2969,7 @@ var ApprovalManager = class extends EventEmitter3 {
|
|
|
2969
2969
|
respondedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2970
2970
|
});
|
|
2971
2971
|
}
|
|
2972
|
-
|
|
2972
|
+
resolve2("approve");
|
|
2973
2973
|
} else if (response.decision === "deny_always") {
|
|
2974
2974
|
this.autoDeniedTools.add(toolName);
|
|
2975
2975
|
const pendingForSameTool = Array.from(this.pendingRequests.entries()).filter(([_, req]) => req.toolName === toolName);
|
|
@@ -2981,9 +2981,9 @@ var ApprovalManager = class extends EventEmitter3 {
|
|
|
2981
2981
|
respondedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2982
2982
|
});
|
|
2983
2983
|
}
|
|
2984
|
-
|
|
2984
|
+
resolve2("deny");
|
|
2985
2985
|
} else {
|
|
2986
|
-
|
|
2986
|
+
resolve2(response.decision);
|
|
2987
2987
|
}
|
|
2988
2988
|
}
|
|
2989
2989
|
};
|
|
@@ -3033,7 +3033,7 @@ function getApprovalManager(options) {
|
|
|
3033
3033
|
import { spawn as spawn4 } from "child_process";
|
|
3034
3034
|
async function searchDuckDuckGo(query, options = {}) {
|
|
3035
3035
|
const { maxResults = 10, timeout = 3e4 } = options;
|
|
3036
|
-
return new Promise((
|
|
3036
|
+
return new Promise((resolve2) => {
|
|
3037
3037
|
const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
|
|
3038
3038
|
const proc = spawn4("curl", [
|
|
3039
3039
|
"-s",
|
|
@@ -3067,10 +3067,10 @@ async function searchDuckDuckGo(query, options = {}) {
|
|
|
3067
3067
|
snippet: snippets[i] || ""
|
|
3068
3068
|
});
|
|
3069
3069
|
}
|
|
3070
|
-
|
|
3070
|
+
resolve2(results);
|
|
3071
3071
|
});
|
|
3072
3072
|
proc.on("error", () => {
|
|
3073
|
-
|
|
3073
|
+
resolve2([]);
|
|
3074
3074
|
});
|
|
3075
3075
|
});
|
|
3076
3076
|
}
|
|
@@ -3130,7 +3130,7 @@ async function withRetry(fn, options = {}) {
|
|
|
3130
3130
|
}
|
|
3131
3131
|
const delay = calculateDelay(attempt, opts);
|
|
3132
3132
|
opts.onRetry?.(attempt + 1, lastError, delay);
|
|
3133
|
-
await new Promise((
|
|
3133
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay));
|
|
3134
3134
|
}
|
|
3135
3135
|
}
|
|
3136
3136
|
throw lastError ?? new Error("Retry failed with no error");
|
|
@@ -3250,6 +3250,184 @@ var ContextManager = class {
|
|
|
3250
3250
|
}
|
|
3251
3251
|
};
|
|
3252
3252
|
|
|
3253
|
+
// src/agents/spec-loader.ts
|
|
3254
|
+
import * as fs3 from "fs";
|
|
3255
|
+
import * as path3 from "path";
|
|
3256
|
+
import * as yaml from "yaml";
|
|
3257
|
+
import { fileURLToPath } from "url";
|
|
3258
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
3259
|
+
var __dirname = path3.dirname(__filename);
|
|
3260
|
+
var SPECS_DIR = path3.join(__dirname, "specs");
|
|
3261
|
+
function loadAgentSpec(specName) {
|
|
3262
|
+
const specPath = path3.join(SPECS_DIR, `${specName}.yaml`);
|
|
3263
|
+
if (!fs3.existsSync(specPath)) {
|
|
3264
|
+
throw new Error(`Agent spec not found: ${specPath}`);
|
|
3265
|
+
}
|
|
3266
|
+
const content = fs3.readFileSync(specPath, "utf-8");
|
|
3267
|
+
const spec = yaml.parse(content);
|
|
3268
|
+
return resolveAgentSpec(spec, specPath);
|
|
3269
|
+
}
|
|
3270
|
+
function resolveAgentSpec(spec, specPath) {
|
|
3271
|
+
const specDir = path3.dirname(specPath);
|
|
3272
|
+
let resolved = {
|
|
3273
|
+
name: spec.agent.name,
|
|
3274
|
+
description: spec.agent.description || "",
|
|
3275
|
+
systemPrompt: "",
|
|
3276
|
+
tools: spec.agent.tools || [],
|
|
3277
|
+
excludeTools: spec.agent.exclude_tools || [],
|
|
3278
|
+
subagents: spec.agent.subagents || {},
|
|
3279
|
+
switchingRules: spec.switching?.rules || []
|
|
3280
|
+
};
|
|
3281
|
+
if (spec.agent.extends) {
|
|
3282
|
+
const basePath = path3.resolve(specDir, spec.agent.extends);
|
|
3283
|
+
const baseContent = fs3.readFileSync(basePath, "utf-8");
|
|
3284
|
+
const baseSpec = yaml.parse(baseContent);
|
|
3285
|
+
const baseResolved = resolveAgentSpec(baseSpec, basePath);
|
|
3286
|
+
resolved = {
|
|
3287
|
+
...baseResolved,
|
|
3288
|
+
name: spec.agent.name || baseResolved.name,
|
|
3289
|
+
description: spec.agent.description || baseResolved.description,
|
|
3290
|
+
tools: spec.agent.tools || baseResolved.tools,
|
|
3291
|
+
excludeTools: [...baseResolved.excludeTools, ...spec.agent.exclude_tools || []],
|
|
3292
|
+
subagents: { ...baseResolved.subagents, ...spec.agent.subagents },
|
|
3293
|
+
switchingRules: spec.switching?.rules || baseResolved.switchingRules
|
|
3294
|
+
};
|
|
3295
|
+
}
|
|
3296
|
+
if (spec.agent.system_prompt) {
|
|
3297
|
+
resolved.systemPrompt = spec.agent.system_prompt;
|
|
3298
|
+
} else if (spec.agent.system_prompt_path) {
|
|
3299
|
+
const promptPath = path3.resolve(specDir, spec.agent.system_prompt_path);
|
|
3300
|
+
if (fs3.existsSync(promptPath)) {
|
|
3301
|
+
resolved.systemPrompt = fs3.readFileSync(promptPath, "utf-8");
|
|
3302
|
+
}
|
|
3303
|
+
}
|
|
3304
|
+
resolved.tools = resolved.tools.filter((t) => !resolved.excludeTools.includes(t));
|
|
3305
|
+
return resolved;
|
|
3306
|
+
}
|
|
3307
|
+
var SpecOrchestrator = class {
|
|
3308
|
+
currentAgent;
|
|
3309
|
+
agents = /* @__PURE__ */ new Map();
|
|
3310
|
+
context = {};
|
|
3311
|
+
constructor() {
|
|
3312
|
+
this.currentAgent = loadAgentSpec("default");
|
|
3313
|
+
this.agents.set("default", this.currentAgent);
|
|
3314
|
+
for (const [name] of Object.entries(this.currentAgent.subagents)) {
|
|
3315
|
+
try {
|
|
3316
|
+
const spec = loadAgentSpec(name);
|
|
3317
|
+
this.agents.set(name, spec);
|
|
3318
|
+
} catch {
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
/**
|
|
3323
|
+
* Get current active agent
|
|
3324
|
+
*/
|
|
3325
|
+
getCurrentAgent() {
|
|
3326
|
+
return this.currentAgent;
|
|
3327
|
+
}
|
|
3328
|
+
/**
|
|
3329
|
+
* Get current agent's system prompt
|
|
3330
|
+
*/
|
|
3331
|
+
getSystemPrompt() {
|
|
3332
|
+
return this.currentAgent.systemPrompt;
|
|
3333
|
+
}
|
|
3334
|
+
/**
|
|
3335
|
+
* Update context for agent switching decisions
|
|
3336
|
+
*/
|
|
3337
|
+
updateContext(key, value) {
|
|
3338
|
+
this.context[key] = value;
|
|
3339
|
+
this.evaluateSwitching();
|
|
3340
|
+
}
|
|
3341
|
+
/**
|
|
3342
|
+
* Manually switch to a specific agent
|
|
3343
|
+
*/
|
|
3344
|
+
switchTo(agentName) {
|
|
3345
|
+
if (this.agents.has(agentName)) {
|
|
3346
|
+
this.currentAgent = this.agents.get(agentName);
|
|
3347
|
+
return true;
|
|
3348
|
+
}
|
|
3349
|
+
try {
|
|
3350
|
+
const spec = loadAgentSpec(agentName);
|
|
3351
|
+
this.agents.set(agentName, spec);
|
|
3352
|
+
this.currentAgent = spec;
|
|
3353
|
+
return true;
|
|
3354
|
+
} catch {
|
|
3355
|
+
return false;
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
/**
|
|
3359
|
+
* Evaluate switching rules and auto-switch if needed
|
|
3360
|
+
*/
|
|
3361
|
+
evaluateSwitching() {
|
|
3362
|
+
for (const rule of this.currentAgent.switchingRules) {
|
|
3363
|
+
if (this.evaluateCondition(rule.condition)) {
|
|
3364
|
+
this.switchTo(rule.agent);
|
|
3365
|
+
break;
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
/**
|
|
3370
|
+
* Evaluate a condition string against current context
|
|
3371
|
+
*/
|
|
3372
|
+
evaluateCondition(condition) {
|
|
3373
|
+
try {
|
|
3374
|
+
const ctx = this.context;
|
|
3375
|
+
const checks = {
|
|
3376
|
+
target_set: !!ctx.target,
|
|
3377
|
+
vulnerability_found: (ctx.vulnerabilities || []).length > 0,
|
|
3378
|
+
shell_obtained: !!ctx.shellObtained,
|
|
3379
|
+
hash_found: (ctx.hashes || []).length > 0
|
|
3380
|
+
};
|
|
3381
|
+
const phaseMatch = condition.match(/phase\s*==\s*['"](\w+)['"]/);
|
|
3382
|
+
if (phaseMatch) {
|
|
3383
|
+
checks[`phase_${phaseMatch[1]}`] = ctx.phase === phaseMatch[1];
|
|
3384
|
+
}
|
|
3385
|
+
const portMatches = condition.matchAll(/port_(\d+)_open/g);
|
|
3386
|
+
const openPorts = ctx.openPorts || [];
|
|
3387
|
+
for (const match of portMatches) {
|
|
3388
|
+
checks[`port_${match[1]}_open`] = openPorts.includes(parseInt(match[1]));
|
|
3389
|
+
}
|
|
3390
|
+
const tokens = condition.split(/\s*(&&|\|\|)\s*/);
|
|
3391
|
+
let result = true;
|
|
3392
|
+
let operator = "&&";
|
|
3393
|
+
for (const token of tokens) {
|
|
3394
|
+
if (token === "&&" || token === "||") {
|
|
3395
|
+
operator = token;
|
|
3396
|
+
continue;
|
|
3397
|
+
}
|
|
3398
|
+
let tokenResult = false;
|
|
3399
|
+
for (const [key, value] of Object.entries(checks)) {
|
|
3400
|
+
if (token.includes(key.replace("_", " ")) || token.includes(key)) {
|
|
3401
|
+
tokenResult = value;
|
|
3402
|
+
break;
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
if (operator === "&&") {
|
|
3406
|
+
result = result && tokenResult;
|
|
3407
|
+
} else {
|
|
3408
|
+
result = result || tokenResult;
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
return result;
|
|
3412
|
+
} catch {
|
|
3413
|
+
return false;
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
/**
|
|
3417
|
+
* Get available subagents for current agent
|
|
3418
|
+
*/
|
|
3419
|
+
getSubagents() {
|
|
3420
|
+
return this.currentAgent.subagents;
|
|
3421
|
+
}
|
|
3422
|
+
/**
|
|
3423
|
+
* Get tools available for current agent
|
|
3424
|
+
*/
|
|
3425
|
+
getTools() {
|
|
3426
|
+
return this.currentAgent.tools;
|
|
3427
|
+
}
|
|
3428
|
+
};
|
|
3429
|
+
var specOrchestrator = new SpecOrchestrator();
|
|
3430
|
+
|
|
3253
3431
|
// src/agents/index.ts
|
|
3254
3432
|
var TARGET_EXPLORER = {
|
|
3255
3433
|
name: "target-explorer",
|
|
@@ -4263,6 +4441,9 @@ var AutonomousHackingAgent = class extends EventEmitter4 {
|
|
|
4263
4441
|
tools;
|
|
4264
4442
|
builtinAgents = BUILTIN_AGENTS;
|
|
4265
4443
|
currentAgent = null;
|
|
4444
|
+
// YAML-based agent orchestration
|
|
4445
|
+
specOrchestrator = null;
|
|
4446
|
+
currentSpec = null;
|
|
4266
4447
|
// Integrated systems
|
|
4267
4448
|
hookExecutor;
|
|
4268
4449
|
mcpManager;
|
|
@@ -4299,13 +4480,22 @@ var AutonomousHackingAgent = class extends EventEmitter4 {
|
|
|
4299
4480
|
this.state = this.createInitialState();
|
|
4300
4481
|
this.initSystems();
|
|
4301
4482
|
}
|
|
4302
|
-
// Initialize systems (hooks, MCP)
|
|
4483
|
+
// Initialize systems (hooks, MCP, spec orchestrator)
|
|
4303
4484
|
async initSystems() {
|
|
4304
4485
|
try {
|
|
4305
4486
|
this.emit(AGENT_EVENT.PLUGINS_LOADED, { agents: this.builtinAgents.length });
|
|
4306
4487
|
await this.hookExecutor.initialize();
|
|
4307
4488
|
this.emit(AGENT_EVENT.HOOKS_LOADED);
|
|
4308
4489
|
this.emit(AGENT_EVENT.COMMANDS_LOADED, { commands: BUILTIN_COMMANDS.length });
|
|
4490
|
+
try {
|
|
4491
|
+
this.specOrchestrator = new SpecOrchestrator();
|
|
4492
|
+
this.currentSpec = this.specOrchestrator.getCurrentAgent();
|
|
4493
|
+
this.emit(AGENT_EVENT.PLUGINS_LOADED, {
|
|
4494
|
+
agents: this.builtinAgents.length,
|
|
4495
|
+
yamlAgents: this.specOrchestrator.getSubagents()
|
|
4496
|
+
});
|
|
4497
|
+
} catch {
|
|
4498
|
+
}
|
|
4309
4499
|
} catch {
|
|
4310
4500
|
}
|
|
4311
4501
|
}
|
|
@@ -4576,7 +4766,20 @@ ${prompt}`
|
|
|
4576
4766
|
* Automatically switch to the best agent for the current phase
|
|
4577
4767
|
*/
|
|
4578
4768
|
autoSwitchAgentForPhase(phaseId) {
|
|
4579
|
-
const
|
|
4769
|
+
const phaseToYamlAgentMap = {
|
|
4770
|
+
[PHASE_ID.RECON]: "recon",
|
|
4771
|
+
[PHASE_ID.SCAN]: "recon",
|
|
4772
|
+
[PHASE_ID.ENUM]: "web",
|
|
4773
|
+
[PHASE_ID.VULN]: "exploit",
|
|
4774
|
+
[PHASE_ID.EXPLOIT]: "exploit",
|
|
4775
|
+
[PHASE_ID.PRIVESC]: "privesc",
|
|
4776
|
+
[PHASE_ID.PIVOT]: "privesc",
|
|
4777
|
+
[PHASE_ID.PERSIST]: "privesc",
|
|
4778
|
+
[PHASE_ID.EXFIL]: "crypto",
|
|
4779
|
+
[PHASE_ID.REPORT]: "recon"
|
|
4780
|
+
// fallback
|
|
4781
|
+
};
|
|
4782
|
+
const phaseToBuiltinAgentMap = {
|
|
4580
4783
|
[PHASE_ID.RECON]: "target-explorer",
|
|
4581
4784
|
[PHASE_ID.SCAN]: "target-explorer",
|
|
4582
4785
|
[PHASE_ID.ENUM]: "target-explorer",
|
|
@@ -4588,13 +4791,30 @@ ${prompt}`
|
|
|
4588
4791
|
[PHASE_ID.EXFIL]: "forensics-analyst",
|
|
4589
4792
|
[PHASE_ID.REPORT]: "finding-reviewer"
|
|
4590
4793
|
};
|
|
4591
|
-
|
|
4794
|
+
if (this.specOrchestrator) {
|
|
4795
|
+
const yamlAgentName = phaseToYamlAgentMap[phaseId];
|
|
4796
|
+
if (yamlAgentName) {
|
|
4797
|
+
this.specOrchestrator.updateContext("phase", phaseId);
|
|
4798
|
+
if (this.specOrchestrator.switchTo(yamlAgentName)) {
|
|
4799
|
+
this.currentSpec = this.specOrchestrator.getCurrentAgent();
|
|
4800
|
+
this.emit(AGENT_EVENT.AGENT_SWITCH, {
|
|
4801
|
+
name: this.currentSpec.name,
|
|
4802
|
+
description: this.currentSpec.description,
|
|
4803
|
+
type: "yaml-spec"
|
|
4804
|
+
});
|
|
4805
|
+
this.think(THOUGHT_TYPE.OBSERVATION, `Switched to ${this.currentSpec.name} agent (YAML spec) for ${phaseId} phase`);
|
|
4806
|
+
return;
|
|
4807
|
+
}
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
const agentName = phaseToBuiltinAgentMap[phaseId];
|
|
4592
4811
|
if (agentName) {
|
|
4593
4812
|
const agent = getAgentByName(agentName);
|
|
4594
4813
|
if (agent) {
|
|
4595
4814
|
this.currentAgent = agent;
|
|
4596
|
-
this.
|
|
4597
|
-
this.
|
|
4815
|
+
this.currentSpec = null;
|
|
4816
|
+
this.emit(AGENT_EVENT.AGENT_SWITCH, { name: agent.name, description: agent.description, type: "builtin" });
|
|
4817
|
+
this.think(THOUGHT_TYPE.OBSERVATION, `Switched to ${agent.name} agent (builtin) for ${phaseId} phase`);
|
|
4598
4818
|
}
|
|
4599
4819
|
}
|
|
4600
4820
|
}
|
|
@@ -4813,7 +5033,15 @@ Goal: Deep penetration to obtain root/system privileges, extract internal data,
|
|
|
4813
5033
|
{ role: "user", content: contextPrompt }
|
|
4814
5034
|
];
|
|
4815
5035
|
let systemPrompt = AUTONOMOUS_HACKING_PROMPT;
|
|
4816
|
-
if (this.
|
|
5036
|
+
if (this.currentSpec && this.currentSpec.systemPrompt) {
|
|
5037
|
+
systemPrompt = `${AUTONOMOUS_HACKING_PROMPT}
|
|
5038
|
+
|
|
5039
|
+
---
|
|
5040
|
+
|
|
5041
|
+
## Current Agent: ${this.currentSpec.name}
|
|
5042
|
+
|
|
5043
|
+
${this.currentSpec.systemPrompt}`;
|
|
5044
|
+
} else if (this.currentAgent) {
|
|
4817
5045
|
systemPrompt = buildAgentSystemPrompt(systemPrompt, this.currentAgent);
|
|
4818
5046
|
}
|
|
4819
5047
|
this.emit(AGENT_EVENT.LLM_START, { model: LLM_MODEL });
|
|
@@ -4912,15 +5140,15 @@ Use report_finding tool for important discoveries.
|
|
|
4912
5140
|
toolInput,
|
|
4913
5141
|
riskLevel: risk
|
|
4914
5142
|
});
|
|
4915
|
-
const decision = await new Promise((
|
|
5143
|
+
const decision = await new Promise((resolve2) => {
|
|
4916
5144
|
const handler = (response2) => {
|
|
4917
5145
|
if (response2.requestId === block.id) {
|
|
4918
5146
|
this.approvalManager.removeListener("approval_response", handler);
|
|
4919
5147
|
if (response2.decision === "approve_always") {
|
|
4920
5148
|
this.approvalManager.autoApprovedTools?.add(toolName);
|
|
4921
|
-
|
|
5149
|
+
resolve2("approve");
|
|
4922
5150
|
} else {
|
|
4923
|
-
|
|
5151
|
+
resolve2(response2.decision);
|
|
4924
5152
|
}
|
|
4925
5153
|
}
|
|
4926
5154
|
};
|
|
@@ -5389,8 +5617,8 @@ Respond helpfully to the user's message. If they ask to perform security testing
|
|
|
5389
5617
|
};
|
|
5390
5618
|
|
|
5391
5619
|
// src/core/session/session-manager.ts
|
|
5392
|
-
import * as
|
|
5393
|
-
import * as
|
|
5620
|
+
import * as fs4 from "fs/promises";
|
|
5621
|
+
import * as path4 from "path";
|
|
5394
5622
|
import { EventEmitter as EventEmitter5 } from "events";
|
|
5395
5623
|
var SESSIONS_DIR = ".pentesting/sessions";
|
|
5396
5624
|
function generateSessionId() {
|
|
@@ -5403,14 +5631,14 @@ var SessionManager = class extends EventEmitter5 {
|
|
|
5403
5631
|
currentSession = null;
|
|
5404
5632
|
constructor(baseDir) {
|
|
5405
5633
|
super();
|
|
5406
|
-
this.sessionsDir =
|
|
5634
|
+
this.sessionsDir = path4.join(baseDir || process.cwd(), SESSIONS_DIR);
|
|
5407
5635
|
}
|
|
5408
5636
|
/**
|
|
5409
5637
|
* Initialize sessions directory
|
|
5410
5638
|
*/
|
|
5411
5639
|
async initialize() {
|
|
5412
5640
|
try {
|
|
5413
|
-
await
|
|
5641
|
+
await fs4.mkdir(this.sessionsDir, { recursive: true });
|
|
5414
5642
|
} catch {
|
|
5415
5643
|
}
|
|
5416
5644
|
}
|
|
@@ -5430,8 +5658,8 @@ var SessionManager = class extends EventEmitter5 {
|
|
|
5430
5658
|
status: "active"
|
|
5431
5659
|
};
|
|
5432
5660
|
this.currentSession = metadata;
|
|
5433
|
-
const sessionDir =
|
|
5434
|
-
await
|
|
5661
|
+
const sessionDir = path4.join(this.sessionsDir, metadata.id);
|
|
5662
|
+
await fs4.mkdir(sessionDir, { recursive: true });
|
|
5435
5663
|
await this.saveMetadata(metadata);
|
|
5436
5664
|
this.emit("session_created", metadata);
|
|
5437
5665
|
return metadata;
|
|
@@ -5440,8 +5668,8 @@ var SessionManager = class extends EventEmitter5 {
|
|
|
5440
5668
|
* Save session metadata
|
|
5441
5669
|
*/
|
|
5442
5670
|
async saveMetadata(metadata) {
|
|
5443
|
-
const metadataPath =
|
|
5444
|
-
await
|
|
5671
|
+
const metadataPath = path4.join(this.sessionsDir, metadata.id, "metadata.json");
|
|
5672
|
+
await fs4.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
|
|
5445
5673
|
}
|
|
5446
5674
|
/**
|
|
5447
5675
|
* Save full session snapshot
|
|
@@ -5450,21 +5678,21 @@ var SessionManager = class extends EventEmitter5 {
|
|
|
5450
5678
|
if (!this.currentSession) {
|
|
5451
5679
|
throw new Error("No active session");
|
|
5452
5680
|
}
|
|
5453
|
-
const sessionDir =
|
|
5681
|
+
const sessionDir = path4.join(this.sessionsDir, this.currentSession.id);
|
|
5454
5682
|
this.currentSession.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5455
5683
|
this.currentSession.currentPhase = snapshot.state.currentPhase;
|
|
5456
5684
|
await this.saveMetadata(this.currentSession);
|
|
5457
|
-
const statePath =
|
|
5458
|
-
await
|
|
5459
|
-
const configPath =
|
|
5460
|
-
await
|
|
5461
|
-
const historyPath =
|
|
5685
|
+
const statePath = path4.join(sessionDir, "state.json");
|
|
5686
|
+
await fs4.writeFile(statePath, JSON.stringify(snapshot.state, null, 2));
|
|
5687
|
+
const configPath = path4.join(sessionDir, "config.json");
|
|
5688
|
+
await fs4.writeFile(configPath, JSON.stringify(snapshot.config, null, 2));
|
|
5689
|
+
const historyPath = path4.join(sessionDir, "history.jsonl");
|
|
5462
5690
|
const historyLine = JSON.stringify({
|
|
5463
5691
|
timestamp: this.currentSession.updatedAt,
|
|
5464
5692
|
iteration: snapshot.state.iteration,
|
|
5465
5693
|
phase: snapshot.state.currentPhase
|
|
5466
5694
|
}) + "\n";
|
|
5467
|
-
await
|
|
5695
|
+
await fs4.appendFile(historyPath, historyLine);
|
|
5468
5696
|
this.emit("snapshot_saved", this.currentSession.id);
|
|
5469
5697
|
}
|
|
5470
5698
|
/**
|
|
@@ -5472,17 +5700,17 @@ var SessionManager = class extends EventEmitter5 {
|
|
|
5472
5700
|
*/
|
|
5473
5701
|
async loadSession(sessionId) {
|
|
5474
5702
|
try {
|
|
5475
|
-
const sessionDir =
|
|
5476
|
-
const metadataPath =
|
|
5477
|
-
const metadataContent = await
|
|
5703
|
+
const sessionDir = path4.join(this.sessionsDir, sessionId);
|
|
5704
|
+
const metadataPath = path4.join(sessionDir, "metadata.json");
|
|
5705
|
+
const metadataContent = await fs4.readFile(metadataPath, "utf-8");
|
|
5478
5706
|
const metadata = JSON.parse(metadataContent);
|
|
5479
|
-
const statePath =
|
|
5480
|
-
const stateContent = await
|
|
5707
|
+
const statePath = path4.join(sessionDir, "state.json");
|
|
5708
|
+
const stateContent = await fs4.readFile(statePath, "utf-8");
|
|
5481
5709
|
const state = JSON.parse(stateContent);
|
|
5482
|
-
const configPath =
|
|
5710
|
+
const configPath = path4.join(sessionDir, "config.json");
|
|
5483
5711
|
let config = {};
|
|
5484
5712
|
try {
|
|
5485
|
-
const configContent = await
|
|
5713
|
+
const configContent = await fs4.readFile(configPath, "utf-8");
|
|
5486
5714
|
config = JSON.parse(configContent);
|
|
5487
5715
|
} catch {
|
|
5488
5716
|
}
|
|
@@ -5499,13 +5727,13 @@ var SessionManager = class extends EventEmitter5 {
|
|
|
5499
5727
|
async listSessions() {
|
|
5500
5728
|
await this.initialize();
|
|
5501
5729
|
try {
|
|
5502
|
-
const entries = await
|
|
5730
|
+
const entries = await fs4.readdir(this.sessionsDir, { withFileTypes: true });
|
|
5503
5731
|
const sessions = [];
|
|
5504
5732
|
for (const entry of entries) {
|
|
5505
5733
|
if (entry.isDirectory()) {
|
|
5506
5734
|
try {
|
|
5507
|
-
const metadataPath =
|
|
5508
|
-
const content = await
|
|
5735
|
+
const metadataPath = path4.join(this.sessionsDir, entry.name, "metadata.json");
|
|
5736
|
+
const content = await fs4.readFile(metadataPath, "utf-8");
|
|
5509
5737
|
const metadata = JSON.parse(content);
|
|
5510
5738
|
sessions.push({
|
|
5511
5739
|
id: metadata.id,
|
|
@@ -5555,14 +5783,14 @@ var SessionManager = class extends EventEmitter5 {
|
|
|
5555
5783
|
await this.initialize();
|
|
5556
5784
|
let deletedCount = 0;
|
|
5557
5785
|
try {
|
|
5558
|
-
const entries = await
|
|
5786
|
+
const entries = await fs4.readdir(this.sessionsDir, { withFileTypes: true });
|
|
5559
5787
|
for (const entry of entries) {
|
|
5560
5788
|
if (entry.isDirectory()) {
|
|
5561
|
-
const metadataPath =
|
|
5789
|
+
const metadataPath = path4.join(this.sessionsDir, entry.name, "metadata.json");
|
|
5562
5790
|
try {
|
|
5563
|
-
await
|
|
5791
|
+
await fs4.access(metadataPath);
|
|
5564
5792
|
} catch {
|
|
5565
|
-
await
|
|
5793
|
+
await fs4.rm(path4.join(this.sessionsDir, entry.name), { recursive: true });
|
|
5566
5794
|
deletedCount++;
|
|
5567
5795
|
}
|
|
5568
5796
|
}
|
|
@@ -5584,8 +5812,8 @@ var SessionManager = class extends EventEmitter5 {
|
|
|
5584
5812
|
*/
|
|
5585
5813
|
async deleteSession(sessionId) {
|
|
5586
5814
|
try {
|
|
5587
|
-
const sessionDir =
|
|
5588
|
-
await
|
|
5815
|
+
const sessionDir = path4.join(this.sessionsDir, sessionId);
|
|
5816
|
+
await fs4.rm(sessionDir, { recursive: true });
|
|
5589
5817
|
this.emit("session_deleted", sessionId);
|
|
5590
5818
|
return true;
|
|
5591
5819
|
} catch {
|
|
@@ -5715,8 +5943,8 @@ function getSlashCommandRegistry() {
|
|
|
5715
5943
|
}
|
|
5716
5944
|
|
|
5717
5945
|
// src/core/context/context-manager.ts
|
|
5718
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from "fs";
|
|
5719
|
-
import { join as
|
|
5946
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync, renameSync } from "fs";
|
|
5947
|
+
import { join as join4, dirname as dirname3 } from "path";
|
|
5720
5948
|
import { EventEmitter as EventEmitter6 } from "events";
|
|
5721
5949
|
var CONTEXT_EVENT = {
|
|
5722
5950
|
MESSAGE_ADDED: "message_added",
|
|
@@ -5731,7 +5959,7 @@ var ContextManager2 = class extends EventEmitter6 {
|
|
|
5731
5959
|
maxMessages;
|
|
5732
5960
|
constructor(sessionDir, options) {
|
|
5733
5961
|
super();
|
|
5734
|
-
this.filePath =
|
|
5962
|
+
this.filePath = join4(sessionDir, "context.jsonl");
|
|
5735
5963
|
this.maxMessages = options?.maxMessages || 100;
|
|
5736
5964
|
this.state = {
|
|
5737
5965
|
messages: [],
|
|
@@ -5739,8 +5967,8 @@ var ContextManager2 = class extends EventEmitter6 {
|
|
|
5739
5967
|
tokenCount: 0,
|
|
5740
5968
|
nextCheckpointId: 0
|
|
5741
5969
|
};
|
|
5742
|
-
const dir =
|
|
5743
|
-
if (!
|
|
5970
|
+
const dir = dirname3(this.filePath);
|
|
5971
|
+
if (!existsSync2(dir)) {
|
|
5744
5972
|
mkdirSync(dir, { recursive: true });
|
|
5745
5973
|
}
|
|
5746
5974
|
}
|
|
@@ -5748,11 +5976,11 @@ var ContextManager2 = class extends EventEmitter6 {
|
|
|
5748
5976
|
* Restore context from file
|
|
5749
5977
|
*/
|
|
5750
5978
|
async restore() {
|
|
5751
|
-
if (!
|
|
5979
|
+
if (!existsSync2(this.filePath)) {
|
|
5752
5980
|
return false;
|
|
5753
5981
|
}
|
|
5754
5982
|
try {
|
|
5755
|
-
const content =
|
|
5983
|
+
const content = readFileSync2(this.filePath, "utf-8");
|
|
5756
5984
|
const lines = content.trim().split("\n").filter((l) => l);
|
|
5757
5985
|
for (const line of lines) {
|
|
5758
5986
|
const data = JSON.parse(line);
|
|
@@ -5827,7 +6055,7 @@ var ContextManager2 = class extends EventEmitter6 {
|
|
|
5827
6055
|
return false;
|
|
5828
6056
|
}
|
|
5829
6057
|
const backupPath = `${this.filePath}.bak`;
|
|
5830
|
-
if (
|
|
6058
|
+
if (existsSync2(this.filePath)) {
|
|
5831
6059
|
renameSync(this.filePath, backupPath);
|
|
5832
6060
|
}
|
|
5833
6061
|
this.state.messages = this.state.messages.slice(0, checkpoint.messageCount);
|
|
@@ -5851,7 +6079,7 @@ var ContextManager2 = class extends EventEmitter6 {
|
|
|
5851
6079
|
*/
|
|
5852
6080
|
async clear() {
|
|
5853
6081
|
const backupPath = `${this.filePath}.${Date.now()}.bak`;
|
|
5854
|
-
if (
|
|
6082
|
+
if (existsSync2(this.filePath)) {
|
|
5855
6083
|
renameSync(this.filePath, backupPath);
|
|
5856
6084
|
}
|
|
5857
6085
|
this.state = {
|
|
@@ -5899,7 +6127,7 @@ ${summary}`,
|
|
|
5899
6127
|
metadata: { compacted: true }
|
|
5900
6128
|
};
|
|
5901
6129
|
const backupPath = `${this.filePath}.compact.bak`;
|
|
5902
|
-
if (
|
|
6130
|
+
if (existsSync2(this.filePath)) {
|
|
5903
6131
|
renameSync(this.filePath, backupPath);
|
|
5904
6132
|
}
|
|
5905
6133
|
this.state.messages = [summaryMessage, ...preserved];
|
|
@@ -5929,20 +6157,20 @@ ${summary}`,
|
|
|
5929
6157
|
};
|
|
5930
6158
|
|
|
5931
6159
|
// src/wire/wire-logger.ts
|
|
5932
|
-
import { existsSync as
|
|
5933
|
-
import { join as
|
|
6160
|
+
import { existsSync as existsSync3, appendFileSync, readFileSync as readFileSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
6161
|
+
import { join as join5, dirname as dirname4 } from "path";
|
|
5934
6162
|
var WireFile = class {
|
|
5935
6163
|
filePath;
|
|
5936
6164
|
sequence = 0;
|
|
5937
6165
|
constructor(sessionDir) {
|
|
5938
|
-
this.filePath =
|
|
5939
|
-
const dir =
|
|
5940
|
-
if (!
|
|
6166
|
+
this.filePath = join5(sessionDir, "wire.jsonl");
|
|
6167
|
+
const dir = dirname4(this.filePath);
|
|
6168
|
+
if (!existsSync3(dir)) {
|
|
5941
6169
|
mkdirSync2(dir, { recursive: true });
|
|
5942
6170
|
}
|
|
5943
|
-
if (
|
|
6171
|
+
if (existsSync3(this.filePath)) {
|
|
5944
6172
|
try {
|
|
5945
|
-
const content =
|
|
6173
|
+
const content = readFileSync3(this.filePath, "utf-8");
|
|
5946
6174
|
this.sequence = content.trim().split("\n").filter((l) => l).length;
|
|
5947
6175
|
} catch {
|
|
5948
6176
|
this.sequence = 0;
|
|
@@ -5968,10 +6196,10 @@ var WireFile = class {
|
|
|
5968
6196
|
* Read all records from the wire log
|
|
5969
6197
|
*/
|
|
5970
6198
|
async *readRecords() {
|
|
5971
|
-
if (!
|
|
6199
|
+
if (!existsSync3(this.filePath)) {
|
|
5972
6200
|
return;
|
|
5973
6201
|
}
|
|
5974
|
-
const content =
|
|
6202
|
+
const content = readFileSync3(this.filePath, "utf-8");
|
|
5975
6203
|
const lines = content.trim().split("\n").filter((l) => l);
|
|
5976
6204
|
for (const line of lines) {
|
|
5977
6205
|
try {
|
|
@@ -5984,11 +6212,11 @@ var WireFile = class {
|
|
|
5984
6212
|
* Check if wire file is empty
|
|
5985
6213
|
*/
|
|
5986
6214
|
isEmpty() {
|
|
5987
|
-
if (!
|
|
6215
|
+
if (!existsSync3(this.filePath)) {
|
|
5988
6216
|
return true;
|
|
5989
6217
|
}
|
|
5990
6218
|
try {
|
|
5991
|
-
const content =
|
|
6219
|
+
const content = readFileSync3(this.filePath, "utf-8");
|
|
5992
6220
|
return content.trim().length === 0;
|
|
5993
6221
|
} catch {
|
|
5994
6222
|
return true;
|
|
@@ -6095,8 +6323,8 @@ function initWireLogger(sessionDir, sessionId) {
|
|
|
6095
6323
|
// src/utils/clipboard.ts
|
|
6096
6324
|
import { execSync } from "child_process";
|
|
6097
6325
|
import { platform } from "os";
|
|
6098
|
-
import { existsSync as
|
|
6099
|
-
import { join as
|
|
6326
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
6327
|
+
import { join as join6 } from "path";
|
|
6100
6328
|
import { tmpdir } from "os";
|
|
6101
6329
|
function readClipboardText() {
|
|
6102
6330
|
const os = platform();
|
|
@@ -6120,7 +6348,7 @@ function readClipboardText() {
|
|
|
6120
6348
|
}
|
|
6121
6349
|
function readClipboardImage() {
|
|
6122
6350
|
const os = platform();
|
|
6123
|
-
const tmpPath =
|
|
6351
|
+
const tmpPath = join6(tmpdir(), `clipboard-${Date.now()}.png`);
|
|
6124
6352
|
try {
|
|
6125
6353
|
if (os === "darwin") {
|
|
6126
6354
|
const script = `
|
|
@@ -6136,8 +6364,8 @@ function readClipboardImage() {
|
|
|
6136
6364
|
end try
|
|
6137
6365
|
`;
|
|
6138
6366
|
const result = execSync(`osascript -e '${script}'`, { encoding: "utf-8" }).trim();
|
|
6139
|
-
if (result === "success" &&
|
|
6140
|
-
const imageBuffer =
|
|
6367
|
+
if (result === "success" && existsSync4(tmpPath)) {
|
|
6368
|
+
const imageBuffer = readFileSync4(tmpPath);
|
|
6141
6369
|
const base64 = imageBuffer.toString("base64");
|
|
6142
6370
|
return { path: tmpPath, base64, mimeType: "image/png" };
|
|
6143
6371
|
}
|
|
@@ -6147,10 +6375,10 @@ function readClipboardImage() {
|
|
|
6147
6375
|
encoding: "utf-8",
|
|
6148
6376
|
shell: "/bin/bash"
|
|
6149
6377
|
});
|
|
6150
|
-
if (
|
|
6378
|
+
if (existsSync4(tmpPath)) {
|
|
6151
6379
|
const stats = __require("fs").statSync(tmpPath);
|
|
6152
6380
|
if (stats.size > 0) {
|
|
6153
|
-
const imageBuffer =
|
|
6381
|
+
const imageBuffer = readFileSync4(tmpPath);
|
|
6154
6382
|
const base64 = imageBuffer.toString("base64");
|
|
6155
6383
|
return { path: tmpPath, base64, mimeType: "image/png" };
|
|
6156
6384
|
}
|
|
@@ -6169,8 +6397,8 @@ function readClipboardImage() {
|
|
|
6169
6397
|
}
|
|
6170
6398
|
`;
|
|
6171
6399
|
const result = execSync(`powershell -command "${script}"`, { encoding: "utf-8" }).trim();
|
|
6172
|
-
if (result === "success" &&
|
|
6173
|
-
const imageBuffer =
|
|
6400
|
+
if (result === "success" && existsSync4(tmpPath)) {
|
|
6401
|
+
const imageBuffer = readFileSync4(tmpPath);
|
|
6174
6402
|
const base64 = imageBuffer.toString("base64");
|
|
6175
6403
|
return { path: tmpPath, base64, mimeType: "image/png" };
|
|
6176
6404
|
}
|
|
@@ -6178,7 +6406,7 @@ function readClipboardImage() {
|
|
|
6178
6406
|
} catch (error) {
|
|
6179
6407
|
console.error("Failed to read clipboard image:", error);
|
|
6180
6408
|
}
|
|
6181
|
-
if (
|
|
6409
|
+
if (existsSync4(tmpPath)) {
|
|
6182
6410
|
try {
|
|
6183
6411
|
unlinkSync2(tmpPath);
|
|
6184
6412
|
} catch {
|
|
@@ -6420,7 +6648,7 @@ var FindingDisplay = ({ block }) => {
|
|
|
6420
6648
|
|
|
6421
6649
|
// src/cli/app.tsx
|
|
6422
6650
|
import { homedir } from "os";
|
|
6423
|
-
import { join as
|
|
6651
|
+
import { join as join7 } from "path";
|
|
6424
6652
|
|
|
6425
6653
|
// src/cli/utils/keyboard-listener.ts
|
|
6426
6654
|
import { EventEmitter as EventEmitter7 } from "events";
|
|
@@ -6723,7 +6951,7 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
6723
6951
|
const [agent] = useState(() => new AutonomousHackingAgent(void 0, { autoApprove }));
|
|
6724
6952
|
const sessionManager2 = getSessionManager();
|
|
6725
6953
|
const approvalManager2 = getApprovalManager({ yoloMode: autoApprove });
|
|
6726
|
-
const sessionDirRef = useRef(
|
|
6954
|
+
const sessionDirRef = useRef(join7(homedir(), ".pentest", "sessions", `session-${Date.now()}`));
|
|
6727
6955
|
const contextManagerRef = useRef(null);
|
|
6728
6956
|
const wireLoggerRef = useRef(null);
|
|
6729
6957
|
const keyboardListenerRef = useRef(getKeyboardListener());
|
|
@@ -7740,8 +7968,8 @@ program.command("run <objective>").alias("r").description("Run a single objectiv
|
|
|
7740
7968
|
const summary = agent.getSummary();
|
|
7741
7969
|
console.log(JSON.stringify(summary, null, 2));
|
|
7742
7970
|
if (options.output) {
|
|
7743
|
-
const
|
|
7744
|
-
await
|
|
7971
|
+
const fs5 = await import("fs/promises");
|
|
7972
|
+
await fs5.writeFile(options.output, JSON.stringify(summary, null, 2));
|
|
7745
7973
|
console.log(chalk.hex(THEME.text.accent)(`
|
|
7746
7974
|
[+] Report saved to: ${options.output}`));
|
|
7747
7975
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pentesting",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.44",
|
|
4
4
|
"description": "Autonomous Penetration Testing AI Agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -69,7 +69,8 @@
|
|
|
69
69
|
"ink-text-input": "^6.0.0",
|
|
70
70
|
"nanospinner": "^1.2.2",
|
|
71
71
|
"ora": "^8.1.1",
|
|
72
|
-
"react": "^18.3.1"
|
|
72
|
+
"react": "^18.3.1",
|
|
73
|
+
"yaml": "^2.8.2"
|
|
73
74
|
},
|
|
74
75
|
"devDependencies": {
|
|
75
76
|
"@types/node": "^22.13.1",
|