@pensar/apex 0.0.88-canary.2b93505f → 0.0.88

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 (2) hide show
  1. package/build/index.js +402 -174
  2. package/package.json +1 -1
package/build/index.js CHANGED
@@ -31971,7 +31971,7 @@ var package_default2;
31971
31971
  var init_package = __esm(() => {
31972
31972
  package_default2 = {
31973
31973
  name: "@pensar/apex",
31974
- version: "0.0.88-canary.2b93505f",
31974
+ version: "0.0.88",
31975
31975
  description: "AI-powered penetration testing CLI tool with terminal UI",
31976
31976
  module: "src/tui/index.tsx",
31977
31977
  main: "build/index.js",
@@ -88478,6 +88478,7 @@ Summary: ${summary}
88478
88478
  Original task: Please respond based on this summary.` : `${opts.prompt}
88479
88479
 
88480
88480
  The previous agent has summarized the conversation to pass to you to continue the task. Here is the summary: ${summary}`;
88481
+ opts.onSummarized?.(summary);
88481
88482
  const resumed = streamResponse({
88482
88483
  ...opts,
88483
88484
  prompt: enhancedPrompt,
@@ -89152,6 +89153,20 @@ function hasOperatorState(session) {
89152
89153
  const statePath = path5.join(session.rootPath, "messages.json");
89153
89154
  return existsSync3(statePath);
89154
89155
  }
89156
+ function getResumeMessages(messages, limit = MAX_RESUME_MESSAGES) {
89157
+ if (messages.length <= limit)
89158
+ return messages;
89159
+ let cutIndex = messages.length - limit;
89160
+ while (cutIndex < messages.length) {
89161
+ if (messages[cutIndex].role === "user")
89162
+ break;
89163
+ cutIndex++;
89164
+ }
89165
+ if (cutIndex >= messages.length) {
89166
+ cutIndex = messages.length - limit;
89167
+ }
89168
+ return messages.slice(cutIndex);
89169
+ }
89155
89170
  async function updateOperatorSettings(sessionId, settings) {
89156
89171
  return await update3(sessionId, (session) => {
89157
89172
  if (!session.config) {
@@ -89224,7 +89239,7 @@ var DEFAULT_OUTCOME_GUIDANCE, EXFIL_OUTCOME_GUIDANCE, DEFAULT_OFFENSIVE_HEADERS,
89224
89239
  input.messageId
89225
89240
  ]);
89226
89241
  return input.messageId;
89227
- }, sessions;
89242
+ }, MAX_RESUME_MESSAGES = 200, sessions;
89228
89243
  var init_session = __esm(() => {
89229
89244
  init_zod();
89230
89245
  init_id();
@@ -89356,6 +89371,7 @@ var init_session = __esm(() => {
89356
89371
  removeMessage,
89357
89372
  loadOperatorState,
89358
89373
  hasOperatorState,
89374
+ getResumeMessages,
89359
89375
  updateOperatorSettings,
89360
89376
  updateToolsetState,
89361
89377
  toggleTool: toggleTool2
@@ -106964,6 +106980,34 @@ var init_executeCommand = __esm(() => {
106964
106980
  });
106965
106981
 
106966
106982
  // src/core/agents/offSecAgent/tools/httpRequest.ts
106983
+ import { join as join10 } from "path";
106984
+ import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync14 } from "fs";
106985
+ function maybeSaveBody(body, ctx4) {
106986
+ if (body.length <= MAX_INLINE_BODY)
106987
+ return { text: body };
106988
+ const outputDir = join10(ctx4.session.logsPath, "http-responses");
106989
+ if (!existsSync14(outputDir)) {
106990
+ mkdirSync6(outputDir, { recursive: true });
106991
+ }
106992
+ const ts = new Date().toISOString().replace(/[:.]/g, "-");
106993
+ const filename = `response-${ts}.txt`;
106994
+ const filePath = join10(outputDir, filename);
106995
+ try {
106996
+ writeFileSync6(filePath, body);
106997
+ } catch {
106998
+ return {
106999
+ text: `${body.substring(0, MAX_INLINE_BODY)}...
107000
+
107001
+ (truncated — failed to save full response to file)`
107002
+ };
107003
+ }
107004
+ return {
107005
+ text: `${body.substring(0, MAX_INLINE_BODY)}...
107006
+
107007
+ (truncated — full response saved to ${filePath}). Use read_file or grep to analyze.`,
107008
+ file: filePath
107009
+ };
107010
+ }
106967
107011
  function parseHeaders(raw) {
106968
107012
  if (!raw)
106969
107013
  return {};
@@ -107052,14 +107096,13 @@ COMMON TESTING PATTERNS:
107052
107096
  } catch {
107053
107097
  responseBody = "(unable to read response body)";
107054
107098
  }
107099
+ const { text: truncatedBody } = maybeSaveBody(responseBody, ctx4);
107055
107100
  return {
107056
107101
  success: true,
107057
107102
  status: response.status,
107058
107103
  statusText: response.statusText,
107059
107104
  headers: responseHeaders,
107060
- body: responseBody.length > 5000 ? `${responseBody.substring(0, 5000)}...
107061
-
107062
- (truncated) use execute_command with grep / tail to paginate the response` : responseBody,
107105
+ body: truncatedBody,
107063
107106
  url: response.url,
107064
107107
  redirected: response.redirected
107065
107108
  };
@@ -107134,14 +107177,13 @@ async function executeSandboxHttpRequest(ctx4, opts) {
107134
107177
  const statusText = statusMatch ? statusMatch[2] : "Unknown";
107135
107178
  const responseBody = lines.slice(bodyStartIndex).join(`
107136
107179
  `);
107180
+ const { text: truncatedBody } = maybeSaveBody(responseBody, ctx4);
107137
107181
  return {
107138
107182
  success: status >= 200 && status < 400,
107139
107183
  status,
107140
107184
  statusText,
107141
107185
  headers: responseHeaders,
107142
- body: responseBody.length > 5000 ? `${responseBody.substring(0, 5000)}...
107143
-
107144
- (truncated) use execute_command with grep / tail to paginate the response` : responseBody,
107186
+ body: truncatedBody,
107145
107187
  url: url2,
107146
107188
  redirected: false
107147
107189
  };
@@ -107159,7 +107201,7 @@ async function executeSandboxHttpRequest(ctx4, opts) {
107159
107201
  };
107160
107202
  }
107161
107203
  }
107162
- var httpRequestInputSchema;
107204
+ var MAX_INLINE_BODY = 5000, httpRequestInputSchema;
107163
107205
  var init_httpRequest = __esm(() => {
107164
107206
  init_dist5();
107165
107207
  init_zod();
@@ -108030,8 +108072,8 @@ var init_cvssScorer = __esm(() => {
108030
108072
  });
108031
108073
 
108032
108074
  // src/core/agents/offSecAgent/tools/documentFinding.ts
108033
- import { join as join10 } from "path";
108034
- import { writeFileSync as writeFileSync6, appendFileSync as appendFileSync2 } from "fs";
108075
+ import { join as join11 } from "path";
108076
+ import { writeFileSync as writeFileSync7, appendFileSync as appendFileSync2 } from "fs";
108035
108077
  function documentVulnerability(ctx4) {
108036
108078
  const { session } = ctx4;
108037
108079
  return tool({
@@ -108060,8 +108102,8 @@ FINDING STRUCTURE:
108060
108102
  if (input.evidence.length > EVIDENCE_FILE_THRESHOLD) {
108061
108103
  const safeSlug = input.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").substring(0, 40);
108062
108104
  const evidenceFilename = `${timestamp.split("T")[0]}-${safeSlug}-evidence.txt`;
108063
- evidenceFilePath = join10(session.findingsPath, evidenceFilename);
108064
- writeFileSync6(evidenceFilePath, input.evidence);
108105
+ evidenceFilePath = join11(session.findingsPath, evidenceFilename);
108106
+ writeFileSync7(evidenceFilePath, input.evidence);
108065
108107
  evidenceForPrompt = input.evidence.substring(0, EVIDENCE_FILE_THRESHOLD) + `
108066
108108
  ... [truncated — full output saved to ${evidenceFilename}]`;
108067
108109
  }
@@ -108120,11 +108162,11 @@ FINDING STRUCTURE:
108120
108162
  const safeTitle = finding.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").substring(0, 50);
108121
108163
  const findingId = `${timestamp.split("T")[0]}-${safeTitle}`;
108122
108164
  const jsonFilename = `${findingId}.json`;
108123
- const jsonPath = join10(session.findingsPath, jsonFilename);
108165
+ const jsonPath = join11(session.findingsPath, jsonFilename);
108124
108166
  const mdFilename = `${findingId}.md`;
108125
- const mdPath = join10(session.findingsPath, mdFilename);
108167
+ const mdPath = join11(session.findingsPath, mdFilename);
108126
108168
  try {
108127
- writeFileSync6(jsonPath, JSON.stringify(findingWithMeta, null, 2));
108169
+ writeFileSync7(jsonPath, JSON.stringify(findingWithMeta, null, 2));
108128
108170
  const cvssSection = cvssWarning ? `## CVSS 4.0 Assessment
108129
108171
 
108130
108172
  **Warning:** ${cvssWarning}
@@ -108186,8 +108228,8 @@ ${finding.references}` : ""}
108186
108228
 
108187
108229
  *This finding was automatically documented by the Pensar penetration testing agent.*
108188
108230
  `;
108189
- writeFileSync6(mdPath, markdown);
108190
- const summaryPath = join10(session.rootPath, "findings-summary.md");
108231
+ writeFileSync7(mdPath, markdown);
108232
+ const summaryPath = join11(session.rootPath, "findings-summary.md");
108191
108233
  const summaryEntry = `- [${finding.severity}] (CVSS ${cvssResult.score}) ${finding.title} - \`findings/${mdFilename}\`
108192
108234
  `;
108193
108235
  try {
@@ -108201,7 +108243,7 @@ ${finding.references}` : ""}
108201
108243
  ## All Findings
108202
108244
 
108203
108245
  `;
108204
- writeFileSync6(summaryPath, header + summaryEntry);
108246
+ writeFileSync7(summaryPath, header + summaryEntry);
108205
108247
  }
108206
108248
  } catch (writeError) {
108207
108249
  if (ctx4.findingsRegistry) {
@@ -108267,14 +108309,14 @@ var init_documentFinding = __esm(() => {
108267
108309
  });
108268
108310
 
108269
108311
  // src/core/agents/offSecAgent/tools/createPoc.ts
108270
- import { join as join11 } from "path";
108312
+ import { join as join12 } from "path";
108271
108313
  import { spawn as spawn2 } from "child_process";
108272
108314
  import {
108273
- existsSync as existsSync14,
108274
- writeFileSync as writeFileSync7,
108315
+ existsSync as existsSync15,
108316
+ writeFileSync as writeFileSync8,
108275
108317
  chmodSync,
108276
108318
  unlinkSync,
108277
- mkdirSync as mkdirSync6
108319
+ mkdirSync as mkdirSync7
108278
108320
  } from "fs";
108279
108321
  function sanitizeFilename(str) {
108280
108322
  return str.toLowerCase().replace(/[^a-z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").substring(0, 50);
@@ -108323,12 +108365,12 @@ Max ${MAX_POC_ATTEMPTS} attempts per approach before pivoting.`,
108323
108365
  async function executeLocalPoc(ctx4, poc, currentAttempts) {
108324
108366
  try {
108325
108367
  const pocsPath = ctx4.session.pocsPath;
108326
- if (!existsSync14(pocsPath)) {
108327
- mkdirSync6(pocsPath, { recursive: true });
108368
+ if (!existsSync15(pocsPath)) {
108369
+ mkdirSync7(pocsPath, { recursive: true });
108328
108370
  }
108329
108371
  const { filename, pocContent } = preparePoc(poc, currentAttempts);
108330
- const pocPath = join11(pocsPath, filename);
108331
- writeFileSync7(pocPath, pocContent);
108372
+ const pocPath = join12(pocsPath, filename);
108373
+ writeFileSync8(pocPath, pocContent);
108332
108374
  chmodSync(pocPath, 493);
108333
108375
  const runner = poc.pocType === "bash" ? "bash" : poc.pocType === "python" ? "python3" : "node";
108334
108376
  const { stdout, stderr, exitCode } = await runScript(runner, pocPath, 60000, ctx4.abortSignal);
@@ -108359,18 +108401,18 @@ async function executeSandboxPoc(ctx4, poc, currentAttempts) {
108359
108401
  try {
108360
108402
  const { filename, pocContent } = preparePoc(poc, currentAttempts);
108361
108403
  const localPocsPath = ctx4.session.pocsPath;
108362
- if (!existsSync14(localPocsPath)) {
108363
- mkdirSync6(localPocsPath, { recursive: true });
108404
+ if (!existsSync15(localPocsPath)) {
108405
+ mkdirSync7(localPocsPath, { recursive: true });
108364
108406
  }
108365
- const localPocPath = join11(localPocsPath, filename);
108366
- if (existsSync14(localPocPath)) {
108407
+ const localPocPath = join12(localPocsPath, filename);
108408
+ if (existsSync15(localPocPath)) {
108367
108409
  return {
108368
108410
  success: false,
108369
108411
  error: `POC already exists at: pocs/${filename}`,
108370
108412
  attemptsRemaining: MAX_POC_ATTEMPTS - currentAttempts
108371
108413
  };
108372
108414
  }
108373
- writeFileSync7(localPocPath, pocContent);
108415
+ writeFileSync8(localPocPath, pocContent);
108374
108416
  const sandboxPocPath = `/tmp/pocs/${filename}`;
108375
108417
  await ctx4.sandbox.execute("mkdir -p /tmp/pocs");
108376
108418
  const base64Content = Buffer.from(pocContent).toString("base64");
@@ -108568,7 +108610,7 @@ var init_readFile = __esm(() => {
108568
108610
 
108569
108611
  // src/core/agents/offSecAgent/tools/listFiles.ts
108570
108612
  import { readdir as readdir2, stat } from "fs/promises";
108571
- import { join as join12, relative, resolve as resolve7, isAbsolute as isAbsolute3 } from "path";
108613
+ import { join as join13, relative, resolve as resolve7, isAbsolute as isAbsolute3 } from "path";
108572
108614
  async function listRecursive(dir, maxEntries) {
108573
108615
  const results = [];
108574
108616
  let total = 0;
@@ -108581,7 +108623,7 @@ async function listRecursive(dir, maxEntries) {
108581
108623
  }
108582
108624
  for (const entry of entries2) {
108583
108625
  total++;
108584
- const fullPath = join12(current, entry.name);
108626
+ const fullPath = join13(current, entry.name);
108585
108627
  if (entry.isDirectory()) {
108586
108628
  if (results.length < maxEntries)
108587
108629
  results.push(`${fullPath}/`);
@@ -108644,7 +108686,7 @@ Each directory entry is suffixed with "/" for easy identification.`,
108644
108686
  }
108645
108687
  const entries2 = await readdir2(dir, { withFileTypes: true });
108646
108688
  const fullPaths = entries2.map((e) => {
108647
- const name26 = join12(dir, e.name);
108689
+ const name26 = join13(dir, e.name);
108648
108690
  return e.isDirectory() ? `${name26}/` : name26;
108649
108691
  });
108650
108692
  const capped = fullPaths.slice(0, MAX_NON_RECURSIVE);
@@ -108790,7 +108832,7 @@ var init_grep = __esm(() => {
108790
108832
  // src/core/agents/offSecAgent/tools/createFile.ts
108791
108833
  import { writeFile, mkdir } from "fs/promises";
108792
108834
  import { dirname as dirname4, resolve as resolve8, isAbsolute as isAbsolute4 } from "path";
108793
- import { existsSync as existsSync15 } from "fs";
108835
+ import { existsSync as existsSync16 } from "fs";
108794
108836
  function createFile(ctx4) {
108795
108837
  return tool({
108796
108838
  description: `Create a new file with the given content.
@@ -108815,7 +108857,7 @@ Parent directories are created automatically if they don't exist.`,
108815
108857
  }
108816
108858
  async function executeLocalCreate(filePath, content, overwrite) {
108817
108859
  try {
108818
- if (!overwrite && existsSync15(filePath)) {
108860
+ if (!overwrite && existsSync16(filePath)) {
108819
108861
  return {
108820
108862
  success: false,
108821
108863
  error: `File already exists: ${filePath}. Set overwrite=true to replace it.`,
@@ -109025,11 +109067,173 @@ var init_updateFile = __esm(() => {
109025
109067
  });
109026
109068
  });
109027
109069
 
109070
+ // src/core/agents/specialized/attackSurface/blackboxRiskScoring.ts
109071
+ function computeBlackboxRiskScore(riskLevel, assetType, details, notes) {
109072
+ const exposure = computeExposure(riskLevel, details);
109073
+ const dataSensitivity = computeDataSensitivity(riskLevel, assetType, details);
109074
+ const functionCriticality = computeFunctionCriticality(riskLevel, assetType, details, notes);
109075
+ const securityIndicators = computeSecurityIndicators(riskLevel, details, notes);
109076
+ const rawSum = exposure + dataSensitivity + functionCriticality + securityIndicators;
109077
+ const score = Math.min(10, Math.max(0, rawSum));
109078
+ const baseScore = RISK_LEVEL_BASE_SCORE[riskLevel] ?? 0;
109079
+ const explanation = buildExplanation(riskLevel, assetType, baseScore, score, {
109080
+ exposure,
109081
+ dataSensitivity,
109082
+ functionCriticality,
109083
+ securityIndicators
109084
+ });
109085
+ return {
109086
+ score,
109087
+ explanation,
109088
+ breakdown: {
109089
+ exposure,
109090
+ dataSensitivity,
109091
+ functionCriticality,
109092
+ securityIndicators
109093
+ }
109094
+ };
109095
+ }
109096
+ function computeExposure(riskLevel, details) {
109097
+ let base = EXPOSURE_BY_RISK[riskLevel] ?? 1;
109098
+ if (details?.authentication) {
109099
+ const authLower = details.authentication.toLowerCase();
109100
+ if (authLower.includes("none") || authLower.includes("no auth") || authLower.includes("public")) {
109101
+ base = Math.max(base, 3);
109102
+ } else if (authLower.includes("admin") || authLower.includes("privileged")) {
109103
+ base = Math.min(base, 1);
109104
+ }
109105
+ }
109106
+ return Math.min(3, Math.max(0, base));
109107
+ }
109108
+ function computeDataSensitivity(riskLevel, assetType, details) {
109109
+ if (riskLevel === "CRITICAL")
109110
+ return 3;
109111
+ let score = riskLevel === "HIGH" ? 2 : riskLevel === "MEDIUM" ? 1 : 0;
109112
+ if (assetType === "admin_panel")
109113
+ score = Math.max(score, 2);
109114
+ const techStr = (details?.technology ?? []).join(" ").toLowerCase();
109115
+ if (techStr.includes("database") || techStr.includes("postgres") || techStr.includes("mysql") || techStr.includes("mongo") || techStr.includes("redis")) {
109116
+ score = Math.max(score, 2);
109117
+ }
109118
+ return Math.min(3, score);
109119
+ }
109120
+ function computeFunctionCriticality(riskLevel, assetType, details, notes) {
109121
+ if (assetType === "admin_panel")
109122
+ return 2;
109123
+ if (riskLevel === "CRITICAL")
109124
+ return 2;
109125
+ const searchText = [
109126
+ ...details?.services ?? [],
109127
+ ...details?.technology ?? [],
109128
+ details?.authentication ?? "",
109129
+ notes ?? ""
109130
+ ].join(" ").toLowerCase();
109131
+ const criticalPatterns = [
109132
+ "auth",
109133
+ "login",
109134
+ "payment",
109135
+ "checkout",
109136
+ "password",
109137
+ "oauth",
109138
+ "sso",
109139
+ "saml",
109140
+ "admin",
109141
+ "transfer",
109142
+ "billing"
109143
+ ];
109144
+ if (criticalPatterns.some((p) => searchText.includes(p)))
109145
+ return 2;
109146
+ if (riskLevel === "HIGH")
109147
+ return 1;
109148
+ if (assetType === "api" || assetType === "web_application")
109149
+ return 1;
109150
+ return 0;
109151
+ }
109152
+ function computeSecurityIndicators(riskLevel, details, notes) {
109153
+ if (riskLevel === "CRITICAL")
109154
+ return 2;
109155
+ const searchText = [
109156
+ ...details?.services ?? [],
109157
+ ...details?.technology ?? [],
109158
+ notes ?? "",
109159
+ String(details?.status ?? "")
109160
+ ].join(" ").toLowerCase();
109161
+ const criticalIndicators = [
109162
+ "injection",
109163
+ "sqli",
109164
+ "xss",
109165
+ "rce",
109166
+ "traversal",
109167
+ "deserialization",
109168
+ "hardcoded",
109169
+ "default credentials",
109170
+ "vulnerable",
109171
+ "cve-",
109172
+ "exploit"
109173
+ ];
109174
+ if (criticalIndicators.some((p) => searchText.includes(p)))
109175
+ return 2;
109176
+ const moderateIndicators = [
109177
+ "outdated",
109178
+ "deprecated",
109179
+ "insecure",
109180
+ "http:",
109181
+ "self-signed",
109182
+ "debug",
109183
+ "verbose error",
109184
+ "stack trace",
109185
+ "cors",
109186
+ "misconfigur"
109187
+ ];
109188
+ if (moderateIndicators.some((p) => searchText.includes(p)))
109189
+ return 1;
109190
+ if (riskLevel === "HIGH")
109191
+ return 1;
109192
+ return 0;
109193
+ }
109194
+ function buildExplanation(riskLevel, assetType, _baseScore, totalScore, breakdown) {
109195
+ const parts = [
109196
+ `${riskLevel} risk ${assetType.replace(/_/g, " ")} (score ${totalScore}/10).`
109197
+ ];
109198
+ if (breakdown.exposure >= 3)
109199
+ parts.push("Publicly exposed.");
109200
+ else if (breakdown.exposure >= 2)
109201
+ parts.push("Externally accessible.");
109202
+ if (breakdown.dataSensitivity >= 3)
109203
+ parts.push("Likely handles sensitive data.");
109204
+ else if (breakdown.dataSensitivity >= 2)
109205
+ parts.push("May handle business-critical data.");
109206
+ if (breakdown.functionCriticality >= 2)
109207
+ parts.push("Critical function.");
109208
+ else if (breakdown.functionCriticality >= 1)
109209
+ parts.push("Core function.");
109210
+ if (breakdown.securityIndicators >= 2)
109211
+ parts.push("Security concerns observed.");
109212
+ else if (breakdown.securityIndicators >= 1)
109213
+ parts.push("Moderate security concerns.");
109214
+ return parts.join(" ");
109215
+ }
109216
+ var RISK_LEVEL_BASE_SCORE, EXPOSURE_BY_RISK;
109217
+ var init_blackboxRiskScoring = __esm(() => {
109218
+ RISK_LEVEL_BASE_SCORE = {
109219
+ CRITICAL: 10,
109220
+ HIGH: 8,
109221
+ MEDIUM: 5,
109222
+ LOW: 2
109223
+ };
109224
+ EXPOSURE_BY_RISK = {
109225
+ CRITICAL: 3,
109226
+ HIGH: 3,
109227
+ MEDIUM: 2,
109228
+ LOW: 1
109229
+ };
109230
+ });
109231
+
109028
109232
  // src/core/agents/offSecAgent/tools/documentAsset.ts
109029
- import { join as join13 } from "path";
109030
- import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, existsSync as existsSync16 } from "fs";
109233
+ import { join as join14 } from "path";
109234
+ import { writeFileSync as writeFileSync9, mkdirSync as mkdirSync8, existsSync as existsSync17 } from "fs";
109031
109235
  function documentAsset(ctx4) {
109032
- const assetsPath = join13(ctx4.session.rootPath, "assets");
109236
+ const assetsPath = join14(ctx4.session.rootPath, "assets");
109033
109237
  return tool({
109034
109238
  description: `Document a discovered asset during attack surface analysis.
109035
109239
 
@@ -109107,21 +109311,23 @@ Each asset creates a JSON file in the assets directory for tracking and analysis
109107
109311
  };
109108
109312
  }
109109
109313
  }
109110
- if (!existsSync16(assetsPath)) {
109111
- mkdirSync7(assetsPath, { recursive: true });
109314
+ if (!existsSync17(assetsPath)) {
109315
+ mkdirSync8(assetsPath, { recursive: true });
109112
109316
  }
109113
109317
  const sanitizedName = asset.assetName.toLowerCase().replace(/[^a-z0-9-_.]/g, "_");
109114
109318
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
109115
109319
  const filename = `asset_${sanitizedName}_${timestamp}.json`;
109116
- const filepath = join13(assetsPath, filename);
109320
+ const filepath = join14(assetsPath, filename);
109321
+ const riskScore = computeBlackboxRiskScore(asset.riskLevel, asset.assetType, asset.details, asset.notes);
109117
109322
  const assetRecord = {
109118
109323
  ...asset,
109119
109324
  discoveredAt: new Date().toISOString(),
109120
109325
  sessionId: ctx4.session.id,
109121
- target: ctx4.session.targets[0]
109326
+ target: ctx4.session.targets[0],
109327
+ riskScore
109122
109328
  };
109123
109329
  try {
109124
- writeFileSync8(filepath, JSON.stringify(assetRecord, null, 2));
109330
+ writeFileSync9(filepath, JSON.stringify(assetRecord, null, 2));
109125
109331
  } catch (writeError) {
109126
109332
  if (ctx4.attackSurfaceRegistry) {
109127
109333
  await ctx4.attackSurfaceRegistry.unregister(asset);
@@ -109142,11 +109348,12 @@ Each asset creates a JSON file in the assets directory for tracking and analysis
109142
109348
  var init_documentAsset = __esm(() => {
109143
109349
  init_dist5();
109144
109350
  init_zod();
109351
+ init_blackboxRiskScoring();
109145
109352
  });
109146
109353
 
109147
109354
  // src/core/agents/offSecAgent/tools/authenticateSession.ts
109148
- import { join as join14 } from "path";
109149
- import { writeFileSync as writeFileSync9 } from "fs";
109355
+ import { join as join15 } from "path";
109356
+ import { writeFileSync as writeFileSync10 } from "fs";
109150
109357
  function authenticateSession(ctx4) {
109151
109358
  return tool({
109152
109359
  description: `Authenticate with credentials and obtain a session cookie for subsequent authenticated requests.
@@ -109234,7 +109441,7 @@ or provide username/password directly.`,
109234
109441
  const sessionCookies = Array.isArray(setCookieHeader) ? setCookieHeader : [setCookieHeader];
109235
109442
  const cookieString = sessionCookies.join("; ");
109236
109443
  const authenticated = result.status >= 200 && result.status < 400 && cookieString.length > 0;
109237
- const sessionInfoPath = join14(ctx4.session.rootPath, "session-info.json");
109444
+ const sessionInfoPath = join15(ctx4.session.rootPath, "session-info.json");
109238
109445
  const sessionInfo = {
109239
109446
  authenticated,
109240
109447
  username,
@@ -109242,7 +109449,7 @@ or provide username/password directly.`,
109242
109449
  loginUrl,
109243
109450
  timestamp: new Date().toISOString()
109244
109451
  };
109245
- writeFileSync9(sessionInfoPath, JSON.stringify(sessionInfo, null, 2));
109452
+ writeFileSync10(sessionInfoPath, JSON.stringify(sessionInfo, null, 2));
109246
109453
  return {
109247
109454
  success: authenticated,
109248
109455
  authenticated,
@@ -109407,10 +109614,10 @@ If you encounter rate-limiting errors (e.g. "Rate limit exceeded", HTTP 429, "to
109407
109614
  `;
109408
109615
 
109409
109616
  // src/core/agents/specialized/authenticationAgent/agent.ts
109410
- import { existsSync as existsSync17, readFileSync as readFileSync7 } from "fs";
109411
- import { join as join15 } from "path";
109617
+ import { existsSync as existsSync18, readFileSync as readFileSync7 } from "fs";
109618
+ import { join as join16 } from "path";
109412
109619
  function loadAuthResult(authDataPath) {
109413
- if (!existsSync17(authDataPath)) {
109620
+ if (!existsSync18(authDataPath)) {
109414
109621
  return {
109415
109622
  success: false,
109416
109623
  summary: "Authentication completed but no auth-data.json was written.",
@@ -109547,7 +109754,7 @@ var init_agent = __esm(() => {
109547
109754
  ],
109548
109755
  stopWhen: hasToolCall("complete_authentication"),
109549
109756
  resolveResult: () => {
109550
- const authDataPath = join15(session.rootPath, "auth", "auth-data.json");
109757
+ const authDataPath = join16(session.rootPath, "auth", "auth-data.json");
109551
109758
  return loadAuthResult(authDataPath);
109552
109759
  }
109553
109760
  });
@@ -109567,8 +109774,8 @@ var init_authentication = __esm(() => {
109567
109774
  });
109568
109775
 
109569
109776
  // src/core/agents/offSecAgent/tools/delegateAuth.ts
109570
- import { join as join16 } from "path";
109571
- import { writeFileSync as writeFileSync10 } from "fs";
109777
+ import { join as join17 } from "path";
109778
+ import { writeFileSync as writeFileSync11 } from "fs";
109572
109779
  function mergeAuthCredentials(sessionCreds, explicit) {
109573
109780
  const hasExplicit = explicit.username || explicit.password || explicit.apiKey || explicit.tokens;
109574
109781
  const hasSession = sessionCreds && (sessionCreds.username || sessionCreds.password || sessionCreds.apiKey || sessionCreds.tokens);
@@ -109766,7 +109973,7 @@ When to use delegate_to_auth_subagent vs authenticate_session:
109766
109973
  status: result.success ? "completed" : "failed"
109767
109974
  });
109768
109975
  if (result.success) {
109769
- const sessionInfoPath = join16(ctx4.session.rootPath, "session-info.json");
109976
+ const sessionInfoPath = join17(ctx4.session.rootPath, "session-info.json");
109770
109977
  const sessionInfo = {
109771
109978
  authenticated: true,
109772
109979
  username: username || "via_subagent",
@@ -109776,7 +109983,7 @@ When to use delegate_to_auth_subagent vs authenticate_session:
109776
109983
  timestamp: new Date().toISOString(),
109777
109984
  delegatedToSubagent: true
109778
109985
  };
109779
- writeFileSync10(sessionInfoPath, JSON.stringify(sessionInfo, null, 2));
109986
+ writeFileSync11(sessionInfoPath, JSON.stringify(sessionInfo, null, 2));
109780
109987
  }
109781
109988
  const hasHeaders = result.exportedHeaders && Object.keys(result.exportedHeaders).length > 0;
109782
109989
  const hasCookies = result.exportedCookies && result.exportedCookies.length > 0;
@@ -110186,8 +110393,8 @@ var init_validateDiscovery = __esm(() => {
110186
110393
  });
110187
110394
 
110188
110395
  // src/core/agents/offSecAgent/tools/createAttackSurfaceReport.ts
110189
- import { join as join17 } from "path";
110190
- import { writeFileSync as writeFileSync11 } from "fs";
110396
+ import { join as join18 } from "path";
110397
+ import { writeFileSync as writeFileSync12 } from "fs";
110191
110398
  function createAttackSurfaceReport(ctx4) {
110192
110399
  return tool({
110193
110400
  description: `Provide attack surface analysis results to the orchestrator agent.
@@ -110213,8 +110420,8 @@ Call this at the END of your analysis with:
110213
110420
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
110214
110421
  }),
110215
110422
  execute: async (results) => {
110216
- const resultsPath = join17(ctx4.session.rootPath, "attack-surface-results.json");
110217
- writeFileSync11(resultsPath, JSON.stringify(results, null, 2));
110423
+ const resultsPath = join18(ctx4.session.rootPath, "attack-surface-results.json");
110424
+ writeFileSync12(resultsPath, JSON.stringify(results, null, 2));
110218
110425
  return {
110219
110426
  success: true,
110220
110427
  resultsPath,
@@ -110230,8 +110437,8 @@ var init_createAttackSurfaceReport = __esm(() => {
110230
110437
  });
110231
110438
 
110232
110439
  // src/core/agents/offSecAgent/tools/completeAuthentication.ts
110233
- import { join as join18 } from "path";
110234
- import { existsSync as existsSync18, mkdirSync as mkdirSync8, writeFileSync as writeFileSync12 } from "fs";
110440
+ import { join as join19 } from "path";
110441
+ import { existsSync as existsSync19, mkdirSync as mkdirSync9, writeFileSync as writeFileSync13 } from "fs";
110235
110442
  function completeAuthentication(ctx4) {
110236
110443
  return tool({
110237
110444
  description: `Signal that the authentication process is complete.
@@ -110273,11 +110480,11 @@ This tool marks the end of the authentication flow.`,
110273
110480
  let authDataPath;
110274
110481
  if (result.success && (result.exportedCookies || result.exportedHeaders)) {
110275
110482
  try {
110276
- const authDir = join18(ctx4.session.rootPath, AUTH_DIR);
110277
- if (!existsSync18(authDir)) {
110278
- mkdirSync8(authDir, { recursive: true });
110483
+ const authDir = join19(ctx4.session.rootPath, AUTH_DIR);
110484
+ if (!existsSync19(authDir)) {
110485
+ mkdirSync9(authDir, { recursive: true });
110279
110486
  }
110280
- authDataPath = join18(authDir, AUTH_DATA_FILENAME);
110487
+ authDataPath = join19(authDir, AUTH_DATA_FILENAME);
110281
110488
  const authData = {
110282
110489
  authenticated: true,
110283
110490
  strategy: result.strategy || "unknown",
@@ -110287,7 +110494,7 @@ This tool marks the end of the authentication flow.`,
110287
110494
  target: ctx4.target || "",
110288
110495
  timestamp: new Date().toISOString()
110289
110496
  };
110290
- writeFileSync12(authDataPath, JSON.stringify(authData, null, 2));
110497
+ writeFileSync13(authDataPath, JSON.stringify(authData, null, 2));
110291
110498
  console.log(`Auth data persisted to ${authDataPath}`);
110292
110499
  } catch (err) {
110293
110500
  console.error(`Failed to persist auth data: ${err}`);
@@ -111035,8 +111242,8 @@ var init_runAttackSurface = __esm(() => {
111035
111242
  });
111036
111243
 
111037
111244
  // src/core/findings/registry.ts
111038
- import { existsSync as existsSync19, readdirSync as readdirSync3, readFileSync as readFileSync8 } from "fs";
111039
- import { join as join19 } from "path";
111245
+ import { existsSync as existsSync20, readdirSync as readdirSync3, readFileSync as readFileSync8 } from "fs";
111246
+ import { join as join20 } from "path";
111040
111247
  function extractVulnClass(title) {
111041
111248
  const t2 = title.trim();
111042
111249
  for (const [pattern, cls] of VULN_CLASS_PATTERNS) {
@@ -111108,12 +111315,12 @@ class FindingsRegistry {
111108
111315
  }
111109
111316
  static fromDirectory(findingsPath, opts) {
111110
111317
  const registry2 = new FindingsRegistry(opts);
111111
- if (!existsSync19(findingsPath))
111318
+ if (!existsSync20(findingsPath))
111112
111319
  return registry2;
111113
111320
  const files = readdirSync3(findingsPath).filter((f) => f.endsWith(".json"));
111114
111321
  for (const file2 of files) {
111115
111322
  try {
111116
- const raw = readFileSync8(join19(findingsPath, file2), "utf-8");
111323
+ const raw = readFileSync8(join20(findingsPath, file2), "utf-8");
111117
111324
  const finding = JSON.parse(raw);
111118
111325
  if (finding && typeof finding.title === "string" && typeof finding.endpoint === "string") {
111119
111326
  registry2.indexFinding(finding);
@@ -111599,8 +111806,8 @@ var init_spawnCodingAgent = __esm(() => {
111599
111806
  });
111600
111807
 
111601
111808
  // src/core/agents/offSecAgent/tools/provideComparisonResults.ts
111602
- import { join as join20 } from "path";
111603
- import { writeFileSync as writeFileSync13 } from "fs";
111809
+ import { join as join21 } from "path";
111810
+ import { writeFileSync as writeFileSync14 } from "fs";
111604
111811
  function provideComparisonResults(ctx4) {
111605
111812
  return tool({
111606
111813
  description: `Provide the final comparison results with matched, missed, and extra findings.
@@ -111646,8 +111853,8 @@ Results will be saved to: comparison-results.json in the session directory.`,
111646
111853
  recall,
111647
111854
  precision
111648
111855
  };
111649
- const resultsPath = join20(ctx4.session.rootPath, "comparison-results.json");
111650
- writeFileSync13(resultsPath, JSON.stringify(result, null, 2));
111856
+ const resultsPath = join21(ctx4.session.rootPath, "comparison-results.json");
111857
+ writeFileSync14(resultsPath, JSON.stringify(result, null, 2));
111651
111858
  return {
111652
111859
  success: true,
111653
111860
  resultsPath,
@@ -140946,8 +141153,8 @@ var require_core5 = __commonJS((exports) => {
140946
141153
  function many1(p) {
140947
141154
  return ab(p, many(p), (head, tail) => [head, ...tail]);
140948
141155
  }
140949
- function ab(pa, pb, join21) {
140950
- return (data, i) => mapOuter(pa(data, i), (ma) => mapInner(pb(data, ma.position), (vb, j2) => join21(ma.value, vb, data, i, j2)));
141156
+ function ab(pa, pb, join22) {
141157
+ return (data, i) => mapOuter(pa(data, i), (ma) => mapInner(pb(data, ma.position), (vb, j2) => join22(ma.value, vb, data, i, j2)));
140951
141158
  }
140952
141159
  function left(pa, pb) {
140953
141160
  return ab(pa, pb, (va) => va);
@@ -140955,8 +141162,8 @@ var require_core5 = __commonJS((exports) => {
140955
141162
  function right(pa, pb) {
140956
141163
  return ab(pa, pb, (va, vb) => vb);
140957
141164
  }
140958
- function abc(pa, pb, pc, join21) {
140959
- return (data, i) => mapOuter(pa(data, i), (ma) => mapOuter(pb(data, ma.position), (mb) => mapInner(pc(data, mb.position), (vc, j2) => join21(ma.value, mb.value, vc, data, i, j2))));
141165
+ function abc(pa, pb, pc, join22) {
141166
+ return (data, i) => mapOuter(pa(data, i), (ma) => mapOuter(pb(data, ma.position), (mb) => mapInner(pc(data, mb.position), (vc, j2) => join22(ma.value, mb.value, vc, data, i, j2))));
140960
141167
  }
140961
141168
  function middle(pa, pb, pc) {
140962
141169
  return abc(pa, pb, pc, (ra, rb) => rb);
@@ -176793,7 +177000,7 @@ var require_thread_stream = __commonJS((exports, module2) => {
176793
177000
  var { version: version2 } = require_package5();
176794
177001
  var { EventEmitter: EventEmitter11 } = __require("events");
176795
177002
  var { Worker: Worker2 } = __require("worker_threads");
176796
- var { join: join21 } = __require("path");
177003
+ var { join: join22 } = __require("path");
176797
177004
  var { pathToFileURL } = __require("url");
176798
177005
  var { wait } = require_wait();
176799
177006
  var {
@@ -176829,7 +177036,7 @@ var require_thread_stream = __commonJS((exports, module2) => {
176829
177036
  function createWorker(stream, opts) {
176830
177037
  const { filename, workerData } = opts;
176831
177038
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
176832
- const toExecute = bundlerOverrides["thread-stream-worker"] || join21(__dirname, "lib", "worker.js");
177039
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join22(__dirname, "lib", "worker.js");
176833
177040
  const worker = new Worker2(toExecute, {
176834
177041
  ...opts.workerOpts,
176835
177042
  trackUnmanagedFds: false,
@@ -177218,7 +177425,7 @@ var require_transport = __commonJS((exports, module2) => {
177218
177425
  var { createRequire: createRequire3 } = __require("module");
177219
177426
  var { existsSync: existsSync4 } = __require("node:fs");
177220
177427
  var getCallers = require_caller();
177221
- var { join: join21, isAbsolute: isAbsolute6, sep } = __require("node:path");
177428
+ var { join: join22, isAbsolute: isAbsolute6, sep } = __require("node:path");
177222
177429
  var { fileURLToPath: fileURLToPath2 } = __require("node:url");
177223
177430
  var sleep2 = require_atomic_sleep();
177224
177431
  var onExit = require_on_exit_leak_free();
@@ -177371,7 +177578,7 @@ var require_transport = __commonJS((exports, module2) => {
177371
177578
  throw new Error("only one of target or targets can be specified");
177372
177579
  }
177373
177580
  if (targets) {
177374
- target = bundlerOverrides["pino-worker"] || join21(__dirname, "worker.js");
177581
+ target = bundlerOverrides["pino-worker"] || join22(__dirname, "worker.js");
177375
177582
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
177376
177583
  return {
177377
177584
  ...dest,
@@ -177388,7 +177595,7 @@ var require_transport = __commonJS((exports, module2) => {
177388
177595
  });
177389
177596
  });
177390
177597
  } else if (pipeline3) {
177391
- target = bundlerOverrides["pino-worker"] || join21(__dirname, "worker.js");
177598
+ target = bundlerOverrides["pino-worker"] || join22(__dirname, "worker.js");
177392
177599
  options.pipelines = [pipeline3.map((dest) => {
177393
177600
  return {
177394
177601
  ...dest,
@@ -177411,7 +177618,7 @@ var require_transport = __commonJS((exports, module2) => {
177411
177618
  return origin;
177412
177619
  }
177413
177620
  if (origin === "pino/file") {
177414
- return join21(__dirname, "..", "file.js");
177621
+ return join22(__dirname, "..", "file.js");
177415
177622
  }
177416
177623
  let fixTarget2;
177417
177624
  for (const filePath of callers) {
@@ -178340,7 +178547,7 @@ var require_safe_stable_stringify = __commonJS((exports, module2) => {
178340
178547
  return circularValue;
178341
178548
  }
178342
178549
  let res = "";
178343
- let join21 = ",";
178550
+ let join22 = ",";
178344
178551
  const originalIndentation = indentation;
178345
178552
  if (Array.isArray(value)) {
178346
178553
  if (value.length === 0) {
@@ -178354,7 +178561,7 @@ var require_safe_stable_stringify = __commonJS((exports, module2) => {
178354
178561
  indentation += spacer;
178355
178562
  res += `
178356
178563
  ${indentation}`;
178357
- join21 = `,
178564
+ join22 = `,
178358
178565
  ${indentation}`;
178359
178566
  }
178360
178567
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -178362,13 +178569,13 @@ ${indentation}`;
178362
178569
  for (;i2 < maximumValuesToStringify - 1; i2++) {
178363
178570
  const tmp2 = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation);
178364
178571
  res += tmp2 !== undefined ? tmp2 : "null";
178365
- res += join21;
178572
+ res += join22;
178366
178573
  }
178367
178574
  const tmp = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation);
178368
178575
  res += tmp !== undefined ? tmp : "null";
178369
178576
  if (value.length - 1 > maximumBreadth) {
178370
178577
  const removedKeys = value.length - maximumBreadth - 1;
178371
- res += `${join21}"... ${getItemCount(removedKeys)} not stringified"`;
178578
+ res += `${join22}"... ${getItemCount(removedKeys)} not stringified"`;
178372
178579
  }
178373
178580
  if (spacer !== "") {
178374
178581
  res += `
@@ -178389,7 +178596,7 @@ ${originalIndentation}`;
178389
178596
  let separator = "";
178390
178597
  if (spacer !== "") {
178391
178598
  indentation += spacer;
178392
- join21 = `,
178599
+ join22 = `,
178393
178600
  ${indentation}`;
178394
178601
  whitespace = " ";
178395
178602
  }
@@ -178403,13 +178610,13 @@ ${indentation}`;
178403
178610
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
178404
178611
  if (tmp !== undefined) {
178405
178612
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
178406
- separator = join21;
178613
+ separator = join22;
178407
178614
  }
178408
178615
  }
178409
178616
  if (keyLength > maximumBreadth) {
178410
178617
  const removedKeys = keyLength - maximumBreadth;
178411
178618
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
178412
- separator = join21;
178619
+ separator = join22;
178413
178620
  }
178414
178621
  if (spacer !== "" && separator.length > 1) {
178415
178622
  res = `
@@ -178449,7 +178656,7 @@ ${originalIndentation}`;
178449
178656
  }
178450
178657
  const originalIndentation = indentation;
178451
178658
  let res = "";
178452
- let join21 = ",";
178659
+ let join22 = ",";
178453
178660
  if (Array.isArray(value)) {
178454
178661
  if (value.length === 0) {
178455
178662
  return "[]";
@@ -178462,7 +178669,7 @@ ${originalIndentation}`;
178462
178669
  indentation += spacer;
178463
178670
  res += `
178464
178671
  ${indentation}`;
178465
- join21 = `,
178672
+ join22 = `,
178466
178673
  ${indentation}`;
178467
178674
  }
178468
178675
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -178470,13 +178677,13 @@ ${indentation}`;
178470
178677
  for (;i2 < maximumValuesToStringify - 1; i2++) {
178471
178678
  const tmp2 = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation);
178472
178679
  res += tmp2 !== undefined ? tmp2 : "null";
178473
- res += join21;
178680
+ res += join22;
178474
178681
  }
178475
178682
  const tmp = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation);
178476
178683
  res += tmp !== undefined ? tmp : "null";
178477
178684
  if (value.length - 1 > maximumBreadth) {
178478
178685
  const removedKeys = value.length - maximumBreadth - 1;
178479
- res += `${join21}"... ${getItemCount(removedKeys)} not stringified"`;
178686
+ res += `${join22}"... ${getItemCount(removedKeys)} not stringified"`;
178480
178687
  }
178481
178688
  if (spacer !== "") {
178482
178689
  res += `
@@ -178489,7 +178696,7 @@ ${originalIndentation}`;
178489
178696
  let whitespace = "";
178490
178697
  if (spacer !== "") {
178491
178698
  indentation += spacer;
178492
- join21 = `,
178699
+ join22 = `,
178493
178700
  ${indentation}`;
178494
178701
  whitespace = " ";
178495
178702
  }
@@ -178498,7 +178705,7 @@ ${indentation}`;
178498
178705
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
178499
178706
  if (tmp !== undefined) {
178500
178707
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
178501
- separator = join21;
178708
+ separator = join22;
178502
178709
  }
178503
178710
  }
178504
178711
  if (spacer !== "" && separator.length > 1) {
@@ -178555,20 +178762,20 @@ ${originalIndentation}`;
178555
178762
  indentation += spacer;
178556
178763
  let res2 = `
178557
178764
  ${indentation}`;
178558
- const join22 = `,
178765
+ const join23 = `,
178559
178766
  ${indentation}`;
178560
178767
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
178561
178768
  let i2 = 0;
178562
178769
  for (;i2 < maximumValuesToStringify - 1; i2++) {
178563
178770
  const tmp2 = stringifyIndent(String(i2), value[i2], stack, spacer, indentation);
178564
178771
  res2 += tmp2 !== undefined ? tmp2 : "null";
178565
- res2 += join22;
178772
+ res2 += join23;
178566
178773
  }
178567
178774
  const tmp = stringifyIndent(String(i2), value[i2], stack, spacer, indentation);
178568
178775
  res2 += tmp !== undefined ? tmp : "null";
178569
178776
  if (value.length - 1 > maximumBreadth) {
178570
178777
  const removedKeys = value.length - maximumBreadth - 1;
178571
- res2 += `${join22}"... ${getItemCount(removedKeys)} not stringified"`;
178778
+ res2 += `${join23}"... ${getItemCount(removedKeys)} not stringified"`;
178572
178779
  }
178573
178780
  res2 += `
178574
178781
  ${originalIndentation}`;
@@ -178584,16 +178791,16 @@ ${originalIndentation}`;
178584
178791
  return '"[Object]"';
178585
178792
  }
178586
178793
  indentation += spacer;
178587
- const join21 = `,
178794
+ const join22 = `,
178588
178795
  ${indentation}`;
178589
178796
  let res = "";
178590
178797
  let separator = "";
178591
178798
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
178592
178799
  if (isTypedArrayWithEntries(value)) {
178593
- res += stringifyTypedArray(value, join21, maximumBreadth);
178800
+ res += stringifyTypedArray(value, join22, maximumBreadth);
178594
178801
  keys = keys.slice(value.length);
178595
178802
  maximumPropertiesToStringify -= value.length;
178596
- separator = join21;
178803
+ separator = join22;
178597
178804
  }
178598
178805
  if (deterministic) {
178599
178806
  keys = sort(keys, comparator);
@@ -178604,13 +178811,13 @@ ${indentation}`;
178604
178811
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
178605
178812
  if (tmp !== undefined) {
178606
178813
  res += `${separator}${strEscape(key2)}: ${tmp}`;
178607
- separator = join21;
178814
+ separator = join22;
178608
178815
  }
178609
178816
  }
178610
178817
  if (keyLength > maximumBreadth) {
178611
178818
  const removedKeys = keyLength - maximumBreadth;
178612
178819
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
178613
- separator = join21;
178820
+ separator = join22;
178614
178821
  }
178615
178822
  if (separator !== "") {
178616
178823
  res = `
@@ -193871,8 +194078,8 @@ var init_operator = __esm(() => {
193871
194078
  });
193872
194079
 
193873
194080
  // src/core/agents/offSecAgent/offensiveSecurityAgent.ts
193874
- import { join as join21 } from "path";
193875
- import { writeFileSync as writeFileSync14, mkdirSync as mkdirSync9, existsSync as existsSync20 } from "fs";
194081
+ import { join as join22 } from "path";
194082
+ import { writeFileSync as writeFileSync15, mkdirSync as mkdirSync10, existsSync as existsSync21 } from "fs";
193876
194083
  function wrapToolsWithApprovalGate(tools, gate) {
193877
194084
  const wrapped = {};
193878
194085
  for (const [name26, coreTool] of Object.entries(tools)) {
@@ -193998,16 +194205,18 @@ var init_offensiveSecurityAgent = __esm(() => {
193998
194205
  const emailToolSet = new Set(EMAIL_TOOL_NAMES);
193999
194206
  const activeTools = hasEmail ? input.activeTools : input.activeTools.filter((t3) => !emailToolSet.has(t3));
194000
194207
  const messagesDir = input.messagesDir ?? input.session.rootPath;
194001
- if (!existsSync20(messagesDir)) {
194002
- mkdirSync9(messagesDir, { recursive: true });
194208
+ if (!existsSync21(messagesDir)) {
194209
+ mkdirSync10(messagesDir, { recursive: true });
194003
194210
  }
194004
- const messagesPath = join21(messagesDir, "messages.json");
194005
- const initialMessages = input.messages ? [...input.messages] : [
194006
- {
194007
- role: "user",
194008
- content: [{ type: "text", text: input.prompt }]
194009
- }
194010
- ];
194211
+ const messagesPath = join22(messagesDir, "messages.json");
194212
+ const initialMessagesRef = {
194213
+ current: input.messages ? [...input.messages] : [
194214
+ {
194215
+ role: "user",
194216
+ content: [{ type: "text", text: input.prompt }]
194217
+ }
194218
+ ]
194219
+ };
194011
194220
  this.streamResult = streamResponse({
194012
194221
  prompt: input.prompt,
194013
194222
  system: (input.system ?? BASE_SYSTEM_PROMPT) + buildSessionWorkspaceSection(input.session),
@@ -194019,11 +194228,17 @@ var init_offensiveSecurityAgent = __esm(() => {
194019
194228
  toolChoice: "auto",
194020
194229
  onStepFinish: (event) => {
194021
194230
  try {
194022
- const allMessages = [...initialMessages, ...event.response.messages];
194023
- writeFileSync14(messagesPath, JSON.stringify(allMessages, null, 2));
194231
+ const allMessages = [
194232
+ ...initialMessagesRef.current,
194233
+ ...event.response.messages
194234
+ ];
194235
+ writeFileSync15(messagesPath, JSON.stringify(allMessages, null, 2));
194024
194236
  } catch {}
194025
194237
  input.onStepFinish?.(event);
194026
194238
  },
194239
+ onSummarized: () => {
194240
+ initialMessagesRef.current = [];
194241
+ },
194027
194242
  onFinish: input.onFinish,
194028
194243
  abortSignal: input.abortSignal,
194029
194244
  authConfig: input.authConfig,
@@ -194106,8 +194321,8 @@ var exports_blackboxAgent = {};
194106
194321
  __export(exports_blackboxAgent, {
194107
194322
  BlackboxAttackSurfaceAgent: () => BlackboxAttackSurfaceAgent
194108
194323
  });
194109
- import { join as join22 } from "path";
194110
- import { existsSync as existsSync21 } from "fs";
194324
+ import { join as join23 } from "path";
194325
+ import { existsSync as existsSync22 } from "fs";
194111
194326
  function buildPrompt3(target, session) {
194112
194327
  const scopeConstraints = session.config?.scopeConstraints;
194113
194328
  const authenticationInstructions = session.config?.authenticationInstructions;
@@ -194158,7 +194373,7 @@ Note any login pages you find as assets and flag them for pentest agents.`;
194158
194373
  return `TARGET: ${target}
194159
194374
 
194160
194375
  Session: ${session.id}
194161
- Assets directory: ${join22(session.rootPath, "assets")}
194376
+ Assets directory: ${join23(session.rootPath, "assets")}
194162
194377
 
194163
194378
  ${authBlock}
194164
194379
 
@@ -194186,8 +194401,8 @@ var init_blackboxAgent = __esm(() => {
194186
194401
  attackSurfaceRegistry
194187
194402
  } = opts;
194188
194403
  const target = opts.target ?? opts.cwd;
194189
- const resultsPath = join22(session.rootPath, "attack-surface-results.json");
194190
- const assetsPath = join22(session.rootPath, "assets");
194404
+ const resultsPath = join23(session.rootPath, "attack-surface-results.json");
194405
+ const assetsPath = join23(session.rootPath, "assets");
194191
194406
  super({
194192
194407
  system: detectOSAndEnhancePrompt(SYSTEM),
194193
194408
  prompt: buildPrompt3(target, session),
@@ -194223,7 +194438,7 @@ var init_blackboxAgent = __esm(() => {
194223
194438
  resolveResult: () => {
194224
194439
  let results = null;
194225
194440
  let targets = [];
194226
- if (existsSync21(resultsPath)) {
194441
+ if (existsSync22(resultsPath)) {
194227
194442
  try {
194228
194443
  results = loadAttackSurfaceResults2(resultsPath);
194229
194444
  targets = results.targets || [];
@@ -194237,8 +194452,8 @@ var init_blackboxAgent = __esm(() => {
194237
194452
  });
194238
194453
 
194239
194454
  // src/core/agents/specialized/pentest/agent.ts
194240
- import { existsSync as existsSync22, readdirSync as readdirSync4, readFileSync as readFileSync9 } from "fs";
194241
- import { join as join23 } from "path";
194455
+ import { existsSync as existsSync23, readdirSync as readdirSync4, readFileSync as readFileSync9 } from "fs";
194456
+ import { join as join24 } from "path";
194242
194457
  function buildSystemPrompt(session) {
194243
194458
  return session.config?.exfilMode ? PENTEST_SYSTEM_PROMPT_EXFIL : PENTEST_SYSTEM_PROMPT_BASE;
194244
194459
  }
@@ -194249,8 +194464,8 @@ function buildPrompt4(target, objectives, session, findingsRegistry) {
194249
194464
  const objectiveList = objectives.map((o, i2) => `${i2 + 1}. ${o}`).join(`
194250
194465
  `);
194251
194466
  let authSection = "";
194252
- const authDataPath = join23(sessionRootPath, "auth", "auth-data.json");
194253
- if (existsSync22(authDataPath)) {
194467
+ const authDataPath = join24(sessionRootPath, "auth", "auth-data.json");
194468
+ if (existsSync23(authDataPath)) {
194254
194469
  try {
194255
194470
  const raw = readFileSync9(authDataPath, "utf-8");
194256
194471
  const authData = JSON.parse(raw);
@@ -194327,12 +194542,12 @@ ${outcomeSection}
194327
194542
  ${instructions}`;
194328
194543
  }
194329
194544
  function loadFindings(findingsPath) {
194330
- if (!existsSync22(findingsPath)) {
194545
+ if (!existsSync23(findingsPath)) {
194331
194546
  return [];
194332
194547
  }
194333
194548
  return readdirSync4(findingsPath).filter((f3) => f3.endsWith(".json")).map((f3) => {
194334
194549
  try {
194335
- const content = readFileSync9(join23(findingsPath, f3), "utf-8");
194550
+ const content = readFileSync9(join24(findingsPath, f3), "utf-8");
194336
194551
  return JSON.parse(content);
194337
194552
  } catch {
194338
194553
  return null;
@@ -194487,8 +194702,8 @@ var init_agent4 = __esm(() => {
194487
194702
  });
194488
194703
 
194489
194704
  // src/core/session/execution-metrics.ts
194490
- import { existsSync as existsSync23, readFileSync as readFileSync10, writeFileSync as writeFileSync15 } from "fs";
194491
- import { join as join24 } from "path";
194705
+ import { existsSync as existsSync24, readFileSync as readFileSync10, writeFileSync as writeFileSync16 } from "fs";
194706
+ import { join as join25 } from "path";
194492
194707
  function toNonNegativeInteger(value) {
194493
194708
  const n = Number(value);
194494
194709
  return Number.isFinite(n) && n > 0 ? Math.floor(n) : 0;
@@ -194505,14 +194720,14 @@ function normalizeTokenUsage(value) {
194505
194720
  };
194506
194721
  }
194507
194722
  function metricsPath(sessionRootPath) {
194508
- return join24(sessionRootPath, EXECUTION_METRICS_FILENAME);
194723
+ return join25(sessionRootPath, EXECUTION_METRICS_FILENAME);
194509
194724
  }
194510
194725
  function sessionJsonPath(sessionRootPath) {
194511
- return join24(sessionRootPath, "session.json");
194726
+ return join25(sessionRootPath, "session.json");
194512
194727
  }
194513
194728
  function readExecutionMetrics(sessionRootPath) {
194514
194729
  const path6 = metricsPath(sessionRootPath);
194515
- if (!existsSync23(path6))
194730
+ if (!existsSync24(path6))
194516
194731
  return null;
194517
194732
  try {
194518
194733
  const parsed = JSON.parse(readFileSync10(path6, "utf-8"));
@@ -194527,13 +194742,13 @@ function readExecutionMetrics(sessionRootPath) {
194527
194742
  }
194528
194743
  function writeSessionJsonTokenTotals(sessionRootPath, tokenUsage) {
194529
194744
  const path6 = sessionJsonPath(sessionRootPath);
194530
- if (!existsSync23(path6))
194745
+ if (!existsSync24(path6))
194531
194746
  return;
194532
194747
  try {
194533
194748
  const parsed = JSON.parse(readFileSync10(path6, "utf-8"));
194534
194749
  parsed.tokensIn = tokenUsage.inputTokens;
194535
194750
  parsed.tokensOut = tokenUsage.outputTokens;
194536
- writeFileSync15(path6, JSON.stringify(parsed, null, 2));
194751
+ writeFileSync16(path6, JSON.stringify(parsed, null, 2));
194537
194752
  } catch {}
194538
194753
  }
194539
194754
  function writeExecutionMetrics(input) {
@@ -194548,7 +194763,7 @@ function writeExecutionMetrics(input) {
194548
194763
  runtime: input.runtime ?? existing?.runtime,
194549
194764
  updatedAt: new Date().toISOString()
194550
194765
  };
194551
- writeFileSync15(metricsPath(input.sessionRootPath), JSON.stringify(next, null, 2), "utf-8");
194766
+ writeFileSync16(metricsPath(input.sessionRootPath), JSON.stringify(next, null, 2), "utf-8");
194552
194767
  writeSessionJsonTokenTotals(input.sessionRootPath, next.tokenUsage);
194553
194768
  return next;
194554
194769
  }
@@ -194611,8 +194826,8 @@ async function scoreEndpoints(input) {
194611
194826
  } = input;
194612
194827
  const results = new Map;
194613
194828
  const scored = await runWithBoundedConcurrency(endpoints, concurrency, async (ep) => {
194614
- const key = `${ep.file}:${ep.path}`;
194615
- const subagentId = `risk-score-${ep.appName}-${ep.path}`;
194829
+ const key = `${ep.method}:${ep.file}:${ep.path}`;
194830
+ const subagentId = `risk-score-${ep.appName}-${ep.method}-${ep.path}`;
194616
194831
  callbacks?.subagentCallbacks?.onSubagentSpawn?.({
194617
194832
  subagentId,
194618
194833
  input: { app: ep.appName, path: ep.path },
@@ -194922,7 +195137,7 @@ async function runWhiteboxAttackSurfaceWorkflow(input) {
194922
195137
  }
194923
195138
  }
194924
195139
  function attachRiskScore(ep) {
194925
- const key = `${ep.file}:${ep.path}`;
195140
+ const key = `${ep.method}:${ep.file}:${ep.path}`;
194926
195141
  const score = riskScores.get(key);
194927
195142
  return score ? { ...ep, riskScore: score } : ep;
194928
195143
  }
@@ -195143,8 +195358,8 @@ __export(exports_pentest, {
195143
195358
  runPentestSwarm: () => runPentestSwarm,
195144
195359
  DEFAULT_CONCURRENCY: () => DEFAULT_CONCURRENCY4
195145
195360
  });
195146
- import { existsSync as existsSync24, readdirSync as readdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync16 } from "fs";
195147
- import { join as join25 } from "path";
195361
+ import { existsSync as existsSync25, readdirSync as readdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync17 } from "fs";
195362
+ import { join as join26 } from "path";
195148
195363
  function addUsageTotals(totals, usage) {
195149
195364
  if (!usage)
195150
195365
  return;
@@ -195288,10 +195503,10 @@ async function runPentestWorkflow(input) {
195288
195503
  sessionId: session.id,
195289
195504
  mode
195290
195505
  });
195291
- const mdPath2 = join25(session.rootPath, REPORT_FILENAME_MD);
195292
- const jsonPath2 = join25(session.rootPath, REPORT_FILENAME_JSON);
195293
- writeFileSync16(mdPath2, renderMarkdown(report2));
195294
- writeFileSync16(jsonPath2, renderJson(report2));
195506
+ const mdPath2 = join26(session.rootPath, REPORT_FILENAME_MD);
195507
+ const jsonPath2 = join26(session.rootPath, REPORT_FILENAME_JSON);
195508
+ writeFileSync17(mdPath2, renderMarkdown(report2));
195509
+ writeFileSync17(jsonPath2, renderJson(report2));
195295
195510
  return {
195296
195511
  findings: [],
195297
195512
  findingsPath: session.findingsPath,
@@ -195321,10 +195536,10 @@ async function runPentestWorkflow(input) {
195321
195536
  sessionId: session.id,
195322
195537
  mode
195323
195538
  });
195324
- const mdPath = join25(session.rootPath, REPORT_FILENAME_MD);
195325
- const jsonPath = join25(session.rootPath, REPORT_FILENAME_JSON);
195326
- writeFileSync16(mdPath, renderMarkdown(report));
195327
- writeFileSync16(jsonPath, renderJson(report));
195539
+ const mdPath = join26(session.rootPath, REPORT_FILENAME_MD);
195540
+ const jsonPath = join26(session.rootPath, REPORT_FILENAME_JSON);
195541
+ writeFileSync17(mdPath, renderMarkdown(report));
195542
+ writeFileSync17(jsonPath, renderJson(report));
195328
195543
  return {
195329
195544
  findings,
195330
195545
  findingsPath: session.findingsPath,
@@ -195405,12 +195620,12 @@ async function runBlackboxPhase(opts) {
195405
195620
  }
195406
195621
  }
195407
195622
  function loadFindings2(findingsPath) {
195408
- if (!existsSync24(findingsPath)) {
195623
+ if (!existsSync25(findingsPath)) {
195409
195624
  return [];
195410
195625
  }
195411
195626
  return readdirSync5(findingsPath).filter((f3) => f3.endsWith(".json")).map((f3) => {
195412
195627
  try {
195413
- const content = readFileSync11(join25(findingsPath, f3), "utf-8");
195628
+ const content = readFileSync11(join26(findingsPath, f3), "utf-8");
195414
195629
  return JSON.parse(content);
195415
195630
  } catch {
195416
195631
  return null;
@@ -279864,8 +280079,8 @@ function KeybindingProvider({
279864
280079
  // src/tui/components/pentest/pentest.tsx
279865
280080
  var import_react74 = __toESM(require_react(), 1);
279866
280081
  init_report();
279867
- import { existsSync as existsSync25, readdirSync as readdirSync6, readFileSync as readFileSync12 } from "fs";
279868
- import { join as join26 } from "path";
280082
+ import { existsSync as existsSync26, readdirSync as readdirSync6, readFileSync as readFileSync12 } from "fs";
280083
+ import { join as join27 } from "path";
279869
280084
  init_session();
279870
280085
 
279871
280086
  // src/core/session/loader.ts
@@ -283127,16 +283342,16 @@ function Pentest({
283127
283342
  import_react74.useEffect(() => {
283128
283343
  if (!session)
283129
283344
  return;
283130
- const assetsPath = join26(session.rootPath, "assets");
283345
+ const assetsPath = join27(session.rootPath, "assets");
283131
283346
  function readAssets() {
283132
- if (!existsSync25(assetsPath))
283347
+ if (!existsSync26(assetsPath))
283133
283348
  return;
283134
283349
  try {
283135
283350
  const files = readdirSync6(assetsPath).filter((f3) => f3.endsWith(".json"));
283136
283351
  const loaded = [];
283137
283352
  for (const file2 of files) {
283138
283353
  try {
283139
- const content = readFileSync12(join26(assetsPath, file2), "utf-8");
283354
+ const content = readFileSync12(join27(assetsPath, file2), "utf-8");
283140
283355
  loaded.push(JSON.parse(content));
283141
283356
  } catch {}
283142
283357
  }
@@ -285350,8 +285565,8 @@ function navigateDown(selectedIndex, queueLength) {
285350
285565
  }
285351
285566
 
285352
285567
  // src/tui/components/operator-dashboard/index.tsx
285353
- import { existsSync as existsSync26, readFileSync as readFileSync13 } from "fs";
285354
- import { join as join27 } from "path";
285568
+ import { existsSync as existsSync27, readFileSync as readFileSync13 } from "fs";
285569
+ import { join as join28 } from "path";
285355
285570
  function OperatorDashboard({
285356
285571
  sessionId,
285357
285572
  initialMessage,
@@ -285468,7 +285683,7 @@ function OperatorDashboard({
285468
285683
  });
285469
285684
  if (Array.isArray(savedState.messages) && savedState.messages.length > 0) {
285470
285685
  const modelMsgs = savedState.messages;
285471
- conversationRef.current = modelMsgs;
285686
+ conversationRef.current = sessions.getResumeMessages(modelMsgs);
285472
285687
  const uiMsgs = convertModelMessagesToUI(modelMsgs);
285473
285688
  setMessages(uiMsgs.map((m4) => ({
285474
285689
  role: m4.role,
@@ -285904,15 +286119,28 @@ function OperatorDashboard({
285904
286119
  setSession(created);
285905
286120
  setSessionCwd(created.rootPath);
285906
286121
  }
285907
- try {
285908
- const response = await agentResult.streamResult.response;
285909
- if (gen === generationRef.current && response.messages) {
285910
- conversationRef.current = [
285911
- ...nextMessages,
285912
- ...response.messages
285913
- ];
286122
+ if (gen === generationRef.current) {
286123
+ try {
286124
+ const rootPath = agentResult.session.rootPath;
286125
+ const mp = join28(rootPath, "messages.json");
286126
+ if (existsSync27(mp)) {
286127
+ const raw = JSON.parse(readFileSync13(mp, "utf-8"));
286128
+ if (Array.isArray(raw) && raw.length > 0) {
286129
+ conversationRef.current = sessions.getResumeMessages(raw);
286130
+ }
286131
+ }
286132
+ } catch {
286133
+ try {
286134
+ const response = await agentResult.streamResult.response;
286135
+ if (response.messages) {
286136
+ conversationRef.current = [
286137
+ ...nextMessages,
286138
+ ...response.messages
286139
+ ];
286140
+ }
286141
+ } catch {}
285914
286142
  }
285915
- } catch {}
286143
+ }
285916
286144
  } catch (e2) {
285917
286145
  if (gen !== generationRef.current)
285918
286146
  return;
@@ -286103,11 +286331,11 @@ function OperatorDashboard({
286103
286331
  approvalGateRef.current.denyAll();
286104
286332
  if (session) {
286105
286333
  try {
286106
- const messagesPath = join27(session.rootPath, "messages.json");
286107
- if (existsSync26(messagesPath)) {
286334
+ const messagesPath = join28(session.rootPath, "messages.json");
286335
+ if (existsSync27(messagesPath)) {
286108
286336
  const raw = JSON.parse(readFileSync13(messagesPath, "utf-8"));
286109
286337
  if (Array.isArray(raw) && raw.length > 0) {
286110
- conversationRef.current = raw;
286338
+ conversationRef.current = sessions.getResumeMessages(raw);
286111
286339
  }
286112
286340
  }
286113
286341
  } catch {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pensar/apex",
3
- "version": "0.0.88-canary.2b93505f",
3
+ "version": "0.0.88",
4
4
  "description": "AI-powered penetration testing CLI tool with terminal UI",
5
5
  "module": "src/tui/index.tsx",
6
6
  "main": "build/index.js",