pentesting 0.73.10 → 0.73.11

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-WEEPTBTF.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-U2NIVQ2O.js";
17
17
  import {
18
18
  DETECTION_PATTERNS,
19
19
  PROCESS_EVENTS,
@@ -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.11";
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",
@@ -69,7 +69,7 @@ import {
69
69
  startBackgroundProcess,
70
70
  stopBackgroundProcess,
71
71
  writeFileContent
72
- } from "./chunk-TFYJWIQF.js";
72
+ } from "./chunk-U2NIVQ2O.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-WLGPVDX6.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,
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-WEEPTBTF.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-U2NIVQ2O.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();
@@ -3273,7 +3274,7 @@ var makeRotateTurns = (_llm, _opts) => async (_ctx) => {
3273
3274
  };
3274
3275
  var makeSaveSession = (_llm, _opts) => async (ctx) => {
3275
3276
  try {
3276
- const { saveState: saveState2 } = await import("./persistence-TSBV5F6R.js");
3277
+ const { saveState: saveState2 } = await import("./persistence-WP43KX7N.js");
3277
3278
  saveState2(ctx.state);
3278
3279
  } catch {
3279
3280
  }
@@ -4258,11 +4259,11 @@ async function writeJsonReport(outputPath, result) {
4258
4259
  }
4259
4260
 
4260
4261
  // src/platform/tui/cli/interactive-runtime.tsx
4261
- import React16 from "react";
4262
+ import React17 from "react";
4262
4263
  import { render } from "ink";
4263
4264
 
4264
4265
  // src/platform/tui/app.tsx
4265
- import { Box as Box18 } from "ink";
4266
+ import { Box as Box19 } from "ink";
4266
4267
 
4267
4268
  // src/platform/tui/hooks/useAgent.ts
4268
4269
  import { useState as useState6, useEffect as useEffect2, useCallback as useCallback7, useRef as useRef7 } from "react";
@@ -4825,6 +4826,8 @@ var UI_STATUS_MESSAGES = {
4825
4826
  START_ALREADY_RUNNING: "Autonomous mode is already active. Current run is still in progress.",
4826
4827
  /** Starting pentest message */
4827
4828
  STARTING_PENTEST: "Starting penetration test...",
4829
+ /** Start cancelled from policy composer */
4830
+ START_CANCELLED: "Start cancelled before execution.",
4828
4831
  /** Pentest task prefix */
4829
4832
  PENTEST_TASK_PREFIX: "Perform comprehensive penetration testing",
4830
4833
  /** Against prefix */
@@ -5736,6 +5739,7 @@ var COMMAND_DEFINITIONS = [
5736
5739
  { name: "target", alias: "t", args: "<ip>", description: "Set target IP or domain" },
5737
5740
  { name: "start", alias: "s", args: "[goal]", description: "Start autonomous pentest" },
5738
5741
  { name: "findings", alias: "f", description: "Show discovered vulnerabilities" },
5742
+ { name: "policy", description: "Open the current policy memory" },
5739
5743
  { name: "report", alias: "r", description: "Open an operation report modal" },
5740
5744
  { name: "graph", alias: "g", description: "Visualize the attack graph" },
5741
5745
  { name: "paths", alias: "p", description: "Show ranked attack paths" },
@@ -5773,8 +5777,10 @@ ${COMMAND_DEFINITIONS.map((cmd) => {
5773
5777
 
5774
5778
  \u2500\u2500 Tips \u2500\u2500
5775
5779
  \u2022 Type / and press Tab to autocomplete commands
5780
+ \u2022 /policy shows the current policy memory
5776
5781
  \u2022 /clear resets the entire session (messages, state, .pentesting data)
5777
5782
  \u2022 /start automatically enables auto-approve for hands-free operation
5783
+ \u2022 You can say "put this into policy memory" in normal chat and the agent will merge it automatically
5778
5784
  `;
5779
5785
 
5780
5786
  // src/platform/tui/hooks/commands/session-commands.ts
@@ -5840,13 +5846,9 @@ var createTargetCommands = (ctx) => {
5840
5846
  ctx.addMessage("system", UI_STATUS_MESSAGES.START_ALREADY_RUNNING);
5841
5847
  return;
5842
5848
  }
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
5849
  const targets = Array.from(ctx.agent.getState().getTargets().keys());
5848
5850
  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}`);
5851
+ ctx.openPolicyComposer(args.join(" ") || `${UI_STATUS_MESSAGES.PENTEST_TASK_PREFIX}${targetInfo}`);
5850
5852
  };
5851
5853
  return {
5852
5854
  [UI_COMMANDS.TARGET]: handleTarget,
@@ -6091,6 +6093,21 @@ var formatGraphWithSummary = (state, findings, flags) => {
6091
6093
  return lines.join("\n");
6092
6094
  };
6093
6095
 
6096
+ // src/platform/tui/hooks/commands/formatters/policy.ts
6097
+ function formatPolicyMemory(content) {
6098
+ const normalized = content.trim() || getDefaultPolicyDocument().trim();
6099
+ return [
6100
+ "POLICY MEMORY",
6101
+ "",
6102
+ "\u2500\u2500 Usage \u2500\u2500",
6103
+ "/policy shows the current policy memory.",
6104
+ "You can also tell the agent to remember a rule or put something into policy memory, and it will merge it automatically.",
6105
+ "",
6106
+ "\u2500\u2500 Current Policy \u2500\u2500",
6107
+ normalized
6108
+ ].join("\n");
6109
+ }
6110
+
6094
6111
  // src/platform/tui/hooks/commands/formatters/report.ts
6095
6112
  var SEVERITY_WEIGHT = {
6096
6113
  critical: 4,
@@ -6253,6 +6270,9 @@ var createDisplayCommands = (ctx) => {
6253
6270
  const flags = state.getFlags();
6254
6271
  ctx.showModal("findings", formatFindingsWithFlags(findings, flags));
6255
6272
  },
6273
+ [UI_COMMANDS.POLICY]: () => {
6274
+ ctx.showModal("policy", formatPolicyMemory(readPolicyDocument()));
6275
+ },
6256
6276
  [UI_COMMANDS.REPORT]: () => {
6257
6277
  const state = ctx.agent.getState();
6258
6278
  ctx.showModal("report", formatOperationReport(state));
@@ -6423,6 +6443,7 @@ var useCommands = (props) => {
6423
6443
  agent: props.agent,
6424
6444
  addMessage: props.addMessage,
6425
6445
  showModal: props.showModal,
6446
+ openPolicyComposer: props.openPolicyComposer,
6426
6447
  setMessages: props.setMessages,
6427
6448
  executeTask: props.executeTask,
6428
6449
  refreshStats: props.refreshStats,
@@ -6436,6 +6457,7 @@ var useCommands = (props) => {
6436
6457
  props.agent,
6437
6458
  props.addMessage,
6438
6459
  props.showModal,
6460
+ props.openPolicyComposer,
6439
6461
  props.setMessages,
6440
6462
  props.executeTask,
6441
6463
  props.refreshStats,
@@ -6704,6 +6726,26 @@ function useAppSubmission({
6704
6726
  };
6705
6727
  }
6706
6728
 
6729
+ // src/platform/tui/policy-composer.ts
6730
+ 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.";
6731
+ var POLICY_COMPOSER_AI_PROMPT = "Before I start, add any competition rules or durable constraints you want me to remember for this run.";
6732
+ var POLICY_COMPOSER_GUIDE = [
6733
+ "Before autonomous execution, add any competition rules or durable engagement constraints here.",
6734
+ "Use /policy to view the current policy memory at any time.",
6735
+ "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.",
6736
+ "Tip: paste a compact summary of the most important rules if the source text is long."
6737
+ ].join("\n");
6738
+ function buildPolicyBootstrapInput(rawPolicy) {
6739
+ const trimmed = rawPolicy.trim();
6740
+ if (!trimmed) return "";
6741
+ return [
6742
+ "Remember and follow this as durable policy memory for the current competition or engagement.",
6743
+ "Merge it into policy memory and apply it in future turns.",
6744
+ "",
6745
+ trimmed
6746
+ ].join("\n");
6747
+ }
6748
+
6707
6749
  // src/platform/tui/hooks/useAppLogic.ts
6708
6750
  var useAppLogic = ({ autoApprove = false, target }) => {
6709
6751
  const { exit } = useApp();
@@ -6712,6 +6754,11 @@ var useAppLogic = ({ autoApprove = false, target }) => {
6712
6754
  const [secretInput, setSecretInput] = useState7("");
6713
6755
  const [autoApproveMode, setAutoApproveMode] = useState7(autoApprove);
6714
6756
  const [modal, setModal] = useState7({ type: null, content: "", scrollOffset: 0 });
6757
+ const [policyComposer, setPolicyComposer] = useState7({
6758
+ isOpen: false,
6759
+ value: "",
6760
+ pendingTask: ""
6761
+ });
6715
6762
  const [footerConfig, setFooterConfig] = useState7(DEFAULT_FOOTER_DISPLAY_CONFIG);
6716
6763
  const isTyping = input.length > 0 || secretInput.length > 0;
6717
6764
  const {
@@ -6744,8 +6791,8 @@ var useAppLogic = ({ autoApprove = false, target }) => {
6744
6791
  autoApproveModeRef.current = autoApproveMode;
6745
6792
  const inputRequestRef = useRef9(inputRequest);
6746
6793
  inputRequestRef.current = inputRequest;
6747
- const isModalOpenRef = useRef9(!!modal.type);
6748
- isModalOpenRef.current = !!modal.type;
6794
+ const isModalOpenRef = useRef9(!!modal.type || policyComposer.isOpen);
6795
+ isModalOpenRef.current = !!modal.type || policyComposer.isOpen;
6749
6796
  const inputRef = useRef9(input);
6750
6797
  inputRef.current = input;
6751
6798
  const clearInput = useCallback13(() => {
@@ -6757,6 +6804,35 @@ var useAppLogic = ({ autoApprove = false, target }) => {
6757
6804
  const closeModal = useCallback13(() => {
6758
6805
  setModal({ type: null, content: "", scrollOffset: 0 });
6759
6806
  }, []);
6807
+ const openPolicyComposer = useCallback13((task) => {
6808
+ addMessage("ai", POLICY_COMPOSER_AI_PROMPT);
6809
+ setPolicyComposer({
6810
+ isOpen: true,
6811
+ value: "",
6812
+ pendingTask: task
6813
+ });
6814
+ }, [addMessage]);
6815
+ const closePolicyComposer = useCallback13(() => {
6816
+ if (!policyComposer.isOpen) return;
6817
+ setPolicyComposer((prev) => {
6818
+ if (!prev.isOpen) return prev;
6819
+ return { isOpen: false, value: "", pendingTask: "" };
6820
+ });
6821
+ addMessage("system", UI_STATUS_MESSAGES.START_CANCELLED);
6822
+ }, [addMessage, policyComposer.isOpen]);
6823
+ const submitPolicyComposer = useCallback13(async () => {
6824
+ const task = policyComposer.pendingTask.trim();
6825
+ const policyInput = buildPolicyBootstrapInput(policyComposer.value);
6826
+ setPolicyComposer({ isOpen: false, value: "", pendingTask: "" });
6827
+ if (policyInput) {
6828
+ agent.enqueueUserInput(policyInput);
6829
+ }
6830
+ setAutoApproveMode(true);
6831
+ agent.setToolAutoApprove(true);
6832
+ addMessage("system", UI_STATUS_MESSAGES.AUTONOMOUS_MODE_ENABLED);
6833
+ addMessage("system", UI_STATUS_MESSAGES.STARTING_PENTEST);
6834
+ await executeTask(task);
6835
+ }, [addMessage, agent, executeTask, policyComposer.pendingTask, policyComposer.value, setAutoApproveMode]);
6760
6836
  const handleModalScroll = useCallback13((delta) => {
6761
6837
  setModal((prev) => {
6762
6838
  const lines = prev.content.split("\n");
@@ -6784,6 +6860,7 @@ var useAppLogic = ({ autoApprove = false, target }) => {
6784
6860
  agent,
6785
6861
  addMessage,
6786
6862
  showModal,
6863
+ openPolicyComposer,
6787
6864
  setMessages,
6788
6865
  executeTask,
6789
6866
  refreshStats,
@@ -6826,6 +6903,12 @@ var useAppLogic = ({ autoApprove = false, target }) => {
6826
6903
  setSecretInput,
6827
6904
  autoApproveMode,
6828
6905
  modal,
6906
+ policyComposer,
6907
+ setPolicyComposer,
6908
+ submitPolicyComposer,
6909
+ closePolicyComposer,
6910
+ policyComposerGuide: POLICY_COMPOSER_GUIDE,
6911
+ policyComposerPlaceholder: POLICY_COMPOSER_PLACEHOLDER,
6829
6912
  handleModalScroll,
6830
6913
  closeModal,
6831
6914
  handleSecretSubmit,
@@ -8254,7 +8337,8 @@ var MODAL_TITLES = {
8254
8337
  findings: "\u25C8 FINDINGS \u25C8",
8255
8338
  report: "\u25C8 OPERATION REPORT \u25C8",
8256
8339
  graph: "\u25C8 ATTACK GRAPH \u25C8",
8257
- help: "\u25C8 COMMANDS \u25C8"
8340
+ help: "\u25C8 COMMANDS \u25C8",
8341
+ policy: "\u25C8 POLICY MEMORY \u25C8"
8258
8342
  };
8259
8343
  var Modal = memo12(({
8260
8344
  type,
@@ -8339,9 +8423,76 @@ var Modal = memo12(({
8339
8423
  );
8340
8424
  });
8341
8425
 
8342
- // src/platform/tui/components/app/bottom-region.tsx
8343
- import { Box as Box17, Text as Text18 } from "ink";
8426
+ // src/platform/tui/components/PolicyComposerModal.tsx
8427
+ import { memo as memo13, useCallback as useCallback16, useRef as useRef14 } from "react";
8428
+ import { Box as Box17, Text as Text18, useInput as useInput4 } from "ink";
8344
8429
  import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
8430
+ var PolicyComposerModal = memo13(({
8431
+ value,
8432
+ onChange,
8433
+ onSubmit,
8434
+ onClose,
8435
+ guide,
8436
+ placeholder
8437
+ }) => {
8438
+ const onCloseRef = useRef14(onClose);
8439
+ onCloseRef.current = onClose;
8440
+ const onSubmitRef = useRef14(onSubmit);
8441
+ onSubmitRef.current = onSubmit;
8442
+ const { columns, rows } = useTerminalSize();
8443
+ const terminalHeight = rows;
8444
+ const terminalWidth = columns - 4;
8445
+ useInput4(useCallback16((_input, key) => {
8446
+ if (key.escape) {
8447
+ onCloseRef.current();
8448
+ }
8449
+ }, []), { isActive: true });
8450
+ return /* @__PURE__ */ jsxs15(Box17, { flexDirection: "column", width: terminalWidth, height: terminalHeight, children: [
8451
+ /* @__PURE__ */ jsx21(Box17, { justifyContent: "center", children: /* @__PURE__ */ jsx21(Text18, { color: THEME.primary, bold: true, children: (() => {
8452
+ const title = "\u25C8 COMPETITION POLICY \u25C8";
8453
+ const sideWidth = Math.max(3, Math.floor((terminalWidth - title.length - 2) / 2));
8454
+ return `${"\u2500".repeat(sideWidth)} ${title} ${"\u2500".repeat(sideWidth)}`;
8455
+ })() }) }),
8456
+ /* @__PURE__ */ jsxs15(
8457
+ Box17,
8458
+ {
8459
+ flexDirection: "column",
8460
+ borderStyle: "round",
8461
+ borderColor: THEME.primary,
8462
+ paddingX: 1,
8463
+ paddingY: 1,
8464
+ flexGrow: 1,
8465
+ children: [
8466
+ /* @__PURE__ */ jsx21(Text18, { color: THEME.white, bold: true, children: "Optional bootstrap policy before /start" }),
8467
+ /* @__PURE__ */ jsx21(Text18, { color: THEME.dimGray, children: " " }),
8468
+ guide.split("\n").map((line, index) => /* @__PURE__ */ jsx21(Text18, { color: THEME.gray, wrap: "wrap", children: line }, index)),
8469
+ /* @__PURE__ */ jsx21(Text18, { color: THEME.dimGray, children: " " }),
8470
+ /* @__PURE__ */ jsx21(Box17, { borderStyle: "round", borderColor: THEME.primary, paddingX: 1, paddingY: 0, children: /* @__PURE__ */ jsx21(
8471
+ NormalInputArea,
8472
+ {
8473
+ inputKey: 0,
8474
+ value,
8475
+ onChange,
8476
+ onSubmit: () => onSubmitRef.current(),
8477
+ placeholder
8478
+ }
8479
+ ) })
8480
+ ]
8481
+ }
8482
+ ),
8483
+ /* @__PURE__ */ jsxs15(Box17, { justifyContent: "space-between", paddingX: 1, children: [
8484
+ /* @__PURE__ */ jsx21(Text18, { color: THEME.dimGray, children: "Enter: continue | Esc: cancel start" }),
8485
+ /* @__PURE__ */ jsxs15(Text18, { color: THEME.primary, children: [
8486
+ value.trim().length,
8487
+ " chars"
8488
+ ] })
8489
+ ] })
8490
+ ] });
8491
+ });
8492
+
8493
+ // src/platform/tui/components/app/bottom-region.tsx
8494
+ import { Box as Box18, Text as Text19 } from "ink";
8495
+ import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
8345
8496
  var BottomRegion = ({
8346
8497
  input,
8347
8498
  setInput,
@@ -8366,8 +8517,8 @@ var BottomRegion = ({
8366
8517
  }) => {
8367
8518
  const { columns } = useTerminalSize();
8368
8519
  const inputSeparatorColor = resolveInputSeparatorColor({ isProcessing, inputRequest });
8369
- return /* @__PURE__ */ jsxs15(Box17, { flexDirection: "column", width: "100%", children: [
8370
- /* @__PURE__ */ jsx21(
8520
+ return /* @__PURE__ */ jsxs16(Box18, { flexDirection: "column", width: "100%", children: [
8521
+ /* @__PURE__ */ jsx22(
8371
8522
  StatusDisplay,
8372
8523
  {
8373
8524
  retryState,
@@ -8378,8 +8529,8 @@ var BottomRegion = ({
8378
8529
  inputRequest
8379
8530
  }
8380
8531
  ),
8381
- /* @__PURE__ */ jsx21(Text18, { color: inputSeparatorColor, children: "\u2500".repeat(Math.max(1, columns - 2)) }),
8382
- /* @__PURE__ */ jsx21(Box17, { width: "100%", children: /* @__PURE__ */ jsx21(
8532
+ /* @__PURE__ */ jsx22(Text19, { color: inputSeparatorColor, children: "\u2500".repeat(Math.max(1, columns - 2)) }),
8533
+ /* @__PURE__ */ jsx22(Box18, { width: "100%", children: /* @__PURE__ */ jsx22(
8383
8534
  ChatInput,
8384
8535
  {
8385
8536
  value: input,
@@ -8396,8 +8547,8 @@ var BottomRegion = ({
8396
8547
  onSecretSubmit: handleSecretSubmit
8397
8548
  }
8398
8549
  ) }),
8399
- /* @__PURE__ */ jsx21(Text18, { color: inputSeparatorColor, children: "\u2500".repeat(Math.max(1, columns - 2)) }),
8400
- /* @__PURE__ */ jsx21(Box17, { width: "100%", children: /* @__PURE__ */ jsx21(
8550
+ /* @__PURE__ */ jsx22(Text19, { color: inputSeparatorColor, children: "\u2500".repeat(Math.max(1, columns - 2)) }),
8551
+ /* @__PURE__ */ jsx22(Box18, { width: "100%", children: /* @__PURE__ */ jsx22(
8401
8552
  footer_default,
8402
8553
  {
8403
8554
  phase: stats.phase,
@@ -8456,7 +8607,7 @@ function useModalMouseWheel({
8456
8607
  }
8457
8608
 
8458
8609
  // src/platform/tui/app.tsx
8459
- import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
8610
+ import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
8460
8611
  var MODEL_NAME = getModel() || DEFAULT_MODEL;
8461
8612
  var App = ({ autoApprove = false, target }) => {
8462
8613
  const {
@@ -8468,6 +8619,12 @@ var App = ({ autoApprove = false, target }) => {
8468
8619
  setSecretInput,
8469
8620
  autoApproveMode,
8470
8621
  modal,
8622
+ policyComposer,
8623
+ submitPolicyComposer,
8624
+ closePolicyComposer,
8625
+ policyComposerGuide,
8626
+ policyComposerPlaceholder,
8627
+ setPolicyComposer,
8471
8628
  handleModalScroll,
8472
8629
  closeModal,
8473
8630
  handleSubmit,
@@ -8492,8 +8649,23 @@ var App = ({ autoApprove = false, target }) => {
8492
8649
  isActive: !!modal.type,
8493
8650
  onScroll: handleModalScroll
8494
8651
  });
8652
+ if (policyComposer.isOpen) {
8653
+ return /* @__PURE__ */ jsx23(Box19, { flexDirection: "column", paddingX: 1, width: terminalWidth, height: terminalHeight - 1, children: /* @__PURE__ */ jsx23(
8654
+ PolicyComposerModal,
8655
+ {
8656
+ value: policyComposer.value,
8657
+ onChange: (value) => {
8658
+ setPolicyComposer((prev) => ({ ...prev, value }));
8659
+ },
8660
+ onSubmit: submitPolicyComposer,
8661
+ onClose: closePolicyComposer,
8662
+ guide: policyComposerGuide,
8663
+ placeholder: policyComposerPlaceholder
8664
+ }
8665
+ ) });
8666
+ }
8495
8667
  if (modal.type) {
8496
- return /* @__PURE__ */ jsx22(Box18, { flexDirection: "column", paddingX: 1, width: terminalWidth, height: terminalHeight - 1, children: /* @__PURE__ */ jsx22(
8668
+ return /* @__PURE__ */ jsx23(Box19, { flexDirection: "column", paddingX: 1, width: terminalWidth, height: terminalHeight - 1, children: /* @__PURE__ */ jsx23(
8497
8669
  Modal,
8498
8670
  {
8499
8671
  type: modal.type,
@@ -8504,8 +8676,8 @@ var App = ({ autoApprove = false, target }) => {
8504
8676
  }
8505
8677
  ) });
8506
8678
  }
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(
8679
+ return /* @__PURE__ */ jsxs17(Box19, { flexDirection: "column", paddingX: 1, paddingBottom: 1, width: terminalWidth, children: [
8680
+ /* @__PURE__ */ jsx23(Box19, { flexDirection: "column", width: "100%", children: /* @__PURE__ */ jsx23(
8509
8681
  MessageList,
8510
8682
  {
8511
8683
  messages,
@@ -8514,7 +8686,7 @@ var App = ({ autoApprove = false, target }) => {
8514
8686
  version: APP_VERSION
8515
8687
  }
8516
8688
  ) }),
8517
- /* @__PURE__ */ jsx22(Box18, { flexDirection: "column", marginTop: 1, width: "100%", children: /* @__PURE__ */ jsx22(
8689
+ /* @__PURE__ */ jsx23(Box19, { flexDirection: "column", marginTop: 1, width: "100%", children: /* @__PURE__ */ jsx23(
8518
8690
  BottomRegion,
8519
8691
  {
8520
8692
  input,
@@ -8545,7 +8717,7 @@ var app_default = App;
8545
8717
 
8546
8718
  // src/platform/tui/components/SplashScreen.tsx
8547
8719
  import { useEffect as useEffect11, useState as useState14 } from "react";
8548
- import { Box as Box19, Text as Text19 } from "ink";
8720
+ import { Box as Box20, Text as Text20 } from "ink";
8549
8721
 
8550
8722
  // src/platform/tui/components/CoinFrames.ts
8551
8723
  var COIN_FRAMES = [
@@ -9236,7 +9408,7 @@ var COIN_FRAMES = [
9236
9408
  ];
9237
9409
 
9238
9410
  // src/platform/tui/components/SplashScreen.tsx
9239
- import { jsx as jsx23 } from "react/jsx-runtime";
9411
+ import { jsx as jsx24 } from "react/jsx-runtime";
9240
9412
  var SplashScreen = ({
9241
9413
  onComplete,
9242
9414
  durationMs = 3e3
@@ -9258,27 +9430,27 @@ var SplashScreen = ({
9258
9430
  return () => clearInterval(interval);
9259
9431
  }, [durationMs, onComplete]);
9260
9432
  const currentFrame = COIN_FRAMES[frameIdx % COIN_FRAMES.length];
9261
- return /* @__PURE__ */ jsx23(
9262
- Box19,
9433
+ return /* @__PURE__ */ jsx24(
9434
+ Box20,
9263
9435
  {
9264
9436
  width: columns,
9265
9437
  minHeight: rows,
9266
9438
  flexDirection: "column",
9267
9439
  alignItems: "center",
9268
9440
  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}`)) }) })
9441
+ 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
9442
  }
9271
9443
  );
9272
9444
  };
9273
9445
 
9274
9446
  // src/platform/tui/cli/interactive-runtime.tsx
9275
- import { jsx as jsx24 } from "react/jsx-runtime";
9447
+ import { jsx as jsx25 } from "react/jsx-runtime";
9276
9448
  var InteractiveRoot = ({ autoApprove, target }) => {
9277
- const [showSplash, setShowSplash] = React16.useState(true);
9449
+ const [showSplash, setShowSplash] = React17.useState(true);
9278
9450
  if (showSplash) {
9279
- return /* @__PURE__ */ jsx24(SplashScreen, { durationMs: 3e3, onComplete: () => setShowSplash(false) });
9451
+ return /* @__PURE__ */ jsx25(SplashScreen, { durationMs: 3e3, onComplete: () => setShowSplash(false) });
9280
9452
  }
9281
- return /* @__PURE__ */ jsx24(
9453
+ return /* @__PURE__ */ jsx25(
9282
9454
  app_default,
9283
9455
  {
9284
9456
  autoApprove,
@@ -9288,7 +9460,7 @@ var InteractiveRoot = ({ autoApprove, target }) => {
9288
9460
  };
9289
9461
  async function renderInteractiveApp(props) {
9290
9462
  const { waitUntilExit } = render(
9291
- /* @__PURE__ */ jsx24(AnimationProvider, { children: /* @__PURE__ */ jsx24(InteractiveRoot, { ...props }) })
9463
+ /* @__PURE__ */ jsx25(AnimationProvider, { children: /* @__PURE__ */ jsx25(InteractiveRoot, { ...props }) })
9292
9464
  );
9293
9465
  await waitUntilExit();
9294
9466
  }
@@ -3,7 +3,7 @@ import {
3
3
  clearWorkspace,
4
4
  loadState,
5
5
  saveState
6
- } from "./chunk-TFYJWIQF.js";
6
+ } from "./chunk-U2NIVQ2O.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.11",
4
4
  "description": "Autonomous Penetration Testing AI Agent",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",