@pensar/apex 2.4.0 → 2.5.0-canary.41357c27

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 (68) hide show
  1. package/build/{agent-nhs1w5w0.js → agent-092hrrbn.js} +11 -10
  2. package/build/{agent-5ejt5vpz.js → agent-jgdfbwse.js} +9 -8
  3. package/build/agent-z3ydv420.js +20 -0
  4. package/build/{apps-17wvz1d7.js → apps-pxwa5s9f.js} +72 -31
  5. package/build/{auth-z3h9859n.js → auth-j34f09ke.js} +25 -20
  6. package/build/authentication-jt9fq8y9.js +20 -0
  7. package/build/blackboxAgent-vwtk3hv1.js +20 -0
  8. package/build/blackboxPentest-nzn4xjd4.js +70 -0
  9. package/build/{cli-vnynf0js.js → cli-13vsx08y.js} +10 -4
  10. package/build/{cli-mavved45.js → cli-1e69fd35.js} +46 -25
  11. package/build/cli-53rm0rrz.js +15 -0
  12. package/build/cli-68260ckj.js +12136 -0
  13. package/build/{cli-tkc598ey.js → cli-70banr6y.js} +411 -280
  14. package/build/{cli-xshasbwe.js → cli-7hqdp86d.js} +34 -4
  15. package/build/cli-7q3ae3ft.js +6 -0
  16. package/build/cli-9pbk8m32.js +32 -0
  17. package/build/{cli-tznv8pf1.js → cli-9y49bzhd.js} +1 -1
  18. package/build/{cli-swpbx60z.js → cli-avmhkjtv.js} +1 -1481
  19. package/build/{cli-9rhzhgx2.js → cli-epqtwyeb.js} +1 -1
  20. package/build/cli-knd276ed.js +1485 -0
  21. package/build/{cli-repbyhkk.js → cli-mjd75xw4.js} +1129 -525
  22. package/build/{cli-5k33webc.js → cli-mtavwpav.js} +45 -43
  23. package/build/{cli-0n4r54hq.js → cli-naapss75.js} +1 -1
  24. package/build/{cli-gq40s5b3.js → cli-pd9j03q2.js} +5 -3
  25. package/build/{cli-qqt4gj1w.js → cli-pepts4ha.js} +5 -3
  26. package/build/{cli-32z0017y.js → cli-q2sq1qkn.js} +2 -2
  27. package/build/{cli-72cvcqhg.js → cli-x4e10v99.js} +1 -1
  28. package/build/{cli-2cbwdk78.js → cli-xan180ab.js} +1 -1
  29. package/build/{cli-vq52kp7j.js → cli-xp52xsqm.js} +23 -5
  30. package/build/{cli-k8kc47pq.js → cli-ygesx0vf.js} +3 -3
  31. package/build/{cli-b1adytsy.js → cli-yzhjh7x1.js} +28 -5
  32. package/build/cli.js +641 -95
  33. package/build/{config-f1mj4nhd.js → config-v87zm6cx.js} +18 -15
  34. package/build/{doctor-ekneewa3.js → doctor-705xb28k.js} +8 -7
  35. package/build/{fastStrike-8zka43xs.js → fastStrike-wp2tvcnq.js} +13 -10
  36. package/build/{fixes-b89s5haw.js → fixes-x8y42dh5.js} +25 -20
  37. package/build/getMachineId-bsd-xj3bn2fv.js +36 -0
  38. package/build/getMachineId-darwin-07jzjcx6.js +36 -0
  39. package/build/getMachineId-linux-ahngynxd.js +29 -0
  40. package/build/getMachineId-unsupported-vy43b44z.js +19 -0
  41. package/build/getMachineId-win-8x66cynz.js +38 -0
  42. package/build/{index-mtq7kmxz.js → index-5wh7gq37.js} +4 -2
  43. package/build/{index-sf16jm0m.js → index-6f06c8v0.js} +9 -7
  44. package/build/{index-hqjdg6fg.js → index-g0fvrp9n.js} +17 -9
  45. package/build/{index-y5w6n3tb.js → index-hdzja756.js} +2 -2
  46. package/build/{index-4ad3sdwk.js → index-q1hh6p80.js} +4 -4
  47. package/build/{index-ghwf5z3v.js → index-qpmdq6vj.js} +3 -3
  48. package/build/{index-6d22pyxt.js → index-sfwny7gx.js} +1756 -1213
  49. package/build/{index-rbzhk712.js → index-sx52n7s9.js} +11 -10
  50. package/build/{issues-xx5bs4md.js → issues-1g7j8ktr.js} +82 -26
  51. package/build/{logs-qtxe51w2.js → logs-6rjwnwz7.js} +25 -20
  52. package/build/{offesecAgent-b9e2xm6v.js → offesecAgent-frnz6ngh.js} +10 -9
  53. package/build/pentest-3w1jgsg7.js +30 -0
  54. package/build/{pentests-6ks3szc4.js → pentests-wxacefk4.js} +26 -21
  55. package/build/{targetedPentest-s1ptvq8e.js → targetedPentest-w1dze9hg.js} +11 -10
  56. package/build/{targets-sxygyj87.js → targets-vhxkvbmg.js} +27 -22
  57. package/build/threatModel-2k259rx1.js +29 -0
  58. package/build/{uninstall-tvsh81v8.js → uninstall-j8dmsaz5.js} +6 -3
  59. package/build/{upload-7wdyyqmr.js → upload-7pz6yt0n.js} +8 -7
  60. package/build/{utils-7fwdkqk6.js → utils-2gvfe1dz.js} +7 -6
  61. package/package.json +8 -2
  62. package/build/agent-mvpgvgks.js +0 -19
  63. package/build/authentication-3s97cpk4.js +0 -19
  64. package/build/blackboxAgent-gw0a1ca4.js +0 -19
  65. package/build/blackboxPentest-44333zss.js +0 -37
  66. package/build/main-mmjp338j.js +0 -324
  67. package/build/pentest-xtc1sjdw.js +0 -29
  68. package/build/threatModel-xsm6fwk5.js +0 -27
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  detectOSAndEnhancePrompt
3
- } from "./cli-tznv8pf1.js";
3
+ } from "./cli-9y49bzhd.js";
4
4
  import {
5
5
  parseTargetUrl
6
6
  } from "./cli-c8131c4q.js";
@@ -10,6 +10,7 @@ import {
10
10
  create,
11
11
  createLogger,
12
12
  generateObjectResponse,
13
+ getActiveTraceCorrelation,
13
14
  getApexTracer,
14
15
  hasToolCall,
15
16
  init_ai,
@@ -24,22 +25,25 @@ import {
24
25
  list,
25
26
  newMessageId,
26
27
  newPartId,
28
+ newRunId,
27
29
  newSessionId,
28
30
  read,
31
+ registerActiveRootSpan,
29
32
  require_tslib,
30
33
  scopedLogger,
31
34
  stepCountIs,
32
35
  streamResponse,
36
+ unregisterActiveRootSpan,
33
37
  withSubagentSessionBaggage,
34
38
  write
35
- } from "./cli-tkc598ey.js";
39
+ } from "./cli-70banr6y.js";
36
40
  import {
37
41
  ensureValidToken,
38
42
  getPensarApiUrl,
39
43
  init_auth,
40
44
  init_constants,
41
45
  signGatewayRequest
42
- } from "./cli-0n4r54hq.js";
46
+ } from "./cli-naapss75.js";
43
47
  import {
44
48
  _enum,
45
49
  _null,
@@ -60,17 +64,23 @@ import {
60
64
  optional,
61
65
  preprocess,
62
66
  record,
63
- require_src,
64
67
  safeParse,
65
68
  string,
66
69
  tool,
67
70
  union,
68
71
  unknown
69
- } from "./cli-swpbx60z.js";
72
+ } from "./cli-avmhkjtv.js";
70
73
  import {
71
74
  config,
72
75
  init_config
73
- } from "./cli-72cvcqhg.js";
76
+ } from "./cli-x4e10v99.js";
77
+ import {
78
+ getCurrentVersion,
79
+ init_installation
80
+ } from "./cli-13vsx08y.js";
81
+ import {
82
+ require_src
83
+ } from "./cli-knd276ed.js";
74
84
  import {
75
85
  __commonJS,
76
86
  __require,
@@ -102763,12 +102773,7 @@ function camoufoxWindowOptions(window2) {
102763
102773
  const [width, height] = window2;
102764
102774
  return {
102765
102775
  window: [width, height],
102766
- screen: {
102767
- minWidth: width,
102768
- maxWidth: width,
102769
- minHeight: height,
102770
- maxHeight: height
102771
- }
102776
+ screen: { minWidth: width, minHeight: height }
102772
102777
  };
102773
102778
  }
102774
102779
  async function resolveCamoufoxLaunchOptions(headless, opts) {
@@ -104466,6 +104471,19 @@ function assertUrlInScope(url, ctx) {
104466
104471
  throw new ScopeViolationError(hostname, allowedHosts);
104467
104472
  }
104468
104473
  }
104474
+ function assertFindingEndpointInScope(endpoint, ctx) {
104475
+ const allowedHosts = getAllowedHosts(ctx);
104476
+ if (allowedHosts.length === 0)
104477
+ return;
104478
+ if (!/^https?:\/\//i.test(endpoint.trim()))
104479
+ return;
104480
+ const hostname = extractHostname2(endpoint);
104481
+ if (!hostname)
104482
+ return;
104483
+ if (!isHostAllowed(hostname, allowedHosts)) {
104484
+ throw new ScopeViolationError(hostname, allowedHosts);
104485
+ }
104486
+ }
104469
104487
  function extractHostsFromCommand(command) {
104470
104488
  const hosts = new Set;
104471
104489
  const urlPattern = /https?:\/\/[^\s"'`;|&)<>]+/gi;
@@ -105055,12 +105073,8 @@ const fs = require('fs');
105055
105073
  ...${JSON.stringify(CAMOUFOX_OPTIONS)},
105056
105074
  headless: __headless,
105057
105075
  window: __window,
105058
- screen: {
105059
- minWidth: __window[0],
105060
- maxWidth: __window[0],
105061
- minHeight: __window[1],
105062
- maxHeight: __window[1],
105063
- },
105076
+ // Floor only — exact-pinning a 720px height throws in browserforge.
105077
+ screen: { minWidth: __window[0], minHeight: __window[1] },
105064
105078
  });
105065
105079
  fs.writeFileSync('${SANDBOX_CAMOU_CACHE}', JSON.stringify(__camou));
105066
105080
  }
@@ -106761,7 +106775,7 @@ IMPORTANT: Pass protectedEndpoints in authHints when you've discovered 401/403 e
106761
106775
  if (credentials) {
106762
106776
  ctx.session.credentialManager.addFromAuthCredentials(credentials);
106763
106777
  }
106764
- const { runAuthenticationAgent } = await import("./authentication-3s97cpk4.js");
106778
+ const { runAuthenticationAgent } = await import("./authentication-jt9fq8y9.js");
106765
106779
  const localBus = new AgentEventBus;
106766
106780
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
106767
106781
  const result = await runAuthenticationAgent({
@@ -107555,7 +107569,7 @@ async function generateThreatModelForEndpoint(ctx, input) {
107555
107569
  return threatModelLimiter(async () => {
107556
107570
  if (ctx.abortSignal?.aborted)
107557
107571
  return null;
107558
- const { CodeAgent } = await import("./agent-mvpgvgks.js");
107572
+ const { CodeAgent } = await import("./agent-z3ydv420.js");
107559
107573
  const subagentId = newSessionId();
107560
107574
  const subagentName = `Threat Model: ${input.routePath}`;
107561
107575
  ctx.eventBus?.emit("subagent-spawn", {
@@ -108044,6 +108058,16 @@ import {
108044
108058
  } from "node:fs";
108045
108059
  import { join as join13 } from "node:path";
108046
108060
 
108061
+ // src/lib/attack-path/types.ts
108062
+ init_zod();
108063
+ var AttackPathSchema = exports_external.array(exports_external.object({
108064
+ applicationId: exports_external.string().optional(),
108065
+ applicationName: exports_external.string().optional(),
108066
+ host: exports_external.string().optional(),
108067
+ relationshipType: exports_external.string().optional(),
108068
+ notes: exports_external.string().optional()
108069
+ }));
108070
+
108047
108071
  // src/lib/cwe/types.ts
108048
108072
  init_zod();
108049
108073
  var CweEntrySchema = exports_external.object({
@@ -108366,6 +108390,47 @@ var MAX_SEVERITY = {
108366
108390
  eq4: { 0: 6, 1: 5, 2: 4 },
108367
108391
  eq5: { 0: 1, 1: 1, 2: 1 }
108368
108392
  };
108393
+ var MAX_COMPOSED = {
108394
+ eq1: {
108395
+ 0: ["AV:N/PR:N/UI:N/"],
108396
+ 1: ["AV:A/PR:N/UI:N/", "AV:N/PR:L/UI:N/", "AV:N/PR:N/UI:P/"],
108397
+ 2: ["AV:P/PR:N/UI:N/", "AV:A/PR:L/UI:P/"]
108398
+ },
108399
+ eq2: {
108400
+ 0: ["AC:L/AT:N/"],
108401
+ 1: ["AC:H/AT:N/", "AC:L/AT:P/"]
108402
+ },
108403
+ eq3: {
108404
+ 0: {
108405
+ "0": ["VC:H/VI:H/VA:H/CR:H/IR:H/AR:H/"],
108406
+ "1": ["VC:H/VI:H/VA:L/CR:M/IR:M/AR:H/", "VC:H/VI:H/VA:H/CR:M/IR:M/AR:M/"]
108407
+ },
108408
+ 1: {
108409
+ "0": ["VC:L/VI:H/VA:H/CR:H/IR:H/AR:H/", "VC:H/VI:L/VA:H/CR:H/IR:H/AR:H/"],
108410
+ "1": [
108411
+ "VC:L/VI:H/VA:L/CR:H/IR:M/AR:H/",
108412
+ "VC:L/VI:H/VA:H/CR:H/IR:M/AR:M/",
108413
+ "VC:H/VI:L/VA:H/CR:M/IR:H/AR:M/",
108414
+ "VC:H/VI:L/VA:L/CR:M/IR:H/AR:H/",
108415
+ "VC:L/VI:L/VA:H/CR:H/IR:H/AR:M/"
108416
+ ]
108417
+ },
108418
+ 2: {
108419
+ "1": ["VC:L/VI:L/VA:L/CR:H/IR:H/AR:H/"]
108420
+ }
108421
+ },
108422
+ eq4: {
108423
+ 0: ["SC:H/SI:S/SA:S/"],
108424
+ 1: ["SC:H/SI:H/SA:H/"],
108425
+ 2: ["SC:L/SI:L/SA:L/"]
108426
+ },
108427
+ eq5: {
108428
+ 0: ["E:A/"],
108429
+ 1: ["E:P/"],
108430
+ 2: ["E:U/"]
108431
+ }
108432
+ };
108433
+ var NO_IMPACT_METRICS = ["VC", "VI", "VA", "SC", "SI", "SA"];
108369
108434
  var STEP = 0.1;
108370
108435
  var EPSILON = 10 ** -6;
108371
108436
 
@@ -108414,6 +108479,12 @@ var ENVIRONMENTAL_METRICS = [
108414
108479
  "MSA"
108415
108480
  ];
108416
108481
  var SUPPLEMENTAL_METRICS = ["S", "AU", "R", "V", "RE", "U"];
108482
+ var KNOWN_METRICS = new Set([
108483
+ ...BASE_METRICS,
108484
+ ...THREAT_METRICS,
108485
+ ...ENVIRONMENTAL_METRICS,
108486
+ ...SUPPLEMENTAL_METRICS
108487
+ ]);
108417
108488
  function buildVectorString(metrics) {
108418
108489
  const parts = ["CVSS:4.0"];
108419
108490
  for (const metric of BASE_METRICS) {
@@ -108442,39 +108513,49 @@ function buildVectorString(metrics) {
108442
108513
  }
108443
108514
  return parts.join("/");
108444
108515
  }
108445
- function getEffectiveValue(metrics, baseMetric, modifiedMetric) {
108446
- if (modifiedMetric) {
108447
- const modValue = metrics[modifiedMetric];
108448
- if (modValue && modValue !== "X") {
108449
- return modValue;
108450
- }
108451
- }
108452
- return metrics[baseMetric] ?? "";
108516
+ var WORST_CASE_DEFAULTS = {
108517
+ E: "A",
108518
+ CR: "H",
108519
+ IR: "H",
108520
+ AR: "H"
108521
+ };
108522
+ function getEffectiveValue(metrics, metric) {
108523
+ const record3 = metrics;
108524
+ const selected = record3[metric] ?? "X";
108525
+ const worstCase = WORST_CASE_DEFAULTS[metric];
108526
+ if (worstCase !== undefined && selected === "X") {
108527
+ return worstCase;
108528
+ }
108529
+ const modified = record3[`M${metric}`];
108530
+ if (modified !== undefined && modified !== "X") {
108531
+ return modified;
108532
+ }
108533
+ return selected;
108453
108534
  }
108454
108535
  function computeEQ1(metrics) {
108455
- const av = getEffectiveValue(metrics, "AV", "MAV");
108456
- const pr = getEffectiveValue(metrics, "PR", "MPR");
108457
- const ui = getEffectiveValue(metrics, "UI", "MUI");
108536
+ const av = getEffectiveValue(metrics, "AV");
108537
+ const pr = getEffectiveValue(metrics, "PR");
108538
+ const ui = getEffectiveValue(metrics, "UI");
108458
108539
  if (av === "N" && pr === "N" && ui === "N") {
108459
108540
  return 0;
108460
108541
  }
108461
- if (!(av === "P" || pr === "H" || ui === "A")) {
108542
+ if ((av === "N" || pr === "N" || ui === "N") && av !== "P") {
108462
108543
  return 1;
108463
108544
  }
108464
108545
  return 2;
108465
108546
  }
108466
108547
  function computeEQ2(metrics) {
108467
- const ac = getEffectiveValue(metrics, "AC", "MAC");
108468
- const at = getEffectiveValue(metrics, "AT", "MAT");
108548
+ const ac = getEffectiveValue(metrics, "AC");
108549
+ const at = getEffectiveValue(metrics, "AT");
108469
108550
  if (ac === "L" && at === "N") {
108470
108551
  return 0;
108471
108552
  }
108472
108553
  return 1;
108473
108554
  }
108474
108555
  function computeEQ3(metrics) {
108475
- const vc = getEffectiveValue(metrics, "VC", "MVC");
108476
- const vi = getEffectiveValue(metrics, "VI", "MVI");
108477
- const va = getEffectiveValue(metrics, "VA", "MVA");
108556
+ const vc = getEffectiveValue(metrics, "VC");
108557
+ const vi = getEffectiveValue(metrics, "VI");
108558
+ const va = getEffectiveValue(metrics, "VA");
108478
108559
  if (vc === "H" && vi === "H") {
108479
108560
  return 0;
108480
108561
  }
@@ -108484,11 +108565,11 @@ function computeEQ3(metrics) {
108484
108565
  return 2;
108485
108566
  }
108486
108567
  function computeEQ4(metrics) {
108487
- const msi = metrics.MSI || "X";
108488
- const msa = metrics.MSA || "X";
108489
- const sc = getEffectiveValue(metrics, "SC", "MSC");
108490
- const si = msi !== "X" ? msi : metrics.SI;
108491
- const sa = msa !== "X" ? msa : metrics.SA;
108568
+ const msi = getEffectiveValue(metrics, "MSI");
108569
+ const msa = getEffectiveValue(metrics, "MSA");
108570
+ const sc = getEffectiveValue(metrics, "SC");
108571
+ const si = getEffectiveValue(metrics, "SI");
108572
+ const sa = getEffectiveValue(metrics, "SA");
108492
108573
  if (msi === "S" || msa === "S") {
108493
108574
  return 0;
108494
108575
  }
@@ -108498,8 +108579,8 @@ function computeEQ4(metrics) {
108498
108579
  return 2;
108499
108580
  }
108500
108581
  function computeEQ5(metrics) {
108501
- const e = metrics.E || "A";
108502
- if (e === "A" || e === "X") {
108582
+ const e = getEffectiveValue(metrics, "E");
108583
+ if (e === "A") {
108503
108584
  return 0;
108504
108585
  }
108505
108586
  if (e === "P") {
@@ -108508,12 +108589,12 @@ function computeEQ5(metrics) {
108508
108589
  return 2;
108509
108590
  }
108510
108591
  function computeEQ6(metrics) {
108511
- const cr = metrics.CR || "H";
108512
- const ir = metrics.IR || "H";
108513
- const ar = metrics.AR || "H";
108514
- const vc = getEffectiveValue(metrics, "VC", "MVC");
108515
- const vi = getEffectiveValue(metrics, "VI", "MVI");
108516
- const va = getEffectiveValue(metrics, "VA", "MVA");
108592
+ const cr = getEffectiveValue(metrics, "CR");
108593
+ const ir = getEffectiveValue(metrics, "IR");
108594
+ const ar = getEffectiveValue(metrics, "AR");
108595
+ const vc = getEffectiveValue(metrics, "VC");
108596
+ const vi = getEffectiveValue(metrics, "VI");
108597
+ const va = getEffectiveValue(metrics, "VA");
108517
108598
  if (cr === "H" && vc === "H" || ir === "H" && vi === "H" || ar === "H" && va === "H") {
108518
108599
  return 0;
108519
108600
  }
@@ -108529,116 +108610,130 @@ function computeMacroVector(metrics) {
108529
108610
  return `${eq1}${eq2}${eq3}${eq4}${eq5}${eq6}`;
108530
108611
  }
108531
108612
  function hasNoImpact(metrics) {
108532
- const vc = getEffectiveValue(metrics, "VC", "MVC");
108533
- const vi = getEffectiveValue(metrics, "VI", "MVI");
108534
- const va = getEffectiveValue(metrics, "VA", "MVA");
108535
- const sc = getEffectiveValue(metrics, "SC", "MSC");
108536
- const si = metrics.MSI !== "X" && metrics.MSI ? metrics.MSI : metrics.SI;
108537
- const sa = metrics.MSA !== "X" && metrics.MSA ? metrics.MSA : metrics.SA;
108538
- return vc === "N" && vi === "N" && va === "N" && sc === "N" && si === "N" && sa === "N";
108613
+ return NO_IMPACT_METRICS.every((metric) => getEffectiveValue(metrics, metric) === "N");
108539
108614
  }
108540
- function getMetricDistance(metrics, metric) {
108541
- const levels = METRIC_LEVELS[metric];
108542
- if (!levels)
108543
- return 0;
108544
- let value;
108545
- const modifiedMetric = `M${metric}`;
108546
- const metricsRecord = metrics;
108547
- if (metricsRecord[modifiedMetric] && metricsRecord[modifiedMetric] !== "X") {
108548
- value = metricsRecord[modifiedMetric] ?? "";
108549
- } else {
108550
- value = metricsRecord[metric] ?? "";
108615
+ function parseMacroVector(macroVector) {
108616
+ return {
108617
+ eq1: Number(macroVector[0]),
108618
+ eq2: Number(macroVector[1]),
108619
+ eq3: Number(macroVector[2]),
108620
+ eq4: Number(macroVector[3]),
108621
+ eq5: Number(macroVector[4]),
108622
+ eq6: Number(macroVector[5])
108623
+ };
108624
+ }
108625
+ function lowerMacroVectorScore(eq, step) {
108626
+ const stepped = { ...eq, ...step };
108627
+ return MACROVECTOR_LOOKUP[`${stepped.eq1}${stepped.eq2}${stepped.eq3}${stepped.eq4}${stepped.eq5}${stepped.eq6}`];
108628
+ }
108629
+ function lowerEq3Eq6Score(eq) {
108630
+ if (eq.eq3 === 0 && eq.eq6 === 0) {
108631
+ const viaEq6 = lowerMacroVectorScore(eq, { eq6: eq.eq6 + 1 });
108632
+ const viaEq3 = lowerMacroVectorScore(eq, { eq3: eq.eq3 + 1 });
108633
+ if (viaEq6 === undefined || viaEq3 === undefined) {
108634
+ return;
108635
+ }
108636
+ return Math.max(viaEq6, viaEq3);
108637
+ }
108638
+ if (eq.eq3 === 1 && eq.eq6 === 0) {
108639
+ return lowerMacroVectorScore(eq, { eq6: eq.eq6 + 1 });
108640
+ }
108641
+ if (eq.eq3 < 2) {
108642
+ return lowerMacroVectorScore(eq, { eq3: eq.eq3 + 1 });
108551
108643
  }
108552
- if (metric === "E" && (!value || value === "X")) {
108553
- value = "A";
108644
+ return lowerMacroVectorScore(eq, { eq3: eq.eq3 + 1, eq6: eq.eq6 + 1 });
108645
+ }
108646
+ function composeMaxVectors(eq) {
108647
+ const eq3Maxima = MAX_COMPOSED.eq3[eq.eq3]?.[eq.eq6];
108648
+ if (eq3Maxima === undefined) {
108649
+ throw new Error(`No max severity vector for eq3=${eq.eq3}, eq6=${eq.eq6}`);
108554
108650
  }
108555
- if ((metric === "CR" || metric === "IR" || metric === "AR") && (!value || value === "X")) {
108556
- value = "H";
108651
+ const vectors = [];
108652
+ for (const eq1Max of MAX_COMPOSED.eq1[eq.eq1]) {
108653
+ for (const eq2Max of MAX_COMPOSED.eq2[eq.eq2]) {
108654
+ for (const eq3Max of eq3Maxima) {
108655
+ for (const eq4Max of MAX_COMPOSED.eq4[eq.eq4]) {
108656
+ for (const eq5Max of MAX_COMPOSED.eq5[eq.eq5]) {
108657
+ vectors.push(eq1Max + eq2Max + eq3Max + eq4Max + eq5Max);
108658
+ }
108659
+ }
108660
+ }
108661
+ }
108557
108662
  }
108558
- return levels[value] || 0;
108663
+ return vectors;
108664
+ }
108665
+ function extractMaxVectorValue(metric, maxVector) {
108666
+ const start = maxVector.indexOf(`${metric}:`);
108667
+ if (start < 0) {
108668
+ throw new Error(`Metric ${metric} missing from max vector ${maxVector}`);
108669
+ }
108670
+ const rest = maxVector.slice(start + metric.length + 1);
108671
+ const end = rest.indexOf("/");
108672
+ return end > 0 ? rest.slice(0, end) : rest;
108559
108673
  }
108560
- function getNextLowerScore(macroVector, position) {
108561
- const digits = macroVector.split("").map(Number);
108562
- digits[position]++;
108563
- const nextMacroVector = digits.join("");
108564
- return MACROVECTOR_LOOKUP[nextMacroVector] ?? null;
108674
+ function severityDistances(metrics, maxVector) {
108675
+ const distances = {};
108676
+ for (const [metric, levels] of Object.entries(METRIC_LEVELS)) {
108677
+ const value = getEffectiveValue(metrics, metric);
108678
+ const maxValue = extractMaxVectorValue(metric, maxVector);
108679
+ const level = levels[value];
108680
+ const maxLevel = levels[maxValue];
108681
+ if (level === undefined) {
108682
+ throw new Error(`Unknown value ${metric}:${value}`);
108683
+ }
108684
+ if (maxLevel === undefined) {
108685
+ throw new Error(`Unknown value ${metric}:${maxValue} in ${maxVector}`);
108686
+ }
108687
+ distances[metric] = level - maxLevel;
108688
+ }
108689
+ return distances;
108565
108690
  }
108566
- function interpolateScore(metrics, macroVector, baseScore) {
108567
- const eq1 = parseInt(macroVector[0], 10);
108568
- const eq2 = parseInt(macroVector[1], 10);
108569
- const eq3 = parseInt(macroVector[2], 10);
108570
- const eq4 = parseInt(macroVector[3], 10);
108571
- const eq5 = parseInt(macroVector[4], 10);
108572
- const eq6 = parseInt(macroVector[5], 10);
108573
- let meanDistance = 0;
108574
- let eqCount = 0;
108575
- const eq1NextLower = getNextLowerScore(macroVector, 0);
108576
- if (eq1NextLower !== null) {
108577
- const msd = baseScore - eq1NextLower;
108578
- const maxDepth = MAX_SEVERITY.eq1[eq1] || 1;
108579
- const avDist = getMetricDistance(metrics, "AV");
108580
- const prDist = getMetricDistance(metrics, "PR");
108581
- const uiDist = getMetricDistance(metrics, "UI");
108582
- const severityDist = avDist + prDist + uiDist;
108583
- const normalizedDist = severityDist / (maxDepth * STEP);
108584
- meanDistance += msd * normalizedDist;
108585
- eqCount++;
108586
- }
108587
- const eq2NextLower = getNextLowerScore(macroVector, 1);
108588
- if (eq2NextLower !== null) {
108589
- const msd = baseScore - eq2NextLower;
108590
- const maxDepth = MAX_SEVERITY.eq2[eq2] || 1;
108591
- const acDist = getMetricDistance(metrics, "AC");
108592
- const atDist = getMetricDistance(metrics, "AT");
108593
- const severityDist = acDist + atDist;
108594
- const normalizedDist = severityDist / (maxDepth * STEP);
108595
- meanDistance += msd * normalizedDist;
108596
- eqCount++;
108597
- }
108598
- const eq3eq6MaxSeverity = MAX_SEVERITY.eq3eq6;
108599
- if (eq3eq6MaxSeverity[eq3] && eq3eq6MaxSeverity[eq3][eq6] !== undefined) {
108600
- const eq3NextLower = getNextLowerScore(macroVector, 2);
108601
- if (eq3NextLower !== null) {
108602
- const msd = baseScore - eq3NextLower;
108603
- const maxDepth = eq3eq6MaxSeverity[eq3][eq6] || 1;
108604
- const vcDist = getMetricDistance(metrics, "VC");
108605
- const viDist = getMetricDistance(metrics, "VI");
108606
- const vaDist = getMetricDistance(metrics, "VA");
108607
- const crDist = getMetricDistance(metrics, "CR");
108608
- const irDist = getMetricDistance(metrics, "IR");
108609
- const arDist = getMetricDistance(metrics, "AR");
108610
- const severityDist = vcDist + viDist + vaDist + crDist + irDist + arDist;
108611
- const normalizedDist = severityDist / (maxDepth * STEP);
108612
- meanDistance += msd * normalizedDist;
108613
- eqCount++;
108614
- }
108615
- }
108616
- const eq4NextLower = getNextLowerScore(macroVector, 3);
108617
- if (eq4NextLower !== null) {
108618
- const msd = baseScore - eq4NextLower;
108619
- const maxDepth = MAX_SEVERITY.eq4[eq4] || 1;
108620
- const scDist = getMetricDistance(metrics, "SC");
108621
- const siDist = getMetricDistance(metrics, "SI");
108622
- const saDist = getMetricDistance(metrics, "SA");
108623
- const severityDist = scDist + siDist + saDist;
108624
- const normalizedDist = severityDist / (maxDepth * STEP);
108625
- meanDistance += msd * normalizedDist;
108626
- eqCount++;
108627
- }
108628
- const eq5NextLower = getNextLowerScore(macroVector, 4);
108629
- if (eq5NextLower !== null) {
108630
- const msd = baseScore - eq5NextLower;
108631
- const maxDepth = MAX_SEVERITY.eq5[eq5] || 1;
108632
- const eDist = getMetricDistance(metrics, "E");
108633
- const normalizedDist = eDist / (maxDepth * STEP);
108634
- meanDistance += msd * normalizedDist;
108635
- eqCount++;
108636
- }
108637
- const avgDistance = eqCount > 0 ? meanDistance / eqCount : 0;
108638
- let finalScore = baseScore - avgDistance;
108639
- finalScore = Math.max(0, Math.min(10, finalScore));
108640
- finalScore = Math.round(finalScore * 10) / 10;
108641
- return finalScore;
108691
+ function interpolateScore(metrics, macroVector, macroScore) {
108692
+ const eq = parseMacroVector(macroVector);
108693
+ let distances;
108694
+ for (const maxVector of composeMaxVectors(eq)) {
108695
+ distances = severityDistances(metrics, maxVector);
108696
+ if (Object.values(distances).every((distance) => distance >= 0)) {
108697
+ break;
108698
+ }
108699
+ }
108700
+ if (distances === undefined) {
108701
+ throw new Error(`No max vectors composed for MacroVector ${macroVector}`);
108702
+ }
108703
+ const severityDistance = {
108704
+ eq1: distances.AV + distances.PR + distances.UI,
108705
+ eq2: distances.AC + distances.AT,
108706
+ eq3eq6: distances.VC + distances.VI + distances.VA + distances.CR + distances.IR + distances.AR,
108707
+ eq4: distances.SC + distances.SI + distances.SA
108708
+ };
108709
+ const lowerScore = {
108710
+ eq1: lowerMacroVectorScore(eq, { eq1: eq.eq1 + 1 }),
108711
+ eq2: lowerMacroVectorScore(eq, { eq2: eq.eq2 + 1 }),
108712
+ eq3eq6: lowerEq3Eq6Score(eq),
108713
+ eq4: lowerMacroVectorScore(eq, { eq4: eq.eq4 + 1 })
108714
+ };
108715
+ const macroVectorDepth = {
108716
+ eq1: MAX_SEVERITY.eq1[eq.eq1] * STEP,
108717
+ eq2: MAX_SEVERITY.eq2[eq.eq2] * STEP,
108718
+ eq3eq6: MAX_SEVERITY.eq3eq6[eq.eq3][eq.eq6] * STEP,
108719
+ eq4: MAX_SEVERITY.eq4[eq.eq4] * STEP
108720
+ };
108721
+ let existingLowerCount = 0;
108722
+ let proportionalDistance = 0;
108723
+ for (const key of ["eq1", "eq2", "eq3eq6", "eq4"]) {
108724
+ const lower = lowerScore[key];
108725
+ if (lower === undefined) {
108726
+ continue;
108727
+ }
108728
+ existingLowerCount++;
108729
+ proportionalDistance += (macroScore - lower) * (severityDistance[key] / macroVectorDepth[key]);
108730
+ }
108731
+ if (lowerMacroVectorScore(eq, { eq5: eq.eq5 + 1 }) !== undefined) {
108732
+ existingLowerCount++;
108733
+ }
108734
+ const meanDistance = existingLowerCount === 0 ? 0 : proportionalDistance / existingLowerCount;
108735
+ const score = Math.max(0, Math.min(10, macroScore - meanDistance));
108736
+ return Math.round((score + EPSILON) * 10) / 10;
108642
108737
  }
108643
108738
  function calculateCVSS4Score(metrics) {
108644
108739
  if (hasNoImpact(metrics)) {
@@ -109480,7 +109575,7 @@ init_lazyLogger();
109480
109575
  var log6 = scopedLogger(() => createLogger("FindingJudge"));
109481
109576
  async function judgeFinding(input, ctx) {
109482
109577
  try {
109483
- const { FindingJudgeAgent } = await import("./agent-5ejt5vpz.js");
109578
+ const { FindingJudgeAgent } = await import("./agent-jgdfbwse.js");
109484
109579
  const agent = new FindingJudgeAgent({
109485
109580
  finding: input,
109486
109581
  model: ctx.model,
@@ -109581,7 +109676,8 @@ var documentVulnerabilityInputSchema = exports_external.object({
109581
109676
  pocName: exports_external.string().describe("Short descriptive name for the POC"),
109582
109677
  pocType: exports_external.enum(["bash", "python", "javascript"]).describe("Script language"),
109583
109678
  pocContent: exports_external.string().describe("The full POC script content"),
109584
- pocDescription: exports_external.string().describe("What this POC demonstrates")
109679
+ pocDescription: exports_external.string().describe("What this POC demonstrates"),
109680
+ attackPath: AttackPathSchema.optional().describe("Required ordered member-to-member hop chain when the finding spans multiple System members; do not leave this chain only in narrative fields")
109585
109681
  });
109586
109682
  function formatMateriality(input) {
109587
109683
  return [
@@ -109651,11 +109747,24 @@ CRITICAL RULES — READ BEFORE CALLING:
109651
109747
  - POC must exit 0 on success (vulnerability confirmed), non-zero on failure
109652
109748
  - POC must print clear evidence of exploitation to stdout
109653
109749
  - Fill the materiality checklist with the concrete exploit path, material security impact, affected non-public asset or abuse path, and why common false-positive traps do not apply
109750
+ - When a finding spans multiple System members, populate attackPath with every hop in order; do not leave the chain only in the description or evidence
109654
109751
  - If the tool returns a POC failure or judge rejection, revise your approach and call again
109655
109752
  - Do NOT use this for: positive observations, informational notes, testing limitations, or anything that is not an exploitable security vulnerability
109656
109753
  - If you could not exploit a vulnerability, do NOT call this tool — mention it in your final response summary instead`,
109657
109754
  inputSchema: documentVulnerabilityInputSchema,
109658
109755
  execute: async (input) => {
109756
+ try {
109757
+ assertFindingEndpointInScope(input.endpoint, ctx);
109758
+ } catch (error) {
109759
+ if (error instanceof ScopeViolationError) {
109760
+ return {
109761
+ success: false,
109762
+ error: error.message,
109763
+ message: `Finding endpoint rejected — out of scope: ${error.message}`
109764
+ };
109765
+ }
109766
+ throw error;
109767
+ }
109659
109768
  try {
109660
109769
  const materializedEvidence = formatMateriality(input);
109661
109770
  if (ctx.findingsRegistry) {
@@ -109870,7 +109979,8 @@ CRITICAL RULES — READ BEFORE CALLING:
109870
109979
  vulnerabilityClass: input.vulnerabilityClass
109871
109980
  },
109872
109981
  severity,
109873
- ...evidenceFiles.length > 0 && { evidenceFiles }
109982
+ ...evidenceFiles.length > 0 && { evidenceFiles },
109983
+ ...input.attackPath && input.attackPath.length > 0 && { attackPath: input.attackPath }
109874
109984
  };
109875
109985
  if (isVulnerability && ctx.findingsRegistry) {
109876
109986
  const check = await ctx.findingsRegistry.register(finding);
@@ -115366,9 +115476,10 @@ class PersistentShell {
115366
115476
  ${commandOutput}`;
115367
115477
  }
115368
115478
  const effectiveExit = cmd.forcedExitCode != null ? cmd.forcedExitCode : Number.isNaN(naturalExitCode) ? 1 : naturalExitCode;
115369
- const effectiveStderr = cmd.forcedStderrSuffix ? (cmd.stderr || "") + cmd.forcedStderrSuffix : cmd.stderr || "";
115479
+ const diskStderr = readTempfileCapped(cmd.errPath);
115370
115480
  unlinkSafe(cmd.outPath);
115371
115481
  unlinkSafe(cmd.errPath);
115482
+ const effectiveStderr = (diskStderr || cmd.stderr || "") + (cmd.forcedStderrSuffix ?? "");
115372
115483
  const resolve4 = cmd.resolve;
115373
115484
  this.current = null;
115374
115485
  this.pendingCancel = null;
@@ -116106,7 +116217,7 @@ should be passed directly to spawn_pentest_swarm for deep testing.`,
116106
116217
  });
116107
116218
  if (cwd) {
116108
116219
  try {
116109
- const { WhiteboxAttackSurfaceAgent } = await import("./index-rbzhk712.js");
116220
+ const { WhiteboxAttackSurfaceAgent } = await import("./index-sx52n7s9.js");
116110
116221
  const localBus = new AgentEventBus;
116111
116222
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
116112
116223
  const agent = new WhiteboxAttackSurfaceAgent({
@@ -116161,7 +116272,7 @@ should be passed directly to spawn_pentest_swarm for deep testing.`,
116161
116272
  }
116162
116273
  }
116163
116274
  try {
116164
- const { BlackboxAttackSurfaceAgent } = await import("./blackboxAgent-gw0a1ca4.js");
116275
+ const { BlackboxAttackSurfaceAgent } = await import("./blackboxAgent-vwtk3hv1.js");
116165
116276
  const localBus = new AgentEventBus;
116166
116277
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
116167
116278
  const agent = new BlackboxAttackSurfaceAgent({
@@ -116239,7 +116350,7 @@ Omit \`cwd\` for blackbox mode (live target probing only).`,
116239
116350
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
116240
116351
  }),
116241
116352
  execute: async ({ target, cwd }) => {
116242
- const { runPentestWorkflow: workflow } = await import("./pentest-xtc1sjdw.js");
116353
+ const { runPentestWorkflow: workflow } = await import("./pentest-3w1jgsg7.js");
116243
116354
  if (!ctx.model) {
116244
116355
  return {
116245
116356
  success: false,
@@ -116299,6 +116410,122 @@ function summarizeFindingsBySeverity(findings) {
116299
116410
  return counts;
116300
116411
  }
116301
116412
 
116413
+ // src/core/agents/offSecAgent/tools/smsListMessages.ts
116414
+ init_dist();
116415
+ init_zod();
116416
+ var SMS_LIST_MESSAGES_TOOL_NAME = "sms_list_messages";
116417
+ var SMS_TOOL_NAMES = [SMS_LIST_MESSAGES_TOOL_NAME];
116418
+ function hasPhoneNumberAuthCredential(session) {
116419
+ const creds = session.config?.authCredentials;
116420
+ const list2 = creds ? Array.isArray(creds) ? creds : [creds] : [];
116421
+ return list2.some((cred) => Boolean(cred.additionalFields?.phoneNumber));
116422
+ }
116423
+ function sessionHasSmsPasswordless(session) {
116424
+ const refs = session.credentialManager?.listReferences() ?? [];
116425
+ if (refs.some((ref) => ref.additionalFieldKeys?.includes("phoneNumber"))) {
116426
+ return true;
116427
+ }
116428
+ return hasPhoneNumberAuthCredential(session);
116429
+ }
116430
+ function requireAgentApi() {
116431
+ const base = process.env.AGENT_API_URL;
116432
+ const token = process.env.AGENT_API_TOKEN;
116433
+ if (!base || !token) {
116434
+ throw new Error("sms_list_messages requires AGENT_API_URL and AGENT_API_TOKEN (Console sandbox dispatch). Local CLI without Console cannot read inbound SMS.");
116435
+ }
116436
+ return { base: base.replace(/\/+$/, ""), token };
116437
+ }
116438
+ async function agentFetch(path, init) {
116439
+ const { token, ...rest } = init;
116440
+ return fetch(path, {
116441
+ ...rest,
116442
+ headers: {
116443
+ Authorization: `Bearer ${token}`,
116444
+ ...rest.headers ?? {}
116445
+ }
116446
+ });
116447
+ }
116448
+ function smsListMessages(ctx) {
116449
+ return tool({
116450
+ description: `Reserve or list inbound SMS on the stage-managed Mobile OTP (sms-passwordless) receiving number.
116451
+
116452
+ Reserve immediately before filling the target phone field and clicking send-code: call with reserve=true. The Console chooses and leases the receiving number from the signed session; never supply or request a phone number here.
116453
+
116454
+ After the target sends a code, sleep with execute_command (e.g. sleep 5), then call with sinceMs from the send-code click. Set claim=true to consume the newest unconsumed message (exclusive; other runs cannot reuse that OTP). This is a single request — it does not wait. A 429 means the shared number is busy; retry the reservation later rather than waiting in this tool.
116455
+
116456
+ Requires a Console sandbox (AGENT_API_URL).`,
116457
+ inputSchema: exports_external.object({
116458
+ reserve: exports_external.boolean().optional().describe("Reserve the session-bound shared number before requesting a code. Cannot be combined with sinceMs or claim."),
116459
+ sinceMs: exports_external.number().optional().describe("Epoch milliseconds of the send-code click. Required unless reserving; messages received before this timestamp are ignored."),
116460
+ claim: exports_external.boolean().optional().describe("Consume the newest unconsumed message so other runs cannot reuse the OTP. Defaults to false (list only)."),
116461
+ toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
116462
+ }).strict().superRefine((input, refinementCtx) => {
116463
+ if (input.reserve) {
116464
+ if (input.sinceMs !== undefined || input.claim !== undefined) {
116465
+ refinementCtx.addIssue({
116466
+ code: "custom",
116467
+ message: "reserve=true cannot be combined with sinceMs or claim"
116468
+ });
116469
+ }
116470
+ return;
116471
+ }
116472
+ if (input.sinceMs === undefined) {
116473
+ refinementCtx.addIssue({
116474
+ code: "custom",
116475
+ path: ["sinceMs"],
116476
+ message: "sinceMs is required when listing SMS messages"
116477
+ });
116478
+ }
116479
+ }),
116480
+ execute: async ({ reserve, sinceMs, claim }) => {
116481
+ const { base, token } = requireAgentApi();
116482
+ const url = new URL(`${base}/agent/sms/messages`);
116483
+ if (reserve) {
116484
+ url.searchParams.set("reserve", "1");
116485
+ } else {
116486
+ if (sinceMs === undefined) {
116487
+ throw new Error("sms_list_messages requires sinceMs when listing");
116488
+ }
116489
+ url.searchParams.set("since", new Date(sinceMs).toISOString());
116490
+ if (claim)
116491
+ url.searchParams.set("claim", "1");
116492
+ }
116493
+ const res = await agentFetch(url.toString(), {
116494
+ method: "GET",
116495
+ token,
116496
+ signal: ctx.abortSignal
116497
+ });
116498
+ if (res.status === 429) {
116499
+ return {
116500
+ success: false,
116501
+ error: "The shared Mobile OTP number is busy. Retry the reservation later; this tool does not wait."
116502
+ };
116503
+ }
116504
+ if (res.status === 403) {
116505
+ return {
116506
+ success: false,
116507
+ error: "No Mobile OTP receiving number is configured for this session."
116508
+ };
116509
+ }
116510
+ if (res.status === 409) {
116511
+ return {
116512
+ success: false,
116513
+ error: "That SMS was already claimed. List without claim, or wait for a newer message."
116514
+ };
116515
+ }
116516
+ if (!res.ok) {
116517
+ throw new Error(`SMS list API error ${res.status} ${res.statusText}`);
116518
+ }
116519
+ const data = await res.json();
116520
+ return {
116521
+ success: true,
116522
+ messages: data.messages,
116523
+ claimed: data.claimed
116524
+ };
116525
+ }
116526
+ });
116527
+ }
116528
+
116302
116529
  // src/core/utils/concurrency.ts
116303
116530
  var import_api = __toESM(require_src(), 1);
116304
116531
  async function runWithBoundedConcurrency(items, concurrency, fn, abortSignal) {
@@ -117817,7 +118044,7 @@ Returns an array of results with the text output from each agent.`,
117817
118044
  });
117818
118045
  }
117819
118046
  async function runSingleCodingAgent(ctx, codebasePath, objective, agentIndex, name) {
117820
- const { CodeAgent } = await import("./agent-mvpgvgks.js");
118047
+ const { CodeAgent } = await import("./agent-z3ydv420.js");
117821
118048
  const childSessionId = newSessionId();
117822
118049
  const subagentId = childSessionId;
117823
118050
  ctx.eventBus?.emit("subagent-spawn", {
@@ -118298,13 +118525,17 @@ init_dist();
118298
118525
  init_zod();
118299
118526
  init_id();
118300
118527
  var WORKER_DRAIN_GRACE_MS = 30000;
118528
+ var ORIGIN_AUTH_FAILURE_GUIDANCE = `A 401/403 from one resource does not by itself prove authentication failure. Verify the session against a known protected or session endpoint and re-authenticate on the assigned origin only if needed. Call report_error with reason "authentication_failed" only if required authentication cannot be established and this blocks the assigned objective or all further testing; otherwise continue any reachable testing.`;
118301
118529
  function spawnPentestAgent(ctx) {
118530
+ const targetScopeGuidance = ctx.systemScope && ctx.systemScope.memberHosts.length > 0 ? `For a cross-service follow-up, you may instead use a full URL on one of these authorized System Scope members: ${ctx.systemScope.memberHosts.join(", ")}.` : "No structured System Scope is present, so keep the assigned host unchanged.";
118302
118531
  return tool({
118303
118532
  description: `Spawn a single focused pentest sub-agent (worker) to test ONE objective at a time.
118304
118533
 
118305
118534
  Use this AFTER stating your plan and performing light reconnaissance. Call this tool ONCE PER OBJECTIVE — do not batch objectives into a single spawn, because the UI surfaces each spawn as its own timeline.
118306
118535
 
118307
- CRITICAL — \`target\` must be the FULL URL including the endpoint path the caller wants tested (e.g. https://example.com/api/users/{id}), not a bare domain. Forward through whatever URL the orchestrator itself received unless recon turned up a related sibling endpoint that genuinely belongs to a follow-up objective.
118536
+ CRITICAL — \`target\` must be a FULL URL including the endpoint path the caller wants tested (e.g. https://example.com/api/users/{id}), not a bare domain. Use the orchestrator's assigned URL by default. Recon-supported sibling endpoints are allowed for a follow-up objective. ${targetScopeGuidance} Never invent a host or endpoint.
118537
+
118538
+ Authentication state is origin-specific. Before spawning a cross-service worker that needs authentication, establish and verify a session on its target origin and describe that status in \`context\`. The worker must verify protected access on its assigned origin. ${ORIGIN_AUTH_FAILURE_GUIDANCE}
118308
118539
 
118309
118540
  Each spawn produces an independent TargetedPentestAgent that:
118310
118541
  1. Tests the assigned objective(s) deeply (execute_command, http_request, browser tools)
@@ -118322,7 +118553,7 @@ False-positive discipline: workers should not call document_vulnerability for pu
118322
118553
  Returns the worker's summary, objective results, and finding count — but NOT the findings themselves (those land in the shared registry).`,
118323
118554
  inputSchema: exports_external.object({
118324
118555
  name: exports_external.string().describe("Short human-readable label for this sub-agent shown in the UI (e.g. 'SQLi /api/users', 'IDOR orders', 'Final chain & explore')."),
118325
- target: exports_external.string().describe("Full target URL INCLUDING the endpoint path you want this worker to focus on (e.g. 'https://example.com/api/users/{id}', 'https://example.com/login'). Pass through whatever URL the orchestrator received as its own target — that is already the domain + endpoint path the console / caller wants tested. Do NOT strip the path back to a bare domain, and do NOT invent a different endpoint; you are not doing endpoint discovery. If a single objective genuinely needs a sibling path (e.g. recon revealed a related admin endpoint on the same host), only then deviate, and keep the full URL."),
118556
+ target: exports_external.string().describe(`Full target URL INCLUDING the endpoint path you want this worker to focus on (e.g. 'https://example.com/api/users/{id}', 'https://example.com/login'). Use the orchestrator's assigned URL by default and never strip it to a bare domain. A recon-supported sibling endpoint is allowed when it belongs to the objective. ${targetScopeGuidance} Never invent a host or endpoint.`),
118326
118557
  objectives: exports_external.array(exports_external.string()).min(1).describe("Testing objectives for this worker. For per-objective fan-out, pass exactly one objective. For the final exploratory pass, pass a single composite objective describing chaining + exploration."),
118327
118558
  context: exports_external.string().optional().describe("Additional grounding context for the worker — e.g. summaries of what earlier workers found, suspicious endpoints to chain, or application-specific guidance. Treated as guidance, not as code to read."),
118328
118559
  toolCallDescription: exports_external.string().describe("Concise, human-readable description of what this spawn is doing (shown in the UI).")
@@ -118334,7 +118565,21 @@ Returns the worker's summary, objective results, and finding count — but NOT t
118334
118565
  message: "spawn_pentest_agent requires a model in the tool context."
118335
118566
  };
118336
118567
  }
118337
- const { TargetedPentestAgent } = await import("./agent-nhs1w5w0.js");
118568
+ if (typeof target !== "string" || parseTargetUrl(target) === null) {
118569
+ return {
118570
+ success: false,
118571
+ message: `spawn_pentest_agent rejected: "target" is not a valid full URL (received ${JSON.stringify(target)}). ` + `Pass a valid full URL authorized by the assigned target or structured System Scope — do NOT invent, default, or substitute a target.`
118572
+ };
118573
+ }
118574
+ try {
118575
+ assertUrlInScope(target, ctx);
118576
+ } catch (error) {
118577
+ if (error instanceof ScopeViolationError) {
118578
+ return { success: false, message: error.message };
118579
+ }
118580
+ throw error;
118581
+ }
118582
+ const { TargetedPentestAgent } = await import("./agent-092hrrbn.js");
118338
118583
  const findingsRegistry = ctx.findingsRegistry ?? FindingsRegistry.fromDirectory(ctx.session.findingsPath, {
118339
118584
  model: ctx.model,
118340
118585
  authConfig: ctx.authConfig,
@@ -118365,12 +118610,15 @@ Returns the worker's summary, objective results, and finding count — but NOT t
118365
118610
  agent = new TargetedPentestAgent({
118366
118611
  target,
118367
118612
  grpc: workerInheritsGrpc(target, ctx.grpc, ctx.target) ? ctx.grpc : undefined,
118613
+ systemScope: ctx.systemScope,
118368
118614
  objectives,
118369
118615
  context: enrichedContext,
118370
118616
  model: ctx.model,
118371
118617
  session: ctx.session,
118372
118618
  authConfig: ctx.authConfig,
118373
118619
  abortSignal: ctx.abortSignal,
118620
+ onStepFinish: ctx.onStepFinish,
118621
+ onCacheMetrics: ctx.onCacheMetrics,
118374
118622
  findingsRegistry,
118375
118623
  eventBus: childBus,
118376
118624
  subagentId,
@@ -118429,7 +118677,7 @@ function workerInheritsGrpc(target, grpc, orchestratorTarget) {
118429
118677
  function buildSharedBrowserSessionContext(existingContext) {
118430
118678
  const note = `## Shared Browser Session
118431
118679
  You are driving the orchestrator's live Playwright browser (NOT a private copy):
118432
- - You are already authenticated for any origin the orchestrator authenticated for. Do NOT re-authenticate unless a request returns 401/403.
118680
+ - You inherit authentication only for origins where the orchestrator established it. Verify protected access on your assigned origin first. ${ORIGIN_AUTH_FAILURE_GUIDANCE}
118433
118681
  - Only one agent uses this browser at a time — the orchestrator is paused while you run — so you have exclusive control during your run.
118434
118682
  - Your navigations, \`browser_evaluate\` mutations, cookies, and \`localStorage\`/\`sessionStorage\` writes PERSIST in this browser and are visible to the orchestrator and to workers spawned after you. Leave the session in a reasonable state (avoid logging out or wedging the page) when you finish.`;
118435
118683
  if (!existingContext || existingContext.trim().length === 0) {
@@ -118468,7 +118716,7 @@ Pass every target you want tested — the swarm handles concurrency automaticall
118468
118716
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
118469
118717
  }),
118470
118718
  execute: async ({ targets }) => {
118471
- const { runPentestSwarm, DEFAULT_CONCURRENCY: DEFAULT_CONCURRENCY2 } = await import("./pentest-xtc1sjdw.js");
118719
+ const { runPentestSwarm, DEFAULT_CONCURRENCY: DEFAULT_CONCURRENCY2 } = await import("./pentest-3w1jgsg7.js");
118472
118720
  if (!ctx.model) {
118473
118721
  return {
118474
118722
  success: false,
@@ -118490,6 +118738,8 @@ Pass every target you want tested — the swarm handles concurrency automaticall
118490
118738
  abortSignal: ctx.abortSignal,
118491
118739
  findingsRegistry,
118492
118740
  eventBus: ctx.eventBus,
118741
+ onStepFinish: ctx.onStepFinish,
118742
+ onCacheMetrics: ctx.onCacheMetrics,
118493
118743
  concurrency: DEFAULT_CONCURRENCY2,
118494
118744
  enableThinking: ctx.enableThinking,
118495
118745
  thinkingEffort: ctx.thinkingEffort,
@@ -119104,6 +119354,29 @@ async function handleSearchResponse(response) {
119104
119354
  // src/core/api/apiClient.ts
119105
119355
  init_auth();
119106
119356
  init_config();
119357
+
119358
+ // src/core/api/clientIdentity.ts
119359
+ init_installation();
119360
+ var CLIENT_HEADERS = {
119361
+ client: "X-Pensar-Client",
119362
+ version: "X-Pensar-Client-Version",
119363
+ command: "X-Pensar-Command"
119364
+ };
119365
+ var CLIENT_NAME = "cli";
119366
+ var currentCommand;
119367
+ function getCurrentCommand() {
119368
+ return currentCommand;
119369
+ }
119370
+ function clientIdentityHeaders() {
119371
+ const command = getCurrentCommand();
119372
+ return {
119373
+ [CLIENT_HEADERS.client]: CLIENT_NAME,
119374
+ [CLIENT_HEADERS.version]: getCurrentVersion(),
119375
+ ...command ? { [CLIENT_HEADERS.command]: command } : {}
119376
+ };
119377
+ }
119378
+
119379
+ // src/core/api/apiClient.ts
119107
119380
  init_constants();
119108
119381
  async function getAuthHeaders() {
119109
119382
  const cfg = await config.get();
@@ -119117,7 +119390,8 @@ async function getAuthHeaders() {
119117
119390
  }
119118
119391
  const headers = {
119119
119392
  "Content-Type": "application/json",
119120
- Authorization: `Bearer ${validToken.token}`
119393
+ Authorization: `Bearer ${validToken.token}`,
119394
+ ...clientIdentityHeaders()
119121
119395
  };
119122
119396
  if (cfg.workspaceId) {
119123
119397
  headers["X-Workspace-Id"] = cfg.workspaceId;
@@ -119151,6 +119425,12 @@ async function apiRequest(method, path, body) {
119151
119425
  }
119152
119426
 
119153
119427
  // src/core/api/apps.ts
119428
+ var ENDPOINT_TRANSPORTS = [
119429
+ "http",
119430
+ "grpc",
119431
+ "grpc_web",
119432
+ "connect"
119433
+ ];
119154
119434
  async function listApps(opts) {
119155
119435
  const params = new URLSearchParams;
119156
119436
  if (opts?.limit !== undefined)
@@ -119263,7 +119543,7 @@ var ENDPOINT_TYPES = [
119263
119543
  "file-storage",
119264
119544
  "asset"
119265
119545
  ];
119266
- var ENDPOINT_TRANSPORTS = [
119546
+ var ENDPOINT_TRANSPORTS2 = [
119267
119547
  "http",
119268
119548
  "grpc",
119269
119549
  "grpc_web",
@@ -119309,7 +119589,7 @@ var createWorkspaceEndpointInputSchema = exports_external.object({
119309
119589
  endpoint: exports_external.string().min(1).describe("Endpoint path, URL, or route"),
119310
119590
  description: exports_external.string().describe("Endpoint description"),
119311
119591
  type: exports_external.enum(ENDPOINT_TYPES).optional(),
119312
- transport: exports_external.enum(ENDPOINT_TRANSPORTS).nullish().transform((value) => value ?? undefined).optional().describe("Wire transport; defaults to http when omitted"),
119592
+ transport: exports_external.enum(ENDPOINT_TRANSPORTS2).nullish().transform((value) => value ?? undefined).optional().describe("Wire transport; defaults to http when omitted"),
119313
119593
  location: exports_external.string().optional().describe("Source file path"),
119314
119594
  startLineNumber: exports_external.number().int().min(0).optional(),
119315
119595
  endLineNumber: exports_external.number().int().min(0).optional(),
@@ -119328,7 +119608,7 @@ var updateWorkspaceEndpointInputSchema = exports_external.object({
119328
119608
  endpoint: exports_external.string().min(1).nullish().transform((value) => value ?? undefined).optional(),
119329
119609
  description: exports_external.string().nullish().transform((value) => value ?? undefined).optional(),
119330
119610
  type: exports_external.enum(ENDPOINT_TYPES).nullable().optional(),
119331
- transport: exports_external.enum(ENDPOINT_TRANSPORTS).nullish().transform((value) => value ?? undefined).optional().describe("Corrected wire transport"),
119611
+ transport: exports_external.enum(ENDPOINT_TRANSPORTS2).nullish().transform((value) => value ?? undefined).optional().describe("Corrected wire transport"),
119332
119612
  location: exports_external.string().nullable().optional(),
119333
119613
  startLineNumber: exports_external.number().int().min(0).nullable().optional(),
119334
119614
  endLineNumber: exports_external.number().int().min(0).nullable().optional(),
@@ -119456,10 +119736,6 @@ Use only when the user explicitly asks to change or repair an existing workspace
119456
119736
  });
119457
119737
  }
119458
119738
 
119459
- // src/core/agents/offSecAgent/tools/workspaceDomains.ts
119460
- init_dist();
119461
- init_zod();
119462
-
119463
119739
  // src/core/api/domains.ts
119464
119740
  async function listDomains() {
119465
119741
  return apiRequest("GET", "/domains");
@@ -119469,6 +119745,8 @@ async function createDomain(data) {
119469
119745
  }
119470
119746
 
119471
119747
  // src/core/agents/offSecAgent/tools/workspaceDomains.ts
119748
+ init_dist();
119749
+ init_zod();
119472
119750
  var toolCallDescription2 = exports_external.string().describe("A concise description of the workspace operation");
119473
119751
  var listWorkspaceDomainsInputSchema = exports_external.object({
119474
119752
  toolCallDescription: toolCallDescription2
@@ -124352,6 +124630,7 @@ function createAllTools(ctx) {
124352
124630
  email_list_messages: emailListMessages(ctx),
124353
124631
  email_search_messages: emailSearchMessages(ctx),
124354
124632
  email_get_message: emailGetMessage(ctx),
124633
+ sms_list_messages: smsListMessages(ctx),
124355
124634
  web_search: webSearch(ctx),
124356
124635
  get_page: getPage(ctx),
124357
124636
  ...ctx.skillsRegistry ? { read_skill: readSkill(ctx) } : {},
@@ -124439,6 +124718,7 @@ var ALL_TOOL_NAMES = [
124439
124718
  "email_get_attachments",
124440
124719
  "email_mark_read",
124441
124720
  "send_email",
124721
+ "sms_list_messages",
124442
124722
  "web_search",
124443
124723
  "get_page",
124444
124724
  "checkpoint_state",
@@ -124510,6 +124790,7 @@ var PLAN_MODE_TOOL_NAMES = [
124510
124790
  "email_get_message",
124511
124791
  "email_search_messages",
124512
124792
  "email_get_attachments",
124793
+ "sms_list_messages",
124513
124794
  "web_search",
124514
124795
  "get_page",
124515
124796
  "write_plan",
@@ -124521,6 +124802,7 @@ var PLAN_MODE_TOOL_NAMES = [
124521
124802
  var SKILL_TOOL_NAMES = ["read_skill"];
124522
124803
 
124523
124804
  // src/core/agents/offSecAgent/trace.ts
124805
+ init_observability();
124524
124806
  import { createHash as createHash2 } from "node:crypto";
124525
124807
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync13 } from "node:fs";
124526
124808
  import { dirname as dirname8 } from "node:path";
@@ -124707,13 +124989,15 @@ class StepTraceWriter {
124707
124989
  this.appendRecord(record3);
124708
124990
  }
124709
124991
  appendRecord(record3) {
124992
+ const correlation = getActiveTraceCorrelation();
124993
+ const enriched = correlation ? { ...record3, correlation } : record3;
124710
124994
  try {
124711
- appendFileSync3(this.tracePath, `${JSON.stringify(record3)}
124995
+ appendFileSync3(this.tracePath, `${JSON.stringify(enriched)}
124712
124996
  `);
124713
124997
  } catch {}
124714
124998
  try {
124715
124999
  this.eventBus?.emit("trace-record", {
124716
- record: record3,
125000
+ record: enriched,
124717
125001
  subagentId: this.agentId ?? undefined
124718
125002
  });
124719
125003
  } catch {}
@@ -124723,8 +125007,8 @@ class StepTraceWriter {
124723
125007
  // src/core/agents/offSecAgent/offensiveSecurityAgent.ts
124724
125008
  init_dist();
124725
125009
  init_ai();
124726
- import { existsSync as existsSync18, mkdirSync as mkdirSync14, readFileSync as readFileSync8 } from "node:fs";
124727
- import { writeFile as writeFile7 } from "node:fs/promises";
125010
+ var import_api2 = __toESM(require_src(), 1);
125011
+ import { existsSync as existsSync19, mkdirSync as mkdirSync14 } from "node:fs";
124728
125012
  import { join as join27 } from "node:path";
124729
125013
  init_id();
124730
125014
  init_structured();
@@ -125006,9 +125290,464 @@ var OperatorSettingsObject = exports_external.object({
125006
125290
  // src/core/agents/offSecAgent/offensiveSecurityAgent.ts
125007
125291
  init_session();
125008
125292
  init_lazyLogger();
125009
- var log13 = scopedLogger(() => createLogger("approval-gate"));
125293
+
125294
+ // src/core/agents/offSecAgent/interruptedStepFinalization.ts
125295
+ import { existsSync as existsSync18, readFileSync as readFileSync8 } from "node:fs";
125296
+
125297
+ // src/core/agents/offSecAgent/interruptedStepMessages.ts
125298
+ function buildSyntheticToolResults(input) {
125299
+ const output = {
125300
+ type: "error-text",
125301
+ value: `Tool execution aborted: ${input.reason}`
125302
+ };
125303
+ const parts = [];
125304
+ for (const [toolCallId, toolName] of input.inFlightTools) {
125305
+ const result = toolName === input.responseToolName && input.responseSubmitted ? { type: "text", value: "Response submitted." } : output;
125306
+ parts.push({
125307
+ type: "tool-result",
125308
+ toolCallId,
125309
+ toolName,
125310
+ output: result
125311
+ });
125312
+ }
125313
+ return parts;
125314
+ }
125315
+ function baseContainsToolCalls(msg, toolCallIds) {
125316
+ if (!Array.isArray(msg.content))
125317
+ return false;
125318
+ const contentToolIds = new Set(msg.content.filter((p) => p.type === "tool-call" && p.toolCallId).map((p) => p.toolCallId));
125319
+ return [...toolCallIds].every((id) => contentToolIds.has(id));
125320
+ }
125321
+ function buildInterruptedStepMessages(input) {
125322
+ const { base, inFlightTools, completedResults, syntheticParts } = input;
125323
+ const allToolCallIds = new Set([
125324
+ ...inFlightTools.keys(),
125325
+ ...completedResults.map((r) => r.toolCallId)
125326
+ ]);
125327
+ const lastMsg = base[base.length - 1];
125328
+ const needsStepReconstruction = !lastMsg || lastMsg.role !== "assistant" || !baseContainsToolCalls(lastMsg, allToolCallIds);
125329
+ const appended = [];
125330
+ if (needsStepReconstruction) {
125331
+ const stepTools = [
125332
+ ...inFlightTools,
125333
+ ...completedResults.map((r) => [
125334
+ r.toolCallId,
125335
+ r.toolName
125336
+ ])
125337
+ ];
125338
+ const reconstructInput = (toolCallId) => {
125339
+ const raw = input.streamedArgText?.get(toolCallId);
125340
+ if (!raw)
125341
+ return {};
125342
+ try {
125343
+ return JSON.parse(raw);
125344
+ } catch {
125345
+ return { _partial: raw };
125346
+ }
125347
+ };
125348
+ appended.push({
125349
+ role: "assistant",
125350
+ content: stepTools.map(([toolCallId, toolName]) => ({
125351
+ type: "tool-call",
125352
+ toolCallId,
125353
+ toolName,
125354
+ input: reconstructInput(toolCallId)
125355
+ }))
125356
+ });
125357
+ }
125358
+ appended.push({
125359
+ role: "tool",
125360
+ content: [...completedResults, ...syntheticParts]
125361
+ });
125362
+ return { appended, needsStepReconstruction };
125363
+ }
125364
+
125365
+ // src/core/agents/offSecAgent/interruptedStepFinalization.ts
125366
+ function createInterruptedStepFinalizer(deps) {
125367
+ const debug = deps.debugLog;
125368
+ const readBaseFromDisk = deps.readBaseFromDisk ?? (() => {
125369
+ const path = deps.writer.messagesPath;
125370
+ if (!path || !existsSync18(path))
125371
+ return null;
125372
+ try {
125373
+ return JSON.parse(readFileSync8(path, "utf-8"));
125374
+ } catch {
125375
+ return null;
125376
+ }
125377
+ });
125378
+ return async (input) => {
125379
+ const { snapshot, reason } = input;
125380
+ const { inFlightTools, completedResults, streamedArgText } = snapshot;
125381
+ const syntheticParts = buildSyntheticToolResults({
125382
+ inFlightTools,
125383
+ reason,
125384
+ responseToolName: deps.responseToolName,
125385
+ responseSubmitted: deps.responseToolFired()
125386
+ });
125387
+ let emissionError;
125388
+ let hasEmissionError = false;
125389
+ if (debug) {
125390
+ const responseInFlight = [...inFlightTools.entries()].filter(([, n7]) => n7 === deps.responseToolName);
125391
+ if (responseInFlight.length > 0) {
125392
+ debug(`[response-debug] emitSyntheticToolResults closing ${responseInFlight.length} response call(s) ` + `ids=${responseInFlight.map(([id]) => id).join(",")} reason="${reason}" ` + `responseToolFired=${deps.responseToolFired()}`);
125393
+ }
125394
+ }
125395
+ for (const part of syntheticParts) {
125396
+ try {
125397
+ deps.eventBus.emit("tool-result", {
125398
+ toolCallId: part.toolCallId,
125399
+ toolName: part.toolName,
125400
+ result: part.output,
125401
+ sessionId: deps.sessionId,
125402
+ subagentId: deps.subagentId,
125403
+ partId: input.partIdFor?.(part.toolCallId),
125404
+ messageId: input.messageId
125405
+ });
125406
+ } catch (error) {
125407
+ if (!hasEmissionError) {
125408
+ emissionError = error;
125409
+ hasEmissionError = true;
125410
+ }
125411
+ }
125412
+ }
125413
+ if (!deps.writer.messagesPath) {
125414
+ if (hasEmissionError)
125415
+ throw emissionError;
125416
+ return;
125417
+ }
125418
+ deps.writer.cancelTimer();
125419
+ await deps.writer.waitForPendingWrites();
125420
+ let base = deps.writer.latest ?? [];
125421
+ if (base.length === 0) {
125422
+ base = readBaseFromDisk() ?? [];
125423
+ }
125424
+ const { appended, needsStepReconstruction } = buildInterruptedStepMessages({
125425
+ base,
125426
+ inFlightTools,
125427
+ completedResults,
125428
+ syntheticParts,
125429
+ streamedArgText
125430
+ });
125431
+ if (needsStepReconstruction && debug) {
125432
+ const responseReconstructed = [
125433
+ ...inFlightTools,
125434
+ ...completedResults.map((r) => [r.toolCallId, r.toolName])
125435
+ ].filter(([, n7]) => n7 === deps.responseToolName).map(([id]) => id);
125436
+ if (responseReconstructed.length > 0) {
125437
+ debug(`[response-debug] step-reconstruction for response call(s) ` + `ids=${responseReconstructed.join(",")} ` + `preservedArgChars=${responseReconstructed.map((id) => streamedArgText?.get(id)?.length ?? 0).join(",")}`);
125438
+ }
125439
+ }
125440
+ const next = [...base, ...appended];
125441
+ deps.writer.setLatest(next);
125442
+ try {
125443
+ await deps.writer.enqueueWrite(next);
125444
+ deps.writer.markSyntheticsPersisted();
125445
+ } catch {}
125446
+ if (hasEmissionError)
125447
+ throw emissionError;
125448
+ };
125449
+ }
125450
+
125451
+ // src/core/agents/offSecAgent/messagePersistence.ts
125452
+ import { writeFile as writeFile7 } from "node:fs/promises";
125453
+ var PERSIST_INTERVAL_MS = 15000;
125454
+
125455
+ class AgentMessageWriter {
125456
+ intervalMs;
125457
+ writeImpl;
125458
+ path;
125459
+ pending = null;
125460
+ tail = Promise.resolve();
125461
+ persistTimer = null;
125462
+ syntheticsWritten = false;
125463
+ constructor(options) {
125464
+ this.path = options.messagesPath;
125465
+ this.intervalMs = options.intervalMs ?? PERSIST_INTERVAL_MS;
125466
+ this.writeImpl = options.writeImpl ?? ((p, contents) => writeFile7(p, contents));
125467
+ }
125468
+ get messagesPath() {
125469
+ return this.path;
125470
+ }
125471
+ get latest() {
125472
+ return this.pending;
125473
+ }
125474
+ setLatest(messages) {
125475
+ this.pending = messages;
125476
+ }
125477
+ get syntheticsPersisted() {
125478
+ return this.syntheticsWritten;
125479
+ }
125480
+ markSyntheticsPersisted() {
125481
+ this.syntheticsWritten = true;
125482
+ }
125483
+ schedulePersist() {
125484
+ if (this.persistTimer)
125485
+ return;
125486
+ this.persistTimer = setTimeout(() => {
125487
+ this.persistTimer = null;
125488
+ const toWrite = this.pending;
125489
+ if (!toWrite)
125490
+ return;
125491
+ this.enqueueWrite(toWrite).then(() => {
125492
+ if (this.pending === toWrite)
125493
+ this.pending = null;
125494
+ }).catch(() => {});
125495
+ }, this.intervalMs);
125496
+ }
125497
+ cancelTimer() {
125498
+ if (this.persistTimer) {
125499
+ clearTimeout(this.persistTimer);
125500
+ this.persistTimer = null;
125501
+ }
125502
+ }
125503
+ async enqueueWrite(messages) {
125504
+ const path = this.path;
125505
+ if (!path)
125506
+ return;
125507
+ const contents = JSON.stringify(messages);
125508
+ const write2 = this.tail.then(() => this.writeImpl(path, contents));
125509
+ this.tail = write2.catch(() => {});
125510
+ await write2;
125511
+ }
125512
+ async waitForPendingWrites() {
125513
+ let pending;
125514
+ do {
125515
+ pending = this.tail;
125516
+ await pending;
125517
+ } while (pending !== this.tail);
125518
+ }
125519
+ }
125520
+
125521
+ // src/core/agents/offSecAgent/streamDiagnostics.ts
125522
+ init_structured();
125523
+ init_lazyLogger();
125524
+ var STREAM_STALL_DEBUG = process.env.STREAM_STALL_DEBUG === "1" || process.env.STREAM_STALL_DEBUG === "true";
125525
+ var STREAM_STALL_TICK_MS = 15000;
125526
+ var STREAM_STALL_WARN_MS = 20000;
125527
+ var STREAM_GAP_RECOVERED_MS = 1e4;
125010
125528
  var RESPONSE_DEBUG = process.env.RESPONSE_DEBUG === "1" || process.env.RESPONSE_DEBUG === "true";
125011
125529
  var rlog = scopedLogger(() => createLogger("response-debug"));
125530
+ function responseArgBytes(input) {
125531
+ if (input == null)
125532
+ return 0;
125533
+ if (typeof input === "string")
125534
+ return input.length;
125535
+ try {
125536
+ return JSON.stringify(input).length;
125537
+ } catch {
125538
+ return -1;
125539
+ }
125540
+ }
125541
+
125542
+ class StreamDiagnostics {
125543
+ opts;
125544
+ stallEnabled;
125545
+ responseDebugEnabled;
125546
+ warn;
125547
+ responseArgChars = new Map;
125548
+ responseSawTerminal = new Map;
125549
+ lastChunkAt = Date.now();
125550
+ lastChunkType = "none";
125551
+ stallStepIndex = -1;
125552
+ stallTimer;
125553
+ constructor(options) {
125554
+ this.opts = options;
125555
+ this.stallEnabled = options.stallEnabled ?? STREAM_STALL_DEBUG;
125556
+ this.responseDebugEnabled = options.responseDebugEnabled ?? RESPONSE_DEBUG;
125557
+ this.warn = options.warn ?? ((message) => rlog.warn(message));
125558
+ }
125559
+ start() {
125560
+ if (!this.stallEnabled || this.stallTimer)
125561
+ return;
125562
+ const label = this.opts.sessionId;
125563
+ const sid = this.opts.subagentId;
125564
+ this.stallTimer = setInterval(() => {
125565
+ const gap = Date.now() - this.lastChunkAt;
125566
+ if (gap > STREAM_STALL_WARN_MS) {
125567
+ this.warn(`[stream-stall] no chunk for ${Math.round(gap / 1000)}s ` + `session=${label} subagent=${sid ?? "-"} step=${this.stallStepIndex} ` + `lastChunkType=${this.lastChunkType} ` + `inFlightTools=${[...this.opts.inFlightTools().values()].join(",")} ` + `responseToolFired=${this.opts.responseToolFired()}`);
125568
+ }
125569
+ }, STREAM_STALL_TICK_MS);
125570
+ }
125571
+ observeChunk(chunk) {
125572
+ if (this.stallEnabled) {
125573
+ const now = Date.now();
125574
+ const gap = now - this.lastChunkAt;
125575
+ this.lastChunkAt = now;
125576
+ this.lastChunkType = chunk.type;
125577
+ if (chunk.type === "start-step")
125578
+ this.stallStepIndex++;
125579
+ if (gap > STREAM_GAP_RECOVERED_MS) {
125580
+ this.warn(`[stream-gap] recovered after ${Math.round(gap / 1000)}s ` + `session=${this.opts.sessionId} chunkType=${chunk.type}`);
125581
+ }
125582
+ }
125583
+ if (this.responseDebugEnabled) {
125584
+ this.traceResponseTool(chunk);
125585
+ }
125586
+ }
125587
+ logSurfacedToolError(info) {
125588
+ if (!this.responseDebugEnabled)
125589
+ return;
125590
+ if (info.toolName !== this.opts.responseToolName)
125591
+ return;
125592
+ this.warn(`[response-debug] tool-error SURFACED id=${info.toolCallId} ` + `streamedArgChars=${info.streamedArgChars} ` + `finishReason=${info.finishReason ?? "unknown"} ` + `outputTokenTruncated=${info.truncated} error=${info.message.slice(0, 300)}`);
125593
+ }
125594
+ logClosingInFlightTool(info) {
125595
+ if (!this.responseDebugEnabled)
125596
+ return;
125597
+ if (info.toolName !== this.opts.responseToolName)
125598
+ return;
125599
+ this.warn(`[response-debug] CLOSING response as "did not complete" id=${info.toolCallId} ` + `streamedArgChars=${this.responseArgChars.get(info.toolCallId) ?? 0} ` + `sawTerminalChunk=${this.responseSawTerminal.get(info.toolCallId) ?? "none"} ` + `finishReason=${info.finishReason ?? "unknown"} outputTokenTruncated=${info.truncated} ` + `responseToolFired=${this.opts.responseToolFired()}`);
125600
+ }
125601
+ stop() {
125602
+ if (this.stallTimer)
125603
+ clearInterval(this.stallTimer);
125604
+ this.stallTimer = undefined;
125605
+ }
125606
+ traceResponseTool(chunk) {
125607
+ const idForChunk = chunk.toolCallId ?? chunk.id;
125608
+ const nameForChunk = chunk.toolName ?? (idForChunk ? this.opts.inFlightTools().get(idForChunk) : undefined);
125609
+ if (nameForChunk !== this.opts.responseToolName || !idForChunk) {
125610
+ if (chunk.type === "finish-step") {
125611
+ const responseInFlight = [...this.opts.inFlightTools().entries()].filter(([, n7]) => n7 === this.opts.responseToolName).map(([id]) => id).join(",");
125612
+ if (responseInFlight) {
125613
+ this.warn(`[response-debug] finish-step finishReason=${chunk.finishReason} ` + `responseInFlight=${responseInFlight} ` + `responseToolFired=${this.opts.responseToolFired()}`);
125614
+ }
125615
+ }
125616
+ return;
125617
+ }
125618
+ switch (chunk.type) {
125619
+ case "tool-input-start":
125620
+ this.responseArgChars.set(idForChunk, 0);
125621
+ this.warn(`[response-debug] tool-input-start id=${idForChunk} session=${this.opts.subagentId ?? this.opts.sessionId}`);
125622
+ break;
125623
+ case "tool-input-delta":
125624
+ this.responseArgChars.set(idForChunk, (this.responseArgChars.get(idForChunk) ?? 0) + (chunk.delta?.length ?? 0));
125625
+ break;
125626
+ case "tool-input-end":
125627
+ this.warn(`[response-debug] tool-input-end id=${idForChunk} argChars=${this.responseArgChars.get(idForChunk) ?? 0}`);
125628
+ break;
125629
+ case "tool-call": {
125630
+ this.responseSawTerminal.set(idForChunk, "tool-call");
125631
+ const inputBytes = responseArgBytes(chunk.input ?? chunk.args);
125632
+ this.warn(`[response-debug] tool-call id=${idForChunk} streamedArgChars=${this.responseArgChars.get(idForChunk) ?? 0} parsedInputBytes=${inputBytes} invalid=${chunk.invalid === true}`);
125633
+ break;
125634
+ }
125635
+ case "tool-error": {
125636
+ this.responseSawTerminal.set(idForChunk, "tool-error");
125637
+ const errMsg = chunk.error instanceof Error ? chunk.error.message : typeof chunk.error === "string" ? chunk.error : JSON.stringify(chunk.error)?.slice(0, 300);
125638
+ this.warn(`[response-debug] tool-error id=${idForChunk} streamedArgChars=${this.responseArgChars.get(idForChunk) ?? 0} stillInFlight=${this.opts.inFlightTools().has(idForChunk)} error=${errMsg}`);
125639
+ break;
125640
+ }
125641
+ case "tool-result":
125642
+ this.responseSawTerminal.set(idForChunk, "tool-result");
125643
+ this.warn(`[response-debug] tool-result id=${idForChunk} streamedArgChars=${this.responseArgChars.get(idForChunk) ?? 0}`);
125644
+ break;
125645
+ }
125646
+ }
125647
+ }
125648
+
125649
+ // src/core/agents/offSecAgent/toolLifecycle.ts
125650
+ class ToolLifecycleTracker {
125651
+ inFlight = new Map;
125652
+ completed = [];
125653
+ streamedArgs = new Map;
125654
+ errors = new Map;
125655
+ observePart(chunk) {
125656
+ switch (chunk.type) {
125657
+ case "tool-input-start":
125658
+ this.inFlight.set(chunk.id, chunk.toolName);
125659
+ this.streamedArgs.set(chunk.id, "");
125660
+ break;
125661
+ case "tool-input-delta":
125662
+ this.streamedArgs.set(chunk.id, (this.streamedArgs.get(chunk.id) ?? "") + (chunk.delta ?? ""));
125663
+ break;
125664
+ case "tool-call":
125665
+ this.inFlight.set(chunk.toolCallId, chunk.toolName);
125666
+ break;
125667
+ case "tool-error": {
125668
+ const toolCallId = chunk.toolCallId;
125669
+ this.inFlight.delete(toolCallId);
125670
+ const errMsg = chunk.error instanceof Error ? chunk.error.message : typeof chunk.error === "string" ? chunk.error : (() => {
125671
+ try {
125672
+ return JSON.stringify(chunk.error);
125673
+ } catch {
125674
+ return String(chunk.error);
125675
+ }
125676
+ })();
125677
+ const partialArgs = chunk.input !== undefined && chunk.input !== null && responseArgBytes(chunk.input) > 2 ? chunk.input : this.streamedArgs.get(toolCallId) ?? "";
125678
+ this.errors.set(toolCallId, {
125679
+ message: errMsg,
125680
+ input: partialArgs,
125681
+ toolName: chunk.toolName
125682
+ });
125683
+ break;
125684
+ }
125685
+ case "tool-result":
125686
+ this.inFlight.delete(chunk.toolCallId);
125687
+ this.completed.push({
125688
+ type: "tool-result",
125689
+ toolCallId: chunk.toolCallId,
125690
+ toolName: chunk.toolName,
125691
+ output: chunk.result ?? chunk.output
125692
+ });
125693
+ break;
125694
+ }
125695
+ }
125696
+ onStepPersisted() {
125697
+ this.completed.length = 0;
125698
+ }
125699
+ flushToolErrorsToResults() {
125700
+ const flushed = [];
125701
+ for (const [toolCallId, info] of this.errors) {
125702
+ this.completed.push({
125703
+ type: "tool-result",
125704
+ toolCallId,
125705
+ toolName: info.toolName,
125706
+ output: {
125707
+ type: "error-text",
125708
+ value: `Tool call failed: ${info.message}`
125709
+ }
125710
+ });
125711
+ flushed.push([toolCallId, info]);
125712
+ }
125713
+ this.errors.clear();
125714
+ return flushed;
125715
+ }
125716
+ clearToolErrors() {
125717
+ this.errors.clear();
125718
+ }
125719
+ clearInFlight() {
125720
+ this.inFlight.clear();
125721
+ }
125722
+ hasUnpersistedState() {
125723
+ return this.inFlight.size > 0 || this.completed.length > 0;
125724
+ }
125725
+ get inFlightTools() {
125726
+ return this.inFlight;
125727
+ }
125728
+ get toolErrors() {
125729
+ return this.errors;
125730
+ }
125731
+ get completedResults() {
125732
+ return this.completed;
125733
+ }
125734
+ get streamedArgText() {
125735
+ return this.streamedArgs;
125736
+ }
125737
+ snapshot() {
125738
+ return {
125739
+ inFlightTools: new Map(this.inFlight),
125740
+ completedResults: this.completed.map((r) => ({ ...r })),
125741
+ streamedArgText: new Map(this.streamedArgs),
125742
+ toolErrors: new Map(this.errors)
125743
+ };
125744
+ }
125745
+ }
125746
+
125747
+ // src/core/agents/offSecAgent/offensiveSecurityAgent.ts
125748
+ var log13 = scopedLogger(() => createLogger("approval-gate"));
125749
+ var RESPONSE_DEBUG2 = process.env.RESPONSE_DEBUG === "1" || process.env.RESPONSE_DEBUG === "true";
125750
+ var rlog2 = scopedLogger(() => createLogger("response-debug"));
125012
125751
  var WORKSPACE_TOOL_NAME_SET = new Set(WORKSPACE_TOOL_NAMES);
125013
125752
  var WORKSPACE_WRITE_TOOL_NAME_SET = new Set(WORKSPACE_WRITE_TOOL_NAMES);
125014
125753
  var WORKSPACE_TARGET_RE = /\b(?:console|workspace)\b/i;
@@ -125058,21 +125797,6 @@ function filterWorkspaceToolsForRun(activeTools, prompt, hasInteractiveApprovalG
125058
125797
  return true;
125059
125798
  });
125060
125799
  }
125061
- var STREAM_STALL_DEBUG = process.env.STREAM_STALL_DEBUG === "1" || process.env.STREAM_STALL_DEBUG === "true";
125062
- var STREAM_STALL_TICK_MS = 15000;
125063
- var STREAM_STALL_WARN_MS = 20000;
125064
- var STREAM_GAP_RECOVERED_MS = 1e4;
125065
- function responseArgBytes(input) {
125066
- if (input == null)
125067
- return 0;
125068
- if (typeof input === "string")
125069
- return input.length;
125070
- try {
125071
- return JSON.stringify(input).length;
125072
- } catch {
125073
- return -1;
125074
- }
125075
- }
125076
125800
 
125077
125801
  class OffensiveSecurityAgent {
125078
125802
  _streamResult = null;
@@ -125091,18 +125815,19 @@ class OffensiveSecurityAgent {
125091
125815
  drained = Promise.resolve();
125092
125816
  subagentId;
125093
125817
  subagentName;
125818
+ agentMode;
125094
125819
  currentMessageId = null;
125095
125820
  persistentShell;
125096
125821
  browserSession;
125097
125822
  ownsBrowserSession;
125098
125823
  browserDisconnected = false;
125824
+ shellDisposed = false;
125099
125825
  abortSignal;
125100
125826
  userPrompt;
125101
125827
  _session;
125102
- latestMessages = null;
125828
+ writer;
125829
+ finalizeInterruptedStep;
125103
125830
  messagesPath = null;
125104
- cancelPersistTimer = null;
125105
- syntheticsPersisted = false;
125106
125831
  static async create(input) {
125107
125832
  let session = input.session;
125108
125833
  if (!session) {
@@ -125127,6 +125852,7 @@ class OffensiveSecurityAgent {
125127
125852
  this._session = input.session;
125128
125853
  this.subagentId = input.subagentId;
125129
125854
  this.subagentName = input.subagentName;
125855
+ this.agentMode = input.mode ?? "default";
125130
125856
  this.abortSignal = input.abortSignal;
125131
125857
  this.userPrompt = input.prompt;
125132
125858
  this.eventBus = input.eventBus ?? new AgentEventBus;
@@ -125175,10 +125901,13 @@ class OffensiveSecurityAgent {
125175
125901
  agentCwd,
125176
125902
  target: input.target,
125177
125903
  grpc: input.grpc,
125904
+ systemScope: input.systemScope,
125178
125905
  abortSignal: input.abortSignal,
125179
125906
  model: input.model,
125180
125907
  authConfig: input.authConfig,
125181
125908
  eventBus: this.eventBus,
125909
+ onStepFinish: input.forwardUsageCallbacksToSpawnedAgents ? input.onStepFinish : undefined,
125910
+ onCacheMetrics: input.forwardUsageCallbacksToSpawnedAgents ? input.onCacheMetrics : undefined,
125182
125911
  sandbox: input.sandbox,
125183
125912
  findingsRegistry: input.findingsRegistry,
125184
125913
  attackSurfaceRegistry: input.attackSurfaceRegistry,
@@ -125210,8 +125939,8 @@ class OffensiveSecurityAgent {
125210
125939
  ...tools,
125211
125940
  [RESPONSE_TOOL_NAME]: createResponseTool(input.responseSchema, (result) => {
125212
125941
  this._responseToolFired = true;
125213
- if (RESPONSE_DEBUG) {
125214
- rlog.warn(`[response-debug] response tool EXECUTED (captured) session=${this.busSessionId} ` + `resultBytes=${responseArgBytes(result)} — happy path`);
125942
+ if (RESPONSE_DEBUG2) {
125943
+ rlog2.warn(`[response-debug] response tool EXECUTED (captured) session=${this.busSessionId} ` + `resultBytes=${responseArgBytes(result)} — happy path`);
125215
125944
  }
125216
125945
  const customResolve = input.resolveResult;
125217
125946
  if (customResolve) {
@@ -125259,7 +125988,11 @@ class OffensiveSecurityAgent {
125259
125988
  const hasEmail = (input.session.config?.emailIntegration?.inboxes?.length ?? 0) > 0;
125260
125989
  const hasSmtp = !!input.session.config?.smtpConfig;
125261
125990
  const emailToolSet = new Set(EMAIL_TOOL_NAMES);
125991
+ const smsToolSet = new Set(SMS_TOOL_NAMES);
125992
+ const hasSms = sessionHasSmsPasswordless(input.session);
125262
125993
  let activeTools = input.activeTools.filter((t) => {
125994
+ if (smsToolSet.has(t))
125995
+ return hasSms;
125263
125996
  if (!emailToolSet.has(t))
125264
125997
  return true;
125265
125998
  if (t === SEND_EMAIL_TOOL_NAME)
@@ -125274,6 +126007,8 @@ class OffensiveSecurityAgent {
125274
126007
  activeTools = Object.keys(tools).filter((t) => {
125275
126008
  if (excluded.has(t))
125276
126009
  return false;
126010
+ if (smsToolSet.has(t))
126011
+ return hasSms;
125277
126012
  if (!emailToolSet.has(t))
125278
126013
  return true;
125279
126014
  if (t === SEND_EMAIL_TOOL_NAME)
@@ -125282,11 +126017,10 @@ class OffensiveSecurityAgent {
125282
126017
  });
125283
126018
  }
125284
126019
  activeTools = filterWorkspaceToolsForRun(activeTools, input.prompt, input.approvalGate !== undefined);
125285
- if (!existsSync18(messagesDir)) {
126020
+ if (!existsSync19(messagesDir)) {
125286
126021
  mkdirSync14(messagesDir, { recursive: true });
125287
126022
  }
125288
126023
  this.messagesPath = join27(messagesDir, "messages.json");
125289
- const messagesPath = this.messagesPath;
125290
126024
  const initialMessagesRef = {
125291
126025
  current: input.messages ? [...input.messages] : [
125292
126026
  {
@@ -125295,26 +126029,17 @@ class OffensiveSecurityAgent {
125295
126029
  }
125296
126030
  ]
125297
126031
  };
125298
- const PERSIST_INTERVAL_MS = 15000;
125299
- let persistTimer = null;
125300
- const schedulePersist = () => {
125301
- if (persistTimer)
125302
- return;
125303
- persistTimer = setTimeout(() => {
125304
- persistTimer = null;
125305
- if (this.latestMessages) {
125306
- const toWrite = this.latestMessages;
125307
- this.latestMessages = null;
125308
- writeFile7(messagesPath, JSON.stringify(toWrite)).catch(() => {});
125309
- }
125310
- }, PERSIST_INTERVAL_MS);
125311
- };
125312
- this.cancelPersistTimer = () => {
125313
- if (persistTimer) {
125314
- clearTimeout(persistTimer);
125315
- persistTimer = null;
125316
- }
125317
- };
126032
+ this.writer = new AgentMessageWriter({ messagesPath: this.messagesPath });
126033
+ this.finalizeInterruptedStep = createInterruptedStepFinalizer({
126034
+ eventBus: this.eventBus,
126035
+ sessionId: this.busSessionId,
126036
+ subagentId: this.subagentId,
126037
+ writer: this.writer,
126038
+ responseToolName: RESPONSE_TOOL_NAME,
126039
+ responseToolFired: () => this._responseToolFired,
126040
+ ...RESPONSE_DEBUG2 ? { debugLog: (message) => rlog2.warn(message) } : {}
126041
+ });
126042
+ const schedulePersist = () => this.writer.schedulePersist();
125318
126043
  const baseSystemPrompt = input.system ?? detectOSAndEnhancePrompt(buildBaseSystemPrompt({
125319
126044
  sandboxMode: agentCwd === input.session.rootPath
125320
126045
  }));
@@ -125339,10 +126064,10 @@ class OffensiveSecurityAgent {
125339
126064
  sessionPath: messagesDir,
125340
126065
  sessionId: this.busSessionId,
125341
126066
  onStepFinish: async (event) => {
125342
- this.latestMessages = [
126067
+ this.writer.setLatest([
125343
126068
  ...initialMessagesRef.current,
125344
126069
  ...event.response.messages
125345
- ];
126070
+ ]);
125346
126071
  schedulePersist();
125347
126072
  traceWriter.recordStep(event.response.messages, {
125348
126073
  inputTokens: event.usage.inputTokens ?? 0,
@@ -125364,16 +126089,14 @@ class OffensiveSecurityAgent {
125364
126089
  traceWriter.markSummarized();
125365
126090
  },
125366
126091
  onFinish: async (event) => {
125367
- if (persistTimer) {
125368
- clearTimeout(persistTimer);
125369
- persistTimer = null;
125370
- }
125371
- if (!this.syntheticsPersisted) {
125372
- const finalMessages = this.latestMessages ?? [
126092
+ this.writer.cancelTimer();
126093
+ if (!this.writer.syntheticsPersisted) {
126094
+ const finalMessages = this.writer.latest ?? [
125373
126095
  ...initialMessagesRef.current,
125374
126096
  ...event.response.messages
125375
126097
  ];
125376
- await writeFile7(messagesPath, JSON.stringify(finalMessages)).catch(() => {});
126098
+ this.writer.setLatest(finalMessages);
126099
+ await this.writer.enqueueWrite(finalMessages).catch(() => {});
125377
126100
  }
125378
126101
  await input.onFinish?.(event);
125379
126102
  },
@@ -125425,205 +126148,34 @@ class OffensiveSecurityAgent {
125425
126148
  return p;
125426
126149
  }
125427
126150
  };
125428
- const inFlightTools = new Map;
125429
- const completedResults = [];
126151
+ const tracker = new ToolLifecycleTracker;
125430
126152
  let streamError = null;
125431
- const responseArgChars = new Map;
125432
- const responseSawTerminal = new Map;
125433
- const streamedArgText = new Map;
125434
- const toolErrors = new Map;
125435
- let lastChunkAt = Date.now();
125436
- let lastChunkType = "none";
125437
- let stallStepIndex = -1;
125438
- let stallTimer;
125439
- if (STREAM_STALL_DEBUG) {
125440
- const label = this._session.id;
125441
- stallTimer = setInterval(() => {
125442
- const gap = Date.now() - lastChunkAt;
125443
- if (gap > STREAM_STALL_WARN_MS) {
125444
- rlog.warn(`[stream-stall] no chunk for ${Math.round(gap / 1000)}s ` + `session=${label} subagent=${sid ?? "-"} step=${stallStepIndex} ` + `lastChunkType=${lastChunkType} ` + `inFlightTools=${[...inFlightTools.values()].join(",")} ` + `responseToolFired=${this._responseToolFired}`);
125445
- }
125446
- }, STREAM_STALL_TICK_MS);
125447
- }
126153
+ const diagnostics = new StreamDiagnostics({
126154
+ sessionId: this._session.id,
126155
+ subagentId: sid,
126156
+ inFlightTools: () => tracker.inFlightTools,
126157
+ responseToolFired: () => this._responseToolFired,
126158
+ responseToolName: RESPONSE_TOOL_NAME
126159
+ });
126160
+ diagnostics.start();
125448
126161
  try {
125449
126162
  for await (const chunk of this.streamResult.fullStream) {
125450
- if (STREAM_STALL_DEBUG) {
125451
- const now = Date.now();
125452
- const gap = now - lastChunkAt;
125453
- lastChunkAt = now;
125454
- lastChunkType = chunk.type;
125455
- if (chunk.type === "start-step")
125456
- stallStepIndex++;
125457
- if (gap > STREAM_GAP_RECOVERED_MS) {
125458
- rlog.warn(`[stream-gap] recovered after ${Math.round(gap / 1000)}s ` + `session=${this._session.id} chunkType=${chunk.type}`);
125459
- }
125460
- }
125461
- if (RESPONSE_DEBUG) {
125462
- const c = chunk;
125463
- const idForChunk = c.toolCallId ?? c.id;
125464
- const nameForChunk = c.toolName ?? (idForChunk ? inFlightTools.get(idForChunk) : undefined);
125465
- if (nameForChunk === RESPONSE_TOOL_NAME && idForChunk) {
125466
- if (chunk.type === "tool-input-start") {
125467
- responseArgChars.set(idForChunk, 0);
125468
- rlog.warn(`[response-debug] tool-input-start id=${idForChunk} session=${this.busSessionId}`);
125469
- } else if (chunk.type === "tool-input-delta") {
125470
- responseArgChars.set(idForChunk, (responseArgChars.get(idForChunk) ?? 0) + (c.delta?.length ?? 0));
125471
- } else if (chunk.type === "tool-input-end") {
125472
- rlog.warn(`[response-debug] tool-input-end id=${idForChunk} argChars=${responseArgChars.get(idForChunk) ?? 0}`);
125473
- } else if (chunk.type === "tool-call") {
125474
- responseSawTerminal.set(idForChunk, "tool-call");
125475
- const inputBytes = responseArgBytes(c.input ?? c.args);
125476
- const invalid = c.invalid === true;
125477
- rlog.warn(`[response-debug] tool-call id=${idForChunk} streamedArgChars=${responseArgChars.get(idForChunk) ?? 0} parsedInputBytes=${inputBytes} invalid=${invalid}`);
125478
- } else if (chunk.type === "tool-error") {
125479
- responseSawTerminal.set(idForChunk, "tool-error");
125480
- const errMsg = c.error instanceof Error ? c.error.message : typeof c.error === "string" ? c.error : JSON.stringify(c.error)?.slice(0, 300);
125481
- rlog.warn(`[response-debug] tool-error id=${idForChunk} streamedArgChars=${responseArgChars.get(idForChunk) ?? 0} stillInFlight=${inFlightTools.has(idForChunk)} error=${errMsg}`);
125482
- } else if (chunk.type === "tool-result") {
125483
- responseSawTerminal.set(idForChunk, "tool-result");
125484
- rlog.warn(`[response-debug] tool-result id=${idForChunk} streamedArgChars=${responseArgChars.get(idForChunk) ?? 0}`);
125485
- } else if (chunk.type === "finish-step") {
125486
- const fr = c.finishReason;
125487
- rlog.warn(`[response-debug] finish-step finishReason=${fr} responseInFlight=${[
125488
- ...inFlightTools.entries()
125489
- ].filter(([, n7]) => n7 === RESPONSE_TOOL_NAME).map(([id]) => id).join(",")} responseToolFired=${this._responseToolFired}`);
125490
- }
125491
- }
125492
- }
125493
- switch (chunk.type) {
125494
- case "start-step":
125495
- ids.messageId = newMessageId();
125496
- this.currentMessageId = ids.messageId;
125497
- ids.textPartId = undefined;
125498
- break;
125499
- case "text-start":
125500
- ids.textPartId = newPartId();
125501
- break;
125502
- case "text-end":
125503
- ids.textPartId = undefined;
125504
- break;
125505
- case "tool-input-start":
125506
- inFlightTools.set(chunk.id, chunk.toolName);
125507
- streamedArgText.set(chunk.id, "");
125508
- break;
125509
- case "tool-input-delta": {
125510
- const d = chunk;
125511
- streamedArgText.set(d.id, (streamedArgText.get(d.id) ?? "") + (d.delta ?? ""));
125512
- break;
125513
- }
125514
- case "tool-call":
125515
- inFlightTools.set(chunk.toolCallId, chunk.toolName);
125516
- break;
125517
- case "tool-error": {
125518
- const te2 = chunk;
125519
- inFlightTools.delete(te2.toolCallId);
125520
- const errMsg = te2.error instanceof Error ? te2.error.message : typeof te2.error === "string" ? te2.error : (() => {
125521
- try {
125522
- return JSON.stringify(te2.error);
125523
- } catch {
125524
- return String(te2.error);
125525
- }
125526
- })();
125527
- const partialArgs = te2.input !== undefined && te2.input !== null && responseArgBytes(te2.input) > 2 ? te2.input : streamedArgText.get(te2.toolCallId) ?? "";
125528
- toolErrors.set(te2.toolCallId, {
125529
- message: errMsg,
125530
- input: partialArgs,
125531
- toolName: te2.toolName
125532
- });
125533
- break;
125534
- }
125535
- case "tool-result": {
125536
- const tc = chunk;
125537
- inFlightTools.delete(tc.toolCallId);
125538
- completedResults.push({
125539
- type: "tool-result",
125540
- toolCallId: tc.toolCallId,
125541
- toolName: tc.toolName,
125542
- output: tc.result ?? tc.output
125543
- });
125544
- break;
125545
- }
125546
- case "finish-step": {
125547
- completedResults.length = 0;
125548
- const finishReason = chunk.finishReason;
125549
- const truncated = finishReason === "length";
125550
- for (const [toolCallId, info] of toolErrors) {
125551
- if (RESPONSE_DEBUG && info.toolName === RESPONSE_TOOL_NAME) {
125552
- rlog.warn(`[response-debug] tool-error SURFACED id=${toolCallId} ` + `streamedArgChars=${(streamedArgText.get(toolCallId) ?? "").length} ` + `finishReason=${finishReason ?? "unknown"} ` + `outputTokenTruncated=${truncated} error=${info.message.slice(0, 300)}`);
125553
- }
125554
- bus.emit("tool-result", {
125555
- toolCallId,
125556
- toolName: info.toolName,
125557
- result: {
125558
- type: "error-text",
125559
- value: truncated ? `Tool call failed: the model's output was truncated at its max output tokens before the "${info.toolName}" arguments were complete. ${info.message}` : `Tool call failed: ${info.message}`
125560
- },
125561
- sessionId: this.busSessionId,
125562
- subagentId: sid,
125563
- partId: ids.toolPartId?.(toolCallId),
125564
- messageId: ids.messageId
125565
- });
125566
- }
125567
- toolErrors.clear();
125568
- for (const [toolCallId, toolName] of inFlightTools) {
125569
- if (RESPONSE_DEBUG && toolName === RESPONSE_TOOL_NAME) {
125570
- rlog.warn(`[response-debug] CLOSING response as "did not complete" id=${toolCallId} ` + `streamedArgChars=${responseArgChars.get(toolCallId) ?? 0} ` + `sawTerminalChunk=${responseSawTerminal.get(toolCallId) ?? "none"} ` + `finishReason=${finishReason ?? "unknown"} outputTokenTruncated=${truncated} ` + `responseToolFired=${this._responseToolFired}`);
125571
- }
125572
- const result2 = toolName === RESPONSE_TOOL_NAME && this._responseToolFired ? { type: "text", value: "Response submitted." } : {
125573
- type: "error-text",
125574
- value: truncated ? "Tool call did not complete: the model's output was truncated at its max output tokens before the arguments were finalized." : "Tool call did not complete"
125575
- };
125576
- bus.emit("tool-result", {
125577
- toolCallId,
125578
- toolName,
125579
- result: result2,
125580
- sessionId: this.busSessionId,
125581
- subagentId: sid,
125582
- partId: ids.toolPartId?.(toolCallId),
125583
- messageId: ids.messageId
125584
- });
125585
- }
125586
- inFlightTools.clear();
125587
- break;
125588
- }
125589
- }
126163
+ diagnostics.observeChunk(chunk);
126164
+ this.applyStreamPart(chunk, { ids, tracker, diagnostics });
125590
126165
  bus.emitStreamPart(chunk, ids);
125591
126166
  }
125592
126167
  } catch (err) {
125593
126168
  streamError = err;
125594
126169
  } finally {
125595
- if (stallTimer)
125596
- clearInterval(stallTimer);
125597
- this.persistentShell?.dispose();
125598
- for (const [toolCallId, info] of toolErrors) {
125599
- const result2 = {
125600
- type: "error-text",
125601
- value: `Tool call failed: ${info.message}`
125602
- };
125603
- bus.emit("tool-result", {
125604
- toolCallId,
125605
- toolName: info.toolName,
125606
- result: result2,
125607
- sessionId: this.busSessionId,
125608
- subagentId: sid,
125609
- partId: ids.toolPartId?.(toolCallId),
125610
- messageId: ids.messageId
125611
- });
125612
- completedResults.push({
125613
- type: "tool-result",
125614
- toolCallId,
125615
- toolName: info.toolName,
125616
- output: result2
125617
- });
125618
- }
125619
- toolErrors.clear();
125620
- if (inFlightTools.size > 0 || completedResults.length > 0) {
125621
- const reason = this.abortSignal?.aborted ? "Agent aborted by user" : streamError instanceof Error && streamError.message ? streamError.message : "Stream terminated unexpectedly";
125622
- try {
125623
- await this.emitSyntheticToolResults(inFlightTools, completedResults, reason, ids.toolPartId, ids.messageId, streamedArgText);
125624
- } catch {}
126170
+ const finalizeError = await this.finalizeRun({
126171
+ tracker,
126172
+ diagnostics,
126173
+ ids,
126174
+ streamError
126175
+ });
126176
+ if (streamError === null && finalizeError !== null) {
126177
+ streamError = finalizeError;
125625
126178
  }
125626
- await this.disconnectOwnedBrowser();
125627
126179
  }
125628
126180
  if (streamError) {
125629
126181
  throw streamError;
@@ -125639,22 +126191,35 @@ class OffensiveSecurityAgent {
125639
126191
  }
125640
126192
  return;
125641
126193
  };
125642
- const spanLabel = this.subagentName ?? sid;
125643
- const drain = !sid ? runConsume() : withSubagentSessionBaggage(sid, () => getApexTracer().startActiveSpan(`invoke_agent ${spanLabel}`, {
125644
- attributes: {
125645
- "gen_ai.operation.name": "invoke_agent",
125646
- "gen_ai.agent.name": spanLabel
126194
+ const isSubagent = Boolean(sid);
126195
+ const spanLabel = isSubagent ? this.subagentName ?? sid ?? "subagent" : this.agentMode;
126196
+ const runId = isSubagent ? undefined : newRunId();
126197
+ const runSpanAttributes = {
126198
+ "gen_ai.operation.name": "invoke_agent",
126199
+ "gen_ai.agent.name": spanLabel,
126200
+ "gen_ai.conversation.id": this.busSessionId,
126201
+ "pensar.session.id": this.busSessionId,
126202
+ ...isSubagent ? {} : {
126203
+ "pensar.run.id": runId,
126204
+ "pensar.agent.mode": this.agentMode
125647
126205
  }
125648
- }, async (span) => {
126206
+ };
126207
+ const runInSpan = () => getApexTracer().startActiveSpan(`invoke_agent ${spanLabel}`, { attributes: runSpanAttributes }, async (span) => {
126208
+ if (!isSubagent)
126209
+ registerActiveRootSpan(span);
125649
126210
  try {
125650
126211
  return await runConsume();
125651
126212
  } catch (err) {
125652
126213
  span.recordException(err);
126214
+ span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
126215
+ span.setAttribute("error.type", err instanceof Error ? err.name : "Error");
125653
126216
  throw err;
125654
126217
  } finally {
126218
+ unregisterActiveRootSpan(span);
125655
126219
  span.end();
125656
126220
  }
125657
- }));
126221
+ });
126222
+ const drain = !isSubagent ? runInSpan() : withSubagentSessionBaggage(sid, runInSpan);
125658
126223
  let rejectDrain;
125659
126224
  this._drainRejection = new Promise((_2, reject) => {
125660
126225
  rejectDrain = reject;
@@ -125678,6 +126243,141 @@ class OffensiveSecurityAgent {
125678
126243
  await this.disconnectOwnedBrowser();
125679
126244
  return result;
125680
126245
  }
126246
+ applyStreamPart(chunk, ctx) {
126247
+ const { ids, tracker, diagnostics } = ctx;
126248
+ const sid = this.subagentId;
126249
+ const bus = this.eventBus;
126250
+ switch (chunk.type) {
126251
+ case "start-step":
126252
+ ids.messageId = newMessageId();
126253
+ this.currentMessageId = ids.messageId;
126254
+ ids.textPartId = undefined;
126255
+ break;
126256
+ case "text-start":
126257
+ ids.textPartId = newPartId();
126258
+ break;
126259
+ case "text-end":
126260
+ ids.textPartId = undefined;
126261
+ break;
126262
+ case "finish-step": {
126263
+ tracker.onStepPersisted();
126264
+ const finishReason = chunk.finishReason;
126265
+ const truncated = finishReason === "length";
126266
+ for (const [toolCallId, info] of tracker.toolErrors) {
126267
+ diagnostics.logSurfacedToolError({
126268
+ toolCallId,
126269
+ toolName: info.toolName,
126270
+ message: info.message,
126271
+ streamedArgChars: (tracker.streamedArgText.get(toolCallId) ?? "").length,
126272
+ finishReason,
126273
+ truncated
126274
+ });
126275
+ bus.emit("tool-result", {
126276
+ toolCallId,
126277
+ toolName: info.toolName,
126278
+ result: {
126279
+ type: "error-text",
126280
+ value: truncated ? `Tool call failed: the model's output was truncated at its max output tokens before the "${info.toolName}" arguments were complete. ${info.message}` : `Tool call failed: ${info.message}`
126281
+ },
126282
+ sessionId: this.busSessionId,
126283
+ subagentId: sid,
126284
+ partId: ids.toolPartId?.(toolCallId),
126285
+ messageId: ids.messageId
126286
+ });
126287
+ }
126288
+ tracker.clearToolErrors();
126289
+ for (const [toolCallId, toolName] of tracker.inFlightTools) {
126290
+ diagnostics.logClosingInFlightTool({
126291
+ toolCallId,
126292
+ toolName,
126293
+ finishReason,
126294
+ truncated
126295
+ });
126296
+ const result = toolName === RESPONSE_TOOL_NAME && this._responseToolFired ? { type: "text", value: "Response submitted." } : {
126297
+ type: "error-text",
126298
+ value: truncated ? "Tool call did not complete: the model's output was truncated at its max output tokens before the arguments were finalized." : "Tool call did not complete"
126299
+ };
126300
+ bus.emit("tool-result", {
126301
+ toolCallId,
126302
+ toolName,
126303
+ result,
126304
+ sessionId: this.busSessionId,
126305
+ subagentId: sid,
126306
+ partId: ids.toolPartId?.(toolCallId),
126307
+ messageId: ids.messageId
126308
+ });
126309
+ }
126310
+ tracker.clearInFlight();
126311
+ break;
126312
+ }
126313
+ default:
126314
+ tracker.observePart(chunk);
126315
+ }
126316
+ }
126317
+ async finalizeRun(input) {
126318
+ const { tracker, diagnostics, ids, streamError } = input;
126319
+ const sid = this.subagentId;
126320
+ const bus = this.eventBus;
126321
+ diagnostics.stop();
126322
+ let finalizationError;
126323
+ let hasFinalizationError = false;
126324
+ const recordFinalizationError = (error) => {
126325
+ if (hasFinalizationError)
126326
+ return;
126327
+ finalizationError = error;
126328
+ hasFinalizationError = true;
126329
+ };
126330
+ try {
126331
+ try {
126332
+ this.disposeOwnedShell();
126333
+ } catch (error) {
126334
+ recordFinalizationError(error);
126335
+ }
126336
+ for (const [toolCallId, info] of tracker.flushToolErrorsToResults()) {
126337
+ const result = {
126338
+ type: "error-text",
126339
+ value: `Tool call failed: ${info.message}`
126340
+ };
126341
+ try {
126342
+ bus.emit("tool-result", {
126343
+ toolCallId,
126344
+ toolName: info.toolName,
126345
+ result,
126346
+ sessionId: this.busSessionId,
126347
+ subagentId: sid,
126348
+ partId: ids.toolPartId?.(toolCallId),
126349
+ messageId: ids.messageId
126350
+ });
126351
+ } catch (error) {
126352
+ recordFinalizationError(error);
126353
+ }
126354
+ }
126355
+ if (tracker.hasUnpersistedState()) {
126356
+ const reason = this.abortSignal?.aborted ? "Agent aborted by user" : streamError instanceof Error && streamError.message ? streamError.message : "Stream terminated unexpectedly";
126357
+ try {
126358
+ await this.finalizeInterruptedStep({
126359
+ snapshot: tracker.snapshot(),
126360
+ reason,
126361
+ partIdFor: ids.toolPartId,
126362
+ messageId: ids.messageId
126363
+ });
126364
+ } catch (error) {
126365
+ recordFinalizationError(error);
126366
+ }
126367
+ }
126368
+ } catch (error) {
126369
+ recordFinalizationError(error);
126370
+ } finally {
126371
+ await this.disconnectOwnedBrowser();
126372
+ }
126373
+ return hasFinalizationError ? finalizationError : null;
126374
+ }
126375
+ disposeOwnedShell() {
126376
+ if (this.shellDisposed)
126377
+ return;
126378
+ this.shellDisposed = true;
126379
+ this.persistentShell?.dispose();
126380
+ }
125681
126381
  async disconnectOwnedBrowser() {
125682
126382
  if (this.browserDisconnected)
125683
126383
  return;
@@ -125693,102 +126393,6 @@ class OffensiveSecurityAgent {
125693
126393
  get response() {
125694
126394
  return this.streamResult.response;
125695
126395
  }
125696
- async emitSyntheticToolResults(inFlightTools, completedResults, reason, partIdFor, messageId, streamedArgText) {
125697
- const sid = this.subagentId;
125698
- const output = {
125699
- type: "error-text",
125700
- value: `Tool execution aborted: ${reason}`
125701
- };
125702
- const syntheticParts = [];
125703
- if (RESPONSE_DEBUG) {
125704
- const responseInFlight = [...inFlightTools.entries()].filter(([, n7]) => n7 === RESPONSE_TOOL_NAME);
125705
- if (responseInFlight.length > 0) {
125706
- rlog.warn(`[response-debug] emitSyntheticToolResults closing ${responseInFlight.length} response call(s) ` + `ids=${responseInFlight.map(([id]) => id).join(",")} reason="${reason}" ` + `aborted=${this.abortSignal?.aborted === true} responseToolFired=${this._responseToolFired}`);
125707
- }
125708
- }
125709
- for (const [toolCallId, toolName] of inFlightTools) {
125710
- const result = toolName === RESPONSE_TOOL_NAME && this._responseToolFired ? { type: "text", value: "Response submitted." } : output;
125711
- this.eventBus.emit("tool-result", {
125712
- toolCallId,
125713
- toolName,
125714
- result,
125715
- sessionId: this.busSessionId,
125716
- subagentId: sid,
125717
- partId: partIdFor?.(toolCallId),
125718
- messageId
125719
- });
125720
- syntheticParts.push({
125721
- type: "tool-result",
125722
- toolCallId,
125723
- toolName,
125724
- output: result
125725
- });
125726
- }
125727
- if (!this.messagesPath)
125728
- return;
125729
- this.cancelPersistTimer?.();
125730
- let base = this.latestMessages ?? [];
125731
- if (base.length === 0 && existsSync18(this.messagesPath)) {
125732
- try {
125733
- base = JSON.parse(readFileSync8(this.messagesPath, "utf-8"));
125734
- } catch {}
125735
- }
125736
- const allToolCallIds = new Set([
125737
- ...inFlightTools.keys(),
125738
- ...completedResults.map((r) => r.toolCallId)
125739
- ]);
125740
- const lastMsg = base[base.length - 1];
125741
- const needsStepReconstruction = !lastMsg || lastMsg.role !== "assistant" || !this.baseContainsToolCalls(lastMsg, allToolCallIds);
125742
- const appended = [];
125743
- if (needsStepReconstruction) {
125744
- const stepTools = [
125745
- ...inFlightTools,
125746
- ...completedResults.map((r) => [
125747
- r.toolCallId,
125748
- r.toolName
125749
- ])
125750
- ];
125751
- const reconstructInput = (toolCallId) => {
125752
- const raw = streamedArgText?.get(toolCallId);
125753
- if (!raw)
125754
- return {};
125755
- try {
125756
- return JSON.parse(raw);
125757
- } catch {
125758
- return { _partial: raw };
125759
- }
125760
- };
125761
- if (RESPONSE_DEBUG) {
125762
- const responseReconstructed = stepTools.filter(([, n7]) => n7 === RESPONSE_TOOL_NAME).map(([id]) => id);
125763
- if (responseReconstructed.length > 0) {
125764
- rlog.warn(`[response-debug] step-reconstruction for response call(s) ` + `ids=${responseReconstructed.join(",")} ` + `preservedArgChars=${responseReconstructed.map((id) => streamedArgText?.get(id)?.length ?? 0).join(",")}`);
125765
- }
125766
- }
125767
- const toolCalls = stepTools.map(([toolCallId, toolName]) => ({
125768
- type: "tool-call",
125769
- toolCallId,
125770
- toolName,
125771
- input: reconstructInput(toolCallId)
125772
- }));
125773
- appended.push({ role: "assistant", content: toolCalls });
125774
- }
125775
- appended.push({
125776
- role: "tool",
125777
- content: [...completedResults, ...syntheticParts]
125778
- });
125779
- const next = [...base, ...appended];
125780
- this.latestMessages = next;
125781
- try {
125782
- await writeFile7(this.messagesPath, JSON.stringify(next));
125783
- this.syntheticsPersisted = true;
125784
- } catch {}
125785
- }
125786
- baseContainsToolCalls(msg, toolCallIds) {
125787
- if (!Array.isArray(msg.content))
125788
- return false;
125789
- const contentToolIds = new Set(msg.content.filter((p) => p.type === "tool-call" && p.toolCallId).map((p) => p.toolCallId));
125790
- return [...toolCallIds].every((id) => contentToolIds.has(id));
125791
- }
125792
126396
  }
125793
126397
  var AGENT_PAUSE_TOOLS = new Set([ASK_USER_QUESTIONS_TOOL_NAME]);
125794
126398
  function wrapToolsWithApprovalGate(tools, gate, exemptToolNames) {
@@ -125828,4 +126432,4 @@ function wrapToolsWithApprovalGate(tools, gate, exemptToolNames) {
125828
126432
  return wrapped;
125829
126433
  }
125830
126434
 
125831
- export { AgentEventBus, INTERNAL_ID_PATTERN, ApprovalGate, OPERATOR_MODES, OPERATOR_MODE_CYCLE, createInitialOperatorState, buildProvidedFilesSection, buildSessionWorkspaceSection, buildBaseSystemPrompt, BASE_SYSTEM_PROMPT, isMemoryEnabled, addMemory2 as addMemory, ASK_USER_QUESTIONS_TOOL_NAME, AskUserQuestionSchema, transformScriptToFunction, parseStorageStateResult, setHeadlessMode, setUserAgent, setViewportSize, PlaywrightMcpSession, createBrowserTools, ScopeViolationError, getAllowedHosts, isHostAllowed, extractHostname2 as extractHostname, assertUrlInScope, extractHostsFromCommand, assertCommandInScope, checkSandboxPlaywright, installSandboxPlaywright, ensureSandboxPlaywright, ensureSandboxBrowser, createSandboxBrowserTools, BROWSER_TOOL_NAMES, createBrowserToolset, checkpointState, completeAuthentication, crawlAuthenticated, createAttackSurfaceReport, createFile, createTask2 as createTask, delegateAuth, detectAuthScheme, documentApp, EndpointTransportEnum, GrpcEndpointMetadataSchema, toGrpcPentestContext, grpcAuthorityTarget, pLimit, documentEndpoint, CweEntrySchema, ValidatedCweEntrySchema, hasCanonicalName, documentVulnerability, createEmailToolset, EMAIL_TOOL_NAMES, SEND_EMAIL_TOOL_NAME, executeCommand, extractJsEndpoints, getMemory2 as getMemory, getPage, grep, httpRequest, listFiles, listMemories2 as listMemories, listTasksTool, readTempfileCapped, getApexTmpRoot, extractFallbackStdout, PersistentShell, probeAuthEndpoints, provideComparisonResults, readFile2 as readFile, readSkill, REPORT_ERROR_TOOL_NAME, ReportErrorReasonSchema, createReportErrorTool, PentestReportedError, RESPONSE_TOOL_NAME, createResponseTool, runAttackSurface, runPentestWorkflow, runWithBoundedConcurrency, spawnCodingAgent, FindingsRegistry, planFilePath, readPlan, hasPlan, spawnPentestAgent, spawnPentestSwarm, submitPlan, testEndpointVariations, updateFile, updateTask2 as updateTask, validateDiscovery, webSearch, apiRequest, listApps, getApp, createApp, updateApp, deleteApp, listEndpoints, getEndpoint, createEndpoint, updateEndpoint, deleteEndpoint, searchApps, searchEndpoints, listWorkspaceApps, createWorkspaceApp, updateWorkspaceApp, listWorkspaceEndpoints, createWorkspaceEndpoint, updateWorkspaceEndpoint, listWorkspaceDomains, createWorkspaceDomain, writePlan, createAllTools, ALL_TOOL_NAMES, FAST_STRIKE_EXCLUDED_TOOL_NAMES, PLAN_MODE_TOOL_NAMES, SKILL_TOOL_NAMES, StepTraceWriter, OffensiveSecurityAgent };
126435
+ export { AgentEventBus, INTERNAL_ID_PATTERN, ApprovalGate, OPERATOR_MODES, OPERATOR_MODE_CYCLE, createInitialOperatorState, buildProvidedFilesSection, buildSessionWorkspaceSection, buildBaseSystemPrompt, BASE_SYSTEM_PROMPT, isMemoryEnabled, addMemory2 as addMemory, ASK_USER_QUESTIONS_TOOL_NAME, AskUserQuestionSchema, transformScriptToFunction, parseStorageStateResult, setHeadlessMode, setUserAgent, setViewportSize, PlaywrightMcpSession, createBrowserTools, ScopeViolationError, getAllowedHosts, isHostAllowed, extractHostname2 as extractHostname, assertUrlInScope, extractHostsFromCommand, assertCommandInScope, checkSandboxPlaywright, installSandboxPlaywright, ensureSandboxPlaywright, ensureSandboxBrowser, createSandboxBrowserTools, BROWSER_TOOL_NAMES, createBrowserToolset, checkpointState, completeAuthentication, crawlAuthenticated, createAttackSurfaceReport, createFile, createTask2 as createTask, delegateAuth, detectAuthScheme, documentApp, EndpointTransportEnum, GrpcEndpointMetadataSchema, toGrpcPentestContext, grpcAuthorityTarget, pLimit, documentEndpoint, AttackPathSchema, CweEntrySchema, ValidatedCweEntrySchema, hasCanonicalName, documentVulnerability, createEmailToolset, EMAIL_TOOL_NAMES, SEND_EMAIL_TOOL_NAME, executeCommand, extractJsEndpoints, getMemory2 as getMemory, getPage, grep, httpRequest, listFiles, listMemories2 as listMemories, listTasksTool, readTempfileCapped, getApexTmpRoot, extractFallbackStdout, PersistentShell, probeAuthEndpoints, provideComparisonResults, readFile2 as readFile, readSkill, REPORT_ERROR_TOOL_NAME, ReportErrorReasonSchema, createReportErrorTool, PentestReportedError, RESPONSE_TOOL_NAME, createResponseTool, runAttackSurface, runPentestWorkflow, SMS_LIST_MESSAGES_TOOL_NAME, SMS_TOOL_NAMES, sessionHasSmsPasswordless, runWithBoundedConcurrency, spawnCodingAgent, FindingsRegistry, planFilePath, readPlan, hasPlan, spawnPentestAgent, spawnPentestSwarm, submitPlan, testEndpointVariations, updateFile, updateTask2 as updateTask, validateDiscovery, webSearch, apiRequest, ENDPOINT_TRANSPORTS, listApps, getApp, createApp, updateApp, deleteApp, listEndpoints, getEndpoint, createEndpoint, updateEndpoint, deleteEndpoint, searchApps, searchEndpoints, listWorkspaceApps, createWorkspaceApp, updateWorkspaceApp, listWorkspaceEndpoints, createWorkspaceEndpoint, updateWorkspaceEndpoint, listDomains, createDomain, listWorkspaceDomains, createWorkspaceDomain, writePlan, createAllTools, ALL_TOOL_NAMES, FAST_STRIKE_EXCLUDED_TOOL_NAMES, PLAN_MODE_TOOL_NAMES, SKILL_TOOL_NAMES, StepTraceWriter, OffensiveSecurityAgent };