@pensar/apex 0.0.57 → 0.0.58-canary.b0e3654f
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 +1145 -529
- 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", {
|
|
@@ -145902,6 +145999,319 @@ function ToolsPanel({
|
|
|
145902
145999
|
}, undefined, false, undefined, this);
|
|
145903
146000
|
}
|
|
145904
146001
|
|
|
146002
|
+
// src/core/session/loader.ts
|
|
146003
|
+
import { join as join15 } from "path";
|
|
146004
|
+
import { existsSync as existsSync20, readdirSync as readdirSync5, readFileSync as readFileSync11 } from "fs";
|
|
146005
|
+
function convertMessagesToUI(messages, baseTime) {
|
|
146006
|
+
const uiMessages = [];
|
|
146007
|
+
let messageIndex = 0;
|
|
146008
|
+
const toolResults = new Map;
|
|
146009
|
+
for (const msg of messages) {
|
|
146010
|
+
if (Array.isArray(msg.content)) {
|
|
146011
|
+
for (const part of msg.content) {
|
|
146012
|
+
if (part.type === "tool-result" && part.toolCallId) {
|
|
146013
|
+
toolResults.set(part.toolCallId, part.output);
|
|
146014
|
+
}
|
|
146015
|
+
}
|
|
146016
|
+
}
|
|
146017
|
+
}
|
|
146018
|
+
for (const msg of messages) {
|
|
146019
|
+
const createdAt = new Date(baseTime.getTime() + messageIndex * 1000);
|
|
146020
|
+
messageIndex++;
|
|
146021
|
+
if (typeof msg.content === "string") {
|
|
146022
|
+
uiMessages.push({
|
|
146023
|
+
role: msg.role,
|
|
146024
|
+
content: msg.content,
|
|
146025
|
+
createdAt
|
|
146026
|
+
});
|
|
146027
|
+
} else if (Array.isArray(msg.content)) {
|
|
146028
|
+
for (const part of msg.content) {
|
|
146029
|
+
if (part.type === "text" && part.text) {
|
|
146030
|
+
uiMessages.push({
|
|
146031
|
+
role: "assistant",
|
|
146032
|
+
content: part.text,
|
|
146033
|
+
createdAt
|
|
146034
|
+
});
|
|
146035
|
+
} else if (part.type === "tool-call") {
|
|
146036
|
+
const toolDescription = typeof part.input?.toolCallDescription === "string" ? part.input.toolCallDescription : part.toolName || "tool";
|
|
146037
|
+
const result = part.toolCallId ? toolResults.get(part.toolCallId) : undefined;
|
|
146038
|
+
uiMessages.push({
|
|
146039
|
+
role: "tool",
|
|
146040
|
+
content: toolDescription,
|
|
146041
|
+
createdAt,
|
|
146042
|
+
toolCallId: part.toolCallId,
|
|
146043
|
+
toolName: part.toolName,
|
|
146044
|
+
args: part.input,
|
|
146045
|
+
result,
|
|
146046
|
+
status: "completed"
|
|
146047
|
+
});
|
|
146048
|
+
}
|
|
146049
|
+
}
|
|
146050
|
+
}
|
|
146051
|
+
}
|
|
146052
|
+
return uiMessages;
|
|
146053
|
+
}
|
|
146054
|
+
function parseSubagentFilename(filename) {
|
|
146055
|
+
if (filename.startsWith("attack-surface-agent")) {
|
|
146056
|
+
return { agentType: "attack-surface", name: "Attack Surface Discovery" };
|
|
146057
|
+
}
|
|
146058
|
+
if (filename.startsWith("vuln-test-")) {
|
|
146059
|
+
const parts = filename.replace("vuln-test-", "").split("-");
|
|
146060
|
+
const vulnClass = parts[0] || "generic";
|
|
146061
|
+
const vulnClassFormatted = vulnClass.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
146062
|
+
return {
|
|
146063
|
+
agentType: "pentest",
|
|
146064
|
+
name: `${vulnClassFormatted} Test`
|
|
146065
|
+
};
|
|
146066
|
+
}
|
|
146067
|
+
if (filename.startsWith("orchestrator-")) {
|
|
146068
|
+
return { agentType: "pentest", name: "Orchestrator Summary" };
|
|
146069
|
+
}
|
|
146070
|
+
return { agentType: "pentest", name: filename.split("-")[0] || "Unknown" };
|
|
146071
|
+
}
|
|
146072
|
+
function loadSubagents(rootPath) {
|
|
146073
|
+
const subagentsPath = join15(rootPath, "subagents");
|
|
146074
|
+
if (!existsSync20(subagentsPath)) {
|
|
146075
|
+
return [];
|
|
146076
|
+
}
|
|
146077
|
+
const subagents = [];
|
|
146078
|
+
const files = readdirSync5(subagentsPath).filter((f) => f.endsWith(".json"));
|
|
146079
|
+
files.sort((a, b2) => {
|
|
146080
|
+
const timeA = a.match(/\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}/)?.[0] || "";
|
|
146081
|
+
const timeB = b2.match(/\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}/)?.[0] || "";
|
|
146082
|
+
return timeA.localeCompare(timeB);
|
|
146083
|
+
});
|
|
146084
|
+
for (const file2 of files) {
|
|
146085
|
+
try {
|
|
146086
|
+
const filePath = join15(subagentsPath, file2);
|
|
146087
|
+
const data = JSON.parse(readFileSync11(filePath, "utf-8"));
|
|
146088
|
+
const { agentType, name: name39 } = parseSubagentFilename(file2);
|
|
146089
|
+
const timestamp = new Date(data.timestamp);
|
|
146090
|
+
if (file2.startsWith("orchestrator-")) {
|
|
146091
|
+
continue;
|
|
146092
|
+
}
|
|
146093
|
+
const messages = convertMessagesToUI(data.messages, timestamp);
|
|
146094
|
+
let status = "completed";
|
|
146095
|
+
switch (data.status) {
|
|
146096
|
+
case "canceled":
|
|
146097
|
+
case "failed":
|
|
146098
|
+
case "completed":
|
|
146099
|
+
case "pending":
|
|
146100
|
+
status = data.status;
|
|
146101
|
+
break;
|
|
146102
|
+
default:
|
|
146103
|
+
if (typeof data.findingsCount === "number" && data.findingsCount < 0) {
|
|
146104
|
+
status = "failed";
|
|
146105
|
+
}
|
|
146106
|
+
break;
|
|
146107
|
+
}
|
|
146108
|
+
subagents.push({
|
|
146109
|
+
id: `loaded-${file2.replace(".json", "")}`,
|
|
146110
|
+
name: data.agentName === "attack-surface-agent" ? "Attack Surface Discovery" : name39,
|
|
146111
|
+
type: agentType,
|
|
146112
|
+
target: data.target || "Unknown",
|
|
146113
|
+
messages,
|
|
146114
|
+
createdAt: timestamp,
|
|
146115
|
+
status
|
|
146116
|
+
});
|
|
146117
|
+
} catch (e) {
|
|
146118
|
+
console.error(`Failed to load subagent file ${file2}:`, e);
|
|
146119
|
+
}
|
|
146120
|
+
}
|
|
146121
|
+
return subagents;
|
|
146122
|
+
}
|
|
146123
|
+
function loadAttackSurfaceResults2(rootPath) {
|
|
146124
|
+
const resultsPath = join15(rootPath, "attack-surface-results.json");
|
|
146125
|
+
if (!existsSync20(resultsPath)) {
|
|
146126
|
+
return null;
|
|
146127
|
+
}
|
|
146128
|
+
try {
|
|
146129
|
+
return JSON.parse(readFileSync11(resultsPath, "utf-8"));
|
|
146130
|
+
} catch (e) {
|
|
146131
|
+
console.error("Failed to load attack surface results:", e);
|
|
146132
|
+
return null;
|
|
146133
|
+
}
|
|
146134
|
+
}
|
|
146135
|
+
function hasReport(rootPath) {
|
|
146136
|
+
const reportPath = join15(rootPath, "comprehensive-pentest-report.md");
|
|
146137
|
+
return existsSync20(reportPath);
|
|
146138
|
+
}
|
|
146139
|
+
function createDiscoveryFromLogs(rootPath, session) {
|
|
146140
|
+
const logPath = join15(rootPath, "logs", "streamlined-pentest.log");
|
|
146141
|
+
if (!existsSync20(logPath)) {
|
|
146142
|
+
return null;
|
|
146143
|
+
}
|
|
146144
|
+
try {
|
|
146145
|
+
const logContent = readFileSync11(logPath, "utf-8");
|
|
146146
|
+
const lines = logContent.split(`
|
|
146147
|
+
`).filter(Boolean);
|
|
146148
|
+
const messages = [];
|
|
146149
|
+
let stepBuffer = "";
|
|
146150
|
+
for (const line of lines) {
|
|
146151
|
+
const match = line.match(/^(\d{4}-\d{2}-\d{2}T[\d:.]+Z) - \[(\w+)\] (.+)$/);
|
|
146152
|
+
if (!match)
|
|
146153
|
+
continue;
|
|
146154
|
+
const [, timestamp, level, content] = match;
|
|
146155
|
+
const createdAt = new Date(timestamp);
|
|
146156
|
+
if (content.startsWith("[Tool]")) {
|
|
146157
|
+
const toolMatch = content.match(/\[Tool\] (\w+): (.+)/);
|
|
146158
|
+
if (toolMatch) {
|
|
146159
|
+
messages.push({
|
|
146160
|
+
role: "tool",
|
|
146161
|
+
content: `✓ ${toolMatch[2]}`,
|
|
146162
|
+
createdAt,
|
|
146163
|
+
toolName: toolMatch[1],
|
|
146164
|
+
status: "completed"
|
|
146165
|
+
});
|
|
146166
|
+
}
|
|
146167
|
+
} else if (content.startsWith("[Step")) {
|
|
146168
|
+
const stepMatch = content.match(/\[Step \d+\] (.+)/);
|
|
146169
|
+
if (stepMatch) {
|
|
146170
|
+
messages.push({
|
|
146171
|
+
role: "assistant",
|
|
146172
|
+
content: stepMatch[1],
|
|
146173
|
+
createdAt
|
|
146174
|
+
});
|
|
146175
|
+
}
|
|
146176
|
+
}
|
|
146177
|
+
}
|
|
146178
|
+
if (messages.length === 0) {
|
|
146179
|
+
return null;
|
|
146180
|
+
}
|
|
146181
|
+
return {
|
|
146182
|
+
id: "discovery-from-logs",
|
|
146183
|
+
name: "Attack Surface Discovery",
|
|
146184
|
+
type: "attack-surface",
|
|
146185
|
+
target: session.targets[0] || "Unknown",
|
|
146186
|
+
messages,
|
|
146187
|
+
createdAt: new Date(session.time.created),
|
|
146188
|
+
status: "completed"
|
|
146189
|
+
};
|
|
146190
|
+
} catch (e) {
|
|
146191
|
+
console.error("Failed to parse logs:", e);
|
|
146192
|
+
return null;
|
|
146193
|
+
}
|
|
146194
|
+
}
|
|
146195
|
+
async function loadSessionState(session) {
|
|
146196
|
+
const rootPath = session.rootPath;
|
|
146197
|
+
let subagents = loadSubagents(rootPath);
|
|
146198
|
+
const hasAttackSurfaceAgent = subagents.some((s) => s.type === "attack-surface");
|
|
146199
|
+
if (!hasAttackSurfaceAgent) {
|
|
146200
|
+
const discoveryAgent = createDiscoveryFromLogs(rootPath, session);
|
|
146201
|
+
if (discoveryAgent) {
|
|
146202
|
+
subagents = [discoveryAgent, ...subagents];
|
|
146203
|
+
}
|
|
146204
|
+
}
|
|
146205
|
+
const manifestPath = join15(rootPath, "agent-manifest.json");
|
|
146206
|
+
if (existsSync20(manifestPath)) {
|
|
146207
|
+
try {
|
|
146208
|
+
const manifest = JSON.parse(readFileSync11(manifestPath, "utf-8"));
|
|
146209
|
+
for (const entry of manifest) {
|
|
146210
|
+
if (entry.status !== "running")
|
|
146211
|
+
continue;
|
|
146212
|
+
const resumeInfo = {
|
|
146213
|
+
target: entry.target,
|
|
146214
|
+
objective: entry.objective,
|
|
146215
|
+
vulnerabilityClass: entry.vulnerabilityClass,
|
|
146216
|
+
authenticationInfo: entry.authInfo
|
|
146217
|
+
};
|
|
146218
|
+
const vulnSlug = entry.vulnerabilityClass.toLowerCase().replace(/\s+/g, "-");
|
|
146219
|
+
const existingIndex = subagents.findIndex((s) => s.type === "pentest" && s.id.includes(`-${vulnSlug}-`) && s.target === entry.target);
|
|
146220
|
+
if (existingIndex >= 0) {
|
|
146221
|
+
subagents[existingIndex] = {
|
|
146222
|
+
...subagents[existingIndex],
|
|
146223
|
+
status: "paused",
|
|
146224
|
+
resumeInfo
|
|
146225
|
+
};
|
|
146226
|
+
} else {
|
|
146227
|
+
let messages = [];
|
|
146228
|
+
const subagentsPath = join15(rootPath, "subagents");
|
|
146229
|
+
if (existsSync20(subagentsPath)) {
|
|
146230
|
+
try {
|
|
146231
|
+
const files = readdirSync5(subagentsPath).filter((f) => f.endsWith(".json"));
|
|
146232
|
+
const matchingFile = files.find((f) => {
|
|
146233
|
+
if (vulnSlug && f.includes(vulnSlug))
|
|
146234
|
+
return true;
|
|
146235
|
+
return false;
|
|
146236
|
+
});
|
|
146237
|
+
if (matchingFile) {
|
|
146238
|
+
const data = JSON.parse(readFileSync11(join15(subagentsPath, matchingFile), "utf-8"));
|
|
146239
|
+
messages = convertMessagesToUI(data.messages, new Date(entry.spawnedAt));
|
|
146240
|
+
}
|
|
146241
|
+
} catch {}
|
|
146242
|
+
}
|
|
146243
|
+
subagents.push({
|
|
146244
|
+
id: entry.id,
|
|
146245
|
+
name: entry.name,
|
|
146246
|
+
type: "pentest",
|
|
146247
|
+
target: entry.target,
|
|
146248
|
+
messages,
|
|
146249
|
+
createdAt: new Date(entry.spawnedAt),
|
|
146250
|
+
status: "paused",
|
|
146251
|
+
resumeInfo
|
|
146252
|
+
});
|
|
146253
|
+
}
|
|
146254
|
+
}
|
|
146255
|
+
} catch (e) {
|
|
146256
|
+
console.error("Failed to load agent manifest:", e);
|
|
146257
|
+
}
|
|
146258
|
+
}
|
|
146259
|
+
const attackSurfaceResults = loadAttackSurfaceResults2(rootPath);
|
|
146260
|
+
const hasReportFile = hasReport(rootPath);
|
|
146261
|
+
const hasDiscoverySubagent = subagents.some((s) => s.type === "attack-surface");
|
|
146262
|
+
const interruptedDuringDiscovery = !attackSurfaceResults && !hasReportFile && hasDiscoverySubagent;
|
|
146263
|
+
if (interruptedDuringDiscovery) {
|
|
146264
|
+
for (let i = 0;i < subagents.length; i++) {
|
|
146265
|
+
if (subagents[i].type === "attack-surface" && subagents[i].status === "completed") {
|
|
146266
|
+
subagents[i] = { ...subagents[i], status: "paused" };
|
|
146267
|
+
}
|
|
146268
|
+
}
|
|
146269
|
+
}
|
|
146270
|
+
const isComplete = hasReportFile || attackSurfaceResults?.summary?.analysisComplete === true && subagents.length > 1;
|
|
146271
|
+
return {
|
|
146272
|
+
session,
|
|
146273
|
+
subagents,
|
|
146274
|
+
attackSurfaceResults,
|
|
146275
|
+
isComplete,
|
|
146276
|
+
hasReport: hasReportFile,
|
|
146277
|
+
interruptedDuringDiscovery
|
|
146278
|
+
};
|
|
146279
|
+
}
|
|
146280
|
+
|
|
146281
|
+
// src/tui/session/swarm-to-operator-adapter.ts
|
|
146282
|
+
function adaptSwarmStateForOperator(state) {
|
|
146283
|
+
const messages = [];
|
|
146284
|
+
messages.push({
|
|
146285
|
+
role: "system",
|
|
146286
|
+
content: `Resuming from auto-mode session. ${state.subagents.length} subagent(s) ran. ${state.hasReport ? "Report available." : ""}`,
|
|
146287
|
+
createdAt: new Date
|
|
146288
|
+
});
|
|
146289
|
+
for (const sub of state.subagents) {
|
|
146290
|
+
const assistantMsgs = sub.messages.filter((m2) => m2.role === "assistant" && typeof m2.content === "string" && m2.content.trim());
|
|
146291
|
+
const lastSummary = assistantMsgs[assistantMsgs.length - 1];
|
|
146292
|
+
if (lastSummary) {
|
|
146293
|
+
messages.push({
|
|
146294
|
+
role: "assistant",
|
|
146295
|
+
content: `[${sub.name}] ${lastSummary.content}`,
|
|
146296
|
+
createdAt: lastSummary.createdAt
|
|
146297
|
+
});
|
|
146298
|
+
}
|
|
146299
|
+
}
|
|
146300
|
+
const attackSurface = [];
|
|
146301
|
+
if (state.attackSurfaceResults?.targets) {
|
|
146302
|
+
for (const target of state.attackSurfaceResults.targets) {
|
|
146303
|
+
attackSurface.push({
|
|
146304
|
+
id: `synth-${attackSurface.length}`,
|
|
146305
|
+
method: "GET",
|
|
146306
|
+
path: target.target,
|
|
146307
|
+
status: "discovered",
|
|
146308
|
+
category: target.objective || "unknown"
|
|
146309
|
+
});
|
|
146310
|
+
}
|
|
146311
|
+
}
|
|
146312
|
+
return { messages, attackSurface };
|
|
146313
|
+
}
|
|
146314
|
+
|
|
145905
146315
|
// src/tui/components/chat/header.tsx
|
|
145906
146316
|
function Header({
|
|
145907
146317
|
mode,
|
|
@@ -147220,6 +147630,7 @@ function SessionComponent({
|
|
|
147220
147630
|
mode,
|
|
147221
147631
|
model: propModel,
|
|
147222
147632
|
isResume = false,
|
|
147633
|
+
openAsOperator = false,
|
|
147223
147634
|
initialDirective,
|
|
147224
147635
|
onExit
|
|
147225
147636
|
}) {
|
|
@@ -147301,7 +147712,7 @@ function SessionComponent({
|
|
|
147301
147712
|
import_react46.useEffect(() => {
|
|
147302
147713
|
if (!isResume || resumeLoaded)
|
|
147303
147714
|
return;
|
|
147304
|
-
Session.loadOperatorState(session.id).then((savedState) => {
|
|
147715
|
+
Session.loadOperatorState(session.id).then(async (savedState) => {
|
|
147305
147716
|
if (savedState) {
|
|
147306
147717
|
setOperatorMode(savedState.mode);
|
|
147307
147718
|
setAutoApproveTier(savedState.autoApproveTier);
|
|
@@ -147322,10 +147733,15 @@ function SessionComponent({
|
|
|
147322
147733
|
const history = savedState.actionHistory || [];
|
|
147323
147734
|
setApprovedCount(history.filter((a) => a.decision === "approved" || a.decision === "auto-approved").length);
|
|
147324
147735
|
setDeniedCount(history.filter((a) => a.decision === "denied").length);
|
|
147736
|
+
} else if (openAsOperator) {
|
|
147737
|
+
const swarmState = await loadSessionState(session);
|
|
147738
|
+
const { messages: synthMessages, attackSurface } = adaptSwarmStateForOperator(swarmState);
|
|
147739
|
+
setMessages(synthMessages);
|
|
147740
|
+
sidebar.updateState({ attackSurface });
|
|
147325
147741
|
}
|
|
147326
147742
|
setResumeLoaded(true);
|
|
147327
147743
|
});
|
|
147328
|
-
}, [isResume, session.id, resumeLoaded, setMessages, sidebar]);
|
|
147744
|
+
}, [isResume, session.id, resumeLoaded, setMessages, sidebar, openAsOperator]);
|
|
147329
147745
|
import_react46.useEffect(() => {
|
|
147330
147746
|
if (agent2)
|
|
147331
147747
|
return;
|
|
@@ -147800,228 +148216,14 @@ Usage: /tier <1-5>`,
|
|
|
147800
148216
|
}
|
|
147801
148217
|
|
|
147802
148218
|
// src/tui/components/operator-dashboard/index.tsx
|
|
147803
|
-
function OperatorDashboard({ session, isResume = false }) {
|
|
148219
|
+
function OperatorDashboard({ session, isResume = false, openAsOperator }) {
|
|
147804
148220
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SessionComponent, {
|
|
147805
148221
|
session,
|
|
147806
148222
|
mode: "operator",
|
|
147807
|
-
isResume
|
|
148223
|
+
isResume,
|
|
148224
|
+
openAsOperator
|
|
147808
148225
|
}, undefined, false, undefined, this);
|
|
147809
148226
|
}
|
|
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
148227
|
// src/core/agent/metaTestingAgent/prompts/execution.ts
|
|
148026
148228
|
var OUTCOME_GUIDANCE_TEMPLATE2 = `{{OUTCOME_GUIDANCE}}`;
|
|
148027
148229
|
var META_TESTING_SYSTEM_PROMPT = `# Meta Testing Agent
|
|
@@ -148473,7 +148675,9 @@ async function runPentestOrchestrator(input) {
|
|
|
148473
148675
|
id: agentId,
|
|
148474
148676
|
name: `${getVulnerabilityClassName(task.vulnClass)} on ${task.target}`,
|
|
148475
148677
|
target: task.target,
|
|
148476
|
-
vulnerabilityClass: task.vulnClass
|
|
148678
|
+
vulnerabilityClass: task.vulnClass,
|
|
148679
|
+
objective: task.objective,
|
|
148680
|
+
authenticationInfo: task.authenticationInfo
|
|
148477
148681
|
});
|
|
148478
148682
|
try {
|
|
148479
148683
|
const result = await runMetaVulnerabilityTestAgent({
|
|
@@ -149154,7 +149358,8 @@ async function runStreamlinedPentest(input) {
|
|
|
149154
149358
|
onPentestAgentComplete,
|
|
149155
149359
|
onAgentAbortControllerCreated,
|
|
149156
149360
|
abortSignal,
|
|
149157
|
-
toolOverride
|
|
149361
|
+
toolOverride,
|
|
149362
|
+
previousDiscoveryResults
|
|
149158
149363
|
} = input;
|
|
149159
149364
|
const session = input.session || await Session.create({
|
|
149160
149365
|
targets: [target],
|
|
@@ -149162,36 +149367,62 @@ async function runStreamlinedPentest(input) {
|
|
|
149162
149367
|
...sessionConfig
|
|
149163
149368
|
});
|
|
149164
149369
|
const logger = new Logger(session, "streamlined-pentest.log");
|
|
149370
|
+
const manifestPath = join18(session.rootPath, "agent-manifest.json");
|
|
149371
|
+
const manifest = (() => {
|
|
149372
|
+
if (!existsSync23(manifestPath))
|
|
149373
|
+
return [];
|
|
149374
|
+
try {
|
|
149375
|
+
return JSON.parse(readFileSync13(manifestPath, "utf-8"));
|
|
149376
|
+
} catch (e) {
|
|
149377
|
+
logger.warn(`Failed to read agent manifest at ${manifestPath}: ${e}`);
|
|
149378
|
+
return [];
|
|
149379
|
+
}
|
|
149380
|
+
})();
|
|
149381
|
+
function flushManifest() {
|
|
149382
|
+
writeFileSync15(manifestPath, JSON.stringify(manifest, null, 2));
|
|
149383
|
+
}
|
|
149165
149384
|
logger.info(`Starting streamlined pentest for ${target}`);
|
|
149166
149385
|
const reportProgress = (status) => {
|
|
149167
149386
|
logger.info(`[${status.phase}] ${status.message}`);
|
|
149168
149387
|
onProgress?.(status);
|
|
149169
149388
|
};
|
|
149170
149389
|
try {
|
|
149171
|
-
|
|
149172
|
-
|
|
149173
|
-
|
|
149174
|
-
|
|
149175
|
-
|
|
149176
|
-
|
|
149177
|
-
|
|
149178
|
-
|
|
149179
|
-
|
|
149180
|
-
|
|
149181
|
-
|
|
149182
|
-
|
|
149183
|
-
|
|
149184
|
-
|
|
149185
|
-
|
|
149186
|
-
|
|
149187
|
-
|
|
149188
|
-
return {
|
|
149189
|
-
success: false,
|
|
149390
|
+
let targets;
|
|
149391
|
+
if (previousDiscoveryResults) {
|
|
149392
|
+
logger.info(`Resuming with ${previousDiscoveryResults.targets?.length || 0} previously discovered targets`);
|
|
149393
|
+
targets = previousDiscoveryResults.targets || [];
|
|
149394
|
+
reportProgress({
|
|
149395
|
+
phase: "discovery",
|
|
149396
|
+
message: `Resuming with ${targets.length} previously discovered targets`,
|
|
149397
|
+
targetsDiscovered: targets.length
|
|
149398
|
+
});
|
|
149399
|
+
} else {
|
|
149400
|
+
reportProgress({
|
|
149401
|
+
phase: "discovery",
|
|
149402
|
+
message: `Discovering attack surface for ${target}`
|
|
149403
|
+
});
|
|
149404
|
+
const discoveryResult = await runDiscoveryPhase({
|
|
149405
|
+
target,
|
|
149406
|
+
model,
|
|
149190
149407
|
session,
|
|
149191
|
-
|
|
149192
|
-
|
|
149193
|
-
|
|
149194
|
-
|
|
149408
|
+
authConfig,
|
|
149409
|
+
abortSignal,
|
|
149410
|
+
toolOverride,
|
|
149411
|
+
logger,
|
|
149412
|
+
onProgress: reportProgress,
|
|
149413
|
+
onStepFinish: onDiscoveryStepFinish,
|
|
149414
|
+
onStream: onDiscoveryStream
|
|
149415
|
+
});
|
|
149416
|
+
if (discoveryResult.discoveryError) {
|
|
149417
|
+
return {
|
|
149418
|
+
success: false,
|
|
149419
|
+
session,
|
|
149420
|
+
targets: [],
|
|
149421
|
+
totalFindings: 0,
|
|
149422
|
+
error: discoveryResult.discoveryError
|
|
149423
|
+
};
|
|
149424
|
+
}
|
|
149425
|
+
targets = discoveryResult.targets;
|
|
149195
149426
|
}
|
|
149196
149427
|
if (targets.length === 0) {
|
|
149197
149428
|
reportProgress({
|
|
@@ -149236,7 +149467,20 @@ async function runStreamlinedPentest(input) {
|
|
|
149236
149467
|
findingsCount: status.findingsCount
|
|
149237
149468
|
});
|
|
149238
149469
|
},
|
|
149239
|
-
onAgentSpawn:
|
|
149470
|
+
onAgentSpawn: (info) => {
|
|
149471
|
+
manifest.push({
|
|
149472
|
+
id: info.id,
|
|
149473
|
+
name: info.name,
|
|
149474
|
+
target: info.target,
|
|
149475
|
+
vulnerabilityClass: info.vulnerabilityClass,
|
|
149476
|
+
objective: info.objective,
|
|
149477
|
+
authInfo: info.authenticationInfo,
|
|
149478
|
+
status: "running",
|
|
149479
|
+
spawnedAt: new Date().toISOString()
|
|
149480
|
+
});
|
|
149481
|
+
flushManifest();
|
|
149482
|
+
onPentestAgentSpawn?.(info);
|
|
149483
|
+
},
|
|
149240
149484
|
onAgentStream: onPentestAgentStream,
|
|
149241
149485
|
onAgentComplete: onPentestAgentComplete,
|
|
149242
149486
|
onAgentAbortControllerCreated
|
|
@@ -149462,14 +149706,16 @@ async function runDiscoveryPhase(params) {
|
|
|
149462
149706
|
}
|
|
149463
149707
|
|
|
149464
149708
|
// src/tui/components/session-view/index.tsx
|
|
149465
|
-
import { existsSync as existsSync24 } from "fs";
|
|
149709
|
+
import { existsSync as existsSync24, readFileSync as readFileSync14 } from "fs";
|
|
149466
149710
|
import { exec as exec3 } from "child_process";
|
|
149711
|
+
import { join as join19 } from "path";
|
|
149467
149712
|
var greenBullet6 = RGBA.fromInts(76, 175, 80, 255);
|
|
149468
149713
|
var creamText6 = RGBA.fromInts(255, 248, 220, 255);
|
|
149469
149714
|
var dimText7 = RGBA.fromInts(120, 120, 120, 255);
|
|
149470
149715
|
function SessionView({
|
|
149471
149716
|
sessionId,
|
|
149472
|
-
isResume = false
|
|
149717
|
+
isResume = false,
|
|
149718
|
+
openAsOperator = false
|
|
149473
149719
|
}) {
|
|
149474
149720
|
const route = useRoute();
|
|
149475
149721
|
const { model, setThinking, isExecuting, addTokenUsage, setIsExecuting } = useAgent();
|
|
@@ -149482,6 +149728,8 @@ function SessionView({
|
|
|
149482
149728
|
const [startTime, setStartTime] = import_react48.useState(null);
|
|
149483
149729
|
const [hasStarted, setHasStarted] = import_react48.useState(false);
|
|
149484
149730
|
const agentAbortControllers = import_react48.useRef(new Map);
|
|
149731
|
+
const subagentsRef = import_react48.useRef(subagents);
|
|
149732
|
+
subagentsRef.current = subagents;
|
|
149485
149733
|
const killAgent = import_react48.useCallback((agentId) => {
|
|
149486
149734
|
const controller = agentAbortControllers.current.get(agentId);
|
|
149487
149735
|
if (controller) {
|
|
@@ -149524,12 +149772,19 @@ function SessionView({
|
|
|
149524
149772
|
target: s.target,
|
|
149525
149773
|
messages: s.messages,
|
|
149526
149774
|
createdAt: s.createdAt,
|
|
149527
|
-
status: s.status
|
|
149775
|
+
status: s.status,
|
|
149776
|
+
resumeInfo: s.resumeInfo
|
|
149528
149777
|
}));
|
|
149529
149778
|
setSubagents(loadedSubagents);
|
|
149530
|
-
setIsCompleted(state.hasReport);
|
|
149531
149779
|
setStartTime(new Date(loadedSession.time.created));
|
|
149532
|
-
|
|
149780
|
+
if (state.hasReport) {
|
|
149781
|
+
setIsCompleted(true);
|
|
149782
|
+
setHasStarted(true);
|
|
149783
|
+
} else if (state.attackSurfaceResults) {
|
|
149784
|
+
setHasStarted(true);
|
|
149785
|
+
} else if (state.interruptedDuringDiscovery) {
|
|
149786
|
+
setHasStarted(true);
|
|
149787
|
+
}
|
|
149533
149788
|
} catch (e) {
|
|
149534
149789
|
console.error("Failed to load session state:", e);
|
|
149535
149790
|
}
|
|
@@ -149543,15 +149798,14 @@ function SessionView({
|
|
|
149543
149798
|
loadSession();
|
|
149544
149799
|
}, [sessionId, isResume]);
|
|
149545
149800
|
import_react48.useEffect(() => {
|
|
149546
|
-
if (session && !hasStarted && !loading
|
|
149801
|
+
if (session && !hasStarted && !loading) {
|
|
149547
149802
|
const mode = session.config?.mode;
|
|
149548
|
-
if (mode === "operator" || mode === "driver")
|
|
149803
|
+
if (mode === "operator" || mode === "driver" || openAsOperator)
|
|
149549
149804
|
return;
|
|
149550
|
-
}
|
|
149551
149805
|
setHasStarted(true);
|
|
149552
149806
|
startPentest(session);
|
|
149553
149807
|
}
|
|
149554
|
-
}, [session, hasStarted, loading,
|
|
149808
|
+
}, [session, hasStarted, loading, openAsOperator]);
|
|
149555
149809
|
import_react48.useEffect(() => {
|
|
149556
149810
|
return () => {
|
|
149557
149811
|
if (abortController) {
|
|
@@ -149559,7 +149813,7 @@ function SessionView({
|
|
|
149559
149813
|
}
|
|
149560
149814
|
};
|
|
149561
149815
|
}, [abortController]);
|
|
149562
|
-
const startPentest = import_react48.useCallback(async (execSession) => {
|
|
149816
|
+
const startPentest = import_react48.useCallback(async (execSession, previousDiscoveryResults) => {
|
|
149563
149817
|
setIsExecuting(true);
|
|
149564
149818
|
setThinking(true);
|
|
149565
149819
|
setStartTime(new Date);
|
|
@@ -149568,23 +149822,36 @@ function SessionView({
|
|
|
149568
149822
|
let currentDiscoveryText = "";
|
|
149569
149823
|
const pentestAgentTexts = new Map;
|
|
149570
149824
|
try {
|
|
149571
|
-
setSubagents(
|
|
149572
|
-
|
|
149573
|
-
|
|
149574
|
-
|
|
149575
|
-
|
|
149576
|
-
|
|
149577
|
-
|
|
149578
|
-
|
|
149579
|
-
|
|
149825
|
+
setSubagents((prev) => {
|
|
149826
|
+
const existingIdx = prev.findIndex((s) => s.id === "attack-surface-discovery");
|
|
149827
|
+
if (existingIdx !== -1) {
|
|
149828
|
+
const updated = [...prev];
|
|
149829
|
+
updated[existingIdx] = {
|
|
149830
|
+
...updated[existingIdx],
|
|
149831
|
+
status: previousDiscoveryResults ? "completed" : "pending"
|
|
149832
|
+
};
|
|
149833
|
+
return updated;
|
|
149580
149834
|
}
|
|
149581
|
-
|
|
149835
|
+
return [
|
|
149836
|
+
...prev,
|
|
149837
|
+
{
|
|
149838
|
+
id: "attack-surface-discovery",
|
|
149839
|
+
name: "Attack Surface Discovery",
|
|
149840
|
+
type: "attack-surface",
|
|
149841
|
+
target: execSession.targets[0],
|
|
149842
|
+
messages: [],
|
|
149843
|
+
status: "pending",
|
|
149844
|
+
createdAt: new Date
|
|
149845
|
+
}
|
|
149846
|
+
];
|
|
149847
|
+
});
|
|
149582
149848
|
const result = await runStreamlinedPentest({
|
|
149583
149849
|
target: execSession.targets[0],
|
|
149584
149850
|
model: model.id,
|
|
149585
149851
|
session: execSession,
|
|
149586
149852
|
sessionConfig: execSession.config,
|
|
149587
149853
|
abortSignal: controller.signal,
|
|
149854
|
+
previousDiscoveryResults,
|
|
149588
149855
|
onAgentAbortControllerCreated: (agentId, abortCtrl) => {
|
|
149589
149856
|
agentAbortControllers.current.set(agentId, abortCtrl);
|
|
149590
149857
|
},
|
|
@@ -149645,7 +149912,7 @@ function SessionView({
|
|
|
149645
149912
|
newMessages[msgIdx] = {
|
|
149646
149913
|
...existingMsg,
|
|
149647
149914
|
status: "completed",
|
|
149648
|
-
content:
|
|
149915
|
+
content: description,
|
|
149649
149916
|
result: tr.output
|
|
149650
149917
|
};
|
|
149651
149918
|
} else {
|
|
@@ -149749,7 +150016,7 @@ function SessionView({
|
|
|
149749
150016
|
newMessages[msgIdx] = {
|
|
149750
150017
|
...existingMsg,
|
|
149751
150018
|
status: "completed",
|
|
149752
|
-
content:
|
|
150019
|
+
content: description,
|
|
149753
150020
|
result: result2
|
|
149754
150021
|
};
|
|
149755
150022
|
} else {
|
|
@@ -149852,11 +150119,200 @@ function SessionView({
|
|
|
149852
150119
|
updated[idx] = { ...subagent, messages: newMessages };
|
|
149853
150120
|
return updated;
|
|
149854
150121
|
});
|
|
149855
|
-
} else if (event.type === "tool-result") {
|
|
149856
|
-
const tr = event.data;
|
|
150122
|
+
} else if (event.type === "tool-result") {
|
|
150123
|
+
const tr = event.data;
|
|
150124
|
+
const toolCallId = tr.toolCallId;
|
|
150125
|
+
const toolName = tr.toolName || "tool";
|
|
150126
|
+
const result2 = tr.output ?? tr.result;
|
|
150127
|
+
setSubagents((prev) => {
|
|
150128
|
+
const idx = prev.findIndex((s) => s.id === agentId);
|
|
150129
|
+
if (idx === -1)
|
|
150130
|
+
return prev;
|
|
150131
|
+
const updated = [...prev];
|
|
150132
|
+
const subagent = updated[idx];
|
|
150133
|
+
const newMessages = [...subagent.messages];
|
|
150134
|
+
const msgIdx = newMessages.findIndex((m2) => m2.role === "tool" && m2.toolCallId === toolCallId);
|
|
150135
|
+
if (msgIdx !== -1) {
|
|
150136
|
+
const existingMsg = newMessages[msgIdx];
|
|
150137
|
+
const description = typeof existingMsg.content === "string" && existingMsg.content !== existingMsg.toolName ? existingMsg.content : existingMsg.toolName || "tool";
|
|
150138
|
+
newMessages[msgIdx] = {
|
|
150139
|
+
...existingMsg,
|
|
150140
|
+
status: "completed",
|
|
150141
|
+
content: description,
|
|
150142
|
+
result: result2
|
|
150143
|
+
};
|
|
150144
|
+
} else {
|
|
150145
|
+
newMessages.push({
|
|
150146
|
+
role: "tool",
|
|
150147
|
+
status: "completed",
|
|
150148
|
+
toolCallId,
|
|
150149
|
+
toolName,
|
|
150150
|
+
content: `+ ${toolName}`,
|
|
150151
|
+
result: result2,
|
|
150152
|
+
createdAt: new Date
|
|
150153
|
+
});
|
|
150154
|
+
}
|
|
150155
|
+
updated[idx] = { ...subagent, messages: newMessages };
|
|
150156
|
+
return updated;
|
|
150157
|
+
});
|
|
150158
|
+
} else if (event.type === "step-finish" && event.data) {
|
|
150159
|
+
const { usage } = event.data;
|
|
150160
|
+
if (usage) {
|
|
150161
|
+
const stepTokens = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
|
|
150162
|
+
if (stepTokens > 0)
|
|
150163
|
+
addTokenUsage(usage.inputTokens ?? 0, usage.outputTokens ?? 0);
|
|
150164
|
+
}
|
|
150165
|
+
pentestAgentTexts.set(agentId, "");
|
|
150166
|
+
}
|
|
150167
|
+
},
|
|
150168
|
+
onPentestAgentComplete: (agentId, agentResult) => {
|
|
150169
|
+
setSubagents((prev) => prev.map((sub) => sub.id === agentId && sub.status !== "canceled" ? {
|
|
150170
|
+
...sub,
|
|
150171
|
+
status: agentResult.error ? "failed" : "completed",
|
|
150172
|
+
messages: [
|
|
150173
|
+
...sub.messages,
|
|
150174
|
+
{
|
|
150175
|
+
role: "assistant",
|
|
150176
|
+
content: `${agentResult.findingsCount > 0 ? "✅" : "⚪"} ${agentResult.summary}`,
|
|
150177
|
+
createdAt: new Date
|
|
150178
|
+
}
|
|
150179
|
+
]
|
|
150180
|
+
} : sub));
|
|
150181
|
+
},
|
|
150182
|
+
onProgress: (status) => {}
|
|
150183
|
+
});
|
|
150184
|
+
if (result.success) {
|
|
150185
|
+
if (result.reportPath && existsSync24(result.reportPath) || existsSync24(result.session.rootPath + "/comprehensive-pentest-report.md")) {
|
|
150186
|
+
setIsCompleted(true);
|
|
150187
|
+
}
|
|
150188
|
+
}
|
|
150189
|
+
setThinking(false);
|
|
150190
|
+
setIsExecuting(false);
|
|
150191
|
+
} catch (error42) {
|
|
150192
|
+
setThinking(false);
|
|
150193
|
+
setIsExecuting(false);
|
|
150194
|
+
if (error42 instanceof Error && error42.name === "AbortError") {} else {
|
|
150195
|
+
setError(error42 instanceof Error ? error42.message : "Unknown error occurred");
|
|
150196
|
+
}
|
|
150197
|
+
}
|
|
150198
|
+
}, [model.id, addTokenUsage, setThinking, setIsExecuting]);
|
|
150199
|
+
const resumeAgent = import_react48.useCallback(async (agentId) => {
|
|
150200
|
+
if (!session)
|
|
150201
|
+
return;
|
|
150202
|
+
const paused = subagentsRef.current.find((s) => s.id === agentId && s.status === "paused");
|
|
150203
|
+
if (!paused)
|
|
150204
|
+
return;
|
|
150205
|
+
if (paused.type === "attack-surface") {
|
|
150206
|
+
let previousResults;
|
|
150207
|
+
const resultsPath = join19(session.rootPath, "attack-surface-results.json");
|
|
150208
|
+
if (existsSync24(resultsPath)) {
|
|
150209
|
+
try {
|
|
150210
|
+
previousResults = JSON.parse(readFileSync14(resultsPath, "utf-8"));
|
|
150211
|
+
} catch {}
|
|
150212
|
+
}
|
|
150213
|
+
await startPentest(session, previousResults);
|
|
150214
|
+
return;
|
|
150215
|
+
}
|
|
150216
|
+
if (!paused.resumeInfo)
|
|
150217
|
+
return;
|
|
150218
|
+
const { target, objective, vulnerabilityClass, authenticationInfo } = paused.resumeInfo;
|
|
150219
|
+
setSubagents((prev) => prev.map((s) => s.id === agentId ? { ...s, status: "pending" } : s));
|
|
150220
|
+
setIsExecuting(true);
|
|
150221
|
+
setThinking(true);
|
|
150222
|
+
let accumulatedText = "";
|
|
150223
|
+
try {
|
|
150224
|
+
const result = await runMetaVulnerabilityTestAgent({
|
|
150225
|
+
input: {
|
|
150226
|
+
target,
|
|
150227
|
+
objective,
|
|
150228
|
+
vulnerabilityClass,
|
|
150229
|
+
authenticationInfo,
|
|
150230
|
+
authenticationInstructions: session.config?.authenticationInstructions,
|
|
150231
|
+
outcomeGuidance: session.config?.outcomeGuidance || "Find and document vulnerabilities",
|
|
150232
|
+
session: {
|
|
150233
|
+
id: session.id,
|
|
150234
|
+
rootPath: session.rootPath,
|
|
150235
|
+
findingsPath: session.findingsPath,
|
|
150236
|
+
logsPath: session.logsPath,
|
|
150237
|
+
pocsPath: session.rootPath + "/pocs"
|
|
150238
|
+
},
|
|
150239
|
+
sessionConfig: {
|
|
150240
|
+
enableCvssScoring: session.config?.enableCvssScoring,
|
|
150241
|
+
cvssModel: session.config?.cvssModel
|
|
150242
|
+
}
|
|
150243
|
+
},
|
|
150244
|
+
model: model.id,
|
|
150245
|
+
abortSignal: abortController?.signal,
|
|
150246
|
+
onChunk: (chunk) => {
|
|
150247
|
+
if (chunk.type === "text-delta" && chunk.text) {
|
|
150248
|
+
accumulatedText += chunk.text;
|
|
150249
|
+
setThinking(false);
|
|
150250
|
+
if (accumulatedText.trim()) {
|
|
150251
|
+
setSubagents((prev) => {
|
|
150252
|
+
const idx = prev.findIndex((s) => s.id === agentId);
|
|
150253
|
+
if (idx === -1)
|
|
150254
|
+
return prev;
|
|
150255
|
+
const updated = [...prev];
|
|
150256
|
+
const subagent = updated[idx];
|
|
150257
|
+
const lastMsg = subagent.messages[subagent.messages.length - 1];
|
|
150258
|
+
if (lastMsg && lastMsg.role === "assistant") {
|
|
150259
|
+
const newMessages = [...subagent.messages];
|
|
150260
|
+
newMessages[newMessages.length - 1] = {
|
|
150261
|
+
...lastMsg,
|
|
150262
|
+
content: accumulatedText
|
|
150263
|
+
};
|
|
150264
|
+
updated[idx] = { ...subagent, messages: newMessages };
|
|
150265
|
+
} else {
|
|
150266
|
+
updated[idx] = {
|
|
150267
|
+
...subagent,
|
|
150268
|
+
messages: [
|
|
150269
|
+
...subagent.messages,
|
|
150270
|
+
{
|
|
150271
|
+
role: "assistant",
|
|
150272
|
+
content: accumulatedText,
|
|
150273
|
+
createdAt: new Date
|
|
150274
|
+
}
|
|
150275
|
+
]
|
|
150276
|
+
};
|
|
150277
|
+
}
|
|
150278
|
+
return updated;
|
|
150279
|
+
});
|
|
150280
|
+
}
|
|
150281
|
+
} else if (chunk.type === "tool-call") {
|
|
150282
|
+
setThinking(false);
|
|
150283
|
+
const tc = chunk;
|
|
150284
|
+
const toolCallId = tc.toolCallId;
|
|
150285
|
+
const toolName = tc.toolName || "tool";
|
|
150286
|
+
const args = tc.input ?? tc.args;
|
|
150287
|
+
const toolDescription = typeof args?.toolCallDescription === "string" ? args.toolCallDescription : toolName;
|
|
150288
|
+
setSubagents((prev) => {
|
|
150289
|
+
const idx = prev.findIndex((s) => s.id === agentId);
|
|
150290
|
+
if (idx === -1)
|
|
150291
|
+
return prev;
|
|
150292
|
+
const updated = [...prev];
|
|
150293
|
+
const subagent = updated[idx];
|
|
150294
|
+
const newMessages = [...subagent.messages];
|
|
150295
|
+
const exists = newMessages.some((m2) => m2.role === "tool" && m2.toolCallId === toolCallId);
|
|
150296
|
+
if (!exists) {
|
|
150297
|
+
newMessages.push({
|
|
150298
|
+
role: "tool",
|
|
150299
|
+
status: "pending",
|
|
150300
|
+
toolCallId,
|
|
150301
|
+
toolName,
|
|
150302
|
+
content: toolDescription,
|
|
150303
|
+
args,
|
|
150304
|
+
createdAt: new Date
|
|
150305
|
+
});
|
|
150306
|
+
}
|
|
150307
|
+
updated[idx] = { ...subagent, messages: newMessages };
|
|
150308
|
+
return updated;
|
|
150309
|
+
});
|
|
150310
|
+
} else if (chunk.type === "tool-result") {
|
|
150311
|
+
setThinking(true);
|
|
150312
|
+
const tr = chunk;
|
|
149857
150313
|
const toolCallId = tr.toolCallId;
|
|
149858
150314
|
const toolName = tr.toolName || "tool";
|
|
149859
|
-
const
|
|
150315
|
+
const resultData = tr.output ?? tr.result;
|
|
149860
150316
|
setSubagents((prev) => {
|
|
149861
150317
|
const idx = prev.findIndex((s) => s.id === agentId);
|
|
149862
150318
|
if (idx === -1)
|
|
@@ -149871,8 +150327,8 @@ function SessionView({
|
|
|
149871
150327
|
newMessages[msgIdx] = {
|
|
149872
150328
|
...existingMsg,
|
|
149873
150329
|
status: "completed",
|
|
149874
|
-
content:
|
|
149875
|
-
result:
|
|
150330
|
+
content: description,
|
|
150331
|
+
result: resultData
|
|
149876
150332
|
};
|
|
149877
150333
|
} else {
|
|
149878
150334
|
newMessages.push({
|
|
@@ -149881,54 +150337,47 @@ function SessionView({
|
|
|
149881
150337
|
toolCallId,
|
|
149882
150338
|
toolName,
|
|
149883
150339
|
content: `+ ${toolName}`,
|
|
149884
|
-
result:
|
|
150340
|
+
result: resultData,
|
|
149885
150341
|
createdAt: new Date
|
|
149886
150342
|
});
|
|
149887
150343
|
}
|
|
149888
150344
|
updated[idx] = { ...subagent, messages: newMessages };
|
|
149889
150345
|
return updated;
|
|
149890
150346
|
});
|
|
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
150347
|
}
|
|
149900
150348
|
},
|
|
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);
|
|
150349
|
+
onStepFinish: (step) => {
|
|
150350
|
+
const usage = step.usage;
|
|
150351
|
+
if (usage) {
|
|
150352
|
+
const stepTokens = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
|
|
150353
|
+
if (stepTokens > 0)
|
|
150354
|
+
addTokenUsage(usage.inputTokens ?? 0, usage.outputTokens ?? 0);
|
|
150355
|
+
}
|
|
150356
|
+
accumulatedText = "";
|
|
149920
150357
|
}
|
|
149921
|
-
}
|
|
149922
|
-
|
|
149923
|
-
|
|
150358
|
+
});
|
|
150359
|
+
setSubagents((prev) => prev.map((s) => s.id === agentId ? {
|
|
150360
|
+
...s,
|
|
150361
|
+
status: result.error ? "failed" : "completed",
|
|
150362
|
+
resumeInfo: undefined,
|
|
150363
|
+
messages: [
|
|
150364
|
+
...s.messages,
|
|
150365
|
+
{
|
|
150366
|
+
role: "assistant",
|
|
150367
|
+
content: `${result.findingsCount > 0 ? "✅" : "⚪"} ${result.summary}`,
|
|
150368
|
+
createdAt: new Date
|
|
150369
|
+
}
|
|
150370
|
+
]
|
|
150371
|
+
} : s));
|
|
149924
150372
|
} catch (error42) {
|
|
149925
|
-
|
|
150373
|
+
setSubagents((prev) => prev.map((s) => s.id === agentId ? { ...s, status: "failed", resumeInfo: undefined } : s));
|
|
150374
|
+
}
|
|
150375
|
+
setThinking(false);
|
|
150376
|
+
const stillRunning = subagentsRef.current.some((s) => s.status === "pending" && s.id !== agentId);
|
|
150377
|
+
if (!stillRunning) {
|
|
149926
150378
|
setIsExecuting(false);
|
|
149927
|
-
if (error42 instanceof Error && error42.name === "AbortError") {} else {
|
|
149928
|
-
setError(error42 instanceof Error ? error42.message : "Unknown error occurred");
|
|
149929
|
-
}
|
|
149930
150379
|
}
|
|
149931
|
-
}, [model.id, addTokenUsage, setThinking, setIsExecuting]);
|
|
150380
|
+
}, [session, model.id, abortController, addTokenUsage, setThinking, setIsExecuting, startPentest]);
|
|
149932
150381
|
const openReport = import_react48.useCallback(() => {
|
|
149933
150382
|
if (session?.rootPath) {
|
|
149934
150383
|
const reportPath = `${session.rootPath}/comprehensive-pentest-report.md`;
|
|
@@ -149989,10 +150438,11 @@ function SessionView({
|
|
|
149989
150438
|
session
|
|
149990
150439
|
}, undefined, false, undefined, this);
|
|
149991
150440
|
}
|
|
149992
|
-
if (session.config?.mode === "operator") {
|
|
150441
|
+
if (session.config?.mode === "operator" || openAsOperator) {
|
|
149993
150442
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(OperatorDashboard, {
|
|
149994
150443
|
session,
|
|
149995
|
-
isResume
|
|
150444
|
+
isResume,
|
|
150445
|
+
openAsOperator
|
|
149996
150446
|
}, undefined, false, undefined, this);
|
|
149997
150447
|
}
|
|
149998
150448
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SwarmDashboard, {
|
|
@@ -150003,7 +150453,8 @@ function SessionView({
|
|
|
150003
150453
|
isCompleted,
|
|
150004
150454
|
onBack: handleBack,
|
|
150005
150455
|
onViewReport: openReport,
|
|
150006
|
-
onKillAgent: killAgent
|
|
150456
|
+
onKillAgent: killAgent,
|
|
150457
|
+
onResumeAgent: resumeAgent
|
|
150007
150458
|
}, undefined, false, undefined, this);
|
|
150008
150459
|
}
|
|
150009
150460
|
|
|
@@ -150752,10 +151203,17 @@ function HomeView({ onNavigate, onStartSession }) {
|
|
|
150752
151203
|
const { executeCommand, autocompleteOptions } = useCommand();
|
|
150753
151204
|
const { setInputValue } = useInput();
|
|
150754
151205
|
const { promptRef } = useFocus();
|
|
151206
|
+
const [hintMessage, setHintMessage] = import_react56.useState(null);
|
|
150755
151207
|
const handleSubmit = import_react56.useCallback((value) => {
|
|
150756
|
-
|
|
151208
|
+
setHintMessage("Type /help to get started");
|
|
150757
151209
|
setInputValue("");
|
|
150758
|
-
}, [
|
|
151210
|
+
}, [setInputValue]);
|
|
151211
|
+
import_react56.useEffect(() => {
|
|
151212
|
+
if (!hintMessage)
|
|
151213
|
+
return;
|
|
151214
|
+
const timer = setTimeout(() => setHintMessage(null), 3000);
|
|
151215
|
+
return () => clearTimeout(timer);
|
|
151216
|
+
}, [hintMessage]);
|
|
150759
151217
|
const handleCommandExecute = import_react56.useCallback(async (command) => {
|
|
150760
151218
|
await executeCommand(command);
|
|
150761
151219
|
}, [executeCommand]);
|
|
@@ -150825,6 +151283,13 @@ function HomeView({ onNavigate, onStartSession }) {
|
|
|
150825
151283
|
onCommandExecute: handleCommandExecute,
|
|
150826
151284
|
showPromptIndicator: true
|
|
150827
151285
|
}, undefined, false, undefined, this),
|
|
151286
|
+
hintMessage && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
151287
|
+
marginTop: 1,
|
|
151288
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
151289
|
+
fg: creamText7,
|
|
151290
|
+
children: hintMessage
|
|
151291
|
+
}, undefined, false, undefined, this)
|
|
151292
|
+
}, undefined, false, undefined, this),
|
|
150828
151293
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
150829
151294
|
marginTop: 1,
|
|
150830
151295
|
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
@@ -153021,13 +153486,27 @@ function WebWizard({
|
|
|
153021
153486
|
}, undefined, true, undefined, this);
|
|
153022
153487
|
}
|
|
153023
153488
|
|
|
153024
|
-
// src/tui/components/commands/
|
|
153489
|
+
// src/tui/components/commands/sessions-browser.tsx
|
|
153490
|
+
var import_react69 = __toESM(require_react(), 1);
|
|
153491
|
+
import { exec as exec5 } from "child_process";
|
|
153492
|
+
import { existsSync as existsSync27 } from "fs";
|
|
153493
|
+
|
|
153494
|
+
// src/tui/hooks/use-sessions-list.ts
|
|
153025
153495
|
var import_react68 = __toESM(require_react(), 1);
|
|
153026
153496
|
import { existsSync as existsSync26, readdirSync as readdirSync7 } from "fs";
|
|
153027
|
-
import { join as
|
|
153028
|
-
|
|
153029
|
-
|
|
153030
|
-
|
|
153497
|
+
import { join as join20 } from "path";
|
|
153498
|
+
function countFindings(findingsPath) {
|
|
153499
|
+
try {
|
|
153500
|
+
if (!existsSync26(findingsPath))
|
|
153501
|
+
return 0;
|
|
153502
|
+
return readdirSync7(findingsPath).filter((f) => f.endsWith(".json")).length;
|
|
153503
|
+
} catch {
|
|
153504
|
+
return 0;
|
|
153505
|
+
}
|
|
153506
|
+
}
|
|
153507
|
+
function checkHasReport(rootPath) {
|
|
153508
|
+
return existsSync26(join20(rootPath, "comprehensive-pentest-report.md"));
|
|
153509
|
+
}
|
|
153031
153510
|
function formatRelativeTime(timestamp) {
|
|
153032
153511
|
const now2 = Date.now();
|
|
153033
153512
|
const diff = now2 - timestamp;
|
|
@@ -153046,89 +153525,177 @@ function formatRelativeTime(timestamp) {
|
|
|
153046
153525
|
return `${days}d ago`;
|
|
153047
153526
|
return new Date(timestamp).toLocaleDateString();
|
|
153048
153527
|
}
|
|
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() {
|
|
153528
|
+
function useSessionsList() {
|
|
153059
153529
|
const [sessions, setSessions] = import_react68.useState([]);
|
|
153060
|
-
const [selectedIndex, setSelectedIndex] = import_react68.useState(0);
|
|
153061
153530
|
const [loading, setLoading] = import_react68.useState(true);
|
|
153062
|
-
const [
|
|
153531
|
+
const [searchTerm, setSearchTerm] = import_react68.useState("");
|
|
153532
|
+
const loadSessions = import_react68.useCallback(async () => {
|
|
153533
|
+
setLoading(true);
|
|
153534
|
+
try {
|
|
153535
|
+
const enriched = [];
|
|
153536
|
+
for await (const session of Session.list()) {
|
|
153537
|
+
const hasOperatorState = existsSync26(join20(session.rootPath, "operator-state.json"));
|
|
153538
|
+
const findingsCount = countFindings(session.findingsPath);
|
|
153539
|
+
const hasReport2 = checkHasReport(session.rootPath);
|
|
153540
|
+
enriched.push({ ...session, findingsCount, hasOperatorState, hasReport: hasReport2 });
|
|
153541
|
+
}
|
|
153542
|
+
enriched.sort((a, b2) => b2.time.updated - a.time.updated);
|
|
153543
|
+
setSessions(enriched);
|
|
153544
|
+
} catch (error41) {
|
|
153545
|
+
console.error("Error loading sessions:", error41);
|
|
153546
|
+
} finally {
|
|
153547
|
+
setLoading(false);
|
|
153548
|
+
}
|
|
153549
|
+
}, []);
|
|
153550
|
+
import_react68.useEffect(() => {
|
|
153551
|
+
loadSessions();
|
|
153552
|
+
}, [loadSessions]);
|
|
153553
|
+
const deleteSession = import_react68.useCallback(async (id) => {
|
|
153554
|
+
await Session.remove({ sessionId: id });
|
|
153555
|
+
await loadSessions();
|
|
153556
|
+
}, [loadSessions]);
|
|
153557
|
+
const filtered = searchTerm ? sessions.filter((s) => s.name.toLowerCase().includes(searchTerm.toLowerCase())) : sessions;
|
|
153558
|
+
const groupsMap = new Map;
|
|
153559
|
+
for (const session of filtered) {
|
|
153560
|
+
const d2 = new Date(session.time.created);
|
|
153561
|
+
const dateStr = d2.toLocaleDateString("en-US", {
|
|
153562
|
+
weekday: "short",
|
|
153563
|
+
month: "short",
|
|
153564
|
+
day: "numeric",
|
|
153565
|
+
year: "numeric"
|
|
153566
|
+
});
|
|
153567
|
+
let group = groupsMap.get(dateStr);
|
|
153568
|
+
if (!group) {
|
|
153569
|
+
group = { date: dateStr, timestamp: d2.getTime(), sessions: [] };
|
|
153570
|
+
groupsMap.set(dateStr, group);
|
|
153571
|
+
}
|
|
153572
|
+
group.sessions.push(session);
|
|
153573
|
+
}
|
|
153574
|
+
const rawGroups = Array.from(groupsMap.values());
|
|
153575
|
+
rawGroups.sort((a, b2) => b2.timestamp - a.timestamp);
|
|
153576
|
+
for (const g2 of rawGroups) {
|
|
153577
|
+
g2.sessions.sort((a, b2) => new Date(b2.time.created).getTime() - new Date(a.time.created).getTime());
|
|
153578
|
+
}
|
|
153579
|
+
const visualOrderSessions = [];
|
|
153580
|
+
const groupedSessions = [];
|
|
153581
|
+
let idx = 0;
|
|
153582
|
+
for (const raw of rawGroups) {
|
|
153583
|
+
const group = { date: raw.date, timestamp: raw.timestamp, sessions: [] };
|
|
153584
|
+
for (const s of raw.sessions) {
|
|
153585
|
+
visualOrderSessions.push(s);
|
|
153586
|
+
group.sessions.push({ ...s, index: idx });
|
|
153587
|
+
idx++;
|
|
153588
|
+
}
|
|
153589
|
+
groupedSessions.push(group);
|
|
153590
|
+
}
|
|
153591
|
+
return {
|
|
153592
|
+
sessions: filtered,
|
|
153593
|
+
groupedSessions,
|
|
153594
|
+
visualOrderSessions,
|
|
153595
|
+
loading,
|
|
153596
|
+
searchTerm,
|
|
153597
|
+
setSearchTerm,
|
|
153598
|
+
deleteSession,
|
|
153599
|
+
reload: loadSessions
|
|
153600
|
+
};
|
|
153601
|
+
}
|
|
153602
|
+
|
|
153603
|
+
// src/tui/components/commands/sessions-browser.tsx
|
|
153604
|
+
var greenAccent5 = RGBA.fromInts(76, 175, 80, 255);
|
|
153605
|
+
var creamText12 = RGBA.fromInts(255, 248, 220, 255);
|
|
153606
|
+
var dimText13 = RGBA.fromInts(120, 120, 120, 255);
|
|
153607
|
+
function SessionsBrowser() {
|
|
153063
153608
|
const route = useRoute();
|
|
153064
153609
|
const { load: loadSession } = useSession();
|
|
153065
153610
|
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
|
-
}
|
|
153611
|
+
const {
|
|
153612
|
+
groupedSessions,
|
|
153613
|
+
visualOrderSessions,
|
|
153614
|
+
loading,
|
|
153615
|
+
searchTerm,
|
|
153616
|
+
setSearchTerm,
|
|
153617
|
+
deleteSession,
|
|
153618
|
+
reload
|
|
153619
|
+
} = useSessionsList();
|
|
153620
|
+
const [selectedIndex, setSelectedIndex] = import_react69.useState(0);
|
|
153621
|
+
const [statusMessage, setStatusMessage] = import_react69.useState("");
|
|
153622
|
+
const scroll = import_react69.useRef(null);
|
|
153623
|
+
import_react69.useEffect(() => {
|
|
153624
|
+
if (visualOrderSessions.length > 0 && selectedIndex >= visualOrderSessions.length) {
|
|
153625
|
+
setSelectedIndex(visualOrderSessions.length - 1);
|
|
153626
|
+
} else if (visualOrderSessions.length === 0) {
|
|
153627
|
+
setSelectedIndex(0);
|
|
153089
153628
|
}
|
|
153090
|
-
|
|
153629
|
+
}, [visualOrderSessions.length, selectedIndex]);
|
|
153630
|
+
const showStatus = import_react69.useCallback((msg) => {
|
|
153631
|
+
setStatusMessage(msg);
|
|
153632
|
+
setTimeout(() => setStatusMessage(""), 2000);
|
|
153091
153633
|
}, []);
|
|
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);
|
|
153634
|
+
const openSession = import_react69.useCallback(async (session, asOperator) => {
|
|
153635
|
+
const loaded = await loadSession(session.id);
|
|
153636
|
+
if (!loaded) {
|
|
153637
|
+
showStatus("Error loading session");
|
|
153638
|
+
return;
|
|
153109
153639
|
}
|
|
153110
|
-
|
|
153111
|
-
|
|
153640
|
+
route.navigate({
|
|
153641
|
+
type: "session",
|
|
153642
|
+
sessionId: session.id,
|
|
153643
|
+
isResume: true,
|
|
153644
|
+
openAsOperator: asOperator || undefined
|
|
153645
|
+
});
|
|
153646
|
+
}, [loadSession, route, showStatus]);
|
|
153647
|
+
const openReport = import_react69.useCallback(async (session) => {
|
|
153648
|
+
const reportPath = await Storage.locate([session.id, "pentest-report"], ".md");
|
|
153649
|
+
if (!existsSync27(reportPath)) {
|
|
153650
|
+
showStatus("Report not found");
|
|
153651
|
+
return;
|
|
153652
|
+
}
|
|
153653
|
+
exec5(`open "${reportPath}"`, (error41) => {
|
|
153654
|
+
if (error41)
|
|
153655
|
+
showStatus("Error opening report");
|
|
153656
|
+
});
|
|
153657
|
+
}, [showStatus]);
|
|
153658
|
+
useKeyboard(async (key) => {
|
|
153112
153659
|
if (key.name === "escape") {
|
|
153113
153660
|
refocusPrompt();
|
|
153114
153661
|
route.navigate({ type: "base", path: "home" });
|
|
153115
153662
|
return;
|
|
153116
153663
|
}
|
|
153117
|
-
if (key.name === "
|
|
153118
|
-
|
|
153664
|
+
if (key.name === "return" && visualOrderSessions.length > 0) {
|
|
153665
|
+
key.preventDefault();
|
|
153666
|
+
const selected = visualOrderSessions[selectedIndex];
|
|
153667
|
+
if (selected)
|
|
153668
|
+
await openSession(selected, false);
|
|
153669
|
+
return;
|
|
153670
|
+
}
|
|
153671
|
+
if ((key.name === "o" || key.name === "O") && !key.ctrl && !key.meta && visualOrderSessions.length > 0) {
|
|
153672
|
+
const selected = visualOrderSessions[selectedIndex];
|
|
153673
|
+
if (selected)
|
|
153674
|
+
await openSession(selected, true);
|
|
153119
153675
|
return;
|
|
153120
153676
|
}
|
|
153121
|
-
if (key.name === "
|
|
153122
|
-
|
|
153677
|
+
if ((key.name === "r" || key.name === "R") && !key.ctrl && !key.meta && visualOrderSessions.length > 0) {
|
|
153678
|
+
const selected = visualOrderSessions[selectedIndex];
|
|
153679
|
+
if (selected)
|
|
153680
|
+
await openReport(selected);
|
|
153123
153681
|
return;
|
|
153124
153682
|
}
|
|
153125
|
-
if (key.name === "
|
|
153126
|
-
const selected =
|
|
153683
|
+
if (key.ctrl && key.name === "d" && visualOrderSessions.length > 0) {
|
|
153684
|
+
const selected = visualOrderSessions[selectedIndex];
|
|
153127
153685
|
if (selected) {
|
|
153128
|
-
|
|
153686
|
+
await deleteSession(selected.id);
|
|
153687
|
+
showStatus("Session deleted");
|
|
153129
153688
|
}
|
|
153130
153689
|
return;
|
|
153131
153690
|
}
|
|
153691
|
+
if (key.name === "up" && visualOrderSessions.length > 0) {
|
|
153692
|
+
setSelectedIndex((i) => i > 0 ? i - 1 : visualOrderSessions.length - 1);
|
|
153693
|
+
return;
|
|
153694
|
+
}
|
|
153695
|
+
if (key.name === "down" && visualOrderSessions.length > 0) {
|
|
153696
|
+
setSelectedIndex((i) => i < visualOrderSessions.length - 1 ? i + 1 : 0);
|
|
153697
|
+
return;
|
|
153698
|
+
}
|
|
153132
153699
|
});
|
|
153133
153700
|
if (loading) {
|
|
153134
153701
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
@@ -153141,7 +153708,7 @@ function ResumeWizard() {
|
|
|
153141
153708
|
}, undefined, false, undefined, this)
|
|
153142
153709
|
}, undefined, false, undefined, this);
|
|
153143
153710
|
}
|
|
153144
|
-
if (
|
|
153711
|
+
if (visualOrderSessions.length === 0) {
|
|
153145
153712
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
153146
153713
|
flexDirection: "column",
|
|
153147
153714
|
padding: 2,
|
|
@@ -153150,15 +153717,15 @@ function ResumeWizard() {
|
|
|
153150
153717
|
children: [
|
|
153151
153718
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153152
153719
|
fg: creamText12,
|
|
153153
|
-
children: "
|
|
153720
|
+
children: "Sessions"
|
|
153154
153721
|
}, undefined, false, undefined, this),
|
|
153155
153722
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153156
153723
|
fg: dimText13,
|
|
153157
|
-
children: "No sessions found
|
|
153724
|
+
children: "No sessions found."
|
|
153158
153725
|
}, undefined, false, undefined, this),
|
|
153159
153726
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153160
153727
|
fg: dimText13,
|
|
153161
|
-
children: "Start a new session with /
|
|
153728
|
+
children: "Start a new session with /pentest or /operator"
|
|
153162
153729
|
}, undefined, false, undefined, this),
|
|
153163
153730
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153164
153731
|
fg: dimText13,
|
|
@@ -153172,98 +153739,142 @@ function ResumeWizard() {
|
|
|
153172
153739
|
padding: 2,
|
|
153173
153740
|
gap: 1,
|
|
153174
153741
|
width: "100%",
|
|
153742
|
+
flexGrow: 1,
|
|
153175
153743
|
children: [
|
|
153176
153744
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153177
153745
|
fg: creamText12,
|
|
153178
|
-
children: "
|
|
153746
|
+
children: "Sessions"
|
|
153179
153747
|
}, undefined, false, undefined, this),
|
|
153180
153748
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153181
153749
|
fg: dimText13,
|
|
153182
|
-
children: "
|
|
153750
|
+
children: "Browse and reopen previous pentest sessions"
|
|
153183
153751
|
}, undefined, false, undefined, this),
|
|
153184
153752
|
/* @__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
|
-
})
|
|
153753
|
+
width: "100%",
|
|
153754
|
+
border: ["left"],
|
|
153755
|
+
borderColor: greenAccent5,
|
|
153756
|
+
backgroundColor: "transparent",
|
|
153757
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
|
|
153758
|
+
paddingLeft: 1,
|
|
153759
|
+
backgroundColor: "transparent",
|
|
153760
|
+
placeholder: "Search sessions...",
|
|
153761
|
+
value: searchTerm,
|
|
153762
|
+
onInput: setSearchTerm,
|
|
153763
|
+
focused: true
|
|
153764
|
+
}, undefined, false, undefined, this)
|
|
153230
153765
|
}, undefined, false, undefined, this),
|
|
153231
153766
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
153232
|
-
marginTop: 2,
|
|
153233
153767
|
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,
|
|
153768
|
+
gap: 1,
|
|
153769
|
+
flexGrow: 1,
|
|
153770
|
+
overflow: "hidden",
|
|
153771
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("scrollbox", {
|
|
153772
|
+
ref: scroll,
|
|
153773
|
+
scrollbarOptions: { visible: false },
|
|
153774
|
+
style: {
|
|
153775
|
+
rootOptions: {
|
|
153776
|
+
width: "100%",
|
|
153777
|
+
flexGrow: 1,
|
|
153778
|
+
flexShrink: 1,
|
|
153779
|
+
overflow: "hidden"
|
|
153780
|
+
},
|
|
153781
|
+
wrapperOptions: { overflow: "hidden" },
|
|
153782
|
+
contentOptions: { gap: 2, flexDirection: "column" }
|
|
153783
|
+
},
|
|
153784
|
+
children: groupedSessions.map((group) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
153785
|
+
flexDirection: "column",
|
|
153786
|
+
gap: 1,
|
|
153257
153787
|
children: [
|
|
153258
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("
|
|
153788
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153259
153789
|
fg: greenAccent5,
|
|
153260
|
-
children:
|
|
153790
|
+
children: group.date
|
|
153261
153791
|
}, undefined, false, undefined, this),
|
|
153262
|
-
|
|
153792
|
+
group.sessions.map((session) => {
|
|
153793
|
+
const isSelected = session.index === selectedIndex;
|
|
153794
|
+
const age = formatRelativeTime(session.time.updated);
|
|
153795
|
+
const mode = session.config?.mode || "auto";
|
|
153796
|
+
const modeBadge = mode === "operator" ? "[operator]" : "[auto]";
|
|
153797
|
+
const findingsText = session.findingsCount > 0 ? `${session.findingsCount} finding${session.findingsCount > 1 ? "s" : ""}` : "";
|
|
153798
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
153799
|
+
id: session.id,
|
|
153800
|
+
backgroundColor: "transparent",
|
|
153801
|
+
border: isSelected ? ["left"] : undefined,
|
|
153802
|
+
borderColor: isSelected ? greenAccent5 : undefined,
|
|
153803
|
+
paddingLeft: isSelected ? 1 : 2,
|
|
153804
|
+
flexDirection: "row",
|
|
153805
|
+
justifyContent: "space-between",
|
|
153806
|
+
width: "100%",
|
|
153807
|
+
children: [
|
|
153808
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
153809
|
+
flexDirection: "row",
|
|
153810
|
+
gap: 1,
|
|
153811
|
+
children: [
|
|
153812
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153813
|
+
fg: isSelected ? greenAccent5 : creamText12,
|
|
153814
|
+
children: [
|
|
153815
|
+
isSelected ? "▸ " : " ",
|
|
153816
|
+
session.name
|
|
153817
|
+
]
|
|
153818
|
+
}, undefined, true, undefined, this),
|
|
153819
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153820
|
+
fg: mode === "operator" ? greenAccent5 : dimText13,
|
|
153821
|
+
children: modeBadge
|
|
153822
|
+
}, undefined, false, undefined, this),
|
|
153823
|
+
findingsText ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153824
|
+
fg: dimText13,
|
|
153825
|
+
children: findingsText
|
|
153826
|
+
}, undefined, false, undefined, this) : null
|
|
153827
|
+
]
|
|
153828
|
+
}, undefined, true, undefined, this),
|
|
153829
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153830
|
+
fg: dimText13,
|
|
153831
|
+
children: age
|
|
153832
|
+
}, undefined, false, undefined, this)
|
|
153833
|
+
]
|
|
153834
|
+
}, session.id, true, undefined, this);
|
|
153835
|
+
})
|
|
153263
153836
|
]
|
|
153264
|
-
},
|
|
153265
|
-
|
|
153266
|
-
}, undefined,
|
|
153837
|
+
}, group.date, true, undefined, this))
|
|
153838
|
+
}, undefined, false, undefined, this)
|
|
153839
|
+
}, undefined, false, undefined, this),
|
|
153840
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
153841
|
+
flexDirection: "row",
|
|
153842
|
+
gap: 1,
|
|
153843
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153844
|
+
fg: dimText13,
|
|
153845
|
+
children: [
|
|
153846
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
153847
|
+
fg: greenAccent5,
|
|
153848
|
+
children: "[Enter]"
|
|
153849
|
+
}, undefined, false, undefined, this),
|
|
153850
|
+
" Open",
|
|
153851
|
+
" ",
|
|
153852
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
153853
|
+
fg: greenAccent5,
|
|
153854
|
+
children: "[O]"
|
|
153855
|
+
}, undefined, false, undefined, this),
|
|
153856
|
+
" Operator",
|
|
153857
|
+
" ",
|
|
153858
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
153859
|
+
fg: greenAccent5,
|
|
153860
|
+
children: "[R]"
|
|
153861
|
+
}, undefined, false, undefined, this),
|
|
153862
|
+
" Report",
|
|
153863
|
+
" ",
|
|
153864
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
153865
|
+
fg: greenAccent5,
|
|
153866
|
+
children: "[Ctrl+D]"
|
|
153867
|
+
}, undefined, false, undefined, this),
|
|
153868
|
+
" Delete",
|
|
153869
|
+
" ",
|
|
153870
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
153871
|
+
fg: greenAccent5,
|
|
153872
|
+
children: "[Esc]"
|
|
153873
|
+
}, undefined, false, undefined, this),
|
|
153874
|
+
" Back"
|
|
153875
|
+
]
|
|
153876
|
+
}, undefined, true, undefined, this)
|
|
153877
|
+
}, undefined, false, undefined, this),
|
|
153267
153878
|
statusMessage && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
153268
153879
|
fg: greenAccent5,
|
|
153269
153880
|
children: statusMessage
|
|
@@ -153273,16 +153884,16 @@ function ResumeWizard() {
|
|
|
153273
153884
|
}
|
|
153274
153885
|
|
|
153275
153886
|
// src/tui/components/commands/provider-manager.tsx
|
|
153276
|
-
var
|
|
153887
|
+
var import_react75 = __toESM(require_react(), 1);
|
|
153277
153888
|
// src/tui/components/commands/provider-selection.tsx
|
|
153278
|
-
var
|
|
153889
|
+
var import_react72 = __toESM(require_react(), 1);
|
|
153279
153890
|
function ProviderSelection({
|
|
153280
153891
|
onProviderSelected,
|
|
153281
153892
|
onClose
|
|
153282
153893
|
}) {
|
|
153283
153894
|
const route = useRoute();
|
|
153284
153895
|
const _config = useConfig();
|
|
153285
|
-
const [highlightedIndex, setHighlightedIndex] =
|
|
153896
|
+
const [highlightedIndex, setHighlightedIndex] = import_react72.useState(0);
|
|
153286
153897
|
const configuredProviders = getConfiguredProviders(_config.data);
|
|
153287
153898
|
useKeyboard((key) => {
|
|
153288
153899
|
if (key.name === "escape") {
|
|
@@ -153435,14 +154046,14 @@ function ProviderSelection({
|
|
|
153435
154046
|
}
|
|
153436
154047
|
|
|
153437
154048
|
// src/tui/components/commands/api-key-input.tsx
|
|
153438
|
-
var
|
|
154049
|
+
var import_react74 = __toESM(require_react(), 1);
|
|
153439
154050
|
function APIKeyInput({
|
|
153440
154051
|
provider,
|
|
153441
154052
|
providerName,
|
|
153442
154053
|
onSubmit,
|
|
153443
154054
|
onCancel
|
|
153444
154055
|
}) {
|
|
153445
|
-
const [apiKey, setApiKey] =
|
|
154056
|
+
const [apiKey, setApiKey] = import_react74.useState("");
|
|
153446
154057
|
useKeyboard((key) => {
|
|
153447
154058
|
if (key.name === "escape") {
|
|
153448
154059
|
onCancel();
|
|
@@ -153554,8 +154165,8 @@ function APIKeyInput({
|
|
|
153554
154165
|
function ProviderManager() {
|
|
153555
154166
|
const route = useRoute();
|
|
153556
154167
|
const _config = useConfig();
|
|
153557
|
-
const [flowState, setFlowState] =
|
|
153558
|
-
const [selectedProvider, setSelectedProvider] =
|
|
154168
|
+
const [flowState, setFlowState] = import_react75.useState("selecting");
|
|
154169
|
+
const [selectedProvider, setSelectedProvider] = import_react75.useState(null);
|
|
153559
154170
|
const handleProviderSelected = (providerId) => {
|
|
153560
154171
|
setSelectedProvider(providerId);
|
|
153561
154172
|
setFlowState("inputting");
|
|
@@ -153613,7 +154224,7 @@ function ProviderManager() {
|
|
|
153613
154224
|
}
|
|
153614
154225
|
|
|
153615
154226
|
// src/tui/components/switch.tsx
|
|
153616
|
-
var
|
|
154227
|
+
var import_react76 = __toESM(require_react(), 1);
|
|
153617
154228
|
var CaseSymbol = Symbol("Switch.Case");
|
|
153618
154229
|
var DefaultSymbol = Symbol("Switch.Default");
|
|
153619
154230
|
function CaseComponent({ children }) {
|
|
@@ -153634,8 +154245,8 @@ function SwitchComponent({
|
|
|
153634
154245
|
}) {
|
|
153635
154246
|
let matchedChild = null;
|
|
153636
154247
|
let defaultChild = null;
|
|
153637
|
-
|
|
153638
|
-
if (
|
|
154248
|
+
import_react76.default.Children.forEach(children, (child) => {
|
|
154249
|
+
if (import_react76.default.isValidElement(child)) {
|
|
153639
154250
|
if (child.type[CaseSymbol]) {
|
|
153640
154251
|
const caseChild = child;
|
|
153641
154252
|
if (caseChild.props.when === condition) {
|
|
@@ -153847,7 +154458,7 @@ function ShortcutsDialog({ open, onClose }) {
|
|
|
153847
154458
|
}
|
|
153848
154459
|
|
|
153849
154460
|
// src/tui/components/commands/help-dialog.tsx
|
|
153850
|
-
var
|
|
154461
|
+
var import_react79 = __toESM(require_react(), 1);
|
|
153851
154462
|
var bgOverlay2 = RGBA.fromInts(0, 0, 0, 200);
|
|
153852
154463
|
var bgPanel2 = RGBA.fromInts(20, 20, 20, 255);
|
|
153853
154464
|
var borderColor3 = RGBA.fromInts(60, 60, 60, 255);
|
|
@@ -153859,10 +154470,10 @@ function HelpDialog() {
|
|
|
153859
154470
|
const { commands: commands2 } = useCommand();
|
|
153860
154471
|
const route = useRoute();
|
|
153861
154472
|
const dimensions = useTerminalDimensions();
|
|
153862
|
-
const [selectedIndex, setSelectedIndex] =
|
|
153863
|
-
const [showDetail, setShowDetail] =
|
|
153864
|
-
const scrollboxRef =
|
|
153865
|
-
const commandsByCategory =
|
|
154473
|
+
const [selectedIndex, setSelectedIndex] = import_react79.useState(0);
|
|
154474
|
+
const [showDetail, setShowDetail] = import_react79.useState(false);
|
|
154475
|
+
const scrollboxRef = import_react79.useRef(null);
|
|
154476
|
+
const commandsByCategory = import_react79.useMemo(() => {
|
|
153866
154477
|
const grouped = {};
|
|
153867
154478
|
for (const cmd of commands2) {
|
|
153868
154479
|
const category = cmd.category || "Other";
|
|
@@ -153873,15 +154484,15 @@ function HelpDialog() {
|
|
|
153873
154484
|
}
|
|
153874
154485
|
return grouped;
|
|
153875
154486
|
}, [commands2]);
|
|
153876
|
-
const flatCommands =
|
|
154487
|
+
const flatCommands = import_react79.useMemo(() => {
|
|
153877
154488
|
return commands2;
|
|
153878
154489
|
}, [commands2]);
|
|
153879
|
-
|
|
154490
|
+
import_react79.useEffect(() => {
|
|
153880
154491
|
if (selectedIndex >= flatCommands.length) {
|
|
153881
154492
|
setSelectedIndex(Math.max(0, flatCommands.length - 1));
|
|
153882
154493
|
}
|
|
153883
154494
|
}, [flatCommands.length, selectedIndex]);
|
|
153884
|
-
|
|
154495
|
+
import_react79.useEffect(() => {
|
|
153885
154496
|
if (!scrollboxRef.current || flatCommands.length === 0)
|
|
153886
154497
|
return;
|
|
153887
154498
|
const scroll = scrollboxRef.current;
|
|
@@ -154333,10 +154944,10 @@ function ModelsDisplay() {
|
|
|
154333
154944
|
}
|
|
154334
154945
|
|
|
154335
154946
|
// src/tui/context/keybinding.tsx
|
|
154336
|
-
var
|
|
154947
|
+
var import_react86 = __toESM(require_react(), 1);
|
|
154337
154948
|
|
|
154338
154949
|
// src/tui/keybindings/keybind.tsx
|
|
154339
|
-
var
|
|
154950
|
+
var import_react82 = __toESM(require_react(), 1);
|
|
154340
154951
|
|
|
154341
154952
|
// src/tui/keybindings/actions.ts
|
|
154342
154953
|
var movementActions = [
|
|
@@ -154588,7 +155199,7 @@ var allActions = [
|
|
|
154588
155199
|
var actionsByKey = new Map(allActions.map((action) => [action.key, action]));
|
|
154589
155200
|
var actionsById = new Map(allActions.map((action) => [action.id, action]));
|
|
154590
155201
|
// src/tui/keybindings/keybind.tsx
|
|
154591
|
-
var LeaderKeyContext =
|
|
155202
|
+
var LeaderKeyContext = import_react82.createContext(null);
|
|
154592
155203
|
// src/tui/keybindings/registry.ts
|
|
154593
155204
|
function createKeybindings(deps) {
|
|
154594
155205
|
const {
|
|
@@ -154794,7 +155405,7 @@ var Keybind;
|
|
|
154794
155405
|
})(Keybind ||= {});
|
|
154795
155406
|
|
|
154796
155407
|
// src/tui/context/keybinding.tsx
|
|
154797
|
-
var KeybindingContext =
|
|
155408
|
+
var KeybindingContext = import_react86.createContext(undefined);
|
|
154798
155409
|
function KeybindingProvider({
|
|
154799
155410
|
children,
|
|
154800
155411
|
deps
|
|
@@ -154835,13 +155446,13 @@ function KeybindingProvider({
|
|
|
154835
155446
|
// src/tui/index.tsx
|
|
154836
155447
|
function App(props) {
|
|
154837
155448
|
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] =
|
|
155449
|
+
const [focusIndex, setFocusIndex] = import_react88.useState(0);
|
|
155450
|
+
const [cwd, setCwd] = import_react88.useState(process.cwd());
|
|
155451
|
+
const [ctrlCPressTime, setCtrlCPressTime] = import_react88.useState(null);
|
|
155452
|
+
const [showExitWarning, setShowExitWarning] = import_react88.useState(false);
|
|
155453
|
+
const [inputKey, setInputKey] = import_react88.useState(0);
|
|
155454
|
+
const [showSessionsDialog, setShowSessionsDialog] = import_react88.useState(false);
|
|
155455
|
+
const [showShortcutsDialog, setShowShortcutsDialog] = import_react88.useState(false);
|
|
154845
155456
|
const navigableItems = ["command-input"];
|
|
154846
155457
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ConfigProvider, {
|
|
154847
155458
|
config: appConfig,
|
|
@@ -154915,7 +155526,7 @@ function AppContent({
|
|
|
154915
155526
|
path: "providers"
|
|
154916
155527
|
});
|
|
154917
155528
|
}
|
|
154918
|
-
|
|
155529
|
+
import_react88.useEffect(() => {
|
|
154919
155530
|
if (showExitWarning) {
|
|
154920
155531
|
const timer = setTimeout(() => {
|
|
154921
155532
|
setShowExitWarning(false);
|
|
@@ -155037,13 +155648,17 @@ function CommandDisplay({
|
|
|
155037
155648
|
initialModel: route.data.options?.model
|
|
155038
155649
|
}, undefined, false, undefined, this)
|
|
155039
155650
|
}, undefined, false, undefined, this),
|
|
155651
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
|
|
155652
|
+
when: "models",
|
|
155653
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ModelsDisplay, {}, undefined, false, undefined, this)
|
|
155654
|
+
}, undefined, false, undefined, this),
|
|
155040
155655
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
|
|
155041
155656
|
when: "providers",
|
|
155042
155657
|
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ProviderManager, {}, undefined, false, undefined, this)
|
|
155043
155658
|
}, undefined, false, undefined, this),
|
|
155044
155659
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
|
|
155045
|
-
when: "
|
|
155046
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(
|
|
155660
|
+
when: "sessions",
|
|
155661
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SessionsBrowser, {}, undefined, false, undefined, this)
|
|
155047
155662
|
}, undefined, false, undefined, this),
|
|
155048
155663
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
|
|
155049
155664
|
when: "help",
|
|
@@ -155060,7 +155675,8 @@ function CommandDisplay({
|
|
|
155060
155675
|
if (route.data.type === "session") {
|
|
155061
155676
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SessionView, {
|
|
155062
155677
|
sessionId: route.data.sessionId,
|
|
155063
|
-
isResume: route.data.isResume
|
|
155678
|
+
isResume: route.data.isResume,
|
|
155679
|
+
openAsOperator: route.data.openAsOperator
|
|
155064
155680
|
}, undefined, false, undefined, this);
|
|
155065
155681
|
}
|
|
155066
155682
|
return null;
|