pentesting 0.3.1 → 0.3.2
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/index.js +719 -38
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
2
8
|
|
|
3
9
|
// src/index.tsx
|
|
4
10
|
import { render } from "ink";
|
|
@@ -6,7 +12,7 @@ import { Command } from "commander";
|
|
|
6
12
|
|
|
7
13
|
// src/cli/app.tsx
|
|
8
14
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
9
|
-
import { Box, Text, useInput, useApp, Static } from "ink";
|
|
15
|
+
import { Box as Box2, Text as Text2, useInput, useApp, Static } from "ink";
|
|
10
16
|
import TextInput from "ink-text-input";
|
|
11
17
|
import Spinner from "ink-spinner";
|
|
12
18
|
|
|
@@ -1194,7 +1200,7 @@ async function executeMetasploit(input) {
|
|
|
1194
1200
|
return executeBash(`msfconsole -q -x "${command}; exit"`, { timeout: 3e5 });
|
|
1195
1201
|
}
|
|
1196
1202
|
async function generatePayload(input) {
|
|
1197
|
-
const { payload_type, lhost, lport, platform, format, encoder, output } = input;
|
|
1203
|
+
const { payload_type, lhost, lport, platform: platform2, format, encoder, output } = input;
|
|
1198
1204
|
const payloads = {
|
|
1199
1205
|
windows: {
|
|
1200
1206
|
reverse_tcp: "windows/meterpreter/reverse_tcp",
|
|
@@ -1213,7 +1219,7 @@ async function generatePayload(input) {
|
|
|
1213
1219
|
reverse_tcp: "python/meterpreter/reverse_tcp"
|
|
1214
1220
|
}
|
|
1215
1221
|
};
|
|
1216
|
-
const payloadName = payloads[
|
|
1222
|
+
const payloadName = payloads[platform2]?.[payload_type] || `${platform2}/meterpreter/reverse_tcp`;
|
|
1217
1223
|
let cmd = `msfvenom -p ${payloadName} LHOST=${lhost} LPORT=${lport}`;
|
|
1218
1224
|
if (format) cmd += ` -f ${format}`;
|
|
1219
1225
|
if (encoder) cmd += ` -e ${encoder}`;
|
|
@@ -1376,7 +1382,7 @@ const { chromium } = require('playwright');
|
|
|
1376
1382
|
}
|
|
1377
1383
|
|
|
1378
1384
|
// src/config/constants.ts
|
|
1379
|
-
var APP_VERSION = "0.3.
|
|
1385
|
+
var APP_VERSION = "0.3.2";
|
|
1380
1386
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
1381
1387
|
var LLM_API_KEY = process.env.PENTEST_API_KEY || process.env.ANTHROPIC_API_KEY || "";
|
|
1382
1388
|
var LLM_BASE_URL = process.env.PENTEST_BASE_URL || void 0;
|
|
@@ -4327,6 +4333,499 @@ function getSlashCommandRegistry() {
|
|
|
4327
4333
|
return registry;
|
|
4328
4334
|
}
|
|
4329
4335
|
|
|
4336
|
+
// src/core/context/context-manager.ts
|
|
4337
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from "fs";
|
|
4338
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
4339
|
+
import { EventEmitter as EventEmitter6 } from "events";
|
|
4340
|
+
var CONTEXT_EVENT = {
|
|
4341
|
+
MESSAGE_ADDED: "message_added",
|
|
4342
|
+
CHECKPOINT_CREATED: "checkpoint_created",
|
|
4343
|
+
REVERTED: "reverted",
|
|
4344
|
+
CLEARED: "cleared",
|
|
4345
|
+
COMPACTED: "compacted"
|
|
4346
|
+
};
|
|
4347
|
+
var ContextManager2 = class extends EventEmitter6 {
|
|
4348
|
+
filePath;
|
|
4349
|
+
state;
|
|
4350
|
+
maxMessages;
|
|
4351
|
+
constructor(sessionDir, options) {
|
|
4352
|
+
super();
|
|
4353
|
+
this.filePath = join3(sessionDir, "context.jsonl");
|
|
4354
|
+
this.maxMessages = options?.maxMessages || 100;
|
|
4355
|
+
this.state = {
|
|
4356
|
+
messages: [],
|
|
4357
|
+
checkpoints: [],
|
|
4358
|
+
tokenCount: 0,
|
|
4359
|
+
nextCheckpointId: 0
|
|
4360
|
+
};
|
|
4361
|
+
const dir = dirname2(this.filePath);
|
|
4362
|
+
if (!existsSync(dir)) {
|
|
4363
|
+
mkdirSync(dir, { recursive: true });
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4366
|
+
/**
|
|
4367
|
+
* Restore context from file
|
|
4368
|
+
*/
|
|
4369
|
+
async restore() {
|
|
4370
|
+
if (!existsSync(this.filePath)) {
|
|
4371
|
+
return false;
|
|
4372
|
+
}
|
|
4373
|
+
try {
|
|
4374
|
+
const content = readFileSync(this.filePath, "utf-8");
|
|
4375
|
+
const lines = content.trim().split("\n").filter((l) => l);
|
|
4376
|
+
for (const line of lines) {
|
|
4377
|
+
const data = JSON.parse(line);
|
|
4378
|
+
if (data.role === "_checkpoint") {
|
|
4379
|
+
this.state.checkpoints.push({
|
|
4380
|
+
id: data.id,
|
|
4381
|
+
timestamp: data.timestamp,
|
|
4382
|
+
messageCount: data.messageCount,
|
|
4383
|
+
description: data.description
|
|
4384
|
+
});
|
|
4385
|
+
this.state.nextCheckpointId = Math.max(this.state.nextCheckpointId, data.id + 1);
|
|
4386
|
+
} else if (data.role === "_usage") {
|
|
4387
|
+
this.state.tokenCount = data.tokenCount;
|
|
4388
|
+
} else {
|
|
4389
|
+
this.state.messages.push(data);
|
|
4390
|
+
}
|
|
4391
|
+
}
|
|
4392
|
+
return this.state.messages.length > 0;
|
|
4393
|
+
} catch (error) {
|
|
4394
|
+
console.error("Failed to restore context:", error);
|
|
4395
|
+
return false;
|
|
4396
|
+
}
|
|
4397
|
+
}
|
|
4398
|
+
/**
|
|
4399
|
+
* Get conversation history
|
|
4400
|
+
*/
|
|
4401
|
+
getHistory() {
|
|
4402
|
+
return [...this.state.messages];
|
|
4403
|
+
}
|
|
4404
|
+
/**
|
|
4405
|
+
* Get checkpoints
|
|
4406
|
+
*/
|
|
4407
|
+
getCheckpoints() {
|
|
4408
|
+
return [...this.state.checkpoints];
|
|
4409
|
+
}
|
|
4410
|
+
/**
|
|
4411
|
+
* Add a message to context
|
|
4412
|
+
*/
|
|
4413
|
+
async addMessage(message) {
|
|
4414
|
+
const msg = {
|
|
4415
|
+
...message,
|
|
4416
|
+
timestamp: Date.now()
|
|
4417
|
+
};
|
|
4418
|
+
this.state.messages.push(msg);
|
|
4419
|
+
await this.appendToFile(msg);
|
|
4420
|
+
this.emit(CONTEXT_EVENT.MESSAGE_ADDED, msg);
|
|
4421
|
+
}
|
|
4422
|
+
/**
|
|
4423
|
+
* Create a checkpoint
|
|
4424
|
+
*/
|
|
4425
|
+
async checkpoint(description) {
|
|
4426
|
+
const checkpoint = {
|
|
4427
|
+
id: this.state.nextCheckpointId++,
|
|
4428
|
+
timestamp: Date.now(),
|
|
4429
|
+
messageCount: this.state.messages.length,
|
|
4430
|
+
description
|
|
4431
|
+
};
|
|
4432
|
+
this.state.checkpoints.push(checkpoint);
|
|
4433
|
+
await this.appendToFile({
|
|
4434
|
+
role: "_checkpoint",
|
|
4435
|
+
...checkpoint
|
|
4436
|
+
});
|
|
4437
|
+
this.emit(CONTEXT_EVENT.CHECKPOINT_CREATED, checkpoint);
|
|
4438
|
+
return checkpoint;
|
|
4439
|
+
}
|
|
4440
|
+
/**
|
|
4441
|
+
* Revert to a specific checkpoint
|
|
4442
|
+
*/
|
|
4443
|
+
async revertTo(checkpointId) {
|
|
4444
|
+
const checkpoint = this.state.checkpoints.find((c) => c.id === checkpointId);
|
|
4445
|
+
if (!checkpoint) {
|
|
4446
|
+
return false;
|
|
4447
|
+
}
|
|
4448
|
+
const backupPath = `${this.filePath}.bak`;
|
|
4449
|
+
if (existsSync(this.filePath)) {
|
|
4450
|
+
renameSync(this.filePath, backupPath);
|
|
4451
|
+
}
|
|
4452
|
+
this.state.messages = this.state.messages.slice(0, checkpoint.messageCount);
|
|
4453
|
+
this.state.checkpoints = this.state.checkpoints.filter((c) => c.id < checkpointId);
|
|
4454
|
+
await this.rewriteFile();
|
|
4455
|
+
this.emit(CONTEXT_EVENT.REVERTED, checkpointId);
|
|
4456
|
+
return true;
|
|
4457
|
+
}
|
|
4458
|
+
/**
|
|
4459
|
+
* Undo last checkpoint (go back one step)
|
|
4460
|
+
*/
|
|
4461
|
+
async undo() {
|
|
4462
|
+
if (this.state.checkpoints.length === 0) {
|
|
4463
|
+
return false;
|
|
4464
|
+
}
|
|
4465
|
+
const lastCheckpoint = this.state.checkpoints[this.state.checkpoints.length - 1];
|
|
4466
|
+
return this.revertTo(lastCheckpoint.id);
|
|
4467
|
+
}
|
|
4468
|
+
/**
|
|
4469
|
+
* Clear all context
|
|
4470
|
+
*/
|
|
4471
|
+
async clear() {
|
|
4472
|
+
const backupPath = `${this.filePath}.${Date.now()}.bak`;
|
|
4473
|
+
if (existsSync(this.filePath)) {
|
|
4474
|
+
renameSync(this.filePath, backupPath);
|
|
4475
|
+
}
|
|
4476
|
+
this.state = {
|
|
4477
|
+
messages: [],
|
|
4478
|
+
checkpoints: [],
|
|
4479
|
+
tokenCount: 0,
|
|
4480
|
+
nextCheckpointId: 0
|
|
4481
|
+
};
|
|
4482
|
+
this.emit(CONTEXT_EVENT.CLEARED);
|
|
4483
|
+
}
|
|
4484
|
+
/**
|
|
4485
|
+
* Update token count
|
|
4486
|
+
*/
|
|
4487
|
+
async updateTokenCount(count) {
|
|
4488
|
+
this.state.tokenCount = count;
|
|
4489
|
+
await this.appendToFile({ role: "_usage", tokenCount: count });
|
|
4490
|
+
}
|
|
4491
|
+
/**
|
|
4492
|
+
* Get token count
|
|
4493
|
+
*/
|
|
4494
|
+
getTokenCount() {
|
|
4495
|
+
return this.state.tokenCount;
|
|
4496
|
+
}
|
|
4497
|
+
/**
|
|
4498
|
+
* Check if context needs compaction
|
|
4499
|
+
*/
|
|
4500
|
+
needsCompaction(maxTokens, reservedTokens = 5e4) {
|
|
4501
|
+
return this.state.tokenCount + reservedTokens >= maxTokens;
|
|
4502
|
+
}
|
|
4503
|
+
/**
|
|
4504
|
+
* Compact context (keep last N messages, summarize rest)
|
|
4505
|
+
*/
|
|
4506
|
+
async compact(summary, keepLast = 2) {
|
|
4507
|
+
if (this.state.messages.length <= keepLast) {
|
|
4508
|
+
return;
|
|
4509
|
+
}
|
|
4510
|
+
const preserved = this.state.messages.slice(-keepLast);
|
|
4511
|
+
const summaryMessage = {
|
|
4512
|
+
role: "system",
|
|
4513
|
+
content: `[Context Compacted]
|
|
4514
|
+
|
|
4515
|
+
Previous conversation summary:
|
|
4516
|
+
${summary}`,
|
|
4517
|
+
timestamp: Date.now(),
|
|
4518
|
+
metadata: { compacted: true }
|
|
4519
|
+
};
|
|
4520
|
+
const backupPath = `${this.filePath}.compact.bak`;
|
|
4521
|
+
if (existsSync(this.filePath)) {
|
|
4522
|
+
renameSync(this.filePath, backupPath);
|
|
4523
|
+
}
|
|
4524
|
+
this.state.messages = [summaryMessage, ...preserved];
|
|
4525
|
+
this.state.checkpoints = [];
|
|
4526
|
+
this.state.nextCheckpointId = 0;
|
|
4527
|
+
await this.rewriteFile();
|
|
4528
|
+
this.emit(CONTEXT_EVENT.COMPACTED, { summary, preserved: preserved.length });
|
|
4529
|
+
}
|
|
4530
|
+
async appendToFile(data) {
|
|
4531
|
+
const line = JSON.stringify(data) + "\n";
|
|
4532
|
+
const { appendFileSync: appendFileSync2 } = await import("fs");
|
|
4533
|
+
appendFileSync2(this.filePath, line, "utf-8");
|
|
4534
|
+
}
|
|
4535
|
+
async rewriteFile() {
|
|
4536
|
+
let content = "";
|
|
4537
|
+
for (const msg of this.state.messages) {
|
|
4538
|
+
content += JSON.stringify(msg) + "\n";
|
|
4539
|
+
}
|
|
4540
|
+
for (const cp of this.state.checkpoints) {
|
|
4541
|
+
content += JSON.stringify({ role: "_checkpoint", ...cp }) + "\n";
|
|
4542
|
+
}
|
|
4543
|
+
if (this.state.tokenCount > 0) {
|
|
4544
|
+
content += JSON.stringify({ role: "_usage", tokenCount: this.state.tokenCount }) + "\n";
|
|
4545
|
+
}
|
|
4546
|
+
writeFileSync(this.filePath, content, "utf-8");
|
|
4547
|
+
}
|
|
4548
|
+
};
|
|
4549
|
+
|
|
4550
|
+
// src/wire/wire-logger.ts
|
|
4551
|
+
import { existsSync as existsSync2, appendFileSync, readFileSync as readFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
4552
|
+
import { join as join4, dirname as dirname3 } from "path";
|
|
4553
|
+
var WireFile = class {
|
|
4554
|
+
filePath;
|
|
4555
|
+
sequence = 0;
|
|
4556
|
+
constructor(sessionDir) {
|
|
4557
|
+
this.filePath = join4(sessionDir, "wire.jsonl");
|
|
4558
|
+
const dir = dirname3(this.filePath);
|
|
4559
|
+
if (!existsSync2(dir)) {
|
|
4560
|
+
mkdirSync2(dir, { recursive: true });
|
|
4561
|
+
}
|
|
4562
|
+
if (existsSync2(this.filePath)) {
|
|
4563
|
+
try {
|
|
4564
|
+
const content = readFileSync2(this.filePath, "utf-8");
|
|
4565
|
+
this.sequence = content.trim().split("\n").filter((l) => l).length;
|
|
4566
|
+
} catch {
|
|
4567
|
+
this.sequence = 0;
|
|
4568
|
+
}
|
|
4569
|
+
}
|
|
4570
|
+
}
|
|
4571
|
+
/**
|
|
4572
|
+
* Write a message to the wire log
|
|
4573
|
+
*/
|
|
4574
|
+
write(message) {
|
|
4575
|
+
const record = {
|
|
4576
|
+
sequence: this.sequence++,
|
|
4577
|
+
message: {
|
|
4578
|
+
...message,
|
|
4579
|
+
timestamp: Date.now()
|
|
4580
|
+
}
|
|
4581
|
+
};
|
|
4582
|
+
const line = JSON.stringify(record) + "\n";
|
|
4583
|
+
appendFileSync(this.filePath, line, "utf-8");
|
|
4584
|
+
return record;
|
|
4585
|
+
}
|
|
4586
|
+
/**
|
|
4587
|
+
* Read all records from the wire log
|
|
4588
|
+
*/
|
|
4589
|
+
async *readRecords() {
|
|
4590
|
+
if (!existsSync2(this.filePath)) {
|
|
4591
|
+
return;
|
|
4592
|
+
}
|
|
4593
|
+
const content = readFileSync2(this.filePath, "utf-8");
|
|
4594
|
+
const lines = content.trim().split("\n").filter((l) => l);
|
|
4595
|
+
for (const line of lines) {
|
|
4596
|
+
try {
|
|
4597
|
+
yield JSON.parse(line);
|
|
4598
|
+
} catch {
|
|
4599
|
+
}
|
|
4600
|
+
}
|
|
4601
|
+
}
|
|
4602
|
+
/**
|
|
4603
|
+
* Check if wire file is empty
|
|
4604
|
+
*/
|
|
4605
|
+
isEmpty() {
|
|
4606
|
+
if (!existsSync2(this.filePath)) {
|
|
4607
|
+
return true;
|
|
4608
|
+
}
|
|
4609
|
+
try {
|
|
4610
|
+
const content = readFileSync2(this.filePath, "utf-8");
|
|
4611
|
+
return content.trim().length === 0;
|
|
4612
|
+
} catch {
|
|
4613
|
+
return true;
|
|
4614
|
+
}
|
|
4615
|
+
}
|
|
4616
|
+
/**
|
|
4617
|
+
* Get file path
|
|
4618
|
+
*/
|
|
4619
|
+
getPath() {
|
|
4620
|
+
return this.filePath;
|
|
4621
|
+
}
|
|
4622
|
+
};
|
|
4623
|
+
var WireLogger = class {
|
|
4624
|
+
wire;
|
|
4625
|
+
sessionId;
|
|
4626
|
+
constructor(sessionDir, sessionId) {
|
|
4627
|
+
this.wire = new WireFile(sessionDir);
|
|
4628
|
+
this.sessionId = sessionId;
|
|
4629
|
+
}
|
|
4630
|
+
turnBegin(userInput) {
|
|
4631
|
+
this.wire.write({
|
|
4632
|
+
type: "turn_begin",
|
|
4633
|
+
sessionId: this.sessionId,
|
|
4634
|
+
data: { userInput }
|
|
4635
|
+
});
|
|
4636
|
+
}
|
|
4637
|
+
turnEnd() {
|
|
4638
|
+
this.wire.write({
|
|
4639
|
+
type: "turn_end",
|
|
4640
|
+
sessionId: this.sessionId,
|
|
4641
|
+
data: {}
|
|
4642
|
+
});
|
|
4643
|
+
}
|
|
4644
|
+
stepBegin(stepId) {
|
|
4645
|
+
this.wire.write({
|
|
4646
|
+
type: "step_begin",
|
|
4647
|
+
sessionId: this.sessionId,
|
|
4648
|
+
data: { stepId }
|
|
4649
|
+
});
|
|
4650
|
+
}
|
|
4651
|
+
stepEnd(stepId) {
|
|
4652
|
+
this.wire.write({
|
|
4653
|
+
type: "step_end",
|
|
4654
|
+
sessionId: this.sessionId,
|
|
4655
|
+
data: { stepId }
|
|
4656
|
+
});
|
|
4657
|
+
}
|
|
4658
|
+
contentPart(content, isThinking = false) {
|
|
4659
|
+
this.wire.write({
|
|
4660
|
+
type: "content_part",
|
|
4661
|
+
sessionId: this.sessionId,
|
|
4662
|
+
data: { content, isThinking }
|
|
4663
|
+
});
|
|
4664
|
+
}
|
|
4665
|
+
toolCall(toolId, toolName, args) {
|
|
4666
|
+
this.wire.write({
|
|
4667
|
+
type: "tool_call",
|
|
4668
|
+
sessionId: this.sessionId,
|
|
4669
|
+
data: { toolId, toolName, args }
|
|
4670
|
+
});
|
|
4671
|
+
}
|
|
4672
|
+
toolResult(toolId, result, isError = false) {
|
|
4673
|
+
this.wire.write({
|
|
4674
|
+
type: "tool_result",
|
|
4675
|
+
sessionId: this.sessionId,
|
|
4676
|
+
data: { toolId, result, isError }
|
|
4677
|
+
});
|
|
4678
|
+
}
|
|
4679
|
+
approvalRequest(id, toolName, riskLevel) {
|
|
4680
|
+
this.wire.write({
|
|
4681
|
+
type: "approval_request",
|
|
4682
|
+
sessionId: this.sessionId,
|
|
4683
|
+
data: { id, toolName, riskLevel }
|
|
4684
|
+
});
|
|
4685
|
+
}
|
|
4686
|
+
approvalResponse(id, decision) {
|
|
4687
|
+
this.wire.write({
|
|
4688
|
+
type: "approval_response",
|
|
4689
|
+
sessionId: this.sessionId,
|
|
4690
|
+
data: { id, decision }
|
|
4691
|
+
});
|
|
4692
|
+
}
|
|
4693
|
+
statusUpdate(data) {
|
|
4694
|
+
this.wire.write({
|
|
4695
|
+
type: "status_update",
|
|
4696
|
+
sessionId: this.sessionId,
|
|
4697
|
+
data
|
|
4698
|
+
});
|
|
4699
|
+
}
|
|
4700
|
+
error(message, stack) {
|
|
4701
|
+
this.wire.write({
|
|
4702
|
+
type: "error",
|
|
4703
|
+
sessionId: this.sessionId,
|
|
4704
|
+
data: { message, stack }
|
|
4705
|
+
});
|
|
4706
|
+
}
|
|
4707
|
+
};
|
|
4708
|
+
var wireLogger = null;
|
|
4709
|
+
function initWireLogger(sessionDir, sessionId) {
|
|
4710
|
+
wireLogger = new WireLogger(sessionDir, sessionId);
|
|
4711
|
+
return wireLogger;
|
|
4712
|
+
}
|
|
4713
|
+
|
|
4714
|
+
// src/utils/clipboard.ts
|
|
4715
|
+
import { execSync } from "child_process";
|
|
4716
|
+
import { platform } from "os";
|
|
4717
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
4718
|
+
import { join as join5 } from "path";
|
|
4719
|
+
import { tmpdir } from "os";
|
|
4720
|
+
function readClipboardText() {
|
|
4721
|
+
const os = platform();
|
|
4722
|
+
try {
|
|
4723
|
+
if (os === "darwin") {
|
|
4724
|
+
return execSync("pbpaste", { encoding: "utf-8" });
|
|
4725
|
+
} else if (os === "linux") {
|
|
4726
|
+
try {
|
|
4727
|
+
return execSync("xclip -selection clipboard -o", { encoding: "utf-8" });
|
|
4728
|
+
} catch {
|
|
4729
|
+
return execSync("xsel --clipboard --output", { encoding: "utf-8" });
|
|
4730
|
+
}
|
|
4731
|
+
} else if (os === "win32") {
|
|
4732
|
+
return execSync('powershell -command "Get-Clipboard"', { encoding: "utf-8" });
|
|
4733
|
+
}
|
|
4734
|
+
} catch (error) {
|
|
4735
|
+
console.error("Failed to read clipboard:", error);
|
|
4736
|
+
return null;
|
|
4737
|
+
}
|
|
4738
|
+
return null;
|
|
4739
|
+
}
|
|
4740
|
+
function readClipboardImage() {
|
|
4741
|
+
const os = platform();
|
|
4742
|
+
const tmpPath = join5(tmpdir(), `clipboard-${Date.now()}.png`);
|
|
4743
|
+
try {
|
|
4744
|
+
if (os === "darwin") {
|
|
4745
|
+
const script = `
|
|
4746
|
+
set saveFile to POSIX file "${tmpPath}"
|
|
4747
|
+
try
|
|
4748
|
+
set imageData to the clipboard as \xABclass PNGf\xBB
|
|
4749
|
+
set fileRef to open for access saveFile with write permission
|
|
4750
|
+
write imageData to fileRef
|
|
4751
|
+
close access fileRef
|
|
4752
|
+
return "success"
|
|
4753
|
+
on error
|
|
4754
|
+
return "no image"
|
|
4755
|
+
end try
|
|
4756
|
+
`;
|
|
4757
|
+
const result = execSync(`osascript -e '${script}'`, { encoding: "utf-8" }).trim();
|
|
4758
|
+
if (result === "success" && existsSync3(tmpPath)) {
|
|
4759
|
+
const imageBuffer = readFileSync3(tmpPath);
|
|
4760
|
+
const base64 = imageBuffer.toString("base64");
|
|
4761
|
+
return { path: tmpPath, base64 };
|
|
4762
|
+
}
|
|
4763
|
+
} else if (os === "linux") {
|
|
4764
|
+
try {
|
|
4765
|
+
execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}"`, {
|
|
4766
|
+
encoding: "utf-8",
|
|
4767
|
+
shell: "/bin/bash"
|
|
4768
|
+
});
|
|
4769
|
+
if (existsSync3(tmpPath)) {
|
|
4770
|
+
const stats = __require("fs").statSync(tmpPath);
|
|
4771
|
+
if (stats.size > 0) {
|
|
4772
|
+
const imageBuffer = readFileSync3(tmpPath);
|
|
4773
|
+
const base64 = imageBuffer.toString("base64");
|
|
4774
|
+
return { path: tmpPath, base64 };
|
|
4775
|
+
}
|
|
4776
|
+
}
|
|
4777
|
+
} catch {
|
|
4778
|
+
}
|
|
4779
|
+
} else if (os === "win32") {
|
|
4780
|
+
const script = `
|
|
4781
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
4782
|
+
$img = [System.Windows.Forms.Clipboard]::GetImage()
|
|
4783
|
+
if ($img -ne $null) {
|
|
4784
|
+
$img.Save("${tmpPath.replace(/\\/g, "\\\\")}")
|
|
4785
|
+
Write-Output "success"
|
|
4786
|
+
} else {
|
|
4787
|
+
Write-Output "no image"
|
|
4788
|
+
}
|
|
4789
|
+
`;
|
|
4790
|
+
const result = execSync(`powershell -command "${script}"`, { encoding: "utf-8" }).trim();
|
|
4791
|
+
if (result === "success" && existsSync3(tmpPath)) {
|
|
4792
|
+
const imageBuffer = readFileSync3(tmpPath);
|
|
4793
|
+
const base64 = imageBuffer.toString("base64");
|
|
4794
|
+
return { path: tmpPath, base64 };
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
} catch (error) {
|
|
4798
|
+
console.error("Failed to read clipboard image:", error);
|
|
4799
|
+
}
|
|
4800
|
+
if (existsSync3(tmpPath)) {
|
|
4801
|
+
try {
|
|
4802
|
+
unlinkSync2(tmpPath);
|
|
4803
|
+
} catch {
|
|
4804
|
+
}
|
|
4805
|
+
}
|
|
4806
|
+
return null;
|
|
4807
|
+
}
|
|
4808
|
+
function hasClipboardImage() {
|
|
4809
|
+
const os = platform();
|
|
4810
|
+
try {
|
|
4811
|
+
if (os === "darwin") {
|
|
4812
|
+
const result = execSync(
|
|
4813
|
+
`osascript -e 'try' -e 'the clipboard as \xABclass PNGf\xBB' -e 'return "yes"' -e 'on error' -e 'return "no"' -e 'end try'`,
|
|
4814
|
+
{ encoding: "utf-8" }
|
|
4815
|
+
).trim();
|
|
4816
|
+
return result === "yes";
|
|
4817
|
+
} else if (os === "linux") {
|
|
4818
|
+
const result = execSync("xclip -selection clipboard -t TARGETS -o", {
|
|
4819
|
+
encoding: "utf-8"
|
|
4820
|
+
});
|
|
4821
|
+
return result.includes("image/png") || result.includes("image/jpeg");
|
|
4822
|
+
}
|
|
4823
|
+
} catch {
|
|
4824
|
+
return false;
|
|
4825
|
+
}
|
|
4826
|
+
return false;
|
|
4827
|
+
}
|
|
4828
|
+
|
|
4330
4829
|
// src/config/theme.ts
|
|
4331
4830
|
var THEME = {
|
|
4332
4831
|
// Primary backgrounds (dark purple tones)
|
|
@@ -4444,8 +4943,68 @@ var ASCII_BANNER = `
|
|
|
4444
4943
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
4445
4944
|
`;
|
|
4446
4945
|
|
|
4447
|
-
// src/cli/
|
|
4946
|
+
// src/cli/components/rich-display.tsx
|
|
4947
|
+
import { Box, Text } from "ink";
|
|
4448
4948
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4949
|
+
var SeverityBadge = ({ severity }) => {
|
|
4950
|
+
const colors = {
|
|
4951
|
+
critical: THEME.semantic.critical,
|
|
4952
|
+
high: THEME.semantic.high,
|
|
4953
|
+
medium: THEME.semantic.medium,
|
|
4954
|
+
low: THEME.semantic.low,
|
|
4955
|
+
info: THEME.semantic.info
|
|
4956
|
+
};
|
|
4957
|
+
return /* @__PURE__ */ jsxs(Text, { color: colors[severity], bold: true, children: [
|
|
4958
|
+
"\u25CF ",
|
|
4959
|
+
severity.toUpperCase()
|
|
4960
|
+
] });
|
|
4961
|
+
};
|
|
4962
|
+
var FindingDisplay = ({ block }) => {
|
|
4963
|
+
const severityColors = {
|
|
4964
|
+
critical: THEME.semantic.critical,
|
|
4965
|
+
high: THEME.semantic.high,
|
|
4966
|
+
medium: THEME.semantic.medium,
|
|
4967
|
+
low: THEME.semantic.low,
|
|
4968
|
+
info: THEME.semantic.info
|
|
4969
|
+
};
|
|
4970
|
+
return /* @__PURE__ */ jsxs(
|
|
4971
|
+
Box,
|
|
4972
|
+
{
|
|
4973
|
+
flexDirection: "column",
|
|
4974
|
+
borderStyle: "double",
|
|
4975
|
+
borderColor: severityColors[block.severity],
|
|
4976
|
+
paddingX: 1,
|
|
4977
|
+
children: [
|
|
4978
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
4979
|
+
/* @__PURE__ */ jsx(SeverityBadge, { severity: block.severity }),
|
|
4980
|
+
/* @__PURE__ */ jsxs(Text, { color: THEME.text.primary, bold: true, children: [
|
|
4981
|
+
" ",
|
|
4982
|
+
block.title
|
|
4983
|
+
] }),
|
|
4984
|
+
block.cve && /* @__PURE__ */ jsxs(Text, { color: THEME.text.muted, children: [
|
|
4985
|
+
" (",
|
|
4986
|
+
block.cve,
|
|
4987
|
+
")"
|
|
4988
|
+
] })
|
|
4989
|
+
] }),
|
|
4990
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx(Text, { color: THEME.text.secondary, children: block.description }) }),
|
|
4991
|
+
block.evidence && /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
4992
|
+
/* @__PURE__ */ jsx(Text, { color: THEME.accent.cyan, bold: true, children: "Evidence:" }),
|
|
4993
|
+
/* @__PURE__ */ jsx(Text, { color: THEME.text.muted, children: block.evidence })
|
|
4994
|
+
] }),
|
|
4995
|
+
block.recommendation && /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
4996
|
+
/* @__PURE__ */ jsx(Text, { color: THEME.accent.green, bold: true, children: "Recommendation:" }),
|
|
4997
|
+
/* @__PURE__ */ jsx(Text, { color: THEME.text.secondary, children: block.recommendation })
|
|
4998
|
+
] })
|
|
4999
|
+
]
|
|
5000
|
+
}
|
|
5001
|
+
);
|
|
5002
|
+
};
|
|
5003
|
+
|
|
5004
|
+
// src/cli/app.tsx
|
|
5005
|
+
import { homedir } from "os";
|
|
5006
|
+
import { join as join6 } from "path";
|
|
5007
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
4449
5008
|
var App = ({ autoApprove = false, target }) => {
|
|
4450
5009
|
const { exit } = useApp();
|
|
4451
5010
|
const [messages, setMessages] = useState([]);
|
|
@@ -4458,9 +5017,23 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4458
5017
|
const [tokenUsage, setTokenUsage] = useState({ input: 0, output: 0, total: 0 });
|
|
4459
5018
|
const [showCommandHints, setShowCommandHints] = useState(false);
|
|
4460
5019
|
const [mode, setMode] = useState("agent");
|
|
5020
|
+
const [checkpointCount, setCheckpointCount] = useState(0);
|
|
4461
5021
|
const [agent] = useState(() => new AutonomousHackingAgent(void 0, { autoApprove }));
|
|
4462
5022
|
const sessionManager2 = getSessionManager();
|
|
4463
5023
|
const approvalManager2 = getApprovalManager({ yoloMode: autoApprove });
|
|
5024
|
+
const sessionDirRef = useRef(join6(homedir(), ".pentest", "sessions", `session-${Date.now()}`));
|
|
5025
|
+
const contextManagerRef = useRef(null);
|
|
5026
|
+
const wireLoggerRef = useRef(null);
|
|
5027
|
+
useEffect(() => {
|
|
5028
|
+
const sessionId = `session-${Date.now()}`;
|
|
5029
|
+
contextManagerRef.current = new ContextManager2(sessionDirRef.current);
|
|
5030
|
+
wireLoggerRef.current = initWireLogger(sessionDirRef.current, sessionId);
|
|
5031
|
+
contextManagerRef.current.restore().then((restored) => {
|
|
5032
|
+
if (restored) {
|
|
5033
|
+
setCheckpointCount(contextManagerRef.current?.getCheckpoints().length || 0);
|
|
5034
|
+
}
|
|
5035
|
+
});
|
|
5036
|
+
}, []);
|
|
4464
5037
|
const startTimeRef = useRef(0);
|
|
4465
5038
|
const timerRef = useRef(null);
|
|
4466
5039
|
const addMessage = useCallback((type, content, duration) => {
|
|
@@ -4498,31 +5071,39 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4498
5071
|
}
|
|
4499
5072
|
agent.on(AGENT_EVENT.THOUGHT, (thought) => {
|
|
4500
5073
|
setCurrentStatus(thought.content.slice(0, 60));
|
|
5074
|
+
wireLoggerRef.current?.contentPart(thought.content, thought.type === "thinking");
|
|
4501
5075
|
});
|
|
4502
5076
|
agent.on(AGENT_EVENT.TOOL_CALL, (data) => {
|
|
4503
5077
|
const args = Object.entries(data.input).slice(0, 2).map(([k, v]) => `${k}=${typeof v === "string" ? v.slice(0, 30) : "..."}`).join(" ");
|
|
4504
5078
|
setCurrentStatus(`Running ${data.name}...`);
|
|
4505
5079
|
addMessage(MESSAGE_TYPE.TOOL, `\u25B6 ${data.name} ${args}`);
|
|
5080
|
+
wireLoggerRef.current?.toolCall(data.id, data.name, data.input);
|
|
4506
5081
|
});
|
|
4507
5082
|
agent.on(AGENT_EVENT.TOOL_RESULT, (data) => {
|
|
4508
5083
|
const icon = data.result.success ? "\u2713" : "\u2717";
|
|
4509
5084
|
const preview = data.result.output?.slice(0, 100).replace(/\n/g, " ") || "";
|
|
4510
5085
|
addMessage(MESSAGE_TYPE.RESULT, `${icon} ${preview}`);
|
|
5086
|
+
wireLoggerRef.current?.toolResult(data.id, data.result, !data.result.success);
|
|
4511
5087
|
});
|
|
4512
5088
|
agent.on(AGENT_EVENT.ITERATION, (data) => {
|
|
4513
5089
|
setCurrentStatus(`Phase: ${data.phase} (iteration ${data.current})`);
|
|
5090
|
+
wireLoggerRef.current?.stepBegin(data.current);
|
|
4514
5091
|
});
|
|
4515
5092
|
agent.on(AGENT_EVENT.FINDING, (finding) => {
|
|
4516
5093
|
addMessage(MESSAGE_TYPE.SYSTEM, `\u{1F3AF} [${finding.severity.toUpperCase()}] ${finding.title}`);
|
|
5094
|
+
wireLoggerRef.current?.statusUpdate({ event: "finding", ...finding });
|
|
4517
5095
|
});
|
|
4518
5096
|
agent.on(AGENT_EVENT.PHASE_CHANGE, (data) => {
|
|
4519
5097
|
addMessage(MESSAGE_TYPE.SYSTEM, `\u{1F4CD} Phase: ${data.phaseId}`);
|
|
5098
|
+
wireLoggerRef.current?.statusUpdate({ event: "phase_change", phase: data.phaseId });
|
|
4520
5099
|
});
|
|
4521
5100
|
agent.on(AGENT_EVENT.CONTEXT_COMPACTED, () => {
|
|
4522
5101
|
addMessage(MESSAGE_TYPE.SYSTEM, "\u{1F4BE} Context compacted to save tokens");
|
|
5102
|
+
wireLoggerRef.current?.statusUpdate({ event: "context_compacted" });
|
|
4523
5103
|
});
|
|
4524
5104
|
agent.on(AGENT_EVENT.TOKEN_USAGE, (usage) => {
|
|
4525
5105
|
setTokenUsage(usage);
|
|
5106
|
+
wireLoggerRef.current?.statusUpdate({ event: "token_usage", ...usage });
|
|
4526
5107
|
});
|
|
4527
5108
|
agent.on(AGENT_EVENT.APPROVAL_NEEDED, (data) => {
|
|
4528
5109
|
setPendingApproval({
|
|
@@ -4601,16 +5182,30 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4601
5182
|
case "h":
|
|
4602
5183
|
addMessage(
|
|
4603
5184
|
MESSAGE_TYPE.SYSTEM,
|
|
4604
|
-
|
|
5185
|
+
`\u2500\u2500 Core \u2500\u2500
|
|
5186
|
+
/target <ip> Set target
|
|
4605
5187
|
/start [goal] Start autonomous pentest
|
|
4606
5188
|
/stop Stop operation
|
|
4607
|
-
/
|
|
5189
|
+
/status Show status report
|
|
5190
|
+
|
|
5191
|
+
\u2500\u2500 Session \u2500\u2500
|
|
5192
|
+
/checkpoint [desc] Create checkpoint
|
|
5193
|
+
/checkpoints List all checkpoints
|
|
5194
|
+
/undo Undo to last checkpoint
|
|
5195
|
+
/revert <id> Revert to checkpoint
|
|
5196
|
+
/compact Compact context
|
|
4608
5197
|
/sessions List saved sessions
|
|
4609
5198
|
/resume [id] Resume session
|
|
5199
|
+
|
|
5200
|
+
\u2500\u2500 Findings \u2500\u2500
|
|
5201
|
+
/findings Show findings
|
|
5202
|
+
|
|
5203
|
+
\u2500\u2500 Utility \u2500\u2500
|
|
5204
|
+
/paste Paste from clipboard
|
|
4610
5205
|
/yolo Toggle auto-approve
|
|
4611
5206
|
/clear Clear screen
|
|
4612
5207
|
/exit Exit
|
|
4613
|
-
/
|
|
5208
|
+
/y /n /ya Approve/Deny/Always (approval)`
|
|
4614
5209
|
);
|
|
4615
5210
|
return;
|
|
4616
5211
|
case CLI_COMMAND.TARGET:
|
|
@@ -4724,17 +5319,99 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4724
5319
|
addMessage(MESSAGE_TYPE.ERROR, "No pending approval");
|
|
4725
5320
|
}
|
|
4726
5321
|
return;
|
|
4727
|
-
// kimi-cli inspired commands
|
|
5322
|
+
// kimi-cli inspired commands - REAL IMPLEMENTATIONS
|
|
4728
5323
|
case "undo":
|
|
4729
5324
|
case "u":
|
|
4730
|
-
|
|
5325
|
+
if (contextManagerRef.current) {
|
|
5326
|
+
const success = await contextManagerRef.current.undo();
|
|
5327
|
+
if (success) {
|
|
5328
|
+
setCheckpointCount((prev) => Math.max(0, prev - 1));
|
|
5329
|
+
wireLoggerRef.current?.statusUpdate({ action: "undo" });
|
|
5330
|
+
addMessage(MESSAGE_TYPE.SYSTEM, "\u21A9\uFE0F Undone to previous checkpoint");
|
|
5331
|
+
} else {
|
|
5332
|
+
addMessage(MESSAGE_TYPE.ERROR, "No checkpoint to undo");
|
|
5333
|
+
}
|
|
5334
|
+
} else {
|
|
5335
|
+
addMessage(MESSAGE_TYPE.ERROR, "Context manager not initialized");
|
|
5336
|
+
}
|
|
4731
5337
|
return;
|
|
4732
5338
|
case "checkpoint":
|
|
4733
5339
|
case "cp":
|
|
4734
|
-
|
|
5340
|
+
if (contextManagerRef.current) {
|
|
5341
|
+
const description = args.join(" ") || void 0;
|
|
5342
|
+
const cp = await contextManagerRef.current.checkpoint(description);
|
|
5343
|
+
setCheckpointCount((prev) => prev + 1);
|
|
5344
|
+
wireLoggerRef.current?.statusUpdate({ action: "checkpoint", id: cp.id });
|
|
5345
|
+
addMessage(MESSAGE_TYPE.SYSTEM, `\u{1F4CD} Checkpoint #${cp.id} created${description ? `: ${description}` : ""}`);
|
|
5346
|
+
} else {
|
|
5347
|
+
addMessage(MESSAGE_TYPE.ERROR, "Context manager not initialized");
|
|
5348
|
+
}
|
|
4735
5349
|
return;
|
|
4736
5350
|
case "compact":
|
|
4737
|
-
|
|
5351
|
+
if (contextManagerRef.current) {
|
|
5352
|
+
const summary = "Previous conversation summarized for context efficiency.";
|
|
5353
|
+
await contextManagerRef.current.compact(summary, 3);
|
|
5354
|
+
wireLoggerRef.current?.statusUpdate({ action: "compact" });
|
|
5355
|
+
addMessage(MESSAGE_TYPE.SYSTEM, "\u{1F5DC}\uFE0F Context compacted (keeping last 3 messages)");
|
|
5356
|
+
} else {
|
|
5357
|
+
addMessage(MESSAGE_TYPE.ERROR, "Context manager not initialized");
|
|
5358
|
+
}
|
|
5359
|
+
return;
|
|
5360
|
+
case "paste":
|
|
5361
|
+
case "p":
|
|
5362
|
+
try {
|
|
5363
|
+
if (hasClipboardImage()) {
|
|
5364
|
+
const img = readClipboardImage();
|
|
5365
|
+
if (img) {
|
|
5366
|
+
addMessage(MESSAGE_TYPE.SYSTEM, `\u{1F4F7} Image from clipboard: ${img.path}`);
|
|
5367
|
+
addMessage(MESSAGE_TYPE.SYSTEM, ` Size: ${Math.round(img.base64.length / 1024)}KB base64`);
|
|
5368
|
+
}
|
|
5369
|
+
} else {
|
|
5370
|
+
const text = readClipboardText();
|
|
5371
|
+
if (text) {
|
|
5372
|
+
const preview = text.length > 100 ? text.slice(0, 100) + "..." : text;
|
|
5373
|
+
addMessage(MESSAGE_TYPE.SYSTEM, `\u{1F4CB} Clipboard: ${preview}`);
|
|
5374
|
+
setInput(text);
|
|
5375
|
+
} else {
|
|
5376
|
+
addMessage(MESSAGE_TYPE.ERROR, "Clipboard is empty");
|
|
5377
|
+
}
|
|
5378
|
+
}
|
|
5379
|
+
} catch (e) {
|
|
5380
|
+
addMessage(MESSAGE_TYPE.ERROR, `Clipboard error: ${e instanceof Error ? e.message : String(e)}`);
|
|
5381
|
+
}
|
|
5382
|
+
return;
|
|
5383
|
+
case "revert":
|
|
5384
|
+
if (contextManagerRef.current && args[0]) {
|
|
5385
|
+
const cpId = parseInt(args[0], 10);
|
|
5386
|
+
if (isNaN(cpId)) {
|
|
5387
|
+
addMessage(MESSAGE_TYPE.ERROR, "Usage: /revert <checkpoint_id>");
|
|
5388
|
+
return;
|
|
5389
|
+
}
|
|
5390
|
+
const success = await contextManagerRef.current.revertTo(cpId);
|
|
5391
|
+
if (success) {
|
|
5392
|
+
wireLoggerRef.current?.statusUpdate({ action: "revert", checkpointId: cpId });
|
|
5393
|
+
addMessage(MESSAGE_TYPE.SYSTEM, `\u21A9\uFE0F Reverted to checkpoint #${cpId}`);
|
|
5394
|
+
} else {
|
|
5395
|
+
addMessage(MESSAGE_TYPE.ERROR, `Checkpoint #${cpId} not found`);
|
|
5396
|
+
}
|
|
5397
|
+
} else {
|
|
5398
|
+
addMessage(MESSAGE_TYPE.ERROR, "Usage: /revert <checkpoint_id>");
|
|
5399
|
+
}
|
|
5400
|
+
return;
|
|
5401
|
+
case "checkpoints":
|
|
5402
|
+
case "cps":
|
|
5403
|
+
if (contextManagerRef.current) {
|
|
5404
|
+
const cps = contextManagerRef.current.getCheckpoints();
|
|
5405
|
+
if (cps.length === 0) {
|
|
5406
|
+
addMessage(MESSAGE_TYPE.SYSTEM, "No checkpoints");
|
|
5407
|
+
} else {
|
|
5408
|
+
addMessage(MESSAGE_TYPE.SYSTEM, `\u{1F4CD} ${cps.length} Checkpoints:`);
|
|
5409
|
+
cps.forEach((cp) => {
|
|
5410
|
+
const time = new Date(cp.timestamp).toLocaleTimeString();
|
|
5411
|
+
addMessage(MESSAGE_TYPE.SYSTEM, ` #${cp.id} @ ${time} (${cp.messageCount} msgs)${cp.description ? ` - ${cp.description}` : ""}`);
|
|
5412
|
+
});
|
|
5413
|
+
}
|
|
5414
|
+
}
|
|
4738
5415
|
return;
|
|
4739
5416
|
case "status":
|
|
4740
5417
|
const state2 = agent.getState();
|
|
@@ -4743,7 +5420,8 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4743
5420
|
Iteration: ${state2.iteration}
|
|
4744
5421
|
Findings: ${state2.findings.length}
|
|
4745
5422
|
Compromised: ${state2.compromisedHosts.length}
|
|
4746
|
-
Tokens: ${tokenUsage.total.toLocaleString()}
|
|
5423
|
+
Tokens: ${tokenUsage.total.toLocaleString()}
|
|
5424
|
+
Checkpoints: ${checkpointCount}`);
|
|
4747
5425
|
return;
|
|
4748
5426
|
case "think":
|
|
4749
5427
|
addMessage(MESSAGE_TYPE.SYSTEM, "\u{1F9E0} Thinking mode: Extended reasoning enabled");
|
|
@@ -4774,8 +5452,8 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4774
5452
|
startTimer();
|
|
4775
5453
|
setCurrentStatus(`Running: ${trimmed}`);
|
|
4776
5454
|
try {
|
|
4777
|
-
const { execSync } = await import("child_process");
|
|
4778
|
-
const output =
|
|
5455
|
+
const { execSync: execSync2 } = await import("child_process");
|
|
5456
|
+
const output = execSync2(trimmed, {
|
|
4779
5457
|
encoding: "utf-8",
|
|
4780
5458
|
timeout: 3e4,
|
|
4781
5459
|
maxBuffer: 1024 * 1024
|
|
@@ -4859,48 +5537,51 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4859
5537
|
return styles[type] || styles[MESSAGE_TYPE.SYSTEM];
|
|
4860
5538
|
};
|
|
4861
5539
|
const state = agent.getState();
|
|
4862
|
-
return /* @__PURE__ */
|
|
4863
|
-
/* @__PURE__ */
|
|
5540
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
5541
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx2(Static, { items: messages.slice(-40), children: (msg) => {
|
|
4864
5542
|
const style = getStyle(msg.type);
|
|
4865
|
-
|
|
5543
|
+
if (msg.finding) {
|
|
5544
|
+
return /* @__PURE__ */ jsx2(Box2, { marginY: 0, children: /* @__PURE__ */ jsx2(FindingDisplay, { block: msg.finding }) }, msg.id);
|
|
5545
|
+
}
|
|
5546
|
+
return /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { color: style.color, dimColor: style.dim, children: [
|
|
4866
5547
|
style.prefix,
|
|
4867
5548
|
" ",
|
|
4868
5549
|
msg.content,
|
|
4869
|
-
msg.duration && /* @__PURE__ */
|
|
5550
|
+
msg.duration && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
4870
5551
|
" (",
|
|
4871
5552
|
msg.duration,
|
|
4872
5553
|
"s)"
|
|
4873
5554
|
] })
|
|
4874
5555
|
] }) }, msg.id);
|
|
4875
5556
|
} }) }),
|
|
4876
|
-
pendingApproval && /* @__PURE__ */
|
|
4877
|
-
/* @__PURE__ */
|
|
5557
|
+
pendingApproval && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginBottom: 1, children: [
|
|
5558
|
+
/* @__PURE__ */ jsxs2(Text2, { color: "yellow", bold: true, children: [
|
|
4878
5559
|
"\u26A0\uFE0F APPROVAL NEEDED: ",
|
|
4879
5560
|
pendingApproval.toolName,
|
|
4880
5561
|
" (",
|
|
4881
5562
|
pendingApproval.riskLevel,
|
|
4882
5563
|
" risk)"
|
|
4883
5564
|
] }),
|
|
4884
|
-
/* @__PURE__ */
|
|
4885
|
-
/* @__PURE__ */
|
|
5565
|
+
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: Object.entries(pendingApproval.toolInput).slice(0, 2).map(([k, v]) => `${k}=${typeof v === "string" ? v.slice(0, 50) : JSON.stringify(v).slice(0, 50)}`).join(", ") }),
|
|
5566
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, children: approvalOptions.map((opt, idx) => /* @__PURE__ */ jsxs2(Text2, { color: idx === approvalSelectedIndex ? "cyan" : "gray", children: [
|
|
4886
5567
|
idx === approvalSelectedIndex ? "\u2192 " : " ",
|
|
4887
5568
|
opt.label
|
|
4888
5569
|
] }, opt.decision)) }),
|
|
4889
|
-
/* @__PURE__ */
|
|
5570
|
+
/* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u2191\u2193 to select, Enter to confirm, or type /y /n /ya" }) })
|
|
4890
5571
|
] }),
|
|
4891
|
-
isProcessing ? /* @__PURE__ */
|
|
4892
|
-
/* @__PURE__ */
|
|
4893
|
-
/* @__PURE__ */
|
|
5572
|
+
isProcessing ? /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
5573
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.status.running, children: /* @__PURE__ */ jsx2(Spinner, { type: "dots" }) }),
|
|
5574
|
+
/* @__PURE__ */ jsxs2(Text2, { color: THEME.text.muted, children: [
|
|
4894
5575
|
" ",
|
|
4895
5576
|
currentStatus,
|
|
4896
|
-
elapsedTime > 0 && /* @__PURE__ */
|
|
5577
|
+
elapsedTime > 0 && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
4897
5578
|
" (",
|
|
4898
5579
|
elapsedTime,
|
|
4899
5580
|
"s)"
|
|
4900
5581
|
] })
|
|
4901
5582
|
] })
|
|
4902
|
-
] }) : /* @__PURE__ */
|
|
4903
|
-
showCommandHints && input.startsWith("/") && /* @__PURE__ */
|
|
5583
|
+
] }) : /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
5584
|
+
showCommandHints && input.startsWith("/") && /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: [
|
|
4904
5585
|
"/target <ip>",
|
|
4905
5586
|
"/start",
|
|
4906
5587
|
"/stop",
|
|
@@ -4911,9 +5592,9 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4911
5592
|
"/exit",
|
|
4912
5593
|
pendingApproval ? "/y /n /ya" : ""
|
|
4913
5594
|
].filter((cmd) => cmd && cmd.toLowerCase().includes(input.toLowerCase().slice(1))).slice(0, 5).join(" \u2502 ") }) }),
|
|
4914
|
-
/* @__PURE__ */
|
|
4915
|
-
/* @__PURE__ */
|
|
4916
|
-
/* @__PURE__ */
|
|
5595
|
+
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
5596
|
+
/* @__PURE__ */ jsx2(Text2, { color: mode === "agent" ? THEME.status.success : "yellow", children: mode === "agent" ? "\u2728 " : "$ " }),
|
|
5597
|
+
/* @__PURE__ */ jsx2(
|
|
4917
5598
|
TextInput,
|
|
4918
5599
|
{
|
|
4919
5600
|
value: input,
|
|
@@ -4927,8 +5608,8 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4927
5608
|
)
|
|
4928
5609
|
] })
|
|
4929
5610
|
] }),
|
|
4930
|
-
/* @__PURE__ */
|
|
4931
|
-
/* @__PURE__ */
|
|
5611
|
+
/* @__PURE__ */ jsxs2(Box2, { marginTop: 1, justifyContent: "space-between", children: [
|
|
5612
|
+
/* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
4932
5613
|
mode === "agent" ? "\u{1F916}" : "$",
|
|
4933
5614
|
" ",
|
|
4934
5615
|
state.target.primary || "No target",
|
|
@@ -4940,7 +5621,7 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4940
5621
|
tokenUsage.total > 0 && `${(tokenUsage.total / 1e3).toFixed(1)}k tokens \u2502`,
|
|
4941
5622
|
state.currentPhase !== AGENT_STATUS.IDLE && ` ${state.currentPhase} \u2502`
|
|
4942
5623
|
] }),
|
|
4943
|
-
/* @__PURE__ */
|
|
5624
|
+
/* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
4944
5625
|
"Ctrl+X mode \u2502 /help \u2502 Ctrl+C ",
|
|
4945
5626
|
isProcessing ? "stop" : "exit"
|
|
4946
5627
|
] })
|
|
@@ -4951,7 +5632,7 @@ var app_default = App;
|
|
|
4951
5632
|
|
|
4952
5633
|
// src/index.tsx
|
|
4953
5634
|
import chalk from "chalk";
|
|
4954
|
-
import { jsx as
|
|
5635
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
4955
5636
|
var program = new Command();
|
|
4956
5637
|
program.name("pentesting").version(APP_VERSION).description(APP_DESCRIPTION).option("--dangerously-skip-permissions", "Skip all permission prompts (dangerous!)").option("-t, --target <target>", "Set initial target");
|
|
4957
5638
|
program.command("interactive", { isDefault: true }).alias("i").description("Start interactive TUI mode").action(() => {
|
|
@@ -4965,7 +5646,7 @@ program.command("interactive", { isDefault: true }).alias("i").description("Star
|
|
|
4965
5646
|
}
|
|
4966
5647
|
console.log(chalk.hex(THEME.text.accent)("Starting Pentest interactive mode...\n"));
|
|
4967
5648
|
const { waitUntilExit } = render(
|
|
4968
|
-
/* @__PURE__ */
|
|
5649
|
+
/* @__PURE__ */ jsx3(
|
|
4969
5650
|
app_default,
|
|
4970
5651
|
{
|
|
4971
5652
|
autoApprove: skipPermissions,
|