@pensar/apex 0.0.93 → 0.0.96-canary.2ce26987
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/bin/pensar.js +10 -26
- package/build/auth.js +603 -0
- package/build/index.js +1650 -995
- package/package.json +2 -2
package/build/index.js
CHANGED
|
@@ -31880,12 +31880,6 @@ var init_openrouter = __esm(() => {
|
|
|
31880
31880
|
var PENSAR_MODELS;
|
|
31881
31881
|
var init_pensar = __esm(() => {
|
|
31882
31882
|
PENSAR_MODELS = [
|
|
31883
|
-
{
|
|
31884
|
-
id: "pensar:anthropic.claude-opus-4-6-v1",
|
|
31885
|
-
name: "Claude Opus 4.6 (Pensar)",
|
|
31886
|
-
provider: "pensar",
|
|
31887
|
-
contextLength: 200000
|
|
31888
|
-
},
|
|
31889
31883
|
{
|
|
31890
31884
|
id: "pensar:anthropic.claude-sonnet-4-5-20250929-v1:0",
|
|
31891
31885
|
name: "Claude Sonnet 4.5 (Pensar)",
|
|
@@ -31977,7 +31971,7 @@ var package_default2;
|
|
|
31977
31971
|
var init_package = __esm(() => {
|
|
31978
31972
|
package_default2 = {
|
|
31979
31973
|
name: "@pensar/apex",
|
|
31980
|
-
version: "0.0.
|
|
31974
|
+
version: "0.0.96-canary.2ce26987",
|
|
31981
31975
|
description: "AI-powered penetration testing CLI tool with terminal UI",
|
|
31982
31976
|
module: "src/tui/index.tsx",
|
|
31983
31977
|
main: "build/index.js",
|
|
@@ -31997,7 +31991,7 @@ var init_package = __esm(() => {
|
|
|
31997
31991
|
"LICENSE"
|
|
31998
31992
|
],
|
|
31999
31993
|
scripts: {
|
|
32000
|
-
build: "bun build src/tui/index.tsx --outdir build --target node --format esm --external sharp",
|
|
31994
|
+
build: "bun build src/tui/index.tsx --outdir build --target node --format esm --external sharp && bun build src/cli/auth.ts --outdir build --target node --format esm",
|
|
32001
31995
|
"generate:ascii": "bun run scripts/generate-ascii-art.ts",
|
|
32002
31996
|
"generate:models": "bun run scripts/generate-models.ts",
|
|
32003
31997
|
"build:binary": "bun run generate:ascii && bun build src/cli.ts --compile --outfile pensar",
|
|
@@ -37045,6 +37039,22 @@ var init_toolset = __esm(() => {
|
|
|
37045
37039
|
detail: "Retrieve the full content of a saved memory by its id. Use List Memories first to discover available memory ids.",
|
|
37046
37040
|
category: "utility",
|
|
37047
37041
|
defaultEnabled: true
|
|
37042
|
+
},
|
|
37043
|
+
{
|
|
37044
|
+
id: "web_search",
|
|
37045
|
+
name: "Web Search",
|
|
37046
|
+
description: "Search the web",
|
|
37047
|
+
detail: "Search the web for real-time information about CVEs, security advisories, exploit techniques, and vulnerability details. Requires a Pensar account.",
|
|
37048
|
+
category: "reconnaissance",
|
|
37049
|
+
defaultEnabled: true
|
|
37050
|
+
},
|
|
37051
|
+
{
|
|
37052
|
+
id: "get_page",
|
|
37053
|
+
name: "Get Page",
|
|
37054
|
+
description: "Fetch page content",
|
|
37055
|
+
detail: "Fetch and extract readable content from a web page. Use after web_search to read full details from found URLs. Requires a Pensar account.",
|
|
37056
|
+
category: "reconnaissance",
|
|
37057
|
+
defaultEnabled: true
|
|
37048
37058
|
}
|
|
37049
37059
|
];
|
|
37050
37060
|
TOOLSETS = [
|
|
@@ -87793,6 +87803,26 @@ async function* parseSSE(stream) {
|
|
|
87793
87803
|
}
|
|
87794
87804
|
}
|
|
87795
87805
|
|
|
87806
|
+
// src/core/auth/signing.ts
|
|
87807
|
+
import { createHmac, createHash, randomUUID } from "crypto";
|
|
87808
|
+
function signGatewayRequest(signingKey, modelId, body) {
|
|
87809
|
+
const timestamp = String(Math.floor(Date.now() / 1000));
|
|
87810
|
+
const nonce = randomUUID();
|
|
87811
|
+
const bodyHash = createHash("sha256").update(body).digest("hex");
|
|
87812
|
+
const payload = `${timestamp}
|
|
87813
|
+
${nonce}
|
|
87814
|
+
${modelId}
|
|
87815
|
+
${bodyHash}`;
|
|
87816
|
+
const signature = createHmac("sha256", signingKey).update(payload).digest("base64");
|
|
87817
|
+
return { signature, timestamp, nonce };
|
|
87818
|
+
}
|
|
87819
|
+
var init_signing = () => {};
|
|
87820
|
+
|
|
87821
|
+
// src/core/ai/providers/pensarSigning.ts
|
|
87822
|
+
var init_pensarSigning = __esm(() => {
|
|
87823
|
+
init_signing();
|
|
87824
|
+
});
|
|
87825
|
+
|
|
87796
87826
|
// src/core/ai/providers/pensar.ts
|
|
87797
87827
|
function log(...args) {
|
|
87798
87828
|
if (DEBUG)
|
|
@@ -87911,7 +87941,17 @@ function createPensarModel(bedrockModelId, config2) {
|
|
|
87911
87941
|
logInfo(`doStream → ${bedrockModelId} (${url2})`);
|
|
87912
87942
|
log(` messages: ${body.messages?.length ?? 0}, tools: ${body.tools?.length ?? 0}`);
|
|
87913
87943
|
const startTime = Date.now();
|
|
87944
|
+
const serializedBody = JSON.stringify({
|
|
87945
|
+
modelId: bedrockModelId,
|
|
87946
|
+
body
|
|
87947
|
+
});
|
|
87914
87948
|
const headers = await buildHeaders();
|
|
87949
|
+
if (config2.signingKey) {
|
|
87950
|
+
const sig = signGatewayRequest(config2.signingKey, bedrockModelId, serializedBody);
|
|
87951
|
+
headers["X-Pensar-Signature"] = sig.signature;
|
|
87952
|
+
headers["X-Pensar-Timestamp"] = sig.timestamp;
|
|
87953
|
+
headers["X-Pensar-Nonce"] = sig.nonce;
|
|
87954
|
+
}
|
|
87915
87955
|
log(` headers: ${Object.keys(headers).join(", ")}`);
|
|
87916
87956
|
let response;
|
|
87917
87957
|
try {
|
|
@@ -87919,10 +87959,7 @@ function createPensarModel(bedrockModelId, config2) {
|
|
|
87919
87959
|
method: "POST",
|
|
87920
87960
|
headers,
|
|
87921
87961
|
signal: options.abortSignal,
|
|
87922
|
-
body:
|
|
87923
|
-
modelId: bedrockModelId,
|
|
87924
|
-
body
|
|
87925
|
-
})
|
|
87962
|
+
body: serializedBody
|
|
87926
87963
|
});
|
|
87927
87964
|
} catch (err) {
|
|
87928
87965
|
logError(` SSE fetch failed (${Date.now() - startTime}ms):`, err);
|
|
@@ -88124,17 +88161,11 @@ function mapStopReason(reason) {
|
|
|
88124
88161
|
}
|
|
88125
88162
|
var DEBUG;
|
|
88126
88163
|
var init_pensar2 = __esm(() => {
|
|
88164
|
+
init_pensarSigning();
|
|
88127
88165
|
DEBUG = process.env.PENSAR_DEBUG === "1" || process.env.PENSAR_DEBUG === "true";
|
|
88128
88166
|
});
|
|
88129
88167
|
|
|
88130
88168
|
// src/core/api/constants.ts
|
|
88131
|
-
var exports_constants = {};
|
|
88132
|
-
__export(exports_constants, {
|
|
88133
|
-
getPensarConsoleUrl: () => getPensarConsoleUrl,
|
|
88134
|
-
getPensarApiUrl: () => getPensarApiUrl,
|
|
88135
|
-
PENSAR_CONSOLE_BASE_URL: () => PENSAR_CONSOLE_BASE_URL,
|
|
88136
|
-
PENSAR_API_BASE_URL: () => PENSAR_API_BASE_URL
|
|
88137
|
-
});
|
|
88138
88169
|
function getPensarApiUrl() {
|
|
88139
88170
|
return PENSAR_API_BASE_URL;
|
|
88140
88171
|
}
|
|
@@ -88154,7 +88185,7 @@ var init_config2 = __esm(() => {
|
|
|
88154
88185
|
};
|
|
88155
88186
|
});
|
|
88156
88187
|
|
|
88157
|
-
// src/core/
|
|
88188
|
+
// src/core/auth/token.ts
|
|
88158
88189
|
function decodeJwtPayload(token) {
|
|
88159
88190
|
try {
|
|
88160
88191
|
const parts = token.split(".");
|
|
@@ -88173,6 +88204,21 @@ function isTokenExpired(token, bufferSeconds = 60) {
|
|
|
88173
88204
|
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
88174
88205
|
return payload.exp - nowSeconds < bufferSeconds;
|
|
88175
88206
|
}
|
|
88207
|
+
async function fetchWorkOSClientId() {
|
|
88208
|
+
if (cachedClientId)
|
|
88209
|
+
return cachedClientId;
|
|
88210
|
+
try {
|
|
88211
|
+
const apiUrl = getPensarApiUrl();
|
|
88212
|
+
const response = await fetch(`${apiUrl}/api/cli/config`);
|
|
88213
|
+
if (!response.ok)
|
|
88214
|
+
return null;
|
|
88215
|
+
const data = await response.json();
|
|
88216
|
+
cachedClientId = data.workosClientId;
|
|
88217
|
+
return cachedClientId;
|
|
88218
|
+
} catch {
|
|
88219
|
+
return null;
|
|
88220
|
+
}
|
|
88221
|
+
}
|
|
88176
88222
|
async function refreshAccessToken(clientId, refreshToken) {
|
|
88177
88223
|
try {
|
|
88178
88224
|
const response = await fetch("https://api.workos.com/user_management/authenticate", {
|
|
@@ -88219,27 +88265,203 @@ async function ensureValidToken(cfg) {
|
|
|
88219
88265
|
}
|
|
88220
88266
|
return null;
|
|
88221
88267
|
}
|
|
88222
|
-
|
|
88223
|
-
|
|
88224
|
-
|
|
88268
|
+
var cachedClientId = null;
|
|
88269
|
+
var init_token = __esm(() => {
|
|
88270
|
+
init_config2();
|
|
88271
|
+
});
|
|
88272
|
+
|
|
88273
|
+
// src/core/auth/device-flow.ts
|
|
88274
|
+
function sleep2(ms) {
|
|
88275
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
88276
|
+
}
|
|
88277
|
+
async function startDeviceFlow(apiUrl) {
|
|
88278
|
+
const url2 = apiUrl ?? getPensarApiUrl();
|
|
88225
88279
|
try {
|
|
88226
|
-
const
|
|
88227
|
-
|
|
88228
|
-
|
|
88229
|
-
|
|
88230
|
-
|
|
88231
|
-
|
|
88232
|
-
|
|
88233
|
-
|
|
88234
|
-
|
|
88235
|
-
|
|
88280
|
+
const configResponse = await fetch(`${url2}/api/cli/config`);
|
|
88281
|
+
if (configResponse.ok) {
|
|
88282
|
+
const cliConfig = await configResponse.json();
|
|
88283
|
+
const response2 = await fetch("https://api.workos.com/user_management/authorize/device", {
|
|
88284
|
+
method: "POST",
|
|
88285
|
+
headers: { "Content-Type": "application/json" },
|
|
88286
|
+
body: JSON.stringify({ client_id: cliConfig.workosClientId })
|
|
88287
|
+
});
|
|
88288
|
+
if (response2.ok) {
|
|
88289
|
+
const deviceInfo2 = await response2.json();
|
|
88290
|
+
return {
|
|
88291
|
+
mode: "workos",
|
|
88292
|
+
clientId: cliConfig.workosClientId,
|
|
88293
|
+
deviceInfo: deviceInfo2
|
|
88294
|
+
};
|
|
88295
|
+
}
|
|
88296
|
+
}
|
|
88297
|
+
} catch {}
|
|
88298
|
+
const response = await fetch(`${url2}/auth/device/code`, {
|
|
88299
|
+
method: "POST",
|
|
88300
|
+
headers: { "Content-Type": "application/json" }
|
|
88301
|
+
});
|
|
88302
|
+
if (!response.ok) {
|
|
88303
|
+
throw new Error("Failed to start device authorization");
|
|
88304
|
+
}
|
|
88305
|
+
const deviceInfo = await response.json();
|
|
88306
|
+
return { mode: "legacy", deviceInfo };
|
|
88307
|
+
}
|
|
88308
|
+
async function pollWorkOSToken(params) {
|
|
88309
|
+
const { clientId, deviceCode, interval, expiresIn, signal } = params;
|
|
88310
|
+
const deadline = Date.now() + expiresIn * 1000;
|
|
88311
|
+
while (Date.now() < deadline) {
|
|
88312
|
+
if (signal?.aborted)
|
|
88313
|
+
throw new Error("Authorization cancelled");
|
|
88314
|
+
await sleep2(interval * 1000);
|
|
88315
|
+
if (signal?.aborted)
|
|
88316
|
+
throw new Error("Authorization cancelled");
|
|
88317
|
+
try {
|
|
88318
|
+
const response = await fetch("https://api.workos.com/user_management/authenticate", {
|
|
88319
|
+
method: "POST",
|
|
88320
|
+
headers: { "Content-Type": "application/json" },
|
|
88321
|
+
body: JSON.stringify({
|
|
88322
|
+
client_id: clientId,
|
|
88323
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
88324
|
+
device_code: deviceCode
|
|
88325
|
+
})
|
|
88326
|
+
});
|
|
88327
|
+
if (response.status === 400) {
|
|
88328
|
+
continue;
|
|
88329
|
+
}
|
|
88330
|
+
if (!response.ok) {
|
|
88331
|
+
throw new Error("Authentication failed");
|
|
88332
|
+
}
|
|
88333
|
+
const data = await response.json();
|
|
88334
|
+
return {
|
|
88335
|
+
accessToken: data.access_token,
|
|
88336
|
+
refreshToken: data.refresh_token
|
|
88337
|
+
};
|
|
88338
|
+
} catch (err) {
|
|
88339
|
+
if (err instanceof Error && (err.message === "Authentication failed" || err.message === "Authorization cancelled")) {
|
|
88340
|
+
throw err;
|
|
88341
|
+
}
|
|
88342
|
+
}
|
|
88236
88343
|
}
|
|
88344
|
+
throw new Error("Authorization timed out. Please try again.");
|
|
88237
88345
|
}
|
|
88238
|
-
|
|
88239
|
-
|
|
88346
|
+
async function pollLegacyToken(params) {
|
|
88347
|
+
const { apiUrl, deviceCode, interval, expiresIn, signal } = params;
|
|
88348
|
+
const deadline = Date.now() + expiresIn * 1000;
|
|
88349
|
+
while (Date.now() < deadline) {
|
|
88350
|
+
if (signal?.aborted)
|
|
88351
|
+
throw new Error("Authorization cancelled");
|
|
88352
|
+
await sleep2(interval * 1000);
|
|
88353
|
+
if (signal?.aborted)
|
|
88354
|
+
throw new Error("Authorization cancelled");
|
|
88355
|
+
try {
|
|
88356
|
+
const response = await fetch(`${apiUrl}/auth/device/token`, {
|
|
88357
|
+
method: "POST",
|
|
88358
|
+
headers: { "Content-Type": "application/json" },
|
|
88359
|
+
body: JSON.stringify({ deviceCode })
|
|
88360
|
+
});
|
|
88361
|
+
if (!response.ok)
|
|
88362
|
+
continue;
|
|
88363
|
+
const data = await response.json();
|
|
88364
|
+
if (data.status === "complete" && data.apiKey) {
|
|
88365
|
+
return data;
|
|
88366
|
+
}
|
|
88367
|
+
if (data.status === "expired") {
|
|
88368
|
+
throw new Error("Authorization expired. Please try again.");
|
|
88369
|
+
}
|
|
88370
|
+
if (data.status === "not_found") {
|
|
88371
|
+
throw new Error("Invalid authorization session. Please try again.");
|
|
88372
|
+
}
|
|
88373
|
+
} catch (err) {
|
|
88374
|
+
if (signal?.aborted) {
|
|
88375
|
+
throw new Error("Authorization cancelled", { cause: err });
|
|
88376
|
+
}
|
|
88377
|
+
if (err instanceof Error && err.message.includes("Please try again")) {
|
|
88378
|
+
throw err;
|
|
88379
|
+
}
|
|
88380
|
+
}
|
|
88381
|
+
}
|
|
88382
|
+
throw new Error("Authorization timed out. Please try again.");
|
|
88383
|
+
}
|
|
88384
|
+
var init_device_flow = () => {};
|
|
88385
|
+
|
|
88386
|
+
// src/core/auth/workspaces.ts
|
|
88387
|
+
function sleep3(ms) {
|
|
88388
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
88389
|
+
}
|
|
88390
|
+
async function fetchWorkspaces(apiUrl, accessToken) {
|
|
88391
|
+
const response = await fetch(`${apiUrl}/api/cli/workspaces`, {
|
|
88392
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
88393
|
+
});
|
|
88394
|
+
if (!response.ok) {
|
|
88395
|
+
throw new Error(`Failed to fetch workspaces (${response.status})`);
|
|
88396
|
+
}
|
|
88397
|
+
const data = await response.json();
|
|
88398
|
+
return data.workspaces;
|
|
88399
|
+
}
|
|
88400
|
+
async function pollForWorkspaceCreation(apiUrl, accessToken, signal) {
|
|
88401
|
+
const POLL_INTERVAL = 3000;
|
|
88402
|
+
const TIMEOUT = 5 * 60 * 1000;
|
|
88403
|
+
const deadline = Date.now() + TIMEOUT;
|
|
88404
|
+
while (Date.now() < deadline) {
|
|
88405
|
+
if (signal?.aborted)
|
|
88406
|
+
throw new Error("Cancelled");
|
|
88407
|
+
await sleep3(POLL_INTERVAL);
|
|
88408
|
+
if (signal?.aborted)
|
|
88409
|
+
throw new Error("Cancelled");
|
|
88410
|
+
try {
|
|
88411
|
+
const response = await fetch(`${apiUrl}/api/cli/workspaces`, {
|
|
88412
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
88413
|
+
});
|
|
88414
|
+
if (!response.ok)
|
|
88415
|
+
continue;
|
|
88416
|
+
const data = await response.json();
|
|
88417
|
+
if (data.workspaces.length > 0) {
|
|
88418
|
+
return data.workspaces;
|
|
88419
|
+
}
|
|
88420
|
+
} catch {}
|
|
88421
|
+
}
|
|
88422
|
+
throw new Error("Workspace creation timed out. Please try again.");
|
|
88423
|
+
}
|
|
88424
|
+
async function selectWorkspace(apiUrl, accessToken, workspaceId) {
|
|
88425
|
+
const response = await fetch(`${apiUrl}/api/cli/select-workspace`, {
|
|
88426
|
+
method: "POST",
|
|
88427
|
+
headers: {
|
|
88428
|
+
"Content-Type": "application/json",
|
|
88429
|
+
Authorization: `Bearer ${accessToken}`
|
|
88430
|
+
},
|
|
88431
|
+
body: JSON.stringify({ workspaceId })
|
|
88432
|
+
});
|
|
88433
|
+
if (!response.ok) {
|
|
88434
|
+
throw new Error("Failed to select workspace");
|
|
88435
|
+
}
|
|
88436
|
+
return await response.json();
|
|
88437
|
+
}
|
|
88438
|
+
|
|
88439
|
+
// src/core/auth/connection.ts
|
|
88440
|
+
function isConnected(cfg) {
|
|
88441
|
+
return !!(cfg.accessToken || cfg.pensarAPIKey);
|
|
88442
|
+
}
|
|
88443
|
+
async function disconnect() {
|
|
88444
|
+
await config2.update({
|
|
88445
|
+
pensarAPIKey: null,
|
|
88446
|
+
accessToken: null,
|
|
88447
|
+
refreshToken: null,
|
|
88448
|
+
workspaceId: null,
|
|
88449
|
+
workspaceSlug: null,
|
|
88450
|
+
gatewaySigningKey: null
|
|
88451
|
+
});
|
|
88452
|
+
}
|
|
88453
|
+
var init_connection = __esm(() => {
|
|
88240
88454
|
init_config2();
|
|
88241
88455
|
});
|
|
88242
88456
|
|
|
88457
|
+
// src/core/auth/index.ts
|
|
88458
|
+
var init_auth = __esm(() => {
|
|
88459
|
+
init_signing();
|
|
88460
|
+
init_token();
|
|
88461
|
+
init_device_flow();
|
|
88462
|
+
init_connection();
|
|
88463
|
+
});
|
|
88464
|
+
|
|
88243
88465
|
// src/core/ai/utils.ts
|
|
88244
88466
|
function buildAuthConfig(cfg) {
|
|
88245
88467
|
return {
|
|
@@ -88252,6 +88474,7 @@ function buildAuthConfig(cfg) {
|
|
|
88252
88474
|
accessToken: cfg.accessToken ?? undefined,
|
|
88253
88475
|
refreshToken: cfg.refreshToken ?? undefined,
|
|
88254
88476
|
workspaceId: cfg.workspaceId ?? undefined,
|
|
88477
|
+
gatewaySigningKey: cfg.gatewaySigningKey ?? undefined,
|
|
88255
88478
|
bedrock: cfg.bedrockAPIKey ? { apiKey: cfg.bedrockAPIKey } : undefined,
|
|
88256
88479
|
local: cfg.localModelUrl ? { baseURL: cfg.localModelUrl } : undefined
|
|
88257
88480
|
};
|
|
@@ -88332,7 +88555,8 @@ function getProviderModel(model, authConfig) {
|
|
|
88332
88555
|
const modelConfig = {
|
|
88333
88556
|
apiKey: pensarApiKey || authConfig?.accessToken || "",
|
|
88334
88557
|
baseUrl: pensarApiUrl,
|
|
88335
|
-
workspaceId: authConfig?.workspaceId
|
|
88558
|
+
workspaceId: authConfig?.workspaceId,
|
|
88559
|
+
signingKey: authConfig?.gatewaySigningKey
|
|
88336
88560
|
};
|
|
88337
88561
|
if (hasWorkOSAuth) {
|
|
88338
88562
|
modelConfig.getToken = async () => {
|
|
@@ -88523,7 +88747,7 @@ var init_utils = __esm(() => {
|
|
|
88523
88747
|
init_dist13();
|
|
88524
88748
|
init_models();
|
|
88525
88749
|
init_pensar2();
|
|
88526
|
-
|
|
88750
|
+
init_auth();
|
|
88527
88751
|
init_config2();
|
|
88528
88752
|
init_dist5();
|
|
88529
88753
|
});
|
|
@@ -108198,7 +108422,7 @@ var init_cvssScorer = __esm(() => {
|
|
|
108198
108422
|
|
|
108199
108423
|
// src/core/agents/offSecAgent/tools/documentFinding.ts
|
|
108200
108424
|
import { join as join11 } from "path";
|
|
108201
|
-
import { writeFileSync as writeFileSync7, appendFileSync as appendFileSync2 } from "fs";
|
|
108425
|
+
import { writeFileSync as writeFileSync7, appendFileSync as appendFileSync2, readFileSync as readFileSync7 } from "fs";
|
|
108202
108426
|
function documentVulnerability(ctx4) {
|
|
108203
108427
|
const { session } = ctx4;
|
|
108204
108428
|
return tool({
|
|
@@ -108271,12 +108495,21 @@ FINDING STRUCTURE:
|
|
|
108271
108495
|
};
|
|
108272
108496
|
}
|
|
108273
108497
|
}
|
|
108498
|
+
let pocOutput = null;
|
|
108499
|
+
if (input.pocPath) {
|
|
108500
|
+
try {
|
|
108501
|
+
const pocBasename = input.pocPath.replace(/^pocs\//, "");
|
|
108502
|
+
const outputPath = join11(session.pocsPath, `${pocBasename}.output.json`);
|
|
108503
|
+
pocOutput = JSON.parse(readFileSync7(outputPath, "utf-8"));
|
|
108504
|
+
} catch {}
|
|
108505
|
+
}
|
|
108274
108506
|
const findingWithMeta = {
|
|
108275
108507
|
...finding,
|
|
108276
108508
|
timestamp,
|
|
108277
108509
|
sessionId: session.id,
|
|
108278
108510
|
target: session.targets[0],
|
|
108279
108511
|
...evidenceFilePath && { evidenceFile: evidenceFilePath },
|
|
108512
|
+
...pocOutput && { pocOutput },
|
|
108280
108513
|
cwes: cvssResult.cwes,
|
|
108281
108514
|
cvss: {
|
|
108282
108515
|
score: cvssResult.score,
|
|
@@ -108515,6 +108748,8 @@ async function executeLocalPoc(ctx4, poc, currentAttempts) {
|
|
|
108515
108748
|
try {
|
|
108516
108749
|
unlinkSync(pocPath);
|
|
108517
108750
|
} catch {}
|
|
108751
|
+
} else {
|
|
108752
|
+
writePocOutputSidecar(pocsPath, filename, stdout, stderr, exitCode, poc.description);
|
|
108518
108753
|
}
|
|
108519
108754
|
return {
|
|
108520
108755
|
success: exitCode === 0,
|
|
@@ -108563,6 +108798,8 @@ async function executeSandboxPoc(ctx4, poc, currentAttempts) {
|
|
|
108563
108798
|
try {
|
|
108564
108799
|
unlinkSync(localPocPath);
|
|
108565
108800
|
} catch {}
|
|
108801
|
+
} else {
|
|
108802
|
+
writePocOutputSidecar(localPocsPath, filename, result.stdout || "", result.stderr || "", result.exitCode, poc.description);
|
|
108566
108803
|
}
|
|
108567
108804
|
return {
|
|
108568
108805
|
success: executionSuccess,
|
|
@@ -108584,6 +108821,19 @@ POC file has been deleted.`,
|
|
|
108584
108821
|
};
|
|
108585
108822
|
}
|
|
108586
108823
|
}
|
|
108824
|
+
function writePocOutputSidecar(pocsPath, filename, stdout, stderr, exitCode, description) {
|
|
108825
|
+
try {
|
|
108826
|
+
const outputPath = join12(pocsPath, `${filename}.output.json`);
|
|
108827
|
+
writeFileSync8(outputPath, JSON.stringify({
|
|
108828
|
+
stdout,
|
|
108829
|
+
stderr,
|
|
108830
|
+
exitCode,
|
|
108831
|
+
executedAt: new Date().toISOString(),
|
|
108832
|
+
pocFile: filename,
|
|
108833
|
+
description
|
|
108834
|
+
}, null, 2));
|
|
108835
|
+
} catch {}
|
|
108836
|
+
}
|
|
108587
108837
|
function preparePoc(poc, currentAttempts) {
|
|
108588
108838
|
const extension = poc.pocType === "bash" ? ".sh" : poc.pocType === "python" ? ".py" : ".js";
|
|
108589
108839
|
const sanitizedName = sanitizeFilename(poc.pocName);
|
|
@@ -109758,7 +110008,7 @@ If you encounter rate-limiting errors (e.g. "Rate limit exceeded", HTTP 429, "to
|
|
|
109758
110008
|
`;
|
|
109759
110009
|
|
|
109760
110010
|
// src/core/agents/specialized/authenticationAgent/agent.ts
|
|
109761
|
-
import { existsSync as existsSync18, readFileSync as
|
|
110011
|
+
import { existsSync as existsSync18, readFileSync as readFileSync8 } from "fs";
|
|
109762
110012
|
import { join as join16 } from "path";
|
|
109763
110013
|
function loadAuthResult(authDataPath) {
|
|
109764
110014
|
if (!existsSync18(authDataPath)) {
|
|
@@ -109773,7 +110023,7 @@ function loadAuthResult(authDataPath) {
|
|
|
109773
110023
|
};
|
|
109774
110024
|
}
|
|
109775
110025
|
try {
|
|
109776
|
-
const raw = JSON.parse(
|
|
110026
|
+
const raw = JSON.parse(readFileSync8(authDataPath, "utf-8"));
|
|
109777
110027
|
return {
|
|
109778
110028
|
success: raw.authenticated ?? false,
|
|
109779
110029
|
summary: raw.summary ?? "Authentication process completed.",
|
|
@@ -109894,7 +110144,9 @@ var init_agent = __esm(() => {
|
|
|
109894
110144
|
"email_list_inboxes",
|
|
109895
110145
|
"email_list_messages",
|
|
109896
110146
|
"email_search_messages",
|
|
109897
|
-
"email_get_message"
|
|
110147
|
+
"email_get_message",
|
|
110148
|
+
"web_search",
|
|
110149
|
+
"get_page"
|
|
109898
110150
|
],
|
|
109899
110151
|
stopWhen: hasToolCall("complete_authentication"),
|
|
109900
110152
|
resolveResult: () => {
|
|
@@ -111386,7 +111638,7 @@ var init_runAttackSurface = __esm(() => {
|
|
|
111386
111638
|
});
|
|
111387
111639
|
|
|
111388
111640
|
// src/core/findings/registry.ts
|
|
111389
|
-
import { existsSync as existsSync20, readdirSync as readdirSync3, readFileSync as
|
|
111641
|
+
import { existsSync as existsSync20, readdirSync as readdirSync3, readFileSync as readFileSync9 } from "fs";
|
|
111390
111642
|
import { join as join20 } from "path";
|
|
111391
111643
|
function extractVulnClass(title) {
|
|
111392
111644
|
const t2 = title.trim();
|
|
@@ -111466,7 +111718,7 @@ class FindingsRegistry {
|
|
|
111466
111718
|
const files = readdirSync3(findingsPath).filter((f) => f.endsWith(".json"));
|
|
111467
111719
|
for (const file2 of files) {
|
|
111468
111720
|
try {
|
|
111469
|
-
const raw =
|
|
111721
|
+
const raw = readFileSync9(join20(findingsPath, file2), "utf-8");
|
|
111470
111722
|
const finding = JSON.parse(raw);
|
|
111471
111723
|
if (finding && typeof finding.title === "string" && typeof finding.endpoint === "string") {
|
|
111472
111724
|
registry2.indexFinding(finding);
|
|
@@ -111791,7 +112043,9 @@ var init_agent3 = __esm(() => {
|
|
|
111791
112043
|
"list_files",
|
|
111792
112044
|
"grep",
|
|
111793
112045
|
"execute_command",
|
|
111794
|
-
"document_asset"
|
|
112046
|
+
"document_asset",
|
|
112047
|
+
"web_search",
|
|
112048
|
+
"get_page"
|
|
111795
112049
|
];
|
|
111796
112050
|
if (responseSchema2) {
|
|
111797
112051
|
activeTools.push("response");
|
|
@@ -157509,7 +157763,7 @@ var require_gaxios = __commonJS((exports) => {
|
|
|
157509
157763
|
var retry_js_1 = require_retry();
|
|
157510
157764
|
var stream_1 = __require("stream");
|
|
157511
157765
|
var interceptor_js_1 = require_interceptor();
|
|
157512
|
-
var
|
|
157766
|
+
var randomUUID2 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
|
|
157513
157767
|
var HTTP_STATUS_NO_CONTENT = 204;
|
|
157514
157768
|
|
|
157515
157769
|
class Gaxios {
|
|
@@ -157720,7 +157974,7 @@ var require_gaxios = __commonJS((exports) => {
|
|
|
157720
157974
|
}
|
|
157721
157975
|
const shouldDirectlyPassData = typeof opts.data === "string" || opts.data instanceof ArrayBuffer || opts.data instanceof Blob || globalThis.File && opts.data instanceof File || opts.data instanceof FormData || opts.data instanceof stream_1.Readable || opts.data instanceof ReadableStream || opts.data instanceof String || opts.data instanceof URLSearchParams || ArrayBuffer.isView(opts.data) || ["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
|
|
157722
157976
|
if (opts.multipart?.length) {
|
|
157723
|
-
const boundary = await
|
|
157977
|
+
const boundary = await randomUUID2();
|
|
157724
157978
|
preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
|
|
157725
157979
|
opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
|
|
157726
157980
|
} else if (shouldDirectlyPassData) {
|
|
@@ -168699,7 +168953,7 @@ var require_apirequest = __commonJS((exports) => {
|
|
|
168699
168953
|
var h22 = require_http2();
|
|
168700
168954
|
var util_1 = require_util7();
|
|
168701
168955
|
var pkg = require_package4();
|
|
168702
|
-
var
|
|
168956
|
+
var randomUUID2 = () => globalThis.crypto?.randomUUID() || __require("crypto").randomUUID();
|
|
168703
168957
|
function isReadableStream(obj) {
|
|
168704
168958
|
return obj !== null && typeof obj === "object" && typeof obj.pipe === "function" && obj.readable !== false && typeof obj._read === "function" && typeof obj._readableState === "object";
|
|
168705
168959
|
}
|
|
@@ -168772,7 +169026,7 @@ var require_apirequest = __commonJS((exports) => {
|
|
|
168772
169026
|
authClient = undefined;
|
|
168773
169027
|
}
|
|
168774
169028
|
function multipartUpload(multipart) {
|
|
168775
|
-
const boundary =
|
|
169029
|
+
const boundary = randomUUID2();
|
|
168776
169030
|
const finale = `--${boundary}--`;
|
|
168777
169031
|
const rStream = new stream.PassThrough({
|
|
168778
169032
|
flush(callback) {
|
|
@@ -168811,7 +169065,7 @@ content-type: ${part["content-type"]}\r
|
|
|
168811
169065
|
options.data = rStream;
|
|
168812
169066
|
}
|
|
168813
169067
|
function browserMultipartUpload(multipart) {
|
|
168814
|
-
const boundary =
|
|
169068
|
+
const boundary = randomUUID2();
|
|
168815
169069
|
const finale = `--${boundary}--`;
|
|
168816
169070
|
headers["content-type"] = `multipart/related; boundary=${boundary}`;
|
|
168817
169071
|
let content = "";
|
|
@@ -176322,7 +176576,7 @@ var require_quick_format_unescaped = __commonJS((exports, module2) => {
|
|
|
176322
176576
|
// node_modules/atomic-sleep/index.js
|
|
176323
176577
|
var require_atomic_sleep = __commonJS((exports, module2) => {
|
|
176324
176578
|
if (typeof SharedArrayBuffer !== "undefined" && typeof Atomics !== "undefined") {
|
|
176325
|
-
let
|
|
176579
|
+
let sleep4 = function(ms) {
|
|
176326
176580
|
const valid = ms > 0 && ms < Infinity;
|
|
176327
176581
|
if (valid === false) {
|
|
176328
176582
|
if (typeof ms !== "number" && typeof ms !== "bigint") {
|
|
@@ -176333,9 +176587,9 @@ var require_atomic_sleep = __commonJS((exports, module2) => {
|
|
|
176333
176587
|
Atomics.wait(nil, 0, 0, Number(ms));
|
|
176334
176588
|
};
|
|
176335
176589
|
const nil = new Int32Array(new SharedArrayBuffer(4));
|
|
176336
|
-
module2.exports =
|
|
176590
|
+
module2.exports = sleep4;
|
|
176337
176591
|
} else {
|
|
176338
|
-
let
|
|
176592
|
+
let sleep4 = function(ms) {
|
|
176339
176593
|
const valid = ms > 0 && ms < Infinity;
|
|
176340
176594
|
if (valid === false) {
|
|
176341
176595
|
if (typeof ms !== "number" && typeof ms !== "bigint") {
|
|
@@ -176346,7 +176600,7 @@ var require_atomic_sleep = __commonJS((exports, module2) => {
|
|
|
176346
176600
|
const target = Date.now() + Number(ms);
|
|
176347
176601
|
while (target > Date.now()) {}
|
|
176348
176602
|
};
|
|
176349
|
-
module2.exports =
|
|
176603
|
+
module2.exports = sleep4;
|
|
176350
176604
|
}
|
|
176351
176605
|
});
|
|
176352
176606
|
|
|
@@ -176356,7 +176610,7 @@ var require_sonic_boom = __commonJS((exports, module2) => {
|
|
|
176356
176610
|
var EventEmitter11 = __require("events");
|
|
176357
176611
|
var inherits = __require("util").inherits;
|
|
176358
176612
|
var path6 = __require("path");
|
|
176359
|
-
var
|
|
176613
|
+
var sleep4 = require_atomic_sleep();
|
|
176360
176614
|
var assert2 = __require("assert");
|
|
176361
176615
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
176362
176616
|
var kEmptyBuffer = Buffer.allocUnsafe(0);
|
|
@@ -176504,7 +176758,7 @@ var require_sonic_boom = __commonJS((exports, module2) => {
|
|
|
176504
176758
|
if ((err.code === "EAGAIN" || err.code === "EBUSY") && this.retryEAGAIN(err, this._writingBuf.length, this._len - this._writingBuf.length)) {
|
|
176505
176759
|
if (this.sync) {
|
|
176506
176760
|
try {
|
|
176507
|
-
|
|
176761
|
+
sleep4(BUSY_WRITE_TIMEOUT);
|
|
176508
176762
|
this.release(undefined, 0);
|
|
176509
176763
|
} catch (err2) {
|
|
176510
176764
|
this.release(err2);
|
|
@@ -176818,7 +177072,7 @@ var require_sonic_boom = __commonJS((exports, module2) => {
|
|
|
176818
177072
|
if (shouldRetry && !this.retryEAGAIN(err, buf.length, this._len - buf.length)) {
|
|
176819
177073
|
throw err;
|
|
176820
177074
|
}
|
|
176821
|
-
|
|
177075
|
+
sleep4(BUSY_WRITE_TIMEOUT);
|
|
176822
177076
|
}
|
|
176823
177077
|
}
|
|
176824
177078
|
try {
|
|
@@ -176854,7 +177108,7 @@ var require_sonic_boom = __commonJS((exports, module2) => {
|
|
|
176854
177108
|
if (shouldRetry && !this.retryEAGAIN(err, buf.length, this._len - buf.length)) {
|
|
176855
177109
|
throw err;
|
|
176856
177110
|
}
|
|
176857
|
-
|
|
177111
|
+
sleep4(BUSY_WRITE_TIMEOUT);
|
|
176858
177112
|
}
|
|
176859
177113
|
}
|
|
176860
177114
|
}
|
|
@@ -177575,7 +177829,7 @@ var require_transport = __commonJS((exports, module2) => {
|
|
|
177575
177829
|
var getCallers = require_caller();
|
|
177576
177830
|
var { join: join22, isAbsolute: isAbsolute6, sep } = __require("node:path");
|
|
177577
177831
|
var { fileURLToPath: fileURLToPath2 } = __require("node:url");
|
|
177578
|
-
var
|
|
177832
|
+
var sleep4 = require_atomic_sleep();
|
|
177579
177833
|
var onExit = require_on_exit_leak_free();
|
|
177580
177834
|
var ThreadStream = require_thread_stream();
|
|
177581
177835
|
function setupOnExit(stream) {
|
|
@@ -177698,7 +177952,7 @@ var require_transport = __commonJS((exports, module2) => {
|
|
|
177698
177952
|
return;
|
|
177699
177953
|
}
|
|
177700
177954
|
stream.flushSync();
|
|
177701
|
-
|
|
177955
|
+
sleep4(100);
|
|
177702
177956
|
stream.end();
|
|
177703
177957
|
}
|
|
177704
177958
|
return stream;
|
|
@@ -187450,7 +187704,7 @@ var require_tools2 = __commonJS((exports, module2) => {
|
|
|
187450
187704
|
var libmime = require_libmime();
|
|
187451
187705
|
var { resolveCharset } = require_charsets2();
|
|
187452
187706
|
var { compiler } = require_imap_handler();
|
|
187453
|
-
var { createHash } = __require("crypto");
|
|
187707
|
+
var { createHash: createHash2 } = __require("crypto");
|
|
187454
187708
|
var { JPDecoder } = require_jp_decoder();
|
|
187455
187709
|
var iconv = require_lib10();
|
|
187456
187710
|
var FLAG_COLORS = ["red", "orange", "yellow", "green", "blue", "purple", "grey"];
|
|
@@ -187757,7 +188011,7 @@ var require_tools2 = __commonJS((exports, module2) => {
|
|
|
187757
188011
|
path6 = iconv.encode(path6, "utf-7-imap").toString();
|
|
187758
188012
|
} catch {}
|
|
187759
188013
|
}
|
|
187760
|
-
map3.id = map3.emailId ||
|
|
188014
|
+
map3.id = map3.emailId || createHash2("md5").update([path6, mailbox.uidValidity?.toString() || "", map3.uid.toString()].join(":")).digest("hex");
|
|
187761
188015
|
}
|
|
187762
188016
|
if (map3.flags) {
|
|
187763
188017
|
let flagColor = tools.getFlagColor(map3.flags);
|
|
@@ -193506,6 +193760,235 @@ var init_email = __esm(() => {
|
|
|
193506
193760
|
];
|
|
193507
193761
|
});
|
|
193508
193762
|
|
|
193763
|
+
// src/core/agents/offSecAgent/tools/webSearch.ts
|
|
193764
|
+
function webSearch2(_ctx) {
|
|
193765
|
+
return tool({
|
|
193766
|
+
description: `Search the web for real-time information about any topic. Returns summarized information from search results.
|
|
193767
|
+
|
|
193768
|
+
USAGE GUIDANCE:
|
|
193769
|
+
- Use this tool to look up CVEs, security advisories, and vulnerability details
|
|
193770
|
+
- Search for exploit techniques, payloads, and bypass methods
|
|
193771
|
+
- Research target technologies, frameworks, and their known vulnerabilities
|
|
193772
|
+
- Find documentation for tools, APIs, and security testing techniques
|
|
193773
|
+
- Look up default credentials, common misconfigurations, and hardening guides
|
|
193774
|
+
|
|
193775
|
+
IMPORTANT: This tool requires a Pensar account. If you're not signed in, you'll receive an error message with instructions to sign in.
|
|
193776
|
+
|
|
193777
|
+
COMMON SEARCH PATTERNS:
|
|
193778
|
+
- "CVE-2024-XXXX exploit" — Find details about specific CVEs
|
|
193779
|
+
- "Apache Struts RCE vulnerability" — Research known vulnerabilities in specific software
|
|
193780
|
+
- "SSRF bypass techniques" — Find security testing techniques
|
|
193781
|
+
- "Spring Boot actuator default credentials" — Look up default credentials
|
|
193782
|
+
- "JWT token security vulnerabilities" — Research vulnerability classes`,
|
|
193783
|
+
inputSchema: webSearchInputSchema2,
|
|
193784
|
+
execute: async ({ query }) => {
|
|
193785
|
+
try {
|
|
193786
|
+
const cfg = await config2.get();
|
|
193787
|
+
const tokenResult = await ensureValidToken({
|
|
193788
|
+
accessToken: cfg.accessToken,
|
|
193789
|
+
refreshToken: cfg.refreshToken,
|
|
193790
|
+
pensarAPIKey: cfg.pensarAPIKey
|
|
193791
|
+
});
|
|
193792
|
+
if (!tokenResult) {
|
|
193793
|
+
return {
|
|
193794
|
+
success: false,
|
|
193795
|
+
results: [],
|
|
193796
|
+
error: "Web search requires a Pensar account. Please sign in to your Pensar account to use this feature. You can sign in via the TUI settings or by running 'pensar auth login'."
|
|
193797
|
+
};
|
|
193798
|
+
}
|
|
193799
|
+
if (!cfg.workspaceId) {
|
|
193800
|
+
return {
|
|
193801
|
+
success: false,
|
|
193802
|
+
results: [],
|
|
193803
|
+
error: "Web search requires a workspace. Please sign in to your Pensar account."
|
|
193804
|
+
};
|
|
193805
|
+
}
|
|
193806
|
+
if (!cfg.gatewaySigningKey) {
|
|
193807
|
+
return {
|
|
193808
|
+
success: false,
|
|
193809
|
+
results: [],
|
|
193810
|
+
error: "Web search requires authentication. Please sign in again to your Pensar account."
|
|
193811
|
+
};
|
|
193812
|
+
}
|
|
193813
|
+
const apiUrl = getPensarApiUrl();
|
|
193814
|
+
const body = JSON.stringify({ query });
|
|
193815
|
+
const { signature, timestamp, nonce } = signGatewayRequest(cfg.gatewaySigningKey, "web_search", body);
|
|
193816
|
+
const response = await fetch(`${apiUrl}/agents/web_search`, {
|
|
193817
|
+
method: "POST",
|
|
193818
|
+
headers: {
|
|
193819
|
+
"Content-Type": "application/json",
|
|
193820
|
+
Authorization: `Bearer ${tokenResult.token}`,
|
|
193821
|
+
"X-Workspace-Id": cfg.workspaceId,
|
|
193822
|
+
"X-Pensar-Timestamp": timestamp,
|
|
193823
|
+
"X-Pensar-Nonce": nonce,
|
|
193824
|
+
"X-Pensar-Signature": signature
|
|
193825
|
+
},
|
|
193826
|
+
body
|
|
193827
|
+
});
|
|
193828
|
+
if (!response.ok) {
|
|
193829
|
+
if (response.status === 401) {
|
|
193830
|
+
return {
|
|
193831
|
+
success: false,
|
|
193832
|
+
results: [],
|
|
193833
|
+
error: "Authentication failed. Please sign in again to your Pensar account."
|
|
193834
|
+
};
|
|
193835
|
+
}
|
|
193836
|
+
if (response.status === 429) {
|
|
193837
|
+
return {
|
|
193838
|
+
success: false,
|
|
193839
|
+
results: [],
|
|
193840
|
+
error: "Rate limit exceeded. Please wait a moment before searching again."
|
|
193841
|
+
};
|
|
193842
|
+
}
|
|
193843
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
193844
|
+
return {
|
|
193845
|
+
success: false,
|
|
193846
|
+
results: [],
|
|
193847
|
+
error: `Web search failed: ${response.status} ${response.statusText}. ${errorText}`
|
|
193848
|
+
};
|
|
193849
|
+
}
|
|
193850
|
+
const data = await response.json();
|
|
193851
|
+
if (data.error) {
|
|
193852
|
+
return {
|
|
193853
|
+
success: false,
|
|
193854
|
+
results: [],
|
|
193855
|
+
error: data.error
|
|
193856
|
+
};
|
|
193857
|
+
}
|
|
193858
|
+
return {
|
|
193859
|
+
success: true,
|
|
193860
|
+
results: data.results || []
|
|
193861
|
+
};
|
|
193862
|
+
} catch (error40) {
|
|
193863
|
+
const errorMsg = error40 instanceof Error ? error40.message : String(error40);
|
|
193864
|
+
return {
|
|
193865
|
+
success: false,
|
|
193866
|
+
results: [],
|
|
193867
|
+
error: `Web search failed: ${errorMsg}`
|
|
193868
|
+
};
|
|
193869
|
+
}
|
|
193870
|
+
}
|
|
193871
|
+
});
|
|
193872
|
+
}
|
|
193873
|
+
var webSearchInputSchema2;
|
|
193874
|
+
var init_webSearch = __esm(() => {
|
|
193875
|
+
init_dist5();
|
|
193876
|
+
init_zod();
|
|
193877
|
+
init_config2();
|
|
193878
|
+
init_auth();
|
|
193879
|
+
webSearchInputSchema2 = exports_external.object({
|
|
193880
|
+
query: exports_external.string().describe("The search query to look up. Be specific and include relevant keywords for better results."),
|
|
193881
|
+
toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing (e.g., 'Searching for CVE-2024-1234 details')")
|
|
193882
|
+
});
|
|
193883
|
+
});
|
|
193884
|
+
|
|
193885
|
+
// src/core/agents/offSecAgent/tools/getPage.ts
|
|
193886
|
+
function extractTitle(html) {
|
|
193887
|
+
const titleMatch = html.match(/<title[^>]*>([^<]+)<\/title>/i);
|
|
193888
|
+
return titleMatch?.[1]?.trim();
|
|
193889
|
+
}
|
|
193890
|
+
function extractTextContent2(html) {
|
|
193891
|
+
let text2 = html;
|
|
193892
|
+
text2 = text2.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "");
|
|
193893
|
+
text2 = text2.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "");
|
|
193894
|
+
text2 = text2.replace(/<noscript[^>]*>[\s\S]*?<\/noscript>/gi, "");
|
|
193895
|
+
text2 = text2.replace(/<!--[\s\S]*?-->/g, "");
|
|
193896
|
+
text2 = text2.replace(/<[^>]+>/g, " ");
|
|
193897
|
+
text2 = text2.replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'");
|
|
193898
|
+
text2 = text2.replace(/\s+/g, " ").trim();
|
|
193899
|
+
const lines = text2.split(/[.\n]/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
193900
|
+
return lines.join(`
|
|
193901
|
+
`);
|
|
193902
|
+
}
|
|
193903
|
+
function getPage(ctx4) {
|
|
193904
|
+
return tool({
|
|
193905
|
+
description: `Fetch and extract readable content from a web page. Returns the page title and main text content.
|
|
193906
|
+
|
|
193907
|
+
USAGE GUIDANCE:
|
|
193908
|
+
- Use this tool to read full content from URLs found via web_search
|
|
193909
|
+
- Fetch CVE details, security advisories, and vulnerability write-ups
|
|
193910
|
+
- Read documentation, API references, and technical guides
|
|
193911
|
+
- Extract exploit code, payloads, and proof-of-concept details from security blogs
|
|
193912
|
+
|
|
193913
|
+
BEST PRACTICES:
|
|
193914
|
+
- First use web_search to find relevant URLs, then use get_page to read the full content
|
|
193915
|
+
- Prefer authoritative sources (NVD, vendor advisories, security researcher blogs)
|
|
193916
|
+
- For large pages, focus on the most relevant sections
|
|
193917
|
+
- If content is truncated, the important information is usually near the beginning`,
|
|
193918
|
+
inputSchema: getPageInputSchema,
|
|
193919
|
+
execute: async ({ url: url2 }) => {
|
|
193920
|
+
try {
|
|
193921
|
+
const controller = new AbortController;
|
|
193922
|
+
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT);
|
|
193923
|
+
const combinedSignal = ctx4.abortSignal ? AbortSignal.any([ctx4.abortSignal, controller.signal]) : controller.signal;
|
|
193924
|
+
const response = await fetch(url2, {
|
|
193925
|
+
method: "GET",
|
|
193926
|
+
headers: {
|
|
193927
|
+
"User-Agent": "Mozilla/5.0 (compatible; PensarBot/1.0; +https://pensar.dev)",
|
|
193928
|
+
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
193929
|
+
"Accept-Language": "en-US,en;q=0.5"
|
|
193930
|
+
},
|
|
193931
|
+
signal: combinedSignal,
|
|
193932
|
+
redirect: "follow"
|
|
193933
|
+
});
|
|
193934
|
+
clearTimeout(timeoutId);
|
|
193935
|
+
if (!response.ok) {
|
|
193936
|
+
return {
|
|
193937
|
+
success: false,
|
|
193938
|
+
url: url2,
|
|
193939
|
+
error: `Failed to fetch page: ${response.status} ${response.statusText}`
|
|
193940
|
+
};
|
|
193941
|
+
}
|
|
193942
|
+
const contentType = response.headers.get("content-type") || "";
|
|
193943
|
+
if (!contentType.includes("text/html") && !contentType.includes("text/plain") && !contentType.includes("application/xhtml")) {
|
|
193944
|
+
return {
|
|
193945
|
+
success: false,
|
|
193946
|
+
url: url2,
|
|
193947
|
+
error: `Unsupported content type: ${contentType}. This tool only supports HTML and text pages.`
|
|
193948
|
+
};
|
|
193949
|
+
}
|
|
193950
|
+
const html = await response.text();
|
|
193951
|
+
const title = extractTitle(html);
|
|
193952
|
+
let content = extractTextContent2(html);
|
|
193953
|
+
if (content.length > MAX_CONTENT_LENGTH) {
|
|
193954
|
+
content = content.substring(0, MAX_CONTENT_LENGTH) + `
|
|
193955
|
+
|
|
193956
|
+
... (content truncated — page exceeded maximum length)`;
|
|
193957
|
+
}
|
|
193958
|
+
return {
|
|
193959
|
+
success: true,
|
|
193960
|
+
url: url2,
|
|
193961
|
+
title,
|
|
193962
|
+
content
|
|
193963
|
+
};
|
|
193964
|
+
} catch (error40) {
|
|
193965
|
+
if (error40 instanceof Error && error40.name === "AbortError") {
|
|
193966
|
+
return {
|
|
193967
|
+
success: false,
|
|
193968
|
+
url: url2,
|
|
193969
|
+
error: ctx4.abortSignal?.aborted ? "Request aborted by user" : `Request timeout after ${REQUEST_TIMEOUT / 1000}s`
|
|
193970
|
+
};
|
|
193971
|
+
}
|
|
193972
|
+
const errorMsg = error40 instanceof Error ? error40.message : String(error40);
|
|
193973
|
+
return {
|
|
193974
|
+
success: false,
|
|
193975
|
+
url: url2,
|
|
193976
|
+
error: `Failed to fetch page: ${errorMsg}`
|
|
193977
|
+
};
|
|
193978
|
+
}
|
|
193979
|
+
}
|
|
193980
|
+
});
|
|
193981
|
+
}
|
|
193982
|
+
var MAX_CONTENT_LENGTH = 50000, REQUEST_TIMEOUT = 30000, getPageInputSchema;
|
|
193983
|
+
var init_getPage = __esm(() => {
|
|
193984
|
+
init_dist5();
|
|
193985
|
+
init_zod();
|
|
193986
|
+
getPageInputSchema = exports_external.object({
|
|
193987
|
+
url: exports_external.string().url().describe("The URL of the page to fetch and extract content from."),
|
|
193988
|
+
toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing (e.g., 'Fetching CVE details from NVD')")
|
|
193989
|
+
});
|
|
193990
|
+
});
|
|
193991
|
+
|
|
193509
193992
|
// src/core/agents/offSecAgent/tools/index.ts
|
|
193510
193993
|
function createAllTools(ctx4) {
|
|
193511
193994
|
return {
|
|
@@ -193541,7 +194024,9 @@ function createAllTools(ctx4) {
|
|
|
193541
194024
|
email_list_inboxes: emailListInboxes(ctx4),
|
|
193542
194025
|
email_list_messages: emailListMessages(ctx4),
|
|
193543
194026
|
email_search_messages: emailSearchMessages(ctx4),
|
|
193544
|
-
email_get_message: emailGetMessage(ctx4)
|
|
194027
|
+
email_get_message: emailGetMessage(ctx4),
|
|
194028
|
+
web_search: webSearch2(ctx4),
|
|
194029
|
+
get_page: getPage(ctx4)
|
|
193545
194030
|
};
|
|
193546
194031
|
}
|
|
193547
194032
|
var ALL_TOOL_NAMES;
|
|
@@ -193576,6 +194061,8 @@ var init_tools = __esm(() => {
|
|
|
193576
194061
|
init_listMemories();
|
|
193577
194062
|
init_getMemory();
|
|
193578
194063
|
init_email();
|
|
194064
|
+
init_webSearch();
|
|
194065
|
+
init_getPage();
|
|
193579
194066
|
init_browserTools();
|
|
193580
194067
|
init_executeCommand();
|
|
193581
194068
|
init_httpRequest();
|
|
@@ -193609,6 +194096,8 @@ var init_tools = __esm(() => {
|
|
|
193609
194096
|
init_listMessages();
|
|
193610
194097
|
init_searchMessages();
|
|
193611
194098
|
init_getMessage();
|
|
194099
|
+
init_webSearch();
|
|
194100
|
+
init_getPage();
|
|
193612
194101
|
init_email();
|
|
193613
194102
|
ALL_TOOL_NAMES = [
|
|
193614
194103
|
"browser_navigate",
|
|
@@ -193645,7 +194134,9 @@ var init_tools = __esm(() => {
|
|
|
193645
194134
|
"email_get_message",
|
|
193646
194135
|
"email_search_messages",
|
|
193647
194136
|
"email_get_attachments",
|
|
193648
|
-
"email_mark_read"
|
|
194137
|
+
"email_mark_read",
|
|
194138
|
+
"web_search",
|
|
194139
|
+
"get_page"
|
|
193649
194140
|
];
|
|
193650
194141
|
});
|
|
193651
194142
|
|
|
@@ -194617,7 +195108,9 @@ var init_blackboxAgent = __esm(() => {
|
|
|
194617
195108
|
"email_list_inboxes",
|
|
194618
195109
|
"email_list_messages",
|
|
194619
195110
|
"email_search_messages",
|
|
194620
|
-
"email_get_message"
|
|
195111
|
+
"email_get_message",
|
|
195112
|
+
"web_search",
|
|
195113
|
+
"get_page"
|
|
194621
195114
|
],
|
|
194622
195115
|
stopWhen: [
|
|
194623
195116
|
hasToolCall("create_attack_surface_report"),
|
|
@@ -194641,7 +195134,7 @@ var init_blackboxAgent = __esm(() => {
|
|
|
194641
195134
|
});
|
|
194642
195135
|
|
|
194643
195136
|
// src/core/agents/specialized/pentest/agent.ts
|
|
194644
|
-
import { existsSync as existsSync23, readdirSync as readdirSync4, readFileSync as
|
|
195137
|
+
import { existsSync as existsSync23, readdirSync as readdirSync4, readFileSync as readFileSync10 } from "fs";
|
|
194645
195138
|
import { join as join24 } from "path";
|
|
194646
195139
|
function buildSystemPrompt(session) {
|
|
194647
195140
|
return session.config?.exfilMode ? PENTEST_SYSTEM_PROMPT_EXFIL : PENTEST_SYSTEM_PROMPT_BASE;
|
|
@@ -194656,7 +195149,7 @@ function buildPrompt4(target, objectives, session, findingsRegistry) {
|
|
|
194656
195149
|
const authDataPath = join24(sessionRootPath, "auth", "auth-data.json");
|
|
194657
195150
|
if (existsSync23(authDataPath)) {
|
|
194658
195151
|
try {
|
|
194659
|
-
const raw =
|
|
195152
|
+
const raw = readFileSync10(authDataPath, "utf-8");
|
|
194660
195153
|
const authData = JSON.parse(raw);
|
|
194661
195154
|
if (authData.authenticated) {
|
|
194662
195155
|
const parts = [
|
|
@@ -194697,7 +195190,7 @@ ${existing}`;
|
|
|
194697
195190
|
const markerPath = join24(sessionRootPath, "scratchpad", ".knowledge-populated");
|
|
194698
195191
|
if (existsSync23(markerPath)) {
|
|
194699
195192
|
try {
|
|
194700
|
-
const count = parseInt(
|
|
195193
|
+
const count = parseInt(readFileSync10(markerPath, "utf-8").trim(), 10) || 0;
|
|
194701
195194
|
if (count > 0) {
|
|
194702
195195
|
knowledgeBaseSection = `
|
|
194703
195196
|
|
|
@@ -194710,7 +195203,7 @@ There are ${count} project knowledge entries in the memory system from previous
|
|
|
194710
195203
|
const knowledgePath = join24(sessionRootPath, "scratchpad", "knowledge-base.md");
|
|
194711
195204
|
if (existsSync23(knowledgePath)) {
|
|
194712
195205
|
try {
|
|
194713
|
-
const knowledgeContent =
|
|
195206
|
+
const knowledgeContent = readFileSync10(knowledgePath, "utf-8").trim();
|
|
194714
195207
|
if (knowledgeContent) {
|
|
194715
195208
|
knowledgeBaseSection = `
|
|
194716
195209
|
|
|
@@ -194730,21 +195223,25 @@ ${outcomeGuidance}
|
|
|
194730
195223
|
Your target is a flag with the format FLAG{...}. Locate and extract it.
|
|
194731
195224
|
|
|
194732
195225
|
## Instructions
|
|
194733
|
-
1.
|
|
194734
|
-
2.
|
|
194735
|
-
3.
|
|
194736
|
-
4.
|
|
194737
|
-
5.
|
|
194738
|
-
6.
|
|
194739
|
-
7.
|
|
194740
|
-
8.
|
|
194741
|
-
|
|
194742
|
-
|
|
194743
|
-
|
|
194744
|
-
|
|
194745
|
-
|
|
194746
|
-
|
|
194747
|
-
|
|
195226
|
+
1. Call list_memories to review any prior knowledge relevant to this target or engagement
|
|
195227
|
+
2. State the objectives and outline your testing plan — describe which techniques and payloads you will use for each objective before executing any tools
|
|
195228
|
+
3. Verify the target endpoint is reachable and understand its baseline behavior
|
|
195229
|
+
4. For each objective, research and craft targeted payloads appropriate to the technology
|
|
195230
|
+
5. Test systematically — vary payloads, encoding, and bypass techniques
|
|
195231
|
+
6. Create POC scripts to reliably demonstrate any confirmed vulnerabilities
|
|
195232
|
+
7. When a vulnerability provides internal access, pivot through it to discover reachable services and extract sensitive data
|
|
195233
|
+
8. Document every confirmed vulnerability (using document_vulnerability) with evidence and remediation steps
|
|
195234
|
+
9. Use add_memory to save reusable learnings from this engagement (effective techniques, target behaviors, technology details)
|
|
195235
|
+
10. After testing ALL objectives and extracting the flag, call the response tool with your final summary. Do NOT call response until you have completed all testing and extraction.` : `## Instructions
|
|
195236
|
+
1. Call list_memories to review any prior knowledge relevant to this target or engagement
|
|
195237
|
+
2. State the objectives and outline your testing plan — describe which techniques and payloads you will use for each objective before executing any tools
|
|
195238
|
+
3. Verify the target endpoint is reachable and understand its baseline behavior
|
|
195239
|
+
4. For each objective, research and craft targeted payloads appropriate to the technology
|
|
195240
|
+
5. Test systematically — vary payloads, encoding, and bypass techniques
|
|
195241
|
+
6. Create POC scripts to reliably demonstrate any confirmed vulnerabilities
|
|
195242
|
+
7. Document every confirmed vulnerability (using document_vulnerability) with evidence and remediation steps — only if you have a working PoC
|
|
195243
|
+
8. Use add_memory to save reusable learnings from this engagement (effective techniques, target behaviors, technology details, false positive patterns)
|
|
195244
|
+
9. After testing ALL objectives, call the response tool with your final summary
|
|
194748
195245
|
|
|
194749
195246
|
Do NOT discover or enumerate other endpoints or services. Focus exclusively on the target and objectives above.`;
|
|
194750
195247
|
return `# Testing Assignment
|
|
@@ -194766,7 +195263,7 @@ function loadFindings(findingsPath) {
|
|
|
194766
195263
|
}
|
|
194767
195264
|
return readdirSync4(findingsPath).filter((f3) => f3.endsWith(".json")).map((f3) => {
|
|
194768
195265
|
try {
|
|
194769
|
-
const content =
|
|
195266
|
+
const content = readFileSync10(join24(findingsPath, f3), "utf-8");
|
|
194770
195267
|
return JSON.parse(content);
|
|
194771
195268
|
} catch {
|
|
194772
195269
|
return null;
|
|
@@ -194785,22 +195282,26 @@ CRITICAL — Source Code Prohibition:
|
|
|
194785
195282
|
- Your testing must rely exclusively on external interaction: sending requests, observing responses, and analyzing observable behavior.
|
|
194786
195283
|
|
|
194787
195284
|
Your methodology:
|
|
194788
|
-
1.
|
|
194789
|
-
2.
|
|
194790
|
-
3.
|
|
194791
|
-
4.
|
|
194792
|
-
5.
|
|
194793
|
-
6.
|
|
194794
|
-
7.
|
|
195285
|
+
1. ORIENT — Start by calling list_memories to review any existing knowledge from previous engagements (target-specific notes, successful techniques, false positive patterns, technology context). Use relevant findings to inform your testing plan.
|
|
195286
|
+
2. PLAN — State the objectives you have been given and outline your testing plan. For each objective, describe which attack techniques, payloads, and tools you intend to use. Output this plan as text before making any tool calls.
|
|
195287
|
+
3. VERIFY — Confirm the target endpoint exists and is reachable. Understand its basic behavior (response format, parameters, auth requirements).
|
|
195288
|
+
4. PREPARE — Research applicable payloads and attack techniques for the given objectives. Craft payloads tailored to the target's technology and behavior.
|
|
195289
|
+
5. TEST — Execute targeted attacks methodically, one payload/technique at a time. Observe responses carefully for indicators of vulnerability.
|
|
195290
|
+
6. EXPLOIT — When a vulnerability is confirmed, create a proof-of-concept script that reliably demonstrates it.
|
|
195291
|
+
7. DOCUMENT — Document every confirmed finding with evidence, impact assessment, and remediation steps.
|
|
195292
|
+
8. LEARN — Before finishing, use add_memory to persist reusable learnings from this engagement (e.g. target-specific behaviors, successful payload patterns, technology fingerprints, false positive patterns, credential formats). This knowledge helps future engagements be more efficient.
|
|
195293
|
+
9. FINISH — After testing ALL objectives and saving learnings, call the response tool to submit your final summary. You may document multiple findings before finishing.
|
|
194795
195294
|
|
|
194796
195295
|
Guidelines:
|
|
194797
|
-
- Always
|
|
195296
|
+
- Always call list_memories first to check for relevant knowledge before planning your approach
|
|
195297
|
+
- State your objectives and plan before executing any attack tools
|
|
194798
195298
|
- Stay focused on the provided objectives — do not scan for other services or enumerate additional endpoints
|
|
194799
195299
|
- Be methodical and thorough — test one payload at a time and observe the response
|
|
194800
195300
|
- Use execute_command for crafting/running exploit scripts and http_request for targeted web tests
|
|
194801
195301
|
- Always create POC scripts to confirm vulnerabilities before documenting
|
|
194802
195302
|
- Document every confirmed vulnerability with document_vulnerability — you can document multiple vulnerabilities in a single run
|
|
194803
195303
|
- Include clear remediation steps in every finding
|
|
195304
|
+
- Before finishing, use add_memory to save reusable learnings (target behaviors, effective techniques, technology details, false positive patterns)
|
|
194804
195305
|
- When you have finished testing ALL objectives, call the response tool with a summary of your results. Do NOT call response until you have completed all testing.
|
|
194805
195306
|
|
|
194806
195307
|
Rate Limiting:
|
|
@@ -194832,24 +195333,28 @@ Authentication:
|
|
|
194832
195333
|
You are given a specific target and specific objectives. Your job is to deeply test the provided target, and when vulnerabilities are confirmed, pivot through them to discover and extract sensitive data.
|
|
194833
195334
|
|
|
194834
195335
|
Your methodology:
|
|
194835
|
-
1.
|
|
194836
|
-
2.
|
|
194837
|
-
3.
|
|
194838
|
-
4.
|
|
194839
|
-
5.
|
|
194840
|
-
6.
|
|
194841
|
-
7.
|
|
194842
|
-
8.
|
|
194843
|
-
9.
|
|
195336
|
+
1. ORIENT — Start by calling list_memories to review any existing knowledge from previous engagements (target-specific notes, successful techniques, false positive patterns, technology context). Use relevant findings to inform your testing plan.
|
|
195337
|
+
2. PLAN — State the objectives you have been given and outline your testing plan. For each objective, describe which attack techniques, payloads, and tools you intend to use. Output this plan as text before making any tool calls.
|
|
195338
|
+
3. VERIFY — Confirm the target endpoint exists and is reachable. Understand its basic behavior (response format, parameters, auth requirements).
|
|
195339
|
+
4. PREPARE — Research applicable payloads and attack techniques for the given objectives. Craft payloads tailored to the target's technology and behavior.
|
|
195340
|
+
5. TEST — Execute targeted attacks methodically, one payload/technique at a time. Observe responses carefully for indicators of vulnerability.
|
|
195341
|
+
6. EXPLOIT — When a vulnerability is confirmed, create a proof-of-concept script that reliably demonstrates it.
|
|
195342
|
+
7. PIVOT — When a vulnerability grants access to internal resources (e.g. SSRF, RCE, LFI), use it to discover and map what's accessible. Reason about what internal services, APIs, and data stores may exist behind the vulnerability — consider common internal hostnames, ports, and paths (e.g. internal DNS names in Docker/Kubernetes environments, common service ports, admin endpoints). Actively explore through the vulnerability to find reachable services.
|
|
195343
|
+
8. EXTRACT — The primary goal is to locate and extract a flag, secret, or sensitive data. Don't stop at proving the vulnerability exists — demonstrate full impact by retrieving the target data through the confirmed attack vector.
|
|
195344
|
+
9. DOCUMENT — Document every confirmed finding with evidence, impact assessment, and remediation steps. You can document multiple findings before finishing.
|
|
195345
|
+
10. LEARN — Before finishing, use add_memory to persist reusable learnings from this engagement (e.g. target-specific behaviors, successful payload patterns, technology fingerprints, false positive patterns, credential formats). This knowledge helps future engagements be more efficient.
|
|
195346
|
+
11. FINISH — After testing ALL objectives, completing extraction, and saving learnings, call the response tool to submit your final summary. Do NOT call response until you have completed all testing and extraction.
|
|
194844
195347
|
|
|
194845
195348
|
Guidelines:
|
|
194846
|
-
- Always
|
|
195349
|
+
- Always call list_memories first to check for relevant knowledge before planning your approach
|
|
195350
|
+
- State your objectives and plan before executing any attack tools
|
|
194847
195351
|
- When you confirm a vulnerability that provides internal access, think through what lies behind it and actively explore through the vulnerability to maximize impact
|
|
194848
195352
|
- Be methodical and thorough — test one payload at a time and observe the response
|
|
194849
195353
|
- Use execute_command for crafting/running exploit scripts and http_request for targeted web tests
|
|
194850
195354
|
- Always create POC scripts to confirm vulnerabilities before documenting
|
|
194851
195355
|
- Document every confirmed vulnerability with document_vulnerability — you can document multiple vulnerabilities in a single run
|
|
194852
195356
|
- Include clear remediation steps in every finding
|
|
195357
|
+
- Before finishing, use add_memory to save reusable learnings (target behaviors, effective techniques, technology details, false positive patterns)
|
|
194853
195358
|
- When you have finished testing ALL objectives and extracting data, call the response tool with a summary of your results. Do NOT call response until you have completed all testing and extraction.
|
|
194854
195359
|
|
|
194855
195360
|
Authentication:
|
|
@@ -194908,7 +195413,10 @@ var init_agent4 = __esm(() => {
|
|
|
194908
195413
|
"email_search_messages",
|
|
194909
195414
|
"email_get_message",
|
|
194910
195415
|
"list_memories",
|
|
194911
|
-
"get_memory"
|
|
195416
|
+
"get_memory",
|
|
195417
|
+
"add_memory",
|
|
195418
|
+
"web_search",
|
|
195419
|
+
"get_page"
|
|
194912
195420
|
],
|
|
194913
195421
|
responseSchema: PentestResponseSchema,
|
|
194914
195422
|
resolveResult: () => {
|
|
@@ -194925,7 +195433,7 @@ var init_agent4 = __esm(() => {
|
|
|
194925
195433
|
});
|
|
194926
195434
|
|
|
194927
195435
|
// src/core/session/execution-metrics.ts
|
|
194928
|
-
import { existsSync as existsSync24, readFileSync as
|
|
195436
|
+
import { existsSync as existsSync24, readFileSync as readFileSync11, writeFileSync as writeFileSync16 } from "fs";
|
|
194929
195437
|
import { join as join25 } from "path";
|
|
194930
195438
|
function toNonNegativeInteger(value) {
|
|
194931
195439
|
const n = Number(value);
|
|
@@ -194953,7 +195461,7 @@ function readExecutionMetrics(sessionRootPath) {
|
|
|
194953
195461
|
if (!existsSync24(path6))
|
|
194954
195462
|
return null;
|
|
194955
195463
|
try {
|
|
194956
|
-
const parsed = JSON.parse(
|
|
195464
|
+
const parsed = JSON.parse(readFileSync11(path6, "utf-8"));
|
|
194957
195465
|
return {
|
|
194958
195466
|
tokenUsage: normalizeTokenUsage(parsed.tokenUsage),
|
|
194959
195467
|
runtime: typeof parsed.runtime === "string" ? parsed.runtime : undefined,
|
|
@@ -194968,7 +195476,7 @@ function writeSessionJsonTokenTotals(sessionRootPath, tokenUsage) {
|
|
|
194968
195476
|
if (!existsSync24(path6))
|
|
194969
195477
|
return;
|
|
194970
195478
|
try {
|
|
194971
|
-
const parsed = JSON.parse(
|
|
195479
|
+
const parsed = JSON.parse(readFileSync11(path6, "utf-8"));
|
|
194972
195480
|
parsed.tokensIn = tokenUsage.inputTokens;
|
|
194973
195481
|
parsed.tokensOut = tokenUsage.outputTokens;
|
|
194974
195482
|
writeFileSync16(path6, JSON.stringify(parsed, null, 2));
|
|
@@ -195581,7 +196089,7 @@ __export(exports_pentest, {
|
|
|
195581
196089
|
runPentestSwarm: () => runPentestSwarm,
|
|
195582
196090
|
DEFAULT_CONCURRENCY: () => DEFAULT_CONCURRENCY4
|
|
195583
196091
|
});
|
|
195584
|
-
import { existsSync as existsSync25, readdirSync as readdirSync5, readFileSync as
|
|
196092
|
+
import { existsSync as existsSync25, readdirSync as readdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync17 } from "fs";
|
|
195585
196093
|
import { join as join26 } from "path";
|
|
195586
196094
|
function addUsageTotals(totals, usage) {
|
|
195587
196095
|
if (!usage)
|
|
@@ -195878,7 +196386,7 @@ function loadFindings2(findingsPath) {
|
|
|
195878
196386
|
}
|
|
195879
196387
|
return readdirSync5(findingsPath).filter((f3) => f3.endsWith(".json")).map((f3) => {
|
|
195880
196388
|
try {
|
|
195881
|
-
const content =
|
|
196389
|
+
const content = readFileSync12(join26(findingsPath, f3), "utf-8");
|
|
195882
196390
|
return JSON.parse(content);
|
|
195883
196391
|
} catch {
|
|
195884
196392
|
return null;
|
|
@@ -272501,7 +273009,7 @@ var useTerminalDimensions = () => {
|
|
|
272501
273009
|
};
|
|
272502
273010
|
|
|
272503
273011
|
// src/tui/index.tsx
|
|
272504
|
-
var
|
|
273012
|
+
var import_react88 = __toESM(require_react(), 1);
|
|
272505
273013
|
|
|
272506
273014
|
// src/tui/components/footer.tsx
|
|
272507
273015
|
import os6 from "os";
|
|
@@ -276900,6 +277408,7 @@ function WebWizard({
|
|
|
276900
277408
|
const [headerNameInput, setHeaderNameInput] = import_react42.useState("");
|
|
276901
277409
|
const [headerValueInput, setHeaderValueInput] = import_react42.useState("");
|
|
276902
277410
|
const [error40, setError] = import_react42.useState(null);
|
|
277411
|
+
const [targetError, setTargetError] = import_react42.useState(null);
|
|
276903
277412
|
async function createSessionAndNavigate() {
|
|
276904
277413
|
if (!state.target.trim())
|
|
276905
277414
|
return;
|
|
@@ -276968,20 +277477,36 @@ function WebWizard({
|
|
|
276968
277477
|
return;
|
|
276969
277478
|
if (currentStep === "target") {
|
|
276970
277479
|
const maxTargetField = state.sourceCodeAccess ? 2 : 1;
|
|
276971
|
-
if (key.name === "tab") {
|
|
277480
|
+
if (key.name === "tab" && !key.shift) {
|
|
276972
277481
|
key.preventDefault();
|
|
276973
|
-
if (
|
|
276974
|
-
|
|
277482
|
+
if (state.target.trim()) {
|
|
277483
|
+
setTargetError(null);
|
|
277484
|
+
setCurrentStep("configure");
|
|
276975
277485
|
} else {
|
|
276976
|
-
|
|
276977
|
-
|
|
276978
|
-
|
|
276979
|
-
|
|
276980
|
-
|
|
277486
|
+
setTargetError("Target URL is required");
|
|
277487
|
+
}
|
|
277488
|
+
return;
|
|
277489
|
+
}
|
|
277490
|
+
if (key.name === "tab" && key.shift) {
|
|
277491
|
+
key.preventDefault();
|
|
277492
|
+
setTargetFocusedField((prev) => Math.max(0, prev - 1));
|
|
277493
|
+
return;
|
|
277494
|
+
}
|
|
277495
|
+
if (key.name === "down") {
|
|
277496
|
+
key.preventDefault();
|
|
277497
|
+
if (targetFocusedField < maxTargetField) {
|
|
277498
|
+
setTargetFocusedField((prev) => prev + 1);
|
|
277499
|
+
}
|
|
277500
|
+
return;
|
|
277501
|
+
}
|
|
277502
|
+
if (key.name === "up") {
|
|
277503
|
+
key.preventDefault();
|
|
277504
|
+
if (targetFocusedField > 0) {
|
|
277505
|
+
setTargetFocusedField((prev) => prev - 1);
|
|
276981
277506
|
}
|
|
276982
277507
|
return;
|
|
276983
277508
|
}
|
|
276984
|
-
if (
|
|
277509
|
+
if (key.sequence === " " && targetFocusedField === 1) {
|
|
276985
277510
|
key.preventDefault();
|
|
276986
277511
|
setState((prev) => ({
|
|
276987
277512
|
...prev,
|
|
@@ -277248,9 +277773,24 @@ function WebWizard({
|
|
|
277248
277773
|
description: "e.g., https://example.com",
|
|
277249
277774
|
placeholder: "https://example.com",
|
|
277250
277775
|
value: state.target,
|
|
277251
|
-
onInput: (v2) =>
|
|
277776
|
+
onInput: (v2) => {
|
|
277777
|
+
setTargetError(null);
|
|
277778
|
+
setState((prev) => ({ ...prev, target: v2 }));
|
|
277779
|
+
},
|
|
277780
|
+
onSubmit: () => {
|
|
277781
|
+
if (state.target.trim()) {
|
|
277782
|
+
setTargetError(null);
|
|
277783
|
+
setCurrentStep("configure");
|
|
277784
|
+
} else {
|
|
277785
|
+
setTargetError("Target URL is required");
|
|
277786
|
+
}
|
|
277787
|
+
},
|
|
277252
277788
|
focused: targetFocusedField === 0
|
|
277253
277789
|
}, undefined, false, undefined, this),
|
|
277790
|
+
targetError && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
277791
|
+
fg: colors2.error,
|
|
277792
|
+
children: targetError
|
|
277793
|
+
}, undefined, false, undefined, this),
|
|
277254
277794
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
277255
277795
|
flexDirection: "column",
|
|
277256
277796
|
gap: 1,
|
|
@@ -277269,7 +277809,7 @@ function WebWizard({
|
|
|
277269
277809
|
}, undefined, false, undefined, this),
|
|
277270
277810
|
targetFocusedField === 1 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
277271
277811
|
fg: colors2.textMuted,
|
|
277272
|
-
children: "(
|
|
277812
|
+
children: "(Space to toggle)"
|
|
277273
277813
|
}, undefined, false, undefined, this)
|
|
277274
277814
|
]
|
|
277275
277815
|
}, undefined, true, undefined, this),
|
|
@@ -277855,11 +278395,12 @@ function WebWizard({
|
|
|
277855
278395
|
}
|
|
277856
278396
|
|
|
277857
278397
|
// src/tui/components/commands/provider-manager.tsx
|
|
277858
|
-
var
|
|
278398
|
+
var import_react50 = __toESM(require_react(), 1);
|
|
277859
278399
|
init_config2();
|
|
277860
278400
|
// src/tui/components/commands/provider-selection.tsx
|
|
277861
278401
|
var import_react45 = __toESM(require_react(), 1);
|
|
277862
278402
|
function ProviderSelection({
|
|
278403
|
+
providers,
|
|
277863
278404
|
onProviderSelected,
|
|
277864
278405
|
onClose
|
|
277865
278406
|
}) {
|
|
@@ -277867,6 +278408,7 @@ function ProviderSelection({
|
|
|
277867
278408
|
const route = useRoute();
|
|
277868
278409
|
const _config = useConfig();
|
|
277869
278410
|
const [highlightedIndex, setHighlightedIndex] = import_react45.useState(0);
|
|
278411
|
+
const providerList = providers ?? AVAILABLE_PROVIDERS;
|
|
277870
278412
|
const configuredProviders = getConfiguredProviders(_config.data);
|
|
277871
278413
|
useKeyboard((key) => {
|
|
277872
278414
|
if (key.name === "escape") {
|
|
@@ -277874,15 +278416,15 @@ function ProviderSelection({
|
|
|
277874
278416
|
return;
|
|
277875
278417
|
}
|
|
277876
278418
|
if (key.name === "up") {
|
|
277877
|
-
setHighlightedIndex((prev) => prev > 0 ? prev - 1 :
|
|
278419
|
+
setHighlightedIndex((prev) => prev > 0 ? prev - 1 : providerList.length - 1);
|
|
277878
278420
|
return;
|
|
277879
278421
|
}
|
|
277880
278422
|
if (key.name === "down") {
|
|
277881
|
-
setHighlightedIndex((prev) => prev <
|
|
278423
|
+
setHighlightedIndex((prev) => prev < providerList.length - 1 ? prev + 1 : 0);
|
|
277882
278424
|
return;
|
|
277883
278425
|
}
|
|
277884
278426
|
if (key.name === "return") {
|
|
277885
|
-
const selected =
|
|
278427
|
+
const selected = providerList[highlightedIndex];
|
|
277886
278428
|
if (selected) {
|
|
277887
278429
|
onProviderSelected(selected.id);
|
|
277888
278430
|
}
|
|
@@ -277952,7 +278494,7 @@ function ProviderSelection({
|
|
|
277952
278494
|
marginBottom: 1,
|
|
277953
278495
|
children: "Popular providers"
|
|
277954
278496
|
}, undefined, false, undefined, this),
|
|
277955
|
-
|
|
278497
|
+
providerList.map((provider, index) => {
|
|
277956
278498
|
const isHighlighted = index === highlightedIndex;
|
|
277957
278499
|
const configured = configuredProviders.find((p) => p.id === provider.id)?.configured;
|
|
277958
278500
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
@@ -278139,12 +278681,649 @@ function APIKeyInput({
|
|
|
278139
278681
|
}, undefined, false, undefined, this);
|
|
278140
278682
|
}
|
|
278141
278683
|
|
|
278684
|
+
// src/tui/components/commands/auth-flow.tsx
|
|
278685
|
+
var import_react48 = __toESM(require_react(), 1);
|
|
278686
|
+
init_config2();
|
|
278687
|
+
init_auth();
|
|
278688
|
+
function AuthFlow({ onClose }) {
|
|
278689
|
+
const { colors: colors2 } = useTheme();
|
|
278690
|
+
const appConfig = useConfig();
|
|
278691
|
+
const alreadyConnected = isConnected(appConfig.data);
|
|
278692
|
+
const [step, setStep] = import_react48.useState(alreadyConnected ? "success" : "start");
|
|
278693
|
+
const [error40, setError] = import_react48.useState(null);
|
|
278694
|
+
const [flowInfo, setFlowInfo] = import_react48.useState(null);
|
|
278695
|
+
const [workspaces, setWorkspaces] = import_react48.useState([]);
|
|
278696
|
+
const [selectedWorkspace, setSelectedWorkspace] = import_react48.useState(null);
|
|
278697
|
+
const [selectedIndex, setSelectedIndex] = import_react48.useState(0);
|
|
278698
|
+
const [billingUrl, setBillingUrl] = import_react48.useState(null);
|
|
278699
|
+
const [balance, setBalance] = import_react48.useState(null);
|
|
278700
|
+
const abortRef = import_react48.useRef(null);
|
|
278701
|
+
const connectedWorkspace = appConfig.data.workspaceSlug ? {
|
|
278702
|
+
name: appConfig.data.workspaceSlug,
|
|
278703
|
+
slug: appConfig.data.workspaceSlug
|
|
278704
|
+
} : null;
|
|
278705
|
+
const goHome = () => {
|
|
278706
|
+
onClose();
|
|
278707
|
+
};
|
|
278708
|
+
const cleanup = () => {
|
|
278709
|
+
abortRef.current?.abort();
|
|
278710
|
+
abortRef.current = null;
|
|
278711
|
+
};
|
|
278712
|
+
import_react48.useEffect(() => {
|
|
278713
|
+
return cleanup;
|
|
278714
|
+
}, []);
|
|
278715
|
+
const openUrl = (url2) => {
|
|
278716
|
+
try {
|
|
278717
|
+
const platform = process.platform;
|
|
278718
|
+
if (platform === "darwin") {
|
|
278719
|
+
Bun.spawn(["open", url2]);
|
|
278720
|
+
} else if (platform === "win32") {
|
|
278721
|
+
Bun.spawn(["cmd", "/c", "start", url2]);
|
|
278722
|
+
} else {
|
|
278723
|
+
Bun.spawn(["xdg-open", url2]);
|
|
278724
|
+
}
|
|
278725
|
+
} catch {}
|
|
278726
|
+
};
|
|
278727
|
+
const startFlow = async () => {
|
|
278728
|
+
setStep("requesting");
|
|
278729
|
+
setError(null);
|
|
278730
|
+
cleanup();
|
|
278731
|
+
const ac = new AbortController;
|
|
278732
|
+
abortRef.current = ac;
|
|
278733
|
+
const apiUrl = getPensarApiUrl();
|
|
278734
|
+
try {
|
|
278735
|
+
const info = await startDeviceFlow(apiUrl);
|
|
278736
|
+
if (ac.signal.aborted)
|
|
278737
|
+
return;
|
|
278738
|
+
setFlowInfo(info);
|
|
278739
|
+
if (info.mode === "workos") {
|
|
278740
|
+
openUrl(info.deviceInfo.verification_uri_complete);
|
|
278741
|
+
} else {
|
|
278742
|
+
openUrl(info.deviceInfo.verificationUriComplete);
|
|
278743
|
+
}
|
|
278744
|
+
setStep("polling");
|
|
278745
|
+
if (info.mode === "workos") {
|
|
278746
|
+
handleWorkOSPoll(apiUrl, info, ac);
|
|
278747
|
+
} else {
|
|
278748
|
+
handleLegacyPoll(apiUrl, info, ac);
|
|
278749
|
+
}
|
|
278750
|
+
} catch (err) {
|
|
278751
|
+
if (ac.signal.aborted)
|
|
278752
|
+
return;
|
|
278753
|
+
setError(err instanceof Error ? err.message : "Failed to start authorization");
|
|
278754
|
+
setStep("error");
|
|
278755
|
+
}
|
|
278756
|
+
};
|
|
278757
|
+
const handleWorkOSPoll = async (apiUrl, info, ac) => {
|
|
278758
|
+
try {
|
|
278759
|
+
const tokens = await pollWorkOSToken({
|
|
278760
|
+
clientId: info.clientId,
|
|
278761
|
+
deviceCode: info.deviceInfo.device_code,
|
|
278762
|
+
interval: info.deviceInfo.interval,
|
|
278763
|
+
expiresIn: info.deviceInfo.expires_in,
|
|
278764
|
+
signal: ac.signal
|
|
278765
|
+
});
|
|
278766
|
+
if (ac.signal.aborted)
|
|
278767
|
+
return;
|
|
278768
|
+
await config2.update({
|
|
278769
|
+
accessToken: tokens.accessToken,
|
|
278770
|
+
refreshToken: tokens.refreshToken
|
|
278771
|
+
});
|
|
278772
|
+
await appConfig.reload();
|
|
278773
|
+
await handleFetchWorkspaces(apiUrl, tokens.accessToken, ac);
|
|
278774
|
+
} catch (err) {
|
|
278775
|
+
if (ac.signal.aborted)
|
|
278776
|
+
return;
|
|
278777
|
+
setError(err instanceof Error ? err.message : "Authentication failed");
|
|
278778
|
+
setStep("error");
|
|
278779
|
+
}
|
|
278780
|
+
};
|
|
278781
|
+
const handleLegacyPoll = async (apiUrl, info, ac) => {
|
|
278782
|
+
try {
|
|
278783
|
+
const data = await pollLegacyToken({
|
|
278784
|
+
apiUrl,
|
|
278785
|
+
deviceCode: info.deviceInfo.deviceCode,
|
|
278786
|
+
interval: info.deviceInfo.interval,
|
|
278787
|
+
expiresIn: info.deviceInfo.expiresIn,
|
|
278788
|
+
signal: ac.signal
|
|
278789
|
+
});
|
|
278790
|
+
if (ac.signal.aborted)
|
|
278791
|
+
return;
|
|
278792
|
+
await config2.update({
|
|
278793
|
+
pensarAPIKey: data.apiKey,
|
|
278794
|
+
gatewaySigningKey: data.signingKey ?? null
|
|
278795
|
+
});
|
|
278796
|
+
if (data.workspace) {
|
|
278797
|
+
await config2.update({
|
|
278798
|
+
workspaceId: data.workspace.id,
|
|
278799
|
+
workspaceSlug: data.workspace.slug
|
|
278800
|
+
});
|
|
278801
|
+
}
|
|
278802
|
+
appConfig.reload();
|
|
278803
|
+
setSelectedWorkspace(data.workspace ? {
|
|
278804
|
+
...data.workspace,
|
|
278805
|
+
balance: data.credits?.balance ?? 0,
|
|
278806
|
+
hasPaymentMethod: true
|
|
278807
|
+
} : null);
|
|
278808
|
+
setBalance(data.credits?.balance ?? null);
|
|
278809
|
+
setStep("success");
|
|
278810
|
+
} catch (err) {
|
|
278811
|
+
if (ac.signal.aborted)
|
|
278812
|
+
return;
|
|
278813
|
+
setError(err instanceof Error ? err.message : "Authentication failed");
|
|
278814
|
+
setStep("error");
|
|
278815
|
+
}
|
|
278816
|
+
};
|
|
278817
|
+
const handleFetchWorkspaces = async (apiUrl, accessToken, ac) => {
|
|
278818
|
+
try {
|
|
278819
|
+
const ws = await fetchWorkspaces(apiUrl, accessToken);
|
|
278820
|
+
if (ac.signal.aborted)
|
|
278821
|
+
return;
|
|
278822
|
+
if (ws.length === 0) {
|
|
278823
|
+
const consoleUrl = getPensarConsoleUrl();
|
|
278824
|
+
openUrl(`${consoleUrl}/credits`);
|
|
278825
|
+
setStep("creating-workspace");
|
|
278826
|
+
handleWorkspaceCreationPoll(apiUrl, accessToken, ac);
|
|
278827
|
+
return;
|
|
278828
|
+
}
|
|
278829
|
+
if (ws.length === 1) {
|
|
278830
|
+
await handleSelectWorkspace(apiUrl, accessToken, ws[0], ac);
|
|
278831
|
+
return;
|
|
278832
|
+
}
|
|
278833
|
+
setWorkspaces(ws);
|
|
278834
|
+
setSelectedIndex(0);
|
|
278835
|
+
setStep("select-workspace");
|
|
278836
|
+
} catch (err) {
|
|
278837
|
+
if (ac.signal.aborted)
|
|
278838
|
+
return;
|
|
278839
|
+
setError(err instanceof Error ? err.message : "Failed to fetch workspaces");
|
|
278840
|
+
setStep("error");
|
|
278841
|
+
}
|
|
278842
|
+
};
|
|
278843
|
+
const handleWorkspaceCreationPoll = async (apiUrl, accessToken, ac) => {
|
|
278844
|
+
try {
|
|
278845
|
+
const ws = await pollForWorkspaceCreation(apiUrl, accessToken, ac.signal);
|
|
278846
|
+
if (ac.signal.aborted)
|
|
278847
|
+
return;
|
|
278848
|
+
if (ws.length === 1) {
|
|
278849
|
+
await handleSelectWorkspace(apiUrl, accessToken, ws[0], ac);
|
|
278850
|
+
} else {
|
|
278851
|
+
setWorkspaces(ws);
|
|
278852
|
+
setSelectedIndex(0);
|
|
278853
|
+
setStep("select-workspace");
|
|
278854
|
+
}
|
|
278855
|
+
} catch (err) {
|
|
278856
|
+
if (ac.signal.aborted)
|
|
278857
|
+
return;
|
|
278858
|
+
setError(err instanceof Error ? err.message : "Workspace creation timed out");
|
|
278859
|
+
setStep("error");
|
|
278860
|
+
}
|
|
278861
|
+
};
|
|
278862
|
+
const handleSelectWorkspace = async (apiUrl, accessToken, workspace, ac) => {
|
|
278863
|
+
setSelectedWorkspace(workspace);
|
|
278864
|
+
setStep("checking-billing");
|
|
278865
|
+
try {
|
|
278866
|
+
const data = await selectWorkspace(apiUrl, accessToken, workspace.id);
|
|
278867
|
+
if (ac.signal.aborted)
|
|
278868
|
+
return;
|
|
278869
|
+
await config2.update({
|
|
278870
|
+
workspaceId: workspace.id,
|
|
278871
|
+
workspaceSlug: workspace.slug,
|
|
278872
|
+
gatewaySigningKey: data.signingKey ?? null
|
|
278873
|
+
});
|
|
278874
|
+
appConfig.reload();
|
|
278875
|
+
setBalance(data.billing.balance);
|
|
278876
|
+
if (!data.confirmed && data.billingUrl) {
|
|
278877
|
+
setBillingUrl(data.billingUrl);
|
|
278878
|
+
}
|
|
278879
|
+
setStep("success");
|
|
278880
|
+
} catch (err) {
|
|
278881
|
+
if (ac.signal.aborted)
|
|
278882
|
+
return;
|
|
278883
|
+
setError(err instanceof Error ? err.message : "Failed to select workspace");
|
|
278884
|
+
setStep("error");
|
|
278885
|
+
}
|
|
278886
|
+
};
|
|
278887
|
+
const handleDisconnect = async () => {
|
|
278888
|
+
await disconnect();
|
|
278889
|
+
appConfig.reload();
|
|
278890
|
+
setFlowInfo(null);
|
|
278891
|
+
setSelectedWorkspace(null);
|
|
278892
|
+
setBalance(null);
|
|
278893
|
+
setBillingUrl(null);
|
|
278894
|
+
setStep("start");
|
|
278895
|
+
};
|
|
278896
|
+
const hasLowBalance = balance !== null && balance < 1;
|
|
278897
|
+
const effectiveBillingUrl = billingUrl || (selectedWorkspace?.slug ? `${getPensarConsoleUrl()}/${selectedWorkspace.slug}/settings/billing` : connectedWorkspace?.slug ? `${getPensarConsoleUrl()}/${connectedWorkspace.slug}/settings/billing` : `${getPensarConsoleUrl()}/credits`);
|
|
278898
|
+
const openBillingPage = () => {
|
|
278899
|
+
openUrl(effectiveBillingUrl);
|
|
278900
|
+
goHome();
|
|
278901
|
+
};
|
|
278902
|
+
const userCode = flowInfo?.mode === "workos" ? flowInfo.deviceInfo.user_code : flowInfo?.mode === "legacy" ? flowInfo.deviceInfo.userCode : null;
|
|
278903
|
+
const verificationUrl = flowInfo?.mode === "workos" ? flowInfo.deviceInfo.verification_uri_complete : flowInfo?.mode === "legacy" ? flowInfo.deviceInfo.verificationUriComplete : null;
|
|
278904
|
+
useKeyboard((key) => {
|
|
278905
|
+
key.preventDefault();
|
|
278906
|
+
if (key.name === "escape") {
|
|
278907
|
+
cleanup();
|
|
278908
|
+
goHome();
|
|
278909
|
+
return;
|
|
278910
|
+
}
|
|
278911
|
+
if (step === "start") {
|
|
278912
|
+
if (key.name === "return") {
|
|
278913
|
+
startFlow();
|
|
278914
|
+
}
|
|
278915
|
+
}
|
|
278916
|
+
if (step === "select-workspace") {
|
|
278917
|
+
if (key.name === "up" && selectedIndex > 0) {
|
|
278918
|
+
setSelectedIndex((i) => i - 1);
|
|
278919
|
+
}
|
|
278920
|
+
if (key.name === "down" && selectedIndex < workspaces.length - 1) {
|
|
278921
|
+
setSelectedIndex((i) => i + 1);
|
|
278922
|
+
}
|
|
278923
|
+
if (key.name === "return" && workspaces[selectedIndex]) {
|
|
278924
|
+
const currentConfig = appConfig.data;
|
|
278925
|
+
const apiUrl = getPensarApiUrl();
|
|
278926
|
+
const accessToken = currentConfig.accessToken;
|
|
278927
|
+
const ac = abortRef.current ?? new AbortController;
|
|
278928
|
+
handleSelectWorkspace(apiUrl, accessToken, workspaces[selectedIndex], ac);
|
|
278929
|
+
}
|
|
278930
|
+
}
|
|
278931
|
+
if (step === "error") {
|
|
278932
|
+
if (key.name === "return") {
|
|
278933
|
+
startFlow();
|
|
278934
|
+
}
|
|
278935
|
+
}
|
|
278936
|
+
if (step === "success") {
|
|
278937
|
+
if (key.name === "return") {
|
|
278938
|
+
if (hasLowBalance || billingUrl) {
|
|
278939
|
+
openBillingPage();
|
|
278940
|
+
} else {
|
|
278941
|
+
goHome();
|
|
278942
|
+
}
|
|
278943
|
+
}
|
|
278944
|
+
if (key.raw === "d" || key.raw === "D") {
|
|
278945
|
+
handleDisconnect();
|
|
278946
|
+
}
|
|
278947
|
+
}
|
|
278948
|
+
});
|
|
278949
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Dialog, {
|
|
278950
|
+
size: "large",
|
|
278951
|
+
onClose: goHome,
|
|
278952
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
278953
|
+
flexDirection: "column",
|
|
278954
|
+
width: "100%",
|
|
278955
|
+
alignItems: "flex-start",
|
|
278956
|
+
padding: 1,
|
|
278957
|
+
children: [
|
|
278958
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
278959
|
+
marginBottom: 1,
|
|
278960
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
278961
|
+
fg: colors2.primary,
|
|
278962
|
+
children: "Pensar Console — Managed Inference"
|
|
278963
|
+
}, undefined, false, undefined, this)
|
|
278964
|
+
}, undefined, false, undefined, this),
|
|
278965
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
278966
|
+
marginBottom: 1,
|
|
278967
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
278968
|
+
fg: colors2.textMuted,
|
|
278969
|
+
children: [
|
|
278970
|
+
"Connect to Pensar Console for usage-based AI inference.",
|
|
278971
|
+
`
|
|
278972
|
+
`,
|
|
278973
|
+
"No API keys needed — just a Pensar account with credits."
|
|
278974
|
+
]
|
|
278975
|
+
}, undefined, true, undefined, this)
|
|
278976
|
+
}, undefined, false, undefined, this),
|
|
278977
|
+
step === "start" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
278978
|
+
flexDirection: "column",
|
|
278979
|
+
gap: 1,
|
|
278980
|
+
children: [
|
|
278981
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
278982
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
278983
|
+
fg: colors2.text,
|
|
278984
|
+
children: [
|
|
278985
|
+
"Press ",
|
|
278986
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
278987
|
+
fg: colors2.primary,
|
|
278988
|
+
children: "[ENTER]"
|
|
278989
|
+
}, undefined, false, undefined, this),
|
|
278990
|
+
" to authorize via your browser."
|
|
278991
|
+
]
|
|
278992
|
+
}, undefined, true, undefined, this)
|
|
278993
|
+
}, undefined, false, undefined, this),
|
|
278994
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
278995
|
+
marginTop: 1,
|
|
278996
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
278997
|
+
fg: colors2.textMuted,
|
|
278998
|
+
children: [
|
|
278999
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279000
|
+
fg: colors2.primary,
|
|
279001
|
+
children: "[ENTER]"
|
|
279002
|
+
}, undefined, false, undefined, this),
|
|
279003
|
+
" Connect ·",
|
|
279004
|
+
" ",
|
|
279005
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279006
|
+
fg: colors2.primary,
|
|
279007
|
+
children: "[ESC]"
|
|
279008
|
+
}, undefined, false, undefined, this),
|
|
279009
|
+
" Cancel"
|
|
279010
|
+
]
|
|
279011
|
+
}, undefined, true, undefined, this)
|
|
279012
|
+
}, undefined, false, undefined, this)
|
|
279013
|
+
]
|
|
279014
|
+
}, undefined, true, undefined, this),
|
|
279015
|
+
step === "requesting" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279016
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279017
|
+
fg: colors2.warning,
|
|
279018
|
+
children: "Starting authorization..."
|
|
279019
|
+
}, undefined, false, undefined, this)
|
|
279020
|
+
}, undefined, false, undefined, this),
|
|
279021
|
+
step === "polling" && flowInfo && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279022
|
+
flexDirection: "column",
|
|
279023
|
+
gap: 1,
|
|
279024
|
+
children: [
|
|
279025
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279026
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279027
|
+
fg: colors2.warning,
|
|
279028
|
+
children: "Waiting for browser authorization..."
|
|
279029
|
+
}, undefined, false, undefined, this)
|
|
279030
|
+
}, undefined, false, undefined, this),
|
|
279031
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279032
|
+
marginTop: 1,
|
|
279033
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279034
|
+
fg: colors2.text,
|
|
279035
|
+
children: [
|
|
279036
|
+
"Your code: ",
|
|
279037
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279038
|
+
fg: colors2.primary,
|
|
279039
|
+
children: userCode
|
|
279040
|
+
}, undefined, false, undefined, this)
|
|
279041
|
+
]
|
|
279042
|
+
}, undefined, true, undefined, this)
|
|
279043
|
+
}, undefined, false, undefined, this),
|
|
279044
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279045
|
+
marginTop: 1,
|
|
279046
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279047
|
+
fg: colors2.textMuted,
|
|
279048
|
+
children: [
|
|
279049
|
+
"If the browser didn't open, visit:",
|
|
279050
|
+
`
|
|
279051
|
+
`,
|
|
279052
|
+
verificationUrl
|
|
279053
|
+
]
|
|
279054
|
+
}, undefined, true, undefined, this)
|
|
279055
|
+
}, undefined, false, undefined, this),
|
|
279056
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279057
|
+
marginTop: 1,
|
|
279058
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279059
|
+
fg: colors2.textMuted,
|
|
279060
|
+
children: [
|
|
279061
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279062
|
+
fg: colors2.primary,
|
|
279063
|
+
children: "[ESC]"
|
|
279064
|
+
}, undefined, false, undefined, this),
|
|
279065
|
+
" Cancel"
|
|
279066
|
+
]
|
|
279067
|
+
}, undefined, true, undefined, this)
|
|
279068
|
+
}, undefined, false, undefined, this)
|
|
279069
|
+
]
|
|
279070
|
+
}, undefined, true, undefined, this),
|
|
279071
|
+
step === "select-workspace" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279072
|
+
flexDirection: "column",
|
|
279073
|
+
gap: 1,
|
|
279074
|
+
children: [
|
|
279075
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279076
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279077
|
+
fg: colors2.text,
|
|
279078
|
+
children: "Select a workspace:"
|
|
279079
|
+
}, undefined, false, undefined, this)
|
|
279080
|
+
}, undefined, false, undefined, this),
|
|
279081
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279082
|
+
flexDirection: "column",
|
|
279083
|
+
marginTop: 1,
|
|
279084
|
+
children: workspaces.map((ws, i) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279085
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279086
|
+
fg: i === selectedIndex ? colors2.primary : colors2.textMuted,
|
|
279087
|
+
children: [
|
|
279088
|
+
i === selectedIndex ? "▸ " : " ",
|
|
279089
|
+
ws.name,
|
|
279090
|
+
" ",
|
|
279091
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279092
|
+
fg: colors2.textMuted,
|
|
279093
|
+
children: [
|
|
279094
|
+
"(",
|
|
279095
|
+
ws.slug,
|
|
279096
|
+
") — $",
|
|
279097
|
+
ws.balance.toFixed(2)
|
|
279098
|
+
]
|
|
279099
|
+
}, undefined, true, undefined, this)
|
|
279100
|
+
]
|
|
279101
|
+
}, undefined, true, undefined, this)
|
|
279102
|
+
}, ws.id, false, undefined, this))
|
|
279103
|
+
}, undefined, false, undefined, this),
|
|
279104
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279105
|
+
marginTop: 1,
|
|
279106
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279107
|
+
fg: colors2.textMuted,
|
|
279108
|
+
children: [
|
|
279109
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279110
|
+
fg: colors2.primary,
|
|
279111
|
+
children: "[↑/↓]"
|
|
279112
|
+
}, undefined, false, undefined, this),
|
|
279113
|
+
" Navigate ·",
|
|
279114
|
+
" ",
|
|
279115
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279116
|
+
fg: colors2.primary,
|
|
279117
|
+
children: "[ENTER]"
|
|
279118
|
+
}, undefined, false, undefined, this),
|
|
279119
|
+
" Select ·",
|
|
279120
|
+
" ",
|
|
279121
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279122
|
+
fg: colors2.primary,
|
|
279123
|
+
children: "[ESC]"
|
|
279124
|
+
}, undefined, false, undefined, this),
|
|
279125
|
+
" Cancel"
|
|
279126
|
+
]
|
|
279127
|
+
}, undefined, true, undefined, this)
|
|
279128
|
+
}, undefined, false, undefined, this)
|
|
279129
|
+
]
|
|
279130
|
+
}, undefined, true, undefined, this),
|
|
279131
|
+
step === "creating-workspace" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279132
|
+
flexDirection: "column",
|
|
279133
|
+
gap: 1,
|
|
279134
|
+
children: [
|
|
279135
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279136
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279137
|
+
fg: colors2.warning,
|
|
279138
|
+
children: "No workspaces found. Opening browser to create one..."
|
|
279139
|
+
}, undefined, false, undefined, this)
|
|
279140
|
+
}, undefined, false, undefined, this),
|
|
279141
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279142
|
+
marginTop: 1,
|
|
279143
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279144
|
+
fg: colors2.text,
|
|
279145
|
+
children: "Create a workspace and add credits in your browser."
|
|
279146
|
+
}, undefined, false, undefined, this)
|
|
279147
|
+
}, undefined, false, undefined, this),
|
|
279148
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279149
|
+
marginTop: 1,
|
|
279150
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279151
|
+
fg: colors2.textMuted,
|
|
279152
|
+
children: "Waiting for workspace creation..."
|
|
279153
|
+
}, undefined, false, undefined, this)
|
|
279154
|
+
}, undefined, false, undefined, this),
|
|
279155
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279156
|
+
marginTop: 1,
|
|
279157
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279158
|
+
fg: colors2.textMuted,
|
|
279159
|
+
children: [
|
|
279160
|
+
"If the browser didn't open, visit:",
|
|
279161
|
+
`
|
|
279162
|
+
`,
|
|
279163
|
+
getPensarConsoleUrl(),
|
|
279164
|
+
"/credits"
|
|
279165
|
+
]
|
|
279166
|
+
}, undefined, true, undefined, this)
|
|
279167
|
+
}, undefined, false, undefined, this),
|
|
279168
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279169
|
+
marginTop: 1,
|
|
279170
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279171
|
+
fg: colors2.textMuted,
|
|
279172
|
+
children: [
|
|
279173
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279174
|
+
fg: colors2.primary,
|
|
279175
|
+
children: "[ESC]"
|
|
279176
|
+
}, undefined, false, undefined, this),
|
|
279177
|
+
" Cancel"
|
|
279178
|
+
]
|
|
279179
|
+
}, undefined, true, undefined, this)
|
|
279180
|
+
}, undefined, false, undefined, this)
|
|
279181
|
+
]
|
|
279182
|
+
}, undefined, true, undefined, this),
|
|
279183
|
+
step === "checking-billing" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279184
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279185
|
+
fg: colors2.warning,
|
|
279186
|
+
children: [
|
|
279187
|
+
"Checking billing for ",
|
|
279188
|
+
selectedWorkspace?.name,
|
|
279189
|
+
"..."
|
|
279190
|
+
]
|
|
279191
|
+
}, undefined, true, undefined, this)
|
|
279192
|
+
}, undefined, false, undefined, this),
|
|
279193
|
+
step === "success" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279194
|
+
flexDirection: "column",
|
|
279195
|
+
gap: 1,
|
|
279196
|
+
children: [
|
|
279197
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279198
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279199
|
+
fg: colors2.success,
|
|
279200
|
+
children: "Connected to Pensar Console"
|
|
279201
|
+
}, undefined, false, undefined, this)
|
|
279202
|
+
}, undefined, false, undefined, this),
|
|
279203
|
+
(selectedWorkspace || connectedWorkspace) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279204
|
+
flexDirection: "column",
|
|
279205
|
+
children: [
|
|
279206
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279207
|
+
fg: colors2.text,
|
|
279208
|
+
children: [
|
|
279209
|
+
"Workspace:",
|
|
279210
|
+
" ",
|
|
279211
|
+
selectedWorkspace?.name || connectedWorkspace?.name
|
|
279212
|
+
]
|
|
279213
|
+
}, undefined, true, undefined, this),
|
|
279214
|
+
balance !== null && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279215
|
+
fg: colors2.text,
|
|
279216
|
+
children: [
|
|
279217
|
+
"Credits:",
|
|
279218
|
+
" ",
|
|
279219
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279220
|
+
fg: hasLowBalance ? colors2.warning : colors2.text,
|
|
279221
|
+
children: [
|
|
279222
|
+
"$",
|
|
279223
|
+
balance.toFixed(2)
|
|
279224
|
+
]
|
|
279225
|
+
}, undefined, true, undefined, this)
|
|
279226
|
+
]
|
|
279227
|
+
}, undefined, true, undefined, this)
|
|
279228
|
+
]
|
|
279229
|
+
}, undefined, true, undefined, this),
|
|
279230
|
+
(hasLowBalance || billingUrl) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279231
|
+
marginTop: 1,
|
|
279232
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279233
|
+
fg: colors2.warning,
|
|
279234
|
+
children: [
|
|
279235
|
+
billingUrl ? "Your workspace needs credits to use Apex CLI." : "Your credit balance is very low. We recommend at least $30 to run",
|
|
279236
|
+
`
|
|
279237
|
+
`,
|
|
279238
|
+
billingUrl ? "Press ENTER to open billing and add credits." : "pentests without interruptions. Press ENTER to open billing."
|
|
279239
|
+
]
|
|
279240
|
+
}, undefined, true, undefined, this)
|
|
279241
|
+
}, undefined, false, undefined, this),
|
|
279242
|
+
!selectedWorkspace && !connectedWorkspace && appConfig.data.pensarAPIKey && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279243
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279244
|
+
fg: colors2.textMuted,
|
|
279245
|
+
children: "Already connected (legacy key saved in config)"
|
|
279246
|
+
}, undefined, false, undefined, this)
|
|
279247
|
+
}, undefined, false, undefined, this),
|
|
279248
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279249
|
+
marginTop: 1,
|
|
279250
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279251
|
+
fg: colors2.textMuted,
|
|
279252
|
+
children: "Pensar models are now available in the model selector."
|
|
279253
|
+
}, undefined, false, undefined, this)
|
|
279254
|
+
}, undefined, false, undefined, this),
|
|
279255
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279256
|
+
marginTop: 1,
|
|
279257
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279258
|
+
fg: colors2.textMuted,
|
|
279259
|
+
children: [
|
|
279260
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279261
|
+
fg: colors2.primary,
|
|
279262
|
+
children: "[ENTER]"
|
|
279263
|
+
}, undefined, false, undefined, this),
|
|
279264
|
+
" ",
|
|
279265
|
+
hasLowBalance || billingUrl ? "Open billing" : "Done",
|
|
279266
|
+
" ·",
|
|
279267
|
+
" ",
|
|
279268
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279269
|
+
fg: colors2.error,
|
|
279270
|
+
children: "[D]"
|
|
279271
|
+
}, undefined, false, undefined, this),
|
|
279272
|
+
" Disconnect ·",
|
|
279273
|
+
" ",
|
|
279274
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279275
|
+
fg: colors2.primary,
|
|
279276
|
+
children: "[ESC]"
|
|
279277
|
+
}, undefined, false, undefined, this),
|
|
279278
|
+
" Back"
|
|
279279
|
+
]
|
|
279280
|
+
}, undefined, true, undefined, this)
|
|
279281
|
+
}, undefined, false, undefined, this)
|
|
279282
|
+
]
|
|
279283
|
+
}, undefined, true, undefined, this),
|
|
279284
|
+
step === "error" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279285
|
+
flexDirection: "column",
|
|
279286
|
+
gap: 1,
|
|
279287
|
+
children: [
|
|
279288
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279289
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279290
|
+
fg: colors2.error,
|
|
279291
|
+
children: error40
|
|
279292
|
+
}, undefined, false, undefined, this)
|
|
279293
|
+
}, undefined, false, undefined, this),
|
|
279294
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279295
|
+
marginTop: 1,
|
|
279296
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279297
|
+
fg: colors2.textMuted,
|
|
279298
|
+
children: [
|
|
279299
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279300
|
+
fg: colors2.primary,
|
|
279301
|
+
children: "[ENTER]"
|
|
279302
|
+
}, undefined, false, undefined, this),
|
|
279303
|
+
" Try again ·",
|
|
279304
|
+
" ",
|
|
279305
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279306
|
+
fg: colors2.primary,
|
|
279307
|
+
children: "[ESC]"
|
|
279308
|
+
}, undefined, false, undefined, this),
|
|
279309
|
+
" Cancel"
|
|
279310
|
+
]
|
|
279311
|
+
}, undefined, true, undefined, this)
|
|
279312
|
+
}, undefined, false, undefined, this)
|
|
279313
|
+
]
|
|
279314
|
+
}, undefined, true, undefined, this)
|
|
279315
|
+
]
|
|
279316
|
+
}, undefined, true, undefined, this)
|
|
279317
|
+
}, undefined, false, undefined, this);
|
|
279318
|
+
}
|
|
279319
|
+
|
|
278142
279320
|
// src/tui/components/commands/provider-manager.tsx
|
|
278143
279321
|
function ProviderManager() {
|
|
278144
279322
|
const route = useRoute();
|
|
278145
279323
|
const _config = useConfig();
|
|
278146
|
-
const
|
|
278147
|
-
const [
|
|
279324
|
+
const isOnboarding = !hasAnyProviderConfigured(_config.data);
|
|
279325
|
+
const [flowState, setFlowState] = import_react50.useState(isOnboarding ? "choosing" : "selecting");
|
|
279326
|
+
const [selectedProvider, setSelectedProvider] = import_react50.useState(null);
|
|
278148
279327
|
const handleProviderSelected = (providerId) => {
|
|
278149
279328
|
setSelectedProvider(providerId);
|
|
278150
279329
|
setFlowState("inputting");
|
|
@@ -278178,7 +279357,11 @@ function ProviderManager() {
|
|
|
278178
279357
|
});
|
|
278179
279358
|
};
|
|
278180
279359
|
const handleAPIKeyCancel = () => {
|
|
278181
|
-
|
|
279360
|
+
if (isOnboarding) {
|
|
279361
|
+
setFlowState("choosing");
|
|
279362
|
+
} else {
|
|
279363
|
+
setFlowState("selecting");
|
|
279364
|
+
}
|
|
278182
279365
|
setSelectedProvider(null);
|
|
278183
279366
|
};
|
|
278184
279367
|
const handleClose = () => {
|
|
@@ -278187,28 +279370,158 @@ function ProviderManager() {
|
|
|
278187
279370
|
path: "home"
|
|
278188
279371
|
});
|
|
278189
279372
|
};
|
|
279373
|
+
const handleAuthClose = () => {
|
|
279374
|
+
route.navigate({ type: "base", path: "home" });
|
|
279375
|
+
};
|
|
279376
|
+
const otherProviders = AVAILABLE_PROVIDERS.filter((p) => p.id !== "pensar");
|
|
278190
279377
|
const selectedProviderInfo = AVAILABLE_PROVIDERS.find((p) => p.id === selectedProvider);
|
|
278191
279378
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
|
|
278192
279379
|
children: [
|
|
279380
|
+
flowState === "choosing" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(OnboardingChoice, {
|
|
279381
|
+
onPensarSelected: () => setFlowState("auth"),
|
|
279382
|
+
onOtherSelected: () => setFlowState("selecting")
|
|
279383
|
+
}, undefined, false, undefined, this),
|
|
278193
279384
|
flowState === "selecting" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ProviderSelection, {
|
|
279385
|
+
providers: isOnboarding ? otherProviders : undefined,
|
|
278194
279386
|
onProviderSelected: handleProviderSelected,
|
|
278195
|
-
onClose: handleClose
|
|
279387
|
+
onClose: isOnboarding ? () => setFlowState("choosing") : handleClose
|
|
278196
279388
|
}, undefined, false, undefined, this),
|
|
278197
279389
|
flowState === "inputting" && selectedProvider && selectedProviderInfo && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(APIKeyInput, {
|
|
278198
279390
|
provider: selectedProvider,
|
|
278199
279391
|
providerName: selectedProviderInfo.name,
|
|
278200
279392
|
onSubmit: handleAPIKeySubmit,
|
|
278201
279393
|
onCancel: handleAPIKeyCancel
|
|
279394
|
+
}, undefined, false, undefined, this),
|
|
279395
|
+
flowState === "auth" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AuthFlow, {
|
|
279396
|
+
onClose: handleAuthClose
|
|
278202
279397
|
}, undefined, false, undefined, this)
|
|
278203
279398
|
]
|
|
278204
279399
|
}, undefined, true, undefined, this);
|
|
278205
279400
|
}
|
|
279401
|
+
function OnboardingChoice({
|
|
279402
|
+
onPensarSelected,
|
|
279403
|
+
onOtherSelected
|
|
279404
|
+
}) {
|
|
279405
|
+
const { colors: colors2 } = useTheme();
|
|
279406
|
+
const [highlightedIndex, setHighlightedIndex] = import_react50.useState(0);
|
|
279407
|
+
const choices = [
|
|
279408
|
+
{
|
|
279409
|
+
label: "Pensar",
|
|
279410
|
+
description: "Managed inference — no API keys needed",
|
|
279411
|
+
action: onPensarSelected
|
|
279412
|
+
},
|
|
279413
|
+
{
|
|
279414
|
+
label: "Use other provider",
|
|
279415
|
+
description: "Connect with your own API key (Anthropic, OpenAI, etc.)",
|
|
279416
|
+
action: onOtherSelected
|
|
279417
|
+
}
|
|
279418
|
+
];
|
|
279419
|
+
useKeyboard((key) => {
|
|
279420
|
+
if (key.name === "up") {
|
|
279421
|
+
setHighlightedIndex((prev) => prev > 0 ? prev - 1 : choices.length - 1);
|
|
279422
|
+
return;
|
|
279423
|
+
}
|
|
279424
|
+
if (key.name === "down") {
|
|
279425
|
+
setHighlightedIndex((prev) => prev < choices.length - 1 ? prev + 1 : 0);
|
|
279426
|
+
return;
|
|
279427
|
+
}
|
|
279428
|
+
if (key.name === "return") {
|
|
279429
|
+
choices[highlightedIndex].action();
|
|
279430
|
+
return;
|
|
279431
|
+
}
|
|
279432
|
+
});
|
|
279433
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279434
|
+
position: "absolute",
|
|
279435
|
+
top: 0,
|
|
279436
|
+
left: 0,
|
|
279437
|
+
zIndex: 1000,
|
|
279438
|
+
width: "100%",
|
|
279439
|
+
height: "100%",
|
|
279440
|
+
justifyContent: "center",
|
|
279441
|
+
alignItems: "center",
|
|
279442
|
+
backgroundColor: "transparent",
|
|
279443
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279444
|
+
width: 70,
|
|
279445
|
+
border: true,
|
|
279446
|
+
borderColor: colors2.primary,
|
|
279447
|
+
backgroundColor: colors2.backgroundPanel,
|
|
279448
|
+
flexDirection: "column",
|
|
279449
|
+
padding: 2,
|
|
279450
|
+
children: [
|
|
279451
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279452
|
+
flexDirection: "row",
|
|
279453
|
+
marginBottom: 2,
|
|
279454
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279455
|
+
fg: colors2.primary,
|
|
279456
|
+
children: "Get Started"
|
|
279457
|
+
}, undefined, false, undefined, this)
|
|
279458
|
+
}, undefined, false, undefined, this),
|
|
279459
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279460
|
+
marginBottom: 2,
|
|
279461
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279462
|
+
fg: colors2.textMuted,
|
|
279463
|
+
children: "Choose how to connect an AI provider."
|
|
279464
|
+
}, undefined, false, undefined, this)
|
|
279465
|
+
}, undefined, false, undefined, this),
|
|
279466
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279467
|
+
flexDirection: "column",
|
|
279468
|
+
gap: 1,
|
|
279469
|
+
children: choices.map((choice2, index) => {
|
|
279470
|
+
const isHighlighted = index === highlightedIndex;
|
|
279471
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279472
|
+
flexDirection: "column",
|
|
279473
|
+
paddingLeft: 1,
|
|
279474
|
+
paddingRight: 1,
|
|
279475
|
+
backgroundColor: isHighlighted ? colors2.backgroundSelected : undefined,
|
|
279476
|
+
onMouseDown: choice2.action,
|
|
279477
|
+
children: [
|
|
279478
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279479
|
+
fg: isHighlighted ? colors2.primary : colors2.text,
|
|
279480
|
+
children: [
|
|
279481
|
+
isHighlighted ? "▸ " : " ",
|
|
279482
|
+
choice2.label
|
|
279483
|
+
]
|
|
279484
|
+
}, undefined, true, undefined, this),
|
|
279485
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279486
|
+
fg: colors2.textMuted,
|
|
279487
|
+
children: [
|
|
279488
|
+
" ",
|
|
279489
|
+
choice2.description
|
|
279490
|
+
]
|
|
279491
|
+
}, undefined, true, undefined, this)
|
|
279492
|
+
]
|
|
279493
|
+
}, choice2.label, true, undefined, this);
|
|
279494
|
+
})
|
|
279495
|
+
}, undefined, false, undefined, this),
|
|
279496
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279497
|
+
marginTop: 2,
|
|
279498
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279499
|
+
fg: colors2.textMuted,
|
|
279500
|
+
children: [
|
|
279501
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279502
|
+
fg: colors2.primary,
|
|
279503
|
+
children: "[↑↓]"
|
|
279504
|
+
}, undefined, false, undefined, this),
|
|
279505
|
+
" Navigate ·",
|
|
279506
|
+
" ",
|
|
279507
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279508
|
+
fg: colors2.primary,
|
|
279509
|
+
children: "[ENTER]"
|
|
279510
|
+
}, undefined, false, undefined, this),
|
|
279511
|
+
" Select"
|
|
279512
|
+
]
|
|
279513
|
+
}, undefined, true, undefined, this)
|
|
279514
|
+
}, undefined, false, undefined, this)
|
|
279515
|
+
]
|
|
279516
|
+
}, undefined, true, undefined, this)
|
|
279517
|
+
}, undefined, false, undefined, this);
|
|
279518
|
+
}
|
|
278206
279519
|
|
|
278207
279520
|
// src/tui/index.tsx
|
|
278208
279521
|
init_config2();
|
|
278209
279522
|
|
|
278210
279523
|
// src/tui/components/switch.tsx
|
|
278211
|
-
var
|
|
279524
|
+
var import_react52 = __toESM(require_react(), 1);
|
|
278212
279525
|
var CaseSymbol = Symbol("Switch.Case");
|
|
278213
279526
|
var DefaultSymbol = Symbol("Switch.Default");
|
|
278214
279527
|
function CaseComponent({
|
|
@@ -278231,8 +279544,8 @@ function SwitchComponent({
|
|
|
278231
279544
|
}) {
|
|
278232
279545
|
let matchedChild = null;
|
|
278233
279546
|
let defaultChild = null;
|
|
278234
|
-
|
|
278235
|
-
if (
|
|
279547
|
+
import_react52.default.Children.forEach(children, (child) => {
|
|
279548
|
+
if (import_react52.default.isValidElement(child)) {
|
|
278236
279549
|
if (child.type[CaseSymbol]) {
|
|
278237
279550
|
const caseChild = child;
|
|
278238
279551
|
if (caseChild.props.when === condition) {
|
|
@@ -278345,8 +279658,8 @@ function ResponsibleUseDisclosure({
|
|
|
278345
279658
|
}
|
|
278346
279659
|
|
|
278347
279660
|
// src/tui/context/toast.tsx
|
|
278348
|
-
var
|
|
278349
|
-
var ToastContext =
|
|
279661
|
+
var import_react54 = __toESM(require_react(), 1);
|
|
279662
|
+
var ToastContext = import_react54.createContext(null);
|
|
278350
279663
|
var nextId = 0;
|
|
278351
279664
|
var DEFAULT_DURATION = {
|
|
278352
279665
|
default: 3000,
|
|
@@ -278354,24 +279667,24 @@ var DEFAULT_DURATION = {
|
|
|
278354
279667
|
error: 5000
|
|
278355
279668
|
};
|
|
278356
279669
|
function ToastProvider({ children }) {
|
|
278357
|
-
const [toasts, setToasts] =
|
|
278358
|
-
const dismiss =
|
|
279670
|
+
const [toasts, setToasts] = import_react54.useState([]);
|
|
279671
|
+
const dismiss = import_react54.useCallback((id) => {
|
|
278359
279672
|
setToasts((prev) => prev.filter((t2) => t2.id !== id));
|
|
278360
279673
|
}, []);
|
|
278361
|
-
const toast =
|
|
279674
|
+
const toast = import_react54.useCallback((message, variant = "default", duration3) => {
|
|
278362
279675
|
const id = nextId++;
|
|
278363
279676
|
const ms = duration3 ?? DEFAULT_DURATION[variant];
|
|
278364
279677
|
setToasts((prev) => [...prev, { id, message, variant, duration: ms }]);
|
|
278365
279678
|
setTimeout(() => dismiss(id), ms);
|
|
278366
279679
|
}, [dismiss]);
|
|
278367
|
-
const value =
|
|
279680
|
+
const value = import_react54.useMemo(() => ({ toasts, toast, dismiss }), [toasts, toast, dismiss]);
|
|
278368
279681
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToastContext.Provider, {
|
|
278369
279682
|
value,
|
|
278370
279683
|
children
|
|
278371
279684
|
}, undefined, false, undefined, this);
|
|
278372
279685
|
}
|
|
278373
279686
|
function useToast() {
|
|
278374
|
-
const ctx4 =
|
|
279687
|
+
const ctx4 = import_react54.useContext(ToastContext);
|
|
278375
279688
|
if (!ctx4)
|
|
278376
279689
|
throw new Error("useToast() must be used within <ToastProvider>");
|
|
278377
279690
|
return ctx4;
|
|
@@ -278444,11 +279757,11 @@ function ToastContainer() {
|
|
|
278444
279757
|
}
|
|
278445
279758
|
|
|
278446
279759
|
// src/tui/components/error-boundary.tsx
|
|
278447
|
-
var
|
|
279760
|
+
var import_react55 = __toESM(require_react(), 1);
|
|
278448
279761
|
var MAX_ERRORS = 3;
|
|
278449
279762
|
var ERROR_WINDOW_MS = 5000;
|
|
278450
279763
|
|
|
278451
|
-
class ErrorBoundaryInner extends
|
|
279764
|
+
class ErrorBoundaryInner extends import_react55.default.Component {
|
|
278452
279765
|
state = {
|
|
278453
279766
|
hasError: false,
|
|
278454
279767
|
errorTimestamps: [],
|
|
@@ -278479,10 +279792,10 @@ class ErrorBoundaryInner extends import_react52.default.Component {
|
|
|
278479
279792
|
}
|
|
278480
279793
|
function ErrorBoundary2({ children }) {
|
|
278481
279794
|
const { toast } = useToast();
|
|
278482
|
-
const handleError =
|
|
279795
|
+
const handleError = import_react55.useCallback((message) => {
|
|
278483
279796
|
toast(message, "error");
|
|
278484
279797
|
}, [toast]);
|
|
278485
|
-
return
|
|
279798
|
+
return import_react55.default.createElement(ErrorBoundaryInner, { onError: handleError }, children);
|
|
278486
279799
|
}
|
|
278487
279800
|
|
|
278488
279801
|
// src/tui/index.tsx
|
|
@@ -278593,16 +279906,16 @@ function ShortcutsDialog({
|
|
|
278593
279906
|
}
|
|
278594
279907
|
|
|
278595
279908
|
// src/tui/components/commands/help-dialog.tsx
|
|
278596
|
-
var
|
|
279909
|
+
var import_react57 = __toESM(require_react(), 1);
|
|
278597
279910
|
function HelpDialog() {
|
|
278598
279911
|
const { colors: colors2 } = useTheme();
|
|
278599
279912
|
const { commands: commands2 } = useCommand();
|
|
278600
279913
|
const route = useRoute();
|
|
278601
279914
|
const dimensions = useDimensions();
|
|
278602
|
-
const [selectedIndex, setSelectedIndex] =
|
|
278603
|
-
const [showDetail, setShowDetail] =
|
|
278604
|
-
const scrollboxRef =
|
|
278605
|
-
const commandsByCategory =
|
|
279915
|
+
const [selectedIndex, setSelectedIndex] = import_react57.useState(0);
|
|
279916
|
+
const [showDetail, setShowDetail] = import_react57.useState(false);
|
|
279917
|
+
const scrollboxRef = import_react57.useRef(null);
|
|
279918
|
+
const commandsByCategory = import_react57.useMemo(() => {
|
|
278606
279919
|
const grouped = {};
|
|
278607
279920
|
for (const cmd of commands2) {
|
|
278608
279921
|
const category = cmd.category || "Other";
|
|
@@ -278613,15 +279926,15 @@ function HelpDialog() {
|
|
|
278613
279926
|
}
|
|
278614
279927
|
return grouped;
|
|
278615
279928
|
}, [commands2]);
|
|
278616
|
-
const flatCommands =
|
|
279929
|
+
const flatCommands = import_react57.useMemo(() => {
|
|
278617
279930
|
return commands2;
|
|
278618
279931
|
}, [commands2]);
|
|
278619
|
-
|
|
279932
|
+
import_react57.useEffect(() => {
|
|
278620
279933
|
if (selectedIndex >= flatCommands.length) {
|
|
278621
279934
|
setSelectedIndex(Math.max(0, flatCommands.length - 1));
|
|
278622
279935
|
}
|
|
278623
279936
|
}, [flatCommands.length, selectedIndex]);
|
|
278624
|
-
|
|
279937
|
+
import_react57.useEffect(() => {
|
|
278625
279938
|
scrollToIndex(scrollboxRef.current, selectedIndex, flatCommands, (cmd) => cmd.name);
|
|
278626
279939
|
}, [selectedIndex, flatCommands]);
|
|
278627
279940
|
const handleClose = () => {
|
|
@@ -279055,677 +280368,16 @@ function ModelsDisplay() {
|
|
|
279055
280368
|
}, undefined, true, undefined, this);
|
|
279056
280369
|
}
|
|
279057
280370
|
|
|
279058
|
-
// src/tui/components/commands/auth-flow.tsx
|
|
279059
|
-
var import_react57 = __toESM(require_react(), 1);
|
|
279060
|
-
init_config2();
|
|
279061
|
-
function AuthFlow({ onClose }) {
|
|
279062
|
-
const { colors: colors2 } = useTheme();
|
|
279063
|
-
const appConfig = useConfig();
|
|
279064
|
-
const isConnected = !!(appConfig.data.accessToken || appConfig.data.pensarAPIKey);
|
|
279065
|
-
const [step, setStep] = import_react57.useState(isConnected ? "success" : "start");
|
|
279066
|
-
const [error40, setError] = import_react57.useState(null);
|
|
279067
|
-
const [authMode, setAuthMode] = import_react57.useState(null);
|
|
279068
|
-
const [deviceInfo, setDeviceInfo] = import_react57.useState(null);
|
|
279069
|
-
const [legacyDeviceInfo, setLegacyDeviceInfo] = import_react57.useState(null);
|
|
279070
|
-
const [workspaces, setWorkspaces] = import_react57.useState([]);
|
|
279071
|
-
const [selectedWorkspace, setSelectedWorkspace] = import_react57.useState(null);
|
|
279072
|
-
const [selectedIndex, setSelectedIndex] = import_react57.useState(0);
|
|
279073
|
-
const [billingUrl, setBillingUrl] = import_react57.useState(null);
|
|
279074
|
-
const [balance, setBalance] = import_react57.useState(null);
|
|
279075
|
-
const pollingRef = import_react57.useRef(null);
|
|
279076
|
-
const cancelledRef = import_react57.useRef(false);
|
|
279077
|
-
const connectedWorkspace = appConfig.data.workspaceSlug ? { name: appConfig.data.workspaceSlug, slug: appConfig.data.workspaceSlug } : null;
|
|
279078
|
-
const goHome = () => {
|
|
279079
|
-
onClose();
|
|
279080
|
-
};
|
|
279081
|
-
const cleanup = () => {
|
|
279082
|
-
cancelledRef.current = true;
|
|
279083
|
-
if (pollingRef.current) {
|
|
279084
|
-
clearTimeout(pollingRef.current);
|
|
279085
|
-
pollingRef.current = null;
|
|
279086
|
-
}
|
|
279087
|
-
};
|
|
279088
|
-
import_react57.useEffect(() => {
|
|
279089
|
-
return cleanup;
|
|
279090
|
-
}, []);
|
|
279091
|
-
const openUrl = (url2) => {
|
|
279092
|
-
try {
|
|
279093
|
-
const platform = process.platform;
|
|
279094
|
-
if (platform === "darwin") {
|
|
279095
|
-
Bun.spawn(["open", url2]);
|
|
279096
|
-
} else if (platform === "win32") {
|
|
279097
|
-
Bun.spawn(["cmd", "/c", "start", url2]);
|
|
279098
|
-
} else {
|
|
279099
|
-
Bun.spawn(["xdg-open", url2]);
|
|
279100
|
-
}
|
|
279101
|
-
} catch {}
|
|
279102
|
-
};
|
|
279103
|
-
const startDeviceFlow = async () => {
|
|
279104
|
-
setStep("requesting");
|
|
279105
|
-
setError(null);
|
|
279106
|
-
cancelledRef.current = false;
|
|
279107
|
-
const apiUrl = getPensarApiUrl();
|
|
279108
|
-
console.error(`[auth] apiUrl=${apiUrl}`);
|
|
279109
|
-
try {
|
|
279110
|
-
console.error(`[auth] fetching ${apiUrl}/api/cli/config`);
|
|
279111
|
-
const configResponse = await fetch(`${apiUrl}/api/cli/config`);
|
|
279112
|
-
console.error(`[auth] config response: ${configResponse.status} ${configResponse.statusText}`);
|
|
279113
|
-
if (configResponse.ok) {
|
|
279114
|
-
const cliConfig = await configResponse.json();
|
|
279115
|
-
console.error(`[auth] got workosClientId=${cliConfig.workosClientId.slice(0, 12)}...`);
|
|
279116
|
-
const response = await fetch("https://api.workos.com/user_management/authorize/device", {
|
|
279117
|
-
method: "POST",
|
|
279118
|
-
headers: { "Content-Type": "application/json" },
|
|
279119
|
-
body: JSON.stringify({ client_id: cliConfig.workosClientId })
|
|
279120
|
-
});
|
|
279121
|
-
console.error(`[auth] device authorize response: ${response.status}`);
|
|
279122
|
-
if (response.ok) {
|
|
279123
|
-
const data = await response.json();
|
|
279124
|
-
console.error(`[auth] device code obtained, polling interval=${data.interval}s, expires=${data.expires_in}s`);
|
|
279125
|
-
setAuthMode("workos");
|
|
279126
|
-
setDeviceInfo(data);
|
|
279127
|
-
openUrl(data.verification_uri_complete);
|
|
279128
|
-
setStep("polling");
|
|
279129
|
-
pollForToken(apiUrl, cliConfig.workosClientId, data.device_code, data.interval, data.expires_in);
|
|
279130
|
-
return;
|
|
279131
|
-
}
|
|
279132
|
-
}
|
|
279133
|
-
} catch (e) {
|
|
279134
|
-
console.error(`[auth] WorkOS flow failed, falling back to legacy:`, e);
|
|
279135
|
-
}
|
|
279136
|
-
try {
|
|
279137
|
-
const response = await fetch(`${apiUrl}/auth/device/code`, {
|
|
279138
|
-
method: "POST",
|
|
279139
|
-
headers: { "Content-Type": "application/json" }
|
|
279140
|
-
});
|
|
279141
|
-
if (!response.ok) {
|
|
279142
|
-
throw new Error("Failed to start device authorization");
|
|
279143
|
-
}
|
|
279144
|
-
const data = await response.json();
|
|
279145
|
-
setAuthMode("legacy");
|
|
279146
|
-
setLegacyDeviceInfo(data);
|
|
279147
|
-
openUrl(data.verificationUriComplete);
|
|
279148
|
-
setStep("polling");
|
|
279149
|
-
pollForLegacyToken(apiUrl, data.deviceCode, data.interval, data.expiresIn);
|
|
279150
|
-
} catch (err) {
|
|
279151
|
-
setError(err instanceof Error ? err.message : "Failed to start authorization");
|
|
279152
|
-
setStep("error");
|
|
279153
|
-
}
|
|
279154
|
-
};
|
|
279155
|
-
const pollForToken = (apiUrl, clientId, deviceCode, interval, expiresIn) => {
|
|
279156
|
-
const deadline = Date.now() + expiresIn * 1000;
|
|
279157
|
-
const poll = async () => {
|
|
279158
|
-
if (cancelledRef.current)
|
|
279159
|
-
return;
|
|
279160
|
-
if (Date.now() > deadline) {
|
|
279161
|
-
setError("Authorization timed out. Please try again.");
|
|
279162
|
-
setStep("error");
|
|
279163
|
-
return;
|
|
279164
|
-
}
|
|
279165
|
-
try {
|
|
279166
|
-
console.error(`[auth] polling WorkOS authenticate...`);
|
|
279167
|
-
const response = await fetch("https://api.workos.com/user_management/authenticate", {
|
|
279168
|
-
method: "POST",
|
|
279169
|
-
headers: { "Content-Type": "application/json" },
|
|
279170
|
-
body: JSON.stringify({
|
|
279171
|
-
client_id: clientId,
|
|
279172
|
-
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
279173
|
-
device_code: deviceCode
|
|
279174
|
-
})
|
|
279175
|
-
});
|
|
279176
|
-
if (cancelledRef.current)
|
|
279177
|
-
return;
|
|
279178
|
-
console.error(`[auth] poll response: ${response.status}`);
|
|
279179
|
-
if (response.status === 400) {
|
|
279180
|
-
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
279181
|
-
return;
|
|
279182
|
-
}
|
|
279183
|
-
if (!response.ok) {
|
|
279184
|
-
const body = await response.text();
|
|
279185
|
-
console.error(`[auth] auth failed: ${response.status} ${body}`);
|
|
279186
|
-
throw new Error("Authentication failed");
|
|
279187
|
-
}
|
|
279188
|
-
const data = await response.json();
|
|
279189
|
-
console.error(`[auth] got tokens, access_token=${data.access_token.length} chars`);
|
|
279190
|
-
await config2.update({
|
|
279191
|
-
accessToken: data.access_token,
|
|
279192
|
-
refreshToken: data.refresh_token
|
|
279193
|
-
});
|
|
279194
|
-
await appConfig.reload();
|
|
279195
|
-
console.error(`[auth] tokens saved, fetching workspaces...`);
|
|
279196
|
-
await fetchWorkspaces(apiUrl, data.access_token);
|
|
279197
|
-
} catch (err) {
|
|
279198
|
-
if (cancelledRef.current)
|
|
279199
|
-
return;
|
|
279200
|
-
console.error(`[auth] poll error, retrying:`, err);
|
|
279201
|
-
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
279202
|
-
}
|
|
279203
|
-
};
|
|
279204
|
-
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
279205
|
-
};
|
|
279206
|
-
const pollForLegacyToken = (apiUrl, deviceCode, interval, expiresIn) => {
|
|
279207
|
-
const deadline = Date.now() + expiresIn * 1000;
|
|
279208
|
-
const poll = async () => {
|
|
279209
|
-
if (cancelledRef.current)
|
|
279210
|
-
return;
|
|
279211
|
-
if (Date.now() > deadline) {
|
|
279212
|
-
setError("Authorization timed out. Please try again.");
|
|
279213
|
-
setStep("error");
|
|
279214
|
-
return;
|
|
279215
|
-
}
|
|
279216
|
-
try {
|
|
279217
|
-
const response = await fetch(`${apiUrl}/auth/device/token`, {
|
|
279218
|
-
method: "POST",
|
|
279219
|
-
headers: { "Content-Type": "application/json" },
|
|
279220
|
-
body: JSON.stringify({ deviceCode })
|
|
279221
|
-
});
|
|
279222
|
-
if (!response.ok) {
|
|
279223
|
-
throw new Error("Failed to check authorization status");
|
|
279224
|
-
}
|
|
279225
|
-
const data = await response.json();
|
|
279226
|
-
if (cancelledRef.current)
|
|
279227
|
-
return;
|
|
279228
|
-
if (data.status === "complete" && data.apiKey) {
|
|
279229
|
-
await config2.update({ pensarAPIKey: data.apiKey });
|
|
279230
|
-
if (data.workspace) {
|
|
279231
|
-
await config2.update({
|
|
279232
|
-
workspaceId: data.workspace.id,
|
|
279233
|
-
workspaceSlug: data.workspace.slug
|
|
279234
|
-
});
|
|
279235
|
-
}
|
|
279236
|
-
appConfig.reload();
|
|
279237
|
-
setSelectedWorkspace(data.workspace ? {
|
|
279238
|
-
...data.workspace,
|
|
279239
|
-
balance: data.credits?.balance ?? 0,
|
|
279240
|
-
hasPaymentMethod: true
|
|
279241
|
-
} : null);
|
|
279242
|
-
setBalance(data.credits?.balance ?? null);
|
|
279243
|
-
setStep("success");
|
|
279244
|
-
return;
|
|
279245
|
-
}
|
|
279246
|
-
if (data.status === "expired") {
|
|
279247
|
-
setError("Authorization expired. Please try again.");
|
|
279248
|
-
setStep("error");
|
|
279249
|
-
return;
|
|
279250
|
-
}
|
|
279251
|
-
if (data.status === "not_found") {
|
|
279252
|
-
setError("Invalid authorization session. Please try again.");
|
|
279253
|
-
setStep("error");
|
|
279254
|
-
return;
|
|
279255
|
-
}
|
|
279256
|
-
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
279257
|
-
} catch (err) {
|
|
279258
|
-
if (cancelledRef.current)
|
|
279259
|
-
return;
|
|
279260
|
-
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
279261
|
-
}
|
|
279262
|
-
};
|
|
279263
|
-
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
279264
|
-
};
|
|
279265
|
-
const fetchWorkspaces = async (apiUrl, accessToken) => {
|
|
279266
|
-
try {
|
|
279267
|
-
const url2 = `${apiUrl}/api/cli/workspaces`;
|
|
279268
|
-
console.error(`[auth] fetchWorkspaces: ${url2} (token=${accessToken.length} chars)`);
|
|
279269
|
-
const response = await fetch(url2, {
|
|
279270
|
-
headers: { Authorization: `Bearer ${accessToken}` }
|
|
279271
|
-
});
|
|
279272
|
-
console.error(`[auth] workspaces response: ${response.status} ${response.statusText}`);
|
|
279273
|
-
if (!response.ok) {
|
|
279274
|
-
const body = await response.text();
|
|
279275
|
-
console.error(`[auth] workspaces error body: ${body}`);
|
|
279276
|
-
throw new Error(`Failed to fetch workspaces (${response.status})`);
|
|
279277
|
-
}
|
|
279278
|
-
const data = await response.json();
|
|
279279
|
-
console.error(`[auth] got ${data.workspaces.length} workspace(s)`);
|
|
279280
|
-
if (data.workspaces.length === 0) {
|
|
279281
|
-
setError("No workspaces found. Create one at console.pensar.dev");
|
|
279282
|
-
setStep("error");
|
|
279283
|
-
return;
|
|
279284
|
-
}
|
|
279285
|
-
if (data.workspaces.length === 1) {
|
|
279286
|
-
await selectWorkspace(apiUrl, accessToken, data.workspaces[0]);
|
|
279287
|
-
return;
|
|
279288
|
-
}
|
|
279289
|
-
setWorkspaces(data.workspaces);
|
|
279290
|
-
setSelectedIndex(0);
|
|
279291
|
-
setStep("select-workspace");
|
|
279292
|
-
} catch (err) {
|
|
279293
|
-
console.error(`[auth] fetchWorkspaces error:`, err);
|
|
279294
|
-
setError(err instanceof Error ? err.message : "Failed to fetch workspaces");
|
|
279295
|
-
setStep("error");
|
|
279296
|
-
}
|
|
279297
|
-
};
|
|
279298
|
-
const selectWorkspace = async (apiUrl, accessToken, workspace) => {
|
|
279299
|
-
setSelectedWorkspace(workspace);
|
|
279300
|
-
setStep("checking-billing");
|
|
279301
|
-
try {
|
|
279302
|
-
console.error(`[auth] selectWorkspace: ${workspace.id} (${workspace.name})`);
|
|
279303
|
-
const response = await fetch(`${apiUrl}/api/cli/select-workspace`, {
|
|
279304
|
-
method: "POST",
|
|
279305
|
-
headers: {
|
|
279306
|
-
"Content-Type": "application/json",
|
|
279307
|
-
Authorization: `Bearer ${accessToken}`
|
|
279308
|
-
},
|
|
279309
|
-
body: JSON.stringify({ workspaceId: workspace.id })
|
|
279310
|
-
});
|
|
279311
|
-
console.error(`[auth] select-workspace response: ${response.status}`);
|
|
279312
|
-
if (!response.ok) {
|
|
279313
|
-
const body = await response.text();
|
|
279314
|
-
console.error(`[auth] select-workspace error: ${body}`);
|
|
279315
|
-
throw new Error("Failed to select workspace");
|
|
279316
|
-
}
|
|
279317
|
-
const data = await response.json();
|
|
279318
|
-
await config2.update({
|
|
279319
|
-
workspaceId: workspace.id,
|
|
279320
|
-
workspaceSlug: workspace.slug
|
|
279321
|
-
});
|
|
279322
|
-
appConfig.reload();
|
|
279323
|
-
setBalance(data.billing.balance);
|
|
279324
|
-
if (!data.confirmed && data.billingUrl) {
|
|
279325
|
-
setBillingUrl(data.billingUrl);
|
|
279326
|
-
}
|
|
279327
|
-
setStep("success");
|
|
279328
|
-
} catch (err) {
|
|
279329
|
-
setError(err instanceof Error ? err.message : "Failed to select workspace");
|
|
279330
|
-
setStep("error");
|
|
279331
|
-
}
|
|
279332
|
-
};
|
|
279333
|
-
const handleDisconnect = async () => {
|
|
279334
|
-
await config2.update({
|
|
279335
|
-
pensarAPIKey: null,
|
|
279336
|
-
accessToken: null,
|
|
279337
|
-
refreshToken: null,
|
|
279338
|
-
workspaceId: null,
|
|
279339
|
-
workspaceSlug: null
|
|
279340
|
-
});
|
|
279341
|
-
appConfig.reload();
|
|
279342
|
-
setAuthMode(null);
|
|
279343
|
-
setSelectedWorkspace(null);
|
|
279344
|
-
setBalance(null);
|
|
279345
|
-
setBillingUrl(null);
|
|
279346
|
-
setDeviceInfo(null);
|
|
279347
|
-
setLegacyDeviceInfo(null);
|
|
279348
|
-
setStep("start");
|
|
279349
|
-
};
|
|
279350
|
-
const hasLowBalance = balance !== null && balance < 1;
|
|
279351
|
-
const effectiveBillingUrl = billingUrl || (selectedWorkspace?.slug ? `${getPensarConsoleUrl()}/${selectedWorkspace.slug}/settings/billing` : connectedWorkspace?.slug ? `${getPensarConsoleUrl()}/${connectedWorkspace.slug}/settings/billing` : `${getPensarConsoleUrl()}/credits`);
|
|
279352
|
-
const openBillingPage = () => {
|
|
279353
|
-
openUrl(effectiveBillingUrl);
|
|
279354
|
-
goHome();
|
|
279355
|
-
};
|
|
279356
|
-
useKeyboard((key) => {
|
|
279357
|
-
key.preventDefault();
|
|
279358
|
-
if (key.name === "escape") {
|
|
279359
|
-
cleanup();
|
|
279360
|
-
goHome();
|
|
279361
|
-
return;
|
|
279362
|
-
}
|
|
279363
|
-
if (step === "start") {
|
|
279364
|
-
if (key.name === "return") {
|
|
279365
|
-
startDeviceFlow();
|
|
279366
|
-
}
|
|
279367
|
-
}
|
|
279368
|
-
if (step === "select-workspace") {
|
|
279369
|
-
if (key.name === "up" && selectedIndex > 0) {
|
|
279370
|
-
setSelectedIndex((i) => i - 1);
|
|
279371
|
-
}
|
|
279372
|
-
if (key.name === "down" && selectedIndex < workspaces.length - 1) {
|
|
279373
|
-
setSelectedIndex((i) => i + 1);
|
|
279374
|
-
}
|
|
279375
|
-
if (key.name === "return" && workspaces[selectedIndex]) {
|
|
279376
|
-
const currentConfig = appConfig.data;
|
|
279377
|
-
const apiUrl = getPensarApiUrl();
|
|
279378
|
-
const accessToken = currentConfig.accessToken;
|
|
279379
|
-
selectWorkspace(apiUrl, accessToken, workspaces[selectedIndex]);
|
|
279380
|
-
}
|
|
279381
|
-
}
|
|
279382
|
-
if (step === "error") {
|
|
279383
|
-
if (key.name === "return") {
|
|
279384
|
-
startDeviceFlow();
|
|
279385
|
-
}
|
|
279386
|
-
}
|
|
279387
|
-
if (step === "success") {
|
|
279388
|
-
if (key.name === "return") {
|
|
279389
|
-
if (hasLowBalance || billingUrl) {
|
|
279390
|
-
openBillingPage();
|
|
279391
|
-
} else {
|
|
279392
|
-
goHome();
|
|
279393
|
-
}
|
|
279394
|
-
}
|
|
279395
|
-
if (key.raw === "d" || key.raw === "D") {
|
|
279396
|
-
handleDisconnect();
|
|
279397
|
-
}
|
|
279398
|
-
}
|
|
279399
|
-
});
|
|
279400
|
-
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Dialog, {
|
|
279401
|
-
size: "large",
|
|
279402
|
-
onClose: goHome,
|
|
279403
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279404
|
-
flexDirection: "column",
|
|
279405
|
-
width: "100%",
|
|
279406
|
-
alignItems: "flex-start",
|
|
279407
|
-
padding: 1,
|
|
279408
|
-
children: [
|
|
279409
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279410
|
-
marginBottom: 1,
|
|
279411
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279412
|
-
fg: colors2.primary,
|
|
279413
|
-
children: "Pensar Console — Managed Inference"
|
|
279414
|
-
}, undefined, false, undefined, this)
|
|
279415
|
-
}, undefined, false, undefined, this),
|
|
279416
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279417
|
-
marginBottom: 1,
|
|
279418
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279419
|
-
fg: colors2.textMuted,
|
|
279420
|
-
children: [
|
|
279421
|
-
"Connect to Pensar Console for usage-based AI inference.",
|
|
279422
|
-
`
|
|
279423
|
-
`,
|
|
279424
|
-
"No API keys needed — just a Pensar account with credits."
|
|
279425
|
-
]
|
|
279426
|
-
}, undefined, true, undefined, this)
|
|
279427
|
-
}, undefined, false, undefined, this),
|
|
279428
|
-
step === "start" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279429
|
-
flexDirection: "column",
|
|
279430
|
-
gap: 1,
|
|
279431
|
-
children: [
|
|
279432
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279433
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279434
|
-
fg: colors2.text,
|
|
279435
|
-
children: [
|
|
279436
|
-
"Press ",
|
|
279437
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279438
|
-
fg: colors2.primary,
|
|
279439
|
-
children: "[ENTER]"
|
|
279440
|
-
}, undefined, false, undefined, this),
|
|
279441
|
-
" to authorize via your browser."
|
|
279442
|
-
]
|
|
279443
|
-
}, undefined, true, undefined, this)
|
|
279444
|
-
}, undefined, false, undefined, this),
|
|
279445
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279446
|
-
marginTop: 1,
|
|
279447
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279448
|
-
fg: colors2.textMuted,
|
|
279449
|
-
children: [
|
|
279450
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279451
|
-
fg: colors2.primary,
|
|
279452
|
-
children: "[ENTER]"
|
|
279453
|
-
}, undefined, false, undefined, this),
|
|
279454
|
-
" Connect ·",
|
|
279455
|
-
" ",
|
|
279456
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279457
|
-
fg: colors2.primary,
|
|
279458
|
-
children: "[ESC]"
|
|
279459
|
-
}, undefined, false, undefined, this),
|
|
279460
|
-
" Cancel"
|
|
279461
|
-
]
|
|
279462
|
-
}, undefined, true, undefined, this)
|
|
279463
|
-
}, undefined, false, undefined, this)
|
|
279464
|
-
]
|
|
279465
|
-
}, undefined, true, undefined, this),
|
|
279466
|
-
step === "requesting" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279467
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279468
|
-
fg: colors2.warning,
|
|
279469
|
-
children: "Starting authorization..."
|
|
279470
|
-
}, undefined, false, undefined, this)
|
|
279471
|
-
}, undefined, false, undefined, this),
|
|
279472
|
-
step === "polling" && (deviceInfo || legacyDeviceInfo) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279473
|
-
flexDirection: "column",
|
|
279474
|
-
gap: 1,
|
|
279475
|
-
children: [
|
|
279476
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279477
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279478
|
-
fg: colors2.warning,
|
|
279479
|
-
children: "Waiting for browser authorization..."
|
|
279480
|
-
}, undefined, false, undefined, this)
|
|
279481
|
-
}, undefined, false, undefined, this),
|
|
279482
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279483
|
-
marginTop: 1,
|
|
279484
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279485
|
-
fg: colors2.text,
|
|
279486
|
-
children: [
|
|
279487
|
-
"Your code:",
|
|
279488
|
-
" ",
|
|
279489
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279490
|
-
fg: colors2.primary,
|
|
279491
|
-
children: deviceInfo?.user_code || legacyDeviceInfo?.userCode
|
|
279492
|
-
}, undefined, false, undefined, this)
|
|
279493
|
-
]
|
|
279494
|
-
}, undefined, true, undefined, this)
|
|
279495
|
-
}, undefined, false, undefined, this),
|
|
279496
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279497
|
-
marginTop: 1,
|
|
279498
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279499
|
-
fg: colors2.textMuted,
|
|
279500
|
-
children: [
|
|
279501
|
-
"If the browser didn't open, visit:",
|
|
279502
|
-
`
|
|
279503
|
-
`,
|
|
279504
|
-
deviceInfo?.verification_uri_complete || legacyDeviceInfo?.verificationUriComplete
|
|
279505
|
-
]
|
|
279506
|
-
}, undefined, true, undefined, this)
|
|
279507
|
-
}, undefined, false, undefined, this),
|
|
279508
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279509
|
-
marginTop: 1,
|
|
279510
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279511
|
-
fg: colors2.textMuted,
|
|
279512
|
-
children: [
|
|
279513
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279514
|
-
fg: colors2.primary,
|
|
279515
|
-
children: "[ESC]"
|
|
279516
|
-
}, undefined, false, undefined, this),
|
|
279517
|
-
" Cancel"
|
|
279518
|
-
]
|
|
279519
|
-
}, undefined, true, undefined, this)
|
|
279520
|
-
}, undefined, false, undefined, this)
|
|
279521
|
-
]
|
|
279522
|
-
}, undefined, true, undefined, this),
|
|
279523
|
-
step === "select-workspace" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279524
|
-
flexDirection: "column",
|
|
279525
|
-
gap: 1,
|
|
279526
|
-
children: [
|
|
279527
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279528
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279529
|
-
fg: colors2.text,
|
|
279530
|
-
children: "Select a workspace:"
|
|
279531
|
-
}, undefined, false, undefined, this)
|
|
279532
|
-
}, undefined, false, undefined, this),
|
|
279533
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279534
|
-
flexDirection: "column",
|
|
279535
|
-
marginTop: 1,
|
|
279536
|
-
children: workspaces.map((ws, i) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279537
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279538
|
-
fg: i === selectedIndex ? colors2.primary : colors2.textMuted,
|
|
279539
|
-
children: [
|
|
279540
|
-
i === selectedIndex ? "▸ " : " ",
|
|
279541
|
-
ws.name,
|
|
279542
|
-
" ",
|
|
279543
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279544
|
-
fg: colors2.textMuted,
|
|
279545
|
-
children: [
|
|
279546
|
-
"(",
|
|
279547
|
-
ws.slug,
|
|
279548
|
-
") — $",
|
|
279549
|
-
ws.balance.toFixed(2)
|
|
279550
|
-
]
|
|
279551
|
-
}, undefined, true, undefined, this)
|
|
279552
|
-
]
|
|
279553
|
-
}, undefined, true, undefined, this)
|
|
279554
|
-
}, ws.id, false, undefined, this))
|
|
279555
|
-
}, undefined, false, undefined, this),
|
|
279556
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279557
|
-
marginTop: 1,
|
|
279558
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279559
|
-
fg: colors2.textMuted,
|
|
279560
|
-
children: [
|
|
279561
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279562
|
-
fg: colors2.primary,
|
|
279563
|
-
children: "[↑/↓]"
|
|
279564
|
-
}, undefined, false, undefined, this),
|
|
279565
|
-
" Navigate ·",
|
|
279566
|
-
" ",
|
|
279567
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279568
|
-
fg: colors2.primary,
|
|
279569
|
-
children: "[ENTER]"
|
|
279570
|
-
}, undefined, false, undefined, this),
|
|
279571
|
-
" Select ·",
|
|
279572
|
-
" ",
|
|
279573
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279574
|
-
fg: colors2.primary,
|
|
279575
|
-
children: "[ESC]"
|
|
279576
|
-
}, undefined, false, undefined, this),
|
|
279577
|
-
" Cancel"
|
|
279578
|
-
]
|
|
279579
|
-
}, undefined, true, undefined, this)
|
|
279580
|
-
}, undefined, false, undefined, this)
|
|
279581
|
-
]
|
|
279582
|
-
}, undefined, true, undefined, this),
|
|
279583
|
-
step === "checking-billing" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279584
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279585
|
-
fg: colors2.warning,
|
|
279586
|
-
children: [
|
|
279587
|
-
"Checking billing for ",
|
|
279588
|
-
selectedWorkspace?.name,
|
|
279589
|
-
"..."
|
|
279590
|
-
]
|
|
279591
|
-
}, undefined, true, undefined, this)
|
|
279592
|
-
}, undefined, false, undefined, this),
|
|
279593
|
-
step === "success" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279594
|
-
flexDirection: "column",
|
|
279595
|
-
gap: 1,
|
|
279596
|
-
children: [
|
|
279597
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279598
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279599
|
-
fg: colors2.success,
|
|
279600
|
-
children: "Connected to Pensar Console"
|
|
279601
|
-
}, undefined, false, undefined, this)
|
|
279602
|
-
}, undefined, false, undefined, this),
|
|
279603
|
-
(selectedWorkspace || connectedWorkspace) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279604
|
-
flexDirection: "column",
|
|
279605
|
-
children: [
|
|
279606
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279607
|
-
fg: colors2.text,
|
|
279608
|
-
children: [
|
|
279609
|
-
"Workspace:",
|
|
279610
|
-
" ",
|
|
279611
|
-
selectedWorkspace?.name || connectedWorkspace?.name
|
|
279612
|
-
]
|
|
279613
|
-
}, undefined, true, undefined, this),
|
|
279614
|
-
balance !== null && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279615
|
-
fg: colors2.text,
|
|
279616
|
-
children: [
|
|
279617
|
-
"Credits:",
|
|
279618
|
-
" ",
|
|
279619
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279620
|
-
fg: hasLowBalance ? colors2.warning : colors2.text,
|
|
279621
|
-
children: [
|
|
279622
|
-
"$",
|
|
279623
|
-
balance.toFixed(2)
|
|
279624
|
-
]
|
|
279625
|
-
}, undefined, true, undefined, this)
|
|
279626
|
-
]
|
|
279627
|
-
}, undefined, true, undefined, this)
|
|
279628
|
-
]
|
|
279629
|
-
}, undefined, true, undefined, this),
|
|
279630
|
-
(hasLowBalance || billingUrl) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279631
|
-
marginTop: 1,
|
|
279632
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279633
|
-
fg: colors2.warning,
|
|
279634
|
-
children: [
|
|
279635
|
-
billingUrl ? "Your workspace needs credits to use Apex CLI." : "Your credit balance is very low. We recommend at least $30 to run",
|
|
279636
|
-
`
|
|
279637
|
-
`,
|
|
279638
|
-
billingUrl ? "Press ENTER to open billing and add credits." : "pentests without interruptions. Press ENTER to open billing."
|
|
279639
|
-
]
|
|
279640
|
-
}, undefined, true, undefined, this)
|
|
279641
|
-
}, undefined, false, undefined, this),
|
|
279642
|
-
!selectedWorkspace && !connectedWorkspace && appConfig.data.pensarAPIKey && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279643
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279644
|
-
fg: colors2.textMuted,
|
|
279645
|
-
children: "Already connected (legacy key saved in config)"
|
|
279646
|
-
}, undefined, false, undefined, this)
|
|
279647
|
-
}, undefined, false, undefined, this),
|
|
279648
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279649
|
-
marginTop: 1,
|
|
279650
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279651
|
-
fg: colors2.textMuted,
|
|
279652
|
-
children: "Pensar models are now available in the model selector."
|
|
279653
|
-
}, undefined, false, undefined, this)
|
|
279654
|
-
}, undefined, false, undefined, this),
|
|
279655
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279656
|
-
marginTop: 1,
|
|
279657
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279658
|
-
fg: colors2.textMuted,
|
|
279659
|
-
children: [
|
|
279660
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279661
|
-
fg: colors2.primary,
|
|
279662
|
-
children: "[ENTER]"
|
|
279663
|
-
}, undefined, false, undefined, this),
|
|
279664
|
-
" ",
|
|
279665
|
-
hasLowBalance || billingUrl ? "Open billing" : "Done",
|
|
279666
|
-
" ·",
|
|
279667
|
-
" ",
|
|
279668
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279669
|
-
fg: colors2.error,
|
|
279670
|
-
children: "[D]"
|
|
279671
|
-
}, undefined, false, undefined, this),
|
|
279672
|
-
" Disconnect ·",
|
|
279673
|
-
" ",
|
|
279674
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279675
|
-
fg: colors2.primary,
|
|
279676
|
-
children: "[ESC]"
|
|
279677
|
-
}, undefined, false, undefined, this),
|
|
279678
|
-
" Back"
|
|
279679
|
-
]
|
|
279680
|
-
}, undefined, true, undefined, this)
|
|
279681
|
-
}, undefined, false, undefined, this)
|
|
279682
|
-
]
|
|
279683
|
-
}, undefined, true, undefined, this),
|
|
279684
|
-
step === "error" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279685
|
-
flexDirection: "column",
|
|
279686
|
-
gap: 1,
|
|
279687
|
-
children: [
|
|
279688
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279689
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279690
|
-
fg: colors2.error,
|
|
279691
|
-
children: error40
|
|
279692
|
-
}, undefined, false, undefined, this)
|
|
279693
|
-
}, undefined, false, undefined, this),
|
|
279694
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279695
|
-
marginTop: 1,
|
|
279696
|
-
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279697
|
-
fg: colors2.textMuted,
|
|
279698
|
-
children: [
|
|
279699
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279700
|
-
fg: colors2.primary,
|
|
279701
|
-
children: "[ENTER]"
|
|
279702
|
-
}, undefined, false, undefined, this),
|
|
279703
|
-
" Try again ·",
|
|
279704
|
-
" ",
|
|
279705
|
-
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
279706
|
-
fg: colors2.primary,
|
|
279707
|
-
children: "[ESC]"
|
|
279708
|
-
}, undefined, false, undefined, this),
|
|
279709
|
-
" Cancel"
|
|
279710
|
-
]
|
|
279711
|
-
}, undefined, true, undefined, this)
|
|
279712
|
-
}, undefined, false, undefined, this)
|
|
279713
|
-
]
|
|
279714
|
-
}, undefined, true, undefined, this)
|
|
279715
|
-
]
|
|
279716
|
-
}, undefined, true, undefined, this)
|
|
279717
|
-
}, undefined, false, undefined, this);
|
|
279718
|
-
}
|
|
279719
|
-
|
|
279720
280371
|
// src/tui/components/commands/credits-flow.tsx
|
|
279721
|
-
var
|
|
279722
|
-
|
|
280372
|
+
var import_react60 = __toESM(require_react(), 1);
|
|
280373
|
+
init_auth();
|
|
280374
|
+
init_config2();
|
|
279723
280375
|
function CreditsFlow({ onOpenAuthDialog }) {
|
|
279724
280376
|
const route = useRoute();
|
|
279725
280377
|
const appConfig = useConfig();
|
|
279726
|
-
const [step, setStep] =
|
|
279727
|
-
const [credits, setCredits] =
|
|
279728
|
-
const [error40, setError] =
|
|
280378
|
+
const [step, setStep] = import_react60.useState("loading");
|
|
280379
|
+
const [credits, setCredits] = import_react60.useState(null);
|
|
280380
|
+
const [error40, setError] = import_react60.useState(null);
|
|
279729
280381
|
const creditsUrl = `${getPensarConsoleUrl()}/credits`;
|
|
279730
280382
|
const goHome = () => {
|
|
279731
280383
|
route.navigate({ type: "base", path: "home" });
|
|
@@ -279772,6 +280424,9 @@ function CreditsFlow({ onOpenAuthDialog }) {
|
|
|
279772
280424
|
throw new Error("Failed to fetch balance");
|
|
279773
280425
|
}
|
|
279774
280426
|
const result = await response.json();
|
|
280427
|
+
if (result.signingKey) {
|
|
280428
|
+
await config2.update({ gatewaySigningKey: result.signingKey });
|
|
280429
|
+
}
|
|
279775
280430
|
setCredits({
|
|
279776
280431
|
balance: result.credits.balance,
|
|
279777
280432
|
workspace: result.workspace.name
|
|
@@ -279782,7 +280437,7 @@ function CreditsFlow({ onOpenAuthDialog }) {
|
|
|
279782
280437
|
setStep("display");
|
|
279783
280438
|
}
|
|
279784
280439
|
};
|
|
279785
|
-
|
|
280440
|
+
import_react60.useEffect(() => {
|
|
279786
280441
|
fetchBalance();
|
|
279787
280442
|
}, []);
|
|
279788
280443
|
useKeyboard((key) => {
|
|
@@ -280021,10 +280676,10 @@ function CreditsFlow({ onOpenAuthDialog }) {
|
|
|
280021
280676
|
}
|
|
280022
280677
|
|
|
280023
280678
|
// src/tui/context/keybinding.tsx
|
|
280024
|
-
var
|
|
280679
|
+
var import_react66 = __toESM(require_react(), 1);
|
|
280025
280680
|
|
|
280026
280681
|
// src/tui/keybindings/keybind.tsx
|
|
280027
|
-
var
|
|
280682
|
+
var import_react62 = __toESM(require_react(), 1);
|
|
280028
280683
|
|
|
280029
280684
|
// src/tui/keybindings/actions.ts
|
|
280030
280685
|
var movementActions = [
|
|
@@ -280276,7 +280931,7 @@ var allActions = [
|
|
|
280276
280931
|
var actionsByKey = new Map(allActions.map((action) => [action.key, action]));
|
|
280277
280932
|
var actionsById = new Map(allActions.map((action) => [action.id, action]));
|
|
280278
280933
|
// src/tui/keybindings/keybind.tsx
|
|
280279
|
-
var LeaderKeyContext =
|
|
280934
|
+
var LeaderKeyContext = import_react62.createContext(null);
|
|
280280
280935
|
// src/tui/keybindings/registry.ts
|
|
280281
280936
|
function createKeybindings(deps) {
|
|
280282
280937
|
const {
|
|
@@ -280457,7 +281112,7 @@ function matchesKeybind(pressed, combo) {
|
|
|
280457
281112
|
}
|
|
280458
281113
|
|
|
280459
281114
|
// src/tui/context/keybinding.tsx
|
|
280460
|
-
var KeybindingContext =
|
|
281115
|
+
var KeybindingContext = import_react66.createContext(undefined);
|
|
280461
281116
|
function KeybindingProvider({
|
|
280462
281117
|
children,
|
|
280463
281118
|
deps
|
|
@@ -280497,9 +281152,9 @@ function KeybindingProvider({
|
|
|
280497
281152
|
}
|
|
280498
281153
|
|
|
280499
281154
|
// src/tui/components/pentest/pentest.tsx
|
|
280500
|
-
var
|
|
281155
|
+
var import_react74 = __toESM(require_react(), 1);
|
|
280501
281156
|
init_report();
|
|
280502
|
-
import { existsSync as existsSync26, readdirSync as readdirSync6, readFileSync as
|
|
281157
|
+
import { existsSync as existsSync26, readdirSync as readdirSync6, readFileSync as readFileSync13 } from "fs";
|
|
280503
281158
|
import { join as join27 } from "path";
|
|
280504
281159
|
init_session();
|
|
280505
281160
|
init_loader();
|
|
@@ -280529,7 +281184,7 @@ Found ${findings.length} vulnerabilities`);
|
|
|
280529
281184
|
init_utils();
|
|
280530
281185
|
|
|
280531
281186
|
// src/tui/components/agent-display.tsx
|
|
280532
|
-
var
|
|
281187
|
+
var import_react73 = __toESM(require_react(), 1);
|
|
280533
281188
|
|
|
280534
281189
|
// node_modules/marked/lib/marked.esm.js
|
|
280535
281190
|
function L2() {
|
|
@@ -281905,7 +282560,7 @@ function markdownToStyledText(content, colors2) {
|
|
|
281905
282560
|
}
|
|
281906
282561
|
}
|
|
281907
282562
|
// src/tui/components/shared/message-utils.ts
|
|
281908
|
-
import { createHash } from "crypto";
|
|
282563
|
+
import { createHash as createHash2 } from "crypto";
|
|
281909
282564
|
|
|
281910
282565
|
// src/tui/components/shared/type-guards.ts
|
|
281911
282566
|
function isToolMessage(msg) {
|
|
@@ -281914,7 +282569,7 @@ function isToolMessage(msg) {
|
|
|
281914
282569
|
|
|
281915
282570
|
// src/tui/components/shared/message-utils.ts
|
|
281916
282571
|
function hashContent(content) {
|
|
281917
|
-
return
|
|
282572
|
+
return createHash2("sha256").update(content).digest("hex").slice(0, 8);
|
|
281918
282573
|
}
|
|
281919
282574
|
function getStableMessageKey(item, contextId = "root") {
|
|
281920
282575
|
if (isToolMessage(item)) {
|
|
@@ -282861,14 +283516,14 @@ ${preview}${suffix}` : preview + suffix || "POC passed",
|
|
|
282861
283516
|
return null;
|
|
282862
283517
|
}
|
|
282863
283518
|
// src/tui/components/shared/ascii-spinner.tsx
|
|
282864
|
-
var
|
|
283519
|
+
var import_react67 = __toESM(require_react(), 1);
|
|
282865
283520
|
var SPINNER_FRAMES = ["/", "-", "\\", "|"];
|
|
282866
283521
|
var SPINNER_INTERVAL = 100;
|
|
282867
283522
|
function AsciiSpinner({ label, fg: fg2 }) {
|
|
282868
283523
|
const { colors: colors2 } = useTheme();
|
|
282869
283524
|
const spinnerColor = fg2 ?? colors2.info;
|
|
282870
|
-
const [frame, setFrame] =
|
|
282871
|
-
|
|
283525
|
+
const [frame, setFrame] = import_react67.useState(0);
|
|
283526
|
+
import_react67.useEffect(() => {
|
|
282872
283527
|
const interval = setInterval(() => {
|
|
282873
283528
|
setFrame((f3) => (f3 + 1) % SPINNER_FRAMES.length);
|
|
282874
283529
|
}, SPINNER_INTERVAL);
|
|
@@ -282880,7 +283535,7 @@ function AsciiSpinner({ label, fg: fg2 }) {
|
|
|
282880
283535
|
}, undefined, false, undefined, this);
|
|
282881
283536
|
}
|
|
282882
283537
|
// src/tui/components/shared/tool-renderer.tsx
|
|
282883
|
-
var
|
|
283538
|
+
var import_react68 = __toESM(require_react(), 1);
|
|
282884
283539
|
var TOOLS_WITH_LOG_WINDOW = new Set([
|
|
282885
283540
|
"execute_command",
|
|
282886
283541
|
"run_attack_surface",
|
|
@@ -282893,13 +283548,13 @@ var TOOLS_WITH_LOG_WINDOW = new Set([
|
|
|
282893
283548
|
"document_vulnerability"
|
|
282894
283549
|
]);
|
|
282895
283550
|
var DEFAULT_SUBAGENT_LOG_LINES = 5;
|
|
282896
|
-
var ToolRenderer =
|
|
283551
|
+
var ToolRenderer = import_react68.memo(function ToolRenderer2({
|
|
282897
283552
|
message,
|
|
282898
283553
|
verbose = false,
|
|
282899
283554
|
expandedLogs = false
|
|
282900
283555
|
}) {
|
|
282901
283556
|
const { colors: colors2 } = useTheme();
|
|
282902
|
-
const [showOutput, setShowOutput] =
|
|
283557
|
+
const [showOutput, setShowOutput] = import_react68.useState(false);
|
|
282903
283558
|
if (!isToolMessage(message)) {
|
|
282904
283559
|
return null;
|
|
282905
283560
|
}
|
|
@@ -283039,7 +283694,7 @@ var ToolRenderer = import_react67.memo(function ToolRenderer2({
|
|
|
283039
283694
|
]
|
|
283040
283695
|
}, undefined, true, undefined, this);
|
|
283041
283696
|
});
|
|
283042
|
-
var SubagentLogWindow =
|
|
283697
|
+
var SubagentLogWindow = import_react68.memo(function SubagentLogWindow2({
|
|
283043
283698
|
subagentId,
|
|
283044
283699
|
entry,
|
|
283045
283700
|
expandedLogs
|
|
@@ -283096,8 +283751,8 @@ var SubagentLogWindow = import_react67.memo(function SubagentLogWindow2({
|
|
|
283096
283751
|
}, undefined, true, undefined, this);
|
|
283097
283752
|
});
|
|
283098
283753
|
// src/tui/components/shared/message-renderer.tsx
|
|
283099
|
-
var
|
|
283100
|
-
var MessageRenderer =
|
|
283754
|
+
var import_react69 = __toESM(require_react(), 1);
|
|
283755
|
+
var MessageRenderer = import_react69.memo(function MessageRenderer2({
|
|
283101
283756
|
message,
|
|
283102
283757
|
isStreaming = false,
|
|
283103
283758
|
verbose = false,
|
|
@@ -283107,7 +283762,7 @@ var MessageRenderer = import_react68.memo(function MessageRenderer2({
|
|
|
283107
283762
|
}) {
|
|
283108
283763
|
const { colors: colors2 } = useTheme();
|
|
283109
283764
|
const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content);
|
|
283110
|
-
const displayContent =
|
|
283765
|
+
const displayContent = import_react69.useMemo(() => message.role === "assistant" ? markdownToStyledText(content, colors2) : content, [content, message.role, colors2]);
|
|
283111
283766
|
if (isToolMessage(message)) {
|
|
283112
283767
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToolRenderer, {
|
|
283113
283768
|
message,
|
|
@@ -283219,9 +283874,9 @@ var MessageRenderer = import_react68.memo(function MessageRenderer2({
|
|
|
283219
283874
|
}, undefined, false, undefined, this);
|
|
283220
283875
|
});
|
|
283221
283876
|
// src/tui/components/shared/approval-prompt.tsx
|
|
283222
|
-
var
|
|
283877
|
+
var import_react70 = __toESM(require_react(), 1);
|
|
283223
283878
|
// src/tui/components/shared/message-reducer.ts
|
|
283224
|
-
var
|
|
283879
|
+
var import_react72 = __toESM(require_react(), 1);
|
|
283225
283880
|
// src/tui/components/agent-display.tsx
|
|
283226
283881
|
function getStableKey(item, contextId = "root") {
|
|
283227
283882
|
if ("messages" in item) {
|
|
@@ -283297,11 +283952,11 @@ function AgentDisplay({
|
|
|
283297
283952
|
]
|
|
283298
283953
|
}, undefined, true, undefined, this);
|
|
283299
283954
|
}
|
|
283300
|
-
var SubAgentDisplay =
|
|
283955
|
+
var SubAgentDisplay = import_react73.memo(function SubAgentDisplay2({
|
|
283301
283956
|
subagent
|
|
283302
283957
|
}) {
|
|
283303
283958
|
const { colors: colors2 } = useTheme();
|
|
283304
|
-
const [open, setOpen] =
|
|
283959
|
+
const [open, setOpen] = import_react73.useState(false);
|
|
283305
283960
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
283306
283961
|
height: open ? 40 : "auto",
|
|
283307
283962
|
onMouseDown: () => setOpen(!open),
|
|
@@ -283356,7 +284011,7 @@ var SubAgentDisplay = import_react72.memo(function SubAgentDisplay2({
|
|
|
283356
284011
|
]
|
|
283357
284012
|
}, undefined, true, undefined, this);
|
|
283358
284013
|
});
|
|
283359
|
-
var AgentMessage =
|
|
284014
|
+
var AgentMessage = import_react73.memo(function AgentMessage2({
|
|
283360
284015
|
message
|
|
283361
284016
|
}) {
|
|
283362
284017
|
const { colors: colors2 } = useTheme();
|
|
@@ -283465,8 +284120,8 @@ var AgentMessage = import_react72.memo(function AgentMessage2({
|
|
|
283465
284120
|
});
|
|
283466
284121
|
function ToolDetails({ message }) {
|
|
283467
284122
|
const { colors: colors2 } = useTheme();
|
|
283468
|
-
const [showArgs, setShowArgs] =
|
|
283469
|
-
const [showResult, setShowResult] =
|
|
284123
|
+
const [showArgs, setShowArgs] = import_react73.useState(false);
|
|
284124
|
+
const [showResult, setShowResult] = import_react73.useState(false);
|
|
283470
284125
|
if (message.role !== "tool") {
|
|
283471
284126
|
return null;
|
|
283472
284127
|
}
|
|
@@ -283572,27 +284227,27 @@ function Pentest({
|
|
|
283572
284227
|
const config3 = useConfig();
|
|
283573
284228
|
const { model, setThinking, setIsExecuting, isExecuting } = useAgent();
|
|
283574
284229
|
const { stack, externalDialogOpen } = useDialog();
|
|
283575
|
-
const [session, setSession] =
|
|
283576
|
-
const [error40, setError] =
|
|
283577
|
-
const [phase, setPhase] =
|
|
283578
|
-
const [abortController, setAbortController] =
|
|
283579
|
-
const [panelMessages, setPanelMessages] =
|
|
283580
|
-
const panelTextRef =
|
|
283581
|
-
const panelSourceRef =
|
|
283582
|
-
const [pentestAgents, setPentestAgents] =
|
|
283583
|
-
const pentestTextRefs =
|
|
283584
|
-
const [assets, setAssets] =
|
|
283585
|
-
const [viewMode, setViewMode] =
|
|
283586
|
-
const [selectedAgentId, setSelectedAgentId] =
|
|
283587
|
-
const [focusedIndex, setFocusedIndex] =
|
|
283588
|
-
const [showOrchestratorPanel, setShowOrchestratorPanel] =
|
|
283589
|
-
const [startTime, setStartTime] =
|
|
283590
|
-
const pentestAgentList =
|
|
283591
|
-
const selectedAgent =
|
|
284230
|
+
const [session, setSession] = import_react74.useState(null);
|
|
284231
|
+
const [error40, setError] = import_react74.useState(null);
|
|
284232
|
+
const [phase, setPhase] = import_react74.useState("loading");
|
|
284233
|
+
const [abortController, setAbortController] = import_react74.useState(null);
|
|
284234
|
+
const [panelMessages, setPanelMessages] = import_react74.useState([]);
|
|
284235
|
+
const panelTextRef = import_react74.useRef("");
|
|
284236
|
+
const panelSourceRef = import_react74.useRef(null);
|
|
284237
|
+
const [pentestAgents, setPentestAgents] = import_react74.useState({});
|
|
284238
|
+
const pentestTextRefs = import_react74.useRef({});
|
|
284239
|
+
const [assets, setAssets] = import_react74.useState([]);
|
|
284240
|
+
const [viewMode, setViewMode] = import_react74.useState("overview");
|
|
284241
|
+
const [selectedAgentId, setSelectedAgentId] = import_react74.useState(null);
|
|
284242
|
+
const [focusedIndex, setFocusedIndex] = import_react74.useState(0);
|
|
284243
|
+
const [showOrchestratorPanel, setShowOrchestratorPanel] = import_react74.useState(false);
|
|
284244
|
+
const [startTime, setStartTime] = import_react74.useState(null);
|
|
284245
|
+
const pentestAgentList = import_react74.useMemo(() => Object.values(pentestAgents).sort((a, b3) => a.createdAt.getTime() - b3.createdAt.getTime()), [pentestAgents]);
|
|
284246
|
+
const selectedAgent = import_react74.useMemo(() => selectedAgentId ? pentestAgents[selectedAgentId] ?? null : null, [pentestAgents, selectedAgentId]);
|
|
283592
284247
|
const { width: termWidth } = useDimensions();
|
|
283593
284248
|
const gridAvailableWidth = showOrchestratorPanel ? Math.floor((termWidth - 4) / 2) - 2 : termWidth - ORCHESTRATOR_PANEL_WIDTH - GRID_OUTER_PADDING;
|
|
283594
284249
|
const gridColumns = Math.max(1, Math.floor((gridAvailableWidth + GRID_GAP) / (CARD_MIN_WIDTH + GRID_GAP)));
|
|
283595
|
-
|
|
284250
|
+
import_react74.useEffect(() => {
|
|
283596
284251
|
async function load2() {
|
|
283597
284252
|
try {
|
|
283598
284253
|
let s2;
|
|
@@ -283653,7 +284308,7 @@ function Pentest({
|
|
|
283653
284308
|
}
|
|
283654
284309
|
load2();
|
|
283655
284310
|
}, [sessionId]);
|
|
283656
|
-
|
|
284311
|
+
import_react74.useEffect(() => {
|
|
283657
284312
|
if (!session)
|
|
283658
284313
|
return;
|
|
283659
284314
|
const assetsPath = join27(session.rootPath, "assets");
|
|
@@ -283665,7 +284320,7 @@ function Pentest({
|
|
|
283665
284320
|
const loaded = [];
|
|
283666
284321
|
for (const file2 of files) {
|
|
283667
284322
|
try {
|
|
283668
|
-
const content =
|
|
284323
|
+
const content = readFileSync13(join27(assetsPath, file2), "utf-8");
|
|
283669
284324
|
loaded.push(JSON.parse(content));
|
|
283670
284325
|
} catch {}
|
|
283671
284326
|
}
|
|
@@ -283676,12 +284331,12 @@ function Pentest({
|
|
|
283676
284331
|
const interval = setInterval(readAssets, 2000);
|
|
283677
284332
|
return () => clearInterval(interval);
|
|
283678
284333
|
}, [session]);
|
|
283679
|
-
|
|
284334
|
+
import_react74.useEffect(() => {
|
|
283680
284335
|
return () => {
|
|
283681
284336
|
abortController?.abort();
|
|
283682
284337
|
};
|
|
283683
284338
|
}, [abortController]);
|
|
283684
|
-
const ensurePentestAgent =
|
|
284339
|
+
const ensurePentestAgent = import_react74.useCallback((subagentId) => {
|
|
283685
284340
|
setPentestAgents((prev) => {
|
|
283686
284341
|
if (prev[subagentId])
|
|
283687
284342
|
return prev;
|
|
@@ -283698,7 +284353,7 @@ function Pentest({
|
|
|
283698
284353
|
};
|
|
283699
284354
|
});
|
|
283700
284355
|
}, []);
|
|
283701
|
-
const handleSubagentSpawn =
|
|
284356
|
+
const handleSubagentSpawn = import_react74.useCallback(({
|
|
283702
284357
|
subagentId,
|
|
283703
284358
|
input
|
|
283704
284359
|
}) => {
|
|
@@ -283718,7 +284373,7 @@ function Pentest({
|
|
|
283718
284373
|
}
|
|
283719
284374
|
}));
|
|
283720
284375
|
}, []);
|
|
283721
|
-
const handleSubagentComplete =
|
|
284376
|
+
const handleSubagentComplete = import_react74.useCallback(({ subagentId, status }) => {
|
|
283722
284377
|
if (!subagentId.startsWith("pentest-agent-"))
|
|
283723
284378
|
return;
|
|
283724
284379
|
setPentestAgents((prev) => {
|
|
@@ -283731,7 +284386,7 @@ function Pentest({
|
|
|
283731
284386
|
};
|
|
283732
284387
|
});
|
|
283733
284388
|
}, []);
|
|
283734
|
-
const appendPanelText =
|
|
284389
|
+
const appendPanelText = import_react74.useCallback((source, text2) => {
|
|
283735
284390
|
if (panelSourceRef.current !== source) {
|
|
283736
284391
|
panelTextRef.current = "";
|
|
283737
284392
|
panelSourceRef.current = source;
|
|
@@ -283756,7 +284411,7 @@ function Pentest({
|
|
|
283756
284411
|
];
|
|
283757
284412
|
});
|
|
283758
284413
|
}, []);
|
|
283759
|
-
const appendPentestText =
|
|
284414
|
+
const appendPentestText = import_react74.useCallback((subagentId, text2) => {
|
|
283760
284415
|
ensurePentestAgent(subagentId);
|
|
283761
284416
|
if (!pentestTextRefs.current[subagentId]) {
|
|
283762
284417
|
pentestTextRefs.current[subagentId] = "";
|
|
@@ -283789,8 +284444,8 @@ function Pentest({
|
|
|
283789
284444
|
};
|
|
283790
284445
|
});
|
|
283791
284446
|
}, [ensurePentestAgent]);
|
|
283792
|
-
const toolArgsDeltaRef =
|
|
283793
|
-
const addPanelStreamingToolCall =
|
|
284447
|
+
const toolArgsDeltaRef = import_react74.useRef(new Map);
|
|
284448
|
+
const addPanelStreamingToolCall = import_react74.useCallback((toolCallId, toolName) => {
|
|
283794
284449
|
panelTextRef.current = "";
|
|
283795
284450
|
panelSourceRef.current = null;
|
|
283796
284451
|
toolArgsDeltaRef.current.set(toolCallId, "");
|
|
@@ -283809,7 +284464,7 @@ function Pentest({
|
|
|
283809
284464
|
return [...prev, msg];
|
|
283810
284465
|
});
|
|
283811
284466
|
}, []);
|
|
283812
|
-
const appendPanelToolCallDelta =
|
|
284467
|
+
const appendPanelToolCallDelta = import_react74.useCallback((toolCallId, argsTextDelta) => {
|
|
283813
284468
|
const prev = toolArgsDeltaRef.current.get(toolCallId) ?? "";
|
|
283814
284469
|
const accumulated = prev + argsTextDelta;
|
|
283815
284470
|
toolArgsDeltaRef.current.set(toolCallId, accumulated);
|
|
@@ -283832,7 +284487,7 @@ function Pentest({
|
|
|
283832
284487
|
return updated;
|
|
283833
284488
|
});
|
|
283834
284489
|
}, []);
|
|
283835
|
-
const addPanelToolCall =
|
|
284490
|
+
const addPanelToolCall = import_react74.useCallback((toolCallId, toolName, args) => {
|
|
283836
284491
|
panelTextRef.current = "";
|
|
283837
284492
|
panelSourceRef.current = null;
|
|
283838
284493
|
toolArgsDeltaRef.current.delete(toolCallId);
|
|
@@ -283864,7 +284519,7 @@ function Pentest({
|
|
|
283864
284519
|
];
|
|
283865
284520
|
});
|
|
283866
284521
|
}, []);
|
|
283867
|
-
const addPentestStreamingToolCall =
|
|
284522
|
+
const addPentestStreamingToolCall = import_react74.useCallback((subagentId, toolCallId, toolName) => {
|
|
283868
284523
|
pentestTextRefs.current[subagentId] = "";
|
|
283869
284524
|
ensurePentestAgent(subagentId);
|
|
283870
284525
|
toolArgsDeltaRef.current.set(toolCallId, "");
|
|
@@ -283889,7 +284544,7 @@ function Pentest({
|
|
|
283889
284544
|
};
|
|
283890
284545
|
});
|
|
283891
284546
|
}, [ensurePentestAgent]);
|
|
283892
|
-
const appendPentestToolCallDelta =
|
|
284547
|
+
const appendPentestToolCallDelta = import_react74.useCallback((subagentId, toolCallId, argsTextDelta) => {
|
|
283893
284548
|
const prev = toolArgsDeltaRef.current.get(toolCallId) ?? "";
|
|
283894
284549
|
const accumulated = prev + argsTextDelta;
|
|
283895
284550
|
toolArgsDeltaRef.current.set(toolCallId, accumulated);
|
|
@@ -283915,7 +284570,7 @@ function Pentest({
|
|
|
283915
284570
|
return { ...agents, [subagentId]: { ...agent, messages: updatedMsgs } };
|
|
283916
284571
|
});
|
|
283917
284572
|
}, []);
|
|
283918
|
-
const addPentestToolCall =
|
|
284573
|
+
const addPentestToolCall = import_react74.useCallback((subagentId, toolCallId, toolName, args) => {
|
|
283919
284574
|
pentestTextRefs.current[subagentId] = "";
|
|
283920
284575
|
ensurePentestAgent(subagentId);
|
|
283921
284576
|
toolArgsDeltaRef.current.delete(toolCallId);
|
|
@@ -283976,12 +284631,12 @@ function Pentest({
|
|
|
283976
284631
|
}
|
|
283977
284632
|
];
|
|
283978
284633
|
};
|
|
283979
|
-
const updatePanelToolResult =
|
|
284634
|
+
const updatePanelToolResult = import_react74.useCallback((toolCallId, toolName, result) => {
|
|
283980
284635
|
panelTextRef.current = "";
|
|
283981
284636
|
panelSourceRef.current = null;
|
|
283982
284637
|
setPanelMessages((prev) => toolResultUpdater(prev, toolCallId, toolName, result));
|
|
283983
284638
|
}, []);
|
|
283984
|
-
const updatePentestToolResult =
|
|
284639
|
+
const updatePentestToolResult = import_react74.useCallback((subagentId, toolCallId, toolName, result) => {
|
|
283985
284640
|
pentestTextRefs.current[subagentId] = "";
|
|
283986
284641
|
setPentestAgents((prev) => {
|
|
283987
284642
|
const agent = prev[subagentId];
|
|
@@ -283996,7 +284651,7 @@ function Pentest({
|
|
|
283996
284651
|
};
|
|
283997
284652
|
});
|
|
283998
284653
|
}, []);
|
|
283999
|
-
const startPentest =
|
|
284654
|
+
const startPentest = import_react74.useCallback(async (s2) => {
|
|
284000
284655
|
setPhase((prev) => prev === "pentesting" || prev === "reporting" ? prev : "discovery");
|
|
284001
284656
|
setStartTime(new Date);
|
|
284002
284657
|
setIsExecuting(true);
|
|
@@ -284124,7 +284779,7 @@ function Pentest({
|
|
|
284124
284779
|
handleSubagentSpawn,
|
|
284125
284780
|
handleSubagentComplete
|
|
284126
284781
|
]);
|
|
284127
|
-
|
|
284782
|
+
import_react74.useEffect(() => {
|
|
284128
284783
|
if (phase === "completed") {
|
|
284129
284784
|
setFocusedIndex(pentestAgentList.length);
|
|
284130
284785
|
}
|
|
@@ -284187,7 +284842,7 @@ function Pentest({
|
|
|
284187
284842
|
}
|
|
284188
284843
|
}
|
|
284189
284844
|
});
|
|
284190
|
-
const openReport =
|
|
284845
|
+
const openReport = import_react74.useCallback(() => {
|
|
284191
284846
|
if (!session)
|
|
284192
284847
|
return;
|
|
284193
284848
|
const err = openSessionReport(session.rootPath);
|
|
@@ -284372,7 +285027,7 @@ function OrchestratorPanel({
|
|
|
284372
285027
|
}) {
|
|
284373
285028
|
const { colors: colors2 } = useTheme();
|
|
284374
285029
|
const isRunning = phase !== "loading" && phase !== "completed" && phase !== "error";
|
|
284375
|
-
const assetSummary =
|
|
285030
|
+
const assetSummary = import_react74.useMemo(() => {
|
|
284376
285031
|
const byType = {};
|
|
284377
285032
|
for (const a of assets) {
|
|
284378
285033
|
const key = a.assetType;
|
|
@@ -284615,13 +285270,13 @@ function AgentCardGrid({
|
|
|
284615
285270
|
onSelectAgent
|
|
284616
285271
|
}) {
|
|
284617
285272
|
const { colors: colors2 } = useTheme();
|
|
284618
|
-
const scrollRef =
|
|
284619
|
-
|
|
285273
|
+
const scrollRef = import_react74.useRef(null);
|
|
285274
|
+
import_react74.useEffect(() => {
|
|
284620
285275
|
const agent = agents[focusedIndex];
|
|
284621
285276
|
if (agent)
|
|
284622
285277
|
scrollToChild(scrollRef.current, agent.id);
|
|
284623
285278
|
}, [focusedIndex, agents]);
|
|
284624
|
-
const rows =
|
|
285279
|
+
const rows = import_react74.useMemo(() => {
|
|
284625
285280
|
const result = [];
|
|
284626
285281
|
for (let i2 = 0;i2 < agents.length; i2 += gridColumns) {
|
|
284627
285282
|
result.push(agents.slice(i2, i2 + gridColumns));
|
|
@@ -284678,14 +285333,14 @@ function AgentCard({
|
|
|
284678
285333
|
completed: colors2.primary,
|
|
284679
285334
|
failed: colors2.error
|
|
284680
285335
|
}[agent.status];
|
|
284681
|
-
const lastActivity =
|
|
285336
|
+
const lastActivity = import_react74.useMemo(() => {
|
|
284682
285337
|
const last = agent.messages[agent.messages.length - 1];
|
|
284683
285338
|
if (!last)
|
|
284684
285339
|
return "Starting...";
|
|
284685
285340
|
const text2 = typeof last.content === "string" ? last.content.replace(/\n/g, " ").trim() : "Working...";
|
|
284686
285341
|
return text2.length > 50 ? text2.substring(0, 47) + "..." : text2;
|
|
284687
285342
|
}, [agent.messages]);
|
|
284688
|
-
const toolCalls =
|
|
285343
|
+
const toolCalls = import_react74.useMemo(() => agent.messages.filter((m4) => m4.role === "tool").length, [agent.messages]);
|
|
284689
285344
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
284690
285345
|
id: agent.id,
|
|
284691
285346
|
flexGrow: 1,
|
|
@@ -284873,8 +285528,8 @@ function MetricsBar({
|
|
|
284873
285528
|
isExecuting
|
|
284874
285529
|
}) {
|
|
284875
285530
|
const { colors: colors2 } = useTheme();
|
|
284876
|
-
const [now2, setNow] =
|
|
284877
|
-
|
|
285531
|
+
const [now2, setNow] = import_react74.useState(Date.now());
|
|
285532
|
+
import_react74.useEffect(() => {
|
|
284878
285533
|
if (!isExecuting)
|
|
284879
285534
|
return;
|
|
284880
285535
|
const interval = setInterval(() => setNow(Date.now()), 1000);
|
|
@@ -285017,7 +285672,7 @@ function MetricsBar({
|
|
|
285017
285672
|
}
|
|
285018
285673
|
|
|
285019
285674
|
// src/tui/components/operator-dashboard/index.tsx
|
|
285020
|
-
var
|
|
285675
|
+
var import_react79 = __toESM(require_react(), 1);
|
|
285021
285676
|
init_session();
|
|
285022
285677
|
|
|
285023
285678
|
// src/core/api/offesecAgent.ts
|
|
@@ -285120,7 +285775,7 @@ function InlineApprovalPrompt2({ approval }) {
|
|
|
285120
285775
|
}
|
|
285121
285776
|
|
|
285122
285777
|
// src/tui/components/chat/loading-indicator.tsx
|
|
285123
|
-
var
|
|
285778
|
+
var import_react76 = __toESM(require_react(), 1);
|
|
285124
285779
|
var SPINNER_FRAMES2 = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
285125
285780
|
var SPINNER_INTERVAL2 = 80;
|
|
285126
285781
|
var DOTS_FRAMES = ["", ".", "..", "..."];
|
|
@@ -285131,15 +285786,15 @@ function LoadingIndicator({
|
|
|
285131
285786
|
toolName
|
|
285132
285787
|
}) {
|
|
285133
285788
|
const { colors: colors2 } = useTheme();
|
|
285134
|
-
const [spinnerFrame, setSpinnerFrame] =
|
|
285135
|
-
const [dotsFrame, setDotsFrame] =
|
|
285136
|
-
|
|
285789
|
+
const [spinnerFrame, setSpinnerFrame] = import_react76.useState(0);
|
|
285790
|
+
const [dotsFrame, setDotsFrame] = import_react76.useState(0);
|
|
285791
|
+
import_react76.useEffect(() => {
|
|
285137
285792
|
const interval = setInterval(() => {
|
|
285138
285793
|
setSpinnerFrame((f3) => (f3 + 1) % SPINNER_FRAMES2.length);
|
|
285139
285794
|
}, SPINNER_INTERVAL2);
|
|
285140
285795
|
return () => clearInterval(interval);
|
|
285141
285796
|
}, []);
|
|
285142
|
-
|
|
285797
|
+
import_react76.useEffect(() => {
|
|
285143
285798
|
const interval = setInterval(() => {
|
|
285144
285799
|
setDotsFrame((f3) => (f3 + 1) % DOTS_FRAMES.length);
|
|
285145
285800
|
}, DOTS_INTERVAL);
|
|
@@ -285393,7 +286048,7 @@ function MessageList({
|
|
|
285393
286048
|
}
|
|
285394
286049
|
|
|
285395
286050
|
// src/tui/components/chat/input-area.tsx
|
|
285396
|
-
var
|
|
286051
|
+
var import_react77 = __toESM(require_react(), 1);
|
|
285397
286052
|
function NormalInputAreaInner({
|
|
285398
286053
|
value,
|
|
285399
286054
|
onChange,
|
|
@@ -285415,10 +286070,10 @@ function NormalInputAreaInner({
|
|
|
285415
286070
|
}) {
|
|
285416
286071
|
const { colors: colors2, theme, mode: colorMode } = useTheme();
|
|
285417
286072
|
const { inputValue, setInputValue } = useInput();
|
|
285418
|
-
const promptRef =
|
|
285419
|
-
const isExternalUpdate =
|
|
285420
|
-
const prevValueRef =
|
|
285421
|
-
|
|
286073
|
+
const promptRef = import_react77.useRef(null);
|
|
286074
|
+
const isExternalUpdate = import_react77.useRef(false);
|
|
286075
|
+
const prevValueRef = import_react77.useRef(value);
|
|
286076
|
+
import_react77.useEffect(() => {
|
|
285422
286077
|
const prevValue = prevValueRef.current;
|
|
285423
286078
|
prevValueRef.current = value;
|
|
285424
286079
|
if (value !== prevValue && value !== inputValue) {
|
|
@@ -285427,7 +286082,7 @@ function NormalInputAreaInner({
|
|
|
285427
286082
|
promptRef.current?.setValue(value);
|
|
285428
286083
|
}
|
|
285429
286084
|
}, [value, inputValue, setInputValue]);
|
|
285430
|
-
|
|
286085
|
+
import_react77.useEffect(() => {
|
|
285431
286086
|
if (isExternalUpdate.current) {
|
|
285432
286087
|
isExternalUpdate.current = false;
|
|
285433
286088
|
return;
|
|
@@ -285602,7 +286257,7 @@ function ApprovalInputArea2({
|
|
|
285602
286257
|
lastDeclineNote
|
|
285603
286258
|
}) {
|
|
285604
286259
|
const { colors: colors2 } = useTheme();
|
|
285605
|
-
const [focusedElement, setFocusedElement] =
|
|
286260
|
+
const [focusedElement, setFocusedElement] = import_react77.useState(0);
|
|
285606
286261
|
useKeyboard((key) => {
|
|
285607
286262
|
if (key.name === "up") {
|
|
285608
286263
|
setFocusedElement((prev) => Math.max(0, prev - 1));
|
|
@@ -285895,7 +286550,7 @@ function navigateDown(selectedIndex, queueLength) {
|
|
|
285895
286550
|
}
|
|
285896
286551
|
|
|
285897
286552
|
// src/tui/components/operator-dashboard/index.tsx
|
|
285898
|
-
import { existsSync as existsSync27, readFileSync as
|
|
286553
|
+
import { existsSync as existsSync27, readFileSync as readFileSync14 } from "fs";
|
|
285899
286554
|
import { join as join28 } from "path";
|
|
285900
286555
|
function OperatorDashboard({
|
|
285901
286556
|
sessionId,
|
|
@@ -285929,29 +286584,29 @@ function OperatorDashboard({
|
|
|
285929
286584
|
clear: clearDialog,
|
|
285930
286585
|
setSize: setDialogSize
|
|
285931
286586
|
} = useDialog();
|
|
285932
|
-
const autocompleteOptions =
|
|
286587
|
+
const autocompleteOptions = import_react79.useMemo(() => {
|
|
285933
286588
|
const skillSlugs = new Set(skills.map((s2) => `/${slugify(s2.name)}`));
|
|
285934
286589
|
return filterOperatorAutocomplete(allAutocompleteOptions, skillSlugs);
|
|
285935
286590
|
}, [allAutocompleteOptions, skills]);
|
|
285936
|
-
const [session, setSession] =
|
|
285937
|
-
const [loading, setLoading] =
|
|
285938
|
-
const [error40, setError] =
|
|
285939
|
-
const pendingNameRef =
|
|
285940
|
-
const [status, setStatus] =
|
|
285941
|
-
const abortControllerRef =
|
|
285942
|
-
const generationRef =
|
|
285943
|
-
const cancelHandleRef =
|
|
286591
|
+
const [session, setSession] = import_react79.useState(null);
|
|
286592
|
+
const [loading, setLoading] = import_react79.useState(true);
|
|
286593
|
+
const [error40, setError] = import_react79.useState(null);
|
|
286594
|
+
const pendingNameRef = import_react79.useRef(null);
|
|
286595
|
+
const [status, setStatus] = import_react79.useState("idle");
|
|
286596
|
+
const abortControllerRef = import_react79.useRef(null);
|
|
286597
|
+
const generationRef = import_react79.useRef(0);
|
|
286598
|
+
const cancelHandleRef = import_react79.useRef({
|
|
285944
286599
|
cancel: () => false
|
|
285945
286600
|
});
|
|
285946
|
-
const commandCancelledRef =
|
|
285947
|
-
const [messages, setMessages] =
|
|
285948
|
-
const textRef =
|
|
285949
|
-
const conversationRef =
|
|
285950
|
-
const [inputValue, setInputValue] =
|
|
285951
|
-
const [queuedMessages, setQueuedMessages] =
|
|
285952
|
-
const [selectedQueueIndex, setSelectedQueueIndex] =
|
|
285953
|
-
const queuedMessagesRef =
|
|
285954
|
-
|
|
286601
|
+
const commandCancelledRef = import_react79.useRef(false);
|
|
286602
|
+
const [messages, setMessages] = import_react79.useState([]);
|
|
286603
|
+
const textRef = import_react79.useRef("");
|
|
286604
|
+
const conversationRef = import_react79.useRef([]);
|
|
286605
|
+
const [inputValue, setInputValue] = import_react79.useState("");
|
|
286606
|
+
const [queuedMessages, setQueuedMessages] = import_react79.useState([]);
|
|
286607
|
+
const [selectedQueueIndex, setSelectedQueueIndex] = import_react79.useState(-1);
|
|
286608
|
+
const queuedMessagesRef = import_react79.useRef([]);
|
|
286609
|
+
import_react79.useEffect(() => {
|
|
285955
286610
|
queuedMessagesRef.current = queuedMessages;
|
|
285956
286611
|
if (queuedMessages.length === 0) {
|
|
285957
286612
|
setSelectedQueueIndex(-1);
|
|
@@ -285959,17 +286614,17 @@ function OperatorDashboard({
|
|
|
285959
286614
|
setSelectedQueueIndex(queuedMessages.length - 1);
|
|
285960
286615
|
}
|
|
285961
286616
|
}, [queuedMessages, selectedQueueIndex]);
|
|
285962
|
-
const [operatorState, setOperatorState] =
|
|
285963
|
-
const approvalGateRef =
|
|
285964
|
-
const [pendingApprovals, setPendingApprovals] =
|
|
285965
|
-
const [lastApprovedAction, setLastApprovedAction] =
|
|
285966
|
-
const [verboseMode, setVerboseMode] =
|
|
285967
|
-
const [expandedLogs, setExpandedLogs] =
|
|
285968
|
-
const tokenUsageRef =
|
|
285969
|
-
|
|
286617
|
+
const [operatorState, setOperatorState] = import_react79.useState(() => createInitialOperatorState("manual", true));
|
|
286618
|
+
const approvalGateRef = import_react79.useRef(new ApprovalGate({ requireApproval: true }));
|
|
286619
|
+
const [pendingApprovals, setPendingApprovals] = import_react79.useState([]);
|
|
286620
|
+
const [lastApprovedAction, setLastApprovedAction] = import_react79.useState(null);
|
|
286621
|
+
const [verboseMode, setVerboseMode] = import_react79.useState(false);
|
|
286622
|
+
const [expandedLogs, setExpandedLogs] = import_react79.useState(false);
|
|
286623
|
+
const tokenUsageRef = import_react79.useRef(tokenUsage);
|
|
286624
|
+
import_react79.useEffect(() => {
|
|
285970
286625
|
tokenUsageRef.current = tokenUsage;
|
|
285971
286626
|
}, [tokenUsage]);
|
|
285972
|
-
|
|
286627
|
+
import_react79.useEffect(() => {
|
|
285973
286628
|
const gate = approvalGateRef.current;
|
|
285974
286629
|
const onApprovalNeeded = () => {
|
|
285975
286630
|
setPendingApprovals(gate.getPendingApprovals());
|
|
@@ -285991,7 +286646,7 @@ function OperatorDashboard({
|
|
|
285991
286646
|
gate.off("approval-resolved", onApprovalResolved);
|
|
285992
286647
|
};
|
|
285993
286648
|
}, []);
|
|
285994
|
-
|
|
286649
|
+
import_react79.useEffect(() => {
|
|
285995
286650
|
async function loadSession() {
|
|
285996
286651
|
try {
|
|
285997
286652
|
if (sessionId) {
|
|
@@ -286048,10 +286703,10 @@ function OperatorDashboard({
|
|
|
286048
286703
|
}
|
|
286049
286704
|
loadSession();
|
|
286050
286705
|
}, [sessionId]);
|
|
286051
|
-
|
|
286706
|
+
import_react79.useEffect(() => {
|
|
286052
286707
|
return () => setSessionCwd(null);
|
|
286053
286708
|
}, [setSessionCwd]);
|
|
286054
|
-
|
|
286709
|
+
import_react79.useEffect(() => {
|
|
286055
286710
|
if (!session)
|
|
286056
286711
|
return;
|
|
286057
286712
|
resetTokenUsage();
|
|
@@ -286069,7 +286724,7 @@ function OperatorDashboard({
|
|
|
286069
286724
|
});
|
|
286070
286725
|
} catch {}
|
|
286071
286726
|
}, [session, addTokenUsage, resetTokenUsage]);
|
|
286072
|
-
const appendText =
|
|
286727
|
+
const appendText = import_react79.useCallback((text2) => {
|
|
286073
286728
|
textRef.current += text2;
|
|
286074
286729
|
const accumulated = textRef.current;
|
|
286075
286730
|
setMessages((prev) => {
|
|
@@ -286085,8 +286740,8 @@ function OperatorDashboard({
|
|
|
286085
286740
|
];
|
|
286086
286741
|
});
|
|
286087
286742
|
}, []);
|
|
286088
|
-
const toolArgsDeltaRef =
|
|
286089
|
-
const addStreamingToolCall =
|
|
286743
|
+
const toolArgsDeltaRef = import_react79.useRef(new Map);
|
|
286744
|
+
const addStreamingToolCall = import_react79.useCallback((toolCallId, toolName) => {
|
|
286090
286745
|
textRef.current = "";
|
|
286091
286746
|
toolArgsDeltaRef.current.set(toolCallId, {
|
|
286092
286747
|
toolName,
|
|
@@ -286105,7 +286760,7 @@ function OperatorDashboard({
|
|
|
286105
286760
|
}
|
|
286106
286761
|
]);
|
|
286107
286762
|
}, []);
|
|
286108
|
-
const appendToolCallDelta =
|
|
286763
|
+
const appendToolCallDelta = import_react79.useCallback((toolCallId, argsTextDelta) => {
|
|
286109
286764
|
const entry = toolArgsDeltaRef.current.get(toolCallId);
|
|
286110
286765
|
const accumulated = (entry?.accumulated ?? "") + argsTextDelta;
|
|
286111
286766
|
toolArgsDeltaRef.current.set(toolCallId, {
|
|
@@ -286127,7 +286782,7 @@ function OperatorDashboard({
|
|
|
286127
286782
|
return updated;
|
|
286128
286783
|
});
|
|
286129
286784
|
}, []);
|
|
286130
|
-
const addToolCall =
|
|
286785
|
+
const addToolCall = import_react79.useCallback((toolCallId, toolName, args) => {
|
|
286131
286786
|
textRef.current = "";
|
|
286132
286787
|
toolArgsDeltaRef.current.delete(toolCallId);
|
|
286133
286788
|
setMessages((prev) => {
|
|
@@ -286156,7 +286811,7 @@ function OperatorDashboard({
|
|
|
286156
286811
|
];
|
|
286157
286812
|
});
|
|
286158
286813
|
}, []);
|
|
286159
|
-
const updateToolResult =
|
|
286814
|
+
const updateToolResult = import_react79.useCallback((toolCallId, _toolName, result) => {
|
|
286160
286815
|
textRef.current = "";
|
|
286161
286816
|
setMessages((prev) => {
|
|
286162
286817
|
const idx = prev.findIndex((m4) => isToolMessage(m4) && m4.toolCallId === toolCallId);
|
|
@@ -286167,10 +286822,10 @@ function OperatorDashboard({
|
|
|
286167
286822
|
return updated;
|
|
286168
286823
|
});
|
|
286169
286824
|
}, []);
|
|
286170
|
-
const cmdOutputBufRef =
|
|
286171
|
-
const cmdFlushTimerRef =
|
|
286825
|
+
const cmdOutputBufRef = import_react79.useRef("");
|
|
286826
|
+
const cmdFlushTimerRef = import_react79.useRef(null);
|
|
286172
286827
|
const MAX_LOG_LINES = 200;
|
|
286173
|
-
const flushCommandOutput =
|
|
286828
|
+
const flushCommandOutput = import_react79.useCallback(() => {
|
|
286174
286829
|
const buf = cmdOutputBufRef.current;
|
|
286175
286830
|
if (!buf)
|
|
286176
286831
|
return;
|
|
@@ -286200,7 +286855,7 @@ function OperatorDashboard({
|
|
|
286200
286855
|
return updated;
|
|
286201
286856
|
});
|
|
286202
286857
|
}, []);
|
|
286203
|
-
const onCommandOutput =
|
|
286858
|
+
const onCommandOutput = import_react79.useCallback((data) => {
|
|
286204
286859
|
cmdOutputBufRef.current += data;
|
|
286205
286860
|
if (!cmdFlushTimerRef.current) {
|
|
286206
286861
|
cmdFlushTimerRef.current = setInterval(() => {
|
|
@@ -286208,7 +286863,7 @@ function OperatorDashboard({
|
|
|
286208
286863
|
}, 150);
|
|
286209
286864
|
}
|
|
286210
286865
|
}, [flushCommandOutput]);
|
|
286211
|
-
|
|
286866
|
+
import_react79.useEffect(() => {
|
|
286212
286867
|
return () => {
|
|
286213
286868
|
if (cmdFlushTimerRef.current) {
|
|
286214
286869
|
clearInterval(cmdFlushTimerRef.current);
|
|
@@ -286216,7 +286871,7 @@ function OperatorDashboard({
|
|
|
286216
286871
|
}
|
|
286217
286872
|
};
|
|
286218
286873
|
}, []);
|
|
286219
|
-
const appendLogToActiveTool =
|
|
286874
|
+
const appendLogToActiveTool = import_react79.useCallback((line) => {
|
|
286220
286875
|
setMessages((prev) => {
|
|
286221
286876
|
const idx = prev.findLastIndex((m4) => isToolMessage(m4) && (m4.status === "pending" || m4.status === "streaming"));
|
|
286222
286877
|
if (idx === -1)
|
|
@@ -286231,7 +286886,7 @@ function OperatorDashboard({
|
|
|
286231
286886
|
return updated;
|
|
286232
286887
|
});
|
|
286233
286888
|
}, []);
|
|
286234
|
-
const initSubagent =
|
|
286889
|
+
const initSubagent = import_react79.useCallback((subagentId, name26) => {
|
|
286235
286890
|
setMessages((prev) => {
|
|
286236
286891
|
const idx = prev.findLastIndex((m4) => isToolMessage(m4) && (m4.status === "pending" || m4.status === "streaming"));
|
|
286237
286892
|
if (idx === -1)
|
|
@@ -286246,7 +286901,7 @@ function OperatorDashboard({
|
|
|
286246
286901
|
return updated;
|
|
286247
286902
|
});
|
|
286248
286903
|
}, []);
|
|
286249
|
-
const completeSubagent =
|
|
286904
|
+
const completeSubagent = import_react79.useCallback((subagentId, status2) => {
|
|
286250
286905
|
setMessages((prev) => {
|
|
286251
286906
|
const idx = prev.findLastIndex((m4) => isToolMessage(m4) && (m4.status === "pending" || m4.status === "streaming"));
|
|
286252
286907
|
if (idx === -1)
|
|
@@ -286264,7 +286919,7 @@ function OperatorDashboard({
|
|
|
286264
286919
|
return updated;
|
|
286265
286920
|
});
|
|
286266
286921
|
}, []);
|
|
286267
|
-
const appendLogToSubagent =
|
|
286922
|
+
const appendLogToSubagent = import_react79.useCallback((subagentId, line) => {
|
|
286268
286923
|
setMessages((prev) => {
|
|
286269
286924
|
const idx = prev.findLastIndex((m4) => isToolMessage(m4) && (m4.status === "pending" || m4.status === "streaming"));
|
|
286270
286925
|
if (idx === -1)
|
|
@@ -286286,13 +286941,13 @@ function OperatorDashboard({
|
|
|
286286
286941
|
return updated;
|
|
286287
286942
|
});
|
|
286288
286943
|
}, []);
|
|
286289
|
-
const handleApprove =
|
|
286944
|
+
const handleApprove = import_react79.useCallback(() => {
|
|
286290
286945
|
const pending = approvalGateRef.current.getPendingApprovals();
|
|
286291
286946
|
if (pending.length > 0) {
|
|
286292
286947
|
approvalGateRef.current.approve(pending[0].id);
|
|
286293
286948
|
}
|
|
286294
286949
|
}, []);
|
|
286295
|
-
const handleAutoApprove =
|
|
286950
|
+
const handleAutoApprove = import_react79.useCallback(() => {
|
|
286296
286951
|
approvalGateRef.current.updateConfig({ requireApproval: false });
|
|
286297
286952
|
setOperatorState((prev) => ({ ...prev, requireApproval: false }));
|
|
286298
286953
|
const pending = approvalGateRef.current.getPendingApprovals();
|
|
@@ -286300,7 +286955,7 @@ function OperatorDashboard({
|
|
|
286300
286955
|
approvalGateRef.current.approve(p.id);
|
|
286301
286956
|
}
|
|
286302
286957
|
}, []);
|
|
286303
|
-
const runAgent =
|
|
286958
|
+
const runAgent = import_react79.useCallback(async (prompt) => {
|
|
286304
286959
|
if (abortControllerRef.current) {
|
|
286305
286960
|
abortControllerRef.current.abort();
|
|
286306
286961
|
abortControllerRef.current = null;
|
|
@@ -286454,7 +287109,7 @@ function OperatorDashboard({
|
|
|
286454
287109
|
const rootPath = agentResult.session.rootPath;
|
|
286455
287110
|
const mp = join28(rootPath, "messages.json");
|
|
286456
287111
|
if (existsSync27(mp)) {
|
|
286457
|
-
const raw = JSON.parse(
|
|
287112
|
+
const raw = JSON.parse(readFileSync14(mp, "utf-8"));
|
|
286458
287113
|
if (Array.isArray(raw) && raw.length > 0) {
|
|
286459
287114
|
conversationRef.current = sessions.getResumeMessages(raw);
|
|
286460
287115
|
}
|
|
@@ -286514,7 +287169,7 @@ function OperatorDashboard({
|
|
|
286514
287169
|
setThinking,
|
|
286515
287170
|
setIsExecuting
|
|
286516
287171
|
]);
|
|
286517
|
-
const handleSubmit =
|
|
287172
|
+
const handleSubmit = import_react79.useCallback((value) => {
|
|
286518
287173
|
const pending = approvalGateRef.current.getPendingApprovals();
|
|
286519
287174
|
const result = resolveSubmit(value, status, pending.length > 0);
|
|
286520
287175
|
if (result.denyPending) {
|
|
@@ -286532,16 +287187,16 @@ function OperatorDashboard({
|
|
|
286532
287187
|
setInputValue("");
|
|
286533
287188
|
runAgent(result.prompt);
|
|
286534
287189
|
}, [status, runAgent]);
|
|
286535
|
-
const initialMessageSentRef =
|
|
286536
|
-
const runAgentRef =
|
|
287190
|
+
const initialMessageSentRef = import_react79.useRef(false);
|
|
287191
|
+
const runAgentRef = import_react79.useRef(runAgent);
|
|
286537
287192
|
runAgentRef.current = runAgent;
|
|
286538
|
-
|
|
287193
|
+
import_react79.useEffect(() => {
|
|
286539
287194
|
if (!loading && initialMessage && !initialMessageSentRef.current) {
|
|
286540
287195
|
initialMessageSentRef.current = true;
|
|
286541
287196
|
runAgentRef.current(initialMessage);
|
|
286542
287197
|
}
|
|
286543
287198
|
}, [loading, initialMessage]);
|
|
286544
|
-
|
|
287199
|
+
import_react79.useEffect(() => {
|
|
286545
287200
|
if (status !== "idle")
|
|
286546
287201
|
return;
|
|
286547
287202
|
const queue = queuedMessagesRef.current;
|
|
@@ -286552,7 +287207,7 @@ function OperatorDashboard({
|
|
|
286552
287207
|
setSelectedQueueIndex(-1);
|
|
286553
287208
|
runAgentRef.current(next);
|
|
286554
287209
|
}, [status]);
|
|
286555
|
-
const showModelPicker =
|
|
287210
|
+
const showModelPicker = import_react79.useCallback(() => {
|
|
286556
287211
|
setDialogSize("large");
|
|
286557
287212
|
showDialog(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
286558
287213
|
flexDirection: "column",
|
|
@@ -286614,7 +287269,7 @@ function OperatorDashboard({
|
|
|
286614
287269
|
clearDialog,
|
|
286615
287270
|
setDialogSize
|
|
286616
287271
|
]);
|
|
286617
|
-
const handleCommandExecute =
|
|
287272
|
+
const handleCommandExecute = import_react79.useCallback(async (command) => {
|
|
286618
287273
|
const action = routeCommand(command, resolveSkillContent);
|
|
286619
287274
|
switch (action.type) {
|
|
286620
287275
|
case "show-models":
|
|
@@ -286632,7 +287287,7 @@ function OperatorDashboard({
|
|
|
286632
287287
|
return;
|
|
286633
287288
|
}
|
|
286634
287289
|
}, [resolveSkillContent, handleSubmit, executeCommand2, showModelPicker]);
|
|
286635
|
-
const handleAbort =
|
|
287290
|
+
const handleAbort = import_react79.useCallback(() => {
|
|
286636
287291
|
if (!abortControllerRef.current)
|
|
286637
287292
|
return;
|
|
286638
287293
|
const action = resolveAbortAction(commandCancelledRef.current, () => cancelHandleRef.current.cancel());
|
|
@@ -286663,7 +287318,7 @@ function OperatorDashboard({
|
|
|
286663
287318
|
try {
|
|
286664
287319
|
const messagesPath = join28(session.rootPath, "messages.json");
|
|
286665
287320
|
if (existsSync27(messagesPath)) {
|
|
286666
|
-
const raw = JSON.parse(
|
|
287321
|
+
const raw = JSON.parse(readFileSync14(messagesPath, "utf-8"));
|
|
286667
287322
|
if (Array.isArray(raw) && raw.length > 0) {
|
|
286668
287323
|
conversationRef.current = sessions.getResumeMessages(raw);
|
|
286669
287324
|
}
|
|
@@ -286682,7 +287337,7 @@ function OperatorDashboard({
|
|
|
286682
287337
|
];
|
|
286683
287338
|
});
|
|
286684
287339
|
}, [session, setThinking, setIsExecuting]);
|
|
286685
|
-
const toggleApproval =
|
|
287340
|
+
const toggleApproval = import_react79.useCallback(() => {
|
|
286686
287341
|
setOperatorState((prev) => {
|
|
286687
287342
|
const newVal = !prev.requireApproval;
|
|
286688
287343
|
approvalGateRef.current.updateConfig({ requireApproval: newVal });
|
|
@@ -286916,7 +287571,7 @@ function OperatorDashboard({
|
|
|
286916
287571
|
}
|
|
286917
287572
|
|
|
286918
287573
|
// src/tui/components/commands/theme-picker.tsx
|
|
286919
|
-
var
|
|
287574
|
+
var import_react81 = __toESM(require_react(), 1);
|
|
286920
287575
|
init_config2();
|
|
286921
287576
|
function ThemePicker({ onClose }) {
|
|
286922
287577
|
const dimensions = useDimensions();
|
|
@@ -286929,15 +287584,15 @@ function ThemePicker({ onClose }) {
|
|
|
286929
287584
|
toggleMode,
|
|
286930
287585
|
setMode
|
|
286931
287586
|
} = useTheme();
|
|
286932
|
-
const [selectedIndex, setSelectedIndex] =
|
|
286933
|
-
const originalThemeRef =
|
|
286934
|
-
const originalModeRef =
|
|
286935
|
-
const handleClose =
|
|
287587
|
+
const [selectedIndex, setSelectedIndex] = import_react81.useState(() => Math.max(0, availableThemes.indexOf(theme.name)));
|
|
287588
|
+
const originalThemeRef = import_react81.useRef(theme.name);
|
|
287589
|
+
const originalModeRef = import_react81.useRef(mode);
|
|
287590
|
+
const handleClose = import_react81.useCallback(() => {
|
|
286936
287591
|
setTheme(originalThemeRef.current);
|
|
286937
287592
|
setMode(originalModeRef.current);
|
|
286938
287593
|
onClose();
|
|
286939
287594
|
}, [setTheme, setMode, onClose]);
|
|
286940
|
-
const handleConfirm =
|
|
287595
|
+
const handleConfirm = import_react81.useCallback(async () => {
|
|
286941
287596
|
const currentThemeName = availableThemes[selectedIndex];
|
|
286942
287597
|
if (currentThemeName) {
|
|
286943
287598
|
await config2.update({ theme: currentThemeName });
|
|
@@ -287066,16 +287721,16 @@ function ThemePicker({ onClose }) {
|
|
|
287066
287721
|
}
|
|
287067
287722
|
|
|
287068
287723
|
// src/tui/components/commands/create-skill-wizard.tsx
|
|
287069
|
-
var
|
|
287724
|
+
var import_react83 = __toESM(require_react(), 1);
|
|
287070
287725
|
function CreateSkillWizard() {
|
|
287071
287726
|
const { colors: colors2 } = useTheme();
|
|
287072
287727
|
const route = useRoute();
|
|
287073
|
-
const [step, setStep] =
|
|
287074
|
-
const [name26, setName] =
|
|
287075
|
-
const [description, setDescription] =
|
|
287076
|
-
const [content, setContent] =
|
|
287077
|
-
const [error40, setError] =
|
|
287078
|
-
const [confirmFocused, setConfirmFocused] =
|
|
287728
|
+
const [step, setStep] = import_react83.useState("name");
|
|
287729
|
+
const [name26, setName] = import_react83.useState("");
|
|
287730
|
+
const [description, setDescription] = import_react83.useState("");
|
|
287731
|
+
const [content, setContent] = import_react83.useState("");
|
|
287732
|
+
const [error40, setError] = import_react83.useState(null);
|
|
287733
|
+
const [confirmFocused, setConfirmFocused] = import_react83.useState(0);
|
|
287079
287734
|
const slug = slugify(name26);
|
|
287080
287735
|
async function handleSave() {
|
|
287081
287736
|
if (!name26.trim() || !content.trim())
|
|
@@ -289951,7 +290606,7 @@ async function detectTerminalMode(timeoutMs = 1000) {
|
|
|
289951
290606
|
}
|
|
289952
290607
|
|
|
289953
290608
|
// src/tui/console-theme.ts
|
|
289954
|
-
var
|
|
290609
|
+
var import_react85 = __toESM(require_react(), 1);
|
|
289955
290610
|
var withAlpha = (rgba, a) => RGBA.fromValues(rgba.r, rgba.g, rgba.b, a);
|
|
289956
290611
|
var overlayThemeRef = {
|
|
289957
290612
|
current: null
|
|
@@ -289974,7 +290629,7 @@ function buildConsoleOptions(themeColors) {
|
|
|
289974
290629
|
function ConsoleThemeSync() {
|
|
289975
290630
|
const { colors: colors2 } = useTheme();
|
|
289976
290631
|
const renderer = useRenderer();
|
|
289977
|
-
|
|
290632
|
+
import_react85.useEffect(() => {
|
|
289978
290633
|
overlayThemeRef.current = colors2;
|
|
289979
290634
|
const c = renderer.console;
|
|
289980
290635
|
c.backgroundColor = withAlpha(colors2.backgroundPanel, 0.85);
|
|
@@ -290062,17 +290717,17 @@ function setupAutoCopy(renderer, copyToClipboard) {
|
|
|
290062
290717
|
|
|
290063
290718
|
// src/tui/index.tsx
|
|
290064
290719
|
function App({ appConfig }) {
|
|
290065
|
-
const [focusIndex, setFocusIndex] =
|
|
290066
|
-
const [cwd, setCwd] =
|
|
290067
|
-
const [ctrlCPressTime, setCtrlCPressTime] =
|
|
290068
|
-
const [showExitWarning, setShowExitWarning] =
|
|
290069
|
-
const [inputKey, setInputKey] =
|
|
290070
|
-
const [showSessionsDialog, setShowSessionsDialog] =
|
|
290071
|
-
const [showShortcutsDialog, setShowShortcutsDialog] =
|
|
290072
|
-
const [showThemeDialog, setShowThemeDialog] =
|
|
290073
|
-
const [showAuthDialog, setShowAuthDialog] =
|
|
290074
|
-
const [showPentestDialog, setShowPentestDialog] =
|
|
290075
|
-
const [pendingPentestFlags, setPendingPentestFlags] =
|
|
290720
|
+
const [focusIndex, setFocusIndex] = import_react88.useState(0);
|
|
290721
|
+
const [cwd, setCwd] = import_react88.useState(process.cwd());
|
|
290722
|
+
const [ctrlCPressTime, setCtrlCPressTime] = import_react88.useState(null);
|
|
290723
|
+
const [showExitWarning, setShowExitWarning] = import_react88.useState(false);
|
|
290724
|
+
const [inputKey, setInputKey] = import_react88.useState(0);
|
|
290725
|
+
const [showSessionsDialog, setShowSessionsDialog] = import_react88.useState(false);
|
|
290726
|
+
const [showShortcutsDialog, setShowShortcutsDialog] = import_react88.useState(false);
|
|
290727
|
+
const [showThemeDialog, setShowThemeDialog] = import_react88.useState(false);
|
|
290728
|
+
const [showAuthDialog, setShowAuthDialog] = import_react88.useState(false);
|
|
290729
|
+
const [showPentestDialog, setShowPentestDialog] = import_react88.useState(false);
|
|
290730
|
+
const [pendingPentestFlags, setPendingPentestFlags] = import_react88.useState(undefined);
|
|
290076
290731
|
const navigableItems = ["command-input"];
|
|
290077
290732
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ConfigProvider, {
|
|
290078
290733
|
config: appConfig,
|
|
@@ -290159,14 +290814,14 @@ function AppContent({
|
|
|
290159
290814
|
const { toast } = useToast();
|
|
290160
290815
|
const { refocusPrompt } = useFocus();
|
|
290161
290816
|
const { setExternalDialogOpen } = useDialog();
|
|
290162
|
-
|
|
290817
|
+
import_react88.useEffect(() => {
|
|
290163
290818
|
checkForUpdate().then(({ updateAvailable, currentVersion, latestVersion }) => {
|
|
290164
290819
|
if (!updateAvailable)
|
|
290165
290820
|
return;
|
|
290166
290821
|
toast(`Update available: v${currentVersion} → v${latestVersion}. Run: pensar upgrade`, "warn", 8000);
|
|
290167
290822
|
});
|
|
290168
290823
|
}, []);
|
|
290169
|
-
|
|
290824
|
+
import_react88.useEffect(() => {
|
|
290170
290825
|
if (route.data.type !== "base")
|
|
290171
290826
|
return;
|
|
290172
290827
|
if (!config3.data.responsibleUseAccepted && route.data.path !== "disclosure") {
|
|
@@ -290175,12 +290830,12 @@ function AppContent({
|
|
|
290175
290830
|
route.navigate({ type: "base", path: "providers" });
|
|
290176
290831
|
}
|
|
290177
290832
|
}, [config3.data.responsibleUseAccepted, route.data]);
|
|
290178
|
-
|
|
290833
|
+
import_react88.useEffect(() => {
|
|
290179
290834
|
if (showThemeDialog || showAuthDialog || showPentestDialog) {
|
|
290180
290835
|
setExternalDialogOpen(true);
|
|
290181
290836
|
}
|
|
290182
290837
|
}, [showThemeDialog, showAuthDialog, showPentestDialog]);
|
|
290183
|
-
|
|
290838
|
+
import_react88.useEffect(() => {
|
|
290184
290839
|
if (showExitWarning) {
|
|
290185
290840
|
const timer = setTimeout(() => {
|
|
290186
290841
|
setShowExitWarning(false);
|
|
@@ -290300,7 +290955,7 @@ function CommandDisplay({
|
|
|
290300
290955
|
await config3.update({ responsibleUseAccepted: true });
|
|
290301
290956
|
route.navigate({
|
|
290302
290957
|
type: "base",
|
|
290303
|
-
path: "
|
|
290958
|
+
path: "providers"
|
|
290304
290959
|
});
|
|
290305
290960
|
};
|
|
290306
290961
|
if (route.data.type === "base") {
|