pentesting 0.73.3 → 0.73.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -42,7 +42,7 @@ import {
42
42
  rotateTurnRecords,
43
43
  setCurrentTurn,
44
44
  writePolicyDocument
45
- } from "./chunk-BKWCGMSV.js";
45
+ } from "./chunk-3KWJPPYB.js";
46
46
  import {
47
47
  AGENT_ROLES,
48
48
  APP_DESCRIPTION,
@@ -75,20 +75,22 @@ import {
75
75
  generateId,
76
76
  getErrorMessage,
77
77
  getProcessOutput,
78
+ getWorkspaceConfig,
78
79
  initDebugLogger,
79
80
  listBackgroundProcesses,
80
81
  loadState,
82
+ readRuntimeAssetFile,
83
+ resolveRuntimeAssetPath,
81
84
  saveState,
82
85
  setActiveSessionRuntime,
83
86
  setTorEnabled,
84
87
  snapshotToPrompt
85
- } from "./chunk-UB7RW6LM.js";
88
+ } from "./chunk-7E2VUIFU.js";
86
89
  import {
87
90
  EXIT_CODES,
88
- getPipelineConfig,
89
- getPromptBuilderConfig,
90
- getPromptSources
91
- } from "./chunk-GLO6TOJN.js";
91
+ getOptionalRuntimeSection,
92
+ getRequiredRuntimeSection
93
+ } from "./chunk-I52SWXYV.js";
92
94
 
93
95
  // src/platform/tui/main.tsx
94
96
  import chalk5 from "chalk";
@@ -294,17 +296,6 @@ var CLI_SCAN_TYPES = Object.freeze([
294
296
  CLI_SCAN_TYPE.VULN
295
297
  ]);
296
298
 
297
- // src/platform/tui/cli/commands/interactive.tsx
298
- import React16 from "react";
299
- import { render } from "ink";
300
- import chalk from "chalk";
301
-
302
- // src/platform/tui/app.tsx
303
- import { Box as Box18 } from "ink";
304
-
305
- // src/platform/tui/hooks/useAgent.ts
306
- import { useState as useState6, useEffect as useEffect2, useCallback as useCallback6, useRef as useRef6 } from "react";
307
-
308
299
  // src/engine/events.ts
309
300
  var AgentEventEmitter = class {
310
301
  listeners = /* @__PURE__ */ new Map();
@@ -591,13 +582,25 @@ var ApprovalGate = class {
591
582
  return this.shouldAutoApprove;
592
583
  }
593
584
  /**
594
- * Runtime-aware approval:
595
- * - containerized runtime defaults to advisory
596
- * - host runtime defaults to require_auto_approve
597
- * Category/level system is retained for audit trail only.
585
+ * Expose the effective runtime approval mode for UI/help text and tests.
586
+ */
587
+ getMode() {
588
+ return this.mode;
589
+ }
590
+ /**
591
+ * Whether tool execution is currently gated on the explicit auto-approve toggle.
592
+ */
593
+ requiresAutoApprove() {
594
+ return this.mode === "require_auto_approve";
595
+ }
596
+ /**
597
+ * Runtime-aware approval.
598
+ *
599
+ * In strict mode we currently have one explicit gate:
600
+ * the operator must enable auto-approve before tool execution proceeds.
598
601
  */
599
602
  async request(toolCall) {
600
- if (this.mode === "require_auto_approve" && !this.shouldAutoApprove) {
603
+ if (this.requiresAutoApprove() && !this.shouldAutoApprove) {
601
604
  return {
602
605
  isApproved: false,
603
606
  reason: AUTO_APPROVE_REQUIRED_REASON(toolCall.name)
@@ -608,34 +611,67 @@ var ApprovalGate = class {
608
611
  };
609
612
 
610
613
  // src/agents/prompt-builder/prompt-loader.ts
611
- import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
614
+ import { readFileSync as readFileSync2 } from "fs";
612
615
  import { join } from "path";
616
+
617
+ // src/agents/prompt-sources.ts
618
+ var DEFAULT_PROMPT_BASE_DIR = "src/agents/prompts/";
619
+ var EMPTY_TECHNIQUE_SOURCES = [];
620
+ var EMPTY_CORE_KNOWLEDGE_SOURCES = [];
621
+ function getPromptSources() {
622
+ return getRequiredRuntimeSection("prompt_sources");
623
+ }
624
+ function getPromptSourceConfigValue(key) {
625
+ return getPromptSources()[key];
626
+ }
627
+ function getPhasePromptSource(phase) {
628
+ return getPromptSourceConfigValue("phase_prompts")?.[phase];
629
+ }
630
+ function getPromptBaseDir() {
631
+ return getPromptSourceConfigValue("base_dir") ?? DEFAULT_PROMPT_BASE_DIR;
632
+ }
633
+ function getPhaseTechniqueSources(phase) {
634
+ return getPromptSourceConfigValue("phase_techniques")?.[phase] ?? EMPTY_TECHNIQUE_SOURCES;
635
+ }
636
+ function getTechniqueBaseDir() {
637
+ return getPromptSourceConfigValue("techniques_dir");
638
+ }
639
+ function getCoreKnowledgeSources() {
640
+ return getPromptSourceConfigValue("core_knowledge") ?? EMPTY_CORE_KNOWLEDGE_SOURCES;
641
+ }
642
+
643
+ // src/agents/prompt-builder/prompt-loader.ts
613
644
  var _promptsDir = null;
614
645
  var _techniquesDir = null;
615
646
  function getPromptsDir() {
616
647
  if (!_promptsDir) {
617
- const sources = getPromptSources();
618
- _promptsDir = join(process.cwd(), sources.base_dir ?? "src/agents/prompts/");
648
+ const baseDir = getPromptBaseDir();
649
+ _promptsDir = resolveRuntimeAssetPath(baseDir) ?? join(process.cwd(), baseDir);
619
650
  }
620
651
  return _promptsDir;
621
652
  }
622
653
  function getTechniquesDir() {
623
654
  if (!_techniquesDir) {
624
- const sources = getPromptSources();
625
- _techniquesDir = sources.techniques_dir ? join(process.cwd(), sources.techniques_dir) : join(getPromptsDir(), PROMPT_PATHS.TECHNIQUES_DIR);
655
+ const techniquesDir = getTechniqueBaseDir();
656
+ _techniquesDir = techniquesDir ? resolveRuntimeAssetPath(techniquesDir) ?? join(process.cwd(), techniquesDir) : join(getPromptsDir(), PROMPT_PATHS.TECHNIQUES_DIR);
626
657
  }
627
658
  return _techniquesDir;
628
659
  }
629
660
  function loadPromptFile(filename) {
630
- const path3 = join(getPromptsDir(), filename);
631
- return existsSync2(path3) ? readFileSync2(path3, PROMPT_CONFIG.ENCODING) : "";
661
+ const path2 = join(getPromptsDir(), filename);
662
+ try {
663
+ const resolved = resolveRuntimeAssetPath(path2) ?? path2;
664
+ return readFileSync2(resolved, PROMPT_CONFIG.ENCODING);
665
+ } catch {
666
+ return "";
667
+ }
632
668
  }
633
669
  function loadTechniqueFile(techniqueName) {
634
670
  const filename = techniqueName.endsWith(".md") ? techniqueName : `${techniqueName}.md`;
635
671
  const filePath = join(getTechniquesDir(), filename);
636
672
  try {
637
- if (!existsSync2(filePath)) return "";
638
- return readFileSync2(filePath, PROMPT_CONFIG.ENCODING);
673
+ const resolved = resolveRuntimeAssetPath(filePath) ?? filePath;
674
+ return readFileSync2(resolved, PROMPT_CONFIG.ENCODING);
639
675
  } catch {
640
676
  return "";
641
677
  }
@@ -794,68 +830,32 @@ function buildUserContextFragment(userInput) {
794
830
  return PROMPT_DEFAULTS.USER_CONTEXT(userInput);
795
831
  }
796
832
 
797
- // src/agents/prompt-builder/yaml-layer-executor.ts
798
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
799
- import path from "path";
800
- var STATE_FRAGMENT_REGISTRY = {
801
- "state.scope": (ctx) => buildScopeFragment(ctx.state),
802
- "state.todo": (ctx) => buildTodoFragment(ctx.state),
803
- "state.time": (ctx) => buildTimeFragment(ctx.state),
804
- "state.serialized": (ctx) => buildStateFragment(ctx.state, StateSerializer.toPrompt(ctx.state)),
805
- "state.workingMemory": (ctx) => buildWorkingMemoryFragment(ctx.state),
806
- "state.challengeAnalysis": (ctx) => buildChallengeAnalysisFragment(ctx.state),
807
- "state.attackGraph": (ctx) => buildAttackGraphFragment(ctx.state),
808
- "state.episodicMemory": (ctx) => buildEpisodicMemoryFragment(ctx.state),
809
- "state.dynamicTechniques": (ctx) => buildDynamicTechniquesFragment(ctx.state),
810
- "state.lastReflection": (ctx) => buildLastReflectionFragment(ctx.state.lastReflection),
811
- "state.targets_ports": (ctx) => buildAttackIntelligenceFragment(ctx.state),
812
- // persistent memory는 별도 처리 (import 순서 문제 방지)
813
- "state.persistentMemory": (ctx) => buildPersistentMemoryFragment(ctx.state)
814
- };
815
- async function executeLayer(layer, ctx) {
816
- try {
817
- switch (layer.type) {
818
- case "file":
819
- return executeFileLayer(layer);
820
- case "file_phase_mapped":
821
- return executePhaseFileLayer(ctx.phase);
822
- case "files":
823
- return executeFilesLayer(layer, ctx.phase);
824
- case "files_phase_mapped":
825
- return executePhaseFilesLayer(layer, ctx.phase);
826
- case "state":
827
- return executeStateLayer(layer, ctx);
828
- case "static":
829
- return layer.content?.trim() ?? null;
830
- case "file_read":
831
- return executeFileReadLayer(layer) || null;
832
- case "user_input":
833
- return buildUserContextFragment(ctx.userInput) || null;
834
- case "memory": {
835
- const key = layer.source?.replace(/^memory\./, "") || "";
836
- return ctx.memory?.[key] || null;
837
- }
838
- default:
839
- return null;
840
- }
841
- } catch {
842
- return null;
833
+ // src/agents/prompt-builder/layer-wrapping.ts
834
+ function wrapLayerContent(template, content, tokens = {}) {
835
+ if (!template) {
836
+ return content;
843
837
  }
838
+ return Object.entries({ ...tokens, content }).reduce(
839
+ (acc, [key, value]) => acc.replace(`{${key}}`, value),
840
+ template
841
+ );
842
+ }
843
+ function wrapTechniqueReference(name, content) {
844
+ return `<technique-reference category="${name}">
845
+ ${content}
846
+ </technique-reference>`;
844
847
  }
848
+
849
+ // src/agents/prompt-builder/file-layer-executors.ts
845
850
  function executeFileReadLayer(layer) {
846
851
  const source = layer.source?.trim();
847
852
  if (!source) return null;
848
853
  if (source.includes("{N-1}")) {
849
854
  return buildJournalFragment() || null;
850
855
  }
851
- const absolutePath = path.resolve(process.cwd(), source);
852
- if (!existsSync3(absolutePath)) return null;
853
- const content = readFileSync3(absolutePath, "utf-8").trim();
856
+ const content = readRuntimeAssetFile(source, "utf-8")?.trim();
854
857
  if (!content) return null;
855
- if (layer.wrap) {
856
- return layer.wrap.replace("{content}", content);
857
- }
858
- return content;
858
+ return wrapLayerContent(layer.wrap, content);
859
859
  }
860
860
  function executeFileLayer(layer) {
861
861
  if (!layer.source) return null;
@@ -864,54 +864,149 @@ function executeFileLayer(layer) {
864
864
  return loadPromptFile(filename) || null;
865
865
  }
866
866
  function executePhaseFileLayer(phase) {
867
- const sources = getPromptSources();
868
- const file = sources.phase_prompts?.[phase];
867
+ const file = getPhasePromptSource(phase);
869
868
  if (!file) return null;
870
869
  return loadPromptFile(file) || null;
871
870
  }
872
871
  function executeFilesLayer(layer, phase) {
873
- const sources = getPromptSources();
874
- const files = sources.core_knowledge ?? [];
875
- const phaseFile = sources.phase_prompts?.[phase];
872
+ const files = getCoreKnowledgeSources();
873
+ const phaseFile = getPhasePromptSource(phase);
876
874
  const filtered = layer.exclude_current_phase_file && phaseFile ? files.filter((f) => f !== phaseFile) : files;
877
- const parts = filtered.map((f) => {
878
- const content = loadPromptFile(f);
875
+ const parts = filtered.map((file) => {
876
+ const content = loadPromptFile(file);
879
877
  if (!content) return "";
880
- const label = f.replace(".md", "");
881
- if (layer.wrap) {
882
- return layer.wrap.replace("{label}", label).replace("{content}", content);
883
- }
884
- return content;
878
+ const label = file.replace(".md", "");
879
+ return wrapLayerContent(layer.wrap, content, { label });
885
880
  });
886
881
  return parts.filter(Boolean).join("\n\n") || null;
887
882
  }
888
883
  function executePhaseFilesLayer(layer, phase) {
889
- const sources = getPromptSources();
890
- const files = sources.phase_techniques?.[phase] ?? [];
884
+ const files = getPhaseTechniqueSources(phase);
891
885
  if (files.length === 0) return null;
892
886
  const parts = files.map((name) => {
893
887
  const content = loadTechniqueFile(name);
894
888
  if (!content) return "";
895
- if (layer.wrap) {
896
- return layer.wrap.replace("{name}", name).replace("{content}", content);
897
- }
898
- return `<technique-reference category="${name}">
899
- ${content}
900
- </technique-reference>`;
889
+ if (layer.wrap) return wrapLayerContent(layer.wrap, content, { name });
890
+ return wrapTechniqueReference(name, content);
901
891
  });
902
892
  return parts.filter(Boolean).join("\n\n") || null;
903
893
  }
894
+
895
+ // src/agents/prompt-builder/state-layer-registry.ts
896
+ var STATE_LAYER_REGISTRY = {
897
+ "state.scope": (ctx) => buildScopeFragment(ctx.state),
898
+ "state.todo": (ctx) => buildTodoFragment(ctx.state),
899
+ "state.time": (ctx) => buildTimeFragment(ctx.state),
900
+ "state.serialized": (ctx) => buildStateFragment(ctx.state, StateSerializer.toPrompt(ctx.state)),
901
+ "state.workingMemory": (ctx) => buildWorkingMemoryFragment(ctx.state),
902
+ "state.challengeAnalysis": (ctx) => buildChallengeAnalysisFragment(ctx.state),
903
+ "state.attackGraph": (ctx) => buildAttackGraphFragment(ctx.state),
904
+ "state.episodicMemory": (ctx) => buildEpisodicMemoryFragment(ctx.state),
905
+ "state.dynamicTechniques": (ctx) => buildDynamicTechniquesFragment(ctx.state),
906
+ "state.lastReflection": (ctx) => buildLastReflectionFragment(ctx.state.lastReflection),
907
+ "state.targets_ports": (ctx) => buildAttackIntelligenceFragment(ctx.state),
908
+ "state.persistentMemory": (ctx) => buildPersistentMemoryFragment(ctx.state)
909
+ };
910
+
911
+ // src/agents/prompt-builder/stateful-layer-executors.ts
904
912
  function executeStateLayer(layer, ctx) {
905
913
  const source = layer.source ?? "";
906
914
  if (source === "state.blind_spots") {
907
915
  return buildBlindSpotsCheckFragment() || null;
908
916
  }
909
- const fn = STATE_FRAGMENT_REGISTRY[source];
917
+ const fn = STATE_LAYER_REGISTRY[source];
910
918
  if (!fn) return null;
911
919
  const fragment = fn(ctx);
912
920
  if (!fragment && layer.on_empty) return layer.on_empty;
913
921
  return fragment || null;
914
922
  }
923
+ function executeMemoryLayer(layer, ctx) {
924
+ const key = layer.source?.replace(/^memory\./, "") || "";
925
+ return ctx.memory?.[key] || null;
926
+ }
927
+
928
+ // src/agents/prompt-builder/layer-executor.ts
929
+ var LAYER_EXECUTORS = {
930
+ file: (layer) => executeFileLayer(layer),
931
+ file_phase_mapped: (_layer, ctx) => executePhaseFileLayer(ctx.phase),
932
+ files: (layer, ctx) => executeFilesLayer(layer, ctx.phase),
933
+ files_phase_mapped: (layer, ctx) => executePhaseFilesLayer(layer, ctx.phase),
934
+ state: (layer, ctx) => executeStateLayer(layer, ctx),
935
+ static: (layer) => layer.content?.trim() ?? null,
936
+ file_read: (layer) => executeFileReadLayer(layer),
937
+ user_input: (_layer, ctx) => buildUserContextFragment(ctx.userInput) || null,
938
+ memory: (layer, ctx) => executeMemoryLayer(layer, ctx)
939
+ };
940
+ async function executeLayer(layer, ctx) {
941
+ try {
942
+ return LAYER_EXECUTORS[layer.type]?.(layer, ctx) ?? null;
943
+ } catch {
944
+ return null;
945
+ }
946
+ }
947
+
948
+ // src/agents/prompt-builder/prompt-section-builder.ts
949
+ function sortLayersByPriority(layers) {
950
+ return [...layers].sort((a, b) => a.id - b.id);
951
+ }
952
+ async function buildPromptSections(layers, ctx) {
953
+ const sortedLayers = sortLayersByPriority(layers);
954
+ const alwaysIncluded = sortedLayers.filter((layer) => layer.always_included);
955
+ const regularLayers = sortedLayers.filter((layer) => !layer.always_included);
956
+ const regularSections = await renderLayerGroup(regularLayers, ctx);
957
+ const alwaysSections = await renderLayerGroup(alwaysIncluded, ctx);
958
+ return { regularSections, alwaysSections };
959
+ }
960
+ async function renderLayerGroup(layers, ctx) {
961
+ const sections = [];
962
+ for (const layer of layers) {
963
+ const fragment = await executeLayer(layer, ctx);
964
+ if (fragment) {
965
+ sections.push(fragment);
966
+ }
967
+ }
968
+ return sections;
969
+ }
970
+
971
+ // src/agents/prompt-builder/prompt-truncation.ts
972
+ var TRUNCATION_NOTICE = "... [PROMPT TRUNCATED: content exceeded context limit] ...";
973
+ var TRUNCATION_NOTICE_RESERVE = 100;
974
+ function joinPromptSections(sections) {
975
+ const alwaysText = sections.alwaysSections.filter(Boolean).join("\n\n");
976
+ const fullBody = sections.regularSections.filter(Boolean).join("\n\n");
977
+ const full = alwaysText ? `${fullBody}
978
+
979
+ ${alwaysText}` : fullBody;
980
+ return { fullBody, alwaysText, full };
981
+ }
982
+ function applyPromptTruncation(fullBody, alwaysText, maxChars, userInput) {
983
+ const full = alwaysText ? `${fullBody}
984
+
985
+ ${alwaysText}` : fullBody;
986
+ if (full.length <= maxChars) {
987
+ return full;
988
+ }
989
+ const reservedLen = alwaysText.length + TRUNCATION_NOTICE_RESERVE;
990
+ const truncated = fullBody.slice(0, maxChars - reservedLen);
991
+ return alwaysText ? `${truncated}
992
+
993
+ ${TRUNCATION_NOTICE}
994
+
995
+ ${alwaysText}` : `${truncated}
996
+
997
+ ${TRUNCATION_NOTICE}
998
+
999
+ ${buildUserContextFragment(userInput)}`;
1000
+ }
1001
+
1002
+ // src/agents/prompt-builder-config.ts
1003
+ var DEFAULT_PROMPT_BUILDER_CONFIG = {};
1004
+ function getPromptBuilderConfig() {
1005
+ return getOptionalRuntimeSection("prompt_builder") ?? DEFAULT_PROMPT_BUILDER_CONFIG;
1006
+ }
1007
+ function getPromptBuilderLayers() {
1008
+ return getPromptBuilderConfig().layers ?? [];
1009
+ }
915
1010
 
916
1011
  // src/agents/prompt-builder/prompt-builder.ts
917
1012
  var DEFAULT_MAX_CHARS = 4e5;
@@ -921,51 +1016,23 @@ var PromptBuilder = class {
921
1016
  this.state = state;
922
1017
  }
923
1018
  /**
924
- * Build the system prompt by executing pipeline.yaml layers in order.
1019
+ * Build the system prompt by executing declarative prompt layers in order.
925
1020
  *
926
- * Layer order is determined by `id` in pipeline.yaml prompt_builder.layers.
927
- * To add/remove/reorder layers: edit pipeline.yaml only.
1021
+ * Layer order is determined by `id` in runtime config prompt_builder.layers.
928
1022
  */
929
1023
  async build(userInput, phase, memory) {
930
1024
  const config = getPromptBuilderConfig();
931
1025
  const maxChars = config.max_chars ?? DEFAULT_MAX_CHARS;
932
- const layers = [...config.layers ?? []].sort((a, b) => a.id - b.id);
933
- const alwaysIncluded = layers.filter((l) => l.always_included);
934
- const regularLayers = layers.filter((l) => !l.always_included);
1026
+ const layers = getPromptBuilderLayers();
935
1027
  const ctx = {
936
1028
  state: this.state,
937
1029
  phase,
938
1030
  userInput,
939
1031
  memory: memory ?? {}
940
1032
  };
941
- const regularSections = [];
942
- for (const layer of regularLayers) {
943
- const fragment = await executeLayer(layer, ctx);
944
- if (fragment) regularSections.push(fragment);
945
- }
946
- const alwaysSections = [];
947
- for (const layer of alwaysIncluded) {
948
- const fragment = await executeLayer(layer, ctx);
949
- if (fragment) alwaysSections.push(fragment);
950
- }
951
- const alwaysText = alwaysSections.filter(Boolean).join("\n\n");
952
- const fullBody = regularSections.filter(Boolean).join("\n\n");
953
- const full = alwaysText ? `${fullBody}
954
-
955
- ${alwaysText}` : fullBody;
956
- if (full.length <= maxChars) return full;
957
- const reservedLen = alwaysText.length + 100;
958
- const truncated = fullBody.slice(0, maxChars - reservedLen);
959
- const notice = "... [PROMPT TRUNCATED: content exceeded context limit] ...";
960
- return alwaysText ? `${truncated}
961
-
962
- ${notice}
963
-
964
- ${alwaysText}` : `${truncated}
965
-
966
- ${notice}
967
-
968
- ${buildUserContextFragment(userInput)}`;
1033
+ const sections = await buildPromptSections(layers, ctx);
1034
+ const { fullBody, alwaysText } = joinPromptSections(sections);
1035
+ return applyPromptTruncation(fullBody, alwaysText, maxChars, userInput);
969
1036
  }
970
1037
  };
971
1038
 
@@ -1091,9 +1158,6 @@ var ActionNode = class {
1091
1158
  // src/engine/pipeline/builder.ts
1092
1159
  var flagsCaptured = (ctx) => ctx.flagsAfter > ctx.flagsBefore;
1093
1160
 
1094
- // src/engine/pipeline/loader.ts
1095
- import { parse as yamlParse } from "yaml";
1096
-
1097
1161
  // src/engine/pipeline/io-registry.ts
1098
1162
  var SOURCE_REGISTRY = {
1099
1163
  // ── Reflector input fields (ReflectorInput) ───────────────────────────────
@@ -1412,7 +1476,7 @@ var makeRotateTurns = (_llm, _opts) => async (_ctx) => {
1412
1476
  };
1413
1477
  var makeSaveSession = (_llm, _opts) => async (ctx) => {
1414
1478
  try {
1415
- const { saveState: saveState2 } = await import("./persistence-2WKQHGOL.js");
1479
+ const { saveState: saveState2 } = await import("./persistence-BNVN3WW6.js");
1416
1480
  saveState2(ctx.state);
1417
1481
  } catch {
1418
1482
  }
@@ -1737,6 +1801,21 @@ var session = {
1737
1801
  load: (state) => loadState(state)
1738
1802
  };
1739
1803
 
1804
+ // src/agents/runtime-pipeline-config.ts
1805
+ function readRuntimePipelineNodes() {
1806
+ return getRequiredRuntimeSection("nodes");
1807
+ }
1808
+ function readRuntimeTurnCycle() {
1809
+ return getRequiredRuntimeSection("turn_cycle");
1810
+ }
1811
+ function getRuntimePipelineConfig() {
1812
+ return {
1813
+ version: getOptionalRuntimeSection("version"),
1814
+ nodes: readRuntimePipelineNodes(),
1815
+ turn_cycle: readRuntimeTurnCycle()
1816
+ };
1817
+ }
1818
+
1740
1819
  // src/agents/main-agent/delegated-task-scheduler.ts
1741
1820
  function getDelegatedTaskPriority(task) {
1742
1821
  const workerPriority = task.nextWorkerType || task.workerType;
@@ -1828,7 +1907,126 @@ var DelegatedTaskQueue = class {
1828
1907
  }
1829
1908
  };
1830
1909
 
1831
- // src/agents/main-agent/delegated-execution-plan.ts
1910
+ // src/agents/main-agent/exploit-runtime-signals.ts
1911
+ function outputContainsAny(output, patterns) {
1912
+ return patterns.some((pattern) => output.includes(pattern.toLowerCase()));
1913
+ }
1914
+ function getExploitResultSignals(result) {
1915
+ const output = (result.output || "").toLowerCase();
1916
+ const hasSession = outputContainsAny(output, ["[sessions]", "shell", "session"]);
1917
+ const hasLoot = outputContainsAny(output, ["[loot]", "password", "credential", "token", "hash"]);
1918
+ const hasAsset = outputContainsAny(output, ["[assets]", "artifact", "file", "payload"]);
1919
+ return {
1920
+ hasSession,
1921
+ hasLoot,
1922
+ hasAsset,
1923
+ indicatesProgress: hasSession || hasLoot || hasAsset || outputContainsAny(output, ["[status] running", "[status] success"])
1924
+ };
1925
+ }
1926
+ function buildExploitExecutionAnalysis(phase, signals) {
1927
+ if (signals.hasSession) {
1928
+ return {
1929
+ phaseObservation: "exploit chain produced a foothold or authenticated session",
1930
+ nextHint: "reuse the current foothold and continue from the confirmed access path"
1931
+ };
1932
+ }
1933
+ if (phase === "credential_followup") {
1934
+ return {
1935
+ phaseObservation: signals.hasLoot ? "credential follow-up produced reusable credential material" : "credential follow-up step executed",
1936
+ nextHint: "reuse validated credentials before changing exploit vectors"
1937
+ };
1938
+ }
1939
+ if (phase === "artifact_ready") {
1940
+ return {
1941
+ phaseObservation: signals.hasAsset ? "artifact validation produced a reusable artifact or asset" : "artifact validation step executed",
1942
+ nextHint: "advance the current artifact before replacing it"
1943
+ };
1944
+ }
1945
+ return {
1946
+ phaseObservation: signals.indicatesProgress ? "exploit chain advanced and produced follow-up signals" : "delegated exploit step executed",
1947
+ nextHint: "continue the selected exploit chain before switching vectors"
1948
+ };
1949
+ }
1950
+
1951
+ // src/agents/main-agent/pwn-runtime-signals.ts
1952
+ function outputContainsAny2(output, patterns) {
1953
+ return patterns.some((pattern) => output.includes(pattern.toLowerCase()));
1954
+ }
1955
+ function getPwnResultSignals(result) {
1956
+ const output = (result.output || "").toLowerCase();
1957
+ const hasFoothold2 = outputContainsAny2(output, ["[sessions]", "shell", "uid=", "got shell"]);
1958
+ const stillCrashing = outputContainsAny2(output, ["crash", "segfault", "core"]);
1959
+ const hasFindings = outputContainsAny2(output, ["[findings]", "rip controlled", "offset", "eip", "pc controlled"]);
1960
+ return {
1961
+ hasFoothold: hasFoothold2,
1962
+ stillCrashing,
1963
+ hasFindings,
1964
+ indicatesProgress: hasFoothold2 || hasFindings || outputContainsAny2(output, ["[status] running", "[status] success", "[nextworker] pwn"])
1965
+ };
1966
+ }
1967
+ function buildPwnExecutionAnalysis(phase, signals) {
1968
+ if (signals.hasFoothold) {
1969
+ return {
1970
+ phaseObservation: "pwn chain achieved code execution or an interactive foothold",
1971
+ nextHint: "reuse the achieved foothold and continue from the working exploit state"
1972
+ };
1973
+ }
1974
+ if (phase === "offset_known") {
1975
+ return {
1976
+ phaseObservation: signals.hasFindings ? "offset-guided pwn iteration confirmed control signals" : "offset-guided pwn iteration executed",
1977
+ nextHint: "continue from the known offset and latest payload revision"
1978
+ };
1979
+ }
1980
+ if (phase === "crash_iteration") {
1981
+ return {
1982
+ phaseObservation: signals.stillCrashing ? "crash-driven pwn iteration preserved the crash state" : "crash-driven pwn iteration executed",
1983
+ nextHint: "preserve crash evidence and narrow the next payload iteration"
1984
+ };
1985
+ }
1986
+ return {
1987
+ phaseObservation: signals.indicatesProgress ? "pwn chain advanced and produced follow-up signals" : "delegated pwn step executed",
1988
+ nextHint: "continue the selected exploit-development loop before broadening scope"
1989
+ };
1990
+ }
1991
+
1992
+ // src/agents/main-agent/delegated-execution-analysis.ts
1993
+ function getBoundedCredentialService(request) {
1994
+ const command = request.boundedCommand || "";
1995
+ if (command.includes("sshpass")) return "ssh";
1996
+ if (command.includes("smbclient")) return "smb";
1997
+ if (command.includes("evil-winrm")) return "winrm";
1998
+ if (command.includes("xfreerdp")) return "rdp";
1999
+ if (command.includes("ldapwhoami") || command.includes("ldapsearch")) return "ldap";
2000
+ if (command.includes("mysql ")) return "mysql";
2001
+ if (command.includes("psql ")) return "postgres";
2002
+ if (command.includes("curl -fsSIL -u")) return "http";
2003
+ if (command.includes("curl -fsS --user")) return "ftp";
2004
+ if (command.includes("Authorization: Bearer") || command.includes("X-API-Key")) return "token_or_api";
2005
+ return null;
2006
+ }
2007
+ function getBoundedArtifactKind(request) {
2008
+ const command = request.boundedCommand || "";
2009
+ if (command.includes("curl -fsSIL") && command.includes("| head -n 5")) return "webshell";
2010
+ if (command.includes("head -n 5") && command.includes(".sql")) return "database_dump";
2011
+ if (command.includes("head -n 5") && command.includes(".db")) return "database_dump";
2012
+ if (command.includes("smbclient -L")) return "smb_share";
2013
+ if (command.includes("curl -fsSIL")) return "url";
2014
+ if (command.includes("test -e")) return "file";
2015
+ return null;
2016
+ }
2017
+ function getBoundedPwnProbeKind(request) {
2018
+ const command = request.boundedCommand || "";
2019
+ if (command.includes("gdb -q") && command.includes("info registers") && command.includes("bt")) {
2020
+ return "core_gdb";
2021
+ }
2022
+ if (command.startsWith("gdb ")) {
2023
+ return "gdb_replay";
2024
+ }
2025
+ if (command.includes("timeout 5")) {
2026
+ return "binary_smoke";
2027
+ }
2028
+ return null;
2029
+ }
1832
2030
  function getPhaseFromContext(context, key) {
1833
2031
  if (!context) {
1834
2032
  return null;
@@ -1836,50 +2034,150 @@ function getPhaseFromContext(context, key) {
1836
2034
  const match = context.match(new RegExp(`${key}=([a-z_]+)`));
1837
2035
  return match?.[1] ?? null;
1838
2036
  }
1839
- function getRecommendedBoundedTool(request) {
1840
- if (request.workerType === "shell-supervisor") {
1841
- const phase = getPhaseFromContext(request.context, "shell_phase");
1842
- if (phase === "listener_waiting") return "listener_status";
1843
- if (phase === "listener_callback_detected") return "shell_promote";
1844
- if (phase === "active_shell_stabilizing") return "shell_upgrade";
1845
- if (phase === "active_shell_stabilized" || phase === "post_exploitation_active") return "shell_check";
1846
- return null;
1847
- }
1848
- if (request.workerType === "exploit") {
1849
- const phase = getPhaseFromContext(request.context, "exploit_phase");
1850
- if (phase === "foothold_active") return "exploit_foothold_check";
1851
- if (phase === "credential_followup") return "exploit_credential_check";
1852
- if (phase === "artifact_ready") return "exploit_artifact_check";
2037
+ function analyzeDelegatedExecutionResult(request, result) {
2038
+ if (!request || !result) {
1853
2039
  return null;
1854
2040
  }
1855
- if (request.workerType === "pwn") {
1856
- const phase = getPhaseFromContext(request.context, "pwn_phase");
1857
- if (phase === "offset_known") return "pwn_offset_check";
1858
- if (phase === "crash_iteration") return "pwn_crash_repro";
1859
- if (phase === "payload_iteration") return "pwn_payload_smoke";
1860
- return null;
2041
+ if (!result.success) {
2042
+ return {
2043
+ phaseObservation: "delegated step failed",
2044
+ nextHint: "retry the same chain only after using the error to narrow the next step"
2045
+ };
1861
2046
  }
1862
- return null;
1863
- }
1864
- function buildDelegatedExecutionPlan(request) {
1865
2047
  if (request.workerType === "shell-supervisor") {
1866
2048
  const phase = getPhaseFromContext(request.context, "shell_phase");
1867
- if (phase === "listener_waiting") return "Poll the listener and promote immediately if a callback appears.";
1868
- if (phase === "listener_callback_detected") return "Promote the callback path and validate the resulting shell.";
1869
- if (phase === "active_shell_stabilizing") return "Finish PTY stabilization before broader post-exploitation.";
1870
- if (phase === "active_shell_stabilized") return "Reuse the stabilized shell for controlled enumeration.";
1871
- if (phase === "post_exploitation_active") return "Continue post-exploitation through the existing shell rather than opening a new chain.";
1872
- return "Continue supervising the current shell/listener chain first.";
2049
+ if (phase === "listener_waiting") {
2050
+ return {
2051
+ phaseObservation: "listener supervision step executed",
2052
+ nextHint: "if callback evidence appeared, promote and validate the shell immediately"
2053
+ };
2054
+ }
2055
+ if (phase === "active_shell_stabilizing") {
2056
+ return {
2057
+ phaseObservation: "shell stabilization step executed",
2058
+ nextHint: "finish PTY stabilization before broader enumeration"
2059
+ };
2060
+ }
2061
+ if (phase === "post_exploitation_active") {
2062
+ return {
2063
+ phaseObservation: "post-exploitation enumeration step executed",
2064
+ nextHint: "continue controlled enumeration through the same shell"
2065
+ };
2066
+ }
1873
2067
  }
1874
2068
  if (request.workerType === "exploit") {
2069
+ if (request.boundedTool === "exploit_credential_check") {
2070
+ const service = getBoundedCredentialService(request);
2071
+ return {
2072
+ phaseObservation: service ? `bounded ${service} credential validation executed for the exploit chain` : "bounded credential validation executed for the exploit chain",
2073
+ nextHint: service ? `reuse the validated ${service} access path or convert it into a foothold before changing vectors` : "reuse the validated credentials or convert the access path into a foothold before changing vectors"
2074
+ };
2075
+ }
2076
+ if (request.boundedTool === "exploit_artifact_check") {
2077
+ const artifactKind = getBoundedArtifactKind(request);
2078
+ return {
2079
+ phaseObservation: artifactKind ? `bounded ${artifactKind} artifact validation executed for the exploit chain` : "bounded artifact validation executed for the exploit chain",
2080
+ nextHint: artifactKind === "webshell" ? "reuse the validated webshell artifact as a foothold before changing exploit delivery" : artifactKind === "database_dump" ? "advance the validated dump into credential extraction, parsing, or authenticated follow-up" : artifactKind === "smb_share" ? "reuse the validated share path for file access or lateral follow-up before changing vectors" : "advance the validated artifact into data access, authenticated use, or foothold confirmation"
2081
+ };
2082
+ }
2083
+ if (request.boundedTool === "exploit_foothold_check") {
2084
+ return {
2085
+ phaseObservation: "bounded foothold validation executed for the exploit chain",
2086
+ nextHint: "reuse the foothold and continue from the confirmed access path instead of restarting delivery"
2087
+ };
2088
+ }
2089
+ if (request.boundedTool === "exploit_vector_check") {
2090
+ return {
2091
+ phaseObservation: "bounded exploit-vector reachability check executed",
2092
+ nextHint: "if the vector is still reachable, continue adapting the current chain before switching to a new one"
2093
+ };
2094
+ }
1875
2095
  const phase = getPhaseFromContext(request.context, "exploit_phase");
2096
+ return buildExploitExecutionAnalysis(phase, getExploitResultSignals(result));
2097
+ }
2098
+ if (request.workerType === "pwn") {
2099
+ if (request.boundedTool === "pwn_offset_check") {
2100
+ const probeKind = getBoundedPwnProbeKind(request);
2101
+ return {
2102
+ phaseObservation: probeKind === "core_gdb" ? "bounded gdb core-state verification executed for the pwn loop" : probeKind === "gdb_replay" ? "bounded gdb replay executed for the pwn loop" : "bounded offset verification executed for the pwn loop",
2103
+ nextHint: probeKind === "core_gdb" ? "reuse the saved core-state evidence and narrow the next payload iteration from the confirmed crash context" : probeKind === "gdb_replay" ? "continue from the gdb-confirmed state and narrow the next payload iteration" : "continue from the known offset and narrow the next payload iteration"
2104
+ };
2105
+ }
2106
+ if (request.boundedTool === "pwn_crash_repro") {
2107
+ const probeKind = getBoundedPwnProbeKind(request);
2108
+ return {
2109
+ phaseObservation: probeKind === "core_gdb" ? "bounded core-backed crash inspection executed for the pwn loop" : probeKind === "gdb_replay" ? "bounded gdb-backed crash replay executed for the pwn loop" : "bounded crash reproduction executed for the pwn loop",
2110
+ nextHint: probeKind === "core_gdb" ? "preserve the core-backed crash state and apply the narrowest next debugging step" : probeKind === "gdb_replay" ? "preserve the gdb replay state and apply the narrowest next debugging or payload mutation step" : "preserve the crash state and apply the narrowest next debugging or payload mutation step"
2111
+ };
2112
+ }
2113
+ if (request.boundedTool === "pwn_payload_smoke") {
2114
+ const probeKind = getBoundedPwnProbeKind(request);
2115
+ return {
2116
+ phaseObservation: probeKind === "gdb_replay" ? "bounded gdb-guided smoke test executed for the pwn loop" : "bounded payload smoke test executed for the pwn loop",
2117
+ nextHint: probeKind === "gdb_replay" ? "preserve the gdb-guided payload state and continue narrowing the next test" : "preserve the last payload revision and continue narrowing the next test"
2118
+ };
2119
+ }
2120
+ const phase = getPhaseFromContext(request.context, "pwn_phase");
2121
+ return buildPwnExecutionAnalysis(phase, getPwnResultSignals(result));
2122
+ }
2123
+ return {
2124
+ phaseObservation: "delegated step executed",
2125
+ nextHint: "continue the selected delegated chain before switching focus"
2126
+ };
2127
+ }
2128
+
2129
+ // src/agents/main-agent/delegated-execution-plan.ts
2130
+ function getPhaseFromContext2(context, key) {
2131
+ if (!context) {
2132
+ return null;
2133
+ }
2134
+ const match = context.match(new RegExp(`${key}=([a-z_]+)`));
2135
+ return match?.[1] ?? null;
2136
+ }
2137
+ function getRecommendedBoundedTool(request) {
2138
+ if (request.workerType === "shell-supervisor") {
2139
+ const phase = getPhaseFromContext2(request.context, "shell_phase");
2140
+ if (phase === "listener_waiting") return "listener_status";
2141
+ if (phase === "listener_callback_detected") return "shell_promote";
2142
+ if (phase === "active_shell_stabilizing") return "shell_upgrade";
2143
+ if (phase === "active_shell_stabilized" || phase === "post_exploitation_active") return "shell_check";
2144
+ return null;
2145
+ }
2146
+ if (request.workerType === "exploit") {
2147
+ const phase = getPhaseFromContext2(request.context, "exploit_phase");
2148
+ if (phase === "foothold_active") return "exploit_foothold_check";
2149
+ if (phase === "credential_followup") return "exploit_credential_check";
2150
+ if (phase === "artifact_ready") return "exploit_artifact_check";
2151
+ return null;
2152
+ }
2153
+ if (request.workerType === "pwn") {
2154
+ const phase = getPhaseFromContext2(request.context, "pwn_phase");
2155
+ if (phase === "offset_known") return "pwn_offset_check";
2156
+ if (phase === "crash_iteration") return "pwn_crash_repro";
2157
+ if (phase === "payload_iteration") return "pwn_payload_smoke";
2158
+ return null;
2159
+ }
2160
+ return null;
2161
+ }
2162
+ function buildDelegatedExecutionPlan(request) {
2163
+ if (request.workerType === "shell-supervisor") {
2164
+ const phase = getPhaseFromContext2(request.context, "shell_phase");
2165
+ if (phase === "listener_waiting") return "Poll the listener and promote immediately if a callback appears.";
2166
+ if (phase === "listener_callback_detected") return "Promote the callback path and validate the resulting shell.";
2167
+ if (phase === "active_shell_stabilizing") return "Finish PTY stabilization before broader post-exploitation.";
2168
+ if (phase === "active_shell_stabilized") return "Reuse the stabilized shell for controlled enumeration.";
2169
+ if (phase === "post_exploitation_active") return "Continue post-exploitation through the existing shell rather than opening a new chain.";
2170
+ return "Continue supervising the current shell/listener chain first.";
2171
+ }
2172
+ if (request.workerType === "exploit") {
2173
+ const phase = getPhaseFromContext2(request.context, "exploit_phase");
1876
2174
  if (phase === "foothold_active") return "Reuse the existing foothold and prefer exploit_foothold_check for bounded access validation.";
1877
2175
  if (phase === "credential_followup") return "Validate and reuse the obtained credentials or tokens, preferring exploit_credential_check for bounded probes.";
1878
2176
  if (phase === "artifact_ready") return "Validate the current exploit artifact, preferring exploit_artifact_check before building a replacement.";
1879
2177
  return "Continue the strongest surviving exploit vector and preserve branch evidence.";
1880
2178
  }
1881
2179
  if (request.workerType === "pwn") {
1882
- const phase = getPhaseFromContext(request.context, "pwn_phase");
2180
+ const phase = getPhaseFromContext2(request.context, "pwn_phase");
1883
2181
  if (phase === "foothold_active") return "Reuse the achieved execution foothold and continue from there.";
1884
2182
  if (phase === "offset_known") return "Resume from the known offset and latest payload revision, preferring pwn_offset_check for bounded verification.";
1885
2183
  if (phase === "crash_iteration") return "Reproduce the latest crash and continue debugging from the preserved crash state, preferring pwn_crash_repro.";
@@ -1888,520 +2186,235 @@ function buildDelegatedExecutionPlan(request) {
1888
2186
  return "Continue the selected delegated chain before starting unrelated work.";
1889
2187
  }
1890
2188
 
1891
- // src/agents/main-agent/exploit-lifecycle.ts
1892
- function getReplayableExploitCommand(task) {
1893
- const candidates = [task.resumeHint || "", ...task.tried, ...task.findings, task.summary].map((value) => value.trim()).filter(Boolean);
1894
- return candidates.find(
1895
- (candidate) => candidate.includes("curl ") || candidate.includes("hydra ") || candidate.includes("sqlmap ") || candidate.includes("psql ") || candidate.includes("mysql ") || candidate.includes("ssh ") || candidate.includes("ftp ") || candidate.includes("smbclient ") || candidate.includes("xfreerdp ") || candidate.includes("evil-winrm ")
1896
- ) || null;
2189
+ // src/agents/main-agent/delegated-execution-formatting.ts
2190
+ var OUTPUT_PREVIEW_LIMIT = 240;
2191
+ var FIELD_PREVIEW_LIMIT = 180;
2192
+ function getDelegatedExecutionSignature(request) {
2193
+ if (!request) return null;
2194
+ return JSON.stringify(request);
1897
2195
  }
1898
- function hasCredentialLoot(task) {
1899
- return task.loot.some((item) => {
1900
- const normalized = item.toLowerCase();
1901
- return normalized.includes("password") || normalized.includes("credential") || normalized.includes("hash") || normalized.includes("token") || normalized.includes("key");
1902
- });
2196
+ function summarizeDelegatedExecutionField(value, limit = FIELD_PREVIEW_LIMIT) {
2197
+ const normalized = value.replace(/\s+/g, " ").trim();
2198
+ if (!normalized) {
2199
+ return "";
2200
+ }
2201
+ if (normalized.length <= limit) {
2202
+ return normalized;
2203
+ }
2204
+ return `${normalized.slice(0, limit - 3)}...`;
1903
2205
  }
1904
- function hasFoothold(task) {
1905
- return task.sessions.length > 0 || task.assets.some((asset) => {
1906
- const normalized = asset.toLowerCase();
1907
- return normalized.includes("shell:") || normalized.includes("stabilized_shell:") || normalized.includes("post_exploitation_shell:") || normalized.includes("listener:") || normalized.includes("session:") || normalized.includes("foothold");
1908
- });
2206
+ function summarizeDelegatedExecutionOutput(output) {
2207
+ return summarizeDelegatedExecutionField(output, OUTPUT_PREVIEW_LIMIT);
1909
2208
  }
1910
- function getArtifactPath(task) {
1911
- for (const asset of task.assets) {
1912
- const trimmed = asset.trim();
1913
- const artifactMatch = trimmed.match(/^artifact:(.+)$/i);
1914
- if (artifactMatch?.[1]) {
1915
- return artifactMatch[1].trim();
1916
- }
1917
- if (trimmed.startsWith("/") || trimmed.startsWith("./")) {
1918
- return trimmed;
1919
- }
2209
+ function buildDelegatedExecutionRequestFragment(request) {
2210
+ if (!request) {
2211
+ return "";
1920
2212
  }
1921
- return null;
2213
+ const executionPlan = buildDelegatedExecutionPlan(request);
2214
+ const lines = [
2215
+ "<delegated-execution-request>",
2216
+ `task: ${summarizeDelegatedExecutionField(request.task)}`,
2217
+ request.workerType ? `worker_type: ${request.workerType}` : "",
2218
+ request.resumeTaskId ? `resume_task_id: ${request.resumeTaskId}` : "",
2219
+ request.target ? `target: ${request.target}` : "",
2220
+ request.context ? `context: ${summarizeDelegatedExecutionField(request.context)}` : "",
2221
+ request.boundedTool ? `bounded_tool: ${request.boundedTool}` : "",
2222
+ request.boundedCommand ? `bounded_command: ${summarizeDelegatedExecutionField(request.boundedCommand)}` : "",
2223
+ request.boundedTimeout ? `bounded_timeout: ${request.boundedTimeout}` : "",
2224
+ request.boundedInstruction ? `bounded_instruction: ${summarizeDelegatedExecutionField(request.boundedInstruction)}` : "",
2225
+ executionPlan ? `execution_plan: ${summarizeDelegatedExecutionField(executionPlan)}` : "",
2226
+ "</delegated-execution-request>"
2227
+ ].filter(Boolean);
2228
+ return lines.join("\n");
1922
2229
  }
1923
- function getExploitLifecycleSnapshot(task) {
1924
- const replayableCommand = getReplayableExploitCommand(task);
1925
- if (hasFoothold(task)) {
1926
- return {
1927
- phase: "foothold_active",
1928
- recommendation: "A foothold already exists. Reuse the current access path and continue the exploit chain from that foothold.",
1929
- boundedTool: "exploit_foothold_check",
1930
- boundedCommand: replayableCommand || void 0,
1931
- boundedTimeout: 4e3,
1932
- boundedInstruction: "Run one narrow foothold validation step before expanding the exploit chain."
1933
- };
1934
- }
1935
- if (hasCredentialLoot(task)) {
1936
- return {
1937
- phase: "credential_followup",
1938
- recommendation: "Credentials or tokens exist. Prioritize validation, reuse, and pivot from the current exploit chain.",
1939
- boundedTool: "exploit_credential_check",
1940
- boundedCommand: replayableCommand || void 0,
1941
- boundedTimeout: 5e3,
1942
- boundedInstruction: "Run one bounded credential or token validation step before changing exploit vectors."
1943
- };
1944
- }
1945
- if (task.assets.length > 0) {
1946
- const artifactPath = getArtifactPath(task);
1947
- return {
1948
- phase: "artifact_ready",
1949
- recommendation: "The exploit chain produced reusable artifacts. Validate and advance the current artifact before changing vectors.",
1950
- boundedTool: "exploit_artifact_check",
1951
- boundedCommand: artifactPath ? `test -e ${artifactPath} && ls -l ${artifactPath} && file ${artifactPath} 2>/dev/null` : void 0,
1952
- boundedTimeout: 3e3,
1953
- boundedInstruction: "Run one bounded artifact validation step before replacing the current artifact."
1954
- };
2230
+ function buildDelegatedExecutionResultFragment(result, analysis) {
2231
+ if (!result) {
2232
+ return "";
1955
2233
  }
2234
+ const outputPreview = summarizeDelegatedExecutionOutput(result.output);
2235
+ const lines = [
2236
+ "<delegated-execution-result>",
2237
+ `success: ${result.success ? "true" : "false"}`,
2238
+ result.error ? `error: ${result.error}` : "",
2239
+ outputPreview ? `output_preview: ${outputPreview}` : "",
2240
+ analysis?.phaseObservation ? `phase_observation: ${analysis.phaseObservation}` : "",
2241
+ analysis?.nextHint ? `next_hint: ${analysis.nextHint}` : "",
2242
+ "</delegated-execution-result>"
2243
+ ].filter(Boolean);
2244
+ return lines.join("\n");
2245
+ }
2246
+
2247
+ // src/agents/main-agent/delegated-execution-state.ts
2248
+ function createDelegatedExecutionState() {
1956
2249
  return {
1957
- phase: "vector_active",
1958
- recommendation: "The current exploit vector is still active. Continue adapting it before switching to a new chain."
2250
+ pendingRequest: null,
2251
+ lastAttemptedSignature: null
1959
2252
  };
1960
2253
  }
1961
-
1962
- // src/agents/main-agent/pwn-lifecycle.ts
1963
- function joinedEvidence(task) {
1964
- return [
1965
- task.summary,
1966
- task.resumeHint,
1967
- task.waitingOn,
1968
- ...task.tried,
1969
- ...task.findings,
1970
- ...task.assets
1971
- ].filter(Boolean).join(" ").toLowerCase();
2254
+ function setDelegatedExecutionState(currentState, request) {
2255
+ const nextRequest = request || null;
2256
+ const nextSignature = getDelegatedExecutionSignature(nextRequest);
2257
+ const currentSignature = getDelegatedExecutionSignature(currentState.pendingRequest);
2258
+ const requestChanged = nextSignature !== currentSignature;
2259
+ return {
2260
+ pendingRequest: nextRequest,
2261
+ lastAttemptedSignature: requestChanged ? null : currentState.lastAttemptedSignature,
2262
+ requestChanged
2263
+ };
1972
2264
  }
1973
- function getReplayableCommand(task) {
1974
- const candidates = [...task.tried, task.resumeHint || "", task.summary].map((value) => value.trim()).filter(Boolean);
1975
- return candidates.find(
1976
- (candidate) => /^(?:\.\/|\/|python(?:3)?\b|gdb\b|qemu(?:-[\w-]+)?\b|nc\b)/i.test(candidate) || candidate.includes("pwntools")
1977
- ) || null;
2265
+ function canAutoExecuteDelegatedState(state) {
2266
+ const pendingSignature = getDelegatedExecutionSignature(state.pendingRequest);
2267
+ return pendingSignature !== null && pendingSignature !== state.lastAttemptedSignature;
1978
2268
  }
1979
- function getCandidateBinaryPath(task) {
1980
- const candidates = [...task.assets, ...task.findings, task.summary].map((value) => value.trim()).filter(Boolean);
1981
- for (const candidate of candidates) {
1982
- const artifactMatch = candidate.match(/^artifact:(.+)$/i);
1983
- const normalized = artifactMatch?.[1]?.trim() || candidate;
1984
- if (normalized.startsWith("./") || normalized.startsWith("/")) {
1985
- return normalized;
1986
- }
1987
- const embeddedPath = normalized.match(/(\.\/[A-Za-z0-9_./-]+|\/[A-Za-z0-9_./-]+)/);
1988
- if (embeddedPath?.[1]) {
1989
- return embeddedPath[1];
1990
- }
1991
- }
1992
- return null;
2269
+ function markDelegatedExecutionAttempt(state) {
2270
+ return {
2271
+ ...state,
2272
+ lastAttemptedSignature: getDelegatedExecutionSignature(state.pendingRequest)
2273
+ };
1993
2274
  }
1994
- function getPwnLifecycleSnapshot(task) {
1995
- const evidence = joinedEvidence(task);
1996
- const replayableCommand = getReplayableCommand(task);
1997
- const binaryPath = getCandidateBinaryPath(task);
1998
- if (task.sessions.length > 0 || task.assets.some((asset) => {
1999
- const normalized = asset.toLowerCase();
2000
- return normalized.includes("shell:") || normalized.includes("stabilized_shell:") || normalized.includes("post_exploitation_shell:");
2001
- })) {
2002
- return {
2003
- phase: "foothold_active",
2004
- recommendation: "The pwn chain already produced execution. Reuse the existing foothold instead of restarting the exploit loop."
2005
- };
2006
- }
2007
- if (evidence.includes("offset") || evidence.includes("pattern") || evidence.includes("eip") || evidence.includes("rip")) {
2008
- return {
2009
- phase: "offset_known",
2010
- recommendation: "Offsets or control primitives are known. Resume from the latest payload iteration instead of rediscovering the crash.",
2011
- boundedTool: "pwn_offset_check",
2012
- boundedCommand: replayableCommand || (binaryPath ? `test -x ${binaryPath} && timeout 5 ${binaryPath} </dev/null` : void 0),
2013
- boundedTimeout: 5e3,
2014
- boundedInstruction: "Run one bounded offset verification step against the latest exploit revision."
2015
- };
2016
- }
2017
- if (evidence.includes("crash") || evidence.includes("segfault") || evidence.includes("core")) {
2018
- return {
2019
- phase: "crash_iteration",
2020
- recommendation: "A crash state exists. Preserve it and continue the debug loop from the latest observed crash.",
2021
- boundedTool: "pwn_crash_repro",
2022
- boundedCommand: replayableCommand || (binaryPath ? `test -x ${binaryPath} && timeout 5 ${binaryPath} </dev/null` : void 0),
2023
- boundedTimeout: 1e4,
2024
- boundedInstruction: "Reproduce the latest crash once and preserve the exact crash state."
2025
- };
2026
- }
2275
+ function consumeDelegatedExecutionState(state) {
2027
2276
  return {
2028
- phase: "payload_iteration",
2029
- recommendation: "The pwn loop is still iterating payload design. Continue from the latest payload revision and observations.",
2030
- boundedTool: "pwn_payload_smoke",
2031
- boundedCommand: replayableCommand || (binaryPath ? `test -x ${binaryPath} && timeout 5 ${binaryPath} </dev/null` : void 0),
2032
- boundedTimeout: 5e3,
2033
- boundedInstruction: "Run one bounded payload smoke test from the latest payload revision."
2277
+ consumedRequest: state.pendingRequest,
2278
+ nextState: createDelegatedExecutionState()
2034
2279
  };
2035
2280
  }
2036
2281
 
2037
- // src/agents/main-agent/delegated-task-handoff.ts
2038
- function buildLifecycleSnapshot(decision) {
2039
- const task = decision.task;
2040
- if (decision.preferredWorkerType !== "shell-supervisor") {
2041
- if (decision.preferredWorkerType === "exploit") {
2042
- return getExploitLifecycleSnapshot(task);
2282
+ // src/agents/main-agent/delegated-execution-runtime.ts
2283
+ var DelegatedExecutionRuntime = class {
2284
+ pendingRequest = createDelegatedExecutionState().pendingRequest;
2285
+ lastAttemptedSignature = createDelegatedExecutionState().lastAttemptedSignature;
2286
+ lastExecutionResult = null;
2287
+ lastExecutionAnalysis = null;
2288
+ set(request) {
2289
+ const nextState = setDelegatedExecutionState(
2290
+ {
2291
+ pendingRequest: this.pendingRequest,
2292
+ lastAttemptedSignature: this.lastAttemptedSignature
2293
+ },
2294
+ request
2295
+ );
2296
+ this.pendingRequest = nextState.pendingRequest;
2297
+ this.lastAttemptedSignature = nextState.lastAttemptedSignature;
2298
+ if (nextState.requestChanged) {
2299
+ this.lastExecutionResult = null;
2300
+ this.lastExecutionAnalysis = null;
2043
2301
  }
2044
- if (decision.preferredWorkerType === "pwn") {
2045
- return getPwnLifecycleSnapshot(task);
2046
- }
2047
- return null;
2048
- }
2049
- return getShellSupervisorLifecycleSnapshot();
2050
- }
2051
- function buildDelegatedRequestContext(decision, lifecycleSnapshot) {
2052
- const task = decision.task;
2053
- if (!lifecycleSnapshot) {
2054
- return task.summary;
2055
2302
  }
2056
- if (decision.preferredWorkerType === "exploit") {
2057
- return [
2058
- task.summary,
2059
- `exploit_phase=${lifecycleSnapshot.phase}`,
2060
- `recommendation=${lifecycleSnapshot.recommendation}`
2061
- ].filter(Boolean).join(" | ");
2303
+ peek() {
2304
+ return this.pendingRequest;
2062
2305
  }
2063
- if (decision.preferredWorkerType === "pwn") {
2064
- return [
2065
- task.summary,
2066
- `pwn_phase=${lifecycleSnapshot.phase}`,
2067
- `recommendation=${lifecycleSnapshot.recommendation}`
2068
- ].filter(Boolean).join(" | ");
2306
+ canAutoExecute() {
2307
+ return canAutoExecuteDelegatedState({
2308
+ pendingRequest: this.pendingRequest,
2309
+ lastAttemptedSignature: this.lastAttemptedSignature
2310
+ });
2069
2311
  }
2070
- const shellSnapshot = lifecycleSnapshot;
2071
- return [
2072
- task.summary,
2073
- `shell_phase=${shellSnapshot.phase}`,
2074
- shellSnapshot.listenerId ? `listener=${shellSnapshot.listenerId}` : "",
2075
- shellSnapshot.activeShellId ? `active_shell=${shellSnapshot.activeShellId}` : "",
2076
- `recommendation=${shellSnapshot.recommendation}`
2077
- ].filter(Boolean).join(" | ");
2078
- }
2079
- function buildDelegatedExecutionRequest(decision, context, lifecycleSnapshot) {
2080
- const task = decision.task;
2081
- const preferredWorkerType = decision.preferredWorkerType;
2082
- const requestTask = task.resumeHint || task.task;
2083
- const boundedLifecycle = preferredWorkerType === "exploit" || preferredWorkerType === "pwn" ? lifecycleSnapshot : null;
2084
- return {
2085
- task: requestTask,
2086
- workerType: preferredWorkerType,
2087
- resumeTaskId: task.id,
2088
- target: task.target,
2089
- context,
2090
- boundedTool: preferredWorkerType ? getRecommendedBoundedTool({
2091
- task: requestTask,
2092
- workerType: preferredWorkerType,
2093
- target: task.target,
2094
- context
2095
- }) ?? void 0 : void 0,
2096
- boundedCommand: boundedLifecycle?.boundedCommand,
2097
- boundedTimeout: boundedLifecycle?.boundedTimeout,
2098
- boundedInstruction: preferredWorkerType ? boundedLifecycle?.boundedInstruction || buildDelegatedExecutionPlan({
2099
- task: requestTask,
2100
- workerType: preferredWorkerType,
2101
- target: task.target,
2102
- context
2103
- }) : void 0
2104
- };
2105
- }
2106
- function buildDelegatedTaskHandoff(decision) {
2107
- const task = decision.task;
2108
- const preferredWorkerType = decision.preferredWorkerType;
2109
- const lifecycleSnapshot = buildLifecycleSnapshot(decision);
2110
- const context = buildDelegatedRequestContext(decision, lifecycleSnapshot);
2111
- const delegatedExecutionRequest = buildDelegatedExecutionRequest(decision, context, lifecycleSnapshot);
2112
- const executionPlan = buildDelegatedExecutionPlan(delegatedExecutionRequest);
2113
- const details = [
2114
- `Resume delegated task: ${task.task}.`,
2115
- `Delegated task ID: ${task.id}.`,
2116
- `Scheduler reason: ${decision.reason}`,
2117
- `Scheduler cycle count: ${decision.resumeCount + 1}.`,
2118
- `Current status: ${task.status}.`,
2119
- task.waitingOn ? `Waiting on: ${task.waitingOn}.` : "",
2120
- task.assets.length > 0 ? `Reuse assets: ${task.assets.join(", ")}.` : "",
2121
- task.sessions.length > 0 ? `Reuse sessions: ${task.sessions.join(", ")}.` : "",
2122
- task.resumeHint ? `Resume guidance: ${task.resumeHint}.` : "",
2123
- preferredWorkerType ? `Preferred worker: ${preferredWorkerType}.` : "",
2124
- delegatedExecutionRequest.boundedTool ? `Bounded tool: ${delegatedExecutionRequest.boundedTool}.` : "",
2125
- delegatedExecutionRequest.boundedCommand ? `Bounded command candidate: ${delegatedExecutionRequest.boundedCommand}.` : "",
2126
- preferredWorkerType ? `Delegation policy: if this requires multi-step follow-up, call run_task with worker_type="${preferredWorkerType}" and resume_task_id="${task.id}" for this selected task before creating any unrelated delegated chain.` : "",
2127
- `Execution hint: ${executionPlan}`,
2128
- "Execution policy: continue the selected delegated chain first. Do not switch to a different active delegated task until this one is advanced or invalidated.",
2129
- "Goal: continue the existing chain instead of creating a duplicate operation."
2130
- ].filter(Boolean);
2131
- return {
2132
- shouldForwardToMain: true,
2133
- forwardedInput: details.join(" "),
2134
- directResponse: "",
2135
- shouldWritePolicy: false,
2136
- policyDocument: "",
2137
- policyUpdateSummary: "",
2138
- insightSummary: `Auto-resume delegated task ${task.id} via handoff builder.`,
2139
- delegatedExecutionRequest,
2140
- success: true
2141
- };
2142
- }
2143
-
2144
- // src/agents/main-agent/exploit-runtime-signals.ts
2145
- function outputContainsAny(output, patterns) {
2146
- return patterns.some((pattern) => output.includes(pattern.toLowerCase()));
2147
- }
2148
- function getExploitResultSignals(result) {
2149
- const output = (result.output || "").toLowerCase();
2150
- const hasSession = outputContainsAny(output, ["[sessions]", "shell", "session"]);
2151
- const hasLoot = outputContainsAny(output, ["[loot]", "password", "credential", "token", "hash"]);
2152
- const hasAsset = outputContainsAny(output, ["[assets]", "artifact", "file", "payload"]);
2153
- return {
2154
- hasSession,
2155
- hasLoot,
2156
- hasAsset,
2157
- indicatesProgress: hasSession || hasLoot || hasAsset || outputContainsAny(output, ["[status] running", "[status] success"])
2158
- };
2159
- }
2160
- function buildExploitExecutionAnalysis(phase, signals) {
2161
- if (signals.hasSession) {
2162
- return {
2163
- phaseObservation: "exploit chain produced a foothold or authenticated session",
2164
- nextHint: "reuse the current foothold and continue from the confirmed access path"
2165
- };
2312
+ markAutoExecutionAttempt() {
2313
+ const nextState = markDelegatedExecutionAttempt({
2314
+ pendingRequest: this.pendingRequest,
2315
+ lastAttemptedSignature: this.lastAttemptedSignature
2316
+ });
2317
+ this.lastAttemptedSignature = nextState.lastAttemptedSignature;
2166
2318
  }
2167
- if (phase === "credential_followup") {
2168
- return {
2169
- phaseObservation: signals.hasLoot ? "credential follow-up produced reusable credential material" : "credential follow-up step executed",
2170
- nextHint: "reuse validated credentials before changing exploit vectors"
2171
- };
2319
+ setLastExecutionResult(result) {
2320
+ this.lastExecutionResult = result;
2321
+ this.lastExecutionAnalysis = analyzeDelegatedExecutionResult(this.pendingRequest, result);
2172
2322
  }
2173
- if (phase === "artifact_ready") {
2174
- return {
2175
- phaseObservation: signals.hasAsset ? "artifact validation produced a reusable artifact or asset" : "artifact validation step executed",
2176
- nextHint: "advance the current artifact before replacing it"
2177
- };
2323
+ consume() {
2324
+ const consumed = consumeDelegatedExecutionState({
2325
+ pendingRequest: this.pendingRequest,
2326
+ lastAttemptedSignature: this.lastAttemptedSignature
2327
+ });
2328
+ this.pendingRequest = consumed.nextState.pendingRequest;
2329
+ this.lastAttemptedSignature = consumed.nextState.lastAttemptedSignature;
2330
+ this.lastExecutionAnalysis = null;
2331
+ return consumed.consumedRequest;
2178
2332
  }
2179
- return {
2180
- phaseObservation: signals.indicatesProgress ? "exploit chain advanced and produced follow-up signals" : "delegated exploit step executed",
2181
- nextHint: "continue the selected exploit chain before switching vectors"
2182
- };
2183
- }
2184
-
2185
- // src/agents/main-agent/pwn-runtime-signals.ts
2186
- function outputContainsAny2(output, patterns) {
2187
- return patterns.some((pattern) => output.includes(pattern.toLowerCase()));
2188
- }
2189
- function getPwnResultSignals(result) {
2190
- const output = (result.output || "").toLowerCase();
2191
- const hasFoothold2 = outputContainsAny2(output, ["[sessions]", "shell", "uid=", "got shell"]);
2192
- const stillCrashing = outputContainsAny2(output, ["crash", "segfault", "core"]);
2193
- const hasFindings = outputContainsAny2(output, ["[findings]", "rip controlled", "offset", "eip", "pc controlled"]);
2194
- return {
2195
- hasFoothold: hasFoothold2,
2196
- stillCrashing,
2197
- hasFindings,
2198
- indicatesProgress: hasFoothold2 || hasFindings || outputContainsAny2(output, ["[status] running", "[status] success", "[nextworker] pwn"])
2199
- };
2200
- }
2201
- function buildPwnExecutionAnalysis(phase, signals) {
2202
- if (signals.hasFoothold) {
2203
- return {
2204
- phaseObservation: "pwn chain achieved code execution or an interactive foothold",
2205
- nextHint: "reuse the achieved foothold and continue from the working exploit state"
2206
- };
2333
+ reset() {
2334
+ const resetState = createDelegatedExecutionState();
2335
+ this.pendingRequest = resetState.pendingRequest;
2336
+ this.lastAttemptedSignature = resetState.lastAttemptedSignature;
2337
+ this.lastExecutionResult = null;
2338
+ this.lastExecutionAnalysis = null;
2207
2339
  }
2208
- if (phase === "offset_known") {
2209
- return {
2210
- phaseObservation: signals.hasFindings ? "offset-guided pwn iteration confirmed control signals" : "offset-guided pwn iteration executed",
2211
- nextHint: "continue from the known offset and latest payload revision"
2212
- };
2340
+ toPromptFragment() {
2341
+ return buildDelegatedExecutionRequestFragment(this.pendingRequest);
2213
2342
  }
2214
- if (phase === "crash_iteration") {
2215
- return {
2216
- phaseObservation: signals.stillCrashing ? "crash-driven pwn iteration preserved the crash state" : "crash-driven pwn iteration executed",
2217
- nextHint: "preserve crash evidence and narrow the next payload iteration"
2218
- };
2343
+ toResultFragment() {
2344
+ return buildDelegatedExecutionResultFragment(
2345
+ this.lastExecutionResult,
2346
+ this.lastExecutionAnalysis
2347
+ );
2219
2348
  }
2349
+ };
2350
+
2351
+ // src/agents/main-agent/delegated-auto-executor-helpers.ts
2352
+ function combineToolResults(results) {
2353
+ const success = results.every((result) => result.success);
2220
2354
  return {
2221
- phaseObservation: signals.indicatesProgress ? "pwn chain advanced and produced follow-up signals" : "delegated pwn step executed",
2222
- nextHint: "continue the selected exploit-development loop before broadening scope"
2355
+ success,
2356
+ output: results.map((result, index) => `Step ${index + 1}:
2357
+ ${result.output}`).join("\n\n"),
2358
+ ...success ? {} : {
2359
+ error: results.find((result) => !result.success)?.error || "delegated auto-execution failed"
2360
+ }
2223
2361
  };
2224
2362
  }
2225
-
2226
- // src/agents/main-agent/delegated-execution-analysis.ts
2227
- function getPhaseFromContext2(context, key) {
2363
+ function buildPatchedContext(context, key, value) {
2364
+ const parts = (context || "").split("|").map((part) => part.trim()).filter(Boolean).filter((part) => !part.startsWith(`${key}=`));
2365
+ parts.push(`${key}=${value}`);
2366
+ return parts.join(" | ");
2367
+ }
2368
+ function getPhaseFromContext3(context, key) {
2228
2369
  if (!context) {
2229
2370
  return null;
2230
2371
  }
2231
2372
  const match = context.match(new RegExp(`${key}=([a-z_]+)`));
2232
2373
  return match?.[1] ?? null;
2233
2374
  }
2234
- function analyzeDelegatedExecutionResult(request, result) {
2235
- if (!request || !result) {
2236
- return null;
2237
- }
2238
- if (!result.success) {
2239
- return {
2240
- phaseObservation: "delegated step failed",
2241
- nextHint: "retry the same chain only after using the error to narrow the next step"
2242
- };
2375
+ function buildRunTaskInput(request, task, workerType, context) {
2376
+ return {
2377
+ name: TOOL_NAMES.RUN_TASK,
2378
+ input: {
2379
+ task,
2380
+ worker_type: workerType,
2381
+ ...request.resumeTaskId ? { resume_task_id: request.resumeTaskId } : {},
2382
+ ...request.target ? { target: request.target } : {},
2383
+ ...context ? { context } : {}
2384
+ }
2385
+ };
2386
+ }
2387
+ function shouldAutoExecuteDelegatedRequest(request) {
2388
+ if (!request || typeof request.resumeTaskId !== "string") {
2389
+ return false;
2243
2390
  }
2244
2391
  if (request.workerType === "shell-supervisor") {
2245
- const phase = getPhaseFromContext2(request.context, "shell_phase");
2246
- if (phase === "listener_waiting") {
2247
- return {
2248
- phaseObservation: "listener supervision step executed",
2249
- nextHint: "if callback evidence appeared, promote and validate the shell immediately"
2250
- };
2251
- }
2252
- if (phase === "active_shell_stabilizing") {
2253
- return {
2254
- phaseObservation: "shell stabilization step executed",
2255
- nextHint: "finish PTY stabilization before broader enumeration"
2256
- };
2257
- }
2258
- if (phase === "post_exploitation_active") {
2259
- return {
2260
- phaseObservation: "post-exploitation enumeration step executed",
2261
- nextHint: "continue controlled enumeration through the same shell"
2262
- };
2263
- }
2392
+ return true;
2264
2393
  }
2265
2394
  if (request.workerType === "exploit") {
2266
- if (request.boundedTool === "exploit_credential_check") {
2267
- return {
2268
- phaseObservation: "bounded credential validation executed for the exploit chain",
2269
- nextHint: "reuse the validated credentials or convert the access path into a foothold before changing vectors"
2270
- };
2271
- }
2272
- if (request.boundedTool === "exploit_artifact_check") {
2273
- return {
2274
- phaseObservation: "bounded artifact validation executed for the exploit chain",
2275
- nextHint: "advance the validated artifact into data access, authenticated use, or foothold confirmation"
2276
- };
2277
- }
2278
- if (request.boundedTool === "exploit_foothold_check") {
2279
- return {
2280
- phaseObservation: "bounded foothold validation executed for the exploit chain",
2281
- nextHint: "reuse the foothold and continue from the confirmed access path instead of restarting delivery"
2282
- };
2283
- }
2284
- const phase = getPhaseFromContext2(request.context, "exploit_phase");
2285
- return buildExploitExecutionAnalysis(phase, getExploitResultSignals(result));
2395
+ const phase = getPhaseFromContext3(request.context, "exploit_phase");
2396
+ return phase === "artifact_ready" || phase === "credential_followup" || phase === "foothold_active";
2286
2397
  }
2287
2398
  if (request.workerType === "pwn") {
2288
- if (request.boundedTool === "pwn_offset_check") {
2289
- return {
2290
- phaseObservation: "bounded offset verification executed for the pwn loop",
2291
- nextHint: "continue from the known offset and narrow the next payload iteration"
2292
- };
2293
- }
2294
- if (request.boundedTool === "pwn_crash_repro") {
2295
- return {
2296
- phaseObservation: "bounded crash reproduction executed for the pwn loop",
2297
- nextHint: "preserve the crash state and apply the narrowest next debugging or payload mutation step"
2298
- };
2299
- }
2300
- if (request.boundedTool === "pwn_payload_smoke") {
2301
- return {
2302
- phaseObservation: "bounded payload smoke test executed for the pwn loop",
2303
- nextHint: "preserve the last payload revision and continue narrowing the next test"
2304
- };
2305
- }
2306
- const phase = getPhaseFromContext2(request.context, "pwn_phase");
2307
- return buildPwnExecutionAnalysis(phase, getPwnResultSignals(result));
2399
+ const phase = getPhaseFromContext3(request.context, "pwn_phase");
2400
+ return phase === "offset_known" || phase === "crash_iteration" || phase === "foothold_active" || phase === "payload_iteration";
2308
2401
  }
2309
- return {
2310
- phaseObservation: "delegated step executed",
2311
- nextHint: "continue the selected delegated chain before switching focus"
2312
- };
2402
+ return false;
2313
2403
  }
2314
-
2315
- // src/agents/main-agent/delegated-execution-runtime.ts
2316
- var DelegatedExecutionRuntime = class {
2317
- pendingRequest = null;
2318
- lastAttemptedSignature = null;
2319
- lastExecutionResult = null;
2320
- lastExecutionAnalysis = null;
2321
- getSignature(request) {
2322
- if (!request) return null;
2323
- return JSON.stringify(request);
2324
- }
2325
- set(request) {
2326
- const nextRequest = request || null;
2327
- const nextSignature = this.getSignature(nextRequest);
2328
- const currentSignature = this.getSignature(this.pendingRequest);
2329
- if (nextSignature !== currentSignature) {
2330
- this.lastAttemptedSignature = null;
2331
- }
2332
- this.pendingRequest = nextRequest;
2333
- if (nextSignature !== currentSignature) {
2334
- this.lastExecutionResult = null;
2335
- this.lastExecutionAnalysis = null;
2336
- }
2337
- }
2338
- peek() {
2339
- return this.pendingRequest;
2340
- }
2341
- canAutoExecute() {
2342
- const pendingSignature = this.getSignature(this.pendingRequest);
2343
- return pendingSignature !== null && pendingSignature !== this.lastAttemptedSignature;
2344
- }
2345
- markAutoExecutionAttempt() {
2346
- this.lastAttemptedSignature = this.getSignature(this.pendingRequest);
2347
- }
2348
- setLastExecutionResult(result) {
2349
- this.lastExecutionResult = result;
2350
- this.lastExecutionAnalysis = analyzeDelegatedExecutionResult(this.pendingRequest, result);
2351
- }
2352
- consume() {
2353
- const request = this.pendingRequest;
2354
- this.pendingRequest = null;
2355
- this.lastAttemptedSignature = null;
2356
- this.lastExecutionAnalysis = null;
2357
- return request;
2358
- }
2359
- reset() {
2360
- this.pendingRequest = null;
2361
- this.lastAttemptedSignature = null;
2362
- this.lastExecutionResult = null;
2363
- this.lastExecutionAnalysis = null;
2364
- }
2365
- toPromptFragment() {
2366
- if (!this.pendingRequest) {
2367
- return "";
2368
- }
2369
- const request = this.pendingRequest;
2370
- const executionPlan = buildDelegatedExecutionPlan(request);
2371
- const lines = [
2372
- "<delegated-execution-request>",
2373
- `task: ${request.task}`,
2374
- request.workerType ? `worker_type: ${request.workerType}` : "",
2375
- request.resumeTaskId ? `resume_task_id: ${request.resumeTaskId}` : "",
2376
- request.target ? `target: ${request.target}` : "",
2377
- request.context ? `context: ${request.context}` : "",
2378
- request.boundedTool ? `bounded_tool: ${request.boundedTool}` : "",
2379
- request.boundedCommand ? `bounded_command: ${request.boundedCommand}` : "",
2380
- request.boundedTimeout ? `bounded_timeout: ${request.boundedTimeout}` : "",
2381
- request.boundedInstruction ? `bounded_instruction: ${request.boundedInstruction}` : "",
2382
- executionPlan ? `execution_plan: ${executionPlan}` : "",
2383
- "</delegated-execution-request>"
2384
- ].filter(Boolean);
2385
- return lines.join("\n");
2404
+ async function executeTwoStepLoop(execute, firstCall, buildFollowupCall, getSignals) {
2405
+ const firstResult = await execute(firstCall);
2406
+ if (!firstResult.success) {
2407
+ return firstResult;
2386
2408
  }
2387
- toResultFragment() {
2388
- if (!this.lastExecutionResult) {
2389
- return "";
2390
- }
2391
- const lines = [
2392
- "<delegated-execution-result>",
2393
- `success: ${this.lastExecutionResult.success ? "true" : "false"}`,
2394
- this.lastExecutionResult.error ? `error: ${this.lastExecutionResult.error}` : "",
2395
- this.lastExecutionResult.output ? `output: ${this.lastExecutionResult.output}` : "",
2396
- this.lastExecutionAnalysis?.phaseObservation ? `phase_observation: ${this.lastExecutionAnalysis.phaseObservation}` : "",
2397
- this.lastExecutionAnalysis?.nextHint ? `next_hint: ${this.lastExecutionAnalysis.nextHint}` : "",
2398
- "</delegated-execution-result>"
2399
- ].filter(Boolean);
2400
- return lines.join("\n");
2409
+ const followupCall = buildFollowupCall(firstResult);
2410
+ if (!followupCall || !getSignals(firstResult).indicatesProgress) {
2411
+ return firstResult;
2401
2412
  }
2402
- };
2413
+ const followupResult = await execute(followupCall);
2414
+ return combineToolResults([firstResult, followupResult]);
2415
+ }
2403
2416
 
2404
- // src/agents/main-agent/delegated-auto-executor.ts
2417
+ // src/agents/main-agent/delegated-auto-executor-shell.ts
2405
2418
  function didStatusDetectConnection(result) {
2406
2419
  const output = result.output || "";
2407
2420
  return output.includes("CONNECTION DETECTED") || output.includes("Promote to shell");
@@ -2460,142 +2473,6 @@ async function executeShellUpgradeSequence(toolRegistry, processId) {
2460
2473
  });
2461
2474
  return combineToolResults([initialCheck, pythonUpgrade, postPythonCheck, scriptUpgrade, finalCheck]);
2462
2475
  }
2463
- function combineToolResults(results) {
2464
- const success = results.every((result) => result.success);
2465
- return {
2466
- success,
2467
- output: results.map((result, index) => `Step ${index + 1}:
2468
- ${result.output}`).join("\n\n"),
2469
- ...success ? {} : {
2470
- error: results.find((result) => !result.success)?.error || "delegated auto-execution failed"
2471
- }
2472
- };
2473
- }
2474
- function buildPatchedContext(context, key, value) {
2475
- const parts = (context || "").split("|").map((part) => part.trim()).filter(Boolean).filter((part) => !part.startsWith(`${key}=`));
2476
- parts.push(`${key}=${value}`);
2477
- return parts.join(" | ");
2478
- }
2479
- function getPhaseFromContext3(context, key) {
2480
- if (!context) {
2481
- return null;
2482
- }
2483
- const match = context.match(new RegExp(`${key}=([a-z_]+)`));
2484
- return match?.[1] ?? null;
2485
- }
2486
- function buildRunTaskInput(request, task, workerType, context) {
2487
- return {
2488
- name: TOOL_NAMES.RUN_TASK,
2489
- input: {
2490
- task,
2491
- worker_type: workerType,
2492
- ...request.resumeTaskId ? { resume_task_id: request.resumeTaskId } : {},
2493
- ...request.target ? { target: request.target } : {},
2494
- ...context ? { context } : {}
2495
- }
2496
- };
2497
- }
2498
- function shouldAutoExecuteDelegatedRequest(request) {
2499
- if (!request || typeof request.resumeTaskId !== "string") {
2500
- return false;
2501
- }
2502
- if (request.workerType === "shell-supervisor") {
2503
- return true;
2504
- }
2505
- if (request.workerType === "exploit") {
2506
- const phase = getPhaseFromContext3(request.context, "exploit_phase");
2507
- return phase === "artifact_ready" || phase === "credential_followup" || phase === "foothold_active";
2508
- }
2509
- if (request.workerType === "pwn") {
2510
- const phase = getPhaseFromContext3(request.context, "pwn_phase");
2511
- return phase === "offset_known" || phase === "crash_iteration" || phase === "foothold_active" || phase === "payload_iteration";
2512
- }
2513
- return false;
2514
- }
2515
- function buildDelegatedRunTaskCall(request) {
2516
- return {
2517
- name: TOOL_NAMES.RUN_TASK,
2518
- input: {
2519
- task: request.task,
2520
- ...request.workerType ? { worker_type: request.workerType } : {},
2521
- ...request.resumeTaskId ? { resume_task_id: request.resumeTaskId } : {},
2522
- ...request.target ? { target: request.target } : {},
2523
- ...request.context ? { context: request.context } : {}
2524
- }
2525
- };
2526
- }
2527
- function buildBoundedDelegatedToolCall(request) {
2528
- if (!request.boundedTool || !request.boundedCommand) {
2529
- return null;
2530
- }
2531
- return {
2532
- name: request.boundedTool,
2533
- input: {
2534
- command: request.boundedCommand,
2535
- ...request.boundedTimeout ? { timeout: request.boundedTimeout } : {}
2536
- }
2537
- };
2538
- }
2539
- function buildExploitPhaseRunTaskCall(request) {
2540
- const phase = getPhaseFromContext3(request.context, "exploit_phase");
2541
- const phaseTask = phase === "foothold_active" ? "Reuse the existing foothold and continue the exploit chain from the current access path." : phase === "credential_followup" ? "Validate and reuse the obtained credentials or tokens before changing exploit vectors." : phase === "artifact_ready" ? "Validate and advance the current exploit artifact before switching to a different vector." : request.task;
2542
- return buildRunTaskInput(request, phaseTask, "exploit", request.context);
2543
- }
2544
- function buildExploitFollowupRunTaskCall(request, previousResult) {
2545
- const phase = getPhaseFromContext3(request.context, "exploit_phase");
2546
- const signals = previousResult ? getExploitResultSignals(previousResult) : null;
2547
- const hasSession = signals?.hasSession ?? false;
2548
- const hasLoot = signals?.hasLoot ?? false;
2549
- if (phase === "credential_followup" || hasLoot) {
2550
- return buildRunTaskInput(
2551
- request,
2552
- hasSession ? "Reuse the confirmed foothold or authenticated path and continue the exploit chain without restarting delivery." : "If credential reuse succeeded, continue from the confirmed foothold or authenticated path without restarting the exploit chain.",
2553
- "exploit",
2554
- buildPatchedContext(request.context, "exploit_phase", hasSession ? "foothold_active" : "credential_followup")
2555
- );
2556
- }
2557
- if (phase === "artifact_ready") {
2558
- return buildRunTaskInput(
2559
- request,
2560
- hasSession ? "A foothold exists from the validated artifact. Reuse it and continue the chain from that access path." : "If the artifact validated successfully, turn it into data extraction, authenticated access, or foothold confirmation before changing vectors.",
2561
- "exploit",
2562
- buildPatchedContext(request.context, "exploit_phase", hasSession ? "foothold_active" : "artifact_ready")
2563
- );
2564
- }
2565
- return null;
2566
- }
2567
- function buildPwnPhaseRunTaskCall(request) {
2568
- const phase = getPhaseFromContext3(request.context, "pwn_phase");
2569
- const phaseTask = phase === "foothold_active" ? "Reuse the existing execution foothold and continue post-exploitation or objective completion." : phase === "offset_known" ? "Resume the exploit loop from the known offset and latest payload revision." : phase === "crash_iteration" ? "Reproduce the latest crash and continue debugging from the preserved crash state." : request.task;
2570
- return buildRunTaskInput(request, phaseTask, "pwn", request.context);
2571
- }
2572
- function buildPwnFollowupRunTaskCall(request, previousResult) {
2573
- const phase = getPhaseFromContext3(request.context, "pwn_phase");
2574
- const signals = previousResult ? getPwnResultSignals(previousResult) : null;
2575
- const hasFoothold2 = signals?.hasFoothold ?? false;
2576
- const stillCrashing = signals?.stillCrashing ?? false;
2577
- if (phase === "offset_known") {
2578
- return buildRunTaskInput(
2579
- request,
2580
- hasFoothold2 ? "Execution is confirmed. Reuse the achieved foothold and continue from the working exploit state." : "Use the known offset to perform the narrowest next payload smoke test and confirm progress toward execution.",
2581
- "pwn",
2582
- buildPatchedContext(request.context, "pwn_phase", hasFoothold2 ? "foothold_active" : "payload_iteration")
2583
- );
2584
- }
2585
- if (phase === "crash_iteration") {
2586
- return buildRunTaskInput(
2587
- request,
2588
- stillCrashing ? "The crash state persists. Apply the narrowest next debugging or payload mutation step from the preserved crash state." : hasFoothold2 ? "Execution is confirmed. Reuse the achieved foothold and continue from the working exploit state." : "Apply the narrowest next debugging or payload mutation step from the preserved crash state.",
2589
- "pwn",
2590
- buildPatchedContext(
2591
- request.context,
2592
- "pwn_phase",
2593
- hasFoothold2 ? "foothold_active" : stillCrashing ? "crash_iteration" : "payload_iteration"
2594
- )
2595
- );
2596
- }
2597
- return null;
2598
- }
2599
2476
  function buildShellSupervisorFastPathCall() {
2600
2477
  const snapshot = getShellSupervisorLifecycleSnapshot();
2601
2478
  switch (snapshot.phase) {
@@ -2731,85 +2608,855 @@ async function executeShellSupervisorMiniLoop(toolRegistry) {
2731
2608
  });
2732
2609
  return combineToolResults([promoteResult, interactResult]);
2733
2610
  }
2734
- const singleCall = buildShellSupervisorFastPathCall();
2735
- if (!singleCall) {
2736
- return null;
2611
+ const singleCall = buildShellSupervisorFastPathCall();
2612
+ if (!singleCall) {
2613
+ return null;
2614
+ }
2615
+ return toolRegistry.execute(singleCall);
2616
+ }
2617
+
2618
+ // src/agents/main-agent/delegated-auto-executor-offense.ts
2619
+ function buildExploitPhaseRunTaskCall(request) {
2620
+ const phase = getPhaseFromContext3(request.context, "exploit_phase");
2621
+ const phaseTask = phase === "foothold_active" ? "Reuse the existing foothold and continue the exploit chain from the current access path." : phase === "credential_followup" ? "Validate and reuse the obtained credentials or tokens before changing exploit vectors." : phase === "artifact_ready" ? "Validate and advance the current exploit artifact before switching to a different vector." : request.task;
2622
+ return buildRunTaskInput(request, phaseTask, "exploit", request.context);
2623
+ }
2624
+ function buildExploitFollowupRunTaskCall(request, previousResult) {
2625
+ const phase = getPhaseFromContext3(request.context, "exploit_phase");
2626
+ const signals = previousResult ? getExploitResultSignals(previousResult) : null;
2627
+ const hasSession = signals?.hasSession ?? false;
2628
+ const hasLoot = signals?.hasLoot ?? false;
2629
+ if (phase === "credential_followup" || hasLoot) {
2630
+ return buildRunTaskInput(
2631
+ request,
2632
+ hasSession ? "Reuse the confirmed foothold or authenticated path and continue the exploit chain without restarting delivery." : "If credential reuse succeeded, continue from the confirmed foothold or authenticated path without restarting the exploit chain.",
2633
+ "exploit",
2634
+ buildPatchedContext(request.context, "exploit_phase", hasSession ? "foothold_active" : "credential_followup")
2635
+ );
2636
+ }
2637
+ if (phase === "artifact_ready") {
2638
+ return buildRunTaskInput(
2639
+ request,
2640
+ hasSession ? "A foothold exists from the validated artifact. Reuse it and continue the chain from that access path." : "If the artifact validated successfully, turn it into data extraction, authenticated access, or foothold confirmation before changing vectors.",
2641
+ "exploit",
2642
+ buildPatchedContext(request.context, "exploit_phase", hasSession ? "foothold_active" : "artifact_ready")
2643
+ );
2644
+ }
2645
+ return null;
2646
+ }
2647
+ function buildPwnPhaseRunTaskCall(request) {
2648
+ const phase = getPhaseFromContext3(request.context, "pwn_phase");
2649
+ const phaseTask = phase === "foothold_active" ? "Reuse the existing execution foothold and continue post-exploitation or objective completion." : phase === "offset_known" ? "Resume the exploit loop from the known offset and latest payload revision." : phase === "crash_iteration" ? "Reproduce the latest crash and continue debugging from the preserved crash state." : request.task;
2650
+ return buildRunTaskInput(request, phaseTask, "pwn", request.context);
2651
+ }
2652
+ function buildPwnFollowupRunTaskCall(request, previousResult) {
2653
+ const phase = getPhaseFromContext3(request.context, "pwn_phase");
2654
+ const signals = previousResult ? getPwnResultSignals(previousResult) : null;
2655
+ const hasFoothold2 = signals?.hasFoothold ?? false;
2656
+ const stillCrashing = signals?.stillCrashing ?? false;
2657
+ if (phase === "offset_known") {
2658
+ return buildRunTaskInput(
2659
+ request,
2660
+ hasFoothold2 ? "Execution is confirmed. Reuse the achieved foothold and continue from the working exploit state." : "Use the known offset to perform the narrowest next payload smoke test and confirm progress toward execution.",
2661
+ "pwn",
2662
+ buildPatchedContext(request.context, "pwn_phase", hasFoothold2 ? "foothold_active" : "payload_iteration")
2663
+ );
2664
+ }
2665
+ if (phase === "crash_iteration") {
2666
+ return buildRunTaskInput(
2667
+ request,
2668
+ stillCrashing ? "The crash state persists. Apply the narrowest next debugging or payload mutation step from the preserved crash state." : hasFoothold2 ? "Execution is confirmed. Reuse the achieved foothold and continue from the working exploit state." : "Apply the narrowest next debugging or payload mutation step from the preserved crash state.",
2669
+ "pwn",
2670
+ buildPatchedContext(
2671
+ request.context,
2672
+ "pwn_phase",
2673
+ hasFoothold2 ? "foothold_active" : stillCrashing ? "crash_iteration" : "payload_iteration"
2674
+ )
2675
+ );
2676
+ }
2677
+ return null;
2678
+ }
2679
+ async function executeExploitMiniLoop(toolRegistry, request) {
2680
+ return executeTwoStepLoop(
2681
+ (call) => toolRegistry.execute(call),
2682
+ buildExploitPhaseRunTaskCall(request),
2683
+ (firstResult) => buildExploitFollowupRunTaskCall(request, firstResult),
2684
+ getExploitResultSignals
2685
+ );
2686
+ }
2687
+ async function executeExploitDirectBoundedLoop(toolRegistry, request, boundedCall) {
2688
+ if (!boundedCall) {
2689
+ return executeExploitMiniLoop(toolRegistry, request);
2690
+ }
2691
+ return executeTwoStepLoop(
2692
+ (call) => toolRegistry.execute(call),
2693
+ boundedCall,
2694
+ (firstResult) => buildExploitFollowupRunTaskCall(request, firstResult),
2695
+ getExploitResultSignals
2696
+ );
2697
+ }
2698
+ async function executePwnMiniLoop(toolRegistry, request) {
2699
+ return executeTwoStepLoop(
2700
+ (call) => toolRegistry.execute(call),
2701
+ buildPwnPhaseRunTaskCall(request),
2702
+ (firstResult) => buildPwnFollowupRunTaskCall(request, firstResult),
2703
+ getPwnResultSignals
2704
+ );
2705
+ }
2706
+ async function executePwnDirectBoundedLoop(toolRegistry, request, boundedCall) {
2707
+ if (!boundedCall) {
2708
+ return executePwnMiniLoop(toolRegistry, request);
2709
+ }
2710
+ return executeTwoStepLoop(
2711
+ (call) => toolRegistry.execute(call),
2712
+ boundedCall,
2713
+ (firstResult) => buildPwnFollowupRunTaskCall(request, firstResult),
2714
+ getPwnResultSignals
2715
+ );
2716
+ }
2717
+
2718
+ // src/agents/main-agent/delegated-auto-executor-calls.ts
2719
+ function buildDelegatedRunTaskCall(request) {
2720
+ return {
2721
+ name: TOOL_NAMES.RUN_TASK,
2722
+ input: {
2723
+ task: request.task,
2724
+ ...request.workerType ? { worker_type: request.workerType } : {},
2725
+ ...request.resumeTaskId ? { resume_task_id: request.resumeTaskId } : {},
2726
+ ...request.target ? { target: request.target } : {},
2727
+ ...request.context ? { context: request.context } : {}
2728
+ }
2729
+ };
2730
+ }
2731
+ function buildBoundedDelegatedToolCall(request) {
2732
+ if (!request.boundedTool || !request.boundedCommand) {
2733
+ return null;
2734
+ }
2735
+ return {
2736
+ name: request.boundedTool,
2737
+ input: {
2738
+ command: request.boundedCommand,
2739
+ ...request.boundedTimeout ? { timeout: request.boundedTimeout } : {}
2740
+ }
2741
+ };
2742
+ }
2743
+
2744
+ // src/agents/main-agent/delegated-auto-execution-strategies.ts
2745
+ var DEFAULT_DELEGATED_EXECUTION_STRATEGY = async (toolRegistry, request) => toolRegistry.execute(buildDelegatedRunTaskCall(request));
2746
+ var SHELL_SUPERVISOR_STRATEGY = async (toolRegistry, request) => await executeShellSupervisorMiniLoop(toolRegistry) || await toolRegistry.execute(buildDelegatedRunTaskCall(request));
2747
+ var EXPLOIT_STRATEGY = async (toolRegistry, request) => executeExploitDirectBoundedLoop(
2748
+ toolRegistry,
2749
+ request,
2750
+ buildBoundedDelegatedToolCall(request)
2751
+ );
2752
+ var PWN_STRATEGY = async (toolRegistry, request) => executePwnDirectBoundedLoop(
2753
+ toolRegistry,
2754
+ request,
2755
+ buildBoundedDelegatedToolCall(request)
2756
+ );
2757
+ var DELEGATED_EXECUTION_STRATEGIES = {
2758
+ "shell-supervisor": SHELL_SUPERVISOR_STRATEGY,
2759
+ exploit: EXPLOIT_STRATEGY,
2760
+ pwn: PWN_STRATEGY
2761
+ };
2762
+ async function executeDelegatedRequestByStrategy(toolRegistry, request) {
2763
+ const strategy = request.workerType ? DELEGATED_EXECUTION_STRATEGIES[request.workerType] : void 0;
2764
+ return (strategy ?? DEFAULT_DELEGATED_EXECUTION_STRATEGY)(toolRegistry, request);
2765
+ }
2766
+
2767
+ // src/agents/main-agent/delegated-auto-executor.ts
2768
+ var DelegatedAutoExecutor = class {
2769
+ canExecutePending(runtime) {
2770
+ return runtime.canAutoExecute() && shouldAutoExecuteDelegatedRequest(runtime.peek());
2771
+ }
2772
+ async executePending(runtime, toolRegistry) {
2773
+ if (!toolRegistry) {
2774
+ return null;
2775
+ }
2776
+ const request = runtime.peek();
2777
+ if (!request || !this.canExecutePending(runtime)) {
2778
+ return null;
2779
+ }
2780
+ runtime.markAutoExecutionAttempt();
2781
+ const result = await executeDelegatedRequestByStrategy(toolRegistry, request);
2782
+ runtime.setLastExecutionResult(result);
2783
+ if (result.success) {
2784
+ runtime.consume();
2785
+ }
2786
+ return result;
2787
+ }
2788
+ };
2789
+
2790
+ // src/agents/main-agent/prompt-assembly.ts
2791
+ async function buildMainAgentPrompt(promptBuilder, state, userInput, delegatedExecution, memory) {
2792
+ const basePrompt = await promptBuilder.build(
2793
+ userInput,
2794
+ state.getPhase() || PHASES.RECON,
2795
+ memory
2796
+ );
2797
+ return [basePrompt, delegatedExecution.request, delegatedExecution.result].filter(Boolean).join("\n\n");
2798
+ }
2799
+
2800
+ // src/agents/main-agent/exploit-lifecycle.ts
2801
+ function shellEscape(value) {
2802
+ return `'${value.replace(/'/g, `'"'"'`)}'`;
2803
+ }
2804
+ function getReplayableExploitCommand(task) {
2805
+ const candidates = [task.resumeHint || "", ...task.tried].map((value) => value.trim()).filter(Boolean);
2806
+ return candidates.find(
2807
+ (candidate) => /^(?:curl|hydra|sqlmap|psql|mysql|ssh|ftp|smbclient|xfreerdp|evil-winrm)\s+/i.test(candidate)
2808
+ ) || null;
2809
+ }
2810
+ function getUrlCandidate(task) {
2811
+ const candidates = [
2812
+ task.target || "",
2813
+ ...task.assets,
2814
+ ...task.findings,
2815
+ task.summary,
2816
+ task.resumeHint || ""
2817
+ ].map((value) => value.trim()).filter(Boolean);
2818
+ for (const candidate of candidates) {
2819
+ const urlMatch = candidate.match(/https?:\/\/[^\s"'`]+/i);
2820
+ if (urlMatch?.[0]) {
2821
+ return urlMatch[0];
2822
+ }
2823
+ const assetMatch = candidate.match(/^url:(https?:\/\/.+)$/i);
2824
+ if (assetMatch?.[1]) {
2825
+ return assetMatch[1].trim();
2826
+ }
2827
+ }
2828
+ return null;
2829
+ }
2830
+ function getTokenProbe(task) {
2831
+ for (const item of task.loot) {
2832
+ const normalized = item.trim();
2833
+ const tokenMatch = normalized.match(/(?:bearer\s+token|token)\s*:\s*(.+)$/i);
2834
+ if (tokenMatch?.[1]) {
2835
+ return {
2836
+ header: "Authorization",
2837
+ secret: `Bearer ${tokenMatch[1].trim()}`
2838
+ };
2839
+ }
2840
+ const apiKeyMatch = normalized.match(/(?:api[_ -]?key|apikey)\s*:\s*(.+)$/i);
2841
+ if (apiKeyMatch?.[1]) {
2842
+ return {
2843
+ header: "X-API-Key",
2844
+ secret: apiKeyMatch[1].trim()
2845
+ };
2846
+ }
2847
+ }
2848
+ return null;
2849
+ }
2850
+ function getJoinedExploitEvidence(task) {
2851
+ return [
2852
+ task.target || "",
2853
+ task.summary,
2854
+ task.resumeHint || "",
2855
+ ...task.assets,
2856
+ ...task.findings,
2857
+ ...task.tried,
2858
+ ...task.loot
2859
+ ].join(" ").toLowerCase();
2860
+ }
2861
+ function getCredentialPair(task) {
2862
+ let username = null;
2863
+ let password = null;
2864
+ for (const item of task.loot) {
2865
+ const normalized = item.trim();
2866
+ const combinedMatch = normalized.match(/^([^\s:]+)\s+password:\s*(.+)$/i);
2867
+ if (combinedMatch?.[1] && combinedMatch?.[2]) {
2868
+ username = combinedMatch[1].trim();
2869
+ password = combinedMatch[2].trim();
2870
+ break;
2871
+ }
2872
+ const userMatch = normalized.match(/^(?:username|user)\s*:\s*(.+)$/i);
2873
+ if (userMatch?.[1]) {
2874
+ username = userMatch[1].trim();
2875
+ }
2876
+ const passwordMatch = normalized.match(/^password\s*:\s*(.+)$/i);
2877
+ if (passwordMatch?.[1]) {
2878
+ password = passwordMatch[1].trim();
2879
+ }
2880
+ }
2881
+ return username && password ? { username, password } : null;
2882
+ }
2883
+ function getHostCandidate(task) {
2884
+ const url = getUrlCandidate(task);
2885
+ if (url) {
2886
+ try {
2887
+ return new URL(url).host;
2888
+ } catch {
2889
+ return null;
2890
+ }
2891
+ }
2892
+ const target = (task.target || "").trim();
2893
+ if (!target) {
2894
+ return null;
2895
+ }
2896
+ if (/^https?:\/\//i.test(target)) {
2897
+ try {
2898
+ return new URL(target).host;
2899
+ } catch {
2900
+ return null;
2901
+ }
2902
+ }
2903
+ return target;
2904
+ }
2905
+ function getServiceHint(task) {
2906
+ const evidence = getJoinedExploitEvidence(task);
2907
+ if (evidence.includes("ssh")) return "ssh";
2908
+ if (evidence.includes("ftp")) return "ftp";
2909
+ if (evidence.includes("smb") || evidence.includes("445")) return "smb";
2910
+ if (evidence.includes("winrm") || evidence.includes("5985") || evidence.includes("5986")) return "winrm";
2911
+ if (evidence.includes("rdp") || evidence.includes("3389")) return "rdp";
2912
+ if (evidence.includes("ldap") || evidence.includes("389") || evidence.includes("636")) return "ldap";
2913
+ if (evidence.includes("mysql")) return "mysql";
2914
+ if (evidence.includes("postgres") || evidence.includes("psql")) return "postgres";
2915
+ if (evidence.includes("http") || evidence.includes("https") || evidence.includes("web")) return "http";
2916
+ return null;
2917
+ }
2918
+ function getServicePort(service) {
2919
+ switch (service) {
2920
+ case "ssh":
2921
+ return 22;
2922
+ case "ftp":
2923
+ return 21;
2924
+ case "http":
2925
+ return 80;
2926
+ case "mysql":
2927
+ return 3306;
2928
+ case "postgres":
2929
+ return 5432;
2930
+ case "smb":
2931
+ return 445;
2932
+ case "winrm":
2933
+ return 5985;
2934
+ case "rdp":
2935
+ return 3389;
2936
+ case "ldap":
2937
+ return 389;
2938
+ default:
2939
+ return null;
2940
+ }
2941
+ }
2942
+ function getVectorBoundedCommand(task) {
2943
+ const url = getUrlCandidate(task);
2944
+ if (url) {
2945
+ return `curl -fsSIL ${shellEscape(url)}`;
2946
+ }
2947
+ const host = getHostCandidate(task);
2948
+ const service = getServiceHint(task);
2949
+ const port = getServicePort(service);
2950
+ if (host && port) {
2951
+ return `nc -vz -w 5 ${shellEscape(host)} ${port}`;
2952
+ }
2953
+ return void 0;
2954
+ }
2955
+ function getCredentialBoundedCommand(task, replayableCommand) {
2956
+ if (replayableCommand) {
2957
+ return replayableCommand;
2958
+ }
2959
+ const url = getUrlCandidate(task);
2960
+ const tokenProbe = getTokenProbe(task);
2961
+ if (url && tokenProbe) {
2962
+ return `curl -fsSIL -H ${shellEscape(`${tokenProbe.header}: ${tokenProbe.secret}`)} ${shellEscape(url)}`;
2963
+ }
2964
+ const pair = getCredentialPair(task);
2965
+ const host = getHostCandidate(task);
2966
+ const service = getServiceHint(task);
2967
+ if (pair && host && service === "ssh") {
2968
+ return `sshpass -p ${shellEscape(pair.password)} ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 ${shellEscape(`${pair.username}@${host}`)} id`;
2969
+ }
2970
+ if (pair && host && service === "ftp") {
2971
+ return `curl -fsS --user ${shellEscape(`${pair.username}:${pair.password}`)} --max-time 5 ${shellEscape(`ftp://${host}/`)}`;
2972
+ }
2973
+ if (pair && service === "http") {
2974
+ const httpTarget = url || (host ? `http://${host}` : null);
2975
+ if (httpTarget) {
2976
+ return `curl -fsSIL -u ${shellEscape(`${pair.username}:${pair.password}`)} ${shellEscape(httpTarget)}`;
2977
+ }
2978
+ }
2979
+ if (pair && host && service === "mysql") {
2980
+ return `mysql -h ${shellEscape(host)} -u ${shellEscape(pair.username)} -p${pair.password} -e 'SELECT 1;'`;
2981
+ }
2982
+ if (pair && host && service === "postgres") {
2983
+ return `PGPASSWORD=${shellEscape(pair.password)} psql -h ${shellEscape(host)} -U ${shellEscape(pair.username)} -c 'SELECT 1;' postgres`;
2984
+ }
2985
+ if (pair && host && service === "smb") {
2986
+ return `smbclient -L ${shellEscape(`//${host}/`)} -U ${shellEscape(`${pair.username}%${pair.password}`)} -m SMB3`;
2987
+ }
2988
+ if (pair && host && service === "winrm") {
2989
+ return `evil-winrm -i ${shellEscape(host)} -u ${shellEscape(pair.username)} -p ${shellEscape(pair.password)} -c whoami`;
2990
+ }
2991
+ if (pair && host && service === "rdp") {
2992
+ return `xfreerdp /cert:ignore /auth-only /u:${shellEscape(pair.username)} /p:${shellEscape(pair.password)} /v:${shellEscape(host)}`;
2993
+ }
2994
+ if (pair && host && service === "ldap") {
2995
+ return `ldapwhoami -x -H ${shellEscape(`ldap://${host}`)} -D ${shellEscape(pair.username)} -w ${shellEscape(pair.password)}`;
2996
+ }
2997
+ return void 0;
2998
+ }
2999
+ function hasCredentialLoot(task) {
3000
+ return task.loot.some((item) => {
3001
+ const normalized = item.toLowerCase();
3002
+ return normalized.includes("password") || normalized.includes("credential") || normalized.includes("hash") || normalized.includes("token") || normalized.includes("key");
3003
+ });
3004
+ }
3005
+ function hasFoothold(task) {
3006
+ return task.sessions.length > 0 || task.assets.some((asset) => {
3007
+ const normalized = asset.toLowerCase();
3008
+ return normalized.includes("shell:") || normalized.includes("stabilized_shell:") || normalized.includes("post_exploitation_shell:") || normalized.includes("listener:") || normalized.includes("session:") || normalized.includes("foothold");
3009
+ });
3010
+ }
3011
+ function getArtifactPath(task) {
3012
+ for (const asset of task.assets) {
3013
+ const trimmed = asset.trim();
3014
+ const artifactMatch = trimmed.match(/^artifact:(.+)$/i);
3015
+ if (artifactMatch?.[1]) {
3016
+ return artifactMatch[1].trim();
3017
+ }
3018
+ if (trimmed.startsWith("/") || trimmed.startsWith("./")) {
3019
+ return trimmed;
3020
+ }
3021
+ }
3022
+ return null;
3023
+ }
3024
+ function getArtifactKind(task, artifactPath, artifactUrl) {
3025
+ const evidence = getJoinedExploitEvidence(task);
3026
+ if (artifactUrl) {
3027
+ if (artifactUrl.match(/\.(php|asp|aspx|jsp|jspx|cfm)(?:[?#].*)?$/i) || evidence.includes("webshell")) {
3028
+ return "webshell";
3029
+ }
3030
+ return "url";
3031
+ }
3032
+ if (!artifactPath) {
3033
+ return null;
3034
+ }
3035
+ if (artifactPath.match(/\.(sql|sqlite|db|mdb|bak|dump)(?:\.[a-z0-9]+)?$/i) || evidence.includes("dump")) {
3036
+ return "database_dump";
3037
+ }
3038
+ if (artifactPath.startsWith("//") || evidence.includes("smb share") || evidence.includes("share:")) {
3039
+ return "smb_share";
3040
+ }
3041
+ return "file";
3042
+ }
3043
+ function getArtifactBoundedCommand(kind, artifactPath, artifactUrl) {
3044
+ if (!kind) {
3045
+ return void 0;
3046
+ }
3047
+ if (kind === "webshell" && artifactUrl) {
3048
+ return `curl -fsSIL ${shellEscape(artifactUrl)} && curl -fsS ${shellEscape(artifactUrl)} | head -n 5`;
3049
+ }
3050
+ if (kind === "url" && artifactUrl) {
3051
+ return `curl -fsSIL ${shellEscape(artifactUrl)}`;
3052
+ }
3053
+ if (kind === "database_dump" && artifactPath) {
3054
+ return `test -e ${artifactPath} && ls -lh ${artifactPath} && file ${artifactPath} 2>/dev/null && head -n 5 ${artifactPath} 2>/dev/null`;
3055
+ }
3056
+ if (kind === "smb_share" && artifactPath) {
3057
+ return `smbclient -L ${shellEscape(artifactPath)} -N -m SMB3`;
3058
+ }
3059
+ if (kind === "file" && artifactPath) {
3060
+ return `test -e ${artifactPath} && ls -l ${artifactPath} && file ${artifactPath} 2>/dev/null`;
3061
+ }
3062
+ return void 0;
3063
+ }
3064
+ function getExploitLifecycleSnapshot(task) {
3065
+ const replayableCommand = getReplayableExploitCommand(task);
3066
+ if (hasFoothold(task)) {
3067
+ return {
3068
+ phase: "foothold_active",
3069
+ recommendation: "A foothold already exists. Reuse the current access path and continue the exploit chain from that foothold.",
3070
+ boundedTool: "exploit_foothold_check",
3071
+ boundedCommand: replayableCommand || void 0,
3072
+ boundedTimeout: 4e3,
3073
+ boundedInstruction: "Run one narrow foothold validation step before expanding the exploit chain."
3074
+ };
3075
+ }
3076
+ if (hasCredentialLoot(task)) {
3077
+ return {
3078
+ phase: "credential_followup",
3079
+ recommendation: "Credentials or tokens exist. Prioritize validation, reuse, and pivot from the current exploit chain.",
3080
+ boundedTool: "exploit_credential_check",
3081
+ boundedCommand: getCredentialBoundedCommand(task, replayableCommand),
3082
+ boundedTimeout: 5e3,
3083
+ boundedInstruction: "Run one bounded credential or token validation step before changing exploit vectors."
3084
+ };
3085
+ }
3086
+ if (task.assets.length > 0) {
3087
+ const artifactPath = getArtifactPath(task);
3088
+ const artifactUrl = getUrlCandidate(task);
3089
+ const artifactKind = getArtifactKind(task, artifactPath, artifactUrl);
3090
+ return {
3091
+ phase: "artifact_ready",
3092
+ recommendation: "The exploit chain produced reusable artifacts. Validate and advance the current artifact before changing vectors.",
3093
+ boundedTool: "exploit_artifact_check",
3094
+ boundedCommand: getArtifactBoundedCommand(artifactKind, artifactPath, artifactUrl),
3095
+ boundedTimeout: 3e3,
3096
+ boundedInstruction: artifactKind === "webshell" ? "Run one bounded webshell validation step before replacing the current foothold artifact." : artifactKind === "database_dump" ? "Run one bounded dump validation step before replacing or parsing the recovered database artifact." : artifactKind === "smb_share" ? "Run one bounded share validation step before changing the current artifact path." : "Run one bounded artifact validation step before replacing the current artifact."
3097
+ };
3098
+ }
3099
+ return {
3100
+ phase: "vector_active",
3101
+ recommendation: "The current exploit vector is still active. Continue adapting it before switching to a new chain.",
3102
+ boundedTool: "exploit_vector_check",
3103
+ boundedCommand: getVectorBoundedCommand(task),
3104
+ boundedTimeout: 5e3,
3105
+ boundedInstruction: "Run one bounded target reachability or service confirmation step before abandoning the current exploit vector."
3106
+ };
3107
+ }
3108
+
3109
+ // src/agents/main-agent/pwn-lifecycle.ts
3110
+ function joinedEvidence(task) {
3111
+ return [
3112
+ task.summary,
3113
+ task.resumeHint,
3114
+ task.waitingOn,
3115
+ ...task.tried,
3116
+ ...task.findings,
3117
+ ...task.assets
3118
+ ].filter(Boolean).join(" ").toLowerCase();
3119
+ }
3120
+ function getReplayableCommand(task) {
3121
+ const candidates = [...task.tried, task.resumeHint || ""].map((value) => value.trim()).filter(Boolean);
3122
+ return candidates.find(
3123
+ (candidate) => /^(?:\.\/|\/|python(?:3)?\b|gdb\b|qemu(?:-[\w-]+)?\b|nc\b)/i.test(candidate) || candidate.includes("pwntools")
3124
+ ) || null;
3125
+ }
3126
+ function getCandidateBinaryPath(task) {
3127
+ const candidates = [...task.assets, ...task.findings, task.summary, task.task, task.resumeHint || ""].map((value) => value.trim()).filter(Boolean);
3128
+ for (const candidate of candidates) {
3129
+ const artifactMatch = candidate.match(/^artifact:(.+)$/i);
3130
+ const normalized = artifactMatch?.[1]?.trim() || candidate;
3131
+ if (normalized.startsWith("./") || normalized.startsWith("/")) {
3132
+ return normalized;
3133
+ }
3134
+ const embeddedPath = normalized.match(/(\.\/[A-Za-z0-9_./-]+|\/[A-Za-z0-9_./-]+)/);
3135
+ if (embeddedPath?.[1]) {
3136
+ return embeddedPath[1];
3137
+ }
3138
+ }
3139
+ return null;
3140
+ }
3141
+ function getCandidateCorePath(task) {
3142
+ const candidates = [...task.assets, ...task.findings, task.summary].map((value) => value.trim()).filter(Boolean);
3143
+ for (const candidate of candidates) {
3144
+ const artifactMatch = candidate.match(/^artifact:(.+)$/i);
3145
+ const normalized = artifactMatch?.[1]?.trim() || candidate;
3146
+ if (normalized.match(/(?:^|\/)core(?:\.[A-Za-z0-9_-]+)?$/i)) {
3147
+ return normalized;
3148
+ }
3149
+ const embeddedCore = normalized.match(/(\.\/core(?:\.[A-Za-z0-9_-]+)?|\/[A-Za-z0-9_./-]*core(?:\.[A-Za-z0-9_-]+)?)/i);
3150
+ if (embeddedCore?.[1]) {
3151
+ return embeddedCore[1];
3152
+ }
3153
+ }
3154
+ return null;
3155
+ }
3156
+ function getPwnProbeKind(replayableCommand, binaryPath, corePath) {
3157
+ if (binaryPath && corePath) {
3158
+ return "core_gdb";
3159
+ }
3160
+ if (replayableCommand?.startsWith("gdb ")) {
3161
+ return "gdb_replay";
3162
+ }
3163
+ return "binary_smoke";
3164
+ }
3165
+ function getBoundedPwnCommand(kind, replayableCommand, binaryPath, corePath) {
3166
+ if (kind === "core_gdb" && binaryPath && corePath) {
3167
+ return `gdb -q ${binaryPath} ${corePath} -batch -ex 'info registers' -ex 'bt'`;
3168
+ }
3169
+ if (kind === "gdb_replay" && replayableCommand) {
3170
+ return replayableCommand;
3171
+ }
3172
+ if (replayableCommand) {
3173
+ return replayableCommand;
3174
+ }
3175
+ if (binaryPath) {
3176
+ return `test -x ${binaryPath} && timeout 5 ${binaryPath} </dev/null`;
3177
+ }
3178
+ return void 0;
3179
+ }
3180
+ function getPwnLifecycleSnapshot(task) {
3181
+ const evidence = joinedEvidence(task);
3182
+ const replayableCommand = getReplayableCommand(task);
3183
+ const binaryPath = getCandidateBinaryPath(task);
3184
+ const corePath = getCandidateCorePath(task);
3185
+ const probeKind = getPwnProbeKind(replayableCommand, binaryPath, corePath);
3186
+ if (task.sessions.length > 0 || task.assets.some((asset) => {
3187
+ const normalized = asset.toLowerCase();
3188
+ return normalized.includes("shell:") || normalized.includes("stabilized_shell:") || normalized.includes("post_exploitation_shell:");
3189
+ })) {
3190
+ return {
3191
+ phase: "foothold_active",
3192
+ recommendation: "The pwn chain already produced execution. Reuse the existing foothold instead of restarting the exploit loop."
3193
+ };
3194
+ }
3195
+ if (evidence.includes("offset") || evidence.includes("pattern") || evidence.includes("eip") || evidence.includes("rip")) {
3196
+ return {
3197
+ phase: "offset_known",
3198
+ recommendation: "Offsets or control primitives are known. Resume from the latest payload iteration instead of rediscovering the crash.",
3199
+ boundedTool: "pwn_offset_check",
3200
+ boundedCommand: getBoundedPwnCommand(probeKind, replayableCommand, binaryPath, corePath),
3201
+ boundedTimeout: 5e3,
3202
+ boundedInstruction: probeKind === "core_gdb" ? "Run one bounded gdb register/backtrace check against the saved core state before changing the payload." : probeKind === "gdb_replay" ? "Run one bounded gdb replay step against the latest exploit revision before changing the payload." : "Run one bounded offset verification step against the latest exploit revision."
3203
+ };
3204
+ }
3205
+ if (evidence.includes("crash") || evidence.includes("segfault") || evidence.includes("core")) {
3206
+ return {
3207
+ phase: "crash_iteration",
3208
+ recommendation: "A crash state exists. Preserve it and continue the debug loop from the latest observed crash.",
3209
+ boundedTool: "pwn_crash_repro",
3210
+ boundedCommand: getBoundedPwnCommand(probeKind, replayableCommand, binaryPath, corePath),
3211
+ boundedTimeout: 1e4,
3212
+ boundedInstruction: probeKind === "core_gdb" ? "Inspect the saved core state once and preserve the exact crash context before changing the exploit loop." : probeKind === "gdb_replay" ? "Replay the latest gdb-driven crash once and preserve the exact crash state." : "Reproduce the latest crash once and preserve the exact crash state."
3213
+ };
3214
+ }
3215
+ return {
3216
+ phase: "payload_iteration",
3217
+ recommendation: "The pwn loop is still iterating payload design. Continue from the latest payload revision and observations.",
3218
+ boundedTool: "pwn_payload_smoke",
3219
+ boundedCommand: getBoundedPwnCommand(probeKind, replayableCommand, binaryPath, corePath),
3220
+ boundedTimeout: 5e3,
3221
+ boundedInstruction: probeKind === "gdb_replay" ? "Run one bounded gdb-guided smoke step from the latest payload revision." : "Run one bounded payload smoke test from the latest payload revision."
3222
+ };
3223
+ }
3224
+
3225
+ // src/agents/main-agent/delegated-task-handoff.ts
3226
+ function buildLifecycleSnapshot(decision) {
3227
+ const task = decision.task;
3228
+ if (decision.preferredWorkerType !== "shell-supervisor") {
3229
+ if (decision.preferredWorkerType === "exploit") {
3230
+ return getExploitLifecycleSnapshot(task);
3231
+ }
3232
+ if (decision.preferredWorkerType === "pwn") {
3233
+ return getPwnLifecycleSnapshot(task);
3234
+ }
3235
+ return null;
3236
+ }
3237
+ return getShellSupervisorLifecycleSnapshot();
3238
+ }
3239
+ function buildDelegatedRequestContext(decision, lifecycleSnapshot) {
3240
+ const task = decision.task;
3241
+ if (!lifecycleSnapshot) {
3242
+ return task.summary;
3243
+ }
3244
+ if (decision.preferredWorkerType === "exploit") {
3245
+ return [
3246
+ task.summary,
3247
+ `exploit_phase=${lifecycleSnapshot.phase}`,
3248
+ `recommendation=${lifecycleSnapshot.recommendation}`
3249
+ ].filter(Boolean).join(" | ");
2737
3250
  }
2738
- return toolRegistry.execute(singleCall);
3251
+ if (decision.preferredWorkerType === "pwn") {
3252
+ return [
3253
+ task.summary,
3254
+ `pwn_phase=${lifecycleSnapshot.phase}`,
3255
+ `recommendation=${lifecycleSnapshot.recommendation}`
3256
+ ].filter(Boolean).join(" | ");
3257
+ }
3258
+ const shellSnapshot = lifecycleSnapshot;
3259
+ return [
3260
+ task.summary,
3261
+ `shell_phase=${shellSnapshot.phase}`,
3262
+ shellSnapshot.listenerId ? `listener=${shellSnapshot.listenerId}` : "",
3263
+ shellSnapshot.activeShellId ? `active_shell=${shellSnapshot.activeShellId}` : "",
3264
+ `recommendation=${shellSnapshot.recommendation}`
3265
+ ].filter(Boolean).join(" | ");
2739
3266
  }
2740
- async function executeExploitMiniLoop(toolRegistry, request) {
2741
- return executeTwoStepLoop(
2742
- toolRegistry,
2743
- buildExploitPhaseRunTaskCall(request),
2744
- (firstResult) => buildExploitFollowupRunTaskCall(request, firstResult),
2745
- getExploitResultSignals
2746
- );
3267
+ function buildDelegatedExecutionRequest(decision, context, lifecycleSnapshot) {
3268
+ const task = decision.task;
3269
+ const preferredWorkerType = decision.preferredWorkerType;
3270
+ const requestTask = task.resumeHint || task.task;
3271
+ const boundedLifecycle = preferredWorkerType === "exploit" || preferredWorkerType === "pwn" ? lifecycleSnapshot : null;
3272
+ return {
3273
+ task: requestTask,
3274
+ workerType: preferredWorkerType,
3275
+ resumeTaskId: task.id,
3276
+ target: task.target,
3277
+ context,
3278
+ boundedTool: preferredWorkerType ? getRecommendedBoundedTool({
3279
+ task: requestTask,
3280
+ workerType: preferredWorkerType,
3281
+ target: task.target,
3282
+ context
3283
+ }) ?? void 0 : void 0,
3284
+ boundedCommand: boundedLifecycle?.boundedCommand,
3285
+ boundedTimeout: boundedLifecycle?.boundedTimeout,
3286
+ boundedInstruction: preferredWorkerType ? boundedLifecycle?.boundedInstruction || buildDelegatedExecutionPlan({
3287
+ task: requestTask,
3288
+ workerType: preferredWorkerType,
3289
+ target: task.target,
3290
+ context
3291
+ }) : void 0
3292
+ };
2747
3293
  }
2748
- async function executeExploitDirectBoundedLoop(toolRegistry, request) {
2749
- const boundedCall = buildBoundedDelegatedToolCall(request);
2750
- if (!boundedCall) {
2751
- return executeExploitMiniLoop(toolRegistry, request);
2752
- }
2753
- return executeTwoStepLoop(
2754
- toolRegistry,
2755
- boundedCall,
2756
- (firstResult) => buildExploitFollowupRunTaskCall(request, firstResult),
2757
- getExploitResultSignals
2758
- );
3294
+ function buildDelegatedTaskHandoff(decision) {
3295
+ const task = decision.task;
3296
+ const preferredWorkerType = decision.preferredWorkerType;
3297
+ const lifecycleSnapshot = buildLifecycleSnapshot(decision);
3298
+ const context = buildDelegatedRequestContext(decision, lifecycleSnapshot);
3299
+ const delegatedExecutionRequest = buildDelegatedExecutionRequest(decision, context, lifecycleSnapshot);
3300
+ const executionPlan = buildDelegatedExecutionPlan(delegatedExecutionRequest);
3301
+ const details = [
3302
+ `Resume delegated task: ${task.task}.`,
3303
+ `Delegated task ID: ${task.id}.`,
3304
+ `Scheduler reason: ${decision.reason}`,
3305
+ `Scheduler cycle count: ${decision.resumeCount + 1}.`,
3306
+ `Current status: ${task.status}.`,
3307
+ task.waitingOn ? `Waiting on: ${task.waitingOn}.` : "",
3308
+ task.assets.length > 0 ? `Reuse assets: ${task.assets.join(", ")}.` : "",
3309
+ task.sessions.length > 0 ? `Reuse sessions: ${task.sessions.join(", ")}.` : "",
3310
+ task.resumeHint ? `Resume guidance: ${task.resumeHint}.` : "",
3311
+ preferredWorkerType ? `Preferred worker: ${preferredWorkerType}.` : "",
3312
+ delegatedExecutionRequest.boundedTool ? `Bounded tool: ${delegatedExecutionRequest.boundedTool}.` : "",
3313
+ delegatedExecutionRequest.boundedCommand ? `Bounded command candidate: ${delegatedExecutionRequest.boundedCommand}.` : "",
3314
+ preferredWorkerType ? `Delegation policy: if this requires multi-step follow-up, call run_task with worker_type="${preferredWorkerType}" and resume_task_id="${task.id}" for this selected task before creating any unrelated delegated chain.` : "",
3315
+ `Execution hint: ${executionPlan}`,
3316
+ "Execution policy: continue the selected delegated chain first. Do not switch to a different active delegated task until this one is advanced or invalidated.",
3317
+ "Goal: continue the existing chain instead of creating a duplicate operation."
3318
+ ].filter(Boolean);
3319
+ return {
3320
+ shouldForwardToMain: true,
3321
+ forwardedInput: details.join(" "),
3322
+ directResponse: "",
3323
+ shouldWritePolicy: false,
3324
+ policyDocument: "",
3325
+ policyUpdateSummary: "",
3326
+ insightSummary: `Auto-resume delegated task ${task.id} via handoff builder.`,
3327
+ delegatedExecutionRequest,
3328
+ success: true
3329
+ };
2759
3330
  }
2760
- async function executePwnMiniLoop(toolRegistry, request) {
2761
- return executeTwoStepLoop(
2762
- toolRegistry,
2763
- buildPwnPhaseRunTaskCall(request),
2764
- (firstResult) => buildPwnFollowupRunTaskCall(request, firstResult),
2765
- getPwnResultSignals
2766
- );
3331
+
3332
+ // src/agents/main-agent/user-input-runtime.ts
3333
+ function collectPendingUserInputs(userInputQueue, pendingInitialUserInput) {
3334
+ const drained = userInputQueue.drain();
3335
+ return [
3336
+ ...pendingInitialUserInput ? [pendingInitialUserInput] : [],
3337
+ ...drained.map((item) => item.text)
3338
+ ].map((text) => text.trim()).filter(Boolean);
2767
3339
  }
2768
- async function executePwnDirectBoundedLoop(toolRegistry, request) {
2769
- const boundedCall = buildBoundedDelegatedToolCall(request);
2770
- if (!boundedCall) {
2771
- return executePwnMiniLoop(toolRegistry, request);
2772
- }
2773
- return executeTwoStepLoop(
2774
- toolRegistry,
2775
- boundedCall,
2776
- (firstResult) => buildPwnFollowupRunTaskCall(request, firstResult),
2777
- getPwnResultSignals
2778
- );
3340
+ function appendUserInput(existing, next) {
3341
+ return existing.trim() === "" ? next : `${existing}
3342
+
3343
+ ${next}`;
2779
3344
  }
2780
- async function executeTwoStepLoop(toolRegistry, firstCall, buildFollowupCall, getSignals) {
2781
- const firstResult = await toolRegistry.execute(firstCall);
2782
- if (!firstResult.success) {
2783
- return firstResult;
2784
- }
2785
- const followupCall = buildFollowupCall(firstResult);
2786
- if (!followupCall || !getSignals(firstResult).indicatesProgress) {
2787
- return firstResult;
3345
+ function normalizeInputProcessorResult(result, fallbackInput) {
3346
+ if (!result.success) {
3347
+ return {
3348
+ shouldForwardToMain: true,
3349
+ forwardedInput: fallbackInput,
3350
+ directResponse: "",
3351
+ shouldWritePolicy: false,
3352
+ policyDocument: "",
3353
+ policyUpdateSummary: "",
3354
+ insightSummary: "Input processor fallback: forwarded raw input.",
3355
+ success: false
3356
+ };
2788
3357
  }
2789
- const followupResult = await toolRegistry.execute(followupCall);
2790
- return combineToolResults([firstResult, followupResult]);
3358
+ return {
3359
+ ...result,
3360
+ forwardedInput: result.forwardedInput.trim() || fallbackInput,
3361
+ directResponse: result.directResponse.trim(),
3362
+ policyDocument: result.policyDocument.trim(),
3363
+ policyUpdateSummary: result.policyUpdateSummary.trim(),
3364
+ insightSummary: result.insightSummary.trim()
3365
+ };
2791
3366
  }
2792
- var DelegatedAutoExecutor = class {
2793
- canExecutePending(runtime) {
2794
- return runtime.canAutoExecute() && shouldAutoExecuteDelegatedRequest(runtime.peek());
3367
+ function buildAutoResumeResult(state, delegatedTaskQueue) {
3368
+ const activeTasks = state.getActiveDelegatedTasks();
3369
+ const decision = delegatedTaskQueue.next(activeTasks);
3370
+ if (!decision) {
3371
+ return null;
2795
3372
  }
2796
- async executePending(runtime, toolRegistry) {
2797
- if (!toolRegistry) {
2798
- return null;
2799
- }
2800
- const request = runtime.peek();
2801
- if (!request || !this.canExecutePending(runtime)) {
2802
- return null;
2803
- }
2804
- runtime.markAutoExecutionAttempt();
2805
- const result = request.workerType === "shell-supervisor" ? await executeShellSupervisorMiniLoop(toolRegistry) || await toolRegistry.execute(buildDelegatedRunTaskCall(request)) : request.workerType === "exploit" ? await executeExploitDirectBoundedLoop(toolRegistry, request) : request.workerType === "pwn" ? await executePwnDirectBoundedLoop(toolRegistry, request) : await toolRegistry.execute(buildDelegatedRunTaskCall(request));
2806
- runtime.setLastExecutionResult(result);
2807
- if (result.success) {
2808
- runtime.consume();
2809
- }
2810
- return result;
3373
+ delegatedTaskQueue.acknowledge(decision.task.id);
3374
+ return buildDelegatedTaskHandoff(decision);
3375
+ }
3376
+ function buildQueueSnapshot(userInputQueue) {
3377
+ return {
3378
+ count: userInputQueue.pendingCount(),
3379
+ preview: userInputQueue.peek().map((item) => item.text)
3380
+ };
3381
+ }
3382
+
3383
+ // src/agents/main-agent/queue-facade.ts
3384
+ function emitMainAgentQueueUpdated(events, userInputQueue) {
3385
+ events.emit({
3386
+ type: EVENT_TYPES.QUEUE_UPDATED,
3387
+ timestamp: Date.now(),
3388
+ data: buildQueueSnapshot(userInputQueue)
3389
+ });
3390
+ }
3391
+ function enqueueMainAgentUserInput(userInputQueue, events, text) {
3392
+ userInputQueue.enqueue(text);
3393
+ emitMainAgentQueueUpdated(events, userInputQueue);
3394
+ }
3395
+ function dequeueMainAgentUserInput(userInputQueue, events) {
3396
+ const value = userInputQueue.dequeueLast();
3397
+ emitMainAgentQueueUpdated(events, userInputQueue);
3398
+ return value;
3399
+ }
3400
+ function getMainAgentPendingUserInputPreview(userInputQueue) {
3401
+ return userInputQueue.peek().map((item) => item.text);
3402
+ }
3403
+
3404
+ // src/agents/main-agent/session-mutations.ts
3405
+ async function resetMainAgentSession(state, userInputQueue) {
3406
+ return resetSessionAction(state, userInputQueue);
3407
+ }
3408
+ function loadMainAgentSession(state) {
3409
+ return session.load(state);
3410
+ }
3411
+ function saveMainAgentSession(state) {
3412
+ return session.save(state);
3413
+ }
3414
+ function applyMainAgentScope(state, allowed, exclusions = []) {
3415
+ state.setScope({
3416
+ allowedCidrs: allowed.filter((a) => a.includes("/")),
3417
+ allowedDomains: allowed.filter((a) => !a.includes("/")),
3418
+ exclusions,
3419
+ isDOSAllowed: false,
3420
+ isSocialAllowed: false
3421
+ });
3422
+ }
3423
+ function addMainAgentTarget(state, events, ip) {
3424
+ state.addTarget({ ip, ports: [], tags: [], firstSeen: Date.now(), hostname: "" });
3425
+ emitStateChange(events, state);
3426
+ }
3427
+
3428
+ // src/agents/main-agent/delegated-execution-facade.ts
3429
+ function resetDelegatedExecutionState(delegatedExecutionRuntime) {
3430
+ delegatedExecutionRuntime.reset();
3431
+ }
3432
+ function setDelegatedExecutionRequest(delegatedExecutionRuntime, request) {
3433
+ delegatedExecutionRuntime.set(request);
3434
+ }
3435
+ function buildDelegatedPromptFragments(delegatedExecutionRuntime) {
3436
+ return {
3437
+ request: delegatedExecutionRuntime.toPromptFragment(),
3438
+ result: delegatedExecutionRuntime.toResultFragment()
3439
+ };
3440
+ }
3441
+ function getDelegatedExecutionRequest(delegatedExecutionRuntime) {
3442
+ return delegatedExecutionRuntime.peek();
3443
+ }
3444
+ function consumeDelegatedExecutionRequest(delegatedExecutionRuntime) {
3445
+ return delegatedExecutionRuntime.consume();
3446
+ }
3447
+ async function executePendingDelegatedRequest(delegatedAutoExecutor, delegatedExecutionRuntime, toolRegistry) {
3448
+ return delegatedAutoExecutor.executePending(delegatedExecutionRuntime, toolRegistry);
3449
+ }
3450
+ async function maybeAutoExecuteDelegatedRequest(delegatedAutoExecutor, delegatedExecutionRuntime, toolRegistry) {
3451
+ if (!delegatedAutoExecutor.canExecutePending(delegatedExecutionRuntime)) {
3452
+ return null;
2811
3453
  }
2812
- };
3454
+ return executePendingDelegatedRequest(
3455
+ delegatedAutoExecutor,
3456
+ delegatedExecutionRuntime,
3457
+ toolRegistry
3458
+ );
3459
+ }
2813
3460
 
2814
3461
  // src/agents/main-agent/main-agent.ts
2815
3462
  var MainAgent = class extends CoreAgent {
@@ -2841,7 +3488,7 @@ var MainAgent = class extends CoreAgent {
2841
3488
  this.inputProcessor = createInputProcessor(this.llm);
2842
3489
  this.sessionRuntime = createSessionRuntime();
2843
3490
  setActiveSessionRuntime(this.sessionRuntime);
2844
- this.turnCyclePipeline = loadPipelineFromConfig(getPipelineConfig(), {
3491
+ this.turnCyclePipeline = loadPipelineFromConfig(getRuntimePipelineConfig(), {
2845
3492
  llm: this.llm,
2846
3493
  conditions: getConditionRegistry(),
2847
3494
  key: "turn_cycle"
@@ -2852,7 +3499,7 @@ var MainAgent = class extends CoreAgent {
2852
3499
  this.userInput = "";
2853
3500
  this.pendingInitialUserInput = userInput;
2854
3501
  this.delegatedTaskQueue.reset();
2855
- this.delegatedExecutionRuntime.reset();
3502
+ resetDelegatedExecutionState(this.delegatedExecutionRuntime);
2856
3503
  emitStart(this.events, userInput, this.state);
2857
3504
  initializeTask(this.state);
2858
3505
  try {
@@ -2861,7 +3508,7 @@ var MainAgent = class extends CoreAgent {
2861
3508
  return result.output;
2862
3509
  } finally {
2863
3510
  try {
2864
- session.save(this.state);
3511
+ saveMainAgentSession(this.state);
2865
3512
  } catch {
2866
3513
  }
2867
3514
  await cleanupAllProcesses();
@@ -2896,10 +3543,10 @@ var MainAgent = class extends CoreAgent {
2896
3543
  };
2897
3544
  }
2898
3545
  async processUserInputTurn() {
2899
- const messages = this.collectPendingUserInputs();
3546
+ const messages = collectPendingUserInputs(this.userInputQueue, this.pendingInitialUserInput);
2900
3547
  this.pendingInitialUserInput = null;
2901
3548
  if (messages.length === 0) {
2902
- const autoResume = this.buildAutoResumeResult();
3549
+ const autoResume = buildAutoResumeResult(this.state, this.delegatedTaskQueue);
2903
3550
  if (autoResume) {
2904
3551
  this.updateObjectiveFromInputProcessor(autoResume);
2905
3552
  await this.maybeAutoExecuteDelegatedRequest();
@@ -2914,11 +3561,11 @@ var MainAgent = class extends CoreAgent {
2914
3561
  hasActiveEngagement: this.state.hasActiveEngagement(),
2915
3562
  currentObjective: this.state.currentObjective || ""
2916
3563
  });
2917
- const normalized = this.normalizeInputProcessorResult(result, rawInput);
3564
+ const normalized = normalizeInputProcessorResult(result, rawInput);
2918
3565
  this.updatePolicyFromInputProcessor(normalized);
2919
3566
  this.updateObjectiveFromInputProcessor(normalized);
2920
3567
  this.events.emit({ type: EVENT_TYPES.QUEUE_DRAINED, timestamp: Date.now() });
2921
- this.emitQueueUpdated();
3568
+ emitMainAgentQueueUpdated(this.events, this.userInputQueue);
2922
3569
  return normalized;
2923
3570
  }
2924
3571
  updatePolicyFromInputProcessor(result) {
@@ -2927,82 +3574,39 @@ var MainAgent = class extends CoreAgent {
2927
3574
  }
2928
3575
  }
2929
3576
  updateObjectiveFromInputProcessor(result) {
2930
- this.delegatedExecutionRuntime.set(result.delegatedExecutionRequest);
3577
+ setDelegatedExecutionRequest(this.delegatedExecutionRuntime, result.delegatedExecutionRequest);
2931
3578
  if (result.shouldForwardToMain && result.forwardedInput.trim()) {
2932
- this.userInput = this.appendUserInput(this.userInput, result.forwardedInput);
3579
+ this.userInput = appendUserInput(this.userInput, result.forwardedInput);
2933
3580
  if (!this.state.hasActiveEngagement()) {
2934
3581
  this.state.currentObjective = result.forwardedInput;
2935
3582
  }
2936
3583
  }
2937
3584
  }
2938
- normalizeInputProcessorResult(result, fallbackInput) {
2939
- if (!result.success) {
2940
- return {
2941
- shouldForwardToMain: true,
2942
- forwardedInput: fallbackInput,
2943
- directResponse: "",
2944
- shouldWritePolicy: false,
2945
- policyDocument: "",
2946
- policyUpdateSummary: "",
2947
- insightSummary: "Input processor fallback: forwarded raw input.",
2948
- success: false
2949
- };
2950
- }
2951
- return {
2952
- ...result,
2953
- forwardedInput: result.forwardedInput.trim() || fallbackInput,
2954
- directResponse: result.directResponse.trim(),
2955
- policyDocument: result.policyDocument.trim(),
2956
- policyUpdateSummary: result.policyUpdateSummary.trim(),
2957
- insightSummary: result.insightSummary.trim()
2958
- };
2959
- }
2960
- collectPendingUserInputs() {
2961
- const drained = this.userInputQueue.drain();
2962
- return [
2963
- ...this.pendingInitialUserInput ? [this.pendingInitialUserInput] : [],
2964
- ...drained.map((item) => item.text)
2965
- ].map((text) => text.trim()).filter(Boolean);
2966
- }
2967
- appendUserInput(existing, next) {
2968
- return existing.trim() === "" ? next : `${existing}
2969
-
2970
- ${next}`;
2971
- }
2972
- buildAutoResumeResult() {
2973
- const activeTasks = this.state.getActiveDelegatedTasks();
2974
- const decision = this.delegatedTaskQueue.next(activeTasks);
2975
- if (!decision) {
2976
- return null;
2977
- }
2978
- this.delegatedTaskQueue.acknowledge(decision.task.id);
2979
- return buildDelegatedTaskHandoff(decision);
2980
- }
2981
3585
  async buildDynamicPrompt(memory) {
2982
- const basePrompt = await this.promptBuilder.build(
3586
+ const delegatedExecution = buildDelegatedPromptFragments(this.delegatedExecutionRuntime);
3587
+ return buildMainAgentPrompt(
3588
+ this.promptBuilder,
3589
+ this.state,
2983
3590
  this.userInput,
2984
- this.state.getPhase() || PHASES.RECON,
3591
+ delegatedExecution,
2985
3592
  memory
2986
3593
  );
2987
- const delegatedExecutionRequest = this.delegatedExecutionRuntime.toPromptFragment();
2988
- const delegatedExecutionResult = this.delegatedExecutionRuntime.toResultFragment();
2989
- return [basePrompt, delegatedExecutionRequest, delegatedExecutionResult].filter(Boolean).join("\n\n");
2990
3594
  }
2991
3595
  // ─── Public API ────────────────────────────────────────────────────────────
2992
3596
  loadPreviousSession() {
2993
- return session.load(this.state);
3597
+ return loadMainAgentSession(this.state);
2994
3598
  }
2995
3599
  saveCurrentState() {
2996
- return session.save(this.state);
3600
+ return saveMainAgentSession(this.state);
2997
3601
  }
2998
3602
  async resetSession() {
2999
- const result = await resetSessionAction(this.state, this.userInputQueue);
3603
+ const result = await resetMainAgentSession(this.state, this.userInputQueue);
3000
3604
  this.userInput = "";
3001
3605
  this.delegatedTaskQueue.reset();
3002
- this.delegatedExecutionRuntime.reset();
3606
+ resetDelegatedExecutionState(this.delegatedExecutionRuntime);
3003
3607
  return result;
3004
3608
  }
3005
- setAutoApprove(shouldEnable) {
3609
+ setToolAutoApprove(shouldEnable) {
3006
3610
  this.approvalGate.setAutoApprove(shouldEnable);
3007
3611
  }
3008
3612
  getState() {
@@ -3018,78 +3622,62 @@ ${next}`;
3018
3622
  return this.sessionRuntime;
3019
3623
  }
3020
3624
  getLastDelegatedExecutionRequest() {
3021
- return this.delegatedExecutionRuntime.peek();
3625
+ return getDelegatedExecutionRequest(this.delegatedExecutionRuntime);
3022
3626
  }
3023
3627
  consumeDelegatedExecutionRequest() {
3024
- return this.delegatedExecutionRuntime.consume();
3628
+ return consumeDelegatedExecutionRequest(this.delegatedExecutionRuntime);
3025
3629
  }
3026
3630
  async executePendingDelegatedRequest() {
3027
- return this.delegatedAutoExecutor.executePending(this.delegatedExecutionRuntime, this.toolRegistry);
3631
+ return executePendingDelegatedRequest(
3632
+ this.delegatedAutoExecutor,
3633
+ this.delegatedExecutionRuntime,
3634
+ this.toolRegistry
3635
+ );
3028
3636
  }
3029
3637
  async maybeAutoExecuteDelegatedRequest() {
3030
- if (!this.delegatedAutoExecutor.canExecutePending(this.delegatedExecutionRuntime)) {
3031
- return null;
3032
- }
3033
- const result = await this.executePendingDelegatedRequest();
3034
- return result;
3638
+ return maybeAutoExecuteDelegatedRequest(
3639
+ this.delegatedAutoExecutor,
3640
+ this.delegatedExecutionRuntime,
3641
+ this.toolRegistry
3642
+ );
3035
3643
  }
3036
- setScope(allowed, exclusions = []) {
3037
- this.state.setScope({
3038
- allowedCidrs: allowed.filter((a) => a.includes("/")),
3039
- allowedDomains: allowed.filter((a) => !a.includes("/")),
3040
- exclusions,
3041
- isDOSAllowed: false,
3042
- isSocialAllowed: false
3043
- });
3644
+ configureTarget(ip, exclusions = []) {
3645
+ addMainAgentTarget(this.state, this.events, ip);
3646
+ applyMainAgentScope(this.state, [ip], exclusions);
3044
3647
  }
3045
3648
  addTarget(ip) {
3046
- this.state.addTarget({ ip, ports: [], tags: [], firstSeen: Date.now(), hostname: "" });
3047
- emitStateChange(this.events, this.state);
3649
+ addMainAgentTarget(this.state, this.events, ip);
3650
+ }
3651
+ setScope(allowed, exclusions = []) {
3652
+ applyMainAgentScope(this.state, allowed, exclusions);
3048
3653
  }
3049
3654
  enqueueUserInput(text) {
3050
- this.userInputQueue.enqueue(text);
3051
- this.emitQueueUpdated();
3655
+ enqueueMainAgentUserInput(this.userInputQueue, this.events, text);
3052
3656
  }
3053
3657
  dequeueLastUserInput() {
3054
- const value = this.userInputQueue.dequeueLast();
3055
- this.emitQueueUpdated();
3056
- return value;
3658
+ return dequeueMainAgentUserInput(this.userInputQueue, this.events);
3057
3659
  }
3058
3660
  hasPendingUserInput() {
3059
3661
  return this.userInputQueue.hasPending();
3060
3662
  }
3061
- getPendingUserInputCount() {
3062
- return this.userInputQueue.pendingCount();
3063
- }
3064
3663
  getPendingUserInputPreview() {
3065
- return this.userInputQueue.peek().map((item) => item.text);
3066
- }
3067
- emitQueueUpdated() {
3068
- this.events.emit({
3069
- type: EVENT_TYPES.QUEUE_UPDATED,
3070
- timestamp: Date.now(),
3071
- data: {
3072
- count: this.getPendingUserInputCount(),
3073
- preview: this.getPendingUserInputPreview()
3074
- }
3075
- });
3664
+ return getMainAgentPendingUserInputPreview(this.userInputQueue);
3076
3665
  }
3077
3666
  };
3078
3667
 
3079
- // src/engine/yaml-runtime.ts
3668
+ // src/engine/agent-runtime.ts
3080
3669
  import fs from "fs";
3081
- import path2 from "path";
3082
- var YamlRuntime = class _YamlRuntime {
3670
+ import path from "path";
3671
+ var AgentRuntime = class _AgentRuntime {
3083
3672
  static build(options) {
3084
- const cfg = getPipelineConfig();
3085
- _YamlRuntime.setupWorkspace(cfg.workspace);
3673
+ _AgentRuntime.setupWorkspace(getWorkspaceConfig());
3086
3674
  return new MainAgent(options);
3087
3675
  }
3088
3676
  static setupWorkspace(workspaceCfg) {
3089
3677
  const directories = workspaceCfg?.directories ?? {};
3090
- for (const [key, dirPath] of Object.entries(directories)) {
3678
+ for (const dirPath of Object.values(directories)) {
3091
3679
  if (dirPath === "DEPRECATED") continue;
3092
- const resolved = path2.resolve(process.cwd(), dirPath);
3680
+ const resolved = path.resolve(process.cwd(), dirPath);
3093
3681
  if (!fs.existsSync(resolved)) {
3094
3682
  fs.mkdirSync(resolved, { recursive: true });
3095
3683
  }
@@ -3098,11 +3686,48 @@ var YamlRuntime = class _YamlRuntime {
3098
3686
  }
3099
3687
  };
3100
3688
 
3689
+ // src/platform/tui/cli/command-runtime.ts
3690
+ import chalk from "chalk";
3691
+ function ignoreCleanupFailure() {
3692
+ }
3693
+ async function cleanupCliProcesses() {
3694
+ await cleanupAllProcesses().catch(ignoreCleanupFailure);
3695
+ }
3696
+ function printAutoApproveWarning(options = {}) {
3697
+ if (options.includeHeader) {
3698
+ console.log(chalk.hex(HEX.red)("[!] WARNING: Running with --dangerously-skip-permissions"));
3699
+ }
3700
+ console.log(chalk.hex(HEX.red)("[!] Strict approval mode will be bypassed by enabling tool auto-approve.\n"));
3701
+ }
3702
+ function registerShutdownSignals(shutdown) {
3703
+ process.on("SIGINT", () => shutdown(EXIT_CODES.SIGINT));
3704
+ process.on("SIGTERM", () => shutdown(EXIT_CODES.SIGTERM));
3705
+ }
3706
+ async function writeJsonReport(outputPath, result) {
3707
+ const fs2 = await import("fs/promises");
3708
+ const { dirname } = await import("path");
3709
+ const outputDir = dirname(outputPath);
3710
+ if (outputDir !== ".") {
3711
+ await fs2.mkdir(outputDir, { recursive: true }).catch(ignoreCleanupFailure);
3712
+ }
3713
+ await fs2.writeFile(outputPath, JSON.stringify({ result }, null, 2));
3714
+ }
3715
+
3716
+ // src/platform/tui/cli/interactive-runtime.tsx
3717
+ import React16 from "react";
3718
+ import { render } from "ink";
3719
+
3720
+ // src/platform/tui/app.tsx
3721
+ import { Box as Box18 } from "ink";
3722
+
3723
+ // src/platform/tui/hooks/useAgent.ts
3724
+ import { useState as useState6, useEffect as useEffect2, useCallback as useCallback6, useRef as useRef6 } from "react";
3725
+
3101
3726
  // src/agents/factory.ts
3102
- function createMainAgent(shouldAutoApprove = false) {
3727
+ function createMainAgent(autoApproveTools = false) {
3103
3728
  const state = new SharedState();
3104
3729
  const events = new AgentEventEmitter();
3105
- const approvalGate = new ApprovalGate(shouldAutoApprove);
3730
+ const approvalGate = new ApprovalGate(autoApproveTools);
3106
3731
  const scopeGuard = new ScopeGuard(state);
3107
3732
  const toolRegistry = new CategorizedToolRegistry(
3108
3733
  state,
@@ -3110,7 +3735,7 @@ function createMainAgent(shouldAutoApprove = false) {
3110
3735
  approvalGate,
3111
3736
  events
3112
3737
  );
3113
- return YamlRuntime.build({ state, events, toolRegistry, approvalGate, scopeGuard });
3738
+ return AgentRuntime.build({ state, events, toolRegistry, approvalGate, scopeGuard });
3114
3739
  }
3115
3740
 
3116
3741
  // src/platform/tui/hooks/useAgentState.ts
@@ -4289,8 +4914,7 @@ var useAgent = (shouldAutoApprove, target, isTyping = false) => {
4289
4914
  }, [messageQueue.length]);
4290
4915
  useEffect2(() => {
4291
4916
  if (target) {
4292
- agent.addTarget(target);
4293
- agent.setScope([target]);
4917
+ agent.configureTarget(target);
4294
4918
  }
4295
4919
  }, [agent, target]);
4296
4920
  useEffect2(() => {
@@ -4516,8 +5140,7 @@ var createTargetCommands = (ctx) => {
4516
5140
  await ctx.agent.resetSession();
4517
5141
  ctx.addMessage("system", UI_STATUS_MESSAGES.TARGET_CLEARED);
4518
5142
  }
4519
- ctx.agent.addTarget(args[0]);
4520
- ctx.agent.setScope([args[0]]);
5143
+ ctx.agent.configureTarget(args[0]);
4521
5144
  ctx.addMessage("system", `${UI_STATUS_MESSAGES.TARGET_SET_PREFIX}${args[0]}`);
4522
5145
  };
4523
5146
  const handleStart = async (args) => {
@@ -4527,7 +5150,7 @@ var createTargetCommands = (ctx) => {
4527
5150
  }
4528
5151
  if (!ctx.autoApproveModeRef.current) {
4529
5152
  ctx.setAutoApproveMode(true);
4530
- ctx.agent.setAutoApprove(true);
5153
+ ctx.agent.setToolAutoApprove(true);
4531
5154
  ctx.addMessage("system", UI_STATUS_MESSAGES.AUTONOMOUS_MODE_ENABLED);
4532
5155
  }
4533
5156
  ctx.addMessage("system", UI_STATUS_MESSAGES.STARTING_PENTEST);
@@ -4927,7 +5550,7 @@ var createToggleCommands = (ctx) => ({
4927
5550
  [UI_COMMANDS.AUTO]: () => {
4928
5551
  ctx.setAutoApproveMode((prev) => {
4929
5552
  const newVal = !prev;
4930
- ctx.agent.setAutoApprove(newVal);
5553
+ ctx.agent.setToolAutoApprove(newVal);
4931
5554
  ctx.addMessage("system", newVal ? UI_STATUS_MESSAGES.AUTO_APPROVE_ON : UI_STATUS_MESSAGES.AUTO_APPROVE_OFF);
4932
5555
  return newVal;
4933
5556
  });
@@ -7736,9 +8359,9 @@ var SplashScreen = ({
7736
8359
  );
7737
8360
  };
7738
8361
 
7739
- // src/platform/tui/cli/commands/interactive.tsx
8362
+ // src/platform/tui/cli/interactive-runtime.tsx
7740
8363
  import { jsx as jsx24 } from "react/jsx-runtime";
7741
- var Root = ({ skipPermissions, target }) => {
8364
+ var InteractiveRoot = ({ autoApprove, target }) => {
7742
8365
  const [showSplash, setShowSplash] = React16.useState(true);
7743
8366
  if (showSplash) {
7744
8367
  return /* @__PURE__ */ jsx24(SplashScreen, { durationMs: 3e3, onComplete: () => setShowSplash(false) });
@@ -7746,65 +8369,62 @@ var Root = ({ skipPermissions, target }) => {
7746
8369
  return /* @__PURE__ */ jsx24(
7747
8370
  app_default,
7748
8371
  {
7749
- autoApprove: skipPermissions,
8372
+ autoApprove,
7750
8373
  target
7751
8374
  }
7752
8375
  );
7753
8376
  };
7754
- async function interactiveAction(options) {
7755
- const { dangerouslySkipPermissions: skipPermissions = false, target } = options;
7756
- console.clear();
7757
- if (skipPermissions) {
7758
- console.log(chalk.hex(HEX.red)("[!] WARNING: Running with --dangerously-skip-permissions"));
7759
- console.log(chalk.hex(HEX.red)("[!] All tool executions will be auto-approved!\n"));
7760
- }
8377
+ async function renderInteractiveApp(props) {
7761
8378
  const { waitUntilExit } = render(
7762
- /* @__PURE__ */ jsx24(AnimationProvider, { children: /* @__PURE__ */ jsx24(Root, { skipPermissions, target }) })
8379
+ /* @__PURE__ */ jsx24(AnimationProvider, { children: /* @__PURE__ */ jsx24(InteractiveRoot, { ...props }) })
7763
8380
  );
7764
8381
  await waitUntilExit();
7765
8382
  }
7766
8383
 
8384
+ // src/platform/tui/cli/commands/interactive.tsx
8385
+ async function interactiveAction(options) {
8386
+ const { dangerouslySkipPermissions: autoApproveTools = false, target } = options;
8387
+ console.clear();
8388
+ if (autoApproveTools) {
8389
+ printAutoApproveWarning({ includeHeader: true });
8390
+ }
8391
+ await renderInteractiveApp({
8392
+ autoApprove: autoApproveTools,
8393
+ target
8394
+ });
8395
+ }
8396
+
7767
8397
  // src/platform/tui/cli/commands/run.ts
7768
8398
  import chalk2 from "chalk";
7769
8399
  async function runAction(objective, options) {
7770
- const skipPermissions = options.dangerouslySkipPermissions || false;
7771
- if (skipPermissions) {
7772
- console.log(chalk2.hex(HEX.red)("[!] WARNING: Running with --dangerously-skip-permissions\n"));
8400
+ const autoApproveTools = options.dangerouslySkipPermissions || false;
8401
+ if (autoApproveTools) {
8402
+ printAutoApproveWarning({ includeHeader: true });
7773
8403
  }
7774
8404
  console.log(chalk2.hex(HEX.primary)(`[target] Objective: ${objective}
7775
8405
  `));
7776
- const agent = createMainAgent(skipPermissions);
7777
- if (skipPermissions) {
7778
- agent.setAutoApprove(true);
8406
+ const agent = createMainAgent(autoApproveTools, options.maxSteps);
8407
+ if (autoApproveTools) {
8408
+ agent.setToolAutoApprove(true);
7779
8409
  }
7780
8410
  if (options.target) {
7781
- agent.addTarget(options.target);
7782
- agent.setScope([options.target]);
8411
+ agent.configureTarget(options.target);
7783
8412
  }
7784
8413
  const shutdown = async (exitCode = 0) => {
7785
- await cleanupAllProcesses().catch(() => {
7786
- });
8414
+ await cleanupCliProcesses();
7787
8415
  const reqs = getGlobalRequestCount();
7788
8416
  const usage = getGlobalTokenUsage();
7789
8417
  console.log(chalk2.hex(HEX.gray)(`
7790
8418
  [Session Summary] Requests: ${reqs} | In: ${usage.input_tokens} | Out: ${usage.output_tokens}`));
7791
8419
  process.exit(exitCode);
7792
8420
  };
7793
- process.on("SIGINT", () => shutdown(EXIT_CODES.SIGINT));
7794
- process.on("SIGTERM", () => shutdown(EXIT_CODES.SIGTERM));
8421
+ registerShutdownSignals(shutdown);
7795
8422
  try {
7796
8423
  const result = await agent.execute(objective);
7797
8424
  console.log(chalk2.hex(HEX.gray)("\n[+] Assessment complete!\n"));
7798
8425
  console.log(result);
7799
8426
  if (options.output) {
7800
- const fs2 = await import("fs/promises");
7801
- const { dirname } = await import("path");
7802
- const outputDir = dirname(options.output);
7803
- if (outputDir && outputDir !== ".") {
7804
- await fs2.mkdir(outputDir, { recursive: true }).catch(() => {
7805
- });
7806
- }
7807
- await fs2.writeFile(options.output, JSON.stringify({ result }, null, 2));
8427
+ await writeJsonReport(options.output, result);
7808
8428
  console.log(chalk2.hex(HEX.primary)(`
7809
8429
  [+] Report saved to: ${options.output}`));
7810
8430
  }
@@ -7820,20 +8440,20 @@ async function runAction(objective, options) {
7820
8440
  // src/platform/tui/cli/commands/scan.ts
7821
8441
  import chalk3 from "chalk";
7822
8442
  async function scanAction(target, options) {
7823
- const skipPermissions = options.dangerouslySkipPermissions || false;
8443
+ const autoApproveTools = options.dangerouslySkipPermissions || false;
7824
8444
  console.log(chalk3.hex(HEX.primary)(`
7825
8445
  [scan] Target: ${target} (${options.scanType})
7826
8446
  `));
7827
- const agent = createMainAgent(skipPermissions);
7828
- agent.addTarget(target);
7829
- agent.setScope([target]);
8447
+ if (autoApproveTools) {
8448
+ printAutoApproveWarning();
8449
+ }
8450
+ const agent = createMainAgent(autoApproveTools);
8451
+ agent.configureTarget(target);
7830
8452
  const shutdown = async (exitCode = 0) => {
7831
- await cleanupAllProcesses().catch(() => {
7832
- });
8453
+ await cleanupCliProcesses();
7833
8454
  process.exit(exitCode);
7834
8455
  };
7835
- process.on("SIGINT", () => shutdown(EXIT_CODES.SIGINT));
7836
- process.on("SIGTERM", () => shutdown(EXIT_CODES.SIGTERM));
8456
+ registerShutdownSignals(shutdown);
7837
8457
  try {
7838
8458
  await agent.execute(`Perform a ${options.scanType} scan on ${target}${options.ports ? ` focusing on ports ${options.ports}` : ""}. Analyze the results and identify potential vulnerabilities.`);
7839
8459
  console.log(chalk3.hex(HEX.gray)("[+] Scan complete!"));
@@ -7855,7 +8475,7 @@ ${chalk4.hex(HEX.primary)(APP_NAME + " - Autonomous Penetration Testing AI")}
7855
8475
 
7856
8476
  ${chalk4.hex(HEX.gray)("$ pentesting")} Start interactive mode
7857
8477
  ${chalk4.hex(HEX.gray)("$ pentesting -t 192.168.1.1")} Start with target
7858
- ${chalk4.hex(HEX.gray)("$ pentesting --dangerously-skip-permissions")} Auto-approve all tools
8478
+ ${chalk4.hex(HEX.gray)("$ pentesting --dangerously-skip-permissions")} Enable tool auto-approve in strict mode
7859
8479
 
7860
8480
  ${chalk4.hex(HEX.yellow)("Commands:")}
7861
8481
 
@@ -7865,7 +8485,7 @@ ${chalk4.hex(HEX.yellow)("Commands:")}
7865
8485
 
7866
8486
  ${chalk4.hex(HEX.yellow)("Options:")}
7867
8487
 
7868
- ${chalk4.hex(HEX.primary)("--dangerously-skip-permissions")} Skip all permission prompts
8488
+ ${chalk4.hex(HEX.primary)("--dangerously-skip-permissions")} Bypass strict approval mode by auto-approving tools
7869
8489
  ${chalk4.hex(HEX.primary)("-t, --target <ip>")} Set target
7870
8490
  ${chalk4.hex(HEX.primary)("-o, --output <file>")} Save results to file
7871
8491
 
@@ -7896,10 +8516,20 @@ ${chalk4.hex(HEX.yellow)("Environment:")}
7896
8516
  `);
7897
8517
  }
7898
8518
 
8519
+ // src/platform/tui/cli/args.ts
8520
+ import { InvalidArgumentError } from "commander";
8521
+ function parsePositiveInt(value) {
8522
+ const parsed = Number.parseInt(value, 10);
8523
+ if (!Number.isInteger(parsed) || parsed <= 0) {
8524
+ throw new InvalidArgumentError("max-steps must be a positive integer");
8525
+ }
8526
+ return parsed;
8527
+ }
8528
+
7899
8529
  // src/platform/tui/cli/program.ts
7900
8530
  function createProgram() {
7901
8531
  const program2 = new Command();
7902
- program2.name("pentesting").version(APP_VERSION).description(APP_DESCRIPTION).option("--dangerously-skip-permissions", "Skip all permission prompts (dangerous!)").option("-t, --target <target>", "Set initial target");
8532
+ program2.name("pentesting").version(APP_VERSION).description(APP_DESCRIPTION).option("--dangerously-skip-permissions", "Enable auto-approve for tool execution in strict approval mode (dangerous!)").option("-t, --target <target>", "Set initial target");
7903
8533
  program2.command("interactive", { isDefault: true }).alias("i").description("Start interactive TUI mode").action(async () => {
7904
8534
  const opts = program2.opts();
7905
8535
  await interactiveAction({
@@ -7907,7 +8537,7 @@ function createProgram() {
7907
8537
  target: opts.target
7908
8538
  });
7909
8539
  });
7910
- program2.command("run <objective>").alias("r").description("Run a single objective and exit").option("-o, --output <file>", "Output file for results").option("--max-steps <n>", "Maximum number of steps", String(CLI_DEFAULT.MAX_STEPS)).action(async (objective, options) => {
8540
+ program2.command("run <objective>").alias("r").description("Run a single objective and exit").option("-o, --output <file>", "Output file for results").option("--max-steps <n>", "Maximum number of steps", parsePositiveInt, CLI_DEFAULT.MAX_STEPS).action(async (objective, options) => {
7911
8541
  const opts = program2.opts();
7912
8542
  await runAction(objective, {
7913
8543
  ...options,