@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.
- package/build/index.js +1210 -561
- 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
|
|
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: "
|
|
71909
|
-
aliases: ["
|
|
71910
|
-
description: "
|
|
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: "
|
|
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 =
|
|
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 === "
|
|
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", {
|
|
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", {
|
|
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 {
|
|
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 ({
|
|
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", {
|
|
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 = {
|
|
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", {
|
|
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
|
-
|
|
149172
|
-
|
|
149173
|
-
|
|
149174
|
-
|
|
149175
|
-
|
|
149176
|
-
|
|
149177
|
-
|
|
149178
|
-
|
|
149179
|
-
|
|
149180
|
-
|
|
149181
|
-
|
|
149182
|
-
|
|
149183
|
-
|
|
149184
|
-
|
|
149185
|
-
|
|
149186
|
-
|
|
149187
|
-
|
|
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
|
-
|
|
149192
|
-
|
|
149193
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
-
|
|
149574
|
-
|
|
149575
|
-
|
|
149576
|
-
|
|
149577
|
-
|
|
149578
|
-
|
|
149579
|
-
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
149875
|
-
result:
|
|
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:
|
|
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
|
-
|
|
149902
|
-
|
|
149903
|
-
|
|
149904
|
-
|
|
149905
|
-
|
|
149906
|
-
|
|
149907
|
-
|
|
149908
|
-
|
|
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
|
-
|
|
149923
|
-
|
|
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
|
-
|
|
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
|
-
|
|
151241
|
+
setHintMessage("Type /help to get started");
|
|
150757
151242
|
setInputValue("");
|
|
150758
|
-
}, [
|
|
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/
|
|
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
|
|
153028
|
-
|
|
153029
|
-
|
|
153030
|
-
|
|
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
|
|
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 [
|
|
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
|
-
|
|
153067
|
-
|
|
153068
|
-
|
|
153069
|
-
|
|
153070
|
-
|
|
153071
|
-
|
|
153072
|
-
|
|
153073
|
-
|
|
153074
|
-
|
|
153075
|
-
|
|
153076
|
-
|
|
153077
|
-
|
|
153078
|
-
|
|
153079
|
-
|
|
153080
|
-
|
|
153081
|
-
|
|
153082
|
-
|
|
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
|
-
|
|
153662
|
+
}, [visualOrderSessions.length, selectedIndex]);
|
|
153663
|
+
const showStatus = import_react69.useCallback((msg) => {
|
|
153664
|
+
setStatusMessage(msg);
|
|
153665
|
+
setTimeout(() => setStatusMessage(""), 2000);
|
|
153091
153666
|
}, []);
|
|
153092
|
-
const
|
|
153093
|
-
|
|
153094
|
-
|
|
153095
|
-
|
|
153096
|
-
|
|
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
|
-
|
|
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 === "
|
|
153118
|
-
|
|
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 === "
|
|
153122
|
-
|
|
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 === "
|
|
153126
|
-
const selected =
|
|
153716
|
+
if (key.ctrl && key.name === "d" && visualOrderSessions.length > 0) {
|
|
153717
|
+
const selected = visualOrderSessions[selectedIndex];
|
|
153127
153718
|
if (selected) {
|
|
153128
|
-
|
|
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 (
|
|
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: "
|
|
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
|
|
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 /
|
|
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: "
|
|
153779
|
+
children: "Sessions"
|
|
153179
153780
|
}, undefined, false, undefined, this),
|
|
153180
153781
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153181
153782
|
fg: dimText13,
|
|
153182
|
-
children: "
|
|
153783
|
+
children: "Browse and reopen previous pentest sessions"
|
|
153183
153784
|
}, undefined, false, undefined, this),
|
|
153184
153785
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
153185
|
-
|
|
153186
|
-
|
|
153187
|
-
|
|
153188
|
-
|
|
153189
|
-
|
|
153190
|
-
|
|
153191
|
-
|
|
153192
|
-
|
|
153193
|
-
|
|
153194
|
-
|
|
153195
|
-
|
|
153196
|
-
|
|
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
|
-
|
|
153235
|
-
|
|
153236
|
-
|
|
153237
|
-
|
|
153238
|
-
|
|
153239
|
-
|
|
153240
|
-
|
|
153241
|
-
|
|
153242
|
-
|
|
153243
|
-
|
|
153244
|
-
|
|
153245
|
-
|
|
153246
|
-
|
|
153247
|
-
|
|
153248
|
-
|
|
153249
|
-
|
|
153250
|
-
|
|
153251
|
-
|
|
153252
|
-
|
|
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("
|
|
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
|
-
|
|
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
|
-
},
|
|
153265
|
-
|
|
153266
|
-
}, undefined,
|
|
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
|
|
153920
|
+
var import_react75 = __toESM(require_react(), 1);
|
|
153277
153921
|
// src/tui/components/commands/provider-selection.tsx
|
|
153278
|
-
var
|
|
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] =
|
|
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
|
|
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] =
|
|
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] =
|
|
153558
|
-
const [selectedProvider, setSelectedProvider] =
|
|
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
|
|
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
|
-
|
|
153638
|
-
if (
|
|
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
|
|
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] =
|
|
153863
|
-
const [showDetail, setShowDetail] =
|
|
153864
|
-
const scrollboxRef =
|
|
153865
|
-
const commandsByCategory =
|
|
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 =
|
|
154520
|
+
const flatCommands = import_react79.useMemo(() => {
|
|
153877
154521
|
return commands2;
|
|
153878
154522
|
}, [commands2]);
|
|
153879
|
-
|
|
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
|
-
|
|
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
|
|
154980
|
+
var import_react86 = __toESM(require_react(), 1);
|
|
154337
154981
|
|
|
154338
154982
|
// src/tui/keybindings/keybind.tsx
|
|
154339
|
-
var
|
|
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 =
|
|
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 =
|
|
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] =
|
|
154839
|
-
const [cwd, setCwd] =
|
|
154840
|
-
const [ctrlCPressTime, setCtrlCPressTime] =
|
|
154841
|
-
const [showExitWarning, setShowExitWarning] =
|
|
154842
|
-
const [inputKey, setInputKey] =
|
|
154843
|
-
const [showSessionsDialog, setShowSessionsDialog] =
|
|
154844
|
-
const [showShortcutsDialog, setShowShortcutsDialog] =
|
|
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
|
-
|
|
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: "
|
|
155046
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(
|
|
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;
|