@pensar/apex 0.0.77 → 0.0.78-canary.27f4f443
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.js +2802 -370
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -31716,6 +31716,55 @@ var init_openrouter = __esm(() => {
|
|
|
31716
31716
|
];
|
|
31717
31717
|
});
|
|
31718
31718
|
|
|
31719
|
+
// src/core/ai/models/pensar.ts
|
|
31720
|
+
var PENSAR_MODELS;
|
|
31721
|
+
var init_pensar = __esm(() => {
|
|
31722
|
+
PENSAR_MODELS = [
|
|
31723
|
+
{
|
|
31724
|
+
id: "pensar:anthropic.claude-sonnet-4-5-20250929-v1:0",
|
|
31725
|
+
name: "Claude Sonnet 4.5 (Pensar)",
|
|
31726
|
+
provider: "pensar",
|
|
31727
|
+
contextLength: 200000
|
|
31728
|
+
},
|
|
31729
|
+
{
|
|
31730
|
+
id: "pensar:anthropic.claude-opus-4-1-20250805-v1:0",
|
|
31731
|
+
name: "Claude Opus 4.1 (Pensar)",
|
|
31732
|
+
provider: "pensar",
|
|
31733
|
+
contextLength: 200000
|
|
31734
|
+
},
|
|
31735
|
+
{
|
|
31736
|
+
id: "pensar:anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
31737
|
+
name: "Claude Haiku 4.5 (Pensar)",
|
|
31738
|
+
provider: "pensar",
|
|
31739
|
+
contextLength: 200000
|
|
31740
|
+
},
|
|
31741
|
+
{
|
|
31742
|
+
id: "pensar:anthropic.claude-sonnet-4-20250514-v1:0",
|
|
31743
|
+
name: "Claude Sonnet 4 (Pensar)",
|
|
31744
|
+
provider: "pensar",
|
|
31745
|
+
contextLength: 200000
|
|
31746
|
+
},
|
|
31747
|
+
{
|
|
31748
|
+
id: "pensar:anthropic.claude-opus-4-20250514-v1:0",
|
|
31749
|
+
name: "Claude Opus 4 (Pensar)",
|
|
31750
|
+
provider: "pensar",
|
|
31751
|
+
contextLength: 200000
|
|
31752
|
+
},
|
|
31753
|
+
{
|
|
31754
|
+
id: "pensar:anthropic.claude-3-7-sonnet-20250219-v1:0",
|
|
31755
|
+
name: "Claude 3.7 Sonnet (Pensar)",
|
|
31756
|
+
provider: "pensar",
|
|
31757
|
+
contextLength: 200000
|
|
31758
|
+
},
|
|
31759
|
+
{
|
|
31760
|
+
id: "pensar:anthropic.claude-3-5-haiku-20241022-v1:0",
|
|
31761
|
+
name: "Claude 3.5 Haiku (Pensar)",
|
|
31762
|
+
provider: "pensar",
|
|
31763
|
+
contextLength: 200000
|
|
31764
|
+
}
|
|
31765
|
+
];
|
|
31766
|
+
});
|
|
31767
|
+
|
|
31719
31768
|
// src/core/ai/models/index.ts
|
|
31720
31769
|
function getModelInfo(model) {
|
|
31721
31770
|
return AVAILABLE_MODELS.find((m2) => m2.id === model) ?? {
|
|
@@ -31730,14 +31779,231 @@ var init_models = __esm(() => {
|
|
|
31730
31779
|
init_openai();
|
|
31731
31780
|
init_bedrock();
|
|
31732
31781
|
init_openrouter();
|
|
31782
|
+
init_pensar();
|
|
31733
31783
|
AVAILABLE_MODELS = [
|
|
31734
31784
|
...ANTHROPIC_MODELS,
|
|
31735
31785
|
...OPENAI_MODELS,
|
|
31736
31786
|
...BEDROCK_MODELS,
|
|
31737
|
-
...OPENROUTER_MODELS
|
|
31787
|
+
...OPENROUTER_MODELS,
|
|
31788
|
+
...PENSAR_MODELS
|
|
31738
31789
|
];
|
|
31739
31790
|
});
|
|
31740
31791
|
|
|
31792
|
+
// package.json
|
|
31793
|
+
var package_default2;
|
|
31794
|
+
var init_package = __esm(() => {
|
|
31795
|
+
package_default2 = {
|
|
31796
|
+
name: "@pensar/apex",
|
|
31797
|
+
version: "0.0.78-canary.27f4f443",
|
|
31798
|
+
description: "AI-powered penetration testing CLI tool with terminal UI",
|
|
31799
|
+
module: "src/tui/index.tsx",
|
|
31800
|
+
main: "build/index.js",
|
|
31801
|
+
type: "module",
|
|
31802
|
+
repository: {
|
|
31803
|
+
type: "git",
|
|
31804
|
+
url: "https://github.com/pensarai/apex.git"
|
|
31805
|
+
},
|
|
31806
|
+
bin: {
|
|
31807
|
+
pensar: "./bin/pensar.js"
|
|
31808
|
+
},
|
|
31809
|
+
files: [
|
|
31810
|
+
"build",
|
|
31811
|
+
"bin",
|
|
31812
|
+
"src/core/installation",
|
|
31813
|
+
"pensar.svg",
|
|
31814
|
+
"LICENSE"
|
|
31815
|
+
],
|
|
31816
|
+
scripts: {
|
|
31817
|
+
build: "bun build src/tui/index.tsx --outdir build --target node --format esm --external sharp",
|
|
31818
|
+
"generate:ascii": "bun run scripts/generate-ascii-art.ts",
|
|
31819
|
+
"generate:models": "bun run scripts/generate-models.ts",
|
|
31820
|
+
"build:binary": "bun run generate:ascii && bun build src/cli.ts --compile --outfile pensar",
|
|
31821
|
+
"build:binary:macos-arm64": "bun build src/cli.ts --compile --target=bun-darwin-arm64 --outfile dist/pensar-darwin-arm64",
|
|
31822
|
+
"build:binary:macos-x64": "bun build src/cli.ts --compile --target=bun-darwin-x64 --outfile dist/pensar-darwin-x64",
|
|
31823
|
+
"build:binary:linux-x64": "bun build src/cli.ts --compile --target=bun-linux-x64 --outfile dist/pensar-linux-x64",
|
|
31824
|
+
"build:binary:linux-arm64": "bun build src/cli.ts --compile --target=bun-linux-arm64 --outfile dist/pensar-linux-arm64",
|
|
31825
|
+
"build:binaries": "bun run generate:ascii && mkdir -p dist && bun run build:binary:macos-arm64 && bun run build:binary:macos-x64 && bun run build:binary:linux-x64 && bun run build:binary:linux-arm64",
|
|
31826
|
+
dev: "bun run scripts/watch.ts",
|
|
31827
|
+
"dev:debug": "SHOW_CONSOLE=true bun run scripts/watch.ts",
|
|
31828
|
+
start: "bun run src/tui/index.tsx",
|
|
31829
|
+
pensar: "node bin/pensar.js",
|
|
31830
|
+
tsc: "tsc --noEmit",
|
|
31831
|
+
"daytona-benchmark": "bun run scripts/daytona-benchmark.ts",
|
|
31832
|
+
"local-benchmark": "bun run scripts/local-benchmark.ts",
|
|
31833
|
+
test: "vitest run",
|
|
31834
|
+
"test:watch": "vitest",
|
|
31835
|
+
lint: "eslint src/",
|
|
31836
|
+
format: "prettier --write .",
|
|
31837
|
+
"format:check": "prettier --check .",
|
|
31838
|
+
prepublishOnly: "npm run build"
|
|
31839
|
+
},
|
|
31840
|
+
keywords: [
|
|
31841
|
+
"penetration-testing",
|
|
31842
|
+
"security",
|
|
31843
|
+
"pentesting",
|
|
31844
|
+
"ai",
|
|
31845
|
+
"cli",
|
|
31846
|
+
"terminal",
|
|
31847
|
+
"tui"
|
|
31848
|
+
],
|
|
31849
|
+
author: "Pensar",
|
|
31850
|
+
license: "MIT",
|
|
31851
|
+
engines: {
|
|
31852
|
+
node: ">=18.0.0",
|
|
31853
|
+
bun: ">=1.0.0"
|
|
31854
|
+
},
|
|
31855
|
+
devDependencies: {
|
|
31856
|
+
"@eslint/js": "^10.0.1",
|
|
31857
|
+
"@playwright/mcp": "^0.0.54",
|
|
31858
|
+
"@types/bun": "^1.3.0",
|
|
31859
|
+
"@types/mailparser": "^3.4.6",
|
|
31860
|
+
"@types/react": "^19.2.6",
|
|
31861
|
+
"@typescript-eslint/eslint-plugin": "^8.55.0",
|
|
31862
|
+
"@typescript-eslint/parser": "^8.55.0",
|
|
31863
|
+
dotenv: "^17.2.3",
|
|
31864
|
+
eslint: "^10.0.0",
|
|
31865
|
+
"eslint-config-prettier": "^10.1.8",
|
|
31866
|
+
"eslint-plugin-unused-imports": "^4.4.1",
|
|
31867
|
+
prettier: "^3.8.1",
|
|
31868
|
+
"typescript-eslint": "^8.55.0",
|
|
31869
|
+
vitest: "^2.1.8"
|
|
31870
|
+
},
|
|
31871
|
+
peerDependencies: {
|
|
31872
|
+
typescript: "^5.9.3"
|
|
31873
|
+
},
|
|
31874
|
+
dependencies: {
|
|
31875
|
+
"@ai-sdk/amazon-bedrock": "^4.0.69",
|
|
31876
|
+
"@ai-sdk/anthropic": "^3.0.50",
|
|
31877
|
+
"@ai-sdk/openai": "^3.0.37",
|
|
31878
|
+
"@daytonaio/sdk": "^0.112.1",
|
|
31879
|
+
"@googleapis/gmail": "^16.1.1",
|
|
31880
|
+
"@microsoft/microsoft-graph-client": "^3.0.7",
|
|
31881
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
31882
|
+
"@openrouter/ai-sdk-provider": "^2.2.3",
|
|
31883
|
+
"@opentui/core": "^0.1.80",
|
|
31884
|
+
"@opentui/react": "^0.1.80",
|
|
31885
|
+
ai: "^6.0.105",
|
|
31886
|
+
glob: "^13.0.0",
|
|
31887
|
+
"google-auth-library": "^10.6.1",
|
|
31888
|
+
ignore: "^7.0.5",
|
|
31889
|
+
imapflow: "^1.2.10",
|
|
31890
|
+
mailparser: "^3.9.3",
|
|
31891
|
+
marked: "^16.4.0",
|
|
31892
|
+
nanoid: "^5.1.6",
|
|
31893
|
+
"p-limit": "^7.2.0",
|
|
31894
|
+
react: "^19.2.0",
|
|
31895
|
+
sharp: "^0.34.4",
|
|
31896
|
+
yaml: "^2.8.2",
|
|
31897
|
+
zod: "^3.25.76"
|
|
31898
|
+
},
|
|
31899
|
+
packageManager: "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
31900
|
+
};
|
|
31901
|
+
});
|
|
31902
|
+
|
|
31903
|
+
// src/core/installation/index.ts
|
|
31904
|
+
function getCurrentVersion() {
|
|
31905
|
+
return package_default2.version;
|
|
31906
|
+
}
|
|
31907
|
+
function isNewerVersion(current, latest) {
|
|
31908
|
+
const parse2 = (v2) => v2.split(".").map((n) => parseInt(n, 10) || 0);
|
|
31909
|
+
const c = parse2(current);
|
|
31910
|
+
const l = parse2(latest);
|
|
31911
|
+
for (let i = 0;i < Math.max(c.length, l.length); i++) {
|
|
31912
|
+
const cv = c[i] ?? 0;
|
|
31913
|
+
const lv = l[i] ?? 0;
|
|
31914
|
+
if (lv > cv)
|
|
31915
|
+
return true;
|
|
31916
|
+
if (lv < cv)
|
|
31917
|
+
return false;
|
|
31918
|
+
}
|
|
31919
|
+
return false;
|
|
31920
|
+
}
|
|
31921
|
+
async function getLatestVersion() {
|
|
31922
|
+
const res = await fetch("https://registry.npmjs.org/@pensar/apex/latest");
|
|
31923
|
+
if (!res.ok)
|
|
31924
|
+
throw new Error(`Failed to fetch latest version: ${res.statusText}`);
|
|
31925
|
+
const data = await res.json();
|
|
31926
|
+
return String(data.version);
|
|
31927
|
+
}
|
|
31928
|
+
async function checkForUpdate() {
|
|
31929
|
+
const currentVersion = getCurrentVersion();
|
|
31930
|
+
let latestVersion;
|
|
31931
|
+
try {
|
|
31932
|
+
latestVersion = await getLatestVersion();
|
|
31933
|
+
} catch {
|
|
31934
|
+
return {
|
|
31935
|
+
updateAvailable: false,
|
|
31936
|
+
currentVersion,
|
|
31937
|
+
latestVersion: currentVersion
|
|
31938
|
+
};
|
|
31939
|
+
}
|
|
31940
|
+
return {
|
|
31941
|
+
updateAvailable: isNewerVersion(currentVersion, latestVersion),
|
|
31942
|
+
currentVersion,
|
|
31943
|
+
latestVersion
|
|
31944
|
+
};
|
|
31945
|
+
}
|
|
31946
|
+
var init_installation = __esm(() => {
|
|
31947
|
+
init_package();
|
|
31948
|
+
});
|
|
31949
|
+
|
|
31950
|
+
// src/core/config/config.ts
|
|
31951
|
+
import os2 from "os";
|
|
31952
|
+
import path2 from "path";
|
|
31953
|
+
import fs2 from "fs/promises";
|
|
31954
|
+
async function init() {
|
|
31955
|
+
const folder = path2.join(os2.homedir(), ".pensar");
|
|
31956
|
+
const file = path2.join(folder, "config.json");
|
|
31957
|
+
const dirExists = await fs2.access(folder).then(() => true).catch(() => false);
|
|
31958
|
+
if (!dirExists) {
|
|
31959
|
+
await fs2.mkdir(folder, { recursive: true });
|
|
31960
|
+
}
|
|
31961
|
+
const fileExists = await fs2.access(file).then(() => true).catch(() => false);
|
|
31962
|
+
if (!fileExists) {
|
|
31963
|
+
await fs2.writeFile(file, JSON.stringify(DEFAULT_CONFIG));
|
|
31964
|
+
}
|
|
31965
|
+
const version = getCurrentVersion();
|
|
31966
|
+
return { ...DEFAULT_CONFIG, version };
|
|
31967
|
+
}
|
|
31968
|
+
async function get() {
|
|
31969
|
+
const folder = path2.join(os2.homedir(), ".pensar");
|
|
31970
|
+
const file = path2.join(folder, "config.json");
|
|
31971
|
+
const exists = await fs2.access(file).then(() => true).catch(() => false);
|
|
31972
|
+
if (!exists) {
|
|
31973
|
+
return await init();
|
|
31974
|
+
}
|
|
31975
|
+
const config = await fs2.readFile(file, "utf8");
|
|
31976
|
+
const parsedConfig = JSON.parse(config);
|
|
31977
|
+
const version = getCurrentVersion();
|
|
31978
|
+
return {
|
|
31979
|
+
...parsedConfig,
|
|
31980
|
+
version,
|
|
31981
|
+
openAiAPIKey: process.env.OPENAI_API_KEY ?? parsedConfig.openAiAPIKey,
|
|
31982
|
+
anthropicAPIKey: process.env.ANTHROPIC_API_KEY ?? parsedConfig.anthropicAPIKey,
|
|
31983
|
+
openRouterAPIKey: process.env.OPENROUTER_API_KEY ?? parsedConfig.openRouterAPIKey,
|
|
31984
|
+
bedrockAPIKey: process.env.BEDROCK_API_KEY ?? parsedConfig.bedrockAPIKey,
|
|
31985
|
+
pensarAPIKey: process.env.PENSAR_API_KEY ?? parsedConfig.pensarAPIKey,
|
|
31986
|
+
pensarApiUrl: process.env.PENSAR_API_URL ?? parsedConfig.pensarApiUrl,
|
|
31987
|
+
daytonaAPIKey: process.env.DAYTONA_API_KEY ?? parsedConfig.daytonaAPIKey,
|
|
31988
|
+
daytonaOrgId: process.env.DAYTONA_ORG_ID ?? parsedConfig.daytonaOrgId,
|
|
31989
|
+
runloopAPIKey: process.env.RUNLOOP_API_KEY ?? parsedConfig.runloopAPIKey
|
|
31990
|
+
};
|
|
31991
|
+
}
|
|
31992
|
+
async function update(config) {
|
|
31993
|
+
const currentConfig = await get();
|
|
31994
|
+
const newConfig = { ...currentConfig, ...config };
|
|
31995
|
+
const folder = path2.join(os2.homedir(), ".pensar");
|
|
31996
|
+
const file = path2.join(folder, "config.json");
|
|
31997
|
+
await fs2.writeFile(file, JSON.stringify(newConfig));
|
|
31998
|
+
}
|
|
31999
|
+
var DEFAULT_CONFIG;
|
|
32000
|
+
var init_config = __esm(() => {
|
|
32001
|
+
init_installation();
|
|
32002
|
+
DEFAULT_CONFIG = {
|
|
32003
|
+
responsibleUseAccepted: false
|
|
32004
|
+
};
|
|
32005
|
+
});
|
|
32006
|
+
|
|
31741
32007
|
// node_modules/zod/v3/helpers/util.js
|
|
31742
32008
|
var util3, objectUtil, ZodParsedType, getParsedType = (data) => {
|
|
31743
32009
|
const t2 = typeof data;
|
|
@@ -36239,6 +36505,119 @@ var init_toolset = __esm(() => {
|
|
|
36239
36505
|
});
|
|
36240
36506
|
});
|
|
36241
36507
|
|
|
36508
|
+
// src/core/config/index.ts
|
|
36509
|
+
var config;
|
|
36510
|
+
var init_config2 = __esm(() => {
|
|
36511
|
+
init_config();
|
|
36512
|
+
config = {
|
|
36513
|
+
get,
|
|
36514
|
+
init,
|
|
36515
|
+
update
|
|
36516
|
+
};
|
|
36517
|
+
});
|
|
36518
|
+
|
|
36519
|
+
// src/core/api/constants.ts
|
|
36520
|
+
var exports_constants = {};
|
|
36521
|
+
__export(exports_constants, {
|
|
36522
|
+
getPensarConsoleUrl: () => getPensarConsoleUrl,
|
|
36523
|
+
getPensarApiUrl: () => getPensarApiUrl,
|
|
36524
|
+
PENSAR_CONSOLE_BASE_URL: () => PENSAR_CONSOLE_BASE_URL,
|
|
36525
|
+
PENSAR_API_BASE_URL: () => PENSAR_API_BASE_URL
|
|
36526
|
+
});
|
|
36527
|
+
function getPensarApiUrl(config2) {
|
|
36528
|
+
return config2?.pensarApiUrl || process.env.PENSAR_API_URL || PENSAR_API_BASE_URL;
|
|
36529
|
+
}
|
|
36530
|
+
function getPensarConsoleUrl() {
|
|
36531
|
+
return process.env.PENSAR_CONSOLE_URL || PENSAR_CONSOLE_BASE_URL;
|
|
36532
|
+
}
|
|
36533
|
+
var PENSAR_API_BASE_URL = "https://api.console.pensar.dev", PENSAR_CONSOLE_BASE_URL = "https://console.pensar.dev";
|
|
36534
|
+
|
|
36535
|
+
// src/core/api/tokenRefresh.ts
|
|
36536
|
+
function decodeJwtPayload(token) {
|
|
36537
|
+
try {
|
|
36538
|
+
const parts = token.split(".");
|
|
36539
|
+
if (parts.length !== 3)
|
|
36540
|
+
return null;
|
|
36541
|
+
const payload = Buffer.from(parts[1], "base64url").toString("utf-8");
|
|
36542
|
+
return JSON.parse(payload);
|
|
36543
|
+
} catch {
|
|
36544
|
+
return null;
|
|
36545
|
+
}
|
|
36546
|
+
}
|
|
36547
|
+
function isTokenExpired(token, bufferSeconds = 60) {
|
|
36548
|
+
const payload = decodeJwtPayload(token);
|
|
36549
|
+
if (!payload || typeof payload.exp !== "number")
|
|
36550
|
+
return true;
|
|
36551
|
+
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
36552
|
+
return payload.exp - nowSeconds < bufferSeconds;
|
|
36553
|
+
}
|
|
36554
|
+
async function refreshAccessToken(clientId, refreshToken) {
|
|
36555
|
+
try {
|
|
36556
|
+
const response = await fetch("https://api.workos.com/user_management/authenticate", {
|
|
36557
|
+
method: "POST",
|
|
36558
|
+
headers: { "Content-Type": "application/json" },
|
|
36559
|
+
body: JSON.stringify({
|
|
36560
|
+
client_id: clientId,
|
|
36561
|
+
grant_type: "refresh_token",
|
|
36562
|
+
refresh_token: refreshToken
|
|
36563
|
+
})
|
|
36564
|
+
});
|
|
36565
|
+
if (!response.ok) {
|
|
36566
|
+
console.error(`[pensar] Token refresh failed: ${response.status} ${response.statusText}`);
|
|
36567
|
+
return null;
|
|
36568
|
+
}
|
|
36569
|
+
const data = await response.json();
|
|
36570
|
+
await config.update({
|
|
36571
|
+
accessToken: data.access_token,
|
|
36572
|
+
refreshToken: data.refresh_token
|
|
36573
|
+
});
|
|
36574
|
+
return data.access_token;
|
|
36575
|
+
} catch (err) {
|
|
36576
|
+
console.error("[pensar] Token refresh error:", err);
|
|
36577
|
+
return null;
|
|
36578
|
+
}
|
|
36579
|
+
}
|
|
36580
|
+
async function ensureValidToken(cfg) {
|
|
36581
|
+
if (cfg.accessToken) {
|
|
36582
|
+
if (!isTokenExpired(cfg.accessToken)) {
|
|
36583
|
+
return { token: cfg.accessToken, type: "workos" };
|
|
36584
|
+
}
|
|
36585
|
+
if (cfg.refreshToken) {
|
|
36586
|
+
const clientId = await fetchWorkOSClientId(cfg);
|
|
36587
|
+
if (clientId) {
|
|
36588
|
+
const newToken = await refreshAccessToken(clientId, cfg.refreshToken);
|
|
36589
|
+
if (newToken) {
|
|
36590
|
+
return { token: newToken, type: "workos" };
|
|
36591
|
+
}
|
|
36592
|
+
}
|
|
36593
|
+
}
|
|
36594
|
+
}
|
|
36595
|
+
if (cfg.pensarAPIKey) {
|
|
36596
|
+
return { token: cfg.pensarAPIKey, type: "legacy" };
|
|
36597
|
+
}
|
|
36598
|
+
return null;
|
|
36599
|
+
}
|
|
36600
|
+
async function fetchWorkOSClientId(cfg) {
|
|
36601
|
+
if (cachedClientId)
|
|
36602
|
+
return cachedClientId;
|
|
36603
|
+
try {
|
|
36604
|
+
const { getPensarApiUrl: getPensarApiUrl2 } = await Promise.resolve().then(() => exports_constants);
|
|
36605
|
+
const apiUrl = getPensarApiUrl2(cfg);
|
|
36606
|
+
const response = await fetch(`${apiUrl}/api/cli/config`);
|
|
36607
|
+
if (!response.ok)
|
|
36608
|
+
return null;
|
|
36609
|
+
const data = await response.json();
|
|
36610
|
+
cachedClientId = data.workosClientId;
|
|
36611
|
+
return cachedClientId;
|
|
36612
|
+
} catch {
|
|
36613
|
+
return null;
|
|
36614
|
+
}
|
|
36615
|
+
}
|
|
36616
|
+
var cachedClientId = null;
|
|
36617
|
+
var init_tokenRefresh = __esm(() => {
|
|
36618
|
+
init_config2();
|
|
36619
|
+
});
|
|
36620
|
+
|
|
36242
36621
|
// node_modules/@ai-sdk/provider/dist/index.mjs
|
|
36243
36622
|
function getErrorMessage(error) {
|
|
36244
36623
|
if (error == null) {
|
|
@@ -60666,7 +61045,7 @@ Run shell commands for reconnaissance. Use for: dig, curl, nmap, whois, and all
|
|
|
60666
61045
|
Record a discovered asset to the session's assets directory. Use extensively — every significant discovery should be documented.
|
|
60667
61046
|
|
|
60668
61047
|
## create_attack_surface_report
|
|
60669
|
-
Submit the final structured report. Call this ONCE at the very end with complete results.
|
|
61048
|
+
Submit the final structured report. Call this ONCE at the very end with complete results. This ends the run.
|
|
60670
61049
|
|
|
60671
61050
|
## Browser tools
|
|
60672
61051
|
- \`browser_navigate\` — Load a URL in the browser
|
|
@@ -80023,7 +80402,345 @@ var init_dist9 = __esm(() => {
|
|
|
80023
80402
|
anthropic = createAnthropic();
|
|
80024
80403
|
});
|
|
80025
80404
|
|
|
80405
|
+
// src/core/ai/providers/pensarFormatters.ts
|
|
80406
|
+
function convertToBedrockFormat(modelId, options) {
|
|
80407
|
+
if (modelId.includes("anthropic.claude")) {
|
|
80408
|
+
return convertToAnthropicFormat(options);
|
|
80409
|
+
}
|
|
80410
|
+
return convertToAnthropicFormat(options);
|
|
80411
|
+
}
|
|
80412
|
+
function convertToAnthropicFormat(options) {
|
|
80413
|
+
const messages = [];
|
|
80414
|
+
let systemPrompt;
|
|
80415
|
+
if (options.prompt) {
|
|
80416
|
+
for (const part of options.prompt) {
|
|
80417
|
+
if (part.role === "system") {
|
|
80418
|
+
systemPrompt = part.content;
|
|
80419
|
+
} else if (part.role === "user") {
|
|
80420
|
+
const content = part.content.map((c) => {
|
|
80421
|
+
if (c.type === "text")
|
|
80422
|
+
return c.text;
|
|
80423
|
+
if (c.type === "file")
|
|
80424
|
+
return "[file]";
|
|
80425
|
+
return "";
|
|
80426
|
+
}).join("");
|
|
80427
|
+
messages.push({ role: "user", content });
|
|
80428
|
+
} else if (part.role === "assistant") {
|
|
80429
|
+
const assistantContent = part.content;
|
|
80430
|
+
const hasToolCalls = assistantContent.some((c) => c.type === "tool-call");
|
|
80431
|
+
if (hasToolCalls) {
|
|
80432
|
+
const content = [];
|
|
80433
|
+
for (const c of assistantContent) {
|
|
80434
|
+
if (c.type === "text" && c.text) {
|
|
80435
|
+
content.push({ type: "text", text: c.text });
|
|
80436
|
+
} else if (c.type === "tool-call") {
|
|
80437
|
+
const parsedInput = typeof c.input === "string" ? JSON.parse(c.input) : c.input;
|
|
80438
|
+
content.push({
|
|
80439
|
+
type: "tool_use",
|
|
80440
|
+
id: c.toolCallId,
|
|
80441
|
+
name: c.toolName,
|
|
80442
|
+
input: parsedInput
|
|
80443
|
+
});
|
|
80444
|
+
}
|
|
80445
|
+
}
|
|
80446
|
+
messages.push({ role: "assistant", content });
|
|
80447
|
+
} else {
|
|
80448
|
+
const text2 = assistantContent.map((c) => c.type === "text" ? c.text : "").join("");
|
|
80449
|
+
messages.push({ role: "assistant", content: text2 });
|
|
80450
|
+
}
|
|
80451
|
+
} else if (part.role === "tool") {
|
|
80452
|
+
const toolResults = part.content.map((c) => {
|
|
80453
|
+
let resultContent;
|
|
80454
|
+
if (c.output.type === "text" || c.output.type === "error-text") {
|
|
80455
|
+
resultContent = c.output.value;
|
|
80456
|
+
} else {
|
|
80457
|
+
resultContent = JSON.stringify(c.output.value);
|
|
80458
|
+
}
|
|
80459
|
+
return {
|
|
80460
|
+
type: "tool_result",
|
|
80461
|
+
tool_use_id: c.toolCallId,
|
|
80462
|
+
content: resultContent
|
|
80463
|
+
};
|
|
80464
|
+
});
|
|
80465
|
+
messages.push({ role: "user", content: toolResults });
|
|
80466
|
+
}
|
|
80467
|
+
}
|
|
80468
|
+
}
|
|
80469
|
+
if (options.responseFormat?.type === "json") {
|
|
80470
|
+
const jsonInstruction = options.responseFormat.schema ? `
|
|
80471
|
+
|
|
80472
|
+
You MUST respond with ONLY valid JSON matching this schema (no markdown, no explanation, no code fences):
|
|
80473
|
+
${JSON.stringify(options.responseFormat.schema)}` : `
|
|
80474
|
+
|
|
80475
|
+
You MUST respond with ONLY valid JSON (no markdown, no explanation, no code fences).`;
|
|
80476
|
+
systemPrompt = (systemPrompt || "") + jsonInstruction;
|
|
80477
|
+
}
|
|
80478
|
+
const body = {
|
|
80479
|
+
anthropic_version: "bedrock-2023-05-31",
|
|
80480
|
+
messages,
|
|
80481
|
+
max_tokens: options.maxOutputTokens ?? 4096
|
|
80482
|
+
};
|
|
80483
|
+
if (systemPrompt) {
|
|
80484
|
+
body.system = systemPrompt;
|
|
80485
|
+
}
|
|
80486
|
+
if (options.temperature != null) {
|
|
80487
|
+
body.temperature = options.temperature;
|
|
80488
|
+
}
|
|
80489
|
+
if (options.topP != null) {
|
|
80490
|
+
body.top_p = options.topP;
|
|
80491
|
+
}
|
|
80492
|
+
if (options.stopSequences && options.stopSequences.length > 0) {
|
|
80493
|
+
body.stop_sequences = options.stopSequences;
|
|
80494
|
+
}
|
|
80495
|
+
if (options.tools && options.tools.length > 0) {
|
|
80496
|
+
body.tools = options.tools.filter((tool2) => tool2.type === "function").map((tool2) => ({
|
|
80497
|
+
name: tool2.name,
|
|
80498
|
+
description: tool2.description,
|
|
80499
|
+
input_schema: tool2.inputSchema
|
|
80500
|
+
}));
|
|
80501
|
+
}
|
|
80502
|
+
if (options.toolChoice) {
|
|
80503
|
+
if (options.toolChoice.type === "auto") {
|
|
80504
|
+
body.tool_choice = { type: "auto" };
|
|
80505
|
+
} else if (options.toolChoice.type === "required") {
|
|
80506
|
+
body.tool_choice = { type: "any" };
|
|
80507
|
+
} else if (options.toolChoice.type === "none") {
|
|
80508
|
+
delete body.tools;
|
|
80509
|
+
} else if (options.toolChoice.type === "tool") {
|
|
80510
|
+
body.tool_choice = {
|
|
80511
|
+
type: "tool",
|
|
80512
|
+
name: options.toolChoice.toolName
|
|
80513
|
+
};
|
|
80514
|
+
}
|
|
80515
|
+
}
|
|
80516
|
+
return body;
|
|
80517
|
+
}
|
|
80518
|
+
function parseBedrockResponse(modelId, response, usage) {
|
|
80519
|
+
if (modelId.includes("anthropic.claude")) {
|
|
80520
|
+
return parseAnthropicResponse(response, usage);
|
|
80521
|
+
}
|
|
80522
|
+
return parseAnthropicResponse(response, usage);
|
|
80523
|
+
}
|
|
80524
|
+
function parseAnthropicResponse(response, usage) {
|
|
80525
|
+
const rawContent = response.content;
|
|
80526
|
+
const content = [];
|
|
80527
|
+
if (rawContent) {
|
|
80528
|
+
for (const block of rawContent) {
|
|
80529
|
+
if (block.type === "text") {
|
|
80530
|
+
content.push({
|
|
80531
|
+
type: "text",
|
|
80532
|
+
text: block.text
|
|
80533
|
+
});
|
|
80534
|
+
} else if (block.type === "tool_use") {
|
|
80535
|
+
content.push({
|
|
80536
|
+
type: "tool-call",
|
|
80537
|
+
toolCallId: block.id,
|
|
80538
|
+
toolName: block.name,
|
|
80539
|
+
input: typeof block.input === "string" ? block.input : JSON.stringify(block.input)
|
|
80540
|
+
});
|
|
80541
|
+
}
|
|
80542
|
+
}
|
|
80543
|
+
}
|
|
80544
|
+
const stopReason = response.stop_reason;
|
|
80545
|
+
let finishReason = "unknown";
|
|
80546
|
+
switch (stopReason) {
|
|
80547
|
+
case "end_turn":
|
|
80548
|
+
finishReason = "stop";
|
|
80549
|
+
break;
|
|
80550
|
+
case "tool_use":
|
|
80551
|
+
finishReason = "tool-calls";
|
|
80552
|
+
break;
|
|
80553
|
+
case "max_tokens":
|
|
80554
|
+
finishReason = "length";
|
|
80555
|
+
break;
|
|
80556
|
+
case "stop_sequence":
|
|
80557
|
+
finishReason = "stop";
|
|
80558
|
+
break;
|
|
80559
|
+
}
|
|
80560
|
+
const respUsage = response.usage;
|
|
80561
|
+
const finalUsage = {
|
|
80562
|
+
inputTokens: respUsage?.input_tokens ?? usage.inputTokens,
|
|
80563
|
+
outputTokens: respUsage?.output_tokens ?? usage.outputTokens,
|
|
80564
|
+
totalTokens: (respUsage?.input_tokens ?? usage.inputTokens) + (respUsage?.output_tokens ?? usage.outputTokens)
|
|
80565
|
+
};
|
|
80566
|
+
return { content, finishReason, usage: finalUsage };
|
|
80567
|
+
}
|
|
80568
|
+
|
|
80569
|
+
// src/core/ai/providers/pensar.ts
|
|
80570
|
+
function log(...args) {
|
|
80571
|
+
if (DEBUG)
|
|
80572
|
+
console.log("[pensar]", ...args);
|
|
80573
|
+
}
|
|
80574
|
+
function logError(...args) {
|
|
80575
|
+
console.error("[pensar]", ...args);
|
|
80576
|
+
}
|
|
80577
|
+
function createPensarModel(bedrockModelId, config3) {
|
|
80578
|
+
const modelId = `pensar:${bedrockModelId}`;
|
|
80579
|
+
async function buildHeaders() {
|
|
80580
|
+
const headers = {
|
|
80581
|
+
"Content-Type": "application/json"
|
|
80582
|
+
};
|
|
80583
|
+
if (config3.getToken) {
|
|
80584
|
+
const result = await config3.getToken();
|
|
80585
|
+
if (!result) {
|
|
80586
|
+
throw new Error("Pensar authentication failed. Run /auth to reconnect.");
|
|
80587
|
+
}
|
|
80588
|
+
headers.Authorization = `Bearer ${result.token}`;
|
|
80589
|
+
if (result.type === "workos" && config3.workspaceId) {
|
|
80590
|
+
headers["X-Workspace-Id"] = config3.workspaceId;
|
|
80591
|
+
}
|
|
80592
|
+
} else {
|
|
80593
|
+
headers.Authorization = `Bearer ${config3.apiKey}`;
|
|
80594
|
+
if (config3.workspaceId && !config3.apiKey.startsWith("sk-")) {
|
|
80595
|
+
headers["X-Workspace-Id"] = config3.workspaceId;
|
|
80596
|
+
}
|
|
80597
|
+
}
|
|
80598
|
+
return headers;
|
|
80599
|
+
}
|
|
80600
|
+
const model = {
|
|
80601
|
+
specificationVersion: "v2",
|
|
80602
|
+
provider: "pensar",
|
|
80603
|
+
modelId,
|
|
80604
|
+
supportedUrls: {},
|
|
80605
|
+
async doGenerate(options) {
|
|
80606
|
+
const body = convertToBedrockFormat(bedrockModelId, options);
|
|
80607
|
+
const url2 = `${config3.baseUrl}/bedrock/invoke`;
|
|
80608
|
+
log(`doGenerate → ${bedrockModelId}`);
|
|
80609
|
+
log(` URL: ${url2}`);
|
|
80610
|
+
log(` messages: ${body.messages?.length ?? 0}, tools: ${body.tools?.length ?? 0}`);
|
|
80611
|
+
const startTime = Date.now();
|
|
80612
|
+
const headers = await buildHeaders();
|
|
80613
|
+
const response = await fetch(url2, {
|
|
80614
|
+
method: "POST",
|
|
80615
|
+
headers,
|
|
80616
|
+
signal: options.abortSignal,
|
|
80617
|
+
body: JSON.stringify({
|
|
80618
|
+
modelId: bedrockModelId,
|
|
80619
|
+
body,
|
|
80620
|
+
stream: false
|
|
80621
|
+
})
|
|
80622
|
+
});
|
|
80623
|
+
log(` response: ${response.status} (${Date.now() - startTime}ms)`);
|
|
80624
|
+
if (!response.ok) {
|
|
80625
|
+
const errorBody = await response.text();
|
|
80626
|
+
let errorMessage;
|
|
80627
|
+
try {
|
|
80628
|
+
const parsed2 = JSON.parse(errorBody);
|
|
80629
|
+
errorMessage = parsed2.error || parsed2.message || errorBody;
|
|
80630
|
+
} catch {
|
|
80631
|
+
errorMessage = errorBody;
|
|
80632
|
+
}
|
|
80633
|
+
logError(` FAILED ${response.status}: ${errorMessage}`);
|
|
80634
|
+
if (response.status === 402) {
|
|
80635
|
+
throw new Error(`Insufficient Pensar credits: ${errorMessage}. ` + `Top up at https://console.pensar.dev`);
|
|
80636
|
+
}
|
|
80637
|
+
throw new Error(`Pensar API error (${response.status}): ${errorMessage}`);
|
|
80638
|
+
}
|
|
80639
|
+
const result = await response.json();
|
|
80640
|
+
const usageFromProxy = result.usage ?? {
|
|
80641
|
+
inputTokens: 0,
|
|
80642
|
+
outputTokens: 0
|
|
80643
|
+
};
|
|
80644
|
+
const parsed = parseBedrockResponse(bedrockModelId, result.response, {
|
|
80645
|
+
inputTokens: usageFromProxy.inputTokens,
|
|
80646
|
+
outputTokens: usageFromProxy.outputTokens
|
|
80647
|
+
});
|
|
80648
|
+
log(` finish: ${parsed.finishReason}, content: ${parsed.content.length} parts`);
|
|
80649
|
+
log(` usage: ${parsed.usage.inputTokens}in / ${parsed.usage.outputTokens}out`);
|
|
80650
|
+
if (result.usage?.totalCost != null) {
|
|
80651
|
+
log(` cost: $${result.usage.totalCost.toFixed(6)}`);
|
|
80652
|
+
}
|
|
80653
|
+
return {
|
|
80654
|
+
content: parsed.content,
|
|
80655
|
+
finishReason: parsed.finishReason,
|
|
80656
|
+
usage: parsed.usage,
|
|
80657
|
+
request: {
|
|
80658
|
+
body
|
|
80659
|
+
},
|
|
80660
|
+
response: {
|
|
80661
|
+
body: result
|
|
80662
|
+
},
|
|
80663
|
+
warnings: []
|
|
80664
|
+
};
|
|
80665
|
+
},
|
|
80666
|
+
async doStream(options) {
|
|
80667
|
+
log(`doStream → wrapping doGenerate for ${bedrockModelId}`);
|
|
80668
|
+
const generateResult = await model.doGenerate(options);
|
|
80669
|
+
const parts = [];
|
|
80670
|
+
parts.push({
|
|
80671
|
+
type: "stream-start",
|
|
80672
|
+
warnings: generateResult.warnings
|
|
80673
|
+
});
|
|
80674
|
+
for (const item of generateResult.content) {
|
|
80675
|
+
if (item.type === "text") {
|
|
80676
|
+
const id = `text-${Date.now()}`;
|
|
80677
|
+
parts.push({ type: "text-start", id });
|
|
80678
|
+
parts.push({ type: "text-delta", id, delta: item.text });
|
|
80679
|
+
parts.push({ type: "text-end", id });
|
|
80680
|
+
} else if (item.type === "tool-call") {
|
|
80681
|
+
const id = item.toolCallId;
|
|
80682
|
+
parts.push({
|
|
80683
|
+
type: "tool-input-start",
|
|
80684
|
+
id,
|
|
80685
|
+
toolName: item.toolName
|
|
80686
|
+
});
|
|
80687
|
+
parts.push({
|
|
80688
|
+
type: "tool-input-delta",
|
|
80689
|
+
id,
|
|
80690
|
+
delta: item.input
|
|
80691
|
+
});
|
|
80692
|
+
parts.push({ type: "tool-input-end", id });
|
|
80693
|
+
parts.push({
|
|
80694
|
+
type: "tool-call",
|
|
80695
|
+
toolCallId: id,
|
|
80696
|
+
toolName: item.toolName,
|
|
80697
|
+
input: item.input
|
|
80698
|
+
});
|
|
80699
|
+
}
|
|
80700
|
+
}
|
|
80701
|
+
parts.push({
|
|
80702
|
+
type: "finish",
|
|
80703
|
+
finishReason: generateResult.finishReason,
|
|
80704
|
+
usage: generateResult.usage
|
|
80705
|
+
});
|
|
80706
|
+
const stream2 = new ReadableStream({
|
|
80707
|
+
start(controller) {
|
|
80708
|
+
for (const part of parts) {
|
|
80709
|
+
controller.enqueue(part);
|
|
80710
|
+
}
|
|
80711
|
+
controller.close();
|
|
80712
|
+
}
|
|
80713
|
+
});
|
|
80714
|
+
return {
|
|
80715
|
+
stream: stream2,
|
|
80716
|
+
request: {
|
|
80717
|
+
body: generateResult.request?.body
|
|
80718
|
+
}
|
|
80719
|
+
};
|
|
80720
|
+
}
|
|
80721
|
+
};
|
|
80722
|
+
return model;
|
|
80723
|
+
}
|
|
80724
|
+
var DEBUG;
|
|
80725
|
+
var init_pensar2 = __esm(() => {
|
|
80726
|
+
DEBUG = process.env.PENSAR_DEBUG === "1" || process.env.PENSAR_DEBUG === "true";
|
|
80727
|
+
});
|
|
80728
|
+
|
|
80026
80729
|
// src/core/ai/utils.ts
|
|
80730
|
+
function buildAuthConfig(cfg) {
|
|
80731
|
+
return {
|
|
80732
|
+
anthropicAPIKey: cfg.anthropicAPIKey ?? undefined,
|
|
80733
|
+
openAiAPIKey: cfg.openAiAPIKey ?? undefined,
|
|
80734
|
+
openRouterAPIKey: cfg.openRouterAPIKey ?? undefined,
|
|
80735
|
+
pensarAPIKey: cfg.pensarAPIKey ?? undefined,
|
|
80736
|
+
pensarApiUrl: cfg.pensarApiUrl ?? undefined,
|
|
80737
|
+
accessToken: cfg.accessToken ?? undefined,
|
|
80738
|
+
refreshToken: cfg.refreshToken ?? undefined,
|
|
80739
|
+
workspaceId: cfg.workspaceId ?? undefined,
|
|
80740
|
+
bedrock: cfg.bedrockAPIKey ? { apiKey: cfg.bedrockAPIKey } : undefined,
|
|
80741
|
+
local: cfg.localModelUrl ? { baseURL: cfg.localModelUrl } : undefined
|
|
80742
|
+
};
|
|
80743
|
+
}
|
|
80027
80744
|
function getProviderModel(model, authConfig) {
|
|
80028
80745
|
const { provider } = getModelInfo(model);
|
|
80029
80746
|
const openAiAPIKey = authConfig?.openAiAPIKey || process.env.OPENAI_API_KEY;
|
|
@@ -80068,6 +80785,36 @@ function getProviderModel(model, authConfig) {
|
|
|
80068
80785
|
apiKey: anthropicAPIKey
|
|
80069
80786
|
}).chat(model);
|
|
80070
80787
|
break;
|
|
80788
|
+
case "pensar": {
|
|
80789
|
+
const pensarApiKey = authConfig?.pensarAPIKey || process.env.PENSAR_API_KEY;
|
|
80790
|
+
const hasWorkOSAuth = !!authConfig?.accessToken;
|
|
80791
|
+
if (!pensarApiKey && !hasWorkOSAuth) {
|
|
80792
|
+
throw new Error("Pensar not configured. Run /auth to connect to Pensar Console.");
|
|
80793
|
+
}
|
|
80794
|
+
const pensarApiUrl = authConfig?.pensarApiUrl || getPensarApiUrl();
|
|
80795
|
+
const bedrockModelId = model.startsWith("pensar:") ? model.slice(7) : model;
|
|
80796
|
+
if (process.env.PENSAR_DEBUG === "1" || process.env.PENSAR_DEBUG === "true") {
|
|
80797
|
+
console.log(`[pensar] getProviderModel: ${model} → bedrock:${bedrockModelId} via ${pensarApiUrl}`);
|
|
80798
|
+
}
|
|
80799
|
+
const modelConfig = {
|
|
80800
|
+
apiKey: pensarApiKey || authConfig?.accessToken || "",
|
|
80801
|
+
baseUrl: pensarApiUrl,
|
|
80802
|
+
workspaceId: authConfig?.workspaceId
|
|
80803
|
+
};
|
|
80804
|
+
if (hasWorkOSAuth) {
|
|
80805
|
+
modelConfig.getToken = async () => {
|
|
80806
|
+
const freshConfig = await config.get();
|
|
80807
|
+
return ensureValidToken({
|
|
80808
|
+
accessToken: freshConfig.accessToken,
|
|
80809
|
+
refreshToken: freshConfig.refreshToken,
|
|
80810
|
+
pensarAPIKey: freshConfig.pensarAPIKey,
|
|
80811
|
+
pensarApiUrl: freshConfig.pensarApiUrl
|
|
80812
|
+
});
|
|
80813
|
+
};
|
|
80814
|
+
}
|
|
80815
|
+
providerModel = createPensarModel(bedrockModelId, modelConfig);
|
|
80816
|
+
break;
|
|
80817
|
+
}
|
|
80071
80818
|
case "local":
|
|
80072
80819
|
providerModel = createOpenAI({
|
|
80073
80820
|
baseURL: localBaseURL,
|
|
@@ -80239,6 +80986,9 @@ var init_utils2 = __esm(() => {
|
|
|
80239
80986
|
init_dist8();
|
|
80240
80987
|
init_dist9();
|
|
80241
80988
|
init_models();
|
|
80989
|
+
init_pensar2();
|
|
80990
|
+
init_tokenRefresh();
|
|
80991
|
+
init_config2();
|
|
80242
80992
|
init_dist5();
|
|
80243
80993
|
});
|
|
80244
80994
|
|
|
@@ -86652,11 +87402,11 @@ var require_core = __commonJS((exports) => {
|
|
|
86652
87402
|
Ajv.ValidationError = validation_error_1.default;
|
|
86653
87403
|
Ajv.MissingRefError = ref_error_1.default;
|
|
86654
87404
|
exports.default = Ajv;
|
|
86655
|
-
function checkOptions(checkOpts, options, msg,
|
|
87405
|
+
function checkOptions(checkOpts, options, msg, log2 = "error") {
|
|
86656
87406
|
for (const key in checkOpts) {
|
|
86657
87407
|
const opt = key;
|
|
86658
87408
|
if (opt in options)
|
|
86659
|
-
this.logger[
|
|
87409
|
+
this.logger[log2](`${msg}: option ${key}. ${checkOpts[opt]}`);
|
|
86660
87410
|
}
|
|
86661
87411
|
}
|
|
86662
87412
|
function getSchEnv(keyRef) {
|
|
@@ -92294,11 +93044,11 @@ var require_core3 = __commonJS((exports) => {
|
|
|
92294
93044
|
Ajv.ValidationError = validation_error_1.default;
|
|
92295
93045
|
Ajv.MissingRefError = ref_error_1.default;
|
|
92296
93046
|
exports.default = Ajv;
|
|
92297
|
-
function checkOptions(checkOpts, options, msg,
|
|
93047
|
+
function checkOptions(checkOpts, options, msg, log2 = "error") {
|
|
92298
93048
|
for (const key in checkOpts) {
|
|
92299
93049
|
const opt = key;
|
|
92300
93050
|
if (opt in options)
|
|
92301
|
-
this.logger[
|
|
93051
|
+
this.logger[log2](`${msg}: option ${key}. ${checkOpts[opt]}`);
|
|
92302
93052
|
}
|
|
92303
93053
|
}
|
|
92304
93054
|
function getSchEnv(keyRef) {
|
|
@@ -96795,6 +97545,852 @@ var init_httpRequest = __esm(() => {
|
|
|
96795
97545
|
});
|
|
96796
97546
|
});
|
|
96797
97547
|
|
|
97548
|
+
// src/lib/cvss/types.ts
|
|
97549
|
+
function getSeverityFromScore(score) {
|
|
97550
|
+
if (score === 0)
|
|
97551
|
+
return "NONE";
|
|
97552
|
+
if (score <= 3.9)
|
|
97553
|
+
return "LOW";
|
|
97554
|
+
if (score <= 6.9)
|
|
97555
|
+
return "MEDIUM";
|
|
97556
|
+
if (score <= 8.9)
|
|
97557
|
+
return "HIGH";
|
|
97558
|
+
return "CRITICAL";
|
|
97559
|
+
}
|
|
97560
|
+
var init_types4 = () => {};
|
|
97561
|
+
|
|
97562
|
+
// src/lib/cvss/macrovector-scores.ts
|
|
97563
|
+
var MACROVECTOR_LOOKUP, METRIC_LEVELS, MAX_SEVERITY, STEP = 0.1, EPSILON;
|
|
97564
|
+
var init_macrovector_scores = __esm(() => {
|
|
97565
|
+
MACROVECTOR_LOOKUP = {
|
|
97566
|
+
"000000": 10,
|
|
97567
|
+
"000001": 9.9,
|
|
97568
|
+
"000010": 9.8,
|
|
97569
|
+
"000011": 9.5,
|
|
97570
|
+
"000020": 9.5,
|
|
97571
|
+
"000021": 9.2,
|
|
97572
|
+
"000100": 10,
|
|
97573
|
+
"000101": 9.6,
|
|
97574
|
+
"000110": 9.3,
|
|
97575
|
+
"000111": 8.7,
|
|
97576
|
+
"000120": 9.1,
|
|
97577
|
+
"000121": 8.1,
|
|
97578
|
+
"000200": 9.3,
|
|
97579
|
+
"000201": 9,
|
|
97580
|
+
"000210": 8.9,
|
|
97581
|
+
"000211": 8,
|
|
97582
|
+
"000220": 8.1,
|
|
97583
|
+
"000221": 6.8,
|
|
97584
|
+
"001000": 9.8,
|
|
97585
|
+
"001001": 9.5,
|
|
97586
|
+
"001010": 9.5,
|
|
97587
|
+
"001011": 9.2,
|
|
97588
|
+
"001020": 9,
|
|
97589
|
+
"001021": 8.4,
|
|
97590
|
+
"001100": 9.3,
|
|
97591
|
+
"001101": 9.2,
|
|
97592
|
+
"001110": 8.9,
|
|
97593
|
+
"001111": 8.1,
|
|
97594
|
+
"001120": 8.1,
|
|
97595
|
+
"001121": 6.5,
|
|
97596
|
+
"001200": 8.8,
|
|
97597
|
+
"001201": 8,
|
|
97598
|
+
"001210": 7.8,
|
|
97599
|
+
"001211": 7,
|
|
97600
|
+
"001220": 6.9,
|
|
97601
|
+
"001221": 4.8,
|
|
97602
|
+
"002001": 9.2,
|
|
97603
|
+
"002011": 8.2,
|
|
97604
|
+
"002021": 7.2,
|
|
97605
|
+
"002101": 7.9,
|
|
97606
|
+
"002111": 6.9,
|
|
97607
|
+
"002121": 5,
|
|
97608
|
+
"002201": 6.9,
|
|
97609
|
+
"002211": 5.5,
|
|
97610
|
+
"002221": 2.7,
|
|
97611
|
+
"010000": 9.9,
|
|
97612
|
+
"010001": 9.7,
|
|
97613
|
+
"010010": 9.5,
|
|
97614
|
+
"010011": 9.2,
|
|
97615
|
+
"010020": 9.2,
|
|
97616
|
+
"010021": 8.5,
|
|
97617
|
+
"010100": 9.5,
|
|
97618
|
+
"010101": 9.1,
|
|
97619
|
+
"010110": 9,
|
|
97620
|
+
"010111": 8.3,
|
|
97621
|
+
"010120": 8.4,
|
|
97622
|
+
"010121": 7.1,
|
|
97623
|
+
"010200": 9.2,
|
|
97624
|
+
"010201": 8.1,
|
|
97625
|
+
"010210": 8.2,
|
|
97626
|
+
"010211": 7.1,
|
|
97627
|
+
"010220": 7.2,
|
|
97628
|
+
"010221": 5.3,
|
|
97629
|
+
"011000": 9.5,
|
|
97630
|
+
"011001": 9.3,
|
|
97631
|
+
"011010": 9.2,
|
|
97632
|
+
"011011": 8.5,
|
|
97633
|
+
"011020": 8.5,
|
|
97634
|
+
"011021": 7.3,
|
|
97635
|
+
"011100": 9.2,
|
|
97636
|
+
"011101": 8.2,
|
|
97637
|
+
"011110": 8,
|
|
97638
|
+
"011111": 7.2,
|
|
97639
|
+
"011120": 7,
|
|
97640
|
+
"011121": 5.9,
|
|
97641
|
+
"011200": 8.4,
|
|
97642
|
+
"011201": 7,
|
|
97643
|
+
"011210": 7.1,
|
|
97644
|
+
"011211": 5.2,
|
|
97645
|
+
"011220": 5,
|
|
97646
|
+
"011221": 3,
|
|
97647
|
+
"012001": 8.6,
|
|
97648
|
+
"012011": 7.5,
|
|
97649
|
+
"012021": 5.2,
|
|
97650
|
+
"012101": 7.1,
|
|
97651
|
+
"012111": 5.2,
|
|
97652
|
+
"012121": 2.9,
|
|
97653
|
+
"012201": 6.3,
|
|
97654
|
+
"012211": 2.9,
|
|
97655
|
+
"012221": 1.7,
|
|
97656
|
+
"100000": 9.8,
|
|
97657
|
+
"100001": 9.5,
|
|
97658
|
+
"100010": 9.4,
|
|
97659
|
+
"100011": 8.7,
|
|
97660
|
+
"100020": 9.1,
|
|
97661
|
+
"100021": 8.1,
|
|
97662
|
+
"100100": 9.4,
|
|
97663
|
+
"100101": 8.9,
|
|
97664
|
+
"100110": 8.6,
|
|
97665
|
+
"100111": 7.4,
|
|
97666
|
+
"100120": 7.7,
|
|
97667
|
+
"100121": 6.4,
|
|
97668
|
+
"100200": 8.7,
|
|
97669
|
+
"100201": 7.5,
|
|
97670
|
+
"100210": 7.4,
|
|
97671
|
+
"100211": 6.3,
|
|
97672
|
+
"100220": 6.3,
|
|
97673
|
+
"100221": 4.9,
|
|
97674
|
+
"101000": 9.4,
|
|
97675
|
+
"101001": 8.9,
|
|
97676
|
+
"101010": 8.8,
|
|
97677
|
+
"101011": 7.7,
|
|
97678
|
+
"101020": 7.6,
|
|
97679
|
+
"101021": 6.7,
|
|
97680
|
+
"101100": 8.6,
|
|
97681
|
+
"101101": 7.6,
|
|
97682
|
+
"101110": 7.4,
|
|
97683
|
+
"101111": 5.8,
|
|
97684
|
+
"101120": 5.9,
|
|
97685
|
+
"101121": 5,
|
|
97686
|
+
"101200": 7.2,
|
|
97687
|
+
"101201": 5.7,
|
|
97688
|
+
"101210": 5.7,
|
|
97689
|
+
"101211": 5.2,
|
|
97690
|
+
"101220": 5.2,
|
|
97691
|
+
"101221": 2.5,
|
|
97692
|
+
"102001": 8.3,
|
|
97693
|
+
"102011": 7,
|
|
97694
|
+
"102021": 5.4,
|
|
97695
|
+
"102101": 6.5,
|
|
97696
|
+
"102111": 5.8,
|
|
97697
|
+
"102121": 2.6,
|
|
97698
|
+
"102201": 5.3,
|
|
97699
|
+
"102211": 2.1,
|
|
97700
|
+
"102221": 1.3,
|
|
97701
|
+
"110000": 9.5,
|
|
97702
|
+
"110001": 9,
|
|
97703
|
+
"110010": 8.8,
|
|
97704
|
+
"110011": 7.6,
|
|
97705
|
+
"110020": 7.6,
|
|
97706
|
+
"110021": 7,
|
|
97707
|
+
"110100": 9,
|
|
97708
|
+
"110101": 7.7,
|
|
97709
|
+
"110110": 7.5,
|
|
97710
|
+
"110111": 6.2,
|
|
97711
|
+
"110120": 6.1,
|
|
97712
|
+
"110121": 5.3,
|
|
97713
|
+
"110200": 7.7,
|
|
97714
|
+
"110201": 6.6,
|
|
97715
|
+
"110210": 6.8,
|
|
97716
|
+
"110211": 5.9,
|
|
97717
|
+
"110220": 5.2,
|
|
97718
|
+
"110221": 3,
|
|
97719
|
+
"111000": 8.9,
|
|
97720
|
+
"111001": 7.8,
|
|
97721
|
+
"111010": 7.6,
|
|
97722
|
+
"111011": 6.7,
|
|
97723
|
+
"111020": 6.2,
|
|
97724
|
+
"111021": 5.8,
|
|
97725
|
+
"111100": 7.4,
|
|
97726
|
+
"111101": 5.9,
|
|
97727
|
+
"111110": 5.7,
|
|
97728
|
+
"111111": 5.7,
|
|
97729
|
+
"111120": 4.7,
|
|
97730
|
+
"111121": 2.3,
|
|
97731
|
+
"111200": 6.1,
|
|
97732
|
+
"111201": 5.2,
|
|
97733
|
+
"111210": 5.7,
|
|
97734
|
+
"111211": 2.9,
|
|
97735
|
+
"111220": 2.4,
|
|
97736
|
+
"111221": 1.6,
|
|
97737
|
+
"112001": 7.1,
|
|
97738
|
+
"112011": 5.9,
|
|
97739
|
+
"112021": 3,
|
|
97740
|
+
"112101": 5.8,
|
|
97741
|
+
"112111": 2.6,
|
|
97742
|
+
"112121": 1.5,
|
|
97743
|
+
"112201": 2.3,
|
|
97744
|
+
"112211": 1.3,
|
|
97745
|
+
"112221": 0.6,
|
|
97746
|
+
"200000": 9.3,
|
|
97747
|
+
"200001": 8.7,
|
|
97748
|
+
"200010": 8.6,
|
|
97749
|
+
"200011": 7.2,
|
|
97750
|
+
"200020": 7.5,
|
|
97751
|
+
"200021": 5.8,
|
|
97752
|
+
"200100": 8.6,
|
|
97753
|
+
"200101": 7.4,
|
|
97754
|
+
"200110": 7.4,
|
|
97755
|
+
"200111": 6.1,
|
|
97756
|
+
"200120": 5.6,
|
|
97757
|
+
"200121": 3.4,
|
|
97758
|
+
"200200": 7,
|
|
97759
|
+
"200201": 5.4,
|
|
97760
|
+
"200210": 5.2,
|
|
97761
|
+
"200211": 4,
|
|
97762
|
+
"200220": 4,
|
|
97763
|
+
"200221": 2.2,
|
|
97764
|
+
"201000": 8.5,
|
|
97765
|
+
"201001": 7.5,
|
|
97766
|
+
"201010": 7.4,
|
|
97767
|
+
"201011": 5.5,
|
|
97768
|
+
"201020": 6.2,
|
|
97769
|
+
"201021": 5.1,
|
|
97770
|
+
"201100": 7.2,
|
|
97771
|
+
"201101": 5.7,
|
|
97772
|
+
"201110": 5.5,
|
|
97773
|
+
"201111": 4.1,
|
|
97774
|
+
"201120": 4.6,
|
|
97775
|
+
"201121": 1.9,
|
|
97776
|
+
"201200": 5.3,
|
|
97777
|
+
"201201": 3.6,
|
|
97778
|
+
"201210": 3.4,
|
|
97779
|
+
"201211": 1.9,
|
|
97780
|
+
"201220": 1.9,
|
|
97781
|
+
"201221": 0.8,
|
|
97782
|
+
"202001": 6.4,
|
|
97783
|
+
"202011": 5.1,
|
|
97784
|
+
"202021": 2,
|
|
97785
|
+
"202101": 4.7,
|
|
97786
|
+
"202111": 2.1,
|
|
97787
|
+
"202121": 1.1,
|
|
97788
|
+
"202201": 2.4,
|
|
97789
|
+
"202211": 0.9,
|
|
97790
|
+
"202221": 0.4,
|
|
97791
|
+
"210000": 8.8,
|
|
97792
|
+
"210001": 7.5,
|
|
97793
|
+
"210010": 7.3,
|
|
97794
|
+
"210011": 5.3,
|
|
97795
|
+
"210020": 6,
|
|
97796
|
+
"210021": 5,
|
|
97797
|
+
"210100": 7.3,
|
|
97798
|
+
"210101": 5.5,
|
|
97799
|
+
"210110": 5.9,
|
|
97800
|
+
"210111": 4,
|
|
97801
|
+
"210120": 4.1,
|
|
97802
|
+
"210121": 2,
|
|
97803
|
+
"210200": 5.4,
|
|
97804
|
+
"210201": 4.3,
|
|
97805
|
+
"210210": 4.5,
|
|
97806
|
+
"210211": 2.2,
|
|
97807
|
+
"210220": 2,
|
|
97808
|
+
"210221": 1.1,
|
|
97809
|
+
"211000": 7.5,
|
|
97810
|
+
"211001": 5.5,
|
|
97811
|
+
"211010": 5.8,
|
|
97812
|
+
"211011": 4.5,
|
|
97813
|
+
"211020": 4,
|
|
97814
|
+
"211021": 2.1,
|
|
97815
|
+
"211100": 6.1,
|
|
97816
|
+
"211101": 5.1,
|
|
97817
|
+
"211110": 4.8,
|
|
97818
|
+
"211111": 1.8,
|
|
97819
|
+
"211120": 2,
|
|
97820
|
+
"211121": 0.9,
|
|
97821
|
+
"211200": 4.6,
|
|
97822
|
+
"211201": 1.8,
|
|
97823
|
+
"211210": 1.7,
|
|
97824
|
+
"211211": 0.7,
|
|
97825
|
+
"211220": 0.8,
|
|
97826
|
+
"211221": 0.2,
|
|
97827
|
+
"212001": 5.3,
|
|
97828
|
+
"212011": 2.4,
|
|
97829
|
+
"212021": 1.4,
|
|
97830
|
+
"212101": 2.4,
|
|
97831
|
+
"212111": 1.2,
|
|
97832
|
+
"212121": 0.5,
|
|
97833
|
+
"212201": 1,
|
|
97834
|
+
"212211": 0.3,
|
|
97835
|
+
"212221": 0.1
|
|
97836
|
+
};
|
|
97837
|
+
METRIC_LEVELS = {
|
|
97838
|
+
AV: { N: 0, A: 0.1, L: 0.2, P: 0.3 },
|
|
97839
|
+
PR: { N: 0, L: 0.1, H: 0.2 },
|
|
97840
|
+
UI: { N: 0, P: 0.1, A: 0.2 },
|
|
97841
|
+
AC: { L: 0, H: 0.1 },
|
|
97842
|
+
AT: { N: 0, P: 0.1 },
|
|
97843
|
+
VC: { H: 0, L: 0.1, N: 0.2 },
|
|
97844
|
+
VI: { H: 0, L: 0.1, N: 0.2 },
|
|
97845
|
+
VA: { H: 0, L: 0.1, N: 0.2 },
|
|
97846
|
+
SC: { H: 0.1, L: 0.2, N: 0.3 },
|
|
97847
|
+
SI: { S: 0, H: 0.1, L: 0.2, N: 0.3 },
|
|
97848
|
+
SA: { S: 0, H: 0.1, L: 0.2, N: 0.3 },
|
|
97849
|
+
CR: { H: 0, M: 0.1, L: 0.2 },
|
|
97850
|
+
IR: { H: 0, M: 0.1, L: 0.2 },
|
|
97851
|
+
AR: { H: 0, M: 0.1, L: 0.2 },
|
|
97852
|
+
E: { A: 0, P: 0.1, U: 0.2 }
|
|
97853
|
+
};
|
|
97854
|
+
MAX_SEVERITY = {
|
|
97855
|
+
eq1: { 0: 1, 1: 4, 2: 5 },
|
|
97856
|
+
eq2: { 0: 1, 1: 2 },
|
|
97857
|
+
eq3eq6: {
|
|
97858
|
+
0: { 0: 7, 1: 6 },
|
|
97859
|
+
1: { 0: 8, 1: 8 },
|
|
97860
|
+
2: { 1: 10 }
|
|
97861
|
+
},
|
|
97862
|
+
eq4: { 0: 6, 1: 5, 2: 4 },
|
|
97863
|
+
eq5: { 0: 1, 1: 1, 2: 1 }
|
|
97864
|
+
};
|
|
97865
|
+
EPSILON = Math.pow(10, -6);
|
|
97866
|
+
});
|
|
97867
|
+
|
|
97868
|
+
// src/lib/cvss/calculator.ts
|
|
97869
|
+
function buildVectorString(metrics) {
|
|
97870
|
+
const parts = ["CVSS:4.0"];
|
|
97871
|
+
for (const metric of BASE_METRICS) {
|
|
97872
|
+
const value = metrics[metric];
|
|
97873
|
+
if (value !== undefined) {
|
|
97874
|
+
parts.push(`${metric}:${value}`);
|
|
97875
|
+
}
|
|
97876
|
+
}
|
|
97877
|
+
for (const metric of THREAT_METRICS) {
|
|
97878
|
+
const value = metrics[metric];
|
|
97879
|
+
if (value !== undefined && value !== "X") {
|
|
97880
|
+
parts.push(`${metric}:${value}`);
|
|
97881
|
+
}
|
|
97882
|
+
}
|
|
97883
|
+
for (const metric of ENVIRONMENTAL_METRICS) {
|
|
97884
|
+
const value = metrics[metric];
|
|
97885
|
+
if (value !== undefined && value !== "X") {
|
|
97886
|
+
parts.push(`${metric}:${value}`);
|
|
97887
|
+
}
|
|
97888
|
+
}
|
|
97889
|
+
for (const metric of SUPPLEMENTAL_METRICS) {
|
|
97890
|
+
const value = metrics[metric];
|
|
97891
|
+
if (value !== undefined && value !== "X") {
|
|
97892
|
+
parts.push(`${metric}:${value}`);
|
|
97893
|
+
}
|
|
97894
|
+
}
|
|
97895
|
+
return parts.join("/");
|
|
97896
|
+
}
|
|
97897
|
+
function getEffectiveValue(metrics, baseMetric, modifiedMetric) {
|
|
97898
|
+
if (modifiedMetric) {
|
|
97899
|
+
const modValue = metrics[modifiedMetric];
|
|
97900
|
+
if (modValue && modValue !== "X") {
|
|
97901
|
+
return modValue;
|
|
97902
|
+
}
|
|
97903
|
+
}
|
|
97904
|
+
return metrics[baseMetric] ?? "";
|
|
97905
|
+
}
|
|
97906
|
+
function computeEQ1(metrics) {
|
|
97907
|
+
const av = getEffectiveValue(metrics, "AV", "MAV");
|
|
97908
|
+
const pr = getEffectiveValue(metrics, "PR", "MPR");
|
|
97909
|
+
const ui = getEffectiveValue(metrics, "UI", "MUI");
|
|
97910
|
+
if (av === "N" && pr === "N" && ui === "N") {
|
|
97911
|
+
return 0;
|
|
97912
|
+
}
|
|
97913
|
+
if (!(av === "P" || pr === "H" || ui === "A")) {
|
|
97914
|
+
return 1;
|
|
97915
|
+
}
|
|
97916
|
+
return 2;
|
|
97917
|
+
}
|
|
97918
|
+
function computeEQ2(metrics) {
|
|
97919
|
+
const ac = getEffectiveValue(metrics, "AC", "MAC");
|
|
97920
|
+
const at = getEffectiveValue(metrics, "AT", "MAT");
|
|
97921
|
+
if (ac === "L" && at === "N") {
|
|
97922
|
+
return 0;
|
|
97923
|
+
}
|
|
97924
|
+
return 1;
|
|
97925
|
+
}
|
|
97926
|
+
function computeEQ3(metrics) {
|
|
97927
|
+
const vc = getEffectiveValue(metrics, "VC", "MVC");
|
|
97928
|
+
const vi = getEffectiveValue(metrics, "VI", "MVI");
|
|
97929
|
+
const va = getEffectiveValue(metrics, "VA", "MVA");
|
|
97930
|
+
if (vc === "H" && vi === "H") {
|
|
97931
|
+
return 0;
|
|
97932
|
+
}
|
|
97933
|
+
if (vc === "H" || vi === "H" || va === "H") {
|
|
97934
|
+
return 1;
|
|
97935
|
+
}
|
|
97936
|
+
return 2;
|
|
97937
|
+
}
|
|
97938
|
+
function computeEQ4(metrics) {
|
|
97939
|
+
const msi = metrics.MSI || "X";
|
|
97940
|
+
const msa = metrics.MSA || "X";
|
|
97941
|
+
const sc = getEffectiveValue(metrics, "SC", "MSC");
|
|
97942
|
+
const si = msi !== "X" ? msi : metrics.SI;
|
|
97943
|
+
const sa = msa !== "X" ? msa : metrics.SA;
|
|
97944
|
+
if (msi === "S" || msa === "S") {
|
|
97945
|
+
return 0;
|
|
97946
|
+
}
|
|
97947
|
+
if (sc === "H" || si === "H" || sa === "H") {
|
|
97948
|
+
return 1;
|
|
97949
|
+
}
|
|
97950
|
+
return 2;
|
|
97951
|
+
}
|
|
97952
|
+
function computeEQ5(metrics) {
|
|
97953
|
+
const e = metrics.E || "A";
|
|
97954
|
+
if (e === "A" || e === "X") {
|
|
97955
|
+
return 0;
|
|
97956
|
+
}
|
|
97957
|
+
if (e === "P") {
|
|
97958
|
+
return 1;
|
|
97959
|
+
}
|
|
97960
|
+
return 2;
|
|
97961
|
+
}
|
|
97962
|
+
function computeEQ6(metrics) {
|
|
97963
|
+
const cr = metrics.CR || "H";
|
|
97964
|
+
const ir = metrics.IR || "H";
|
|
97965
|
+
const ar = metrics.AR || "H";
|
|
97966
|
+
const vc = getEffectiveValue(metrics, "VC", "MVC");
|
|
97967
|
+
const vi = getEffectiveValue(metrics, "VI", "MVI");
|
|
97968
|
+
const va = getEffectiveValue(metrics, "VA", "MVA");
|
|
97969
|
+
if (cr === "H" && vc === "H" || ir === "H" && vi === "H" || ar === "H" && va === "H") {
|
|
97970
|
+
return 0;
|
|
97971
|
+
}
|
|
97972
|
+
return 1;
|
|
97973
|
+
}
|
|
97974
|
+
function computeMacroVector(metrics) {
|
|
97975
|
+
const eq1 = computeEQ1(metrics);
|
|
97976
|
+
const eq2 = computeEQ2(metrics);
|
|
97977
|
+
const eq3 = computeEQ3(metrics);
|
|
97978
|
+
const eq4 = computeEQ4(metrics);
|
|
97979
|
+
const eq5 = computeEQ5(metrics);
|
|
97980
|
+
const eq6 = computeEQ6(metrics);
|
|
97981
|
+
return `${eq1}${eq2}${eq3}${eq4}${eq5}${eq6}`;
|
|
97982
|
+
}
|
|
97983
|
+
function hasNoImpact(metrics) {
|
|
97984
|
+
const vc = getEffectiveValue(metrics, "VC", "MVC");
|
|
97985
|
+
const vi = getEffectiveValue(metrics, "VI", "MVI");
|
|
97986
|
+
const va = getEffectiveValue(metrics, "VA", "MVA");
|
|
97987
|
+
const sc = getEffectiveValue(metrics, "SC", "MSC");
|
|
97988
|
+
const si = metrics.MSI !== "X" && metrics.MSI ? metrics.MSI : metrics.SI;
|
|
97989
|
+
const sa = metrics.MSA !== "X" && metrics.MSA ? metrics.MSA : metrics.SA;
|
|
97990
|
+
return vc === "N" && vi === "N" && va === "N" && sc === "N" && si === "N" && sa === "N";
|
|
97991
|
+
}
|
|
97992
|
+
function getMetricDistance(metrics, metric) {
|
|
97993
|
+
const levels = METRIC_LEVELS[metric];
|
|
97994
|
+
if (!levels)
|
|
97995
|
+
return 0;
|
|
97996
|
+
let value;
|
|
97997
|
+
const modifiedMetric = "M" + metric;
|
|
97998
|
+
const metricsRecord = metrics;
|
|
97999
|
+
if (metricsRecord[modifiedMetric] && metricsRecord[modifiedMetric] !== "X") {
|
|
98000
|
+
value = metricsRecord[modifiedMetric] ?? "";
|
|
98001
|
+
} else {
|
|
98002
|
+
value = metricsRecord[metric] ?? "";
|
|
98003
|
+
}
|
|
98004
|
+
if (metric === "E" && (!value || value === "X")) {
|
|
98005
|
+
value = "A";
|
|
98006
|
+
}
|
|
98007
|
+
if ((metric === "CR" || metric === "IR" || metric === "AR") && (!value || value === "X")) {
|
|
98008
|
+
value = "H";
|
|
98009
|
+
}
|
|
98010
|
+
return levels[value] || 0;
|
|
98011
|
+
}
|
|
98012
|
+
function getNextLowerScore(macroVector, position) {
|
|
98013
|
+
const digits = macroVector.split("").map(Number);
|
|
98014
|
+
digits[position]++;
|
|
98015
|
+
const nextMacroVector = digits.join("");
|
|
98016
|
+
return MACROVECTOR_LOOKUP[nextMacroVector] ?? null;
|
|
98017
|
+
}
|
|
98018
|
+
function interpolateScore(metrics, macroVector, baseScore) {
|
|
98019
|
+
const eq1 = parseInt(macroVector[0]);
|
|
98020
|
+
const eq2 = parseInt(macroVector[1]);
|
|
98021
|
+
const eq3 = parseInt(macroVector[2]);
|
|
98022
|
+
const eq4 = parseInt(macroVector[3]);
|
|
98023
|
+
const eq5 = parseInt(macroVector[4]);
|
|
98024
|
+
const eq6 = parseInt(macroVector[5]);
|
|
98025
|
+
let meanDistance = 0;
|
|
98026
|
+
let eqCount = 0;
|
|
98027
|
+
const eq1NextLower = getNextLowerScore(macroVector, 0);
|
|
98028
|
+
if (eq1NextLower !== null) {
|
|
98029
|
+
const msd = baseScore - eq1NextLower;
|
|
98030
|
+
const maxDepth = MAX_SEVERITY.eq1[eq1] || 1;
|
|
98031
|
+
const avDist = getMetricDistance(metrics, "AV");
|
|
98032
|
+
const prDist = getMetricDistance(metrics, "PR");
|
|
98033
|
+
const uiDist = getMetricDistance(metrics, "UI");
|
|
98034
|
+
const severityDist = avDist + prDist + uiDist;
|
|
98035
|
+
const normalizedDist = severityDist / (maxDepth * STEP);
|
|
98036
|
+
meanDistance += msd * normalizedDist;
|
|
98037
|
+
eqCount++;
|
|
98038
|
+
}
|
|
98039
|
+
const eq2NextLower = getNextLowerScore(macroVector, 1);
|
|
98040
|
+
if (eq2NextLower !== null) {
|
|
98041
|
+
const msd = baseScore - eq2NextLower;
|
|
98042
|
+
const maxDepth = MAX_SEVERITY.eq2[eq2] || 1;
|
|
98043
|
+
const acDist = getMetricDistance(metrics, "AC");
|
|
98044
|
+
const atDist = getMetricDistance(metrics, "AT");
|
|
98045
|
+
const severityDist = acDist + atDist;
|
|
98046
|
+
const normalizedDist = severityDist / (maxDepth * STEP);
|
|
98047
|
+
meanDistance += msd * normalizedDist;
|
|
98048
|
+
eqCount++;
|
|
98049
|
+
}
|
|
98050
|
+
const eq3eq6MaxSeverity = MAX_SEVERITY.eq3eq6;
|
|
98051
|
+
if (eq3eq6MaxSeverity[eq3] && eq3eq6MaxSeverity[eq3][eq6] !== undefined) {
|
|
98052
|
+
const eq3NextLower = getNextLowerScore(macroVector, 2);
|
|
98053
|
+
if (eq3NextLower !== null) {
|
|
98054
|
+
const msd = baseScore - eq3NextLower;
|
|
98055
|
+
const maxDepth = eq3eq6MaxSeverity[eq3][eq6] || 1;
|
|
98056
|
+
const vcDist = getMetricDistance(metrics, "VC");
|
|
98057
|
+
const viDist = getMetricDistance(metrics, "VI");
|
|
98058
|
+
const vaDist = getMetricDistance(metrics, "VA");
|
|
98059
|
+
const crDist = getMetricDistance(metrics, "CR");
|
|
98060
|
+
const irDist = getMetricDistance(metrics, "IR");
|
|
98061
|
+
const arDist = getMetricDistance(metrics, "AR");
|
|
98062
|
+
const severityDist = vcDist + viDist + vaDist + crDist + irDist + arDist;
|
|
98063
|
+
const normalizedDist = severityDist / (maxDepth * STEP);
|
|
98064
|
+
meanDistance += msd * normalizedDist;
|
|
98065
|
+
eqCount++;
|
|
98066
|
+
}
|
|
98067
|
+
}
|
|
98068
|
+
const eq4NextLower = getNextLowerScore(macroVector, 3);
|
|
98069
|
+
if (eq4NextLower !== null) {
|
|
98070
|
+
const msd = baseScore - eq4NextLower;
|
|
98071
|
+
const maxDepth = MAX_SEVERITY.eq4[eq4] || 1;
|
|
98072
|
+
const scDist = getMetricDistance(metrics, "SC");
|
|
98073
|
+
const siDist = getMetricDistance(metrics, "SI");
|
|
98074
|
+
const saDist = getMetricDistance(metrics, "SA");
|
|
98075
|
+
const severityDist = scDist + siDist + saDist;
|
|
98076
|
+
const normalizedDist = severityDist / (maxDepth * STEP);
|
|
98077
|
+
meanDistance += msd * normalizedDist;
|
|
98078
|
+
eqCount++;
|
|
98079
|
+
}
|
|
98080
|
+
const eq5NextLower = getNextLowerScore(macroVector, 4);
|
|
98081
|
+
if (eq5NextLower !== null) {
|
|
98082
|
+
const msd = baseScore - eq5NextLower;
|
|
98083
|
+
const maxDepth = MAX_SEVERITY.eq5[eq5] || 1;
|
|
98084
|
+
const eDist = getMetricDistance(metrics, "E");
|
|
98085
|
+
const normalizedDist = eDist / (maxDepth * STEP);
|
|
98086
|
+
meanDistance += msd * normalizedDist;
|
|
98087
|
+
eqCount++;
|
|
98088
|
+
}
|
|
98089
|
+
const avgDistance = eqCount > 0 ? meanDistance / eqCount : 0;
|
|
98090
|
+
let finalScore = baseScore - avgDistance;
|
|
98091
|
+
finalScore = Math.max(0, Math.min(10, finalScore));
|
|
98092
|
+
finalScore = Math.round(finalScore * 10) / 10;
|
|
98093
|
+
return finalScore;
|
|
98094
|
+
}
|
|
98095
|
+
function calculateCVSS4Score(metrics) {
|
|
98096
|
+
if (hasNoImpact(metrics)) {
|
|
98097
|
+
return {
|
|
98098
|
+
score: 0,
|
|
98099
|
+
severity: "NONE",
|
|
98100
|
+
vectorString: buildVectorString(metrics),
|
|
98101
|
+
metrics,
|
|
98102
|
+
scoreType: getScoreType(metrics)
|
|
98103
|
+
};
|
|
98104
|
+
}
|
|
98105
|
+
const macroVector = computeMacroVector(metrics);
|
|
98106
|
+
const baseScore = MACROVECTOR_LOOKUP[macroVector];
|
|
98107
|
+
if (baseScore === undefined) {
|
|
98108
|
+
throw new Error(`Invalid MacroVector: ${macroVector}`);
|
|
98109
|
+
}
|
|
98110
|
+
const score = interpolateScore(metrics, macroVector, baseScore);
|
|
98111
|
+
const severity = getSeverityFromScore(score);
|
|
98112
|
+
const scoreType = getScoreType(metrics);
|
|
98113
|
+
return {
|
|
98114
|
+
score,
|
|
98115
|
+
severity,
|
|
98116
|
+
vectorString: buildVectorString(metrics),
|
|
98117
|
+
metrics,
|
|
98118
|
+
scoreType
|
|
98119
|
+
};
|
|
98120
|
+
}
|
|
98121
|
+
function getScoreType(metrics) {
|
|
98122
|
+
const hasThreat = metrics.E !== undefined && metrics.E !== "X";
|
|
98123
|
+
const hasEnvironmental = metrics.CR !== undefined && metrics.CR !== "X" || metrics.IR !== undefined && metrics.IR !== "X" || metrics.AR !== undefined && metrics.AR !== "X" || metrics.MAV !== undefined && metrics.MAV !== "X" || metrics.MAC !== undefined && metrics.MAC !== "X" || metrics.MAT !== undefined && metrics.MAT !== "X" || metrics.MPR !== undefined && metrics.MPR !== "X" || metrics.MUI !== undefined && metrics.MUI !== "X" || metrics.MVC !== undefined && metrics.MVC !== "X" || metrics.MVI !== undefined && metrics.MVI !== "X" || metrics.MVA !== undefined && metrics.MVA !== "X" || metrics.MSC !== undefined && metrics.MSC !== "X" || metrics.MSI !== undefined && metrics.MSI !== "X" || metrics.MSA !== undefined && metrics.MSA !== "X";
|
|
98124
|
+
if (hasThreat && hasEnvironmental)
|
|
98125
|
+
return "CVSS-BTE";
|
|
98126
|
+
if (hasEnvironmental)
|
|
98127
|
+
return "CVSS-BE";
|
|
98128
|
+
if (hasThreat)
|
|
98129
|
+
return "CVSS-BT";
|
|
98130
|
+
return "CVSS-B";
|
|
98131
|
+
}
|
|
98132
|
+
var BASE_METRICS, THREAT_METRICS, ENVIRONMENTAL_METRICS, SUPPLEMENTAL_METRICS;
|
|
98133
|
+
var init_calculator = __esm(() => {
|
|
98134
|
+
init_types4();
|
|
98135
|
+
init_macrovector_scores();
|
|
98136
|
+
BASE_METRICS = [
|
|
98137
|
+
"AV",
|
|
98138
|
+
"AC",
|
|
98139
|
+
"AT",
|
|
98140
|
+
"PR",
|
|
98141
|
+
"UI",
|
|
98142
|
+
"VC",
|
|
98143
|
+
"VI",
|
|
98144
|
+
"VA",
|
|
98145
|
+
"SC",
|
|
98146
|
+
"SI",
|
|
98147
|
+
"SA"
|
|
98148
|
+
];
|
|
98149
|
+
THREAT_METRICS = ["E"];
|
|
98150
|
+
ENVIRONMENTAL_METRICS = [
|
|
98151
|
+
"CR",
|
|
98152
|
+
"IR",
|
|
98153
|
+
"AR",
|
|
98154
|
+
"MAV",
|
|
98155
|
+
"MAC",
|
|
98156
|
+
"MAT",
|
|
98157
|
+
"MPR",
|
|
98158
|
+
"MUI",
|
|
98159
|
+
"MVC",
|
|
98160
|
+
"MVI",
|
|
98161
|
+
"MVA",
|
|
98162
|
+
"MSC",
|
|
98163
|
+
"MSI",
|
|
98164
|
+
"MSA"
|
|
98165
|
+
];
|
|
98166
|
+
SUPPLEMENTAL_METRICS = ["S", "AU", "R", "V", "RE", "U"];
|
|
98167
|
+
});
|
|
98168
|
+
|
|
98169
|
+
// src/lib/cvss/index.ts
|
|
98170
|
+
var init_cvss = __esm(() => {
|
|
98171
|
+
init_types4();
|
|
98172
|
+
init_calculator();
|
|
98173
|
+
init_macrovector_scores();
|
|
98174
|
+
});
|
|
98175
|
+
|
|
98176
|
+
// src/core/agents/specialized/cvssScorer/index.ts
|
|
98177
|
+
async function scoreFindingWithCVSS(input, model, authConfig) {
|
|
98178
|
+
const prompt = buildScoringPrompt(input);
|
|
98179
|
+
const assessment = await generateObjectResponse({
|
|
98180
|
+
model,
|
|
98181
|
+
schema: CVSSMetricsOutputSchema,
|
|
98182
|
+
prompt,
|
|
98183
|
+
system: CVSS_SCORER_SYSTEM_PROMPT,
|
|
98184
|
+
authConfig
|
|
98185
|
+
});
|
|
98186
|
+
const cvssResult = calculateCVSS4Score({
|
|
98187
|
+
...assessment.metrics
|
|
98188
|
+
});
|
|
98189
|
+
return {
|
|
98190
|
+
score: cvssResult.score,
|
|
98191
|
+
severity: cvssResult.severity,
|
|
98192
|
+
vectorString: cvssResult.vectorString,
|
|
98193
|
+
metrics: cvssResult.metrics,
|
|
98194
|
+
scoreType: cvssResult.scoreType,
|
|
98195
|
+
reasoning: assessment.reasoning
|
|
98196
|
+
};
|
|
98197
|
+
}
|
|
98198
|
+
function buildScoringPrompt(input) {
|
|
98199
|
+
const { finding, agentMessages } = input;
|
|
98200
|
+
let prompt = `# Vulnerability Finding to Score
|
|
98201
|
+
|
|
98202
|
+
## Finding Details
|
|
98203
|
+
|
|
98204
|
+
**Title:** ${finding.title}
|
|
98205
|
+
**Vulnerability Class:** ${finding.vulnerabilityClass || "Unknown"}
|
|
98206
|
+
**Endpoint:** ${finding.endpoint}
|
|
98207
|
+
|
|
98208
|
+
### Description
|
|
98209
|
+
${finding.description}
|
|
98210
|
+
|
|
98211
|
+
### Impact Assessment
|
|
98212
|
+
${finding.impact}
|
|
98213
|
+
|
|
98214
|
+
### Evidence (POC Output)
|
|
98215
|
+
\`\`\`
|
|
98216
|
+
${finding.evidence}
|
|
98217
|
+
\`\`\`
|
|
98218
|
+
|
|
98219
|
+
`;
|
|
98220
|
+
if (agentMessages && agentMessages.length > 0) {
|
|
98221
|
+
prompt += `## Discovery Context
|
|
98222
|
+
|
|
98223
|
+
The following is a summary of how this vulnerability was discovered (from the testing agent's conversation):
|
|
98224
|
+
|
|
98225
|
+
`;
|
|
98226
|
+
const contextSummary = extractContextSummary(agentMessages);
|
|
98227
|
+
prompt += contextSummary;
|
|
98228
|
+
}
|
|
98229
|
+
prompt += `
|
|
98230
|
+
## Task
|
|
98231
|
+
|
|
98232
|
+
Analyze this vulnerability finding and determine the appropriate CVSS 4.0 metrics.
|
|
98233
|
+
|
|
98234
|
+
Consider:
|
|
98235
|
+
1. How the vulnerability is exploited (attack vector, complexity, requirements)
|
|
98236
|
+
2. What privileges/authentication were needed
|
|
98237
|
+
3. Whether user interaction is required
|
|
98238
|
+
4. The actual impact demonstrated in the evidence
|
|
98239
|
+
5. Potential for lateral movement or subsequent system compromise
|
|
98240
|
+
|
|
98241
|
+
Provide your metrics assessment and brief reasoning.
|
|
98242
|
+
`;
|
|
98243
|
+
return prompt;
|
|
98244
|
+
}
|
|
98245
|
+
function extractContextSummary(messages) {
|
|
98246
|
+
const contextParts = [];
|
|
98247
|
+
let foundToolCalls = 0;
|
|
98248
|
+
const maxToolCalls = 5;
|
|
98249
|
+
for (const message of messages) {
|
|
98250
|
+
if (foundToolCalls >= maxToolCalls)
|
|
98251
|
+
break;
|
|
98252
|
+
if (message.role === "assistant" && typeof message.content === "string") {
|
|
98253
|
+
const hypothesisMatch = message.content.match(/HYPOTHESIS:[\s\S]*?(?=VALIDATION:|$)/);
|
|
98254
|
+
const validationMatch = message.content.match(/VALIDATION:[\s\S]*?(?=HYPOTHESIS:|$)/);
|
|
98255
|
+
if (hypothesisMatch) {
|
|
98256
|
+
contextParts.push(`- ${hypothesisMatch[0].substring(0, 300)}...`);
|
|
98257
|
+
}
|
|
98258
|
+
if (validationMatch) {
|
|
98259
|
+
contextParts.push(`- ${validationMatch[0].substring(0, 300)}...`);
|
|
98260
|
+
}
|
|
98261
|
+
}
|
|
98262
|
+
if (message.role === "assistant" && Array.isArray(message.content)) {
|
|
98263
|
+
for (const rawPart of message.content) {
|
|
98264
|
+
const part = rawPart;
|
|
98265
|
+
if (part.type === "tool-call" && part.toolName) {
|
|
98266
|
+
const input = part.input;
|
|
98267
|
+
const desc = input?.toolCallDescription || `Used ${part.toolName}`;
|
|
98268
|
+
contextParts.push(`- Tool: ${String(desc)}`);
|
|
98269
|
+
foundToolCalls++;
|
|
98270
|
+
}
|
|
98271
|
+
}
|
|
98272
|
+
}
|
|
98273
|
+
}
|
|
98274
|
+
if (contextParts.length === 0) {
|
|
98275
|
+
return `No additional context available from testing conversation.
|
|
98276
|
+
`;
|
|
98277
|
+
}
|
|
98278
|
+
return contextParts.join(`
|
|
98279
|
+
`) + `
|
|
98280
|
+
`;
|
|
98281
|
+
}
|
|
98282
|
+
var CVSSMetricsOutputSchema, CVSS_SCORER_SYSTEM_PROMPT = `You are a CVSS 4.0 scoring specialist. Your task is to analyze vulnerability findings and determine the appropriate CVSS 4.0 Base metrics.
|
|
98283
|
+
|
|
98284
|
+
## CVSS 4.0 Metrics Guide
|
|
98285
|
+
|
|
98286
|
+
### Attack Vector (AV)
|
|
98287
|
+
- **N (Network)**: Remotely exploitable over the internet (web app vulns, network services)
|
|
98288
|
+
- **A (Adjacent)**: Requires shared physical or logical network (same WiFi, VLAN)
|
|
98289
|
+
- **L (Local)**: Requires local access or user interaction to deliver payload
|
|
98290
|
+
- **P (Physical)**: Requires physical hardware access
|
|
98291
|
+
|
|
98292
|
+
### Attack Complexity (AC)
|
|
98293
|
+
- **L (Low)**: No special preparation needed, works reliably
|
|
98294
|
+
- **H (High)**: Requires race conditions, bypassing defenses, or specific configurations
|
|
98295
|
+
|
|
98296
|
+
### Attack Requirements (AT)
|
|
98297
|
+
- **N (None)**: Works under normal conditions
|
|
98298
|
+
- **P (Present)**: Requires specific deployment conditions (race window, man-in-the-middle position)
|
|
98299
|
+
|
|
98300
|
+
### Privileges Required (PR)
|
|
98301
|
+
- **N (None)**: Unauthenticated attack
|
|
98302
|
+
- **L (Low)**: Requires basic user-level privileges
|
|
98303
|
+
- **H (High)**: Requires administrative/root privileges
|
|
98304
|
+
|
|
98305
|
+
### User Interaction (UI)
|
|
98306
|
+
- **N (None)**: No user action required
|
|
98307
|
+
- **P (Passive)**: User visits a page, opens a file, or is on a vulnerable session
|
|
98308
|
+
- **A (Active)**: User must click a link, dismiss warnings, or actively interact
|
|
98309
|
+
|
|
98310
|
+
### Confidentiality Impact (VC - Vulnerable System, SC - Subsequent Systems)
|
|
98311
|
+
- **H (High)**: Complete loss of confidentiality (full data access, credential theft)
|
|
98312
|
+
- **L (Low)**: Limited data exposure (some info leak but not critical)
|
|
98313
|
+
- **N (None)**: No confidentiality impact
|
|
98314
|
+
|
|
98315
|
+
### Integrity Impact (VI - Vulnerable System, SI - Subsequent Systems)
|
|
98316
|
+
- **H (High)**: Complete loss of integrity (arbitrary modification, code execution)
|
|
98317
|
+
- **L (Low)**: Limited modification capability
|
|
98318
|
+
- **N (None)**: No integrity impact
|
|
98319
|
+
|
|
98320
|
+
### Availability Impact (VA - Vulnerable System, SA - Subsequent Systems)
|
|
98321
|
+
- **H (High)**: Complete denial of service
|
|
98322
|
+
- **L (Low)**: Reduced performance or intermittent availability
|
|
98323
|
+
- **N (None)**: No availability impact
|
|
98324
|
+
|
|
98325
|
+
### Exploit Maturity (E)
|
|
98326
|
+
- **A (Attacked)**: Working exploit exists (POC confirmed vulnerability)
|
|
98327
|
+
- **P (POC)**: Proof-of-concept code exists but may not be weaponized
|
|
98328
|
+
- **U (Unreported)**: No known public exploit
|
|
98329
|
+
|
|
98330
|
+
## Vulnerability Class Guidelines
|
|
98331
|
+
|
|
98332
|
+
### SQL Injection (sqli)
|
|
98333
|
+
- Typically: AV:N, AC:L, AT:N, PR varies, UI:N
|
|
98334
|
+
- VC:H (data access), VI:H (data modification), VA:L-H (depending on impact)
|
|
98335
|
+
- SC/SI/SA: Usually N unless database is shared
|
|
98336
|
+
|
|
98337
|
+
### Cross-Site Scripting (xss)
|
|
98338
|
+
- Reflected: AV:N, AC:L, AT:N, PR:N, UI:A (user must click)
|
|
98339
|
+
- Stored: AV:N, AC:L, AT:N, PR varies, UI:P (user visits page)
|
|
98340
|
+
- VC:L (session theft), VI:L (DOM modification), VA:N
|
|
98341
|
+
- SC/SI/SA: Usually N (client-side only)
|
|
98342
|
+
|
|
98343
|
+
### Command Injection / RCE
|
|
98344
|
+
- Typically: AV:N, AC:L, AT:N, PR varies, UI:N
|
|
98345
|
+
- VC:H, VI:H, VA:H (complete system compromise)
|
|
98346
|
+
- SC/SI/SA: Potentially H if can pivot
|
|
98347
|
+
|
|
98348
|
+
### IDOR / Access Control
|
|
98349
|
+
- Typically: AV:N, AC:L, AT:N, PR:L (needs some access), UI:N
|
|
98350
|
+
- Impact varies based on what data is accessed
|
|
98351
|
+
|
|
98352
|
+
### SSRF
|
|
98353
|
+
- Typically: AV:N, AC:L, AT:N, PR varies, UI:N
|
|
98354
|
+
- VC on vulnerable: L-N, SC on subsequent: H (internal network access)
|
|
98355
|
+
|
|
98356
|
+
### Path Traversal / LFI
|
|
98357
|
+
- Typically: AV:N, AC:L, AT:N, PR varies, UI:N
|
|
98358
|
+
- VC:H (file read), VI:N (unless write), VA:N
|
|
98359
|
+
|
|
98360
|
+
## Analysis Instructions
|
|
98361
|
+
|
|
98362
|
+
1. Read the finding description and evidence carefully
|
|
98363
|
+
2. Consider the attack vector based on how the vulnerability was exploited
|
|
98364
|
+
3. Assess complexity based on whether special conditions were needed
|
|
98365
|
+
4. Determine privileges based on authentication requirements
|
|
98366
|
+
5. Evaluate user interaction based on exploit mechanics
|
|
98367
|
+
6. Assess impact on both the vulnerable system AND potential subsequent systems
|
|
98368
|
+
7. Since a POC exists and confirmed the vulnerability, E should typically be 'A'
|
|
98369
|
+
|
|
98370
|
+
Always provide brief reasoning explaining your key decisions.`;
|
|
98371
|
+
var init_cvssScorer = __esm(() => {
|
|
98372
|
+
init_zod();
|
|
98373
|
+
init_ai2();
|
|
98374
|
+
init_cvss();
|
|
98375
|
+
CVSSMetricsOutputSchema = exports_external.object({
|
|
98376
|
+
metrics: exports_external.object({
|
|
98377
|
+
AV: exports_external.enum(["N", "A", "L", "P"]).describe("Attack Vector: N=Network (remotely exploitable), A=Adjacent network, L=Local access required, P=Physical access required"),
|
|
98378
|
+
AC: exports_external.enum(["L", "H"]).describe("Attack Complexity: L=Low (no special conditions), H=High (requires specific conditions/bypassing)"),
|
|
98379
|
+
AT: exports_external.enum(["N", "P"]).describe("Attack Requirements: N=None (works in most configs), P=Present (requires race conditions/specific setup)"),
|
|
98380
|
+
PR: exports_external.enum(["N", "L", "H"]).describe("Privileges Required: N=None (unauthenticated), L=Low (basic user), H=High (admin)"),
|
|
98381
|
+
UI: exports_external.enum(["N", "P", "A"]).describe("User Interaction: N=None, P=Passive (user visits page), A=Active (user must click/interact)"),
|
|
98382
|
+
VC: exports_external.enum(["H", "L", "N"]).describe("Confidentiality Impact on Vulnerable System: H=High (total loss), L=Low (partial), N=None"),
|
|
98383
|
+
VI: exports_external.enum(["H", "L", "N"]).describe("Integrity Impact on Vulnerable System: H=High (total loss), L=Low (partial), N=None"),
|
|
98384
|
+
VA: exports_external.enum(["H", "L", "N"]).describe("Availability Impact on Vulnerable System: H=High (total loss), L=Low (partial), N=None"),
|
|
98385
|
+
SC: exports_external.enum(["H", "L", "N"]).describe("Confidentiality Impact on Subsequent Systems: H=High, L=Low, N=None (no pivoting)"),
|
|
98386
|
+
SI: exports_external.enum(["H", "L", "N"]).describe("Integrity Impact on Subsequent Systems: H=High, L=Low, N=None"),
|
|
98387
|
+
SA: exports_external.enum(["H", "L", "N"]).describe("Availability Impact on Subsequent Systems: H=High, L=Low, N=None"),
|
|
98388
|
+
E: exports_external.enum(["A", "P", "U"]).describe("Exploit Maturity: A=Attacked (working exploit exists), P=POC available, U=Unreported")
|
|
98389
|
+
}),
|
|
98390
|
+
reasoning: exports_external.string().describe("Brief explanation (2-3 sentences) of the key factors that influenced the metric choices")
|
|
98391
|
+
});
|
|
98392
|
+
});
|
|
98393
|
+
|
|
96798
98394
|
// src/core/agents/offSecAgent/tools/documentFinding.ts
|
|
96799
98395
|
import { join as join5 } from "path";
|
|
96800
98396
|
import { writeFileSync as writeFileSync4, appendFileSync as appendFileSync2 } from "fs";
|
|
@@ -96840,11 +98436,37 @@ FINDING STRUCTURE:
|
|
|
96840
98436
|
}
|
|
96841
98437
|
}
|
|
96842
98438
|
const timestamp = new Date().toISOString();
|
|
98439
|
+
let cvssResult;
|
|
98440
|
+
try {
|
|
98441
|
+
cvssResult = await scoreFindingWithCVSS({
|
|
98442
|
+
finding: {
|
|
98443
|
+
title: finding.title,
|
|
98444
|
+
description: finding.description,
|
|
98445
|
+
impact: finding.impact,
|
|
98446
|
+
evidence: finding.evidence,
|
|
98447
|
+
endpoint: finding.endpoint,
|
|
98448
|
+
remediation: finding.remediation
|
|
98449
|
+
},
|
|
98450
|
+
agentMessages: []
|
|
98451
|
+
}, ctx4.model, ctx4.authConfig);
|
|
98452
|
+
} catch (err) {
|
|
98453
|
+
console.warn("CVSS scoring failed, proceeding without score:", err instanceof Error ? err.message : err);
|
|
98454
|
+
}
|
|
96843
98455
|
const findingWithMeta = {
|
|
96844
98456
|
...finding,
|
|
96845
98457
|
timestamp,
|
|
96846
98458
|
sessionId: session.id,
|
|
96847
|
-
target: session.targets[0]
|
|
98459
|
+
target: session.targets[0],
|
|
98460
|
+
...cvssResult && {
|
|
98461
|
+
cvss: {
|
|
98462
|
+
score: cvssResult.score,
|
|
98463
|
+
severity: cvssResult.severity,
|
|
98464
|
+
vectorString: cvssResult.vectorString,
|
|
98465
|
+
metrics: cvssResult.metrics,
|
|
98466
|
+
scoreType: cvssResult.scoreType,
|
|
98467
|
+
reasoning: cvssResult.reasoning
|
|
98468
|
+
}
|
|
98469
|
+
}
|
|
96848
98470
|
};
|
|
96849
98471
|
const safeTitle = finding.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").substring(0, 50);
|
|
96850
98472
|
const findingId = `${timestamp.split("T")[0]}-${safeTitle}`;
|
|
@@ -96854,9 +98476,21 @@ FINDING STRUCTURE:
|
|
|
96854
98476
|
const mdPath = join5(session.findingsPath, mdFilename);
|
|
96855
98477
|
try {
|
|
96856
98478
|
writeFileSync4(jsonPath, JSON.stringify(findingWithMeta, null, 2));
|
|
98479
|
+
const cvssLine = cvssResult ? `
|
|
98480
|
+
**CVSS 4.0 Score:** ${cvssResult.score} (${cvssResult.severity})
|
|
98481
|
+
**Vector:** \`${cvssResult.vectorString}\` ` : "";
|
|
98482
|
+
const cvssSection = cvssResult ? `
|
|
98483
|
+
## CVSS 4.0 Assessment
|
|
98484
|
+
|
|
98485
|
+
**Score:** ${cvssResult.score} / 10.0 (${cvssResult.severity})
|
|
98486
|
+
**Vector:** \`${cvssResult.vectorString}\`
|
|
98487
|
+
**Score Type:** ${cvssResult.scoreType}
|
|
98488
|
+
|
|
98489
|
+
**Reasoning:** ${cvssResult.reasoning}
|
|
98490
|
+
` : "";
|
|
96857
98491
|
const markdown = `# ${finding.title}
|
|
96858
98492
|
|
|
96859
|
-
**Severity:** ${finding.severity}
|
|
98493
|
+
**Severity:** ${finding.severity} ${cvssLine}
|
|
96860
98494
|
**Target:** ${session.targets[0]}
|
|
96861
98495
|
**Endpoint:** ${finding.endpoint}
|
|
96862
98496
|
**Date:** ${timestamp}
|
|
@@ -96869,7 +98503,7 @@ ${finding.description}
|
|
|
96869
98503
|
## Impact
|
|
96870
98504
|
|
|
96871
98505
|
${finding.impact}
|
|
96872
|
-
|
|
98506
|
+
${cvssSection}
|
|
96873
98507
|
## Evidence
|
|
96874
98508
|
|
|
96875
98509
|
\`\`\`
|
|
@@ -96894,7 +98528,8 @@ ${finding.references}` : ""}
|
|
|
96894
98528
|
`;
|
|
96895
98529
|
writeFileSync4(mdPath, markdown);
|
|
96896
98530
|
const summaryPath = join5(session.rootPath, "findings-summary.md");
|
|
96897
|
-
const
|
|
98531
|
+
const cvssTag = cvssResult ? ` (CVSS ${cvssResult.score})` : "";
|
|
98532
|
+
const summaryEntry = `- [${finding.severity}]${cvssTag} ${finding.title} - \`findings/${mdFilename}\`
|
|
96898
98533
|
`;
|
|
96899
98534
|
try {
|
|
96900
98535
|
appendFileSync2(summaryPath, summaryEntry);
|
|
@@ -96936,6 +98571,7 @@ var documentVulnerabilityInputSchema;
|
|
|
96936
98571
|
var init_documentFinding = __esm(() => {
|
|
96937
98572
|
init_dist5();
|
|
96938
98573
|
init_zod();
|
|
98574
|
+
init_cvssScorer();
|
|
96939
98575
|
documentVulnerabilityInputSchema = exports_external.object({
|
|
96940
98576
|
title: exports_external.string().describe("Finding title"),
|
|
96941
98577
|
severity: exports_external.enum(["CRITICAL", "HIGH", "MEDIUM", "LOW"]),
|
|
@@ -99103,7 +100739,7 @@ For each app you identified, spawn a coding agent with a detailed objective. The
|
|
|
99103
100739
|
|
|
99104
100740
|
// src/core/agents/specialized/whiteboxAttackSurface/types.ts
|
|
99105
100741
|
var EndpointSchema, AppSchema, WhiteboxAttackSurfaceResultSchema;
|
|
99106
|
-
var
|
|
100742
|
+
var init_types5 = __esm(() => {
|
|
99107
100743
|
init_zod();
|
|
99108
100744
|
EndpointSchema = exports_external.object({
|
|
99109
100745
|
method: exports_external.string().describe("HTTP method (GET, POST, PUT, DELETE, etc.) or 'PAGE' for web pages"),
|
|
@@ -99165,7 +100801,7 @@ var init_agent2 = __esm(() => {
|
|
|
99165
100801
|
init_dist5();
|
|
99166
100802
|
init_dist5();
|
|
99167
100803
|
init_offensiveSecurityAgent();
|
|
99168
|
-
|
|
100804
|
+
init_types5();
|
|
99169
100805
|
WhiteboxAttackSurfaceAgent = class WhiteboxAttackSurfaceAgent extends OffensiveSecurityAgent {
|
|
99170
100806
|
constructor(opts) {
|
|
99171
100807
|
const {
|
|
@@ -99718,6 +101354,13 @@ var PentestResponseSchema, TargetedPentestAgent, PENTEST_SYSTEM_PROMPT = `You ar
|
|
|
99718
101354
|
|
|
99719
101355
|
You are given a specific target and specific objectives. Do NOT perform broad reconnaissance or service/endpoint discovery — that has already been done for you. Your job is to deeply test the provided target against the provided objectives.
|
|
99720
101356
|
|
|
101357
|
+
CRITICAL — Source Code Prohibition:
|
|
101358
|
+
- You are performing a BLACKBOX penetration test. You must NEVER read, view, access, or analyze source code under any circumstances.
|
|
101359
|
+
- Do NOT use execute_command to read files on the local filesystem (no cat, less, more, head, tail, find, ls on source directories, strings, xxd, or any other file-reading command targeting application source code).
|
|
101360
|
+
- Do NOT attempt to download, fetch, or retrieve source code from the target server (e.g. via .git exposure, backup files, directory traversal to read source, or source map files) for the purpose of analyzing application logic. If you discover such an exposure, document it as a finding but do NOT read or analyze the contents.
|
|
101361
|
+
- Do NOT reference, assume, or reason about internal implementation details. Treat the target as a completely opaque black box — you can only observe its external behavior through HTTP responses, browser rendering, and error messages.
|
|
101362
|
+
- Your testing must rely exclusively on external interaction: sending requests, observing responses, and analyzing observable behavior.
|
|
101363
|
+
|
|
99721
101364
|
Your methodology:
|
|
99722
101365
|
1. PLAN — Begin by stating the objectives you have been given and outlining 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.
|
|
99723
101366
|
2. VERIFY — Confirm the target endpoint exists and is reachable. Understand its basic behavior (response format, parameters, auth requirements).
|
|
@@ -138829,7 +140472,7 @@ var require_node3 = __commonJS((exports, module2) => {
|
|
|
138829
140472
|
var tty = __require("tty");
|
|
138830
140473
|
var util4 = __require("util");
|
|
138831
140474
|
exports.init = init2;
|
|
138832
|
-
exports.log =
|
|
140475
|
+
exports.log = log2;
|
|
138833
140476
|
exports.formatArgs = formatArgs;
|
|
138834
140477
|
exports.save = save;
|
|
138835
140478
|
exports.load = load;
|
|
@@ -138961,7 +140604,7 @@ var require_node3 = __commonJS((exports, module2) => {
|
|
|
138961
140604
|
}
|
|
138962
140605
|
return new Date().toISOString() + " ";
|
|
138963
140606
|
}
|
|
138964
|
-
function
|
|
140607
|
+
function log2(...args) {
|
|
138965
140608
|
return process.stderr.write(util4.formatWithOptions(exports.inspectOpts, ...args) + `
|
|
138966
140609
|
`);
|
|
138967
140610
|
}
|
|
@@ -147926,7 +149569,7 @@ var require_logging_utils = __commonJS((exports) => {
|
|
|
147926
149569
|
exports.getDebugBackend = getDebugBackend;
|
|
147927
149570
|
exports.getStructuredBackend = getStructuredBackend;
|
|
147928
149571
|
exports.setBackend = setBackend;
|
|
147929
|
-
exports.log =
|
|
149572
|
+
exports.log = log2;
|
|
147930
149573
|
var events_1 = __require("events");
|
|
147931
149574
|
var process3 = __importStar(__require("process"));
|
|
147932
149575
|
var util4 = __importStar(__require("util"));
|
|
@@ -147953,7 +149596,7 @@ var require_logging_utils = __commonJS((exports) => {
|
|
|
147953
149596
|
this.func.info = (...args) => this.invokeSeverity(LogSeverity.INFO, ...args);
|
|
147954
149597
|
this.func.warn = (...args) => this.invokeSeverity(LogSeverity.WARNING, ...args);
|
|
147955
149598
|
this.func.error = (...args) => this.invokeSeverity(LogSeverity.ERROR, ...args);
|
|
147956
|
-
this.func.sublog = (namespace2) =>
|
|
149599
|
+
this.func.sublog = (namespace2) => log2(namespace2, this.func);
|
|
147957
149600
|
}
|
|
147958
149601
|
invoke(fields, ...args) {
|
|
147959
149602
|
if (this.upstream) {
|
|
@@ -148114,7 +149757,7 @@ var require_logging_utils = __commonJS((exports) => {
|
|
|
148114
149757
|
cachedBackend = backend;
|
|
148115
149758
|
loggerCache.clear();
|
|
148116
149759
|
}
|
|
148117
|
-
function
|
|
149760
|
+
function log2(namespace, parent) {
|
|
148118
149761
|
if (!cachedBackend) {
|
|
148119
149762
|
const enablesFlag = process3.env[exports.env.nodeEnables];
|
|
148120
149763
|
if (!enablesFlag) {
|
|
@@ -148254,7 +149897,7 @@ var require_src6 = __commonJS((exports) => {
|
|
|
148254
149897
|
exports.HEADER_NAME = "Metadata-Flavor";
|
|
148255
149898
|
exports.HEADER_VALUE = "Google";
|
|
148256
149899
|
exports.HEADERS = Object.freeze({ [exports.HEADER_NAME]: exports.HEADER_VALUE });
|
|
148257
|
-
var
|
|
149900
|
+
var log2 = logger.log("gcp-metadata");
|
|
148258
149901
|
exports.METADATA_SERVER_DETECTION = Object.freeze({
|
|
148259
149902
|
"assume-present": "don't try to ping the metadata server, but assume it's present",
|
|
148260
149903
|
none: "don't try to ping the metadata server, but don't try to use it either",
|
|
@@ -148317,9 +149960,9 @@ var require_src6 = __commonJS((exports) => {
|
|
|
148317
149960
|
responseType: "text",
|
|
148318
149961
|
timeout: requestTimeout()
|
|
148319
149962
|
};
|
|
148320
|
-
|
|
149963
|
+
log2.info("instance request %j", req);
|
|
148321
149964
|
const res = await requestMethod(req);
|
|
148322
|
-
|
|
149965
|
+
log2.info("instance metadata is %s", res.data);
|
|
148323
149966
|
const metadataFlavor = res.headers.get(exports.HEADER_NAME);
|
|
148324
149967
|
if (metadataFlavor !== exports.HEADER_VALUE) {
|
|
148325
149968
|
throw new RangeError(`Invalid response from metadata service: incorrect ${exports.HEADER_NAME} header. Expected '${exports.HEADER_VALUE}', got ${metadataFlavor ? `'${metadataFlavor}'` : "no header"}`);
|
|
@@ -156447,7 +158090,7 @@ var require_http2 = __commonJS((exports) => {
|
|
|
156447
158090
|
var process3 = __require("process");
|
|
156448
158091
|
var util_1 = require_util7();
|
|
156449
158092
|
var { HTTP2_HEADER_CONTENT_ENCODING, HTTP2_HEADER_CONTENT_TYPE, HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, HTTP2_HEADER_STATUS } = http22.constants;
|
|
156450
|
-
var
|
|
158093
|
+
var DEBUG2 = !!process3.env.HTTP2_DEBUG;
|
|
156451
158094
|
exports.sessions = {};
|
|
156452
158095
|
async function request(config3) {
|
|
156453
158096
|
const opts = extend3(true, {}, config3);
|
|
@@ -156561,7 +158204,7 @@ var require_http2 = __commonJS((exports) => {
|
|
|
156561
158204
|
}
|
|
156562
158205
|
function _getClient(host) {
|
|
156563
158206
|
if (!exports.sessions[host]) {
|
|
156564
|
-
if (
|
|
158207
|
+
if (DEBUG2) {
|
|
156565
158208
|
console.log(`Creating client for ${host}`);
|
|
156566
158209
|
}
|
|
156567
158210
|
const session = http22.connect(`https://${host}`);
|
|
@@ -156574,7 +158217,7 @@ var require_http2 = __commonJS((exports) => {
|
|
|
156574
158217
|
});
|
|
156575
158218
|
exports.sessions[host] = { session };
|
|
156576
158219
|
} else {
|
|
156577
|
-
if (
|
|
158220
|
+
if (DEBUG2) {
|
|
156578
158221
|
console.log(`Used cached client for ${host}`);
|
|
156579
158222
|
}
|
|
156580
158223
|
}
|
|
@@ -156587,17 +158230,17 @@ var require_http2 = __commonJS((exports) => {
|
|
|
156587
158230
|
}
|
|
156588
158231
|
const { session } = sessionData;
|
|
156589
158232
|
delete exports.sessions[url2.host];
|
|
156590
|
-
if (
|
|
158233
|
+
if (DEBUG2) {
|
|
156591
158234
|
console.error(`Closing ${url2.host}`);
|
|
156592
158235
|
}
|
|
156593
158236
|
session.close(() => {
|
|
156594
|
-
if (
|
|
158237
|
+
if (DEBUG2) {
|
|
156595
158238
|
console.error(`Closed ${url2.host}`);
|
|
156596
158239
|
}
|
|
156597
158240
|
});
|
|
156598
158241
|
setTimeout(() => {
|
|
156599
158242
|
if (session && !session.destroyed) {
|
|
156600
|
-
if (
|
|
158243
|
+
if (DEBUG2) {
|
|
156601
158244
|
console.log(`Forcing close ${url2.host}`);
|
|
156602
158245
|
}
|
|
156603
158246
|
if (session) {
|
|
@@ -166108,11 +167751,11 @@ var require_tools = __commonJS((exports, module2) => {
|
|
|
166108
167751
|
}
|
|
166109
167752
|
}
|
|
166110
167753
|
}
|
|
166111
|
-
function buildFormatters(level, bindings,
|
|
167754
|
+
function buildFormatters(level, bindings, log2) {
|
|
166112
167755
|
return {
|
|
166113
167756
|
level,
|
|
166114
167757
|
bindings,
|
|
166115
|
-
log
|
|
167758
|
+
log: log2
|
|
166116
167759
|
};
|
|
166117
167760
|
}
|
|
166118
167761
|
function normalizeDestFileDescriptor(destination) {
|
|
@@ -166457,8 +168100,8 @@ var require_proto = __commonJS((exports, module2) => {
|
|
|
166457
168100
|
} else
|
|
166458
168101
|
instance[serializersSym] = serializers;
|
|
166459
168102
|
if (options.hasOwnProperty("formatters")) {
|
|
166460
|
-
const { level, bindings: chindings, log } = options.formatters;
|
|
166461
|
-
instance[formattersSym] = buildFormatters(level || formatters.level, chindings || resetChildingsFormatter,
|
|
168103
|
+
const { level, bindings: chindings, log: log2 } = options.formatters;
|
|
168104
|
+
instance[formattersSym] = buildFormatters(level || formatters.level, chindings || resetChildingsFormatter, log2 || formatters.log);
|
|
166462
168105
|
} else {
|
|
166463
168106
|
instance[formattersSym] = buildFormatters(formatters.level, resetChildingsFormatter, formatters.log);
|
|
166464
168107
|
}
|
|
@@ -209469,219 +211112,16 @@ var useTerminalDimensions = () => {
|
|
|
209469
211112
|
};
|
|
209470
211113
|
|
|
209471
211114
|
// src/tui/index.tsx
|
|
209472
|
-
var
|
|
211115
|
+
var import_react87 = __toESM(require_react(), 1);
|
|
209473
211116
|
|
|
209474
211117
|
// src/tui/components/footer.tsx
|
|
209475
211118
|
import os5 from "os";
|
|
209476
211119
|
|
|
209477
211120
|
// src/tui/context/agent.tsx
|
|
209478
211121
|
init_models();
|
|
211122
|
+
init_config();
|
|
209479
211123
|
var import_react11 = __toESM(require_react(), 1);
|
|
209480
211124
|
|
|
209481
|
-
// src/core/config/config.ts
|
|
209482
|
-
import os2 from "os";
|
|
209483
|
-
import path2 from "path";
|
|
209484
|
-
import fs2 from "fs/promises";
|
|
209485
|
-
// package.json
|
|
209486
|
-
var package_default2 = {
|
|
209487
|
-
name: "@pensar/apex",
|
|
209488
|
-
version: "0.0.77",
|
|
209489
|
-
description: "AI-powered penetration testing CLI tool with terminal UI",
|
|
209490
|
-
module: "src/tui/index.tsx",
|
|
209491
|
-
main: "build/index.js",
|
|
209492
|
-
type: "module",
|
|
209493
|
-
repository: {
|
|
209494
|
-
type: "git",
|
|
209495
|
-
url: "https://github.com/pensarai/apex.git"
|
|
209496
|
-
},
|
|
209497
|
-
bin: {
|
|
209498
|
-
pensar: "./bin/pensar.js"
|
|
209499
|
-
},
|
|
209500
|
-
files: [
|
|
209501
|
-
"build",
|
|
209502
|
-
"bin",
|
|
209503
|
-
"src/core/installation",
|
|
209504
|
-
"pensar.svg",
|
|
209505
|
-
"LICENSE"
|
|
209506
|
-
],
|
|
209507
|
-
scripts: {
|
|
209508
|
-
build: "bun build src/tui/index.tsx --outdir build --target node --format esm --external sharp",
|
|
209509
|
-
"generate:ascii": "bun run scripts/generate-ascii-art.ts",
|
|
209510
|
-
"generate:models": "bun run scripts/generate-models.ts",
|
|
209511
|
-
"build:binary": "bun run generate:ascii && bun build src/cli.ts --compile --outfile pensar",
|
|
209512
|
-
"build:binary:macos-arm64": "bun build src/cli.ts --compile --target=bun-darwin-arm64 --outfile dist/pensar-darwin-arm64",
|
|
209513
|
-
"build:binary:macos-x64": "bun build src/cli.ts --compile --target=bun-darwin-x64 --outfile dist/pensar-darwin-x64",
|
|
209514
|
-
"build:binary:linux-x64": "bun build src/cli.ts --compile --target=bun-linux-x64 --outfile dist/pensar-linux-x64",
|
|
209515
|
-
"build:binary:linux-arm64": "bun build src/cli.ts --compile --target=bun-linux-arm64 --outfile dist/pensar-linux-arm64",
|
|
209516
|
-
"build:binaries": "bun run generate:ascii && mkdir -p dist && bun run build:binary:macos-arm64 && bun run build:binary:macos-x64 && bun run build:binary:linux-x64 && bun run build:binary:linux-arm64",
|
|
209517
|
-
dev: "bun run scripts/watch.ts",
|
|
209518
|
-
"dev:debug": "SHOW_CONSOLE=true bun run scripts/watch.ts",
|
|
209519
|
-
start: "bun run src/tui/index.tsx",
|
|
209520
|
-
pensar: "node bin/pensar.js",
|
|
209521
|
-
tsc: "tsc --noEmit",
|
|
209522
|
-
"daytona-benchmark": "bun run scripts/daytona-benchmark.ts",
|
|
209523
|
-
"local-benchmark": "bun run scripts/local-benchmark.ts",
|
|
209524
|
-
test: "vitest run",
|
|
209525
|
-
"test:watch": "vitest",
|
|
209526
|
-
lint: "eslint src/",
|
|
209527
|
-
format: "prettier --write .",
|
|
209528
|
-
"format:check": "prettier --check .",
|
|
209529
|
-
prepublishOnly: "npm run build"
|
|
209530
|
-
},
|
|
209531
|
-
keywords: [
|
|
209532
|
-
"penetration-testing",
|
|
209533
|
-
"security",
|
|
209534
|
-
"pentesting",
|
|
209535
|
-
"ai",
|
|
209536
|
-
"cli",
|
|
209537
|
-
"terminal",
|
|
209538
|
-
"tui"
|
|
209539
|
-
],
|
|
209540
|
-
author: "Pensar",
|
|
209541
|
-
license: "MIT",
|
|
209542
|
-
engines: {
|
|
209543
|
-
node: ">=18.0.0",
|
|
209544
|
-
bun: ">=1.0.0"
|
|
209545
|
-
},
|
|
209546
|
-
devDependencies: {
|
|
209547
|
-
"@eslint/js": "^10.0.1",
|
|
209548
|
-
"@playwright/mcp": "^0.0.54",
|
|
209549
|
-
"@types/bun": "^1.3.0",
|
|
209550
|
-
"@types/mailparser": "^3.4.6",
|
|
209551
|
-
"@types/react": "^19.2.6",
|
|
209552
|
-
"@typescript-eslint/eslint-plugin": "^8.55.0",
|
|
209553
|
-
"@typescript-eslint/parser": "^8.55.0",
|
|
209554
|
-
dotenv: "^17.2.3",
|
|
209555
|
-
eslint: "^10.0.0",
|
|
209556
|
-
"eslint-config-prettier": "^10.1.8",
|
|
209557
|
-
"eslint-plugin-unused-imports": "^4.4.1",
|
|
209558
|
-
prettier: "^3.8.1",
|
|
209559
|
-
"typescript-eslint": "^8.55.0",
|
|
209560
|
-
vitest: "^2.1.8"
|
|
209561
|
-
},
|
|
209562
|
-
peerDependencies: {
|
|
209563
|
-
typescript: "^5.9.3"
|
|
209564
|
-
},
|
|
209565
|
-
dependencies: {
|
|
209566
|
-
"@ai-sdk/amazon-bedrock": "^4.0.69",
|
|
209567
|
-
"@ai-sdk/anthropic": "^3.0.50",
|
|
209568
|
-
"@ai-sdk/openai": "^3.0.37",
|
|
209569
|
-
"@daytonaio/sdk": "^0.112.1",
|
|
209570
|
-
"@googleapis/gmail": "^16.1.1",
|
|
209571
|
-
"@microsoft/microsoft-graph-client": "^3.0.7",
|
|
209572
|
-
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
209573
|
-
"@openrouter/ai-sdk-provider": "^2.2.3",
|
|
209574
|
-
"@opentui/core": "^0.1.80",
|
|
209575
|
-
"@opentui/react": "^0.1.80",
|
|
209576
|
-
ai: "^6.0.105",
|
|
209577
|
-
glob: "^13.0.0",
|
|
209578
|
-
"google-auth-library": "^10.6.1",
|
|
209579
|
-
ignore: "^7.0.5",
|
|
209580
|
-
imapflow: "^1.2.10",
|
|
209581
|
-
mailparser: "^3.9.3",
|
|
209582
|
-
marked: "^16.4.0",
|
|
209583
|
-
nanoid: "^5.1.6",
|
|
209584
|
-
"p-limit": "^7.2.0",
|
|
209585
|
-
react: "^19.2.0",
|
|
209586
|
-
sharp: "^0.34.4",
|
|
209587
|
-
yaml: "^2.8.2",
|
|
209588
|
-
zod: "^3.25.76"
|
|
209589
|
-
},
|
|
209590
|
-
packageManager: "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
209591
|
-
};
|
|
209592
|
-
|
|
209593
|
-
// src/core/installation/index.ts
|
|
209594
|
-
function getCurrentVersion() {
|
|
209595
|
-
return package_default2.version;
|
|
209596
|
-
}
|
|
209597
|
-
function isNewerVersion(current, latest) {
|
|
209598
|
-
const parse2 = (v2) => v2.split(".").map((n) => parseInt(n, 10) || 0);
|
|
209599
|
-
const c = parse2(current);
|
|
209600
|
-
const l = parse2(latest);
|
|
209601
|
-
for (let i = 0;i < Math.max(c.length, l.length); i++) {
|
|
209602
|
-
const cv = c[i] ?? 0;
|
|
209603
|
-
const lv = l[i] ?? 0;
|
|
209604
|
-
if (lv > cv)
|
|
209605
|
-
return true;
|
|
209606
|
-
if (lv < cv)
|
|
209607
|
-
return false;
|
|
209608
|
-
}
|
|
209609
|
-
return false;
|
|
209610
|
-
}
|
|
209611
|
-
async function getLatestVersion() {
|
|
209612
|
-
const res = await fetch("https://registry.npmjs.org/@pensar/apex/latest");
|
|
209613
|
-
if (!res.ok)
|
|
209614
|
-
throw new Error(`Failed to fetch latest version: ${res.statusText}`);
|
|
209615
|
-
const data = await res.json();
|
|
209616
|
-
return String(data.version);
|
|
209617
|
-
}
|
|
209618
|
-
async function checkForUpdate() {
|
|
209619
|
-
const currentVersion = getCurrentVersion();
|
|
209620
|
-
let latestVersion;
|
|
209621
|
-
try {
|
|
209622
|
-
latestVersion = await getLatestVersion();
|
|
209623
|
-
} catch {
|
|
209624
|
-
return {
|
|
209625
|
-
updateAvailable: false,
|
|
209626
|
-
currentVersion,
|
|
209627
|
-
latestVersion: currentVersion
|
|
209628
|
-
};
|
|
209629
|
-
}
|
|
209630
|
-
return {
|
|
209631
|
-
updateAvailable: isNewerVersion(currentVersion, latestVersion),
|
|
209632
|
-
currentVersion,
|
|
209633
|
-
latestVersion
|
|
209634
|
-
};
|
|
209635
|
-
}
|
|
209636
|
-
|
|
209637
|
-
// src/core/config/config.ts
|
|
209638
|
-
var DEFAULT_CONFIG = {
|
|
209639
|
-
responsibleUseAccepted: false
|
|
209640
|
-
};
|
|
209641
|
-
async function init() {
|
|
209642
|
-
const folder = path2.join(os2.homedir(), ".pensar");
|
|
209643
|
-
const file = path2.join(folder, "config.json");
|
|
209644
|
-
const dirExists = await fs2.access(folder).then(() => true).catch(() => false);
|
|
209645
|
-
if (!dirExists) {
|
|
209646
|
-
await fs2.mkdir(folder, { recursive: true });
|
|
209647
|
-
}
|
|
209648
|
-
const fileExists = await fs2.access(file).then(() => true).catch(() => false);
|
|
209649
|
-
if (!fileExists) {
|
|
209650
|
-
await fs2.writeFile(file, JSON.stringify(DEFAULT_CONFIG));
|
|
209651
|
-
}
|
|
209652
|
-
const version = getCurrentVersion();
|
|
209653
|
-
return { ...DEFAULT_CONFIG, version };
|
|
209654
|
-
}
|
|
209655
|
-
async function get() {
|
|
209656
|
-
const folder = path2.join(os2.homedir(), ".pensar");
|
|
209657
|
-
const file = path2.join(folder, "config.json");
|
|
209658
|
-
const exists = await fs2.access(file).then(() => true).catch(() => false);
|
|
209659
|
-
if (!exists) {
|
|
209660
|
-
return await init();
|
|
209661
|
-
}
|
|
209662
|
-
const config = await fs2.readFile(file, "utf8");
|
|
209663
|
-
const parsedConfig = JSON.parse(config);
|
|
209664
|
-
const version = getCurrentVersion();
|
|
209665
|
-
return {
|
|
209666
|
-
...parsedConfig,
|
|
209667
|
-
version,
|
|
209668
|
-
openAiAPIKey: process.env.OPENAI_API_KEY ?? parsedConfig.openAiAPIKey,
|
|
209669
|
-
anthropicAPIKey: process.env.ANTHROPIC_API_KEY ?? parsedConfig.anthropicAPIKey,
|
|
209670
|
-
openRouterAPIKey: process.env.OPENROUTER_API_KEY ?? parsedConfig.openRouterAPIKey,
|
|
209671
|
-
bedrockAPIKey: process.env.BEDROCK_API_KEY ?? parsedConfig.bedrockAPIKey,
|
|
209672
|
-
daytonaAPIKey: process.env.DAYTONA_API_KEY ?? parsedConfig.daytonaAPIKey,
|
|
209673
|
-
daytonaOrgId: process.env.DAYTONA_ORG_ID ?? parsedConfig.daytonaOrgId,
|
|
209674
|
-
runloopAPIKey: process.env.RUNLOOP_API_KEY ?? parsedConfig.runloopAPIKey
|
|
209675
|
-
};
|
|
209676
|
-
}
|
|
209677
|
-
async function update(config) {
|
|
209678
|
-
const currentConfig = await get();
|
|
209679
|
-
const newConfig = { ...currentConfig, ...config };
|
|
209680
|
-
const folder = path2.join(os2.homedir(), ".pensar");
|
|
209681
|
-
const file = path2.join(folder, "config.json");
|
|
209682
|
-
await fs2.writeFile(file, JSON.stringify(newConfig));
|
|
209683
|
-
}
|
|
209684
|
-
|
|
209685
211125
|
// src/core/providers/utils.ts
|
|
209686
211126
|
init_models();
|
|
209687
211127
|
|
|
@@ -209716,6 +211156,12 @@ var AVAILABLE_PROVIDERS = [
|
|
|
209716
211156
|
name: "Local LLM",
|
|
209717
211157
|
description: "OpenAI-compatible local model (vLLM, LM Studio, Ollama)",
|
|
209718
211158
|
requiresAPIKey: false
|
|
211159
|
+
},
|
|
211160
|
+
{
|
|
211161
|
+
id: "pensar",
|
|
211162
|
+
name: "Pensar",
|
|
211163
|
+
description: "Managed inference via Pensar Console (usage-based billing)",
|
|
211164
|
+
requiresAPIKey: true
|
|
209719
211165
|
}
|
|
209720
211166
|
];
|
|
209721
211167
|
|
|
@@ -209742,12 +211188,14 @@ function isProviderConfigured(providerId, config) {
|
|
|
209742
211188
|
return !!config.bedrockAPIKey;
|
|
209743
211189
|
case "local":
|
|
209744
211190
|
return !!(config.localModelUrl || config.localModelName || process.env.LOCAL_MODEL_URL);
|
|
211191
|
+
case "pensar":
|
|
211192
|
+
return !!(config.pensarAPIKey || config.accessToken);
|
|
209745
211193
|
default:
|
|
209746
211194
|
return false;
|
|
209747
211195
|
}
|
|
209748
211196
|
}
|
|
209749
211197
|
function hasAnyProviderConfigured(config) {
|
|
209750
|
-
return !!config.anthropicAPIKey || !!config.openAiAPIKey || !!config.openRouterAPIKey || !!config.bedrockAPIKey || !!config.localModelUrl || !!config.localModelName || !!process.env.LOCAL_MODEL_URL;
|
|
211198
|
+
return !!config.anthropicAPIKey || !!config.openAiAPIKey || !!config.openRouterAPIKey || !!config.bedrockAPIKey || !!config.localModelUrl || !!config.localModelName || !!process.env.LOCAL_MODEL_URL || !!config.pensarAPIKey || !!config.accessToken;
|
|
209751
211199
|
}
|
|
209752
211200
|
function getAvailableModels(config) {
|
|
209753
211201
|
const models = AVAILABLE_MODELS.filter((model) => {
|
|
@@ -209768,10 +211216,17 @@ var import_jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
|
|
|
209768
211216
|
|
|
209769
211217
|
// src/tui/context/agent.tsx
|
|
209770
211218
|
var PREFERRED_DEFAULTS = {
|
|
211219
|
+
pensar: "pensar:anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
209771
211220
|
anthropic: "claude-haiku-4-5",
|
|
209772
211221
|
openai: "gpt-4o-mini"
|
|
209773
211222
|
};
|
|
209774
|
-
var PROVIDER_PREFERENCE = [
|
|
211223
|
+
var PROVIDER_PREFERENCE = [
|
|
211224
|
+
"pensar",
|
|
211225
|
+
"anthropic",
|
|
211226
|
+
"openai",
|
|
211227
|
+
"openrouter",
|
|
211228
|
+
"bedrock"
|
|
211229
|
+
];
|
|
209775
211230
|
var AgentContext = import_react11.createContext(null);
|
|
209776
211231
|
function useAgent() {
|
|
209777
211232
|
const context = import_react11.useContext(AgentContext);
|
|
@@ -210091,6 +211546,9 @@ function create(prefix, descending2, timestamp) {
|
|
|
210091
211546
|
return prefixes[prefix] + "_" + timeBytes.toString("hex") + randomBase62(LENGTH - 12);
|
|
210092
211547
|
}
|
|
210093
211548
|
|
|
211549
|
+
// src/core/session/index.ts
|
|
211550
|
+
init_installation();
|
|
211551
|
+
|
|
210094
211552
|
// src/core/storage/index.ts
|
|
210095
211553
|
init_zod();
|
|
210096
211554
|
import os3 from "os";
|
|
@@ -210509,8 +211967,6 @@ var SessionConfigObject = zod_default.object({
|
|
|
210509
211967
|
authenticationInstructions: zod_default.string().optional(),
|
|
210510
211968
|
requestsPerSecond: zod_default.number().optional(),
|
|
210511
211969
|
operatorSettings: OperatorSettingsObject.optional(),
|
|
210512
|
-
enableCvssScoring: zod_default.boolean().optional(),
|
|
210513
|
-
cvssModel: zod_default.string().optional(),
|
|
210514
211970
|
toolsetState: ToolsetStateSchema.optional(),
|
|
210515
211971
|
enumerateSubdomains: zod_default.boolean().optional(),
|
|
210516
211972
|
cwd: zod_default.string().optional(),
|
|
@@ -211356,14 +212812,8 @@ async function createSwarmSessionFromFlags(flags) {
|
|
|
211356
212812
|
return session;
|
|
211357
212813
|
}
|
|
211358
212814
|
|
|
211359
|
-
// src/core/config/index.ts
|
|
211360
|
-
var config = {
|
|
211361
|
-
get,
|
|
211362
|
-
init,
|
|
211363
|
-
update
|
|
211364
|
-
};
|
|
211365
|
-
|
|
211366
212815
|
// src/tui/command-registry.ts
|
|
212816
|
+
init_config2();
|
|
211367
212817
|
var commands = [
|
|
211368
212818
|
{
|
|
211369
212819
|
name: "pentest",
|
|
@@ -211648,6 +213098,29 @@ var commands = [
|
|
|
211648
213098
|
handler: async () => {
|
|
211649
213099
|
process.kill(process.pid, "SIGINT");
|
|
211650
213100
|
}
|
|
213101
|
+
},
|
|
213102
|
+
{
|
|
213103
|
+
name: "auth",
|
|
213104
|
+
description: "Connect to Pensar Console for managed inference",
|
|
213105
|
+
category: "General",
|
|
213106
|
+
handler: async (args, ctx3) => {
|
|
213107
|
+
ctx3.navigate({
|
|
213108
|
+
type: "base",
|
|
213109
|
+
path: "auth"
|
|
213110
|
+
});
|
|
213111
|
+
}
|
|
213112
|
+
},
|
|
213113
|
+
{
|
|
213114
|
+
name: "credits",
|
|
213115
|
+
aliases: ["buy"],
|
|
213116
|
+
description: "Buy credits / check balance",
|
|
213117
|
+
category: "General",
|
|
213118
|
+
handler: async (args, ctx3) => {
|
|
213119
|
+
ctx3.navigate({
|
|
213120
|
+
type: "base",
|
|
213121
|
+
path: "credits"
|
|
213122
|
+
});
|
|
213123
|
+
}
|
|
211651
213124
|
}
|
|
211652
213125
|
];
|
|
211653
213126
|
var commandRegistry = commands.map((config2) => (ctx3) => ({
|
|
@@ -212325,6 +213798,7 @@ function AlertDialog({
|
|
|
212325
213798
|
}
|
|
212326
213799
|
|
|
212327
213800
|
// src/tui/components/commands/config-dialog.tsx
|
|
213801
|
+
init_config2();
|
|
212328
213802
|
function ConfigDialog() {
|
|
212329
213803
|
const route = useRoute();
|
|
212330
213804
|
const [open, setOpen] = import_react25.useState(false);
|
|
@@ -212408,6 +213882,7 @@ function ConfigForm({ appConfig }) {
|
|
|
212408
213882
|
var import_react37 = __toESM(require_react(), 1);
|
|
212409
213883
|
|
|
212410
213884
|
// src/tui/context/config.tsx
|
|
213885
|
+
init_config2();
|
|
212411
213886
|
var import_react26 = __toESM(require_react(), 1);
|
|
212412
213887
|
var ctx3 = import_react26.createContext(null);
|
|
212413
213888
|
function ConfigProvider({ children, config: config2 }) {
|
|
@@ -213006,9 +214481,17 @@ var providerNames = {
|
|
|
213006
214481
|
openai: "OpenAI",
|
|
213007
214482
|
openrouter: "OpenRouter",
|
|
213008
214483
|
bedrock: "Bedrock",
|
|
214484
|
+
pensar: "Pensar",
|
|
213009
214485
|
local: "Local LLM"
|
|
213010
214486
|
};
|
|
213011
|
-
var providerOrder = [
|
|
214487
|
+
var providerOrder = [
|
|
214488
|
+
"pensar",
|
|
214489
|
+
"anthropic",
|
|
214490
|
+
"openai",
|
|
214491
|
+
"openrouter",
|
|
214492
|
+
"bedrock",
|
|
214493
|
+
"local"
|
|
214494
|
+
];
|
|
213012
214495
|
function ModelPicker({
|
|
213013
214496
|
config: config2,
|
|
213014
214497
|
selectedModel,
|
|
@@ -216338,6 +217821,7 @@ function SessionsBrowser() {
|
|
|
216338
217821
|
|
|
216339
217822
|
// src/tui/components/commands/provider-manager.tsx
|
|
216340
217823
|
var import_react50 = __toESM(require_react(), 1);
|
|
217824
|
+
init_config2();
|
|
216341
217825
|
// src/tui/components/commands/provider-selection.tsx
|
|
216342
217826
|
var import_react47 = __toESM(require_react(), 1);
|
|
216343
217827
|
function ProviderSelection({
|
|
@@ -216525,6 +218009,8 @@ function APIKeyInput({
|
|
|
216525
218009
|
return "Get your API key from openrouter.ai/keys";
|
|
216526
218010
|
case "bedrock":
|
|
216527
218011
|
return "Enter your AWS Access Key ID (configure region separately) or AWS Bedrock API Key";
|
|
218012
|
+
case "pensar":
|
|
218013
|
+
return "Get your API key from console.pensar.dev/connect (or run /auth)";
|
|
216528
218014
|
default:
|
|
216529
218015
|
return "Enter your API key";
|
|
216530
218016
|
}
|
|
@@ -216678,6 +218164,9 @@ function ProviderManager() {
|
|
|
216678
218164
|
}, undefined, true, undefined, this);
|
|
216679
218165
|
}
|
|
216680
218166
|
|
|
218167
|
+
// src/tui/index.tsx
|
|
218168
|
+
init_config2();
|
|
218169
|
+
|
|
216681
218170
|
// src/tui/components/switch.tsx
|
|
216682
218171
|
var import_react51 = __toESM(require_react(), 1);
|
|
216683
218172
|
var CaseSymbol = Symbol("Switch.Case");
|
|
@@ -217015,6 +218504,9 @@ function ErrorBoundary2({ children }) {
|
|
|
217015
218504
|
return import_react55.default.createElement(ErrorBoundaryInner, { onError: handleError }, children);
|
|
217016
218505
|
}
|
|
217017
218506
|
|
|
218507
|
+
// src/tui/index.tsx
|
|
218508
|
+
init_installation();
|
|
218509
|
+
|
|
217018
218510
|
// src/tui/keybindings-registry.ts
|
|
217019
218511
|
var keybindings = [
|
|
217020
218512
|
{
|
|
@@ -217582,11 +219074,946 @@ function ModelsDisplay() {
|
|
|
217582
219074
|
}, undefined, true, undefined, this);
|
|
217583
219075
|
}
|
|
217584
219076
|
|
|
219077
|
+
// src/tui/components/commands/auth-flow.tsx
|
|
219078
|
+
var import_react60 = __toESM(require_react(), 1);
|
|
219079
|
+
init_config2();
|
|
219080
|
+
function AuthFlow() {
|
|
219081
|
+
const route = useRoute();
|
|
219082
|
+
const appConfig = useConfig();
|
|
219083
|
+
const isConnected = !!(appConfig.data.accessToken || appConfig.data.pensarAPIKey);
|
|
219084
|
+
const [step, setStep] = import_react60.useState(isConnected ? "success" : "start");
|
|
219085
|
+
const [error, setError] = import_react60.useState(null);
|
|
219086
|
+
const [authMode, setAuthMode] = import_react60.useState(null);
|
|
219087
|
+
const [deviceInfo, setDeviceInfo] = import_react60.useState(null);
|
|
219088
|
+
const [legacyDeviceInfo, setLegacyDeviceInfo] = import_react60.useState(null);
|
|
219089
|
+
const [workspaces, setWorkspaces] = import_react60.useState([]);
|
|
219090
|
+
const [selectedWorkspace, setSelectedWorkspace] = import_react60.useState(null);
|
|
219091
|
+
const [selectedIndex, setSelectedIndex] = import_react60.useState(0);
|
|
219092
|
+
const [billingUrl, setBillingUrl] = import_react60.useState(null);
|
|
219093
|
+
const [balance, setBalance] = import_react60.useState(null);
|
|
219094
|
+
const pollingRef = import_react60.useRef(null);
|
|
219095
|
+
const cancelledRef = import_react60.useRef(false);
|
|
219096
|
+
const connectedWorkspace = appConfig.data.workspaceSlug ? { name: appConfig.data.workspaceSlug, slug: appConfig.data.workspaceSlug } : null;
|
|
219097
|
+
const goHome = () => {
|
|
219098
|
+
route.navigate({ type: "base", path: "home" });
|
|
219099
|
+
};
|
|
219100
|
+
const cleanup = () => {
|
|
219101
|
+
cancelledRef.current = true;
|
|
219102
|
+
if (pollingRef.current) {
|
|
219103
|
+
clearTimeout(pollingRef.current);
|
|
219104
|
+
pollingRef.current = null;
|
|
219105
|
+
}
|
|
219106
|
+
};
|
|
219107
|
+
import_react60.useEffect(() => {
|
|
219108
|
+
return cleanup;
|
|
219109
|
+
}, []);
|
|
219110
|
+
const openUrl = (url) => {
|
|
219111
|
+
try {
|
|
219112
|
+
const platform = process.platform;
|
|
219113
|
+
if (platform === "darwin") {
|
|
219114
|
+
Bun.spawn(["open", url]);
|
|
219115
|
+
} else if (platform === "win32") {
|
|
219116
|
+
Bun.spawn(["cmd", "/c", "start", url]);
|
|
219117
|
+
} else {
|
|
219118
|
+
Bun.spawn(["xdg-open", url]);
|
|
219119
|
+
}
|
|
219120
|
+
} catch {}
|
|
219121
|
+
};
|
|
219122
|
+
const startDeviceFlow = async () => {
|
|
219123
|
+
setStep("requesting");
|
|
219124
|
+
setError(null);
|
|
219125
|
+
cancelledRef.current = false;
|
|
219126
|
+
const apiUrl = getPensarApiUrl(appConfig.data);
|
|
219127
|
+
try {
|
|
219128
|
+
const configResponse = await fetch(`${apiUrl}/api/cli/config`);
|
|
219129
|
+
if (configResponse.ok) {
|
|
219130
|
+
const cliConfig = await configResponse.json();
|
|
219131
|
+
const response = await fetch("https://api.workos.com/user_management/authorize/device", {
|
|
219132
|
+
method: "POST",
|
|
219133
|
+
headers: { "Content-Type": "application/json" },
|
|
219134
|
+
body: JSON.stringify({ client_id: cliConfig.workosClientId })
|
|
219135
|
+
});
|
|
219136
|
+
if (response.ok) {
|
|
219137
|
+
const data = await response.json();
|
|
219138
|
+
setAuthMode("workos");
|
|
219139
|
+
setDeviceInfo(data);
|
|
219140
|
+
openUrl(data.verification_uri_complete);
|
|
219141
|
+
setStep("polling");
|
|
219142
|
+
pollForToken(apiUrl, cliConfig.workosClientId, data.device_code, data.interval, data.expires_in);
|
|
219143
|
+
return;
|
|
219144
|
+
}
|
|
219145
|
+
}
|
|
219146
|
+
} catch {}
|
|
219147
|
+
try {
|
|
219148
|
+
const response = await fetch(`${apiUrl}/auth/device/code`, {
|
|
219149
|
+
method: "POST",
|
|
219150
|
+
headers: { "Content-Type": "application/json" }
|
|
219151
|
+
});
|
|
219152
|
+
if (!response.ok) {
|
|
219153
|
+
throw new Error("Failed to start device authorization");
|
|
219154
|
+
}
|
|
219155
|
+
const data = await response.json();
|
|
219156
|
+
setAuthMode("legacy");
|
|
219157
|
+
setLegacyDeviceInfo(data);
|
|
219158
|
+
openUrl(data.verificationUriComplete);
|
|
219159
|
+
setStep("polling");
|
|
219160
|
+
pollForLegacyToken(apiUrl, data.deviceCode, data.interval, data.expiresIn);
|
|
219161
|
+
} catch (err) {
|
|
219162
|
+
setError(err instanceof Error ? err.message : "Failed to start authorization");
|
|
219163
|
+
setStep("error");
|
|
219164
|
+
}
|
|
219165
|
+
};
|
|
219166
|
+
const pollForToken = (apiUrl, clientId, deviceCode, interval, expiresIn) => {
|
|
219167
|
+
const deadline = Date.now() + expiresIn * 1000;
|
|
219168
|
+
const poll = async () => {
|
|
219169
|
+
if (cancelledRef.current)
|
|
219170
|
+
return;
|
|
219171
|
+
if (Date.now() > deadline) {
|
|
219172
|
+
setError("Authorization timed out. Please try again.");
|
|
219173
|
+
setStep("error");
|
|
219174
|
+
return;
|
|
219175
|
+
}
|
|
219176
|
+
try {
|
|
219177
|
+
const response = await fetch("https://api.workos.com/user_management/authenticate", {
|
|
219178
|
+
method: "POST",
|
|
219179
|
+
headers: { "Content-Type": "application/json" },
|
|
219180
|
+
body: JSON.stringify({
|
|
219181
|
+
client_id: clientId,
|
|
219182
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
219183
|
+
device_code: deviceCode
|
|
219184
|
+
})
|
|
219185
|
+
});
|
|
219186
|
+
if (cancelledRef.current)
|
|
219187
|
+
return;
|
|
219188
|
+
if (response.status === 400) {
|
|
219189
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219190
|
+
return;
|
|
219191
|
+
}
|
|
219192
|
+
if (!response.ok) {
|
|
219193
|
+
throw new Error("Authentication failed");
|
|
219194
|
+
}
|
|
219195
|
+
const data = await response.json();
|
|
219196
|
+
await config.update({
|
|
219197
|
+
accessToken: data.access_token,
|
|
219198
|
+
refreshToken: data.refresh_token
|
|
219199
|
+
});
|
|
219200
|
+
await appConfig.reload();
|
|
219201
|
+
await fetchWorkspaces(apiUrl, data.access_token);
|
|
219202
|
+
} catch (err) {
|
|
219203
|
+
if (cancelledRef.current)
|
|
219204
|
+
return;
|
|
219205
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219206
|
+
}
|
|
219207
|
+
};
|
|
219208
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219209
|
+
};
|
|
219210
|
+
const pollForLegacyToken = (apiUrl, deviceCode, interval, expiresIn) => {
|
|
219211
|
+
const deadline = Date.now() + expiresIn * 1000;
|
|
219212
|
+
const poll = async () => {
|
|
219213
|
+
if (cancelledRef.current)
|
|
219214
|
+
return;
|
|
219215
|
+
if (Date.now() > deadline) {
|
|
219216
|
+
setError("Authorization timed out. Please try again.");
|
|
219217
|
+
setStep("error");
|
|
219218
|
+
return;
|
|
219219
|
+
}
|
|
219220
|
+
try {
|
|
219221
|
+
const response = await fetch(`${apiUrl}/auth/device/token`, {
|
|
219222
|
+
method: "POST",
|
|
219223
|
+
headers: { "Content-Type": "application/json" },
|
|
219224
|
+
body: JSON.stringify({ deviceCode })
|
|
219225
|
+
});
|
|
219226
|
+
if (!response.ok) {
|
|
219227
|
+
throw new Error("Failed to check authorization status");
|
|
219228
|
+
}
|
|
219229
|
+
const data = await response.json();
|
|
219230
|
+
if (cancelledRef.current)
|
|
219231
|
+
return;
|
|
219232
|
+
if (data.status === "complete" && data.apiKey) {
|
|
219233
|
+
await config.update({ pensarAPIKey: data.apiKey });
|
|
219234
|
+
if (data.workspace) {
|
|
219235
|
+
await config.update({
|
|
219236
|
+
workspaceId: data.workspace.id,
|
|
219237
|
+
workspaceSlug: data.workspace.slug
|
|
219238
|
+
});
|
|
219239
|
+
}
|
|
219240
|
+
appConfig.reload();
|
|
219241
|
+
setSelectedWorkspace(data.workspace ? {
|
|
219242
|
+
...data.workspace,
|
|
219243
|
+
balance: data.credits?.balance ?? 0,
|
|
219244
|
+
hasPaymentMethod: true
|
|
219245
|
+
} : null);
|
|
219246
|
+
setBalance(data.credits?.balance ?? null);
|
|
219247
|
+
setStep("success");
|
|
219248
|
+
return;
|
|
219249
|
+
}
|
|
219250
|
+
if (data.status === "expired") {
|
|
219251
|
+
setError("Authorization expired. Please try again.");
|
|
219252
|
+
setStep("error");
|
|
219253
|
+
return;
|
|
219254
|
+
}
|
|
219255
|
+
if (data.status === "not_found") {
|
|
219256
|
+
setError("Invalid authorization session. Please try again.");
|
|
219257
|
+
setStep("error");
|
|
219258
|
+
return;
|
|
219259
|
+
}
|
|
219260
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219261
|
+
} catch (err) {
|
|
219262
|
+
if (cancelledRef.current)
|
|
219263
|
+
return;
|
|
219264
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219265
|
+
}
|
|
219266
|
+
};
|
|
219267
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219268
|
+
};
|
|
219269
|
+
const fetchWorkspaces = async (apiUrl, accessToken) => {
|
|
219270
|
+
try {
|
|
219271
|
+
const response = await fetch(`${apiUrl}/api/cli/workspaces`, {
|
|
219272
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
219273
|
+
});
|
|
219274
|
+
if (!response.ok) {
|
|
219275
|
+
throw new Error("Failed to fetch workspaces");
|
|
219276
|
+
}
|
|
219277
|
+
const data = await response.json();
|
|
219278
|
+
if (data.workspaces.length === 0) {
|
|
219279
|
+
setError("No workspaces found. Create one at console.pensar.dev");
|
|
219280
|
+
setStep("error");
|
|
219281
|
+
return;
|
|
219282
|
+
}
|
|
219283
|
+
if (data.workspaces.length === 1) {
|
|
219284
|
+
await selectWorkspace(apiUrl, accessToken, data.workspaces[0]);
|
|
219285
|
+
return;
|
|
219286
|
+
}
|
|
219287
|
+
setWorkspaces(data.workspaces);
|
|
219288
|
+
setSelectedIndex(0);
|
|
219289
|
+
setStep("select-workspace");
|
|
219290
|
+
} catch (err) {
|
|
219291
|
+
setError(err instanceof Error ? err.message : "Failed to fetch workspaces");
|
|
219292
|
+
setStep("error");
|
|
219293
|
+
}
|
|
219294
|
+
};
|
|
219295
|
+
const selectWorkspace = async (apiUrl, accessToken, workspace) => {
|
|
219296
|
+
setSelectedWorkspace(workspace);
|
|
219297
|
+
setStep("checking-billing");
|
|
219298
|
+
try {
|
|
219299
|
+
const response = await fetch(`${apiUrl}/api/cli/select-workspace`, {
|
|
219300
|
+
method: "POST",
|
|
219301
|
+
headers: {
|
|
219302
|
+
"Content-Type": "application/json",
|
|
219303
|
+
Authorization: `Bearer ${accessToken}`
|
|
219304
|
+
},
|
|
219305
|
+
body: JSON.stringify({ workspaceId: workspace.id })
|
|
219306
|
+
});
|
|
219307
|
+
if (!response.ok) {
|
|
219308
|
+
throw new Error("Failed to select workspace");
|
|
219309
|
+
}
|
|
219310
|
+
const data = await response.json();
|
|
219311
|
+
await config.update({
|
|
219312
|
+
workspaceId: workspace.id,
|
|
219313
|
+
workspaceSlug: workspace.slug
|
|
219314
|
+
});
|
|
219315
|
+
appConfig.reload();
|
|
219316
|
+
setBalance(data.billing.balance);
|
|
219317
|
+
if (!data.confirmed && data.billingUrl) {
|
|
219318
|
+
setBillingUrl(data.billingUrl);
|
|
219319
|
+
}
|
|
219320
|
+
setStep("success");
|
|
219321
|
+
} catch (err) {
|
|
219322
|
+
setError(err instanceof Error ? err.message : "Failed to select workspace");
|
|
219323
|
+
setStep("error");
|
|
219324
|
+
}
|
|
219325
|
+
};
|
|
219326
|
+
const handleDisconnect = async () => {
|
|
219327
|
+
await config.update({
|
|
219328
|
+
pensarAPIKey: null,
|
|
219329
|
+
accessToken: null,
|
|
219330
|
+
refreshToken: null,
|
|
219331
|
+
workspaceId: null,
|
|
219332
|
+
workspaceSlug: null
|
|
219333
|
+
});
|
|
219334
|
+
appConfig.reload();
|
|
219335
|
+
setAuthMode(null);
|
|
219336
|
+
setSelectedWorkspace(null);
|
|
219337
|
+
setBalance(null);
|
|
219338
|
+
setBillingUrl(null);
|
|
219339
|
+
setDeviceInfo(null);
|
|
219340
|
+
setLegacyDeviceInfo(null);
|
|
219341
|
+
setStep("start");
|
|
219342
|
+
};
|
|
219343
|
+
const hasLowBalance = balance !== null && balance < 1;
|
|
219344
|
+
const effectiveBillingUrl = billingUrl || (selectedWorkspace?.slug ? `${getPensarConsoleUrl()}/${selectedWorkspace.slug}/settings/billing` : connectedWorkspace?.slug ? `${getPensarConsoleUrl()}/${connectedWorkspace.slug}/settings/billing` : `${getPensarConsoleUrl()}/credits`);
|
|
219345
|
+
const openBillingPage = () => {
|
|
219346
|
+
openUrl(effectiveBillingUrl);
|
|
219347
|
+
goHome();
|
|
219348
|
+
};
|
|
219349
|
+
useKeyboard((key) => {
|
|
219350
|
+
if (key.name === "escape") {
|
|
219351
|
+
cleanup();
|
|
219352
|
+
goHome();
|
|
219353
|
+
return;
|
|
219354
|
+
}
|
|
219355
|
+
if (step === "start") {
|
|
219356
|
+
if (key.name === "return") {
|
|
219357
|
+
startDeviceFlow();
|
|
219358
|
+
}
|
|
219359
|
+
}
|
|
219360
|
+
if (step === "select-workspace") {
|
|
219361
|
+
if (key.name === "up" && selectedIndex > 0) {
|
|
219362
|
+
setSelectedIndex((i) => i - 1);
|
|
219363
|
+
}
|
|
219364
|
+
if (key.name === "down" && selectedIndex < workspaces.length - 1) {
|
|
219365
|
+
setSelectedIndex((i) => i + 1);
|
|
219366
|
+
}
|
|
219367
|
+
if (key.name === "return" && workspaces[selectedIndex]) {
|
|
219368
|
+
const currentConfig = appConfig.data;
|
|
219369
|
+
const apiUrl = getPensarApiUrl(currentConfig);
|
|
219370
|
+
const accessToken = currentConfig.accessToken;
|
|
219371
|
+
selectWorkspace(apiUrl, accessToken, workspaces[selectedIndex]);
|
|
219372
|
+
}
|
|
219373
|
+
}
|
|
219374
|
+
if (step === "error") {
|
|
219375
|
+
if (key.name === "return") {
|
|
219376
|
+
startDeviceFlow();
|
|
219377
|
+
}
|
|
219378
|
+
}
|
|
219379
|
+
if (step === "success") {
|
|
219380
|
+
if (key.name === "return") {
|
|
219381
|
+
if (hasLowBalance || billingUrl) {
|
|
219382
|
+
openBillingPage();
|
|
219383
|
+
} else {
|
|
219384
|
+
goHome();
|
|
219385
|
+
}
|
|
219386
|
+
}
|
|
219387
|
+
if (key.raw === "d" || key.raw === "D") {
|
|
219388
|
+
handleDisconnect();
|
|
219389
|
+
}
|
|
219390
|
+
}
|
|
219391
|
+
});
|
|
219392
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219393
|
+
flexDirection: "column",
|
|
219394
|
+
width: "100%",
|
|
219395
|
+
maxWidth: 80,
|
|
219396
|
+
alignItems: "flex-start",
|
|
219397
|
+
padding: 1,
|
|
219398
|
+
children: [
|
|
219399
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219400
|
+
marginBottom: 1,
|
|
219401
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219402
|
+
fg: "green",
|
|
219403
|
+
children: "Pensar Console — Managed Inference"
|
|
219404
|
+
}, undefined, false, undefined, this)
|
|
219405
|
+
}, undefined, false, undefined, this),
|
|
219406
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219407
|
+
marginBottom: 1,
|
|
219408
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219409
|
+
fg: "gray",
|
|
219410
|
+
children: [
|
|
219411
|
+
"Connect to Pensar Console for usage-based AI inference.",
|
|
219412
|
+
`
|
|
219413
|
+
`,
|
|
219414
|
+
"No API keys needed — just a Pensar account with credits."
|
|
219415
|
+
]
|
|
219416
|
+
}, undefined, true, undefined, this)
|
|
219417
|
+
}, undefined, false, undefined, this),
|
|
219418
|
+
step === "start" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219419
|
+
flexDirection: "column",
|
|
219420
|
+
gap: 1,
|
|
219421
|
+
children: [
|
|
219422
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219423
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219424
|
+
fg: "white",
|
|
219425
|
+
children: [
|
|
219426
|
+
"Press ",
|
|
219427
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219428
|
+
fg: "green",
|
|
219429
|
+
children: "[ENTER]"
|
|
219430
|
+
}, undefined, false, undefined, this),
|
|
219431
|
+
" to authorize via your browser."
|
|
219432
|
+
]
|
|
219433
|
+
}, undefined, true, undefined, this)
|
|
219434
|
+
}, undefined, false, undefined, this),
|
|
219435
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219436
|
+
marginTop: 1,
|
|
219437
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219438
|
+
fg: "gray",
|
|
219439
|
+
children: [
|
|
219440
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219441
|
+
fg: "green",
|
|
219442
|
+
children: "[ENTER]"
|
|
219443
|
+
}, undefined, false, undefined, this),
|
|
219444
|
+
" Connect ·",
|
|
219445
|
+
" ",
|
|
219446
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219447
|
+
fg: "green",
|
|
219448
|
+
children: "[ESC]"
|
|
219449
|
+
}, undefined, false, undefined, this),
|
|
219450
|
+
" Cancel"
|
|
219451
|
+
]
|
|
219452
|
+
}, undefined, true, undefined, this)
|
|
219453
|
+
}, undefined, false, undefined, this)
|
|
219454
|
+
]
|
|
219455
|
+
}, undefined, true, undefined, this),
|
|
219456
|
+
step === "requesting" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219457
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219458
|
+
fg: "yellow",
|
|
219459
|
+
children: "Starting authorization..."
|
|
219460
|
+
}, undefined, false, undefined, this)
|
|
219461
|
+
}, undefined, false, undefined, this),
|
|
219462
|
+
step === "polling" && (deviceInfo || legacyDeviceInfo) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219463
|
+
flexDirection: "column",
|
|
219464
|
+
gap: 1,
|
|
219465
|
+
children: [
|
|
219466
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219467
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219468
|
+
fg: "yellow",
|
|
219469
|
+
children: "Waiting for browser authorization..."
|
|
219470
|
+
}, undefined, false, undefined, this)
|
|
219471
|
+
}, undefined, false, undefined, this),
|
|
219472
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219473
|
+
marginTop: 1,
|
|
219474
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219475
|
+
fg: "white",
|
|
219476
|
+
children: [
|
|
219477
|
+
"Your code:",
|
|
219478
|
+
" ",
|
|
219479
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219480
|
+
fg: "green",
|
|
219481
|
+
children: deviceInfo?.user_code || legacyDeviceInfo?.userCode
|
|
219482
|
+
}, undefined, false, undefined, this)
|
|
219483
|
+
]
|
|
219484
|
+
}, undefined, true, undefined, this)
|
|
219485
|
+
}, undefined, false, undefined, this),
|
|
219486
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219487
|
+
marginTop: 1,
|
|
219488
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219489
|
+
fg: "gray",
|
|
219490
|
+
children: [
|
|
219491
|
+
"If the browser didn't open, visit:",
|
|
219492
|
+
`
|
|
219493
|
+
`,
|
|
219494
|
+
deviceInfo?.verification_uri_complete || legacyDeviceInfo?.verificationUriComplete
|
|
219495
|
+
]
|
|
219496
|
+
}, undefined, true, undefined, this)
|
|
219497
|
+
}, undefined, false, undefined, this),
|
|
219498
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219499
|
+
marginTop: 1,
|
|
219500
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219501
|
+
fg: "gray",
|
|
219502
|
+
children: [
|
|
219503
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219504
|
+
fg: "green",
|
|
219505
|
+
children: "[ESC]"
|
|
219506
|
+
}, undefined, false, undefined, this),
|
|
219507
|
+
" Cancel"
|
|
219508
|
+
]
|
|
219509
|
+
}, undefined, true, undefined, this)
|
|
219510
|
+
}, undefined, false, undefined, this)
|
|
219511
|
+
]
|
|
219512
|
+
}, undefined, true, undefined, this),
|
|
219513
|
+
step === "select-workspace" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219514
|
+
flexDirection: "column",
|
|
219515
|
+
gap: 1,
|
|
219516
|
+
children: [
|
|
219517
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219518
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219519
|
+
fg: "white",
|
|
219520
|
+
children: "Select a workspace:"
|
|
219521
|
+
}, undefined, false, undefined, this)
|
|
219522
|
+
}, undefined, false, undefined, this),
|
|
219523
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219524
|
+
flexDirection: "column",
|
|
219525
|
+
marginTop: 1,
|
|
219526
|
+
children: workspaces.map((ws, i) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219527
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219528
|
+
fg: i === selectedIndex ? "green" : "gray",
|
|
219529
|
+
children: [
|
|
219530
|
+
i === selectedIndex ? "▸ " : " ",
|
|
219531
|
+
ws.name,
|
|
219532
|
+
" ",
|
|
219533
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219534
|
+
fg: "gray",
|
|
219535
|
+
children: [
|
|
219536
|
+
"(",
|
|
219537
|
+
ws.slug,
|
|
219538
|
+
") — $",
|
|
219539
|
+
ws.balance.toFixed(2)
|
|
219540
|
+
]
|
|
219541
|
+
}, undefined, true, undefined, this)
|
|
219542
|
+
]
|
|
219543
|
+
}, undefined, true, undefined, this)
|
|
219544
|
+
}, ws.id, false, undefined, this))
|
|
219545
|
+
}, undefined, false, undefined, this),
|
|
219546
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219547
|
+
marginTop: 1,
|
|
219548
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219549
|
+
fg: "gray",
|
|
219550
|
+
children: [
|
|
219551
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219552
|
+
fg: "green",
|
|
219553
|
+
children: "[↑/↓]"
|
|
219554
|
+
}, undefined, false, undefined, this),
|
|
219555
|
+
" Navigate ·",
|
|
219556
|
+
" ",
|
|
219557
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219558
|
+
fg: "green",
|
|
219559
|
+
children: "[ENTER]"
|
|
219560
|
+
}, undefined, false, undefined, this),
|
|
219561
|
+
" Select ·",
|
|
219562
|
+
" ",
|
|
219563
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219564
|
+
fg: "green",
|
|
219565
|
+
children: "[ESC]"
|
|
219566
|
+
}, undefined, false, undefined, this),
|
|
219567
|
+
" Cancel"
|
|
219568
|
+
]
|
|
219569
|
+
}, undefined, true, undefined, this)
|
|
219570
|
+
}, undefined, false, undefined, this)
|
|
219571
|
+
]
|
|
219572
|
+
}, undefined, true, undefined, this),
|
|
219573
|
+
step === "checking-billing" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219574
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219575
|
+
fg: "yellow",
|
|
219576
|
+
children: [
|
|
219577
|
+
"Checking billing for ",
|
|
219578
|
+
selectedWorkspace?.name,
|
|
219579
|
+
"..."
|
|
219580
|
+
]
|
|
219581
|
+
}, undefined, true, undefined, this)
|
|
219582
|
+
}, undefined, false, undefined, this),
|
|
219583
|
+
step === "success" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219584
|
+
flexDirection: "column",
|
|
219585
|
+
gap: 1,
|
|
219586
|
+
children: [
|
|
219587
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219588
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219589
|
+
fg: "green",
|
|
219590
|
+
children: "Connected to Pensar Console"
|
|
219591
|
+
}, undefined, false, undefined, this)
|
|
219592
|
+
}, undefined, false, undefined, this),
|
|
219593
|
+
(selectedWorkspace || connectedWorkspace) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219594
|
+
flexDirection: "column",
|
|
219595
|
+
children: [
|
|
219596
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219597
|
+
fg: "white",
|
|
219598
|
+
children: [
|
|
219599
|
+
"Workspace: ",
|
|
219600
|
+
selectedWorkspace?.name || connectedWorkspace?.name
|
|
219601
|
+
]
|
|
219602
|
+
}, undefined, true, undefined, this),
|
|
219603
|
+
balance !== null && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219604
|
+
fg: "white",
|
|
219605
|
+
children: [
|
|
219606
|
+
"Credits:",
|
|
219607
|
+
" ",
|
|
219608
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219609
|
+
fg: hasLowBalance ? "yellow" : "white",
|
|
219610
|
+
children: [
|
|
219611
|
+
"$",
|
|
219612
|
+
balance.toFixed(2)
|
|
219613
|
+
]
|
|
219614
|
+
}, undefined, true, undefined, this)
|
|
219615
|
+
]
|
|
219616
|
+
}, undefined, true, undefined, this)
|
|
219617
|
+
]
|
|
219618
|
+
}, undefined, true, undefined, this),
|
|
219619
|
+
(hasLowBalance || billingUrl) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219620
|
+
marginTop: 1,
|
|
219621
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219622
|
+
fg: "yellow",
|
|
219623
|
+
children: [
|
|
219624
|
+
billingUrl ? "Your workspace needs credits to use Apex CLI." : "Your credit balance is very low. We recommend at least $30 to run",
|
|
219625
|
+
`
|
|
219626
|
+
`,
|
|
219627
|
+
billingUrl ? "Press ENTER to open billing and add credits." : "pentests without interruptions. Press ENTER to open billing."
|
|
219628
|
+
]
|
|
219629
|
+
}, undefined, true, undefined, this)
|
|
219630
|
+
}, undefined, false, undefined, this),
|
|
219631
|
+
!selectedWorkspace && !connectedWorkspace && appConfig.data.pensarAPIKey && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219632
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219633
|
+
fg: "gray",
|
|
219634
|
+
children: "Already connected (legacy key saved in config)"
|
|
219635
|
+
}, undefined, false, undefined, this)
|
|
219636
|
+
}, undefined, false, undefined, this),
|
|
219637
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219638
|
+
marginTop: 1,
|
|
219639
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219640
|
+
fg: "gray",
|
|
219641
|
+
children: "Pensar models are now available in the model selector."
|
|
219642
|
+
}, undefined, false, undefined, this)
|
|
219643
|
+
}, undefined, false, undefined, this),
|
|
219644
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219645
|
+
marginTop: 1,
|
|
219646
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219647
|
+
fg: "gray",
|
|
219648
|
+
children: [
|
|
219649
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219650
|
+
fg: "green",
|
|
219651
|
+
children: "[ENTER]"
|
|
219652
|
+
}, undefined, false, undefined, this),
|
|
219653
|
+
" ",
|
|
219654
|
+
hasLowBalance || billingUrl ? "Open billing" : "Done",
|
|
219655
|
+
" ·",
|
|
219656
|
+
" ",
|
|
219657
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219658
|
+
fg: "red",
|
|
219659
|
+
children: "[D]"
|
|
219660
|
+
}, undefined, false, undefined, this),
|
|
219661
|
+
" Disconnect ·",
|
|
219662
|
+
" ",
|
|
219663
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219664
|
+
fg: "green",
|
|
219665
|
+
children: "[ESC]"
|
|
219666
|
+
}, undefined, false, undefined, this),
|
|
219667
|
+
" Back"
|
|
219668
|
+
]
|
|
219669
|
+
}, undefined, true, undefined, this)
|
|
219670
|
+
}, undefined, false, undefined, this)
|
|
219671
|
+
]
|
|
219672
|
+
}, undefined, true, undefined, this),
|
|
219673
|
+
step === "error" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219674
|
+
flexDirection: "column",
|
|
219675
|
+
gap: 1,
|
|
219676
|
+
children: [
|
|
219677
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219678
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219679
|
+
fg: "red",
|
|
219680
|
+
children: error
|
|
219681
|
+
}, undefined, false, undefined, this)
|
|
219682
|
+
}, undefined, false, undefined, this),
|
|
219683
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219684
|
+
marginTop: 1,
|
|
219685
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219686
|
+
fg: "gray",
|
|
219687
|
+
children: [
|
|
219688
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219689
|
+
fg: "green",
|
|
219690
|
+
children: "[ENTER]"
|
|
219691
|
+
}, undefined, false, undefined, this),
|
|
219692
|
+
" Try again ·",
|
|
219693
|
+
" ",
|
|
219694
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219695
|
+
fg: "green",
|
|
219696
|
+
children: "[ESC]"
|
|
219697
|
+
}, undefined, false, undefined, this),
|
|
219698
|
+
" Cancel"
|
|
219699
|
+
]
|
|
219700
|
+
}, undefined, true, undefined, this)
|
|
219701
|
+
}, undefined, false, undefined, this)
|
|
219702
|
+
]
|
|
219703
|
+
}, undefined, true, undefined, this)
|
|
219704
|
+
]
|
|
219705
|
+
}, undefined, true, undefined, this);
|
|
219706
|
+
}
|
|
219707
|
+
|
|
219708
|
+
// src/tui/components/commands/credits-flow.tsx
|
|
219709
|
+
var import_react62 = __toESM(require_react(), 1);
|
|
219710
|
+
init_tokenRefresh();
|
|
219711
|
+
function CreditsFlow() {
|
|
219712
|
+
const route = useRoute();
|
|
219713
|
+
const appConfig = useConfig();
|
|
219714
|
+
const [step, setStep] = import_react62.useState("loading");
|
|
219715
|
+
const [credits, setCredits] = import_react62.useState(null);
|
|
219716
|
+
const [error, setError] = import_react62.useState(null);
|
|
219717
|
+
const creditsUrl = `${getPensarConsoleUrl()}/credits`;
|
|
219718
|
+
const goHome = () => {
|
|
219719
|
+
route.navigate({ type: "base", path: "home" });
|
|
219720
|
+
};
|
|
219721
|
+
const openBrowser = () => {
|
|
219722
|
+
const url = creditsUrl;
|
|
219723
|
+
try {
|
|
219724
|
+
const platform = process.platform;
|
|
219725
|
+
if (platform === "darwin") {
|
|
219726
|
+
Bun.spawn(["open", url]);
|
|
219727
|
+
} else if (platform === "win32") {
|
|
219728
|
+
Bun.spawn(["cmd", "/c", "start", url]);
|
|
219729
|
+
} else {
|
|
219730
|
+
Bun.spawn(["xdg-open", url]);
|
|
219731
|
+
}
|
|
219732
|
+
} catch {}
|
|
219733
|
+
setStep("browser-opened");
|
|
219734
|
+
};
|
|
219735
|
+
const fetchBalance = async () => {
|
|
219736
|
+
const tokenResult = await ensureValidToken({
|
|
219737
|
+
accessToken: appConfig.data.accessToken,
|
|
219738
|
+
refreshToken: appConfig.data.refreshToken,
|
|
219739
|
+
pensarAPIKey: appConfig.data.pensarAPIKey,
|
|
219740
|
+
pensarApiUrl: appConfig.data.pensarApiUrl
|
|
219741
|
+
});
|
|
219742
|
+
if (!tokenResult) {
|
|
219743
|
+
setStep("no-auth");
|
|
219744
|
+
return;
|
|
219745
|
+
}
|
|
219746
|
+
setStep("loading");
|
|
219747
|
+
setError(null);
|
|
219748
|
+
try {
|
|
219749
|
+
const apiUrl = getPensarApiUrl(appConfig.data);
|
|
219750
|
+
const headers = {
|
|
219751
|
+
Authorization: `Bearer ${tokenResult.token}`
|
|
219752
|
+
};
|
|
219753
|
+
if (tokenResult.type === "workos" && appConfig.data.workspaceId) {
|
|
219754
|
+
headers["X-Workspace-Id"] = appConfig.data.workspaceId;
|
|
219755
|
+
}
|
|
219756
|
+
const response = await fetch(`${apiUrl}/bedrock/validate`, {
|
|
219757
|
+
method: "GET",
|
|
219758
|
+
headers
|
|
219759
|
+
});
|
|
219760
|
+
if (!response.ok) {
|
|
219761
|
+
throw new Error("Failed to fetch balance");
|
|
219762
|
+
}
|
|
219763
|
+
const result = await response.json();
|
|
219764
|
+
setCredits({
|
|
219765
|
+
balance: result.credits.balance,
|
|
219766
|
+
workspace: result.workspace.name
|
|
219767
|
+
});
|
|
219768
|
+
setStep("display");
|
|
219769
|
+
} catch (err) {
|
|
219770
|
+
setError(err instanceof Error ? err.message : "Failed to fetch balance");
|
|
219771
|
+
setStep("display");
|
|
219772
|
+
}
|
|
219773
|
+
};
|
|
219774
|
+
import_react62.useEffect(() => {
|
|
219775
|
+
fetchBalance();
|
|
219776
|
+
}, []);
|
|
219777
|
+
useKeyboard((key) => {
|
|
219778
|
+
if (key.name === "escape") {
|
|
219779
|
+
goHome();
|
|
219780
|
+
return;
|
|
219781
|
+
}
|
|
219782
|
+
if (step === "no-auth") {
|
|
219783
|
+
if (key.name === "return") {
|
|
219784
|
+
route.navigate({ type: "base", path: "auth" });
|
|
219785
|
+
}
|
|
219786
|
+
}
|
|
219787
|
+
if (step === "display") {
|
|
219788
|
+
if (key.name === "return") {
|
|
219789
|
+
openBrowser();
|
|
219790
|
+
}
|
|
219791
|
+
if (key.raw === "r" || key.raw === "R") {
|
|
219792
|
+
fetchBalance();
|
|
219793
|
+
}
|
|
219794
|
+
}
|
|
219795
|
+
if (step === "browser-opened") {
|
|
219796
|
+
if (key.name === "return") {
|
|
219797
|
+
fetchBalance();
|
|
219798
|
+
}
|
|
219799
|
+
}
|
|
219800
|
+
});
|
|
219801
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219802
|
+
flexDirection: "column",
|
|
219803
|
+
width: "100%",
|
|
219804
|
+
maxWidth: 80,
|
|
219805
|
+
alignItems: "flex-start",
|
|
219806
|
+
padding: 1,
|
|
219807
|
+
children: [
|
|
219808
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219809
|
+
marginBottom: 1,
|
|
219810
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219811
|
+
fg: "green",
|
|
219812
|
+
children: "Credits"
|
|
219813
|
+
}, undefined, false, undefined, this)
|
|
219814
|
+
}, undefined, false, undefined, this),
|
|
219815
|
+
step === "loading" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219816
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219817
|
+
fg: "yellow",
|
|
219818
|
+
children: "Fetching balance..."
|
|
219819
|
+
}, undefined, false, undefined, this)
|
|
219820
|
+
}, undefined, false, undefined, this),
|
|
219821
|
+
step === "no-auth" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219822
|
+
flexDirection: "column",
|
|
219823
|
+
gap: 1,
|
|
219824
|
+
children: [
|
|
219825
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219826
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219827
|
+
fg: "yellow",
|
|
219828
|
+
children: "Not connected to Pensar Console."
|
|
219829
|
+
}, undefined, false, undefined, this)
|
|
219830
|
+
}, undefined, false, undefined, this),
|
|
219831
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219832
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219833
|
+
fg: "gray",
|
|
219834
|
+
children: [
|
|
219835
|
+
"Run ",
|
|
219836
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219837
|
+
fg: "green",
|
|
219838
|
+
children: "/auth"
|
|
219839
|
+
}, undefined, false, undefined, this),
|
|
219840
|
+
" first to connect your account."
|
|
219841
|
+
]
|
|
219842
|
+
}, undefined, true, undefined, this)
|
|
219843
|
+
}, undefined, false, undefined, this),
|
|
219844
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219845
|
+
marginTop: 1,
|
|
219846
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219847
|
+
fg: "gray",
|
|
219848
|
+
children: [
|
|
219849
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219850
|
+
fg: "green",
|
|
219851
|
+
children: "[ENTER]"
|
|
219852
|
+
}, undefined, false, undefined, this),
|
|
219853
|
+
" Run /auth ·",
|
|
219854
|
+
" ",
|
|
219855
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219856
|
+
fg: "green",
|
|
219857
|
+
children: "[ESC]"
|
|
219858
|
+
}, undefined, false, undefined, this),
|
|
219859
|
+
" Back"
|
|
219860
|
+
]
|
|
219861
|
+
}, undefined, true, undefined, this)
|
|
219862
|
+
}, undefined, false, undefined, this)
|
|
219863
|
+
]
|
|
219864
|
+
}, undefined, true, undefined, this),
|
|
219865
|
+
step === "display" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219866
|
+
flexDirection: "column",
|
|
219867
|
+
gap: 1,
|
|
219868
|
+
children: [
|
|
219869
|
+
error ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219870
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219871
|
+
fg: "red",
|
|
219872
|
+
children: [
|
|
219873
|
+
"Error: ",
|
|
219874
|
+
error
|
|
219875
|
+
]
|
|
219876
|
+
}, undefined, true, undefined, this)
|
|
219877
|
+
}, undefined, false, undefined, this) : credits ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
|
|
219878
|
+
children: [
|
|
219879
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219880
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219881
|
+
fg: "white",
|
|
219882
|
+
children: [
|
|
219883
|
+
"Workspace: ",
|
|
219884
|
+
credits.workspace
|
|
219885
|
+
]
|
|
219886
|
+
}, undefined, true, undefined, this)
|
|
219887
|
+
}, undefined, false, undefined, this),
|
|
219888
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219889
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219890
|
+
fg: "white",
|
|
219891
|
+
children: [
|
|
219892
|
+
"Balance:",
|
|
219893
|
+
" ",
|
|
219894
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219895
|
+
fg: credits.balance < 5 ? "yellow" : "green",
|
|
219896
|
+
children: [
|
|
219897
|
+
"$",
|
|
219898
|
+
credits.balance.toFixed(2)
|
|
219899
|
+
]
|
|
219900
|
+
}, undefined, true, undefined, this)
|
|
219901
|
+
]
|
|
219902
|
+
}, undefined, true, undefined, this)
|
|
219903
|
+
}, undefined, false, undefined, this),
|
|
219904
|
+
credits.balance < 5 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219905
|
+
marginTop: 1,
|
|
219906
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219907
|
+
fg: "yellow",
|
|
219908
|
+
children: "Low balance. We recommend at least $30 for uninterrupted pentest runs."
|
|
219909
|
+
}, undefined, false, undefined, this)
|
|
219910
|
+
}, undefined, false, undefined, this)
|
|
219911
|
+
]
|
|
219912
|
+
}, undefined, true, undefined, this) : null,
|
|
219913
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219914
|
+
marginTop: 1,
|
|
219915
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219916
|
+
fg: "gray",
|
|
219917
|
+
children: [
|
|
219918
|
+
"Press ",
|
|
219919
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219920
|
+
fg: "green",
|
|
219921
|
+
children: "[ENTER]"
|
|
219922
|
+
}, undefined, false, undefined, this),
|
|
219923
|
+
" to buy credits in your browser."
|
|
219924
|
+
]
|
|
219925
|
+
}, undefined, true, undefined, this)
|
|
219926
|
+
}, undefined, false, undefined, this),
|
|
219927
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219928
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219929
|
+
fg: "gray",
|
|
219930
|
+
children: [
|
|
219931
|
+
"Or visit: ",
|
|
219932
|
+
creditsUrl
|
|
219933
|
+
]
|
|
219934
|
+
}, undefined, true, undefined, this)
|
|
219935
|
+
}, undefined, false, undefined, this),
|
|
219936
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219937
|
+
marginTop: 1,
|
|
219938
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219939
|
+
fg: "gray",
|
|
219940
|
+
children: [
|
|
219941
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219942
|
+
fg: "green",
|
|
219943
|
+
children: "[ENTER]"
|
|
219944
|
+
}, undefined, false, undefined, this),
|
|
219945
|
+
" Open browser ·",
|
|
219946
|
+
" ",
|
|
219947
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219948
|
+
fg: "green",
|
|
219949
|
+
children: "[R]"
|
|
219950
|
+
}, undefined, false, undefined, this),
|
|
219951
|
+
" Refresh ·",
|
|
219952
|
+
" ",
|
|
219953
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219954
|
+
fg: "green",
|
|
219955
|
+
children: "[ESC]"
|
|
219956
|
+
}, undefined, false, undefined, this),
|
|
219957
|
+
" Back"
|
|
219958
|
+
]
|
|
219959
|
+
}, undefined, true, undefined, this)
|
|
219960
|
+
}, undefined, false, undefined, this)
|
|
219961
|
+
]
|
|
219962
|
+
}, undefined, true, undefined, this),
|
|
219963
|
+
step === "browser-opened" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219964
|
+
flexDirection: "column",
|
|
219965
|
+
gap: 1,
|
|
219966
|
+
children: [
|
|
219967
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219968
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219969
|
+
fg: "green",
|
|
219970
|
+
children: "Browser opened. Purchase credits on the Pensar Console."
|
|
219971
|
+
}, undefined, false, undefined, this)
|
|
219972
|
+
}, undefined, false, undefined, this),
|
|
219973
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219974
|
+
marginTop: 1,
|
|
219975
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219976
|
+
fg: "gray",
|
|
219977
|
+
children: [
|
|
219978
|
+
"Press ",
|
|
219979
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219980
|
+
fg: "green",
|
|
219981
|
+
children: "[ENTER]"
|
|
219982
|
+
}, undefined, false, undefined, this),
|
|
219983
|
+
" to refresh your balance after purchasing."
|
|
219984
|
+
]
|
|
219985
|
+
}, undefined, true, undefined, this)
|
|
219986
|
+
}, undefined, false, undefined, this),
|
|
219987
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219988
|
+
marginTop: 1,
|
|
219989
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219990
|
+
fg: "gray",
|
|
219991
|
+
children: [
|
|
219992
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219993
|
+
fg: "green",
|
|
219994
|
+
children: "[ENTER]"
|
|
219995
|
+
}, undefined, false, undefined, this),
|
|
219996
|
+
" Refresh balance ·",
|
|
219997
|
+
" ",
|
|
219998
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219999
|
+
fg: "green",
|
|
220000
|
+
children: "[ESC]"
|
|
220001
|
+
}, undefined, false, undefined, this),
|
|
220002
|
+
" Back"
|
|
220003
|
+
]
|
|
220004
|
+
}, undefined, true, undefined, this)
|
|
220005
|
+
}, undefined, false, undefined, this)
|
|
220006
|
+
]
|
|
220007
|
+
}, undefined, true, undefined, this)
|
|
220008
|
+
]
|
|
220009
|
+
}, undefined, true, undefined, this);
|
|
220010
|
+
}
|
|
220011
|
+
|
|
217585
220012
|
// src/tui/context/keybinding.tsx
|
|
217586
|
-
var
|
|
220013
|
+
var import_react68 = __toESM(require_react(), 1);
|
|
217587
220014
|
|
|
217588
220015
|
// src/tui/keybindings/keybind.tsx
|
|
217589
|
-
var
|
|
220016
|
+
var import_react64 = __toESM(require_react(), 1);
|
|
217590
220017
|
|
|
217591
220018
|
// src/tui/keybindings/actions.ts
|
|
217592
220019
|
var movementActions = [
|
|
@@ -217838,7 +220265,7 @@ var allActions = [
|
|
|
217838
220265
|
var actionsByKey = new Map(allActions.map((action) => [action.key, action]));
|
|
217839
220266
|
var actionsById = new Map(allActions.map((action) => [action.id, action]));
|
|
217840
220267
|
// src/tui/keybindings/keybind.tsx
|
|
217841
|
-
var LeaderKeyContext =
|
|
220268
|
+
var LeaderKeyContext = import_react64.createContext(null);
|
|
217842
220269
|
// src/tui/keybindings/registry.ts
|
|
217843
220270
|
function createKeybindings(deps) {
|
|
217844
220271
|
const {
|
|
@@ -218016,7 +220443,7 @@ function matchesKeybind(pressed, combo) {
|
|
|
218016
220443
|
}
|
|
218017
220444
|
|
|
218018
220445
|
// src/tui/context/keybinding.tsx
|
|
218019
|
-
var KeybindingContext =
|
|
220446
|
+
var KeybindingContext = import_react68.createContext(undefined);
|
|
218020
220447
|
function KeybindingProvider({
|
|
218021
220448
|
children,
|
|
218022
220449
|
deps
|
|
@@ -218055,7 +220482,7 @@ function KeybindingProvider({
|
|
|
218055
220482
|
}
|
|
218056
220483
|
|
|
218057
220484
|
// src/tui/components/pentest/pentest.tsx
|
|
218058
|
-
var
|
|
220485
|
+
var import_react77 = __toESM(require_react(), 1);
|
|
218059
220486
|
import { existsSync as existsSync19, readdirSync as readdirSync5, readFileSync as readFileSync9 } from "fs";
|
|
218060
220487
|
import { join as join19 } from "path";
|
|
218061
220488
|
import { exec as exec3 } from "child_process";
|
|
@@ -218070,7 +220497,7 @@ import { join as join18 } from "path";
|
|
|
218070
220497
|
// src/core/workflows/whiteboxAttackSurface.ts
|
|
218071
220498
|
init_zod();
|
|
218072
220499
|
init_agent4();
|
|
218073
|
-
|
|
220500
|
+
init_types5();
|
|
218074
220501
|
var DEFAULT_CONCURRENCY3 = 5;
|
|
218075
220502
|
var WHITEBOX_CODE_AGENT_SYSTEM_PROMPT = `You are an expert source-code analyst with direct filesystem access. You will be given a specific objective — focus exclusively on completing it.
|
|
218076
220503
|
|
|
@@ -218608,8 +221035,11 @@ Found ${findings.length} vulnerabilities`);
|
|
|
218608
221035
|
return { findings, findingsPath, pocsPath, reportPath };
|
|
218609
221036
|
}
|
|
218610
221037
|
|
|
221038
|
+
// src/tui/components/pentest/pentest.tsx
|
|
221039
|
+
init_utils2();
|
|
221040
|
+
|
|
218611
221041
|
// src/tui/components/agent-display.tsx
|
|
218612
|
-
var
|
|
221042
|
+
var import_react75 = __toESM(require_react(), 1);
|
|
218613
221043
|
|
|
218614
221044
|
// node_modules/marked/lib/marked.esm.js
|
|
218615
221045
|
function L2() {
|
|
@@ -220375,14 +222805,14 @@ function getResultSummary(result, toolName) {
|
|
|
220375
222805
|
return null;
|
|
220376
222806
|
}
|
|
220377
222807
|
// src/tui/components/shared/ascii-spinner.tsx
|
|
220378
|
-
var
|
|
222808
|
+
var import_react69 = __toESM(require_react(), 1);
|
|
220379
222809
|
var SPINNER_FRAMES = ["/", "-", "\\", "|"];
|
|
220380
222810
|
var SPINNER_INTERVAL = 100;
|
|
220381
222811
|
function AsciiSpinner({ label, fg: fg2 }) {
|
|
220382
222812
|
const { colors: colors2 } = useTheme();
|
|
220383
222813
|
const spinnerColor = fg2 ?? colors2.info;
|
|
220384
|
-
const [frame, setFrame] =
|
|
220385
|
-
|
|
222814
|
+
const [frame, setFrame] = import_react69.useState(0);
|
|
222815
|
+
import_react69.useEffect(() => {
|
|
220386
222816
|
const interval = setInterval(() => {
|
|
220387
222817
|
setFrame((f3) => (f3 + 1) % SPINNER_FRAMES.length);
|
|
220388
222818
|
}, SPINNER_INTERVAL);
|
|
@@ -220394,14 +222824,14 @@ function AsciiSpinner({ label, fg: fg2 }) {
|
|
|
220394
222824
|
}, undefined, false, undefined, this);
|
|
220395
222825
|
}
|
|
220396
222826
|
// src/tui/components/shared/tool-renderer.tsx
|
|
220397
|
-
var
|
|
220398
|
-
var ToolRenderer =
|
|
222827
|
+
var import_react70 = __toESM(require_react(), 1);
|
|
222828
|
+
var ToolRenderer = import_react70.memo(function ToolRenderer2({
|
|
220399
222829
|
message,
|
|
220400
222830
|
verbose = false,
|
|
220401
222831
|
expandedLogs = false
|
|
220402
222832
|
}) {
|
|
220403
222833
|
const { colors: colors2 } = useTheme();
|
|
220404
|
-
const [showOutput, setShowOutput] =
|
|
222834
|
+
const [showOutput, setShowOutput] = import_react70.useState(false);
|
|
220405
222835
|
if (!isToolMessage(message)) {
|
|
220406
222836
|
return null;
|
|
220407
222837
|
}
|
|
@@ -220498,8 +222928,8 @@ var ToolRenderer = import_react66.memo(function ToolRenderer2({
|
|
|
220498
222928
|
}, undefined, true, undefined, this);
|
|
220499
222929
|
});
|
|
220500
222930
|
// src/tui/components/shared/message-renderer.tsx
|
|
220501
|
-
var
|
|
220502
|
-
var MessageRenderer =
|
|
222931
|
+
var import_react71 = __toESM(require_react(), 1);
|
|
222932
|
+
var MessageRenderer = import_react71.memo(function MessageRenderer2({
|
|
220503
222933
|
message,
|
|
220504
222934
|
isStreaming = false,
|
|
220505
222935
|
verbose = false,
|
|
@@ -220509,7 +222939,7 @@ var MessageRenderer = import_react67.memo(function MessageRenderer2({
|
|
|
220509
222939
|
}) {
|
|
220510
222940
|
const { colors: colors2 } = useTheme();
|
|
220511
222941
|
const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content);
|
|
220512
|
-
const displayContent =
|
|
222942
|
+
const displayContent = import_react71.useMemo(() => message.role === "assistant" ? markdownToStyledText(content, colors2) : content, [content, message.role, colors2]);
|
|
220513
222943
|
if (isToolMessage(message)) {
|
|
220514
222944
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToolRenderer, {
|
|
220515
222945
|
message,
|
|
@@ -220621,9 +223051,9 @@ var MessageRenderer = import_react67.memo(function MessageRenderer2({
|
|
|
220621
223051
|
}, undefined, false, undefined, this);
|
|
220622
223052
|
});
|
|
220623
223053
|
// src/tui/components/shared/approval-prompt.tsx
|
|
220624
|
-
var
|
|
223054
|
+
var import_react72 = __toESM(require_react(), 1);
|
|
220625
223055
|
// src/tui/components/shared/message-reducer.ts
|
|
220626
|
-
var
|
|
223056
|
+
var import_react74 = __toESM(require_react(), 1);
|
|
220627
223057
|
// src/tui/components/agent-display.tsx
|
|
220628
223058
|
function getStableKey(item, contextId = "root") {
|
|
220629
223059
|
if ("messages" in item) {
|
|
@@ -220699,11 +223129,11 @@ function AgentDisplay({
|
|
|
220699
223129
|
]
|
|
220700
223130
|
}, undefined, true, undefined, this);
|
|
220701
223131
|
}
|
|
220702
|
-
var SubAgentDisplay =
|
|
223132
|
+
var SubAgentDisplay = import_react75.memo(function SubAgentDisplay2({
|
|
220703
223133
|
subagent
|
|
220704
223134
|
}) {
|
|
220705
223135
|
const { colors: colors2 } = useTheme();
|
|
220706
|
-
const [open, setOpen] =
|
|
223136
|
+
const [open, setOpen] = import_react75.useState(false);
|
|
220707
223137
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
220708
223138
|
height: open ? 40 : "auto",
|
|
220709
223139
|
onMouseDown: () => setOpen(!open),
|
|
@@ -220758,7 +223188,7 @@ var SubAgentDisplay = import_react71.memo(function SubAgentDisplay2({
|
|
|
220758
223188
|
]
|
|
220759
223189
|
}, undefined, true, undefined, this);
|
|
220760
223190
|
});
|
|
220761
|
-
var AgentMessage =
|
|
223191
|
+
var AgentMessage = import_react75.memo(function AgentMessage2({
|
|
220762
223192
|
message
|
|
220763
223193
|
}) {
|
|
220764
223194
|
const { colors: colors2 } = useTheme();
|
|
@@ -220822,9 +223252,9 @@ var AgentMessage = import_react71.memo(function AgentMessage2({
|
|
|
220822
223252
|
flexDirection: "column",
|
|
220823
223253
|
marginTop: 0,
|
|
220824
223254
|
paddingLeft: 2,
|
|
220825
|
-
children: streamingLogs.slice(-3).map((
|
|
223255
|
+
children: streamingLogs.slice(-3).map((log2, idx) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
220826
223256
|
fg: colors2.textMuted,
|
|
220827
|
-
content:
|
|
223257
|
+
content: log2.length > 100 ? log2.slice(0, 100) + "…" : log2
|
|
220828
223258
|
}, idx, false, undefined, this))
|
|
220829
223259
|
}, undefined, false, undefined, this)
|
|
220830
223260
|
]
|
|
@@ -220871,8 +223301,8 @@ var AgentMessage = import_react71.memo(function AgentMessage2({
|
|
|
220871
223301
|
});
|
|
220872
223302
|
function ToolDetails({ message }) {
|
|
220873
223303
|
const { colors: colors2 } = useTheme();
|
|
220874
|
-
const [showArgs, setShowArgs] =
|
|
220875
|
-
const [showResult, setShowResult] =
|
|
223304
|
+
const [showArgs, setShowArgs] = import_react75.useState(false);
|
|
223305
|
+
const [showResult, setShowResult] = import_react75.useState(false);
|
|
220876
223306
|
if (message.role !== "tool") {
|
|
220877
223307
|
return null;
|
|
220878
223308
|
}
|
|
@@ -220950,24 +223380,24 @@ function Pentest({ sessionId }) {
|
|
|
220950
223380
|
const config3 = useConfig();
|
|
220951
223381
|
const { model, setThinking, setIsExecuting, isExecuting } = useAgent();
|
|
220952
223382
|
const { stack, externalDialogOpen } = useDialog();
|
|
220953
|
-
const [session, setSession] =
|
|
220954
|
-
const [error40, setError] =
|
|
220955
|
-
const [phase, setPhase] =
|
|
220956
|
-
const [abortController, setAbortController] =
|
|
220957
|
-
const [panelMessages, setPanelMessages] =
|
|
220958
|
-
const panelTextRef =
|
|
220959
|
-
const panelSourceRef =
|
|
220960
|
-
const [pentestAgents, setPentestAgents] =
|
|
220961
|
-
const pentestTextRefs =
|
|
220962
|
-
const [assets, setAssets] =
|
|
220963
|
-
const [viewMode, setViewMode] =
|
|
220964
|
-
const [selectedAgentId, setSelectedAgentId] =
|
|
220965
|
-
const [focusedIndex, setFocusedIndex] =
|
|
220966
|
-
const [showOrchestratorPanel, setShowOrchestratorPanel] =
|
|
220967
|
-
const [startTime, setStartTime] =
|
|
220968
|
-
const pentestAgentList =
|
|
220969
|
-
const selectedAgent =
|
|
220970
|
-
|
|
223383
|
+
const [session, setSession] = import_react77.useState(null);
|
|
223384
|
+
const [error40, setError] = import_react77.useState(null);
|
|
223385
|
+
const [phase, setPhase] = import_react77.useState("loading");
|
|
223386
|
+
const [abortController, setAbortController] = import_react77.useState(null);
|
|
223387
|
+
const [panelMessages, setPanelMessages] = import_react77.useState([]);
|
|
223388
|
+
const panelTextRef = import_react77.useRef("");
|
|
223389
|
+
const panelSourceRef = import_react77.useRef(null);
|
|
223390
|
+
const [pentestAgents, setPentestAgents] = import_react77.useState({});
|
|
223391
|
+
const pentestTextRefs = import_react77.useRef({});
|
|
223392
|
+
const [assets, setAssets] = import_react77.useState([]);
|
|
223393
|
+
const [viewMode, setViewMode] = import_react77.useState("overview");
|
|
223394
|
+
const [selectedAgentId, setSelectedAgentId] = import_react77.useState(null);
|
|
223395
|
+
const [focusedIndex, setFocusedIndex] = import_react77.useState(0);
|
|
223396
|
+
const [showOrchestratorPanel, setShowOrchestratorPanel] = import_react77.useState(false);
|
|
223397
|
+
const [startTime, setStartTime] = import_react77.useState(null);
|
|
223398
|
+
const pentestAgentList = import_react77.useMemo(() => Object.values(pentestAgents).sort((a, b3) => a.createdAt.getTime() - b3.createdAt.getTime()), [pentestAgents]);
|
|
223399
|
+
const selectedAgent = import_react77.useMemo(() => selectedAgentId ? pentestAgents[selectedAgentId] ?? null : null, [pentestAgents, selectedAgentId]);
|
|
223400
|
+
import_react77.useEffect(() => {
|
|
220971
223401
|
async function load() {
|
|
220972
223402
|
try {
|
|
220973
223403
|
const s2 = await sessions.get(sessionId);
|
|
@@ -220984,7 +223414,7 @@ function Pentest({ sessionId }) {
|
|
|
220984
223414
|
}
|
|
220985
223415
|
load();
|
|
220986
223416
|
}, [sessionId]);
|
|
220987
|
-
|
|
223417
|
+
import_react77.useEffect(() => {
|
|
220988
223418
|
if (!session)
|
|
220989
223419
|
return;
|
|
220990
223420
|
const assetsPath = join19(session.rootPath, "assets");
|
|
@@ -221007,12 +223437,12 @@ function Pentest({ sessionId }) {
|
|
|
221007
223437
|
const interval = setInterval(readAssets, 2000);
|
|
221008
223438
|
return () => clearInterval(interval);
|
|
221009
223439
|
}, [session]);
|
|
221010
|
-
|
|
223440
|
+
import_react77.useEffect(() => {
|
|
221011
223441
|
return () => {
|
|
221012
223442
|
abortController?.abort();
|
|
221013
223443
|
};
|
|
221014
223444
|
}, [abortController]);
|
|
221015
|
-
const ensurePentestAgent =
|
|
223445
|
+
const ensurePentestAgent = import_react77.useCallback((subagentId) => {
|
|
221016
223446
|
setPentestAgents((prev) => {
|
|
221017
223447
|
if (prev[subagentId])
|
|
221018
223448
|
return prev;
|
|
@@ -221029,7 +223459,7 @@ function Pentest({ sessionId }) {
|
|
|
221029
223459
|
};
|
|
221030
223460
|
});
|
|
221031
223461
|
}, []);
|
|
221032
|
-
const handleSubagentSpawn =
|
|
223462
|
+
const handleSubagentSpawn = import_react77.useCallback(({
|
|
221033
223463
|
subagentId,
|
|
221034
223464
|
input
|
|
221035
223465
|
}) => {
|
|
@@ -221049,7 +223479,7 @@ function Pentest({ sessionId }) {
|
|
|
221049
223479
|
}
|
|
221050
223480
|
}));
|
|
221051
223481
|
}, []);
|
|
221052
|
-
const handleSubagentComplete =
|
|
223482
|
+
const handleSubagentComplete = import_react77.useCallback(({ subagentId, status }) => {
|
|
221053
223483
|
if (!subagentId.startsWith("pentest-agent-"))
|
|
221054
223484
|
return;
|
|
221055
223485
|
setPentestAgents((prev) => {
|
|
@@ -221062,7 +223492,7 @@ function Pentest({ sessionId }) {
|
|
|
221062
223492
|
};
|
|
221063
223493
|
});
|
|
221064
223494
|
}, []);
|
|
221065
|
-
const appendPanelText =
|
|
223495
|
+
const appendPanelText = import_react77.useCallback((source, text2) => {
|
|
221066
223496
|
if (panelSourceRef.current !== source) {
|
|
221067
223497
|
panelTextRef.current = "";
|
|
221068
223498
|
panelSourceRef.current = source;
|
|
@@ -221087,7 +223517,7 @@ function Pentest({ sessionId }) {
|
|
|
221087
223517
|
];
|
|
221088
223518
|
});
|
|
221089
223519
|
}, []);
|
|
221090
|
-
const appendPentestText =
|
|
223520
|
+
const appendPentestText = import_react77.useCallback((subagentId, text2) => {
|
|
221091
223521
|
ensurePentestAgent(subagentId);
|
|
221092
223522
|
if (!pentestTextRefs.current[subagentId]) {
|
|
221093
223523
|
pentestTextRefs.current[subagentId] = "";
|
|
@@ -221120,7 +223550,7 @@ function Pentest({ sessionId }) {
|
|
|
221120
223550
|
};
|
|
221121
223551
|
});
|
|
221122
223552
|
}, [ensurePentestAgent]);
|
|
221123
|
-
const addPanelToolCall =
|
|
223553
|
+
const addPanelToolCall = import_react77.useCallback((toolCallId, toolName, args) => {
|
|
221124
223554
|
panelTextRef.current = "";
|
|
221125
223555
|
panelSourceRef.current = null;
|
|
221126
223556
|
const description = typeof args?.toolCallDescription === "string" ? args.toolCallDescription : toolName;
|
|
@@ -221139,7 +223569,7 @@ function Pentest({ sessionId }) {
|
|
|
221139
223569
|
return [...prev, msg];
|
|
221140
223570
|
});
|
|
221141
223571
|
}, []);
|
|
221142
|
-
const addPentestToolCall =
|
|
223572
|
+
const addPentestToolCall = import_react77.useCallback((subagentId, toolCallId, toolName, args) => {
|
|
221143
223573
|
pentestTextRefs.current[subagentId] = "";
|
|
221144
223574
|
ensurePentestAgent(subagentId);
|
|
221145
223575
|
const description = typeof args?.toolCallDescription === "string" ? args.toolCallDescription : toolName;
|
|
@@ -221184,12 +223614,12 @@ function Pentest({ sessionId }) {
|
|
|
221184
223614
|
}
|
|
221185
223615
|
];
|
|
221186
223616
|
};
|
|
221187
|
-
const updatePanelToolResult =
|
|
223617
|
+
const updatePanelToolResult = import_react77.useCallback((toolCallId, toolName, result) => {
|
|
221188
223618
|
panelTextRef.current = "";
|
|
221189
223619
|
panelSourceRef.current = null;
|
|
221190
223620
|
setPanelMessages((prev) => toolResultUpdater(prev, toolCallId, toolName, result));
|
|
221191
223621
|
}, []);
|
|
221192
|
-
const updatePentestToolResult =
|
|
223622
|
+
const updatePentestToolResult = import_react77.useCallback((subagentId, toolCallId, toolName, result) => {
|
|
221193
223623
|
pentestTextRefs.current[subagentId] = "";
|
|
221194
223624
|
setPentestAgents((prev) => {
|
|
221195
223625
|
const agent = prev[subagentId];
|
|
@@ -221204,7 +223634,7 @@ function Pentest({ sessionId }) {
|
|
|
221204
223634
|
};
|
|
221205
223635
|
});
|
|
221206
223636
|
}, []);
|
|
221207
|
-
const startPentest =
|
|
223637
|
+
const startPentest = import_react77.useCallback(async (s2) => {
|
|
221208
223638
|
setPhase("discovery");
|
|
221209
223639
|
setStartTime(new Date);
|
|
221210
223640
|
setIsExecuting(true);
|
|
@@ -221218,12 +223648,7 @@ function Pentest({ sessionId }) {
|
|
|
221218
223648
|
session: s2,
|
|
221219
223649
|
model: model.id,
|
|
221220
223650
|
abortSignal: controller.signal,
|
|
221221
|
-
authConfig:
|
|
221222
|
-
anthropicAPIKey: config3.data.anthropicAPIKey ?? undefined,
|
|
221223
|
-
openAiAPIKey: config3.data.openAiAPIKey ?? undefined,
|
|
221224
|
-
openRouterAPIKey: config3.data.openRouterAPIKey ?? undefined,
|
|
221225
|
-
local: config3.data.localModelUrl ? { baseURL: config3.data.localModelUrl } : undefined
|
|
221226
|
-
},
|
|
223651
|
+
authConfig: buildAuthConfig(config3.data),
|
|
221227
223652
|
callbacks: {
|
|
221228
223653
|
onTextDelta: (d3) => {
|
|
221229
223654
|
setThinking(false);
|
|
@@ -221306,7 +223731,7 @@ function Pentest({ sessionId }) {
|
|
|
221306
223731
|
handleSubagentSpawn,
|
|
221307
223732
|
handleSubagentComplete
|
|
221308
223733
|
]);
|
|
221309
|
-
|
|
223734
|
+
import_react77.useEffect(() => {
|
|
221310
223735
|
if (session && phase === "loading") {
|
|
221311
223736
|
startPentest(session);
|
|
221312
223737
|
}
|
|
@@ -221368,7 +223793,7 @@ function Pentest({ sessionId }) {
|
|
|
221368
223793
|
}
|
|
221369
223794
|
}
|
|
221370
223795
|
});
|
|
221371
|
-
const openReport =
|
|
223796
|
+
const openReport = import_react77.useCallback(() => {
|
|
221372
223797
|
if (!session)
|
|
221373
223798
|
return;
|
|
221374
223799
|
const reportPath = join19(session.rootPath, "pentest-report.md");
|
|
@@ -221560,7 +223985,7 @@ function OrchestratorPanel({
|
|
|
221560
223985
|
}) {
|
|
221561
223986
|
const { colors: colors2 } = useTheme();
|
|
221562
223987
|
const isRunning = phase !== "loading" && phase !== "completed" && phase !== "error";
|
|
221563
|
-
const assetSummary =
|
|
223988
|
+
const assetSummary = import_react77.useMemo(() => {
|
|
221564
223989
|
const byType = {};
|
|
221565
223990
|
for (const a of assets) {
|
|
221566
223991
|
const key = a.assetType;
|
|
@@ -221809,7 +224234,7 @@ function AgentCardGrid({
|
|
|
221809
224234
|
onSelectAgent
|
|
221810
224235
|
}) {
|
|
221811
224236
|
const { colors: colors2 } = useTheme();
|
|
221812
|
-
const rows =
|
|
224237
|
+
const rows = import_react77.useMemo(() => {
|
|
221813
224238
|
const result = [];
|
|
221814
224239
|
for (let i2 = 0;i2 < agents.length; i2 += 2) {
|
|
221815
224240
|
result.push(agents.slice(i2, i2 + 2));
|
|
@@ -221857,14 +224282,14 @@ function AgentCard({
|
|
|
221857
224282
|
completed: colors2.primary,
|
|
221858
224283
|
failed: colors2.error
|
|
221859
224284
|
}[agent.status];
|
|
221860
|
-
const lastActivity =
|
|
224285
|
+
const lastActivity = import_react77.useMemo(() => {
|
|
221861
224286
|
const last = agent.messages[agent.messages.length - 1];
|
|
221862
224287
|
if (!last)
|
|
221863
224288
|
return "Starting...";
|
|
221864
224289
|
const text2 = typeof last.content === "string" ? last.content.replace(/\n/g, " ").trim() : "Working...";
|
|
221865
224290
|
return text2.length > 50 ? text2.substring(0, 47) + "..." : text2;
|
|
221866
224291
|
}, [agent.messages]);
|
|
221867
|
-
const toolCalls =
|
|
224292
|
+
const toolCalls = import_react77.useMemo(() => agent.messages.filter((m4) => m4.role === "tool").length, [agent.messages]);
|
|
221868
224293
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
221869
224294
|
flexGrow: 1,
|
|
221870
224295
|
flexBasis: 0,
|
|
@@ -222051,8 +224476,8 @@ function MetricsBar({
|
|
|
222051
224476
|
isExecuting
|
|
222052
224477
|
}) {
|
|
222053
224478
|
const { colors: colors2 } = useTheme();
|
|
222054
|
-
const [now2, setNow] =
|
|
222055
|
-
|
|
224479
|
+
const [now2, setNow] = import_react77.useState(Date.now());
|
|
224480
|
+
import_react77.useEffect(() => {
|
|
222056
224481
|
if (!isExecuting)
|
|
222057
224482
|
return;
|
|
222058
224483
|
const interval = setInterval(() => setNow(Date.now()), 1000);
|
|
@@ -222195,7 +224620,7 @@ function MetricsBar({
|
|
|
222195
224620
|
}
|
|
222196
224621
|
|
|
222197
224622
|
// src/tui/components/operator-dashboard/index.tsx
|
|
222198
|
-
var
|
|
224623
|
+
var import_react82 = __toESM(require_react(), 1);
|
|
222199
224624
|
|
|
222200
224625
|
// src/core/api/offesecAgent.ts
|
|
222201
224626
|
init_offensiveSecurityAgent();
|
|
@@ -222210,6 +224635,9 @@ async function runOffensiveSecurityAgent(input) {
|
|
|
222210
224635
|
});
|
|
222211
224636
|
}
|
|
222212
224637
|
|
|
224638
|
+
// src/tui/components/operator-dashboard/index.tsx
|
|
224639
|
+
init_utils2();
|
|
224640
|
+
|
|
222213
224641
|
// src/core/agents/offSecAgent/index.ts
|
|
222214
224642
|
init_offensiveSecurityAgent();
|
|
222215
224643
|
init_tools();
|
|
@@ -222292,7 +224720,7 @@ function InlineApprovalPrompt2({ approval }) {
|
|
|
222292
224720
|
}
|
|
222293
224721
|
|
|
222294
224722
|
// src/tui/components/chat/loading-indicator.tsx
|
|
222295
|
-
var
|
|
224723
|
+
var import_react79 = __toESM(require_react(), 1);
|
|
222296
224724
|
var SPINNER_FRAMES2 = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
222297
224725
|
var SPINNER_INTERVAL2 = 80;
|
|
222298
224726
|
var DOTS_FRAMES = ["", ".", "..", "..."];
|
|
@@ -222303,15 +224731,15 @@ function LoadingIndicator({
|
|
|
222303
224731
|
toolName
|
|
222304
224732
|
}) {
|
|
222305
224733
|
const { colors: colors2 } = useTheme();
|
|
222306
|
-
const [spinnerFrame, setSpinnerFrame] =
|
|
222307
|
-
const [dotsFrame, setDotsFrame] =
|
|
222308
|
-
|
|
224734
|
+
const [spinnerFrame, setSpinnerFrame] = import_react79.useState(0);
|
|
224735
|
+
const [dotsFrame, setDotsFrame] = import_react79.useState(0);
|
|
224736
|
+
import_react79.useEffect(() => {
|
|
222309
224737
|
const interval = setInterval(() => {
|
|
222310
224738
|
setSpinnerFrame((f3) => (f3 + 1) % SPINNER_FRAMES2.length);
|
|
222311
224739
|
}, SPINNER_INTERVAL2);
|
|
222312
224740
|
return () => clearInterval(interval);
|
|
222313
224741
|
}, []);
|
|
222314
|
-
|
|
224742
|
+
import_react79.useEffect(() => {
|
|
222315
224743
|
const interval = setInterval(() => {
|
|
222316
224744
|
setDotsFrame((f3) => (f3 + 1) % DOTS_FRAMES.length);
|
|
222317
224745
|
}, DOTS_INTERVAL);
|
|
@@ -222581,7 +225009,7 @@ function MessageList({
|
|
|
222581
225009
|
}
|
|
222582
225010
|
|
|
222583
225011
|
// src/tui/components/chat/input-area.tsx
|
|
222584
|
-
var
|
|
225012
|
+
var import_react80 = __toESM(require_react(), 1);
|
|
222585
225013
|
function NormalInputAreaInner({
|
|
222586
225014
|
value,
|
|
222587
225015
|
onChange,
|
|
@@ -222596,17 +225024,17 @@ function NormalInputAreaInner({
|
|
|
222596
225024
|
}) {
|
|
222597
225025
|
const { colors: colors2 } = useTheme();
|
|
222598
225026
|
const { inputValue, setInputValue } = useInput();
|
|
222599
|
-
const promptRef =
|
|
222600
|
-
const isExternalUpdate =
|
|
225027
|
+
const promptRef = import_react80.useRef(null);
|
|
225028
|
+
const isExternalUpdate = import_react80.useRef(false);
|
|
222601
225029
|
const isDisabled = status === "running";
|
|
222602
|
-
|
|
225030
|
+
import_react80.useEffect(() => {
|
|
222603
225031
|
if (value !== inputValue) {
|
|
222604
225032
|
isExternalUpdate.current = true;
|
|
222605
225033
|
setInputValue(value);
|
|
222606
225034
|
promptRef.current?.setValue(value);
|
|
222607
225035
|
}
|
|
222608
225036
|
}, [value]);
|
|
222609
|
-
|
|
225037
|
+
import_react80.useEffect(() => {
|
|
222610
225038
|
if (isExternalUpdate.current) {
|
|
222611
225039
|
isExternalUpdate.current = false;
|
|
222612
225040
|
return;
|
|
@@ -222756,7 +225184,7 @@ function ApprovalInputArea2({
|
|
|
222756
225184
|
lastDeclineNote
|
|
222757
225185
|
}) {
|
|
222758
225186
|
const { colors: colors2 } = useTheme();
|
|
222759
|
-
const [focusedElement, setFocusedElement] =
|
|
225187
|
+
const [focusedElement, setFocusedElement] = import_react80.useState(0);
|
|
222760
225188
|
const tierColor = getTierColor(colors2, approval.tier);
|
|
222761
225189
|
useKeyboard((key) => {
|
|
222762
225190
|
if (key.name === "up") {
|
|
@@ -222878,20 +225306,20 @@ function OperatorDashboard({
|
|
|
222878
225306
|
const route = useRoute();
|
|
222879
225307
|
const config3 = useConfig();
|
|
222880
225308
|
const { model, setThinking, setIsExecuting } = useAgent();
|
|
222881
|
-
const [session, setSession] =
|
|
222882
|
-
const [loading, setLoading] =
|
|
222883
|
-
const [error40, setError] =
|
|
222884
|
-
const [status, setStatus] =
|
|
222885
|
-
const abortControllerRef =
|
|
222886
|
-
const [messages, setMessages] =
|
|
222887
|
-
const textRef =
|
|
222888
|
-
const [inputValue, setInputValue] =
|
|
222889
|
-
const [operatorState, setOperatorState] =
|
|
222890
|
-
const [pendingApprovals] =
|
|
222891
|
-
const [lastApprovedAction] =
|
|
222892
|
-
const [verboseMode, setVerboseMode] =
|
|
222893
|
-
const [expandedLogs, setExpandedLogs] =
|
|
222894
|
-
|
|
225309
|
+
const [session, setSession] = import_react82.useState(null);
|
|
225310
|
+
const [loading, setLoading] = import_react82.useState(true);
|
|
225311
|
+
const [error40, setError] = import_react82.useState(null);
|
|
225312
|
+
const [status, setStatus] = import_react82.useState("idle");
|
|
225313
|
+
const abortControllerRef = import_react82.useRef(null);
|
|
225314
|
+
const [messages, setMessages] = import_react82.useState([]);
|
|
225315
|
+
const textRef = import_react82.useRef("");
|
|
225316
|
+
const [inputValue, setInputValue] = import_react82.useState("");
|
|
225317
|
+
const [operatorState, setOperatorState] = import_react82.useState(() => createInitialOperatorState("manual", 2));
|
|
225318
|
+
const [pendingApprovals] = import_react82.useState([]);
|
|
225319
|
+
const [lastApprovedAction] = import_react82.useState(null);
|
|
225320
|
+
const [verboseMode, setVerboseMode] = import_react82.useState(false);
|
|
225321
|
+
const [expandedLogs, setExpandedLogs] = import_react82.useState(false);
|
|
225322
|
+
import_react82.useEffect(() => {
|
|
222895
225323
|
async function loadSession() {
|
|
222896
225324
|
try {
|
|
222897
225325
|
const s2 = await sessions.get(sessionId);
|
|
@@ -222923,7 +225351,7 @@ function OperatorDashboard({
|
|
|
222923
225351
|
}
|
|
222924
225352
|
loadSession();
|
|
222925
225353
|
}, [sessionId, isResume]);
|
|
222926
|
-
const appendText =
|
|
225354
|
+
const appendText = import_react82.useCallback((text2) => {
|
|
222927
225355
|
textRef.current += text2;
|
|
222928
225356
|
const accumulated = textRef.current;
|
|
222929
225357
|
setMessages((prev) => {
|
|
@@ -222939,7 +225367,7 @@ function OperatorDashboard({
|
|
|
222939
225367
|
];
|
|
222940
225368
|
});
|
|
222941
225369
|
}, []);
|
|
222942
|
-
const addToolCall =
|
|
225370
|
+
const addToolCall = import_react82.useCallback((toolCallId, toolName, args) => {
|
|
222943
225371
|
textRef.current = "";
|
|
222944
225372
|
setMessages((prev) => [
|
|
222945
225373
|
...prev,
|
|
@@ -222954,7 +225382,7 @@ function OperatorDashboard({
|
|
|
222954
225382
|
}
|
|
222955
225383
|
]);
|
|
222956
225384
|
}, []);
|
|
222957
|
-
const updateToolResult =
|
|
225385
|
+
const updateToolResult = import_react82.useCallback((toolCallId, _toolName, result) => {
|
|
222958
225386
|
textRef.current = "";
|
|
222959
225387
|
setMessages((prev) => {
|
|
222960
225388
|
const idx = prev.findIndex((m4) => isToolMessage(m4) && m4.toolCallId === toolCallId);
|
|
@@ -222965,7 +225393,7 @@ function OperatorDashboard({
|
|
|
222965
225393
|
return updated;
|
|
222966
225394
|
});
|
|
222967
225395
|
}, []);
|
|
222968
|
-
const runAgent =
|
|
225396
|
+
const runAgent = import_react82.useCallback(async (prompt) => {
|
|
222969
225397
|
if (!session)
|
|
222970
225398
|
return;
|
|
222971
225399
|
setStatus("running");
|
|
@@ -222989,12 +225417,7 @@ function OperatorDashboard({
|
|
|
222989
225417
|
target: session.targets[0],
|
|
222990
225418
|
activeTools: [...ALL_TOOL_NAMES],
|
|
222991
225419
|
abortSignal: controller.signal,
|
|
222992
|
-
authConfig:
|
|
222993
|
-
anthropicAPIKey: config3.data.anthropicAPIKey ?? undefined,
|
|
222994
|
-
openAiAPIKey: config3.data.openAiAPIKey ?? undefined,
|
|
222995
|
-
openRouterAPIKey: config3.data.openRouterAPIKey ?? undefined,
|
|
222996
|
-
local: config3.data.localModelUrl ? { baseURL: config3.data.localModelUrl } : undefined
|
|
222997
|
-
},
|
|
225420
|
+
authConfig: buildAuthConfig(config3.data),
|
|
222998
225421
|
callbacks: {
|
|
222999
225422
|
onTextDelta: (d3) => {
|
|
223000
225423
|
setThinking(false);
|
|
@@ -223044,13 +225467,13 @@ function OperatorDashboard({
|
|
|
223044
225467
|
setThinking,
|
|
223045
225468
|
setIsExecuting
|
|
223046
225469
|
]);
|
|
223047
|
-
const handleSubmit =
|
|
225470
|
+
const handleSubmit = import_react82.useCallback((value) => {
|
|
223048
225471
|
if (!value.trim() || status === "running")
|
|
223049
225472
|
return;
|
|
223050
225473
|
setInputValue("");
|
|
223051
225474
|
runAgent(value.trim());
|
|
223052
225475
|
}, [status, runAgent]);
|
|
223053
|
-
const handleAbort =
|
|
225476
|
+
const handleAbort = import_react82.useCallback(() => {
|
|
223054
225477
|
if (abortControllerRef.current) {
|
|
223055
225478
|
abortControllerRef.current.abort();
|
|
223056
225479
|
abortControllerRef.current = null;
|
|
@@ -223261,7 +225684,8 @@ Session paths:
|
|
|
223261
225684
|
}
|
|
223262
225685
|
|
|
223263
225686
|
// src/tui/components/commands/theme-picker.tsx
|
|
223264
|
-
var
|
|
225687
|
+
var import_react84 = __toESM(require_react(), 1);
|
|
225688
|
+
init_config2();
|
|
223265
225689
|
function ThemePicker() {
|
|
223266
225690
|
const dimensions = useTerminalDimensions();
|
|
223267
225691
|
const route = useRoute();
|
|
@@ -223274,15 +225698,15 @@ function ThemePicker() {
|
|
|
223274
225698
|
toggleMode,
|
|
223275
225699
|
setMode
|
|
223276
225700
|
} = useTheme();
|
|
223277
|
-
const [selectedIndex, setSelectedIndex] =
|
|
223278
|
-
const originalThemeRef =
|
|
223279
|
-
const originalModeRef =
|
|
223280
|
-
const handleClose =
|
|
225701
|
+
const [selectedIndex, setSelectedIndex] = import_react84.useState(() => Math.max(0, availableThemes.indexOf(theme.name)));
|
|
225702
|
+
const originalThemeRef = import_react84.useRef(theme.name);
|
|
225703
|
+
const originalModeRef = import_react84.useRef(mode);
|
|
225704
|
+
const handleClose = import_react84.useCallback(() => {
|
|
223281
225705
|
setTheme(originalThemeRef.current);
|
|
223282
225706
|
setMode(originalModeRef.current);
|
|
223283
225707
|
route.navigate({ type: "base", path: "home" });
|
|
223284
225708
|
}, [setTheme, setMode, route]);
|
|
223285
|
-
const handleConfirm =
|
|
225709
|
+
const handleConfirm = import_react84.useCallback(async () => {
|
|
223286
225710
|
const currentThemeName = availableThemes[selectedIndex];
|
|
223287
225711
|
if (currentThemeName) {
|
|
223288
225712
|
await config.update({ theme: currentThemeName });
|
|
@@ -225810,13 +228234,13 @@ async function detectTerminalMode(timeoutMs = 1000) {
|
|
|
225810
228234
|
|
|
225811
228235
|
// src/tui/index.tsx
|
|
225812
228236
|
function App({ appConfig }) {
|
|
225813
|
-
const [focusIndex, setFocusIndex] =
|
|
225814
|
-
const [cwd, setCwd] =
|
|
225815
|
-
const [ctrlCPressTime, setCtrlCPressTime] =
|
|
225816
|
-
const [showExitWarning, setShowExitWarning] =
|
|
225817
|
-
const [inputKey, setInputKey] =
|
|
225818
|
-
const [showSessionsDialog, setShowSessionsDialog] =
|
|
225819
|
-
const [showShortcutsDialog, setShowShortcutsDialog] =
|
|
228237
|
+
const [focusIndex, setFocusIndex] = import_react87.useState(0);
|
|
228238
|
+
const [cwd, setCwd] = import_react87.useState(process.cwd());
|
|
228239
|
+
const [ctrlCPressTime, setCtrlCPressTime] = import_react87.useState(null);
|
|
228240
|
+
const [showExitWarning, setShowExitWarning] = import_react87.useState(false);
|
|
228241
|
+
const [inputKey, setInputKey] = import_react87.useState(0);
|
|
228242
|
+
const [showSessionsDialog, setShowSessionsDialog] = import_react87.useState(false);
|
|
228243
|
+
const [showShortcutsDialog, setShowShortcutsDialog] = import_react87.useState(false);
|
|
225820
228244
|
const navigableItems = ["command-input"];
|
|
225821
228245
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ConfigProvider, {
|
|
225822
228246
|
config: appConfig,
|
|
@@ -225880,14 +228304,14 @@ function AppContent({
|
|
|
225880
228304
|
const { toast } = useToast();
|
|
225881
228305
|
const { refocusPrompt } = useFocus();
|
|
225882
228306
|
const { setExternalDialogOpen } = useDialog();
|
|
225883
|
-
|
|
228307
|
+
import_react87.useEffect(() => {
|
|
225884
228308
|
checkForUpdate().then(({ updateAvailable, currentVersion, latestVersion }) => {
|
|
225885
228309
|
if (!updateAvailable)
|
|
225886
228310
|
return;
|
|
225887
228311
|
toast(`Update available: v${currentVersion} → v${latestVersion}. Run: pensar upgrade`, "warn", 8000);
|
|
225888
228312
|
});
|
|
225889
228313
|
}, []);
|
|
225890
|
-
|
|
228314
|
+
import_react87.useEffect(() => {
|
|
225891
228315
|
if (route.data.type !== "base")
|
|
225892
228316
|
return;
|
|
225893
228317
|
if (!config3.data.responsibleUseAccepted && route.data.path !== "disclosure") {
|
|
@@ -225896,7 +228320,7 @@ function AppContent({
|
|
|
225896
228320
|
route.navigate({ type: "base", path: "providers" });
|
|
225897
228321
|
}
|
|
225898
228322
|
}, [config3.data.responsibleUseAccepted, route.data]);
|
|
225899
|
-
|
|
228323
|
+
import_react87.useEffect(() => {
|
|
225900
228324
|
if (showExitWarning) {
|
|
225901
228325
|
const timer = setTimeout(() => {
|
|
225902
228326
|
setShowExitWarning(false);
|
|
@@ -226042,6 +228466,14 @@ function CommandDisplay({
|
|
|
226042
228466
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
|
|
226043
228467
|
when: "models",
|
|
226044
228468
|
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ModelsDisplay, {}, undefined, false, undefined, this)
|
|
228469
|
+
}, undefined, false, undefined, this),
|
|
228470
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
|
|
228471
|
+
when: "auth",
|
|
228472
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AuthFlow, {}, undefined, false, undefined, this)
|
|
228473
|
+
}, undefined, false, undefined, this),
|
|
228474
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
|
|
228475
|
+
when: "credits",
|
|
228476
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(CreditsFlow, {}, undefined, false, undefined, this)
|
|
226045
228477
|
}, undefined, false, undefined, this)
|
|
226046
228478
|
]
|
|
226047
228479
|
}, undefined, true, undefined, this)
|