@pensar/apex 0.0.91 → 0.0.92-canary.1e2cfc8f

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 +594 -524
  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.91",
31974
+ version: "0.0.92-canary.1e2cfc8f",
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",
@@ -32165,7 +32165,6 @@ async function get() {
32165
32165
  inceptionAPIKey: process.env.INCEPTION_API_KEY ?? parsedConfig.inceptionAPIKey,
32166
32166
  bedrockAPIKey: process.env.BEDROCK_API_KEY ?? parsedConfig.bedrockAPIKey,
32167
32167
  pensarAPIKey: process.env.PENSAR_API_KEY ?? parsedConfig.pensarAPIKey,
32168
- pensarApiUrl: process.env.PENSAR_API_URL ?? parsedConfig.pensarApiUrl,
32169
32168
  daytonaAPIKey: process.env.DAYTONA_API_KEY ?? parsedConfig.daytonaAPIKey,
32170
32169
  daytonaOrgId: process.env.DAYTONA_ORG_ID ?? parsedConfig.daytonaOrgId,
32171
32170
  runloopAPIKey: process.env.RUNLOOP_API_KEY ?? parsedConfig.runloopAPIKey
@@ -88130,13 +88129,13 @@ __export(exports_constants, {
88130
88129
  PENSAR_CONSOLE_BASE_URL: () => PENSAR_CONSOLE_BASE_URL,
88131
88130
  PENSAR_API_BASE_URL: () => PENSAR_API_BASE_URL
88132
88131
  });
88133
- function getPensarApiUrl(config2) {
88134
- return config2?.pensarApiUrl || process.env.PENSAR_API_URL || PENSAR_API_BASE_URL;
88132
+ function getPensarApiUrl() {
88133
+ return PENSAR_API_BASE_URL;
88135
88134
  }
88136
88135
  function getPensarConsoleUrl() {
88137
88136
  return process.env.PENSAR_CONSOLE_URL || PENSAR_CONSOLE_BASE_URL;
88138
88137
  }
88139
- var PENSAR_API_BASE_URL = "https://api.console.pensar.dev", PENSAR_CONSOLE_BASE_URL = "https://console.pensar.dev";
88138
+ var PENSAR_API_BASE_URL = "https://api.pensar.dev", PENSAR_CONSOLE_BASE_URL = "https://console.pensar.dev";
88140
88139
 
88141
88140
  // src/core/config/index.ts
88142
88141
  var config2;
@@ -88200,7 +88199,7 @@ async function ensureValidToken(cfg) {
88200
88199
  return { token: cfg.accessToken, type: "workos" };
88201
88200
  }
88202
88201
  if (cfg.refreshToken) {
88203
- const clientId = await fetchWorkOSClientId(cfg);
88202
+ const clientId = await fetchWorkOSClientId();
88204
88203
  if (clientId) {
88205
88204
  const newToken = await refreshAccessToken(clientId, cfg.refreshToken);
88206
88205
  if (newToken) {
@@ -88214,12 +88213,12 @@ async function ensureValidToken(cfg) {
88214
88213
  }
88215
88214
  return null;
88216
88215
  }
88217
- async function fetchWorkOSClientId(cfg) {
88216
+ async function fetchWorkOSClientId() {
88218
88217
  if (cachedClientId)
88219
88218
  return cachedClientId;
88220
88219
  try {
88221
88220
  const { getPensarApiUrl: getPensarApiUrl2 } = await Promise.resolve().then(() => exports_constants);
88222
- const apiUrl = getPensarApiUrl2(cfg);
88221
+ const apiUrl = getPensarApiUrl2();
88223
88222
  const response = await fetch(`${apiUrl}/api/cli/config`);
88224
88223
  if (!response.ok)
88225
88224
  return null;
@@ -88244,7 +88243,6 @@ function buildAuthConfig(cfg) {
88244
88243
  openRouterAPIKey: cfg.openRouterAPIKey ?? undefined,
88245
88244
  inceptionAPIKey: cfg.inceptionAPIKey ?? undefined,
88246
88245
  pensarAPIKey: cfg.pensarAPIKey ?? undefined,
88247
- pensarApiUrl: cfg.pensarApiUrl ?? undefined,
88248
88246
  accessToken: cfg.accessToken ?? undefined,
88249
88247
  refreshToken: cfg.refreshToken ?? undefined,
88250
88248
  workspaceId: cfg.workspaceId ?? undefined,
@@ -88320,7 +88318,7 @@ function getProviderModel(model, authConfig) {
88320
88318
  if (!pensarApiKey && !hasWorkOSAuth) {
88321
88319
  throw new Error("Pensar not configured. Run /auth to connect to Pensar Console.");
88322
88320
  }
88323
- const pensarApiUrl = authConfig?.pensarApiUrl || getPensarApiUrl();
88321
+ const pensarApiUrl = getPensarApiUrl();
88324
88322
  const bedrockModelId = model.startsWith("pensar:") ? model.slice(7) : model;
88325
88323
  if (process.env.PENSAR_DEBUG === "1" || process.env.PENSAR_DEBUG === "true") {
88326
88324
  console.log(`[pensar] getProviderModel: ${model} → bedrock:${bedrockModelId} via ${pensarApiUrl}`);
@@ -88336,8 +88334,7 @@ function getProviderModel(model, authConfig) {
88336
88334
  return ensureValidToken({
88337
88335
  accessToken: freshConfig.accessToken,
88338
88336
  refreshToken: freshConfig.refreshToken,
88339
- pensarAPIKey: freshConfig.pensarAPIKey,
88340
- pensarApiUrl: freshConfig.pensarApiUrl
88337
+ pensarAPIKey: freshConfig.pensarAPIKey
88341
88338
  });
88342
88339
  };
88343
88340
  }
@@ -89526,44 +89523,22 @@ import {
89526
89523
  readdirSync as readdirSync2
89527
89524
  } from "fs";
89528
89525
  import { join as join4 } from "path";
89529
- function mapToSavedMessage(msg) {
89530
- const m2 = msg;
89531
- if (typeof m2.content === "string") {
89532
- return { role: m2.role, content: m2.content };
89533
- }
89534
- if (Array.isArray(m2.content)) {
89535
- const mapped = m2.content.map((part) => {
89536
- if (part.type === "tool-call") {
89537
- return {
89538
- type: "tool-call",
89539
- toolCallId: part.toolCallId,
89540
- toolName: part.toolName,
89541
- input: part.args ?? part.input
89542
- };
89543
- }
89544
- if (part.type === "tool-result") {
89545
- return {
89546
- type: "tool-result",
89547
- toolCallId: part.toolCallId,
89548
- toolName: part.toolName,
89549
- output: part.result ?? part.output
89550
- };
89551
- }
89552
- return {
89553
- type: "text",
89554
- text: part.text ?? ""
89555
- };
89556
- });
89557
- return { role: m2.role, content: mapped };
89526
+ function loadSubagentMessages(session, agentName) {
89527
+ const filePath = join4(session.rootPath, SUBAGENTS_DIR, `${agentName}.json`);
89528
+ if (!existsSync8(filePath))
89529
+ return [];
89530
+ try {
89531
+ const data = JSON.parse(readFileSync3(filePath, "utf-8"));
89532
+ return data.messages;
89533
+ } catch {
89534
+ return [];
89558
89535
  }
89559
- return { role: m2.role, content: String(m2.content) };
89560
89536
  }
89561
89537
  function saveSubagentData(session, data) {
89562
89538
  const subagentsDir = join4(session.rootPath, SUBAGENTS_DIR);
89563
89539
  mkdirSync2(subagentsDir, { recursive: true });
89564
89540
  let toolCallCount = 0;
89565
89541
  let stepCount = 0;
89566
- const savedMessages = [];
89567
89542
  for (const msg of data.messages) {
89568
89543
  if (msg.role === "assistant") {
89569
89544
  stepCount++;
@@ -89574,12 +89549,10 @@ function saveSubagentData(session, data) {
89574
89549
  }
89575
89550
  }
89576
89551
  }
89577
- savedMessages.push(mapToSavedMessage(msg));
89578
89552
  }
89579
- const now2 = new Date;
89580
89553
  const savedData = {
89581
89554
  agentName: data.agentName,
89582
- timestamp: now2.toISOString(),
89555
+ timestamp: new Date().toISOString(),
89583
89556
  target: data.target,
89584
89557
  objective: data.objective,
89585
89558
  vulnerabilityClass: data.vulnerabilityClass,
@@ -89588,16 +89561,24 @@ function saveSubagentData(session, data) {
89588
89561
  findingsCount: data.findingsCount ?? 0,
89589
89562
  status: data.status,
89590
89563
  error: data.error,
89591
- messages: savedMessages
89564
+ messages: data.messages
89592
89565
  };
89593
- const ts = now2.toISOString().replace(/[:.]/g, "-");
89594
- const filename = `${data.agentName}-${ts}.json`;
89595
- writeFileSync2(join4(subagentsDir, filename), JSON.stringify(savedData, null, 2));
89566
+ writeFileSync2(join4(subagentsDir, `${data.agentName}.json`), JSON.stringify(savedData, null, 2));
89596
89567
  }
89597
89568
  function writeAgentManifest(session, entries2) {
89598
89569
  const manifestPath = join4(session.rootPath, MANIFEST_FILE);
89599
89570
  writeFileSync2(manifestPath, JSON.stringify(entries2, null, 2));
89600
89571
  }
89572
+ function readAgentManifest(session) {
89573
+ const manifestPath = join4(session.rootPath, MANIFEST_FILE);
89574
+ if (!existsSync8(manifestPath))
89575
+ return [];
89576
+ try {
89577
+ return JSON.parse(readFileSync3(manifestPath, "utf-8"));
89578
+ } catch {
89579
+ return [];
89580
+ }
89581
+ }
89601
89582
  function buildManifestEntries(targets) {
89602
89583
  return targets.map((t2, i) => ({
89603
89584
  id: `pentest-agent-${i + 1}`,
@@ -89610,18 +89591,31 @@ function buildManifestEntries(targets) {
89610
89591
  }));
89611
89592
  }
89612
89593
  function finalizeManifest(session, entries2, results) {
89613
- const finalManifest = entries2.map((entry, i) => ({
89614
- ...entry,
89615
- status: results[i] != null ? "completed" : "failed",
89616
- completedAt: new Date().toISOString()
89617
- }));
89594
+ const finalManifest = entries2.map((entry, i) => {
89595
+ if (entry.status === "completed")
89596
+ return entry;
89597
+ return {
89598
+ ...entry,
89599
+ status: results[i] != null ? "completed" : "failed",
89600
+ completedAt: new Date().toISOString()
89601
+ };
89602
+ });
89618
89603
  writeAgentManifest(session, finalManifest);
89619
89604
  }
89605
+ function updateManifestEntryStatus(session, agentId, status) {
89606
+ const manifest = readAgentManifest(session);
89607
+ const updated = manifest.map((e) => e.id === agentId ? { ...e, status, completedAt: new Date().toISOString() } : e);
89608
+ writeAgentManifest(session, updated);
89609
+ }
89610
+ function getCompletedAgentIds(session) {
89611
+ const manifest = readAgentManifest(session);
89612
+ return new Set(manifest.filter((e) => e.id.startsWith("pentest-agent-") && e.status === "completed").map((e) => e.id));
89613
+ }
89620
89614
  function parseSubagentFilename(filename) {
89621
89615
  if (filename.startsWith("attack-surface-agent")) {
89622
89616
  return { agentType: "attack-surface", name: "Attack Surface Discovery" };
89623
89617
  }
89624
- const pentestMatch = filename.match(/^pentest-agent-(\d+)-/);
89618
+ const pentestMatch = filename.match(/^pentest-agent-(\d+)/);
89625
89619
  if (pentestMatch) {
89626
89620
  return {
89627
89621
  agentType: "pentest",
@@ -89673,7 +89667,8 @@ function convertMessagesToUI(messages, baseTime) {
89673
89667
  createdAt
89674
89668
  });
89675
89669
  } else if (part.type === "tool-call") {
89676
- const toolDescription = typeof part.input?.toolCallDescription === "string" ? part.input.toolCallDescription : part.toolName || "tool";
89670
+ const input = part.input;
89671
+ const toolDescription = typeof input?.toolCallDescription === "string" ? input.toolCallDescription : part.toolName || "tool";
89677
89672
  const result = part.toolCallId ? toolResults.get(part.toolCallId) : undefined;
89678
89673
  uiMessages.push({
89679
89674
  role: "tool",
@@ -89681,7 +89676,7 @@ function convertMessagesToUI(messages, baseTime) {
89681
89676
  createdAt,
89682
89677
  toolCallId: part.toolCallId,
89683
89678
  toolName: part.toolName,
89684
- args: part.input,
89679
+ args: input,
89685
89680
  result,
89686
89681
  status: "completed"
89687
89682
  });
@@ -89692,8 +89687,7 @@ function convertMessagesToUI(messages, baseTime) {
89692
89687
  return uiMessages;
89693
89688
  }
89694
89689
  function convertModelMessagesToUI(messages) {
89695
- const saved = messages.map((m2) => mapToSavedMessage(m2));
89696
- return convertMessagesToUI(saved, new Date);
89690
+ return convertMessagesToUI(messages, new Date);
89697
89691
  }
89698
89692
  function loadSubagents(rootPath) {
89699
89693
  const subagentsPath = join4(rootPath, SUBAGENTS_DIR);
@@ -89701,11 +89695,7 @@ function loadSubagents(rootPath) {
89701
89695
  const agentNameIndex = new Map;
89702
89696
  if (existsSync8(subagentsPath)) {
89703
89697
  const files = readdirSync2(subagentsPath).filter((f) => f.endsWith(".json"));
89704
- files.sort((a, b2) => {
89705
- const timeA = a.match(/\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}/)?.[0] || "";
89706
- const timeB = b2.match(/\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}/)?.[0] || "";
89707
- return timeA.localeCompare(timeB);
89708
- });
89698
+ files.sort();
89709
89699
  for (const file2 of files) {
89710
89700
  if (file2.startsWith("orchestrator-"))
89711
89701
  continue;
@@ -89729,9 +89719,9 @@ function loadSubagents(rootPath) {
89729
89719
  }
89730
89720
  break;
89731
89721
  }
89732
- const idx = subagents.length;
89722
+ agentNameIndex.set(data.agentName, subagents.length);
89733
89723
  subagents.push({
89734
- id: `loaded-${file2.replace(".json", "")}`,
89724
+ id: data.agentName,
89735
89725
  name: data.agentName === "attack-surface-agent" ? "Attack Surface Discovery" : name26,
89736
89726
  type: agentType,
89737
89727
  target: data.target || "Unknown",
@@ -89739,7 +89729,6 @@ function loadSubagents(rootPath) {
89739
89729
  createdAt: timestamp,
89740
89730
  status
89741
89731
  });
89742
- agentNameIndex.set(data.agentName, idx);
89743
89732
  } catch (e) {
89744
89733
  console.error(`Failed to load subagent file ${file2}:`, e);
89745
89734
  }
@@ -89787,6 +89776,116 @@ function loadSubagents(rootPath) {
89787
89776
  var SUBAGENTS_DIR = "subagents", MANIFEST_FILE = "agent-manifest.json";
89788
89777
  var init_persistence = () => {};
89789
89778
 
89779
+ // src/core/session/loader.ts
89780
+ import { join as join5 } from "path";
89781
+ import { existsSync as existsSync9, readFileSync as readFileSync4 } from "fs";
89782
+ function loadAttackSurfaceResults(rootPath) {
89783
+ const resultsPath = join5(rootPath, "attack-surface-results.json");
89784
+ if (!existsSync9(resultsPath)) {
89785
+ return null;
89786
+ }
89787
+ try {
89788
+ return JSON.parse(readFileSync4(resultsPath, "utf-8"));
89789
+ } catch (e) {
89790
+ console.error("Failed to load attack surface results:", e);
89791
+ return null;
89792
+ }
89793
+ }
89794
+ function hasReport(rootPath) {
89795
+ const reportPath = join5(rootPath, REPORT_FILENAME_MD);
89796
+ return existsSync9(reportPath);
89797
+ }
89798
+ function createDiscoveryFromLogs(rootPath, session) {
89799
+ const logPath = join5(rootPath, "logs", "streamlined-pentest.log");
89800
+ if (!existsSync9(logPath)) {
89801
+ return null;
89802
+ }
89803
+ try {
89804
+ const logContent = readFileSync4(logPath, "utf-8");
89805
+ const lines = logContent.split(`
89806
+ `).filter(Boolean);
89807
+ const messages = [];
89808
+ for (const line of lines) {
89809
+ const match = line.match(/^(\d{4}-\d{2}-\d{2}T[\d:.]+Z) - \[(\w+)\] (.+)$/);
89810
+ if (!match)
89811
+ continue;
89812
+ const [, timestamp, _level, content] = match;
89813
+ const createdAt = new Date(timestamp);
89814
+ if (content.startsWith("[Tool]")) {
89815
+ const toolMatch = content.match(/\[Tool\] (\w+): (.+)/);
89816
+ if (toolMatch) {
89817
+ messages.push({
89818
+ role: "tool",
89819
+ content: `✓ ${toolMatch[2]}`,
89820
+ createdAt,
89821
+ toolName: toolMatch[1],
89822
+ status: "completed"
89823
+ });
89824
+ }
89825
+ } else if (content.startsWith("[Step")) {
89826
+ const stepMatch = content.match(/\[Step \d+\] (.+)/);
89827
+ if (stepMatch) {
89828
+ messages.push({
89829
+ role: "assistant",
89830
+ content: stepMatch[1],
89831
+ createdAt
89832
+ });
89833
+ }
89834
+ }
89835
+ }
89836
+ if (messages.length === 0) {
89837
+ return null;
89838
+ }
89839
+ return {
89840
+ id: "discovery-from-logs",
89841
+ name: "Attack Surface Discovery",
89842
+ type: "attack-surface",
89843
+ target: session.targets[0] || "Unknown",
89844
+ messages,
89845
+ createdAt: new Date(session.time.created),
89846
+ status: "completed"
89847
+ };
89848
+ } catch (e) {
89849
+ console.error("Failed to parse logs:", e);
89850
+ return null;
89851
+ }
89852
+ }
89853
+ async function loadSessionState(session) {
89854
+ const rootPath = session.rootPath;
89855
+ let subagents = loadSubagents(rootPath);
89856
+ const hasAttackSurfaceAgent = subagents.some((s) => s.type === "attack-surface");
89857
+ if (!hasAttackSurfaceAgent) {
89858
+ const discoveryAgent = createDiscoveryFromLogs(rootPath, session);
89859
+ if (discoveryAgent) {
89860
+ subagents = [discoveryAgent, ...subagents];
89861
+ }
89862
+ }
89863
+ const attackSurfaceResults = loadAttackSurfaceResults(rootPath);
89864
+ const hasReportFile = hasReport(rootPath);
89865
+ const hasDiscoverySubagent = subagents.some((s) => s.type === "attack-surface");
89866
+ const interruptedDuringDiscovery = !attackSurfaceResults && !hasReportFile && hasDiscoverySubagent;
89867
+ if (interruptedDuringDiscovery) {
89868
+ for (let i = 0;i < subagents.length; i++) {
89869
+ if (subagents[i].type === "attack-surface" && subagents[i].status === "completed") {
89870
+ subagents[i] = { ...subagents[i], status: "paused" };
89871
+ }
89872
+ }
89873
+ }
89874
+ const isComplete = hasReportFile;
89875
+ return {
89876
+ session,
89877
+ subagents,
89878
+ attackSurfaceResults,
89879
+ isComplete,
89880
+ hasReport: hasReportFile,
89881
+ interruptedDuringDiscovery
89882
+ };
89883
+ }
89884
+ var init_loader = __esm(() => {
89885
+ init_persistence();
89886
+ init_report();
89887
+ });
89888
+
89790
89889
  // src/core/agents/specialized/attackSurface/prompts.ts
89791
89890
  var SYSTEM = `You are an autonomous attack surface analysis agent. Your mission is to comprehensively map the attack surface of a target and produce a structured report of all discovered assets and pentest objectives.
89792
89891
 
@@ -105652,9 +105751,10 @@ class PlaywrightMcpSession {
105652
105751
  }
105653
105752
  function createBrowserTools(targetUrl, evidenceDir, mode = "pentest", logger, abortSignal, headless) {
105654
105753
  const session = new PlaywrightMcpSession(headless ?? defaultHeadless);
105655
- abortSignal?.addEventListener("abort", () => {
105656
- session.disconnect().catch(() => {});
105657
- });
105754
+ if (abortSignal) {
105755
+ const onAbort = () => session.disconnect().catch(() => {});
105756
+ abortSignal.addEventListener("abort", onAbort, { once: true });
105757
+ }
105658
105758
  if (!existsSync11(evidenceDir)) {
105659
105759
  mkdirSync3(evidenceDir, { recursive: true });
105660
105760
  }
@@ -108517,9 +108617,17 @@ function runScript(runner, scriptPath, timeout, abortSignal) {
108517
108617
  let stderr = "";
108518
108618
  let killed = false;
108519
108619
  let resolved = false;
108620
+ let abortCleanup;
108621
+ if (abortSignal) {
108622
+ const handler = () => killProcess();
108623
+ abortSignal.addEventListener("abort", handler, { once: true });
108624
+ abortCleanup = () => abortSignal.removeEventListener("abort", handler);
108625
+ }
108520
108626
  const safeResolve = (result) => {
108521
108627
  if (!resolved) {
108522
108628
  resolved = true;
108629
+ clearTimeout(timeoutTimer);
108630
+ abortCleanup?.();
108523
108631
  resolve4(result);
108524
108632
  }
108525
108633
  };
@@ -108553,18 +108661,11 @@ function runScript(runner, scriptPath, timeout, abortSignal) {
108553
108661
  stderr += data.toString();
108554
108662
  });
108555
108663
  child.on("close", (code) => {
108556
- clearTimeout(timeoutTimer);
108557
108664
  safeResolve({ stdout, stderr, exitCode: code ?? 1 });
108558
108665
  });
108559
108666
  child.on("error", (err) => {
108560
- clearTimeout(timeoutTimer);
108561
108667
  safeResolve({ stdout, stderr, exitCode: 1 });
108562
108668
  });
108563
- if (abortSignal) {
108564
- const handler = () => killProcess();
108565
- abortSignal.addEventListener("abort", handler, { once: true });
108566
- child.on("close", () => abortSignal.removeEventListener("abort", handler));
108567
- }
108568
108669
  });
108569
108670
  }
108570
108671
  var MAX_POC_ATTEMPTS = 3, createPocInputSchema;
@@ -108799,6 +108900,23 @@ search with flags or a more specific directory if results are truncated.`,
108799
108900
  });
108800
108901
  let stdout = "";
108801
108902
  let stderr = "";
108903
+ let resolved = false;
108904
+ let abortCleanup;
108905
+ if (ctx4.abortSignal) {
108906
+ const abortHandler = () => child.kill("SIGTERM");
108907
+ ctx4.abortSignal.addEventListener("abort", abortHandler, {
108908
+ once: true
108909
+ });
108910
+ abortCleanup = () => ctx4.abortSignal.removeEventListener("abort", abortHandler);
108911
+ }
108912
+ const safeResolve = (result) => {
108913
+ if (resolved)
108914
+ return;
108915
+ resolved = true;
108916
+ clearTimeout(timeout);
108917
+ abortCleanup?.();
108918
+ resolve4(result);
108919
+ };
108802
108920
  const timeout = setTimeout(() => {
108803
108921
  child.kill("SIGTERM");
108804
108922
  }, 30000);
@@ -108809,7 +108927,6 @@ search with flags or a more specific directory if results are truncated.`,
108809
108927
  stderr += data.toString();
108810
108928
  });
108811
108929
  child.on("close", (code) => {
108812
- clearTimeout(timeout);
108813
108930
  const noMatch = code === 1 && stderr === "";
108814
108931
  const matchCount = stdout ? stdout.trimEnd().split(`
108815
108932
  `).length : 0;
@@ -108817,7 +108934,7 @@ search with flags or a more specific directory if results are truncated.`,
108817
108934
  const output = truncated ? `${stdout.substring(0, 50000)}
108818
108935
 
108819
108936
  (truncated — narrow your search)` : stdout || "(no matches)";
108820
- resolve4({
108937
+ safeResolve({
108821
108938
  success: code === 0 || noMatch,
108822
108939
  error: noMatch || code === 0 ? "" : stderr || `Exit code: ${code}`,
108823
108940
  output,
@@ -108826,8 +108943,7 @@ search with flags or a more specific directory if results are truncated.`,
108826
108943
  });
108827
108944
  });
108828
108945
  child.on("error", (err) => {
108829
- clearTimeout(timeout);
108830
- resolve4({
108946
+ safeResolve({
108831
108947
  success: false,
108832
108948
  error: err.message,
108833
108949
  output: "",
@@ -108835,15 +108951,6 @@ search with flags or a more specific directory if results are truncated.`,
108835
108951
  command
108836
108952
  });
108837
108953
  });
108838
- if (ctx4.abortSignal) {
108839
- const abortHandler = () => child.kill("SIGTERM");
108840
- ctx4.abortSignal.addEventListener("abort", abortHandler, {
108841
- once: true
108842
- });
108843
- child.on("close", () => {
108844
- ctx4.abortSignal.removeEventListener("abort", abortHandler);
108845
- });
108846
- }
108847
108954
  });
108848
108955
  }
108849
108956
  });
@@ -194191,6 +194298,7 @@ var init_offensiveSecurityAgent = __esm(() => {
194191
194298
  resolveResult;
194192
194299
  subagentId;
194193
194300
  persistentShell;
194301
+ abortSignal;
194194
194302
  _session;
194195
194303
  static async create(input) {
194196
194304
  let session = input.session;
@@ -194212,6 +194320,7 @@ var init_offensiveSecurityAgent = __esm(() => {
194212
194320
  constructor(input) {
194213
194321
  this._session = input.session;
194214
194322
  this.subagentId = input.subagentId;
194323
+ this.abortSignal = input.abortSignal;
194215
194324
  if (!input.sandbox) {
194216
194325
  this.persistentShell = new PersistentShell({
194217
194326
  cwd: input.session.rootPath
@@ -194375,6 +194484,9 @@ var init_offensiveSecurityAgent = __esm(() => {
194375
194484
  }
194376
194485
  }
194377
194486
  this.persistentShell?.dispose();
194487
+ if (this.abortSignal?.aborted) {
194488
+ throw new DOMException("Agent aborted by user", "AbortError");
194489
+ }
194378
194490
  if (this.resolveResult) {
194379
194491
  return this.resolveResult(this.streamResult);
194380
194492
  }
@@ -194483,6 +194595,7 @@ var init_blackboxAgent = __esm(() => {
194483
194595
  onStepFinish,
194484
194596
  abortSignal,
194485
194597
  attackSurfaceRegistry,
194598
+ messages: opts.messages,
194486
194599
  activeTools: [
194487
194600
  "execute_command",
194488
194601
  "document_asset",
@@ -194758,7 +194871,8 @@ var init_agent4 = __esm(() => {
194758
194871
  onStepFinish,
194759
194872
  abortSignal,
194760
194873
  sandbox,
194761
- findingsRegistry
194874
+ findingsRegistry,
194875
+ messages
194762
194876
  } = opts;
194763
194877
  super({
194764
194878
  system: buildSystemPrompt(session),
@@ -194771,6 +194885,7 @@ var init_agent4 = __esm(() => {
194771
194885
  abortSignal,
194772
194886
  sandbox,
194773
194887
  findingsRegistry,
194888
+ messages,
194774
194889
  activeTools: [
194775
194890
  "execute_command",
194776
194891
  "http_request",
@@ -194880,7 +194995,7 @@ var EXECUTION_METRICS_FILENAME = "execution-metrics.json";
194880
194995
  var init_execution_metrics = () => {};
194881
194996
 
194882
194997
  // src/core/utils/concurrency.ts
194883
- async function runWithBoundedConcurrency(items, concurrency, fn) {
194998
+ async function runWithBoundedConcurrency(items, concurrency, fn, abortSignal) {
194884
194999
  const results = new Array(items.length).fill(null);
194885
195000
  let nextIdx = 0;
194886
195001
  let completed = 0;
@@ -194891,11 +195006,11 @@ async function runWithBoundedConcurrency(items, concurrency, fn) {
194891
195006
  }
194892
195007
  let active = 0;
194893
195008
  function next() {
194894
- if (completed === items.length) {
195009
+ if (completed >= nextIdx && (nextIdx === items.length || abortSignal?.aborted)) {
194895
195010
  resolve4();
194896
195011
  return;
194897
195012
  }
194898
- while (active < concurrency && nextIdx < items.length) {
195013
+ while (active < concurrency && nextIdx < items.length && !abortSignal?.aborted) {
194899
195014
  const idx = nextIdx++;
194900
195015
  active++;
194901
195016
  fn(items[idx], idx).then((r2) => {
@@ -195485,10 +195600,21 @@ async function runPentestSwarm(input) {
195485
195600
  concurrency = DEFAULT_CONCURRENCY4,
195486
195601
  onStepFinish
195487
195602
  } = input;
195488
- const manifestEntries = buildManifestEntries(targets);
195603
+ const completedIds = getCompletedAgentIds(session);
195604
+ const existingManifest = readAgentManifest(session);
195605
+ const freshEntries = buildManifestEntries(targets);
195606
+ const manifestEntries = freshEntries.map((fresh) => {
195607
+ const existing = existingManifest.find((e2) => e2.id === fresh.id);
195608
+ if (existing && existing.status === "completed")
195609
+ return existing;
195610
+ return fresh;
195611
+ });
195489
195612
  writeAgentManifest(session, manifestEntries);
195490
195613
  const results = await runWithBoundedConcurrency(targets, concurrency, async (target, index) => {
195491
195614
  const subagentId = `pentest-agent-${index + 1}`;
195615
+ if (completedIds.has(subagentId))
195616
+ return null;
195617
+ const previousMessages = loadSubagentMessages(session, subagentId);
195492
195618
  let lastMessages = [];
195493
195619
  const handleStepFinish = (e2) => {
195494
195620
  if (e2.response.messages) {
@@ -195522,7 +195648,8 @@ async function runPentestSwarm(input) {
195522
195648
  authConfig,
195523
195649
  abortSignal,
195524
195650
  findingsRegistry,
195525
- onStepFinish: handleStepFinish
195651
+ onStepFinish: handleStepFinish,
195652
+ messages: previousMessages.length > 0 ? previousMessages : undefined
195526
195653
  });
195527
195654
  const result = await agent.consume({
195528
195655
  onError: (e2) => onError?.(e2),
@@ -195534,8 +195661,9 @@ async function runPentestSwarm(input) {
195534
195661
  objective: target.objectives.join("; "),
195535
195662
  status: "completed",
195536
195663
  findingsCount: result.findings.length,
195537
- messages: lastMessages
195664
+ messages: [...previousMessages, ...lastMessages]
195538
195665
  });
195666
+ updateManifestEntryStatus(session, subagentId, "completed");
195539
195667
  subagentCallbacks?.onSubagentComplete?.({
195540
195668
  subagentId,
195541
195669
  input: { target: target.target, objectives: target.objectives },
@@ -195549,8 +195677,9 @@ async function runPentestSwarm(input) {
195549
195677
  objective: target.objectives.join("; "),
195550
195678
  status: "failed",
195551
195679
  error: error40 instanceof Error ? error40.message : String(error40),
195552
- messages: lastMessages
195680
+ messages: [...previousMessages, ...lastMessages]
195553
195681
  });
195682
+ updateManifestEntryStatus(session, subagentId, "failed");
195554
195683
  subagentCallbacks?.onSubagentComplete?.({
195555
195684
  subagentId,
195556
195685
  input: { target: target.target, objectives: target.objectives },
@@ -195558,7 +195687,7 @@ async function runPentestSwarm(input) {
195558
195687
  });
195559
195688
  throw error40;
195560
195689
  }
195561
- });
195690
+ }, abortSignal);
195562
195691
  finalizeManifest(session, manifestEntries, results);
195563
195692
  return results;
195564
195693
  }
@@ -195576,7 +195705,13 @@ async function runPentestWorkflow(input) {
195576
195705
  try {
195577
195706
  const mode = cwd ? "whitebox" : "blackbox";
195578
195707
  let swarmTargets;
195579
- if (mode === "whitebox") {
195708
+ const existingResults = loadAttackSurfaceResults(session.rootPath);
195709
+ if (existingResults?.targets && existingResults.targets.length > 0) {
195710
+ swarmTargets = existingResults.targets.map((t3) => ({
195711
+ target: t3.target,
195712
+ objectives: [t3.objective]
195713
+ }));
195714
+ } else if (mode === "whitebox") {
195580
195715
  swarmTargets = await runWhiteboxPhase({
195581
195716
  codebasePath: cwd,
195582
195717
  baseTarget: target,
@@ -195598,6 +195733,9 @@ async function runPentestWorkflow(input) {
195598
195733
  onStepFinish
195599
195734
  });
195600
195735
  }
195736
+ if (abortSignal?.aborted) {
195737
+ throw new DOMException("Pentest aborted by user", "AbortError");
195738
+ }
195601
195739
  if (swarmTargets.length === 0) {
195602
195740
  const report2 = buildPentestReport([], {
195603
195741
  target,
@@ -195621,17 +195759,23 @@ async function runPentestWorkflow(input) {
195621
195759
  authConfig,
195622
195760
  abortSignal
195623
195761
  });
195624
- await runPentestSwarm({
195625
- targets: swarmTargets,
195626
- model,
195627
- session,
195628
- authConfig,
195629
- abortSignal,
195630
- findingsRegistry,
195631
- subagentCallbacks: callbacks?.subagentCallbacks,
195632
- onError: (e2) => callbacks?.onError?.(e2),
195633
- onStepFinish
195634
- });
195762
+ const completedCount = getCompletedAgentIds(session).size;
195763
+ if (completedCount < swarmTargets.length) {
195764
+ await runPentestSwarm({
195765
+ targets: swarmTargets,
195766
+ model,
195767
+ session,
195768
+ authConfig,
195769
+ abortSignal,
195770
+ findingsRegistry,
195771
+ subagentCallbacks: callbacks?.subagentCallbacks,
195772
+ onError: (e2) => callbacks?.onError?.(e2),
195773
+ onStepFinish
195774
+ });
195775
+ }
195776
+ if (abortSignal?.aborted) {
195777
+ throw new DOMException("Pentest aborted by user", "AbortError");
195778
+ }
195635
195779
  const findings = loadFindings2(session.findingsPath);
195636
195780
  const report = buildPentestReport(findings, {
195637
195781
  target,
@@ -195743,6 +195887,7 @@ var init_pentest = __esm(() => {
195743
195887
  init_report();
195744
195888
  init_persistence();
195745
195889
  init_execution_metrics();
195890
+ init_loader();
195746
195891
  init_whiteboxAttackSurface();
195747
195892
  });
195748
195893
 
@@ -272350,7 +272495,7 @@ var useTerminalDimensions = () => {
272350
272495
  };
272351
272496
 
272352
272497
  // src/tui/index.tsx
272353
- var import_react89 = __toESM(require_react(), 1);
272498
+ var import_react87 = __toESM(require_react(), 1);
272354
272499
 
272355
272500
  // src/tui/components/footer.tsx
272356
272501
  import os6 from "os";
@@ -273821,7 +273966,7 @@ function CommandProvider({
273821
273966
  }
273822
273967
 
273823
273968
  // src/tui/components/commands/sessions-display.tsx
273824
- var import_react22 = __toESM(require_react(), 1);
273969
+ var import_react24 = __toESM(require_react(), 1);
273825
273970
 
273826
273971
  // src/tui/context/focus.tsx
273827
273972
  var import_react18 = __toESM(require_react(), 1);
@@ -273890,10 +274035,29 @@ function openSessionReport(sessionRootPath) {
273890
274035
  }
273891
274036
  }
273892
274037
 
274038
+ // src/tui/context/dimensions.tsx
274039
+ var import_react19 = __toESM(require_react(), 1);
274040
+ var DimensionsContext = import_react19.createContext(null);
274041
+ function TerminalDimensionsProvider({
274042
+ children
274043
+ }) {
274044
+ const dimensions = useTerminalDimensions();
274045
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(DimensionsContext.Provider, {
274046
+ value: dimensions,
274047
+ children
274048
+ }, undefined, false, undefined, this);
274049
+ }
274050
+ function useDimensions() {
274051
+ const ctx3 = import_react19.useContext(DimensionsContext);
274052
+ if (!ctx3)
274053
+ throw new Error("useDimensions() must be used within <TerminalDimensionsProvider>");
274054
+ return ctx3;
274055
+ }
274056
+
273893
274057
  // src/tui/context/dialog.tsx
273894
- var import_react20 = __toESM(require_react(), 1);
274058
+ var import_react22 = __toESM(require_react(), 1);
273895
274059
  function Dialog({ size = "medium", onClose, children }) {
273896
- const dimensions = useTerminalDimensions();
274060
+ const dimensions = useDimensions();
273897
274061
  const renderer = useRenderer();
273898
274062
  const { colors: themeColors } = useTheme();
273899
274063
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
@@ -273928,14 +274092,14 @@ function Dialog({ size = "medium", onClose, children }) {
273928
274092
  }, undefined, false, undefined, this)
273929
274093
  }, undefined, false, undefined, this);
273930
274094
  }
273931
- var DialogContext = import_react20.createContext(null);
274095
+ var DialogContext = import_react22.createContext(null);
273932
274096
  function DialogProvider({ children }) {
273933
- const [stack, setStack] = import_react20.useState([]);
273934
- const [size, setSize] = import_react20.useState("medium");
273935
- const [externalDialogOpen, setExternalDialogOpen] = import_react20.useState(false);
274097
+ const [stack, setStack] = import_react22.useState([]);
274098
+ const [size, setSize] = import_react22.useState("medium");
274099
+ const [externalDialogOpen, setExternalDialogOpen] = import_react22.useState(false);
273936
274100
  const renderer = useRenderer();
273937
- const focusRef = import_react20.useRef(null);
273938
- const refocus = import_react20.useCallback(() => {
274101
+ const focusRef = import_react22.useRef(null);
274102
+ const refocus = import_react22.useCallback(() => {
273939
274103
  setTimeout(() => {
273940
274104
  const focus = focusRef.current;
273941
274105
  if (!focus)
@@ -273957,7 +274121,7 @@ function DialogProvider({ children }) {
273957
274121
  focus.focus();
273958
274122
  }, 1);
273959
274123
  }, [renderer]);
273960
- const clear = import_react20.useCallback(() => {
274124
+ const clear = import_react22.useCallback(() => {
273961
274125
  for (const item of stack) {
273962
274126
  if (item.onClose)
273963
274127
  item.onClose();
@@ -273966,7 +274130,7 @@ function DialogProvider({ children }) {
273966
274130
  setStack([]);
273967
274131
  refocus();
273968
274132
  }, [stack, refocus]);
273969
- const replace = import_react20.useCallback((element, onClose) => {
274133
+ const replace = import_react22.useCallback((element, onClose) => {
273970
274134
  if (stack.length === 0) {
273971
274135
  focusRef.current = renderer.currentFocusedRenderable;
273972
274136
  }
@@ -274011,7 +274175,7 @@ function DialogProvider({ children }) {
274011
274175
  }, undefined, true, undefined, this);
274012
274176
  }
274013
274177
  function useDialog() {
274014
- const value = import_react20.useContext(DialogContext);
274178
+ const value = import_react22.useContext(DialogContext);
274015
274179
  if (!value) {
274016
274180
  throw new Error("useDialog must be used within a DialogProvider");
274017
274181
  }
@@ -274076,7 +274240,7 @@ function findChildById(scrollBox, id) {
274076
274240
  // src/tui/hooks/use-sessions-list.ts
274077
274241
  init_session();
274078
274242
  init_report();
274079
- var import_react21 = __toESM(require_react(), 1);
274243
+ var import_react23 = __toESM(require_react(), 1);
274080
274244
  import { existsSync as existsSync7, readdirSync } from "fs";
274081
274245
  import { join as join3 } from "path";
274082
274246
  function countFindings(findingsPath) {
@@ -274092,10 +274256,10 @@ function checkHasReport(rootPath) {
274092
274256
  return existsSync7(join3(rootPath, REPORT_FILENAME_MD));
274093
274257
  }
274094
274258
  function useSessionsList() {
274095
- const [allSessions, setAllSessions] = import_react21.useState([]);
274096
- const [loading, setLoading] = import_react21.useState(true);
274097
- const [searchTerm, setSearchTerm] = import_react21.useState("");
274098
- const loadSessions = import_react21.useCallback(async () => {
274259
+ const [allSessions, setAllSessions] = import_react23.useState([]);
274260
+ const [loading, setLoading] = import_react23.useState(true);
274261
+ const [searchTerm, setSearchTerm] = import_react23.useState("");
274262
+ const loadSessions = import_react23.useCallback(async () => {
274099
274263
  setLoading(true);
274100
274264
  try {
274101
274265
  const enriched = [];
@@ -274118,10 +274282,10 @@ function useSessionsList() {
274118
274282
  setLoading(false);
274119
274283
  }
274120
274284
  }, []);
274121
- import_react21.useEffect(() => {
274285
+ import_react23.useEffect(() => {
274122
274286
  loadSessions();
274123
274287
  }, [loadSessions]);
274124
- const deleteSession = import_react21.useCallback(async (id) => {
274288
+ const deleteSession = import_react23.useCallback(async (id) => {
274125
274289
  await sessions.remove({ sessionId: id });
274126
274290
  await loadSessions();
274127
274291
  }, [loadSessions]);
@@ -274180,10 +274344,10 @@ function useSessionsList() {
274180
274344
  function SessionsDisplay({ onClose }) {
274181
274345
  const { colors: colors2 } = useTheme();
274182
274346
  const { refocusPrompt } = useFocus();
274183
- const [selectedIndex, setSelectedIndex] = import_react22.useState(0);
274184
- const [statusMessage, setStatusMessage] = import_react22.useState("");
274347
+ const [selectedIndex, setSelectedIndex] = import_react24.useState(0);
274348
+ const [statusMessage, setStatusMessage] = import_react24.useState("");
274185
274349
  const route = useRoute();
274186
- const scroll = import_react22.useRef(null);
274350
+ const scroll = import_react24.useRef(null);
274187
274351
  const {
274188
274352
  groupedSessions,
274189
274353
  visualOrderSessions,
@@ -274199,7 +274363,7 @@ function SessionsDisplay({ onClose }) {
274199
274363
  setTimeout(() => setStatusMessage(""), 2000);
274200
274364
  }
274201
274365
  }
274202
- import_react22.useEffect(() => {
274366
+ import_react24.useEffect(() => {
274203
274367
  if (visualOrderSessions.length > 0 && selectedIndex >= visualOrderSessions.length) {
274204
274368
  setSelectedIndex(visualOrderSessions.length - 1);
274205
274369
  } else if (visualOrderSessions.length === 0) {
@@ -274235,7 +274399,7 @@ function SessionsDisplay({ onClose }) {
274235
274399
  setTimeout(() => setStatusMessage(""), 2000);
274236
274400
  return;
274237
274401
  }
274238
- const isOperator = currentSelection.config?.mode === "operator" || currentSelection.hasOperatorState;
274402
+ const isOperator = currentSelection.config?.mode === "operator" || !currentSelection.config?.mode && currentSelection.hasOperatorState;
274239
274403
  refocusPrompt();
274240
274404
  onClose();
274241
274405
  route.navigate({
@@ -274281,6 +274445,11 @@ function SessionsDisplay({ onClose }) {
274281
274445
  const currentSelection = visualOrderSessions[selectedIndex];
274282
274446
  if (!currentSelection)
274283
274447
  return;
274448
+ if (!currentSelection.hasReport) {
274449
+ setStatusMessage("No report available");
274450
+ setTimeout(() => setStatusMessage(""), 2000);
274451
+ return;
274452
+ }
274284
274453
  openReport(currentSelection.id);
274285
274454
  return;
274286
274455
  }
@@ -274384,6 +274553,7 @@ function SessionsDisplay({ onClose }) {
274384
274553
  });
274385
274554
  const mode = session.config?.mode || "auto";
274386
274555
  const modeBadge = mode === "operator" ? "[operator]" : "[auto]";
274556
+ const statusBadge = session.hasReport ? "✓" : "…";
274387
274557
  const findingsText = session.findingsCount > 0 ? `${session.findingsCount} finding${session.findingsCount > 1 ? "s" : ""}` : "";
274388
274558
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
274389
274559
  id: session.id,
@@ -274408,6 +274578,10 @@ function SessionsDisplay({ onClose }) {
274408
274578
  fg: isSelected ? colors2.text : colors2.textMuted,
274409
274579
  children: session.name
274410
274580
  }, undefined, false, undefined, this),
274581
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
274582
+ fg: session.hasReport ? colors2.primary : colors2.textMuted,
274583
+ children: statusBadge
274584
+ }, undefined, false, undefined, this),
274411
274585
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
274412
274586
  fg: mode === "operator" ? colors2.primary : colors2.textMuted,
274413
274587
  children: modeBadge
@@ -274471,7 +274645,7 @@ function SessionsDisplay({ onClose }) {
274471
274645
  }
274472
274646
 
274473
274647
  // src/tui/components/commands/config-dialog.tsx
274474
- var import_react25 = __toESM(require_react(), 1);
274648
+ var import_react27 = __toESM(require_react(), 1);
274475
274649
 
274476
274650
  // src/tui/components/alert-dialog.tsx
274477
274651
  function AlertDialog({
@@ -274484,7 +274658,7 @@ function AlertDialog({
274484
274658
  size = "medium"
274485
274659
  }) {
274486
274660
  const { colors: colors2 } = useTheme();
274487
- const dimensions = useTerminalDimensions();
274661
+ const dimensions = useDimensions();
274488
274662
  const renderer = useRenderer();
274489
274663
  useKeyboard((key) => {
274490
274664
  if (!open)
@@ -274558,8 +274732,8 @@ function AlertDialog({
274558
274732
  init_config2();
274559
274733
  function ConfigDialog() {
274560
274734
  const route = useRoute();
274561
- const [open, setOpen] = import_react25.useState(false);
274562
- import_react25.useEffect(() => {
274735
+ const [open, setOpen] = import_react27.useState(false);
274736
+ import_react27.useEffect(() => {
274563
274737
  if (route.data.type === "base" && route.data.path === "config") {
274564
274738
  setOpen(true);
274565
274739
  } else {
@@ -274573,8 +274747,8 @@ function ConfigDialog() {
274573
274747
  path: "home"
274574
274748
  });
274575
274749
  };
274576
- const [appConfig, setAppConfig] = import_react25.useState(null);
274577
- import_react25.useEffect(() => {
274750
+ const [appConfig, setAppConfig] = import_react27.useState(null);
274751
+ import_react27.useEffect(() => {
274578
274752
  async function getConfig() {
274579
274753
  const _appConfig = await config2.get();
274580
274754
  setAppConfig(_appConfig);
@@ -274649,11 +274823,11 @@ var import_react38 = __toESM(require_react(), 1);
274649
274823
 
274650
274824
  // src/tui/context/config.tsx
274651
274825
  init_config2();
274652
- var import_react26 = __toESM(require_react(), 1);
274653
- var ctx3 = import_react26.createContext(null);
274826
+ var import_react28 = __toESM(require_react(), 1);
274827
+ var ctx3 = import_react28.createContext(null);
274654
274828
  function ConfigProvider({ children, config: config3 }) {
274655
- const [appConfig, setAppConfig] = import_react26.useState(config3);
274656
- const value = import_react26.useMemo(() => ({
274829
+ const [appConfig, setAppConfig] = import_react28.useState(config3);
274830
+ const value = import_react28.useMemo(() => ({
274657
274831
  data: appConfig,
274658
274832
  update: async (newConfig) => {
274659
274833
  await config2.update(newConfig);
@@ -274673,7 +274847,7 @@ function ConfigProvider({ children, config: config3 }) {
274673
274847
  }, undefined, false, undefined, this);
274674
274848
  }
274675
274849
  var useConfig = () => {
274676
- const config3 = import_react26.useContext(ctx3);
274850
+ const config3 = import_react28.useContext(ctx3);
274677
274851
  if (!config3) {
274678
274852
  throw new Error("useConfig must be called within a ConfigProvider");
274679
274853
  }
@@ -274681,10 +274855,10 @@ var useConfig = () => {
274681
274855
  };
274682
274856
 
274683
274857
  // src/tui/components/chat/home-view.tsx
274684
- var import_react32 = __toESM(require_react(), 1);
274858
+ var import_react33 = __toESM(require_react(), 1);
274685
274859
 
274686
274860
  // src/tui/components/chat/petri-animation.tsx
274687
- var import_react27 = __toESM(require_react(), 1);
274861
+ var import_react29 = __toESM(require_react(), 1);
274688
274862
 
274689
274863
  // src/tui/components/chat/lib/play-core/num.ts
274690
274864
  function clamp(x2, min, max) {
@@ -274780,8 +274954,8 @@ function stopGlobalTick2() {
274780
274954
  }
274781
274955
  }
274782
274956
  function useGlobalTick2() {
274783
- const [, setTick] = import_react27.useState(0);
274784
- import_react27.useEffect(() => {
274957
+ const [, setTick] = import_react29.useState(0);
274958
+ import_react29.useEffect(() => {
274785
274959
  const listener = () => setTick((t2) => t2 + 1);
274786
274960
  globalListeners2.add(listener);
274787
274961
  startGlobalTick2();
@@ -274806,19 +274980,19 @@ function PetriAnimation({
274806
274980
  height = 0.4,
274807
274981
  width = "100%"
274808
274982
  }) {
274809
- const dimensions = useTerminalDimensions();
274983
+ const dimensions = useDimensions();
274810
274984
  const tick = useGlobalTick2();
274811
274985
  const { colors: colors2 } = useTheme();
274812
- const simulationRef = import_react27.useRef(null);
274813
- const [frame, setFrame] = import_react27.useState([]);
274814
- const gradientColors = import_react27.useMemo(() => generateGradient(colors2.primary, 9), [colors2.primary]);
274815
- const actualHeight = import_react27.useMemo(() => {
274986
+ const simulationRef = import_react29.useRef(null);
274987
+ const [frame, setFrame] = import_react29.useState([]);
274988
+ const gradientColors = import_react29.useMemo(() => generateGradient(colors2.primary, 9), [colors2.primary]);
274989
+ const actualHeight = import_react29.useMemo(() => {
274816
274990
  if (typeof height === "number" && height <= 1) {
274817
274991
  return Math.floor(dimensions.height * height);
274818
274992
  }
274819
274993
  return typeof height === "number" ? height : Math.floor(dimensions.height * 0.4);
274820
274994
  }, [height, dimensions.height]);
274821
- const actualWidth = import_react27.useMemo(() => {
274995
+ const actualWidth = import_react29.useMemo(() => {
274822
274996
  if (typeof width === "number" && width <= 1) {
274823
274997
  return Math.floor(dimensions.width * width);
274824
274998
  }
@@ -274827,7 +275001,7 @@ function PetriAnimation({
274827
275001
  }
274828
275002
  return typeof width === "number" ? width : dimensions.width;
274829
275003
  }, [width, dimensions.width]);
274830
- import_react27.useEffect(() => {
275004
+ import_react29.useEffect(() => {
274831
275005
  if (actualWidth <= 0 || actualHeight <= 0)
274832
275006
  return;
274833
275007
  if (!simulationRef.current) {
@@ -274836,7 +275010,7 @@ function PetriAnimation({
274836
275010
  simulationRef.current.resize(actualWidth, actualHeight);
274837
275011
  }
274838
275012
  }, [actualWidth, actualHeight]);
274839
- import_react27.useEffect(() => {
275013
+ import_react29.useEffect(() => {
274840
275014
  if (simulationRef.current) {
274841
275015
  simulationRef.current.step();
274842
275016
  setFrame(simulationRef.current.render());
@@ -274862,7 +275036,7 @@ function getRowColor(rowIdx, totalRows, gradient) {
274862
275036
  }
274863
275037
 
274864
275038
  // src/tui/components/shared/prompt-input.tsx
274865
- var import_react30 = __toESM(require_react(), 1);
275039
+ var import_react31 = __toESM(require_react(), 1);
274866
275040
 
274867
275041
  // src/tui/components/shared/prompt-input-logic.ts
274868
275042
  function filterSuggestions(inputValue, options, maxSuggestions) {
@@ -274983,13 +275157,13 @@ function shouldResetHistory(historyIndex, isNavigatingHistory) {
274983
275157
  }
274984
275158
 
274985
275159
  // src/tui/components/shared/use-paste-extmarks.ts
274986
- var import_react29 = __toESM(require_react(), 1);
275160
+ var import_react30 = __toESM(require_react(), 1);
274987
275161
  var LARGE_PASTE_MIN_LINES = 5;
274988
275162
  var LARGE_PASTE_MIN_CHARS = 500;
274989
275163
  function usePasteExtmarks(textareaRef) {
274990
- const countRef = import_react29.useRef(0);
274991
- const typeIdRef = import_react29.useRef(-1);
274992
- const dataRef = import_react29.useRef(new Map);
275164
+ const countRef = import_react30.useRef(0);
275165
+ const typeIdRef = import_react30.useRef(-1);
275166
+ const dataRef = import_react30.useRef(new Map);
274993
275167
  const clearPaste = () => {
274994
275168
  textareaRef.current?.extmarks.clear();
274995
275169
  countRef.current = 0;
@@ -275059,7 +275233,7 @@ var chatKeyBindings = [
275059
275233
  { name: "return", shift: true, action: "newline" },
275060
275234
  { name: "linefeed", shift: true, action: "newline" }
275061
275235
  ];
275062
- var PromptInput = import_react30.forwardRef(function PromptInput2({
275236
+ var PromptInput = import_react31.forwardRef(function PromptInput2({
275063
275237
  width,
275064
275238
  minHeight = 1,
275065
275239
  maxHeight = 6,
@@ -275084,31 +275258,31 @@ var PromptInput = import_react30.forwardRef(function PromptInput2({
275084
275258
  const { colors: colors2 } = useTheme();
275085
275259
  const { inputValue, setInputValue } = useInput();
275086
275260
  const { registerPromptRef } = useFocus();
275087
- const textareaRef = import_react30.useRef(null);
275088
- const [selectedSuggestionIndex, setSelectedSuggestionIndex] = import_react30.useState(-1);
275089
- const [historyIndex, setHistoryIndex] = import_react30.useState(-1);
275090
- const savedInputRef = import_react30.useRef("");
275091
- const historyRef = import_react30.useRef(commandHistory);
275261
+ const textareaRef = import_react31.useRef(null);
275262
+ const [selectedSuggestionIndex, setSelectedSuggestionIndex] = import_react31.useState(-1);
275263
+ const [historyIndex, setHistoryIndex] = import_react31.useState(-1);
275264
+ const savedInputRef = import_react31.useRef("");
275265
+ const historyRef = import_react31.useRef(commandHistory);
275092
275266
  historyRef.current = commandHistory;
275093
- const isNavigatingHistoryRef = import_react30.useRef(false);
275094
- const selectedIndexRef = import_react30.useRef(selectedSuggestionIndex);
275095
- const suggestionsRef = import_react30.useRef([]);
275096
- const onCommandExecuteRef = import_react30.useRef(onCommandExecute);
275267
+ const isNavigatingHistoryRef = import_react31.useRef(false);
275268
+ const selectedIndexRef = import_react31.useRef(selectedSuggestionIndex);
275269
+ const suggestionsRef = import_react31.useRef([]);
275270
+ const onCommandExecuteRef = import_react31.useRef(onCommandExecute);
275097
275271
  onCommandExecuteRef.current = onCommandExecute;
275098
- const onSubmitRef = import_react30.useRef(onSubmit);
275272
+ const onSubmitRef = import_react31.useRef(onSubmit);
275099
275273
  onSubmitRef.current = onSubmit;
275100
275274
  const { handlePaste, resolveText, clearPaste } = usePasteExtmarks(textareaRef);
275101
- const suggestions = import_react30.useMemo(() => enableAutocomplete ? filterSuggestions(inputValue, autocompleteOptions, maxSuggestions) : [], [enableAutocomplete, autocompleteOptions, inputValue, maxSuggestions]);
275102
- import_react30.useEffect(() => {
275275
+ const suggestions = import_react31.useMemo(() => enableAutocomplete ? filterSuggestions(inputValue, autocompleteOptions, maxSuggestions) : [], [enableAutocomplete, autocompleteOptions, inputValue, maxSuggestions]);
275276
+ import_react31.useEffect(() => {
275103
275277
  suggestionsRef.current = suggestions;
275104
275278
  }, [suggestions]);
275105
- import_react30.useEffect(() => {
275279
+ import_react31.useEffect(() => {
275106
275280
  selectedIndexRef.current = selectedSuggestionIndex;
275107
275281
  }, [selectedSuggestionIndex]);
275108
- import_react30.useEffect(() => {
275282
+ import_react31.useEffect(() => {
275109
275283
  setSelectedSuggestionIndex(suggestions.length > 0 ? 0 : -1);
275110
275284
  }, [suggestions.length]);
275111
- const imperativeRef = import_react30.useRef({
275285
+ const imperativeRef = import_react31.useRef({
275112
275286
  focus: () => textareaRef.current?.focus(),
275113
275287
  blur: () => textareaRef.current?.blur(),
275114
275288
  reset: () => {
@@ -275125,11 +275299,11 @@ var PromptInput = import_react30.forwardRef(function PromptInput2({
275125
275299
  getValue: () => inputValue,
275126
275300
  getTextareaRef: () => textareaRef.current
275127
275301
  });
275128
- import_react30.useEffect(() => {
275302
+ import_react31.useEffect(() => {
275129
275303
  imperativeRef.current.getValue = () => inputValue;
275130
275304
  }, [inputValue]);
275131
- import_react30.useImperativeHandle(ref, () => imperativeRef.current, []);
275132
- import_react30.useEffect(() => {
275305
+ import_react31.useImperativeHandle(ref, () => imperativeRef.current, []);
275306
+ import_react31.useEffect(() => {
275133
275307
  registerPromptRef(imperativeRef.current);
275134
275308
  return () => registerPromptRef(null);
275135
275309
  }, [registerPromptRef]);
@@ -275345,41 +275519,41 @@ function getEntries() {
275345
275519
  // src/tui/components/chat/home-view.tsx
275346
275520
  function HomeView({ onNavigate, onStartSession }) {
275347
275521
  const { colors: colors2 } = useTheme();
275348
- const dimensions = useTerminalDimensions();
275522
+ const dimensions = useDimensions();
275349
275523
  const config3 = useConfig();
275350
275524
  const route = useRoute();
275351
275525
  const { executeCommand, autocompleteOptions, resolveSkillContent, skills } = useCommand();
275352
275526
  const { setInputValue } = useInput();
275353
275527
  const { promptRef } = useFocus();
275354
275528
  const { externalDialogOpen, stack } = useDialog();
275355
- const [hintMessage, setHintMessage] = import_react32.useState(null);
275356
- const [commandHistory, setCommandHistory] = import_react32.useState(getEntries);
275357
- import_react32.useEffect(() => {
275529
+ const [hintMessage, setHintMessage] = import_react33.useState(null);
275530
+ const [commandHistory, setCommandHistory] = import_react33.useState(getEntries);
275531
+ import_react33.useEffect(() => {
275358
275532
  load().then(setCommandHistory);
275359
275533
  }, []);
275360
- const launchOperator = import_react32.useCallback((message, options) => {
275534
+ const launchOperator = import_react33.useCallback((message, options) => {
275361
275535
  route.navigate({
275362
275536
  type: "operator",
275363
275537
  initialMessage: message,
275364
275538
  initialConfig: { requireApproval: options?.requireApproval ?? true }
275365
275539
  });
275366
275540
  }, [route]);
275367
- const pushHistory = import_react32.useCallback((entry) => {
275541
+ const pushHistory = import_react33.useCallback((entry) => {
275368
275542
  push(entry).then(() => setCommandHistory([...getEntries()]));
275369
275543
  }, []);
275370
- const handleSubmit = import_react32.useCallback((value) => {
275544
+ const handleSubmit = import_react33.useCallback((value) => {
275371
275545
  if (!value.trim())
275372
275546
  return;
275373
275547
  pushHistory(value.trim());
275374
275548
  launchOperator(value.trim());
275375
275549
  }, [launchOperator, pushHistory]);
275376
- import_react32.useEffect(() => {
275550
+ import_react33.useEffect(() => {
275377
275551
  if (!hintMessage)
275378
275552
  return;
275379
275553
  const timer = setTimeout(() => setHintMessage(null), 3000);
275380
275554
  return () => clearTimeout(timer);
275381
275555
  }, [hintMessage]);
275382
- const handleCommandExecute = import_react32.useCallback(async (command) => {
275556
+ const handleCommandExecute = import_react33.useCallback(async (command) => {
275383
275557
  const trimmed = command.trim();
275384
275558
  pushHistory(trimmed);
275385
275559
  const parts = trimmed.replace(/^\/+/, "").split(/\s+/);
@@ -278243,7 +278417,7 @@ function ToastItem({
278243
278417
  }
278244
278418
  function ToastContainer() {
278245
278419
  const { toasts, dismiss } = useToast();
278246
- const dims = useTerminalDimensions();
278420
+ const dims = useDimensions();
278247
278421
  if (toasts.length === 0)
278248
278422
  return null;
278249
278423
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
@@ -278264,11 +278438,11 @@ function ToastContainer() {
278264
278438
  }
278265
278439
 
278266
278440
  // src/tui/components/error-boundary.tsx
278267
- var import_react53 = __toESM(require_react(), 1);
278441
+ var import_react52 = __toESM(require_react(), 1);
278268
278442
  var MAX_ERRORS = 3;
278269
278443
  var ERROR_WINDOW_MS = 5000;
278270
278444
 
278271
- class ErrorBoundaryInner extends import_react53.default.Component {
278445
+ class ErrorBoundaryInner extends import_react52.default.Component {
278272
278446
  state = {
278273
278447
  hasError: false,
278274
278448
  errorTimestamps: [],
@@ -278299,10 +278473,10 @@ class ErrorBoundaryInner extends import_react53.default.Component {
278299
278473
  }
278300
278474
  function ErrorBoundary2({ children }) {
278301
278475
  const { toast } = useToast();
278302
- const handleError = import_react53.useCallback((message) => {
278476
+ const handleError = import_react52.useCallback((message) => {
278303
278477
  toast(message, "error");
278304
278478
  }, [toast]);
278305
- return import_react53.default.createElement(ErrorBoundaryInner, { onError: handleError }, children);
278479
+ return import_react52.default.createElement(ErrorBoundaryInner, { onError: handleError }, children);
278306
278480
  }
278307
278481
 
278308
278482
  // src/tui/index.tsx
@@ -278413,16 +278587,16 @@ function ShortcutsDialog({
278413
278587
  }
278414
278588
 
278415
278589
  // src/tui/components/commands/help-dialog.tsx
278416
- var import_react55 = __toESM(require_react(), 1);
278590
+ var import_react54 = __toESM(require_react(), 1);
278417
278591
  function HelpDialog() {
278418
278592
  const { colors: colors2 } = useTheme();
278419
278593
  const { commands: commands2 } = useCommand();
278420
278594
  const route = useRoute();
278421
- const dimensions = useTerminalDimensions();
278422
- const [selectedIndex, setSelectedIndex] = import_react55.useState(0);
278423
- const [showDetail, setShowDetail] = import_react55.useState(false);
278424
- const scrollboxRef = import_react55.useRef(null);
278425
- const commandsByCategory = import_react55.useMemo(() => {
278595
+ const dimensions = useDimensions();
278596
+ const [selectedIndex, setSelectedIndex] = import_react54.useState(0);
278597
+ const [showDetail, setShowDetail] = import_react54.useState(false);
278598
+ const scrollboxRef = import_react54.useRef(null);
278599
+ const commandsByCategory = import_react54.useMemo(() => {
278426
278600
  const grouped = {};
278427
278601
  for (const cmd of commands2) {
278428
278602
  const category = cmd.category || "Other";
@@ -278433,15 +278607,15 @@ function HelpDialog() {
278433
278607
  }
278434
278608
  return grouped;
278435
278609
  }, [commands2]);
278436
- const flatCommands = import_react55.useMemo(() => {
278610
+ const flatCommands = import_react54.useMemo(() => {
278437
278611
  return commands2;
278438
278612
  }, [commands2]);
278439
- import_react55.useEffect(() => {
278613
+ import_react54.useEffect(() => {
278440
278614
  if (selectedIndex >= flatCommands.length) {
278441
278615
  setSelectedIndex(Math.max(0, flatCommands.length - 1));
278442
278616
  }
278443
278617
  }, [flatCommands.length, selectedIndex]);
278444
- import_react55.useEffect(() => {
278618
+ import_react54.useEffect(() => {
278445
278619
  scrollToIndex(scrollboxRef.current, selectedIndex, flatCommands, (cmd) => cmd.name);
278446
278620
  }, [selectedIndex, flatCommands]);
278447
278621
  const handleClose = () => {
@@ -278876,24 +279050,24 @@ function ModelsDisplay() {
278876
279050
  }
278877
279051
 
278878
279052
  // src/tui/components/commands/auth-flow.tsx
278879
- var import_react58 = __toESM(require_react(), 1);
279053
+ var import_react57 = __toESM(require_react(), 1);
278880
279054
  init_config2();
278881
279055
  function AuthFlow({ onClose }) {
278882
279056
  const { colors: colors2 } = useTheme();
278883
279057
  const appConfig = useConfig();
278884
279058
  const isConnected = !!(appConfig.data.accessToken || appConfig.data.pensarAPIKey);
278885
- const [step, setStep] = import_react58.useState(isConnected ? "success" : "start");
278886
- const [error40, setError] = import_react58.useState(null);
278887
- const [authMode, setAuthMode] = import_react58.useState(null);
278888
- const [deviceInfo, setDeviceInfo] = import_react58.useState(null);
278889
- const [legacyDeviceInfo, setLegacyDeviceInfo] = import_react58.useState(null);
278890
- const [workspaces, setWorkspaces] = import_react58.useState([]);
278891
- const [selectedWorkspace, setSelectedWorkspace] = import_react58.useState(null);
278892
- const [selectedIndex, setSelectedIndex] = import_react58.useState(0);
278893
- const [billingUrl, setBillingUrl] = import_react58.useState(null);
278894
- const [balance, setBalance] = import_react58.useState(null);
278895
- const pollingRef = import_react58.useRef(null);
278896
- const cancelledRef = import_react58.useRef(false);
279059
+ const [step, setStep] = import_react57.useState(isConnected ? "success" : "start");
279060
+ const [error40, setError] = import_react57.useState(null);
279061
+ const [authMode, setAuthMode] = import_react57.useState(null);
279062
+ const [deviceInfo, setDeviceInfo] = import_react57.useState(null);
279063
+ const [legacyDeviceInfo, setLegacyDeviceInfo] = import_react57.useState(null);
279064
+ const [workspaces, setWorkspaces] = import_react57.useState([]);
279065
+ const [selectedWorkspace, setSelectedWorkspace] = import_react57.useState(null);
279066
+ const [selectedIndex, setSelectedIndex] = import_react57.useState(0);
279067
+ const [billingUrl, setBillingUrl] = import_react57.useState(null);
279068
+ const [balance, setBalance] = import_react57.useState(null);
279069
+ const pollingRef = import_react57.useRef(null);
279070
+ const cancelledRef = import_react57.useRef(false);
278897
279071
  const connectedWorkspace = appConfig.data.workspaceSlug ? { name: appConfig.data.workspaceSlug, slug: appConfig.data.workspaceSlug } : null;
278898
279072
  const goHome = () => {
278899
279073
  onClose();
@@ -278905,7 +279079,7 @@ function AuthFlow({ onClose }) {
278905
279079
  pollingRef.current = null;
278906
279080
  }
278907
279081
  };
278908
- import_react58.useEffect(() => {
279082
+ import_react57.useEffect(() => {
278909
279083
  return cleanup;
278910
279084
  }, []);
278911
279085
  const openUrl = (url2) => {
@@ -278924,7 +279098,7 @@ function AuthFlow({ onClose }) {
278924
279098
  setStep("requesting");
278925
279099
  setError(null);
278926
279100
  cancelledRef.current = false;
278927
- const apiUrl = getPensarApiUrl(appConfig.data);
279101
+ const apiUrl = getPensarApiUrl();
278928
279102
  console.error(`[auth] apiUrl=${apiUrl}`);
278929
279103
  try {
278930
279104
  console.error(`[auth] fetching ${apiUrl}/api/cli/config`);
@@ -279194,7 +279368,7 @@ function AuthFlow({ onClose }) {
279194
279368
  }
279195
279369
  if (key.name === "return" && workspaces[selectedIndex]) {
279196
279370
  const currentConfig = appConfig.data;
279197
- const apiUrl = getPensarApiUrl(currentConfig);
279371
+ const apiUrl = getPensarApiUrl();
279198
279372
  const accessToken = currentConfig.accessToken;
279199
279373
  selectWorkspace(apiUrl, accessToken, workspaces[selectedIndex]);
279200
279374
  }
@@ -279538,14 +279712,14 @@ function AuthFlow({ onClose }) {
279538
279712
  }
279539
279713
 
279540
279714
  // src/tui/components/commands/credits-flow.tsx
279541
- var import_react60 = __toESM(require_react(), 1);
279715
+ var import_react59 = __toESM(require_react(), 1);
279542
279716
  init_tokenRefresh();
279543
279717
  function CreditsFlow({ onOpenAuthDialog }) {
279544
279718
  const route = useRoute();
279545
279719
  const appConfig = useConfig();
279546
- const [step, setStep] = import_react60.useState("loading");
279547
- const [credits, setCredits] = import_react60.useState(null);
279548
- const [error40, setError] = import_react60.useState(null);
279720
+ const [step, setStep] = import_react59.useState("loading");
279721
+ const [credits, setCredits] = import_react59.useState(null);
279722
+ const [error40, setError] = import_react59.useState(null);
279549
279723
  const creditsUrl = `${getPensarConsoleUrl()}/credits`;
279550
279724
  const goHome = () => {
279551
279725
  route.navigate({ type: "base", path: "home" });
@@ -279568,8 +279742,7 @@ function CreditsFlow({ onOpenAuthDialog }) {
279568
279742
  const tokenResult = await ensureValidToken({
279569
279743
  accessToken: appConfig.data.accessToken,
279570
279744
  refreshToken: appConfig.data.refreshToken,
279571
- pensarAPIKey: appConfig.data.pensarAPIKey,
279572
- pensarApiUrl: appConfig.data.pensarApiUrl
279745
+ pensarAPIKey: appConfig.data.pensarAPIKey
279573
279746
  });
279574
279747
  if (!tokenResult) {
279575
279748
  setStep("no-auth");
@@ -279578,7 +279751,7 @@ function CreditsFlow({ onOpenAuthDialog }) {
279578
279751
  setStep("loading");
279579
279752
  setError(null);
279580
279753
  try {
279581
- const apiUrl = getPensarApiUrl(appConfig.data);
279754
+ const apiUrl = getPensarApiUrl();
279582
279755
  const headers = {
279583
279756
  Authorization: `Bearer ${tokenResult.token}`
279584
279757
  };
@@ -279603,7 +279776,7 @@ function CreditsFlow({ onOpenAuthDialog }) {
279603
279776
  setStep("display");
279604
279777
  }
279605
279778
  };
279606
- import_react60.useEffect(() => {
279779
+ import_react59.useEffect(() => {
279607
279780
  fetchBalance();
279608
279781
  }, []);
279609
279782
  useKeyboard((key) => {
@@ -279842,10 +280015,10 @@ function CreditsFlow({ onOpenAuthDialog }) {
279842
280015
  }
279843
280016
 
279844
280017
  // src/tui/context/keybinding.tsx
279845
- var import_react66 = __toESM(require_react(), 1);
280018
+ var import_react65 = __toESM(require_react(), 1);
279846
280019
 
279847
280020
  // src/tui/keybindings/keybind.tsx
279848
- var import_react62 = __toESM(require_react(), 1);
280021
+ var import_react61 = __toESM(require_react(), 1);
279849
280022
 
279850
280023
  // src/tui/keybindings/actions.ts
279851
280024
  var movementActions = [
@@ -280097,7 +280270,7 @@ var allActions = [
280097
280270
  var actionsByKey = new Map(allActions.map((action) => [action.key, action]));
280098
280271
  var actionsById = new Map(allActions.map((action) => [action.id, action]));
280099
280272
  // src/tui/keybindings/keybind.tsx
280100
- var LeaderKeyContext = import_react62.createContext(null);
280273
+ var LeaderKeyContext = import_react61.createContext(null);
280101
280274
  // src/tui/keybindings/registry.ts
280102
280275
  function createKeybindings(deps) {
280103
280276
  const {
@@ -280278,7 +280451,7 @@ function matchesKeybind(pressed, combo) {
280278
280451
  }
280279
280452
 
280280
280453
  // src/tui/context/keybinding.tsx
280281
- var KeybindingContext = import_react66.createContext(undefined);
280454
+ var KeybindingContext = import_react65.createContext(undefined);
280282
280455
  function KeybindingProvider({
280283
280456
  children,
280284
280457
  deps
@@ -280318,121 +280491,12 @@ function KeybindingProvider({
280318
280491
  }
280319
280492
 
280320
280493
  // src/tui/components/pentest/pentest.tsx
280321
- var import_react75 = __toESM(require_react(), 1);
280494
+ var import_react73 = __toESM(require_react(), 1);
280322
280495
  init_report();
280323
280496
  import { existsSync as existsSync26, readdirSync as readdirSync6, readFileSync as readFileSync12 } from "fs";
280324
280497
  import { join as join27 } from "path";
280325
280498
  init_session();
280326
-
280327
- // src/core/session/loader.ts
280328
- init_persistence();
280329
- init_report();
280330
- import { join as join5 } from "path";
280331
- import { existsSync as existsSync9, readFileSync as readFileSync4 } from "fs";
280332
- function loadAttackSurfaceResults(rootPath) {
280333
- const resultsPath = join5(rootPath, "attack-surface-results.json");
280334
- if (!existsSync9(resultsPath)) {
280335
- return null;
280336
- }
280337
- try {
280338
- return JSON.parse(readFileSync4(resultsPath, "utf-8"));
280339
- } catch (e) {
280340
- console.error("Failed to load attack surface results:", e);
280341
- return null;
280342
- }
280343
- }
280344
- function hasReport(rootPath) {
280345
- const reportPath = join5(rootPath, REPORT_FILENAME_MD);
280346
- return existsSync9(reportPath);
280347
- }
280348
- function createDiscoveryFromLogs(rootPath, session) {
280349
- const logPath = join5(rootPath, "logs", "streamlined-pentest.log");
280350
- if (!existsSync9(logPath)) {
280351
- return null;
280352
- }
280353
- try {
280354
- const logContent = readFileSync4(logPath, "utf-8");
280355
- const lines = logContent.split(`
280356
- `).filter(Boolean);
280357
- const messages = [];
280358
- for (const line of lines) {
280359
- const match = line.match(/^(\d{4}-\d{2}-\d{2}T[\d:.]+Z) - \[(\w+)\] (.+)$/);
280360
- if (!match)
280361
- continue;
280362
- const [, timestamp, _level, content] = match;
280363
- const createdAt = new Date(timestamp);
280364
- if (content.startsWith("[Tool]")) {
280365
- const toolMatch = content.match(/\[Tool\] (\w+): (.+)/);
280366
- if (toolMatch) {
280367
- messages.push({
280368
- role: "tool",
280369
- content: `✓ ${toolMatch[2]}`,
280370
- createdAt,
280371
- toolName: toolMatch[1],
280372
- status: "completed"
280373
- });
280374
- }
280375
- } else if (content.startsWith("[Step")) {
280376
- const stepMatch = content.match(/\[Step \d+\] (.+)/);
280377
- if (stepMatch) {
280378
- messages.push({
280379
- role: "assistant",
280380
- content: stepMatch[1],
280381
- createdAt
280382
- });
280383
- }
280384
- }
280385
- }
280386
- if (messages.length === 0) {
280387
- return null;
280388
- }
280389
- return {
280390
- id: "discovery-from-logs",
280391
- name: "Attack Surface Discovery",
280392
- type: "attack-surface",
280393
- target: session.targets[0] || "Unknown",
280394
- messages,
280395
- createdAt: new Date(session.time.created),
280396
- status: "completed"
280397
- };
280398
- } catch (e) {
280399
- console.error("Failed to parse logs:", e);
280400
- return null;
280401
- }
280402
- }
280403
- async function loadSessionState(session) {
280404
- const rootPath = session.rootPath;
280405
- let subagents = loadSubagents(rootPath);
280406
- const hasAttackSurfaceAgent = subagents.some((s) => s.type === "attack-surface");
280407
- if (!hasAttackSurfaceAgent) {
280408
- const discoveryAgent = createDiscoveryFromLogs(rootPath, session);
280409
- if (discoveryAgent) {
280410
- subagents = [discoveryAgent, ...subagents];
280411
- }
280412
- }
280413
- const attackSurfaceResults = loadAttackSurfaceResults(rootPath);
280414
- const hasReportFile = hasReport(rootPath);
280415
- const hasDiscoverySubagent = subagents.some((s) => s.type === "attack-surface");
280416
- const interruptedDuringDiscovery = !attackSurfaceResults && !hasReportFile && hasDiscoverySubagent;
280417
- if (interruptedDuringDiscovery) {
280418
- for (let i = 0;i < subagents.length; i++) {
280419
- if (subagents[i].type === "attack-surface" && subagents[i].status === "completed") {
280420
- subagents[i] = { ...subagents[i], status: "paused" };
280421
- }
280422
- }
280423
- }
280424
- const pentestSubagents = subagents.filter((s) => s.type === "pentest");
280425
- const allPentestDone = pentestSubagents.length > 0 && pentestSubagents.every((s) => s.status === "completed" || s.status === "failed");
280426
- const isComplete = hasReportFile || attackSurfaceResults?.summary?.analysisComplete === true && allPentestDone;
280427
- return {
280428
- session,
280429
- subagents,
280430
- attackSurfaceResults,
280431
- isComplete,
280432
- hasReport: hasReportFile,
280433
- interruptedDuringDiscovery
280434
- };
280435
- }
280499
+ init_loader();
280436
280500
 
280437
280501
  // src/core/api/blackboxPentest.ts
280438
280502
  init_pentest();
@@ -280459,7 +280523,7 @@ Found ${findings.length} vulnerabilities`);
280459
280523
  init_utils();
280460
280524
 
280461
280525
  // src/tui/components/agent-display.tsx
280462
- var import_react73 = __toESM(require_react(), 1);
280526
+ var import_react72 = __toESM(require_react(), 1);
280463
280527
 
280464
280528
  // node_modules/marked/lib/marked.esm.js
280465
280529
  function L2() {
@@ -282791,14 +282855,14 @@ ${preview}${suffix}` : preview + suffix || "POC passed",
282791
282855
  return null;
282792
282856
  }
282793
282857
  // src/tui/components/shared/ascii-spinner.tsx
282794
- var import_react67 = __toESM(require_react(), 1);
282858
+ var import_react66 = __toESM(require_react(), 1);
282795
282859
  var SPINNER_FRAMES = ["/", "-", "\\", "|"];
282796
282860
  var SPINNER_INTERVAL = 100;
282797
282861
  function AsciiSpinner({ label, fg: fg2 }) {
282798
282862
  const { colors: colors2 } = useTheme();
282799
282863
  const spinnerColor = fg2 ?? colors2.info;
282800
- const [frame, setFrame] = import_react67.useState(0);
282801
- import_react67.useEffect(() => {
282864
+ const [frame, setFrame] = import_react66.useState(0);
282865
+ import_react66.useEffect(() => {
282802
282866
  const interval = setInterval(() => {
282803
282867
  setFrame((f3) => (f3 + 1) % SPINNER_FRAMES.length);
282804
282868
  }, SPINNER_INTERVAL);
@@ -282810,7 +282874,7 @@ function AsciiSpinner({ label, fg: fg2 }) {
282810
282874
  }, undefined, false, undefined, this);
282811
282875
  }
282812
282876
  // src/tui/components/shared/tool-renderer.tsx
282813
- var import_react68 = __toESM(require_react(), 1);
282877
+ var import_react67 = __toESM(require_react(), 1);
282814
282878
  var TOOLS_WITH_LOG_WINDOW = new Set([
282815
282879
  "execute_command",
282816
282880
  "run_attack_surface",
@@ -282823,13 +282887,13 @@ var TOOLS_WITH_LOG_WINDOW = new Set([
282823
282887
  "document_vulnerability"
282824
282888
  ]);
282825
282889
  var DEFAULT_SUBAGENT_LOG_LINES = 5;
282826
- var ToolRenderer = import_react68.memo(function ToolRenderer2({
282890
+ var ToolRenderer = import_react67.memo(function ToolRenderer2({
282827
282891
  message,
282828
282892
  verbose = false,
282829
282893
  expandedLogs = false
282830
282894
  }) {
282831
282895
  const { colors: colors2 } = useTheme();
282832
- const [showOutput, setShowOutput] = import_react68.useState(false);
282896
+ const [showOutput, setShowOutput] = import_react67.useState(false);
282833
282897
  if (!isToolMessage(message)) {
282834
282898
  return null;
282835
282899
  }
@@ -282969,7 +283033,7 @@ var ToolRenderer = import_react68.memo(function ToolRenderer2({
282969
283033
  ]
282970
283034
  }, undefined, true, undefined, this);
282971
283035
  });
282972
- var SubagentLogWindow = import_react68.memo(function SubagentLogWindow2({
283036
+ var SubagentLogWindow = import_react67.memo(function SubagentLogWindow2({
282973
283037
  subagentId,
282974
283038
  entry,
282975
283039
  expandedLogs
@@ -283026,8 +283090,8 @@ var SubagentLogWindow = import_react68.memo(function SubagentLogWindow2({
283026
283090
  }, undefined, true, undefined, this);
283027
283091
  });
283028
283092
  // src/tui/components/shared/message-renderer.tsx
283029
- var import_react69 = __toESM(require_react(), 1);
283030
- var MessageRenderer = import_react69.memo(function MessageRenderer2({
283093
+ var import_react68 = __toESM(require_react(), 1);
283094
+ var MessageRenderer = import_react68.memo(function MessageRenderer2({
283031
283095
  message,
283032
283096
  isStreaming = false,
283033
283097
  verbose = false,
@@ -283037,7 +283101,7 @@ var MessageRenderer = import_react69.memo(function MessageRenderer2({
283037
283101
  }) {
283038
283102
  const { colors: colors2 } = useTheme();
283039
283103
  const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content);
283040
- const displayContent = import_react69.useMemo(() => message.role === "assistant" ? markdownToStyledText(content, colors2) : content, [content, message.role, colors2]);
283104
+ const displayContent = import_react68.useMemo(() => message.role === "assistant" ? markdownToStyledText(content, colors2) : content, [content, message.role, colors2]);
283041
283105
  if (isToolMessage(message)) {
283042
283106
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToolRenderer, {
283043
283107
  message,
@@ -283149,9 +283213,9 @@ var MessageRenderer = import_react69.memo(function MessageRenderer2({
283149
283213
  }, undefined, false, undefined, this);
283150
283214
  });
283151
283215
  // src/tui/components/shared/approval-prompt.tsx
283152
- var import_react70 = __toESM(require_react(), 1);
283216
+ var import_react69 = __toESM(require_react(), 1);
283153
283217
  // src/tui/components/shared/message-reducer.ts
283154
- var import_react72 = __toESM(require_react(), 1);
283218
+ var import_react71 = __toESM(require_react(), 1);
283155
283219
  // src/tui/components/agent-display.tsx
283156
283220
  function getStableKey(item, contextId = "root") {
283157
283221
  if ("messages" in item) {
@@ -283227,11 +283291,11 @@ function AgentDisplay({
283227
283291
  ]
283228
283292
  }, undefined, true, undefined, this);
283229
283293
  }
283230
- var SubAgentDisplay = import_react73.memo(function SubAgentDisplay2({
283294
+ var SubAgentDisplay = import_react72.memo(function SubAgentDisplay2({
283231
283295
  subagent
283232
283296
  }) {
283233
283297
  const { colors: colors2 } = useTheme();
283234
- const [open, setOpen] = import_react73.useState(false);
283298
+ const [open, setOpen] = import_react72.useState(false);
283235
283299
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
283236
283300
  height: open ? 40 : "auto",
283237
283301
  onMouseDown: () => setOpen(!open),
@@ -283286,11 +283350,11 @@ var SubAgentDisplay = import_react73.memo(function SubAgentDisplay2({
283286
283350
  ]
283287
283351
  }, undefined, true, undefined, this);
283288
283352
  });
283289
- var AgentMessage = import_react73.memo(function AgentMessage2({
283353
+ var AgentMessage = import_react72.memo(function AgentMessage2({
283290
283354
  message
283291
283355
  }) {
283292
283356
  const { colors: colors2 } = useTheme();
283293
- const dimensions = useTerminalDimensions();
283357
+ const dimensions = useDimensions();
283294
283358
  let content = "";
283295
283359
  if (typeof message.content === "string") {
283296
283360
  content = message.content;
@@ -283395,8 +283459,8 @@ var AgentMessage = import_react73.memo(function AgentMessage2({
283395
283459
  });
283396
283460
  function ToolDetails({ message }) {
283397
283461
  const { colors: colors2 } = useTheme();
283398
- const [showArgs, setShowArgs] = import_react73.useState(false);
283399
- const [showResult, setShowResult] = import_react73.useState(false);
283462
+ const [showArgs, setShowArgs] = import_react72.useState(false);
283463
+ const [showResult, setShowResult] = import_react72.useState(false);
283400
283464
  if (message.role !== "tool") {
283401
283465
  return null;
283402
283466
  }
@@ -283502,27 +283566,27 @@ function Pentest({
283502
283566
  const config3 = useConfig();
283503
283567
  const { model, setThinking, setIsExecuting, isExecuting } = useAgent();
283504
283568
  const { stack, externalDialogOpen } = useDialog();
283505
- const [session, setSession] = import_react75.useState(null);
283506
- const [error40, setError] = import_react75.useState(null);
283507
- const [phase, setPhase] = import_react75.useState("loading");
283508
- const [abortController, setAbortController] = import_react75.useState(null);
283509
- const [panelMessages, setPanelMessages] = import_react75.useState([]);
283510
- const panelTextRef = import_react75.useRef("");
283511
- const panelSourceRef = import_react75.useRef(null);
283512
- const [pentestAgents, setPentestAgents] = import_react75.useState({});
283513
- const pentestTextRefs = import_react75.useRef({});
283514
- const [assets, setAssets] = import_react75.useState([]);
283515
- const [viewMode, setViewMode] = import_react75.useState("overview");
283516
- const [selectedAgentId, setSelectedAgentId] = import_react75.useState(null);
283517
- const [focusedIndex, setFocusedIndex] = import_react75.useState(0);
283518
- const [showOrchestratorPanel, setShowOrchestratorPanel] = import_react75.useState(false);
283519
- const [startTime, setStartTime] = import_react75.useState(null);
283520
- const pentestAgentList = import_react75.useMemo(() => Object.values(pentestAgents).sort((a, b3) => a.createdAt.getTime() - b3.createdAt.getTime()), [pentestAgents]);
283521
- const selectedAgent = import_react75.useMemo(() => selectedAgentId ? pentestAgents[selectedAgentId] ?? null : null, [pentestAgents, selectedAgentId]);
283522
- const { width: termWidth } = useTerminalDimensions();
283569
+ const [session, setSession] = import_react73.useState(null);
283570
+ const [error40, setError] = import_react73.useState(null);
283571
+ const [phase, setPhase] = import_react73.useState("loading");
283572
+ const [abortController, setAbortController] = import_react73.useState(null);
283573
+ const [panelMessages, setPanelMessages] = import_react73.useState([]);
283574
+ const panelTextRef = import_react73.useRef("");
283575
+ const panelSourceRef = import_react73.useRef(null);
283576
+ const [pentestAgents, setPentestAgents] = import_react73.useState({});
283577
+ const pentestTextRefs = import_react73.useRef({});
283578
+ const [assets, setAssets] = import_react73.useState([]);
283579
+ const [viewMode, setViewMode] = import_react73.useState("overview");
283580
+ const [selectedAgentId, setSelectedAgentId] = import_react73.useState(null);
283581
+ const [focusedIndex, setFocusedIndex] = import_react73.useState(0);
283582
+ const [showOrchestratorPanel, setShowOrchestratorPanel] = import_react73.useState(false);
283583
+ const [startTime, setStartTime] = import_react73.useState(null);
283584
+ const pentestAgentList = import_react73.useMemo(() => Object.values(pentestAgents).sort((a, b3) => a.createdAt.getTime() - b3.createdAt.getTime()), [pentestAgents]);
283585
+ const selectedAgent = import_react73.useMemo(() => selectedAgentId ? pentestAgents[selectedAgentId] ?? null : null, [pentestAgents, selectedAgentId]);
283586
+ const { width: termWidth } = useDimensions();
283523
283587
  const gridAvailableWidth = showOrchestratorPanel ? Math.floor((termWidth - 4) / 2) - 2 : termWidth - ORCHESTRATOR_PANEL_WIDTH - GRID_OUTER_PADDING;
283524
283588
  const gridColumns = Math.max(1, Math.floor((gridAvailableWidth + GRID_GAP) / (CARD_MIN_WIDTH + GRID_GAP)));
283525
- import_react75.useEffect(() => {
283589
+ import_react73.useEffect(() => {
283526
283590
  async function load2() {
283527
283591
  try {
283528
283592
  let s2;
@@ -283568,6 +283632,9 @@ function Pentest({
283568
283632
  if (attackSurfaceAgents.some((sa) => sa.messages.length > 0)) {
283569
283633
  setShowOrchestratorPanel(true);
283570
283634
  }
283635
+ if (state.attackSurfaceResults?.summary?.analysisComplete) {
283636
+ setPhase("pentesting");
283637
+ }
283571
283638
  startPentest(s2);
283572
283639
  }
283573
283640
  } else {
@@ -283580,7 +283647,7 @@ function Pentest({
283580
283647
  }
283581
283648
  load2();
283582
283649
  }, [sessionId]);
283583
- import_react75.useEffect(() => {
283650
+ import_react73.useEffect(() => {
283584
283651
  if (!session)
283585
283652
  return;
283586
283653
  const assetsPath = join27(session.rootPath, "assets");
@@ -283603,12 +283670,12 @@ function Pentest({
283603
283670
  const interval = setInterval(readAssets, 2000);
283604
283671
  return () => clearInterval(interval);
283605
283672
  }, [session]);
283606
- import_react75.useEffect(() => {
283673
+ import_react73.useEffect(() => {
283607
283674
  return () => {
283608
283675
  abortController?.abort();
283609
283676
  };
283610
283677
  }, [abortController]);
283611
- const ensurePentestAgent = import_react75.useCallback((subagentId) => {
283678
+ const ensurePentestAgent = import_react73.useCallback((subagentId) => {
283612
283679
  setPentestAgents((prev) => {
283613
283680
  if (prev[subagentId])
283614
283681
  return prev;
@@ -283625,7 +283692,7 @@ function Pentest({
283625
283692
  };
283626
283693
  });
283627
283694
  }, []);
283628
- const handleSubagentSpawn = import_react75.useCallback(({
283695
+ const handleSubagentSpawn = import_react73.useCallback(({
283629
283696
  subagentId,
283630
283697
  input
283631
283698
  }) => {
@@ -283645,7 +283712,7 @@ function Pentest({
283645
283712
  }
283646
283713
  }));
283647
283714
  }, []);
283648
- const handleSubagentComplete = import_react75.useCallback(({ subagentId, status }) => {
283715
+ const handleSubagentComplete = import_react73.useCallback(({ subagentId, status }) => {
283649
283716
  if (!subagentId.startsWith("pentest-agent-"))
283650
283717
  return;
283651
283718
  setPentestAgents((prev) => {
@@ -283658,7 +283725,7 @@ function Pentest({
283658
283725
  };
283659
283726
  });
283660
283727
  }, []);
283661
- const appendPanelText = import_react75.useCallback((source, text2) => {
283728
+ const appendPanelText = import_react73.useCallback((source, text2) => {
283662
283729
  if (panelSourceRef.current !== source) {
283663
283730
  panelTextRef.current = "";
283664
283731
  panelSourceRef.current = source;
@@ -283683,7 +283750,7 @@ function Pentest({
283683
283750
  ];
283684
283751
  });
283685
283752
  }, []);
283686
- const appendPentestText = import_react75.useCallback((subagentId, text2) => {
283753
+ const appendPentestText = import_react73.useCallback((subagentId, text2) => {
283687
283754
  ensurePentestAgent(subagentId);
283688
283755
  if (!pentestTextRefs.current[subagentId]) {
283689
283756
  pentestTextRefs.current[subagentId] = "";
@@ -283716,8 +283783,8 @@ function Pentest({
283716
283783
  };
283717
283784
  });
283718
283785
  }, [ensurePentestAgent]);
283719
- const toolArgsDeltaRef = import_react75.useRef(new Map);
283720
- const addPanelStreamingToolCall = import_react75.useCallback((toolCallId, toolName) => {
283786
+ const toolArgsDeltaRef = import_react73.useRef(new Map);
283787
+ const addPanelStreamingToolCall = import_react73.useCallback((toolCallId, toolName) => {
283721
283788
  panelTextRef.current = "";
283722
283789
  panelSourceRef.current = null;
283723
283790
  toolArgsDeltaRef.current.set(toolCallId, "");
@@ -283736,7 +283803,7 @@ function Pentest({
283736
283803
  return [...prev, msg];
283737
283804
  });
283738
283805
  }, []);
283739
- const appendPanelToolCallDelta = import_react75.useCallback((toolCallId, argsTextDelta) => {
283806
+ const appendPanelToolCallDelta = import_react73.useCallback((toolCallId, argsTextDelta) => {
283740
283807
  const prev = toolArgsDeltaRef.current.get(toolCallId) ?? "";
283741
283808
  const accumulated = prev + argsTextDelta;
283742
283809
  toolArgsDeltaRef.current.set(toolCallId, accumulated);
@@ -283759,7 +283826,7 @@ function Pentest({
283759
283826
  return updated;
283760
283827
  });
283761
283828
  }, []);
283762
- const addPanelToolCall = import_react75.useCallback((toolCallId, toolName, args) => {
283829
+ const addPanelToolCall = import_react73.useCallback((toolCallId, toolName, args) => {
283763
283830
  panelTextRef.current = "";
283764
283831
  panelSourceRef.current = null;
283765
283832
  toolArgsDeltaRef.current.delete(toolCallId);
@@ -283791,7 +283858,7 @@ function Pentest({
283791
283858
  ];
283792
283859
  });
283793
283860
  }, []);
283794
- const addPentestStreamingToolCall = import_react75.useCallback((subagentId, toolCallId, toolName) => {
283861
+ const addPentestStreamingToolCall = import_react73.useCallback((subagentId, toolCallId, toolName) => {
283795
283862
  pentestTextRefs.current[subagentId] = "";
283796
283863
  ensurePentestAgent(subagentId);
283797
283864
  toolArgsDeltaRef.current.set(toolCallId, "");
@@ -283816,7 +283883,7 @@ function Pentest({
283816
283883
  };
283817
283884
  });
283818
283885
  }, [ensurePentestAgent]);
283819
- const appendPentestToolCallDelta = import_react75.useCallback((subagentId, toolCallId, argsTextDelta) => {
283886
+ const appendPentestToolCallDelta = import_react73.useCallback((subagentId, toolCallId, argsTextDelta) => {
283820
283887
  const prev = toolArgsDeltaRef.current.get(toolCallId) ?? "";
283821
283888
  const accumulated = prev + argsTextDelta;
283822
283889
  toolArgsDeltaRef.current.set(toolCallId, accumulated);
@@ -283842,7 +283909,7 @@ function Pentest({
283842
283909
  return { ...agents, [subagentId]: { ...agent, messages: updatedMsgs } };
283843
283910
  });
283844
283911
  }, []);
283845
- const addPentestToolCall = import_react75.useCallback((subagentId, toolCallId, toolName, args) => {
283912
+ const addPentestToolCall = import_react73.useCallback((subagentId, toolCallId, toolName, args) => {
283846
283913
  pentestTextRefs.current[subagentId] = "";
283847
283914
  ensurePentestAgent(subagentId);
283848
283915
  toolArgsDeltaRef.current.delete(toolCallId);
@@ -283903,12 +283970,12 @@ function Pentest({
283903
283970
  }
283904
283971
  ];
283905
283972
  };
283906
- const updatePanelToolResult = import_react75.useCallback((toolCallId, toolName, result) => {
283973
+ const updatePanelToolResult = import_react73.useCallback((toolCallId, toolName, result) => {
283907
283974
  panelTextRef.current = "";
283908
283975
  panelSourceRef.current = null;
283909
283976
  setPanelMessages((prev) => toolResultUpdater(prev, toolCallId, toolName, result));
283910
283977
  }, []);
283911
- const updatePentestToolResult = import_react75.useCallback((subagentId, toolCallId, toolName, result) => {
283978
+ const updatePentestToolResult = import_react73.useCallback((subagentId, toolCallId, toolName, result) => {
283912
283979
  pentestTextRefs.current[subagentId] = "";
283913
283980
  setPentestAgents((prev) => {
283914
283981
  const agent = prev[subagentId];
@@ -283923,11 +283990,12 @@ function Pentest({
283923
283990
  };
283924
283991
  });
283925
283992
  }, []);
283926
- const startPentest = import_react75.useCallback(async (s2) => {
283927
- setPhase("discovery");
283993
+ const startPentest = import_react73.useCallback(async (s2) => {
283994
+ setPhase((prev) => prev === "pentesting" || prev === "reporting" ? prev : "discovery");
283928
283995
  setStartTime(new Date);
283929
283996
  setIsExecuting(true);
283930
- setThinking(true);
283997
+ const discoveryDone = existsSync26(join27(s2.rootPath, "attack-surface-results.json"));
283998
+ setThinking(!discoveryDone);
283931
283999
  const controller = new AbortController;
283932
284000
  setAbortController(controller);
283933
284001
  try {
@@ -284050,7 +284118,7 @@ function Pentest({
284050
284118
  handleSubagentSpawn,
284051
284119
  handleSubagentComplete
284052
284120
  ]);
284053
- import_react75.useEffect(() => {
284121
+ import_react73.useEffect(() => {
284054
284122
  if (phase === "completed") {
284055
284123
  setFocusedIndex(pentestAgentList.length);
284056
284124
  }
@@ -284113,7 +284181,7 @@ function Pentest({
284113
284181
  }
284114
284182
  }
284115
284183
  });
284116
- const openReport = import_react75.useCallback(() => {
284184
+ const openReport = import_react73.useCallback(() => {
284117
284185
  if (!session)
284118
284186
  return;
284119
284187
  const err = openSessionReport(session.rootPath);
@@ -284298,7 +284366,7 @@ function OrchestratorPanel({
284298
284366
  }) {
284299
284367
  const { colors: colors2 } = useTheme();
284300
284368
  const isRunning = phase !== "loading" && phase !== "completed" && phase !== "error";
284301
- const assetSummary = import_react75.useMemo(() => {
284369
+ const assetSummary = import_react73.useMemo(() => {
284302
284370
  const byType = {};
284303
284371
  for (const a of assets) {
284304
284372
  const key = a.assetType;
@@ -284541,13 +284609,13 @@ function AgentCardGrid({
284541
284609
  onSelectAgent
284542
284610
  }) {
284543
284611
  const { colors: colors2 } = useTheme();
284544
- const scrollRef = import_react75.useRef(null);
284545
- import_react75.useEffect(() => {
284612
+ const scrollRef = import_react73.useRef(null);
284613
+ import_react73.useEffect(() => {
284546
284614
  const agent = agents[focusedIndex];
284547
284615
  if (agent)
284548
284616
  scrollToChild(scrollRef.current, agent.id);
284549
284617
  }, [focusedIndex, agents]);
284550
- const rows = import_react75.useMemo(() => {
284618
+ const rows = import_react73.useMemo(() => {
284551
284619
  const result = [];
284552
284620
  for (let i2 = 0;i2 < agents.length; i2 += gridColumns) {
284553
284621
  result.push(agents.slice(i2, i2 + gridColumns));
@@ -284604,14 +284672,14 @@ function AgentCard({
284604
284672
  completed: colors2.primary,
284605
284673
  failed: colors2.error
284606
284674
  }[agent.status];
284607
- const lastActivity = import_react75.useMemo(() => {
284675
+ const lastActivity = import_react73.useMemo(() => {
284608
284676
  const last = agent.messages[agent.messages.length - 1];
284609
284677
  if (!last)
284610
284678
  return "Starting...";
284611
284679
  const text2 = typeof last.content === "string" ? last.content.replace(/\n/g, " ").trim() : "Working...";
284612
284680
  return text2.length > 50 ? text2.substring(0, 47) + "..." : text2;
284613
284681
  }, [agent.messages]);
284614
- const toolCalls = import_react75.useMemo(() => agent.messages.filter((m4) => m4.role === "tool").length, [agent.messages]);
284682
+ const toolCalls = import_react73.useMemo(() => agent.messages.filter((m4) => m4.role === "tool").length, [agent.messages]);
284615
284683
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
284616
284684
  id: agent.id,
284617
284685
  flexGrow: 1,
@@ -284799,8 +284867,8 @@ function MetricsBar({
284799
284867
  isExecuting
284800
284868
  }) {
284801
284869
  const { colors: colors2 } = useTheme();
284802
- const [now2, setNow] = import_react75.useState(Date.now());
284803
- import_react75.useEffect(() => {
284870
+ const [now2, setNow] = import_react73.useState(Date.now());
284871
+ import_react73.useEffect(() => {
284804
284872
  if (!isExecuting)
284805
284873
  return;
284806
284874
  const interval = setInterval(() => setNow(Date.now()), 1000);
@@ -284943,7 +285011,7 @@ function MetricsBar({
284943
285011
  }
284944
285012
 
284945
285013
  // src/tui/components/operator-dashboard/index.tsx
284946
- var import_react80 = __toESM(require_react(), 1);
285014
+ var import_react78 = __toESM(require_react(), 1);
284947
285015
  init_session();
284948
285016
 
284949
285017
  // src/core/api/offesecAgent.ts
@@ -285046,7 +285114,7 @@ function InlineApprovalPrompt2({ approval }) {
285046
285114
  }
285047
285115
 
285048
285116
  // src/tui/components/chat/loading-indicator.tsx
285049
- var import_react77 = __toESM(require_react(), 1);
285117
+ var import_react75 = __toESM(require_react(), 1);
285050
285118
  var SPINNER_FRAMES2 = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
285051
285119
  var SPINNER_INTERVAL2 = 80;
285052
285120
  var DOTS_FRAMES = ["", ".", "..", "..."];
@@ -285057,15 +285125,15 @@ function LoadingIndicator({
285057
285125
  toolName
285058
285126
  }) {
285059
285127
  const { colors: colors2 } = useTheme();
285060
- const [spinnerFrame, setSpinnerFrame] = import_react77.useState(0);
285061
- const [dotsFrame, setDotsFrame] = import_react77.useState(0);
285062
- import_react77.useEffect(() => {
285128
+ const [spinnerFrame, setSpinnerFrame] = import_react75.useState(0);
285129
+ const [dotsFrame, setDotsFrame] = import_react75.useState(0);
285130
+ import_react75.useEffect(() => {
285063
285131
  const interval = setInterval(() => {
285064
285132
  setSpinnerFrame((f3) => (f3 + 1) % SPINNER_FRAMES2.length);
285065
285133
  }, SPINNER_INTERVAL2);
285066
285134
  return () => clearInterval(interval);
285067
285135
  }, []);
285068
- import_react77.useEffect(() => {
285136
+ import_react75.useEffect(() => {
285069
285137
  const interval = setInterval(() => {
285070
285138
  setDotsFrame((f3) => (f3 + 1) % DOTS_FRAMES.length);
285071
285139
  }, DOTS_INTERVAL);
@@ -285319,7 +285387,7 @@ function MessageList({
285319
285387
  }
285320
285388
 
285321
285389
  // src/tui/components/chat/input-area.tsx
285322
- var import_react78 = __toESM(require_react(), 1);
285390
+ var import_react76 = __toESM(require_react(), 1);
285323
285391
  function NormalInputAreaInner({
285324
285392
  value,
285325
285393
  onChange,
@@ -285341,10 +285409,10 @@ function NormalInputAreaInner({
285341
285409
  }) {
285342
285410
  const { colors: colors2, theme, mode: colorMode } = useTheme();
285343
285411
  const { inputValue, setInputValue } = useInput();
285344
- const promptRef = import_react78.useRef(null);
285345
- const isExternalUpdate = import_react78.useRef(false);
285346
- const prevValueRef = import_react78.useRef(value);
285347
- import_react78.useEffect(() => {
285412
+ const promptRef = import_react76.useRef(null);
285413
+ const isExternalUpdate = import_react76.useRef(false);
285414
+ const prevValueRef = import_react76.useRef(value);
285415
+ import_react76.useEffect(() => {
285348
285416
  const prevValue = prevValueRef.current;
285349
285417
  prevValueRef.current = value;
285350
285418
  if (value !== prevValue && value !== inputValue) {
@@ -285353,7 +285421,7 @@ function NormalInputAreaInner({
285353
285421
  promptRef.current?.setValue(value);
285354
285422
  }
285355
285423
  }, [value, inputValue, setInputValue]);
285356
- import_react78.useEffect(() => {
285424
+ import_react76.useEffect(() => {
285357
285425
  if (isExternalUpdate.current) {
285358
285426
  isExternalUpdate.current = false;
285359
285427
  return;
@@ -285528,7 +285596,7 @@ function ApprovalInputArea2({
285528
285596
  lastDeclineNote
285529
285597
  }) {
285530
285598
  const { colors: colors2 } = useTheme();
285531
- const [focusedElement, setFocusedElement] = import_react78.useState(0);
285599
+ const [focusedElement, setFocusedElement] = import_react76.useState(0);
285532
285600
  useKeyboard((key) => {
285533
285601
  if (key.name === "up") {
285534
285602
  setFocusedElement((prev) => Math.max(0, prev - 1));
@@ -285855,29 +285923,29 @@ function OperatorDashboard({
285855
285923
  clear: clearDialog,
285856
285924
  setSize: setDialogSize
285857
285925
  } = useDialog();
285858
- const autocompleteOptions = import_react80.useMemo(() => {
285926
+ const autocompleteOptions = import_react78.useMemo(() => {
285859
285927
  const skillSlugs = new Set(skills.map((s2) => `/${slugify(s2.name)}`));
285860
285928
  return filterOperatorAutocomplete(allAutocompleteOptions, skillSlugs);
285861
285929
  }, [allAutocompleteOptions, skills]);
285862
- const [session, setSession] = import_react80.useState(null);
285863
- const [loading, setLoading] = import_react80.useState(true);
285864
- const [error40, setError] = import_react80.useState(null);
285865
- const pendingNameRef = import_react80.useRef(null);
285866
- const [status, setStatus] = import_react80.useState("idle");
285867
- const abortControllerRef = import_react80.useRef(null);
285868
- const generationRef = import_react80.useRef(0);
285869
- const cancelHandleRef = import_react80.useRef({
285930
+ const [session, setSession] = import_react78.useState(null);
285931
+ const [loading, setLoading] = import_react78.useState(true);
285932
+ const [error40, setError] = import_react78.useState(null);
285933
+ const pendingNameRef = import_react78.useRef(null);
285934
+ const [status, setStatus] = import_react78.useState("idle");
285935
+ const abortControllerRef = import_react78.useRef(null);
285936
+ const generationRef = import_react78.useRef(0);
285937
+ const cancelHandleRef = import_react78.useRef({
285870
285938
  cancel: () => false
285871
285939
  });
285872
- const commandCancelledRef = import_react80.useRef(false);
285873
- const [messages, setMessages] = import_react80.useState([]);
285874
- const textRef = import_react80.useRef("");
285875
- const conversationRef = import_react80.useRef([]);
285876
- const [inputValue, setInputValue] = import_react80.useState("");
285877
- const [queuedMessages, setQueuedMessages] = import_react80.useState([]);
285878
- const [selectedQueueIndex, setSelectedQueueIndex] = import_react80.useState(-1);
285879
- const queuedMessagesRef = import_react80.useRef([]);
285880
- import_react80.useEffect(() => {
285940
+ const commandCancelledRef = import_react78.useRef(false);
285941
+ const [messages, setMessages] = import_react78.useState([]);
285942
+ const textRef = import_react78.useRef("");
285943
+ const conversationRef = import_react78.useRef([]);
285944
+ const [inputValue, setInputValue] = import_react78.useState("");
285945
+ const [queuedMessages, setQueuedMessages] = import_react78.useState([]);
285946
+ const [selectedQueueIndex, setSelectedQueueIndex] = import_react78.useState(-1);
285947
+ const queuedMessagesRef = import_react78.useRef([]);
285948
+ import_react78.useEffect(() => {
285881
285949
  queuedMessagesRef.current = queuedMessages;
285882
285950
  if (queuedMessages.length === 0) {
285883
285951
  setSelectedQueueIndex(-1);
@@ -285885,17 +285953,17 @@ function OperatorDashboard({
285885
285953
  setSelectedQueueIndex(queuedMessages.length - 1);
285886
285954
  }
285887
285955
  }, [queuedMessages, selectedQueueIndex]);
285888
- const [operatorState, setOperatorState] = import_react80.useState(() => createInitialOperatorState("manual", true));
285889
- const approvalGateRef = import_react80.useRef(new ApprovalGate({ requireApproval: true }));
285890
- const [pendingApprovals, setPendingApprovals] = import_react80.useState([]);
285891
- const [lastApprovedAction, setLastApprovedAction] = import_react80.useState(null);
285892
- const [verboseMode, setVerboseMode] = import_react80.useState(false);
285893
- const [expandedLogs, setExpandedLogs] = import_react80.useState(false);
285894
- const tokenUsageRef = import_react80.useRef(tokenUsage);
285895
- import_react80.useEffect(() => {
285956
+ const [operatorState, setOperatorState] = import_react78.useState(() => createInitialOperatorState("manual", true));
285957
+ const approvalGateRef = import_react78.useRef(new ApprovalGate({ requireApproval: true }));
285958
+ const [pendingApprovals, setPendingApprovals] = import_react78.useState([]);
285959
+ const [lastApprovedAction, setLastApprovedAction] = import_react78.useState(null);
285960
+ const [verboseMode, setVerboseMode] = import_react78.useState(false);
285961
+ const [expandedLogs, setExpandedLogs] = import_react78.useState(false);
285962
+ const tokenUsageRef = import_react78.useRef(tokenUsage);
285963
+ import_react78.useEffect(() => {
285896
285964
  tokenUsageRef.current = tokenUsage;
285897
285965
  }, [tokenUsage]);
285898
- import_react80.useEffect(() => {
285966
+ import_react78.useEffect(() => {
285899
285967
  const gate = approvalGateRef.current;
285900
285968
  const onApprovalNeeded = () => {
285901
285969
  setPendingApprovals(gate.getPendingApprovals());
@@ -285917,7 +285985,7 @@ function OperatorDashboard({
285917
285985
  gate.off("approval-resolved", onApprovalResolved);
285918
285986
  };
285919
285987
  }, []);
285920
- import_react80.useEffect(() => {
285988
+ import_react78.useEffect(() => {
285921
285989
  async function loadSession() {
285922
285990
  try {
285923
285991
  if (sessionId) {
@@ -285974,10 +286042,10 @@ function OperatorDashboard({
285974
286042
  }
285975
286043
  loadSession();
285976
286044
  }, [sessionId]);
285977
- import_react80.useEffect(() => {
286045
+ import_react78.useEffect(() => {
285978
286046
  return () => setSessionCwd(null);
285979
286047
  }, [setSessionCwd]);
285980
- import_react80.useEffect(() => {
286048
+ import_react78.useEffect(() => {
285981
286049
  if (!session)
285982
286050
  return;
285983
286051
  resetTokenUsage();
@@ -285995,7 +286063,7 @@ function OperatorDashboard({
285995
286063
  });
285996
286064
  } catch {}
285997
286065
  }, [session, addTokenUsage, resetTokenUsage]);
285998
- const appendText = import_react80.useCallback((text2) => {
286066
+ const appendText = import_react78.useCallback((text2) => {
285999
286067
  textRef.current += text2;
286000
286068
  const accumulated = textRef.current;
286001
286069
  setMessages((prev) => {
@@ -286011,8 +286079,8 @@ function OperatorDashboard({
286011
286079
  ];
286012
286080
  });
286013
286081
  }, []);
286014
- const toolArgsDeltaRef = import_react80.useRef(new Map);
286015
- const addStreamingToolCall = import_react80.useCallback((toolCallId, toolName) => {
286082
+ const toolArgsDeltaRef = import_react78.useRef(new Map);
286083
+ const addStreamingToolCall = import_react78.useCallback((toolCallId, toolName) => {
286016
286084
  textRef.current = "";
286017
286085
  toolArgsDeltaRef.current.set(toolCallId, {
286018
286086
  toolName,
@@ -286031,7 +286099,7 @@ function OperatorDashboard({
286031
286099
  }
286032
286100
  ]);
286033
286101
  }, []);
286034
- const appendToolCallDelta = import_react80.useCallback((toolCallId, argsTextDelta) => {
286102
+ const appendToolCallDelta = import_react78.useCallback((toolCallId, argsTextDelta) => {
286035
286103
  const entry = toolArgsDeltaRef.current.get(toolCallId);
286036
286104
  const accumulated = (entry?.accumulated ?? "") + argsTextDelta;
286037
286105
  toolArgsDeltaRef.current.set(toolCallId, {
@@ -286053,7 +286121,7 @@ function OperatorDashboard({
286053
286121
  return updated;
286054
286122
  });
286055
286123
  }, []);
286056
- const addToolCall = import_react80.useCallback((toolCallId, toolName, args) => {
286124
+ const addToolCall = import_react78.useCallback((toolCallId, toolName, args) => {
286057
286125
  textRef.current = "";
286058
286126
  toolArgsDeltaRef.current.delete(toolCallId);
286059
286127
  setMessages((prev) => {
@@ -286082,7 +286150,7 @@ function OperatorDashboard({
286082
286150
  ];
286083
286151
  });
286084
286152
  }, []);
286085
- const updateToolResult = import_react80.useCallback((toolCallId, _toolName, result) => {
286153
+ const updateToolResult = import_react78.useCallback((toolCallId, _toolName, result) => {
286086
286154
  textRef.current = "";
286087
286155
  setMessages((prev) => {
286088
286156
  const idx = prev.findIndex((m4) => isToolMessage(m4) && m4.toolCallId === toolCallId);
@@ -286093,10 +286161,10 @@ function OperatorDashboard({
286093
286161
  return updated;
286094
286162
  });
286095
286163
  }, []);
286096
- const cmdOutputBufRef = import_react80.useRef("");
286097
- const cmdFlushTimerRef = import_react80.useRef(null);
286164
+ const cmdOutputBufRef = import_react78.useRef("");
286165
+ const cmdFlushTimerRef = import_react78.useRef(null);
286098
286166
  const MAX_LOG_LINES = 200;
286099
- const flushCommandOutput = import_react80.useCallback(() => {
286167
+ const flushCommandOutput = import_react78.useCallback(() => {
286100
286168
  const buf = cmdOutputBufRef.current;
286101
286169
  if (!buf)
286102
286170
  return;
@@ -286126,7 +286194,7 @@ function OperatorDashboard({
286126
286194
  return updated;
286127
286195
  });
286128
286196
  }, []);
286129
- const onCommandOutput = import_react80.useCallback((data) => {
286197
+ const onCommandOutput = import_react78.useCallback((data) => {
286130
286198
  cmdOutputBufRef.current += data;
286131
286199
  if (!cmdFlushTimerRef.current) {
286132
286200
  cmdFlushTimerRef.current = setInterval(() => {
@@ -286134,7 +286202,7 @@ function OperatorDashboard({
286134
286202
  }, 150);
286135
286203
  }
286136
286204
  }, [flushCommandOutput]);
286137
- import_react80.useEffect(() => {
286205
+ import_react78.useEffect(() => {
286138
286206
  return () => {
286139
286207
  if (cmdFlushTimerRef.current) {
286140
286208
  clearInterval(cmdFlushTimerRef.current);
@@ -286142,7 +286210,7 @@ function OperatorDashboard({
286142
286210
  }
286143
286211
  };
286144
286212
  }, []);
286145
- const appendLogToActiveTool = import_react80.useCallback((line) => {
286213
+ const appendLogToActiveTool = import_react78.useCallback((line) => {
286146
286214
  setMessages((prev) => {
286147
286215
  const idx = prev.findLastIndex((m4) => isToolMessage(m4) && (m4.status === "pending" || m4.status === "streaming"));
286148
286216
  if (idx === -1)
@@ -286157,7 +286225,7 @@ function OperatorDashboard({
286157
286225
  return updated;
286158
286226
  });
286159
286227
  }, []);
286160
- const initSubagent = import_react80.useCallback((subagentId, name26) => {
286228
+ const initSubagent = import_react78.useCallback((subagentId, name26) => {
286161
286229
  setMessages((prev) => {
286162
286230
  const idx = prev.findLastIndex((m4) => isToolMessage(m4) && (m4.status === "pending" || m4.status === "streaming"));
286163
286231
  if (idx === -1)
@@ -286172,7 +286240,7 @@ function OperatorDashboard({
286172
286240
  return updated;
286173
286241
  });
286174
286242
  }, []);
286175
- const completeSubagent = import_react80.useCallback((subagentId, status2) => {
286243
+ const completeSubagent = import_react78.useCallback((subagentId, status2) => {
286176
286244
  setMessages((prev) => {
286177
286245
  const idx = prev.findLastIndex((m4) => isToolMessage(m4) && (m4.status === "pending" || m4.status === "streaming"));
286178
286246
  if (idx === -1)
@@ -286190,7 +286258,7 @@ function OperatorDashboard({
286190
286258
  return updated;
286191
286259
  });
286192
286260
  }, []);
286193
- const appendLogToSubagent = import_react80.useCallback((subagentId, line) => {
286261
+ const appendLogToSubagent = import_react78.useCallback((subagentId, line) => {
286194
286262
  setMessages((prev) => {
286195
286263
  const idx = prev.findLastIndex((m4) => isToolMessage(m4) && (m4.status === "pending" || m4.status === "streaming"));
286196
286264
  if (idx === -1)
@@ -286212,13 +286280,13 @@ function OperatorDashboard({
286212
286280
  return updated;
286213
286281
  });
286214
286282
  }, []);
286215
- const handleApprove = import_react80.useCallback(() => {
286283
+ const handleApprove = import_react78.useCallback(() => {
286216
286284
  const pending = approvalGateRef.current.getPendingApprovals();
286217
286285
  if (pending.length > 0) {
286218
286286
  approvalGateRef.current.approve(pending[0].id);
286219
286287
  }
286220
286288
  }, []);
286221
- const handleAutoApprove = import_react80.useCallback(() => {
286289
+ const handleAutoApprove = import_react78.useCallback(() => {
286222
286290
  approvalGateRef.current.updateConfig({ requireApproval: false });
286223
286291
  setOperatorState((prev) => ({ ...prev, requireApproval: false }));
286224
286292
  const pending = approvalGateRef.current.getPendingApprovals();
@@ -286226,7 +286294,7 @@ function OperatorDashboard({
286226
286294
  approvalGateRef.current.approve(p.id);
286227
286295
  }
286228
286296
  }, []);
286229
- const runAgent = import_react80.useCallback(async (prompt) => {
286297
+ const runAgent = import_react78.useCallback(async (prompt) => {
286230
286298
  if (abortControllerRef.current) {
286231
286299
  abortControllerRef.current.abort();
286232
286300
  abortControllerRef.current = null;
@@ -286440,7 +286508,7 @@ function OperatorDashboard({
286440
286508
  setThinking,
286441
286509
  setIsExecuting
286442
286510
  ]);
286443
- const handleSubmit = import_react80.useCallback((value) => {
286511
+ const handleSubmit = import_react78.useCallback((value) => {
286444
286512
  const pending = approvalGateRef.current.getPendingApprovals();
286445
286513
  const result = resolveSubmit(value, status, pending.length > 0);
286446
286514
  if (result.denyPending) {
@@ -286458,16 +286526,16 @@ function OperatorDashboard({
286458
286526
  setInputValue("");
286459
286527
  runAgent(result.prompt);
286460
286528
  }, [status, runAgent]);
286461
- const initialMessageSentRef = import_react80.useRef(false);
286462
- const runAgentRef = import_react80.useRef(runAgent);
286529
+ const initialMessageSentRef = import_react78.useRef(false);
286530
+ const runAgentRef = import_react78.useRef(runAgent);
286463
286531
  runAgentRef.current = runAgent;
286464
- import_react80.useEffect(() => {
286532
+ import_react78.useEffect(() => {
286465
286533
  if (!loading && initialMessage && !initialMessageSentRef.current) {
286466
286534
  initialMessageSentRef.current = true;
286467
286535
  runAgentRef.current(initialMessage);
286468
286536
  }
286469
286537
  }, [loading, initialMessage]);
286470
- import_react80.useEffect(() => {
286538
+ import_react78.useEffect(() => {
286471
286539
  if (status !== "idle")
286472
286540
  return;
286473
286541
  const queue = queuedMessagesRef.current;
@@ -286478,7 +286546,7 @@ function OperatorDashboard({
286478
286546
  setSelectedQueueIndex(-1);
286479
286547
  runAgentRef.current(next);
286480
286548
  }, [status]);
286481
- const showModelPicker = import_react80.useCallback(() => {
286549
+ const showModelPicker = import_react78.useCallback(() => {
286482
286550
  setDialogSize("large");
286483
286551
  showDialog(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
286484
286552
  flexDirection: "column",
@@ -286540,7 +286608,7 @@ function OperatorDashboard({
286540
286608
  clearDialog,
286541
286609
  setDialogSize
286542
286610
  ]);
286543
- const handleCommandExecute = import_react80.useCallback(async (command) => {
286611
+ const handleCommandExecute = import_react78.useCallback(async (command) => {
286544
286612
  const action = routeCommand(command, resolveSkillContent);
286545
286613
  switch (action.type) {
286546
286614
  case "show-models":
@@ -286558,7 +286626,7 @@ function OperatorDashboard({
286558
286626
  return;
286559
286627
  }
286560
286628
  }, [resolveSkillContent, handleSubmit, executeCommand2, showModelPicker]);
286561
- const handleAbort = import_react80.useCallback(() => {
286629
+ const handleAbort = import_react78.useCallback(() => {
286562
286630
  if (!abortControllerRef.current)
286563
286631
  return;
286564
286632
  const action = resolveAbortAction(commandCancelledRef.current, () => cancelHandleRef.current.cancel());
@@ -286608,7 +286676,7 @@ function OperatorDashboard({
286608
286676
  ];
286609
286677
  });
286610
286678
  }, [session, setThinking, setIsExecuting]);
286611
- const toggleApproval = import_react80.useCallback(() => {
286679
+ const toggleApproval = import_react78.useCallback(() => {
286612
286680
  setOperatorState((prev) => {
286613
286681
  const newVal = !prev.requireApproval;
286614
286682
  approvalGateRef.current.updateConfig({ requireApproval: newVal });
@@ -286842,10 +286910,10 @@ function OperatorDashboard({
286842
286910
  }
286843
286911
 
286844
286912
  // src/tui/components/commands/theme-picker.tsx
286845
- var import_react82 = __toESM(require_react(), 1);
286913
+ var import_react80 = __toESM(require_react(), 1);
286846
286914
  init_config2();
286847
286915
  function ThemePicker({ onClose }) {
286848
- const dimensions = useTerminalDimensions();
286916
+ const dimensions = useDimensions();
286849
286917
  const {
286850
286918
  colors: colors2,
286851
286919
  theme,
@@ -286855,15 +286923,15 @@ function ThemePicker({ onClose }) {
286855
286923
  toggleMode,
286856
286924
  setMode
286857
286925
  } = useTheme();
286858
- const [selectedIndex, setSelectedIndex] = import_react82.useState(() => Math.max(0, availableThemes.indexOf(theme.name)));
286859
- const originalThemeRef = import_react82.useRef(theme.name);
286860
- const originalModeRef = import_react82.useRef(mode);
286861
- const handleClose = import_react82.useCallback(() => {
286926
+ const [selectedIndex, setSelectedIndex] = import_react80.useState(() => Math.max(0, availableThemes.indexOf(theme.name)));
286927
+ const originalThemeRef = import_react80.useRef(theme.name);
286928
+ const originalModeRef = import_react80.useRef(mode);
286929
+ const handleClose = import_react80.useCallback(() => {
286862
286930
  setTheme(originalThemeRef.current);
286863
286931
  setMode(originalModeRef.current);
286864
286932
  onClose();
286865
286933
  }, [setTheme, setMode, onClose]);
286866
- const handleConfirm = import_react82.useCallback(async () => {
286934
+ const handleConfirm = import_react80.useCallback(async () => {
286867
286935
  const currentThemeName = availableThemes[selectedIndex];
286868
286936
  if (currentThemeName) {
286869
286937
  await config2.update({ theme: currentThemeName });
@@ -286992,16 +287060,16 @@ function ThemePicker({ onClose }) {
286992
287060
  }
286993
287061
 
286994
287062
  // src/tui/components/commands/create-skill-wizard.tsx
286995
- var import_react84 = __toESM(require_react(), 1);
287063
+ var import_react82 = __toESM(require_react(), 1);
286996
287064
  function CreateSkillWizard() {
286997
287065
  const { colors: colors2 } = useTheme();
286998
287066
  const route = useRoute();
286999
- const [step, setStep] = import_react84.useState("name");
287000
- const [name26, setName] = import_react84.useState("");
287001
- const [description, setDescription] = import_react84.useState("");
287002
- const [content, setContent] = import_react84.useState("");
287003
- const [error40, setError] = import_react84.useState(null);
287004
- const [confirmFocused, setConfirmFocused] = import_react84.useState(0);
287067
+ const [step, setStep] = import_react82.useState("name");
287068
+ const [name26, setName] = import_react82.useState("");
287069
+ const [description, setDescription] = import_react82.useState("");
287070
+ const [content, setContent] = import_react82.useState("");
287071
+ const [error40, setError] = import_react82.useState(null);
287072
+ const [confirmFocused, setConfirmFocused] = import_react82.useState(0);
287005
287073
  const slug = slugify(name26);
287006
287074
  async function handleSave() {
287007
287075
  if (!name26.trim() || !content.trim())
@@ -289877,7 +289945,7 @@ async function detectTerminalMode(timeoutMs = 1000) {
289877
289945
  }
289878
289946
 
289879
289947
  // src/tui/console-theme.ts
289880
- var import_react86 = __toESM(require_react(), 1);
289948
+ var import_react84 = __toESM(require_react(), 1);
289881
289949
  var withAlpha = (rgba, a) => RGBA.fromValues(rgba.r, rgba.g, rgba.b, a);
289882
289950
  var overlayThemeRef = {
289883
289951
  current: null
@@ -289900,7 +289968,7 @@ function buildConsoleOptions(themeColors) {
289900
289968
  function ConsoleThemeSync() {
289901
289969
  const { colors: colors2 } = useTheme();
289902
289970
  const renderer = useRenderer();
289903
- import_react86.useEffect(() => {
289971
+ import_react84.useEffect(() => {
289904
289972
  overlayThemeRef.current = colors2;
289905
289973
  const c = renderer.console;
289906
289974
  c.backgroundColor = withAlpha(colors2.backgroundPanel, 0.85);
@@ -289988,17 +290056,17 @@ function setupAutoCopy(renderer, copyToClipboard) {
289988
290056
 
289989
290057
  // src/tui/index.tsx
289990
290058
  function App({ appConfig }) {
289991
- const [focusIndex, setFocusIndex] = import_react89.useState(0);
289992
- const [cwd, setCwd] = import_react89.useState(process.cwd());
289993
- const [ctrlCPressTime, setCtrlCPressTime] = import_react89.useState(null);
289994
- const [showExitWarning, setShowExitWarning] = import_react89.useState(false);
289995
- const [inputKey, setInputKey] = import_react89.useState(0);
289996
- const [showSessionsDialog, setShowSessionsDialog] = import_react89.useState(false);
289997
- const [showShortcutsDialog, setShowShortcutsDialog] = import_react89.useState(false);
289998
- const [showThemeDialog, setShowThemeDialog] = import_react89.useState(false);
289999
- const [showAuthDialog, setShowAuthDialog] = import_react89.useState(false);
290000
- const [showPentestDialog, setShowPentestDialog] = import_react89.useState(false);
290001
- const [pendingPentestFlags, setPendingPentestFlags] = import_react89.useState(undefined);
290059
+ const [focusIndex, setFocusIndex] = import_react87.useState(0);
290060
+ const [cwd, setCwd] = import_react87.useState(process.cwd());
290061
+ const [ctrlCPressTime, setCtrlCPressTime] = import_react87.useState(null);
290062
+ const [showExitWarning, setShowExitWarning] = import_react87.useState(false);
290063
+ const [inputKey, setInputKey] = import_react87.useState(0);
290064
+ const [showSessionsDialog, setShowSessionsDialog] = import_react87.useState(false);
290065
+ const [showShortcutsDialog, setShowShortcutsDialog] = import_react87.useState(false);
290066
+ const [showThemeDialog, setShowThemeDialog] = import_react87.useState(false);
290067
+ const [showAuthDialog, setShowAuthDialog] = import_react87.useState(false);
290068
+ const [showPentestDialog, setShowPentestDialog] = import_react87.useState(false);
290069
+ const [pendingPentestFlags, setPendingPentestFlags] = import_react87.useState(undefined);
290002
290070
  const navigableItems = ["command-input"];
290003
290071
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ConfigProvider, {
290004
290072
  config: appConfig,
@@ -290085,14 +290153,14 @@ function AppContent({
290085
290153
  const { toast } = useToast();
290086
290154
  const { refocusPrompt } = useFocus();
290087
290155
  const { setExternalDialogOpen } = useDialog();
290088
- import_react89.useEffect(() => {
290156
+ import_react87.useEffect(() => {
290089
290157
  checkForUpdate().then(({ updateAvailable, currentVersion, latestVersion }) => {
290090
290158
  if (!updateAvailable)
290091
290159
  return;
290092
290160
  toast(`Update available: v${currentVersion} → v${latestVersion}. Run: pensar upgrade`, "warn", 8000);
290093
290161
  });
290094
290162
  }, []);
290095
- import_react89.useEffect(() => {
290163
+ import_react87.useEffect(() => {
290096
290164
  if (route.data.type !== "base")
290097
290165
  return;
290098
290166
  if (!config3.data.responsibleUseAccepted && route.data.path !== "disclosure") {
@@ -290101,12 +290169,12 @@ function AppContent({
290101
290169
  route.navigate({ type: "base", path: "providers" });
290102
290170
  }
290103
290171
  }, [config3.data.responsibleUseAccepted, route.data]);
290104
- import_react89.useEffect(() => {
290172
+ import_react87.useEffect(() => {
290105
290173
  if (showThemeDialog || showAuthDialog || showPentestDialog) {
290106
290174
  setExternalDialogOpen(true);
290107
290175
  }
290108
290176
  }, [showThemeDialog, showAuthDialog, showPentestDialog]);
290109
- import_react89.useEffect(() => {
290177
+ import_react87.useEffect(() => {
290110
290178
  if (showExitWarning) {
290111
290179
  const timer = setTimeout(() => {
290112
290180
  setShowExitWarning(false);
@@ -290360,16 +290428,18 @@ async function main2() {
290360
290428
  initialMode: mode,
290361
290429
  children: [
290362
290430
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ConsoleThemeSync, {}, undefined, false, undefined, this),
290363
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToastProvider, {
290364
- children: [
290365
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ErrorBoundary2, {
290366
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(App, {
290367
- appConfig
290368
- }, undefined, false, undefined, this)
290369
- }, undefined, false, undefined, this),
290370
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToastContainer, {}, undefined, false, undefined, this)
290371
- ]
290372
- }, undefined, true, undefined, this)
290431
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(TerminalDimensionsProvider, {
290432
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToastProvider, {
290433
+ children: [
290434
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ErrorBoundary2, {
290435
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(App, {
290436
+ appConfig
290437
+ }, undefined, false, undefined, this)
290438
+ }, undefined, false, undefined, this),
290439
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToastContainer, {}, undefined, false, undefined, this)
290440
+ ]
290441
+ }, undefined, true, undefined, this)
290442
+ }, undefined, false, undefined, this)
290373
290443
  ]
290374
290444
  }, undefined, true, undefined, this));
290375
290445
  }