@pensar/apex 0.0.104 → 0.0.105
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/auth.js +1 -1
- package/build/index.js +436 -253
- package/package.json +1 -1
package/build/auth.js
CHANGED
|
@@ -8,7 +8,7 @@ import fs from "fs/promises";
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "@pensar/apex",
|
|
11
|
-
version: "0.0.
|
|
11
|
+
version: "0.0.105",
|
|
12
12
|
description: "AI-powered penetration testing CLI tool with terminal UI",
|
|
13
13
|
module: "src/tui/index.tsx",
|
|
14
14
|
main: "build/index.js",
|
package/build/index.js
CHANGED
|
@@ -31977,7 +31977,7 @@ var package_default2;
|
|
|
31977
31977
|
var init_package = __esm(() => {
|
|
31978
31978
|
package_default2 = {
|
|
31979
31979
|
name: "@pensar/apex",
|
|
31980
|
-
version: "0.0.
|
|
31980
|
+
version: "0.0.105",
|
|
31981
31981
|
description: "AI-powered penetration testing CLI tool with terminal UI",
|
|
31982
31982
|
module: "src/tui/index.tsx",
|
|
31983
31983
|
main: "build/index.js",
|
|
@@ -162544,7 +162544,7 @@ var require_jwa = __commonJS((exports, module2) => {
|
|
|
162544
162544
|
return bufferEqual(a, b2);
|
|
162545
162545
|
};
|
|
162546
162546
|
function createHmacVerifier(bits) {
|
|
162547
|
-
return function
|
|
162547
|
+
return function verify2(thing, signature, secret) {
|
|
162548
162548
|
var computedSig = createHmacSigner(bits)(thing, secret);
|
|
162549
162549
|
return timingSafeEqual(Buffer4.from(signature), Buffer4.from(computedSig));
|
|
162550
162550
|
};
|
|
@@ -162559,7 +162559,7 @@ var require_jwa = __commonJS((exports, module2) => {
|
|
|
162559
162559
|
};
|
|
162560
162560
|
}
|
|
162561
162561
|
function createKeyVerifier(bits) {
|
|
162562
|
-
return function
|
|
162562
|
+
return function verify2(thing, signature, publicKey) {
|
|
162563
162563
|
checkIsPublicKey(publicKey);
|
|
162564
162564
|
thing = normalizeInput(thing);
|
|
162565
162565
|
signature = toBase64(signature);
|
|
@@ -162582,7 +162582,7 @@ var require_jwa = __commonJS((exports, module2) => {
|
|
|
162582
162582
|
};
|
|
162583
162583
|
}
|
|
162584
162584
|
function createPSSKeyVerifier(bits) {
|
|
162585
|
-
return function
|
|
162585
|
+
return function verify2(thing, signature, publicKey) {
|
|
162586
162586
|
checkIsPublicKey(publicKey);
|
|
162587
162587
|
thing = normalizeInput(thing);
|
|
162588
162588
|
signature = toBase64(signature);
|
|
@@ -162605,7 +162605,7 @@ var require_jwa = __commonJS((exports, module2) => {
|
|
|
162605
162605
|
}
|
|
162606
162606
|
function createECDSAVerifer(bits) {
|
|
162607
162607
|
var inner = createKeyVerifier(bits);
|
|
162608
|
-
return function
|
|
162608
|
+
return function verify2(thing, signature, publicKey) {
|
|
162609
162609
|
signature = formatEcdsa.joseToDer(signature, "ES" + bits).toString("base64");
|
|
162610
162610
|
var result = inner(thing, signature, publicKey);
|
|
162611
162611
|
return result;
|
|
@@ -162617,7 +162617,7 @@ var require_jwa = __commonJS((exports, module2) => {
|
|
|
162617
162617
|
};
|
|
162618
162618
|
}
|
|
162619
162619
|
function createNoneVerifier() {
|
|
162620
|
-
return function
|
|
162620
|
+
return function verify2(thing, signature) {
|
|
162621
162621
|
return signature === "";
|
|
162622
162622
|
};
|
|
162623
162623
|
}
|
|
@@ -162825,7 +162825,7 @@ var require_verify_stream = __commonJS((exports, module2) => {
|
|
|
162825
162825
|
}.bind(this));
|
|
162826
162826
|
}
|
|
162827
162827
|
util4.inherits(VerifyStream, Stream3);
|
|
162828
|
-
VerifyStream.prototype.verify = function
|
|
162828
|
+
VerifyStream.prototype.verify = function verify2() {
|
|
162829
162829
|
try {
|
|
162830
162830
|
var valid = jwsVerify(this.signature.buffer, this.algorithm, this.key.buffer);
|
|
162831
162831
|
var obj = jwsDecode(this.signature.buffer, this.encoding);
|
|
@@ -273082,7 +273082,7 @@ import os6 from "os";
|
|
|
273082
273082
|
// src/tui/context/agent.tsx
|
|
273083
273083
|
init_models();
|
|
273084
273084
|
init_config();
|
|
273085
|
-
var
|
|
273085
|
+
var import_react12 = __toESM(require_react(), 1);
|
|
273086
273086
|
|
|
273087
273087
|
// src/core/providers/utils.ts
|
|
273088
273088
|
init_models();
|
|
@@ -273135,11 +273135,26 @@ var AVAILABLE_PROVIDERS = [
|
|
|
273135
273135
|
id: "pensar",
|
|
273136
273136
|
name: "Pensar",
|
|
273137
273137
|
description: "Managed inference via Pensar Console (usage-based billing)",
|
|
273138
|
-
requiresAPIKey:
|
|
273138
|
+
requiresAPIKey: false
|
|
273139
273139
|
}
|
|
273140
273140
|
];
|
|
273141
273141
|
|
|
273142
273142
|
// src/core/providers/utils.ts
|
|
273143
|
+
var PROVIDER_PREFERENCE_ORDER = [
|
|
273144
|
+
"pensar",
|
|
273145
|
+
"anthropic",
|
|
273146
|
+
"openai",
|
|
273147
|
+
"google",
|
|
273148
|
+
"openrouter",
|
|
273149
|
+
"bedrock"
|
|
273150
|
+
];
|
|
273151
|
+
var PREFERRED_MODEL_BY_PROVIDER = {
|
|
273152
|
+
pensar: "pensar:anthropic.claude-opus-4-1-20250805-v1:0",
|
|
273153
|
+
anthropic: "claude-opus-4-6",
|
|
273154
|
+
openai: "gpt-5.2-pro",
|
|
273155
|
+
google: "gemini-3.1-pro-preview",
|
|
273156
|
+
openrouter: "anthropic/claude-opus-4.6"
|
|
273157
|
+
};
|
|
273143
273158
|
function getConfiguredProviders(config) {
|
|
273144
273159
|
return AVAILABLE_PROVIDERS.map((provider) => {
|
|
273145
273160
|
const configured = isProviderConfigured(provider.id, config);
|
|
@@ -273188,6 +273203,30 @@ function getAvailableModels(config) {
|
|
|
273188
273203
|
}
|
|
273189
273204
|
return models;
|
|
273190
273205
|
}
|
|
273206
|
+
function getDefaultModelForConfig(config) {
|
|
273207
|
+
const available = getAvailableModels(config);
|
|
273208
|
+
if (available.length === 0)
|
|
273209
|
+
return null;
|
|
273210
|
+
const byProvider = new Map;
|
|
273211
|
+
for (const m2 of available) {
|
|
273212
|
+
const list = byProvider.get(m2.provider) || [];
|
|
273213
|
+
list.push(m2);
|
|
273214
|
+
byProvider.set(m2.provider, list);
|
|
273215
|
+
}
|
|
273216
|
+
for (const provider of PROVIDER_PREFERENCE_ORDER) {
|
|
273217
|
+
const models = byProvider.get(provider);
|
|
273218
|
+
if (!models || models.length === 0)
|
|
273219
|
+
continue;
|
|
273220
|
+
const preferredId = PREFERRED_MODEL_BY_PROVIDER[provider];
|
|
273221
|
+
if (preferredId) {
|
|
273222
|
+
const preferred = models.find((m2) => m2.id === preferredId);
|
|
273223
|
+
if (preferred)
|
|
273224
|
+
return preferred;
|
|
273225
|
+
}
|
|
273226
|
+
return models[0];
|
|
273227
|
+
}
|
|
273228
|
+
return available[0] ?? null;
|
|
273229
|
+
}
|
|
273191
273230
|
|
|
273192
273231
|
// src/core/logger/index.ts
|
|
273193
273232
|
init_session();
|
|
@@ -273247,45 +273286,69 @@ ${error40.stack ?? ""}` : String(error40);
|
|
|
273247
273286
|
} catch {}
|
|
273248
273287
|
}
|
|
273249
273288
|
|
|
273289
|
+
// src/tui/context/config.tsx
|
|
273290
|
+
init_config2();
|
|
273291
|
+
var import_react11 = __toESM(require_react(), 1);
|
|
273292
|
+
|
|
273250
273293
|
// node_modules/@opentui/react/jsx-dev-runtime.js
|
|
273251
273294
|
var import_jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
|
|
273252
273295
|
|
|
273253
|
-
// src/tui/context/
|
|
273254
|
-
var
|
|
273255
|
-
|
|
273256
|
-
|
|
273257
|
-
|
|
273258
|
-
|
|
273296
|
+
// src/tui/context/config.tsx
|
|
273297
|
+
var ctx = import_react11.createContext(null);
|
|
273298
|
+
function ConfigProvider({ children, config: config3 }) {
|
|
273299
|
+
const [appConfig, setAppConfig] = import_react11.useState(config3);
|
|
273300
|
+
const value = import_react11.useMemo(() => ({
|
|
273301
|
+
data: appConfig,
|
|
273302
|
+
update: async (newConfig) => {
|
|
273303
|
+
await config2.update(newConfig);
|
|
273304
|
+
setAppConfig({
|
|
273305
|
+
...appConfig,
|
|
273306
|
+
...newConfig
|
|
273307
|
+
});
|
|
273308
|
+
},
|
|
273309
|
+
reload: async () => {
|
|
273310
|
+
const freshConfig = await config2.get();
|
|
273311
|
+
setAppConfig(freshConfig);
|
|
273312
|
+
}
|
|
273313
|
+
}), [appConfig]);
|
|
273314
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ctx.Provider, {
|
|
273315
|
+
value,
|
|
273316
|
+
children
|
|
273317
|
+
}, undefined, false, undefined, this);
|
|
273318
|
+
}
|
|
273319
|
+
var useConfig = () => {
|
|
273320
|
+
const config3 = import_react11.useContext(ctx);
|
|
273321
|
+
if (!config3) {
|
|
273322
|
+
throw new Error("useConfig must be called within a ConfigProvider");
|
|
273323
|
+
}
|
|
273324
|
+
return config3;
|
|
273259
273325
|
};
|
|
273260
|
-
|
|
273261
|
-
|
|
273262
|
-
|
|
273263
|
-
"openai",
|
|
273264
|
-
"google",
|
|
273265
|
-
"openrouter",
|
|
273266
|
-
"bedrock"
|
|
273267
|
-
];
|
|
273268
|
-
var AgentContext = import_react11.createContext(null);
|
|
273326
|
+
|
|
273327
|
+
// src/tui/context/agent.tsx
|
|
273328
|
+
var AgentContext = import_react12.createContext(null);
|
|
273269
273329
|
function useAgent() {
|
|
273270
|
-
const context2 =
|
|
273330
|
+
const context2 = import_react12.useContext(AgentContext);
|
|
273271
273331
|
if (!context2) {
|
|
273272
273332
|
throw new Error("useAgent must be used within AgentProvider");
|
|
273273
273333
|
}
|
|
273274
273334
|
return context2;
|
|
273275
273335
|
}
|
|
273276
273336
|
function AgentProvider({ children }) {
|
|
273277
|
-
const
|
|
273278
|
-
const [
|
|
273279
|
-
|
|
273337
|
+
const appConfig = useConfig();
|
|
273338
|
+
const [model, setModelInternal] = import_react12.useState(() => {
|
|
273339
|
+
return getDefaultModelForConfig(appConfig.data) ?? AVAILABLE_MODELS[0];
|
|
273340
|
+
});
|
|
273341
|
+
const [isModelUserSelected, setIsModelUserSelected] = import_react12.useState(false);
|
|
273342
|
+
const [tokenUsage, setTokenUsage] = import_react12.useState({
|
|
273280
273343
|
inputTokens: 0,
|
|
273281
273344
|
outputTokens: 0,
|
|
273282
273345
|
totalTokens: 0
|
|
273283
273346
|
});
|
|
273284
|
-
const [hasExecuted, setHasExecuted] =
|
|
273285
|
-
const [thinking, setThinking] =
|
|
273286
|
-
const [isExecuting, setIsExecuting] =
|
|
273287
|
-
const [sessionCwd, setSessionCwd] =
|
|
273288
|
-
const setModel =
|
|
273347
|
+
const [hasExecuted, setHasExecuted] = import_react12.useState(false);
|
|
273348
|
+
const [thinking, setThinking] = import_react12.useState(false);
|
|
273349
|
+
const [isExecuting, setIsExecuting] = import_react12.useState(false);
|
|
273350
|
+
const [sessionCwd, setSessionCwd] = import_react12.useState(null);
|
|
273351
|
+
const setModel = import_react12.useCallback((newModel, persist = true) => {
|
|
273289
273352
|
setModelInternal(newModel);
|
|
273290
273353
|
if (persist) {
|
|
273291
273354
|
setIsModelUserSelected(true);
|
|
@@ -273294,49 +273357,27 @@ function AgentProvider({ children }) {
|
|
|
273294
273357
|
});
|
|
273295
273358
|
}
|
|
273296
273359
|
}, []);
|
|
273297
|
-
|
|
273298
|
-
|
|
273299
|
-
|
|
273300
|
-
|
|
273360
|
+
import_react12.useEffect(() => {
|
|
273361
|
+
if (isModelUserSelected)
|
|
273362
|
+
return;
|
|
273363
|
+
const cfg = appConfig.data;
|
|
273364
|
+
const available = getAvailableModels(cfg);
|
|
273365
|
+
if (available.length === 0)
|
|
273366
|
+
return;
|
|
273367
|
+
if (cfg.selectedModelId) {
|
|
273368
|
+
const savedModel = available.find((m2) => m2.id === cfg.selectedModelId);
|
|
273369
|
+
if (savedModel) {
|
|
273370
|
+
setModelInternal(savedModel);
|
|
273371
|
+
setIsModelUserSelected(true);
|
|
273301
273372
|
return;
|
|
273302
|
-
if (config3.selectedModelId) {
|
|
273303
|
-
const savedModel = available.find((m2) => m2.id === config3.selectedModelId);
|
|
273304
|
-
if (savedModel) {
|
|
273305
|
-
setModelInternal(savedModel);
|
|
273306
|
-
setIsModelUserSelected(true);
|
|
273307
|
-
return;
|
|
273308
|
-
}
|
|
273309
|
-
}
|
|
273310
|
-
const byProvider = new Map;
|
|
273311
|
-
for (const m2 of available) {
|
|
273312
|
-
const list3 = byProvider.get(m2.provider) || [];
|
|
273313
|
-
list3.push(m2);
|
|
273314
|
-
byProvider.set(m2.provider, list3);
|
|
273315
273373
|
}
|
|
273316
|
-
|
|
273317
|
-
|
|
273318
|
-
|
|
273319
|
-
|
|
273320
|
-
|
|
273321
|
-
|
|
273322
|
-
|
|
273323
|
-
const preferred = models.find((m2) => m2.id === preferredId);
|
|
273324
|
-
if (preferred) {
|
|
273325
|
-
selectedModel = preferred;
|
|
273326
|
-
break;
|
|
273327
|
-
}
|
|
273328
|
-
}
|
|
273329
|
-
selectedModel = models[0];
|
|
273330
|
-
break;
|
|
273331
|
-
}
|
|
273332
|
-
if (selectedModel) {
|
|
273333
|
-
setModelInternal(selectedModel);
|
|
273334
|
-
}
|
|
273335
|
-
}).catch((err) => {
|
|
273336
|
-
writeErrorLog(err, "AGENT_CONTEXT");
|
|
273337
|
-
});
|
|
273338
|
-
}, []);
|
|
273339
|
-
const addTokenUsage = import_react11.useCallback((input, output) => {
|
|
273374
|
+
}
|
|
273375
|
+
const defaultModel = getDefaultModelForConfig(cfg);
|
|
273376
|
+
if (defaultModel) {
|
|
273377
|
+
setModelInternal(defaultModel);
|
|
273378
|
+
}
|
|
273379
|
+
}, [appConfig.data, isModelUserSelected]);
|
|
273380
|
+
const addTokenUsage = import_react12.useCallback((input, output) => {
|
|
273340
273381
|
setHasExecuted(true);
|
|
273341
273382
|
setTokenUsage((prev) => ({
|
|
273342
273383
|
inputTokens: prev.inputTokens + input,
|
|
@@ -273344,11 +273385,11 @@ function AgentProvider({ children }) {
|
|
|
273344
273385
|
totalTokens: prev.totalTokens + input + output
|
|
273345
273386
|
}));
|
|
273346
273387
|
}, []);
|
|
273347
|
-
const resetTokenUsage =
|
|
273388
|
+
const resetTokenUsage = import_react12.useCallback(() => {
|
|
273348
273389
|
setHasExecuted(false);
|
|
273349
273390
|
setTokenUsage({ inputTokens: 0, outputTokens: 0, totalTokens: 0 });
|
|
273350
273391
|
}, []);
|
|
273351
|
-
const contextValue =
|
|
273392
|
+
const contextValue = import_react12.useMemo(() => ({
|
|
273352
273393
|
model,
|
|
273353
273394
|
setModel,
|
|
273354
273395
|
isModelUserSelected,
|
|
@@ -273381,7 +273422,7 @@ function AgentProvider({ children }) {
|
|
|
273381
273422
|
}
|
|
273382
273423
|
|
|
273383
273424
|
// src/tui/components/sprites.tsx
|
|
273384
|
-
var
|
|
273425
|
+
var import_react14 = __toESM(require_react(), 1);
|
|
273385
273426
|
|
|
273386
273427
|
// src/tui/theme/registry.ts
|
|
273387
273428
|
var themes = new Map;
|
|
@@ -273401,8 +273442,8 @@ function getAllThemeNames() {
|
|
|
273401
273442
|
return Array.from(themes.keys()).sort();
|
|
273402
273443
|
}
|
|
273403
273444
|
// src/tui/theme/context.tsx
|
|
273404
|
-
var
|
|
273405
|
-
var ThemeContext =
|
|
273445
|
+
var import_react13 = __toESM(require_react(), 1);
|
|
273446
|
+
var ThemeContext = import_react13.createContext(null);
|
|
273406
273447
|
function resolveColor(value, mode) {
|
|
273407
273448
|
if ("r" in value)
|
|
273408
273449
|
return value;
|
|
@@ -273421,17 +273462,17 @@ function ThemeProvider({
|
|
|
273421
273462
|
initialMode = "dark",
|
|
273422
273463
|
children
|
|
273423
273464
|
}) {
|
|
273424
|
-
const [theme, setThemeState] =
|
|
273425
|
-
const [mode, setModeState] =
|
|
273426
|
-
const colors =
|
|
273427
|
-
const setTheme =
|
|
273465
|
+
const [theme, setThemeState] = import_react13.useState(() => getTheme(initialTheme ?? DEFAULT_THEME_NAME));
|
|
273466
|
+
const [mode, setModeState] = import_react13.useState(initialMode);
|
|
273467
|
+
const colors = import_react13.useMemo(() => resolveThemeColors(theme, mode), [theme, mode]);
|
|
273468
|
+
const setTheme = import_react13.useCallback((name26) => {
|
|
273428
273469
|
const newTheme = getTheme(name26);
|
|
273429
273470
|
setThemeState(newTheme);
|
|
273430
273471
|
}, []);
|
|
273431
|
-
const toggleMode =
|
|
273472
|
+
const toggleMode = import_react13.useCallback(() => {
|
|
273432
273473
|
setModeState((prev) => prev === "dark" ? "light" : "dark");
|
|
273433
273474
|
}, []);
|
|
273434
|
-
const setMode =
|
|
273475
|
+
const setMode = import_react13.useCallback((m2) => {
|
|
273435
273476
|
setModeState(m2);
|
|
273436
273477
|
}, []);
|
|
273437
273478
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ThemeContext, {
|
|
@@ -273448,10 +273489,10 @@ function ThemeProvider({
|
|
|
273448
273489
|
}, undefined, false, undefined, this);
|
|
273449
273490
|
}
|
|
273450
273491
|
function useTheme() {
|
|
273451
|
-
const
|
|
273452
|
-
if (!
|
|
273492
|
+
const ctx2 = import_react13.useContext(ThemeContext);
|
|
273493
|
+
if (!ctx2)
|
|
273453
273494
|
throw new Error("useTheme() must be used within <ThemeProvider>");
|
|
273454
|
-
return
|
|
273495
|
+
return ctx2;
|
|
273455
273496
|
}
|
|
273456
273497
|
// src/tui/theme/colors.ts
|
|
273457
273498
|
var colors = {
|
|
@@ -273492,8 +273533,8 @@ function stopGlobalTick() {
|
|
|
273492
273533
|
}
|
|
273493
273534
|
}
|
|
273494
273535
|
function useGlobalTick() {
|
|
273495
|
-
const [, setTick] =
|
|
273496
|
-
|
|
273536
|
+
const [, setTick] = import_react14.useState(0);
|
|
273537
|
+
import_react14.useEffect(() => {
|
|
273497
273538
|
const listener = () => setTick((t2) => t2 + 1);
|
|
273498
273539
|
globalListeners.add(listener);
|
|
273499
273540
|
startGlobalTick();
|
|
@@ -273520,11 +273561,11 @@ function SpinnerDots({
|
|
|
273520
273561
|
|
|
273521
273562
|
// src/tui/context/session.tsx
|
|
273522
273563
|
init_session();
|
|
273523
|
-
var
|
|
273524
|
-
var
|
|
273564
|
+
var import_react15 = __toESM(require_react(), 1);
|
|
273565
|
+
var ctx2 = import_react15.createContext(null);
|
|
273525
273566
|
function SessionProvider({ children, session }) {
|
|
273526
|
-
const [activeSession, setActiveSession] =
|
|
273527
|
-
const value =
|
|
273567
|
+
const [activeSession, setActiveSession] = import_react15.useState(session);
|
|
273568
|
+
const value = import_react15.useMemo(() => ({
|
|
273528
273569
|
active: activeSession,
|
|
273529
273570
|
load: async (id) => {
|
|
273530
273571
|
try {
|
|
@@ -273545,40 +273586,40 @@ function SessionProvider({ children, session }) {
|
|
|
273545
273586
|
return _session;
|
|
273546
273587
|
}
|
|
273547
273588
|
}), [activeSession]);
|
|
273548
|
-
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(
|
|
273589
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ctx2.Provider, {
|
|
273549
273590
|
value,
|
|
273550
273591
|
children
|
|
273551
273592
|
}, undefined, false, undefined, this);
|
|
273552
273593
|
}
|
|
273553
273594
|
var useSession = () => {
|
|
273554
|
-
const session =
|
|
273595
|
+
const session = import_react15.useContext(ctx2);
|
|
273555
273596
|
if (!session)
|
|
273556
273597
|
throw new Error("useSession must be called within a SessionProvider");
|
|
273557
273598
|
return session;
|
|
273558
273599
|
};
|
|
273559
273600
|
|
|
273560
273601
|
// src/tui/context/route.tsx
|
|
273561
|
-
var
|
|
273562
|
-
var
|
|
273602
|
+
var import_react16 = __toESM(require_react(), 1);
|
|
273603
|
+
var ctx3 = import_react16.createContext(null);
|
|
273563
273604
|
function RouteProvider({ children }) {
|
|
273564
|
-
const [route, setRoute] =
|
|
273605
|
+
const [route, setRoute] = import_react16.useState({
|
|
273565
273606
|
type: "base",
|
|
273566
273607
|
path: "home"
|
|
273567
273608
|
});
|
|
273568
|
-
const value =
|
|
273609
|
+
const value = import_react16.useMemo(() => ({
|
|
273569
273610
|
data: route,
|
|
273570
273611
|
navigate: (newRoute) => {
|
|
273571
273612
|
console.log("navigating to:", newRoute);
|
|
273572
273613
|
setRoute(newRoute);
|
|
273573
273614
|
}
|
|
273574
273615
|
}), [route]);
|
|
273575
|
-
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(
|
|
273616
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ctx3.Provider, {
|
|
273576
273617
|
value,
|
|
273577
273618
|
children
|
|
273578
273619
|
}, undefined, false, undefined, this);
|
|
273579
273620
|
}
|
|
273580
273621
|
var useRoute = () => {
|
|
273581
|
-
const route =
|
|
273622
|
+
const route = import_react16.useContext(ctx3);
|
|
273582
273623
|
if (!route) {
|
|
273583
273624
|
throw new Error("useRoute must be called within a RouteProvider");
|
|
273584
273625
|
}
|
|
@@ -273586,11 +273627,11 @@ var useRoute = () => {
|
|
|
273586
273627
|
};
|
|
273587
273628
|
|
|
273588
273629
|
// src/tui/context/input.tsx
|
|
273589
|
-
var
|
|
273590
|
-
var InputContext =
|
|
273630
|
+
var import_react17 = __toESM(require_react(), 1);
|
|
273631
|
+
var InputContext = import_react17.createContext(undefined);
|
|
273591
273632
|
function InputProvider({ children }) {
|
|
273592
|
-
const [inputValue, setInputValue] =
|
|
273593
|
-
const clearInput =
|
|
273633
|
+
const [inputValue, setInputValue] = import_react17.useState("");
|
|
273634
|
+
const clearInput = import_react17.useCallback(() => {
|
|
273594
273635
|
setInputValue("");
|
|
273595
273636
|
}, []);
|
|
273596
273637
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(InputContext.Provider, {
|
|
@@ -273604,7 +273645,7 @@ function InputProvider({ children }) {
|
|
|
273604
273645
|
}, undefined, false, undefined, this);
|
|
273605
273646
|
}
|
|
273606
273647
|
function useInput() {
|
|
273607
|
-
const context2 =
|
|
273648
|
+
const context2 = import_react17.useContext(InputContext);
|
|
273608
273649
|
if (!context2) {
|
|
273609
273650
|
throw new Error("useInput must be used within InputProvider");
|
|
273610
273651
|
}
|
|
@@ -273744,7 +273785,7 @@ function AgentStatus() {
|
|
|
273744
273785
|
}
|
|
273745
273786
|
|
|
273746
273787
|
// src/tui/context/command.tsx
|
|
273747
|
-
var
|
|
273788
|
+
var import_react18 = __toESM(require_react(), 1);
|
|
273748
273789
|
|
|
273749
273790
|
// src/tui/command-router.ts
|
|
273750
273791
|
class CommandRouter {
|
|
@@ -273756,8 +273797,8 @@ class CommandRouter {
|
|
|
273756
273797
|
for (const n of names)
|
|
273757
273798
|
this.nameToCommand.set(n, command);
|
|
273758
273799
|
}
|
|
273759
|
-
registerWithContext(definition,
|
|
273760
|
-
const { handler, ...metadata } = definition(
|
|
273800
|
+
registerWithContext(definition, ctx4) {
|
|
273801
|
+
const { handler, ...metadata } = definition(ctx4);
|
|
273761
273802
|
this.register({
|
|
273762
273803
|
...metadata,
|
|
273763
273804
|
handler: (args) => handler(args)
|
|
@@ -273781,14 +273822,14 @@ class CommandRouter {
|
|
|
273781
273822
|
return { name: null, args };
|
|
273782
273823
|
return { name: name26, args };
|
|
273783
273824
|
}
|
|
273784
|
-
async execute(input,
|
|
273825
|
+
async execute(input, ctx4) {
|
|
273785
273826
|
const { name: name26, args } = this.parse(input);
|
|
273786
273827
|
if (!name26)
|
|
273787
273828
|
return false;
|
|
273788
273829
|
const cmd = this.nameToCommand.get(name26);
|
|
273789
273830
|
if (!cmd)
|
|
273790
273831
|
return false;
|
|
273791
|
-
await cmd.handler(args,
|
|
273832
|
+
await cmd.handler(args, ctx4);
|
|
273792
273833
|
return true;
|
|
273793
273834
|
}
|
|
273794
273835
|
}
|
|
@@ -274080,18 +274121,18 @@ var commands = [
|
|
|
274080
274121
|
},
|
|
274081
274122
|
{ name: "--model", valueHint: "<model>", description: "AI model to use" }
|
|
274082
274123
|
],
|
|
274083
|
-
handler: async (args,
|
|
274124
|
+
handler: async (args, ctx4) => {
|
|
274084
274125
|
const flags = parseWebFlags(args);
|
|
274085
274126
|
if (flags.target && hasEnoughFlagsToSkipWizard(flags)) {
|
|
274086
274127
|
const params = buildSwarmSessionConfig(flags);
|
|
274087
|
-
|
|
274128
|
+
ctx4.navigate({
|
|
274088
274129
|
type: "pentest",
|
|
274089
274130
|
targets: params.targets,
|
|
274090
274131
|
sessionConfig: params.config
|
|
274091
274132
|
});
|
|
274092
274133
|
return;
|
|
274093
274134
|
}
|
|
274094
|
-
|
|
274135
|
+
ctx4.openPentestDialog?.({ auto: true, ...flags });
|
|
274095
274136
|
}
|
|
274096
274137
|
},
|
|
274097
274138
|
{
|
|
@@ -274154,10 +274195,10 @@ var commands = [
|
|
|
274154
274195
|
},
|
|
274155
274196
|
{ name: "--model", valueHint: "<model>", description: "AI model to use" }
|
|
274156
274197
|
],
|
|
274157
|
-
handler: async (args,
|
|
274198
|
+
handler: async (args, ctx4) => {
|
|
274158
274199
|
const flags = parseWebFlags(args);
|
|
274159
274200
|
const params = buildOperatorSessionConfig(flags);
|
|
274160
|
-
|
|
274201
|
+
ctx4.navigate({
|
|
274161
274202
|
type: "operator",
|
|
274162
274203
|
nonce: Date.now(),
|
|
274163
274204
|
initialConfig: {
|
|
@@ -274171,8 +274212,8 @@ var commands = [
|
|
|
274171
274212
|
name: "help",
|
|
274172
274213
|
description: "Show help dialog",
|
|
274173
274214
|
category: "General",
|
|
274174
|
-
handler: async (args,
|
|
274175
|
-
|
|
274215
|
+
handler: async (args, ctx4) => {
|
|
274216
|
+
ctx4.navigate({
|
|
274176
274217
|
type: "base",
|
|
274177
274218
|
path: "help"
|
|
274178
274219
|
});
|
|
@@ -274182,8 +274223,8 @@ var commands = [
|
|
|
274182
274223
|
name: "config",
|
|
274183
274224
|
description: "Show config dialog",
|
|
274184
274225
|
category: "General",
|
|
274185
|
-
handler: async (args,
|
|
274186
|
-
|
|
274226
|
+
handler: async (args, ctx4) => {
|
|
274227
|
+
ctx4.navigate({
|
|
274187
274228
|
type: "base",
|
|
274188
274229
|
path: "config"
|
|
274189
274230
|
});
|
|
@@ -274193,8 +274234,8 @@ var commands = [
|
|
|
274193
274234
|
name: "models",
|
|
274194
274235
|
description: "Show available AI models",
|
|
274195
274236
|
category: "General",
|
|
274196
|
-
handler: async (args,
|
|
274197
|
-
|
|
274237
|
+
handler: async (args, ctx4) => {
|
|
274238
|
+
ctx4.navigate({
|
|
274198
274239
|
type: "base",
|
|
274199
274240
|
path: "models"
|
|
274200
274241
|
});
|
|
@@ -274204,8 +274245,8 @@ var commands = [
|
|
|
274204
274245
|
name: "providers",
|
|
274205
274246
|
description: "Manage AI providers and API keys",
|
|
274206
274247
|
category: "General",
|
|
274207
|
-
handler: async (args,
|
|
274208
|
-
|
|
274248
|
+
handler: async (args, ctx4) => {
|
|
274249
|
+
ctx4.navigate({
|
|
274209
274250
|
type: "base",
|
|
274210
274251
|
path: "providers"
|
|
274211
274252
|
});
|
|
@@ -274216,16 +274257,16 @@ var commands = [
|
|
|
274216
274257
|
aliases: ["s"],
|
|
274217
274258
|
description: "Browse previous sessions",
|
|
274218
274259
|
category: "Pentesting",
|
|
274219
|
-
handler: async (_args,
|
|
274220
|
-
|
|
274260
|
+
handler: async (_args, ctx4) => {
|
|
274261
|
+
ctx4.openSessionsDialog?.();
|
|
274221
274262
|
}
|
|
274222
274263
|
},
|
|
274223
274264
|
{
|
|
274224
274265
|
name: "new",
|
|
274225
274266
|
description: "Start a new operator session",
|
|
274226
274267
|
category: "Session",
|
|
274227
|
-
handler: async (args,
|
|
274228
|
-
|
|
274268
|
+
handler: async (args, ctx4) => {
|
|
274269
|
+
ctx4.navigate({ type: "operator", nonce: Date.now() });
|
|
274229
274270
|
}
|
|
274230
274271
|
},
|
|
274231
274272
|
{
|
|
@@ -274234,8 +274275,8 @@ var commands = [
|
|
|
274234
274275
|
description: "Open the Chat TUI interface",
|
|
274235
274276
|
category: "General",
|
|
274236
274277
|
hidden: true,
|
|
274237
|
-
handler: async (args,
|
|
274238
|
-
|
|
274278
|
+
handler: async (args, ctx4) => {
|
|
274279
|
+
ctx4.navigate({
|
|
274239
274280
|
type: "base",
|
|
274240
274281
|
path: "home"
|
|
274241
274282
|
});
|
|
@@ -274256,7 +274297,7 @@ var commands = [
|
|
|
274256
274297
|
description: "Toggle or set dark/light mode (dark|light|auto)"
|
|
274257
274298
|
}
|
|
274258
274299
|
],
|
|
274259
|
-
handler: async (args,
|
|
274300
|
+
handler: async (args, ctx4) => {
|
|
274260
274301
|
if (args[0] === "mode") {
|
|
274261
274302
|
const modeArg = args[1];
|
|
274262
274303
|
if (modeArg === "dark" || modeArg === "light") {
|
|
@@ -274279,7 +274320,7 @@ var commands = [
|
|
|
274279
274320
|
}
|
|
274280
274321
|
return;
|
|
274281
274322
|
}
|
|
274282
|
-
|
|
274323
|
+
ctx4.openThemeDialog?.();
|
|
274283
274324
|
}
|
|
274284
274325
|
},
|
|
274285
274326
|
{
|
|
@@ -274288,8 +274329,8 @@ var commands = [
|
|
|
274288
274329
|
description: "View and manage active tools (session only)",
|
|
274289
274330
|
category: "Session",
|
|
274290
274331
|
hidden: true,
|
|
274291
|
-
handler: async (args,
|
|
274292
|
-
if (
|
|
274332
|
+
handler: async (args, ctx4) => {
|
|
274333
|
+
if (ctx4.route.type !== "pentest") {
|
|
274293
274334
|
return;
|
|
274294
274335
|
}
|
|
274295
274336
|
}
|
|
@@ -274307,8 +274348,8 @@ var commands = [
|
|
|
274307
274348
|
name: "auth",
|
|
274308
274349
|
description: "Connect to Pensar Console for managed inference",
|
|
274309
274350
|
category: "General",
|
|
274310
|
-
handler: async (args,
|
|
274311
|
-
|
|
274351
|
+
handler: async (args, ctx4) => {
|
|
274352
|
+
ctx4.openAuthDialog?.();
|
|
274312
274353
|
}
|
|
274313
274354
|
},
|
|
274314
274355
|
{
|
|
@@ -274316,8 +274357,8 @@ var commands = [
|
|
|
274316
274357
|
aliases: ["buy"],
|
|
274317
274358
|
description: "Buy credits / check balance",
|
|
274318
274359
|
category: "General",
|
|
274319
|
-
handler: async (args,
|
|
274320
|
-
|
|
274360
|
+
handler: async (args, ctx4) => {
|
|
274361
|
+
ctx4.navigate({
|
|
274321
274362
|
type: "base",
|
|
274322
274363
|
path: "credits"
|
|
274323
274364
|
});
|
|
@@ -274327,20 +274368,20 @@ var commands = [
|
|
|
274327
274368
|
name: "create-skill",
|
|
274328
274369
|
description: "Create a new operator skill",
|
|
274329
274370
|
category: "Skills",
|
|
274330
|
-
handler: async (args,
|
|
274331
|
-
|
|
274371
|
+
handler: async (args, ctx4) => {
|
|
274372
|
+
ctx4.navigate({
|
|
274332
274373
|
type: "base",
|
|
274333
274374
|
path: "create-skill"
|
|
274334
274375
|
});
|
|
274335
274376
|
}
|
|
274336
274377
|
}
|
|
274337
274378
|
];
|
|
274338
|
-
var commandRegistry = commands.map((config3) => (
|
|
274379
|
+
var commandRegistry = commands.map((config3) => (ctx4) => ({
|
|
274339
274380
|
name: config3.name,
|
|
274340
274381
|
aliases: config3.aliases,
|
|
274341
274382
|
description: config3.description,
|
|
274342
274383
|
handler: async (args) => {
|
|
274343
|
-
await config3.handler(args,
|
|
274384
|
+
await config3.handler(args, ctx4);
|
|
274344
274385
|
}
|
|
274345
274386
|
}));
|
|
274346
274387
|
|
|
@@ -274435,9 +274476,9 @@ async function skillExists(slug) {
|
|
|
274435
274476
|
}
|
|
274436
274477
|
|
|
274437
274478
|
// src/tui/context/command.tsx
|
|
274438
|
-
var CommandContext =
|
|
274479
|
+
var CommandContext = import_react18.createContext(null);
|
|
274439
274480
|
function useCommand() {
|
|
274440
|
-
const context2 =
|
|
274481
|
+
const context2 = import_react18.useContext(CommandContext);
|
|
274441
274482
|
if (!context2) {
|
|
274442
274483
|
throw new Error("useCommand must be used within CommandProvider");
|
|
274443
274484
|
}
|
|
@@ -274451,9 +274492,9 @@ function CommandProvider({
|
|
|
274451
274492
|
onOpenPentestDialog
|
|
274452
274493
|
}) {
|
|
274453
274494
|
const route = useRoute();
|
|
274454
|
-
const [skills, setSkills] =
|
|
274455
|
-
const
|
|
274456
|
-
const
|
|
274495
|
+
const [skills, setSkills] = import_react18.useState([]);
|
|
274496
|
+
const ctx4 = import_react18.useMemo(() => {
|
|
274497
|
+
const ctx5 = {
|
|
274457
274498
|
route: route.data,
|
|
274458
274499
|
navigate: route.navigate,
|
|
274459
274500
|
openSessionsDialog: onOpenSessionsDialog,
|
|
@@ -274461,7 +274502,7 @@ function CommandProvider({
|
|
|
274461
274502
|
openAuthDialog: onOpenAuthDialog,
|
|
274462
274503
|
openPentestDialog: onOpenPentestDialog
|
|
274463
274504
|
};
|
|
274464
|
-
return
|
|
274505
|
+
return ctx5;
|
|
274465
274506
|
}, [
|
|
274466
274507
|
route,
|
|
274467
274508
|
onOpenSessionsDialog,
|
|
@@ -274469,33 +274510,33 @@ function CommandProvider({
|
|
|
274469
274510
|
onOpenAuthDialog,
|
|
274470
274511
|
onOpenPentestDialog
|
|
274471
274512
|
]);
|
|
274472
|
-
const refreshSkills =
|
|
274513
|
+
const refreshSkills = import_react18.useCallback(async () => {
|
|
274473
274514
|
const loaded = await loadSkills();
|
|
274474
274515
|
setSkills(loaded);
|
|
274475
274516
|
}, []);
|
|
274476
|
-
|
|
274517
|
+
import_react18.useEffect(() => {
|
|
274477
274518
|
refreshSkills();
|
|
274478
274519
|
}, [route.data]);
|
|
274479
|
-
const router =
|
|
274520
|
+
const router = import_react18.useMemo(() => {
|
|
274480
274521
|
const router2 = new CommandRouter;
|
|
274481
274522
|
for (const commandDef of commandRegistry) {
|
|
274482
|
-
router2.registerWithContext(commandDef,
|
|
274523
|
+
router2.registerWithContext(commandDef, ctx4);
|
|
274483
274524
|
}
|
|
274484
274525
|
return router2;
|
|
274485
274526
|
}, []);
|
|
274486
|
-
const skillSlugMap =
|
|
274527
|
+
const skillSlugMap = import_react18.useMemo(() => {
|
|
274487
274528
|
const map2 = new Map;
|
|
274488
274529
|
for (const skill of skills) {
|
|
274489
274530
|
map2.set(slugify(skill.name), skill);
|
|
274490
274531
|
}
|
|
274491
274532
|
return map2;
|
|
274492
274533
|
}, [skills]);
|
|
274493
|
-
const resolveSkillContent =
|
|
274534
|
+
const resolveSkillContent = import_react18.useCallback((input) => {
|
|
274494
274535
|
const trimmed = input.trim().replace(/^\/+/, "").toLowerCase();
|
|
274495
274536
|
const skill = skillSlugMap.get(trimmed);
|
|
274496
274537
|
return skill?.content ?? null;
|
|
274497
274538
|
}, [skillSlugMap]);
|
|
274498
|
-
const autocompleteOptions =
|
|
274539
|
+
const autocompleteOptions = import_react18.useMemo(() => {
|
|
274499
274540
|
const routerCommands = router.getAllCommands();
|
|
274500
274541
|
const options = [];
|
|
274501
274542
|
for (const cmd of routerCommands) {
|
|
@@ -274539,10 +274580,10 @@ function CommandProvider({
|
|
|
274539
274580
|
return a.value.localeCompare(b2.value);
|
|
274540
274581
|
});
|
|
274541
274582
|
}, [router, skills]);
|
|
274542
|
-
const executeCommand =
|
|
274543
|
-
return await router.execute(input,
|
|
274544
|
-
}, [router,
|
|
274545
|
-
const value =
|
|
274583
|
+
const executeCommand = import_react18.useCallback(async (input) => {
|
|
274584
|
+
return await router.execute(input, ctx4);
|
|
274585
|
+
}, [router, ctx4]);
|
|
274586
|
+
const value = import_react18.useMemo(() => ({
|
|
274546
274587
|
router,
|
|
274547
274588
|
autocompleteOptions,
|
|
274548
274589
|
executeCommand,
|
|
@@ -274565,24 +274606,24 @@ function CommandProvider({
|
|
|
274565
274606
|
}
|
|
274566
274607
|
|
|
274567
274608
|
// src/tui/components/commands/sessions-display.tsx
|
|
274568
|
-
var
|
|
274609
|
+
var import_react25 = __toESM(require_react(), 1);
|
|
274569
274610
|
|
|
274570
274611
|
// src/tui/context/focus.tsx
|
|
274571
|
-
var
|
|
274572
|
-
var FocusContext =
|
|
274612
|
+
var import_react19 = __toESM(require_react(), 1);
|
|
274613
|
+
var FocusContext = import_react19.createContext(undefined);
|
|
274573
274614
|
function FocusProvider({ children }) {
|
|
274574
|
-
const promptRef =
|
|
274575
|
-
const refocusPrompt =
|
|
274615
|
+
const promptRef = import_react19.useRef(null);
|
|
274616
|
+
const refocusPrompt = import_react19.useCallback(() => {
|
|
274576
274617
|
setTimeout(() => {
|
|
274577
274618
|
promptRef.current?.focus();
|
|
274578
274619
|
}, 1);
|
|
274579
274620
|
}, []);
|
|
274580
|
-
const focusPrompt =
|
|
274581
|
-
const blurPrompt =
|
|
274582
|
-
const resetPrompt =
|
|
274583
|
-
const setPromptValue =
|
|
274584
|
-
const getPromptValue =
|
|
274585
|
-
const registerPromptRef =
|
|
274621
|
+
const focusPrompt = import_react19.useCallback(() => promptRef.current?.focus(), []);
|
|
274622
|
+
const blurPrompt = import_react19.useCallback(() => promptRef.current?.blur(), []);
|
|
274623
|
+
const resetPrompt = import_react19.useCallback(() => promptRef.current?.reset(), []);
|
|
274624
|
+
const setPromptValue = import_react19.useCallback((value) => promptRef.current?.setValue(value), []);
|
|
274625
|
+
const getPromptValue = import_react19.useCallback(() => promptRef.current?.getValue() ?? "", []);
|
|
274626
|
+
const registerPromptRef = import_react19.useCallback((ref) => {
|
|
274586
274627
|
promptRef.current = ref;
|
|
274587
274628
|
}, []);
|
|
274588
274629
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FocusContext.Provider, {
|
|
@@ -274600,7 +274641,7 @@ function FocusProvider({ children }) {
|
|
|
274600
274641
|
}, undefined, false, undefined, this);
|
|
274601
274642
|
}
|
|
274602
274643
|
function useFocus() {
|
|
274603
|
-
const context2 =
|
|
274644
|
+
const context2 = import_react19.useContext(FocusContext);
|
|
274604
274645
|
if (!context2) {
|
|
274605
274646
|
throw new Error("useFocus must be used within FocusProvider");
|
|
274606
274647
|
}
|
|
@@ -274635,8 +274676,8 @@ function openSessionReport(sessionRootPath) {
|
|
|
274635
274676
|
}
|
|
274636
274677
|
|
|
274637
274678
|
// src/tui/context/dimensions.tsx
|
|
274638
|
-
var
|
|
274639
|
-
var DimensionsContext =
|
|
274679
|
+
var import_react20 = __toESM(require_react(), 1);
|
|
274680
|
+
var DimensionsContext = import_react20.createContext(null);
|
|
274640
274681
|
function TerminalDimensionsProvider({
|
|
274641
274682
|
children
|
|
274642
274683
|
}) {
|
|
@@ -274647,14 +274688,14 @@ function TerminalDimensionsProvider({
|
|
|
274647
274688
|
}, undefined, false, undefined, this);
|
|
274648
274689
|
}
|
|
274649
274690
|
function useDimensions() {
|
|
274650
|
-
const
|
|
274651
|
-
if (!
|
|
274691
|
+
const ctx4 = import_react20.useContext(DimensionsContext);
|
|
274692
|
+
if (!ctx4)
|
|
274652
274693
|
throw new Error("useDimensions() must be used within <TerminalDimensionsProvider>");
|
|
274653
|
-
return
|
|
274694
|
+
return ctx4;
|
|
274654
274695
|
}
|
|
274655
274696
|
|
|
274656
274697
|
// src/tui/context/dialog.tsx
|
|
274657
|
-
var
|
|
274698
|
+
var import_react23 = __toESM(require_react(), 1);
|
|
274658
274699
|
function Dialog({ size = "medium", onClose, children }) {
|
|
274659
274700
|
const dimensions = useDimensions();
|
|
274660
274701
|
const renderer = useRenderer();
|
|
@@ -274691,14 +274732,14 @@ function Dialog({ size = "medium", onClose, children }) {
|
|
|
274691
274732
|
}, undefined, false, undefined, this)
|
|
274692
274733
|
}, undefined, false, undefined, this);
|
|
274693
274734
|
}
|
|
274694
|
-
var DialogContext =
|
|
274735
|
+
var DialogContext = import_react23.createContext(null);
|
|
274695
274736
|
function DialogProvider({ children }) {
|
|
274696
|
-
const [stack, setStack] =
|
|
274697
|
-
const [size, setSize] =
|
|
274698
|
-
const [externalDialogOpen, setExternalDialogOpen] =
|
|
274737
|
+
const [stack, setStack] = import_react23.useState([]);
|
|
274738
|
+
const [size, setSize] = import_react23.useState("medium");
|
|
274739
|
+
const [externalDialogOpen, setExternalDialogOpen] = import_react23.useState(false);
|
|
274699
274740
|
const renderer = useRenderer();
|
|
274700
|
-
const focusRef =
|
|
274701
|
-
const refocus =
|
|
274741
|
+
const focusRef = import_react23.useRef(null);
|
|
274742
|
+
const refocus = import_react23.useCallback(() => {
|
|
274702
274743
|
setTimeout(() => {
|
|
274703
274744
|
const focus = focusRef.current;
|
|
274704
274745
|
if (!focus)
|
|
@@ -274720,7 +274761,7 @@ function DialogProvider({ children }) {
|
|
|
274720
274761
|
focus.focus();
|
|
274721
274762
|
}, 1);
|
|
274722
274763
|
}, [renderer]);
|
|
274723
|
-
const clear =
|
|
274764
|
+
const clear = import_react23.useCallback(() => {
|
|
274724
274765
|
for (const item of stack) {
|
|
274725
274766
|
if (item.onClose)
|
|
274726
274767
|
item.onClose();
|
|
@@ -274729,7 +274770,7 @@ function DialogProvider({ children }) {
|
|
|
274729
274770
|
setStack([]);
|
|
274730
274771
|
refocus();
|
|
274731
274772
|
}, [stack, refocus]);
|
|
274732
|
-
const replace =
|
|
274773
|
+
const replace = import_react23.useCallback((element, onClose) => {
|
|
274733
274774
|
if (stack.length === 0) {
|
|
274734
274775
|
focusRef.current = renderer.currentFocusedRenderable;
|
|
274735
274776
|
}
|
|
@@ -274774,7 +274815,7 @@ function DialogProvider({ children }) {
|
|
|
274774
274815
|
}, undefined, true, undefined, this);
|
|
274775
274816
|
}
|
|
274776
274817
|
function useDialog() {
|
|
274777
|
-
const value =
|
|
274818
|
+
const value = import_react23.useContext(DialogContext);
|
|
274778
274819
|
if (!value) {
|
|
274779
274820
|
throw new Error("useDialog must be used within a DialogProvider");
|
|
274780
274821
|
}
|
|
@@ -274839,7 +274880,7 @@ function findChildById(scrollBox, id) {
|
|
|
274839
274880
|
// src/tui/hooks/use-sessions-list.ts
|
|
274840
274881
|
init_session();
|
|
274841
274882
|
init_report();
|
|
274842
|
-
var
|
|
274883
|
+
var import_react24 = __toESM(require_react(), 1);
|
|
274843
274884
|
import { existsSync as existsSync7, readdirSync } from "fs";
|
|
274844
274885
|
import { join as join3 } from "path";
|
|
274845
274886
|
function countFindings(findingsPath) {
|
|
@@ -274855,10 +274896,10 @@ function checkHasReport(rootPath) {
|
|
|
274855
274896
|
return existsSync7(join3(rootPath, REPORT_FILENAME_MD));
|
|
274856
274897
|
}
|
|
274857
274898
|
function useSessionsList() {
|
|
274858
|
-
const [allSessions, setAllSessions] =
|
|
274859
|
-
const [loading, setLoading] =
|
|
274860
|
-
const [searchTerm, setSearchTerm] =
|
|
274861
|
-
const loadSessions =
|
|
274899
|
+
const [allSessions, setAllSessions] = import_react24.useState([]);
|
|
274900
|
+
const [loading, setLoading] = import_react24.useState(true);
|
|
274901
|
+
const [searchTerm, setSearchTerm] = import_react24.useState("");
|
|
274902
|
+
const loadSessions = import_react24.useCallback(async () => {
|
|
274862
274903
|
setLoading(true);
|
|
274863
274904
|
try {
|
|
274864
274905
|
const enriched = [];
|
|
@@ -274881,10 +274922,10 @@ function useSessionsList() {
|
|
|
274881
274922
|
setLoading(false);
|
|
274882
274923
|
}
|
|
274883
274924
|
}, []);
|
|
274884
|
-
|
|
274925
|
+
import_react24.useEffect(() => {
|
|
274885
274926
|
loadSessions();
|
|
274886
274927
|
}, [loadSessions]);
|
|
274887
|
-
const deleteSession =
|
|
274928
|
+
const deleteSession = import_react24.useCallback(async (id) => {
|
|
274888
274929
|
await sessions.remove({ sessionId: id });
|
|
274889
274930
|
await loadSessions();
|
|
274890
274931
|
}, [loadSessions]);
|
|
@@ -274943,10 +274984,10 @@ function useSessionsList() {
|
|
|
274943
274984
|
function SessionsDisplay({ onClose }) {
|
|
274944
274985
|
const { colors: colors2 } = useTheme();
|
|
274945
274986
|
const { refocusPrompt } = useFocus();
|
|
274946
|
-
const [selectedIndex, setSelectedIndex] =
|
|
274947
|
-
const [statusMessage, setStatusMessage] =
|
|
274987
|
+
const [selectedIndex, setSelectedIndex] = import_react25.useState(0);
|
|
274988
|
+
const [statusMessage, setStatusMessage] = import_react25.useState("");
|
|
274948
274989
|
const route = useRoute();
|
|
274949
|
-
const scroll =
|
|
274990
|
+
const scroll = import_react25.useRef(null);
|
|
274950
274991
|
const {
|
|
274951
274992
|
groupedSessions,
|
|
274952
274993
|
visualOrderSessions,
|
|
@@ -274962,7 +275003,7 @@ function SessionsDisplay({ onClose }) {
|
|
|
274962
275003
|
setTimeout(() => setStatusMessage(""), 2000);
|
|
274963
275004
|
}
|
|
274964
275005
|
}
|
|
274965
|
-
|
|
275006
|
+
import_react25.useEffect(() => {
|
|
274966
275007
|
if (visualOrderSessions.length > 0 && selectedIndex >= visualOrderSessions.length) {
|
|
274967
275008
|
setSelectedIndex(visualOrderSessions.length - 1);
|
|
274968
275009
|
} else if (visualOrderSessions.length === 0) {
|
|
@@ -275244,7 +275285,7 @@ function SessionsDisplay({ onClose }) {
|
|
|
275244
275285
|
}
|
|
275245
275286
|
|
|
275246
275287
|
// src/tui/components/commands/config-dialog.tsx
|
|
275247
|
-
var
|
|
275288
|
+
var import_react28 = __toESM(require_react(), 1);
|
|
275248
275289
|
|
|
275249
275290
|
// src/tui/components/alert-dialog.tsx
|
|
275250
275291
|
function AlertDialog({
|
|
@@ -275331,8 +275372,8 @@ function AlertDialog({
|
|
|
275331
275372
|
init_config2();
|
|
275332
275373
|
function ConfigDialog() {
|
|
275333
275374
|
const route = useRoute();
|
|
275334
|
-
const [open, setOpen] =
|
|
275335
|
-
|
|
275375
|
+
const [open, setOpen] = import_react28.useState(false);
|
|
275376
|
+
import_react28.useEffect(() => {
|
|
275336
275377
|
if (route.data.type === "base" && route.data.path === "config") {
|
|
275337
275378
|
setOpen(true);
|
|
275338
275379
|
} else {
|
|
@@ -275346,8 +275387,8 @@ function ConfigDialog() {
|
|
|
275346
275387
|
path: "home"
|
|
275347
275388
|
});
|
|
275348
275389
|
};
|
|
275349
|
-
const [appConfig, setAppConfig] =
|
|
275350
|
-
|
|
275390
|
+
const [appConfig, setAppConfig] = import_react28.useState(null);
|
|
275391
|
+
import_react28.useEffect(() => {
|
|
275351
275392
|
async function getConfig() {
|
|
275352
275393
|
const _appConfig = await config2.get();
|
|
275353
275394
|
setAppConfig(_appConfig);
|
|
@@ -275420,39 +275461,6 @@ function ConfigForm({ appConfig }) {
|
|
|
275420
275461
|
init_session();
|
|
275421
275462
|
var import_react38 = __toESM(require_react(), 1);
|
|
275422
275463
|
|
|
275423
|
-
// src/tui/context/config.tsx
|
|
275424
|
-
init_config2();
|
|
275425
|
-
var import_react28 = __toESM(require_react(), 1);
|
|
275426
|
-
var ctx3 = import_react28.createContext(null);
|
|
275427
|
-
function ConfigProvider({ children, config: config3 }) {
|
|
275428
|
-
const [appConfig, setAppConfig] = import_react28.useState(config3);
|
|
275429
|
-
const value = import_react28.useMemo(() => ({
|
|
275430
|
-
data: appConfig,
|
|
275431
|
-
update: async (newConfig) => {
|
|
275432
|
-
await config2.update(newConfig);
|
|
275433
|
-
setAppConfig({
|
|
275434
|
-
...appConfig,
|
|
275435
|
-
...newConfig
|
|
275436
|
-
});
|
|
275437
|
-
},
|
|
275438
|
-
reload: async () => {
|
|
275439
|
-
const freshConfig = await config2.get();
|
|
275440
|
-
setAppConfig(freshConfig);
|
|
275441
|
-
}
|
|
275442
|
-
}), [appConfig]);
|
|
275443
|
-
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ctx3.Provider, {
|
|
275444
|
-
value,
|
|
275445
|
-
children
|
|
275446
|
-
}, undefined, false, undefined, this);
|
|
275447
|
-
}
|
|
275448
|
-
var useConfig = () => {
|
|
275449
|
-
const config3 = import_react28.useContext(ctx3);
|
|
275450
|
-
if (!config3) {
|
|
275451
|
-
throw new Error("useConfig must be called within a ConfigProvider");
|
|
275452
|
-
}
|
|
275453
|
-
return config3;
|
|
275454
|
-
};
|
|
275455
|
-
|
|
275456
275464
|
// src/tui/components/chat/home-view.tsx
|
|
275457
275465
|
var import_react33 = __toESM(require_react(), 1);
|
|
275458
275466
|
|
|
@@ -276915,18 +276923,25 @@ function ConfigView({ config: config3, onBack, onStart }) {
|
|
|
276915
276923
|
const { colors: colors2 } = useTheme();
|
|
276916
276924
|
const [targetUrl, setTargetUrl] = import_react36.useState("https://");
|
|
276917
276925
|
const [strictScope, setStrictScope] = import_react36.useState(true);
|
|
276918
|
-
const [selectedModel, setSelectedModel] = import_react36.useState({
|
|
276919
|
-
|
|
276920
|
-
|
|
276921
|
-
|
|
276926
|
+
const [selectedModel, setSelectedModel] = import_react36.useState(() => {
|
|
276927
|
+
if (config3) {
|
|
276928
|
+
const dynamicDefault = getDefaultModelForConfig(config3);
|
|
276929
|
+
if (dynamicDefault)
|
|
276930
|
+
return dynamicDefault;
|
|
276931
|
+
}
|
|
276932
|
+
return {
|
|
276933
|
+
id: "claude-sonnet-4-20250514",
|
|
276934
|
+
name: "Claude Sonnet 4",
|
|
276935
|
+
provider: "anthropic"
|
|
276936
|
+
};
|
|
276922
276937
|
});
|
|
276923
276938
|
const [isModelUserSelected, setIsModelUserSelected] = import_react36.useState(false);
|
|
276924
276939
|
const [focusedField, setFocusedField] = import_react36.useState("url");
|
|
276925
276940
|
import_react36.useEffect(() => {
|
|
276926
|
-
if (config3) {
|
|
276941
|
+
if (config3 && !isModelUserSelected) {
|
|
276927
276942
|
const models = getAvailableModels(config3);
|
|
276928
|
-
if (models.length > 0
|
|
276929
|
-
const defaultModel =
|
|
276943
|
+
if (models.length > 0) {
|
|
276944
|
+
const defaultModel = getDefaultModelForConfig(config3) ?? models[0];
|
|
276930
276945
|
setSelectedModel(defaultModel);
|
|
276931
276946
|
}
|
|
276932
276947
|
}
|
|
@@ -278643,6 +278658,142 @@ function WebWizard({
|
|
|
278643
278658
|
// src/tui/components/commands/provider-manager.tsx
|
|
278644
278659
|
var import_react50 = __toESM(require_react(), 1);
|
|
278645
278660
|
init_config2();
|
|
278661
|
+
// src/core/providers/verify.ts
|
|
278662
|
+
var VERIFY_TIMEOUT_MS = 15000;
|
|
278663
|
+
async function fetchWithTimeout(url2, init2) {
|
|
278664
|
+
const controller = new AbortController;
|
|
278665
|
+
const timer = setTimeout(() => controller.abort(), VERIFY_TIMEOUT_MS);
|
|
278666
|
+
try {
|
|
278667
|
+
return await fetch(url2, { ...init2, signal: controller.signal });
|
|
278668
|
+
} finally {
|
|
278669
|
+
clearTimeout(timer);
|
|
278670
|
+
}
|
|
278671
|
+
}
|
|
278672
|
+
async function verifyAnthropic(apiKey) {
|
|
278673
|
+
try {
|
|
278674
|
+
const res = await fetchWithTimeout("https://api.anthropic.com/v1/models", {
|
|
278675
|
+
method: "GET",
|
|
278676
|
+
headers: {
|
|
278677
|
+
"x-api-key": apiKey,
|
|
278678
|
+
"anthropic-version": "2023-06-01"
|
|
278679
|
+
}
|
|
278680
|
+
});
|
|
278681
|
+
if (res.ok)
|
|
278682
|
+
return { valid: true };
|
|
278683
|
+
if (res.status === 401)
|
|
278684
|
+
return { valid: false, error: "Invalid API key" };
|
|
278685
|
+
return {
|
|
278686
|
+
valid: false,
|
|
278687
|
+
error: `Anthropic returned HTTP ${res.status}`
|
|
278688
|
+
};
|
|
278689
|
+
} catch (err) {
|
|
278690
|
+
return {
|
|
278691
|
+
valid: false,
|
|
278692
|
+
error: err instanceof DOMException && err.name === "AbortError" ? "Request timed out" : "Could not reach Anthropic API"
|
|
278693
|
+
};
|
|
278694
|
+
}
|
|
278695
|
+
}
|
|
278696
|
+
async function verifyOpenAI(apiKey) {
|
|
278697
|
+
try {
|
|
278698
|
+
const res = await fetchWithTimeout("https://api.openai.com/v1/models", {
|
|
278699
|
+
method: "GET",
|
|
278700
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
278701
|
+
});
|
|
278702
|
+
if (res.ok)
|
|
278703
|
+
return { valid: true };
|
|
278704
|
+
if (res.status === 401)
|
|
278705
|
+
return { valid: false, error: "Invalid API key" };
|
|
278706
|
+
return {
|
|
278707
|
+
valid: false,
|
|
278708
|
+
error: `OpenAI returned HTTP ${res.status}`
|
|
278709
|
+
};
|
|
278710
|
+
} catch (err) {
|
|
278711
|
+
return {
|
|
278712
|
+
valid: false,
|
|
278713
|
+
error: err instanceof DOMException && err.name === "AbortError" ? "Request timed out" : "Could not reach OpenAI API"
|
|
278714
|
+
};
|
|
278715
|
+
}
|
|
278716
|
+
}
|
|
278717
|
+
async function verifyGoogle(apiKey) {
|
|
278718
|
+
try {
|
|
278719
|
+
const res = await fetchWithTimeout(`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(apiKey)}`, { method: "GET" });
|
|
278720
|
+
if (res.ok)
|
|
278721
|
+
return { valid: true };
|
|
278722
|
+
if (res.status === 400 || res.status === 403)
|
|
278723
|
+
return { valid: false, error: "Invalid API key" };
|
|
278724
|
+
return {
|
|
278725
|
+
valid: false,
|
|
278726
|
+
error: `Google returned HTTP ${res.status}`
|
|
278727
|
+
};
|
|
278728
|
+
} catch (err) {
|
|
278729
|
+
return {
|
|
278730
|
+
valid: false,
|
|
278731
|
+
error: err instanceof DOMException && err.name === "AbortError" ? "Request timed out" : "Could not reach Google AI API"
|
|
278732
|
+
};
|
|
278733
|
+
}
|
|
278734
|
+
}
|
|
278735
|
+
async function verifyOpenRouter(apiKey) {
|
|
278736
|
+
try {
|
|
278737
|
+
const res = await fetchWithTimeout("https://openrouter.ai/api/v1/auth/key", {
|
|
278738
|
+
method: "GET",
|
|
278739
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
278740
|
+
});
|
|
278741
|
+
if (res.ok)
|
|
278742
|
+
return { valid: true };
|
|
278743
|
+
if (res.status === 401 || res.status === 403)
|
|
278744
|
+
return { valid: false, error: "Invalid API key" };
|
|
278745
|
+
return {
|
|
278746
|
+
valid: false,
|
|
278747
|
+
error: `OpenRouter returned HTTP ${res.status}`
|
|
278748
|
+
};
|
|
278749
|
+
} catch (err) {
|
|
278750
|
+
return {
|
|
278751
|
+
valid: false,
|
|
278752
|
+
error: err instanceof DOMException && err.name === "AbortError" ? "Request timed out" : "Could not reach OpenRouter API"
|
|
278753
|
+
};
|
|
278754
|
+
}
|
|
278755
|
+
}
|
|
278756
|
+
async function verifyInception(apiKey) {
|
|
278757
|
+
try {
|
|
278758
|
+
const res = await fetchWithTimeout("https://api.inceptionlabs.ai/v1/models", {
|
|
278759
|
+
method: "GET",
|
|
278760
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
278761
|
+
});
|
|
278762
|
+
if (res.ok)
|
|
278763
|
+
return { valid: true };
|
|
278764
|
+
if (res.status === 401 || res.status === 403)
|
|
278765
|
+
return { valid: false, error: "Invalid API key" };
|
|
278766
|
+
return {
|
|
278767
|
+
valid: false,
|
|
278768
|
+
error: `Inception returned HTTP ${res.status}`
|
|
278769
|
+
};
|
|
278770
|
+
} catch (err) {
|
|
278771
|
+
return {
|
|
278772
|
+
valid: false,
|
|
278773
|
+
error: err instanceof DOMException && err.name === "AbortError" ? "Request timed out" : "Could not reach Inception API"
|
|
278774
|
+
};
|
|
278775
|
+
}
|
|
278776
|
+
}
|
|
278777
|
+
async function verifyApiKey(provider, apiKey) {
|
|
278778
|
+
switch (provider) {
|
|
278779
|
+
case "anthropic":
|
|
278780
|
+
return verifyAnthropic(apiKey);
|
|
278781
|
+
case "openai":
|
|
278782
|
+
return verifyOpenAI(apiKey);
|
|
278783
|
+
case "google":
|
|
278784
|
+
return verifyGoogle(apiKey);
|
|
278785
|
+
case "openrouter":
|
|
278786
|
+
return verifyOpenRouter(apiKey);
|
|
278787
|
+
case "inception":
|
|
278788
|
+
return verifyInception(apiKey);
|
|
278789
|
+
case "bedrock":
|
|
278790
|
+
case "local":
|
|
278791
|
+
case "pensar":
|
|
278792
|
+
return { valid: true };
|
|
278793
|
+
default:
|
|
278794
|
+
return { valid: true };
|
|
278795
|
+
}
|
|
278796
|
+
}
|
|
278646
278797
|
// src/tui/components/commands/provider-selection.tsx
|
|
278647
278798
|
var import_react45 = __toESM(require_react(), 1);
|
|
278648
278799
|
function ProviderSelection({
|
|
@@ -278816,12 +278967,30 @@ function APIKeyInput({
|
|
|
278816
278967
|
}) {
|
|
278817
278968
|
const { colors: colors2 } = useTheme();
|
|
278818
278969
|
const [apiKey, setApiKey] = import_react47.useState("");
|
|
278970
|
+
const [verifyState, setVerifyState] = import_react47.useState("idle");
|
|
278971
|
+
const [errorMessage, setErrorMessage] = import_react47.useState("");
|
|
278819
278972
|
useKeyboard((key) => {
|
|
278820
278973
|
if (key.name === "escape") {
|
|
278974
|
+
if (verifyState === "verifying")
|
|
278975
|
+
return;
|
|
278821
278976
|
onCancel();
|
|
278822
278977
|
return;
|
|
278823
278978
|
}
|
|
278824
278979
|
});
|
|
278980
|
+
const handleSubmit = async () => {
|
|
278981
|
+
const key = apiKey.trim();
|
|
278982
|
+
if (!key || verifyState === "verifying")
|
|
278983
|
+
return;
|
|
278984
|
+
setVerifyState("verifying");
|
|
278985
|
+
setErrorMessage("");
|
|
278986
|
+
const result = await verifyApiKey(provider, key);
|
|
278987
|
+
if (result.valid) {
|
|
278988
|
+
onSubmit(key);
|
|
278989
|
+
} else {
|
|
278990
|
+
setVerifyState("error");
|
|
278991
|
+
setErrorMessage(result.error ?? "Invalid API key");
|
|
278992
|
+
}
|
|
278993
|
+
};
|
|
278825
278994
|
const getProviderInstructions = (provider2) => {
|
|
278826
278995
|
switch (provider2) {
|
|
278827
278996
|
case "anthropic":
|
|
@@ -278834,8 +279003,6 @@ function APIKeyInput({
|
|
|
278834
279003
|
return "Get your API key from openrouter.ai/keys";
|
|
278835
279004
|
case "bedrock":
|
|
278836
279005
|
return "Enter your AWS Access Key ID (configure region separately) or AWS Bedrock API Key";
|
|
278837
|
-
case "pensar":
|
|
278838
|
-
return "Get your API key from console.pensar.dev/connect (or run /auth)";
|
|
278839
279006
|
default:
|
|
278840
279007
|
return "Enter your API key";
|
|
278841
279008
|
}
|
|
@@ -278889,20 +279056,32 @@ function APIKeyInput({
|
|
|
278889
279056
|
label: "API Key",
|
|
278890
279057
|
description: "Your API key will be stored locally in ~/.pensar/config.json",
|
|
278891
279058
|
value: apiKey,
|
|
278892
|
-
focused:
|
|
279059
|
+
focused: verifyState !== "verifying",
|
|
278893
279060
|
onChange: (value) => setApiKey(typeof value === "string" ? value : ""),
|
|
278894
279061
|
onPaste: (event) => {
|
|
278895
279062
|
const cleaned = String(event.text);
|
|
278896
279063
|
setApiKey((prev) => `${prev}${cleaned}`);
|
|
278897
279064
|
},
|
|
278898
|
-
onSubmit:
|
|
278899
|
-
const key = apiKey.trim();
|
|
278900
|
-
if (key) {
|
|
278901
|
-
onSubmit(key);
|
|
278902
|
-
}
|
|
278903
|
-
}
|
|
279065
|
+
onSubmit: handleSubmit
|
|
278904
279066
|
}, undefined, false, undefined, this)
|
|
278905
279067
|
}, undefined, false, undefined, this),
|
|
279068
|
+
verifyState === "verifying" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279069
|
+
marginBottom: 1,
|
|
279070
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279071
|
+
fg: colors2.textMuted,
|
|
279072
|
+
children: "Verifying API key..."
|
|
279073
|
+
}, undefined, false, undefined, this)
|
|
279074
|
+
}, undefined, false, undefined, this),
|
|
279075
|
+
verifyState === "error" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
279076
|
+
marginBottom: 1,
|
|
279077
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
279078
|
+
fg: colors2.error,
|
|
279079
|
+
children: [
|
|
279080
|
+
"✗ ",
|
|
279081
|
+
errorMessage
|
|
279082
|
+
]
|
|
279083
|
+
}, undefined, true, undefined, this)
|
|
279084
|
+
}, undefined, false, undefined, this),
|
|
278906
279085
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
278907
279086
|
marginTop: 1,
|
|
278908
279087
|
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
@@ -279588,7 +279767,11 @@ function ProviderManager() {
|
|
|
279588
279767
|
const [selectedProvider, setSelectedProvider] = import_react50.useState(null);
|
|
279589
279768
|
const handleProviderSelected = (providerId) => {
|
|
279590
279769
|
setSelectedProvider(providerId);
|
|
279591
|
-
|
|
279770
|
+
if (providerId === "pensar") {
|
|
279771
|
+
setFlowState("auth");
|
|
279772
|
+
} else {
|
|
279773
|
+
setFlowState("inputting");
|
|
279774
|
+
}
|
|
279592
279775
|
};
|
|
279593
279776
|
const handleAPIKeySubmit = async (apiKey) => {
|
|
279594
279777
|
if (!selectedProvider)
|