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.
@@ -13,12 +13,13 @@ import {
13
13
  getAllProcesses,
14
14
  getBackgroundProcessesMap,
15
15
  getLimits,
16
- getPipelineConfig,
17
16
  getProcess,
18
17
  getProcessEventLog,
18
+ getRequiredRuntimeSection,
19
+ getRuntimeSectionOr,
19
20
  logEvent,
20
21
  setProcess
21
- } from "./chunk-GLO6TOJN.js";
22
+ } from "./chunk-I52SWXYV.js";
22
23
 
23
24
  // src/shared/constants/time/conversions.ts
24
25
  var MS_PER_MINUTE = 6e4;
@@ -138,6 +139,119 @@ var DISPLAY_LIMITS = {
138
139
  SESSION_VALUE_PREVIEW: 300
139
140
  };
140
141
 
142
+ // src/shared/utils/file-ops/runtime-asset-resolver.ts
143
+ import { existsSync, readFileSync } from "fs";
144
+ import path from "path";
145
+ import { fileURLToPath } from "url";
146
+ var RUNTIME_FILE_DIR = path.dirname(fileURLToPath(import.meta.url));
147
+ var DIST_DIR = path.basename(RUNTIME_FILE_DIR) === "dist" ? RUNTIME_FILE_DIR : path.resolve(process.cwd(), "dist");
148
+ function mapSourceAssetToDist(declaredPath) {
149
+ if (declaredPath.startsWith("src/agents/prompts/")) {
150
+ return path.join(DIST_DIR, "prompts", declaredPath.slice("src/agents/prompts/".length));
151
+ }
152
+ if (/^src\/domains\/[^/]+\/prompt\.md$/.test(declaredPath)) {
153
+ const [, domain] = declaredPath.split("/");
154
+ return path.join(DIST_DIR, domain, "prompt.md");
155
+ }
156
+ return null;
157
+ }
158
+ function getRuntimeAssetCandidates(declaredPath) {
159
+ const normalized = declaredPath.replace(/\\/g, "/").replace(/\/+$/, "");
160
+ const candidates = [path.resolve(process.cwd(), normalized)];
161
+ const distCandidate = mapSourceAssetToDist(normalized);
162
+ if (distCandidate) {
163
+ candidates.push(distCandidate);
164
+ }
165
+ return [...new Set(candidates)];
166
+ }
167
+ function resolveRuntimeAssetPath(declaredPath) {
168
+ for (const candidate of getRuntimeAssetCandidates(declaredPath)) {
169
+ if (existsSync(candidate)) {
170
+ return candidate;
171
+ }
172
+ }
173
+ return null;
174
+ }
175
+ function readRuntimeAssetFile(declaredPath, encoding = "utf-8") {
176
+ const resolved = resolveRuntimeAssetPath(declaredPath);
177
+ if (!resolved) {
178
+ return null;
179
+ }
180
+ return readFileSync(resolved, encoding);
181
+ }
182
+
183
+ // src/agents/llm-node-config.ts
184
+ var RUNTIME_CONFIG_PATH = "src/agents/runtime-config.ts";
185
+ function buildMissingNodeError(nodeName) {
186
+ return new Error(
187
+ `[runtime-config] llm_nodes.${nodeName} is not declared. Add it to ${RUNTIME_CONFIG_PATH}.`
188
+ );
189
+ }
190
+ function buildMissingPromptError(nodeName) {
191
+ return new Error(
192
+ `[runtime-config] llm_nodes.${nodeName} must declare system_prompt_file, fallback_system_prompt_file, or system_prompt. Add one to ${RUNTIME_CONFIG_PATH}.`
193
+ );
194
+ }
195
+ function buildMissingCooldownPolicyError(nodeName) {
196
+ return new Error(
197
+ `[runtime-config] llm_nodes.${nodeName}.cooldown_policy is required but not set. Add it to ${RUNTIME_CONFIG_PATH}.`
198
+ );
199
+ }
200
+ function resolvePromptFile(declaredPath, context) {
201
+ const content = readRuntimeAssetFile(declaredPath, "utf-8");
202
+ if (content === null) {
203
+ throw new Error(
204
+ `[runtime-config] ${context} points to "${declaredPath}" but no runtime asset was found. Tried: ${getRuntimeAssetCandidates(declaredPath).join(", ")}`
205
+ );
206
+ }
207
+ return content.trim();
208
+ }
209
+ function resolveInlinePrompt(prompt2) {
210
+ return prompt2 ? prompt2.trim() : void 0;
211
+ }
212
+ function resolveConfiguredPrompt(nodeName, nodeConfig) {
213
+ if (nodeConfig.system_prompt_file) {
214
+ return resolvePromptFile(
215
+ nodeConfig.system_prompt_file,
216
+ `llm_nodes.${nodeName}.system_prompt_file`
217
+ );
218
+ }
219
+ if (nodeConfig.fallback_system_prompt_file) {
220
+ return resolvePromptFile(
221
+ nodeConfig.fallback_system_prompt_file,
222
+ `llm_nodes.${nodeName}.fallback_system_prompt_file`
223
+ );
224
+ }
225
+ return resolveInlinePrompt(nodeConfig.system_prompt) ?? resolveInlinePrompt(nodeConfig.fallback_system_prompt);
226
+ }
227
+ function getLlmNodeConfig(nodeName) {
228
+ const nodeConfig = getRequiredRuntimeSection("llm_nodes")[nodeName];
229
+ if (!nodeConfig) {
230
+ throw buildMissingNodeError(nodeName);
231
+ }
232
+ return nodeConfig;
233
+ }
234
+ function llmNodeSystemPrompt(nodeName) {
235
+ const prompt2 = resolveConfiguredPrompt(nodeName, getLlmNodeConfig(nodeName));
236
+ if (!prompt2) {
237
+ throw buildMissingPromptError(nodeName);
238
+ }
239
+ return prompt2;
240
+ }
241
+ function llmNodeOutputParsing(nodeName) {
242
+ return getLlmNodeConfig(nodeName).output_parsing;
243
+ }
244
+ function llmNodeCooldownPolicy(nodeName) {
245
+ const policy = getLlmNodeConfig(nodeName).cooldown_policy;
246
+ if (!policy) {
247
+ throw buildMissingCooldownPolicyError(nodeName);
248
+ }
249
+ return policy;
250
+ }
251
+ function llmNodeMaxTokens(nodeName, fallback) {
252
+ return getLlmNodeConfig(nodeName).limits?.max_tokens ?? fallback;
253
+ }
254
+
141
255
  // src/shared/constants/llm/config.ts
142
256
  var RETRY_CONFIG = {
143
257
  baseDelayMs: 2e3,
@@ -150,9 +264,8 @@ var RETRY_CONFIG = {
150
264
  autoRetryDelayMs: 1e4
151
265
  // 10s fixed interval for 429/network errors
152
266
  };
153
- var config = getPipelineConfig();
154
- var mainLlmTokens = config.llm_nodes?.["main_llm"]?.limits?.max_tokens ?? 128e3;
155
- var strategistTokens = config.llm_nodes?.["strategist"]?.limits?.max_tokens ?? 262144;
267
+ var mainLlmTokens = llmNodeMaxTokens("main_llm", 128e3);
268
+ var strategistTokens = llmNodeMaxTokens("strategist", 262144);
156
269
  var LLM_LIMITS = {
157
270
  /** WHY 64K: non-streaming calls (orchestrator, summaries) benefit from
158
271
  * generous output budgets. Don't force premature truncation. */
@@ -194,7 +307,7 @@ var AGENT_LIMITS = {
194
307
  MAX_FAILED_PATHS: state.max_failed_paths,
195
308
  MAX_ATTACK_NODES: state.max_attack_nodes,
196
309
  MAX_ATTACK_EDGES: state.max_attack_edges,
197
- // ─── Fixed Infrastructure Constants (not tunable via yaml) ───
310
+ // ─── Fixed Infrastructure Constants (not tunable via runtime config) ───
198
311
  /** Infinite retry on LLM errors — rate limit recovery */
199
312
  MAX_CONSECUTIVE_LLM_ERRORS: agent_loop.max_consecutive_llm_errors === "infinity" || agent_loop.max_consecutive_llm_errors === Infinity ? Infinity : Number(agent_loop.max_consecutive_llm_errors ?? Infinity),
200
313
  MAX_RETRIES: agent_loop.max_retries ?? 3,
@@ -218,7 +331,7 @@ var MEMORY_LIMITS = {
218
331
  TECHNIQUE_FAILURE_DECAY: state2.technique_failure_decay,
219
332
  TECHNIQUE_PRUNE_THRESHOLD: state2.technique_prune_threshold,
220
333
  MAX_TURN_ENTRIES: archive.max_turn_entries,
221
- /** Maximum unverified techniques to show in prompt (display-only, not in yaml) */
334
+ /** Maximum unverified techniques to show in prompt (display-only, not in runtime config) */
222
335
  PROMPT_UNVERIFIED_TECHNIQUES: 10
223
336
  };
224
337
 
@@ -235,7 +348,7 @@ var INPUT_PROMPT_PATTERNS = [
235
348
 
236
349
  // src/shared/constants/agent.ts
237
350
  var APP_NAME = "Pentest AI";
238
- var APP_VERSION = "0.73.3";
351
+ var APP_VERSION = "0.73.4";
239
352
  var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
240
353
  var LLM_ROLES = {
241
354
  SYSTEM: "system",
@@ -518,6 +631,7 @@ var TOOL_NAMES = {
518
631
  EXPLOIT_CREDENTIAL_CHECK: "exploit_credential_check",
519
632
  EXPLOIT_ARTIFACT_CHECK: "exploit_artifact_check",
520
633
  EXPLOIT_FOOTHOLD_CHECK: "exploit_foothold_check",
634
+ EXPLOIT_VECTOR_CHECK: "exploit_vector_check",
521
635
  PWN_CRASH_REPRO: "pwn_crash_repro",
522
636
  PWN_OFFSET_CHECK: "pwn_offset_check",
523
637
  PWN_PAYLOAD_SMOKE: "pwn_payload_smoke",
@@ -948,7 +1062,20 @@ function getInputHandler() {
948
1062
  }
949
1063
 
950
1064
  // src/shared/constants/paths.ts
951
- import path from "path";
1065
+ import path2 from "path";
1066
+
1067
+ // src/agents/workspace-config.ts
1068
+ var DEFAULT_WORKSPACE_ROOT = ".pentesting";
1069
+ var DEFAULT_WORKSPACE_DIRECTORIES = {};
1070
+ function getWorkspaceConfig() {
1071
+ return getRuntimeSectionOr("workspace", {});
1072
+ }
1073
+ function getWorkspaceRoot() {
1074
+ return getWorkspaceConfig().root ?? DEFAULT_WORKSPACE_ROOT;
1075
+ }
1076
+ function getWorkspaceDirectories() {
1077
+ return getWorkspaceConfig().directories ?? DEFAULT_WORKSPACE_DIRECTORIES;
1078
+ }
952
1079
 
953
1080
  // src/shared/constants/files/extensions.ts
954
1081
  var FILE_EXTENSIONS = {
@@ -995,9 +1122,9 @@ var SPECIAL_FILES = {
995
1122
  };
996
1123
 
997
1124
  // src/shared/utils/file-ops/file-utils.ts
998
- import { existsSync, mkdirSync } from "fs";
1125
+ import { existsSync as existsSync2, mkdirSync } from "fs";
999
1126
  function ensureDirExists(dirPath) {
1000
- if (!existsSync(dirPath)) {
1127
+ if (!existsSync2(dirPath)) {
1001
1128
  mkdirSync(dirPath, { recursive: true });
1002
1129
  }
1003
1130
  }
@@ -1025,15 +1152,13 @@ var _dirs = null;
1025
1152
  var _root = null;
1026
1153
  function getRoot() {
1027
1154
  if (_root === null) {
1028
- const ws = getPipelineConfig().workspace;
1029
- _root = ws?.root ?? ".pentesting";
1155
+ _root = getWorkspaceRoot();
1030
1156
  }
1031
1157
  return _root;
1032
1158
  }
1033
1159
  function getDirs() {
1034
1160
  if (_dirs === null) {
1035
- const ws = getPipelineConfig().workspace;
1036
- _dirs = ws?.directories ?? {};
1161
+ _dirs = getWorkspaceDirectories();
1037
1162
  }
1038
1163
  return _dirs;
1039
1164
  }
@@ -1045,39 +1170,39 @@ var WORK_DIR = dir("workspace", `${getRoot()}/workspace`);
1045
1170
  var MEMORY_DIR = dir("memory", `${getRoot()}/memory`);
1046
1171
  var WORKSPACE = {
1047
1172
  get ROOT() {
1048
- return path.resolve(getRoot());
1173
+ return path2.resolve(getRoot());
1049
1174
  },
1050
1175
  get TMP() {
1051
- return path.resolve(dir("workspace", `${getRoot()}/workspace`));
1176
+ return path2.resolve(dir("workspace", `${getRoot()}/workspace`));
1052
1177
  },
1053
1178
  get MEMORY() {
1054
- return path.resolve(dir("memory", `${getRoot()}/memory`));
1179
+ return path2.resolve(dir("memory", `${getRoot()}/memory`));
1055
1180
  },
1056
1181
  get POLICY() {
1057
- return path.resolve(dir("memory", `${getRoot()}/memory`), SPECIAL_FILES.POLICY);
1182
+ return path2.resolve(dir("memory", `${getRoot()}/memory`), SPECIAL_FILES.POLICY);
1058
1183
  },
1059
1184
  get REPORTS() {
1060
- return path.resolve(dir("reports", `${getRoot()}/reports`));
1185
+ return path2.resolve(dir("reports", `${getRoot()}/reports`));
1061
1186
  },
1062
1187
  get SESSIONS() {
1063
- return path.resolve(dir("sessions", `${getRoot()}/sessions`));
1188
+ return path2.resolve(dir("sessions", `${getRoot()}/sessions`));
1064
1189
  },
1065
1190
  get LOOT() {
1066
- return path.resolve(dir("loot", `${getRoot()}/loot`));
1191
+ return path2.resolve(dir("loot", `${getRoot()}/loot`));
1067
1192
  },
1068
1193
  get DEBUG() {
1069
- return path.resolve(dir("debug", `${getRoot()}/debug`));
1194
+ return path2.resolve(dir("debug", `${getRoot()}/debug`));
1070
1195
  },
1071
1196
  /** Turn insight files root: .pentesting/turns/ */
1072
1197
  get TURNS() {
1073
- return path.resolve(dir("turns", `${getRoot()}/turns`));
1198
+ return path2.resolve(dir("turns", `${getRoot()}/turns`));
1074
1199
  },
1075
1200
  /**
1076
1201
  * Resolve the turn memory file for a specific turn: .pentesting/turns/{N}-memory.md
1077
- * Pipeline.yaml: workspace.turn_structure → single file per turn
1202
+ * Runtime config turn storage policy → single file per turn
1078
1203
  */
1079
1204
  turnPath(turn) {
1080
- return path.resolve(dir("turns", `${getRoot()}/turns`), `${turn}-memory.md`);
1205
+ return path2.resolve(dir("turns", `${getRoot()}/turns`), `${turn}-memory.md`);
1081
1206
  }
1082
1207
  };
1083
1208
 
@@ -1310,7 +1435,7 @@ var BLOCKED_BINARIES = /* @__PURE__ */ new Set([
1310
1435
  ]);
1311
1436
 
1312
1437
  // src/shared/utils/debug/debug-logger.ts
1313
- import { appendFileSync, writeFileSync, statSync, readFileSync } from "fs";
1438
+ import { appendFileSync, writeFileSync, statSync, readFileSync as readFileSync2 } from "fs";
1314
1439
  import { join } from "path";
1315
1440
  var ROTATE_BYTES = 5 * 1024 * 1024;
1316
1441
  var WIPE_BYTES = 20 * 1024 * 1024;
@@ -1362,7 +1487,7 @@ var DebugLogger = class _DebugLogger {
1362
1487
  writeFileSync(this.logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [GENERAL] === LOG WIPED (exceeded ${Math.round(WIPE_BYTES / 1024 / 1024)}MB) ===
1363
1488
  `);
1364
1489
  } else if (size > ROTATE_BYTES) {
1365
- const content = readFileSync(this.logPath, "utf-8");
1490
+ const content = readFileSync2(this.logPath, "utf-8");
1366
1491
  const half = content.slice(Math.floor(content.length / 2));
1367
1492
  const firstNewline = half.indexOf("\n");
1368
1493
  const trimmed = firstNewline >= 0 ? half.slice(firstNewline + 1) : half;
@@ -2344,7 +2469,7 @@ Suggestion: ${torLeak.suggestion}`
2344
2469
  }
2345
2470
 
2346
2471
  // src/engine/tools-base/file-operations.ts
2347
- import { readFileSync as readFileSync2, existsSync as existsSync2, writeFileSync as writeFileSync2 } from "fs";
2472
+ import { readFileSync as readFileSync3, existsSync as existsSync3, writeFileSync as writeFileSync2 } from "fs";
2348
2473
  import { dirname } from "path";
2349
2474
  import { join as join2 } from "path";
2350
2475
  import { tmpdir } from "os";
@@ -2364,14 +2489,14 @@ function getErrorMessage(error) {
2364
2489
  // src/engine/tools-base/file-operations.ts
2365
2490
  async function readFileContent(filePath) {
2366
2491
  try {
2367
- if (!existsSync2(filePath)) {
2492
+ if (!existsSync3(filePath)) {
2368
2493
  return {
2369
2494
  success: false,
2370
2495
  output: "",
2371
2496
  error: `File not found: ${filePath}`
2372
2497
  };
2373
2498
  }
2374
- const content = readFileSync2(filePath, "utf-8");
2499
+ const content = readFileSync3(filePath, "utf-8");
2375
2500
  return {
2376
2501
  success: true,
2377
2502
  output: content
@@ -2482,7 +2607,7 @@ function startBackgroundProcess(command, options = {}) {
2482
2607
  }
2483
2608
 
2484
2609
  // src/engine/process/process-interaction.ts
2485
- import { existsSync as existsSync3, readFileSync as readFileSync3, appendFileSync as appendFileSync2 } from "fs";
2610
+ import { existsSync as existsSync4, readFileSync as readFileSync4, appendFileSync as appendFileSync2 } from "fs";
2486
2611
  async function sendToProcess(processId, input, waitMs = SYSTEM_LIMITS.DEFAULT_WAIT_MS_INTERACT) {
2487
2612
  const proc = getProcess(processId);
2488
2613
  if (!proc) return { success: false, output: `Process ${processId} not found`, newOutput: "" };
@@ -2490,8 +2615,8 @@ async function sendToProcess(processId, input, waitMs = SYSTEM_LIMITS.DEFAULT_WA
2490
2615
  if (proc.hasExited) return { success: false, output: `Process ${processId} has exited`, newOutput: "" };
2491
2616
  let currentLen = 0;
2492
2617
  try {
2493
- if (existsSync3(proc.stdoutFile)) {
2494
- currentLen = readFileSync3(proc.stdoutFile, "utf-8").length;
2618
+ if (existsSync4(proc.stdoutFile)) {
2619
+ currentLen = readFileSync4(proc.stdoutFile, "utf-8").length;
2495
2620
  }
2496
2621
  } catch {
2497
2622
  }
@@ -2504,8 +2629,8 @@ async function sendToProcess(processId, input, waitMs = SYSTEM_LIMITS.DEFAULT_WA
2504
2629
  await new Promise((r) => setTimeout(r, waitMs));
2505
2630
  let fullStdout = "";
2506
2631
  try {
2507
- if (existsSync3(proc.stdoutFile)) {
2508
- fullStdout = readFileSync3(proc.stdoutFile, "utf-8");
2632
+ if (existsSync4(proc.stdoutFile)) {
2633
+ fullStdout = readFileSync4(proc.stdoutFile, "utf-8");
2509
2634
  }
2510
2635
  } catch {
2511
2636
  }
@@ -2527,7 +2652,7 @@ function promoteToShell(processId, description) {
2527
2652
  }
2528
2653
 
2529
2654
  // src/engine/process/process-monitor.ts
2530
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
2655
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
2531
2656
  function isProcessRunning(processId) {
2532
2657
  const proc = getProcess(processId);
2533
2658
  if (!proc) return false;
@@ -2540,8 +2665,8 @@ function isProcessRunning(processId) {
2540
2665
  proc.childPids = discoverAllDescendants(proc.pid);
2541
2666
  if (proc.role === PROCESS_ROLES.LISTENER) {
2542
2667
  try {
2543
- if (existsSync4(proc.stdoutFile)) {
2544
- const stdout = readFileSync4(proc.stdoutFile, "utf-8");
2668
+ if (existsSync5(proc.stdoutFile)) {
2669
+ const stdout = readFileSync5(proc.stdoutFile, "utf-8");
2545
2670
  if (detectConnection(stdout)) {
2546
2671
  promoteToShell(processId, "Reverse shell connected (auto-detected)");
2547
2672
  logEvent(processId, PROCESS_EVENTS.CONNECTION_DETECTED, `Connection detected on port ${proc.listeningPort}`);
@@ -2559,16 +2684,16 @@ function getProcessOutput(processId) {
2559
2684
  let stdout = "";
2560
2685
  let stderr = "";
2561
2686
  try {
2562
- if (existsSync4(proc.stdoutFile)) {
2563
- const content = readFileSync4(proc.stdoutFile, "utf-8");
2687
+ if (existsSync5(proc.stdoutFile)) {
2688
+ const content = readFileSync5(proc.stdoutFile, "utf-8");
2564
2689
  stdout = content.length > SYSTEM_LIMITS.MAX_STDOUT_SLICE ? `... [truncated ${content.length - SYSTEM_LIMITS.MAX_STDOUT_SLICE} chars] ...
2565
2690
  ` + content.slice(-SYSTEM_LIMITS.MAX_STDOUT_SLICE) : content;
2566
2691
  }
2567
2692
  } catch {
2568
2693
  }
2569
2694
  try {
2570
- if (existsSync4(proc.stderrFile)) {
2571
- const content = readFileSync4(proc.stderrFile, "utf-8");
2695
+ if (existsSync5(proc.stderrFile)) {
2696
+ const content = readFileSync5(proc.stderrFile, "utf-8");
2572
2697
  stderr = content.length > SYSTEM_LIMITS.MAX_STDERR_SLICE ? `... [truncated ${content.length - SYSTEM_LIMITS.MAX_STDERR_SLICE} chars] ...
2573
2698
  ` + content.slice(-SYSTEM_LIMITS.MAX_STDERR_SLICE) : content;
2574
2699
  }
@@ -2674,7 +2799,7 @@ async function cleanupAllProcesses() {
2674
2799
  cleanupDone = false;
2675
2800
  return;
2676
2801
  }
2677
- const { getBackgroundProcessesMap: getBackgroundProcessesMap2 } = await import("./process-registry-QIW7ZIUT.js");
2802
+ const { getBackgroundProcessesMap: getBackgroundProcessesMap2 } = await import("./process-registry-BI7BKPHN.js");
2678
2803
  const backgroundProcesses = getBackgroundProcessesMap2();
2679
2804
  terminateAllNatively(backgroundProcesses, "SIGTERM");
2680
2805
  await new Promise((r) => setTimeout(r, SYSTEM_LIMITS.CLEANUP_BATCH_WAIT_MS));
@@ -2741,7 +2866,7 @@ function cleanupOrphanProcesses() {
2741
2866
  }
2742
2867
 
2743
2868
  // src/engine/process/resource-summary.ts
2744
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
2869
+ import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
2745
2870
  function formatActiveProcesses(running, lines) {
2746
2871
  if (running.length === 0) return;
2747
2872
  lines.push(`Active Assets (${running.length}):`);
@@ -2753,8 +2878,8 @@ function formatActiveProcesses(running, lines) {
2753
2878
  const roleIcon = PROCESS_ICONS[p.role] || PROCESS_ICONS[PROCESS_ROLES.BACKGROUND];
2754
2879
  let lastOutput = "";
2755
2880
  try {
2756
- if (p.stdoutFile && existsSync5(p.stdoutFile)) {
2757
- const content = readFileSync5(p.stdoutFile, "utf-8");
2881
+ if (p.stdoutFile && existsSync6(p.stdoutFile)) {
2882
+ const content = readFileSync6(p.stdoutFile, "utf-8");
2758
2883
  const outputLines = content.trim().split("\n");
2759
2884
  lastOutput = outputLines.slice(-SYSTEM_LIMITS.RECENT_OUTPUT_LINES).join(" | ").replace(/\n/g, " ");
2760
2885
  }
@@ -3228,7 +3353,7 @@ var EpisodicMemory = class {
3228
3353
  };
3229
3354
 
3230
3355
  // src/shared/utils/agent-memory/persistent-memory.ts
3231
- import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
3356
+ import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
3232
3357
  import { join as join4 } from "path";
3233
3358
 
3234
3359
  // src/shared/utils/agent-memory/similarity.ts
@@ -3257,7 +3382,7 @@ function matchesServiceProfile(serviceProfile, services) {
3257
3382
  }
3258
3383
 
3259
3384
  // src/shared/utils/agent-memory/session-snapshot.ts
3260
- import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4, unlinkSync as unlinkSync4 } from "fs";
3385
+ import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync as unlinkSync4 } from "fs";
3261
3386
  import { join as join3 } from "path";
3262
3387
  var SNAPSHOT_FILE = join3(WORKSPACE.MEMORY, SPECIAL_FILES.SESSION_SNAPSHOT);
3263
3388
  function saveSessionSnapshot(snapshot) {
@@ -3269,8 +3394,8 @@ function saveSessionSnapshot(snapshot) {
3269
3394
  }
3270
3395
  function loadSessionSnapshot() {
3271
3396
  try {
3272
- if (existsSync6(SNAPSHOT_FILE)) {
3273
- return JSON.parse(readFileSync6(SNAPSHOT_FILE, "utf-8"));
3397
+ if (existsSync7(SNAPSHOT_FILE)) {
3398
+ return JSON.parse(readFileSync7(SNAPSHOT_FILE, "utf-8"));
3274
3399
  }
3275
3400
  } catch {
3276
3401
  }
@@ -3301,7 +3426,7 @@ function snapshotToPrompt() {
3301
3426
  }
3302
3427
  function clearSessionSnapshot() {
3303
3428
  try {
3304
- if (existsSync6(SNAPSHOT_FILE)) {
3429
+ if (existsSync7(SNAPSHOT_FILE)) {
3305
3430
  unlinkSync4(SNAPSHOT_FILE);
3306
3431
  }
3307
3432
  } catch {
@@ -3451,8 +3576,8 @@ var PersistentMemory = class {
3451
3576
  }
3452
3577
  load() {
3453
3578
  try {
3454
- if (existsSync7(MEMORY_FILE)) {
3455
- const data = JSON.parse(readFileSync7(MEMORY_FILE, "utf-8"));
3579
+ if (existsSync8(MEMORY_FILE)) {
3580
+ const data = JSON.parse(readFileSync8(MEMORY_FILE, "utf-8"));
3456
3581
  return {
3457
3582
  ...data,
3458
3583
  exploitChains: data.exploitChains ?? []
@@ -3898,15 +4023,15 @@ function pruneOldSessions(sessionsDir) {
3898
4023
  }
3899
4024
 
3900
4025
  // src/engine/state/persistence/loader.ts
3901
- import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
4026
+ import { readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
3902
4027
  import { join as join6 } from "path";
3903
4028
  function loadState(state3) {
3904
4029
  const latestFile = join6(WORKSPACE.SESSIONS, "latest.json");
3905
- if (!existsSync8(latestFile)) {
4030
+ if (!existsSync9(latestFile)) {
3906
4031
  return false;
3907
4032
  }
3908
4033
  try {
3909
- const raw = readFileSync8(latestFile, "utf-8");
4034
+ const raw = readFileSync9(latestFile, "utf-8");
3910
4035
  const snapshot = JSON.parse(raw);
3911
4036
  if (snapshot.version !== 1) {
3912
4037
  debugLog("general", `Unknown snapshot version: ${snapshot.version}`);
@@ -3953,8 +4078,8 @@ function loadState(state3) {
3953
4078
  }
3954
4079
 
3955
4080
  // src/engine/state/persistence/janitor.ts
3956
- import { existsSync as existsSync9, rmSync } from "fs";
3957
- import path2 from "path";
4081
+ import { existsSync as existsSync10, rmSync } from "fs";
4082
+ import path3 from "path";
3958
4083
  function clearWorkspace() {
3959
4084
  const cleared = [];
3960
4085
  const errors = [];
@@ -3965,13 +4090,13 @@ function clearWorkspace() {
3965
4090
  { path: WORKSPACE.TMP, label: "workspace/temp" },
3966
4091
  { path: WORKSPACE.LOOT, label: "loot" },
3967
4092
  { path: WORKSPACE.REPORTS, label: "reports" },
3968
- { path: path2.join(root, "archive"), label: "archive (historical cleanup)" },
3969
- { path: path2.join(root, "outputs"), label: "outputs (historical cleanup)" },
3970
- { path: path2.join(root, "journal"), label: "journal (historical cleanup)" }
4093
+ { path: path3.join(root, "archive"), label: "archive (historical cleanup)" },
4094
+ { path: path3.join(root, "outputs"), label: "outputs (historical cleanup)" },
4095
+ { path: path3.join(root, "journal"), label: "journal (historical cleanup)" }
3971
4096
  ];
3972
4097
  for (const dir2 of dirsToClean) {
3973
4098
  try {
3974
- if (existsSync9(dir2.path)) {
4099
+ if (existsSync10(dir2.path)) {
3975
4100
  rmSync(dir2.path, { recursive: true, force: true });
3976
4101
  ensureDirExists(dir2.path);
3977
4102
  cleared.push(dir2.label);
@@ -3985,6 +4110,7 @@ function clearWorkspace() {
3985
4110
 
3986
4111
  export {
3987
4112
  ensureDirExists,
4113
+ getWorkspaceConfig,
3988
4114
  FILE_EXTENSIONS,
3989
4115
  FILE_PATTERNS,
3990
4116
  WORK_DIR,
@@ -3996,6 +4122,11 @@ export {
3996
4122
  getTorBrowserArgs,
3997
4123
  MS_PER_MINUTE,
3998
4124
  DISPLAY_LIMITS,
4125
+ resolveRuntimeAssetPath,
4126
+ readRuntimeAssetFile,
4127
+ llmNodeSystemPrompt,
4128
+ llmNodeOutputParsing,
4129
+ llmNodeCooldownPolicy,
3999
4130
  RETRY_CONFIG,
4000
4131
  LLM_LIMITS,
4001
4132
  LLM_ERROR_TYPES,