@pensar/apex 2.4.0 → 2.5.0-canary.aa559068

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-48xj79bj.js +20 -0
  2. package/build/{agent-nhs1w5w0.js → agent-7q3c9cjt.js} +11 -10
  3. package/build/{agent-5ejt5vpz.js → agent-ve8pkr6q.js} +9 -8
  4. package/build/{apps-17wvz1d7.js → apps-4rsrnftx.js} +72 -31
  5. package/build/{auth-z3h9859n.js → auth-0w07dbg2.js} +25 -20
  6. package/build/authentication-87zzmjdd.js +20 -0
  7. package/build/blackboxAgent-x0e1wqjx.js +20 -0
  8. package/build/blackboxPentest-0hwj49dr.js +70 -0
  9. package/build/{cli-32z0017y.js → cli-12ky98ey.js} +2 -2
  10. package/build/{cli-5k33webc.js → cli-2ar3m569.js} +45 -43
  11. package/build/cli-53rm0rrz.js +15 -0
  12. package/build/{cli-72cvcqhg.js → cli-54egv3xw.js} +1 -1
  13. package/build/cli-68260ckj.js +12136 -0
  14. package/build/{cli-gq40s5b3.js → cli-6cq67y5m.js} +5 -3
  15. package/build/{cli-mavved45.js → cli-7735d17s.js} +46 -25
  16. package/build/cli-7q3ae3ft.js +6 -0
  17. package/build/{cli-tznv8pf1.js → cli-8mws7sa5.js} +1 -1
  18. package/build/cli-9pbk8m32.js +32 -0
  19. package/build/{cli-swpbx60z.js → cli-avmhkjtv.js} +1 -1481
  20. package/build/{cli-9rhzhgx2.js → cli-eaaqeve1.js} +1 -1
  21. package/build/{cli-qqt4gj1w.js → cli-g0whajsq.js} +5 -3
  22. package/build/{cli-vq52kp7j.js → cli-gb1s7k3v.js} +17 -5
  23. package/build/{cli-2cbwdk78.js → cli-h8xsqggy.js} +1 -1
  24. package/build/{cli-0n4r54hq.js → cli-jsw8vt43.js} +1 -1
  25. package/build/cli-knd276ed.js +1485 -0
  26. package/build/{cli-repbyhkk.js → cli-kya26m6f.js} +1136 -525
  27. package/build/{cli-k8kc47pq.js → cli-mmyn6wmb.js} +3 -3
  28. package/build/{cli-tkc598ey.js → cli-qwv4jsj2.js} +371 -279
  29. package/build/{cli-xshasbwe.js → cli-r3w58pmq.js} +30 -4
  30. package/build/{cli-vnynf0js.js → cli-w51z9qjr.js} +10 -4
  31. package/build/{cli-b1adytsy.js → cli-whp0f8gp.js} +28 -5
  32. package/build/cli.js +553 -95
  33. package/build/{config-f1mj4nhd.js → config-z9k13rvy.js} +18 -15
  34. package/build/{doctor-ekneewa3.js → doctor-tc5zs6pn.js} +8 -7
  35. package/build/{fastStrike-8zka43xs.js → fastStrike-ssm7df42.js} +13 -10
  36. package/build/{fixes-b89s5haw.js → fixes-av9nq0hq.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-hqjdg6fg.js → index-1ppbwgf9.js} +17 -9
  43. package/build/{index-mtq7kmxz.js → index-5wh7gq37.js} +4 -2
  44. package/build/{index-6d22pyxt.js → index-718m7jw9.js} +1669 -1193
  45. package/build/{index-rbzhk712.js → index-gng8ebqf.js} +11 -10
  46. package/build/{index-y5w6n3tb.js → index-hhcjyc6j.js} +2 -2
  47. package/build/{index-sf16jm0m.js → index-mffgf5hg.js} +9 -7
  48. package/build/{index-ghwf5z3v.js → index-p1atm3ha.js} +3 -3
  49. package/build/{index-4ad3sdwk.js → index-vvkvwmyr.js} +4 -4
  50. package/build/{issues-xx5bs4md.js → issues-hfg8jydv.js} +72 -26
  51. package/build/{logs-qtxe51w2.js → logs-0rd1z7ct.js} +25 -20
  52. package/build/{offesecAgent-b9e2xm6v.js → offesecAgent-j4epj93p.js} +10 -9
  53. package/build/pentest-dp9w88pw.js +30 -0
  54. package/build/{pentests-6ks3szc4.js → pentests-enyxjtg6.js} +26 -21
  55. package/build/{targetedPentest-s1ptvq8e.js → targetedPentest-kwabfy86.js} +11 -10
  56. package/build/{targets-sxygyj87.js → targets-7x0pcmws.js} +27 -22
  57. package/build/threatModel-zwk5eb6r.js +29 -0
  58. package/build/{uninstall-tvsh81v8.js → uninstall-psm9btpt.js} +6 -3
  59. package/build/{upload-7wdyyqmr.js → upload-dybnknjs.js} +8 -7
  60. package/build/{utils-7fwdkqk6.js → utils-dsfk965b.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-8mws7sa5.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,6 +25,7 @@ import {
24
25
  list,
25
26
  newMessageId,
26
27
  newPartId,
28
+ newRunId,
27
29
  newSessionId,
28
30
  read,
29
31
  require_tslib,
@@ -32,14 +34,14 @@ import {
32
34
  streamResponse,
33
35
  withSubagentSessionBaggage,
34
36
  write
35
- } from "./cli-tkc598ey.js";
37
+ } from "./cli-qwv4jsj2.js";
36
38
  import {
37
39
  ensureValidToken,
38
40
  getPensarApiUrl,
39
41
  init_auth,
40
42
  init_constants,
41
43
  signGatewayRequest
42
- } from "./cli-0n4r54hq.js";
44
+ } from "./cli-jsw8vt43.js";
43
45
  import {
44
46
  _enum,
45
47
  _null,
@@ -60,17 +62,23 @@ import {
60
62
  optional,
61
63
  preprocess,
62
64
  record,
63
- require_src,
64
65
  safeParse,
65
66
  string,
66
67
  tool,
67
68
  union,
68
69
  unknown
69
- } from "./cli-swpbx60z.js";
70
+ } from "./cli-avmhkjtv.js";
70
71
  import {
71
72
  config,
72
73
  init_config
73
- } from "./cli-72cvcqhg.js";
74
+ } from "./cli-54egv3xw.js";
75
+ import {
76
+ getCurrentVersion,
77
+ init_installation
78
+ } from "./cli-w51z9qjr.js";
79
+ import {
80
+ require_src
81
+ } from "./cli-knd276ed.js";
74
82
  import {
75
83
  __commonJS,
76
84
  __require,
@@ -102763,12 +102771,7 @@ function camoufoxWindowOptions(window2) {
102763
102771
  const [width, height] = window2;
102764
102772
  return {
102765
102773
  window: [width, height],
102766
- screen: {
102767
- minWidth: width,
102768
- maxWidth: width,
102769
- minHeight: height,
102770
- maxHeight: height
102771
- }
102774
+ screen: { minWidth: width, minHeight: height }
102772
102775
  };
102773
102776
  }
102774
102777
  async function resolveCamoufoxLaunchOptions(headless, opts) {
@@ -104466,6 +104469,19 @@ function assertUrlInScope(url, ctx) {
104466
104469
  throw new ScopeViolationError(hostname, allowedHosts);
104467
104470
  }
104468
104471
  }
104472
+ function assertFindingEndpointInScope(endpoint, ctx) {
104473
+ const allowedHosts = getAllowedHosts(ctx);
104474
+ if (allowedHosts.length === 0)
104475
+ return;
104476
+ if (!/^https?:\/\//i.test(endpoint.trim()))
104477
+ return;
104478
+ const hostname = extractHostname2(endpoint);
104479
+ if (!hostname)
104480
+ return;
104481
+ if (!isHostAllowed(hostname, allowedHosts)) {
104482
+ throw new ScopeViolationError(hostname, allowedHosts);
104483
+ }
104484
+ }
104469
104485
  function extractHostsFromCommand(command) {
104470
104486
  const hosts = new Set;
104471
104487
  const urlPattern = /https?:\/\/[^\s"'`;|&)<>]+/gi;
@@ -105055,12 +105071,8 @@ const fs = require('fs');
105055
105071
  ...${JSON.stringify(CAMOUFOX_OPTIONS)},
105056
105072
  headless: __headless,
105057
105073
  window: __window,
105058
- screen: {
105059
- minWidth: __window[0],
105060
- maxWidth: __window[0],
105061
- minHeight: __window[1],
105062
- maxHeight: __window[1],
105063
- },
105074
+ // Floor only — exact-pinning a 720px height throws in browserforge.
105075
+ screen: { minWidth: __window[0], minHeight: __window[1] },
105064
105076
  });
105065
105077
  fs.writeFileSync('${SANDBOX_CAMOU_CACHE}', JSON.stringify(__camou));
105066
105078
  }
@@ -106761,7 +106773,7 @@ IMPORTANT: Pass protectedEndpoints in authHints when you've discovered 401/403 e
106761
106773
  if (credentials) {
106762
106774
  ctx.session.credentialManager.addFromAuthCredentials(credentials);
106763
106775
  }
106764
- const { runAuthenticationAgent } = await import("./authentication-3s97cpk4.js");
106776
+ const { runAuthenticationAgent } = await import("./authentication-87zzmjdd.js");
106765
106777
  const localBus = new AgentEventBus;
106766
106778
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
106767
106779
  const result = await runAuthenticationAgent({
@@ -107555,7 +107567,7 @@ async function generateThreatModelForEndpoint(ctx, input) {
107555
107567
  return threatModelLimiter(async () => {
107556
107568
  if (ctx.abortSignal?.aborted)
107557
107569
  return null;
107558
- const { CodeAgent } = await import("./agent-mvpgvgks.js");
107570
+ const { CodeAgent } = await import("./agent-48xj79bj.js");
107559
107571
  const subagentId = newSessionId();
107560
107572
  const subagentName = `Threat Model: ${input.routePath}`;
107561
107573
  ctx.eventBus?.emit("subagent-spawn", {
@@ -108044,6 +108056,16 @@ import {
108044
108056
  } from "node:fs";
108045
108057
  import { join as join13 } from "node:path";
108046
108058
 
108059
+ // src/lib/attack-path/types.ts
108060
+ init_zod();
108061
+ var AttackPathSchema = exports_external.array(exports_external.object({
108062
+ applicationId: exports_external.string().optional(),
108063
+ applicationName: exports_external.string().optional(),
108064
+ host: exports_external.string().optional(),
108065
+ relationshipType: exports_external.string().optional(),
108066
+ notes: exports_external.string().optional()
108067
+ }));
108068
+
108047
108069
  // src/lib/cwe/types.ts
108048
108070
  init_zod();
108049
108071
  var CweEntrySchema = exports_external.object({
@@ -108366,6 +108388,47 @@ var MAX_SEVERITY = {
108366
108388
  eq4: { 0: 6, 1: 5, 2: 4 },
108367
108389
  eq5: { 0: 1, 1: 1, 2: 1 }
108368
108390
  };
108391
+ var MAX_COMPOSED = {
108392
+ eq1: {
108393
+ 0: ["AV:N/PR:N/UI:N/"],
108394
+ 1: ["AV:A/PR:N/UI:N/", "AV:N/PR:L/UI:N/", "AV:N/PR:N/UI:P/"],
108395
+ 2: ["AV:P/PR:N/UI:N/", "AV:A/PR:L/UI:P/"]
108396
+ },
108397
+ eq2: {
108398
+ 0: ["AC:L/AT:N/"],
108399
+ 1: ["AC:H/AT:N/", "AC:L/AT:P/"]
108400
+ },
108401
+ eq3: {
108402
+ 0: {
108403
+ "0": ["VC:H/VI:H/VA:H/CR:H/IR:H/AR:H/"],
108404
+ "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/"]
108405
+ },
108406
+ 1: {
108407
+ "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/"],
108408
+ "1": [
108409
+ "VC:L/VI:H/VA:L/CR:H/IR:M/AR:H/",
108410
+ "VC:L/VI:H/VA:H/CR:H/IR:M/AR:M/",
108411
+ "VC:H/VI:L/VA:H/CR:M/IR:H/AR:M/",
108412
+ "VC:H/VI:L/VA:L/CR:M/IR:H/AR:H/",
108413
+ "VC:L/VI:L/VA:H/CR:H/IR:H/AR:M/"
108414
+ ]
108415
+ },
108416
+ 2: {
108417
+ "1": ["VC:L/VI:L/VA:L/CR:H/IR:H/AR:H/"]
108418
+ }
108419
+ },
108420
+ eq4: {
108421
+ 0: ["SC:H/SI:S/SA:S/"],
108422
+ 1: ["SC:H/SI:H/SA:H/"],
108423
+ 2: ["SC:L/SI:L/SA:L/"]
108424
+ },
108425
+ eq5: {
108426
+ 0: ["E:A/"],
108427
+ 1: ["E:P/"],
108428
+ 2: ["E:U/"]
108429
+ }
108430
+ };
108431
+ var NO_IMPACT_METRICS = ["VC", "VI", "VA", "SC", "SI", "SA"];
108369
108432
  var STEP = 0.1;
108370
108433
  var EPSILON = 10 ** -6;
108371
108434
 
@@ -108414,6 +108477,12 @@ var ENVIRONMENTAL_METRICS = [
108414
108477
  "MSA"
108415
108478
  ];
108416
108479
  var SUPPLEMENTAL_METRICS = ["S", "AU", "R", "V", "RE", "U"];
108480
+ var KNOWN_METRICS = new Set([
108481
+ ...BASE_METRICS,
108482
+ ...THREAT_METRICS,
108483
+ ...ENVIRONMENTAL_METRICS,
108484
+ ...SUPPLEMENTAL_METRICS
108485
+ ]);
108417
108486
  function buildVectorString(metrics) {
108418
108487
  const parts = ["CVSS:4.0"];
108419
108488
  for (const metric of BASE_METRICS) {
@@ -108442,39 +108511,49 @@ function buildVectorString(metrics) {
108442
108511
  }
108443
108512
  return parts.join("/");
108444
108513
  }
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] ?? "";
108514
+ var WORST_CASE_DEFAULTS = {
108515
+ E: "A",
108516
+ CR: "H",
108517
+ IR: "H",
108518
+ AR: "H"
108519
+ };
108520
+ function getEffectiveValue(metrics, metric) {
108521
+ const record3 = metrics;
108522
+ const selected = record3[metric] ?? "X";
108523
+ const worstCase = WORST_CASE_DEFAULTS[metric];
108524
+ if (worstCase !== undefined && selected === "X") {
108525
+ return worstCase;
108526
+ }
108527
+ const modified = record3[`M${metric}`];
108528
+ if (modified !== undefined && modified !== "X") {
108529
+ return modified;
108530
+ }
108531
+ return selected;
108453
108532
  }
108454
108533
  function computeEQ1(metrics) {
108455
- const av = getEffectiveValue(metrics, "AV", "MAV");
108456
- const pr = getEffectiveValue(metrics, "PR", "MPR");
108457
- const ui = getEffectiveValue(metrics, "UI", "MUI");
108534
+ const av = getEffectiveValue(metrics, "AV");
108535
+ const pr = getEffectiveValue(metrics, "PR");
108536
+ const ui = getEffectiveValue(metrics, "UI");
108458
108537
  if (av === "N" && pr === "N" && ui === "N") {
108459
108538
  return 0;
108460
108539
  }
108461
- if (!(av === "P" || pr === "H" || ui === "A")) {
108540
+ if ((av === "N" || pr === "N" || ui === "N") && av !== "P") {
108462
108541
  return 1;
108463
108542
  }
108464
108543
  return 2;
108465
108544
  }
108466
108545
  function computeEQ2(metrics) {
108467
- const ac = getEffectiveValue(metrics, "AC", "MAC");
108468
- const at = getEffectiveValue(metrics, "AT", "MAT");
108546
+ const ac = getEffectiveValue(metrics, "AC");
108547
+ const at = getEffectiveValue(metrics, "AT");
108469
108548
  if (ac === "L" && at === "N") {
108470
108549
  return 0;
108471
108550
  }
108472
108551
  return 1;
108473
108552
  }
108474
108553
  function computeEQ3(metrics) {
108475
- const vc = getEffectiveValue(metrics, "VC", "MVC");
108476
- const vi = getEffectiveValue(metrics, "VI", "MVI");
108477
- const va = getEffectiveValue(metrics, "VA", "MVA");
108554
+ const vc = getEffectiveValue(metrics, "VC");
108555
+ const vi = getEffectiveValue(metrics, "VI");
108556
+ const va = getEffectiveValue(metrics, "VA");
108478
108557
  if (vc === "H" && vi === "H") {
108479
108558
  return 0;
108480
108559
  }
@@ -108484,11 +108563,11 @@ function computeEQ3(metrics) {
108484
108563
  return 2;
108485
108564
  }
108486
108565
  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;
108566
+ const msi = getEffectiveValue(metrics, "MSI");
108567
+ const msa = getEffectiveValue(metrics, "MSA");
108568
+ const sc = getEffectiveValue(metrics, "SC");
108569
+ const si = getEffectiveValue(metrics, "SI");
108570
+ const sa = getEffectiveValue(metrics, "SA");
108492
108571
  if (msi === "S" || msa === "S") {
108493
108572
  return 0;
108494
108573
  }
@@ -108498,8 +108577,8 @@ function computeEQ4(metrics) {
108498
108577
  return 2;
108499
108578
  }
108500
108579
  function computeEQ5(metrics) {
108501
- const e = metrics.E || "A";
108502
- if (e === "A" || e === "X") {
108580
+ const e = getEffectiveValue(metrics, "E");
108581
+ if (e === "A") {
108503
108582
  return 0;
108504
108583
  }
108505
108584
  if (e === "P") {
@@ -108508,12 +108587,12 @@ function computeEQ5(metrics) {
108508
108587
  return 2;
108509
108588
  }
108510
108589
  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");
108590
+ const cr = getEffectiveValue(metrics, "CR");
108591
+ const ir = getEffectiveValue(metrics, "IR");
108592
+ const ar = getEffectiveValue(metrics, "AR");
108593
+ const vc = getEffectiveValue(metrics, "VC");
108594
+ const vi = getEffectiveValue(metrics, "VI");
108595
+ const va = getEffectiveValue(metrics, "VA");
108517
108596
  if (cr === "H" && vc === "H" || ir === "H" && vi === "H" || ar === "H" && va === "H") {
108518
108597
  return 0;
108519
108598
  }
@@ -108529,116 +108608,130 @@ function computeMacroVector(metrics) {
108529
108608
  return `${eq1}${eq2}${eq3}${eq4}${eq5}${eq6}`;
108530
108609
  }
108531
108610
  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";
108611
+ return NO_IMPACT_METRICS.every((metric) => getEffectiveValue(metrics, metric) === "N");
108539
108612
  }
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] ?? "";
108613
+ function parseMacroVector(macroVector) {
108614
+ return {
108615
+ eq1: Number(macroVector[0]),
108616
+ eq2: Number(macroVector[1]),
108617
+ eq3: Number(macroVector[2]),
108618
+ eq4: Number(macroVector[3]),
108619
+ eq5: Number(macroVector[4]),
108620
+ eq6: Number(macroVector[5])
108621
+ };
108622
+ }
108623
+ function lowerMacroVectorScore(eq, step) {
108624
+ const stepped = { ...eq, ...step };
108625
+ return MACROVECTOR_LOOKUP[`${stepped.eq1}${stepped.eq2}${stepped.eq3}${stepped.eq4}${stepped.eq5}${stepped.eq6}`];
108626
+ }
108627
+ function lowerEq3Eq6Score(eq) {
108628
+ if (eq.eq3 === 0 && eq.eq6 === 0) {
108629
+ const viaEq6 = lowerMacroVectorScore(eq, { eq6: eq.eq6 + 1 });
108630
+ const viaEq3 = lowerMacroVectorScore(eq, { eq3: eq.eq3 + 1 });
108631
+ if (viaEq6 === undefined || viaEq3 === undefined) {
108632
+ return;
108633
+ }
108634
+ return Math.max(viaEq6, viaEq3);
108635
+ }
108636
+ if (eq.eq3 === 1 && eq.eq6 === 0) {
108637
+ return lowerMacroVectorScore(eq, { eq6: eq.eq6 + 1 });
108638
+ }
108639
+ if (eq.eq3 < 2) {
108640
+ return lowerMacroVectorScore(eq, { eq3: eq.eq3 + 1 });
108551
108641
  }
108552
- if (metric === "E" && (!value || value === "X")) {
108553
- value = "A";
108642
+ return lowerMacroVectorScore(eq, { eq3: eq.eq3 + 1, eq6: eq.eq6 + 1 });
108643
+ }
108644
+ function composeMaxVectors(eq) {
108645
+ const eq3Maxima = MAX_COMPOSED.eq3[eq.eq3]?.[eq.eq6];
108646
+ if (eq3Maxima === undefined) {
108647
+ throw new Error(`No max severity vector for eq3=${eq.eq3}, eq6=${eq.eq6}`);
108554
108648
  }
108555
- if ((metric === "CR" || metric === "IR" || metric === "AR") && (!value || value === "X")) {
108556
- value = "H";
108649
+ const vectors = [];
108650
+ for (const eq1Max of MAX_COMPOSED.eq1[eq.eq1]) {
108651
+ for (const eq2Max of MAX_COMPOSED.eq2[eq.eq2]) {
108652
+ for (const eq3Max of eq3Maxima) {
108653
+ for (const eq4Max of MAX_COMPOSED.eq4[eq.eq4]) {
108654
+ for (const eq5Max of MAX_COMPOSED.eq5[eq.eq5]) {
108655
+ vectors.push(eq1Max + eq2Max + eq3Max + eq4Max + eq5Max);
108656
+ }
108657
+ }
108658
+ }
108659
+ }
108557
108660
  }
108558
- return levels[value] || 0;
108661
+ return vectors;
108559
108662
  }
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;
108663
+ function extractMaxVectorValue(metric, maxVector) {
108664
+ const start = maxVector.indexOf(`${metric}:`);
108665
+ if (start < 0) {
108666
+ throw new Error(`Metric ${metric} missing from max vector ${maxVector}`);
108667
+ }
108668
+ const rest = maxVector.slice(start + metric.length + 1);
108669
+ const end = rest.indexOf("/");
108670
+ return end > 0 ? rest.slice(0, end) : rest;
108565
108671
  }
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;
108672
+ function severityDistances(metrics, maxVector) {
108673
+ const distances = {};
108674
+ for (const [metric, levels] of Object.entries(METRIC_LEVELS)) {
108675
+ const value = getEffectiveValue(metrics, metric);
108676
+ const maxValue = extractMaxVectorValue(metric, maxVector);
108677
+ const level = levels[value];
108678
+ const maxLevel = levels[maxValue];
108679
+ if (level === undefined) {
108680
+ throw new Error(`Unknown value ${metric}:${value}`);
108681
+ }
108682
+ if (maxLevel === undefined) {
108683
+ throw new Error(`Unknown value ${metric}:${maxValue} in ${maxVector}`);
108684
+ }
108685
+ distances[metric] = level - maxLevel;
108686
+ }
108687
+ return distances;
108688
+ }
108689
+ function interpolateScore(metrics, macroVector, macroScore) {
108690
+ const eq = parseMacroVector(macroVector);
108691
+ let distances;
108692
+ for (const maxVector of composeMaxVectors(eq)) {
108693
+ distances = severityDistances(metrics, maxVector);
108694
+ if (Object.values(distances).every((distance) => distance >= 0)) {
108695
+ break;
108696
+ }
108697
+ }
108698
+ if (distances === undefined) {
108699
+ throw new Error(`No max vectors composed for MacroVector ${macroVector}`);
108700
+ }
108701
+ const severityDistance = {
108702
+ eq1: distances.AV + distances.PR + distances.UI,
108703
+ eq2: distances.AC + distances.AT,
108704
+ eq3eq6: distances.VC + distances.VI + distances.VA + distances.CR + distances.IR + distances.AR,
108705
+ eq4: distances.SC + distances.SI + distances.SA
108706
+ };
108707
+ const lowerScore = {
108708
+ eq1: lowerMacroVectorScore(eq, { eq1: eq.eq1 + 1 }),
108709
+ eq2: lowerMacroVectorScore(eq, { eq2: eq.eq2 + 1 }),
108710
+ eq3eq6: lowerEq3Eq6Score(eq),
108711
+ eq4: lowerMacroVectorScore(eq, { eq4: eq.eq4 + 1 })
108712
+ };
108713
+ const macroVectorDepth = {
108714
+ eq1: MAX_SEVERITY.eq1[eq.eq1] * STEP,
108715
+ eq2: MAX_SEVERITY.eq2[eq.eq2] * STEP,
108716
+ eq3eq6: MAX_SEVERITY.eq3eq6[eq.eq3][eq.eq6] * STEP,
108717
+ eq4: MAX_SEVERITY.eq4[eq.eq4] * STEP
108718
+ };
108719
+ let existingLowerCount = 0;
108720
+ let proportionalDistance = 0;
108721
+ for (const key of ["eq1", "eq2", "eq3eq6", "eq4"]) {
108722
+ const lower = lowerScore[key];
108723
+ if (lower === undefined) {
108724
+ continue;
108725
+ }
108726
+ existingLowerCount++;
108727
+ proportionalDistance += (macroScore - lower) * (severityDistance[key] / macroVectorDepth[key]);
108728
+ }
108729
+ if (lowerMacroVectorScore(eq, { eq5: eq.eq5 + 1 }) !== undefined) {
108730
+ existingLowerCount++;
108731
+ }
108732
+ const meanDistance = existingLowerCount === 0 ? 0 : proportionalDistance / existingLowerCount;
108733
+ const score = Math.max(0, Math.min(10, macroScore - meanDistance));
108734
+ return Math.round((score + EPSILON) * 10) / 10;
108642
108735
  }
108643
108736
  function calculateCVSS4Score(metrics) {
108644
108737
  if (hasNoImpact(metrics)) {
@@ -109480,7 +109573,7 @@ init_lazyLogger();
109480
109573
  var log6 = scopedLogger(() => createLogger("FindingJudge"));
109481
109574
  async function judgeFinding(input, ctx) {
109482
109575
  try {
109483
- const { FindingJudgeAgent } = await import("./agent-5ejt5vpz.js");
109576
+ const { FindingJudgeAgent } = await import("./agent-ve8pkr6q.js");
109484
109577
  const agent = new FindingJudgeAgent({
109485
109578
  finding: input,
109486
109579
  model: ctx.model,
@@ -109581,7 +109674,8 @@ var documentVulnerabilityInputSchema = exports_external.object({
109581
109674
  pocName: exports_external.string().describe("Short descriptive name for the POC"),
109582
109675
  pocType: exports_external.enum(["bash", "python", "javascript"]).describe("Script language"),
109583
109676
  pocContent: exports_external.string().describe("The full POC script content"),
109584
- pocDescription: exports_external.string().describe("What this POC demonstrates")
109677
+ pocDescription: exports_external.string().describe("What this POC demonstrates"),
109678
+ 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
109679
  });
109586
109680
  function formatMateriality(input) {
109587
109681
  return [
@@ -109651,11 +109745,24 @@ CRITICAL RULES — READ BEFORE CALLING:
109651
109745
  - POC must exit 0 on success (vulnerability confirmed), non-zero on failure
109652
109746
  - POC must print clear evidence of exploitation to stdout
109653
109747
  - 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
109748
+ - 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
109749
  - If the tool returns a POC failure or judge rejection, revise your approach and call again
109655
109750
  - Do NOT use this for: positive observations, informational notes, testing limitations, or anything that is not an exploitable security vulnerability
109656
109751
  - If you could not exploit a vulnerability, do NOT call this tool — mention it in your final response summary instead`,
109657
109752
  inputSchema: documentVulnerabilityInputSchema,
109658
109753
  execute: async (input) => {
109754
+ try {
109755
+ assertFindingEndpointInScope(input.endpoint, ctx);
109756
+ } catch (error) {
109757
+ if (error instanceof ScopeViolationError) {
109758
+ return {
109759
+ success: false,
109760
+ error: error.message,
109761
+ message: `Finding endpoint rejected — out of scope: ${error.message}`
109762
+ };
109763
+ }
109764
+ throw error;
109765
+ }
109659
109766
  try {
109660
109767
  const materializedEvidence = formatMateriality(input);
109661
109768
  if (ctx.findingsRegistry) {
@@ -109870,7 +109977,8 @@ CRITICAL RULES — READ BEFORE CALLING:
109870
109977
  vulnerabilityClass: input.vulnerabilityClass
109871
109978
  },
109872
109979
  severity,
109873
- ...evidenceFiles.length > 0 && { evidenceFiles }
109980
+ ...evidenceFiles.length > 0 && { evidenceFiles },
109981
+ ...input.attackPath && input.attackPath.length > 0 && { attackPath: input.attackPath }
109874
109982
  };
109875
109983
  if (isVulnerability && ctx.findingsRegistry) {
109876
109984
  const check = await ctx.findingsRegistry.register(finding);
@@ -115366,9 +115474,10 @@ class PersistentShell {
115366
115474
  ${commandOutput}`;
115367
115475
  }
115368
115476
  const effectiveExit = cmd.forcedExitCode != null ? cmd.forcedExitCode : Number.isNaN(naturalExitCode) ? 1 : naturalExitCode;
115369
- const effectiveStderr = cmd.forcedStderrSuffix ? (cmd.stderr || "") + cmd.forcedStderrSuffix : cmd.stderr || "";
115477
+ const diskStderr = readTempfileCapped(cmd.errPath);
115370
115478
  unlinkSafe(cmd.outPath);
115371
115479
  unlinkSafe(cmd.errPath);
115480
+ const effectiveStderr = (diskStderr || cmd.stderr || "") + (cmd.forcedStderrSuffix ?? "");
115372
115481
  const resolve4 = cmd.resolve;
115373
115482
  this.current = null;
115374
115483
  this.pendingCancel = null;
@@ -116106,7 +116215,7 @@ should be passed directly to spawn_pentest_swarm for deep testing.`,
116106
116215
  });
116107
116216
  if (cwd) {
116108
116217
  try {
116109
- const { WhiteboxAttackSurfaceAgent } = await import("./index-rbzhk712.js");
116218
+ const { WhiteboxAttackSurfaceAgent } = await import("./index-gng8ebqf.js");
116110
116219
  const localBus = new AgentEventBus;
116111
116220
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
116112
116221
  const agent = new WhiteboxAttackSurfaceAgent({
@@ -116161,7 +116270,7 @@ should be passed directly to spawn_pentest_swarm for deep testing.`,
116161
116270
  }
116162
116271
  }
116163
116272
  try {
116164
- const { BlackboxAttackSurfaceAgent } = await import("./blackboxAgent-gw0a1ca4.js");
116273
+ const { BlackboxAttackSurfaceAgent } = await import("./blackboxAgent-x0e1wqjx.js");
116165
116274
  const localBus = new AgentEventBus;
116166
116275
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
116167
116276
  const agent = new BlackboxAttackSurfaceAgent({
@@ -116239,7 +116348,7 @@ Omit \`cwd\` for blackbox mode (live target probing only).`,
116239
116348
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
116240
116349
  }),
116241
116350
  execute: async ({ target, cwd }) => {
116242
- const { runPentestWorkflow: workflow } = await import("./pentest-xtc1sjdw.js");
116351
+ const { runPentestWorkflow: workflow } = await import("./pentest-dp9w88pw.js");
116243
116352
  if (!ctx.model) {
116244
116353
  return {
116245
116354
  success: false,
@@ -116299,6 +116408,134 @@ function summarizeFindingsBySeverity(findings) {
116299
116408
  return counts;
116300
116409
  }
116301
116410
 
116411
+ // src/core/agents/offSecAgent/tools/smsListMessages.ts
116412
+ init_dist();
116413
+ init_zod();
116414
+ var SMS_LIST_MESSAGES_TOOL_NAME = "sms_list_messages";
116415
+ var SMS_TOOL_NAMES = [SMS_LIST_MESSAGES_TOOL_NAME];
116416
+ function phoneFromAuthCredentials(session) {
116417
+ const creds = session.config?.authCredentials;
116418
+ const list2 = creds ? Array.isArray(creds) ? creds : [creds] : [];
116419
+ for (const cred of list2) {
116420
+ const phone = cred.additionalFields?.phoneNumber;
116421
+ if (phone)
116422
+ return phone;
116423
+ }
116424
+ }
116425
+ function sessionHasSmsPasswordless(session) {
116426
+ const refs = session.credentialManager?.listReferences() ?? [];
116427
+ if (refs.some((ref) => ref.additionalFieldKeys?.includes("phoneNumber"))) {
116428
+ return true;
116429
+ }
116430
+ return Boolean(phoneFromAuthCredentials(session));
116431
+ }
116432
+ function requireAgentApi() {
116433
+ const base = process.env.AGENT_API_URL;
116434
+ const token = process.env.AGENT_API_TOKEN;
116435
+ if (!base || !token) {
116436
+ 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.");
116437
+ }
116438
+ return { base: base.replace(/\/+$/, ""), token };
116439
+ }
116440
+ function resolvePhoneNumber(ctx, input) {
116441
+ if (input.phoneNumber)
116442
+ return input.phoneNumber;
116443
+ const cm = ctx.credentialManager ?? ctx.session.credentialManager;
116444
+ if (input.credentialId) {
116445
+ const stored = cm?.resolve(input.credentialId);
116446
+ const phone = stored?.additionalFields?.phoneNumber;
116447
+ if (!phone) {
116448
+ throw new Error(`Credential ${input.credentialId} has no phoneNumber additional field`);
116449
+ }
116450
+ return phone;
116451
+ }
116452
+ const refs = cm?.listReferences() ?? [];
116453
+ const smsRef = refs.find((ref) => ref.additionalFieldKeys?.includes("phoneNumber"));
116454
+ if (smsRef) {
116455
+ const stored = cm?.resolve(smsRef.id);
116456
+ const phone = stored?.additionalFields?.phoneNumber;
116457
+ if (phone)
116458
+ return phone;
116459
+ }
116460
+ const fromAuth = phoneFromAuthCredentials(ctx.session);
116461
+ if (fromAuth)
116462
+ return fromAuth;
116463
+ throw new Error("No sms-passwordless credential with a phoneNumber field is available");
116464
+ }
116465
+ async function agentFetch(path, init) {
116466
+ const { token, ...rest } = init;
116467
+ return fetch(path, {
116468
+ ...rest,
116469
+ headers: {
116470
+ Authorization: `Bearer ${token}`,
116471
+ ...rest.headers ?? {}
116472
+ }
116473
+ });
116474
+ }
116475
+ function smsListMessages(ctx) {
116476
+ return tool({
116477
+ description: `List inbound SMS on a Mobile OTP (sms-passwordless) receiving number.
116478
+
116479
+ This is a single read — it does not wait. After the target sends a code, sleep with execute_command (e.g. sleep 5) then call this tool. If the list is empty, sleep and list again, or stop and report what you observed. Do not hang in a wait loop.
116480
+
116481
+ Pass sinceMs as Date.now() from the send-code click so earlier messages are ignored. Set claim=true to consume the newest unconsumed message (exclusive; other runs cannot reuse that OTP). Fill the OTP with browser_fill from the returned code/body — do not report phone_verification as a barrier for this flow.
116482
+
116483
+ Requires a Console sandbox (AGENT_API_URL). Concurrent lists on the same shared number are exclusive; a 429 means another run holds the number.`,
116484
+ inputSchema: exports_external.object({
116485
+ credentialId: exports_external.string().optional().describe("Credential ID whose additionalFields.phoneNumber is the receiving number. Omit to use the session's sms-passwordless credential."),
116486
+ phoneNumber: exports_external.string().optional().describe("Explicit E.164 receiving number. Prefer credentialId so the number is resolved from the stored credential."),
116487
+ sinceMs: exports_external.number().describe("Epoch milliseconds of the send-code click. Messages received before this timestamp are ignored."),
116488
+ claim: exports_external.boolean().optional().describe("If true, consume the newest unconsumed message so other runs cannot reuse the OTP. Defaults to false (list only)."),
116489
+ toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
116490
+ }),
116491
+ execute: async ({ credentialId, phoneNumber, sinceMs, claim }) => {
116492
+ const { base, token } = requireAgentApi();
116493
+ const toPhoneNumber = resolvePhoneNumber(ctx, {
116494
+ credentialId,
116495
+ phoneNumber
116496
+ });
116497
+ const since = new Date(sinceMs).toISOString();
116498
+ const url = new URL(`${base}/agent/sms/messages`);
116499
+ url.searchParams.set("toPhoneNumber", toPhoneNumber);
116500
+ url.searchParams.set("since", since);
116501
+ if (claim)
116502
+ url.searchParams.set("claim", "1");
116503
+ const res = await agentFetch(url.toString(), {
116504
+ method: "GET",
116505
+ token,
116506
+ signal: ctx.abortSignal
116507
+ });
116508
+ if (res.status === 429) {
116509
+ return {
116510
+ success: false,
116511
+ error: "Another agent run holds the exclusive lease on this phone number. Wait and retry, or use a different Mobile OTP number."
116512
+ };
116513
+ }
116514
+ if (res.status === 403) {
116515
+ return {
116516
+ success: false,
116517
+ error: "This phone number is not configured as a Mobile OTP credential in this workspace."
116518
+ };
116519
+ }
116520
+ if (res.status === 409) {
116521
+ return {
116522
+ success: false,
116523
+ error: "That SMS was already claimed. List without claim, or wait for a newer message."
116524
+ };
116525
+ }
116526
+ if (!res.ok) {
116527
+ throw new Error(`SMS list API error ${res.status} ${res.statusText}`);
116528
+ }
116529
+ const data = await res.json();
116530
+ return {
116531
+ success: true,
116532
+ messages: data.messages,
116533
+ claimed: data.claimed
116534
+ };
116535
+ }
116536
+ });
116537
+ }
116538
+
116302
116539
  // src/core/utils/concurrency.ts
116303
116540
  var import_api = __toESM(require_src(), 1);
116304
116541
  async function runWithBoundedConcurrency(items, concurrency, fn, abortSignal) {
@@ -117817,7 +118054,7 @@ Returns an array of results with the text output from each agent.`,
117817
118054
  });
117818
118055
  }
117819
118056
  async function runSingleCodingAgent(ctx, codebasePath, objective, agentIndex, name) {
117820
- const { CodeAgent } = await import("./agent-mvpgvgks.js");
118057
+ const { CodeAgent } = await import("./agent-48xj79bj.js");
117821
118058
  const childSessionId = newSessionId();
117822
118059
  const subagentId = childSessionId;
117823
118060
  ctx.eventBus?.emit("subagent-spawn", {
@@ -118298,13 +118535,17 @@ init_dist();
118298
118535
  init_zod();
118299
118536
  init_id();
118300
118537
  var WORKER_DRAIN_GRACE_MS = 30000;
118538
+ 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
118539
  function spawnPentestAgent(ctx) {
118540
+ 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
118541
  return tool({
118303
118542
  description: `Spawn a single focused pentest sub-agent (worker) to test ONE objective at a time.
118304
118543
 
118305
118544
  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
118545
 
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.
118546
+ 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.
118547
+
118548
+ 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
118549
 
118309
118550
  Each spawn produces an independent TargetedPentestAgent that:
118310
118551
  1. Tests the assigned objective(s) deeply (execute_command, http_request, browser tools)
@@ -118322,7 +118563,7 @@ False-positive discipline: workers should not call document_vulnerability for pu
118322
118563
  Returns the worker's summary, objective results, and finding count — but NOT the findings themselves (those land in the shared registry).`,
118323
118564
  inputSchema: exports_external.object({
118324
118565
  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."),
118566
+ 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
118567
  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
118568
  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
118569
  toolCallDescription: exports_external.string().describe("Concise, human-readable description of what this spawn is doing (shown in the UI).")
@@ -118334,7 +118575,21 @@ Returns the worker's summary, objective results, and finding count — but NOT t
118334
118575
  message: "spawn_pentest_agent requires a model in the tool context."
118335
118576
  };
118336
118577
  }
118337
- const { TargetedPentestAgent } = await import("./agent-nhs1w5w0.js");
118578
+ if (typeof target !== "string" || parseTargetUrl(target) === null) {
118579
+ return {
118580
+ success: false,
118581
+ 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.`
118582
+ };
118583
+ }
118584
+ try {
118585
+ assertUrlInScope(target, ctx);
118586
+ } catch (error) {
118587
+ if (error instanceof ScopeViolationError) {
118588
+ return { success: false, message: error.message };
118589
+ }
118590
+ throw error;
118591
+ }
118592
+ const { TargetedPentestAgent } = await import("./agent-7q3c9cjt.js");
118338
118593
  const findingsRegistry = ctx.findingsRegistry ?? FindingsRegistry.fromDirectory(ctx.session.findingsPath, {
118339
118594
  model: ctx.model,
118340
118595
  authConfig: ctx.authConfig,
@@ -118365,12 +118620,15 @@ Returns the worker's summary, objective results, and finding count — but NOT t
118365
118620
  agent = new TargetedPentestAgent({
118366
118621
  target,
118367
118622
  grpc: workerInheritsGrpc(target, ctx.grpc, ctx.target) ? ctx.grpc : undefined,
118623
+ systemScope: ctx.systemScope,
118368
118624
  objectives,
118369
118625
  context: enrichedContext,
118370
118626
  model: ctx.model,
118371
118627
  session: ctx.session,
118372
118628
  authConfig: ctx.authConfig,
118373
118629
  abortSignal: ctx.abortSignal,
118630
+ onStepFinish: ctx.onStepFinish,
118631
+ onCacheMetrics: ctx.onCacheMetrics,
118374
118632
  findingsRegistry,
118375
118633
  eventBus: childBus,
118376
118634
  subagentId,
@@ -118429,7 +118687,7 @@ function workerInheritsGrpc(target, grpc, orchestratorTarget) {
118429
118687
  function buildSharedBrowserSessionContext(existingContext) {
118430
118688
  const note = `## Shared Browser Session
118431
118689
  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.
118690
+ - You inherit authentication only for origins where the orchestrator established it. Verify protected access on your assigned origin first. ${ORIGIN_AUTH_FAILURE_GUIDANCE}
118433
118691
  - 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
118692
  - 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
118693
  if (!existingContext || existingContext.trim().length === 0) {
@@ -118468,7 +118726,7 @@ Pass every target you want tested — the swarm handles concurrency automaticall
118468
118726
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
118469
118727
  }),
118470
118728
  execute: async ({ targets }) => {
118471
- const { runPentestSwarm, DEFAULT_CONCURRENCY: DEFAULT_CONCURRENCY2 } = await import("./pentest-xtc1sjdw.js");
118729
+ const { runPentestSwarm, DEFAULT_CONCURRENCY: DEFAULT_CONCURRENCY2 } = await import("./pentest-dp9w88pw.js");
118472
118730
  if (!ctx.model) {
118473
118731
  return {
118474
118732
  success: false,
@@ -118490,6 +118748,8 @@ Pass every target you want tested — the swarm handles concurrency automaticall
118490
118748
  abortSignal: ctx.abortSignal,
118491
118749
  findingsRegistry,
118492
118750
  eventBus: ctx.eventBus,
118751
+ onStepFinish: ctx.onStepFinish,
118752
+ onCacheMetrics: ctx.onCacheMetrics,
118493
118753
  concurrency: DEFAULT_CONCURRENCY2,
118494
118754
  enableThinking: ctx.enableThinking,
118495
118755
  thinkingEffort: ctx.thinkingEffort,
@@ -119104,6 +119364,29 @@ async function handleSearchResponse(response) {
119104
119364
  // src/core/api/apiClient.ts
119105
119365
  init_auth();
119106
119366
  init_config();
119367
+
119368
+ // src/core/api/clientIdentity.ts
119369
+ init_installation();
119370
+ var CLIENT_HEADERS = {
119371
+ client: "X-Pensar-Client",
119372
+ version: "X-Pensar-Client-Version",
119373
+ command: "X-Pensar-Command"
119374
+ };
119375
+ var CLIENT_NAME = "cli";
119376
+ var currentCommand;
119377
+ function getCurrentCommand() {
119378
+ return currentCommand;
119379
+ }
119380
+ function clientIdentityHeaders() {
119381
+ const command = getCurrentCommand();
119382
+ return {
119383
+ [CLIENT_HEADERS.client]: CLIENT_NAME,
119384
+ [CLIENT_HEADERS.version]: getCurrentVersion(),
119385
+ ...command ? { [CLIENT_HEADERS.command]: command } : {}
119386
+ };
119387
+ }
119388
+
119389
+ // src/core/api/apiClient.ts
119107
119390
  init_constants();
119108
119391
  async function getAuthHeaders() {
119109
119392
  const cfg = await config.get();
@@ -119117,7 +119400,8 @@ async function getAuthHeaders() {
119117
119400
  }
119118
119401
  const headers = {
119119
119402
  "Content-Type": "application/json",
119120
- Authorization: `Bearer ${validToken.token}`
119403
+ Authorization: `Bearer ${validToken.token}`,
119404
+ ...clientIdentityHeaders()
119121
119405
  };
119122
119406
  if (cfg.workspaceId) {
119123
119407
  headers["X-Workspace-Id"] = cfg.workspaceId;
@@ -119151,6 +119435,12 @@ async function apiRequest(method, path, body) {
119151
119435
  }
119152
119436
 
119153
119437
  // src/core/api/apps.ts
119438
+ var ENDPOINT_TRANSPORTS = [
119439
+ "http",
119440
+ "grpc",
119441
+ "grpc_web",
119442
+ "connect"
119443
+ ];
119154
119444
  async function listApps(opts) {
119155
119445
  const params = new URLSearchParams;
119156
119446
  if (opts?.limit !== undefined)
@@ -119263,7 +119553,7 @@ var ENDPOINT_TYPES = [
119263
119553
  "file-storage",
119264
119554
  "asset"
119265
119555
  ];
119266
- var ENDPOINT_TRANSPORTS = [
119556
+ var ENDPOINT_TRANSPORTS2 = [
119267
119557
  "http",
119268
119558
  "grpc",
119269
119559
  "grpc_web",
@@ -119309,7 +119599,7 @@ var createWorkspaceEndpointInputSchema = exports_external.object({
119309
119599
  endpoint: exports_external.string().min(1).describe("Endpoint path, URL, or route"),
119310
119600
  description: exports_external.string().describe("Endpoint description"),
119311
119601
  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"),
119602
+ transport: exports_external.enum(ENDPOINT_TRANSPORTS2).nullish().transform((value) => value ?? undefined).optional().describe("Wire transport; defaults to http when omitted"),
119313
119603
  location: exports_external.string().optional().describe("Source file path"),
119314
119604
  startLineNumber: exports_external.number().int().min(0).optional(),
119315
119605
  endLineNumber: exports_external.number().int().min(0).optional(),
@@ -119328,7 +119618,7 @@ var updateWorkspaceEndpointInputSchema = exports_external.object({
119328
119618
  endpoint: exports_external.string().min(1).nullish().transform((value) => value ?? undefined).optional(),
119329
119619
  description: exports_external.string().nullish().transform((value) => value ?? undefined).optional(),
119330
119620
  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"),
119621
+ transport: exports_external.enum(ENDPOINT_TRANSPORTS2).nullish().transform((value) => value ?? undefined).optional().describe("Corrected wire transport"),
119332
119622
  location: exports_external.string().nullable().optional(),
119333
119623
  startLineNumber: exports_external.number().int().min(0).nullable().optional(),
119334
119624
  endLineNumber: exports_external.number().int().min(0).nullable().optional(),
@@ -119456,10 +119746,6 @@ Use only when the user explicitly asks to change or repair an existing workspace
119456
119746
  });
119457
119747
  }
119458
119748
 
119459
- // src/core/agents/offSecAgent/tools/workspaceDomains.ts
119460
- init_dist();
119461
- init_zod();
119462
-
119463
119749
  // src/core/api/domains.ts
119464
119750
  async function listDomains() {
119465
119751
  return apiRequest("GET", "/domains");
@@ -119469,6 +119755,8 @@ async function createDomain(data) {
119469
119755
  }
119470
119756
 
119471
119757
  // src/core/agents/offSecAgent/tools/workspaceDomains.ts
119758
+ init_dist();
119759
+ init_zod();
119472
119760
  var toolCallDescription2 = exports_external.string().describe("A concise description of the workspace operation");
119473
119761
  var listWorkspaceDomainsInputSchema = exports_external.object({
119474
119762
  toolCallDescription: toolCallDescription2
@@ -124352,6 +124640,7 @@ function createAllTools(ctx) {
124352
124640
  email_list_messages: emailListMessages(ctx),
124353
124641
  email_search_messages: emailSearchMessages(ctx),
124354
124642
  email_get_message: emailGetMessage(ctx),
124643
+ sms_list_messages: smsListMessages(ctx),
124355
124644
  web_search: webSearch(ctx),
124356
124645
  get_page: getPage(ctx),
124357
124646
  ...ctx.skillsRegistry ? { read_skill: readSkill(ctx) } : {},
@@ -124439,6 +124728,7 @@ var ALL_TOOL_NAMES = [
124439
124728
  "email_get_attachments",
124440
124729
  "email_mark_read",
124441
124730
  "send_email",
124731
+ "sms_list_messages",
124442
124732
  "web_search",
124443
124733
  "get_page",
124444
124734
  "checkpoint_state",
@@ -124510,6 +124800,7 @@ var PLAN_MODE_TOOL_NAMES = [
124510
124800
  "email_get_message",
124511
124801
  "email_search_messages",
124512
124802
  "email_get_attachments",
124803
+ "sms_list_messages",
124513
124804
  "web_search",
124514
124805
  "get_page",
124515
124806
  "write_plan",
@@ -124521,6 +124812,7 @@ var PLAN_MODE_TOOL_NAMES = [
124521
124812
  var SKILL_TOOL_NAMES = ["read_skill"];
124522
124813
 
124523
124814
  // src/core/agents/offSecAgent/trace.ts
124815
+ init_observability();
124524
124816
  import { createHash as createHash2 } from "node:crypto";
124525
124817
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync13 } from "node:fs";
124526
124818
  import { dirname as dirname8 } from "node:path";
@@ -124707,13 +124999,15 @@ class StepTraceWriter {
124707
124999
  this.appendRecord(record3);
124708
125000
  }
124709
125001
  appendRecord(record3) {
125002
+ const correlation = getActiveTraceCorrelation();
125003
+ const enriched = correlation ? { ...record3, correlation } : record3;
124710
125004
  try {
124711
- appendFileSync3(this.tracePath, `${JSON.stringify(record3)}
125005
+ appendFileSync3(this.tracePath, `${JSON.stringify(enriched)}
124712
125006
  `);
124713
125007
  } catch {}
124714
125008
  try {
124715
125009
  this.eventBus?.emit("trace-record", {
124716
- record: record3,
125010
+ record: enriched,
124717
125011
  subagentId: this.agentId ?? undefined
124718
125012
  });
124719
125013
  } catch {}
@@ -124723,8 +125017,8 @@ class StepTraceWriter {
124723
125017
  // src/core/agents/offSecAgent/offensiveSecurityAgent.ts
124724
125018
  init_dist();
124725
125019
  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";
125020
+ var import_api2 = __toESM(require_src(), 1);
125021
+ import { existsSync as existsSync19, mkdirSync as mkdirSync14 } from "node:fs";
124728
125022
  import { join as join27 } from "node:path";
124729
125023
  init_id();
124730
125024
  init_structured();
@@ -125006,9 +125300,464 @@ var OperatorSettingsObject = exports_external.object({
125006
125300
  // src/core/agents/offSecAgent/offensiveSecurityAgent.ts
125007
125301
  init_session();
125008
125302
  init_lazyLogger();
125009
- var log13 = scopedLogger(() => createLogger("approval-gate"));
125303
+
125304
+ // src/core/agents/offSecAgent/interruptedStepFinalization.ts
125305
+ import { existsSync as existsSync18, readFileSync as readFileSync8 } from "node:fs";
125306
+
125307
+ // src/core/agents/offSecAgent/interruptedStepMessages.ts
125308
+ function buildSyntheticToolResults(input) {
125309
+ const output = {
125310
+ type: "error-text",
125311
+ value: `Tool execution aborted: ${input.reason}`
125312
+ };
125313
+ const parts = [];
125314
+ for (const [toolCallId, toolName] of input.inFlightTools) {
125315
+ const result = toolName === input.responseToolName && input.responseSubmitted ? { type: "text", value: "Response submitted." } : output;
125316
+ parts.push({
125317
+ type: "tool-result",
125318
+ toolCallId,
125319
+ toolName,
125320
+ output: result
125321
+ });
125322
+ }
125323
+ return parts;
125324
+ }
125325
+ function baseContainsToolCalls(msg, toolCallIds) {
125326
+ if (!Array.isArray(msg.content))
125327
+ return false;
125328
+ const contentToolIds = new Set(msg.content.filter((p) => p.type === "tool-call" && p.toolCallId).map((p) => p.toolCallId));
125329
+ return [...toolCallIds].every((id) => contentToolIds.has(id));
125330
+ }
125331
+ function buildInterruptedStepMessages(input) {
125332
+ const { base, inFlightTools, completedResults, syntheticParts } = input;
125333
+ const allToolCallIds = new Set([
125334
+ ...inFlightTools.keys(),
125335
+ ...completedResults.map((r) => r.toolCallId)
125336
+ ]);
125337
+ const lastMsg = base[base.length - 1];
125338
+ const needsStepReconstruction = !lastMsg || lastMsg.role !== "assistant" || !baseContainsToolCalls(lastMsg, allToolCallIds);
125339
+ const appended = [];
125340
+ if (needsStepReconstruction) {
125341
+ const stepTools = [
125342
+ ...inFlightTools,
125343
+ ...completedResults.map((r) => [
125344
+ r.toolCallId,
125345
+ r.toolName
125346
+ ])
125347
+ ];
125348
+ const reconstructInput = (toolCallId) => {
125349
+ const raw = input.streamedArgText?.get(toolCallId);
125350
+ if (!raw)
125351
+ return {};
125352
+ try {
125353
+ return JSON.parse(raw);
125354
+ } catch {
125355
+ return { _partial: raw };
125356
+ }
125357
+ };
125358
+ appended.push({
125359
+ role: "assistant",
125360
+ content: stepTools.map(([toolCallId, toolName]) => ({
125361
+ type: "tool-call",
125362
+ toolCallId,
125363
+ toolName,
125364
+ input: reconstructInput(toolCallId)
125365
+ }))
125366
+ });
125367
+ }
125368
+ appended.push({
125369
+ role: "tool",
125370
+ content: [...completedResults, ...syntheticParts]
125371
+ });
125372
+ return { appended, needsStepReconstruction };
125373
+ }
125374
+
125375
+ // src/core/agents/offSecAgent/interruptedStepFinalization.ts
125376
+ function createInterruptedStepFinalizer(deps) {
125377
+ const debug = deps.debugLog;
125378
+ const readBaseFromDisk = deps.readBaseFromDisk ?? (() => {
125379
+ const path = deps.writer.messagesPath;
125380
+ if (!path || !existsSync18(path))
125381
+ return null;
125382
+ try {
125383
+ return JSON.parse(readFileSync8(path, "utf-8"));
125384
+ } catch {
125385
+ return null;
125386
+ }
125387
+ });
125388
+ return async (input) => {
125389
+ const { snapshot, reason } = input;
125390
+ const { inFlightTools, completedResults, streamedArgText } = snapshot;
125391
+ const syntheticParts = buildSyntheticToolResults({
125392
+ inFlightTools,
125393
+ reason,
125394
+ responseToolName: deps.responseToolName,
125395
+ responseSubmitted: deps.responseToolFired()
125396
+ });
125397
+ let emissionError;
125398
+ let hasEmissionError = false;
125399
+ if (debug) {
125400
+ const responseInFlight = [...inFlightTools.entries()].filter(([, n7]) => n7 === deps.responseToolName);
125401
+ if (responseInFlight.length > 0) {
125402
+ debug(`[response-debug] emitSyntheticToolResults closing ${responseInFlight.length} response call(s) ` + `ids=${responseInFlight.map(([id]) => id).join(",")} reason="${reason}" ` + `responseToolFired=${deps.responseToolFired()}`);
125403
+ }
125404
+ }
125405
+ for (const part of syntheticParts) {
125406
+ try {
125407
+ deps.eventBus.emit("tool-result", {
125408
+ toolCallId: part.toolCallId,
125409
+ toolName: part.toolName,
125410
+ result: part.output,
125411
+ sessionId: deps.sessionId,
125412
+ subagentId: deps.subagentId,
125413
+ partId: input.partIdFor?.(part.toolCallId),
125414
+ messageId: input.messageId
125415
+ });
125416
+ } catch (error) {
125417
+ if (!hasEmissionError) {
125418
+ emissionError = error;
125419
+ hasEmissionError = true;
125420
+ }
125421
+ }
125422
+ }
125423
+ if (!deps.writer.messagesPath) {
125424
+ if (hasEmissionError)
125425
+ throw emissionError;
125426
+ return;
125427
+ }
125428
+ deps.writer.cancelTimer();
125429
+ await deps.writer.waitForPendingWrites();
125430
+ let base = deps.writer.latest ?? [];
125431
+ if (base.length === 0) {
125432
+ base = readBaseFromDisk() ?? [];
125433
+ }
125434
+ const { appended, needsStepReconstruction } = buildInterruptedStepMessages({
125435
+ base,
125436
+ inFlightTools,
125437
+ completedResults,
125438
+ syntheticParts,
125439
+ streamedArgText
125440
+ });
125441
+ if (needsStepReconstruction && debug) {
125442
+ const responseReconstructed = [
125443
+ ...inFlightTools,
125444
+ ...completedResults.map((r) => [r.toolCallId, r.toolName])
125445
+ ].filter(([, n7]) => n7 === deps.responseToolName).map(([id]) => id);
125446
+ if (responseReconstructed.length > 0) {
125447
+ debug(`[response-debug] step-reconstruction for response call(s) ` + `ids=${responseReconstructed.join(",")} ` + `preservedArgChars=${responseReconstructed.map((id) => streamedArgText?.get(id)?.length ?? 0).join(",")}`);
125448
+ }
125449
+ }
125450
+ const next = [...base, ...appended];
125451
+ deps.writer.setLatest(next);
125452
+ try {
125453
+ await deps.writer.enqueueWrite(next);
125454
+ deps.writer.markSyntheticsPersisted();
125455
+ } catch {}
125456
+ if (hasEmissionError)
125457
+ throw emissionError;
125458
+ };
125459
+ }
125460
+
125461
+ // src/core/agents/offSecAgent/messagePersistence.ts
125462
+ import { writeFile as writeFile7 } from "node:fs/promises";
125463
+ var PERSIST_INTERVAL_MS = 15000;
125464
+
125465
+ class AgentMessageWriter {
125466
+ intervalMs;
125467
+ writeImpl;
125468
+ path;
125469
+ pending = null;
125470
+ tail = Promise.resolve();
125471
+ persistTimer = null;
125472
+ syntheticsWritten = false;
125473
+ constructor(options) {
125474
+ this.path = options.messagesPath;
125475
+ this.intervalMs = options.intervalMs ?? PERSIST_INTERVAL_MS;
125476
+ this.writeImpl = options.writeImpl ?? ((p, contents) => writeFile7(p, contents));
125477
+ }
125478
+ get messagesPath() {
125479
+ return this.path;
125480
+ }
125481
+ get latest() {
125482
+ return this.pending;
125483
+ }
125484
+ setLatest(messages) {
125485
+ this.pending = messages;
125486
+ }
125487
+ get syntheticsPersisted() {
125488
+ return this.syntheticsWritten;
125489
+ }
125490
+ markSyntheticsPersisted() {
125491
+ this.syntheticsWritten = true;
125492
+ }
125493
+ schedulePersist() {
125494
+ if (this.persistTimer)
125495
+ return;
125496
+ this.persistTimer = setTimeout(() => {
125497
+ this.persistTimer = null;
125498
+ const toWrite = this.pending;
125499
+ if (!toWrite)
125500
+ return;
125501
+ this.enqueueWrite(toWrite).then(() => {
125502
+ if (this.pending === toWrite)
125503
+ this.pending = null;
125504
+ }).catch(() => {});
125505
+ }, this.intervalMs);
125506
+ }
125507
+ cancelTimer() {
125508
+ if (this.persistTimer) {
125509
+ clearTimeout(this.persistTimer);
125510
+ this.persistTimer = null;
125511
+ }
125512
+ }
125513
+ async enqueueWrite(messages) {
125514
+ const path = this.path;
125515
+ if (!path)
125516
+ return;
125517
+ const contents = JSON.stringify(messages);
125518
+ const write2 = this.tail.then(() => this.writeImpl(path, contents));
125519
+ this.tail = write2.catch(() => {});
125520
+ await write2;
125521
+ }
125522
+ async waitForPendingWrites() {
125523
+ let pending;
125524
+ do {
125525
+ pending = this.tail;
125526
+ await pending;
125527
+ } while (pending !== this.tail);
125528
+ }
125529
+ }
125530
+
125531
+ // src/core/agents/offSecAgent/streamDiagnostics.ts
125532
+ init_structured();
125533
+ init_lazyLogger();
125534
+ var STREAM_STALL_DEBUG = process.env.STREAM_STALL_DEBUG === "1" || process.env.STREAM_STALL_DEBUG === "true";
125535
+ var STREAM_STALL_TICK_MS = 15000;
125536
+ var STREAM_STALL_WARN_MS = 20000;
125537
+ var STREAM_GAP_RECOVERED_MS = 1e4;
125010
125538
  var RESPONSE_DEBUG = process.env.RESPONSE_DEBUG === "1" || process.env.RESPONSE_DEBUG === "true";
125011
125539
  var rlog = scopedLogger(() => createLogger("response-debug"));
125540
+ function responseArgBytes(input) {
125541
+ if (input == null)
125542
+ return 0;
125543
+ if (typeof input === "string")
125544
+ return input.length;
125545
+ try {
125546
+ return JSON.stringify(input).length;
125547
+ } catch {
125548
+ return -1;
125549
+ }
125550
+ }
125551
+
125552
+ class StreamDiagnostics {
125553
+ opts;
125554
+ stallEnabled;
125555
+ responseDebugEnabled;
125556
+ warn;
125557
+ responseArgChars = new Map;
125558
+ responseSawTerminal = new Map;
125559
+ lastChunkAt = Date.now();
125560
+ lastChunkType = "none";
125561
+ stallStepIndex = -1;
125562
+ stallTimer;
125563
+ constructor(options) {
125564
+ this.opts = options;
125565
+ this.stallEnabled = options.stallEnabled ?? STREAM_STALL_DEBUG;
125566
+ this.responseDebugEnabled = options.responseDebugEnabled ?? RESPONSE_DEBUG;
125567
+ this.warn = options.warn ?? ((message) => rlog.warn(message));
125568
+ }
125569
+ start() {
125570
+ if (!this.stallEnabled || this.stallTimer)
125571
+ return;
125572
+ const label = this.opts.sessionId;
125573
+ const sid = this.opts.subagentId;
125574
+ this.stallTimer = setInterval(() => {
125575
+ const gap = Date.now() - this.lastChunkAt;
125576
+ if (gap > STREAM_STALL_WARN_MS) {
125577
+ 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()}`);
125578
+ }
125579
+ }, STREAM_STALL_TICK_MS);
125580
+ }
125581
+ observeChunk(chunk) {
125582
+ if (this.stallEnabled) {
125583
+ const now = Date.now();
125584
+ const gap = now - this.lastChunkAt;
125585
+ this.lastChunkAt = now;
125586
+ this.lastChunkType = chunk.type;
125587
+ if (chunk.type === "start-step")
125588
+ this.stallStepIndex++;
125589
+ if (gap > STREAM_GAP_RECOVERED_MS) {
125590
+ this.warn(`[stream-gap] recovered after ${Math.round(gap / 1000)}s ` + `session=${this.opts.sessionId} chunkType=${chunk.type}`);
125591
+ }
125592
+ }
125593
+ if (this.responseDebugEnabled) {
125594
+ this.traceResponseTool(chunk);
125595
+ }
125596
+ }
125597
+ logSurfacedToolError(info) {
125598
+ if (!this.responseDebugEnabled)
125599
+ return;
125600
+ if (info.toolName !== this.opts.responseToolName)
125601
+ return;
125602
+ 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)}`);
125603
+ }
125604
+ logClosingInFlightTool(info) {
125605
+ if (!this.responseDebugEnabled)
125606
+ return;
125607
+ if (info.toolName !== this.opts.responseToolName)
125608
+ return;
125609
+ 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()}`);
125610
+ }
125611
+ stop() {
125612
+ if (this.stallTimer)
125613
+ clearInterval(this.stallTimer);
125614
+ this.stallTimer = undefined;
125615
+ }
125616
+ traceResponseTool(chunk) {
125617
+ const idForChunk = chunk.toolCallId ?? chunk.id;
125618
+ const nameForChunk = chunk.toolName ?? (idForChunk ? this.opts.inFlightTools().get(idForChunk) : undefined);
125619
+ if (nameForChunk !== this.opts.responseToolName || !idForChunk) {
125620
+ if (chunk.type === "finish-step") {
125621
+ const responseInFlight = [...this.opts.inFlightTools().entries()].filter(([, n7]) => n7 === this.opts.responseToolName).map(([id]) => id).join(",");
125622
+ if (responseInFlight) {
125623
+ this.warn(`[response-debug] finish-step finishReason=${chunk.finishReason} ` + `responseInFlight=${responseInFlight} ` + `responseToolFired=${this.opts.responseToolFired()}`);
125624
+ }
125625
+ }
125626
+ return;
125627
+ }
125628
+ switch (chunk.type) {
125629
+ case "tool-input-start":
125630
+ this.responseArgChars.set(idForChunk, 0);
125631
+ this.warn(`[response-debug] tool-input-start id=${idForChunk} session=${this.opts.subagentId ?? this.opts.sessionId}`);
125632
+ break;
125633
+ case "tool-input-delta":
125634
+ this.responseArgChars.set(idForChunk, (this.responseArgChars.get(idForChunk) ?? 0) + (chunk.delta?.length ?? 0));
125635
+ break;
125636
+ case "tool-input-end":
125637
+ this.warn(`[response-debug] tool-input-end id=${idForChunk} argChars=${this.responseArgChars.get(idForChunk) ?? 0}`);
125638
+ break;
125639
+ case "tool-call": {
125640
+ this.responseSawTerminal.set(idForChunk, "tool-call");
125641
+ const inputBytes = responseArgBytes(chunk.input ?? chunk.args);
125642
+ this.warn(`[response-debug] tool-call id=${idForChunk} streamedArgChars=${this.responseArgChars.get(idForChunk) ?? 0} parsedInputBytes=${inputBytes} invalid=${chunk.invalid === true}`);
125643
+ break;
125644
+ }
125645
+ case "tool-error": {
125646
+ this.responseSawTerminal.set(idForChunk, "tool-error");
125647
+ const errMsg = chunk.error instanceof Error ? chunk.error.message : typeof chunk.error === "string" ? chunk.error : JSON.stringify(chunk.error)?.slice(0, 300);
125648
+ this.warn(`[response-debug] tool-error id=${idForChunk} streamedArgChars=${this.responseArgChars.get(idForChunk) ?? 0} stillInFlight=${this.opts.inFlightTools().has(idForChunk)} error=${errMsg}`);
125649
+ break;
125650
+ }
125651
+ case "tool-result":
125652
+ this.responseSawTerminal.set(idForChunk, "tool-result");
125653
+ this.warn(`[response-debug] tool-result id=${idForChunk} streamedArgChars=${this.responseArgChars.get(idForChunk) ?? 0}`);
125654
+ break;
125655
+ }
125656
+ }
125657
+ }
125658
+
125659
+ // src/core/agents/offSecAgent/toolLifecycle.ts
125660
+ class ToolLifecycleTracker {
125661
+ inFlight = new Map;
125662
+ completed = [];
125663
+ streamedArgs = new Map;
125664
+ errors = new Map;
125665
+ observePart(chunk) {
125666
+ switch (chunk.type) {
125667
+ case "tool-input-start":
125668
+ this.inFlight.set(chunk.id, chunk.toolName);
125669
+ this.streamedArgs.set(chunk.id, "");
125670
+ break;
125671
+ case "tool-input-delta":
125672
+ this.streamedArgs.set(chunk.id, (this.streamedArgs.get(chunk.id) ?? "") + (chunk.delta ?? ""));
125673
+ break;
125674
+ case "tool-call":
125675
+ this.inFlight.set(chunk.toolCallId, chunk.toolName);
125676
+ break;
125677
+ case "tool-error": {
125678
+ const toolCallId = chunk.toolCallId;
125679
+ this.inFlight.delete(toolCallId);
125680
+ const errMsg = chunk.error instanceof Error ? chunk.error.message : typeof chunk.error === "string" ? chunk.error : (() => {
125681
+ try {
125682
+ return JSON.stringify(chunk.error);
125683
+ } catch {
125684
+ return String(chunk.error);
125685
+ }
125686
+ })();
125687
+ const partialArgs = chunk.input !== undefined && chunk.input !== null && responseArgBytes(chunk.input) > 2 ? chunk.input : this.streamedArgs.get(toolCallId) ?? "";
125688
+ this.errors.set(toolCallId, {
125689
+ message: errMsg,
125690
+ input: partialArgs,
125691
+ toolName: chunk.toolName
125692
+ });
125693
+ break;
125694
+ }
125695
+ case "tool-result":
125696
+ this.inFlight.delete(chunk.toolCallId);
125697
+ this.completed.push({
125698
+ type: "tool-result",
125699
+ toolCallId: chunk.toolCallId,
125700
+ toolName: chunk.toolName,
125701
+ output: chunk.result ?? chunk.output
125702
+ });
125703
+ break;
125704
+ }
125705
+ }
125706
+ onStepPersisted() {
125707
+ this.completed.length = 0;
125708
+ }
125709
+ flushToolErrorsToResults() {
125710
+ const flushed = [];
125711
+ for (const [toolCallId, info] of this.errors) {
125712
+ this.completed.push({
125713
+ type: "tool-result",
125714
+ toolCallId,
125715
+ toolName: info.toolName,
125716
+ output: {
125717
+ type: "error-text",
125718
+ value: `Tool call failed: ${info.message}`
125719
+ }
125720
+ });
125721
+ flushed.push([toolCallId, info]);
125722
+ }
125723
+ this.errors.clear();
125724
+ return flushed;
125725
+ }
125726
+ clearToolErrors() {
125727
+ this.errors.clear();
125728
+ }
125729
+ clearInFlight() {
125730
+ this.inFlight.clear();
125731
+ }
125732
+ hasUnpersistedState() {
125733
+ return this.inFlight.size > 0 || this.completed.length > 0;
125734
+ }
125735
+ get inFlightTools() {
125736
+ return this.inFlight;
125737
+ }
125738
+ get toolErrors() {
125739
+ return this.errors;
125740
+ }
125741
+ get completedResults() {
125742
+ return this.completed;
125743
+ }
125744
+ get streamedArgText() {
125745
+ return this.streamedArgs;
125746
+ }
125747
+ snapshot() {
125748
+ return {
125749
+ inFlightTools: new Map(this.inFlight),
125750
+ completedResults: this.completed.map((r) => ({ ...r })),
125751
+ streamedArgText: new Map(this.streamedArgs),
125752
+ toolErrors: new Map(this.errors)
125753
+ };
125754
+ }
125755
+ }
125756
+
125757
+ // src/core/agents/offSecAgent/offensiveSecurityAgent.ts
125758
+ var log13 = scopedLogger(() => createLogger("approval-gate"));
125759
+ var RESPONSE_DEBUG2 = process.env.RESPONSE_DEBUG === "1" || process.env.RESPONSE_DEBUG === "true";
125760
+ var rlog2 = scopedLogger(() => createLogger("response-debug"));
125012
125761
  var WORKSPACE_TOOL_NAME_SET = new Set(WORKSPACE_TOOL_NAMES);
125013
125762
  var WORKSPACE_WRITE_TOOL_NAME_SET = new Set(WORKSPACE_WRITE_TOOL_NAMES);
125014
125763
  var WORKSPACE_TARGET_RE = /\b(?:console|workspace)\b/i;
@@ -125058,21 +125807,6 @@ function filterWorkspaceToolsForRun(activeTools, prompt, hasInteractiveApprovalG
125058
125807
  return true;
125059
125808
  });
125060
125809
  }
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
125810
 
125077
125811
  class OffensiveSecurityAgent {
125078
125812
  _streamResult = null;
@@ -125091,18 +125825,19 @@ class OffensiveSecurityAgent {
125091
125825
  drained = Promise.resolve();
125092
125826
  subagentId;
125093
125827
  subagentName;
125828
+ agentMode;
125094
125829
  currentMessageId = null;
125095
125830
  persistentShell;
125096
125831
  browserSession;
125097
125832
  ownsBrowserSession;
125098
125833
  browserDisconnected = false;
125834
+ shellDisposed = false;
125099
125835
  abortSignal;
125100
125836
  userPrompt;
125101
125837
  _session;
125102
- latestMessages = null;
125838
+ writer;
125839
+ finalizeInterruptedStep;
125103
125840
  messagesPath = null;
125104
- cancelPersistTimer = null;
125105
- syntheticsPersisted = false;
125106
125841
  static async create(input) {
125107
125842
  let session = input.session;
125108
125843
  if (!session) {
@@ -125127,6 +125862,7 @@ class OffensiveSecurityAgent {
125127
125862
  this._session = input.session;
125128
125863
  this.subagentId = input.subagentId;
125129
125864
  this.subagentName = input.subagentName;
125865
+ this.agentMode = input.mode ?? "default";
125130
125866
  this.abortSignal = input.abortSignal;
125131
125867
  this.userPrompt = input.prompt;
125132
125868
  this.eventBus = input.eventBus ?? new AgentEventBus;
@@ -125175,10 +125911,13 @@ class OffensiveSecurityAgent {
125175
125911
  agentCwd,
125176
125912
  target: input.target,
125177
125913
  grpc: input.grpc,
125914
+ systemScope: input.systemScope,
125178
125915
  abortSignal: input.abortSignal,
125179
125916
  model: input.model,
125180
125917
  authConfig: input.authConfig,
125181
125918
  eventBus: this.eventBus,
125919
+ onStepFinish: input.forwardUsageCallbacksToSpawnedAgents ? input.onStepFinish : undefined,
125920
+ onCacheMetrics: input.forwardUsageCallbacksToSpawnedAgents ? input.onCacheMetrics : undefined,
125182
125921
  sandbox: input.sandbox,
125183
125922
  findingsRegistry: input.findingsRegistry,
125184
125923
  attackSurfaceRegistry: input.attackSurfaceRegistry,
@@ -125210,8 +125949,8 @@ class OffensiveSecurityAgent {
125210
125949
  ...tools,
125211
125950
  [RESPONSE_TOOL_NAME]: createResponseTool(input.responseSchema, (result) => {
125212
125951
  this._responseToolFired = true;
125213
- if (RESPONSE_DEBUG) {
125214
- rlog.warn(`[response-debug] response tool EXECUTED (captured) session=${this.busSessionId} ` + `resultBytes=${responseArgBytes(result)} — happy path`);
125952
+ if (RESPONSE_DEBUG2) {
125953
+ rlog2.warn(`[response-debug] response tool EXECUTED (captured) session=${this.busSessionId} ` + `resultBytes=${responseArgBytes(result)} — happy path`);
125215
125954
  }
125216
125955
  const customResolve = input.resolveResult;
125217
125956
  if (customResolve) {
@@ -125259,7 +125998,11 @@ class OffensiveSecurityAgent {
125259
125998
  const hasEmail = (input.session.config?.emailIntegration?.inboxes?.length ?? 0) > 0;
125260
125999
  const hasSmtp = !!input.session.config?.smtpConfig;
125261
126000
  const emailToolSet = new Set(EMAIL_TOOL_NAMES);
126001
+ const smsToolSet = new Set(SMS_TOOL_NAMES);
126002
+ const hasSms = sessionHasSmsPasswordless(input.session);
125262
126003
  let activeTools = input.activeTools.filter((t) => {
126004
+ if (smsToolSet.has(t))
126005
+ return hasSms;
125263
126006
  if (!emailToolSet.has(t))
125264
126007
  return true;
125265
126008
  if (t === SEND_EMAIL_TOOL_NAME)
@@ -125274,6 +126017,8 @@ class OffensiveSecurityAgent {
125274
126017
  activeTools = Object.keys(tools).filter((t) => {
125275
126018
  if (excluded.has(t))
125276
126019
  return false;
126020
+ if (smsToolSet.has(t))
126021
+ return hasSms;
125277
126022
  if (!emailToolSet.has(t))
125278
126023
  return true;
125279
126024
  if (t === SEND_EMAIL_TOOL_NAME)
@@ -125282,11 +126027,10 @@ class OffensiveSecurityAgent {
125282
126027
  });
125283
126028
  }
125284
126029
  activeTools = filterWorkspaceToolsForRun(activeTools, input.prompt, input.approvalGate !== undefined);
125285
- if (!existsSync18(messagesDir)) {
126030
+ if (!existsSync19(messagesDir)) {
125286
126031
  mkdirSync14(messagesDir, { recursive: true });
125287
126032
  }
125288
126033
  this.messagesPath = join27(messagesDir, "messages.json");
125289
- const messagesPath = this.messagesPath;
125290
126034
  const initialMessagesRef = {
125291
126035
  current: input.messages ? [...input.messages] : [
125292
126036
  {
@@ -125295,26 +126039,17 @@ class OffensiveSecurityAgent {
125295
126039
  }
125296
126040
  ]
125297
126041
  };
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
- };
126042
+ this.writer = new AgentMessageWriter({ messagesPath: this.messagesPath });
126043
+ this.finalizeInterruptedStep = createInterruptedStepFinalizer({
126044
+ eventBus: this.eventBus,
126045
+ sessionId: this.busSessionId,
126046
+ subagentId: this.subagentId,
126047
+ writer: this.writer,
126048
+ responseToolName: RESPONSE_TOOL_NAME,
126049
+ responseToolFired: () => this._responseToolFired,
126050
+ ...RESPONSE_DEBUG2 ? { debugLog: (message) => rlog2.warn(message) } : {}
126051
+ });
126052
+ const schedulePersist = () => this.writer.schedulePersist();
125318
126053
  const baseSystemPrompt = input.system ?? detectOSAndEnhancePrompt(buildBaseSystemPrompt({
125319
126054
  sandboxMode: agentCwd === input.session.rootPath
125320
126055
  }));
@@ -125339,10 +126074,10 @@ class OffensiveSecurityAgent {
125339
126074
  sessionPath: messagesDir,
125340
126075
  sessionId: this.busSessionId,
125341
126076
  onStepFinish: async (event) => {
125342
- this.latestMessages = [
126077
+ this.writer.setLatest([
125343
126078
  ...initialMessagesRef.current,
125344
126079
  ...event.response.messages
125345
- ];
126080
+ ]);
125346
126081
  schedulePersist();
125347
126082
  traceWriter.recordStep(event.response.messages, {
125348
126083
  inputTokens: event.usage.inputTokens ?? 0,
@@ -125364,16 +126099,14 @@ class OffensiveSecurityAgent {
125364
126099
  traceWriter.markSummarized();
125365
126100
  },
125366
126101
  onFinish: async (event) => {
125367
- if (persistTimer) {
125368
- clearTimeout(persistTimer);
125369
- persistTimer = null;
125370
- }
125371
- if (!this.syntheticsPersisted) {
125372
- const finalMessages = this.latestMessages ?? [
126102
+ this.writer.cancelTimer();
126103
+ if (!this.writer.syntheticsPersisted) {
126104
+ const finalMessages = this.writer.latest ?? [
125373
126105
  ...initialMessagesRef.current,
125374
126106
  ...event.response.messages
125375
126107
  ];
125376
- await writeFile7(messagesPath, JSON.stringify(finalMessages)).catch(() => {});
126108
+ this.writer.setLatest(finalMessages);
126109
+ await this.writer.enqueueWrite(finalMessages).catch(() => {});
125377
126110
  }
125378
126111
  await input.onFinish?.(event);
125379
126112
  },
@@ -125425,205 +126158,34 @@ class OffensiveSecurityAgent {
125425
126158
  return p;
125426
126159
  }
125427
126160
  };
125428
- const inFlightTools = new Map;
125429
- const completedResults = [];
126161
+ const tracker = new ToolLifecycleTracker;
125430
126162
  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
- }
126163
+ const diagnostics = new StreamDiagnostics({
126164
+ sessionId: this._session.id,
126165
+ subagentId: sid,
126166
+ inFlightTools: () => tracker.inFlightTools,
126167
+ responseToolFired: () => this._responseToolFired,
126168
+ responseToolName: RESPONSE_TOOL_NAME
126169
+ });
126170
+ diagnostics.start();
125448
126171
  try {
125449
126172
  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
- }
126173
+ diagnostics.observeChunk(chunk);
126174
+ this.applyStreamPart(chunk, { ids, tracker, diagnostics });
125590
126175
  bus.emitStreamPart(chunk, ids);
125591
126176
  }
125592
126177
  } catch (err) {
125593
126178
  streamError = err;
125594
126179
  } 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 {}
126180
+ const finalizeError = await this.finalizeRun({
126181
+ tracker,
126182
+ diagnostics,
126183
+ ids,
126184
+ streamError
126185
+ });
126186
+ if (streamError === null && finalizeError !== null) {
126187
+ streamError = finalizeError;
125625
126188
  }
125626
- await this.disconnectOwnedBrowser();
125627
126189
  }
125628
126190
  if (streamError) {
125629
126191
  throw streamError;
@@ -125639,22 +126201,32 @@ class OffensiveSecurityAgent {
125639
126201
  }
125640
126202
  return;
125641
126203
  };
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
126204
+ const isSubagent = Boolean(sid);
126205
+ const spanLabel = isSubagent ? this.subagentName ?? sid ?? "subagent" : this.agentMode;
126206
+ const runId = isSubagent ? undefined : newRunId();
126207
+ const runSpanAttributes = {
126208
+ "gen_ai.operation.name": "invoke_agent",
126209
+ "gen_ai.agent.name": spanLabel,
126210
+ "gen_ai.conversation.id": this.busSessionId,
126211
+ "pensar.session.id": this.busSessionId,
126212
+ ...isSubagent ? {} : {
126213
+ "pensar.run.id": runId,
126214
+ "pensar.agent.mode": this.agentMode
125647
126215
  }
125648
- }, async (span) => {
126216
+ };
126217
+ const runInSpan = () => getApexTracer().startActiveSpan(`invoke_agent ${spanLabel}`, { attributes: runSpanAttributes }, async (span) => {
125649
126218
  try {
125650
126219
  return await runConsume();
125651
126220
  } catch (err) {
125652
126221
  span.recordException(err);
126222
+ span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
126223
+ span.setAttribute("error.type", err instanceof Error ? err.name : "Error");
125653
126224
  throw err;
125654
126225
  } finally {
125655
126226
  span.end();
125656
126227
  }
125657
- }));
126228
+ });
126229
+ const drain = !isSubagent ? runInSpan() : withSubagentSessionBaggage(sid, runInSpan);
125658
126230
  let rejectDrain;
125659
126231
  this._drainRejection = new Promise((_2, reject) => {
125660
126232
  rejectDrain = reject;
@@ -125678,6 +126250,141 @@ class OffensiveSecurityAgent {
125678
126250
  await this.disconnectOwnedBrowser();
125679
126251
  return result;
125680
126252
  }
126253
+ applyStreamPart(chunk, ctx) {
126254
+ const { ids, tracker, diagnostics } = ctx;
126255
+ const sid = this.subagentId;
126256
+ const bus = this.eventBus;
126257
+ switch (chunk.type) {
126258
+ case "start-step":
126259
+ ids.messageId = newMessageId();
126260
+ this.currentMessageId = ids.messageId;
126261
+ ids.textPartId = undefined;
126262
+ break;
126263
+ case "text-start":
126264
+ ids.textPartId = newPartId();
126265
+ break;
126266
+ case "text-end":
126267
+ ids.textPartId = undefined;
126268
+ break;
126269
+ case "finish-step": {
126270
+ tracker.onStepPersisted();
126271
+ const finishReason = chunk.finishReason;
126272
+ const truncated = finishReason === "length";
126273
+ for (const [toolCallId, info] of tracker.toolErrors) {
126274
+ diagnostics.logSurfacedToolError({
126275
+ toolCallId,
126276
+ toolName: info.toolName,
126277
+ message: info.message,
126278
+ streamedArgChars: (tracker.streamedArgText.get(toolCallId) ?? "").length,
126279
+ finishReason,
126280
+ truncated
126281
+ });
126282
+ bus.emit("tool-result", {
126283
+ toolCallId,
126284
+ toolName: info.toolName,
126285
+ result: {
126286
+ type: "error-text",
126287
+ 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}`
126288
+ },
126289
+ sessionId: this.busSessionId,
126290
+ subagentId: sid,
126291
+ partId: ids.toolPartId?.(toolCallId),
126292
+ messageId: ids.messageId
126293
+ });
126294
+ }
126295
+ tracker.clearToolErrors();
126296
+ for (const [toolCallId, toolName] of tracker.inFlightTools) {
126297
+ diagnostics.logClosingInFlightTool({
126298
+ toolCallId,
126299
+ toolName,
126300
+ finishReason,
126301
+ truncated
126302
+ });
126303
+ const result = toolName === RESPONSE_TOOL_NAME && this._responseToolFired ? { type: "text", value: "Response submitted." } : {
126304
+ type: "error-text",
126305
+ 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"
126306
+ };
126307
+ bus.emit("tool-result", {
126308
+ toolCallId,
126309
+ toolName,
126310
+ result,
126311
+ sessionId: this.busSessionId,
126312
+ subagentId: sid,
126313
+ partId: ids.toolPartId?.(toolCallId),
126314
+ messageId: ids.messageId
126315
+ });
126316
+ }
126317
+ tracker.clearInFlight();
126318
+ break;
126319
+ }
126320
+ default:
126321
+ tracker.observePart(chunk);
126322
+ }
126323
+ }
126324
+ async finalizeRun(input) {
126325
+ const { tracker, diagnostics, ids, streamError } = input;
126326
+ const sid = this.subagentId;
126327
+ const bus = this.eventBus;
126328
+ diagnostics.stop();
126329
+ let finalizationError;
126330
+ let hasFinalizationError = false;
126331
+ const recordFinalizationError = (error) => {
126332
+ if (hasFinalizationError)
126333
+ return;
126334
+ finalizationError = error;
126335
+ hasFinalizationError = true;
126336
+ };
126337
+ try {
126338
+ try {
126339
+ this.disposeOwnedShell();
126340
+ } catch (error) {
126341
+ recordFinalizationError(error);
126342
+ }
126343
+ for (const [toolCallId, info] of tracker.flushToolErrorsToResults()) {
126344
+ const result = {
126345
+ type: "error-text",
126346
+ value: `Tool call failed: ${info.message}`
126347
+ };
126348
+ try {
126349
+ bus.emit("tool-result", {
126350
+ toolCallId,
126351
+ toolName: info.toolName,
126352
+ result,
126353
+ sessionId: this.busSessionId,
126354
+ subagentId: sid,
126355
+ partId: ids.toolPartId?.(toolCallId),
126356
+ messageId: ids.messageId
126357
+ });
126358
+ } catch (error) {
126359
+ recordFinalizationError(error);
126360
+ }
126361
+ }
126362
+ if (tracker.hasUnpersistedState()) {
126363
+ const reason = this.abortSignal?.aborted ? "Agent aborted by user" : streamError instanceof Error && streamError.message ? streamError.message : "Stream terminated unexpectedly";
126364
+ try {
126365
+ await this.finalizeInterruptedStep({
126366
+ snapshot: tracker.snapshot(),
126367
+ reason,
126368
+ partIdFor: ids.toolPartId,
126369
+ messageId: ids.messageId
126370
+ });
126371
+ } catch (error) {
126372
+ recordFinalizationError(error);
126373
+ }
126374
+ }
126375
+ } catch (error) {
126376
+ recordFinalizationError(error);
126377
+ } finally {
126378
+ await this.disconnectOwnedBrowser();
126379
+ }
126380
+ return hasFinalizationError ? finalizationError : null;
126381
+ }
126382
+ disposeOwnedShell() {
126383
+ if (this.shellDisposed)
126384
+ return;
126385
+ this.shellDisposed = true;
126386
+ this.persistentShell?.dispose();
126387
+ }
125681
126388
  async disconnectOwnedBrowser() {
125682
126389
  if (this.browserDisconnected)
125683
126390
  return;
@@ -125693,102 +126400,6 @@ class OffensiveSecurityAgent {
125693
126400
  get response() {
125694
126401
  return this.streamResult.response;
125695
126402
  }
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
126403
  }
125793
126404
  var AGENT_PAUSE_TOOLS = new Set([ASK_USER_QUESTIONS_TOOL_NAME]);
125794
126405
  function wrapToolsWithApprovalGate(tools, gate, exemptToolNames) {
@@ -125828,4 +126439,4 @@ function wrapToolsWithApprovalGate(tools, gate, exemptToolNames) {
125828
126439
  return wrapped;
125829
126440
  }
125830
126441
 
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 };
126442
+ 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 };