@pensar/apex 0.0.65 → 0.0.66

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 (3) hide show
  1. package/README.md +1 -1
  2. package/build/index.js +654 -274
  3. package/package.json +1 -1
package/build/index.js CHANGED
@@ -49473,19 +49473,19 @@ var require_token_io = __commonJS((exports, module2) => {
49473
49473
  getUserDataDir: () => getUserDataDir
49474
49474
  });
49475
49475
  module2.exports = __toCommonJS2(token_io_exports);
49476
- var import_path10 = __toESM2(__require("path"));
49477
- var import_fs9 = __toESM2(__require("fs"));
49478
- var import_os6 = __toESM2(__require("os"));
49476
+ var import_path11 = __toESM2(__require("path"));
49477
+ var import_fs10 = __toESM2(__require("fs"));
49478
+ var import_os7 = __toESM2(__require("os"));
49479
49479
  var import_token_error = require_token_error();
49480
49480
  function findRootDir() {
49481
49481
  try {
49482
49482
  let dir = process.cwd();
49483
- while (dir !== import_path10.default.dirname(dir)) {
49484
- const pkgPath = import_path10.default.join(dir, ".vercel");
49485
- if (import_fs9.default.existsSync(pkgPath)) {
49483
+ while (dir !== import_path11.default.dirname(dir)) {
49484
+ const pkgPath = import_path11.default.join(dir, ".vercel");
49485
+ if (import_fs10.default.existsSync(pkgPath)) {
49486
49486
  return dir;
49487
49487
  }
49488
- dir = import_path10.default.dirname(dir);
49488
+ dir = import_path11.default.dirname(dir);
49489
49489
  }
49490
49490
  } catch (e) {
49491
49491
  throw new import_token_error.VercelOidcTokenError("Token refresh only supported in node server environments");
@@ -49496,11 +49496,11 @@ var require_token_io = __commonJS((exports, module2) => {
49496
49496
  if (process.env.XDG_DATA_HOME) {
49497
49497
  return process.env.XDG_DATA_HOME;
49498
49498
  }
49499
- switch (import_os6.default.platform()) {
49499
+ switch (import_os7.default.platform()) {
49500
49500
  case "darwin":
49501
- return import_path10.default.join(import_os6.default.homedir(), "Library/Application Support");
49501
+ return import_path11.default.join(import_os7.default.homedir(), "Library/Application Support");
49502
49502
  case "linux":
49503
- return import_path10.default.join(import_os6.default.homedir(), ".local/share");
49503
+ return import_path11.default.join(import_os7.default.homedir(), ".local/share");
49504
49504
  case "win32":
49505
49505
  if (process.env.LOCALAPPDATA) {
49506
49506
  return process.env.LOCALAPPDATA;
@@ -49609,10 +49609,10 @@ var require_oauth = __commonJS((exports, module2) => {
49609
49609
  refreshTokenRequest: () => refreshTokenRequest
49610
49610
  });
49611
49611
  module2.exports = __toCommonJS2(oauth_exports);
49612
- var import_os6 = __require("os");
49612
+ var import_os7 = __require("os");
49613
49613
  var VERCEL_ISSUER = "https://vercel.com";
49614
49614
  var VERCEL_CLI_CLIENT_ID = "cl_HYyOPBNtFMfHhaUn9L4QPfTZz6TP47bp";
49615
- var userAgent = `@vercel/oidc node-${process.version} ${(0, import_os6.platform)()} (${(0, import_os6.arch)()}) ${(0, import_os6.hostname)()}`;
49615
+ var userAgent = `@vercel/oidc node-${process.version} ${(0, import_os7.platform)()} (${(0, import_os7.arch)()}) ${(0, import_os7.hostname)()}`;
49616
49616
  var _tokenEndpoint = null;
49617
49617
  async function getTokenEndpoint() {
49618
49618
  if (_tokenEndpoint) {
@@ -61019,11 +61019,11 @@ Submit the final structured report. Call this ONCE at the very end with complete
61019
61019
  If resuming from a previous run, review the assets already in the session assets folder and continue where you left off.`;
61020
61020
 
61021
61021
  // src/core/agents/specialized/utils.ts
61022
- import { readFileSync as readFileSync2, existsSync as existsSync8 } from "fs";
61022
+ import { readFileSync as readFileSync3, existsSync as existsSync9 } from "fs";
61023
61023
  import { execSync } from "child_process";
61024
61024
  function readOsRelease() {
61025
61025
  try {
61026
- const content = readFileSync2("/etc/os-release", "utf8");
61026
+ const content = readFileSync3("/etc/os-release", "utf8");
61027
61027
  const lines = content.split(/\r?\n/);
61028
61028
  const map2 = {};
61029
61029
  for (const line of lines) {
@@ -61044,11 +61044,11 @@ function readOsRelease() {
61044
61044
  }
61045
61045
  function detectDocker() {
61046
61046
  try {
61047
- if (existsSync8("/.dockerenv"))
61047
+ if (existsSync9("/.dockerenv"))
61048
61048
  return true;
61049
61049
  } catch {}
61050
61050
  try {
61051
- const cgroup = readFileSync2("/proc/1/cgroup", "utf8");
61051
+ const cgroup = readFileSync3("/proc/1/cgroup", "utf8");
61052
61052
  if (/docker|containerd|kubepods/i.test(cgroup))
61053
61053
  return true;
61054
61054
  } catch {}
@@ -61128,9 +61128,9 @@ ${prompt}`;
61128
61128
  var init_utils = () => {};
61129
61129
 
61130
61130
  // src/core/agents/specialized/attackSurface/types.ts
61131
- import { readFileSync as readFileSync3 } from "fs";
61131
+ import { readFileSync as readFileSync4 } from "fs";
61132
61132
  function loadAttackSurfaceResults(resultsPath) {
61133
- const data = readFileSync3(resultsPath, "utf-8");
61133
+ const data = readFileSync4(resultsPath, "utf-8");
61134
61134
  return JSON.parse(data);
61135
61135
  }
61136
61136
  var init_types2 = () => {};
@@ -104156,7 +104156,7 @@ var init_stdio2 = __esm(() => {
104156
104156
  });
104157
104157
 
104158
104158
  // src/core/agents/offSecAgent/tools/playwrightMcp.ts
104159
- import { writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync9 } from "fs";
104159
+ import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync10 } from "fs";
104160
104160
  import { join as join3, dirname as dirname2 } from "path";
104161
104161
  async function initializeMcpClient() {
104162
104162
  if (mcpClient) {
@@ -104239,8 +104239,8 @@ function createBrowserTools(targetUrl, evidenceDir, mode = "pentest", logger, ab
104239
104239
  abortSignal?.addEventListener("abort", () => {
104240
104240
  disconnectMcpClient().catch(() => {});
104241
104241
  });
104242
- if (!existsSync9(evidenceDir)) {
104243
- mkdirSync(evidenceDir, { recursive: true });
104242
+ if (!existsSync10(evidenceDir)) {
104243
+ mkdirSync2(evidenceDir, { recursive: true });
104244
104244
  }
104245
104245
  const descriptions = mode === "pentest" ? PENTEST_DESCRIPTIONS : mode === "auth" ? AUTH_DESCRIPTIONS : OPERATOR_DESCRIPTIONS;
104246
104246
  const browser_navigate = tool2({
@@ -104280,10 +104280,10 @@ Target base URL: ${targetUrl}`,
104280
104280
  const screenshotFilename = `${filename}_${timestamp}.png`;
104281
104281
  const screenshotPath = join3(evidenceDir, screenshotFilename);
104282
104282
  const dir = dirname2(screenshotPath);
104283
- if (!existsSync9(dir)) {
104284
- mkdirSync(dir, { recursive: true });
104283
+ if (!existsSync10(dir)) {
104284
+ mkdirSync2(dir, { recursive: true });
104285
104285
  }
104286
- writeFileSync2(screenshotPath, Buffer.from(result.data, "base64"));
104286
+ writeFileSync3(screenshotPath, Buffer.from(result.data, "base64"));
104287
104287
  return {
104288
104288
  success: true,
104289
104289
  path: screenshotPath,
@@ -104725,6 +104725,32 @@ IMPORTANT: Always analyze results and adjust your approach based on findings.`,
104725
104725
  command
104726
104726
  };
104727
104727
  }
104728
+ if (ctx4.sandbox) {
104729
+ try {
104730
+ const ssmTimeout = Math.max(Math.ceil(timeout / 1000), 30);
104731
+ const result = await ctx4.sandbox.execute(command, {
104732
+ timeout: ssmTimeout
104733
+ });
104734
+ return {
104735
+ success: result.success,
104736
+ error: !result.success ? result.stderr || "Command failed" : "",
104737
+ stdout: result.stdout.length > 50000 ? `${result.stdout.substring(0, 50000)}...
104738
+
104739
+ (truncated) call the command again with grep / tail to paginate` : result.stdout || "(no output)",
104740
+ stderr: result.stderr || "",
104741
+ command
104742
+ };
104743
+ } catch (error41) {
104744
+ const msg = error41 instanceof Error ? error41.message : String(error41);
104745
+ return {
104746
+ success: false,
104747
+ error: msg,
104748
+ stdout: "",
104749
+ stderr: msg,
104750
+ command
104751
+ };
104752
+ }
104753
+ }
104728
104754
  return new Promise((resolve4) => {
104729
104755
  const shellCmd = process.platform === "win32" ? "cmd" : "bash";
104730
104756
  const shellArgs = process.platform === "win32" ? ["/c", command] : ["-lc", command];
@@ -104823,6 +104849,16 @@ COMMON TESTING PATTERNS:
104823
104849
  followRedirects,
104824
104850
  timeout
104825
104851
  }) => {
104852
+ if (ctx4.sandbox) {
104853
+ return executeSandboxHttpRequest(ctx4, {
104854
+ url: url2,
104855
+ method,
104856
+ headers,
104857
+ body,
104858
+ followRedirects,
104859
+ timeout
104860
+ });
104861
+ }
104826
104862
  let timeoutId;
104827
104863
  try {
104828
104864
  if (ctx4.abortSignal?.aborted) {
@@ -104890,6 +104926,82 @@ COMMON TESTING PATTERNS:
104890
104926
  }
104891
104927
  });
104892
104928
  }
104929
+ async function executeSandboxHttpRequest(ctx4, opts) {
104930
+ const { url: url2, method, headers, body, followRedirects, timeout } = opts;
104931
+ try {
104932
+ let curlCommand = `curl -i -X ${method}`;
104933
+ if (headers) {
104934
+ for (const [key, value] of Object.entries(headers)) {
104935
+ curlCommand += ` -H "${key}: ${value}"`;
104936
+ }
104937
+ }
104938
+ if (body && ["POST", "PUT", "PATCH"].includes(method)) {
104939
+ const escapedBody = body.replace(/"/g, "\\\"").replace(/\$/g, "\\$");
104940
+ curlCommand += ` -d "${escapedBody}"`;
104941
+ }
104942
+ if (followRedirects) {
104943
+ curlCommand += " -L";
104944
+ }
104945
+ const timeoutSeconds = Math.ceil(timeout / 1000);
104946
+ curlCommand += ` --max-time ${timeoutSeconds}`;
104947
+ curlCommand += ` "${url2}" 2>&1`;
104948
+ const ssmTimeout = Math.max(timeoutSeconds, 30);
104949
+ const result = await ctx4.sandbox.execute(curlCommand, {
104950
+ timeout: ssmTimeout
104951
+ });
104952
+ const output = result.stdout || "";
104953
+ const lines = output.split(`
104954
+ `);
104955
+ let statusLine = "";
104956
+ const responseHeaders = {};
104957
+ let bodyStartIndex = 0;
104958
+ for (let i = 0;i < lines.length; i++) {
104959
+ const line = lines[i];
104960
+ if (line.startsWith("HTTP/")) {
104961
+ statusLine = line;
104962
+ for (let j2 = i + 1;j2 < lines.length; j2++) {
104963
+ if (lines[j2].trim() === "") {
104964
+ bodyStartIndex = j2 + 1;
104965
+ break;
104966
+ }
104967
+ const headerMatch = lines[j2].match(/^([^:]+):\s*(.+)$/);
104968
+ if (headerMatch) {
104969
+ responseHeaders[headerMatch[1].toLowerCase()] = headerMatch[2];
104970
+ }
104971
+ }
104972
+ break;
104973
+ }
104974
+ }
104975
+ const statusMatch = statusLine.match(/HTTP\/[\d.]+\s+(\d+)\s+(.+)/);
104976
+ const status = statusMatch ? parseInt(statusMatch[1]) : 0;
104977
+ const statusText = statusMatch ? statusMatch[2] : "Unknown";
104978
+ const responseBody = lines.slice(bodyStartIndex).join(`
104979
+ `);
104980
+ return {
104981
+ success: status >= 200 && status < 400,
104982
+ status,
104983
+ statusText,
104984
+ headers: responseHeaders,
104985
+ body: responseBody.length > 5000 ? `${responseBody.substring(0, 5000)}...
104986
+
104987
+ (truncated) use execute_command with grep / tail to paginate the response` : responseBody,
104988
+ url: url2,
104989
+ redirected: false
104990
+ };
104991
+ } catch (error41) {
104992
+ const msg = error41 instanceof Error ? error41.message : String(error41);
104993
+ return {
104994
+ success: false,
104995
+ error: msg,
104996
+ status: 0,
104997
+ statusText: "Error",
104998
+ headers: {},
104999
+ body: "",
105000
+ url: url2,
105001
+ redirected: false
105002
+ };
105003
+ }
105004
+ }
104893
105005
  var httpRequestInputSchema;
104894
105006
  var init_httpRequest = __esm(() => {
104895
105007
  init_dist7();
@@ -104916,7 +105028,7 @@ var init_httpRequest = __esm(() => {
104916
105028
 
104917
105029
  // src/core/agents/offSecAgent/tools/documentFinding.ts
104918
105030
  import { join as join5 } from "path";
104919
- import { writeFileSync as writeFileSync3, appendFileSync } from "fs";
105031
+ import { writeFileSync as writeFileSync4, appendFileSync as appendFileSync2 } from "fs";
104920
105032
  function documentFinding(ctx4) {
104921
105033
  const { session } = ctx4;
104922
105034
  return tool2({
@@ -104952,7 +105064,7 @@ FINDING STRUCTURE:
104952
105064
  const jsonPath = join5(session.findingsPath, jsonFilename);
104953
105065
  const mdFilename = `${findingId}.md`;
104954
105066
  const mdPath = join5(session.findingsPath, mdFilename);
104955
- writeFileSync3(jsonPath, JSON.stringify(findingWithMeta, null, 2));
105067
+ writeFileSync4(jsonPath, JSON.stringify(findingWithMeta, null, 2));
104956
105068
  const markdown = `# ${finding.title}
104957
105069
 
104958
105070
  **Severity:** ${finding.severity}
@@ -104991,12 +105103,12 @@ ${finding.references}` : ""}
104991
105103
 
104992
105104
  *This finding was automatically documented by the Pensar penetration testing agent.*
104993
105105
  `;
104994
- writeFileSync3(mdPath, markdown);
105106
+ writeFileSync4(mdPath, markdown);
104995
105107
  const summaryPath = join5(session.rootPath, "findings-summary.md");
104996
105108
  const summaryEntry = `- [${finding.severity}] ${finding.title} - \`findings/${mdFilename}\`
104997
105109
  `;
104998
105110
  try {
104999
- appendFileSync(summaryPath, summaryEntry);
105111
+ appendFileSync2(summaryPath, summaryEntry);
105000
105112
  } catch {
105001
105113
  const header = `# Findings Summary
105002
105114
 
@@ -105006,7 +105118,7 @@ ${finding.references}` : ""}
105006
105118
  ## All Findings
105007
105119
 
105008
105120
  `;
105009
- writeFileSync3(summaryPath, header + summaryEntry);
105121
+ writeFileSync4(summaryPath, header + summaryEntry);
105010
105122
  }
105011
105123
  return {
105012
105124
  success: true,
@@ -105047,11 +105159,11 @@ var init_documentFinding = __esm(() => {
105047
105159
  import { join as join6 } from "path";
105048
105160
  import { spawn as spawn3 } from "child_process";
105049
105161
  import {
105050
- existsSync as existsSync10,
105051
- writeFileSync as writeFileSync4,
105162
+ existsSync as existsSync11,
105163
+ writeFileSync as writeFileSync5,
105052
105164
  chmodSync,
105053
105165
  unlinkSync,
105054
- mkdirSync as mkdirSync2
105166
+ mkdirSync as mkdirSync3
105055
105167
  } from "fs";
105056
105168
  function sanitizeFilename(str) {
105057
105169
  return str.toLowerCase().replace(/[^a-z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").substring(0, 50);
@@ -105090,67 +105202,126 @@ Max ${MAX_POC_ATTEMPTS} attempts per approach before pivoting.`,
105090
105202
  attemptsRemaining: 0
105091
105203
  };
105092
105204
  }
105205
+ if (ctx4.sandbox) {
105206
+ return executeSandboxPoc(ctx4, poc, currentAttempts);
105207
+ }
105208
+ return executeLocalPoc(ctx4, poc, currentAttempts);
105209
+ }
105210
+ });
105211
+ }
105212
+ async function executeLocalPoc(ctx4, poc, currentAttempts) {
105213
+ try {
105214
+ const pocsPath = ctx4.session.pocsPath;
105215
+ if (!existsSync11(pocsPath)) {
105216
+ mkdirSync3(pocsPath, { recursive: true });
105217
+ }
105218
+ const { filename, pocContent } = preparePoc(poc, currentAttempts);
105219
+ const pocPath = join6(pocsPath, filename);
105220
+ writeFileSync5(pocPath, pocContent);
105221
+ chmodSync(pocPath, 493);
105222
+ const runner = poc.pocType === "bash" ? "bash" : poc.pocType === "python" ? "python3" : "node";
105223
+ const { stdout, stderr, exitCode } = await runScript(runner, pocPath, 60000, ctx4.abortSignal);
105224
+ if (exitCode !== 0) {
105225
+ try {
105226
+ unlinkSync(pocPath);
105227
+ } catch {}
105228
+ }
105229
+ return {
105230
+ success: exitCode === 0,
105231
+ pocPath: exitCode === 0 ? `pocs/${filename}` : undefined,
105232
+ stdout,
105233
+ stderr,
105234
+ exitCode,
105235
+ attemptsRemaining: MAX_POC_ATTEMPTS - currentAttempts,
105236
+ error: exitCode !== 0 ? `POC exited with code ${exitCode}. ${MAX_POC_ATTEMPTS - currentAttempts} attempts remaining.` : undefined
105237
+ };
105238
+ } catch (error41) {
105239
+ const errorMsg = error41 instanceof Error ? error41.message : String(error41);
105240
+ return {
105241
+ success: false,
105242
+ error: errorMsg,
105243
+ attemptsRemaining: MAX_POC_ATTEMPTS - currentAttempts
105244
+ };
105245
+ }
105246
+ }
105247
+ async function executeSandboxPoc(ctx4, poc, currentAttempts) {
105248
+ try {
105249
+ const { filename, pocContent } = preparePoc(poc, currentAttempts);
105250
+ const localPocsPath = ctx4.session.pocsPath;
105251
+ if (!existsSync11(localPocsPath)) {
105252
+ mkdirSync3(localPocsPath, { recursive: true });
105253
+ }
105254
+ const localPocPath = join6(localPocsPath, filename);
105255
+ if (existsSync11(localPocPath)) {
105256
+ return {
105257
+ success: false,
105258
+ error: `POC already exists at: pocs/${filename}`,
105259
+ attemptsRemaining: MAX_POC_ATTEMPTS - currentAttempts
105260
+ };
105261
+ }
105262
+ writeFileSync5(localPocPath, pocContent);
105263
+ const sandboxPocPath = `/tmp/pocs/${filename}`;
105264
+ await ctx4.sandbox.execute("mkdir -p /tmp/pocs");
105265
+ const base64Content = Buffer.from(pocContent).toString("base64");
105266
+ await ctx4.sandbox.execute(`echo "${base64Content}" | base64 -d > ${sandboxPocPath}`);
105267
+ await ctx4.sandbox.execute(`chmod +x ${sandboxPocPath}`);
105268
+ const runner = poc.pocType === "bash" ? "bash" : poc.pocType === "python" ? "python3" : "node";
105269
+ const result = await ctx4.sandbox.execute(`cd /tmp && ${runner} ${sandboxPocPath}`, { timeout: 60 });
105270
+ const executionSuccess = result.success || result.exitCode === 0;
105271
+ if (!executionSuccess) {
105272
+ await ctx4.sandbox.execute(`rm -f ${sandboxPocPath}`);
105093
105273
  try {
105094
- const pocsPath = ctx4.session.pocsPath;
105095
- if (!existsSync10(pocsPath)) {
105096
- mkdirSync2(pocsPath, { recursive: true });
105097
- }
105098
- const extension = poc.pocType === "bash" ? ".sh" : poc.pocType === "python" ? ".py" : ".js";
105099
- const sanitizedName = sanitizeFilename(poc.pocName);
105100
- const filename = `poc_${sanitizedName}${extension}`;
105101
- const pocPath = join6(pocsPath, filename);
105102
- let pocContent = poc.pocContent.trim();
105103
- if (!pocContent.startsWith("#!")) {
105104
- const shebangs = {
105105
- bash: `#!/bin/bash
105274
+ unlinkSync(localPocPath);
105275
+ } catch {}
105276
+ }
105277
+ return {
105278
+ success: executionSuccess,
105279
+ pocPath: executionSuccess ? `pocs/${filename}` : undefined,
105280
+ stdout: result.stdout || "(no output)",
105281
+ stderr: executionSuccess ? result.stderr || "(no errors)" : (result.stderr || "POC execution failed") + `
105282
+
105283
+ POC file has been deleted.`,
105284
+ exitCode: result.exitCode,
105285
+ attemptsRemaining: MAX_POC_ATTEMPTS - currentAttempts,
105286
+ error: !executionSuccess ? `POC exited with code ${result.exitCode}. ${MAX_POC_ATTEMPTS - currentAttempts} attempts remaining.` : undefined
105287
+ };
105288
+ } catch (error41) {
105289
+ const errorMsg = error41 instanceof Error ? error41.message : String(error41);
105290
+ return {
105291
+ success: false,
105292
+ error: errorMsg,
105293
+ attemptsRemaining: MAX_POC_ATTEMPTS - currentAttempts
105294
+ };
105295
+ }
105296
+ }
105297
+ function preparePoc(poc, currentAttempts) {
105298
+ const extension = poc.pocType === "bash" ? ".sh" : poc.pocType === "python" ? ".py" : ".js";
105299
+ const sanitizedName = sanitizeFilename(poc.pocName);
105300
+ const filename = `poc_${sanitizedName}${extension}`;
105301
+ let pocContent = poc.pocContent.trim();
105302
+ if (!pocContent.startsWith("#!")) {
105303
+ const shebangs = {
105304
+ bash: `#!/bin/bash
105106
105305
  set -e
105107
105306
 
105108
105307
  `,
105109
- python: `#!/usr/bin/env python3
105308
+ python: `#!/usr/bin/env python3
105110
105309
 
105111
105310
  `,
105112
- javascript: `#!/usr/bin/env node
105311
+ javascript: `#!/usr/bin/env node
105113
105312
 
105114
105313
  `
105115
- };
105116
- pocContent = shebangs[poc.pocType] + pocContent;
105117
- }
105118
- const commentChar = poc.pocType === "javascript" ? "//" : "#";
105119
- const header = `${commentChar} POC: ${poc.description}
105314
+ };
105315
+ pocContent = shebangs[poc.pocType] + pocContent;
105316
+ }
105317
+ const commentChar = poc.pocType === "javascript" ? "//" : "#";
105318
+ const header = `${commentChar} POC: ${poc.description}
105120
105319
  ${commentChar} Created: ${new Date().toISOString()}
105121
105320
  ${commentChar} Attempt: ${currentAttempts}/${MAX_POC_ATTEMPTS}
105122
105321
 
105123
105322
  `;
105124
- const afterShebang = pocContent.replace(/^#!.*\n/, (match) => match + header);
105125
- pocContent = afterShebang;
105126
- writeFileSync4(pocPath, pocContent);
105127
- chmodSync(pocPath, 493);
105128
- const runner = poc.pocType === "bash" ? "bash" : poc.pocType === "python" ? "python3" : "node";
105129
- const { stdout, stderr, exitCode } = await runScript(runner, pocPath, 60000, ctx4.abortSignal);
105130
- if (exitCode !== 0) {
105131
- try {
105132
- unlinkSync(pocPath);
105133
- } catch {}
105134
- }
105135
- return {
105136
- success: exitCode === 0,
105137
- pocPath: exitCode === 0 ? `pocs/${filename}` : undefined,
105138
- stdout,
105139
- stderr,
105140
- exitCode,
105141
- attemptsRemaining: MAX_POC_ATTEMPTS - currentAttempts,
105142
- error: exitCode !== 0 ? `POC exited with code ${exitCode}. ${MAX_POC_ATTEMPTS - currentAttempts} attempts remaining.` : undefined
105143
- };
105144
- } catch (error41) {
105145
- const errorMsg = error41 instanceof Error ? error41.message : String(error41);
105146
- return {
105147
- success: false,
105148
- error: errorMsg,
105149
- attemptsRemaining: MAX_POC_ATTEMPTS - currentAttempts
105150
- };
105151
- }
105152
- }
105153
- });
105323
+ pocContent = pocContent.replace(/^#!.*\n/, (match) => match + header);
105324
+ return { filename, pocContent };
105154
105325
  }
105155
105326
  function runScript(runner, scriptPath, timeout, abortSignal) {
105156
105327
  return new Promise((resolve4) => {
@@ -105447,7 +105618,7 @@ var init_grep = __esm(() => {
105447
105618
 
105448
105619
  // src/core/agents/offSecAgent/tools/documentAsset.ts
105449
105620
  import { join as join8 } from "path";
105450
- import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync3, existsSync as existsSync11 } from "fs";
105621
+ import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync4, existsSync as existsSync12 } from "fs";
105451
105622
  function documentAsset(ctx4) {
105452
105623
  const assetsPath = join8(ctx4.session.rootPath, "assets");
105453
105624
  return tool2({
@@ -105514,8 +105685,8 @@ Each asset creates a JSON file in the assets directory for tracking and analysis
105514
105685
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
105515
105686
  }),
105516
105687
  execute: async (asset) => {
105517
- if (!existsSync11(assetsPath)) {
105518
- mkdirSync3(assetsPath, { recursive: true });
105688
+ if (!existsSync12(assetsPath)) {
105689
+ mkdirSync4(assetsPath, { recursive: true });
105519
105690
  }
105520
105691
  const sanitizedName = asset.assetName.toLowerCase().replace(/[^a-z0-9-_.]/g, "_");
105521
105692
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
@@ -105527,7 +105698,7 @@ Each asset creates a JSON file in the assets directory for tracking and analysis
105527
105698
  sessionId: ctx4.session.id,
105528
105699
  target: ctx4.session.targets[0]
105529
105700
  };
105530
- writeFileSync5(filepath, JSON.stringify(assetRecord, null, 2));
105701
+ writeFileSync6(filepath, JSON.stringify(assetRecord, null, 2));
105531
105702
  return {
105532
105703
  success: true,
105533
105704
  assetName: asset.assetName,
@@ -105546,7 +105717,7 @@ var init_documentAsset = __esm(() => {
105546
105717
 
105547
105718
  // src/core/agents/offSecAgent/tools/authenticateSession.ts
105548
105719
  import { join as join9 } from "path";
105549
- import { writeFileSync as writeFileSync6 } from "fs";
105720
+ import { writeFileSync as writeFileSync7 } from "fs";
105550
105721
  function authenticateSession(ctx4) {
105551
105722
  return tool2({
105552
105723
  description: `Authenticate with credentials and obtain a session cookie for subsequent authenticated requests.
@@ -105611,7 +105782,7 @@ Use this to:
105611
105782
  loginUrl,
105612
105783
  timestamp: new Date().toISOString()
105613
105784
  };
105614
- writeFileSync6(sessionInfoPath, JSON.stringify(sessionInfo, null, 2));
105785
+ writeFileSync7(sessionInfoPath, JSON.stringify(sessionInfo, null, 2));
105615
105786
  return {
105616
105787
  success: authenticated,
105617
105788
  authenticated,
@@ -105923,7 +106094,7 @@ var init_authentication = __esm(() => {
105923
106094
 
105924
106095
  // src/core/agents/offSecAgent/tools/delegateAuth.ts
105925
106096
  import { join as join10 } from "path";
105926
- import { writeFileSync as writeFileSync7 } from "fs";
106097
+ import { writeFileSync as writeFileSync8 } from "fs";
105927
106098
  function mergeAuthCredentials(sessionCreds, explicit) {
105928
106099
  const hasExplicit = explicit.username || explicit.password || explicit.apiKey || explicit.tokens;
105929
106100
  const hasSession = sessionCreds && (sessionCreds.username || sessionCreds.password || sessionCreds.apiKey || sessionCreds.tokens);
@@ -106084,7 +106255,7 @@ When to use delegate_to_auth_subagent vs authenticate_session:
106084
106255
  timestamp: new Date().toISOString(),
106085
106256
  delegatedToSubagent: true
106086
106257
  };
106087
- writeFileSync7(sessionInfoPath, JSON.stringify(sessionInfo, null, 2));
106258
+ writeFileSync8(sessionInfoPath, JSON.stringify(sessionInfo, null, 2));
106088
106259
  }
106089
106260
  const hasHeaders = result.exportedHeaders && Object.keys(result.exportedHeaders).length > 0;
106090
106261
  const hasCookies = result.exportedCookies && result.exportedCookies.length > 0;
@@ -106489,7 +106660,7 @@ var init_validateDiscovery = __esm(() => {
106489
106660
 
106490
106661
  // src/core/agents/offSecAgent/tools/createAttackSurfaceReport.ts
106491
106662
  import { join as join11 } from "path";
106492
- import { writeFileSync as writeFileSync8 } from "fs";
106663
+ import { writeFileSync as writeFileSync9 } from "fs";
106493
106664
  function createAttackSurfaceReport(ctx4) {
106494
106665
  return tool2({
106495
106666
  description: `Provide attack surface analysis results to the orchestrator agent.
@@ -106516,7 +106687,7 @@ Call this at the END of your analysis with:
106516
106687
  }),
106517
106688
  execute: async (results) => {
106518
106689
  const resultsPath = join11(ctx4.session.rootPath, "attack-surface-results.json");
106519
- writeFileSync8(resultsPath, JSON.stringify(results, null, 2));
106690
+ writeFileSync9(resultsPath, JSON.stringify(results, null, 2));
106520
106691
  return {
106521
106692
  success: true,
106522
106693
  resultsPath,
@@ -106533,7 +106704,7 @@ var init_createAttackSurfaceReport = __esm(() => {
106533
106704
 
106534
106705
  // src/core/agents/offSecAgent/tools/completeAuthentication.ts
106535
106706
  import { join as join12 } from "path";
106536
- import { existsSync as existsSync12, mkdirSync as mkdirSync4, writeFileSync as writeFileSync9 } from "fs";
106707
+ import { existsSync as existsSync13, mkdirSync as mkdirSync5, writeFileSync as writeFileSync10 } from "fs";
106537
106708
  function completeAuthentication(ctx4) {
106538
106709
  return tool2({
106539
106710
  description: `Signal that the authentication process is complete.
@@ -106576,8 +106747,8 @@ This tool marks the end of the authentication flow.`,
106576
106747
  if (result.success && (result.exportedCookies || result.exportedHeaders)) {
106577
106748
  try {
106578
106749
  const authDir = join12(ctx4.session.rootPath, AUTH_DIR);
106579
- if (!existsSync12(authDir)) {
106580
- mkdirSync4(authDir, { recursive: true });
106750
+ if (!existsSync13(authDir)) {
106751
+ mkdirSync5(authDir, { recursive: true });
106581
106752
  }
106582
106753
  authDataPath = join12(authDir, AUTH_DATA_FILENAME);
106583
106754
  const authData = {
@@ -106589,7 +106760,7 @@ This tool marks the end of the authentication flow.`,
106589
106760
  target: ctx4.target || "",
106590
106761
  timestamp: new Date().toISOString()
106591
106762
  };
106592
- writeFileSync9(authDataPath, JSON.stringify(authData, null, 2));
106763
+ writeFileSync10(authDataPath, JSON.stringify(authData, null, 2));
106593
106764
  console.log(`Auth data persisted to ${authDataPath}`);
106594
106765
  } catch (err) {
106595
106766
  console.error(`Failed to persist auth data: ${err}`);
@@ -107299,16 +107470,16 @@ __export(exports_agent2, {
107299
107470
  runPentestAgent: () => runPentestAgent,
107300
107471
  TargetedPentestAgent: () => TargetedPentestAgent
107301
107472
  });
107302
- import { existsSync as existsSync13, readdirSync as readdirSync2, readFileSync as readFileSync4 } from "fs";
107473
+ import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync5 } from "fs";
107303
107474
  import { join as join13 } from "path";
107304
107475
  function buildPrompt2(target, objectives, sessionRootPath) {
107305
107476
  const objectiveList = objectives.map((o, i) => `${i + 1}. ${o}`).join(`
107306
107477
  `);
107307
107478
  let authSection = "";
107308
107479
  const authDataPath = join13(sessionRootPath, "auth", "auth-data.json");
107309
- if (existsSync13(authDataPath)) {
107480
+ if (existsSync14(authDataPath)) {
107310
107481
  try {
107311
- const raw = readFileSync4(authDataPath, "utf-8");
107482
+ const raw = readFileSync5(authDataPath, "utf-8");
107312
107483
  const authData = JSON.parse(raw);
107313
107484
  if (authData.authenticated) {
107314
107485
  const parts = [
@@ -107354,12 +107525,12 @@ ${objectiveList}
107354
107525
  Do NOT discover or enumerate other endpoints or services. Focus exclusively on the target and objectives above.`;
107355
107526
  }
107356
107527
  function loadFindings(findingsPath) {
107357
- if (!existsSync13(findingsPath)) {
107528
+ if (!existsSync14(findingsPath)) {
107358
107529
  return [];
107359
107530
  }
107360
107531
  return readdirSync2(findingsPath).filter((f) => f.endsWith(".json")).map((f) => {
107361
107532
  try {
107362
- const content = readFileSync4(join13(findingsPath, f), "utf-8");
107533
+ const content = readFileSync5(join13(findingsPath, f), "utf-8");
107363
107534
  return JSON.parse(content);
107364
107535
  } catch {
107365
107536
  return null;
@@ -107416,7 +107587,8 @@ var init_agent3 = __esm(() => {
107416
107587
  session,
107417
107588
  authConfig,
107418
107589
  onStepFinish,
107419
- abortSignal
107590
+ abortSignal,
107591
+ sandbox
107420
107592
  } = opts;
107421
107593
  super({
107422
107594
  system: PENTEST_SYSTEM_PROMPT,
@@ -107427,6 +107599,7 @@ var init_agent3 = __esm(() => {
107427
107599
  authConfig,
107428
107600
  onStepFinish,
107429
107601
  abortSignal,
107602
+ sandbox,
107430
107603
  activeTools: [
107431
107604
  "execute_command",
107432
107605
  "http_request",
@@ -107809,7 +107982,7 @@ var init_spawnCodingAgent = __esm(() => {
107809
107982
 
107810
107983
  // src/core/agents/offSecAgent/tools/provideComparisonResults.ts
107811
107984
  import { join as join14 } from "path";
107812
- import { writeFileSync as writeFileSync10 } from "fs";
107985
+ import { writeFileSync as writeFileSync11 } from "fs";
107813
107986
  function provideComparisonResults(ctx4) {
107814
107987
  return tool2({
107815
107988
  description: `Provide the final comparison results with matched, missed, and extra findings.
@@ -107856,7 +108029,7 @@ Results will be saved to: comparison-results.json in the session directory.`,
107856
108029
  precision
107857
108030
  };
107858
108031
  const resultsPath = join14(ctx4.session.rootPath, "comparison-results.json");
107859
- writeFileSync10(resultsPath, JSON.stringify(result, null, 2));
108032
+ writeFileSync11(resultsPath, JSON.stringify(result, null, 2));
107860
108033
  return {
107861
108034
  success: true,
107862
108035
  resultsPath,
@@ -108087,7 +108260,8 @@ var init_offensiveSecurityAgent = __esm(() => {
108087
108260
  model: input.model,
108088
108261
  authConfig: input.authConfig,
108089
108262
  callbacks: input.callbacks,
108090
- subagentCallbacks: input.subagentCallbacks
108263
+ subagentCallbacks: input.subagentCallbacks,
108264
+ sandbox: input.sandbox
108091
108265
  });
108092
108266
  let tools = input.extraTools ? { ...builtinTools, ...input.extraTools } : { ...builtinTools };
108093
108267
  let capturedResponse = null;
@@ -108191,7 +108365,7 @@ __export(exports_blackboxAgent, {
108191
108365
  BlackboxAttackSurfaceAgent: () => BlackboxAttackSurfaceAgent
108192
108366
  });
108193
108367
  import { join as join15 } from "path";
108194
- import { existsSync as existsSync14, mkdirSync as mkdirSync5, writeFileSync as writeFileSync11 } from "fs";
108368
+ import { existsSync as existsSync15, mkdirSync as mkdirSync6, writeFileSync as writeFileSync12 } from "fs";
108195
108369
  function buildPrompt4(target, session) {
108196
108370
  const scopeConstraints = session.config?.scopeConstraints;
108197
108371
  const authenticationInstructions = session.config?.authenticationInstructions;
@@ -108285,8 +108459,8 @@ var init_blackboxAgent = __esm(() => {
108285
108459
  const resultsPath = join15(session.rootPath, "attack-surface-results.json");
108286
108460
  const assetsPath = join15(session.rootPath, "assets");
108287
108461
  const subagentFolder = join15(session.rootPath, "subagents", "attack-surface-agent");
108288
- if (!existsSync14(subagentFolder)) {
108289
- mkdirSync5(subagentFolder, { recursive: true });
108462
+ if (!existsSync15(subagentFolder)) {
108463
+ mkdirSync6(subagentFolder, { recursive: true });
108290
108464
  }
108291
108465
  super({
108292
108466
  system: detectOSAndEnhancePrompt(SYSTEM),
@@ -108299,7 +108473,7 @@ var init_blackboxAgent = __esm(() => {
108299
108473
  onStepFinish?.(e);
108300
108474
  const messages = e.response.messages;
108301
108475
  if (messages !== undefined) {
108302
- writeFileSync11(join15(subagentFolder, "attack-surface-agent.log"), JSON.stringify(messages, null, 2));
108476
+ writeFileSync12(join15(subagentFolder, "attack-surface-agent.log"), JSON.stringify(messages, null, 2));
108303
108477
  }
108304
108478
  },
108305
108479
  abortSignal,
@@ -108324,7 +108498,7 @@ var init_blackboxAgent = __esm(() => {
108324
108498
  resolveResult: () => {
108325
108499
  let results = null;
108326
108500
  let targets = [];
108327
- if (existsSync14(resultsPath)) {
108501
+ if (existsSync15(resultsPath)) {
108328
108502
  try {
108329
108503
  results = loadAttackSurfaceResults(resultsPath);
108330
108504
  targets = results.targets || [];
@@ -135125,7 +135299,7 @@ var useTerminalDimensions = () => {
135125
135299
  };
135126
135300
 
135127
135301
  // src/tui/index.tsx
135128
- var import_react80 = __toESM(require_react(), 1);
135302
+ var import_react83 = __toESM(require_react(), 1);
135129
135303
 
135130
135304
  // src/tui/components/footer.tsx
135131
135305
  import os5 from "os";
@@ -142370,6 +142544,206 @@ function ResponsibleUseDisclosure({
142370
142544
  }, undefined, true, undefined, this);
142371
142545
  }
142372
142546
 
142547
+ // src/tui/context/toast.tsx
142548
+ var import_react53 = __toESM(require_react(), 1);
142549
+ var ToastContext = import_react53.createContext(null);
142550
+ var nextId = 0;
142551
+ var DEFAULT_DURATION = {
142552
+ default: 3000,
142553
+ warn: 4000,
142554
+ error: 5000
142555
+ };
142556
+ function ToastProvider({ children }) {
142557
+ const [toasts, setToasts] = import_react53.useState([]);
142558
+ const dismiss = import_react53.useCallback((id) => {
142559
+ setToasts((prev) => prev.filter((t2) => t2.id !== id));
142560
+ }, []);
142561
+ const toast = import_react53.useCallback((message, variant = "default", duration) => {
142562
+ const id = nextId++;
142563
+ const ms = duration ?? DEFAULT_DURATION[variant];
142564
+ setToasts((prev) => [...prev, { id, message, variant, duration: ms }]);
142565
+ setTimeout(() => dismiss(id), ms);
142566
+ }, [dismiss]);
142567
+ const value = import_react53.useMemo(() => ({ toasts, toast, dismiss }), [toasts, toast, dismiss]);
142568
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToastContext.Provider, {
142569
+ value,
142570
+ children
142571
+ }, undefined, false, undefined, this);
142572
+ }
142573
+ function useToast() {
142574
+ const ctx4 = import_react53.useContext(ToastContext);
142575
+ if (!ctx4)
142576
+ throw new Error("useToast() must be used within <ToastProvider>");
142577
+ return ctx4;
142578
+ }
142579
+
142580
+ // src/tui/components/toast.tsx
142581
+ var VARIANT_ICONS = {
142582
+ default: "●",
142583
+ error: "✖",
142584
+ warn: "⚠"
142585
+ };
142586
+ function variantColor(variant, colors2) {
142587
+ switch (variant) {
142588
+ case "error":
142589
+ return colors2.error;
142590
+ case "warn":
142591
+ return colors2.warning;
142592
+ default:
142593
+ return colors2.info;
142594
+ }
142595
+ }
142596
+ function ToastItem({
142597
+ message,
142598
+ variant,
142599
+ onDismiss
142600
+ }) {
142601
+ const { colors: colors2 } = useTheme();
142602
+ const accent = variantColor(variant, colors2);
142603
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
142604
+ flexDirection: "row",
142605
+ gap: 1,
142606
+ paddingLeft: 1,
142607
+ paddingRight: 1,
142608
+ border: ["left"],
142609
+ borderColor: accent,
142610
+ backgroundColor: colors2.backgroundPanel,
142611
+ onMouseUp: () => onDismiss(),
142612
+ children: [
142613
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
142614
+ fg: accent,
142615
+ children: VARIANT_ICONS[variant]
142616
+ }, undefined, false, undefined, this),
142617
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
142618
+ fg: colors2.text,
142619
+ children: message
142620
+ }, undefined, false, undefined, this)
142621
+ ]
142622
+ }, undefined, true, undefined, this);
142623
+ }
142624
+ function ToastContainer() {
142625
+ const { toasts, dismiss } = useToast();
142626
+ const dims = useTerminalDimensions();
142627
+ if (toasts.length === 0)
142628
+ return null;
142629
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
142630
+ position: "absolute",
142631
+ right: 1,
142632
+ top: 0,
142633
+ flexDirection: "column",
142634
+ gap: 0,
142635
+ alignItems: "flex-end",
142636
+ maxWidth: Math.min(60, dims.width - 4),
142637
+ zIndex: 9999,
142638
+ children: toasts.map((t2) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToastItem, {
142639
+ message: t2.message,
142640
+ variant: t2.variant,
142641
+ onDismiss: () => dismiss(t2.id)
142642
+ }, t2.id, false, undefined, this))
142643
+ }, undefined, false, undefined, this);
142644
+ }
142645
+
142646
+ // src/tui/components/error-boundary.tsx
142647
+ var import_react55 = __toESM(require_react(), 1);
142648
+
142649
+ // src/core/logger/index.ts
142650
+ import {
142651
+ appendFileSync,
142652
+ existsSync as existsSync8,
142653
+ mkdirSync,
142654
+ readFileSync as readFileSync2,
142655
+ writeFileSync as writeFileSync2
142656
+ } from "fs";
142657
+ import os6 from "os";
142658
+ import path7 from "path";
142659
+ var ERROR_LOG_PATH = path7.join(os6.homedir(), ".pensar", "error.log");
142660
+ var RETENTION_DAYS = 7;
142661
+ var TIMESTAMP_RE = /^(\d{4}-\d{2}-\d{2}T[\d:.]+Z) - /;
142662
+ var hasPruned = false;
142663
+ function pruneErrorLog() {
142664
+ if (hasPruned)
142665
+ return;
142666
+ hasPruned = true;
142667
+ try {
142668
+ if (!existsSync8(ERROR_LOG_PATH))
142669
+ return;
142670
+ const cutoff = Date.now() - RETENTION_DAYS * 86400000;
142671
+ const raw = readFileSync2(ERROR_LOG_PATH, "utf8");
142672
+ const lines = raw.split(`
142673
+ `);
142674
+ const kept = [];
142675
+ let keeping = true;
142676
+ for (const line of lines) {
142677
+ const match = TIMESTAMP_RE.exec(line);
142678
+ if (match) {
142679
+ keeping = new Date(match[1]).getTime() >= cutoff;
142680
+ }
142681
+ if (keeping) {
142682
+ kept.push(line);
142683
+ }
142684
+ }
142685
+ writeFileSync2(ERROR_LOG_PATH, kept.join(`
142686
+ `), "utf8");
142687
+ } catch {}
142688
+ }
142689
+ function writeErrorLog(error, source) {
142690
+ try {
142691
+ pruneErrorLog();
142692
+ const dir = path7.dirname(ERROR_LOG_PATH);
142693
+ if (!existsSync8(dir)) {
142694
+ mkdirSync(dir, { recursive: true });
142695
+ }
142696
+ const timestamp = new Date().toISOString();
142697
+ const tag = source ? `[${source}] ` : "";
142698
+ const message = error instanceof Error ? `${error.message}
142699
+ ${error.stack ?? ""}` : String(error);
142700
+ const entry = `${timestamp} - [ERROR] ${tag}${message}
142701
+ `;
142702
+ appendFileSync(ERROR_LOG_PATH, entry, "utf8");
142703
+ } catch {}
142704
+ }
142705
+
142706
+ // src/tui/components/error-boundary.tsx
142707
+ var MAX_ERRORS = 3;
142708
+ var ERROR_WINDOW_MS = 5000;
142709
+
142710
+ class ErrorBoundaryInner extends import_react55.default.Component {
142711
+ state = {
142712
+ hasError: false,
142713
+ errorTimestamps: [],
142714
+ halted: false
142715
+ };
142716
+ static getDerivedStateFromError() {
142717
+ return { hasError: true };
142718
+ }
142719
+ componentDidCatch(error) {
142720
+ console.error("[ErrorBoundary]", error);
142721
+ writeErrorLog(error, "TUI");
142722
+ this.props.onError(error.message);
142723
+ const now = Date.now();
142724
+ const recent = [...this.state.errorTimestamps, now].filter((t2) => now - t2 < ERROR_WINDOW_MS);
142725
+ if (recent.length >= MAX_ERRORS) {
142726
+ this.props.onError("Too many errors in quick succession — UI recovery halted.");
142727
+ this.setState({ halted: true, hasError: false, errorTimestamps: recent });
142728
+ return;
142729
+ }
142730
+ this.setState({ hasError: false, errorTimestamps: recent });
142731
+ }
142732
+ render() {
142733
+ if (this.state.halted) {
142734
+ return null;
142735
+ }
142736
+ return this.props.children;
142737
+ }
142738
+ }
142739
+ function ErrorBoundary2({ children }) {
142740
+ const { toast } = useToast();
142741
+ const handleError = import_react55.useCallback((message) => {
142742
+ toast(message, "error");
142743
+ }, [toast]);
142744
+ return import_react55.default.createElement(ErrorBoundaryInner, { onError: handleError }, children);
142745
+ }
142746
+
142373
142747
  // src/tui/keybindings-registry.ts
142374
142748
  var keybindings = [
142375
142749
  {
@@ -142475,16 +142849,16 @@ function ShortcutsDialog({
142475
142849
  }
142476
142850
 
142477
142851
  // src/tui/components/commands/help-dialog.tsx
142478
- var import_react54 = __toESM(require_react(), 1);
142852
+ var import_react57 = __toESM(require_react(), 1);
142479
142853
  function HelpDialog() {
142480
142854
  const { colors: colors2 } = useTheme();
142481
142855
  const { commands: commands2 } = useCommand();
142482
142856
  const route = useRoute();
142483
142857
  const dimensions = useTerminalDimensions();
142484
- const [selectedIndex, setSelectedIndex] = import_react54.useState(0);
142485
- const [showDetail, setShowDetail] = import_react54.useState(false);
142486
- const scrollboxRef = import_react54.useRef(null);
142487
- const commandsByCategory = import_react54.useMemo(() => {
142858
+ const [selectedIndex, setSelectedIndex] = import_react57.useState(0);
142859
+ const [showDetail, setShowDetail] = import_react57.useState(false);
142860
+ const scrollboxRef = import_react57.useRef(null);
142861
+ const commandsByCategory = import_react57.useMemo(() => {
142488
142862
  const grouped = {};
142489
142863
  for (const cmd of commands2) {
142490
142864
  const category = cmd.category || "Other";
@@ -142495,15 +142869,15 @@ function HelpDialog() {
142495
142869
  }
142496
142870
  return grouped;
142497
142871
  }, [commands2]);
142498
- const flatCommands = import_react54.useMemo(() => {
142872
+ const flatCommands = import_react57.useMemo(() => {
142499
142873
  return commands2;
142500
142874
  }, [commands2]);
142501
- import_react54.useEffect(() => {
142875
+ import_react57.useEffect(() => {
142502
142876
  if (selectedIndex >= flatCommands.length) {
142503
142877
  setSelectedIndex(Math.max(0, flatCommands.length - 1));
142504
142878
  }
142505
142879
  }, [flatCommands.length, selectedIndex]);
142506
- import_react54.useEffect(() => {
142880
+ import_react57.useEffect(() => {
142507
142881
  scrollToIndex(scrollboxRef.current, selectedIndex, flatCommands, (cmd) => cmd.name);
142508
142882
  }, [selectedIndex, flatCommands]);
142509
142883
  const handleClose = () => {
@@ -142938,10 +143312,10 @@ function ModelsDisplay() {
142938
143312
  }
142939
143313
 
142940
143314
  // src/tui/context/keybinding.tsx
142941
- var import_react61 = __toESM(require_react(), 1);
143315
+ var import_react64 = __toESM(require_react(), 1);
142942
143316
 
142943
143317
  // src/tui/keybindings/keybind.tsx
142944
- var import_react57 = __toESM(require_react(), 1);
143318
+ var import_react60 = __toESM(require_react(), 1);
142945
143319
 
142946
143320
  // src/tui/keybindings/actions.ts
142947
143321
  var movementActions = [
@@ -143193,7 +143567,7 @@ var allActions = [
143193
143567
  var actionsByKey = new Map(allActions.map((action) => [action.key, action]));
143194
143568
  var actionsById = new Map(allActions.map((action) => [action.id, action]));
143195
143569
  // src/tui/keybindings/keybind.tsx
143196
- var LeaderKeyContext = import_react57.createContext(null);
143570
+ var LeaderKeyContext = import_react60.createContext(null);
143197
143571
  // src/tui/keybindings/registry.ts
143198
143572
  function createKeybindings(deps) {
143199
143573
  const {
@@ -143399,7 +143773,7 @@ var Keybind;
143399
143773
  })(Keybind ||= {});
143400
143774
 
143401
143775
  // src/tui/context/keybinding.tsx
143402
- var KeybindingContext = import_react61.createContext(undefined);
143776
+ var KeybindingContext = import_react64.createContext(undefined);
143403
143777
  function KeybindingProvider({
143404
143778
  children,
143405
143779
  deps
@@ -143438,15 +143812,15 @@ function KeybindingProvider({
143438
143812
  }
143439
143813
 
143440
143814
  // src/tui/components/pentest/pentest.tsx
143441
- var import_react70 = __toESM(require_react(), 1);
143442
- import { existsSync as existsSync16, readdirSync as readdirSync4, readFileSync as readFileSync6 } from "fs";
143815
+ var import_react73 = __toESM(require_react(), 1);
143816
+ import { existsSync as existsSync17, readdirSync as readdirSync4, readFileSync as readFileSync7 } from "fs";
143443
143817
  import { join as join17 } from "path";
143444
143818
  import { exec as exec3 } from "child_process";
143445
143819
 
143446
143820
  // src/core/workflows/pentest.ts
143447
143821
  init_blackboxAgent();
143448
143822
  init_agent3();
143449
- import { existsSync as existsSync15, readdirSync as readdirSync3, readFileSync as readFileSync5 } from "fs";
143823
+ import { existsSync as existsSync16, readdirSync as readdirSync3, readFileSync as readFileSync6 } from "fs";
143450
143824
  import { join as join16 } from "path";
143451
143825
 
143452
143826
  // src/core/workflows/whiteboxAttackSurface.ts
@@ -143885,7 +144259,7 @@ async function runPentestWorkflow(input) {
143885
144259
  findings,
143886
144260
  findingsPath: session.findingsPath,
143887
144261
  pocsPath: session.pocsPath,
143888
- reportPath: existsSync15(reportPath) ? reportPath : null
144262
+ reportPath: existsSync16(reportPath) ? reportPath : null
143889
144263
  };
143890
144264
  }
143891
144265
  async function runWhiteboxPhase(opts) {
@@ -143955,12 +144329,12 @@ async function runWithBoundedConcurrency2(items, concurrency, fn) {
143955
144329
  return results;
143956
144330
  }
143957
144331
  function loadFindings2(findingsPath) {
143958
- if (!existsSync15(findingsPath)) {
144332
+ if (!existsSync16(findingsPath)) {
143959
144333
  return [];
143960
144334
  }
143961
144335
  return readdirSync3(findingsPath).filter((f) => f.endsWith(".json")).map((f) => {
143962
144336
  try {
143963
- const content = readFileSync5(join16(findingsPath, f), "utf-8");
144337
+ const content = readFileSync6(join16(findingsPath, f), "utf-8");
143964
144338
  return JSON.parse(content);
143965
144339
  } catch {
143966
144340
  return null;
@@ -143989,7 +144363,7 @@ Found ${findings.length} vulnerabilities`);
143989
144363
  }
143990
144364
 
143991
144365
  // src/tui/components/agent-display.tsx
143992
- var import_react68 = __toESM(require_react(), 1);
144366
+ var import_react71 = __toESM(require_react(), 1);
143993
144367
 
143994
144368
  // node_modules/marked/lib/marked.esm.js
143995
144369
  function L2() {
@@ -145755,14 +146129,14 @@ function getResultSummary(result, toolName) {
145755
146129
  return null;
145756
146130
  }
145757
146131
  // src/tui/components/shared/ascii-spinner.tsx
145758
- var import_react62 = __toESM(require_react(), 1);
146132
+ var import_react65 = __toESM(require_react(), 1);
145759
146133
  var SPINNER_FRAMES = ["/", "-", "\\", "|"];
145760
146134
  var SPINNER_INTERVAL = 100;
145761
146135
  function AsciiSpinner({ label, fg: fg2 }) {
145762
146136
  const { colors: colors2 } = useTheme();
145763
146137
  const spinnerColor = fg2 ?? colors2.info;
145764
- const [frame, setFrame] = import_react62.useState(0);
145765
- import_react62.useEffect(() => {
146138
+ const [frame, setFrame] = import_react65.useState(0);
146139
+ import_react65.useEffect(() => {
145766
146140
  const interval = setInterval(() => {
145767
146141
  setFrame((f) => (f + 1) % SPINNER_FRAMES.length);
145768
146142
  }, SPINNER_INTERVAL);
@@ -145774,14 +146148,14 @@ function AsciiSpinner({ label, fg: fg2 }) {
145774
146148
  }, undefined, false, undefined, this);
145775
146149
  }
145776
146150
  // src/tui/components/shared/tool-renderer.tsx
145777
- var import_react63 = __toESM(require_react(), 1);
145778
- var ToolRenderer = import_react63.memo(function ToolRenderer2({
146151
+ var import_react66 = __toESM(require_react(), 1);
146152
+ var ToolRenderer = import_react66.memo(function ToolRenderer2({
145779
146153
  message,
145780
146154
  verbose = false,
145781
146155
  expandedLogs = false
145782
146156
  }) {
145783
146157
  const { colors: colors2 } = useTheme();
145784
- const [showOutput, setShowOutput] = import_react63.useState(false);
146158
+ const [showOutput, setShowOutput] = import_react66.useState(false);
145785
146159
  if (!isToolMessage(message)) {
145786
146160
  return null;
145787
146161
  }
@@ -145878,8 +146252,8 @@ var ToolRenderer = import_react63.memo(function ToolRenderer2({
145878
146252
  }, undefined, true, undefined, this);
145879
146253
  });
145880
146254
  // src/tui/components/shared/message-renderer.tsx
145881
- var import_react64 = __toESM(require_react(), 1);
145882
- var MessageRenderer = import_react64.memo(function MessageRenderer2({
146255
+ var import_react67 = __toESM(require_react(), 1);
146256
+ var MessageRenderer = import_react67.memo(function MessageRenderer2({
145883
146257
  message,
145884
146258
  isStreaming = false,
145885
146259
  verbose = false,
@@ -145889,7 +146263,7 @@ var MessageRenderer = import_react64.memo(function MessageRenderer2({
145889
146263
  }) {
145890
146264
  const { colors: colors2 } = useTheme();
145891
146265
  const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content);
145892
- const displayContent = import_react64.useMemo(() => message.role === "assistant" ? markdownToStyledText(content, colors2) : content, [content, message.role, colors2]);
146266
+ const displayContent = import_react67.useMemo(() => message.role === "assistant" ? markdownToStyledText(content, colors2) : content, [content, message.role, colors2]);
145893
146267
  if (isToolMessage(message)) {
145894
146268
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToolRenderer, {
145895
146269
  message,
@@ -146001,9 +146375,9 @@ var MessageRenderer = import_react64.memo(function MessageRenderer2({
146001
146375
  }, undefined, false, undefined, this);
146002
146376
  });
146003
146377
  // src/tui/components/shared/approval-prompt.tsx
146004
- var import_react65 = __toESM(require_react(), 1);
146378
+ var import_react68 = __toESM(require_react(), 1);
146005
146379
  // src/tui/components/shared/message-reducer.ts
146006
- var import_react67 = __toESM(require_react(), 1);
146380
+ var import_react70 = __toESM(require_react(), 1);
146007
146381
  // src/tui/components/agent-display.tsx
146008
146382
  function getStableKey(item, contextId = "root") {
146009
146383
  if ("messages" in item) {
@@ -146079,11 +146453,11 @@ function AgentDisplay({
146079
146453
  ]
146080
146454
  }, undefined, true, undefined, this);
146081
146455
  }
146082
- var SubAgentDisplay = import_react68.memo(function SubAgentDisplay2({
146456
+ var SubAgentDisplay = import_react71.memo(function SubAgentDisplay2({
146083
146457
  subagent
146084
146458
  }) {
146085
146459
  const { colors: colors2 } = useTheme();
146086
- const [open, setOpen] = import_react68.useState(false);
146460
+ const [open, setOpen] = import_react71.useState(false);
146087
146461
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
146088
146462
  height: open ? 40 : "auto",
146089
146463
  onMouseDown: () => setOpen(!open),
@@ -146138,7 +146512,7 @@ var SubAgentDisplay = import_react68.memo(function SubAgentDisplay2({
146138
146512
  ]
146139
146513
  }, undefined, true, undefined, this);
146140
146514
  });
146141
- var AgentMessage = import_react68.memo(function AgentMessage2({
146515
+ var AgentMessage = import_react71.memo(function AgentMessage2({
146142
146516
  message
146143
146517
  }) {
146144
146518
  const { colors: colors2 } = useTheme();
@@ -146251,8 +146625,8 @@ var AgentMessage = import_react68.memo(function AgentMessage2({
146251
146625
  });
146252
146626
  function ToolDetails({ message }) {
146253
146627
  const { colors: colors2 } = useTheme();
146254
- const [showArgs, setShowArgs] = import_react68.useState(false);
146255
- const [showResult, setShowResult] = import_react68.useState(false);
146628
+ const [showArgs, setShowArgs] = import_react71.useState(false);
146629
+ const [showResult, setShowResult] = import_react71.useState(false);
146256
146630
  if (message.role !== "tool") {
146257
146631
  return null;
146258
146632
  }
@@ -146329,24 +146703,24 @@ function Pentest({ sessionId }) {
146329
146703
  const route = useRoute();
146330
146704
  const { model, setThinking, setIsExecuting, isExecuting } = useAgent();
146331
146705
  const { stack, externalDialogOpen } = useDialog();
146332
- const [session, setSession] = import_react70.useState(null);
146333
- const [error41, setError] = import_react70.useState(null);
146334
- const [phase, setPhase] = import_react70.useState("loading");
146335
- const [abortController, setAbortController] = import_react70.useState(null);
146336
- const [panelMessages, setPanelMessages] = import_react70.useState([]);
146337
- const panelTextRef = import_react70.useRef("");
146338
- const panelSourceRef = import_react70.useRef(null);
146339
- const [pentestAgents, setPentestAgents] = import_react70.useState({});
146340
- const pentestTextRefs = import_react70.useRef({});
146341
- const [assets, setAssets] = import_react70.useState([]);
146342
- const [viewMode, setViewMode] = import_react70.useState("overview");
146343
- const [selectedAgentId, setSelectedAgentId] = import_react70.useState(null);
146344
- const [focusedIndex, setFocusedIndex] = import_react70.useState(0);
146345
- const [showOrchestratorPanel, setShowOrchestratorPanel] = import_react70.useState(false);
146346
- const [startTime, setStartTime] = import_react70.useState(null);
146347
- const pentestAgentList = import_react70.useMemo(() => Object.values(pentestAgents).sort((a, b3) => a.createdAt.getTime() - b3.createdAt.getTime()), [pentestAgents]);
146348
- const selectedAgent = import_react70.useMemo(() => selectedAgentId ? pentestAgents[selectedAgentId] ?? null : null, [pentestAgents, selectedAgentId]);
146349
- import_react70.useEffect(() => {
146706
+ const [session, setSession] = import_react73.useState(null);
146707
+ const [error41, setError] = import_react73.useState(null);
146708
+ const [phase, setPhase] = import_react73.useState("loading");
146709
+ const [abortController, setAbortController] = import_react73.useState(null);
146710
+ const [panelMessages, setPanelMessages] = import_react73.useState([]);
146711
+ const panelTextRef = import_react73.useRef("");
146712
+ const panelSourceRef = import_react73.useRef(null);
146713
+ const [pentestAgents, setPentestAgents] = import_react73.useState({});
146714
+ const pentestTextRefs = import_react73.useRef({});
146715
+ const [assets, setAssets] = import_react73.useState([]);
146716
+ const [viewMode, setViewMode] = import_react73.useState("overview");
146717
+ const [selectedAgentId, setSelectedAgentId] = import_react73.useState(null);
146718
+ const [focusedIndex, setFocusedIndex] = import_react73.useState(0);
146719
+ const [showOrchestratorPanel, setShowOrchestratorPanel] = import_react73.useState(false);
146720
+ const [startTime, setStartTime] = import_react73.useState(null);
146721
+ const pentestAgentList = import_react73.useMemo(() => Object.values(pentestAgents).sort((a, b3) => a.createdAt.getTime() - b3.createdAt.getTime()), [pentestAgents]);
146722
+ const selectedAgent = import_react73.useMemo(() => selectedAgentId ? pentestAgents[selectedAgentId] ?? null : null, [pentestAgents, selectedAgentId]);
146723
+ import_react73.useEffect(() => {
146350
146724
  async function load() {
146351
146725
  try {
146352
146726
  const s = await sessions.get(sessionId);
@@ -146363,19 +146737,19 @@ function Pentest({ sessionId }) {
146363
146737
  }
146364
146738
  load();
146365
146739
  }, [sessionId]);
146366
- import_react70.useEffect(() => {
146740
+ import_react73.useEffect(() => {
146367
146741
  if (!session)
146368
146742
  return;
146369
146743
  const assetsPath = join17(session.rootPath, "assets");
146370
146744
  function readAssets() {
146371
- if (!existsSync16(assetsPath))
146745
+ if (!existsSync17(assetsPath))
146372
146746
  return;
146373
146747
  try {
146374
146748
  const files = readdirSync4(assetsPath).filter((f) => f.endsWith(".json"));
146375
146749
  const loaded = [];
146376
146750
  for (const file2 of files) {
146377
146751
  try {
146378
- const content = readFileSync6(join17(assetsPath, file2), "utf-8");
146752
+ const content = readFileSync7(join17(assetsPath, file2), "utf-8");
146379
146753
  loaded.push(JSON.parse(content));
146380
146754
  } catch {}
146381
146755
  }
@@ -146386,12 +146760,12 @@ function Pentest({ sessionId }) {
146386
146760
  const interval = setInterval(readAssets, 2000);
146387
146761
  return () => clearInterval(interval);
146388
146762
  }, [session]);
146389
- import_react70.useEffect(() => {
146763
+ import_react73.useEffect(() => {
146390
146764
  return () => {
146391
146765
  abortController?.abort();
146392
146766
  };
146393
146767
  }, [abortController]);
146394
- const ensurePentestAgent = import_react70.useCallback((subagentId) => {
146768
+ const ensurePentestAgent = import_react73.useCallback((subagentId) => {
146395
146769
  setPentestAgents((prev) => {
146396
146770
  if (prev[subagentId])
146397
146771
  return prev;
@@ -146408,7 +146782,7 @@ function Pentest({ sessionId }) {
146408
146782
  };
146409
146783
  });
146410
146784
  }, []);
146411
- const handleSubagentSpawn = import_react70.useCallback(({
146785
+ const handleSubagentSpawn = import_react73.useCallback(({
146412
146786
  subagentId,
146413
146787
  input
146414
146788
  }) => {
@@ -146428,7 +146802,7 @@ function Pentest({ sessionId }) {
146428
146802
  }
146429
146803
  }));
146430
146804
  }, []);
146431
- const handleSubagentComplete = import_react70.useCallback(({ subagentId, status }) => {
146805
+ const handleSubagentComplete = import_react73.useCallback(({ subagentId, status }) => {
146432
146806
  if (!subagentId.startsWith("pentest-agent-"))
146433
146807
  return;
146434
146808
  setPentestAgents((prev) => {
@@ -146441,7 +146815,7 @@ function Pentest({ sessionId }) {
146441
146815
  };
146442
146816
  });
146443
146817
  }, []);
146444
- const appendPanelText = import_react70.useCallback((source, text2) => {
146818
+ const appendPanelText = import_react73.useCallback((source, text2) => {
146445
146819
  if (panelSourceRef.current !== source) {
146446
146820
  panelTextRef.current = "";
146447
146821
  panelSourceRef.current = source;
@@ -146466,7 +146840,7 @@ function Pentest({ sessionId }) {
146466
146840
  ];
146467
146841
  });
146468
146842
  }, []);
146469
- const appendPentestText = import_react70.useCallback((subagentId, text2) => {
146843
+ const appendPentestText = import_react73.useCallback((subagentId, text2) => {
146470
146844
  ensurePentestAgent(subagentId);
146471
146845
  if (!pentestTextRefs.current[subagentId]) {
146472
146846
  pentestTextRefs.current[subagentId] = "";
@@ -146499,7 +146873,7 @@ function Pentest({ sessionId }) {
146499
146873
  };
146500
146874
  });
146501
146875
  }, [ensurePentestAgent]);
146502
- const addPanelToolCall = import_react70.useCallback((toolCallId, toolName, args) => {
146876
+ const addPanelToolCall = import_react73.useCallback((toolCallId, toolName, args) => {
146503
146877
  panelTextRef.current = "";
146504
146878
  panelSourceRef.current = null;
146505
146879
  const description = typeof args?.toolCallDescription === "string" ? args.toolCallDescription : toolName;
@@ -146518,7 +146892,7 @@ function Pentest({ sessionId }) {
146518
146892
  return [...prev, msg];
146519
146893
  });
146520
146894
  }, []);
146521
- const addPentestToolCall = import_react70.useCallback((subagentId, toolCallId, toolName, args) => {
146895
+ const addPentestToolCall = import_react73.useCallback((subagentId, toolCallId, toolName, args) => {
146522
146896
  pentestTextRefs.current[subagentId] = "";
146523
146897
  ensurePentestAgent(subagentId);
146524
146898
  const description = typeof args?.toolCallDescription === "string" ? args.toolCallDescription : toolName;
@@ -146563,12 +146937,12 @@ function Pentest({ sessionId }) {
146563
146937
  }
146564
146938
  ];
146565
146939
  };
146566
- const updatePanelToolResult = import_react70.useCallback((toolCallId, toolName, result) => {
146940
+ const updatePanelToolResult = import_react73.useCallback((toolCallId, toolName, result) => {
146567
146941
  panelTextRef.current = "";
146568
146942
  panelSourceRef.current = null;
146569
146943
  setPanelMessages((prev) => toolResultUpdater(prev, toolCallId, toolName, result));
146570
146944
  }, []);
146571
- const updatePentestToolResult = import_react70.useCallback((subagentId, toolCallId, toolName, result) => {
146945
+ const updatePentestToolResult = import_react73.useCallback((subagentId, toolCallId, toolName, result) => {
146572
146946
  pentestTextRefs.current[subagentId] = "";
146573
146947
  setPentestAgents((prev) => {
146574
146948
  const agent = prev[subagentId];
@@ -146583,7 +146957,7 @@ function Pentest({ sessionId }) {
146583
146957
  };
146584
146958
  });
146585
146959
  }, []);
146586
- const startPentest = import_react70.useCallback(async (s) => {
146960
+ const startPentest = import_react73.useCallback(async (s) => {
146587
146961
  setPhase("discovery");
146588
146962
  setStartTime(new Date);
146589
146963
  setIsExecuting(true);
@@ -146679,7 +147053,7 @@ function Pentest({ sessionId }) {
146679
147053
  handleSubagentSpawn,
146680
147054
  handleSubagentComplete
146681
147055
  ]);
146682
- import_react70.useEffect(() => {
147056
+ import_react73.useEffect(() => {
146683
147057
  if (session && phase === "loading") {
146684
147058
  startPentest(session);
146685
147059
  }
@@ -146741,11 +147115,11 @@ function Pentest({ sessionId }) {
146741
147115
  }
146742
147116
  }
146743
147117
  });
146744
- const openReport = import_react70.useCallback(() => {
147118
+ const openReport = import_react73.useCallback(() => {
146745
147119
  if (!session)
146746
147120
  return;
146747
147121
  const reportPath = join17(session.rootPath, "pentest-report.md");
146748
- if (existsSync16(reportPath)) {
147122
+ if (existsSync17(reportPath)) {
146749
147123
  exec3(`open "${reportPath}"`);
146750
147124
  } else {
146751
147125
  exec3(`open "${session.rootPath}"`);
@@ -146933,7 +147307,7 @@ function OrchestratorPanel({
146933
147307
  }) {
146934
147308
  const { colors: colors2 } = useTheme();
146935
147309
  const isRunning = phase !== "loading" && phase !== "completed" && phase !== "error";
146936
- const assetSummary = import_react70.useMemo(() => {
147310
+ const assetSummary = import_react73.useMemo(() => {
146937
147311
  const byType = {};
146938
147312
  for (const a of assets) {
146939
147313
  const key = a.assetType;
@@ -147182,7 +147556,7 @@ function AgentCardGrid({
147182
147556
  onSelectAgent
147183
147557
  }) {
147184
147558
  const { colors: colors2 } = useTheme();
147185
- const rows = import_react70.useMemo(() => {
147559
+ const rows = import_react73.useMemo(() => {
147186
147560
  const result = [];
147187
147561
  for (let i = 0;i < agents.length; i += 2) {
147188
147562
  result.push(agents.slice(i, i + 2));
@@ -147230,14 +147604,14 @@ function AgentCard({
147230
147604
  completed: colors2.primary,
147231
147605
  failed: colors2.error
147232
147606
  }[agent.status];
147233
- const lastActivity = import_react70.useMemo(() => {
147607
+ const lastActivity = import_react73.useMemo(() => {
147234
147608
  const last = agent.messages[agent.messages.length - 1];
147235
147609
  if (!last)
147236
147610
  return "Starting...";
147237
147611
  const text2 = typeof last.content === "string" ? last.content.replace(/\n/g, " ").trim() : "Working...";
147238
147612
  return text2.length > 50 ? text2.substring(0, 47) + "..." : text2;
147239
147613
  }, [agent.messages]);
147240
- const toolCalls = import_react70.useMemo(() => agent.messages.filter((m3) => m3.role === "tool").length, [agent.messages]);
147614
+ const toolCalls = import_react73.useMemo(() => agent.messages.filter((m3) => m3.role === "tool").length, [agent.messages]);
147241
147615
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
147242
147616
  flexGrow: 1,
147243
147617
  flexBasis: 0,
@@ -147424,8 +147798,8 @@ function MetricsBar({
147424
147798
  isExecuting
147425
147799
  }) {
147426
147800
  const { colors: colors2 } = useTheme();
147427
- const [now2, setNow] = import_react70.useState(Date.now());
147428
- import_react70.useEffect(() => {
147801
+ const [now2, setNow] = import_react73.useState(Date.now());
147802
+ import_react73.useEffect(() => {
147429
147803
  if (!isExecuting)
147430
147804
  return;
147431
147805
  const interval = setInterval(() => setNow(Date.now()), 1000);
@@ -147568,7 +147942,7 @@ function MetricsBar({
147568
147942
  }
147569
147943
 
147570
147944
  // src/tui/components/operator-dashboard/index.tsx
147571
- var import_react75 = __toESM(require_react(), 1);
147945
+ var import_react78 = __toESM(require_react(), 1);
147572
147946
 
147573
147947
  // src/core/api/offesecAgent.ts
147574
147948
  init_offensiveSecurityAgent();
@@ -147665,7 +148039,7 @@ function InlineApprovalPrompt2({ approval }) {
147665
148039
  }
147666
148040
 
147667
148041
  // src/tui/components/chat/loading-indicator.tsx
147668
- var import_react72 = __toESM(require_react(), 1);
148042
+ var import_react75 = __toESM(require_react(), 1);
147669
148043
  var SPINNER_FRAMES2 = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
147670
148044
  var SPINNER_INTERVAL2 = 80;
147671
148045
  var DOTS_FRAMES = ["", ".", "..", "..."];
@@ -147676,15 +148050,15 @@ function LoadingIndicator({
147676
148050
  toolName
147677
148051
  }) {
147678
148052
  const { colors: colors2 } = useTheme();
147679
- const [spinnerFrame, setSpinnerFrame] = import_react72.useState(0);
147680
- const [dotsFrame, setDotsFrame] = import_react72.useState(0);
147681
- import_react72.useEffect(() => {
148053
+ const [spinnerFrame, setSpinnerFrame] = import_react75.useState(0);
148054
+ const [dotsFrame, setDotsFrame] = import_react75.useState(0);
148055
+ import_react75.useEffect(() => {
147682
148056
  const interval = setInterval(() => {
147683
148057
  setSpinnerFrame((f) => (f + 1) % SPINNER_FRAMES2.length);
147684
148058
  }, SPINNER_INTERVAL2);
147685
148059
  return () => clearInterval(interval);
147686
148060
  }, []);
147687
- import_react72.useEffect(() => {
148061
+ import_react75.useEffect(() => {
147688
148062
  const interval = setInterval(() => {
147689
148063
  setDotsFrame((f) => (f + 1) % DOTS_FRAMES.length);
147690
148064
  }, DOTS_INTERVAL);
@@ -147954,7 +148328,7 @@ function MessageList({
147954
148328
  }
147955
148329
 
147956
148330
  // src/tui/components/chat/input-area.tsx
147957
- var import_react73 = __toESM(require_react(), 1);
148331
+ var import_react76 = __toESM(require_react(), 1);
147958
148332
  function NormalInputAreaInner({
147959
148333
  value,
147960
148334
  onChange,
@@ -147969,17 +148343,17 @@ function NormalInputAreaInner({
147969
148343
  }) {
147970
148344
  const { colors: colors2 } = useTheme();
147971
148345
  const { inputValue, setInputValue } = useInput();
147972
- const promptRef = import_react73.useRef(null);
147973
- const isExternalUpdate = import_react73.useRef(false);
148346
+ const promptRef = import_react76.useRef(null);
148347
+ const isExternalUpdate = import_react76.useRef(false);
147974
148348
  const isDisabled = status === "running";
147975
- import_react73.useEffect(() => {
148349
+ import_react76.useEffect(() => {
147976
148350
  if (value !== inputValue) {
147977
148351
  isExternalUpdate.current = true;
147978
148352
  setInputValue(value);
147979
148353
  promptRef.current?.setValue(value);
147980
148354
  }
147981
148355
  }, [value]);
147982
- import_react73.useEffect(() => {
148356
+ import_react76.useEffect(() => {
147983
148357
  if (isExternalUpdate.current) {
147984
148358
  isExternalUpdate.current = false;
147985
148359
  return;
@@ -148129,7 +148503,7 @@ function ApprovalInputArea2({
148129
148503
  lastDeclineNote
148130
148504
  }) {
148131
148505
  const { colors: colors2 } = useTheme();
148132
- const [focusedElement, setFocusedElement] = import_react73.useState(0);
148506
+ const [focusedElement, setFocusedElement] = import_react76.useState(0);
148133
148507
  const tierColor = getTierColor(colors2, approval.tier);
148134
148508
  useKeyboard((key) => {
148135
148509
  if (key.name === "up") {
@@ -148251,20 +148625,20 @@ function OperatorDashboard({
148251
148625
  const route = useRoute();
148252
148626
  const config4 = useConfig();
148253
148627
  const { model, setThinking, setIsExecuting } = useAgent();
148254
- const [session, setSession] = import_react75.useState(null);
148255
- const [loading, setLoading] = import_react75.useState(true);
148256
- const [error41, setError] = import_react75.useState(null);
148257
- const [status, setStatus] = import_react75.useState("idle");
148258
- const abortControllerRef = import_react75.useRef(null);
148259
- const [messages, setMessages] = import_react75.useState([]);
148260
- const textRef = import_react75.useRef("");
148261
- const [inputValue, setInputValue] = import_react75.useState("");
148262
- const [operatorState, setOperatorState] = import_react75.useState(() => createInitialOperatorState("manual", 2));
148263
- const [pendingApprovals] = import_react75.useState([]);
148264
- const [lastApprovedAction] = import_react75.useState(null);
148265
- const [verboseMode, setVerboseMode] = import_react75.useState(false);
148266
- const [expandedLogs, setExpandedLogs] = import_react75.useState(false);
148267
- import_react75.useEffect(() => {
148628
+ const [session, setSession] = import_react78.useState(null);
148629
+ const [loading, setLoading] = import_react78.useState(true);
148630
+ const [error41, setError] = import_react78.useState(null);
148631
+ const [status, setStatus] = import_react78.useState("idle");
148632
+ const abortControllerRef = import_react78.useRef(null);
148633
+ const [messages, setMessages] = import_react78.useState([]);
148634
+ const textRef = import_react78.useRef("");
148635
+ const [inputValue, setInputValue] = import_react78.useState("");
148636
+ const [operatorState, setOperatorState] = import_react78.useState(() => createInitialOperatorState("manual", 2));
148637
+ const [pendingApprovals] = import_react78.useState([]);
148638
+ const [lastApprovedAction] = import_react78.useState(null);
148639
+ const [verboseMode, setVerboseMode] = import_react78.useState(false);
148640
+ const [expandedLogs, setExpandedLogs] = import_react78.useState(false);
148641
+ import_react78.useEffect(() => {
148268
148642
  async function loadSession() {
148269
148643
  try {
148270
148644
  const s = await sessions.get(sessionId);
@@ -148296,7 +148670,7 @@ function OperatorDashboard({
148296
148670
  }
148297
148671
  loadSession();
148298
148672
  }, [sessionId, isResume]);
148299
- const appendText = import_react75.useCallback((text2) => {
148673
+ const appendText = import_react78.useCallback((text2) => {
148300
148674
  textRef.current += text2;
148301
148675
  const accumulated = textRef.current;
148302
148676
  setMessages((prev) => {
@@ -148312,7 +148686,7 @@ function OperatorDashboard({
148312
148686
  ];
148313
148687
  });
148314
148688
  }, []);
148315
- const addToolCall = import_react75.useCallback((toolCallId, toolName, args) => {
148689
+ const addToolCall = import_react78.useCallback((toolCallId, toolName, args) => {
148316
148690
  textRef.current = "";
148317
148691
  setMessages((prev) => [
148318
148692
  ...prev,
@@ -148327,7 +148701,7 @@ function OperatorDashboard({
148327
148701
  }
148328
148702
  ]);
148329
148703
  }, []);
148330
- const updateToolResult = import_react75.useCallback((toolCallId, _toolName, result) => {
148704
+ const updateToolResult = import_react78.useCallback((toolCallId, _toolName, result) => {
148331
148705
  textRef.current = "";
148332
148706
  setMessages((prev) => {
148333
148707
  const idx = prev.findIndex((m3) => isToolMessage(m3) && m3.toolCallId === toolCallId);
@@ -148338,7 +148712,7 @@ function OperatorDashboard({
148338
148712
  return updated;
148339
148713
  });
148340
148714
  }, []);
148341
- const runAgent = import_react75.useCallback(async (prompt) => {
148715
+ const runAgent = import_react78.useCallback(async (prompt) => {
148342
148716
  if (!session)
148343
148717
  return;
148344
148718
  setStatus("running");
@@ -148417,13 +148791,13 @@ function OperatorDashboard({
148417
148791
  setThinking,
148418
148792
  setIsExecuting
148419
148793
  ]);
148420
- const handleSubmit = import_react75.useCallback((value) => {
148794
+ const handleSubmit = import_react78.useCallback((value) => {
148421
148795
  if (!value.trim() || status === "running")
148422
148796
  return;
148423
148797
  setInputValue("");
148424
148798
  runAgent(value.trim());
148425
148799
  }, [status, runAgent]);
148426
- const handleAbort = import_react75.useCallback(() => {
148800
+ const handleAbort = import_react78.useCallback(() => {
148427
148801
  if (abortControllerRef.current) {
148428
148802
  abortControllerRef.current.abort();
148429
148803
  abortControllerRef.current = null;
@@ -148634,7 +149008,7 @@ Session paths:
148634
149008
  }
148635
149009
 
148636
149010
  // src/tui/components/commands/theme-picker.tsx
148637
- var import_react77 = __toESM(require_react(), 1);
149011
+ var import_react80 = __toESM(require_react(), 1);
148638
149012
  function ThemePicker() {
148639
149013
  const dimensions = useTerminalDimensions();
148640
149014
  const route = useRoute();
@@ -148647,15 +149021,15 @@ function ThemePicker() {
148647
149021
  toggleMode,
148648
149022
  setMode
148649
149023
  } = useTheme();
148650
- const [selectedIndex, setSelectedIndex] = import_react77.useState(() => Math.max(0, availableThemes.indexOf(theme.name)));
148651
- const originalThemeRef = import_react77.useRef(theme.name);
148652
- const originalModeRef = import_react77.useRef(mode);
148653
- const handleClose = import_react77.useCallback(() => {
149024
+ const [selectedIndex, setSelectedIndex] = import_react80.useState(() => Math.max(0, availableThemes.indexOf(theme.name)));
149025
+ const originalThemeRef = import_react80.useRef(theme.name);
149026
+ const originalModeRef = import_react80.useRef(mode);
149027
+ const handleClose = import_react80.useCallback(() => {
148654
149028
  setTheme(originalThemeRef.current);
148655
149029
  setMode(originalModeRef.current);
148656
149030
  route.navigate({ type: "base", path: "home" });
148657
149031
  }, [setTheme, setMode, route]);
148658
- const handleConfirm = import_react77.useCallback(async () => {
149032
+ const handleConfirm = import_react80.useCallback(async () => {
148659
149033
  const currentThemeName = availableThemes[selectedIndex];
148660
149034
  if (currentThemeName) {
148661
149035
  await config.update({ theme: currentThemeName });
@@ -151182,52 +151556,47 @@ async function detectTerminalMode(timeoutMs = 1000) {
151182
151556
  }
151183
151557
 
151184
151558
  // src/tui/index.tsx
151185
- function App(props) {
151186
- const { appConfig, initialTheme, initialMode } = props;
151187
- const [focusIndex, setFocusIndex] = import_react80.useState(0);
151188
- const [cwd, setCwd] = import_react80.useState(process.cwd());
151189
- const [ctrlCPressTime, setCtrlCPressTime] = import_react80.useState(null);
151190
- const [showExitWarning, setShowExitWarning] = import_react80.useState(false);
151191
- const [inputKey, setInputKey] = import_react80.useState(0);
151192
- const [showSessionsDialog, setShowSessionsDialog] = import_react80.useState(false);
151193
- const [showShortcutsDialog, setShowShortcutsDialog] = import_react80.useState(false);
151559
+ function App({ appConfig }) {
151560
+ const [focusIndex, setFocusIndex] = import_react83.useState(0);
151561
+ const [cwd, setCwd] = import_react83.useState(process.cwd());
151562
+ const [ctrlCPressTime, setCtrlCPressTime] = import_react83.useState(null);
151563
+ const [showExitWarning, setShowExitWarning] = import_react83.useState(false);
151564
+ const [inputKey, setInputKey] = import_react83.useState(0);
151565
+ const [showSessionsDialog, setShowSessionsDialog] = import_react83.useState(false);
151566
+ const [showShortcutsDialog, setShowShortcutsDialog] = import_react83.useState(false);
151194
151567
  const navigableItems = ["command-input"];
151195
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ThemeProvider, {
151196
- initialTheme,
151197
- initialMode,
151198
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ConfigProvider, {
151199
- config: appConfig,
151200
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SessionProvider, {
151201
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteProvider, {
151202
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FocusProvider, {
151203
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(InputProvider, {
151204
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(DialogProvider, {
151205
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AgentProvider, {
151206
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(CommandProvider, {
151207
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(KeybindingProvider, {
151208
- deps: {
151209
- ctrlCPressTime,
151210
- setCtrlCPressTime,
151211
- setShowExitWarning,
151212
- setInputKey,
151213
- setShowSessionsDialog,
151214
- setShowShortcutsDialog,
151215
- setFocusIndex,
151216
- navigableItems
151217
- },
151218
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AppContent, {
151219
- focusIndex,
151220
- showSessionsDialog,
151221
- setShowSessionsDialog,
151222
- showShortcutsDialog,
151223
- setShowShortcutsDialog,
151224
- cwd,
151225
- setCtrlCPressTime,
151226
- showExitWarning,
151227
- setShowExitWarning,
151228
- inputKey,
151229
- setInputKey
151230
- }, undefined, false, undefined, this)
151568
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ConfigProvider, {
151569
+ config: appConfig,
151570
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SessionProvider, {
151571
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteProvider, {
151572
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FocusProvider, {
151573
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(InputProvider, {
151574
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(DialogProvider, {
151575
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AgentProvider, {
151576
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(CommandProvider, {
151577
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(KeybindingProvider, {
151578
+ deps: {
151579
+ ctrlCPressTime,
151580
+ setCtrlCPressTime,
151581
+ setShowExitWarning,
151582
+ setInputKey,
151583
+ setShowSessionsDialog,
151584
+ setShowShortcutsDialog,
151585
+ setFocusIndex,
151586
+ navigableItems
151587
+ },
151588
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AppContent, {
151589
+ focusIndex,
151590
+ showSessionsDialog,
151591
+ setShowSessionsDialog,
151592
+ showShortcutsDialog,
151593
+ setShowShortcutsDialog,
151594
+ cwd,
151595
+ setCtrlCPressTime,
151596
+ showExitWarning,
151597
+ setShowExitWarning,
151598
+ inputKey,
151599
+ setInputKey
151231
151600
  }, undefined, false, undefined, this)
151232
151601
  }, undefined, false, undefined, this)
151233
151602
  }, undefined, false, undefined, this)
@@ -151257,7 +151626,7 @@ function AppContent({
151257
151626
  const { colors: colors2 } = useTheme();
151258
151627
  const { refocusPrompt } = useFocus();
151259
151628
  const { setExternalDialogOpen } = useDialog();
151260
- import_react80.useEffect(() => {
151629
+ import_react83.useEffect(() => {
151261
151630
  if (route.data.type !== "base")
151262
151631
  return;
151263
151632
  if (!config4.data.responsibleUseAccepted && route.data.path !== "disclosure") {
@@ -151266,7 +151635,7 @@ function AppContent({
151266
151635
  route.navigate({ type: "base", path: "providers" });
151267
151636
  }
151268
151637
  }, [config4.data.responsibleUseAccepted, route.data]);
151269
- import_react80.useEffect(() => {
151638
+ import_react83.useEffect(() => {
151270
151639
  if (showExitWarning) {
151271
151640
  const timer = setTimeout(() => {
151272
151641
  setShowExitWarning(false);
@@ -151449,17 +151818,28 @@ async function main2() {
151449
151818
  process.on("uncaughtException", (err) => {
151450
151819
  renderer.destroy();
151451
151820
  console.error("Uncaught exception:", err);
151821
+ writeErrorLog(err, "UNCAUGHT");
151452
151822
  process.exit(1);
151453
151823
  });
151454
151824
  process.on("unhandledRejection", (reason) => {
151455
151825
  renderer.destroy();
151456
151826
  console.error("Unhandled rejection:", reason);
151827
+ writeErrorLog(reason, "UNHANDLED_REJECTION");
151457
151828
  process.exit(1);
151458
151829
  });
151459
- createRoot(renderer).render(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(App, {
151460
- appConfig,
151830
+ createRoot(renderer).render(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ThemeProvider, {
151461
151831
  initialTheme: themeName,
151462
- initialMode: mode
151832
+ initialMode: mode,
151833
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToastProvider, {
151834
+ children: [
151835
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ErrorBoundary2, {
151836
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(App, {
151837
+ appConfig
151838
+ }, undefined, false, undefined, this)
151839
+ }, undefined, false, undefined, this),
151840
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToastContainer, {}, undefined, false, undefined, this)
151841
+ ]
151842
+ }, undefined, true, undefined, this)
151463
151843
  }, undefined, false, undefined, this));
151464
151844
  }
151465
151845
  main2();