pentesting 0.3.0 → 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.
Files changed (2) hide show
  1. package/dist/index.js +845 -33
  2. 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[platform]?.[payload_type] || `${platform}/meterpreter/reverse_tcp`;
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.0";
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;
@@ -4231,6 +4237,595 @@ function getSessionManager() {
4231
4237
  return sessionManager;
4232
4238
  }
4233
4239
 
4240
+ // src/core/commands/slash-registry.ts
4241
+ var SlashCommandRegistry = class {
4242
+ commands = /* @__PURE__ */ new Map();
4243
+ aliases = /* @__PURE__ */ new Map();
4244
+ /**
4245
+ * Register a command with optional aliases
4246
+ */
4247
+ register(name, handler, options) {
4248
+ const cmd = {
4249
+ name,
4250
+ description: options?.description || "",
4251
+ aliases: options?.aliases || [],
4252
+ handler
4253
+ };
4254
+ this.commands.set(name, cmd);
4255
+ this.aliases.set(name, cmd);
4256
+ for (const alias of cmd.aliases) {
4257
+ this.aliases.set(alias, cmd);
4258
+ }
4259
+ }
4260
+ /**
4261
+ * Find a command by name or alias
4262
+ */
4263
+ find(nameOrAlias) {
4264
+ return this.aliases.get(nameOrAlias);
4265
+ }
4266
+ /**
4267
+ * Execute a command
4268
+ */
4269
+ async execute(input) {
4270
+ const parsed = this.parse(input);
4271
+ if (!parsed) {
4272
+ return { handled: false };
4273
+ }
4274
+ const cmd = this.find(parsed.name);
4275
+ if (!cmd) {
4276
+ return { handled: false };
4277
+ }
4278
+ const result = await cmd.handler(parsed.args);
4279
+ return { handled: true, result: result || void 0 };
4280
+ }
4281
+ /**
4282
+ * Parse slash command from input
4283
+ */
4284
+ parse(input) {
4285
+ const trimmed = input.trim();
4286
+ if (!trimmed.startsWith("/")) {
4287
+ return null;
4288
+ }
4289
+ const match = trimmed.match(/^\/([a-zA-Z0-9_-]+)(?:\s+(.*))?$/);
4290
+ if (!match) {
4291
+ return null;
4292
+ }
4293
+ return {
4294
+ name: match[1].toLowerCase(),
4295
+ args: match[2] || ""
4296
+ };
4297
+ }
4298
+ /**
4299
+ * Get all commands (for help display)
4300
+ */
4301
+ list() {
4302
+ return Array.from(this.commands.values());
4303
+ }
4304
+ /**
4305
+ * Get formatted help text
4306
+ */
4307
+ getHelp() {
4308
+ const lines = ["Available commands:", ""];
4309
+ for (const cmd of this.list()) {
4310
+ const aliasStr = cmd.aliases.length > 0 ? ` (${cmd.aliases.join(", ")})` : "";
4311
+ lines.push(` /${cmd.name}${aliasStr}`);
4312
+ if (cmd.description) {
4313
+ lines.push(` ${cmd.description}`);
4314
+ }
4315
+ }
4316
+ return lines.join("\n");
4317
+ }
4318
+ /**
4319
+ * Get matching commands for autocomplete
4320
+ */
4321
+ getCompletions(partial) {
4322
+ const search = partial.toLowerCase().replace(/^\//, "");
4323
+ return this.list().filter(
4324
+ (cmd) => cmd.name.startsWith(search) || cmd.aliases.some((a) => a.startsWith(search))
4325
+ );
4326
+ }
4327
+ };
4328
+ var registry = null;
4329
+ function getSlashCommandRegistry() {
4330
+ if (!registry) {
4331
+ registry = new SlashCommandRegistry();
4332
+ }
4333
+ return registry;
4334
+ }
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
+
4234
4829
  // src/config/theme.ts
4235
4830
  var THEME = {
4236
4831
  // Primary backgrounds (dark purple tones)
@@ -4348,8 +4943,68 @@ var ASCII_BANNER = `
4348
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
4349
4944
  `;
4350
4945
 
4351
- // src/cli/app.tsx
4946
+ // src/cli/components/rich-display.tsx
4947
+ import { Box, Text } from "ink";
4352
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";
4353
5008
  var App = ({ autoApprove = false, target }) => {
4354
5009
  const { exit } = useApp();
4355
5010
  const [messages, setMessages] = useState([]);
@@ -4362,9 +5017,23 @@ var App = ({ autoApprove = false, target }) => {
4362
5017
  const [tokenUsage, setTokenUsage] = useState({ input: 0, output: 0, total: 0 });
4363
5018
  const [showCommandHints, setShowCommandHints] = useState(false);
4364
5019
  const [mode, setMode] = useState("agent");
5020
+ const [checkpointCount, setCheckpointCount] = useState(0);
4365
5021
  const [agent] = useState(() => new AutonomousHackingAgent(void 0, { autoApprove }));
4366
5022
  const sessionManager2 = getSessionManager();
4367
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
+ }, []);
4368
5037
  const startTimeRef = useRef(0);
4369
5038
  const timerRef = useRef(null);
4370
5039
  const addMessage = useCallback((type, content, duration) => {
@@ -4402,31 +5071,39 @@ var App = ({ autoApprove = false, target }) => {
4402
5071
  }
4403
5072
  agent.on(AGENT_EVENT.THOUGHT, (thought) => {
4404
5073
  setCurrentStatus(thought.content.slice(0, 60));
5074
+ wireLoggerRef.current?.contentPart(thought.content, thought.type === "thinking");
4405
5075
  });
4406
5076
  agent.on(AGENT_EVENT.TOOL_CALL, (data) => {
4407
5077
  const args = Object.entries(data.input).slice(0, 2).map(([k, v]) => `${k}=${typeof v === "string" ? v.slice(0, 30) : "..."}`).join(" ");
4408
5078
  setCurrentStatus(`Running ${data.name}...`);
4409
5079
  addMessage(MESSAGE_TYPE.TOOL, `\u25B6 ${data.name} ${args}`);
5080
+ wireLoggerRef.current?.toolCall(data.id, data.name, data.input);
4410
5081
  });
4411
5082
  agent.on(AGENT_EVENT.TOOL_RESULT, (data) => {
4412
5083
  const icon = data.result.success ? "\u2713" : "\u2717";
4413
5084
  const preview = data.result.output?.slice(0, 100).replace(/\n/g, " ") || "";
4414
5085
  addMessage(MESSAGE_TYPE.RESULT, `${icon} ${preview}`);
5086
+ wireLoggerRef.current?.toolResult(data.id, data.result, !data.result.success);
4415
5087
  });
4416
5088
  agent.on(AGENT_EVENT.ITERATION, (data) => {
4417
5089
  setCurrentStatus(`Phase: ${data.phase} (iteration ${data.current})`);
5090
+ wireLoggerRef.current?.stepBegin(data.current);
4418
5091
  });
4419
5092
  agent.on(AGENT_EVENT.FINDING, (finding) => {
4420
5093
  addMessage(MESSAGE_TYPE.SYSTEM, `\u{1F3AF} [${finding.severity.toUpperCase()}] ${finding.title}`);
5094
+ wireLoggerRef.current?.statusUpdate({ event: "finding", ...finding });
4421
5095
  });
4422
5096
  agent.on(AGENT_EVENT.PHASE_CHANGE, (data) => {
4423
5097
  addMessage(MESSAGE_TYPE.SYSTEM, `\u{1F4CD} Phase: ${data.phaseId}`);
5098
+ wireLoggerRef.current?.statusUpdate({ event: "phase_change", phase: data.phaseId });
4424
5099
  });
4425
5100
  agent.on(AGENT_EVENT.CONTEXT_COMPACTED, () => {
4426
5101
  addMessage(MESSAGE_TYPE.SYSTEM, "\u{1F4BE} Context compacted to save tokens");
5102
+ wireLoggerRef.current?.statusUpdate({ event: "context_compacted" });
4427
5103
  });
4428
5104
  agent.on(AGENT_EVENT.TOKEN_USAGE, (usage) => {
4429
5105
  setTokenUsage(usage);
5106
+ wireLoggerRef.current?.statusUpdate({ event: "token_usage", ...usage });
4430
5107
  });
4431
5108
  agent.on(AGENT_EVENT.APPROVAL_NEEDED, (data) => {
4432
5109
  setPendingApproval({
@@ -4505,16 +5182,30 @@ var App = ({ autoApprove = false, target }) => {
4505
5182
  case "h":
4506
5183
  addMessage(
4507
5184
  MESSAGE_TYPE.SYSTEM,
4508
- `/target <ip> Set target
5185
+ `\u2500\u2500 Core \u2500\u2500
5186
+ /target <ip> Set target
4509
5187
  /start [goal] Start autonomous pentest
4510
5188
  /stop Stop operation
4511
- /findings Show findings
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
4512
5197
  /sessions List saved sessions
4513
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
4514
5205
  /yolo Toggle auto-approve
4515
5206
  /clear Clear screen
4516
5207
  /exit Exit
4517
- /approve /deny Approve/deny tool (during approval)`
5208
+ /y /n /ya Approve/Deny/Always (approval)`
4518
5209
  );
4519
5210
  return;
4520
5211
  case CLI_COMMAND.TARGET:
@@ -4628,7 +5319,125 @@ var App = ({ autoApprove = false, target }) => {
4628
5319
  addMessage(MESSAGE_TYPE.ERROR, "No pending approval");
4629
5320
  }
4630
5321
  return;
5322
+ // kimi-cli inspired commands - REAL IMPLEMENTATIONS
5323
+ case "undo":
5324
+ case "u":
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
+ }
5337
+ return;
5338
+ case "checkpoint":
5339
+ case "cp":
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
+ }
5349
+ return;
5350
+ case "compact":
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
+ }
5415
+ return;
5416
+ case "status":
5417
+ const state2 = agent.getState();
5418
+ addMessage(MESSAGE_TYPE.SYSTEM, `\u{1F4CA} Status Report:
5419
+ Phase: ${state2.currentPhase}
5420
+ Iteration: ${state2.iteration}
5421
+ Findings: ${state2.findings.length}
5422
+ Compromised: ${state2.compromisedHosts.length}
5423
+ Tokens: ${tokenUsage.total.toLocaleString()}
5424
+ Checkpoints: ${checkpointCount}`);
5425
+ return;
5426
+ case "think":
5427
+ addMessage(MESSAGE_TYPE.SYSTEM, "\u{1F9E0} Thinking mode: Extended reasoning enabled");
5428
+ return;
4631
5429
  default:
5430
+ const slashRegistry = getSlashCommandRegistry();
5431
+ const slashCmd = slashRegistry.find(cmd);
5432
+ if (slashCmd) {
5433
+ try {
5434
+ const result = await slashCmd.handler(args.join(" "));
5435
+ addMessage(MESSAGE_TYPE.SYSTEM, result || `\u2713 /${cmd} executed`);
5436
+ } catch (e) {
5437
+ addMessage(MESSAGE_TYPE.ERROR, e instanceof Error ? e.message : String(e));
5438
+ }
5439
+ return;
5440
+ }
4632
5441
  const cmdResult = await agent.processCommand(trimmed);
4633
5442
  if (cmdResult) {
4634
5443
  addMessage(MESSAGE_TYPE.ASSISTANT, cmdResult);
@@ -4643,8 +5452,8 @@ var App = ({ autoApprove = false, target }) => {
4643
5452
  startTimer();
4644
5453
  setCurrentStatus(`Running: ${trimmed}`);
4645
5454
  try {
4646
- const { execSync } = await import("child_process");
4647
- const output = execSync(trimmed, {
5455
+ const { execSync: execSync2 } = await import("child_process");
5456
+ const output = execSync2(trimmed, {
4648
5457
  encoding: "utf-8",
4649
5458
  timeout: 3e4,
4650
5459
  maxBuffer: 1024 * 1024
@@ -4728,48 +5537,51 @@ var App = ({ autoApprove = false, target }) => {
4728
5537
  return styles[type] || styles[MESSAGE_TYPE.SYSTEM];
4729
5538
  };
4730
5539
  const state = agent.getState();
4731
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
4732
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx(Static, { items: messages.slice(-40), children: (msg) => {
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) => {
4733
5542
  const style = getStyle(msg.type);
4734
- return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: style.color, dimColor: style.dim, children: [
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: [
4735
5547
  style.prefix,
4736
5548
  " ",
4737
5549
  msg.content,
4738
- msg.duration && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5550
+ msg.duration && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
4739
5551
  " (",
4740
5552
  msg.duration,
4741
5553
  "s)"
4742
5554
  ] })
4743
5555
  ] }) }, msg.id);
4744
5556
  } }) }),
4745
- pendingApproval && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginBottom: 1, children: [
4746
- /* @__PURE__ */ jsxs(Text, { color: "yellow", bold: true, children: [
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: [
4747
5559
  "\u26A0\uFE0F APPROVAL NEEDED: ",
4748
5560
  pendingApproval.toolName,
4749
5561
  " (",
4750
5562
  pendingApproval.riskLevel,
4751
5563
  " risk)"
4752
5564
  ] }),
4753
- /* @__PURE__ */ jsx(Text, { 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(", ") }),
4754
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: approvalOptions.map((opt, idx) => /* @__PURE__ */ jsxs(Text, { color: idx === approvalSelectedIndex ? "cyan" : "gray", children: [
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: [
4755
5567
  idx === approvalSelectedIndex ? "\u2192 " : " ",
4756
5568
  opt.label
4757
5569
  ] }, opt.decision)) }),
4758
- /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191\u2193 to select, Enter to confirm, or type /y /n /ya" }) })
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" }) })
4759
5571
  ] }),
4760
- isProcessing ? /* @__PURE__ */ jsxs(Box, { children: [
4761
- /* @__PURE__ */ jsx(Text, { color: THEME.status.running, children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
4762
- /* @__PURE__ */ jsxs(Text, { color: THEME.text.muted, children: [
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: [
4763
5575
  " ",
4764
5576
  currentStatus,
4765
- elapsedTime > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5577
+ elapsedTime > 0 && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
4766
5578
  " (",
4767
5579
  elapsedTime,
4768
5580
  "s)"
4769
5581
  ] })
4770
5582
  ] })
4771
- ] }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
4772
- showCommandHints && input.startsWith("/") && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: [
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: [
4773
5585
  "/target <ip>",
4774
5586
  "/start",
4775
5587
  "/stop",
@@ -4780,9 +5592,9 @@ var App = ({ autoApprove = false, target }) => {
4780
5592
  "/exit",
4781
5593
  pendingApproval ? "/y /n /ya" : ""
4782
5594
  ].filter((cmd) => cmd && cmd.toLowerCase().includes(input.toLowerCase().slice(1))).slice(0, 5).join(" \u2502 ") }) }),
4783
- /* @__PURE__ */ jsxs(Box, { children: [
4784
- /* @__PURE__ */ jsx(Text, { color: mode === "agent" ? THEME.status.success : "yellow", children: mode === "agent" ? "\u2728 " : "$ " }),
4785
- /* @__PURE__ */ jsx(
5595
+ /* @__PURE__ */ jsxs2(Box2, { children: [
5596
+ /* @__PURE__ */ jsx2(Text2, { color: mode === "agent" ? THEME.status.success : "yellow", children: mode === "agent" ? "\u2728 " : "$ " }),
5597
+ /* @__PURE__ */ jsx2(
4786
5598
  TextInput,
4787
5599
  {
4788
5600
  value: input,
@@ -4796,8 +5608,8 @@ var App = ({ autoApprove = false, target }) => {
4796
5608
  )
4797
5609
  ] })
4798
5610
  ] }),
4799
- /* @__PURE__ */ jsxs(Box, { marginTop: 1, justifyContent: "space-between", children: [
4800
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5611
+ /* @__PURE__ */ jsxs2(Box2, { marginTop: 1, justifyContent: "space-between", children: [
5612
+ /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
4801
5613
  mode === "agent" ? "\u{1F916}" : "$",
4802
5614
  " ",
4803
5615
  state.target.primary || "No target",
@@ -4809,7 +5621,7 @@ var App = ({ autoApprove = false, target }) => {
4809
5621
  tokenUsage.total > 0 && `${(tokenUsage.total / 1e3).toFixed(1)}k tokens \u2502`,
4810
5622
  state.currentPhase !== AGENT_STATUS.IDLE && ` ${state.currentPhase} \u2502`
4811
5623
  ] }),
4812
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5624
+ /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
4813
5625
  "Ctrl+X mode \u2502 /help \u2502 Ctrl+C ",
4814
5626
  isProcessing ? "stop" : "exit"
4815
5627
  ] })
@@ -4820,7 +5632,7 @@ var app_default = App;
4820
5632
 
4821
5633
  // src/index.tsx
4822
5634
  import chalk from "chalk";
4823
- import { jsx as jsx2 } from "react/jsx-runtime";
5635
+ import { jsx as jsx3 } from "react/jsx-runtime";
4824
5636
  var program = new Command();
4825
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");
4826
5638
  program.command("interactive", { isDefault: true }).alias("i").description("Start interactive TUI mode").action(() => {
@@ -4834,7 +5646,7 @@ program.command("interactive", { isDefault: true }).alias("i").description("Star
4834
5646
  }
4835
5647
  console.log(chalk.hex(THEME.text.accent)("Starting Pentest interactive mode...\n"));
4836
5648
  const { waitUntilExit } = render(
4837
- /* @__PURE__ */ jsx2(
5649
+ /* @__PURE__ */ jsx3(
4838
5650
  app_default,
4839
5651
  {
4840
5652
  autoApprove: skipPermissions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pentesting",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Autonomous Penetration Testing AI Agent",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",