@pensar/apex 0.0.57 → 0.0.58-canary.8d44eb90

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 +1210 -561
  2. package/package.json +1 -1
package/build/index.js CHANGED
@@ -69284,7 +69284,7 @@ function createRoot(renderer) {
69284
69284
  }
69285
69285
 
69286
69286
  // src/tui/index.tsx
69287
- var import_react87 = __toESM(require_react(), 1);
69287
+ var import_react88 = __toESM(require_react(), 1);
69288
69288
 
69289
69289
  // src/tui/components/footer.tsx
69290
69290
  import os5 from "os";
@@ -70114,13 +70114,13 @@ async function get() {
70114
70114
  return {
70115
70115
  ...parsedConfig,
70116
70116
  version,
70117
- openAiAPIKey: process.env.OPENAI_API_KEY,
70118
- anthropicAPIKey: process.env.ANTHROPIC_API_KEY,
70119
- openRouterAPIKey: process.env.OPENROUTER_API_KEY,
70120
- bedrockAPIKey: process.env.BEDROCK_API_KEY,
70121
- daytonaAPIKey: process.env.DAYTONA_API_KEY,
70122
- daytonaOrgId: process.env.DAYTONA_ORG_ID,
70123
- runloopAPIKey: process.env.RUNLOOP_API_KEY
70117
+ openAiAPIKey: process.env.OPENAI_API_KEY ?? parsedConfig.openAiAPIKey,
70118
+ anthropicAPIKey: process.env.ANTHROPIC_API_KEY ?? parsedConfig.anthropicAPIKey,
70119
+ openRouterAPIKey: process.env.OPENROUTER_API_KEY ?? parsedConfig.openRouterAPIKey,
70120
+ bedrockAPIKey: process.env.BEDROCK_API_KEY ?? parsedConfig.bedrockAPIKey,
70121
+ daytonaAPIKey: process.env.DAYTONA_API_KEY ?? parsedConfig.daytonaAPIKey,
70122
+ daytonaOrgId: process.env.DAYTONA_ORG_ID ?? parsedConfig.daytonaOrgId,
70123
+ runloopAPIKey: process.env.RUNLOOP_API_KEY ?? parsedConfig.runloopAPIKey
70124
70124
  };
70125
70125
  }
70126
70126
  async function update(config) {
@@ -71905,14 +71905,14 @@ var commands = [
71905
71905
  }
71906
71906
  },
71907
71907
  {
71908
- name: "resume",
71909
- aliases: ["r"],
71910
- description: "Resume a previous pentest session",
71908
+ name: "sessions",
71909
+ aliases: ["s"],
71910
+ description: "Browse previous sessions",
71911
71911
  category: "Pentesting",
71912
71912
  handler: async (args, ctx3) => {
71913
71913
  ctx3.navigate({
71914
71914
  type: "base",
71915
- path: "resume"
71915
+ path: "sessions"
71916
71916
  });
71917
71917
  }
71918
71918
  },
@@ -71921,6 +71921,7 @@ var commands = [
71921
71921
  aliases: ["c"],
71922
71922
  description: "Open the Chat TUI interface",
71923
71923
  category: "General",
71924
+ hidden: true,
71924
71925
  handler: async (args, ctx3) => {
71925
71926
  ctx3.navigate({
71926
71927
  type: "base",
@@ -71933,6 +71934,7 @@ var commands = [
71933
71934
  aliases: ["t"],
71934
71935
  description: "View and manage active tools (session only)",
71935
71936
  category: "Session",
71937
+ hidden: true,
71936
71938
  handler: async (args, ctx3) => {
71937
71939
  if (ctx3.route.type !== "session") {
71938
71940
  return;
@@ -71979,6 +71981,8 @@ function CommandProvider({ children }) {
71979
71981
  const options = [];
71980
71982
  for (const cmd of routerCommands) {
71981
71983
  const cmdConfig = commands.find((c) => c.name === cmd.name);
71984
+ if (cmdConfig?.hidden)
71985
+ continue;
71982
71986
  let description = cmd.description || "";
71983
71987
  options.push({
71984
71988
  value: `/${cmd.name}`,
@@ -74216,7 +74220,7 @@ var PromptInput = import_react25.forwardRef(function PromptInput2({
74216
74220
  onSubmit,
74217
74221
  enableAutocomplete = false,
74218
74222
  autocompleteOptions = [],
74219
- maxSuggestions = 6,
74223
+ maxSuggestions = 10,
74220
74224
  enableCommands = false,
74221
74225
  onCommandExecute,
74222
74226
  showPromptIndicator = false
@@ -74502,6 +74506,13 @@ var SubAgentDisplay = import_react27.memo(function SubAgentDisplay2({
74502
74506
  subagent.name
74503
74507
  ]
74504
74508
  }, undefined, true, undefined, this),
74509
+ subagent.status === "paused" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
74510
+ fg: colors.orangeText,
74511
+ children: [
74512
+ "⏸ ",
74513
+ subagent.name
74514
+ ]
74515
+ }, undefined, true, undefined, this),
74505
74516
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
74506
74517
  fg: "gray",
74507
74518
  children: open ? "▼" : "▶"
@@ -74837,15 +74848,31 @@ function SwarmDashboard({
74837
74848
  isCompleted,
74838
74849
  onBack,
74839
74850
  onViewReport,
74840
- onKillAgent
74851
+ onKillAgent,
74852
+ onResumeAgent
74841
74853
  }) {
74842
74854
  const [currentView, setCurrentView] = import_react31.useState("overview");
74843
74855
  const [selectedAgentId, setSelectedAgentId] = import_react31.useState(null);
74844
74856
  const [focusedIndex, setFocusedIndex] = import_react31.useState(0);
74845
74857
  const [showDiscoveryLogs, setShowDiscoveryLogs] = import_react31.useState(false);
74846
74858
  const { stack, externalDialogOpen } = useDialog();
74847
- const discoveryAgent = import_react31.useMemo(() => subagents.find((s) => s.type === "attack-surface") || null, [subagents]);
74859
+ const discoveryAgent = import_react31.useMemo(() => subagents.find((s) => s.type === "attack-surface" && s.status === "pending") || subagents.find((s) => s.type === "attack-surface") || null, [subagents]);
74848
74860
  const pentestAgents = import_react31.useMemo(() => subagents.filter((s) => s.type === "pentest"), [subagents]);
74861
+ const allEndpoints = import_react31.useMemo(() => {
74862
+ const endpointSet = new Set;
74863
+ const attackSurfaceAgents = subagents.filter((s) => s.type === "attack-surface");
74864
+ for (const agent of attackSurfaceAgents) {
74865
+ for (const msg of agent.messages) {
74866
+ if (msg.role === "assistant" && typeof msg.content === "string") {
74867
+ const urlMatches = msg.content.match(/\/[a-zA-Z0-9\/_.-]+/g);
74868
+ if (urlMatches) {
74869
+ urlMatches.forEach((u) => endpointSet.add(u));
74870
+ }
74871
+ }
74872
+ }
74873
+ }
74874
+ return Array.from(endpointSet).slice(0, 50);
74875
+ }, [subagents]);
74849
74876
  const metrics = import_react31.useMemo(() => {
74850
74877
  const findingsCount = subagents.reduce((sum, s) => {
74851
74878
  return sum + s.messages.filter((m2) => m2.role === "assistant" && typeof m2.content === "string" && (m2.content.includes("finding") || m2.content.includes("vulnerability"))).length;
@@ -74868,6 +74895,10 @@ function SwarmDashboard({
74868
74895
  setShowDiscoveryLogs((prev) => !prev);
74869
74896
  return;
74870
74897
  }
74898
+ if ((key.name === "r" || key.name === "R") && discoveryAgent?.status === "paused") {
74899
+ onResumeAgent?.(discoveryAgent.id);
74900
+ return;
74901
+ }
74871
74902
  const agentCount = pentestAgents.length;
74872
74903
  if (key.name === "escape") {
74873
74904
  if (showDiscoveryLogs) {
@@ -74922,6 +74953,10 @@ function SwarmDashboard({
74922
74953
  setSelectedAgentId(null);
74923
74954
  return;
74924
74955
  }
74956
+ if ((key.name === "r" || key.name === "R") && selectedAgent?.status === "paused") {
74957
+ onResumeAgent?.(selectedAgent.id);
74958
+ return;
74959
+ }
74925
74960
  }
74926
74961
  });
74927
74962
  if (currentView === "detail" && selectedAgent) {
@@ -74930,7 +74965,8 @@ function SwarmDashboard({
74930
74965
  onBack: () => {
74931
74966
  setCurrentView("overview");
74932
74967
  setSelectedAgentId(null);
74933
- }
74968
+ },
74969
+ onResume: selectedAgent.status === "paused" ? () => onResumeAgent?.(selectedAgent.id) : undefined
74934
74970
  }, undefined, false, undefined, this);
74935
74971
  }
74936
74972
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
@@ -74947,6 +74983,7 @@ function SwarmDashboard({
74947
74983
  children: [
74948
74984
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(DiscoveryPanel, {
74949
74985
  agent: discoveryAgent,
74986
+ endpoints: allEndpoints,
74950
74987
  showLogs: showDiscoveryLogs,
74951
74988
  onToggleLogs: () => setShowDiscoveryLogs((prev) => !prev)
74952
74989
  }, undefined, false, undefined, this),
@@ -74962,7 +74999,28 @@ function SwarmDashboard({
74962
74999
  borderColor: dimText,
74963
75000
  backgroundColor: darkBg,
74964
75001
  padding: 2,
74965
- children: discoveryAgent?.status === "pending" ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
75002
+ children: discoveryAgent?.status === "paused" ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
75003
+ flexDirection: "column",
75004
+ alignItems: "center",
75005
+ gap: 1,
75006
+ children: [
75007
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75008
+ fg: colors.orangeText,
75009
+ children: "⏸ Discovery was interrupted"
75010
+ }, undefined, false, undefined, this),
75011
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75012
+ fg: dimText,
75013
+ children: [
75014
+ "Press ",
75015
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
75016
+ fg: colors.orangeText,
75017
+ children: "[R]"
75018
+ }, undefined, false, undefined, this),
75019
+ " to resume"
75020
+ ]
75021
+ }, undefined, true, undefined, this)
75022
+ ]
75023
+ }, undefined, true, undefined, this) : discoveryAgent?.status === "pending" ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
74966
75024
  flexDirection: "column",
74967
75025
  alignItems: "center",
74968
75026
  gap: 1,
@@ -75051,30 +75109,18 @@ function SwarmDashboard({
75051
75109
  canceledAgents: metrics.canceledAgents,
75052
75110
  duration: metrics.duration,
75053
75111
  isExecuting,
75054
- showKillHint: !!onKillAgent
75112
+ showKillHint: !!onKillAgent,
75113
+ discoveryPaused: discoveryAgent?.status === "paused"
75055
75114
  }, undefined, false, undefined, this)
75056
75115
  ]
75057
75116
  }, undefined, true, undefined, this);
75058
75117
  }
75059
75118
  function DiscoveryPanel({
75060
75119
  agent,
75120
+ endpoints,
75061
75121
  showLogs,
75062
75122
  onToggleLogs
75063
75123
  }) {
75064
- const endpoints = import_react31.useMemo(() => {
75065
- if (!agent)
75066
- return [];
75067
- const endpointSet = new Set;
75068
- for (const msg of agent.messages) {
75069
- if (msg.role === "assistant" && typeof msg.content === "string") {
75070
- const urlMatches = msg.content.match(/\/[a-zA-Z0-9\/_-]+/g);
75071
- if (urlMatches) {
75072
- urlMatches.forEach((u) => endpointSet.add(u));
75073
- }
75074
- }
75075
- }
75076
- return Array.from(endpointSet).slice(0, 50);
75077
- }, [agent?.messages]);
75078
75124
  if (showLogs && agent) {
75079
75125
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
75080
75126
  flexGrow: 1,
@@ -75106,6 +75152,10 @@ function DiscoveryPanel({
75106
75152
  agent.status === "failed" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75107
75153
  fg: "red",
75108
75154
  children: "✗ Attack Surface Discovery"
75155
+ }, undefined, false, undefined, this),
75156
+ agent.status === "paused" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75157
+ fg: colors.orangeText,
75158
+ children: "⏸ Attack Surface Discovery (Paused)"
75109
75159
  }, undefined, false, undefined, this)
75110
75160
  ]
75111
75161
  }, undefined, true, undefined, this),
@@ -75196,6 +75246,10 @@ function DiscoveryPanel({
75196
75246
  agent?.status === "failed" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75197
75247
  fg: "red",
75198
75248
  children: "✗ Discovery"
75249
+ }, undefined, false, undefined, this),
75250
+ agent?.status === "paused" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75251
+ fg: colors.orangeText,
75252
+ children: "⏸ Discovery"
75199
75253
  }, undefined, false, undefined, this)
75200
75254
  ]
75201
75255
  }, undefined, true, undefined, this),
@@ -75217,7 +75271,7 @@ function DiscoveryPanel({
75217
75271
  children: "Status: "
75218
75272
  }, undefined, false, undefined, this),
75219
75273
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
75220
- fg: agent.status === "pending" ? greenBullet : creamText,
75274
+ fg: agent.status === "pending" ? greenBullet : agent.status === "paused" ? colors.orangeText : creamText,
75221
75275
  children: agent.status
75222
75276
  }, undefined, false, undefined, this)
75223
75277
  ]
@@ -75245,6 +75299,18 @@ function DiscoveryPanel({
75245
75299
  children: endpoints.length
75246
75300
  }, undefined, false, undefined, this)
75247
75301
  ]
75302
+ }, undefined, true, undefined, this),
75303
+ agent.status === "paused" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75304
+ children: [
75305
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
75306
+ fg: colors.orangeText,
75307
+ children: "[R]"
75308
+ }, undefined, false, undefined, this),
75309
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
75310
+ fg: dimText,
75311
+ children: " Resume"
75312
+ }, undefined, false, undefined, this)
75313
+ ]
75248
75314
  }, undefined, true, undefined, this)
75249
75315
  ]
75250
75316
  }, undefined, true, undefined, this),
@@ -75280,12 +75346,14 @@ function AgentCard({ agent, focused, onSelect }) {
75280
75346
  pending: "◐",
75281
75347
  completed: "✓",
75282
75348
  failed: "✗",
75349
+ paused: "⏸",
75283
75350
  canceled: "⊘"
75284
75351
  }[agent.status];
75285
75352
  const statusColor = {
75286
75353
  pending: greenBullet,
75287
75354
  completed: greenBullet,
75288
75355
  failed: RGBA.fromInts(244, 67, 54, 255),
75356
+ paused: colors.orangeText,
75289
75357
  canceled: dimText
75290
75358
  }[agent.status];
75291
75359
  const lastActivity = import_react31.useMemo(() => {
@@ -75377,6 +75445,9 @@ function AgentCard({ agent, focused, onSelect }) {
75377
75445
  }, undefined, false, undefined, this) : agent.status === "pending" ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SpinnerDots, {
75378
75446
  label: lastActivity,
75379
75447
  fg: "green"
75448
+ }, undefined, false, undefined, this) : agent.status === "paused" ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75449
+ fg: colors.orangeText,
75450
+ children: "⏸ Paused — press Enter then R to resume"
75380
75451
  }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75381
75452
  fg: agent.status === "completed" ? greenBullet : dimText,
75382
75453
  children: agent.status === "completed" ? "✓ Complete" : lastActivity
@@ -75433,7 +75504,8 @@ function MetricsBar({
75433
75504
  canceledAgents,
75434
75505
  duration,
75435
75506
  isExecuting,
75436
- showKillHint
75507
+ showKillHint,
75508
+ discoveryPaused
75437
75509
  }) {
75438
75510
  const formattedDuration = import_react31.useMemo(() => {
75439
75511
  const mins = Math.floor(duration / 60);
@@ -75518,6 +75590,18 @@ function MetricsBar({
75518
75590
  flexDirection: "row",
75519
75591
  gap: 2,
75520
75592
  children: [
75593
+ discoveryPaused && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75594
+ children: [
75595
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
75596
+ fg: colors.orangeText,
75597
+ children: "[R]"
75598
+ }, undefined, false, undefined, this),
75599
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
75600
+ fg: dimText,
75601
+ children: " Resume"
75602
+ }, undefined, false, undefined, this)
75603
+ ]
75604
+ }, undefined, true, undefined, this),
75521
75605
  showKillHint && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75522
75606
  children: [
75523
75607
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
@@ -75583,11 +75667,12 @@ function MetricsBar({
75583
75667
  ]
75584
75668
  }, undefined, true, undefined, this);
75585
75669
  }
75586
- function AgentDetailView({ agent, onBack }) {
75670
+ function AgentDetailView({ agent, onBack, onResume }) {
75587
75671
  const statusColor = {
75588
75672
  pending: greenBullet,
75589
75673
  completed: greenBullet,
75590
75674
  failed: RGBA.fromInts(244, 67, 54, 255),
75675
+ paused: colors.orangeText,
75591
75676
  canceled: dimText
75592
75677
  }[agent.status];
75593
75678
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
@@ -75670,6 +75755,18 @@ function AgentDetailView({ agent, onBack }) {
75670
75755
  flexDirection: "row",
75671
75756
  gap: 2,
75672
75757
  children: [
75758
+ agent.status === "paused" && onResume && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75759
+ children: [
75760
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
75761
+ fg: colors.orangeText,
75762
+ children: "[R]"
75763
+ }, undefined, false, undefined, this),
75764
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
75765
+ fg: dimText,
75766
+ children: " Resume"
75767
+ }, undefined, false, undefined, this)
75768
+ ]
75769
+ }, undefined, true, undefined, this),
75673
75770
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
75674
75771
  children: [
75675
75772
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
@@ -125562,7 +125659,7 @@ Example workflow:
125562
125659
  execute: async (params) => recordTestResultCore(session, params)
125563
125660
  });
125564
125661
  }
125565
- async function generateTestStrategy(params, model, onTokenUsage) {
125662
+ async function generateTestStrategy(params, model, onTokenUsage, authConfig) {
125566
125663
  const prompt = `You are a penetration testing expert. Generate a concise testing strategy:
125567
125664
 
125568
125665
  Attack Type: ${params.knowledge.name}
@@ -125583,7 +125680,7 @@ Generate a 2-3 sentence testing strategy:
125583
125680
 
125584
125681
  Be tactical and specific.`;
125585
125682
  try {
125586
- const providerModel = getProviderModel(model);
125683
+ const providerModel = getProviderModel(model, authConfig);
125587
125684
  const result = await generateText({
125588
125685
  model: providerModel,
125589
125686
  prompt
@@ -125596,7 +125693,7 @@ Be tactical and specific.`;
125596
125693
  return params.knowledge.adaptiveStrategy;
125597
125694
  }
125598
125695
  }
125599
- async function generatePayload(params, model, onTokenUsage) {
125696
+ async function generatePayload(params, model, onTokenUsage, authConfig) {
125600
125697
  const prompt = `Generate ONE ${params.knowledge.name} payload for testing.
125601
125698
 
125602
125699
  Techniques:
@@ -125621,7 +125718,8 @@ Generate ONE specific payload. Return ONLY JSON:
125621
125718
  model,
125622
125719
  schema: PayloadSchema,
125623
125720
  prompt,
125624
- onTokenUsage
125721
+ onTokenUsage,
125722
+ authConfig
125625
125723
  });
125626
125724
  return result;
125627
125725
  } catch (error40) {
@@ -125634,7 +125732,7 @@ Generate ONE specific payload. Return ONLY JSON:
125634
125732
  technique: technique.name
125635
125733
  };
125636
125734
  }
125637
- async function analyzeResponse(params, model, onTokenUsage) {
125735
+ async function analyzeResponse(params, model, onTokenUsage, authConfig) {
125638
125736
  const prompt = `Analyze this security test response:
125639
125737
 
125640
125738
  Attack: ${params.knowledge.name}
@@ -125663,7 +125761,8 @@ Analyze: Is this vulnerable? Return ONLY JSON:
125663
125761
  model,
125664
125762
  schema: AnalysisSchema,
125665
125763
  prompt,
125666
- onTokenUsage
125764
+ onTokenUsage,
125765
+ authConfig
125667
125766
  });
125668
125767
  return result;
125669
125768
  } catch (error40) {
@@ -125682,7 +125781,7 @@ Analyze: Is this vulnerable? Return ONLY JSON:
125682
125781
  suggestedNextTest: "Try alternative payload or technique"
125683
125782
  };
125684
125783
  }
125685
- function createSmartTestTool(session, model, onTokenUsage) {
125784
+ function createSmartTestTool(session, model, onTokenUsage, authConfig) {
125686
125785
  return tool2({
125687
125786
  description: `Intelligently test a parameter for a vulnerability using AI-powered adaptive testing.
125688
125787
 
@@ -125751,7 +125850,7 @@ test_parameter({
125751
125850
  parameter,
125752
125851
  endpoint,
125753
125852
  context: context2
125754
- }, model, onTokenUsage);
125853
+ }, model, onTokenUsage, authConfig);
125755
125854
  console.log(`Strategy: ${strategy}`);
125756
125855
  const results = [];
125757
125856
  let vulnerable = false;
@@ -125764,7 +125863,7 @@ test_parameter({
125764
125863
  context: { ...context2, parameter, endpoint },
125765
125864
  previousResults: results,
125766
125865
  round
125767
- }, model, onTokenUsage);
125866
+ }, model, onTokenUsage, authConfig);
125768
125867
  console.log(` Payload: ${payloadData.payload}`);
125769
125868
  console.log(` Reasoning: ${payloadData.reasoning}`);
125770
125869
  let response;
@@ -125793,7 +125892,7 @@ test_parameter({
125793
125892
  attackType,
125794
125893
  knowledge,
125795
125894
  previousResults: results
125796
- }, model, onTokenUsage);
125895
+ }, model, onTokenUsage, authConfig);
125797
125896
  console.log(` Analysis: ${analysis.reasoning}`);
125798
125897
  console.log(` Vulnerable: ${analysis.vulnerable} (confidence: ${analysis.confidence})`);
125799
125898
  results.push({
@@ -126237,7 +126336,7 @@ function wrapCommandWithHeaders(command, headers) {
126237
126336
  }
126238
126337
  return wrapped;
126239
126338
  }
126240
- function createPentestTools(session, model, toolOverride, onTokenUsage, abortSignal, operatorMode) {
126339
+ function createPentestTools(session, model, toolOverride, onTokenUsage, abortSignal, operatorMode, authConfig) {
126241
126340
  const offensiveHeaders = Session.getOffensiveHeaders(session);
126242
126341
  const fuzzEndpoint = tool2({
126243
126342
  description: "Fuzz an endpoint with values between a given range to test for IDOR vulnerabilities. Only try to fuzz at most 50 values with each call of this tool.",
@@ -126793,7 +126892,7 @@ Example flow:
126793
126892
  cve_lookup: createCVELookupTool(),
126794
126893
  document_finding: createDocumentFindingTool(session),
126795
126894
  record_test_result: createRecordTestResultTool(session),
126796
- test_parameter: createSmartTestTool(session, model || "claude-sonnet-4-20250514", onTokenUsage),
126895
+ test_parameter: createSmartTestTool(session, model || "claude-sonnet-4-20250514", onTokenUsage, authConfig),
126797
126896
  check_testing_coverage: createCheckTestingCoverageTool(session),
126798
126897
  validate_completeness: createValidateCompletenessTool(session),
126799
126898
  enumerate_endpoints: createEnumerateEndpointsTool(session),
@@ -136760,7 +136859,7 @@ async function runAgent(opts) {
136760
136859
  http_request,
136761
136860
  cve_lookup,
136762
136861
  smart_enumerate
136763
- } = createPentestTools(session, model, toolOverride, onToolTokenUsage, abortSignal);
136862
+ } = createPentestTools(session, model, toolOverride, onToolTokenUsage, abortSignal, undefined, authConfig);
136764
136863
  const evidenceDir = join7(session.rootPath, "evidence");
136765
136864
  const browserTools = createBrowserTools(target, evidenceDir, "operator", undefined, abortSignal);
136766
136865
  const document_asset = tool2({
@@ -138385,13 +138484,14 @@ var CVSS_SCORER_SYSTEM_PROMPT = `You are a CVSS 4.0 scoring specialist. Your tas
138385
138484
  7. Since a POC exists and confirmed the vulnerability, E should typically be 'A'
138386
138485
 
138387
138486
  Always provide brief reasoning explaining your key decisions.`;
138388
- async function scoreFindingWithCVSS(input, model) {
138487
+ async function scoreFindingWithCVSS(input, model, authConfig) {
138389
138488
  const prompt = buildScoringPrompt(input);
138390
138489
  const assessment = await generateObjectResponse({
138391
138490
  model,
138392
138491
  schema: CVSSMetricsOutputSchema,
138393
138492
  prompt,
138394
- system: CVSS_SCORER_SYSTEM_PROMPT
138493
+ system: CVSS_SCORER_SYSTEM_PROMPT,
138494
+ authConfig
138395
138495
  });
138396
138496
  const cvssResult = calculateCVSS4Score({
138397
138497
  ...assessment.metrics
@@ -138785,7 +138885,7 @@ Continue testing for OTHER vulnerabilities at different endpoints.`
138785
138885
  remediation: finding.remediation
138786
138886
  },
138787
138887
  agentMessages: messages
138788
- }, cvssModel);
138888
+ }, cvssModel, cvssOptions?.authConfig);
138789
138889
  cvssData = {
138790
138890
  score: cvssResult.score,
138791
138891
  severity: cvssResult.severity,
@@ -141988,7 +142088,7 @@ async function runAuthBypassAgent(opts) {
141988
142088
  }, "auth-bypass-agent.log");
141989
142089
  logger.info(`Starting AuthBypassAgent for ${input.baseUrl}`);
141990
142090
  logger.info(`Auth endpoints: ${input.authContext.endpoints.join(", ")}`);
141991
- const { document_finding, findingPaths } = createDocumentFindingTool2(session, logger, input.baseUrl);
142091
+ const { document_finding, findingPaths } = createDocumentFindingTool2(session, logger, input.baseUrl, { authConfig });
141992
142092
  const httpRequest = tool2({
141993
142093
  description: "Make HTTP requests to test authorization",
141994
142094
  inputSchema: exports_external.object({
@@ -142369,12 +142469,13 @@ async function runMetaVulnerabilityTestAgent(opts) {
142369
142469
  smart_enumerate,
142370
142470
  cve_lookup,
142371
142471
  mutate_payload
142372
- } = createPentestTools(sessionForTools, undefined, toolOverride, undefined, abortSignal);
142472
+ } = createPentestTools(sessionForTools, undefined, toolOverride, undefined, abortSignal, undefined, authConfig);
142373
142473
  const { create_poc, pocPaths } = createPocTool(sessionInfo, logger, toolOverride);
142374
142474
  const { document_finding, findingPaths } = createDocumentFindingTool2(sessionInfo, logger, target, {
142375
142475
  enableCvssScoring: sessionConfig?.enableCvssScoring,
142376
142476
  cvssModel: sessionConfig?.cvssModel,
142377
- getMessages: () => messagesRef.current
142477
+ getMessages: () => messagesRef.current,
142478
+ authConfig
142378
142479
  });
142379
142480
  const { store_plan, get_plan, store_adaptation } = createPlanMemoryTools(sessionInfo, logger);
142380
142481
  const { optimize_prompt } = createPromptOptimizerTool(sessionInfo, logger);
@@ -142869,7 +142970,7 @@ function findEndpoint(mention, endpoints) {
142869
142970
  return;
142870
142971
  }
142871
142972
  async function extractPentestTarget(input) {
142872
- const { userMessage, discoveredEndpoints, model, onTokenUsage } = input;
142973
+ const { userMessage, discoveredEndpoints, model, onTokenUsage, authConfig } = input;
142873
142974
  const mentions = parseAtMentions(userMessage);
142874
142975
  if (mentions.length > 0) {
142875
142976
  for (const mention of mentions) {
@@ -142910,7 +143011,8 @@ Return a JSON object with:
142910
143011
  prompt,
142911
143012
  maxTokens: 500,
142912
143013
  temperature: 0.3,
142913
- onTokenUsage
143014
+ onTokenUsage,
143015
+ authConfig
142914
143016
  });
142915
143017
  return {
142916
143018
  target: result.target,
@@ -144704,12 +144806,20 @@ class OperatorAgent extends EventEmitter15 {
144704
144806
  }
144705
144807
  approve(approvalId) {
144706
144808
  const pending = this.approvalGate.getPendingApprovals().find((p) => p.id === approvalId);
144707
- this.log("action_approved", { approvalId, toolName: pending?.toolName, args: pending?.args });
144809
+ this.log("action_approved", {
144810
+ approvalId,
144811
+ toolName: pending?.toolName,
144812
+ args: pending?.args
144813
+ });
144708
144814
  this.approvalGate.approve(approvalId);
144709
144815
  }
144710
144816
  deny(approvalId) {
144711
144817
  const pending = this.approvalGate.getPendingApprovals().find((p) => p.id === approvalId);
144712
- this.log("action_denied", { approvalId, toolName: pending?.toolName, args: pending?.args });
144818
+ this.log("action_denied", {
144819
+ approvalId,
144820
+ toolName: pending?.toolName,
144821
+ args: pending?.args
144822
+ });
144713
144823
  this.approvalGate.deny(approvalId);
144714
144824
  }
144715
144825
  batchApprove(approvalIds) {
@@ -144745,7 +144855,11 @@ class OperatorAgent extends EventEmitter15 {
144745
144855
  if (this.abortController?.signal.aborted) {
144746
144856
  this.log("agent_stopped", { reason: "user_abort" });
144747
144857
  this.setStatus("idle");
144748
- return { findingsCount: 0, pocPaths: [], summary: "Agent stopped by user" };
144858
+ return {
144859
+ findingsCount: 0,
144860
+ pocPaths: [],
144861
+ summary: "Agent stopped by user"
144862
+ };
144749
144863
  }
144750
144864
  this.log("agent_error", { error: error41?.message || String(error41) });
144751
144865
  this.setStatus("failed");
@@ -144960,9 +145074,7 @@ Document significant findings using the document_finding tool.`;
144960
145074
  }
144961
145075
  async runAgentLoop(systemMessage, initialUserMessage) {
144962
145076
  const session = this.config.session;
144963
- const messages = [
144964
- { role: "system", content: systemMessage }
144965
- ];
145077
+ const messages = [{ role: "system", content: systemMessage }];
144966
145078
  if (this.isResume && this.messages.length > 0) {
144967
145079
  const recentMessages = this.messages.slice(-20);
144968
145080
  for (const msg of recentMessages) {
@@ -144972,7 +145084,7 @@ Document significant findings using the document_finding tool.`;
144972
145084
  }
144973
145085
  }
144974
145086
  messages.push({ role: "user", content: initialUserMessage });
144975
- const baseTools = createPentestTools(session, this.config.model, undefined, undefined, this.abortController?.signal, true);
145087
+ const baseTools = createPentestTools(session, this.config.model, undefined, undefined, this.abortController?.signal, true, this.config.authConfig);
144976
145088
  const evidenceDir = join14(session.rootPath, "evidence");
144977
145089
  const browserTools = createBrowserTools(session.targets[0] || "", evidenceDir, "operator", undefined, this.abortController?.signal);
144978
145090
  let pocTools = {};
@@ -145008,9 +145120,18 @@ and probe for self-registration if available.
145008
145120
 
145009
145121
  This tool requires user approval (T3 tier - Probing).`,
145010
145122
  inputSchema: RunAuthSubagentInput,
145011
- execute: async ({ target, username, password, reason }) => {
145123
+ execute: async ({
145124
+ target,
145125
+ username,
145126
+ password,
145127
+ reason
145128
+ }) => {
145012
145129
  this.emit("operator-event", { type: "auth-subagent-started", target });
145013
- this.log("auth_subagent_started", { target, reason, hasCredentials: !!(username || password) });
145130
+ this.log("auth_subagent_started", {
145131
+ target,
145132
+ reason,
145133
+ hasCredentials: !!(username || password)
145134
+ });
145014
145135
  try {
145015
145136
  const result2 = await runAuthenticationSubagent({
145016
145137
  input: {
@@ -145057,7 +145178,12 @@ This tool requires user approval (T3 tier - Probing).`,
145057
145178
  }
145058
145179
  });
145059
145180
  const authTools = { run_auth_subagent };
145060
- const allTools = { ...baseTools, ...browserTools, ...pocTools, ...authTools };
145181
+ const allTools = {
145182
+ ...baseTools,
145183
+ ...browserTools,
145184
+ ...pocTools,
145185
+ ...authTools
145186
+ };
145061
145187
  const activeToolNames = getActiveToolNames(session.config?.toolsetState);
145062
145188
  const filteredTools = {};
145063
145189
  for (const [toolName, tool6] of Object.entries(allTools)) {
@@ -145225,7 +145351,11 @@ This tool requires user approval (T3 tier - Probing).`,
145225
145351
  pocPaths,
145226
145352
  summary: `Completed ${iterations} iterations in ${this.currentStage} stage`
145227
145353
  };
145228
- this.log("agent_loop_completed", { iterations, stage: this.currentStage, result });
145354
+ this.log("agent_loop_completed", {
145355
+ iterations,
145356
+ stage: this.currentStage,
145357
+ result
145358
+ });
145229
145359
  return result;
145230
145360
  }
145231
145361
  static STREAMING_TOOLS = new Set(["execute_command"]);
@@ -145902,6 +146032,319 @@ function ToolsPanel({
145902
146032
  }, undefined, false, undefined, this);
145903
146033
  }
145904
146034
 
146035
+ // src/core/session/loader.ts
146036
+ import { join as join15 } from "path";
146037
+ import { existsSync as existsSync20, readdirSync as readdirSync5, readFileSync as readFileSync11 } from "fs";
146038
+ function convertMessagesToUI(messages, baseTime) {
146039
+ const uiMessages = [];
146040
+ let messageIndex = 0;
146041
+ const toolResults = new Map;
146042
+ for (const msg of messages) {
146043
+ if (Array.isArray(msg.content)) {
146044
+ for (const part of msg.content) {
146045
+ if (part.type === "tool-result" && part.toolCallId) {
146046
+ toolResults.set(part.toolCallId, part.output);
146047
+ }
146048
+ }
146049
+ }
146050
+ }
146051
+ for (const msg of messages) {
146052
+ const createdAt = new Date(baseTime.getTime() + messageIndex * 1000);
146053
+ messageIndex++;
146054
+ if (typeof msg.content === "string") {
146055
+ uiMessages.push({
146056
+ role: msg.role,
146057
+ content: msg.content,
146058
+ createdAt
146059
+ });
146060
+ } else if (Array.isArray(msg.content)) {
146061
+ for (const part of msg.content) {
146062
+ if (part.type === "text" && part.text) {
146063
+ uiMessages.push({
146064
+ role: "assistant",
146065
+ content: part.text,
146066
+ createdAt
146067
+ });
146068
+ } else if (part.type === "tool-call") {
146069
+ const toolDescription = typeof part.input?.toolCallDescription === "string" ? part.input.toolCallDescription : part.toolName || "tool";
146070
+ const result = part.toolCallId ? toolResults.get(part.toolCallId) : undefined;
146071
+ uiMessages.push({
146072
+ role: "tool",
146073
+ content: toolDescription,
146074
+ createdAt,
146075
+ toolCallId: part.toolCallId,
146076
+ toolName: part.toolName,
146077
+ args: part.input,
146078
+ result,
146079
+ status: "completed"
146080
+ });
146081
+ }
146082
+ }
146083
+ }
146084
+ }
146085
+ return uiMessages;
146086
+ }
146087
+ function parseSubagentFilename(filename) {
146088
+ if (filename.startsWith("attack-surface-agent")) {
146089
+ return { agentType: "attack-surface", name: "Attack Surface Discovery" };
146090
+ }
146091
+ if (filename.startsWith("vuln-test-")) {
146092
+ const parts = filename.replace("vuln-test-", "").split("-");
146093
+ const vulnClass = parts[0] || "generic";
146094
+ const vulnClassFormatted = vulnClass.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
146095
+ return {
146096
+ agentType: "pentest",
146097
+ name: `${vulnClassFormatted} Test`
146098
+ };
146099
+ }
146100
+ if (filename.startsWith("orchestrator-")) {
146101
+ return { agentType: "pentest", name: "Orchestrator Summary" };
146102
+ }
146103
+ return { agentType: "pentest", name: filename.split("-")[0] || "Unknown" };
146104
+ }
146105
+ function loadSubagents(rootPath) {
146106
+ const subagentsPath = join15(rootPath, "subagents");
146107
+ if (!existsSync20(subagentsPath)) {
146108
+ return [];
146109
+ }
146110
+ const subagents = [];
146111
+ const files = readdirSync5(subagentsPath).filter((f) => f.endsWith(".json"));
146112
+ files.sort((a, b2) => {
146113
+ const timeA = a.match(/\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}/)?.[0] || "";
146114
+ const timeB = b2.match(/\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}/)?.[0] || "";
146115
+ return timeA.localeCompare(timeB);
146116
+ });
146117
+ for (const file2 of files) {
146118
+ try {
146119
+ const filePath = join15(subagentsPath, file2);
146120
+ const data = JSON.parse(readFileSync11(filePath, "utf-8"));
146121
+ const { agentType, name: name39 } = parseSubagentFilename(file2);
146122
+ const timestamp = new Date(data.timestamp);
146123
+ if (file2.startsWith("orchestrator-")) {
146124
+ continue;
146125
+ }
146126
+ const messages = convertMessagesToUI(data.messages, timestamp);
146127
+ let status = "completed";
146128
+ switch (data.status) {
146129
+ case "canceled":
146130
+ case "failed":
146131
+ case "completed":
146132
+ case "pending":
146133
+ status = data.status;
146134
+ break;
146135
+ default:
146136
+ if (typeof data.findingsCount === "number" && data.findingsCount < 0) {
146137
+ status = "failed";
146138
+ }
146139
+ break;
146140
+ }
146141
+ subagents.push({
146142
+ id: `loaded-${file2.replace(".json", "")}`,
146143
+ name: data.agentName === "attack-surface-agent" ? "Attack Surface Discovery" : name39,
146144
+ type: agentType,
146145
+ target: data.target || "Unknown",
146146
+ messages,
146147
+ createdAt: timestamp,
146148
+ status
146149
+ });
146150
+ } catch (e) {
146151
+ console.error(`Failed to load subagent file ${file2}:`, e);
146152
+ }
146153
+ }
146154
+ return subagents;
146155
+ }
146156
+ function loadAttackSurfaceResults2(rootPath) {
146157
+ const resultsPath = join15(rootPath, "attack-surface-results.json");
146158
+ if (!existsSync20(resultsPath)) {
146159
+ return null;
146160
+ }
146161
+ try {
146162
+ return JSON.parse(readFileSync11(resultsPath, "utf-8"));
146163
+ } catch (e) {
146164
+ console.error("Failed to load attack surface results:", e);
146165
+ return null;
146166
+ }
146167
+ }
146168
+ function hasReport(rootPath) {
146169
+ const reportPath = join15(rootPath, "comprehensive-pentest-report.md");
146170
+ return existsSync20(reportPath);
146171
+ }
146172
+ function createDiscoveryFromLogs(rootPath, session) {
146173
+ const logPath = join15(rootPath, "logs", "streamlined-pentest.log");
146174
+ if (!existsSync20(logPath)) {
146175
+ return null;
146176
+ }
146177
+ try {
146178
+ const logContent = readFileSync11(logPath, "utf-8");
146179
+ const lines = logContent.split(`
146180
+ `).filter(Boolean);
146181
+ const messages = [];
146182
+ let stepBuffer = "";
146183
+ for (const line of lines) {
146184
+ const match = line.match(/^(\d{4}-\d{2}-\d{2}T[\d:.]+Z) - \[(\w+)\] (.+)$/);
146185
+ if (!match)
146186
+ continue;
146187
+ const [, timestamp, level, content] = match;
146188
+ const createdAt = new Date(timestamp);
146189
+ if (content.startsWith("[Tool]")) {
146190
+ const toolMatch = content.match(/\[Tool\] (\w+): (.+)/);
146191
+ if (toolMatch) {
146192
+ messages.push({
146193
+ role: "tool",
146194
+ content: `✓ ${toolMatch[2]}`,
146195
+ createdAt,
146196
+ toolName: toolMatch[1],
146197
+ status: "completed"
146198
+ });
146199
+ }
146200
+ } else if (content.startsWith("[Step")) {
146201
+ const stepMatch = content.match(/\[Step \d+\] (.+)/);
146202
+ if (stepMatch) {
146203
+ messages.push({
146204
+ role: "assistant",
146205
+ content: stepMatch[1],
146206
+ createdAt
146207
+ });
146208
+ }
146209
+ }
146210
+ }
146211
+ if (messages.length === 0) {
146212
+ return null;
146213
+ }
146214
+ return {
146215
+ id: "discovery-from-logs",
146216
+ name: "Attack Surface Discovery",
146217
+ type: "attack-surface",
146218
+ target: session.targets[0] || "Unknown",
146219
+ messages,
146220
+ createdAt: new Date(session.time.created),
146221
+ status: "completed"
146222
+ };
146223
+ } catch (e) {
146224
+ console.error("Failed to parse logs:", e);
146225
+ return null;
146226
+ }
146227
+ }
146228
+ async function loadSessionState(session) {
146229
+ const rootPath = session.rootPath;
146230
+ let subagents = loadSubagents(rootPath);
146231
+ const hasAttackSurfaceAgent = subagents.some((s) => s.type === "attack-surface");
146232
+ if (!hasAttackSurfaceAgent) {
146233
+ const discoveryAgent = createDiscoveryFromLogs(rootPath, session);
146234
+ if (discoveryAgent) {
146235
+ subagents = [discoveryAgent, ...subagents];
146236
+ }
146237
+ }
146238
+ const manifestPath = join15(rootPath, "agent-manifest.json");
146239
+ if (existsSync20(manifestPath)) {
146240
+ try {
146241
+ const manifest = JSON.parse(readFileSync11(manifestPath, "utf-8"));
146242
+ for (const entry of manifest) {
146243
+ if (entry.status !== "running")
146244
+ continue;
146245
+ const resumeInfo = {
146246
+ target: entry.target,
146247
+ objective: entry.objective,
146248
+ vulnerabilityClass: entry.vulnerabilityClass,
146249
+ authenticationInfo: entry.authInfo
146250
+ };
146251
+ const vulnSlug = entry.vulnerabilityClass.toLowerCase().replace(/\s+/g, "-");
146252
+ const existingIndex = subagents.findIndex((s) => s.type === "pentest" && s.id.includes(`-${vulnSlug}-`) && s.target === entry.target);
146253
+ if (existingIndex >= 0) {
146254
+ subagents[existingIndex] = {
146255
+ ...subagents[existingIndex],
146256
+ status: "paused",
146257
+ resumeInfo
146258
+ };
146259
+ } else {
146260
+ let messages = [];
146261
+ const subagentsPath = join15(rootPath, "subagents");
146262
+ if (existsSync20(subagentsPath)) {
146263
+ try {
146264
+ const files = readdirSync5(subagentsPath).filter((f) => f.endsWith(".json"));
146265
+ const matchingFile = files.find((f) => {
146266
+ if (vulnSlug && f.includes(vulnSlug))
146267
+ return true;
146268
+ return false;
146269
+ });
146270
+ if (matchingFile) {
146271
+ const data = JSON.parse(readFileSync11(join15(subagentsPath, matchingFile), "utf-8"));
146272
+ messages = convertMessagesToUI(data.messages, new Date(entry.spawnedAt));
146273
+ }
146274
+ } catch {}
146275
+ }
146276
+ subagents.push({
146277
+ id: entry.id,
146278
+ name: entry.name,
146279
+ type: "pentest",
146280
+ target: entry.target,
146281
+ messages,
146282
+ createdAt: new Date(entry.spawnedAt),
146283
+ status: "paused",
146284
+ resumeInfo
146285
+ });
146286
+ }
146287
+ }
146288
+ } catch (e) {
146289
+ console.error("Failed to load agent manifest:", e);
146290
+ }
146291
+ }
146292
+ const attackSurfaceResults = loadAttackSurfaceResults2(rootPath);
146293
+ const hasReportFile = hasReport(rootPath);
146294
+ const hasDiscoverySubagent = subagents.some((s) => s.type === "attack-surface");
146295
+ const interruptedDuringDiscovery = !attackSurfaceResults && !hasReportFile && hasDiscoverySubagent;
146296
+ if (interruptedDuringDiscovery) {
146297
+ for (let i = 0;i < subagents.length; i++) {
146298
+ if (subagents[i].type === "attack-surface" && subagents[i].status === "completed") {
146299
+ subagents[i] = { ...subagents[i], status: "paused" };
146300
+ }
146301
+ }
146302
+ }
146303
+ const isComplete = hasReportFile || attackSurfaceResults?.summary?.analysisComplete === true && subagents.length > 1;
146304
+ return {
146305
+ session,
146306
+ subagents,
146307
+ attackSurfaceResults,
146308
+ isComplete,
146309
+ hasReport: hasReportFile,
146310
+ interruptedDuringDiscovery
146311
+ };
146312
+ }
146313
+
146314
+ // src/tui/session/swarm-to-operator-adapter.ts
146315
+ function adaptSwarmStateForOperator(state) {
146316
+ const messages = [];
146317
+ messages.push({
146318
+ role: "system",
146319
+ content: `Resuming from auto-mode session. ${state.subagents.length} subagent(s) ran. ${state.hasReport ? "Report available." : ""}`,
146320
+ createdAt: new Date
146321
+ });
146322
+ for (const sub of state.subagents) {
146323
+ const assistantMsgs = sub.messages.filter((m2) => m2.role === "assistant" && typeof m2.content === "string" && m2.content.trim());
146324
+ const lastSummary = assistantMsgs[assistantMsgs.length - 1];
146325
+ if (lastSummary) {
146326
+ messages.push({
146327
+ role: "assistant",
146328
+ content: `[${sub.name}] ${lastSummary.content}`,
146329
+ createdAt: lastSummary.createdAt
146330
+ });
146331
+ }
146332
+ }
146333
+ const attackSurface = [];
146334
+ if (state.attackSurfaceResults?.targets) {
146335
+ for (const target of state.attackSurfaceResults.targets) {
146336
+ attackSurface.push({
146337
+ id: `synth-${attackSurface.length}`,
146338
+ method: "GET",
146339
+ path: target.target,
146340
+ status: "discovered",
146341
+ category: target.objective || "unknown"
146342
+ });
146343
+ }
146344
+ }
146345
+ return { messages, attackSurface };
146346
+ }
146347
+
145905
146348
  // src/tui/components/chat/header.tsx
145906
146349
  function Header({
145907
146350
  mode,
@@ -147220,6 +147663,7 @@ function SessionComponent({
147220
147663
  mode,
147221
147664
  model: propModel,
147222
147665
  isResume = false,
147666
+ openAsOperator = false,
147223
147667
  initialDirective,
147224
147668
  onExit
147225
147669
  }) {
@@ -147301,7 +147745,7 @@ function SessionComponent({
147301
147745
  import_react46.useEffect(() => {
147302
147746
  if (!isResume || resumeLoaded)
147303
147747
  return;
147304
- Session.loadOperatorState(session.id).then((savedState) => {
147748
+ Session.loadOperatorState(session.id).then(async (savedState) => {
147305
147749
  if (savedState) {
147306
147750
  setOperatorMode(savedState.mode);
147307
147751
  setAutoApproveTier(savedState.autoApproveTier);
@@ -147322,10 +147766,15 @@ function SessionComponent({
147322
147766
  const history = savedState.actionHistory || [];
147323
147767
  setApprovedCount(history.filter((a) => a.decision === "approved" || a.decision === "auto-approved").length);
147324
147768
  setDeniedCount(history.filter((a) => a.decision === "denied").length);
147769
+ } else if (openAsOperator) {
147770
+ const swarmState = await loadSessionState(session);
147771
+ const { messages: synthMessages, attackSurface } = adaptSwarmStateForOperator(swarmState);
147772
+ setMessages(synthMessages);
147773
+ sidebar.updateState({ attackSurface });
147325
147774
  }
147326
147775
  setResumeLoaded(true);
147327
147776
  });
147328
- }, [isResume, session.id, resumeLoaded, setMessages, sidebar]);
147777
+ }, [isResume, session.id, resumeLoaded, setMessages, sidebar, openAsOperator]);
147329
147778
  import_react46.useEffect(() => {
147330
147779
  if (agent2)
147331
147780
  return;
@@ -147800,228 +148249,14 @@ Usage: /tier <1-5>`,
147800
148249
  }
147801
148250
 
147802
148251
  // src/tui/components/operator-dashboard/index.tsx
147803
- function OperatorDashboard({ session, isResume = false }) {
148252
+ function OperatorDashboard({ session, isResume = false, openAsOperator }) {
147804
148253
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SessionComponent, {
147805
148254
  session,
147806
148255
  mode: "operator",
147807
- isResume
148256
+ isResume,
148257
+ openAsOperator
147808
148258
  }, undefined, false, undefined, this);
147809
148259
  }
147810
-
147811
- // src/core/session/loader.ts
147812
- import { join as join15 } from "path";
147813
- import { existsSync as existsSync20, readdirSync as readdirSync5, readFileSync as readFileSync11 } from "fs";
147814
- function convertMessagesToUI(messages, baseTime) {
147815
- const uiMessages = [];
147816
- let messageIndex = 0;
147817
- const toolResults = new Map;
147818
- for (const msg of messages) {
147819
- if (Array.isArray(msg.content)) {
147820
- for (const part of msg.content) {
147821
- if (part.type === "tool-result" && part.toolCallId) {
147822
- toolResults.set(part.toolCallId, part.output);
147823
- }
147824
- }
147825
- }
147826
- }
147827
- for (const msg of messages) {
147828
- const createdAt = new Date(baseTime.getTime() + messageIndex * 1000);
147829
- messageIndex++;
147830
- if (typeof msg.content === "string") {
147831
- uiMessages.push({
147832
- role: msg.role,
147833
- content: msg.content,
147834
- createdAt
147835
- });
147836
- } else if (Array.isArray(msg.content)) {
147837
- for (const part of msg.content) {
147838
- if (part.type === "text" && part.text) {
147839
- uiMessages.push({
147840
- role: "assistant",
147841
- content: part.text,
147842
- createdAt
147843
- });
147844
- } else if (part.type === "tool-call") {
147845
- const toolDescription = typeof part.input?.toolCallDescription === "string" ? part.input.toolCallDescription : part.toolName || "tool";
147846
- const result = part.toolCallId ? toolResults.get(part.toolCallId) : undefined;
147847
- uiMessages.push({
147848
- role: "tool",
147849
- content: `✓ ${toolDescription}`,
147850
- createdAt,
147851
- toolCallId: part.toolCallId,
147852
- toolName: part.toolName,
147853
- args: part.input,
147854
- result,
147855
- status: "completed"
147856
- });
147857
- }
147858
- }
147859
- }
147860
- }
147861
- return uiMessages;
147862
- }
147863
- function parseSubagentFilename(filename) {
147864
- if (filename.startsWith("attack-surface-agent")) {
147865
- return { agentType: "attack-surface", name: "Attack Surface Discovery" };
147866
- }
147867
- if (filename.startsWith("vuln-test-")) {
147868
- const parts = filename.replace("vuln-test-", "").split("-");
147869
- const vulnClass = parts[0] || "generic";
147870
- const vulnClassFormatted = vulnClass.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
147871
- return {
147872
- agentType: "pentest",
147873
- name: `${vulnClassFormatted} Test`
147874
- };
147875
- }
147876
- if (filename.startsWith("orchestrator-")) {
147877
- return { agentType: "pentest", name: "Orchestrator Summary" };
147878
- }
147879
- return { agentType: "pentest", name: filename.split("-")[0] || "Unknown" };
147880
- }
147881
- function loadSubagents(rootPath) {
147882
- const subagentsPath = join15(rootPath, "subagents");
147883
- if (!existsSync20(subagentsPath)) {
147884
- return [];
147885
- }
147886
- const subagents = [];
147887
- const files = readdirSync5(subagentsPath).filter((f) => f.endsWith(".json"));
147888
- files.sort((a, b2) => {
147889
- const timeA = a.match(/\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}/)?.[0] || "";
147890
- const timeB = b2.match(/\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}/)?.[0] || "";
147891
- return timeA.localeCompare(timeB);
147892
- });
147893
- for (const file2 of files) {
147894
- try {
147895
- const filePath = join15(subagentsPath, file2);
147896
- const data = JSON.parse(readFileSync11(filePath, "utf-8"));
147897
- const { agentType, name: name39 } = parseSubagentFilename(file2);
147898
- const timestamp = new Date(data.timestamp);
147899
- if (file2.startsWith("orchestrator-")) {
147900
- continue;
147901
- }
147902
- const messages = convertMessagesToUI(data.messages, timestamp);
147903
- let status = "completed";
147904
- switch (data.status) {
147905
- case "canceled":
147906
- case "failed":
147907
- case "completed":
147908
- case "pending":
147909
- status = data.status;
147910
- break;
147911
- default:
147912
- if (typeof data.findingsCount === "number" && data.findingsCount < 0) {
147913
- status = "failed";
147914
- }
147915
- break;
147916
- }
147917
- subagents.push({
147918
- id: `loaded-${file2.replace(".json", "")}`,
147919
- name: data.agentName === "attack-surface-agent" ? "Attack Surface Discovery" : name39,
147920
- type: agentType,
147921
- target: data.target || "Unknown",
147922
- messages,
147923
- createdAt: timestamp,
147924
- status
147925
- });
147926
- } catch (e) {
147927
- console.error(`Failed to load subagent file ${file2}:`, e);
147928
- }
147929
- }
147930
- return subagents;
147931
- }
147932
- function loadAttackSurfaceResults2(rootPath) {
147933
- const resultsPath = join15(rootPath, "attack-surface-results.json");
147934
- if (!existsSync20(resultsPath)) {
147935
- return null;
147936
- }
147937
- try {
147938
- return JSON.parse(readFileSync11(resultsPath, "utf-8"));
147939
- } catch (e) {
147940
- console.error("Failed to load attack surface results:", e);
147941
- return null;
147942
- }
147943
- }
147944
- function hasReport(rootPath) {
147945
- const reportPath = join15(rootPath, "comprehensive-pentest-report.md");
147946
- return existsSync20(reportPath);
147947
- }
147948
- function createDiscoveryFromLogs(rootPath, session) {
147949
- const logPath = join15(rootPath, "logs", "streamlined-pentest.log");
147950
- if (!existsSync20(logPath)) {
147951
- return null;
147952
- }
147953
- try {
147954
- const logContent = readFileSync11(logPath, "utf-8");
147955
- const lines = logContent.split(`
147956
- `).filter(Boolean);
147957
- const messages = [];
147958
- let stepBuffer = "";
147959
- for (const line of lines) {
147960
- const match = line.match(/^(\d{4}-\d{2}-\d{2}T[\d:.]+Z) - \[(\w+)\] (.+)$/);
147961
- if (!match)
147962
- continue;
147963
- const [, timestamp, level, content] = match;
147964
- const createdAt = new Date(timestamp);
147965
- if (content.startsWith("[Tool]")) {
147966
- const toolMatch = content.match(/\[Tool\] (\w+): (.+)/);
147967
- if (toolMatch) {
147968
- messages.push({
147969
- role: "tool",
147970
- content: `✓ ${toolMatch[2]}`,
147971
- createdAt,
147972
- toolName: toolMatch[1],
147973
- status: "completed"
147974
- });
147975
- }
147976
- } else if (content.startsWith("[Step")) {
147977
- const stepMatch = content.match(/\[Step \d+\] (.+)/);
147978
- if (stepMatch) {
147979
- messages.push({
147980
- role: "assistant",
147981
- content: stepMatch[1],
147982
- createdAt
147983
- });
147984
- }
147985
- }
147986
- }
147987
- if (messages.length === 0) {
147988
- return null;
147989
- }
147990
- return {
147991
- id: "discovery-from-logs",
147992
- name: "Attack Surface Discovery",
147993
- type: "attack-surface",
147994
- target: session.targets[0] || "Unknown",
147995
- messages,
147996
- createdAt: new Date(session.time.created),
147997
- status: "completed"
147998
- };
147999
- } catch (e) {
148000
- console.error("Failed to parse logs:", e);
148001
- return null;
148002
- }
148003
- }
148004
- async function loadSessionState(session) {
148005
- const rootPath = session.rootPath;
148006
- let subagents = loadSubagents(rootPath);
148007
- const hasAttackSurfaceAgent = subagents.some((s) => s.type === "attack-surface");
148008
- if (!hasAttackSurfaceAgent) {
148009
- const discoveryAgent = createDiscoveryFromLogs(rootPath, session);
148010
- if (discoveryAgent) {
148011
- subagents = [discoveryAgent, ...subagents];
148012
- }
148013
- }
148014
- const attackSurfaceResults = loadAttackSurfaceResults2(rootPath);
148015
- const hasReportFile = hasReport(rootPath);
148016
- const isComplete = hasReportFile || attackSurfaceResults?.summary?.analysisComplete === true && subagents.length > 1;
148017
- return {
148018
- session,
148019
- subagents,
148020
- attackSurfaceResults,
148021
- isComplete,
148022
- hasReport: hasReportFile
148023
- };
148024
- }
148025
148260
  // src/core/agent/metaTestingAgent/prompts/execution.ts
148026
148261
  var OUTCOME_GUIDANCE_TEMPLATE2 = `{{OUTCOME_GUIDANCE}}`;
148027
148262
  var META_TESTING_SYSTEM_PROMPT = `# Meta Testing Agent
@@ -148473,7 +148708,9 @@ async function runPentestOrchestrator(input) {
148473
148708
  id: agentId,
148474
148709
  name: `${getVulnerabilityClassName(task.vulnClass)} on ${task.target}`,
148475
148710
  target: task.target,
148476
- vulnerabilityClass: task.vulnClass
148711
+ vulnerabilityClass: task.vulnClass,
148712
+ objective: task.objective,
148713
+ authenticationInfo: task.authenticationInfo
148477
148714
  });
148478
148715
  try {
148479
148716
  const result = await runMetaVulnerabilityTestAgent({
@@ -149154,7 +149391,8 @@ async function runStreamlinedPentest(input) {
149154
149391
  onPentestAgentComplete,
149155
149392
  onAgentAbortControllerCreated,
149156
149393
  abortSignal,
149157
- toolOverride
149394
+ toolOverride,
149395
+ previousDiscoveryResults
149158
149396
  } = input;
149159
149397
  const session = input.session || await Session.create({
149160
149398
  targets: [target],
@@ -149162,36 +149400,62 @@ async function runStreamlinedPentest(input) {
149162
149400
  ...sessionConfig
149163
149401
  });
149164
149402
  const logger = new Logger(session, "streamlined-pentest.log");
149403
+ const manifestPath = join18(session.rootPath, "agent-manifest.json");
149404
+ const manifest = (() => {
149405
+ if (!existsSync23(manifestPath))
149406
+ return [];
149407
+ try {
149408
+ return JSON.parse(readFileSync13(manifestPath, "utf-8"));
149409
+ } catch (e) {
149410
+ logger.warn(`Failed to read agent manifest at ${manifestPath}: ${e}`);
149411
+ return [];
149412
+ }
149413
+ })();
149414
+ function flushManifest() {
149415
+ writeFileSync15(manifestPath, JSON.stringify(manifest, null, 2));
149416
+ }
149165
149417
  logger.info(`Starting streamlined pentest for ${target}`);
149166
149418
  const reportProgress = (status) => {
149167
149419
  logger.info(`[${status.phase}] ${status.message}`);
149168
149420
  onProgress?.(status);
149169
149421
  };
149170
149422
  try {
149171
- reportProgress({
149172
- phase: "discovery",
149173
- message: `Discovering attack surface for ${target}`
149174
- });
149175
- const { targets, discoveryError } = await runDiscoveryPhase({
149176
- target,
149177
- model,
149178
- session,
149179
- authConfig,
149180
- abortSignal,
149181
- toolOverride,
149182
- logger,
149183
- onProgress: reportProgress,
149184
- onStepFinish: onDiscoveryStepFinish,
149185
- onStream: onDiscoveryStream
149186
- });
149187
- if (discoveryError) {
149188
- return {
149189
- success: false,
149423
+ let targets;
149424
+ if (previousDiscoveryResults) {
149425
+ logger.info(`Resuming with ${previousDiscoveryResults.targets?.length || 0} previously discovered targets`);
149426
+ targets = previousDiscoveryResults.targets || [];
149427
+ reportProgress({
149428
+ phase: "discovery",
149429
+ message: `Resuming with ${targets.length} previously discovered targets`,
149430
+ targetsDiscovered: targets.length
149431
+ });
149432
+ } else {
149433
+ reportProgress({
149434
+ phase: "discovery",
149435
+ message: `Discovering attack surface for ${target}`
149436
+ });
149437
+ const discoveryResult = await runDiscoveryPhase({
149438
+ target,
149439
+ model,
149190
149440
  session,
149191
- targets: [],
149192
- totalFindings: 0,
149193
- error: discoveryError
149194
- };
149441
+ authConfig,
149442
+ abortSignal,
149443
+ toolOverride,
149444
+ logger,
149445
+ onProgress: reportProgress,
149446
+ onStepFinish: onDiscoveryStepFinish,
149447
+ onStream: onDiscoveryStream
149448
+ });
149449
+ if (discoveryResult.discoveryError) {
149450
+ return {
149451
+ success: false,
149452
+ session,
149453
+ targets: [],
149454
+ totalFindings: 0,
149455
+ error: discoveryResult.discoveryError
149456
+ };
149457
+ }
149458
+ targets = discoveryResult.targets;
149195
149459
  }
149196
149460
  if (targets.length === 0) {
149197
149461
  reportProgress({
@@ -149236,7 +149500,20 @@ async function runStreamlinedPentest(input) {
149236
149500
  findingsCount: status.findingsCount
149237
149501
  });
149238
149502
  },
149239
- onAgentSpawn: onPentestAgentSpawn,
149503
+ onAgentSpawn: (info) => {
149504
+ manifest.push({
149505
+ id: info.id,
149506
+ name: info.name,
149507
+ target: info.target,
149508
+ vulnerabilityClass: info.vulnerabilityClass,
149509
+ objective: info.objective,
149510
+ authInfo: info.authenticationInfo,
149511
+ status: "running",
149512
+ spawnedAt: new Date().toISOString()
149513
+ });
149514
+ flushManifest();
149515
+ onPentestAgentSpawn?.(info);
149516
+ },
149240
149517
  onAgentStream: onPentestAgentStream,
149241
149518
  onAgentComplete: onPentestAgentComplete,
149242
149519
  onAgentAbortControllerCreated
@@ -149462,14 +149739,16 @@ async function runDiscoveryPhase(params) {
149462
149739
  }
149463
149740
 
149464
149741
  // src/tui/components/session-view/index.tsx
149465
- import { existsSync as existsSync24 } from "fs";
149742
+ import { existsSync as existsSync24, readFileSync as readFileSync14 } from "fs";
149466
149743
  import { exec as exec3 } from "child_process";
149744
+ import { join as join19 } from "path";
149467
149745
  var greenBullet6 = RGBA.fromInts(76, 175, 80, 255);
149468
149746
  var creamText6 = RGBA.fromInts(255, 248, 220, 255);
149469
149747
  var dimText7 = RGBA.fromInts(120, 120, 120, 255);
149470
149748
  function SessionView({
149471
149749
  sessionId,
149472
- isResume = false
149750
+ isResume = false,
149751
+ openAsOperator = false
149473
149752
  }) {
149474
149753
  const route = useRoute();
149475
149754
  const { model, setThinking, isExecuting, addTokenUsage, setIsExecuting } = useAgent();
@@ -149482,6 +149761,8 @@ function SessionView({
149482
149761
  const [startTime, setStartTime] = import_react48.useState(null);
149483
149762
  const [hasStarted, setHasStarted] = import_react48.useState(false);
149484
149763
  const agentAbortControllers = import_react48.useRef(new Map);
149764
+ const subagentsRef = import_react48.useRef(subagents);
149765
+ subagentsRef.current = subagents;
149485
149766
  const killAgent = import_react48.useCallback((agentId) => {
149486
149767
  const controller = agentAbortControllers.current.get(agentId);
149487
149768
  if (controller) {
@@ -149524,12 +149805,19 @@ function SessionView({
149524
149805
  target: s.target,
149525
149806
  messages: s.messages,
149526
149807
  createdAt: s.createdAt,
149527
- status: s.status
149808
+ status: s.status,
149809
+ resumeInfo: s.resumeInfo
149528
149810
  }));
149529
149811
  setSubagents(loadedSubagents);
149530
- setIsCompleted(state.hasReport);
149531
149812
  setStartTime(new Date(loadedSession.time.created));
149532
- setHasStarted(true);
149813
+ if (state.hasReport) {
149814
+ setIsCompleted(true);
149815
+ setHasStarted(true);
149816
+ } else if (state.attackSurfaceResults) {
149817
+ setHasStarted(true);
149818
+ } else if (state.interruptedDuringDiscovery) {
149819
+ setHasStarted(true);
149820
+ }
149533
149821
  } catch (e) {
149534
149822
  console.error("Failed to load session state:", e);
149535
149823
  }
@@ -149543,15 +149831,14 @@ function SessionView({
149543
149831
  loadSession();
149544
149832
  }, [sessionId, isResume]);
149545
149833
  import_react48.useEffect(() => {
149546
- if (session && !hasStarted && !loading && !isResume) {
149834
+ if (session && !hasStarted && !loading) {
149547
149835
  const mode = session.config?.mode;
149548
- if (mode === "operator" || mode === "driver") {
149836
+ if (mode === "operator" || mode === "driver" || openAsOperator)
149549
149837
  return;
149550
- }
149551
149838
  setHasStarted(true);
149552
149839
  startPentest(session);
149553
149840
  }
149554
- }, [session, hasStarted, loading, isResume]);
149841
+ }, [session, hasStarted, loading, openAsOperator]);
149555
149842
  import_react48.useEffect(() => {
149556
149843
  return () => {
149557
149844
  if (abortController) {
@@ -149559,7 +149846,7 @@ function SessionView({
149559
149846
  }
149560
149847
  };
149561
149848
  }, [abortController]);
149562
- const startPentest = import_react48.useCallback(async (execSession) => {
149849
+ const startPentest = import_react48.useCallback(async (execSession, previousDiscoveryResults) => {
149563
149850
  setIsExecuting(true);
149564
149851
  setThinking(true);
149565
149852
  setStartTime(new Date);
@@ -149568,23 +149855,36 @@ function SessionView({
149568
149855
  let currentDiscoveryText = "";
149569
149856
  const pentestAgentTexts = new Map;
149570
149857
  try {
149571
- setSubagents([
149572
- {
149573
- id: "attack-surface-discovery",
149574
- name: "Attack Surface Discovery",
149575
- type: "attack-surface",
149576
- target: execSession.targets[0],
149577
- messages: [],
149578
- status: "pending",
149579
- createdAt: new Date
149858
+ setSubagents((prev) => {
149859
+ const existingIdx = prev.findIndex((s) => s.id === "attack-surface-discovery");
149860
+ if (existingIdx !== -1) {
149861
+ const updated = [...prev];
149862
+ updated[existingIdx] = {
149863
+ ...updated[existingIdx],
149864
+ status: previousDiscoveryResults ? "completed" : "pending"
149865
+ };
149866
+ return updated;
149580
149867
  }
149581
- ]);
149868
+ return [
149869
+ ...prev,
149870
+ {
149871
+ id: "attack-surface-discovery",
149872
+ name: "Attack Surface Discovery",
149873
+ type: "attack-surface",
149874
+ target: execSession.targets[0],
149875
+ messages: [],
149876
+ status: "pending",
149877
+ createdAt: new Date
149878
+ }
149879
+ ];
149880
+ });
149582
149881
  const result = await runStreamlinedPentest({
149583
149882
  target: execSession.targets[0],
149584
149883
  model: model.id,
149585
149884
  session: execSession,
149586
149885
  sessionConfig: execSession.config,
149587
149886
  abortSignal: controller.signal,
149887
+ previousDiscoveryResults,
149588
149888
  onAgentAbortControllerCreated: (agentId, abortCtrl) => {
149589
149889
  agentAbortControllers.current.set(agentId, abortCtrl);
149590
149890
  },
@@ -149645,7 +149945,7 @@ function SessionView({
149645
149945
  newMessages[msgIdx] = {
149646
149946
  ...existingMsg,
149647
149947
  status: "completed",
149648
- content: `+ ${description}`,
149948
+ content: description,
149649
149949
  result: tr.output
149650
149950
  };
149651
149951
  } else {
@@ -149749,7 +150049,7 @@ function SessionView({
149749
150049
  newMessages[msgIdx] = {
149750
150050
  ...existingMsg,
149751
150051
  status: "completed",
149752
- content: `+ ${description}`,
150052
+ content: description,
149753
150053
  result: result2
149754
150054
  };
149755
150055
  } else {
@@ -149852,11 +150152,200 @@ function SessionView({
149852
150152
  updated[idx] = { ...subagent, messages: newMessages };
149853
150153
  return updated;
149854
150154
  });
149855
- } else if (event.type === "tool-result") {
149856
- const tr = event.data;
150155
+ } else if (event.type === "tool-result") {
150156
+ const tr = event.data;
150157
+ const toolCallId = tr.toolCallId;
150158
+ const toolName = tr.toolName || "tool";
150159
+ const result2 = tr.output ?? tr.result;
150160
+ setSubagents((prev) => {
150161
+ const idx = prev.findIndex((s) => s.id === agentId);
150162
+ if (idx === -1)
150163
+ return prev;
150164
+ const updated = [...prev];
150165
+ const subagent = updated[idx];
150166
+ const newMessages = [...subagent.messages];
150167
+ const msgIdx = newMessages.findIndex((m2) => m2.role === "tool" && m2.toolCallId === toolCallId);
150168
+ if (msgIdx !== -1) {
150169
+ const existingMsg = newMessages[msgIdx];
150170
+ const description = typeof existingMsg.content === "string" && existingMsg.content !== existingMsg.toolName ? existingMsg.content : existingMsg.toolName || "tool";
150171
+ newMessages[msgIdx] = {
150172
+ ...existingMsg,
150173
+ status: "completed",
150174
+ content: description,
150175
+ result: result2
150176
+ };
150177
+ } else {
150178
+ newMessages.push({
150179
+ role: "tool",
150180
+ status: "completed",
150181
+ toolCallId,
150182
+ toolName,
150183
+ content: `+ ${toolName}`,
150184
+ result: result2,
150185
+ createdAt: new Date
150186
+ });
150187
+ }
150188
+ updated[idx] = { ...subagent, messages: newMessages };
150189
+ return updated;
150190
+ });
150191
+ } else if (event.type === "step-finish" && event.data) {
150192
+ const { usage } = event.data;
150193
+ if (usage) {
150194
+ const stepTokens = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
150195
+ if (stepTokens > 0)
150196
+ addTokenUsage(usage.inputTokens ?? 0, usage.outputTokens ?? 0);
150197
+ }
150198
+ pentestAgentTexts.set(agentId, "");
150199
+ }
150200
+ },
150201
+ onPentestAgentComplete: (agentId, agentResult) => {
150202
+ setSubagents((prev) => prev.map((sub) => sub.id === agentId && sub.status !== "canceled" ? {
150203
+ ...sub,
150204
+ status: agentResult.error ? "failed" : "completed",
150205
+ messages: [
150206
+ ...sub.messages,
150207
+ {
150208
+ role: "assistant",
150209
+ content: `${agentResult.findingsCount > 0 ? "✅" : "⚪"} ${agentResult.summary}`,
150210
+ createdAt: new Date
150211
+ }
150212
+ ]
150213
+ } : sub));
150214
+ },
150215
+ onProgress: (status) => {}
150216
+ });
150217
+ if (result.success) {
150218
+ if (result.reportPath && existsSync24(result.reportPath) || existsSync24(result.session.rootPath + "/comprehensive-pentest-report.md")) {
150219
+ setIsCompleted(true);
150220
+ }
150221
+ }
150222
+ setThinking(false);
150223
+ setIsExecuting(false);
150224
+ } catch (error42) {
150225
+ setThinking(false);
150226
+ setIsExecuting(false);
150227
+ if (error42 instanceof Error && error42.name === "AbortError") {} else {
150228
+ setError(error42 instanceof Error ? error42.message : "Unknown error occurred");
150229
+ }
150230
+ }
150231
+ }, [model.id, addTokenUsage, setThinking, setIsExecuting]);
150232
+ const resumeAgent = import_react48.useCallback(async (agentId) => {
150233
+ if (!session)
150234
+ return;
150235
+ const paused = subagentsRef.current.find((s) => s.id === agentId && s.status === "paused");
150236
+ if (!paused)
150237
+ return;
150238
+ if (paused.type === "attack-surface") {
150239
+ let previousResults;
150240
+ const resultsPath = join19(session.rootPath, "attack-surface-results.json");
150241
+ if (existsSync24(resultsPath)) {
150242
+ try {
150243
+ previousResults = JSON.parse(readFileSync14(resultsPath, "utf-8"));
150244
+ } catch {}
150245
+ }
150246
+ await startPentest(session, previousResults);
150247
+ return;
150248
+ }
150249
+ if (!paused.resumeInfo)
150250
+ return;
150251
+ const { target, objective, vulnerabilityClass, authenticationInfo } = paused.resumeInfo;
150252
+ setSubagents((prev) => prev.map((s) => s.id === agentId ? { ...s, status: "pending" } : s));
150253
+ setIsExecuting(true);
150254
+ setThinking(true);
150255
+ let accumulatedText = "";
150256
+ try {
150257
+ const result = await runMetaVulnerabilityTestAgent({
150258
+ input: {
150259
+ target,
150260
+ objective,
150261
+ vulnerabilityClass,
150262
+ authenticationInfo,
150263
+ authenticationInstructions: session.config?.authenticationInstructions,
150264
+ outcomeGuidance: session.config?.outcomeGuidance || "Find and document vulnerabilities",
150265
+ session: {
150266
+ id: session.id,
150267
+ rootPath: session.rootPath,
150268
+ findingsPath: session.findingsPath,
150269
+ logsPath: session.logsPath,
150270
+ pocsPath: session.rootPath + "/pocs"
150271
+ },
150272
+ sessionConfig: {
150273
+ enableCvssScoring: session.config?.enableCvssScoring,
150274
+ cvssModel: session.config?.cvssModel
150275
+ }
150276
+ },
150277
+ model: model.id,
150278
+ abortSignal: abortController?.signal,
150279
+ onChunk: (chunk) => {
150280
+ if (chunk.type === "text-delta" && chunk.text) {
150281
+ accumulatedText += chunk.text;
150282
+ setThinking(false);
150283
+ if (accumulatedText.trim()) {
150284
+ setSubagents((prev) => {
150285
+ const idx = prev.findIndex((s) => s.id === agentId);
150286
+ if (idx === -1)
150287
+ return prev;
150288
+ const updated = [...prev];
150289
+ const subagent = updated[idx];
150290
+ const lastMsg = subagent.messages[subagent.messages.length - 1];
150291
+ if (lastMsg && lastMsg.role === "assistant") {
150292
+ const newMessages = [...subagent.messages];
150293
+ newMessages[newMessages.length - 1] = {
150294
+ ...lastMsg,
150295
+ content: accumulatedText
150296
+ };
150297
+ updated[idx] = { ...subagent, messages: newMessages };
150298
+ } else {
150299
+ updated[idx] = {
150300
+ ...subagent,
150301
+ messages: [
150302
+ ...subagent.messages,
150303
+ {
150304
+ role: "assistant",
150305
+ content: accumulatedText,
150306
+ createdAt: new Date
150307
+ }
150308
+ ]
150309
+ };
150310
+ }
150311
+ return updated;
150312
+ });
150313
+ }
150314
+ } else if (chunk.type === "tool-call") {
150315
+ setThinking(false);
150316
+ const tc = chunk;
150317
+ const toolCallId = tc.toolCallId;
150318
+ const toolName = tc.toolName || "tool";
150319
+ const args = tc.input ?? tc.args;
150320
+ const toolDescription = typeof args?.toolCallDescription === "string" ? args.toolCallDescription : toolName;
150321
+ setSubagents((prev) => {
150322
+ const idx = prev.findIndex((s) => s.id === agentId);
150323
+ if (idx === -1)
150324
+ return prev;
150325
+ const updated = [...prev];
150326
+ const subagent = updated[idx];
150327
+ const newMessages = [...subagent.messages];
150328
+ const exists = newMessages.some((m2) => m2.role === "tool" && m2.toolCallId === toolCallId);
150329
+ if (!exists) {
150330
+ newMessages.push({
150331
+ role: "tool",
150332
+ status: "pending",
150333
+ toolCallId,
150334
+ toolName,
150335
+ content: toolDescription,
150336
+ args,
150337
+ createdAt: new Date
150338
+ });
150339
+ }
150340
+ updated[idx] = { ...subagent, messages: newMessages };
150341
+ return updated;
150342
+ });
150343
+ } else if (chunk.type === "tool-result") {
150344
+ setThinking(true);
150345
+ const tr = chunk;
149857
150346
  const toolCallId = tr.toolCallId;
149858
150347
  const toolName = tr.toolName || "tool";
149859
- const result2 = tr.output ?? tr.result;
150348
+ const resultData = tr.output ?? tr.result;
149860
150349
  setSubagents((prev) => {
149861
150350
  const idx = prev.findIndex((s) => s.id === agentId);
149862
150351
  if (idx === -1)
@@ -149871,8 +150360,8 @@ function SessionView({
149871
150360
  newMessages[msgIdx] = {
149872
150361
  ...existingMsg,
149873
150362
  status: "completed",
149874
- content: `+ ${description}`,
149875
- result: result2
150363
+ content: description,
150364
+ result: resultData
149876
150365
  };
149877
150366
  } else {
149878
150367
  newMessages.push({
@@ -149881,54 +150370,47 @@ function SessionView({
149881
150370
  toolCallId,
149882
150371
  toolName,
149883
150372
  content: `+ ${toolName}`,
149884
- result: result2,
150373
+ result: resultData,
149885
150374
  createdAt: new Date
149886
150375
  });
149887
150376
  }
149888
150377
  updated[idx] = { ...subagent, messages: newMessages };
149889
150378
  return updated;
149890
150379
  });
149891
- } else if (event.type === "step-finish" && event.data) {
149892
- const { usage } = event.data;
149893
- if (usage) {
149894
- const stepTokens = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
149895
- if (stepTokens > 0)
149896
- addTokenUsage(usage.inputTokens ?? 0, usage.outputTokens ?? 0);
149897
- }
149898
- pentestAgentTexts.set(agentId, "");
149899
150380
  }
149900
150381
  },
149901
- onPentestAgentComplete: (agentId, agentResult) => {
149902
- setSubagents((prev) => prev.map((sub) => sub.id === agentId && sub.status !== "canceled" ? {
149903
- ...sub,
149904
- status: agentResult.error ? "failed" : "completed",
149905
- messages: [
149906
- ...sub.messages,
149907
- {
149908
- role: "assistant",
149909
- content: `${agentResult.findingsCount > 0 ? "✅" : "⚪"} ${agentResult.summary}`,
149910
- createdAt: new Date
149911
- }
149912
- ]
149913
- } : sub));
149914
- },
149915
- onProgress: (status) => {}
149916
- });
149917
- if (result.success) {
149918
- if (result.reportPath && existsSync24(result.reportPath) || existsSync24(result.session.rootPath + "/comprehensive-pentest-report.md")) {
149919
- setIsCompleted(true);
150382
+ onStepFinish: (step) => {
150383
+ const usage = step.usage;
150384
+ if (usage) {
150385
+ const stepTokens = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
150386
+ if (stepTokens > 0)
150387
+ addTokenUsage(usage.inputTokens ?? 0, usage.outputTokens ?? 0);
150388
+ }
150389
+ accumulatedText = "";
149920
150390
  }
149921
- }
149922
- setThinking(false);
149923
- setIsExecuting(false);
150391
+ });
150392
+ setSubagents((prev) => prev.map((s) => s.id === agentId ? {
150393
+ ...s,
150394
+ status: result.error ? "failed" : "completed",
150395
+ resumeInfo: undefined,
150396
+ messages: [
150397
+ ...s.messages,
150398
+ {
150399
+ role: "assistant",
150400
+ content: `${result.findingsCount > 0 ? "✅" : "⚪"} ${result.summary}`,
150401
+ createdAt: new Date
150402
+ }
150403
+ ]
150404
+ } : s));
149924
150405
  } catch (error42) {
149925
- setThinking(false);
150406
+ setSubagents((prev) => prev.map((s) => s.id === agentId ? { ...s, status: "failed", resumeInfo: undefined } : s));
150407
+ }
150408
+ setThinking(false);
150409
+ const stillRunning = subagentsRef.current.some((s) => s.status === "pending" && s.id !== agentId);
150410
+ if (!stillRunning) {
149926
150411
  setIsExecuting(false);
149927
- if (error42 instanceof Error && error42.name === "AbortError") {} else {
149928
- setError(error42 instanceof Error ? error42.message : "Unknown error occurred");
149929
- }
149930
150412
  }
149931
- }, [model.id, addTokenUsage, setThinking, setIsExecuting]);
150413
+ }, [session, model.id, abortController, addTokenUsage, setThinking, setIsExecuting, startPentest]);
149932
150414
  const openReport = import_react48.useCallback(() => {
149933
150415
  if (session?.rootPath) {
149934
150416
  const reportPath = `${session.rootPath}/comprehensive-pentest-report.md`;
@@ -149989,10 +150471,11 @@ function SessionView({
149989
150471
  session
149990
150472
  }, undefined, false, undefined, this);
149991
150473
  }
149992
- if (session.config?.mode === "operator") {
150474
+ if (session.config?.mode === "operator" || openAsOperator) {
149993
150475
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(OperatorDashboard, {
149994
150476
  session,
149995
- isResume
150477
+ isResume,
150478
+ openAsOperator
149996
150479
  }, undefined, false, undefined, this);
149997
150480
  }
149998
150481
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SwarmDashboard, {
@@ -150003,7 +150486,8 @@ function SessionView({
150003
150486
  isCompleted,
150004
150487
  onBack: handleBack,
150005
150488
  onViewReport: openReport,
150006
- onKillAgent: killAgent
150489
+ onKillAgent: killAgent,
150490
+ onResumeAgent: resumeAgent
150007
150491
  }, undefined, false, undefined, this);
150008
150492
  }
150009
150493
 
@@ -150752,10 +151236,17 @@ function HomeView({ onNavigate, onStartSession }) {
150752
151236
  const { executeCommand, autocompleteOptions } = useCommand();
150753
151237
  const { setInputValue } = useInput();
150754
151238
  const { promptRef } = useFocus();
151239
+ const [hintMessage, setHintMessage] = import_react56.useState(null);
150755
151240
  const handleSubmit = import_react56.useCallback((value) => {
150756
- onStartSession(value);
151241
+ setHintMessage("Type /help to get started");
150757
151242
  setInputValue("");
150758
- }, [onStartSession, setInputValue]);
151243
+ }, [setInputValue]);
151244
+ import_react56.useEffect(() => {
151245
+ if (!hintMessage)
151246
+ return;
151247
+ const timer = setTimeout(() => setHintMessage(null), 3000);
151248
+ return () => clearTimeout(timer);
151249
+ }, [hintMessage]);
150759
151250
  const handleCommandExecute = import_react56.useCallback(async (command) => {
150760
151251
  await executeCommand(command);
150761
151252
  }, [executeCommand]);
@@ -150825,6 +151316,13 @@ function HomeView({ onNavigate, onStartSession }) {
150825
151316
  onCommandExecute: handleCommandExecute,
150826
151317
  showPromptIndicator: true
150827
151318
  }, undefined, false, undefined, this),
151319
+ hintMessage && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
151320
+ marginTop: 1,
151321
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
151322
+ fg: creamText7,
151323
+ children: hintMessage
151324
+ }, undefined, false, undefined, this)
151325
+ }, undefined, false, undefined, this),
150828
151326
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
150829
151327
  marginTop: 1,
150830
151328
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
@@ -153021,13 +153519,27 @@ function WebWizard({
153021
153519
  }, undefined, true, undefined, this);
153022
153520
  }
153023
153521
 
153024
- // src/tui/components/commands/resume-wizard.tsx
153522
+ // src/tui/components/commands/sessions-browser.tsx
153523
+ var import_react69 = __toESM(require_react(), 1);
153524
+ import { exec as exec5 } from "child_process";
153525
+ import { existsSync as existsSync27 } from "fs";
153526
+
153527
+ // src/tui/hooks/use-sessions-list.ts
153025
153528
  var import_react68 = __toESM(require_react(), 1);
153026
153529
  import { existsSync as existsSync26, readdirSync as readdirSync7 } from "fs";
153027
- import { join as join19 } from "path";
153028
- var greenAccent5 = RGBA.fromInts(76, 175, 80, 255);
153029
- var creamText12 = RGBA.fromInts(255, 248, 220, 255);
153030
- var dimText13 = RGBA.fromInts(120, 120, 120, 255);
153530
+ import { join as join20 } from "path";
153531
+ function countFindings(findingsPath) {
153532
+ try {
153533
+ if (!existsSync26(findingsPath))
153534
+ return 0;
153535
+ return readdirSync7(findingsPath).filter((f) => f.endsWith(".json")).length;
153536
+ } catch {
153537
+ return 0;
153538
+ }
153539
+ }
153540
+ function checkHasReport(rootPath) {
153541
+ return existsSync26(join20(rootPath, "comprehensive-pentest-report.md"));
153542
+ }
153031
153543
  function formatRelativeTime(timestamp) {
153032
153544
  const now2 = Date.now();
153033
153545
  const diff = now2 - timestamp;
@@ -153046,89 +153558,177 @@ function formatRelativeTime(timestamp) {
153046
153558
  return `${days}d ago`;
153047
153559
  return new Date(timestamp).toLocaleDateString();
153048
153560
  }
153049
- function countFindings(findingsPath) {
153050
- try {
153051
- if (!existsSync26(findingsPath))
153052
- return 0;
153053
- return readdirSync7(findingsPath).filter((f) => f.endsWith(".json")).length;
153054
- } catch {
153055
- return 0;
153056
- }
153057
- }
153058
- function ResumeWizard() {
153561
+ function useSessionsList() {
153059
153562
  const [sessions, setSessions] = import_react68.useState([]);
153060
- const [selectedIndex, setSelectedIndex] = import_react68.useState(0);
153061
153563
  const [loading, setLoading] = import_react68.useState(true);
153062
- const [statusMessage, setStatusMessage] = import_react68.useState("");
153564
+ const [searchTerm, setSearchTerm] = import_react68.useState("");
153565
+ const loadSessions = import_react68.useCallback(async () => {
153566
+ setLoading(true);
153567
+ try {
153568
+ const enriched = [];
153569
+ for await (const session of Session.list()) {
153570
+ const hasOperatorState = existsSync26(join20(session.rootPath, "operator-state.json"));
153571
+ const findingsCount = countFindings(session.findingsPath);
153572
+ const hasReport2 = checkHasReport(session.rootPath);
153573
+ enriched.push({ ...session, findingsCount, hasOperatorState, hasReport: hasReport2 });
153574
+ }
153575
+ enriched.sort((a, b2) => b2.time.updated - a.time.updated);
153576
+ setSessions(enriched);
153577
+ } catch (error41) {
153578
+ console.error("Error loading sessions:", error41);
153579
+ } finally {
153580
+ setLoading(false);
153581
+ }
153582
+ }, []);
153583
+ import_react68.useEffect(() => {
153584
+ loadSessions();
153585
+ }, [loadSessions]);
153586
+ const deleteSession = import_react68.useCallback(async (id) => {
153587
+ await Session.remove({ sessionId: id });
153588
+ await loadSessions();
153589
+ }, [loadSessions]);
153590
+ const filtered = searchTerm ? sessions.filter((s) => s.name.toLowerCase().includes(searchTerm.toLowerCase())) : sessions;
153591
+ const groupsMap = new Map;
153592
+ for (const session of filtered) {
153593
+ const d2 = new Date(session.time.created);
153594
+ const dateStr = d2.toLocaleDateString("en-US", {
153595
+ weekday: "short",
153596
+ month: "short",
153597
+ day: "numeric",
153598
+ year: "numeric"
153599
+ });
153600
+ let group = groupsMap.get(dateStr);
153601
+ if (!group) {
153602
+ group = { date: dateStr, timestamp: d2.getTime(), sessions: [] };
153603
+ groupsMap.set(dateStr, group);
153604
+ }
153605
+ group.sessions.push(session);
153606
+ }
153607
+ const rawGroups = Array.from(groupsMap.values());
153608
+ rawGroups.sort((a, b2) => b2.timestamp - a.timestamp);
153609
+ for (const g2 of rawGroups) {
153610
+ g2.sessions.sort((a, b2) => new Date(b2.time.created).getTime() - new Date(a.time.created).getTime());
153611
+ }
153612
+ const visualOrderSessions = [];
153613
+ const groupedSessions = [];
153614
+ let idx = 0;
153615
+ for (const raw of rawGroups) {
153616
+ const group = { date: raw.date, timestamp: raw.timestamp, sessions: [] };
153617
+ for (const s of raw.sessions) {
153618
+ visualOrderSessions.push(s);
153619
+ group.sessions.push({ ...s, index: idx });
153620
+ idx++;
153621
+ }
153622
+ groupedSessions.push(group);
153623
+ }
153624
+ return {
153625
+ sessions: filtered,
153626
+ groupedSessions,
153627
+ visualOrderSessions,
153628
+ loading,
153629
+ searchTerm,
153630
+ setSearchTerm,
153631
+ deleteSession,
153632
+ reload: loadSessions
153633
+ };
153634
+ }
153635
+
153636
+ // src/tui/components/commands/sessions-browser.tsx
153637
+ var greenAccent5 = RGBA.fromInts(76, 175, 80, 255);
153638
+ var creamText12 = RGBA.fromInts(255, 248, 220, 255);
153639
+ var dimText13 = RGBA.fromInts(120, 120, 120, 255);
153640
+ function SessionsBrowser() {
153063
153641
  const route = useRoute();
153064
153642
  const { load: loadSession } = useSession();
153065
153643
  const { refocusPrompt } = useFocus();
153066
- import_react68.useEffect(() => {
153067
- async function loadOperatorSessions() {
153068
- setLoading(true);
153069
- try {
153070
- const enrichedSessions = [];
153071
- for await (const session of Session.list()) {
153072
- const statePath = join19(session.rootPath, "operator-state.json");
153073
- const hasOperatorState = existsSync26(statePath);
153074
- const findingsCount = countFindings(session.findingsPath);
153075
- enrichedSessions.push({
153076
- ...session,
153077
- findingsCount,
153078
- hasOperatorState
153079
- });
153080
- }
153081
- enrichedSessions.sort((a, b2) => b2.time.updated - a.time.updated);
153082
- setSessions(enrichedSessions.slice(0, 20));
153083
- } catch (error41) {
153084
- console.error("Error loading sessions:", error41);
153085
- setStatusMessage("Error loading sessions");
153086
- } finally {
153087
- setLoading(false);
153088
- }
153644
+ const {
153645
+ groupedSessions,
153646
+ visualOrderSessions,
153647
+ loading,
153648
+ searchTerm,
153649
+ setSearchTerm,
153650
+ deleteSession,
153651
+ reload
153652
+ } = useSessionsList();
153653
+ const [selectedIndex, setSelectedIndex] = import_react69.useState(0);
153654
+ const [statusMessage, setStatusMessage] = import_react69.useState("");
153655
+ const scroll = import_react69.useRef(null);
153656
+ import_react69.useEffect(() => {
153657
+ if (visualOrderSessions.length > 0 && selectedIndex >= visualOrderSessions.length) {
153658
+ setSelectedIndex(visualOrderSessions.length - 1);
153659
+ } else if (visualOrderSessions.length === 0) {
153660
+ setSelectedIndex(0);
153089
153661
  }
153090
- loadOperatorSessions();
153662
+ }, [visualOrderSessions.length, selectedIndex]);
153663
+ const showStatus = import_react69.useCallback((msg) => {
153664
+ setStatusMessage(msg);
153665
+ setTimeout(() => setStatusMessage(""), 2000);
153091
153666
  }, []);
153092
- const resumeSession = async (session) => {
153093
- try {
153094
- const loaded = await loadSession(session.id);
153095
- if (!loaded) {
153096
- setStatusMessage("Error loading session");
153097
- setTimeout(() => setStatusMessage(""), 2000);
153098
- return;
153099
- }
153100
- route.navigate({
153101
- type: "session",
153102
- sessionId: session.id,
153103
- isResume: true
153104
- });
153105
- } catch (error41) {
153106
- console.error("Error resuming session:", error41);
153107
- setStatusMessage("Error resuming session");
153108
- setTimeout(() => setStatusMessage(""), 2000);
153667
+ const openSession = import_react69.useCallback(async (session, asOperator) => {
153668
+ const loaded = await loadSession(session.id);
153669
+ if (!loaded) {
153670
+ showStatus("Error loading session");
153671
+ return;
153109
153672
  }
153110
- };
153111
- useKeyboard((key) => {
153673
+ route.navigate({
153674
+ type: "session",
153675
+ sessionId: session.id,
153676
+ isResume: true,
153677
+ openAsOperator: asOperator || undefined
153678
+ });
153679
+ }, [loadSession, route, showStatus]);
153680
+ const openReport = import_react69.useCallback(async (session) => {
153681
+ const reportPath = await Storage.locate([session.id, "pentest-report"], ".md");
153682
+ if (!existsSync27(reportPath)) {
153683
+ showStatus("Report not found");
153684
+ return;
153685
+ }
153686
+ exec5(`open "${reportPath}"`, (error41) => {
153687
+ if (error41)
153688
+ showStatus("Error opening report");
153689
+ });
153690
+ }, [showStatus]);
153691
+ useKeyboard(async (key) => {
153112
153692
  if (key.name === "escape") {
153113
153693
  refocusPrompt();
153114
153694
  route.navigate({ type: "base", path: "home" });
153115
153695
  return;
153116
153696
  }
153117
- if (key.name === "up" && sessions.length > 0) {
153118
- setSelectedIndex((i) => i > 0 ? i - 1 : sessions.length - 1);
153697
+ if (key.name === "return" && visualOrderSessions.length > 0) {
153698
+ key.preventDefault();
153699
+ const selected = visualOrderSessions[selectedIndex];
153700
+ if (selected)
153701
+ await openSession(selected, false);
153702
+ return;
153703
+ }
153704
+ if ((key.name === "o" || key.name === "O") && !key.ctrl && !key.meta && visualOrderSessions.length > 0) {
153705
+ const selected = visualOrderSessions[selectedIndex];
153706
+ if (selected)
153707
+ await openSession(selected, true);
153119
153708
  return;
153120
153709
  }
153121
- if (key.name === "down" && sessions.length > 0) {
153122
- setSelectedIndex((i) => i < sessions.length - 1 ? i + 1 : 0);
153710
+ if ((key.name === "r" || key.name === "R") && !key.ctrl && !key.meta && visualOrderSessions.length > 0) {
153711
+ const selected = visualOrderSessions[selectedIndex];
153712
+ if (selected)
153713
+ await openReport(selected);
153123
153714
  return;
153124
153715
  }
153125
- if (key.name === "return" && sessions.length > 0) {
153126
- const selected = sessions[selectedIndex];
153716
+ if (key.ctrl && key.name === "d" && visualOrderSessions.length > 0) {
153717
+ const selected = visualOrderSessions[selectedIndex];
153127
153718
  if (selected) {
153128
- resumeSession(selected);
153719
+ await deleteSession(selected.id);
153720
+ showStatus("Session deleted");
153129
153721
  }
153130
153722
  return;
153131
153723
  }
153724
+ if (key.name === "up" && visualOrderSessions.length > 0) {
153725
+ setSelectedIndex((i) => i > 0 ? i - 1 : visualOrderSessions.length - 1);
153726
+ return;
153727
+ }
153728
+ if (key.name === "down" && visualOrderSessions.length > 0) {
153729
+ setSelectedIndex((i) => i < visualOrderSessions.length - 1 ? i + 1 : 0);
153730
+ return;
153731
+ }
153132
153732
  });
153133
153733
  if (loading) {
153134
153734
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
@@ -153141,7 +153741,7 @@ function ResumeWizard() {
153141
153741
  }, undefined, false, undefined, this)
153142
153742
  }, undefined, false, undefined, this);
153143
153743
  }
153144
- if (sessions.length === 0) {
153744
+ if (visualOrderSessions.length === 0) {
153145
153745
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
153146
153746
  flexDirection: "column",
153147
153747
  padding: 2,
@@ -153150,15 +153750,15 @@ function ResumeWizard() {
153150
153750
  children: [
153151
153751
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153152
153752
  fg: creamText12,
153153
- children: "Resume Pentest Session"
153753
+ children: "Sessions"
153154
153754
  }, undefined, false, undefined, this),
153155
153755
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153156
153756
  fg: dimText13,
153157
- children: "No sessions found to resume."
153757
+ children: "No sessions found."
153158
153758
  }, undefined, false, undefined, this),
153159
153759
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153160
153760
  fg: dimText13,
153161
- children: "Start a new session with /web or /operator"
153761
+ children: "Start a new session with /pentest or /operator"
153162
153762
  }, undefined, false, undefined, this),
153163
153763
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153164
153764
  fg: dimText13,
@@ -153172,98 +153772,142 @@ function ResumeWizard() {
153172
153772
  padding: 2,
153173
153773
  gap: 1,
153174
153774
  width: "100%",
153775
+ flexGrow: 1,
153175
153776
  children: [
153176
153777
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153177
153778
  fg: creamText12,
153178
- children: "Resume Pentest Session"
153779
+ children: "Sessions"
153179
153780
  }, undefined, false, undefined, this),
153180
153781
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153181
153782
  fg: dimText13,
153182
- children: "Select a session to continue where you left off"
153783
+ children: "Browse and reopen previous pentest sessions"
153183
153784
  }, undefined, false, undefined, this),
153184
153785
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
153185
- flexDirection: "column",
153186
- marginTop: 1,
153187
- children: sessions.map((session, index) => {
153188
- const isSelected = index === selectedIndex;
153189
- const age = formatRelativeTime(session.time.updated);
153190
- const target = session.targets[0] || "No target";
153191
- const findingsText = session.findingsCount > 0 ? `${session.findingsCount} finding${session.findingsCount > 1 ? "s" : ""}` : "No findings";
153192
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
153193
- flexDirection: "row",
153194
- justifyContent: "space-between",
153195
- width: "100%",
153196
- border: isSelected ? ["left"] : undefined,
153197
- borderColor: isSelected ? greenAccent5 : undefined,
153198
- paddingLeft: isSelected ? 1 : 2,
153199
- children: [
153200
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
153201
- flexDirection: "row",
153202
- gap: 1,
153203
- children: [
153204
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153205
- fg: isSelected ? greenAccent5 : creamText12,
153206
- children: [
153207
- isSelected ? "▸ " : " ",
153208
- session.name
153209
- ]
153210
- }, undefined, true, undefined, this),
153211
- session.hasOperatorState && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153212
- fg: greenAccent5,
153213
- children: "●"
153214
- }, undefined, false, undefined, this)
153215
- ]
153216
- }, undefined, true, undefined, this),
153217
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153218
- fg: dimText13,
153219
- children: [
153220
- target,
153221
- " · ",
153222
- findingsText,
153223
- " · ",
153224
- age
153225
- ]
153226
- }, undefined, true, undefined, this)
153227
- ]
153228
- }, session.id, true, undefined, this);
153229
- })
153786
+ width: "100%",
153787
+ border: ["left"],
153788
+ borderColor: greenAccent5,
153789
+ backgroundColor: "transparent",
153790
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
153791
+ paddingLeft: 1,
153792
+ backgroundColor: "transparent",
153793
+ placeholder: "Search sessions...",
153794
+ value: searchTerm,
153795
+ onInput: setSearchTerm,
153796
+ focused: true
153797
+ }, undefined, false, undefined, this)
153230
153798
  }, undefined, false, undefined, this),
153231
153799
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
153232
- marginTop: 2,
153233
153800
  flexDirection: "column",
153234
- children: [
153235
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153236
- fg: dimText13,
153237
- children: [
153238
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
153239
- fg: greenAccent5,
153240
- children: "↑↓"
153241
- }, undefined, false, undefined, this),
153242
- " Navigate ",
153243
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
153244
- fg: greenAccent5,
153245
- children: "Enter"
153246
- }, undefined, false, undefined, this),
153247
- " Resume ",
153248
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
153249
- fg: greenAccent5,
153250
- children: "Esc"
153251
- }, undefined, false, undefined, this),
153252
- " Cancel"
153253
- ]
153254
- }, undefined, true, undefined, this),
153255
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153256
- fg: dimText13,
153801
+ gap: 1,
153802
+ flexGrow: 1,
153803
+ overflow: "hidden",
153804
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("scrollbox", {
153805
+ ref: scroll,
153806
+ scrollbarOptions: { visible: false },
153807
+ style: {
153808
+ rootOptions: {
153809
+ width: "100%",
153810
+ flexGrow: 1,
153811
+ flexShrink: 1,
153812
+ overflow: "hidden"
153813
+ },
153814
+ wrapperOptions: { overflow: "hidden" },
153815
+ contentOptions: { gap: 2, flexDirection: "column" }
153816
+ },
153817
+ children: groupedSessions.map((group) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
153818
+ flexDirection: "column",
153819
+ gap: 1,
153257
153820
  children: [
153258
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
153821
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153259
153822
  fg: greenAccent5,
153260
- children: "●"
153823
+ children: group.date
153261
153824
  }, undefined, false, undefined, this),
153262
- " = Has saved state (full context restore)"
153825
+ group.sessions.map((session) => {
153826
+ const isSelected = session.index === selectedIndex;
153827
+ const age = formatRelativeTime(session.time.updated);
153828
+ const mode = session.config?.mode || "auto";
153829
+ const modeBadge = mode === "operator" ? "[operator]" : "[auto]";
153830
+ const findingsText = session.findingsCount > 0 ? `${session.findingsCount} finding${session.findingsCount > 1 ? "s" : ""}` : "";
153831
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
153832
+ id: session.id,
153833
+ backgroundColor: "transparent",
153834
+ border: isSelected ? ["left"] : undefined,
153835
+ borderColor: isSelected ? greenAccent5 : undefined,
153836
+ paddingLeft: isSelected ? 1 : 2,
153837
+ flexDirection: "row",
153838
+ justifyContent: "space-between",
153839
+ width: "100%",
153840
+ children: [
153841
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
153842
+ flexDirection: "row",
153843
+ gap: 1,
153844
+ children: [
153845
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153846
+ fg: isSelected ? greenAccent5 : creamText12,
153847
+ children: [
153848
+ isSelected ? "▸ " : " ",
153849
+ session.name
153850
+ ]
153851
+ }, undefined, true, undefined, this),
153852
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153853
+ fg: mode === "operator" ? greenAccent5 : dimText13,
153854
+ children: modeBadge
153855
+ }, undefined, false, undefined, this),
153856
+ findingsText ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153857
+ fg: dimText13,
153858
+ children: findingsText
153859
+ }, undefined, false, undefined, this) : null
153860
+ ]
153861
+ }, undefined, true, undefined, this),
153862
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153863
+ fg: dimText13,
153864
+ children: age
153865
+ }, undefined, false, undefined, this)
153866
+ ]
153867
+ }, session.id, true, undefined, this);
153868
+ })
153263
153869
  ]
153264
- }, undefined, true, undefined, this)
153265
- ]
153266
- }, undefined, true, undefined, this),
153870
+ }, group.date, true, undefined, this))
153871
+ }, undefined, false, undefined, this)
153872
+ }, undefined, false, undefined, this),
153873
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
153874
+ flexDirection: "row",
153875
+ gap: 1,
153876
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153877
+ fg: dimText13,
153878
+ children: [
153879
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
153880
+ fg: greenAccent5,
153881
+ children: "[Enter]"
153882
+ }, undefined, false, undefined, this),
153883
+ " Open",
153884
+ " ",
153885
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
153886
+ fg: greenAccent5,
153887
+ children: "[O]"
153888
+ }, undefined, false, undefined, this),
153889
+ " Operator",
153890
+ " ",
153891
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
153892
+ fg: greenAccent5,
153893
+ children: "[R]"
153894
+ }, undefined, false, undefined, this),
153895
+ " Report",
153896
+ " ",
153897
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
153898
+ fg: greenAccent5,
153899
+ children: "[Ctrl+D]"
153900
+ }, undefined, false, undefined, this),
153901
+ " Delete",
153902
+ " ",
153903
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
153904
+ fg: greenAccent5,
153905
+ children: "[Esc]"
153906
+ }, undefined, false, undefined, this),
153907
+ " Back"
153908
+ ]
153909
+ }, undefined, true, undefined, this)
153910
+ }, undefined, false, undefined, this),
153267
153911
  statusMessage && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
153268
153912
  fg: greenAccent5,
153269
153913
  children: statusMessage
@@ -153273,16 +153917,16 @@ function ResumeWizard() {
153273
153917
  }
153274
153918
 
153275
153919
  // src/tui/components/commands/provider-manager.tsx
153276
- var import_react74 = __toESM(require_react(), 1);
153920
+ var import_react75 = __toESM(require_react(), 1);
153277
153921
  // src/tui/components/commands/provider-selection.tsx
153278
- var import_react71 = __toESM(require_react(), 1);
153922
+ var import_react72 = __toESM(require_react(), 1);
153279
153923
  function ProviderSelection({
153280
153924
  onProviderSelected,
153281
153925
  onClose
153282
153926
  }) {
153283
153927
  const route = useRoute();
153284
153928
  const _config = useConfig();
153285
- const [highlightedIndex, setHighlightedIndex] = import_react71.useState(0);
153929
+ const [highlightedIndex, setHighlightedIndex] = import_react72.useState(0);
153286
153930
  const configuredProviders = getConfiguredProviders(_config.data);
153287
153931
  useKeyboard((key) => {
153288
153932
  if (key.name === "escape") {
@@ -153435,14 +154079,14 @@ function ProviderSelection({
153435
154079
  }
153436
154080
 
153437
154081
  // src/tui/components/commands/api-key-input.tsx
153438
- var import_react73 = __toESM(require_react(), 1);
154082
+ var import_react74 = __toESM(require_react(), 1);
153439
154083
  function APIKeyInput({
153440
154084
  provider,
153441
154085
  providerName,
153442
154086
  onSubmit,
153443
154087
  onCancel
153444
154088
  }) {
153445
- const [apiKey, setApiKey] = import_react73.useState("");
154089
+ const [apiKey, setApiKey] = import_react74.useState("");
153446
154090
  useKeyboard((key) => {
153447
154091
  if (key.name === "escape") {
153448
154092
  onCancel();
@@ -153554,8 +154198,8 @@ function APIKeyInput({
153554
154198
  function ProviderManager() {
153555
154199
  const route = useRoute();
153556
154200
  const _config = useConfig();
153557
- const [flowState, setFlowState] = import_react74.useState("selecting");
153558
- const [selectedProvider, setSelectedProvider] = import_react74.useState(null);
154201
+ const [flowState, setFlowState] = import_react75.useState("selecting");
154202
+ const [selectedProvider, setSelectedProvider] = import_react75.useState(null);
153559
154203
  const handleProviderSelected = (providerId) => {
153560
154204
  setSelectedProvider(providerId);
153561
154205
  setFlowState("inputting");
@@ -153613,7 +154257,7 @@ function ProviderManager() {
153613
154257
  }
153614
154258
 
153615
154259
  // src/tui/components/switch.tsx
153616
- var import_react75 = __toESM(require_react(), 1);
154260
+ var import_react76 = __toESM(require_react(), 1);
153617
154261
  var CaseSymbol = Symbol("Switch.Case");
153618
154262
  var DefaultSymbol = Symbol("Switch.Default");
153619
154263
  function CaseComponent({ children }) {
@@ -153634,8 +154278,8 @@ function SwitchComponent({
153634
154278
  }) {
153635
154279
  let matchedChild = null;
153636
154280
  let defaultChild = null;
153637
- import_react75.default.Children.forEach(children, (child) => {
153638
- if (import_react75.default.isValidElement(child)) {
154281
+ import_react76.default.Children.forEach(children, (child) => {
154282
+ if (import_react76.default.isValidElement(child)) {
153639
154283
  if (child.type[CaseSymbol]) {
153640
154284
  const caseChild = child;
153641
154285
  if (caseChild.props.when === condition) {
@@ -153847,7 +154491,7 @@ function ShortcutsDialog({ open, onClose }) {
153847
154491
  }
153848
154492
 
153849
154493
  // src/tui/components/commands/help-dialog.tsx
153850
- var import_react78 = __toESM(require_react(), 1);
154494
+ var import_react79 = __toESM(require_react(), 1);
153851
154495
  var bgOverlay2 = RGBA.fromInts(0, 0, 0, 200);
153852
154496
  var bgPanel2 = RGBA.fromInts(20, 20, 20, 255);
153853
154497
  var borderColor3 = RGBA.fromInts(60, 60, 60, 255);
@@ -153859,10 +154503,10 @@ function HelpDialog() {
153859
154503
  const { commands: commands2 } = useCommand();
153860
154504
  const route = useRoute();
153861
154505
  const dimensions = useTerminalDimensions();
153862
- const [selectedIndex, setSelectedIndex] = import_react78.useState(0);
153863
- const [showDetail, setShowDetail] = import_react78.useState(false);
153864
- const scrollboxRef = import_react78.useRef(null);
153865
- const commandsByCategory = import_react78.useMemo(() => {
154506
+ const [selectedIndex, setSelectedIndex] = import_react79.useState(0);
154507
+ const [showDetail, setShowDetail] = import_react79.useState(false);
154508
+ const scrollboxRef = import_react79.useRef(null);
154509
+ const commandsByCategory = import_react79.useMemo(() => {
153866
154510
  const grouped = {};
153867
154511
  for (const cmd of commands2) {
153868
154512
  const category = cmd.category || "Other";
@@ -153873,15 +154517,15 @@ function HelpDialog() {
153873
154517
  }
153874
154518
  return grouped;
153875
154519
  }, [commands2]);
153876
- const flatCommands = import_react78.useMemo(() => {
154520
+ const flatCommands = import_react79.useMemo(() => {
153877
154521
  return commands2;
153878
154522
  }, [commands2]);
153879
- import_react78.useEffect(() => {
154523
+ import_react79.useEffect(() => {
153880
154524
  if (selectedIndex >= flatCommands.length) {
153881
154525
  setSelectedIndex(Math.max(0, flatCommands.length - 1));
153882
154526
  }
153883
154527
  }, [flatCommands.length, selectedIndex]);
153884
- import_react78.useEffect(() => {
154528
+ import_react79.useEffect(() => {
153885
154529
  if (!scrollboxRef.current || flatCommands.length === 0)
153886
154530
  return;
153887
154531
  const scroll = scrollboxRef.current;
@@ -154333,10 +154977,10 @@ function ModelsDisplay() {
154333
154977
  }
154334
154978
 
154335
154979
  // src/tui/context/keybinding.tsx
154336
- var import_react85 = __toESM(require_react(), 1);
154980
+ var import_react86 = __toESM(require_react(), 1);
154337
154981
 
154338
154982
  // src/tui/keybindings/keybind.tsx
154339
- var import_react81 = __toESM(require_react(), 1);
154983
+ var import_react82 = __toESM(require_react(), 1);
154340
154984
 
154341
154985
  // src/tui/keybindings/actions.ts
154342
154986
  var movementActions = [
@@ -154588,7 +155232,7 @@ var allActions = [
154588
155232
  var actionsByKey = new Map(allActions.map((action) => [action.key, action]));
154589
155233
  var actionsById = new Map(allActions.map((action) => [action.id, action]));
154590
155234
  // src/tui/keybindings/keybind.tsx
154591
- var LeaderKeyContext = import_react81.createContext(null);
155235
+ var LeaderKeyContext = import_react82.createContext(null);
154592
155236
  // src/tui/keybindings/registry.ts
154593
155237
  function createKeybindings(deps) {
154594
155238
  const {
@@ -154794,7 +155438,7 @@ var Keybind;
154794
155438
  })(Keybind ||= {});
154795
155439
 
154796
155440
  // src/tui/context/keybinding.tsx
154797
- var KeybindingContext = import_react85.createContext(undefined);
155441
+ var KeybindingContext = import_react86.createContext(undefined);
154798
155442
  function KeybindingProvider({
154799
155443
  children,
154800
155444
  deps
@@ -154835,13 +155479,13 @@ function KeybindingProvider({
154835
155479
  // src/tui/index.tsx
154836
155480
  function App(props) {
154837
155481
  const { appConfig } = props;
154838
- const [focusIndex, setFocusIndex] = import_react87.useState(0);
154839
- const [cwd, setCwd] = import_react87.useState(process.cwd());
154840
- const [ctrlCPressTime, setCtrlCPressTime] = import_react87.useState(null);
154841
- const [showExitWarning, setShowExitWarning] = import_react87.useState(false);
154842
- const [inputKey, setInputKey] = import_react87.useState(0);
154843
- const [showSessionsDialog, setShowSessionsDialog] = import_react87.useState(false);
154844
- const [showShortcutsDialog, setShowShortcutsDialog] = import_react87.useState(false);
155482
+ const [focusIndex, setFocusIndex] = import_react88.useState(0);
155483
+ const [cwd, setCwd] = import_react88.useState(process.cwd());
155484
+ const [ctrlCPressTime, setCtrlCPressTime] = import_react88.useState(null);
155485
+ const [showExitWarning, setShowExitWarning] = import_react88.useState(false);
155486
+ const [inputKey, setInputKey] = import_react88.useState(0);
155487
+ const [showSessionsDialog, setShowSessionsDialog] = import_react88.useState(false);
155488
+ const [showShortcutsDialog, setShowShortcutsDialog] = import_react88.useState(false);
154845
155489
  const navigableItems = ["command-input"];
154846
155490
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ConfigProvider, {
154847
155491
  config: appConfig,
@@ -154915,7 +155559,7 @@ function AppContent({
154915
155559
  path: "providers"
154916
155560
  });
154917
155561
  }
154918
- import_react87.useEffect(() => {
155562
+ import_react88.useEffect(() => {
154919
155563
  if (showExitWarning) {
154920
155564
  const timer = setTimeout(() => {
154921
155565
  setShowExitWarning(false);
@@ -155037,13 +155681,17 @@ function CommandDisplay({
155037
155681
  initialModel: route.data.options?.model
155038
155682
  }, undefined, false, undefined, this)
155039
155683
  }, undefined, false, undefined, this),
155684
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
155685
+ when: "models",
155686
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ModelsDisplay, {}, undefined, false, undefined, this)
155687
+ }, undefined, false, undefined, this),
155040
155688
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
155041
155689
  when: "providers",
155042
155690
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ProviderManager, {}, undefined, false, undefined, this)
155043
155691
  }, undefined, false, undefined, this),
155044
155692
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
155045
- when: "resume",
155046
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ResumeWizard, {}, undefined, false, undefined, this)
155693
+ when: "sessions",
155694
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SessionsBrowser, {}, undefined, false, undefined, this)
155047
155695
  }, undefined, false, undefined, this),
155048
155696
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
155049
155697
  when: "help",
@@ -155060,7 +155708,8 @@ function CommandDisplay({
155060
155708
  if (route.data.type === "session") {
155061
155709
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SessionView, {
155062
155710
  sessionId: route.data.sessionId,
155063
- isResume: route.data.isResume
155711
+ isResume: route.data.isResume,
155712
+ openAsOperator: route.data.openAsOperator
155064
155713
  }, undefined, false, undefined, this);
155065
155714
  }
155066
155715
  return null;