@pensar/apex 1.7.0 → 1.8.0-canary.1db2dac9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/build/{agent-beywhvf3.js → agent-pzymaexc.js} +7 -7
  2. package/build/agent-rsvcxej9.js +19 -0
  3. package/build/{auth-wvh553ea.js → auth-z89eba1d.js} +4 -4
  4. package/build/{authentication-ec7trwb4.js → authentication-3tstyqna.js} +7 -7
  5. package/build/{blackboxAgent-ng2t2p2x.js → blackboxAgent-z5081b7k.js} +8 -8
  6. package/build/{blackboxPentest-rwyjy4kq.js → blackboxPentest-rkxe2mcn.js} +12 -12
  7. package/build/{cli-09prdch1.js → cli-0cgtn46q.js} +6 -6
  8. package/build/{cli-q2dty8g4.js → cli-1aswmqw0.js} +1 -1
  9. package/build/{cli-06zt0g1a.js → cli-3escpq81.js} +2 -2
  10. package/build/{cli-836bfgxg.js → cli-5d8gtwm9.js} +1 -1
  11. package/build/{cli-vvyq7ace.js → cli-6dzawz8t.js} +1 -1
  12. package/build/{cli-gr3zncst.js → cli-7zdq20ny.js} +1 -1
  13. package/build/{cli-x3k26g1t.js → cli-8e3jxvsa.js} +296 -181
  14. package/build/{cli-rc7hyq7e.js → cli-f55c0xh4.js} +92 -6
  15. package/build/{cli-5m0347h3.js → cli-h2geq3ft.js} +1 -1
  16. package/build/{cli-zr7sg2m2.js → cli-mnx6v52y.js} +2 -2
  17. package/build/{cli-r879p2yz.js → cli-mqp1725p.js} +1 -1
  18. package/build/{cli-xtqm11qt.js → cli-p8zdr5yc.js} +1 -1
  19. package/build/{cli-nqx9y9ds.js → cli-zhs8z3ay.js} +1 -1
  20. package/build/{cli-40ef01tb.js → cli-zvjf2zxh.js} +1 -1
  21. package/build/cli.js +50 -41
  22. package/build/{fixes-1z283wdz.js → fixes-073psn8y.js} +4 -4
  23. package/build/{index-j3hw6d4w.js → index-16m6v082.js} +133 -100
  24. package/build/{index-1p5bg26t.js → index-f6w6vdtj.js} +4 -4
  25. package/build/{index-py7gtxez.js → index-mn8a1ej3.js} +2 -2
  26. package/build/{index-a4ydz3dd.js → index-x7nnxbgg.js} +7 -7
  27. package/build/{index-5a173a2k.js → index-z2v0ck06.js} +6 -6
  28. package/build/{issues-trbzy8n0.js → issues-p52tvm5m.js} +4 -4
  29. package/build/{logs-c88md0h3.js → logs-v8sxy4aj.js} +4 -4
  30. package/build/{offesecAgent-ahcz5hcx.js → offesecAgent-a5vgdg3p.js} +7 -7
  31. package/build/{pentest-4932ke3a.js → pentest-277h4psc.js} +12 -12
  32. package/build/{pentests-re8dzxt9.js → pentests-wc7jv4w7.js} +4 -4
  33. package/build/{projects-dqp4m0ws.js → projects-wc1q31pd.js} +4 -4
  34. package/build/{targetedPentest-de8a67va.js → targetedPentest-x52as9qn.js} +8 -8
  35. package/build/{threatModel-waz866yk.js → threatModel-86tctt66.js} +8 -8
  36. package/build/{uninstall-0bwz7jdn.js → uninstall-7qq038qw.js} +1 -1
  37. package/package.json +1 -1
  38. package/build/agent-63cc9rpx.js +0 -19
@@ -16,7 +16,7 @@ import {
16
16
  update,
17
17
  write,
18
18
  writeRaw
19
- } from "./cli-nqx9y9ds.js";
19
+ } from "./cli-zhs8z3ay.js";
20
20
  import {
21
21
  parseTargetUrl
22
22
  } from "./cli-3y0dgy56.js";
@@ -29,7 +29,7 @@ import {
29
29
  require_tslib,
30
30
  streamResponse,
31
31
  toggleTool
32
- } from "./cli-rc7hyq7e.js";
32
+ } from "./cli-f55c0xh4.js";
33
33
  import {
34
34
  _enum,
35
35
  _null,
@@ -57,15 +57,15 @@ import {
57
57
  } from "./cli-0ghkg3w6.js";
58
58
  import {
59
59
  signGatewayRequest
60
- } from "./cli-xtqm11qt.js";
60
+ } from "./cli-p8zdr5yc.js";
61
61
  import {
62
62
  config,
63
63
  ensureValidToken,
64
64
  getPensarApiUrl
65
- } from "./cli-q2dty8g4.js";
65
+ } from "./cli-1aswmqw0.js";
66
66
  import {
67
67
  getCurrentVersion
68
- } from "./cli-r879p2yz.js";
68
+ } from "./cli-mqp1725p.js";
69
69
  import {
70
70
  __commonJS,
71
71
  __require,
@@ -110688,18 +110688,23 @@ var require_mimeScore = __commonJS((exports, module) => {
110688
110688
 
110689
110689
  // src/core/eventBus.ts
110690
110690
  import { EventEmitter } from "events";
110691
- var CHILD_BUS_FORWARDED_EVENTS = [
110692
- "text-delta",
110693
- "tool-call-start",
110694
- "tool-call-delta",
110695
- "tool-call-complete",
110696
- "tool-result",
110697
- "subagent-spawn",
110698
- "subagent-complete",
110699
- "command-output",
110700
- "error",
110701
- "step-finish"
110702
- ];
110691
+ var CHILD_BUS_FORWARD_POLICY = {
110692
+ "text-delta": "forward",
110693
+ "tool-call-start": "forward",
110694
+ "tool-call-delta": "forward",
110695
+ "tool-call-complete": "forward",
110696
+ "tool-result": "forward",
110697
+ "subagent-spawn": "forward",
110698
+ "subagent-complete": "forward",
110699
+ "step-finish": "forward",
110700
+ "command-output": "forward",
110701
+ error: "forward",
110702
+ "trace-record": "forward",
110703
+ "workflow-phase-start": "parent-only",
110704
+ "workflow-phase-complete": "parent-only",
110705
+ "app-analysis-progress": "parent-only"
110706
+ };
110707
+ var CHILD_BUS_FORWARDED_EVENTS = Object.keys(CHILD_BUS_FORWARD_POLICY).filter((key) => CHILD_BUS_FORWARD_POLICY[key] === "forward");
110703
110708
 
110704
110709
  class AgentEventBus {
110705
110710
  emitter = new EventEmitter;
@@ -110730,10 +110735,10 @@ class AgentEventBus {
110730
110735
  return this;
110731
110736
  }
110732
110737
  static attachChild(child, parent, subagentId) {
110738
+ if (!parent)
110739
+ return;
110733
110740
  for (const key of CHILD_BUS_FORWARDED_EVENTS) {
110734
110741
  child.on(key, (payload) => {
110735
- if (!parent)
110736
- return;
110737
110742
  const p = payload;
110738
110743
  if (!p.subagentId) {
110739
110744
  parent.emit(key, { ...p, subagentId });
@@ -115782,6 +115787,32 @@ OUTPUT HANDLING:
115782
115787
  - The tool's timeout parameter is in SECONDS, not milliseconds
115783
115788
  - Good timeout examples: 30, 60, 120
115784
115789
  - Do NOT pass millisecond values like 30000 or 120000
115790
+ - If the tool's timeout is hit, the partial stdout the command had already
115791
+ produced is still returned (with exit code 124). It is safe to set a
115792
+ conservative timeout: you will not lose the bytes a fuzzer printed
115793
+ before the kill.
115794
+
115795
+ LONG-RUNNING FUZZERS AND SCANNERS:
115796
+
115797
+ Wordlist fuzzers (ffuf, gobuster, dirb, wfuzz, dirsearch) and large nmap
115798
+ scans against slow targets routinely take longer than a single tool call
115799
+ should. ALWAYS bound them with their OWN internal time budget, set BELOW
115800
+ the tool's timeout, so the tool exits cleanly with full output and you
115801
+ don't have to rely on signal-based truncation.
115802
+
115803
+ General rule: set the inner tool's runtime cap at least 5s below the
115804
+ execute_command timeout, so the tool exits gracefully and flushes its
115805
+ results to disk before any signal arrives.
115806
+
115807
+ - ffuf: pair with -maxtime <seconds> and a sane -rate.
115808
+ Example: ffuf -u <url>/FUZZ -w <wordlist> -maxtime 55 -rate 50
115809
+ with the tool's timeout=60.
115810
+ - gobuster: has no -maxtime flag. Wrap with the \`timeout\` coreutils
115811
+ command and tune --timeout / --threads.
115812
+ Example: timeout 55 gobuster dir -u <url> -w <wordlist> --timeout 5s --threads 20
115813
+ with the tool's timeout=60.
115814
+ - nmap: prefer --host-timeout, --max-rtt-timeout, and -T4 / --min-rate
115815
+ to bound total runtime against slow networks.
115785
115816
 
115786
115817
  IMPORTANT: Always analyze results and adjust your approach based on findings.`,
115787
115818
  inputSchema: executeCommandInputSchema,
@@ -119360,7 +119391,7 @@ async function generateThreatModelForEndpoint(ctx, input) {
119360
119391
  return threatModelLimiter(async () => {
119361
119392
  if (ctx.abortSignal?.aborted)
119362
119393
  return null;
119363
- const { CodeAgent } = await import("./agent-63cc9rpx.js");
119394
+ const { CodeAgent } = await import("./agent-rsvcxej9.js");
119364
119395
  const subagentId = `threat-model-${sanitize(input.appName)}-${sanitize(input.routePath)}`;
119365
119396
  ctx.eventBus?.emit("subagent-spawn", {
119366
119397
  subagentId,
@@ -120049,7 +120080,7 @@ When to use delegate_to_auth_subagent vs authenticate_session:
120049
120080
  if (credentials) {
120050
120081
  ctx.session.credentialManager.addFromAuthCredentials(credentials);
120051
120082
  }
120052
- const { runAuthenticationAgent } = await import("./authentication-ec7trwb4.js");
120083
+ const { runAuthenticationAgent } = await import("./authentication-3tstyqna.js");
120053
120084
  const localBus = new AgentEventBus;
120054
120085
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
120055
120086
  const result = await runAuthenticationAgent({
@@ -120962,7 +120993,7 @@ should be passed directly to spawn_pentest_swarm for deep testing.`,
120962
120993
  });
120963
120994
  if (cwd) {
120964
120995
  try {
120965
- const { WhiteboxAttackSurfaceAgent } = await import("./agent-beywhvf3.js");
120996
+ const { WhiteboxAttackSurfaceAgent } = await import("./agent-pzymaexc.js");
120966
120997
  const localBus = new AgentEventBus;
120967
120998
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
120968
120999
  const agent = new WhiteboxAttackSurfaceAgent({
@@ -121011,7 +121042,7 @@ should be passed directly to spawn_pentest_swarm for deep testing.`,
121011
121042
  }
121012
121043
  }
121013
121044
  try {
121014
- const { BlackboxAttackSurfaceAgent } = await import("./blackboxAgent-ng2t2p2x.js");
121045
+ const { BlackboxAttackSurfaceAgent } = await import("./blackboxAgent-z5081b7k.js");
121015
121046
  const localBus = new AgentEventBus;
121016
121047
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
121017
121048
  const agent = new BlackboxAttackSurfaceAgent({
@@ -121087,7 +121118,7 @@ Pass every target you want tested — the swarm handles concurrency automaticall
121087
121118
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
121088
121119
  }),
121089
121120
  execute: async ({ targets }) => {
121090
- const { runPentestSwarm, DEFAULT_CONCURRENCY } = await import("./pentest-4932ke3a.js");
121121
+ const { runPentestSwarm, DEFAULT_CONCURRENCY } = await import("./pentest-277h4psc.js");
121091
121122
  if (!ctx.model) {
121092
121123
  return {
121093
121124
  success: false,
@@ -121215,7 +121246,7 @@ Returns an array of results with the text output from each agent.`,
121215
121246
  });
121216
121247
  }
121217
121248
  async function runSingleCodingAgent(ctx, codebasePath, objective, agentIndex, name) {
121218
- const { CodeAgent } = await import("./agent-63cc9rpx.js");
121249
+ const { CodeAgent } = await import("./agent-rsvcxej9.js");
121219
121250
  const subagentId = `coding-agent-${agentIndex}`;
121220
121251
  ctx.eventBus?.emit("subagent-spawn", {
121221
121252
  subagentId,
@@ -121276,7 +121307,7 @@ Omit \`cwd\` for blackbox mode (live target probing only).`,
121276
121307
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
121277
121308
  }),
121278
121309
  execute: async ({ target, cwd }) => {
121279
- const { runPentestWorkflow: workflow } = await import("./pentest-4932ke3a.js");
121310
+ const { runPentestWorkflow: workflow } = await import("./pentest-277h4psc.js");
121280
121311
  if (!ctx.model) {
121281
121312
  return {
121282
121313
  success: false,
@@ -125938,7 +125969,48 @@ function createResponseTool(responseSchema, onResult) {
125938
125969
  // src/core/agents/offSecAgent/tools/persistentShell.ts
125939
125970
  import { spawn as spawn4, spawnSync } from "child_process";
125940
125971
  import { randomBytes } from "crypto";
125972
+ import {
125973
+ closeSync,
125974
+ mkdirSync as mkdirSync12,
125975
+ openSync,
125976
+ readFileSync as readFileSync4,
125977
+ readSync,
125978
+ statSync,
125979
+ unlinkSync as unlinkSync2
125980
+ } from "fs";
125981
+ import { tmpdir } from "os";
125982
+ import { join as join18 } from "path";
125941
125983
  var MAX_BUFFER = 5000000;
125984
+ var APEX_TMP_ROOT = join18(tmpdir(), `apex-shell-${process.pid}`);
125985
+ try {
125986
+ mkdirSync12(APEX_TMP_ROOT, { recursive: true });
125987
+ } catch {}
125988
+ function readTempfileCapped(path) {
125989
+ try {
125990
+ const stat2 = statSync(path);
125991
+ if (stat2.size === 0)
125992
+ return "";
125993
+ if (stat2.size <= MAX_BUFFER) {
125994
+ return readFileSync4(path, "utf-8");
125995
+ }
125996
+ const fd = openSync(path, "r");
125997
+ try {
125998
+ const buf = Buffer.alloc(MAX_BUFFER);
125999
+ readSync(fd, buf, 0, MAX_BUFFER, stat2.size - MAX_BUFFER);
126000
+ return `(stdout truncated)...
126001
+ ` + buf.toString("utf-8");
126002
+ } finally {
126003
+ closeSync(fd);
126004
+ }
126005
+ } catch {
126006
+ return "";
126007
+ }
126008
+ }
126009
+ function unlinkSafe(path) {
126010
+ try {
126011
+ unlinkSync2(path);
126012
+ } catch {}
126013
+ }
125942
126014
  var stdbufAvailable = null;
125943
126015
  function hasStdbuf() {
125944
126016
  if (stdbufAvailable !== null)
@@ -125983,6 +126055,7 @@ class PersistentShell {
125983
126055
  extraEnv;
125984
126056
  current = null;
125985
126057
  pendingCancel = null;
126058
+ writeChain = Promise.resolve();
125986
126059
  constructor(opts) {
125987
126060
  this.cwd = opts?.cwd;
125988
126061
  this.extraEnv = opts?.env;
@@ -126019,9 +126092,13 @@ class PersistentShell {
126019
126092
  if (cmd) {
126020
126093
  this.current = null;
126021
126094
  this.pendingCancel = null;
126095
+ const diskStdout = readTempfileCapped(cmd.outPath);
126096
+ const diskStderr = readTempfileCapped(cmd.errPath);
126097
+ unlinkSafe(cmd.outPath);
126098
+ unlinkSafe(cmd.errPath);
126022
126099
  cmd.resolve({
126023
- stdout: extractFallbackStdout(cmd),
126024
- stderr: cmd.stderr || "",
126100
+ stdout: diskStdout || extractFallbackStdout(cmd) || "(no output)",
126101
+ stderr: diskStderr || cmd.stderr || "",
126025
126102
  exitCode: 1
126026
126103
  });
126027
126104
  }
@@ -126080,6 +126157,8 @@ class PersistentShell {
126080
126157
  }
126081
126158
  const effectiveExit = cmd.forcedExitCode != null ? cmd.forcedExitCode : isNaN(naturalExitCode) ? 1 : naturalExitCode;
126082
126159
  const effectiveStderr = cmd.forcedStderrSuffix ? (cmd.stderr || "") + cmd.forcedStderrSuffix : cmd.stderr || "";
126160
+ unlinkSafe(cmd.outPath);
126161
+ unlinkSafe(cmd.errPath);
126083
126162
  const resolve5 = cmd.resolve;
126084
126163
  this.current = null;
126085
126164
  this.pendingCancel = null;
@@ -126110,129 +126189,131 @@ class PersistentShell {
126110
126189
  return { stdout: "", stderr: "Shell has been disposed", exitCode: 1 };
126111
126190
  }
126112
126191
  if (abortSignal?.aborted) {
126113
- return {
126114
- stdout: "",
126115
- stderr: "Command aborted",
126116
- exitCode: 130
126117
- };
126118
- }
126119
- this.ensureAlive();
126120
- const proc = this.proc;
126121
- if (!proc || !proc.stdin || !proc.stdout || !proc.stderr) {
126122
- return { stdout: "", stderr: "Failed to spawn shell", exitCode: 1 };
126192
+ return { stdout: "", stderr: "Command aborted", exitCode: 130 };
126123
126193
  }
126124
- const marker = `__APEX_${randomBytes(8).toString("hex")}__`;
126125
- const exitMarkerPrefix = `${marker}_EXIT_`;
126126
- const cutoverMarker = `${marker}_CUTOVER`;
126127
- return new Promise((resolve5) => {
126128
- let resolved = false;
126129
- let timeoutTimer;
126130
- let killEscalationTimer;
126131
- const pending = {
126132
- streamedStdout: "",
126133
- authoritativeStdout: "",
126134
- cutoverSeen: false,
126135
- cutoverMarker,
126136
- stderr: "",
126137
- stdoutTruncated: false,
126138
- exitMarkerPrefix,
126139
- onData,
126140
- forcedExitCode: null,
126141
- forcedStderrSuffix: null,
126142
- resolve: (result) => {
126143
- if (resolved)
126144
- return;
126145
- resolved = true;
126146
- if (timeoutTimer)
126147
- clearTimeout(timeoutTimer);
126148
- if (killEscalationTimer)
126149
- clearTimeout(killEscalationTimer);
126150
- if (abortCleanup)
126151
- abortCleanup();
126152
- resolve5(result);
126153
- }
126154
- };
126155
- this.current = pending;
126156
- this.pendingCancel = pending.resolve;
126157
- let abortCleanup;
126158
- if (abortSignal) {
126159
- const onAbort = () => {
126160
- if (resolved)
126161
- return;
126162
- pending.forcedExitCode = 130;
126163
- pending.forcedStderrSuffix = pending.stderr ? `
126164
- (aborted)` : "(aborted)";
126165
- killDescendants(proc.pid, "SIGTERM");
126166
- killEscalationTimer = setTimeout(() => {
126194
+ const release = await this.acquireTurn();
126195
+ try {
126196
+ if (this.disposed) {
126197
+ return { stdout: "", stderr: "Shell has been disposed", exitCode: 1 };
126198
+ }
126199
+ if (abortSignal?.aborted) {
126200
+ return { stdout: "", stderr: "Command aborted", exitCode: 130 };
126201
+ }
126202
+ this.ensureAlive();
126203
+ const proc = this.proc;
126204
+ if (!proc || !proc.stdin || !proc.stdout || !proc.stderr) {
126205
+ return { stdout: "", stderr: "Failed to spawn shell", exitCode: 1 };
126206
+ }
126207
+ return await new Promise((resolve5) => {
126208
+ let resolved = false;
126209
+ let timeoutTimer;
126210
+ let abortCleanup;
126211
+ const nonceHex = randomBytes(8).toString("hex");
126212
+ const marker = `__APEX_${nonceHex}__`;
126213
+ const exitMarkerPrefix = `${marker}_EXIT_`;
126214
+ const cutoverMarker = `${marker}_CUTOVER`;
126215
+ const outPath = join18(APEX_TMP_ROOT, `${nonceHex}.out`);
126216
+ const errPath = join18(APEX_TMP_ROOT, `${nonceHex}.err`);
126217
+ const pending = {
126218
+ streamedStdout: "",
126219
+ authoritativeStdout: "",
126220
+ cutoverSeen: false,
126221
+ cutoverMarker,
126222
+ stderr: "",
126223
+ stdoutTruncated: false,
126224
+ exitMarkerPrefix,
126225
+ onData,
126226
+ forcedExitCode: null,
126227
+ forcedStderrSuffix: null,
126228
+ outPath,
126229
+ errPath,
126230
+ resolve: (result) => {
126167
126231
  if (resolved)
126168
126232
  return;
126169
- killDescendants(proc.pid, "SIGKILL");
126170
- setTimeout(() => {
126171
- if (resolved)
126172
- return;
126173
- pending.resolve({
126174
- stdout: extractFallbackStdout(pending),
126175
- stderr: (pending.stderr || "") + (pending.forcedStderrSuffix ?? ""),
126176
- exitCode: 130
126177
- });
126178
- }, 2000);
126179
- }, 500);
126233
+ resolved = true;
126234
+ if (timeoutTimer)
126235
+ clearTimeout(timeoutTimer);
126236
+ if (pending.killEscalationTimer)
126237
+ clearTimeout(pending.killEscalationTimer);
126238
+ pending._activeSalvageId = undefined;
126239
+ if (abortCleanup)
126240
+ abortCleanup();
126241
+ resolve5(result);
126242
+ }
126180
126243
  };
126181
- abortSignal.addEventListener("abort", onAbort, { once: true });
126182
- abortCleanup = () => abortSignal.removeEventListener("abort", onAbort);
126183
- }
126184
- if (timeoutSeconds != null && timeoutSeconds > 0) {
126185
- timeoutTimer = setTimeout(() => {
126186
- if (resolved)
126187
- return;
126188
- pending.forcedExitCode = 124;
126189
- killDescendants(proc.pid, "SIGTERM");
126190
- killEscalationTimer = setTimeout(() => {
126244
+ this.current = pending;
126245
+ this.pendingCancel = pending.resolve;
126246
+ if (abortSignal) {
126247
+ const onAbort = () => {
126191
126248
  if (resolved)
126192
126249
  return;
126193
- killDescendants(proc.pid, "SIGKILL");
126194
- setTimeout(() => {
126195
- if (resolved)
126196
- return;
126197
- pending.resolve({
126198
- stdout: extractFallbackStdout(pending),
126199
- stderr: pending.stderr || "",
126200
- exitCode: 124
126201
- });
126202
- }, 2000);
126203
- }, 500);
126204
- }, timeoutSeconds * 1000);
126205
- }
126206
- const tailCmd = hasStdbuf() ? `stdbuf -oL tail -n +1 -f -s 0.05 "$__APEX_OUT"` : `tail -n +1 -f -s 0.05 "$__APEX_OUT"`;
126207
- const wrapped = [
126208
- `__APEX_OUT=$(mktemp 2>/dev/null || echo /tmp/.apex_out_$$)`,
126209
- `__APEX_ERR=$(mktemp 2>/dev/null || echo /tmp/.apex_err_$$)`,
126210
- `${tailCmd} 2>/dev/null &`,
126211
- `__APEX_TAIL=$!`,
126212
- `{ ${command}
126250
+ pending.forcedExitCode = 130;
126251
+ pending.forcedStderrSuffix = pending.stderr ? `
126252
+ (aborted)` : "(aborted)";
126253
+ pending.killEscalationTimer = scheduleSalvageKill(proc.pid, pending, 130);
126254
+ };
126255
+ abortSignal.addEventListener("abort", onAbort, { once: true });
126256
+ abortCleanup = () => abortSignal.removeEventListener("abort", onAbort);
126257
+ }
126258
+ if (timeoutSeconds != null && timeoutSeconds > 0) {
126259
+ timeoutTimer = setTimeout(() => {
126260
+ if (resolved)
126261
+ return;
126262
+ pending.forcedExitCode = 124;
126263
+ pending.killEscalationTimer = scheduleSalvageKill(proc.pid, pending, 124);
126264
+ }, timeoutSeconds * 1000);
126265
+ }
126266
+ const tailCmd = hasStdbuf() ? `stdbuf -oL tail -n +1 -f -s 0.05 "$__APEX_OUT"` : `tail -n +1 -f -s 0.05 "$__APEX_OUT"`;
126267
+ const shOutPath = `'${outPath.replace(/'/g, `'\\''`)}'`;
126268
+ const shErrPath = `'${errPath.replace(/'/g, `'\\''`)}'`;
126269
+ const wrapped = [
126270
+ `__APEX_OUT=${shOutPath}`,
126271
+ `__APEX_ERR=${shErrPath}`,
126272
+ `: > "$__APEX_OUT"`,
126273
+ `: > "$__APEX_ERR"`,
126274
+ `${tailCmd} 2>/dev/null &`,
126275
+ `__APEX_TAIL=$!`,
126276
+ `{ ${command}
126213
126277
  } </dev/null >"$__APEX_OUT" 2>"$__APEX_ERR"`,
126214
- `__APEX_EC=$?`,
126215
- `sleep 0.1`,
126216
- `kill "$__APEX_TAIL" 2>/dev/null`,
126217
- `wait "$__APEX_TAIL" 2>/dev/null`,
126218
- `printf '%s\\n' "${cutoverMarker}"`,
126219
- `cat "$__APEX_OUT"`,
126220
- `cat "$__APEX_ERR" >&2`,
126221
- `rm -f "$__APEX_OUT" "$__APEX_ERR"`,
126222
- `echo "${exitMarkerPrefix}$__APEX_EC"`,
126223
- ``
126224
- ].join(`
126278
+ `__APEX_EC=$?`,
126279
+ `sleep 0.1`,
126280
+ `kill "$__APEX_TAIL" 2>/dev/null`,
126281
+ `wait "$__APEX_TAIL" 2>/dev/null`,
126282
+ `printf '%s\\n' "${cutoverMarker}"`,
126283
+ `cat "$__APEX_OUT"`,
126284
+ `cat "$__APEX_ERR" >&2`,
126285
+ `echo "${exitMarkerPrefix}$__APEX_EC"`,
126286
+ ``
126287
+ ].join(`
126225
126288
  `);
126226
- try {
126227
- proc.stdin.write(wrapped);
126228
- } catch {
126229
- pending.resolve({
126230
- stdout: "",
126231
- stderr: "Failed to write to shell stdin",
126232
- exitCode: 1
126233
- });
126234
- }
126289
+ try {
126290
+ proc.stdin.write(wrapped);
126291
+ } catch {
126292
+ pending.resolve({
126293
+ stdout: "",
126294
+ stderr: "Failed to write to shell stdin",
126295
+ exitCode: 1
126296
+ });
126297
+ }
126298
+ });
126299
+ } catch (e) {
126300
+ return {
126301
+ stdout: "",
126302
+ stderr: e instanceof Error ? e.message : String(e),
126303
+ exitCode: 1
126304
+ };
126305
+ } finally {
126306
+ release();
126307
+ }
126308
+ }
126309
+ async acquireTurn() {
126310
+ const myTurn = this.writeChain;
126311
+ let release;
126312
+ this.writeChain = new Promise((res) => {
126313
+ release = res;
126235
126314
  });
126315
+ await myTurn;
126316
+ return release;
126236
126317
  }
126237
126318
  cancelCurrentCommand() {
126238
126319
  const cmd = this.current;
@@ -126242,19 +126323,10 @@ class PersistentShell {
126242
126323
  cmd.forcedStderrSuffix = cmd.stderr ? `
126243
126324
  (cancelled by user)` : "(cancelled by user)";
126244
126325
  if (this.proc.pid && process.platform !== "win32") {
126245
- killDescendants(this.proc.pid, "SIGTERM");
126246
- setTimeout(() => {
126247
- if (this.proc?.pid)
126248
- killDescendants(this.proc.pid, "SIGKILL");
126249
- setTimeout(() => {
126250
- cmd.resolve({
126251
- stdout: extractFallbackStdout(cmd),
126252
- stderr: (cmd.stderr || "") + (cmd.forcedStderrSuffix ?? ""),
126253
- exitCode: 130
126254
- });
126255
- }, 2000);
126256
- }, 500);
126326
+ cmd.killEscalationTimer = scheduleSalvageKill(this.proc.pid, cmd, 130);
126257
126327
  } else {
126328
+ unlinkSafe(cmd.outPath);
126329
+ unlinkSafe(cmd.errPath);
126258
126330
  cmd.resolve({
126259
126331
  stdout: extractFallbackStdout(cmd),
126260
126332
  stderr: (cmd.stderr || "") + (cmd.forcedStderrSuffix ?? ""),
@@ -126267,6 +126339,13 @@ class PersistentShell {
126267
126339
  if (this.disposed)
126268
126340
  return;
126269
126341
  this.disposed = true;
126342
+ if (this.current?.killEscalationTimer) {
126343
+ clearTimeout(this.current.killEscalationTimer);
126344
+ }
126345
+ if (this.current) {
126346
+ unlinkSafe(this.current.outPath);
126347
+ unlinkSafe(this.current.errPath);
126348
+ }
126270
126349
  if (this.proc) {
126271
126350
  try {
126272
126351
  this.proc.stdin?.write(`exit
@@ -126299,10 +126378,10 @@ class PersistentShell {
126299
126378
  this.proc = null;
126300
126379
  }
126301
126380
  }
126302
- function killDescendants(rootPid, signal) {
126381
+ function enumerateDescendants(rootPid) {
126303
126382
  if (!rootPid || process.platform === "win32")
126304
- return;
126305
- const toKill = [];
126383
+ return [];
126384
+ const descendants = [];
126306
126385
  const queue = [rootPid];
126307
126386
  while (queue.length > 0) {
126308
126387
  const pid = queue.shift();
@@ -126313,25 +126392,54 @@ function killDescendants(rootPid, signal) {
126313
126392
  `)) {
126314
126393
  const child = parseInt(line, 10);
126315
126394
  if (Number.isFinite(child) && child > 0) {
126316
- toKill.push(child);
126395
+ descendants.push(child);
126317
126396
  queue.push(child);
126318
126397
  }
126319
126398
  }
126320
126399
  }
126321
126400
  } catch {}
126322
126401
  }
126323
- for (let i = toKill.length - 1;i >= 0; i--) {
126402
+ return descendants;
126403
+ }
126404
+ function signalPids(pids, signal) {
126405
+ if (process.platform === "win32")
126406
+ return;
126407
+ for (let i = pids.length - 1;i >= 0; i--) {
126324
126408
  try {
126325
- process.kill(toKill[i], signal);
126409
+ process.kill(pids[i], signal);
126326
126410
  } catch {}
126327
126411
  }
126328
126412
  }
126413
+ var SALVAGE_GRACE_MS = 200;
126414
+ function scheduleSalvageKill(rootPid, pending, exitCode) {
126415
+ if (pending.killEscalationTimer) {
126416
+ clearTimeout(pending.killEscalationTimer);
126417
+ }
126418
+ const pids = enumerateDescendants(rootPid);
126419
+ signalPids(pids, "SIGTERM");
126420
+ const salvageId = {};
126421
+ pending._activeSalvageId = salvageId;
126422
+ return setTimeout(() => {
126423
+ if (pending._activeSalvageId !== salvageId)
126424
+ return;
126425
+ const diskStdout = readTempfileCapped(pending.outPath);
126426
+ const diskStderr = readTempfileCapped(pending.errPath);
126427
+ unlinkSafe(pending.outPath);
126428
+ unlinkSafe(pending.errPath);
126429
+ signalPids(pids, "SIGKILL");
126430
+ pending.resolve({
126431
+ stdout: diskStdout || extractFallbackStdout(pending) || "(no output)",
126432
+ stderr: (diskStderr || pending.stderr || "") + (pending.forcedStderrSuffix ?? ""),
126433
+ exitCode
126434
+ });
126435
+ }, SALVAGE_GRACE_MS);
126436
+ }
126329
126437
 
126330
126438
  // src/core/agents/offSecAgent/prompt.ts
126331
- import { existsSync as existsSync12, readdirSync as readdirSync3, statSync } from "fs";
126332
- import { join as join18 } from "path";
126439
+ import { existsSync as existsSync12, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
126440
+ import { join as join19 } from "path";
126333
126441
  function buildProvidedFilesSection(sessionRootPath) {
126334
- const providedDir = join18(sessionRootPath, "provided_files");
126442
+ const providedDir = join19(sessionRootPath, "provided_files");
126335
126443
  if (!existsSync12(providedDir))
126336
126444
  return "";
126337
126445
  let entries;
@@ -126342,7 +126450,7 @@ function buildProvidedFilesSection(sessionRootPath) {
126342
126450
  }
126343
126451
  const fileEntries = entries.filter((name) => name !== "README.md").map((name) => {
126344
126452
  try {
126345
- const stat2 = statSync(join18(providedDir, name));
126453
+ const stat2 = statSync2(join19(providedDir, name));
126346
126454
  if (!stat2.isFile())
126347
126455
  return null;
126348
126456
  return { name, size: stat2.size };
@@ -126612,6 +126720,7 @@ var OperatorSettingsObject = exports_external.object({
126612
126720
  import { EventEmitter as EventEmitter3 } from "events";
126613
126721
  import { randomBytes as randomBytes2 } from "crypto";
126614
126722
  var DEFAULT_DECISION_TIMEOUT_MS = 15 * 60 * 1000;
126723
+ var INTERNAL_ID_PATTERN = /^(apr|act|tc)_\d+_[0-9a-f]{8}$/;
126615
126724
 
126616
126725
  class ApprovalGate extends EventEmitter3 {
126617
126726
  config;
@@ -126670,16 +126779,18 @@ class ApprovalGate extends EventEmitter3 {
126670
126779
  const deferred = this.pendingApprovals.get(approvalId);
126671
126780
  if (!deferred)
126672
126781
  return;
126782
+ const approval = deferred.approval;
126673
126783
  this.pendingApprovals.delete(approvalId);
126674
- const entry = this.recordAction(deferred.approval.toolName, deferred.approval.toolCallId, "denied");
126784
+ const entry = this.recordAction(approval.toolName, approval.toolCallId, "denied");
126675
126785
  entry.resultSummary = `decision_timeout:${timeoutMs}ms`;
126676
126786
  this.emitEvent({
126677
126787
  type: "approval-resolved",
126678
126788
  id: approvalId,
126679
- decision: "denied"
126789
+ decision: "denied",
126790
+ approval
126680
126791
  });
126681
126792
  this.emitEvent({ type: "action-completed", entry });
126682
- deferred.reject(new ApprovalTimeoutError(`Operator decision timeout after ${timeoutMs}ms for ${deferred.approval.toolName} — default-safe deny`));
126793
+ deferred.reject(new ApprovalTimeoutError(`Operator decision timeout after ${timeoutMs}ms for ${approval.toolName} — default-safe deny`));
126683
126794
  }
126684
126795
  approve(approvalId) {
126685
126796
  const deferred = this.pendingApprovals.get(approvalId);
@@ -126688,12 +126799,14 @@ class ApprovalGate extends EventEmitter3 {
126688
126799
  }
126689
126800
  if (deferred.timeoutHandle)
126690
126801
  clearTimeout(deferred.timeoutHandle);
126802
+ const approval = deferred.approval;
126691
126803
  this.pendingApprovals.delete(approvalId);
126692
- const entry = this.recordAction(deferred.approval.toolName, deferred.approval.toolCallId, "approved");
126804
+ const entry = this.recordAction(approval.toolName, approval.toolCallId, "approved");
126693
126805
  this.emitEvent({
126694
126806
  type: "approval-resolved",
126695
126807
  id: approvalId,
126696
- decision: "approved"
126808
+ decision: "approved",
126809
+ approval
126697
126810
  });
126698
126811
  this.emitEvent({ type: "action-completed", entry });
126699
126812
  deferred.resolve("approved");
@@ -126704,12 +126817,14 @@ class ApprovalGate extends EventEmitter3 {
126704
126817
  return;
126705
126818
  if (deferred.timeoutHandle)
126706
126819
  clearTimeout(deferred.timeoutHandle);
126820
+ const approval = deferred.approval;
126707
126821
  this.pendingApprovals.delete(approvalId);
126708
- const entry = this.recordAction(deferred.approval.toolName, deferred.approval.toolCallId, "denied");
126822
+ const entry = this.recordAction(approval.toolName, approval.toolCallId, "denied");
126709
126823
  this.emitEvent({
126710
126824
  type: "approval-resolved",
126711
126825
  id: approvalId,
126712
- decision: "denied"
126826
+ decision: "denied",
126827
+ approval
126713
126828
  });
126714
126829
  this.emitEvent({ type: "action-completed", entry });
126715
126830
  deferred.reject(new ApprovalDeniedError("Action denied by user"));
@@ -126763,7 +126878,7 @@ class ApprovalTimeoutError extends ApprovalDeniedError {
126763
126878
  init_zod();
126764
126879
  import path from "path";
126765
126880
  import os from "os";
126766
- import { existsSync as existsSync13, readFileSync as readFileSync4 } from "fs";
126881
+ import { existsSync as existsSync13, readFileSync as readFileSync5 } from "fs";
126767
126882
  init_toolset();
126768
126883
  var DEFAULT_OUTCOME_GUIDANCE = "Prove the exploit can be run but do not exfiltrate data or cause any harm to the system. " + "Create proof-of-concept exploits that demonstrate the vulnerability exists without causing damage.";
126769
126884
  var EXFIL_OUTCOME_GUIDANCE = "Exfiltrate data to extract the flag value. " + "Create proof-of-concept exploits that successfully extract the flag from the target system.";
@@ -127115,7 +127230,7 @@ async function loadOperatorState(sessionId) {
127115
127230
  const statePath = path.join(session.rootPath, "messages.json");
127116
127231
  if (!existsSync13(statePath))
127117
127232
  return null;
127118
- const data = readFileSync4(statePath, "utf-8");
127233
+ const data = readFileSync5(statePath, "utf-8");
127119
127234
  const parsed = JSON.parse(data);
127120
127235
  if (Array.isArray(parsed)) {
127121
127236
  return {
@@ -127265,8 +127380,8 @@ var sessions = {
127265
127380
  };
127266
127381
 
127267
127382
  // src/core/agents/offSecAgent/offensiveSecurityAgent.ts
127268
- import { join as join19 } from "path";
127269
- import { mkdirSync as mkdirSync12, existsSync as existsSync14 } from "fs";
127383
+ import { join as join20 } from "path";
127384
+ import { mkdirSync as mkdirSync13, existsSync as existsSync14 } from "fs";
127270
127385
  import { writeFile as writeFile4 } from "fs/promises";
127271
127386
  class OffensiveSecurityAgent {
127272
127387
  streamResult;
@@ -127311,15 +127426,15 @@ class OffensiveSecurityAgent {
127311
127426
  input.commandCancelHandle.cancel = () => shell.cancelCurrentCommand();
127312
127427
  }
127313
127428
  }
127314
- const messagesDir = input.messagesDir ?? (input.subagentId ? join19(input.session.rootPath, "subagents", input.subagentId) : input.session.rootPath);
127315
- const tracePath = input.subagentId ? join19(input.session.rootPath, "subagents", `${input.subagentId}.trace.jsonl`) : join19(messagesDir, "trace.jsonl");
127429
+ const messagesDir = input.messagesDir ?? (input.subagentId ? join20(input.session.rootPath, "subagents", input.subagentId) : input.session.rootPath);
127430
+ const tracePath = input.subagentId ? join20(input.session.rootPath, "subagents", `${input.subagentId}.trace.jsonl`) : join20(messagesDir, "trace.jsonl");
127316
127431
  const traceWriter = new StepTraceWriter({
127317
127432
  tracePath,
127318
127433
  agentId: input.subagentId ?? null,
127319
127434
  eventBus: this.eventBus
127320
127435
  });
127321
127436
  const taskDriven = input.session.config?.taskDriven ?? false;
127322
- const tasksDir = input.tasksDir ?? (taskDriven ? input.subagentId ? join19(input.session.rootPath, "subagents", `${input.subagentId}-tasks`) : join19(input.session.rootPath, "tasks") : undefined);
127437
+ const tasksDir = input.tasksDir ?? (taskDriven ? input.subagentId ? join20(input.session.rootPath, "subagents", `${input.subagentId}-tasks`) : join20(input.session.rootPath, "tasks") : undefined);
127323
127438
  const credentialManager = input.credentialManager ?? input.session.credentialManager;
127324
127439
  const builtinTools = createAllTools({
127325
127440
  session: input.session,
@@ -127390,9 +127505,9 @@ class OffensiveSecurityAgent {
127390
127505
  activeTools = activeTools.filter((t) => planSet.has(t));
127391
127506
  }
127392
127507
  if (!existsSync14(messagesDir)) {
127393
- mkdirSync12(messagesDir, { recursive: true });
127508
+ mkdirSync13(messagesDir, { recursive: true });
127394
127509
  }
127395
- const messagesPath = join19(messagesDir, "messages.json");
127510
+ const messagesPath = join20(messagesDir, "messages.json");
127396
127511
  const initialMessagesRef = {
127397
127512
  current: input.messages ? [...input.messages] : [
127398
127513
  {
@@ -127550,4 +127665,4 @@ function wrapToolsWithApprovalGate(tools, gate, exemptToolNames) {
127550
127665
  return wrapped;
127551
127666
  }
127552
127667
 
127553
- export { CweEntrySchema, ValidatedCweEntrySchema, hasCanonicalName, AgentEventBus, FindingsRegistry, planFilePath, readPlan, hasPlan, ASK_USER_QUESTIONS_TOOL_NAME, createAllTools, ALL_TOOL_NAMES, PLAN_MODE_TOOL_NAMES, SKILL_TOOL_NAMES, buildBaseSystemPrompt, OPERATOR_MODES, OPERATOR_MODE_CYCLE, createInitialOperatorState, ApprovalGate, normalizeMessages, sessions, StepTraceWriter, OffensiveSecurityAgent };
127668
+ export { CweEntrySchema, ValidatedCweEntrySchema, hasCanonicalName, AgentEventBus, FindingsRegistry, planFilePath, readPlan, hasPlan, ASK_USER_QUESTIONS_TOOL_NAME, createAllTools, ALL_TOOL_NAMES, PLAN_MODE_TOOL_NAMES, SKILL_TOOL_NAMES, buildBaseSystemPrompt, OPERATOR_MODES, OPERATOR_MODE_CYCLE, createInitialOperatorState, INTERNAL_ID_PATTERN, ApprovalGate, normalizeMessages, sessions, StepTraceWriter, OffensiveSecurityAgent };