@pensar/apex 0.0.77 → 0.0.78-canary.224df24d
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 +2817 -372
- 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.224df24d",
|
|
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) {
|
|
@@ -95700,6 +96450,20 @@ var init_stdio2 = __esm(() => {
|
|
|
95700
96450
|
import { createRequire as createRequire2 } from "module";
|
|
95701
96451
|
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync10 } from "fs";
|
|
95702
96452
|
import { join as join3, dirname as dirname2 } from "path";
|
|
96453
|
+
function transformScriptToFunction(script) {
|
|
96454
|
+
const trimmed = script.trim();
|
|
96455
|
+
const iifeTrailing = /\(\s*\)\s*;?\s*$/.test(trimmed);
|
|
96456
|
+
const iifeLeading = /^\s*\((?:async\s+)?(?:function|\()/.test(trimmed);
|
|
96457
|
+
if (iifeLeading && iifeTrailing) {
|
|
96458
|
+
let extracted = trimmed.replace(/\(\s*\)\s*;?\s*$/, "").trim();
|
|
96459
|
+
if (extracted.startsWith("(") && extracted.endsWith(")")) {
|
|
96460
|
+
extracted = extracted.slice(1, -1).trim();
|
|
96461
|
+
}
|
|
96462
|
+
return extracted;
|
|
96463
|
+
}
|
|
96464
|
+
const isFunction = /^\s*(async\s+)?\(/.test(script) || /^\s*(async\s+)?function\s*\(/.test(script);
|
|
96465
|
+
return isFunction ? script : `() => (${script})`;
|
|
96466
|
+
}
|
|
95703
96467
|
function withTimeout(promise3, ms, message) {
|
|
95704
96468
|
let timer;
|
|
95705
96469
|
const timeout = new Promise((_2, reject) => {
|
|
@@ -96041,8 +96805,7 @@ IMPORTANT: For reliable form filling, first call browser_snapshot to get element
|
|
|
96041
96805
|
toolCallDescription
|
|
96042
96806
|
}) => {
|
|
96043
96807
|
try {
|
|
96044
|
-
const
|
|
96045
|
-
const fnScript = isFunction ? script : `() => (${script})`;
|
|
96808
|
+
const fnScript = transformScriptToFunction(script);
|
|
96046
96809
|
const result = await session.callTool("browser_evaluate", { function: fnScript }, abortSignal);
|
|
96047
96810
|
return { success: true, script, result };
|
|
96048
96811
|
} catch (error40) {
|
|
@@ -96795,6 +97558,852 @@ var init_httpRequest = __esm(() => {
|
|
|
96795
97558
|
});
|
|
96796
97559
|
});
|
|
96797
97560
|
|
|
97561
|
+
// src/lib/cvss/types.ts
|
|
97562
|
+
function getSeverityFromScore(score) {
|
|
97563
|
+
if (score === 0)
|
|
97564
|
+
return "NONE";
|
|
97565
|
+
if (score <= 3.9)
|
|
97566
|
+
return "LOW";
|
|
97567
|
+
if (score <= 6.9)
|
|
97568
|
+
return "MEDIUM";
|
|
97569
|
+
if (score <= 8.9)
|
|
97570
|
+
return "HIGH";
|
|
97571
|
+
return "CRITICAL";
|
|
97572
|
+
}
|
|
97573
|
+
var init_types4 = () => {};
|
|
97574
|
+
|
|
97575
|
+
// src/lib/cvss/macrovector-scores.ts
|
|
97576
|
+
var MACROVECTOR_LOOKUP, METRIC_LEVELS, MAX_SEVERITY, STEP = 0.1, EPSILON;
|
|
97577
|
+
var init_macrovector_scores = __esm(() => {
|
|
97578
|
+
MACROVECTOR_LOOKUP = {
|
|
97579
|
+
"000000": 10,
|
|
97580
|
+
"000001": 9.9,
|
|
97581
|
+
"000010": 9.8,
|
|
97582
|
+
"000011": 9.5,
|
|
97583
|
+
"000020": 9.5,
|
|
97584
|
+
"000021": 9.2,
|
|
97585
|
+
"000100": 10,
|
|
97586
|
+
"000101": 9.6,
|
|
97587
|
+
"000110": 9.3,
|
|
97588
|
+
"000111": 8.7,
|
|
97589
|
+
"000120": 9.1,
|
|
97590
|
+
"000121": 8.1,
|
|
97591
|
+
"000200": 9.3,
|
|
97592
|
+
"000201": 9,
|
|
97593
|
+
"000210": 8.9,
|
|
97594
|
+
"000211": 8,
|
|
97595
|
+
"000220": 8.1,
|
|
97596
|
+
"000221": 6.8,
|
|
97597
|
+
"001000": 9.8,
|
|
97598
|
+
"001001": 9.5,
|
|
97599
|
+
"001010": 9.5,
|
|
97600
|
+
"001011": 9.2,
|
|
97601
|
+
"001020": 9,
|
|
97602
|
+
"001021": 8.4,
|
|
97603
|
+
"001100": 9.3,
|
|
97604
|
+
"001101": 9.2,
|
|
97605
|
+
"001110": 8.9,
|
|
97606
|
+
"001111": 8.1,
|
|
97607
|
+
"001120": 8.1,
|
|
97608
|
+
"001121": 6.5,
|
|
97609
|
+
"001200": 8.8,
|
|
97610
|
+
"001201": 8,
|
|
97611
|
+
"001210": 7.8,
|
|
97612
|
+
"001211": 7,
|
|
97613
|
+
"001220": 6.9,
|
|
97614
|
+
"001221": 4.8,
|
|
97615
|
+
"002001": 9.2,
|
|
97616
|
+
"002011": 8.2,
|
|
97617
|
+
"002021": 7.2,
|
|
97618
|
+
"002101": 7.9,
|
|
97619
|
+
"002111": 6.9,
|
|
97620
|
+
"002121": 5,
|
|
97621
|
+
"002201": 6.9,
|
|
97622
|
+
"002211": 5.5,
|
|
97623
|
+
"002221": 2.7,
|
|
97624
|
+
"010000": 9.9,
|
|
97625
|
+
"010001": 9.7,
|
|
97626
|
+
"010010": 9.5,
|
|
97627
|
+
"010011": 9.2,
|
|
97628
|
+
"010020": 9.2,
|
|
97629
|
+
"010021": 8.5,
|
|
97630
|
+
"010100": 9.5,
|
|
97631
|
+
"010101": 9.1,
|
|
97632
|
+
"010110": 9,
|
|
97633
|
+
"010111": 8.3,
|
|
97634
|
+
"010120": 8.4,
|
|
97635
|
+
"010121": 7.1,
|
|
97636
|
+
"010200": 9.2,
|
|
97637
|
+
"010201": 8.1,
|
|
97638
|
+
"010210": 8.2,
|
|
97639
|
+
"010211": 7.1,
|
|
97640
|
+
"010220": 7.2,
|
|
97641
|
+
"010221": 5.3,
|
|
97642
|
+
"011000": 9.5,
|
|
97643
|
+
"011001": 9.3,
|
|
97644
|
+
"011010": 9.2,
|
|
97645
|
+
"011011": 8.5,
|
|
97646
|
+
"011020": 8.5,
|
|
97647
|
+
"011021": 7.3,
|
|
97648
|
+
"011100": 9.2,
|
|
97649
|
+
"011101": 8.2,
|
|
97650
|
+
"011110": 8,
|
|
97651
|
+
"011111": 7.2,
|
|
97652
|
+
"011120": 7,
|
|
97653
|
+
"011121": 5.9,
|
|
97654
|
+
"011200": 8.4,
|
|
97655
|
+
"011201": 7,
|
|
97656
|
+
"011210": 7.1,
|
|
97657
|
+
"011211": 5.2,
|
|
97658
|
+
"011220": 5,
|
|
97659
|
+
"011221": 3,
|
|
97660
|
+
"012001": 8.6,
|
|
97661
|
+
"012011": 7.5,
|
|
97662
|
+
"012021": 5.2,
|
|
97663
|
+
"012101": 7.1,
|
|
97664
|
+
"012111": 5.2,
|
|
97665
|
+
"012121": 2.9,
|
|
97666
|
+
"012201": 6.3,
|
|
97667
|
+
"012211": 2.9,
|
|
97668
|
+
"012221": 1.7,
|
|
97669
|
+
"100000": 9.8,
|
|
97670
|
+
"100001": 9.5,
|
|
97671
|
+
"100010": 9.4,
|
|
97672
|
+
"100011": 8.7,
|
|
97673
|
+
"100020": 9.1,
|
|
97674
|
+
"100021": 8.1,
|
|
97675
|
+
"100100": 9.4,
|
|
97676
|
+
"100101": 8.9,
|
|
97677
|
+
"100110": 8.6,
|
|
97678
|
+
"100111": 7.4,
|
|
97679
|
+
"100120": 7.7,
|
|
97680
|
+
"100121": 6.4,
|
|
97681
|
+
"100200": 8.7,
|
|
97682
|
+
"100201": 7.5,
|
|
97683
|
+
"100210": 7.4,
|
|
97684
|
+
"100211": 6.3,
|
|
97685
|
+
"100220": 6.3,
|
|
97686
|
+
"100221": 4.9,
|
|
97687
|
+
"101000": 9.4,
|
|
97688
|
+
"101001": 8.9,
|
|
97689
|
+
"101010": 8.8,
|
|
97690
|
+
"101011": 7.7,
|
|
97691
|
+
"101020": 7.6,
|
|
97692
|
+
"101021": 6.7,
|
|
97693
|
+
"101100": 8.6,
|
|
97694
|
+
"101101": 7.6,
|
|
97695
|
+
"101110": 7.4,
|
|
97696
|
+
"101111": 5.8,
|
|
97697
|
+
"101120": 5.9,
|
|
97698
|
+
"101121": 5,
|
|
97699
|
+
"101200": 7.2,
|
|
97700
|
+
"101201": 5.7,
|
|
97701
|
+
"101210": 5.7,
|
|
97702
|
+
"101211": 5.2,
|
|
97703
|
+
"101220": 5.2,
|
|
97704
|
+
"101221": 2.5,
|
|
97705
|
+
"102001": 8.3,
|
|
97706
|
+
"102011": 7,
|
|
97707
|
+
"102021": 5.4,
|
|
97708
|
+
"102101": 6.5,
|
|
97709
|
+
"102111": 5.8,
|
|
97710
|
+
"102121": 2.6,
|
|
97711
|
+
"102201": 5.3,
|
|
97712
|
+
"102211": 2.1,
|
|
97713
|
+
"102221": 1.3,
|
|
97714
|
+
"110000": 9.5,
|
|
97715
|
+
"110001": 9,
|
|
97716
|
+
"110010": 8.8,
|
|
97717
|
+
"110011": 7.6,
|
|
97718
|
+
"110020": 7.6,
|
|
97719
|
+
"110021": 7,
|
|
97720
|
+
"110100": 9,
|
|
97721
|
+
"110101": 7.7,
|
|
97722
|
+
"110110": 7.5,
|
|
97723
|
+
"110111": 6.2,
|
|
97724
|
+
"110120": 6.1,
|
|
97725
|
+
"110121": 5.3,
|
|
97726
|
+
"110200": 7.7,
|
|
97727
|
+
"110201": 6.6,
|
|
97728
|
+
"110210": 6.8,
|
|
97729
|
+
"110211": 5.9,
|
|
97730
|
+
"110220": 5.2,
|
|
97731
|
+
"110221": 3,
|
|
97732
|
+
"111000": 8.9,
|
|
97733
|
+
"111001": 7.8,
|
|
97734
|
+
"111010": 7.6,
|
|
97735
|
+
"111011": 6.7,
|
|
97736
|
+
"111020": 6.2,
|
|
97737
|
+
"111021": 5.8,
|
|
97738
|
+
"111100": 7.4,
|
|
97739
|
+
"111101": 5.9,
|
|
97740
|
+
"111110": 5.7,
|
|
97741
|
+
"111111": 5.7,
|
|
97742
|
+
"111120": 4.7,
|
|
97743
|
+
"111121": 2.3,
|
|
97744
|
+
"111200": 6.1,
|
|
97745
|
+
"111201": 5.2,
|
|
97746
|
+
"111210": 5.7,
|
|
97747
|
+
"111211": 2.9,
|
|
97748
|
+
"111220": 2.4,
|
|
97749
|
+
"111221": 1.6,
|
|
97750
|
+
"112001": 7.1,
|
|
97751
|
+
"112011": 5.9,
|
|
97752
|
+
"112021": 3,
|
|
97753
|
+
"112101": 5.8,
|
|
97754
|
+
"112111": 2.6,
|
|
97755
|
+
"112121": 1.5,
|
|
97756
|
+
"112201": 2.3,
|
|
97757
|
+
"112211": 1.3,
|
|
97758
|
+
"112221": 0.6,
|
|
97759
|
+
"200000": 9.3,
|
|
97760
|
+
"200001": 8.7,
|
|
97761
|
+
"200010": 8.6,
|
|
97762
|
+
"200011": 7.2,
|
|
97763
|
+
"200020": 7.5,
|
|
97764
|
+
"200021": 5.8,
|
|
97765
|
+
"200100": 8.6,
|
|
97766
|
+
"200101": 7.4,
|
|
97767
|
+
"200110": 7.4,
|
|
97768
|
+
"200111": 6.1,
|
|
97769
|
+
"200120": 5.6,
|
|
97770
|
+
"200121": 3.4,
|
|
97771
|
+
"200200": 7,
|
|
97772
|
+
"200201": 5.4,
|
|
97773
|
+
"200210": 5.2,
|
|
97774
|
+
"200211": 4,
|
|
97775
|
+
"200220": 4,
|
|
97776
|
+
"200221": 2.2,
|
|
97777
|
+
"201000": 8.5,
|
|
97778
|
+
"201001": 7.5,
|
|
97779
|
+
"201010": 7.4,
|
|
97780
|
+
"201011": 5.5,
|
|
97781
|
+
"201020": 6.2,
|
|
97782
|
+
"201021": 5.1,
|
|
97783
|
+
"201100": 7.2,
|
|
97784
|
+
"201101": 5.7,
|
|
97785
|
+
"201110": 5.5,
|
|
97786
|
+
"201111": 4.1,
|
|
97787
|
+
"201120": 4.6,
|
|
97788
|
+
"201121": 1.9,
|
|
97789
|
+
"201200": 5.3,
|
|
97790
|
+
"201201": 3.6,
|
|
97791
|
+
"201210": 3.4,
|
|
97792
|
+
"201211": 1.9,
|
|
97793
|
+
"201220": 1.9,
|
|
97794
|
+
"201221": 0.8,
|
|
97795
|
+
"202001": 6.4,
|
|
97796
|
+
"202011": 5.1,
|
|
97797
|
+
"202021": 2,
|
|
97798
|
+
"202101": 4.7,
|
|
97799
|
+
"202111": 2.1,
|
|
97800
|
+
"202121": 1.1,
|
|
97801
|
+
"202201": 2.4,
|
|
97802
|
+
"202211": 0.9,
|
|
97803
|
+
"202221": 0.4,
|
|
97804
|
+
"210000": 8.8,
|
|
97805
|
+
"210001": 7.5,
|
|
97806
|
+
"210010": 7.3,
|
|
97807
|
+
"210011": 5.3,
|
|
97808
|
+
"210020": 6,
|
|
97809
|
+
"210021": 5,
|
|
97810
|
+
"210100": 7.3,
|
|
97811
|
+
"210101": 5.5,
|
|
97812
|
+
"210110": 5.9,
|
|
97813
|
+
"210111": 4,
|
|
97814
|
+
"210120": 4.1,
|
|
97815
|
+
"210121": 2,
|
|
97816
|
+
"210200": 5.4,
|
|
97817
|
+
"210201": 4.3,
|
|
97818
|
+
"210210": 4.5,
|
|
97819
|
+
"210211": 2.2,
|
|
97820
|
+
"210220": 2,
|
|
97821
|
+
"210221": 1.1,
|
|
97822
|
+
"211000": 7.5,
|
|
97823
|
+
"211001": 5.5,
|
|
97824
|
+
"211010": 5.8,
|
|
97825
|
+
"211011": 4.5,
|
|
97826
|
+
"211020": 4,
|
|
97827
|
+
"211021": 2.1,
|
|
97828
|
+
"211100": 6.1,
|
|
97829
|
+
"211101": 5.1,
|
|
97830
|
+
"211110": 4.8,
|
|
97831
|
+
"211111": 1.8,
|
|
97832
|
+
"211120": 2,
|
|
97833
|
+
"211121": 0.9,
|
|
97834
|
+
"211200": 4.6,
|
|
97835
|
+
"211201": 1.8,
|
|
97836
|
+
"211210": 1.7,
|
|
97837
|
+
"211211": 0.7,
|
|
97838
|
+
"211220": 0.8,
|
|
97839
|
+
"211221": 0.2,
|
|
97840
|
+
"212001": 5.3,
|
|
97841
|
+
"212011": 2.4,
|
|
97842
|
+
"212021": 1.4,
|
|
97843
|
+
"212101": 2.4,
|
|
97844
|
+
"212111": 1.2,
|
|
97845
|
+
"212121": 0.5,
|
|
97846
|
+
"212201": 1,
|
|
97847
|
+
"212211": 0.3,
|
|
97848
|
+
"212221": 0.1
|
|
97849
|
+
};
|
|
97850
|
+
METRIC_LEVELS = {
|
|
97851
|
+
AV: { N: 0, A: 0.1, L: 0.2, P: 0.3 },
|
|
97852
|
+
PR: { N: 0, L: 0.1, H: 0.2 },
|
|
97853
|
+
UI: { N: 0, P: 0.1, A: 0.2 },
|
|
97854
|
+
AC: { L: 0, H: 0.1 },
|
|
97855
|
+
AT: { N: 0, P: 0.1 },
|
|
97856
|
+
VC: { H: 0, L: 0.1, N: 0.2 },
|
|
97857
|
+
VI: { H: 0, L: 0.1, N: 0.2 },
|
|
97858
|
+
VA: { H: 0, L: 0.1, N: 0.2 },
|
|
97859
|
+
SC: { H: 0.1, L: 0.2, N: 0.3 },
|
|
97860
|
+
SI: { S: 0, H: 0.1, L: 0.2, N: 0.3 },
|
|
97861
|
+
SA: { S: 0, H: 0.1, L: 0.2, N: 0.3 },
|
|
97862
|
+
CR: { H: 0, M: 0.1, L: 0.2 },
|
|
97863
|
+
IR: { H: 0, M: 0.1, L: 0.2 },
|
|
97864
|
+
AR: { H: 0, M: 0.1, L: 0.2 },
|
|
97865
|
+
E: { A: 0, P: 0.1, U: 0.2 }
|
|
97866
|
+
};
|
|
97867
|
+
MAX_SEVERITY = {
|
|
97868
|
+
eq1: { 0: 1, 1: 4, 2: 5 },
|
|
97869
|
+
eq2: { 0: 1, 1: 2 },
|
|
97870
|
+
eq3eq6: {
|
|
97871
|
+
0: { 0: 7, 1: 6 },
|
|
97872
|
+
1: { 0: 8, 1: 8 },
|
|
97873
|
+
2: { 1: 10 }
|
|
97874
|
+
},
|
|
97875
|
+
eq4: { 0: 6, 1: 5, 2: 4 },
|
|
97876
|
+
eq5: { 0: 1, 1: 1, 2: 1 }
|
|
97877
|
+
};
|
|
97878
|
+
EPSILON = Math.pow(10, -6);
|
|
97879
|
+
});
|
|
97880
|
+
|
|
97881
|
+
// src/lib/cvss/calculator.ts
|
|
97882
|
+
function buildVectorString(metrics) {
|
|
97883
|
+
const parts = ["CVSS:4.0"];
|
|
97884
|
+
for (const metric of BASE_METRICS) {
|
|
97885
|
+
const value = metrics[metric];
|
|
97886
|
+
if (value !== undefined) {
|
|
97887
|
+
parts.push(`${metric}:${value}`);
|
|
97888
|
+
}
|
|
97889
|
+
}
|
|
97890
|
+
for (const metric of THREAT_METRICS) {
|
|
97891
|
+
const value = metrics[metric];
|
|
97892
|
+
if (value !== undefined && value !== "X") {
|
|
97893
|
+
parts.push(`${metric}:${value}`);
|
|
97894
|
+
}
|
|
97895
|
+
}
|
|
97896
|
+
for (const metric of ENVIRONMENTAL_METRICS) {
|
|
97897
|
+
const value = metrics[metric];
|
|
97898
|
+
if (value !== undefined && value !== "X") {
|
|
97899
|
+
parts.push(`${metric}:${value}`);
|
|
97900
|
+
}
|
|
97901
|
+
}
|
|
97902
|
+
for (const metric of SUPPLEMENTAL_METRICS) {
|
|
97903
|
+
const value = metrics[metric];
|
|
97904
|
+
if (value !== undefined && value !== "X") {
|
|
97905
|
+
parts.push(`${metric}:${value}`);
|
|
97906
|
+
}
|
|
97907
|
+
}
|
|
97908
|
+
return parts.join("/");
|
|
97909
|
+
}
|
|
97910
|
+
function getEffectiveValue(metrics, baseMetric, modifiedMetric) {
|
|
97911
|
+
if (modifiedMetric) {
|
|
97912
|
+
const modValue = metrics[modifiedMetric];
|
|
97913
|
+
if (modValue && modValue !== "X") {
|
|
97914
|
+
return modValue;
|
|
97915
|
+
}
|
|
97916
|
+
}
|
|
97917
|
+
return metrics[baseMetric] ?? "";
|
|
97918
|
+
}
|
|
97919
|
+
function computeEQ1(metrics) {
|
|
97920
|
+
const av = getEffectiveValue(metrics, "AV", "MAV");
|
|
97921
|
+
const pr = getEffectiveValue(metrics, "PR", "MPR");
|
|
97922
|
+
const ui = getEffectiveValue(metrics, "UI", "MUI");
|
|
97923
|
+
if (av === "N" && pr === "N" && ui === "N") {
|
|
97924
|
+
return 0;
|
|
97925
|
+
}
|
|
97926
|
+
if (!(av === "P" || pr === "H" || ui === "A")) {
|
|
97927
|
+
return 1;
|
|
97928
|
+
}
|
|
97929
|
+
return 2;
|
|
97930
|
+
}
|
|
97931
|
+
function computeEQ2(metrics) {
|
|
97932
|
+
const ac = getEffectiveValue(metrics, "AC", "MAC");
|
|
97933
|
+
const at = getEffectiveValue(metrics, "AT", "MAT");
|
|
97934
|
+
if (ac === "L" && at === "N") {
|
|
97935
|
+
return 0;
|
|
97936
|
+
}
|
|
97937
|
+
return 1;
|
|
97938
|
+
}
|
|
97939
|
+
function computeEQ3(metrics) {
|
|
97940
|
+
const vc = getEffectiveValue(metrics, "VC", "MVC");
|
|
97941
|
+
const vi = getEffectiveValue(metrics, "VI", "MVI");
|
|
97942
|
+
const va = getEffectiveValue(metrics, "VA", "MVA");
|
|
97943
|
+
if (vc === "H" && vi === "H") {
|
|
97944
|
+
return 0;
|
|
97945
|
+
}
|
|
97946
|
+
if (vc === "H" || vi === "H" || va === "H") {
|
|
97947
|
+
return 1;
|
|
97948
|
+
}
|
|
97949
|
+
return 2;
|
|
97950
|
+
}
|
|
97951
|
+
function computeEQ4(metrics) {
|
|
97952
|
+
const msi = metrics.MSI || "X";
|
|
97953
|
+
const msa = metrics.MSA || "X";
|
|
97954
|
+
const sc = getEffectiveValue(metrics, "SC", "MSC");
|
|
97955
|
+
const si = msi !== "X" ? msi : metrics.SI;
|
|
97956
|
+
const sa = msa !== "X" ? msa : metrics.SA;
|
|
97957
|
+
if (msi === "S" || msa === "S") {
|
|
97958
|
+
return 0;
|
|
97959
|
+
}
|
|
97960
|
+
if (sc === "H" || si === "H" || sa === "H") {
|
|
97961
|
+
return 1;
|
|
97962
|
+
}
|
|
97963
|
+
return 2;
|
|
97964
|
+
}
|
|
97965
|
+
function computeEQ5(metrics) {
|
|
97966
|
+
const e = metrics.E || "A";
|
|
97967
|
+
if (e === "A" || e === "X") {
|
|
97968
|
+
return 0;
|
|
97969
|
+
}
|
|
97970
|
+
if (e === "P") {
|
|
97971
|
+
return 1;
|
|
97972
|
+
}
|
|
97973
|
+
return 2;
|
|
97974
|
+
}
|
|
97975
|
+
function computeEQ6(metrics) {
|
|
97976
|
+
const cr = metrics.CR || "H";
|
|
97977
|
+
const ir = metrics.IR || "H";
|
|
97978
|
+
const ar = metrics.AR || "H";
|
|
97979
|
+
const vc = getEffectiveValue(metrics, "VC", "MVC");
|
|
97980
|
+
const vi = getEffectiveValue(metrics, "VI", "MVI");
|
|
97981
|
+
const va = getEffectiveValue(metrics, "VA", "MVA");
|
|
97982
|
+
if (cr === "H" && vc === "H" || ir === "H" && vi === "H" || ar === "H" && va === "H") {
|
|
97983
|
+
return 0;
|
|
97984
|
+
}
|
|
97985
|
+
return 1;
|
|
97986
|
+
}
|
|
97987
|
+
function computeMacroVector(metrics) {
|
|
97988
|
+
const eq1 = computeEQ1(metrics);
|
|
97989
|
+
const eq2 = computeEQ2(metrics);
|
|
97990
|
+
const eq3 = computeEQ3(metrics);
|
|
97991
|
+
const eq4 = computeEQ4(metrics);
|
|
97992
|
+
const eq5 = computeEQ5(metrics);
|
|
97993
|
+
const eq6 = computeEQ6(metrics);
|
|
97994
|
+
return `${eq1}${eq2}${eq3}${eq4}${eq5}${eq6}`;
|
|
97995
|
+
}
|
|
97996
|
+
function hasNoImpact(metrics) {
|
|
97997
|
+
const vc = getEffectiveValue(metrics, "VC", "MVC");
|
|
97998
|
+
const vi = getEffectiveValue(metrics, "VI", "MVI");
|
|
97999
|
+
const va = getEffectiveValue(metrics, "VA", "MVA");
|
|
98000
|
+
const sc = getEffectiveValue(metrics, "SC", "MSC");
|
|
98001
|
+
const si = metrics.MSI !== "X" && metrics.MSI ? metrics.MSI : metrics.SI;
|
|
98002
|
+
const sa = metrics.MSA !== "X" && metrics.MSA ? metrics.MSA : metrics.SA;
|
|
98003
|
+
return vc === "N" && vi === "N" && va === "N" && sc === "N" && si === "N" && sa === "N";
|
|
98004
|
+
}
|
|
98005
|
+
function getMetricDistance(metrics, metric) {
|
|
98006
|
+
const levels = METRIC_LEVELS[metric];
|
|
98007
|
+
if (!levels)
|
|
98008
|
+
return 0;
|
|
98009
|
+
let value;
|
|
98010
|
+
const modifiedMetric = "M" + metric;
|
|
98011
|
+
const metricsRecord = metrics;
|
|
98012
|
+
if (metricsRecord[modifiedMetric] && metricsRecord[modifiedMetric] !== "X") {
|
|
98013
|
+
value = metricsRecord[modifiedMetric] ?? "";
|
|
98014
|
+
} else {
|
|
98015
|
+
value = metricsRecord[metric] ?? "";
|
|
98016
|
+
}
|
|
98017
|
+
if (metric === "E" && (!value || value === "X")) {
|
|
98018
|
+
value = "A";
|
|
98019
|
+
}
|
|
98020
|
+
if ((metric === "CR" || metric === "IR" || metric === "AR") && (!value || value === "X")) {
|
|
98021
|
+
value = "H";
|
|
98022
|
+
}
|
|
98023
|
+
return levels[value] || 0;
|
|
98024
|
+
}
|
|
98025
|
+
function getNextLowerScore(macroVector, position) {
|
|
98026
|
+
const digits = macroVector.split("").map(Number);
|
|
98027
|
+
digits[position]++;
|
|
98028
|
+
const nextMacroVector = digits.join("");
|
|
98029
|
+
return MACROVECTOR_LOOKUP[nextMacroVector] ?? null;
|
|
98030
|
+
}
|
|
98031
|
+
function interpolateScore(metrics, macroVector, baseScore) {
|
|
98032
|
+
const eq1 = parseInt(macroVector[0]);
|
|
98033
|
+
const eq2 = parseInt(macroVector[1]);
|
|
98034
|
+
const eq3 = parseInt(macroVector[2]);
|
|
98035
|
+
const eq4 = parseInt(macroVector[3]);
|
|
98036
|
+
const eq5 = parseInt(macroVector[4]);
|
|
98037
|
+
const eq6 = parseInt(macroVector[5]);
|
|
98038
|
+
let meanDistance = 0;
|
|
98039
|
+
let eqCount = 0;
|
|
98040
|
+
const eq1NextLower = getNextLowerScore(macroVector, 0);
|
|
98041
|
+
if (eq1NextLower !== null) {
|
|
98042
|
+
const msd = baseScore - eq1NextLower;
|
|
98043
|
+
const maxDepth = MAX_SEVERITY.eq1[eq1] || 1;
|
|
98044
|
+
const avDist = getMetricDistance(metrics, "AV");
|
|
98045
|
+
const prDist = getMetricDistance(metrics, "PR");
|
|
98046
|
+
const uiDist = getMetricDistance(metrics, "UI");
|
|
98047
|
+
const severityDist = avDist + prDist + uiDist;
|
|
98048
|
+
const normalizedDist = severityDist / (maxDepth * STEP);
|
|
98049
|
+
meanDistance += msd * normalizedDist;
|
|
98050
|
+
eqCount++;
|
|
98051
|
+
}
|
|
98052
|
+
const eq2NextLower = getNextLowerScore(macroVector, 1);
|
|
98053
|
+
if (eq2NextLower !== null) {
|
|
98054
|
+
const msd = baseScore - eq2NextLower;
|
|
98055
|
+
const maxDepth = MAX_SEVERITY.eq2[eq2] || 1;
|
|
98056
|
+
const acDist = getMetricDistance(metrics, "AC");
|
|
98057
|
+
const atDist = getMetricDistance(metrics, "AT");
|
|
98058
|
+
const severityDist = acDist + atDist;
|
|
98059
|
+
const normalizedDist = severityDist / (maxDepth * STEP);
|
|
98060
|
+
meanDistance += msd * normalizedDist;
|
|
98061
|
+
eqCount++;
|
|
98062
|
+
}
|
|
98063
|
+
const eq3eq6MaxSeverity = MAX_SEVERITY.eq3eq6;
|
|
98064
|
+
if (eq3eq6MaxSeverity[eq3] && eq3eq6MaxSeverity[eq3][eq6] !== undefined) {
|
|
98065
|
+
const eq3NextLower = getNextLowerScore(macroVector, 2);
|
|
98066
|
+
if (eq3NextLower !== null) {
|
|
98067
|
+
const msd = baseScore - eq3NextLower;
|
|
98068
|
+
const maxDepth = eq3eq6MaxSeverity[eq3][eq6] || 1;
|
|
98069
|
+
const vcDist = getMetricDistance(metrics, "VC");
|
|
98070
|
+
const viDist = getMetricDistance(metrics, "VI");
|
|
98071
|
+
const vaDist = getMetricDistance(metrics, "VA");
|
|
98072
|
+
const crDist = getMetricDistance(metrics, "CR");
|
|
98073
|
+
const irDist = getMetricDistance(metrics, "IR");
|
|
98074
|
+
const arDist = getMetricDistance(metrics, "AR");
|
|
98075
|
+
const severityDist = vcDist + viDist + vaDist + crDist + irDist + arDist;
|
|
98076
|
+
const normalizedDist = severityDist / (maxDepth * STEP);
|
|
98077
|
+
meanDistance += msd * normalizedDist;
|
|
98078
|
+
eqCount++;
|
|
98079
|
+
}
|
|
98080
|
+
}
|
|
98081
|
+
const eq4NextLower = getNextLowerScore(macroVector, 3);
|
|
98082
|
+
if (eq4NextLower !== null) {
|
|
98083
|
+
const msd = baseScore - eq4NextLower;
|
|
98084
|
+
const maxDepth = MAX_SEVERITY.eq4[eq4] || 1;
|
|
98085
|
+
const scDist = getMetricDistance(metrics, "SC");
|
|
98086
|
+
const siDist = getMetricDistance(metrics, "SI");
|
|
98087
|
+
const saDist = getMetricDistance(metrics, "SA");
|
|
98088
|
+
const severityDist = scDist + siDist + saDist;
|
|
98089
|
+
const normalizedDist = severityDist / (maxDepth * STEP);
|
|
98090
|
+
meanDistance += msd * normalizedDist;
|
|
98091
|
+
eqCount++;
|
|
98092
|
+
}
|
|
98093
|
+
const eq5NextLower = getNextLowerScore(macroVector, 4);
|
|
98094
|
+
if (eq5NextLower !== null) {
|
|
98095
|
+
const msd = baseScore - eq5NextLower;
|
|
98096
|
+
const maxDepth = MAX_SEVERITY.eq5[eq5] || 1;
|
|
98097
|
+
const eDist = getMetricDistance(metrics, "E");
|
|
98098
|
+
const normalizedDist = eDist / (maxDepth * STEP);
|
|
98099
|
+
meanDistance += msd * normalizedDist;
|
|
98100
|
+
eqCount++;
|
|
98101
|
+
}
|
|
98102
|
+
const avgDistance = eqCount > 0 ? meanDistance / eqCount : 0;
|
|
98103
|
+
let finalScore = baseScore - avgDistance;
|
|
98104
|
+
finalScore = Math.max(0, Math.min(10, finalScore));
|
|
98105
|
+
finalScore = Math.round(finalScore * 10) / 10;
|
|
98106
|
+
return finalScore;
|
|
98107
|
+
}
|
|
98108
|
+
function calculateCVSS4Score(metrics) {
|
|
98109
|
+
if (hasNoImpact(metrics)) {
|
|
98110
|
+
return {
|
|
98111
|
+
score: 0,
|
|
98112
|
+
severity: "NONE",
|
|
98113
|
+
vectorString: buildVectorString(metrics),
|
|
98114
|
+
metrics,
|
|
98115
|
+
scoreType: getScoreType(metrics)
|
|
98116
|
+
};
|
|
98117
|
+
}
|
|
98118
|
+
const macroVector = computeMacroVector(metrics);
|
|
98119
|
+
const baseScore = MACROVECTOR_LOOKUP[macroVector];
|
|
98120
|
+
if (baseScore === undefined) {
|
|
98121
|
+
throw new Error(`Invalid MacroVector: ${macroVector}`);
|
|
98122
|
+
}
|
|
98123
|
+
const score = interpolateScore(metrics, macroVector, baseScore);
|
|
98124
|
+
const severity = getSeverityFromScore(score);
|
|
98125
|
+
const scoreType = getScoreType(metrics);
|
|
98126
|
+
return {
|
|
98127
|
+
score,
|
|
98128
|
+
severity,
|
|
98129
|
+
vectorString: buildVectorString(metrics),
|
|
98130
|
+
metrics,
|
|
98131
|
+
scoreType
|
|
98132
|
+
};
|
|
98133
|
+
}
|
|
98134
|
+
function getScoreType(metrics) {
|
|
98135
|
+
const hasThreat = metrics.E !== undefined && metrics.E !== "X";
|
|
98136
|
+
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";
|
|
98137
|
+
if (hasThreat && hasEnvironmental)
|
|
98138
|
+
return "CVSS-BTE";
|
|
98139
|
+
if (hasEnvironmental)
|
|
98140
|
+
return "CVSS-BE";
|
|
98141
|
+
if (hasThreat)
|
|
98142
|
+
return "CVSS-BT";
|
|
98143
|
+
return "CVSS-B";
|
|
98144
|
+
}
|
|
98145
|
+
var BASE_METRICS, THREAT_METRICS, ENVIRONMENTAL_METRICS, SUPPLEMENTAL_METRICS;
|
|
98146
|
+
var init_calculator = __esm(() => {
|
|
98147
|
+
init_types4();
|
|
98148
|
+
init_macrovector_scores();
|
|
98149
|
+
BASE_METRICS = [
|
|
98150
|
+
"AV",
|
|
98151
|
+
"AC",
|
|
98152
|
+
"AT",
|
|
98153
|
+
"PR",
|
|
98154
|
+
"UI",
|
|
98155
|
+
"VC",
|
|
98156
|
+
"VI",
|
|
98157
|
+
"VA",
|
|
98158
|
+
"SC",
|
|
98159
|
+
"SI",
|
|
98160
|
+
"SA"
|
|
98161
|
+
];
|
|
98162
|
+
THREAT_METRICS = ["E"];
|
|
98163
|
+
ENVIRONMENTAL_METRICS = [
|
|
98164
|
+
"CR",
|
|
98165
|
+
"IR",
|
|
98166
|
+
"AR",
|
|
98167
|
+
"MAV",
|
|
98168
|
+
"MAC",
|
|
98169
|
+
"MAT",
|
|
98170
|
+
"MPR",
|
|
98171
|
+
"MUI",
|
|
98172
|
+
"MVC",
|
|
98173
|
+
"MVI",
|
|
98174
|
+
"MVA",
|
|
98175
|
+
"MSC",
|
|
98176
|
+
"MSI",
|
|
98177
|
+
"MSA"
|
|
98178
|
+
];
|
|
98179
|
+
SUPPLEMENTAL_METRICS = ["S", "AU", "R", "V", "RE", "U"];
|
|
98180
|
+
});
|
|
98181
|
+
|
|
98182
|
+
// src/lib/cvss/index.ts
|
|
98183
|
+
var init_cvss = __esm(() => {
|
|
98184
|
+
init_types4();
|
|
98185
|
+
init_calculator();
|
|
98186
|
+
init_macrovector_scores();
|
|
98187
|
+
});
|
|
98188
|
+
|
|
98189
|
+
// src/core/agents/specialized/cvssScorer/index.ts
|
|
98190
|
+
async function scoreFindingWithCVSS(input, model, authConfig) {
|
|
98191
|
+
const prompt = buildScoringPrompt(input);
|
|
98192
|
+
const assessment = await generateObjectResponse({
|
|
98193
|
+
model,
|
|
98194
|
+
schema: CVSSMetricsOutputSchema,
|
|
98195
|
+
prompt,
|
|
98196
|
+
system: CVSS_SCORER_SYSTEM_PROMPT,
|
|
98197
|
+
authConfig
|
|
98198
|
+
});
|
|
98199
|
+
const cvssResult = calculateCVSS4Score({
|
|
98200
|
+
...assessment.metrics
|
|
98201
|
+
});
|
|
98202
|
+
return {
|
|
98203
|
+
score: cvssResult.score,
|
|
98204
|
+
severity: cvssResult.severity,
|
|
98205
|
+
vectorString: cvssResult.vectorString,
|
|
98206
|
+
metrics: cvssResult.metrics,
|
|
98207
|
+
scoreType: cvssResult.scoreType,
|
|
98208
|
+
reasoning: assessment.reasoning
|
|
98209
|
+
};
|
|
98210
|
+
}
|
|
98211
|
+
function buildScoringPrompt(input) {
|
|
98212
|
+
const { finding, agentMessages } = input;
|
|
98213
|
+
let prompt = `# Vulnerability Finding to Score
|
|
98214
|
+
|
|
98215
|
+
## Finding Details
|
|
98216
|
+
|
|
98217
|
+
**Title:** ${finding.title}
|
|
98218
|
+
**Vulnerability Class:** ${finding.vulnerabilityClass || "Unknown"}
|
|
98219
|
+
**Endpoint:** ${finding.endpoint}
|
|
98220
|
+
|
|
98221
|
+
### Description
|
|
98222
|
+
${finding.description}
|
|
98223
|
+
|
|
98224
|
+
### Impact Assessment
|
|
98225
|
+
${finding.impact}
|
|
98226
|
+
|
|
98227
|
+
### Evidence (POC Output)
|
|
98228
|
+
\`\`\`
|
|
98229
|
+
${finding.evidence}
|
|
98230
|
+
\`\`\`
|
|
98231
|
+
|
|
98232
|
+
`;
|
|
98233
|
+
if (agentMessages && agentMessages.length > 0) {
|
|
98234
|
+
prompt += `## Discovery Context
|
|
98235
|
+
|
|
98236
|
+
The following is a summary of how this vulnerability was discovered (from the testing agent's conversation):
|
|
98237
|
+
|
|
98238
|
+
`;
|
|
98239
|
+
const contextSummary = extractContextSummary(agentMessages);
|
|
98240
|
+
prompt += contextSummary;
|
|
98241
|
+
}
|
|
98242
|
+
prompt += `
|
|
98243
|
+
## Task
|
|
98244
|
+
|
|
98245
|
+
Analyze this vulnerability finding and determine the appropriate CVSS 4.0 metrics.
|
|
98246
|
+
|
|
98247
|
+
Consider:
|
|
98248
|
+
1. How the vulnerability is exploited (attack vector, complexity, requirements)
|
|
98249
|
+
2. What privileges/authentication were needed
|
|
98250
|
+
3. Whether user interaction is required
|
|
98251
|
+
4. The actual impact demonstrated in the evidence
|
|
98252
|
+
5. Potential for lateral movement or subsequent system compromise
|
|
98253
|
+
|
|
98254
|
+
Provide your metrics assessment and brief reasoning.
|
|
98255
|
+
`;
|
|
98256
|
+
return prompt;
|
|
98257
|
+
}
|
|
98258
|
+
function extractContextSummary(messages) {
|
|
98259
|
+
const contextParts = [];
|
|
98260
|
+
let foundToolCalls = 0;
|
|
98261
|
+
const maxToolCalls = 5;
|
|
98262
|
+
for (const message of messages) {
|
|
98263
|
+
if (foundToolCalls >= maxToolCalls)
|
|
98264
|
+
break;
|
|
98265
|
+
if (message.role === "assistant" && typeof message.content === "string") {
|
|
98266
|
+
const hypothesisMatch = message.content.match(/HYPOTHESIS:[\s\S]*?(?=VALIDATION:|$)/);
|
|
98267
|
+
const validationMatch = message.content.match(/VALIDATION:[\s\S]*?(?=HYPOTHESIS:|$)/);
|
|
98268
|
+
if (hypothesisMatch) {
|
|
98269
|
+
contextParts.push(`- ${hypothesisMatch[0].substring(0, 300)}...`);
|
|
98270
|
+
}
|
|
98271
|
+
if (validationMatch) {
|
|
98272
|
+
contextParts.push(`- ${validationMatch[0].substring(0, 300)}...`);
|
|
98273
|
+
}
|
|
98274
|
+
}
|
|
98275
|
+
if (message.role === "assistant" && Array.isArray(message.content)) {
|
|
98276
|
+
for (const rawPart of message.content) {
|
|
98277
|
+
const part = rawPart;
|
|
98278
|
+
if (part.type === "tool-call" && part.toolName) {
|
|
98279
|
+
const input = part.input;
|
|
98280
|
+
const desc = input?.toolCallDescription || `Used ${part.toolName}`;
|
|
98281
|
+
contextParts.push(`- Tool: ${String(desc)}`);
|
|
98282
|
+
foundToolCalls++;
|
|
98283
|
+
}
|
|
98284
|
+
}
|
|
98285
|
+
}
|
|
98286
|
+
}
|
|
98287
|
+
if (contextParts.length === 0) {
|
|
98288
|
+
return `No additional context available from testing conversation.
|
|
98289
|
+
`;
|
|
98290
|
+
}
|
|
98291
|
+
return contextParts.join(`
|
|
98292
|
+
`) + `
|
|
98293
|
+
`;
|
|
98294
|
+
}
|
|
98295
|
+
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.
|
|
98296
|
+
|
|
98297
|
+
## CVSS 4.0 Metrics Guide
|
|
98298
|
+
|
|
98299
|
+
### Attack Vector (AV)
|
|
98300
|
+
- **N (Network)**: Remotely exploitable over the internet (web app vulns, network services)
|
|
98301
|
+
- **A (Adjacent)**: Requires shared physical or logical network (same WiFi, VLAN)
|
|
98302
|
+
- **L (Local)**: Requires local access or user interaction to deliver payload
|
|
98303
|
+
- **P (Physical)**: Requires physical hardware access
|
|
98304
|
+
|
|
98305
|
+
### Attack Complexity (AC)
|
|
98306
|
+
- **L (Low)**: No special preparation needed, works reliably
|
|
98307
|
+
- **H (High)**: Requires race conditions, bypassing defenses, or specific configurations
|
|
98308
|
+
|
|
98309
|
+
### Attack Requirements (AT)
|
|
98310
|
+
- **N (None)**: Works under normal conditions
|
|
98311
|
+
- **P (Present)**: Requires specific deployment conditions (race window, man-in-the-middle position)
|
|
98312
|
+
|
|
98313
|
+
### Privileges Required (PR)
|
|
98314
|
+
- **N (None)**: Unauthenticated attack
|
|
98315
|
+
- **L (Low)**: Requires basic user-level privileges
|
|
98316
|
+
- **H (High)**: Requires administrative/root privileges
|
|
98317
|
+
|
|
98318
|
+
### User Interaction (UI)
|
|
98319
|
+
- **N (None)**: No user action required
|
|
98320
|
+
- **P (Passive)**: User visits a page, opens a file, or is on a vulnerable session
|
|
98321
|
+
- **A (Active)**: User must click a link, dismiss warnings, or actively interact
|
|
98322
|
+
|
|
98323
|
+
### Confidentiality Impact (VC - Vulnerable System, SC - Subsequent Systems)
|
|
98324
|
+
- **H (High)**: Complete loss of confidentiality (full data access, credential theft)
|
|
98325
|
+
- **L (Low)**: Limited data exposure (some info leak but not critical)
|
|
98326
|
+
- **N (None)**: No confidentiality impact
|
|
98327
|
+
|
|
98328
|
+
### Integrity Impact (VI - Vulnerable System, SI - Subsequent Systems)
|
|
98329
|
+
- **H (High)**: Complete loss of integrity (arbitrary modification, code execution)
|
|
98330
|
+
- **L (Low)**: Limited modification capability
|
|
98331
|
+
- **N (None)**: No integrity impact
|
|
98332
|
+
|
|
98333
|
+
### Availability Impact (VA - Vulnerable System, SA - Subsequent Systems)
|
|
98334
|
+
- **H (High)**: Complete denial of service
|
|
98335
|
+
- **L (Low)**: Reduced performance or intermittent availability
|
|
98336
|
+
- **N (None)**: No availability impact
|
|
98337
|
+
|
|
98338
|
+
### Exploit Maturity (E)
|
|
98339
|
+
- **A (Attacked)**: Working exploit exists (POC confirmed vulnerability)
|
|
98340
|
+
- **P (POC)**: Proof-of-concept code exists but may not be weaponized
|
|
98341
|
+
- **U (Unreported)**: No known public exploit
|
|
98342
|
+
|
|
98343
|
+
## Vulnerability Class Guidelines
|
|
98344
|
+
|
|
98345
|
+
### SQL Injection (sqli)
|
|
98346
|
+
- Typically: AV:N, AC:L, AT:N, PR varies, UI:N
|
|
98347
|
+
- VC:H (data access), VI:H (data modification), VA:L-H (depending on impact)
|
|
98348
|
+
- SC/SI/SA: Usually N unless database is shared
|
|
98349
|
+
|
|
98350
|
+
### Cross-Site Scripting (xss)
|
|
98351
|
+
- Reflected: AV:N, AC:L, AT:N, PR:N, UI:A (user must click)
|
|
98352
|
+
- Stored: AV:N, AC:L, AT:N, PR varies, UI:P (user visits page)
|
|
98353
|
+
- VC:L (session theft), VI:L (DOM modification), VA:N
|
|
98354
|
+
- SC/SI/SA: Usually N (client-side only)
|
|
98355
|
+
|
|
98356
|
+
### Command Injection / RCE
|
|
98357
|
+
- Typically: AV:N, AC:L, AT:N, PR varies, UI:N
|
|
98358
|
+
- VC:H, VI:H, VA:H (complete system compromise)
|
|
98359
|
+
- SC/SI/SA: Potentially H if can pivot
|
|
98360
|
+
|
|
98361
|
+
### IDOR / Access Control
|
|
98362
|
+
- Typically: AV:N, AC:L, AT:N, PR:L (needs some access), UI:N
|
|
98363
|
+
- Impact varies based on what data is accessed
|
|
98364
|
+
|
|
98365
|
+
### SSRF
|
|
98366
|
+
- Typically: AV:N, AC:L, AT:N, PR varies, UI:N
|
|
98367
|
+
- VC on vulnerable: L-N, SC on subsequent: H (internal network access)
|
|
98368
|
+
|
|
98369
|
+
### Path Traversal / LFI
|
|
98370
|
+
- Typically: AV:N, AC:L, AT:N, PR varies, UI:N
|
|
98371
|
+
- VC:H (file read), VI:N (unless write), VA:N
|
|
98372
|
+
|
|
98373
|
+
## Analysis Instructions
|
|
98374
|
+
|
|
98375
|
+
1. Read the finding description and evidence carefully
|
|
98376
|
+
2. Consider the attack vector based on how the vulnerability was exploited
|
|
98377
|
+
3. Assess complexity based on whether special conditions were needed
|
|
98378
|
+
4. Determine privileges based on authentication requirements
|
|
98379
|
+
5. Evaluate user interaction based on exploit mechanics
|
|
98380
|
+
6. Assess impact on both the vulnerable system AND potential subsequent systems
|
|
98381
|
+
7. Since a POC exists and confirmed the vulnerability, E should typically be 'A'
|
|
98382
|
+
|
|
98383
|
+
Always provide brief reasoning explaining your key decisions.`;
|
|
98384
|
+
var init_cvssScorer = __esm(() => {
|
|
98385
|
+
init_zod();
|
|
98386
|
+
init_ai2();
|
|
98387
|
+
init_cvss();
|
|
98388
|
+
CVSSMetricsOutputSchema = exports_external.object({
|
|
98389
|
+
metrics: exports_external.object({
|
|
98390
|
+
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"),
|
|
98391
|
+
AC: exports_external.enum(["L", "H"]).describe("Attack Complexity: L=Low (no special conditions), H=High (requires specific conditions/bypassing)"),
|
|
98392
|
+
AT: exports_external.enum(["N", "P"]).describe("Attack Requirements: N=None (works in most configs), P=Present (requires race conditions/specific setup)"),
|
|
98393
|
+
PR: exports_external.enum(["N", "L", "H"]).describe("Privileges Required: N=None (unauthenticated), L=Low (basic user), H=High (admin)"),
|
|
98394
|
+
UI: exports_external.enum(["N", "P", "A"]).describe("User Interaction: N=None, P=Passive (user visits page), A=Active (user must click/interact)"),
|
|
98395
|
+
VC: exports_external.enum(["H", "L", "N"]).describe("Confidentiality Impact on Vulnerable System: H=High (total loss), L=Low (partial), N=None"),
|
|
98396
|
+
VI: exports_external.enum(["H", "L", "N"]).describe("Integrity Impact on Vulnerable System: H=High (total loss), L=Low (partial), N=None"),
|
|
98397
|
+
VA: exports_external.enum(["H", "L", "N"]).describe("Availability Impact on Vulnerable System: H=High (total loss), L=Low (partial), N=None"),
|
|
98398
|
+
SC: exports_external.enum(["H", "L", "N"]).describe("Confidentiality Impact on Subsequent Systems: H=High, L=Low, N=None (no pivoting)"),
|
|
98399
|
+
SI: exports_external.enum(["H", "L", "N"]).describe("Integrity Impact on Subsequent Systems: H=High, L=Low, N=None"),
|
|
98400
|
+
SA: exports_external.enum(["H", "L", "N"]).describe("Availability Impact on Subsequent Systems: H=High, L=Low, N=None"),
|
|
98401
|
+
E: exports_external.enum(["A", "P", "U"]).describe("Exploit Maturity: A=Attacked (working exploit exists), P=POC available, U=Unreported")
|
|
98402
|
+
}),
|
|
98403
|
+
reasoning: exports_external.string().describe("Brief explanation (2-3 sentences) of the key factors that influenced the metric choices")
|
|
98404
|
+
});
|
|
98405
|
+
});
|
|
98406
|
+
|
|
96798
98407
|
// src/core/agents/offSecAgent/tools/documentFinding.ts
|
|
96799
98408
|
import { join as join5 } from "path";
|
|
96800
98409
|
import { writeFileSync as writeFileSync4, appendFileSync as appendFileSync2 } from "fs";
|
|
@@ -96840,11 +98449,37 @@ FINDING STRUCTURE:
|
|
|
96840
98449
|
}
|
|
96841
98450
|
}
|
|
96842
98451
|
const timestamp = new Date().toISOString();
|
|
98452
|
+
let cvssResult;
|
|
98453
|
+
try {
|
|
98454
|
+
cvssResult = await scoreFindingWithCVSS({
|
|
98455
|
+
finding: {
|
|
98456
|
+
title: finding.title,
|
|
98457
|
+
description: finding.description,
|
|
98458
|
+
impact: finding.impact,
|
|
98459
|
+
evidence: finding.evidence,
|
|
98460
|
+
endpoint: finding.endpoint,
|
|
98461
|
+
remediation: finding.remediation
|
|
98462
|
+
},
|
|
98463
|
+
agentMessages: []
|
|
98464
|
+
}, ctx4.model, ctx4.authConfig);
|
|
98465
|
+
} catch (err) {
|
|
98466
|
+
console.warn("CVSS scoring failed, proceeding without score:", err instanceof Error ? err.message : err);
|
|
98467
|
+
}
|
|
96843
98468
|
const findingWithMeta = {
|
|
96844
98469
|
...finding,
|
|
96845
98470
|
timestamp,
|
|
96846
98471
|
sessionId: session.id,
|
|
96847
|
-
target: session.targets[0]
|
|
98472
|
+
target: session.targets[0],
|
|
98473
|
+
...cvssResult && {
|
|
98474
|
+
cvss: {
|
|
98475
|
+
score: cvssResult.score,
|
|
98476
|
+
severity: cvssResult.severity,
|
|
98477
|
+
vectorString: cvssResult.vectorString,
|
|
98478
|
+
metrics: cvssResult.metrics,
|
|
98479
|
+
scoreType: cvssResult.scoreType,
|
|
98480
|
+
reasoning: cvssResult.reasoning
|
|
98481
|
+
}
|
|
98482
|
+
}
|
|
96848
98483
|
};
|
|
96849
98484
|
const safeTitle = finding.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").substring(0, 50);
|
|
96850
98485
|
const findingId = `${timestamp.split("T")[0]}-${safeTitle}`;
|
|
@@ -96854,9 +98489,21 @@ FINDING STRUCTURE:
|
|
|
96854
98489
|
const mdPath = join5(session.findingsPath, mdFilename);
|
|
96855
98490
|
try {
|
|
96856
98491
|
writeFileSync4(jsonPath, JSON.stringify(findingWithMeta, null, 2));
|
|
98492
|
+
const cvssLine = cvssResult ? `
|
|
98493
|
+
**CVSS 4.0 Score:** ${cvssResult.score} (${cvssResult.severity})
|
|
98494
|
+
**Vector:** \`${cvssResult.vectorString}\` ` : "";
|
|
98495
|
+
const cvssSection = cvssResult ? `
|
|
98496
|
+
## CVSS 4.0 Assessment
|
|
98497
|
+
|
|
98498
|
+
**Score:** ${cvssResult.score} / 10.0 (${cvssResult.severity})
|
|
98499
|
+
**Vector:** \`${cvssResult.vectorString}\`
|
|
98500
|
+
**Score Type:** ${cvssResult.scoreType}
|
|
98501
|
+
|
|
98502
|
+
**Reasoning:** ${cvssResult.reasoning}
|
|
98503
|
+
` : "";
|
|
96857
98504
|
const markdown = `# ${finding.title}
|
|
96858
98505
|
|
|
96859
|
-
**Severity:** ${finding.severity}
|
|
98506
|
+
**Severity:** ${finding.severity} ${cvssLine}
|
|
96860
98507
|
**Target:** ${session.targets[0]}
|
|
96861
98508
|
**Endpoint:** ${finding.endpoint}
|
|
96862
98509
|
**Date:** ${timestamp}
|
|
@@ -96869,7 +98516,7 @@ ${finding.description}
|
|
|
96869
98516
|
## Impact
|
|
96870
98517
|
|
|
96871
98518
|
${finding.impact}
|
|
96872
|
-
|
|
98519
|
+
${cvssSection}
|
|
96873
98520
|
## Evidence
|
|
96874
98521
|
|
|
96875
98522
|
\`\`\`
|
|
@@ -96894,7 +98541,8 @@ ${finding.references}` : ""}
|
|
|
96894
98541
|
`;
|
|
96895
98542
|
writeFileSync4(mdPath, markdown);
|
|
96896
98543
|
const summaryPath = join5(session.rootPath, "findings-summary.md");
|
|
96897
|
-
const
|
|
98544
|
+
const cvssTag = cvssResult ? ` (CVSS ${cvssResult.score})` : "";
|
|
98545
|
+
const summaryEntry = `- [${finding.severity}]${cvssTag} ${finding.title} - \`findings/${mdFilename}\`
|
|
96898
98546
|
`;
|
|
96899
98547
|
try {
|
|
96900
98548
|
appendFileSync2(summaryPath, summaryEntry);
|
|
@@ -96936,6 +98584,7 @@ var documentVulnerabilityInputSchema;
|
|
|
96936
98584
|
var init_documentFinding = __esm(() => {
|
|
96937
98585
|
init_dist5();
|
|
96938
98586
|
init_zod();
|
|
98587
|
+
init_cvssScorer();
|
|
96939
98588
|
documentVulnerabilityInputSchema = exports_external.object({
|
|
96940
98589
|
title: exports_external.string().describe("Finding title"),
|
|
96941
98590
|
severity: exports_external.enum(["CRITICAL", "HIGH", "MEDIUM", "LOW"]),
|
|
@@ -99103,7 +100752,7 @@ For each app you identified, spawn a coding agent with a detailed objective. The
|
|
|
99103
100752
|
|
|
99104
100753
|
// src/core/agents/specialized/whiteboxAttackSurface/types.ts
|
|
99105
100754
|
var EndpointSchema, AppSchema, WhiteboxAttackSurfaceResultSchema;
|
|
99106
|
-
var
|
|
100755
|
+
var init_types5 = __esm(() => {
|
|
99107
100756
|
init_zod();
|
|
99108
100757
|
EndpointSchema = exports_external.object({
|
|
99109
100758
|
method: exports_external.string().describe("HTTP method (GET, POST, PUT, DELETE, etc.) or 'PAGE' for web pages"),
|
|
@@ -99165,7 +100814,7 @@ var init_agent2 = __esm(() => {
|
|
|
99165
100814
|
init_dist5();
|
|
99166
100815
|
init_dist5();
|
|
99167
100816
|
init_offensiveSecurityAgent();
|
|
99168
|
-
|
|
100817
|
+
init_types5();
|
|
99169
100818
|
WhiteboxAttackSurfaceAgent = class WhiteboxAttackSurfaceAgent extends OffensiveSecurityAgent {
|
|
99170
100819
|
constructor(opts) {
|
|
99171
100820
|
const {
|
|
@@ -99718,6 +101367,13 @@ var PentestResponseSchema, TargetedPentestAgent, PENTEST_SYSTEM_PROMPT = `You ar
|
|
|
99718
101367
|
|
|
99719
101368
|
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
101369
|
|
|
101370
|
+
CRITICAL — Source Code Prohibition:
|
|
101371
|
+
- You are performing a BLACKBOX penetration test. You must NEVER read, view, access, or analyze source code under any circumstances.
|
|
101372
|
+
- 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).
|
|
101373
|
+
- 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.
|
|
101374
|
+
- 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.
|
|
101375
|
+
- Your testing must rely exclusively on external interaction: sending requests, observing responses, and analyzing observable behavior.
|
|
101376
|
+
|
|
99721
101377
|
Your methodology:
|
|
99722
101378
|
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
101379
|
2. VERIFY — Confirm the target endpoint exists and is reachable. Understand its basic behavior (response format, parameters, auth requirements).
|
|
@@ -138829,7 +140485,7 @@ var require_node3 = __commonJS((exports, module2) => {
|
|
|
138829
140485
|
var tty = __require("tty");
|
|
138830
140486
|
var util4 = __require("util");
|
|
138831
140487
|
exports.init = init2;
|
|
138832
|
-
exports.log =
|
|
140488
|
+
exports.log = log2;
|
|
138833
140489
|
exports.formatArgs = formatArgs;
|
|
138834
140490
|
exports.save = save;
|
|
138835
140491
|
exports.load = load;
|
|
@@ -138961,7 +140617,7 @@ var require_node3 = __commonJS((exports, module2) => {
|
|
|
138961
140617
|
}
|
|
138962
140618
|
return new Date().toISOString() + " ";
|
|
138963
140619
|
}
|
|
138964
|
-
function
|
|
140620
|
+
function log2(...args) {
|
|
138965
140621
|
return process.stderr.write(util4.formatWithOptions(exports.inspectOpts, ...args) + `
|
|
138966
140622
|
`);
|
|
138967
140623
|
}
|
|
@@ -147926,7 +149582,7 @@ var require_logging_utils = __commonJS((exports) => {
|
|
|
147926
149582
|
exports.getDebugBackend = getDebugBackend;
|
|
147927
149583
|
exports.getStructuredBackend = getStructuredBackend;
|
|
147928
149584
|
exports.setBackend = setBackend;
|
|
147929
|
-
exports.log =
|
|
149585
|
+
exports.log = log2;
|
|
147930
149586
|
var events_1 = __require("events");
|
|
147931
149587
|
var process3 = __importStar(__require("process"));
|
|
147932
149588
|
var util4 = __importStar(__require("util"));
|
|
@@ -147953,7 +149609,7 @@ var require_logging_utils = __commonJS((exports) => {
|
|
|
147953
149609
|
this.func.info = (...args) => this.invokeSeverity(LogSeverity.INFO, ...args);
|
|
147954
149610
|
this.func.warn = (...args) => this.invokeSeverity(LogSeverity.WARNING, ...args);
|
|
147955
149611
|
this.func.error = (...args) => this.invokeSeverity(LogSeverity.ERROR, ...args);
|
|
147956
|
-
this.func.sublog = (namespace2) =>
|
|
149612
|
+
this.func.sublog = (namespace2) => log2(namespace2, this.func);
|
|
147957
149613
|
}
|
|
147958
149614
|
invoke(fields, ...args) {
|
|
147959
149615
|
if (this.upstream) {
|
|
@@ -148114,7 +149770,7 @@ var require_logging_utils = __commonJS((exports) => {
|
|
|
148114
149770
|
cachedBackend = backend;
|
|
148115
149771
|
loggerCache.clear();
|
|
148116
149772
|
}
|
|
148117
|
-
function
|
|
149773
|
+
function log2(namespace, parent) {
|
|
148118
149774
|
if (!cachedBackend) {
|
|
148119
149775
|
const enablesFlag = process3.env[exports.env.nodeEnables];
|
|
148120
149776
|
if (!enablesFlag) {
|
|
@@ -148254,7 +149910,7 @@ var require_src6 = __commonJS((exports) => {
|
|
|
148254
149910
|
exports.HEADER_NAME = "Metadata-Flavor";
|
|
148255
149911
|
exports.HEADER_VALUE = "Google";
|
|
148256
149912
|
exports.HEADERS = Object.freeze({ [exports.HEADER_NAME]: exports.HEADER_VALUE });
|
|
148257
|
-
var
|
|
149913
|
+
var log2 = logger.log("gcp-metadata");
|
|
148258
149914
|
exports.METADATA_SERVER_DETECTION = Object.freeze({
|
|
148259
149915
|
"assume-present": "don't try to ping the metadata server, but assume it's present",
|
|
148260
149916
|
none: "don't try to ping the metadata server, but don't try to use it either",
|
|
@@ -148317,9 +149973,9 @@ var require_src6 = __commonJS((exports) => {
|
|
|
148317
149973
|
responseType: "text",
|
|
148318
149974
|
timeout: requestTimeout()
|
|
148319
149975
|
};
|
|
148320
|
-
|
|
149976
|
+
log2.info("instance request %j", req);
|
|
148321
149977
|
const res = await requestMethod(req);
|
|
148322
|
-
|
|
149978
|
+
log2.info("instance metadata is %s", res.data);
|
|
148323
149979
|
const metadataFlavor = res.headers.get(exports.HEADER_NAME);
|
|
148324
149980
|
if (metadataFlavor !== exports.HEADER_VALUE) {
|
|
148325
149981
|
throw new RangeError(`Invalid response from metadata service: incorrect ${exports.HEADER_NAME} header. Expected '${exports.HEADER_VALUE}', got ${metadataFlavor ? `'${metadataFlavor}'` : "no header"}`);
|
|
@@ -156447,7 +158103,7 @@ var require_http2 = __commonJS((exports) => {
|
|
|
156447
158103
|
var process3 = __require("process");
|
|
156448
158104
|
var util_1 = require_util7();
|
|
156449
158105
|
var { HTTP2_HEADER_CONTENT_ENCODING, HTTP2_HEADER_CONTENT_TYPE, HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, HTTP2_HEADER_STATUS } = http22.constants;
|
|
156450
|
-
var
|
|
158106
|
+
var DEBUG2 = !!process3.env.HTTP2_DEBUG;
|
|
156451
158107
|
exports.sessions = {};
|
|
156452
158108
|
async function request(config3) {
|
|
156453
158109
|
const opts = extend3(true, {}, config3);
|
|
@@ -156561,7 +158217,7 @@ var require_http2 = __commonJS((exports) => {
|
|
|
156561
158217
|
}
|
|
156562
158218
|
function _getClient(host) {
|
|
156563
158219
|
if (!exports.sessions[host]) {
|
|
156564
|
-
if (
|
|
158220
|
+
if (DEBUG2) {
|
|
156565
158221
|
console.log(`Creating client for ${host}`);
|
|
156566
158222
|
}
|
|
156567
158223
|
const session = http22.connect(`https://${host}`);
|
|
@@ -156574,7 +158230,7 @@ var require_http2 = __commonJS((exports) => {
|
|
|
156574
158230
|
});
|
|
156575
158231
|
exports.sessions[host] = { session };
|
|
156576
158232
|
} else {
|
|
156577
|
-
if (
|
|
158233
|
+
if (DEBUG2) {
|
|
156578
158234
|
console.log(`Used cached client for ${host}`);
|
|
156579
158235
|
}
|
|
156580
158236
|
}
|
|
@@ -156587,17 +158243,17 @@ var require_http2 = __commonJS((exports) => {
|
|
|
156587
158243
|
}
|
|
156588
158244
|
const { session } = sessionData;
|
|
156589
158245
|
delete exports.sessions[url2.host];
|
|
156590
|
-
if (
|
|
158246
|
+
if (DEBUG2) {
|
|
156591
158247
|
console.error(`Closing ${url2.host}`);
|
|
156592
158248
|
}
|
|
156593
158249
|
session.close(() => {
|
|
156594
|
-
if (
|
|
158250
|
+
if (DEBUG2) {
|
|
156595
158251
|
console.error(`Closed ${url2.host}`);
|
|
156596
158252
|
}
|
|
156597
158253
|
});
|
|
156598
158254
|
setTimeout(() => {
|
|
156599
158255
|
if (session && !session.destroyed) {
|
|
156600
|
-
if (
|
|
158256
|
+
if (DEBUG2) {
|
|
156601
158257
|
console.log(`Forcing close ${url2.host}`);
|
|
156602
158258
|
}
|
|
156603
158259
|
if (session) {
|
|
@@ -166108,11 +167764,11 @@ var require_tools = __commonJS((exports, module2) => {
|
|
|
166108
167764
|
}
|
|
166109
167765
|
}
|
|
166110
167766
|
}
|
|
166111
|
-
function buildFormatters(level, bindings,
|
|
167767
|
+
function buildFormatters(level, bindings, log2) {
|
|
166112
167768
|
return {
|
|
166113
167769
|
level,
|
|
166114
167770
|
bindings,
|
|
166115
|
-
log
|
|
167771
|
+
log: log2
|
|
166116
167772
|
};
|
|
166117
167773
|
}
|
|
166118
167774
|
function normalizeDestFileDescriptor(destination) {
|
|
@@ -166457,8 +168113,8 @@ var require_proto = __commonJS((exports, module2) => {
|
|
|
166457
168113
|
} else
|
|
166458
168114
|
instance[serializersSym] = serializers;
|
|
166459
168115
|
if (options.hasOwnProperty("formatters")) {
|
|
166460
|
-
const { level, bindings: chindings, log } = options.formatters;
|
|
166461
|
-
instance[formattersSym] = buildFormatters(level || formatters.level, chindings || resetChildingsFormatter,
|
|
168116
|
+
const { level, bindings: chindings, log: log2 } = options.formatters;
|
|
168117
|
+
instance[formattersSym] = buildFormatters(level || formatters.level, chindings || resetChildingsFormatter, log2 || formatters.log);
|
|
166462
168118
|
} else {
|
|
166463
168119
|
instance[formattersSym] = buildFormatters(formatters.level, resetChildingsFormatter, formatters.log);
|
|
166464
168120
|
}
|
|
@@ -209469,219 +211125,16 @@ var useTerminalDimensions = () => {
|
|
|
209469
211125
|
};
|
|
209470
211126
|
|
|
209471
211127
|
// src/tui/index.tsx
|
|
209472
|
-
var
|
|
211128
|
+
var import_react87 = __toESM(require_react(), 1);
|
|
209473
211129
|
|
|
209474
211130
|
// src/tui/components/footer.tsx
|
|
209475
211131
|
import os5 from "os";
|
|
209476
211132
|
|
|
209477
211133
|
// src/tui/context/agent.tsx
|
|
209478
211134
|
init_models();
|
|
211135
|
+
init_config();
|
|
209479
211136
|
var import_react11 = __toESM(require_react(), 1);
|
|
209480
211137
|
|
|
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
211138
|
// src/core/providers/utils.ts
|
|
209686
211139
|
init_models();
|
|
209687
211140
|
|
|
@@ -209716,6 +211169,12 @@ var AVAILABLE_PROVIDERS = [
|
|
|
209716
211169
|
name: "Local LLM",
|
|
209717
211170
|
description: "OpenAI-compatible local model (vLLM, LM Studio, Ollama)",
|
|
209718
211171
|
requiresAPIKey: false
|
|
211172
|
+
},
|
|
211173
|
+
{
|
|
211174
|
+
id: "pensar",
|
|
211175
|
+
name: "Pensar",
|
|
211176
|
+
description: "Managed inference via Pensar Console (usage-based billing)",
|
|
211177
|
+
requiresAPIKey: true
|
|
209719
211178
|
}
|
|
209720
211179
|
];
|
|
209721
211180
|
|
|
@@ -209742,12 +211201,14 @@ function isProviderConfigured(providerId, config) {
|
|
|
209742
211201
|
return !!config.bedrockAPIKey;
|
|
209743
211202
|
case "local":
|
|
209744
211203
|
return !!(config.localModelUrl || config.localModelName || process.env.LOCAL_MODEL_URL);
|
|
211204
|
+
case "pensar":
|
|
211205
|
+
return !!(config.pensarAPIKey || config.accessToken);
|
|
209745
211206
|
default:
|
|
209746
211207
|
return false;
|
|
209747
211208
|
}
|
|
209748
211209
|
}
|
|
209749
211210
|
function hasAnyProviderConfigured(config) {
|
|
209750
|
-
return !!config.anthropicAPIKey || !!config.openAiAPIKey || !!config.openRouterAPIKey || !!config.bedrockAPIKey || !!config.localModelUrl || !!config.localModelName || !!process.env.LOCAL_MODEL_URL;
|
|
211211
|
+
return !!config.anthropicAPIKey || !!config.openAiAPIKey || !!config.openRouterAPIKey || !!config.bedrockAPIKey || !!config.localModelUrl || !!config.localModelName || !!process.env.LOCAL_MODEL_URL || !!config.pensarAPIKey || !!config.accessToken;
|
|
209751
211212
|
}
|
|
209752
211213
|
function getAvailableModels(config) {
|
|
209753
211214
|
const models = AVAILABLE_MODELS.filter((model) => {
|
|
@@ -209768,10 +211229,17 @@ var import_jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
|
|
|
209768
211229
|
|
|
209769
211230
|
// src/tui/context/agent.tsx
|
|
209770
211231
|
var PREFERRED_DEFAULTS = {
|
|
211232
|
+
pensar: "pensar:anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
209771
211233
|
anthropic: "claude-haiku-4-5",
|
|
209772
211234
|
openai: "gpt-4o-mini"
|
|
209773
211235
|
};
|
|
209774
|
-
var PROVIDER_PREFERENCE = [
|
|
211236
|
+
var PROVIDER_PREFERENCE = [
|
|
211237
|
+
"pensar",
|
|
211238
|
+
"anthropic",
|
|
211239
|
+
"openai",
|
|
211240
|
+
"openrouter",
|
|
211241
|
+
"bedrock"
|
|
211242
|
+
];
|
|
209775
211243
|
var AgentContext = import_react11.createContext(null);
|
|
209776
211244
|
function useAgent() {
|
|
209777
211245
|
const context = import_react11.useContext(AgentContext);
|
|
@@ -210091,6 +211559,9 @@ function create(prefix, descending2, timestamp) {
|
|
|
210091
211559
|
return prefixes[prefix] + "_" + timeBytes.toString("hex") + randomBase62(LENGTH - 12);
|
|
210092
211560
|
}
|
|
210093
211561
|
|
|
211562
|
+
// src/core/session/index.ts
|
|
211563
|
+
init_installation();
|
|
211564
|
+
|
|
210094
211565
|
// src/core/storage/index.ts
|
|
210095
211566
|
init_zod();
|
|
210096
211567
|
import os3 from "os";
|
|
@@ -210509,8 +211980,6 @@ var SessionConfigObject = zod_default.object({
|
|
|
210509
211980
|
authenticationInstructions: zod_default.string().optional(),
|
|
210510
211981
|
requestsPerSecond: zod_default.number().optional(),
|
|
210511
211982
|
operatorSettings: OperatorSettingsObject.optional(),
|
|
210512
|
-
enableCvssScoring: zod_default.boolean().optional(),
|
|
210513
|
-
cvssModel: zod_default.string().optional(),
|
|
210514
211983
|
toolsetState: ToolsetStateSchema.optional(),
|
|
210515
211984
|
enumerateSubdomains: zod_default.boolean().optional(),
|
|
210516
211985
|
cwd: zod_default.string().optional(),
|
|
@@ -211356,14 +212825,8 @@ async function createSwarmSessionFromFlags(flags) {
|
|
|
211356
212825
|
return session;
|
|
211357
212826
|
}
|
|
211358
212827
|
|
|
211359
|
-
// src/core/config/index.ts
|
|
211360
|
-
var config = {
|
|
211361
|
-
get,
|
|
211362
|
-
init,
|
|
211363
|
-
update
|
|
211364
|
-
};
|
|
211365
|
-
|
|
211366
212828
|
// src/tui/command-registry.ts
|
|
212829
|
+
init_config2();
|
|
211367
212830
|
var commands = [
|
|
211368
212831
|
{
|
|
211369
212832
|
name: "pentest",
|
|
@@ -211648,6 +213111,29 @@ var commands = [
|
|
|
211648
213111
|
handler: async () => {
|
|
211649
213112
|
process.kill(process.pid, "SIGINT");
|
|
211650
213113
|
}
|
|
213114
|
+
},
|
|
213115
|
+
{
|
|
213116
|
+
name: "auth",
|
|
213117
|
+
description: "Connect to Pensar Console for managed inference",
|
|
213118
|
+
category: "General",
|
|
213119
|
+
handler: async (args, ctx3) => {
|
|
213120
|
+
ctx3.navigate({
|
|
213121
|
+
type: "base",
|
|
213122
|
+
path: "auth"
|
|
213123
|
+
});
|
|
213124
|
+
}
|
|
213125
|
+
},
|
|
213126
|
+
{
|
|
213127
|
+
name: "credits",
|
|
213128
|
+
aliases: ["buy"],
|
|
213129
|
+
description: "Buy credits / check balance",
|
|
213130
|
+
category: "General",
|
|
213131
|
+
handler: async (args, ctx3) => {
|
|
213132
|
+
ctx3.navigate({
|
|
213133
|
+
type: "base",
|
|
213134
|
+
path: "credits"
|
|
213135
|
+
});
|
|
213136
|
+
}
|
|
211651
213137
|
}
|
|
211652
213138
|
];
|
|
211653
213139
|
var commandRegistry = commands.map((config2) => (ctx3) => ({
|
|
@@ -212325,6 +213811,7 @@ function AlertDialog({
|
|
|
212325
213811
|
}
|
|
212326
213812
|
|
|
212327
213813
|
// src/tui/components/commands/config-dialog.tsx
|
|
213814
|
+
init_config2();
|
|
212328
213815
|
function ConfigDialog() {
|
|
212329
213816
|
const route = useRoute();
|
|
212330
213817
|
const [open, setOpen] = import_react25.useState(false);
|
|
@@ -212408,6 +213895,7 @@ function ConfigForm({ appConfig }) {
|
|
|
212408
213895
|
var import_react37 = __toESM(require_react(), 1);
|
|
212409
213896
|
|
|
212410
213897
|
// src/tui/context/config.tsx
|
|
213898
|
+
init_config2();
|
|
212411
213899
|
var import_react26 = __toESM(require_react(), 1);
|
|
212412
213900
|
var ctx3 = import_react26.createContext(null);
|
|
212413
213901
|
function ConfigProvider({ children, config: config2 }) {
|
|
@@ -213006,9 +214494,17 @@ var providerNames = {
|
|
|
213006
214494
|
openai: "OpenAI",
|
|
213007
214495
|
openrouter: "OpenRouter",
|
|
213008
214496
|
bedrock: "Bedrock",
|
|
214497
|
+
pensar: "Pensar",
|
|
213009
214498
|
local: "Local LLM"
|
|
213010
214499
|
};
|
|
213011
|
-
var providerOrder = [
|
|
214500
|
+
var providerOrder = [
|
|
214501
|
+
"pensar",
|
|
214502
|
+
"anthropic",
|
|
214503
|
+
"openai",
|
|
214504
|
+
"openrouter",
|
|
214505
|
+
"bedrock",
|
|
214506
|
+
"local"
|
|
214507
|
+
];
|
|
213012
214508
|
function ModelPicker({
|
|
213013
214509
|
config: config2,
|
|
213014
214510
|
selectedModel,
|
|
@@ -216338,6 +217834,7 @@ function SessionsBrowser() {
|
|
|
216338
217834
|
|
|
216339
217835
|
// src/tui/components/commands/provider-manager.tsx
|
|
216340
217836
|
var import_react50 = __toESM(require_react(), 1);
|
|
217837
|
+
init_config2();
|
|
216341
217838
|
// src/tui/components/commands/provider-selection.tsx
|
|
216342
217839
|
var import_react47 = __toESM(require_react(), 1);
|
|
216343
217840
|
function ProviderSelection({
|
|
@@ -216525,6 +218022,8 @@ function APIKeyInput({
|
|
|
216525
218022
|
return "Get your API key from openrouter.ai/keys";
|
|
216526
218023
|
case "bedrock":
|
|
216527
218024
|
return "Enter your AWS Access Key ID (configure region separately) or AWS Bedrock API Key";
|
|
218025
|
+
case "pensar":
|
|
218026
|
+
return "Get your API key from console.pensar.dev/connect (or run /auth)";
|
|
216528
218027
|
default:
|
|
216529
218028
|
return "Enter your API key";
|
|
216530
218029
|
}
|
|
@@ -216678,6 +218177,9 @@ function ProviderManager() {
|
|
|
216678
218177
|
}, undefined, true, undefined, this);
|
|
216679
218178
|
}
|
|
216680
218179
|
|
|
218180
|
+
// src/tui/index.tsx
|
|
218181
|
+
init_config2();
|
|
218182
|
+
|
|
216681
218183
|
// src/tui/components/switch.tsx
|
|
216682
218184
|
var import_react51 = __toESM(require_react(), 1);
|
|
216683
218185
|
var CaseSymbol = Symbol("Switch.Case");
|
|
@@ -217015,6 +218517,9 @@ function ErrorBoundary2({ children }) {
|
|
|
217015
218517
|
return import_react55.default.createElement(ErrorBoundaryInner, { onError: handleError }, children);
|
|
217016
218518
|
}
|
|
217017
218519
|
|
|
218520
|
+
// src/tui/index.tsx
|
|
218521
|
+
init_installation();
|
|
218522
|
+
|
|
217018
218523
|
// src/tui/keybindings-registry.ts
|
|
217019
218524
|
var keybindings = [
|
|
217020
218525
|
{
|
|
@@ -217582,11 +219087,946 @@ function ModelsDisplay() {
|
|
|
217582
219087
|
}, undefined, true, undefined, this);
|
|
217583
219088
|
}
|
|
217584
219089
|
|
|
219090
|
+
// src/tui/components/commands/auth-flow.tsx
|
|
219091
|
+
var import_react60 = __toESM(require_react(), 1);
|
|
219092
|
+
init_config2();
|
|
219093
|
+
function AuthFlow() {
|
|
219094
|
+
const route = useRoute();
|
|
219095
|
+
const appConfig = useConfig();
|
|
219096
|
+
const isConnected = !!(appConfig.data.accessToken || appConfig.data.pensarAPIKey);
|
|
219097
|
+
const [step, setStep] = import_react60.useState(isConnected ? "success" : "start");
|
|
219098
|
+
const [error, setError] = import_react60.useState(null);
|
|
219099
|
+
const [authMode, setAuthMode] = import_react60.useState(null);
|
|
219100
|
+
const [deviceInfo, setDeviceInfo] = import_react60.useState(null);
|
|
219101
|
+
const [legacyDeviceInfo, setLegacyDeviceInfo] = import_react60.useState(null);
|
|
219102
|
+
const [workspaces, setWorkspaces] = import_react60.useState([]);
|
|
219103
|
+
const [selectedWorkspace, setSelectedWorkspace] = import_react60.useState(null);
|
|
219104
|
+
const [selectedIndex, setSelectedIndex] = import_react60.useState(0);
|
|
219105
|
+
const [billingUrl, setBillingUrl] = import_react60.useState(null);
|
|
219106
|
+
const [balance, setBalance] = import_react60.useState(null);
|
|
219107
|
+
const pollingRef = import_react60.useRef(null);
|
|
219108
|
+
const cancelledRef = import_react60.useRef(false);
|
|
219109
|
+
const connectedWorkspace = appConfig.data.workspaceSlug ? { name: appConfig.data.workspaceSlug, slug: appConfig.data.workspaceSlug } : null;
|
|
219110
|
+
const goHome = () => {
|
|
219111
|
+
route.navigate({ type: "base", path: "home" });
|
|
219112
|
+
};
|
|
219113
|
+
const cleanup = () => {
|
|
219114
|
+
cancelledRef.current = true;
|
|
219115
|
+
if (pollingRef.current) {
|
|
219116
|
+
clearTimeout(pollingRef.current);
|
|
219117
|
+
pollingRef.current = null;
|
|
219118
|
+
}
|
|
219119
|
+
};
|
|
219120
|
+
import_react60.useEffect(() => {
|
|
219121
|
+
return cleanup;
|
|
219122
|
+
}, []);
|
|
219123
|
+
const openUrl = (url) => {
|
|
219124
|
+
try {
|
|
219125
|
+
const platform = process.platform;
|
|
219126
|
+
if (platform === "darwin") {
|
|
219127
|
+
Bun.spawn(["open", url]);
|
|
219128
|
+
} else if (platform === "win32") {
|
|
219129
|
+
Bun.spawn(["cmd", "/c", "start", url]);
|
|
219130
|
+
} else {
|
|
219131
|
+
Bun.spawn(["xdg-open", url]);
|
|
219132
|
+
}
|
|
219133
|
+
} catch {}
|
|
219134
|
+
};
|
|
219135
|
+
const startDeviceFlow = async () => {
|
|
219136
|
+
setStep("requesting");
|
|
219137
|
+
setError(null);
|
|
219138
|
+
cancelledRef.current = false;
|
|
219139
|
+
const apiUrl = getPensarApiUrl(appConfig.data);
|
|
219140
|
+
try {
|
|
219141
|
+
const configResponse = await fetch(`${apiUrl}/api/cli/config`);
|
|
219142
|
+
if (configResponse.ok) {
|
|
219143
|
+
const cliConfig = await configResponse.json();
|
|
219144
|
+
const response = await fetch("https://api.workos.com/user_management/authorize/device", {
|
|
219145
|
+
method: "POST",
|
|
219146
|
+
headers: { "Content-Type": "application/json" },
|
|
219147
|
+
body: JSON.stringify({ client_id: cliConfig.workosClientId })
|
|
219148
|
+
});
|
|
219149
|
+
if (response.ok) {
|
|
219150
|
+
const data = await response.json();
|
|
219151
|
+
setAuthMode("workos");
|
|
219152
|
+
setDeviceInfo(data);
|
|
219153
|
+
openUrl(data.verification_uri_complete);
|
|
219154
|
+
setStep("polling");
|
|
219155
|
+
pollForToken(apiUrl, cliConfig.workosClientId, data.device_code, data.interval, data.expires_in);
|
|
219156
|
+
return;
|
|
219157
|
+
}
|
|
219158
|
+
}
|
|
219159
|
+
} catch {}
|
|
219160
|
+
try {
|
|
219161
|
+
const response = await fetch(`${apiUrl}/auth/device/code`, {
|
|
219162
|
+
method: "POST",
|
|
219163
|
+
headers: { "Content-Type": "application/json" }
|
|
219164
|
+
});
|
|
219165
|
+
if (!response.ok) {
|
|
219166
|
+
throw new Error("Failed to start device authorization");
|
|
219167
|
+
}
|
|
219168
|
+
const data = await response.json();
|
|
219169
|
+
setAuthMode("legacy");
|
|
219170
|
+
setLegacyDeviceInfo(data);
|
|
219171
|
+
openUrl(data.verificationUriComplete);
|
|
219172
|
+
setStep("polling");
|
|
219173
|
+
pollForLegacyToken(apiUrl, data.deviceCode, data.interval, data.expiresIn);
|
|
219174
|
+
} catch (err) {
|
|
219175
|
+
setError(err instanceof Error ? err.message : "Failed to start authorization");
|
|
219176
|
+
setStep("error");
|
|
219177
|
+
}
|
|
219178
|
+
};
|
|
219179
|
+
const pollForToken = (apiUrl, clientId, deviceCode, interval, expiresIn) => {
|
|
219180
|
+
const deadline = Date.now() + expiresIn * 1000;
|
|
219181
|
+
const poll = async () => {
|
|
219182
|
+
if (cancelledRef.current)
|
|
219183
|
+
return;
|
|
219184
|
+
if (Date.now() > deadline) {
|
|
219185
|
+
setError("Authorization timed out. Please try again.");
|
|
219186
|
+
setStep("error");
|
|
219187
|
+
return;
|
|
219188
|
+
}
|
|
219189
|
+
try {
|
|
219190
|
+
const response = await fetch("https://api.workos.com/user_management/authenticate", {
|
|
219191
|
+
method: "POST",
|
|
219192
|
+
headers: { "Content-Type": "application/json" },
|
|
219193
|
+
body: JSON.stringify({
|
|
219194
|
+
client_id: clientId,
|
|
219195
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
219196
|
+
device_code: deviceCode
|
|
219197
|
+
})
|
|
219198
|
+
});
|
|
219199
|
+
if (cancelledRef.current)
|
|
219200
|
+
return;
|
|
219201
|
+
if (response.status === 400) {
|
|
219202
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219203
|
+
return;
|
|
219204
|
+
}
|
|
219205
|
+
if (!response.ok) {
|
|
219206
|
+
throw new Error("Authentication failed");
|
|
219207
|
+
}
|
|
219208
|
+
const data = await response.json();
|
|
219209
|
+
await config.update({
|
|
219210
|
+
accessToken: data.access_token,
|
|
219211
|
+
refreshToken: data.refresh_token
|
|
219212
|
+
});
|
|
219213
|
+
await appConfig.reload();
|
|
219214
|
+
await fetchWorkspaces(apiUrl, data.access_token);
|
|
219215
|
+
} catch (err) {
|
|
219216
|
+
if (cancelledRef.current)
|
|
219217
|
+
return;
|
|
219218
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219219
|
+
}
|
|
219220
|
+
};
|
|
219221
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219222
|
+
};
|
|
219223
|
+
const pollForLegacyToken = (apiUrl, deviceCode, interval, expiresIn) => {
|
|
219224
|
+
const deadline = Date.now() + expiresIn * 1000;
|
|
219225
|
+
const poll = async () => {
|
|
219226
|
+
if (cancelledRef.current)
|
|
219227
|
+
return;
|
|
219228
|
+
if (Date.now() > deadline) {
|
|
219229
|
+
setError("Authorization timed out. Please try again.");
|
|
219230
|
+
setStep("error");
|
|
219231
|
+
return;
|
|
219232
|
+
}
|
|
219233
|
+
try {
|
|
219234
|
+
const response = await fetch(`${apiUrl}/auth/device/token`, {
|
|
219235
|
+
method: "POST",
|
|
219236
|
+
headers: { "Content-Type": "application/json" },
|
|
219237
|
+
body: JSON.stringify({ deviceCode })
|
|
219238
|
+
});
|
|
219239
|
+
if (!response.ok) {
|
|
219240
|
+
throw new Error("Failed to check authorization status");
|
|
219241
|
+
}
|
|
219242
|
+
const data = await response.json();
|
|
219243
|
+
if (cancelledRef.current)
|
|
219244
|
+
return;
|
|
219245
|
+
if (data.status === "complete" && data.apiKey) {
|
|
219246
|
+
await config.update({ pensarAPIKey: data.apiKey });
|
|
219247
|
+
if (data.workspace) {
|
|
219248
|
+
await config.update({
|
|
219249
|
+
workspaceId: data.workspace.id,
|
|
219250
|
+
workspaceSlug: data.workspace.slug
|
|
219251
|
+
});
|
|
219252
|
+
}
|
|
219253
|
+
appConfig.reload();
|
|
219254
|
+
setSelectedWorkspace(data.workspace ? {
|
|
219255
|
+
...data.workspace,
|
|
219256
|
+
balance: data.credits?.balance ?? 0,
|
|
219257
|
+
hasPaymentMethod: true
|
|
219258
|
+
} : null);
|
|
219259
|
+
setBalance(data.credits?.balance ?? null);
|
|
219260
|
+
setStep("success");
|
|
219261
|
+
return;
|
|
219262
|
+
}
|
|
219263
|
+
if (data.status === "expired") {
|
|
219264
|
+
setError("Authorization expired. Please try again.");
|
|
219265
|
+
setStep("error");
|
|
219266
|
+
return;
|
|
219267
|
+
}
|
|
219268
|
+
if (data.status === "not_found") {
|
|
219269
|
+
setError("Invalid authorization session. Please try again.");
|
|
219270
|
+
setStep("error");
|
|
219271
|
+
return;
|
|
219272
|
+
}
|
|
219273
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219274
|
+
} catch (err) {
|
|
219275
|
+
if (cancelledRef.current)
|
|
219276
|
+
return;
|
|
219277
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219278
|
+
}
|
|
219279
|
+
};
|
|
219280
|
+
pollingRef.current = setTimeout(poll, interval * 1000);
|
|
219281
|
+
};
|
|
219282
|
+
const fetchWorkspaces = async (apiUrl, accessToken) => {
|
|
219283
|
+
try {
|
|
219284
|
+
const response = await fetch(`${apiUrl}/api/cli/workspaces`, {
|
|
219285
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
219286
|
+
});
|
|
219287
|
+
if (!response.ok) {
|
|
219288
|
+
throw new Error("Failed to fetch workspaces");
|
|
219289
|
+
}
|
|
219290
|
+
const data = await response.json();
|
|
219291
|
+
if (data.workspaces.length === 0) {
|
|
219292
|
+
setError("No workspaces found. Create one at console.pensar.dev");
|
|
219293
|
+
setStep("error");
|
|
219294
|
+
return;
|
|
219295
|
+
}
|
|
219296
|
+
if (data.workspaces.length === 1) {
|
|
219297
|
+
await selectWorkspace(apiUrl, accessToken, data.workspaces[0]);
|
|
219298
|
+
return;
|
|
219299
|
+
}
|
|
219300
|
+
setWorkspaces(data.workspaces);
|
|
219301
|
+
setSelectedIndex(0);
|
|
219302
|
+
setStep("select-workspace");
|
|
219303
|
+
} catch (err) {
|
|
219304
|
+
setError(err instanceof Error ? err.message : "Failed to fetch workspaces");
|
|
219305
|
+
setStep("error");
|
|
219306
|
+
}
|
|
219307
|
+
};
|
|
219308
|
+
const selectWorkspace = async (apiUrl, accessToken, workspace) => {
|
|
219309
|
+
setSelectedWorkspace(workspace);
|
|
219310
|
+
setStep("checking-billing");
|
|
219311
|
+
try {
|
|
219312
|
+
const response = await fetch(`${apiUrl}/api/cli/select-workspace`, {
|
|
219313
|
+
method: "POST",
|
|
219314
|
+
headers: {
|
|
219315
|
+
"Content-Type": "application/json",
|
|
219316
|
+
Authorization: `Bearer ${accessToken}`
|
|
219317
|
+
},
|
|
219318
|
+
body: JSON.stringify({ workspaceId: workspace.id })
|
|
219319
|
+
});
|
|
219320
|
+
if (!response.ok) {
|
|
219321
|
+
throw new Error("Failed to select workspace");
|
|
219322
|
+
}
|
|
219323
|
+
const data = await response.json();
|
|
219324
|
+
await config.update({
|
|
219325
|
+
workspaceId: workspace.id,
|
|
219326
|
+
workspaceSlug: workspace.slug
|
|
219327
|
+
});
|
|
219328
|
+
appConfig.reload();
|
|
219329
|
+
setBalance(data.billing.balance);
|
|
219330
|
+
if (!data.confirmed && data.billingUrl) {
|
|
219331
|
+
setBillingUrl(data.billingUrl);
|
|
219332
|
+
}
|
|
219333
|
+
setStep("success");
|
|
219334
|
+
} catch (err) {
|
|
219335
|
+
setError(err instanceof Error ? err.message : "Failed to select workspace");
|
|
219336
|
+
setStep("error");
|
|
219337
|
+
}
|
|
219338
|
+
};
|
|
219339
|
+
const handleDisconnect = async () => {
|
|
219340
|
+
await config.update({
|
|
219341
|
+
pensarAPIKey: null,
|
|
219342
|
+
accessToken: null,
|
|
219343
|
+
refreshToken: null,
|
|
219344
|
+
workspaceId: null,
|
|
219345
|
+
workspaceSlug: null
|
|
219346
|
+
});
|
|
219347
|
+
appConfig.reload();
|
|
219348
|
+
setAuthMode(null);
|
|
219349
|
+
setSelectedWorkspace(null);
|
|
219350
|
+
setBalance(null);
|
|
219351
|
+
setBillingUrl(null);
|
|
219352
|
+
setDeviceInfo(null);
|
|
219353
|
+
setLegacyDeviceInfo(null);
|
|
219354
|
+
setStep("start");
|
|
219355
|
+
};
|
|
219356
|
+
const hasLowBalance = balance !== null && balance < 1;
|
|
219357
|
+
const effectiveBillingUrl = billingUrl || (selectedWorkspace?.slug ? `${getPensarConsoleUrl()}/${selectedWorkspace.slug}/settings/billing` : connectedWorkspace?.slug ? `${getPensarConsoleUrl()}/${connectedWorkspace.slug}/settings/billing` : `${getPensarConsoleUrl()}/credits`);
|
|
219358
|
+
const openBillingPage = () => {
|
|
219359
|
+
openUrl(effectiveBillingUrl);
|
|
219360
|
+
goHome();
|
|
219361
|
+
};
|
|
219362
|
+
useKeyboard((key) => {
|
|
219363
|
+
if (key.name === "escape") {
|
|
219364
|
+
cleanup();
|
|
219365
|
+
goHome();
|
|
219366
|
+
return;
|
|
219367
|
+
}
|
|
219368
|
+
if (step === "start") {
|
|
219369
|
+
if (key.name === "return") {
|
|
219370
|
+
startDeviceFlow();
|
|
219371
|
+
}
|
|
219372
|
+
}
|
|
219373
|
+
if (step === "select-workspace") {
|
|
219374
|
+
if (key.name === "up" && selectedIndex > 0) {
|
|
219375
|
+
setSelectedIndex((i) => i - 1);
|
|
219376
|
+
}
|
|
219377
|
+
if (key.name === "down" && selectedIndex < workspaces.length - 1) {
|
|
219378
|
+
setSelectedIndex((i) => i + 1);
|
|
219379
|
+
}
|
|
219380
|
+
if (key.name === "return" && workspaces[selectedIndex]) {
|
|
219381
|
+
const currentConfig = appConfig.data;
|
|
219382
|
+
const apiUrl = getPensarApiUrl(currentConfig);
|
|
219383
|
+
const accessToken = currentConfig.accessToken;
|
|
219384
|
+
selectWorkspace(apiUrl, accessToken, workspaces[selectedIndex]);
|
|
219385
|
+
}
|
|
219386
|
+
}
|
|
219387
|
+
if (step === "error") {
|
|
219388
|
+
if (key.name === "return") {
|
|
219389
|
+
startDeviceFlow();
|
|
219390
|
+
}
|
|
219391
|
+
}
|
|
219392
|
+
if (step === "success") {
|
|
219393
|
+
if (key.name === "return") {
|
|
219394
|
+
if (hasLowBalance || billingUrl) {
|
|
219395
|
+
openBillingPage();
|
|
219396
|
+
} else {
|
|
219397
|
+
goHome();
|
|
219398
|
+
}
|
|
219399
|
+
}
|
|
219400
|
+
if (key.raw === "d" || key.raw === "D") {
|
|
219401
|
+
handleDisconnect();
|
|
219402
|
+
}
|
|
219403
|
+
}
|
|
219404
|
+
});
|
|
219405
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219406
|
+
flexDirection: "column",
|
|
219407
|
+
width: "100%",
|
|
219408
|
+
maxWidth: 80,
|
|
219409
|
+
alignItems: "flex-start",
|
|
219410
|
+
padding: 1,
|
|
219411
|
+
children: [
|
|
219412
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219413
|
+
marginBottom: 1,
|
|
219414
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219415
|
+
fg: "green",
|
|
219416
|
+
children: "Pensar Console — Managed Inference"
|
|
219417
|
+
}, undefined, false, undefined, this)
|
|
219418
|
+
}, undefined, false, undefined, this),
|
|
219419
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219420
|
+
marginBottom: 1,
|
|
219421
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219422
|
+
fg: "gray",
|
|
219423
|
+
children: [
|
|
219424
|
+
"Connect to Pensar Console for usage-based AI inference.",
|
|
219425
|
+
`
|
|
219426
|
+
`,
|
|
219427
|
+
"No API keys needed — just a Pensar account with credits."
|
|
219428
|
+
]
|
|
219429
|
+
}, undefined, true, undefined, this)
|
|
219430
|
+
}, undefined, false, undefined, this),
|
|
219431
|
+
step === "start" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219432
|
+
flexDirection: "column",
|
|
219433
|
+
gap: 1,
|
|
219434
|
+
children: [
|
|
219435
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219436
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219437
|
+
fg: "white",
|
|
219438
|
+
children: [
|
|
219439
|
+
"Press ",
|
|
219440
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219441
|
+
fg: "green",
|
|
219442
|
+
children: "[ENTER]"
|
|
219443
|
+
}, undefined, false, undefined, this),
|
|
219444
|
+
" to authorize via your browser."
|
|
219445
|
+
]
|
|
219446
|
+
}, undefined, true, undefined, this)
|
|
219447
|
+
}, undefined, false, undefined, this),
|
|
219448
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219449
|
+
marginTop: 1,
|
|
219450
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219451
|
+
fg: "gray",
|
|
219452
|
+
children: [
|
|
219453
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219454
|
+
fg: "green",
|
|
219455
|
+
children: "[ENTER]"
|
|
219456
|
+
}, undefined, false, undefined, this),
|
|
219457
|
+
" Connect ·",
|
|
219458
|
+
" ",
|
|
219459
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219460
|
+
fg: "green",
|
|
219461
|
+
children: "[ESC]"
|
|
219462
|
+
}, undefined, false, undefined, this),
|
|
219463
|
+
" Cancel"
|
|
219464
|
+
]
|
|
219465
|
+
}, undefined, true, undefined, this)
|
|
219466
|
+
}, undefined, false, undefined, this)
|
|
219467
|
+
]
|
|
219468
|
+
}, undefined, true, undefined, this),
|
|
219469
|
+
step === "requesting" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219470
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219471
|
+
fg: "yellow",
|
|
219472
|
+
children: "Starting authorization..."
|
|
219473
|
+
}, undefined, false, undefined, this)
|
|
219474
|
+
}, undefined, false, undefined, this),
|
|
219475
|
+
step === "polling" && (deviceInfo || legacyDeviceInfo) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219476
|
+
flexDirection: "column",
|
|
219477
|
+
gap: 1,
|
|
219478
|
+
children: [
|
|
219479
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219480
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219481
|
+
fg: "yellow",
|
|
219482
|
+
children: "Waiting for browser authorization..."
|
|
219483
|
+
}, undefined, false, undefined, this)
|
|
219484
|
+
}, undefined, false, undefined, this),
|
|
219485
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219486
|
+
marginTop: 1,
|
|
219487
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219488
|
+
fg: "white",
|
|
219489
|
+
children: [
|
|
219490
|
+
"Your code:",
|
|
219491
|
+
" ",
|
|
219492
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219493
|
+
fg: "green",
|
|
219494
|
+
children: deviceInfo?.user_code || legacyDeviceInfo?.userCode
|
|
219495
|
+
}, undefined, false, undefined, this)
|
|
219496
|
+
]
|
|
219497
|
+
}, undefined, true, undefined, this)
|
|
219498
|
+
}, undefined, false, undefined, this),
|
|
219499
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219500
|
+
marginTop: 1,
|
|
219501
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219502
|
+
fg: "gray",
|
|
219503
|
+
children: [
|
|
219504
|
+
"If the browser didn't open, visit:",
|
|
219505
|
+
`
|
|
219506
|
+
`,
|
|
219507
|
+
deviceInfo?.verification_uri_complete || legacyDeviceInfo?.verificationUriComplete
|
|
219508
|
+
]
|
|
219509
|
+
}, undefined, true, undefined, this)
|
|
219510
|
+
}, undefined, false, undefined, this),
|
|
219511
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219512
|
+
marginTop: 1,
|
|
219513
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219514
|
+
fg: "gray",
|
|
219515
|
+
children: [
|
|
219516
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219517
|
+
fg: "green",
|
|
219518
|
+
children: "[ESC]"
|
|
219519
|
+
}, undefined, false, undefined, this),
|
|
219520
|
+
" Cancel"
|
|
219521
|
+
]
|
|
219522
|
+
}, undefined, true, undefined, this)
|
|
219523
|
+
}, undefined, false, undefined, this)
|
|
219524
|
+
]
|
|
219525
|
+
}, undefined, true, undefined, this),
|
|
219526
|
+
step === "select-workspace" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219527
|
+
flexDirection: "column",
|
|
219528
|
+
gap: 1,
|
|
219529
|
+
children: [
|
|
219530
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219531
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219532
|
+
fg: "white",
|
|
219533
|
+
children: "Select a workspace:"
|
|
219534
|
+
}, undefined, false, undefined, this)
|
|
219535
|
+
}, undefined, false, undefined, this),
|
|
219536
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219537
|
+
flexDirection: "column",
|
|
219538
|
+
marginTop: 1,
|
|
219539
|
+
children: workspaces.map((ws, i) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219540
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219541
|
+
fg: i === selectedIndex ? "green" : "gray",
|
|
219542
|
+
children: [
|
|
219543
|
+
i === selectedIndex ? "▸ " : " ",
|
|
219544
|
+
ws.name,
|
|
219545
|
+
" ",
|
|
219546
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219547
|
+
fg: "gray",
|
|
219548
|
+
children: [
|
|
219549
|
+
"(",
|
|
219550
|
+
ws.slug,
|
|
219551
|
+
") — $",
|
|
219552
|
+
ws.balance.toFixed(2)
|
|
219553
|
+
]
|
|
219554
|
+
}, undefined, true, undefined, this)
|
|
219555
|
+
]
|
|
219556
|
+
}, undefined, true, undefined, this)
|
|
219557
|
+
}, ws.id, false, undefined, this))
|
|
219558
|
+
}, undefined, false, undefined, this),
|
|
219559
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219560
|
+
marginTop: 1,
|
|
219561
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219562
|
+
fg: "gray",
|
|
219563
|
+
children: [
|
|
219564
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219565
|
+
fg: "green",
|
|
219566
|
+
children: "[↑/↓]"
|
|
219567
|
+
}, undefined, false, undefined, this),
|
|
219568
|
+
" Navigate ·",
|
|
219569
|
+
" ",
|
|
219570
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219571
|
+
fg: "green",
|
|
219572
|
+
children: "[ENTER]"
|
|
219573
|
+
}, undefined, false, undefined, this),
|
|
219574
|
+
" Select ·",
|
|
219575
|
+
" ",
|
|
219576
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219577
|
+
fg: "green",
|
|
219578
|
+
children: "[ESC]"
|
|
219579
|
+
}, undefined, false, undefined, this),
|
|
219580
|
+
" Cancel"
|
|
219581
|
+
]
|
|
219582
|
+
}, undefined, true, undefined, this)
|
|
219583
|
+
}, undefined, false, undefined, this)
|
|
219584
|
+
]
|
|
219585
|
+
}, undefined, true, undefined, this),
|
|
219586
|
+
step === "checking-billing" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219587
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219588
|
+
fg: "yellow",
|
|
219589
|
+
children: [
|
|
219590
|
+
"Checking billing for ",
|
|
219591
|
+
selectedWorkspace?.name,
|
|
219592
|
+
"..."
|
|
219593
|
+
]
|
|
219594
|
+
}, undefined, true, undefined, this)
|
|
219595
|
+
}, undefined, false, undefined, this),
|
|
219596
|
+
step === "success" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219597
|
+
flexDirection: "column",
|
|
219598
|
+
gap: 1,
|
|
219599
|
+
children: [
|
|
219600
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219601
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219602
|
+
fg: "green",
|
|
219603
|
+
children: "Connected to Pensar Console"
|
|
219604
|
+
}, undefined, false, undefined, this)
|
|
219605
|
+
}, undefined, false, undefined, this),
|
|
219606
|
+
(selectedWorkspace || connectedWorkspace) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219607
|
+
flexDirection: "column",
|
|
219608
|
+
children: [
|
|
219609
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219610
|
+
fg: "white",
|
|
219611
|
+
children: [
|
|
219612
|
+
"Workspace: ",
|
|
219613
|
+
selectedWorkspace?.name || connectedWorkspace?.name
|
|
219614
|
+
]
|
|
219615
|
+
}, undefined, true, undefined, this),
|
|
219616
|
+
balance !== null && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219617
|
+
fg: "white",
|
|
219618
|
+
children: [
|
|
219619
|
+
"Credits:",
|
|
219620
|
+
" ",
|
|
219621
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219622
|
+
fg: hasLowBalance ? "yellow" : "white",
|
|
219623
|
+
children: [
|
|
219624
|
+
"$",
|
|
219625
|
+
balance.toFixed(2)
|
|
219626
|
+
]
|
|
219627
|
+
}, undefined, true, undefined, this)
|
|
219628
|
+
]
|
|
219629
|
+
}, undefined, true, undefined, this)
|
|
219630
|
+
]
|
|
219631
|
+
}, undefined, true, undefined, this),
|
|
219632
|
+
(hasLowBalance || billingUrl) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219633
|
+
marginTop: 1,
|
|
219634
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219635
|
+
fg: "yellow",
|
|
219636
|
+
children: [
|
|
219637
|
+
billingUrl ? "Your workspace needs credits to use Apex CLI." : "Your credit balance is very low. We recommend at least $30 to run",
|
|
219638
|
+
`
|
|
219639
|
+
`,
|
|
219640
|
+
billingUrl ? "Press ENTER to open billing and add credits." : "pentests without interruptions. Press ENTER to open billing."
|
|
219641
|
+
]
|
|
219642
|
+
}, undefined, true, undefined, this)
|
|
219643
|
+
}, undefined, false, undefined, this),
|
|
219644
|
+
!selectedWorkspace && !connectedWorkspace && appConfig.data.pensarAPIKey && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219645
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219646
|
+
fg: "gray",
|
|
219647
|
+
children: "Already connected (legacy key saved in config)"
|
|
219648
|
+
}, undefined, false, undefined, this)
|
|
219649
|
+
}, undefined, false, undefined, this),
|
|
219650
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219651
|
+
marginTop: 1,
|
|
219652
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219653
|
+
fg: "gray",
|
|
219654
|
+
children: "Pensar models are now available in the model selector."
|
|
219655
|
+
}, undefined, false, undefined, this)
|
|
219656
|
+
}, undefined, false, undefined, this),
|
|
219657
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219658
|
+
marginTop: 1,
|
|
219659
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219660
|
+
fg: "gray",
|
|
219661
|
+
children: [
|
|
219662
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219663
|
+
fg: "green",
|
|
219664
|
+
children: "[ENTER]"
|
|
219665
|
+
}, undefined, false, undefined, this),
|
|
219666
|
+
" ",
|
|
219667
|
+
hasLowBalance || billingUrl ? "Open billing" : "Done",
|
|
219668
|
+
" ·",
|
|
219669
|
+
" ",
|
|
219670
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219671
|
+
fg: "red",
|
|
219672
|
+
children: "[D]"
|
|
219673
|
+
}, undefined, false, undefined, this),
|
|
219674
|
+
" Disconnect ·",
|
|
219675
|
+
" ",
|
|
219676
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219677
|
+
fg: "green",
|
|
219678
|
+
children: "[ESC]"
|
|
219679
|
+
}, undefined, false, undefined, this),
|
|
219680
|
+
" Back"
|
|
219681
|
+
]
|
|
219682
|
+
}, undefined, true, undefined, this)
|
|
219683
|
+
}, undefined, false, undefined, this)
|
|
219684
|
+
]
|
|
219685
|
+
}, undefined, true, undefined, this),
|
|
219686
|
+
step === "error" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219687
|
+
flexDirection: "column",
|
|
219688
|
+
gap: 1,
|
|
219689
|
+
children: [
|
|
219690
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219691
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219692
|
+
fg: "red",
|
|
219693
|
+
children: error
|
|
219694
|
+
}, undefined, false, undefined, this)
|
|
219695
|
+
}, undefined, false, undefined, this),
|
|
219696
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219697
|
+
marginTop: 1,
|
|
219698
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219699
|
+
fg: "gray",
|
|
219700
|
+
children: [
|
|
219701
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219702
|
+
fg: "green",
|
|
219703
|
+
children: "[ENTER]"
|
|
219704
|
+
}, undefined, false, undefined, this),
|
|
219705
|
+
" Try again ·",
|
|
219706
|
+
" ",
|
|
219707
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219708
|
+
fg: "green",
|
|
219709
|
+
children: "[ESC]"
|
|
219710
|
+
}, undefined, false, undefined, this),
|
|
219711
|
+
" Cancel"
|
|
219712
|
+
]
|
|
219713
|
+
}, undefined, true, undefined, this)
|
|
219714
|
+
}, undefined, false, undefined, this)
|
|
219715
|
+
]
|
|
219716
|
+
}, undefined, true, undefined, this)
|
|
219717
|
+
]
|
|
219718
|
+
}, undefined, true, undefined, this);
|
|
219719
|
+
}
|
|
219720
|
+
|
|
219721
|
+
// src/tui/components/commands/credits-flow.tsx
|
|
219722
|
+
var import_react62 = __toESM(require_react(), 1);
|
|
219723
|
+
init_tokenRefresh();
|
|
219724
|
+
function CreditsFlow() {
|
|
219725
|
+
const route = useRoute();
|
|
219726
|
+
const appConfig = useConfig();
|
|
219727
|
+
const [step, setStep] = import_react62.useState("loading");
|
|
219728
|
+
const [credits, setCredits] = import_react62.useState(null);
|
|
219729
|
+
const [error, setError] = import_react62.useState(null);
|
|
219730
|
+
const creditsUrl = `${getPensarConsoleUrl()}/credits`;
|
|
219731
|
+
const goHome = () => {
|
|
219732
|
+
route.navigate({ type: "base", path: "home" });
|
|
219733
|
+
};
|
|
219734
|
+
const openBrowser = () => {
|
|
219735
|
+
const url = creditsUrl;
|
|
219736
|
+
try {
|
|
219737
|
+
const platform = process.platform;
|
|
219738
|
+
if (platform === "darwin") {
|
|
219739
|
+
Bun.spawn(["open", url]);
|
|
219740
|
+
} else if (platform === "win32") {
|
|
219741
|
+
Bun.spawn(["cmd", "/c", "start", url]);
|
|
219742
|
+
} else {
|
|
219743
|
+
Bun.spawn(["xdg-open", url]);
|
|
219744
|
+
}
|
|
219745
|
+
} catch {}
|
|
219746
|
+
setStep("browser-opened");
|
|
219747
|
+
};
|
|
219748
|
+
const fetchBalance = async () => {
|
|
219749
|
+
const tokenResult = await ensureValidToken({
|
|
219750
|
+
accessToken: appConfig.data.accessToken,
|
|
219751
|
+
refreshToken: appConfig.data.refreshToken,
|
|
219752
|
+
pensarAPIKey: appConfig.data.pensarAPIKey,
|
|
219753
|
+
pensarApiUrl: appConfig.data.pensarApiUrl
|
|
219754
|
+
});
|
|
219755
|
+
if (!tokenResult) {
|
|
219756
|
+
setStep("no-auth");
|
|
219757
|
+
return;
|
|
219758
|
+
}
|
|
219759
|
+
setStep("loading");
|
|
219760
|
+
setError(null);
|
|
219761
|
+
try {
|
|
219762
|
+
const apiUrl = getPensarApiUrl(appConfig.data);
|
|
219763
|
+
const headers = {
|
|
219764
|
+
Authorization: `Bearer ${tokenResult.token}`
|
|
219765
|
+
};
|
|
219766
|
+
if (tokenResult.type === "workos" && appConfig.data.workspaceId) {
|
|
219767
|
+
headers["X-Workspace-Id"] = appConfig.data.workspaceId;
|
|
219768
|
+
}
|
|
219769
|
+
const response = await fetch(`${apiUrl}/bedrock/validate`, {
|
|
219770
|
+
method: "GET",
|
|
219771
|
+
headers
|
|
219772
|
+
});
|
|
219773
|
+
if (!response.ok) {
|
|
219774
|
+
throw new Error("Failed to fetch balance");
|
|
219775
|
+
}
|
|
219776
|
+
const result = await response.json();
|
|
219777
|
+
setCredits({
|
|
219778
|
+
balance: result.credits.balance,
|
|
219779
|
+
workspace: result.workspace.name
|
|
219780
|
+
});
|
|
219781
|
+
setStep("display");
|
|
219782
|
+
} catch (err) {
|
|
219783
|
+
setError(err instanceof Error ? err.message : "Failed to fetch balance");
|
|
219784
|
+
setStep("display");
|
|
219785
|
+
}
|
|
219786
|
+
};
|
|
219787
|
+
import_react62.useEffect(() => {
|
|
219788
|
+
fetchBalance();
|
|
219789
|
+
}, []);
|
|
219790
|
+
useKeyboard((key) => {
|
|
219791
|
+
if (key.name === "escape") {
|
|
219792
|
+
goHome();
|
|
219793
|
+
return;
|
|
219794
|
+
}
|
|
219795
|
+
if (step === "no-auth") {
|
|
219796
|
+
if (key.name === "return") {
|
|
219797
|
+
route.navigate({ type: "base", path: "auth" });
|
|
219798
|
+
}
|
|
219799
|
+
}
|
|
219800
|
+
if (step === "display") {
|
|
219801
|
+
if (key.name === "return") {
|
|
219802
|
+
openBrowser();
|
|
219803
|
+
}
|
|
219804
|
+
if (key.raw === "r" || key.raw === "R") {
|
|
219805
|
+
fetchBalance();
|
|
219806
|
+
}
|
|
219807
|
+
}
|
|
219808
|
+
if (step === "browser-opened") {
|
|
219809
|
+
if (key.name === "return") {
|
|
219810
|
+
fetchBalance();
|
|
219811
|
+
}
|
|
219812
|
+
}
|
|
219813
|
+
});
|
|
219814
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219815
|
+
flexDirection: "column",
|
|
219816
|
+
width: "100%",
|
|
219817
|
+
maxWidth: 80,
|
|
219818
|
+
alignItems: "flex-start",
|
|
219819
|
+
padding: 1,
|
|
219820
|
+
children: [
|
|
219821
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219822
|
+
marginBottom: 1,
|
|
219823
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219824
|
+
fg: "green",
|
|
219825
|
+
children: "Credits"
|
|
219826
|
+
}, undefined, false, undefined, this)
|
|
219827
|
+
}, undefined, false, undefined, this),
|
|
219828
|
+
step === "loading" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219829
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219830
|
+
fg: "yellow",
|
|
219831
|
+
children: "Fetching balance..."
|
|
219832
|
+
}, undefined, false, undefined, this)
|
|
219833
|
+
}, undefined, false, undefined, this),
|
|
219834
|
+
step === "no-auth" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219835
|
+
flexDirection: "column",
|
|
219836
|
+
gap: 1,
|
|
219837
|
+
children: [
|
|
219838
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219839
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219840
|
+
fg: "yellow",
|
|
219841
|
+
children: "Not connected to Pensar Console."
|
|
219842
|
+
}, undefined, false, undefined, this)
|
|
219843
|
+
}, undefined, false, undefined, this),
|
|
219844
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219845
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219846
|
+
fg: "gray",
|
|
219847
|
+
children: [
|
|
219848
|
+
"Run ",
|
|
219849
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219850
|
+
fg: "green",
|
|
219851
|
+
children: "/auth"
|
|
219852
|
+
}, undefined, false, undefined, this),
|
|
219853
|
+
" first to connect your account."
|
|
219854
|
+
]
|
|
219855
|
+
}, undefined, true, undefined, this)
|
|
219856
|
+
}, undefined, false, undefined, this),
|
|
219857
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219858
|
+
marginTop: 1,
|
|
219859
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219860
|
+
fg: "gray",
|
|
219861
|
+
children: [
|
|
219862
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219863
|
+
fg: "green",
|
|
219864
|
+
children: "[ENTER]"
|
|
219865
|
+
}, undefined, false, undefined, this),
|
|
219866
|
+
" Run /auth ·",
|
|
219867
|
+
" ",
|
|
219868
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219869
|
+
fg: "green",
|
|
219870
|
+
children: "[ESC]"
|
|
219871
|
+
}, undefined, false, undefined, this),
|
|
219872
|
+
" Back"
|
|
219873
|
+
]
|
|
219874
|
+
}, undefined, true, undefined, this)
|
|
219875
|
+
}, undefined, false, undefined, this)
|
|
219876
|
+
]
|
|
219877
|
+
}, undefined, true, undefined, this),
|
|
219878
|
+
step === "display" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219879
|
+
flexDirection: "column",
|
|
219880
|
+
gap: 1,
|
|
219881
|
+
children: [
|
|
219882
|
+
error ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219883
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219884
|
+
fg: "red",
|
|
219885
|
+
children: [
|
|
219886
|
+
"Error: ",
|
|
219887
|
+
error
|
|
219888
|
+
]
|
|
219889
|
+
}, undefined, true, undefined, this)
|
|
219890
|
+
}, undefined, false, undefined, this) : credits ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
|
|
219891
|
+
children: [
|
|
219892
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219893
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219894
|
+
fg: "white",
|
|
219895
|
+
children: [
|
|
219896
|
+
"Workspace: ",
|
|
219897
|
+
credits.workspace
|
|
219898
|
+
]
|
|
219899
|
+
}, undefined, true, undefined, this)
|
|
219900
|
+
}, undefined, false, undefined, this),
|
|
219901
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219902
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219903
|
+
fg: "white",
|
|
219904
|
+
children: [
|
|
219905
|
+
"Balance:",
|
|
219906
|
+
" ",
|
|
219907
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219908
|
+
fg: credits.balance < 5 ? "yellow" : "green",
|
|
219909
|
+
children: [
|
|
219910
|
+
"$",
|
|
219911
|
+
credits.balance.toFixed(2)
|
|
219912
|
+
]
|
|
219913
|
+
}, undefined, true, undefined, this)
|
|
219914
|
+
]
|
|
219915
|
+
}, undefined, true, undefined, this)
|
|
219916
|
+
}, undefined, false, undefined, this),
|
|
219917
|
+
credits.balance < 5 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219918
|
+
marginTop: 1,
|
|
219919
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219920
|
+
fg: "yellow",
|
|
219921
|
+
children: "Low balance. We recommend at least $30 for uninterrupted pentest runs."
|
|
219922
|
+
}, undefined, false, undefined, this)
|
|
219923
|
+
}, undefined, false, undefined, this)
|
|
219924
|
+
]
|
|
219925
|
+
}, undefined, true, undefined, this) : null,
|
|
219926
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219927
|
+
marginTop: 1,
|
|
219928
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219929
|
+
fg: "gray",
|
|
219930
|
+
children: [
|
|
219931
|
+
"Press ",
|
|
219932
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219933
|
+
fg: "green",
|
|
219934
|
+
children: "[ENTER]"
|
|
219935
|
+
}, undefined, false, undefined, this),
|
|
219936
|
+
" to buy credits in your browser."
|
|
219937
|
+
]
|
|
219938
|
+
}, undefined, true, undefined, this)
|
|
219939
|
+
}, undefined, false, undefined, this),
|
|
219940
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219941
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219942
|
+
fg: "gray",
|
|
219943
|
+
children: [
|
|
219944
|
+
"Or visit: ",
|
|
219945
|
+
creditsUrl
|
|
219946
|
+
]
|
|
219947
|
+
}, undefined, true, undefined, this)
|
|
219948
|
+
}, undefined, false, undefined, this),
|
|
219949
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219950
|
+
marginTop: 1,
|
|
219951
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219952
|
+
fg: "gray",
|
|
219953
|
+
children: [
|
|
219954
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219955
|
+
fg: "green",
|
|
219956
|
+
children: "[ENTER]"
|
|
219957
|
+
}, undefined, false, undefined, this),
|
|
219958
|
+
" Open browser ·",
|
|
219959
|
+
" ",
|
|
219960
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219961
|
+
fg: "green",
|
|
219962
|
+
children: "[R]"
|
|
219963
|
+
}, undefined, false, undefined, this),
|
|
219964
|
+
" Refresh ·",
|
|
219965
|
+
" ",
|
|
219966
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219967
|
+
fg: "green",
|
|
219968
|
+
children: "[ESC]"
|
|
219969
|
+
}, undefined, false, undefined, this),
|
|
219970
|
+
" Back"
|
|
219971
|
+
]
|
|
219972
|
+
}, undefined, true, undefined, this)
|
|
219973
|
+
}, undefined, false, undefined, this)
|
|
219974
|
+
]
|
|
219975
|
+
}, undefined, true, undefined, this),
|
|
219976
|
+
step === "browser-opened" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219977
|
+
flexDirection: "column",
|
|
219978
|
+
gap: 1,
|
|
219979
|
+
children: [
|
|
219980
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219981
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219982
|
+
fg: "green",
|
|
219983
|
+
children: "Browser opened. Purchase credits on the Pensar Console."
|
|
219984
|
+
}, undefined, false, undefined, this)
|
|
219985
|
+
}, undefined, false, undefined, this),
|
|
219986
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
219987
|
+
marginTop: 1,
|
|
219988
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
219989
|
+
fg: "gray",
|
|
219990
|
+
children: [
|
|
219991
|
+
"Press ",
|
|
219992
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
219993
|
+
fg: "green",
|
|
219994
|
+
children: "[ENTER]"
|
|
219995
|
+
}, undefined, false, undefined, this),
|
|
219996
|
+
" to refresh your balance after purchasing."
|
|
219997
|
+
]
|
|
219998
|
+
}, undefined, true, undefined, this)
|
|
219999
|
+
}, undefined, false, undefined, this),
|
|
220000
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
220001
|
+
marginTop: 1,
|
|
220002
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
220003
|
+
fg: "gray",
|
|
220004
|
+
children: [
|
|
220005
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
220006
|
+
fg: "green",
|
|
220007
|
+
children: "[ENTER]"
|
|
220008
|
+
}, undefined, false, undefined, this),
|
|
220009
|
+
" Refresh balance ·",
|
|
220010
|
+
" ",
|
|
220011
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
220012
|
+
fg: "green",
|
|
220013
|
+
children: "[ESC]"
|
|
220014
|
+
}, undefined, false, undefined, this),
|
|
220015
|
+
" Back"
|
|
220016
|
+
]
|
|
220017
|
+
}, undefined, true, undefined, this)
|
|
220018
|
+
}, undefined, false, undefined, this)
|
|
220019
|
+
]
|
|
220020
|
+
}, undefined, true, undefined, this)
|
|
220021
|
+
]
|
|
220022
|
+
}, undefined, true, undefined, this);
|
|
220023
|
+
}
|
|
220024
|
+
|
|
217585
220025
|
// src/tui/context/keybinding.tsx
|
|
217586
|
-
var
|
|
220026
|
+
var import_react68 = __toESM(require_react(), 1);
|
|
217587
220027
|
|
|
217588
220028
|
// src/tui/keybindings/keybind.tsx
|
|
217589
|
-
var
|
|
220029
|
+
var import_react64 = __toESM(require_react(), 1);
|
|
217590
220030
|
|
|
217591
220031
|
// src/tui/keybindings/actions.ts
|
|
217592
220032
|
var movementActions = [
|
|
@@ -217838,7 +220278,7 @@ var allActions = [
|
|
|
217838
220278
|
var actionsByKey = new Map(allActions.map((action) => [action.key, action]));
|
|
217839
220279
|
var actionsById = new Map(allActions.map((action) => [action.id, action]));
|
|
217840
220280
|
// src/tui/keybindings/keybind.tsx
|
|
217841
|
-
var LeaderKeyContext =
|
|
220281
|
+
var LeaderKeyContext = import_react64.createContext(null);
|
|
217842
220282
|
// src/tui/keybindings/registry.ts
|
|
217843
220283
|
function createKeybindings(deps) {
|
|
217844
220284
|
const {
|
|
@@ -218016,7 +220456,7 @@ function matchesKeybind(pressed, combo) {
|
|
|
218016
220456
|
}
|
|
218017
220457
|
|
|
218018
220458
|
// src/tui/context/keybinding.tsx
|
|
218019
|
-
var KeybindingContext =
|
|
220459
|
+
var KeybindingContext = import_react68.createContext(undefined);
|
|
218020
220460
|
function KeybindingProvider({
|
|
218021
220461
|
children,
|
|
218022
220462
|
deps
|
|
@@ -218055,7 +220495,7 @@ function KeybindingProvider({
|
|
|
218055
220495
|
}
|
|
218056
220496
|
|
|
218057
220497
|
// src/tui/components/pentest/pentest.tsx
|
|
218058
|
-
var
|
|
220498
|
+
var import_react77 = __toESM(require_react(), 1);
|
|
218059
220499
|
import { existsSync as existsSync19, readdirSync as readdirSync5, readFileSync as readFileSync9 } from "fs";
|
|
218060
220500
|
import { join as join19 } from "path";
|
|
218061
220501
|
import { exec as exec3 } from "child_process";
|
|
@@ -218070,7 +220510,7 @@ import { join as join18 } from "path";
|
|
|
218070
220510
|
// src/core/workflows/whiteboxAttackSurface.ts
|
|
218071
220511
|
init_zod();
|
|
218072
220512
|
init_agent4();
|
|
218073
|
-
|
|
220513
|
+
init_types5();
|
|
218074
220514
|
var DEFAULT_CONCURRENCY3 = 5;
|
|
218075
220515
|
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
220516
|
|
|
@@ -218608,8 +221048,11 @@ Found ${findings.length} vulnerabilities`);
|
|
|
218608
221048
|
return { findings, findingsPath, pocsPath, reportPath };
|
|
218609
221049
|
}
|
|
218610
221050
|
|
|
221051
|
+
// src/tui/components/pentest/pentest.tsx
|
|
221052
|
+
init_utils2();
|
|
221053
|
+
|
|
218611
221054
|
// src/tui/components/agent-display.tsx
|
|
218612
|
-
var
|
|
221055
|
+
var import_react75 = __toESM(require_react(), 1);
|
|
218613
221056
|
|
|
218614
221057
|
// node_modules/marked/lib/marked.esm.js
|
|
218615
221058
|
function L2() {
|
|
@@ -220375,14 +222818,14 @@ function getResultSummary(result, toolName) {
|
|
|
220375
222818
|
return null;
|
|
220376
222819
|
}
|
|
220377
222820
|
// src/tui/components/shared/ascii-spinner.tsx
|
|
220378
|
-
var
|
|
222821
|
+
var import_react69 = __toESM(require_react(), 1);
|
|
220379
222822
|
var SPINNER_FRAMES = ["/", "-", "\\", "|"];
|
|
220380
222823
|
var SPINNER_INTERVAL = 100;
|
|
220381
222824
|
function AsciiSpinner({ label, fg: fg2 }) {
|
|
220382
222825
|
const { colors: colors2 } = useTheme();
|
|
220383
222826
|
const spinnerColor = fg2 ?? colors2.info;
|
|
220384
|
-
const [frame, setFrame] =
|
|
220385
|
-
|
|
222827
|
+
const [frame, setFrame] = import_react69.useState(0);
|
|
222828
|
+
import_react69.useEffect(() => {
|
|
220386
222829
|
const interval = setInterval(() => {
|
|
220387
222830
|
setFrame((f3) => (f3 + 1) % SPINNER_FRAMES.length);
|
|
220388
222831
|
}, SPINNER_INTERVAL);
|
|
@@ -220394,14 +222837,14 @@ function AsciiSpinner({ label, fg: fg2 }) {
|
|
|
220394
222837
|
}, undefined, false, undefined, this);
|
|
220395
222838
|
}
|
|
220396
222839
|
// src/tui/components/shared/tool-renderer.tsx
|
|
220397
|
-
var
|
|
220398
|
-
var ToolRenderer =
|
|
222840
|
+
var import_react70 = __toESM(require_react(), 1);
|
|
222841
|
+
var ToolRenderer = import_react70.memo(function ToolRenderer2({
|
|
220399
222842
|
message,
|
|
220400
222843
|
verbose = false,
|
|
220401
222844
|
expandedLogs = false
|
|
220402
222845
|
}) {
|
|
220403
222846
|
const { colors: colors2 } = useTheme();
|
|
220404
|
-
const [showOutput, setShowOutput] =
|
|
222847
|
+
const [showOutput, setShowOutput] = import_react70.useState(false);
|
|
220405
222848
|
if (!isToolMessage(message)) {
|
|
220406
222849
|
return null;
|
|
220407
222850
|
}
|
|
@@ -220498,8 +222941,8 @@ var ToolRenderer = import_react66.memo(function ToolRenderer2({
|
|
|
220498
222941
|
}, undefined, true, undefined, this);
|
|
220499
222942
|
});
|
|
220500
222943
|
// src/tui/components/shared/message-renderer.tsx
|
|
220501
|
-
var
|
|
220502
|
-
var MessageRenderer =
|
|
222944
|
+
var import_react71 = __toESM(require_react(), 1);
|
|
222945
|
+
var MessageRenderer = import_react71.memo(function MessageRenderer2({
|
|
220503
222946
|
message,
|
|
220504
222947
|
isStreaming = false,
|
|
220505
222948
|
verbose = false,
|
|
@@ -220509,7 +222952,7 @@ var MessageRenderer = import_react67.memo(function MessageRenderer2({
|
|
|
220509
222952
|
}) {
|
|
220510
222953
|
const { colors: colors2 } = useTheme();
|
|
220511
222954
|
const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content);
|
|
220512
|
-
const displayContent =
|
|
222955
|
+
const displayContent = import_react71.useMemo(() => message.role === "assistant" ? markdownToStyledText(content, colors2) : content, [content, message.role, colors2]);
|
|
220513
222956
|
if (isToolMessage(message)) {
|
|
220514
222957
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ToolRenderer, {
|
|
220515
222958
|
message,
|
|
@@ -220621,9 +223064,9 @@ var MessageRenderer = import_react67.memo(function MessageRenderer2({
|
|
|
220621
223064
|
}, undefined, false, undefined, this);
|
|
220622
223065
|
});
|
|
220623
223066
|
// src/tui/components/shared/approval-prompt.tsx
|
|
220624
|
-
var
|
|
223067
|
+
var import_react72 = __toESM(require_react(), 1);
|
|
220625
223068
|
// src/tui/components/shared/message-reducer.ts
|
|
220626
|
-
var
|
|
223069
|
+
var import_react74 = __toESM(require_react(), 1);
|
|
220627
223070
|
// src/tui/components/agent-display.tsx
|
|
220628
223071
|
function getStableKey(item, contextId = "root") {
|
|
220629
223072
|
if ("messages" in item) {
|
|
@@ -220699,11 +223142,11 @@ function AgentDisplay({
|
|
|
220699
223142
|
]
|
|
220700
223143
|
}, undefined, true, undefined, this);
|
|
220701
223144
|
}
|
|
220702
|
-
var SubAgentDisplay =
|
|
223145
|
+
var SubAgentDisplay = import_react75.memo(function SubAgentDisplay2({
|
|
220703
223146
|
subagent
|
|
220704
223147
|
}) {
|
|
220705
223148
|
const { colors: colors2 } = useTheme();
|
|
220706
|
-
const [open, setOpen] =
|
|
223149
|
+
const [open, setOpen] = import_react75.useState(false);
|
|
220707
223150
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
220708
223151
|
height: open ? 40 : "auto",
|
|
220709
223152
|
onMouseDown: () => setOpen(!open),
|
|
@@ -220758,7 +223201,7 @@ var SubAgentDisplay = import_react71.memo(function SubAgentDisplay2({
|
|
|
220758
223201
|
]
|
|
220759
223202
|
}, undefined, true, undefined, this);
|
|
220760
223203
|
});
|
|
220761
|
-
var AgentMessage =
|
|
223204
|
+
var AgentMessage = import_react75.memo(function AgentMessage2({
|
|
220762
223205
|
message
|
|
220763
223206
|
}) {
|
|
220764
223207
|
const { colors: colors2 } = useTheme();
|
|
@@ -220822,9 +223265,9 @@ var AgentMessage = import_react71.memo(function AgentMessage2({
|
|
|
220822
223265
|
flexDirection: "column",
|
|
220823
223266
|
marginTop: 0,
|
|
220824
223267
|
paddingLeft: 2,
|
|
220825
|
-
children: streamingLogs.slice(-3).map((
|
|
223268
|
+
children: streamingLogs.slice(-3).map((log2, idx) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
220826
223269
|
fg: colors2.textMuted,
|
|
220827
|
-
content:
|
|
223270
|
+
content: log2.length > 100 ? log2.slice(0, 100) + "…" : log2
|
|
220828
223271
|
}, idx, false, undefined, this))
|
|
220829
223272
|
}, undefined, false, undefined, this)
|
|
220830
223273
|
]
|
|
@@ -220871,8 +223314,8 @@ var AgentMessage = import_react71.memo(function AgentMessage2({
|
|
|
220871
223314
|
});
|
|
220872
223315
|
function ToolDetails({ message }) {
|
|
220873
223316
|
const { colors: colors2 } = useTheme();
|
|
220874
|
-
const [showArgs, setShowArgs] =
|
|
220875
|
-
const [showResult, setShowResult] =
|
|
223317
|
+
const [showArgs, setShowArgs] = import_react75.useState(false);
|
|
223318
|
+
const [showResult, setShowResult] = import_react75.useState(false);
|
|
220876
223319
|
if (message.role !== "tool") {
|
|
220877
223320
|
return null;
|
|
220878
223321
|
}
|
|
@@ -220950,24 +223393,24 @@ function Pentest({ sessionId }) {
|
|
|
220950
223393
|
const config3 = useConfig();
|
|
220951
223394
|
const { model, setThinking, setIsExecuting, isExecuting } = useAgent();
|
|
220952
223395
|
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
|
-
|
|
223396
|
+
const [session, setSession] = import_react77.useState(null);
|
|
223397
|
+
const [error40, setError] = import_react77.useState(null);
|
|
223398
|
+
const [phase, setPhase] = import_react77.useState("loading");
|
|
223399
|
+
const [abortController, setAbortController] = import_react77.useState(null);
|
|
223400
|
+
const [panelMessages, setPanelMessages] = import_react77.useState([]);
|
|
223401
|
+
const panelTextRef = import_react77.useRef("");
|
|
223402
|
+
const panelSourceRef = import_react77.useRef(null);
|
|
223403
|
+
const [pentestAgents, setPentestAgents] = import_react77.useState({});
|
|
223404
|
+
const pentestTextRefs = import_react77.useRef({});
|
|
223405
|
+
const [assets, setAssets] = import_react77.useState([]);
|
|
223406
|
+
const [viewMode, setViewMode] = import_react77.useState("overview");
|
|
223407
|
+
const [selectedAgentId, setSelectedAgentId] = import_react77.useState(null);
|
|
223408
|
+
const [focusedIndex, setFocusedIndex] = import_react77.useState(0);
|
|
223409
|
+
const [showOrchestratorPanel, setShowOrchestratorPanel] = import_react77.useState(false);
|
|
223410
|
+
const [startTime, setStartTime] = import_react77.useState(null);
|
|
223411
|
+
const pentestAgentList = import_react77.useMemo(() => Object.values(pentestAgents).sort((a, b3) => a.createdAt.getTime() - b3.createdAt.getTime()), [pentestAgents]);
|
|
223412
|
+
const selectedAgent = import_react77.useMemo(() => selectedAgentId ? pentestAgents[selectedAgentId] ?? null : null, [pentestAgents, selectedAgentId]);
|
|
223413
|
+
import_react77.useEffect(() => {
|
|
220971
223414
|
async function load() {
|
|
220972
223415
|
try {
|
|
220973
223416
|
const s2 = await sessions.get(sessionId);
|
|
@@ -220984,7 +223427,7 @@ function Pentest({ sessionId }) {
|
|
|
220984
223427
|
}
|
|
220985
223428
|
load();
|
|
220986
223429
|
}, [sessionId]);
|
|
220987
|
-
|
|
223430
|
+
import_react77.useEffect(() => {
|
|
220988
223431
|
if (!session)
|
|
220989
223432
|
return;
|
|
220990
223433
|
const assetsPath = join19(session.rootPath, "assets");
|
|
@@ -221007,12 +223450,12 @@ function Pentest({ sessionId }) {
|
|
|
221007
223450
|
const interval = setInterval(readAssets, 2000);
|
|
221008
223451
|
return () => clearInterval(interval);
|
|
221009
223452
|
}, [session]);
|
|
221010
|
-
|
|
223453
|
+
import_react77.useEffect(() => {
|
|
221011
223454
|
return () => {
|
|
221012
223455
|
abortController?.abort();
|
|
221013
223456
|
};
|
|
221014
223457
|
}, [abortController]);
|
|
221015
|
-
const ensurePentestAgent =
|
|
223458
|
+
const ensurePentestAgent = import_react77.useCallback((subagentId) => {
|
|
221016
223459
|
setPentestAgents((prev) => {
|
|
221017
223460
|
if (prev[subagentId])
|
|
221018
223461
|
return prev;
|
|
@@ -221029,7 +223472,7 @@ function Pentest({ sessionId }) {
|
|
|
221029
223472
|
};
|
|
221030
223473
|
});
|
|
221031
223474
|
}, []);
|
|
221032
|
-
const handleSubagentSpawn =
|
|
223475
|
+
const handleSubagentSpawn = import_react77.useCallback(({
|
|
221033
223476
|
subagentId,
|
|
221034
223477
|
input
|
|
221035
223478
|
}) => {
|
|
@@ -221049,7 +223492,7 @@ function Pentest({ sessionId }) {
|
|
|
221049
223492
|
}
|
|
221050
223493
|
}));
|
|
221051
223494
|
}, []);
|
|
221052
|
-
const handleSubagentComplete =
|
|
223495
|
+
const handleSubagentComplete = import_react77.useCallback(({ subagentId, status }) => {
|
|
221053
223496
|
if (!subagentId.startsWith("pentest-agent-"))
|
|
221054
223497
|
return;
|
|
221055
223498
|
setPentestAgents((prev) => {
|
|
@@ -221062,7 +223505,7 @@ function Pentest({ sessionId }) {
|
|
|
221062
223505
|
};
|
|
221063
223506
|
});
|
|
221064
223507
|
}, []);
|
|
221065
|
-
const appendPanelText =
|
|
223508
|
+
const appendPanelText = import_react77.useCallback((source, text2) => {
|
|
221066
223509
|
if (panelSourceRef.current !== source) {
|
|
221067
223510
|
panelTextRef.current = "";
|
|
221068
223511
|
panelSourceRef.current = source;
|
|
@@ -221087,7 +223530,7 @@ function Pentest({ sessionId }) {
|
|
|
221087
223530
|
];
|
|
221088
223531
|
});
|
|
221089
223532
|
}, []);
|
|
221090
|
-
const appendPentestText =
|
|
223533
|
+
const appendPentestText = import_react77.useCallback((subagentId, text2) => {
|
|
221091
223534
|
ensurePentestAgent(subagentId);
|
|
221092
223535
|
if (!pentestTextRefs.current[subagentId]) {
|
|
221093
223536
|
pentestTextRefs.current[subagentId] = "";
|
|
@@ -221120,7 +223563,7 @@ function Pentest({ sessionId }) {
|
|
|
221120
223563
|
};
|
|
221121
223564
|
});
|
|
221122
223565
|
}, [ensurePentestAgent]);
|
|
221123
|
-
const addPanelToolCall =
|
|
223566
|
+
const addPanelToolCall = import_react77.useCallback((toolCallId, toolName, args) => {
|
|
221124
223567
|
panelTextRef.current = "";
|
|
221125
223568
|
panelSourceRef.current = null;
|
|
221126
223569
|
const description = typeof args?.toolCallDescription === "string" ? args.toolCallDescription : toolName;
|
|
@@ -221139,7 +223582,7 @@ function Pentest({ sessionId }) {
|
|
|
221139
223582
|
return [...prev, msg];
|
|
221140
223583
|
});
|
|
221141
223584
|
}, []);
|
|
221142
|
-
const addPentestToolCall =
|
|
223585
|
+
const addPentestToolCall = import_react77.useCallback((subagentId, toolCallId, toolName, args) => {
|
|
221143
223586
|
pentestTextRefs.current[subagentId] = "";
|
|
221144
223587
|
ensurePentestAgent(subagentId);
|
|
221145
223588
|
const description = typeof args?.toolCallDescription === "string" ? args.toolCallDescription : toolName;
|
|
@@ -221184,12 +223627,12 @@ function Pentest({ sessionId }) {
|
|
|
221184
223627
|
}
|
|
221185
223628
|
];
|
|
221186
223629
|
};
|
|
221187
|
-
const updatePanelToolResult =
|
|
223630
|
+
const updatePanelToolResult = import_react77.useCallback((toolCallId, toolName, result) => {
|
|
221188
223631
|
panelTextRef.current = "";
|
|
221189
223632
|
panelSourceRef.current = null;
|
|
221190
223633
|
setPanelMessages((prev) => toolResultUpdater(prev, toolCallId, toolName, result));
|
|
221191
223634
|
}, []);
|
|
221192
|
-
const updatePentestToolResult =
|
|
223635
|
+
const updatePentestToolResult = import_react77.useCallback((subagentId, toolCallId, toolName, result) => {
|
|
221193
223636
|
pentestTextRefs.current[subagentId] = "";
|
|
221194
223637
|
setPentestAgents((prev) => {
|
|
221195
223638
|
const agent = prev[subagentId];
|
|
@@ -221204,7 +223647,7 @@ function Pentest({ sessionId }) {
|
|
|
221204
223647
|
};
|
|
221205
223648
|
});
|
|
221206
223649
|
}, []);
|
|
221207
|
-
const startPentest =
|
|
223650
|
+
const startPentest = import_react77.useCallback(async (s2) => {
|
|
221208
223651
|
setPhase("discovery");
|
|
221209
223652
|
setStartTime(new Date);
|
|
221210
223653
|
setIsExecuting(true);
|
|
@@ -221218,12 +223661,7 @@ function Pentest({ sessionId }) {
|
|
|
221218
223661
|
session: s2,
|
|
221219
223662
|
model: model.id,
|
|
221220
223663
|
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
|
-
},
|
|
223664
|
+
authConfig: buildAuthConfig(config3.data),
|
|
221227
223665
|
callbacks: {
|
|
221228
223666
|
onTextDelta: (d3) => {
|
|
221229
223667
|
setThinking(false);
|
|
@@ -221306,7 +223744,7 @@ function Pentest({ sessionId }) {
|
|
|
221306
223744
|
handleSubagentSpawn,
|
|
221307
223745
|
handleSubagentComplete
|
|
221308
223746
|
]);
|
|
221309
|
-
|
|
223747
|
+
import_react77.useEffect(() => {
|
|
221310
223748
|
if (session && phase === "loading") {
|
|
221311
223749
|
startPentest(session);
|
|
221312
223750
|
}
|
|
@@ -221368,7 +223806,7 @@ function Pentest({ sessionId }) {
|
|
|
221368
223806
|
}
|
|
221369
223807
|
}
|
|
221370
223808
|
});
|
|
221371
|
-
const openReport =
|
|
223809
|
+
const openReport = import_react77.useCallback(() => {
|
|
221372
223810
|
if (!session)
|
|
221373
223811
|
return;
|
|
221374
223812
|
const reportPath = join19(session.rootPath, "pentest-report.md");
|
|
@@ -221560,7 +223998,7 @@ function OrchestratorPanel({
|
|
|
221560
223998
|
}) {
|
|
221561
223999
|
const { colors: colors2 } = useTheme();
|
|
221562
224000
|
const isRunning = phase !== "loading" && phase !== "completed" && phase !== "error";
|
|
221563
|
-
const assetSummary =
|
|
224001
|
+
const assetSummary = import_react77.useMemo(() => {
|
|
221564
224002
|
const byType = {};
|
|
221565
224003
|
for (const a of assets) {
|
|
221566
224004
|
const key = a.assetType;
|
|
@@ -221809,7 +224247,7 @@ function AgentCardGrid({
|
|
|
221809
224247
|
onSelectAgent
|
|
221810
224248
|
}) {
|
|
221811
224249
|
const { colors: colors2 } = useTheme();
|
|
221812
|
-
const rows =
|
|
224250
|
+
const rows = import_react77.useMemo(() => {
|
|
221813
224251
|
const result = [];
|
|
221814
224252
|
for (let i2 = 0;i2 < agents.length; i2 += 2) {
|
|
221815
224253
|
result.push(agents.slice(i2, i2 + 2));
|
|
@@ -221857,14 +224295,14 @@ function AgentCard({
|
|
|
221857
224295
|
completed: colors2.primary,
|
|
221858
224296
|
failed: colors2.error
|
|
221859
224297
|
}[agent.status];
|
|
221860
|
-
const lastActivity =
|
|
224298
|
+
const lastActivity = import_react77.useMemo(() => {
|
|
221861
224299
|
const last = agent.messages[agent.messages.length - 1];
|
|
221862
224300
|
if (!last)
|
|
221863
224301
|
return "Starting...";
|
|
221864
224302
|
const text2 = typeof last.content === "string" ? last.content.replace(/\n/g, " ").trim() : "Working...";
|
|
221865
224303
|
return text2.length > 50 ? text2.substring(0, 47) + "..." : text2;
|
|
221866
224304
|
}, [agent.messages]);
|
|
221867
|
-
const toolCalls =
|
|
224305
|
+
const toolCalls = import_react77.useMemo(() => agent.messages.filter((m4) => m4.role === "tool").length, [agent.messages]);
|
|
221868
224306
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
221869
224307
|
flexGrow: 1,
|
|
221870
224308
|
flexBasis: 0,
|
|
@@ -222051,8 +224489,8 @@ function MetricsBar({
|
|
|
222051
224489
|
isExecuting
|
|
222052
224490
|
}) {
|
|
222053
224491
|
const { colors: colors2 } = useTheme();
|
|
222054
|
-
const [now2, setNow] =
|
|
222055
|
-
|
|
224492
|
+
const [now2, setNow] = import_react77.useState(Date.now());
|
|
224493
|
+
import_react77.useEffect(() => {
|
|
222056
224494
|
if (!isExecuting)
|
|
222057
224495
|
return;
|
|
222058
224496
|
const interval = setInterval(() => setNow(Date.now()), 1000);
|
|
@@ -222195,7 +224633,7 @@ function MetricsBar({
|
|
|
222195
224633
|
}
|
|
222196
224634
|
|
|
222197
224635
|
// src/tui/components/operator-dashboard/index.tsx
|
|
222198
|
-
var
|
|
224636
|
+
var import_react82 = __toESM(require_react(), 1);
|
|
222199
224637
|
|
|
222200
224638
|
// src/core/api/offesecAgent.ts
|
|
222201
224639
|
init_offensiveSecurityAgent();
|
|
@@ -222210,6 +224648,9 @@ async function runOffensiveSecurityAgent(input) {
|
|
|
222210
224648
|
});
|
|
222211
224649
|
}
|
|
222212
224650
|
|
|
224651
|
+
// src/tui/components/operator-dashboard/index.tsx
|
|
224652
|
+
init_utils2();
|
|
224653
|
+
|
|
222213
224654
|
// src/core/agents/offSecAgent/index.ts
|
|
222214
224655
|
init_offensiveSecurityAgent();
|
|
222215
224656
|
init_tools();
|
|
@@ -222292,7 +224733,7 @@ function InlineApprovalPrompt2({ approval }) {
|
|
|
222292
224733
|
}
|
|
222293
224734
|
|
|
222294
224735
|
// src/tui/components/chat/loading-indicator.tsx
|
|
222295
|
-
var
|
|
224736
|
+
var import_react79 = __toESM(require_react(), 1);
|
|
222296
224737
|
var SPINNER_FRAMES2 = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
222297
224738
|
var SPINNER_INTERVAL2 = 80;
|
|
222298
224739
|
var DOTS_FRAMES = ["", ".", "..", "..."];
|
|
@@ -222303,15 +224744,15 @@ function LoadingIndicator({
|
|
|
222303
224744
|
toolName
|
|
222304
224745
|
}) {
|
|
222305
224746
|
const { colors: colors2 } = useTheme();
|
|
222306
|
-
const [spinnerFrame, setSpinnerFrame] =
|
|
222307
|
-
const [dotsFrame, setDotsFrame] =
|
|
222308
|
-
|
|
224747
|
+
const [spinnerFrame, setSpinnerFrame] = import_react79.useState(0);
|
|
224748
|
+
const [dotsFrame, setDotsFrame] = import_react79.useState(0);
|
|
224749
|
+
import_react79.useEffect(() => {
|
|
222309
224750
|
const interval = setInterval(() => {
|
|
222310
224751
|
setSpinnerFrame((f3) => (f3 + 1) % SPINNER_FRAMES2.length);
|
|
222311
224752
|
}, SPINNER_INTERVAL2);
|
|
222312
224753
|
return () => clearInterval(interval);
|
|
222313
224754
|
}, []);
|
|
222314
|
-
|
|
224755
|
+
import_react79.useEffect(() => {
|
|
222315
224756
|
const interval = setInterval(() => {
|
|
222316
224757
|
setDotsFrame((f3) => (f3 + 1) % DOTS_FRAMES.length);
|
|
222317
224758
|
}, DOTS_INTERVAL);
|
|
@@ -222581,7 +225022,7 @@ function MessageList({
|
|
|
222581
225022
|
}
|
|
222582
225023
|
|
|
222583
225024
|
// src/tui/components/chat/input-area.tsx
|
|
222584
|
-
var
|
|
225025
|
+
var import_react80 = __toESM(require_react(), 1);
|
|
222585
225026
|
function NormalInputAreaInner({
|
|
222586
225027
|
value,
|
|
222587
225028
|
onChange,
|
|
@@ -222596,17 +225037,17 @@ function NormalInputAreaInner({
|
|
|
222596
225037
|
}) {
|
|
222597
225038
|
const { colors: colors2 } = useTheme();
|
|
222598
225039
|
const { inputValue, setInputValue } = useInput();
|
|
222599
|
-
const promptRef =
|
|
222600
|
-
const isExternalUpdate =
|
|
225040
|
+
const promptRef = import_react80.useRef(null);
|
|
225041
|
+
const isExternalUpdate = import_react80.useRef(false);
|
|
222601
225042
|
const isDisabled = status === "running";
|
|
222602
|
-
|
|
225043
|
+
import_react80.useEffect(() => {
|
|
222603
225044
|
if (value !== inputValue) {
|
|
222604
225045
|
isExternalUpdate.current = true;
|
|
222605
225046
|
setInputValue(value);
|
|
222606
225047
|
promptRef.current?.setValue(value);
|
|
222607
225048
|
}
|
|
222608
225049
|
}, [value]);
|
|
222609
|
-
|
|
225050
|
+
import_react80.useEffect(() => {
|
|
222610
225051
|
if (isExternalUpdate.current) {
|
|
222611
225052
|
isExternalUpdate.current = false;
|
|
222612
225053
|
return;
|
|
@@ -222756,7 +225197,7 @@ function ApprovalInputArea2({
|
|
|
222756
225197
|
lastDeclineNote
|
|
222757
225198
|
}) {
|
|
222758
225199
|
const { colors: colors2 } = useTheme();
|
|
222759
|
-
const [focusedElement, setFocusedElement] =
|
|
225200
|
+
const [focusedElement, setFocusedElement] = import_react80.useState(0);
|
|
222760
225201
|
const tierColor = getTierColor(colors2, approval.tier);
|
|
222761
225202
|
useKeyboard((key) => {
|
|
222762
225203
|
if (key.name === "up") {
|
|
@@ -222878,20 +225319,20 @@ function OperatorDashboard({
|
|
|
222878
225319
|
const route = useRoute();
|
|
222879
225320
|
const config3 = useConfig();
|
|
222880
225321
|
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
|
-
|
|
225322
|
+
const [session, setSession] = import_react82.useState(null);
|
|
225323
|
+
const [loading, setLoading] = import_react82.useState(true);
|
|
225324
|
+
const [error40, setError] = import_react82.useState(null);
|
|
225325
|
+
const [status, setStatus] = import_react82.useState("idle");
|
|
225326
|
+
const abortControllerRef = import_react82.useRef(null);
|
|
225327
|
+
const [messages, setMessages] = import_react82.useState([]);
|
|
225328
|
+
const textRef = import_react82.useRef("");
|
|
225329
|
+
const [inputValue, setInputValue] = import_react82.useState("");
|
|
225330
|
+
const [operatorState, setOperatorState] = import_react82.useState(() => createInitialOperatorState("manual", 2));
|
|
225331
|
+
const [pendingApprovals] = import_react82.useState([]);
|
|
225332
|
+
const [lastApprovedAction] = import_react82.useState(null);
|
|
225333
|
+
const [verboseMode, setVerboseMode] = import_react82.useState(false);
|
|
225334
|
+
const [expandedLogs, setExpandedLogs] = import_react82.useState(false);
|
|
225335
|
+
import_react82.useEffect(() => {
|
|
222895
225336
|
async function loadSession() {
|
|
222896
225337
|
try {
|
|
222897
225338
|
const s2 = await sessions.get(sessionId);
|
|
@@ -222923,7 +225364,7 @@ function OperatorDashboard({
|
|
|
222923
225364
|
}
|
|
222924
225365
|
loadSession();
|
|
222925
225366
|
}, [sessionId, isResume]);
|
|
222926
|
-
const appendText =
|
|
225367
|
+
const appendText = import_react82.useCallback((text2) => {
|
|
222927
225368
|
textRef.current += text2;
|
|
222928
225369
|
const accumulated = textRef.current;
|
|
222929
225370
|
setMessages((prev) => {
|
|
@@ -222939,7 +225380,7 @@ function OperatorDashboard({
|
|
|
222939
225380
|
];
|
|
222940
225381
|
});
|
|
222941
225382
|
}, []);
|
|
222942
|
-
const addToolCall =
|
|
225383
|
+
const addToolCall = import_react82.useCallback((toolCallId, toolName, args) => {
|
|
222943
225384
|
textRef.current = "";
|
|
222944
225385
|
setMessages((prev) => [
|
|
222945
225386
|
...prev,
|
|
@@ -222954,7 +225395,7 @@ function OperatorDashboard({
|
|
|
222954
225395
|
}
|
|
222955
225396
|
]);
|
|
222956
225397
|
}, []);
|
|
222957
|
-
const updateToolResult =
|
|
225398
|
+
const updateToolResult = import_react82.useCallback((toolCallId, _toolName, result) => {
|
|
222958
225399
|
textRef.current = "";
|
|
222959
225400
|
setMessages((prev) => {
|
|
222960
225401
|
const idx = prev.findIndex((m4) => isToolMessage(m4) && m4.toolCallId === toolCallId);
|
|
@@ -222965,7 +225406,7 @@ function OperatorDashboard({
|
|
|
222965
225406
|
return updated;
|
|
222966
225407
|
});
|
|
222967
225408
|
}, []);
|
|
222968
|
-
const runAgent =
|
|
225409
|
+
const runAgent = import_react82.useCallback(async (prompt) => {
|
|
222969
225410
|
if (!session)
|
|
222970
225411
|
return;
|
|
222971
225412
|
setStatus("running");
|
|
@@ -222989,12 +225430,7 @@ function OperatorDashboard({
|
|
|
222989
225430
|
target: session.targets[0],
|
|
222990
225431
|
activeTools: [...ALL_TOOL_NAMES],
|
|
222991
225432
|
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
|
-
},
|
|
225433
|
+
authConfig: buildAuthConfig(config3.data),
|
|
222998
225434
|
callbacks: {
|
|
222999
225435
|
onTextDelta: (d3) => {
|
|
223000
225436
|
setThinking(false);
|
|
@@ -223044,13 +225480,13 @@ function OperatorDashboard({
|
|
|
223044
225480
|
setThinking,
|
|
223045
225481
|
setIsExecuting
|
|
223046
225482
|
]);
|
|
223047
|
-
const handleSubmit =
|
|
225483
|
+
const handleSubmit = import_react82.useCallback((value) => {
|
|
223048
225484
|
if (!value.trim() || status === "running")
|
|
223049
225485
|
return;
|
|
223050
225486
|
setInputValue("");
|
|
223051
225487
|
runAgent(value.trim());
|
|
223052
225488
|
}, [status, runAgent]);
|
|
223053
|
-
const handleAbort =
|
|
225489
|
+
const handleAbort = import_react82.useCallback(() => {
|
|
223054
225490
|
if (abortControllerRef.current) {
|
|
223055
225491
|
abortControllerRef.current.abort();
|
|
223056
225492
|
abortControllerRef.current = null;
|
|
@@ -223261,7 +225697,8 @@ Session paths:
|
|
|
223261
225697
|
}
|
|
223262
225698
|
|
|
223263
225699
|
// src/tui/components/commands/theme-picker.tsx
|
|
223264
|
-
var
|
|
225700
|
+
var import_react84 = __toESM(require_react(), 1);
|
|
225701
|
+
init_config2();
|
|
223265
225702
|
function ThemePicker() {
|
|
223266
225703
|
const dimensions = useTerminalDimensions();
|
|
223267
225704
|
const route = useRoute();
|
|
@@ -223274,15 +225711,15 @@ function ThemePicker() {
|
|
|
223274
225711
|
toggleMode,
|
|
223275
225712
|
setMode
|
|
223276
225713
|
} = useTheme();
|
|
223277
|
-
const [selectedIndex, setSelectedIndex] =
|
|
223278
|
-
const originalThemeRef =
|
|
223279
|
-
const originalModeRef =
|
|
223280
|
-
const handleClose =
|
|
225714
|
+
const [selectedIndex, setSelectedIndex] = import_react84.useState(() => Math.max(0, availableThemes.indexOf(theme.name)));
|
|
225715
|
+
const originalThemeRef = import_react84.useRef(theme.name);
|
|
225716
|
+
const originalModeRef = import_react84.useRef(mode);
|
|
225717
|
+
const handleClose = import_react84.useCallback(() => {
|
|
223281
225718
|
setTheme(originalThemeRef.current);
|
|
223282
225719
|
setMode(originalModeRef.current);
|
|
223283
225720
|
route.navigate({ type: "base", path: "home" });
|
|
223284
225721
|
}, [setTheme, setMode, route]);
|
|
223285
|
-
const handleConfirm =
|
|
225722
|
+
const handleConfirm = import_react84.useCallback(async () => {
|
|
223286
225723
|
const currentThemeName = availableThemes[selectedIndex];
|
|
223287
225724
|
if (currentThemeName) {
|
|
223288
225725
|
await config.update({ theme: currentThemeName });
|
|
@@ -225810,13 +228247,13 @@ async function detectTerminalMode(timeoutMs = 1000) {
|
|
|
225810
228247
|
|
|
225811
228248
|
// src/tui/index.tsx
|
|
225812
228249
|
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] =
|
|
228250
|
+
const [focusIndex, setFocusIndex] = import_react87.useState(0);
|
|
228251
|
+
const [cwd, setCwd] = import_react87.useState(process.cwd());
|
|
228252
|
+
const [ctrlCPressTime, setCtrlCPressTime] = import_react87.useState(null);
|
|
228253
|
+
const [showExitWarning, setShowExitWarning] = import_react87.useState(false);
|
|
228254
|
+
const [inputKey, setInputKey] = import_react87.useState(0);
|
|
228255
|
+
const [showSessionsDialog, setShowSessionsDialog] = import_react87.useState(false);
|
|
228256
|
+
const [showShortcutsDialog, setShowShortcutsDialog] = import_react87.useState(false);
|
|
225820
228257
|
const navigableItems = ["command-input"];
|
|
225821
228258
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ConfigProvider, {
|
|
225822
228259
|
config: appConfig,
|
|
@@ -225880,14 +228317,14 @@ function AppContent({
|
|
|
225880
228317
|
const { toast } = useToast();
|
|
225881
228318
|
const { refocusPrompt } = useFocus();
|
|
225882
228319
|
const { setExternalDialogOpen } = useDialog();
|
|
225883
|
-
|
|
228320
|
+
import_react87.useEffect(() => {
|
|
225884
228321
|
checkForUpdate().then(({ updateAvailable, currentVersion, latestVersion }) => {
|
|
225885
228322
|
if (!updateAvailable)
|
|
225886
228323
|
return;
|
|
225887
228324
|
toast(`Update available: v${currentVersion} → v${latestVersion}. Run: pensar upgrade`, "warn", 8000);
|
|
225888
228325
|
});
|
|
225889
228326
|
}, []);
|
|
225890
|
-
|
|
228327
|
+
import_react87.useEffect(() => {
|
|
225891
228328
|
if (route.data.type !== "base")
|
|
225892
228329
|
return;
|
|
225893
228330
|
if (!config3.data.responsibleUseAccepted && route.data.path !== "disclosure") {
|
|
@@ -225896,7 +228333,7 @@ function AppContent({
|
|
|
225896
228333
|
route.navigate({ type: "base", path: "providers" });
|
|
225897
228334
|
}
|
|
225898
228335
|
}, [config3.data.responsibleUseAccepted, route.data]);
|
|
225899
|
-
|
|
228336
|
+
import_react87.useEffect(() => {
|
|
225900
228337
|
if (showExitWarning) {
|
|
225901
228338
|
const timer = setTimeout(() => {
|
|
225902
228339
|
setShowExitWarning(false);
|
|
@@ -226042,6 +228479,14 @@ function CommandDisplay({
|
|
|
226042
228479
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
|
|
226043
228480
|
when: "models",
|
|
226044
228481
|
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ModelsDisplay, {}, undefined, false, undefined, this)
|
|
228482
|
+
}, undefined, false, undefined, this),
|
|
228483
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
|
|
228484
|
+
when: "auth",
|
|
228485
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AuthFlow, {}, undefined, false, undefined, this)
|
|
228486
|
+
}, undefined, false, undefined, this),
|
|
228487
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteSwitch.Case, {
|
|
228488
|
+
when: "credits",
|
|
228489
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(CreditsFlow, {}, undefined, false, undefined, this)
|
|
226045
228490
|
}, undefined, false, undefined, this)
|
|
226046
228491
|
]
|
|
226047
228492
|
}, undefined, true, undefined, this)
|