pentesting 0.73.10 → 0.73.12

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.
@@ -5,7 +5,7 @@ import {
5
5
  createContextExtractor,
6
6
  getLLMClient,
7
7
  getShellSupervisorLifecycleSnapshot
8
- } from "./chunk-OP3YVCKB.js";
8
+ } from "./chunk-4DUF6JX2.js";
9
9
  import {
10
10
  AGENT_ROLES,
11
11
  EVENT_TYPES,
@@ -13,7 +13,7 @@ import {
13
13
  TOOL_NAMES,
14
14
  getProcessOutput,
15
15
  listBackgroundProcesses
16
- } from "./chunk-TFYJWIQF.js";
16
+ } from "./chunk-5JXATHQ3.js";
17
17
  import {
18
18
  DETECTION_PATTERNS,
19
19
  PROCESS_EVENTS,
@@ -69,7 +69,7 @@ import {
69
69
  startBackgroundProcess,
70
70
  stopBackgroundProcess,
71
71
  writeFileContent
72
- } from "./chunk-TFYJWIQF.js";
72
+ } from "./chunk-5JXATHQ3.js";
73
73
  import {
74
74
  DETECTION_PATTERNS,
75
75
  HEALTH_CONFIG,
@@ -736,6 +736,55 @@ var AuxiliaryLLMBase = class {
736
736
  }
737
737
  };
738
738
 
739
+ // src/shared/utils/policy/document.ts
740
+ import fs from "fs";
741
+ import path from "path";
742
+ var DEFAULT_POLICY_DOCUMENT = `# Policy Memory
743
+
744
+ No persistent user policy has been recorded yet.
745
+ Store only durable constraints, sensitive handling rules, and reusable engagement guidance here.
746
+ `;
747
+ function getPolicyDocumentPath() {
748
+ return WORKSPACE.POLICY;
749
+ }
750
+ function ensurePolicyDocument() {
751
+ const filePath = getPolicyDocumentPath();
752
+ const dirPath = path.dirname(filePath);
753
+ if (!fs.existsSync(dirPath)) {
754
+ fs.mkdirSync(dirPath, { recursive: true });
755
+ }
756
+ if (!fs.existsSync(filePath)) {
757
+ fs.writeFileSync(filePath, DEFAULT_POLICY_DOCUMENT, "utf-8");
758
+ }
759
+ return filePath;
760
+ }
761
+ function readPolicyDocument() {
762
+ try {
763
+ ensurePolicyDocument();
764
+ return fs.readFileSync(getPolicyDocumentPath(), "utf-8").trim();
765
+ } catch {
766
+ return "";
767
+ }
768
+ }
769
+ function writePolicyDocument(content) {
770
+ ensurePolicyDocument();
771
+ fs.writeFileSync(
772
+ getPolicyDocumentPath(),
773
+ content.trim() || DEFAULT_POLICY_DOCUMENT,
774
+ "utf-8"
775
+ );
776
+ }
777
+ function getDefaultPolicyDocument() {
778
+ return DEFAULT_POLICY_DOCUMENT;
779
+ }
780
+ function formatPolicyMemorySection(heading = "POLICY MEMORY") {
781
+ const content = readPolicyDocument().trim();
782
+ if (!content) return "";
783
+ return `${heading}:
784
+ ${content}
785
+ `;
786
+ }
787
+
739
788
  // src/engine/auxiliary-llm/context-extractor.ts
740
789
  function formatForExtraction(messages) {
741
790
  const parts = [];
@@ -758,7 +807,10 @@ var ContextExtractor = class extends AuxiliaryLLMBase {
758
807
  super(llm, { systemPrompt: llmNodeSystemPrompt("context_extractor"), logErrors: true });
759
808
  }
760
809
  formatInput(input) {
761
- return formatForExtraction(input.messages);
810
+ const extracted = formatForExtraction(input.messages);
811
+ const policySection = formatPolicyMemorySection();
812
+ return policySection ? `${policySection}
813
+ ${extracted}` : extracted;
762
814
  }
763
815
  parseOutput(response) {
764
816
  return { extractedContext: response, success: true };
@@ -6575,12 +6627,15 @@ var Reflector = class extends AuxiliaryLLMBase {
6575
6627
  super(llm, { systemPrompt: llmNodeSystemPrompt("reflector"), logErrors: true });
6576
6628
  }
6577
6629
  formatInput(input) {
6578
- return formatReflectionInput({
6630
+ const reflectionInput = formatReflectionInput({
6579
6631
  tools: input.tools,
6580
6632
  memo: input.memo,
6581
6633
  phase: input.phase,
6582
6634
  triageMemo: input.triageMemo
6583
6635
  });
6636
+ const policySection = formatPolicyMemorySection();
6637
+ return policySection ? `${policySection}
6638
+ ${reflectionInput}` : reflectionInput;
6584
6639
  }
6585
6640
  parseOutput(response) {
6586
6641
  return { reflection: response, success: true };
@@ -6599,15 +6654,20 @@ var MemorySynth = class extends AuxiliaryLLMBase {
6599
6654
  super(llm, { systemPrompt: llmNodeSystemPrompt("memory_synth"), logErrors: true });
6600
6655
  }
6601
6656
  formatInput(input) {
6657
+ const policySection = formatPolicyMemorySection();
6602
6658
  if (input.existingSummary) {
6603
- return `Previous memory:
6659
+ const body2 = `Previous memory:
6604
6660
  ${input.existingSummary}
6605
6661
 
6606
6662
  Current turn:
6607
6663
  ${input.turnData}`;
6664
+ return policySection ? `${policySection}
6665
+ ${body2}` : body2;
6608
6666
  }
6609
- return `First turn data:
6667
+ const body = `First turn data:
6610
6668
  ${input.turnData}`;
6669
+ return policySection ? `${policySection}
6670
+ ${body}` : body;
6611
6671
  }
6612
6672
  parseOutput(response) {
6613
6673
  return { summary: response, success: true };
@@ -6645,7 +6705,10 @@ var PlaybookSynthesizer = class extends AuxiliaryLLMBase {
6645
6705
  if (input.existingChainSummary) {
6646
6706
  lines.push("", `EXISTING SUMMARY (regex-based, for reference): ${input.existingChainSummary}`);
6647
6707
  }
6648
- return lines.join("\n");
6708
+ const body = lines.join("\n");
6709
+ const policySection = formatPolicyMemorySection();
6710
+ return policySection ? `${policySection}
6711
+ ${body}` : body;
6649
6712
  }
6650
6713
  parseOutput(response) {
6651
6714
  const trimmed = response.trim();
@@ -6675,11 +6738,14 @@ var ReportGenerator = class extends AuxiliaryLLMBase {
6675
6738
  const valB = severityOrder[b.severity.toLowerCase()] ?? 0;
6676
6739
  return valB - valA;
6677
6740
  });
6678
- return `Mission Summary:
6741
+ const body = `Mission Summary:
6679
6742
  ${input.missionSummary}
6680
6743
 
6681
6744
  Findings (Sorted by Severity):
6682
6745
  ${JSON.stringify(sortedFindings, null, 2)}`;
6746
+ const policySection = formatPolicyMemorySection();
6747
+ return policySection ? `${policySection}
6748
+ ${body}` : body;
6683
6749
  }
6684
6750
  parseOutput(response) {
6685
6751
  return { reportMarkdown: response, success: true };
@@ -6715,11 +6781,14 @@ ${summary}`;
6715
6781
  PREVIOUS TRIAGE (for delta analysis):
6716
6782
  ${input.previousTriage}
6717
6783
  ` : "";
6718
- return `PHASE: ${input.phase}
6784
+ const body = `PHASE: ${input.phase}
6719
6785
  ${prevSection}
6720
6786
  TOOL RESULTS THIS TURN:
6721
6787
 
6722
6788
  ${toolLines || "No tools executed this turn."}`;
6789
+ const policySection = formatPolicyMemorySection();
6790
+ return policySection ? `${policySection}
6791
+ ${body}` : body;
6723
6792
  }
6724
6793
  parseOutput(response) {
6725
6794
  return { triage: response, success: true };
@@ -7532,45 +7601,6 @@ var SharedState = class {
7532
7601
  }
7533
7602
  };
7534
7603
 
7535
- // src/shared/utils/policy/document.ts
7536
- import fs from "fs";
7537
- import path from "path";
7538
- var DEFAULT_POLICY_DOCUMENT = `# Policy Memory
7539
-
7540
- No persistent user policy has been recorded yet.
7541
- Store only durable constraints, sensitive handling rules, and reusable engagement guidance here.
7542
- `;
7543
- function getPolicyDocumentPath() {
7544
- return WORKSPACE.POLICY;
7545
- }
7546
- function ensurePolicyDocument() {
7547
- const filePath = getPolicyDocumentPath();
7548
- const dirPath = path.dirname(filePath);
7549
- if (!fs.existsSync(dirPath)) {
7550
- fs.mkdirSync(dirPath, { recursive: true });
7551
- }
7552
- if (!fs.existsSync(filePath)) {
7553
- fs.writeFileSync(filePath, DEFAULT_POLICY_DOCUMENT, "utf-8");
7554
- }
7555
- return filePath;
7556
- }
7557
- function readPolicyDocument() {
7558
- try {
7559
- ensurePolicyDocument();
7560
- return fs.readFileSync(getPolicyDocumentPath(), "utf-8").trim();
7561
- } catch {
7562
- return "";
7563
- }
7564
- }
7565
- function writePolicyDocument(content) {
7566
- ensurePolicyDocument();
7567
- fs.writeFileSync(
7568
- getPolicyDocumentPath(),
7569
- content.trim() || DEFAULT_POLICY_DOCUMENT,
7570
- "utf-8"
7571
- );
7572
- }
7573
-
7574
7604
  // src/engine/auxiliary-llm/strategist-prompt.ts
7575
7605
  function buildStrategistPrompt(input) {
7576
7606
  const state = input.state;
@@ -11054,7 +11084,7 @@ After completion: record key loot/findings from the sub-agent output to canonica
11054
11084
  rootTaskId: activeExecution.rootTaskId
11055
11085
  }
11056
11086
  });
11057
- const { AgentTool } = await import("./agent-tool-K3ETJX2V.js");
11087
+ const { AgentTool } = await import("./agent-tool-RTF2W3GB.js");
11058
11088
  const executor = new AgentTool(state, events, scopeGuard, approvalGate);
11059
11089
  try {
11060
11090
  const result = await executor.execute(input);
@@ -11344,6 +11374,10 @@ export {
11344
11374
  getLLMClient,
11345
11375
  getGlobalRequestCount,
11346
11376
  getGlobalTokenUsage,
11377
+ ensurePolicyDocument,
11378
+ readPolicyDocument,
11379
+ writePolicyDocument,
11380
+ getDefaultPolicyDocument,
11347
11381
  createContextExtractor,
11348
11382
  parseTurnNumbers,
11349
11383
  rotateTurnRecords,
@@ -11356,9 +11390,6 @@ export {
11356
11390
  createMemorySynth,
11357
11391
  createPlaybookSynthesizer,
11358
11392
  createTriager,
11359
- ensurePolicyDocument,
11360
- readPolicyDocument,
11361
- writePolicyDocument,
11362
11393
  createStrategist,
11363
11394
  createInputProcessor,
11364
11395
  getServiceContext,
@@ -348,7 +348,7 @@ var INPUT_PROMPT_PATTERNS = [
348
348
  ];
349
349
 
350
350
  // src/shared/constants/agent.ts
351
- var APP_VERSION = "0.73.10";
351
+ var APP_VERSION = "0.73.12";
352
352
  var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
353
353
  var LLM_ROLES = {
354
354
  SYSTEM: "system",
@@ -842,6 +842,7 @@ var UI_COMMANDS = {
842
842
  START_SHORT: "s",
843
843
  FINDINGS: "findings",
844
844
  FINDINGS_SHORT: "f",
845
+ POLICY: "policy",
845
846
  REPORT: "report",
846
847
  REPORT_SHORT: "r",
847
848
  ASSETS: "assets",
package/dist/main.js CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  formatChallengeAnalysis,
25
25
  formatTurnRecord,
26
26
  getApiKey,
27
+ getDefaultPolicyDocument,
27
28
  getGlobalRequestCount,
28
29
  getGlobalTokenUsage,
29
30
  getModel,
@@ -38,7 +39,7 @@ import {
38
39
  rotateTurnRecords,
39
40
  setCurrentTurn,
40
41
  writePolicyDocument
41
- } from "./chunk-OP3YVCKB.js";
42
+ } from "./chunk-4DUF6JX2.js";
42
43
  import {
43
44
  AGENT_ROLES,
44
45
  APP_DESCRIPTION,
@@ -87,7 +88,7 @@ import {
87
88
  setActiveSessionRuntime,
88
89
  setTorEnabled,
89
90
  snapshotToPrompt
90
- } from "./chunk-TFYJWIQF.js";
91
+ } from "./chunk-5JXATHQ3.js";
91
92
  import {
92
93
  EXIT_CODES,
93
94
  getOptionalRuntimeSection,
@@ -650,14 +651,14 @@ async function recordTurn(context) {
650
651
  return turnCounter + 1;
651
652
  }
652
653
  async function writeTurnInsight(turnCounter, memorySynth, ctx) {
653
- const { phase, toolJournal, memo: memo13, reflections } = ctx;
654
- const fallbackNextSteps = Array.isArray(memo13.nextSteps) ? memo13.nextSteps : [];
654
+ const { phase, toolJournal, memo: memo14, reflections } = ctx;
655
+ const fallbackNextSteps = Array.isArray(memo14.nextSteps) ? memo14.nextSteps : [];
655
656
  const turnData = formatTurnRecord({
656
657
  turn: turnCounter,
657
658
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
658
659
  phase,
659
660
  tools: toolJournal,
660
- memo: memo13,
661
+ memo: memo14,
661
662
  reflection: reflections.length > 0 ? reflections.join(" | ") : fallbackNextSteps.join("; ")
662
663
  });
663
664
  const existingSummary = readJournalSummary();
@@ -2496,6 +2497,17 @@ var MainAgentInteractionCoordinator = class {
2496
2497
  emitMainAgentQueueUpdated(this.options.events, this.userInputQueue);
2497
2498
  return normalized;
2498
2499
  }
2500
+ async processStandalonePolicyInput(rawInput) {
2501
+ const result = await this.options.inputProcessor.execute({
2502
+ rawInput,
2503
+ existingPolicy: readPolicyDocument(),
2504
+ hasActiveEngagement: this.options.state.hasActiveEngagement(),
2505
+ currentObjective: this.options.state.currentObjective || ""
2506
+ });
2507
+ const normalized = normalizeInputProcessorResult(result, rawInput);
2508
+ this.updatePolicyFromInputProcessor(normalized);
2509
+ return normalized;
2510
+ }
2499
2511
  getUserInputQueue() {
2500
2512
  return this.userInputQueue;
2501
2513
  }
@@ -3273,7 +3285,7 @@ var makeRotateTurns = (_llm, _opts) => async (_ctx) => {
3273
3285
  };
3274
3286
  var makeSaveSession = (_llm, _opts) => async (ctx) => {
3275
3287
  try {
3276
- const { saveState: saveState2 } = await import("./persistence-TSBV5F6R.js");
3288
+ const { saveState: saveState2 } = await import("./persistence-DC6QI7XQ.js");
3277
3289
  saveState2(ctx.state);
3278
3290
  } catch {
3279
3291
  }
@@ -4143,6 +4155,9 @@ var MainAgent = class extends CoreAgent {
4143
4155
  }
4144
4156
  return result;
4145
4157
  }
4158
+ async applyStandalonePolicyInput(rawInput) {
4159
+ return this.interactionCoordinator.processStandalonePolicyInput(rawInput);
4160
+ }
4146
4161
  async buildDynamicPrompt(memory) {
4147
4162
  return this.promptState.buildDynamicPrompt(memory);
4148
4163
  }
@@ -4258,11 +4273,11 @@ async function writeJsonReport(outputPath, result) {
4258
4273
  }
4259
4274
 
4260
4275
  // src/platform/tui/cli/interactive-runtime.tsx
4261
- import React16 from "react";
4276
+ import React17 from "react";
4262
4277
  import { render } from "ink";
4263
4278
 
4264
4279
  // src/platform/tui/app.tsx
4265
- import { Box as Box18 } from "ink";
4280
+ import { Box as Box19 } from "ink";
4266
4281
 
4267
4282
  // src/platform/tui/hooks/useAgent.ts
4268
4283
  import { useState as useState6, useEffect as useEffect2, useCallback as useCallback7, useRef as useRef7 } from "react";
@@ -4825,6 +4840,12 @@ var UI_STATUS_MESSAGES = {
4825
4840
  START_ALREADY_RUNNING: "Autonomous mode is already active. Current run is still in progress.",
4826
4841
  /** Starting pentest message */
4827
4842
  STARTING_PENTEST: "Starting penetration test...",
4843
+ /** Start cancelled from policy composer */
4844
+ START_CANCELLED: "Start cancelled before execution.",
4845
+ /** Policy bootstrap was saved before autonomous execution */
4846
+ POLICY_BOOTSTRAP_SAVED: "Competition policy saved for this run.",
4847
+ /** Policy bootstrap did not produce a durable update */
4848
+ POLICY_BOOTSTRAP_NO_CHANGE: "Competition policy was reviewed, but no durable policy change was recorded.",
4828
4849
  /** Pentest task prefix */
4829
4850
  PENTEST_TASK_PREFIX: "Perform comprehensive penetration testing",
4830
4851
  /** Against prefix */
@@ -5736,6 +5757,7 @@ var COMMAND_DEFINITIONS = [
5736
5757
  { name: "target", alias: "t", args: "<ip>", description: "Set target IP or domain" },
5737
5758
  { name: "start", alias: "s", args: "[goal]", description: "Start autonomous pentest" },
5738
5759
  { name: "findings", alias: "f", description: "Show discovered vulnerabilities" },
5760
+ { name: "policy", description: "Open the current policy memory" },
5739
5761
  { name: "report", alias: "r", description: "Open an operation report modal" },
5740
5762
  { name: "graph", alias: "g", description: "Visualize the attack graph" },
5741
5763
  { name: "paths", alias: "p", description: "Show ranked attack paths" },
@@ -5773,8 +5795,10 @@ ${COMMAND_DEFINITIONS.map((cmd) => {
5773
5795
 
5774
5796
  \u2500\u2500 Tips \u2500\u2500
5775
5797
  \u2022 Type / and press Tab to autocomplete commands
5798
+ \u2022 /policy shows the current policy memory
5776
5799
  \u2022 /clear resets the entire session (messages, state, .pentesting data)
5777
5800
  \u2022 /start automatically enables auto-approve for hands-free operation
5801
+ \u2022 You can say "put this into policy memory" in normal chat and the agent will merge it automatically
5778
5802
  `;
5779
5803
 
5780
5804
  // src/platform/tui/hooks/commands/session-commands.ts
@@ -5840,13 +5864,9 @@ var createTargetCommands = (ctx) => {
5840
5864
  ctx.addMessage("system", UI_STATUS_MESSAGES.START_ALREADY_RUNNING);
5841
5865
  return;
5842
5866
  }
5843
- ctx.setAutoApproveMode(true);
5844
- ctx.agent.setToolAutoApprove(true);
5845
- ctx.addMessage("system", UI_STATUS_MESSAGES.AUTONOMOUS_MODE_ENABLED);
5846
- ctx.addMessage("system", UI_STATUS_MESSAGES.STARTING_PENTEST);
5847
5867
  const targets = Array.from(ctx.agent.getState().getTargets().keys());
5848
5868
  const targetInfo = targets.length > 0 ? `${UI_STATUS_MESSAGES.AGAINST_PREFIX}${targets.join(", ")}` : "";
5849
- await ctx.executeTask(args.join(" ") || `${UI_STATUS_MESSAGES.PENTEST_TASK_PREFIX}${targetInfo}`);
5869
+ ctx.openPolicyComposer(args.join(" ") || `${UI_STATUS_MESSAGES.PENTEST_TASK_PREFIX}${targetInfo}`);
5850
5870
  };
5851
5871
  return {
5852
5872
  [UI_COMMANDS.TARGET]: handleTarget,
@@ -6091,6 +6111,21 @@ var formatGraphWithSummary = (state, findings, flags) => {
6091
6111
  return lines.join("\n");
6092
6112
  };
6093
6113
 
6114
+ // src/platform/tui/hooks/commands/formatters/policy.ts
6115
+ function formatPolicyMemory(content) {
6116
+ const normalized = content.trim() || getDefaultPolicyDocument().trim();
6117
+ return [
6118
+ "POLICY MEMORY",
6119
+ "",
6120
+ "\u2500\u2500 Usage \u2500\u2500",
6121
+ "/policy shows the current policy memory.",
6122
+ "You can also tell the agent to remember a rule or put something into policy memory, and it will merge it automatically.",
6123
+ "",
6124
+ "\u2500\u2500 Current Policy \u2500\u2500",
6125
+ normalized
6126
+ ].join("\n");
6127
+ }
6128
+
6094
6129
  // src/platform/tui/hooks/commands/formatters/report.ts
6095
6130
  var SEVERITY_WEIGHT = {
6096
6131
  critical: 4,
@@ -6253,6 +6288,9 @@ var createDisplayCommands = (ctx) => {
6253
6288
  const flags = state.getFlags();
6254
6289
  ctx.showModal("findings", formatFindingsWithFlags(findings, flags));
6255
6290
  },
6291
+ [UI_COMMANDS.POLICY]: () => {
6292
+ ctx.showModal("policy", formatPolicyMemory(readPolicyDocument()));
6293
+ },
6256
6294
  [UI_COMMANDS.REPORT]: () => {
6257
6295
  const state = ctx.agent.getState();
6258
6296
  ctx.showModal("report", formatOperationReport(state));
@@ -6423,6 +6461,7 @@ var useCommands = (props) => {
6423
6461
  agent: props.agent,
6424
6462
  addMessage: props.addMessage,
6425
6463
  showModal: props.showModal,
6464
+ openPolicyComposer: props.openPolicyComposer,
6426
6465
  setMessages: props.setMessages,
6427
6466
  executeTask: props.executeTask,
6428
6467
  refreshStats: props.refreshStats,
@@ -6436,6 +6475,7 @@ var useCommands = (props) => {
6436
6475
  props.agent,
6437
6476
  props.addMessage,
6438
6477
  props.showModal,
6478
+ props.openPolicyComposer,
6439
6479
  props.setMessages,
6440
6480
  props.executeTask,
6441
6481
  props.refreshStats,
@@ -6704,6 +6744,26 @@ function useAppSubmission({
6704
6744
  };
6705
6745
  }
6706
6746
 
6747
+ // src/platform/tui/policy-composer.ts
6748
+ var POLICY_COMPOSER_PLACEHOLDER = "Paste competition rules or durable constraints to remember. Example: personal event, no write-up sharing, avoid platform abuse, flag format ENKI{...}, write-up required.";
6749
+ var POLICY_COMPOSER_AI_PROMPT = "Before I start, add any competition rules or durable constraints you want me to remember for this run.";
6750
+ var POLICY_COMPOSER_GUIDE = [
6751
+ "Before autonomous execution, add any competition rules or durable engagement constraints here.",
6752
+ "Use /policy to view the current policy memory at any time.",
6753
+ "You can also tell the agent to remember a rule or put something into policy memory in normal chat, and it will merge it automatically.",
6754
+ "Tip: paste a compact summary of the most important rules if the source text is long."
6755
+ ].join("\n");
6756
+ function buildPolicyBootstrapInput(rawPolicy) {
6757
+ const trimmed = rawPolicy.trim();
6758
+ if (!trimmed) return "";
6759
+ return [
6760
+ "Remember and follow this as durable policy memory for the current competition or engagement.",
6761
+ "Merge it into policy memory and apply it in future turns.",
6762
+ "",
6763
+ trimmed
6764
+ ].join("\n");
6765
+ }
6766
+
6707
6767
  // src/platform/tui/hooks/useAppLogic.ts
6708
6768
  var useAppLogic = ({ autoApprove = false, target }) => {
6709
6769
  const { exit } = useApp();
@@ -6712,6 +6772,11 @@ var useAppLogic = ({ autoApprove = false, target }) => {
6712
6772
  const [secretInput, setSecretInput] = useState7("");
6713
6773
  const [autoApproveMode, setAutoApproveMode] = useState7(autoApprove);
6714
6774
  const [modal, setModal] = useState7({ type: null, content: "", scrollOffset: 0 });
6775
+ const [policyComposer, setPolicyComposer] = useState7({
6776
+ isOpen: false,
6777
+ value: "",
6778
+ pendingTask: ""
6779
+ });
6715
6780
  const [footerConfig, setFooterConfig] = useState7(DEFAULT_FOOTER_DISPLAY_CONFIG);
6716
6781
  const isTyping = input.length > 0 || secretInput.length > 0;
6717
6782
  const {
@@ -6744,8 +6809,8 @@ var useAppLogic = ({ autoApprove = false, target }) => {
6744
6809
  autoApproveModeRef.current = autoApproveMode;
6745
6810
  const inputRequestRef = useRef9(inputRequest);
6746
6811
  inputRequestRef.current = inputRequest;
6747
- const isModalOpenRef = useRef9(!!modal.type);
6748
- isModalOpenRef.current = !!modal.type;
6812
+ const isModalOpenRef = useRef9(!!modal.type || policyComposer.isOpen);
6813
+ isModalOpenRef.current = !!modal.type || policyComposer.isOpen;
6749
6814
  const inputRef = useRef9(input);
6750
6815
  inputRef.current = input;
6751
6816
  const clearInput = useCallback13(() => {
@@ -6757,6 +6822,39 @@ var useAppLogic = ({ autoApprove = false, target }) => {
6757
6822
  const closeModal = useCallback13(() => {
6758
6823
  setModal({ type: null, content: "", scrollOffset: 0 });
6759
6824
  }, []);
6825
+ const openPolicyComposer = useCallback13((task) => {
6826
+ addMessage("ai", POLICY_COMPOSER_AI_PROMPT);
6827
+ setPolicyComposer({
6828
+ isOpen: true,
6829
+ value: "",
6830
+ pendingTask: task
6831
+ });
6832
+ }, [addMessage]);
6833
+ const closePolicyComposer = useCallback13(() => {
6834
+ if (!policyComposer.isOpen) return;
6835
+ setPolicyComposer((prev) => {
6836
+ if (!prev.isOpen) return prev;
6837
+ return { isOpen: false, value: "", pendingTask: "" };
6838
+ });
6839
+ addMessage("system", UI_STATUS_MESSAGES.START_CANCELLED);
6840
+ }, [addMessage, policyComposer.isOpen]);
6841
+ const submitPolicyComposer = useCallback13(async () => {
6842
+ const task = policyComposer.pendingTask.trim();
6843
+ const policyInput = buildPolicyBootstrapInput(policyComposer.value);
6844
+ setPolicyComposer({ isOpen: false, value: "", pendingTask: "" });
6845
+ if (policyInput) {
6846
+ const policyResult = await agent.applyStandalonePolicyInput(policyInput);
6847
+ addMessage(
6848
+ "system",
6849
+ policyResult.shouldWritePolicy ? policyResult.policyUpdateSummary || UI_STATUS_MESSAGES.POLICY_BOOTSTRAP_SAVED : UI_STATUS_MESSAGES.POLICY_BOOTSTRAP_NO_CHANGE
6850
+ );
6851
+ }
6852
+ setAutoApproveMode(true);
6853
+ agent.setToolAutoApprove(true);
6854
+ addMessage("system", UI_STATUS_MESSAGES.AUTONOMOUS_MODE_ENABLED);
6855
+ addMessage("system", UI_STATUS_MESSAGES.STARTING_PENTEST);
6856
+ await executeTask(task);
6857
+ }, [addMessage, agent, executeTask, policyComposer.pendingTask, policyComposer.value, setAutoApproveMode]);
6760
6858
  const handleModalScroll = useCallback13((delta) => {
6761
6859
  setModal((prev) => {
6762
6860
  const lines = prev.content.split("\n");
@@ -6784,6 +6882,7 @@ var useAppLogic = ({ autoApprove = false, target }) => {
6784
6882
  agent,
6785
6883
  addMessage,
6786
6884
  showModal,
6885
+ openPolicyComposer,
6787
6886
  setMessages,
6788
6887
  executeTask,
6789
6888
  refreshStats,
@@ -6826,6 +6925,12 @@ var useAppLogic = ({ autoApprove = false, target }) => {
6826
6925
  setSecretInput,
6827
6926
  autoApproveMode,
6828
6927
  modal,
6928
+ policyComposer,
6929
+ setPolicyComposer,
6930
+ submitPolicyComposer,
6931
+ closePolicyComposer,
6932
+ policyComposerGuide: POLICY_COMPOSER_GUIDE,
6933
+ policyComposerPlaceholder: POLICY_COMPOSER_PLACEHOLDER,
6829
6934
  handleModalScroll,
6830
6935
  closeModal,
6831
6936
  handleSecretSubmit,
@@ -8254,7 +8359,8 @@ var MODAL_TITLES = {
8254
8359
  findings: "\u25C8 FINDINGS \u25C8",
8255
8360
  report: "\u25C8 OPERATION REPORT \u25C8",
8256
8361
  graph: "\u25C8 ATTACK GRAPH \u25C8",
8257
- help: "\u25C8 COMMANDS \u25C8"
8362
+ help: "\u25C8 COMMANDS \u25C8",
8363
+ policy: "\u25C8 POLICY MEMORY \u25C8"
8258
8364
  };
8259
8365
  var Modal = memo12(({
8260
8366
  type,
@@ -8339,9 +8445,76 @@ var Modal = memo12(({
8339
8445
  );
8340
8446
  });
8341
8447
 
8342
- // src/platform/tui/components/app/bottom-region.tsx
8343
- import { Box as Box17, Text as Text18 } from "ink";
8448
+ // src/platform/tui/components/PolicyComposerModal.tsx
8449
+ import { memo as memo13, useCallback as useCallback16, useRef as useRef14 } from "react";
8450
+ import { Box as Box17, Text as Text18, useInput as useInput4 } from "ink";
8344
8451
  import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
8452
+ var PolicyComposerModal = memo13(({
8453
+ value,
8454
+ onChange,
8455
+ onSubmit,
8456
+ onClose,
8457
+ guide,
8458
+ placeholder
8459
+ }) => {
8460
+ const onCloseRef = useRef14(onClose);
8461
+ onCloseRef.current = onClose;
8462
+ const onSubmitRef = useRef14(onSubmit);
8463
+ onSubmitRef.current = onSubmit;
8464
+ const { columns, rows } = useTerminalSize();
8465
+ const terminalHeight = rows;
8466
+ const terminalWidth = columns - 4;
8467
+ useInput4(useCallback16((_input, key) => {
8468
+ if (key.escape) {
8469
+ onCloseRef.current();
8470
+ }
8471
+ }, []), { isActive: true });
8472
+ return /* @__PURE__ */ jsxs15(Box17, { flexDirection: "column", width: terminalWidth, height: terminalHeight, children: [
8473
+ /* @__PURE__ */ jsx21(Box17, { justifyContent: "center", children: /* @__PURE__ */ jsx21(Text18, { color: THEME.primary, bold: true, children: (() => {
8474
+ const title = "\u25C8 COMPETITION POLICY \u25C8";
8475
+ const sideWidth = Math.max(3, Math.floor((terminalWidth - title.length - 2) / 2));
8476
+ return `${"\u2500".repeat(sideWidth)} ${title} ${"\u2500".repeat(sideWidth)}`;
8477
+ })() }) }),
8478
+ /* @__PURE__ */ jsxs15(
8479
+ Box17,
8480
+ {
8481
+ flexDirection: "column",
8482
+ borderStyle: "round",
8483
+ borderColor: THEME.primary,
8484
+ paddingX: 1,
8485
+ paddingY: 1,
8486
+ flexGrow: 1,
8487
+ children: [
8488
+ /* @__PURE__ */ jsx21(Text18, { color: THEME.white, bold: true, children: "Optional bootstrap policy before /start" }),
8489
+ /* @__PURE__ */ jsx21(Text18, { color: THEME.dimGray, children: " " }),
8490
+ guide.split("\n").map((line, index) => /* @__PURE__ */ jsx21(Text18, { color: THEME.gray, wrap: "wrap", children: line }, index)),
8491
+ /* @__PURE__ */ jsx21(Text18, { color: THEME.dimGray, children: " " }),
8492
+ /* @__PURE__ */ jsx21(Box17, { borderStyle: "round", borderColor: THEME.primary, paddingX: 1, paddingY: 0, children: /* @__PURE__ */ jsx21(
8493
+ NormalInputArea,
8494
+ {
8495
+ inputKey: 0,
8496
+ value,
8497
+ onChange,
8498
+ onSubmit: () => onSubmitRef.current(),
8499
+ placeholder
8500
+ }
8501
+ ) })
8502
+ ]
8503
+ }
8504
+ ),
8505
+ /* @__PURE__ */ jsxs15(Box17, { justifyContent: "space-between", paddingX: 1, children: [
8506
+ /* @__PURE__ */ jsx21(Text18, { color: THEME.dimGray, children: "Enter: continue | Esc: cancel start" }),
8507
+ /* @__PURE__ */ jsxs15(Text18, { color: THEME.primary, children: [
8508
+ value.trim().length,
8509
+ " chars"
8510
+ ] })
8511
+ ] })
8512
+ ] });
8513
+ });
8514
+
8515
+ // src/platform/tui/components/app/bottom-region.tsx
8516
+ import { Box as Box18, Text as Text19 } from "ink";
8517
+ import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
8345
8518
  var BottomRegion = ({
8346
8519
  input,
8347
8520
  setInput,
@@ -8366,8 +8539,8 @@ var BottomRegion = ({
8366
8539
  }) => {
8367
8540
  const { columns } = useTerminalSize();
8368
8541
  const inputSeparatorColor = resolveInputSeparatorColor({ isProcessing, inputRequest });
8369
- return /* @__PURE__ */ jsxs15(Box17, { flexDirection: "column", width: "100%", children: [
8370
- /* @__PURE__ */ jsx21(
8542
+ return /* @__PURE__ */ jsxs16(Box18, { flexDirection: "column", width: "100%", children: [
8543
+ /* @__PURE__ */ jsx22(
8371
8544
  StatusDisplay,
8372
8545
  {
8373
8546
  retryState,
@@ -8378,8 +8551,8 @@ var BottomRegion = ({
8378
8551
  inputRequest
8379
8552
  }
8380
8553
  ),
8381
- /* @__PURE__ */ jsx21(Text18, { color: inputSeparatorColor, children: "\u2500".repeat(Math.max(1, columns - 2)) }),
8382
- /* @__PURE__ */ jsx21(Box17, { width: "100%", children: /* @__PURE__ */ jsx21(
8554
+ /* @__PURE__ */ jsx22(Text19, { color: inputSeparatorColor, children: "\u2500".repeat(Math.max(1, columns - 2)) }),
8555
+ /* @__PURE__ */ jsx22(Box18, { width: "100%", children: /* @__PURE__ */ jsx22(
8383
8556
  ChatInput,
8384
8557
  {
8385
8558
  value: input,
@@ -8396,8 +8569,8 @@ var BottomRegion = ({
8396
8569
  onSecretSubmit: handleSecretSubmit
8397
8570
  }
8398
8571
  ) }),
8399
- /* @__PURE__ */ jsx21(Text18, { color: inputSeparatorColor, children: "\u2500".repeat(Math.max(1, columns - 2)) }),
8400
- /* @__PURE__ */ jsx21(Box17, { width: "100%", children: /* @__PURE__ */ jsx21(
8572
+ /* @__PURE__ */ jsx22(Text19, { color: inputSeparatorColor, children: "\u2500".repeat(Math.max(1, columns - 2)) }),
8573
+ /* @__PURE__ */ jsx22(Box18, { width: "100%", children: /* @__PURE__ */ jsx22(
8401
8574
  footer_default,
8402
8575
  {
8403
8576
  phase: stats.phase,
@@ -8456,7 +8629,7 @@ function useModalMouseWheel({
8456
8629
  }
8457
8630
 
8458
8631
  // src/platform/tui/app.tsx
8459
- import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
8632
+ import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
8460
8633
  var MODEL_NAME = getModel() || DEFAULT_MODEL;
8461
8634
  var App = ({ autoApprove = false, target }) => {
8462
8635
  const {
@@ -8468,6 +8641,12 @@ var App = ({ autoApprove = false, target }) => {
8468
8641
  setSecretInput,
8469
8642
  autoApproveMode,
8470
8643
  modal,
8644
+ policyComposer,
8645
+ submitPolicyComposer,
8646
+ closePolicyComposer,
8647
+ policyComposerGuide,
8648
+ policyComposerPlaceholder,
8649
+ setPolicyComposer,
8471
8650
  handleModalScroll,
8472
8651
  closeModal,
8473
8652
  handleSubmit,
@@ -8492,8 +8671,23 @@ var App = ({ autoApprove = false, target }) => {
8492
8671
  isActive: !!modal.type,
8493
8672
  onScroll: handleModalScroll
8494
8673
  });
8674
+ if (policyComposer.isOpen) {
8675
+ return /* @__PURE__ */ jsx23(Box19, { flexDirection: "column", paddingX: 1, width: terminalWidth, height: terminalHeight - 1, children: /* @__PURE__ */ jsx23(
8676
+ PolicyComposerModal,
8677
+ {
8678
+ value: policyComposer.value,
8679
+ onChange: (value) => {
8680
+ setPolicyComposer((prev) => ({ ...prev, value }));
8681
+ },
8682
+ onSubmit: submitPolicyComposer,
8683
+ onClose: closePolicyComposer,
8684
+ guide: policyComposerGuide,
8685
+ placeholder: policyComposerPlaceholder
8686
+ }
8687
+ ) });
8688
+ }
8495
8689
  if (modal.type) {
8496
- return /* @__PURE__ */ jsx22(Box18, { flexDirection: "column", paddingX: 1, width: terminalWidth, height: terminalHeight - 1, children: /* @__PURE__ */ jsx22(
8690
+ return /* @__PURE__ */ jsx23(Box19, { flexDirection: "column", paddingX: 1, width: terminalWidth, height: terminalHeight - 1, children: /* @__PURE__ */ jsx23(
8497
8691
  Modal,
8498
8692
  {
8499
8693
  type: modal.type,
@@ -8504,8 +8698,8 @@ var App = ({ autoApprove = false, target }) => {
8504
8698
  }
8505
8699
  ) });
8506
8700
  }
8507
- return /* @__PURE__ */ jsxs16(Box18, { flexDirection: "column", paddingX: 1, paddingBottom: 1, width: terminalWidth, children: [
8508
- /* @__PURE__ */ jsx22(Box18, { flexDirection: "column", width: "100%", children: /* @__PURE__ */ jsx22(
8701
+ return /* @__PURE__ */ jsxs17(Box19, { flexDirection: "column", paddingX: 1, paddingBottom: 1, width: terminalWidth, children: [
8702
+ /* @__PURE__ */ jsx23(Box19, { flexDirection: "column", width: "100%", children: /* @__PURE__ */ jsx23(
8509
8703
  MessageList,
8510
8704
  {
8511
8705
  messages,
@@ -8514,7 +8708,7 @@ var App = ({ autoApprove = false, target }) => {
8514
8708
  version: APP_VERSION
8515
8709
  }
8516
8710
  ) }),
8517
- /* @__PURE__ */ jsx22(Box18, { flexDirection: "column", marginTop: 1, width: "100%", children: /* @__PURE__ */ jsx22(
8711
+ /* @__PURE__ */ jsx23(Box19, { flexDirection: "column", marginTop: 1, width: "100%", children: /* @__PURE__ */ jsx23(
8518
8712
  BottomRegion,
8519
8713
  {
8520
8714
  input,
@@ -8545,7 +8739,7 @@ var app_default = App;
8545
8739
 
8546
8740
  // src/platform/tui/components/SplashScreen.tsx
8547
8741
  import { useEffect as useEffect11, useState as useState14 } from "react";
8548
- import { Box as Box19, Text as Text19 } from "ink";
8742
+ import { Box as Box20, Text as Text20 } from "ink";
8549
8743
 
8550
8744
  // src/platform/tui/components/CoinFrames.ts
8551
8745
  var COIN_FRAMES = [
@@ -9236,7 +9430,7 @@ var COIN_FRAMES = [
9236
9430
  ];
9237
9431
 
9238
9432
  // src/platform/tui/components/SplashScreen.tsx
9239
- import { jsx as jsx23 } from "react/jsx-runtime";
9433
+ import { jsx as jsx24 } from "react/jsx-runtime";
9240
9434
  var SplashScreen = ({
9241
9435
  onComplete,
9242
9436
  durationMs = 3e3
@@ -9258,27 +9452,27 @@ var SplashScreen = ({
9258
9452
  return () => clearInterval(interval);
9259
9453
  }, [durationMs, onComplete]);
9260
9454
  const currentFrame = COIN_FRAMES[frameIdx % COIN_FRAMES.length];
9261
- return /* @__PURE__ */ jsx23(
9262
- Box19,
9455
+ return /* @__PURE__ */ jsx24(
9456
+ Box20,
9263
9457
  {
9264
9458
  width: columns,
9265
9459
  minHeight: rows,
9266
9460
  flexDirection: "column",
9267
9461
  alignItems: "center",
9268
9462
  justifyContent: "center",
9269
- children: /* @__PURE__ */ jsx23(Box19, { flexDirection: "column", alignItems: "center", flexShrink: 0, children: /* @__PURE__ */ jsx23(Box19, { flexDirection: "column", alignItems: "center", children: currentFrame.map((line, i) => /* @__PURE__ */ jsx23(Box19, { flexShrink: 0, height: 1, children: /* @__PURE__ */ jsx23(Text19, { color: THEME.white, bold: true, wrap: "truncate-end", children: line }, `coin-text-${i}`) }, `coin-row-${i}`)) }) })
9463
+ children: /* @__PURE__ */ jsx24(Box20, { flexDirection: "column", alignItems: "center", flexShrink: 0, children: /* @__PURE__ */ jsx24(Box20, { flexDirection: "column", alignItems: "center", children: currentFrame.map((line, i) => /* @__PURE__ */ jsx24(Box20, { flexShrink: 0, height: 1, children: /* @__PURE__ */ jsx24(Text20, { color: THEME.white, bold: true, wrap: "truncate-end", children: line }, `coin-text-${i}`) }, `coin-row-${i}`)) }) })
9270
9464
  }
9271
9465
  );
9272
9466
  };
9273
9467
 
9274
9468
  // src/platform/tui/cli/interactive-runtime.tsx
9275
- import { jsx as jsx24 } from "react/jsx-runtime";
9469
+ import { jsx as jsx25 } from "react/jsx-runtime";
9276
9470
  var InteractiveRoot = ({ autoApprove, target }) => {
9277
- const [showSplash, setShowSplash] = React16.useState(true);
9471
+ const [showSplash, setShowSplash] = React17.useState(true);
9278
9472
  if (showSplash) {
9279
- return /* @__PURE__ */ jsx24(SplashScreen, { durationMs: 3e3, onComplete: () => setShowSplash(false) });
9473
+ return /* @__PURE__ */ jsx25(SplashScreen, { durationMs: 3e3, onComplete: () => setShowSplash(false) });
9280
9474
  }
9281
- return /* @__PURE__ */ jsx24(
9475
+ return /* @__PURE__ */ jsx25(
9282
9476
  app_default,
9283
9477
  {
9284
9478
  autoApprove,
@@ -9288,7 +9482,7 @@ var InteractiveRoot = ({ autoApprove, target }) => {
9288
9482
  };
9289
9483
  async function renderInteractiveApp(props) {
9290
9484
  const { waitUntilExit } = render(
9291
- /* @__PURE__ */ jsx24(AnimationProvider, { children: /* @__PURE__ */ jsx24(InteractiveRoot, { ...props }) })
9485
+ /* @__PURE__ */ jsx25(AnimationProvider, { children: /* @__PURE__ */ jsx25(InteractiveRoot, { ...props }) })
9292
9486
  );
9293
9487
  await waitUntilExit();
9294
9488
  }
@@ -3,7 +3,7 @@ import {
3
3
  clearWorkspace,
4
4
  loadState,
5
5
  saveState
6
- } from "./chunk-TFYJWIQF.js";
6
+ } from "./chunk-5JXATHQ3.js";
7
7
  import "./chunk-S5ZMXFHR.js";
8
8
  export {
9
9
  StateSerializer,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pentesting",
3
- "version": "0.73.10",
3
+ "version": "0.73.12",
4
4
  "description": "Autonomous Penetration Testing AI Agent",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",