@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 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.104",
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.104",
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 verify(thing, signature, secret) {
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 verify(thing, signature, publicKey) {
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 verify(thing, signature, publicKey) {
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 verify(thing, signature, publicKey) {
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 verify(thing, signature) {
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 verify() {
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 import_react11 = __toESM(require_react(), 1);
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: true
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/agent.tsx
273254
- var PREFERRED_DEFAULTS = {
273255
- pensar: "pensar:anthropic.claude-haiku-4-5-20251001-v1:0",
273256
- anthropic: "claude-haiku-4-5",
273257
- openai: "gpt-4o-mini",
273258
- google: "gemini-2.5-flash"
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
- var PROVIDER_PREFERENCE = [
273261
- "pensar",
273262
- "anthropic",
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 = import_react11.useContext(AgentContext);
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 [model, setModelInternal] = import_react11.useState(AVAILABLE_MODELS[0]);
273278
- const [isModelUserSelected, setIsModelUserSelected] = import_react11.useState(false);
273279
- const [tokenUsage, setTokenUsage] = import_react11.useState({
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] = import_react11.useState(false);
273285
- const [thinking, setThinking] = import_react11.useState(false);
273286
- const [isExecuting, setIsExecuting] = import_react11.useState(false);
273287
- const [sessionCwd, setSessionCwd] = import_react11.useState(null);
273288
- const setModel = import_react11.useCallback((newModel, persist = true) => {
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
- import_react11.useEffect(() => {
273298
- get().then((config3) => {
273299
- const available = getAvailableModels(config3);
273300
- if (available.length === 0)
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
- let selectedModel = null;
273317
- for (const provider of PROVIDER_PREFERENCE) {
273318
- const models = byProvider.get(provider);
273319
- if (!models || models.length === 0)
273320
- continue;
273321
- const preferredId = PREFERRED_DEFAULTS[provider];
273322
- if (preferredId) {
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 = import_react11.useCallback(() => {
273388
+ const resetTokenUsage = import_react12.useCallback(() => {
273348
273389
  setHasExecuted(false);
273349
273390
  setTokenUsage({ inputTokens: 0, outputTokens: 0, totalTokens: 0 });
273350
273391
  }, []);
273351
- const contextValue = import_react11.useMemo(() => ({
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 import_react13 = __toESM(require_react(), 1);
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 import_react12 = __toESM(require_react(), 1);
273405
- var ThemeContext = import_react12.createContext(null);
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] = import_react12.useState(() => getTheme(initialTheme ?? DEFAULT_THEME_NAME));
273425
- const [mode, setModeState] = import_react12.useState(initialMode);
273426
- const colors = import_react12.useMemo(() => resolveThemeColors(theme, mode), [theme, mode]);
273427
- const setTheme = import_react12.useCallback((name26) => {
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 = import_react12.useCallback(() => {
273472
+ const toggleMode = import_react13.useCallback(() => {
273432
273473
  setModeState((prev) => prev === "dark" ? "light" : "dark");
273433
273474
  }, []);
273434
- const setMode = import_react12.useCallback((m2) => {
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 ctx = import_react12.useContext(ThemeContext);
273452
- if (!ctx)
273492
+ const ctx2 = import_react13.useContext(ThemeContext);
273493
+ if (!ctx2)
273453
273494
  throw new Error("useTheme() must be used within <ThemeProvider>");
273454
- return ctx;
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] = import_react13.useState(0);
273496
- import_react13.useEffect(() => {
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 import_react14 = __toESM(require_react(), 1);
273524
- var ctx = import_react14.createContext(null);
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] = import_react14.useState(session);
273527
- const value = import_react14.useMemo(() => ({
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(ctx.Provider, {
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 = import_react14.useContext(ctx);
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 import_react15 = __toESM(require_react(), 1);
273562
- var ctx2 = import_react15.createContext(null);
273602
+ var import_react16 = __toESM(require_react(), 1);
273603
+ var ctx3 = import_react16.createContext(null);
273563
273604
  function RouteProvider({ children }) {
273564
- const [route, setRoute] = import_react15.useState({
273605
+ const [route, setRoute] = import_react16.useState({
273565
273606
  type: "base",
273566
273607
  path: "home"
273567
273608
  });
273568
- const value = import_react15.useMemo(() => ({
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(ctx2.Provider, {
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 = import_react15.useContext(ctx2);
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 import_react16 = __toESM(require_react(), 1);
273590
- var InputContext = import_react16.createContext(undefined);
273630
+ var import_react17 = __toESM(require_react(), 1);
273631
+ var InputContext = import_react17.createContext(undefined);
273591
273632
  function InputProvider({ children }) {
273592
- const [inputValue, setInputValue] = import_react16.useState("");
273593
- const clearInput = import_react16.useCallback(() => {
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 = import_react16.useContext(InputContext);
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 import_react17 = __toESM(require_react(), 1);
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, ctx3) {
273760
- const { handler, ...metadata } = definition(ctx3);
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, ctx3) {
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, ctx3);
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, ctx3) => {
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
- ctx3.navigate({
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
- ctx3.openPentestDialog?.({ auto: true, ...flags });
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, ctx3) => {
274198
+ handler: async (args, ctx4) => {
274158
274199
  const flags = parseWebFlags(args);
274159
274200
  const params = buildOperatorSessionConfig(flags);
274160
- ctx3.navigate({
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, ctx3) => {
274175
- ctx3.navigate({
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, ctx3) => {
274186
- ctx3.navigate({
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, ctx3) => {
274197
- ctx3.navigate({
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, ctx3) => {
274208
- ctx3.navigate({
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, ctx3) => {
274220
- ctx3.openSessionsDialog?.();
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, ctx3) => {
274228
- ctx3.navigate({ type: "operator", nonce: Date.now() });
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, ctx3) => {
274238
- ctx3.navigate({
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, ctx3) => {
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
- ctx3.openThemeDialog?.();
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, ctx3) => {
274292
- if (ctx3.route.type !== "pentest") {
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, ctx3) => {
274311
- ctx3.openAuthDialog?.();
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, ctx3) => {
274320
- ctx3.navigate({
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, ctx3) => {
274331
- ctx3.navigate({
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) => (ctx3) => ({
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, ctx3);
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 = import_react17.createContext(null);
274479
+ var CommandContext = import_react18.createContext(null);
274439
274480
  function useCommand() {
274440
- const context2 = import_react17.useContext(CommandContext);
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] = import_react17.useState([]);
274455
- const ctx3 = import_react17.useMemo(() => {
274456
- const ctx4 = {
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 ctx4;
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 = import_react17.useCallback(async () => {
274513
+ const refreshSkills = import_react18.useCallback(async () => {
274473
274514
  const loaded = await loadSkills();
274474
274515
  setSkills(loaded);
274475
274516
  }, []);
274476
- import_react17.useEffect(() => {
274517
+ import_react18.useEffect(() => {
274477
274518
  refreshSkills();
274478
274519
  }, [route.data]);
274479
- const router = import_react17.useMemo(() => {
274520
+ const router = import_react18.useMemo(() => {
274480
274521
  const router2 = new CommandRouter;
274481
274522
  for (const commandDef of commandRegistry) {
274482
- router2.registerWithContext(commandDef, ctx3);
274523
+ router2.registerWithContext(commandDef, ctx4);
274483
274524
  }
274484
274525
  return router2;
274485
274526
  }, []);
274486
- const skillSlugMap = import_react17.useMemo(() => {
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 = import_react17.useCallback((input) => {
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 = import_react17.useMemo(() => {
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 = import_react17.useCallback(async (input) => {
274543
- return await router.execute(input, ctx3);
274544
- }, [router, ctx3]);
274545
- const value = import_react17.useMemo(() => ({
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 import_react24 = __toESM(require_react(), 1);
274609
+ var import_react25 = __toESM(require_react(), 1);
274569
274610
 
274570
274611
  // src/tui/context/focus.tsx
274571
- var import_react18 = __toESM(require_react(), 1);
274572
- var FocusContext = import_react18.createContext(undefined);
274612
+ var import_react19 = __toESM(require_react(), 1);
274613
+ var FocusContext = import_react19.createContext(undefined);
274573
274614
  function FocusProvider({ children }) {
274574
- const promptRef = import_react18.useRef(null);
274575
- const refocusPrompt = import_react18.useCallback(() => {
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 = import_react18.useCallback(() => promptRef.current?.focus(), []);
274581
- const blurPrompt = import_react18.useCallback(() => promptRef.current?.blur(), []);
274582
- const resetPrompt = import_react18.useCallback(() => promptRef.current?.reset(), []);
274583
- const setPromptValue = import_react18.useCallback((value) => promptRef.current?.setValue(value), []);
274584
- const getPromptValue = import_react18.useCallback(() => promptRef.current?.getValue() ?? "", []);
274585
- const registerPromptRef = import_react18.useCallback((ref) => {
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 = import_react18.useContext(FocusContext);
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 import_react19 = __toESM(require_react(), 1);
274639
- var DimensionsContext = import_react19.createContext(null);
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 ctx3 = import_react19.useContext(DimensionsContext);
274651
- if (!ctx3)
274691
+ const ctx4 = import_react20.useContext(DimensionsContext);
274692
+ if (!ctx4)
274652
274693
  throw new Error("useDimensions() must be used within <TerminalDimensionsProvider>");
274653
- return ctx3;
274694
+ return ctx4;
274654
274695
  }
274655
274696
 
274656
274697
  // src/tui/context/dialog.tsx
274657
- var import_react22 = __toESM(require_react(), 1);
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 = import_react22.createContext(null);
274735
+ var DialogContext = import_react23.createContext(null);
274695
274736
  function DialogProvider({ children }) {
274696
- const [stack, setStack] = import_react22.useState([]);
274697
- const [size, setSize] = import_react22.useState("medium");
274698
- const [externalDialogOpen, setExternalDialogOpen] = import_react22.useState(false);
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 = import_react22.useRef(null);
274701
- const refocus = import_react22.useCallback(() => {
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 = import_react22.useCallback(() => {
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 = import_react22.useCallback((element, onClose) => {
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 = import_react22.useContext(DialogContext);
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 import_react23 = __toESM(require_react(), 1);
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] = import_react23.useState([]);
274859
- const [loading, setLoading] = import_react23.useState(true);
274860
- const [searchTerm, setSearchTerm] = import_react23.useState("");
274861
- const loadSessions = import_react23.useCallback(async () => {
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
- import_react23.useEffect(() => {
274925
+ import_react24.useEffect(() => {
274885
274926
  loadSessions();
274886
274927
  }, [loadSessions]);
274887
- const deleteSession = import_react23.useCallback(async (id) => {
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] = import_react24.useState(0);
274947
- const [statusMessage, setStatusMessage] = import_react24.useState("");
274987
+ const [selectedIndex, setSelectedIndex] = import_react25.useState(0);
274988
+ const [statusMessage, setStatusMessage] = import_react25.useState("");
274948
274989
  const route = useRoute();
274949
- const scroll = import_react24.useRef(null);
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
- import_react24.useEffect(() => {
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 import_react27 = __toESM(require_react(), 1);
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] = import_react27.useState(false);
275335
- import_react27.useEffect(() => {
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] = import_react27.useState(null);
275350
- import_react27.useEffect(() => {
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
- id: "claude-sonnet-4-20250514",
276920
- name: "Claude Sonnet 4",
276921
- provider: "anthropic"
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 && !isModelUserSelected) {
276929
- const defaultModel = models.find((m2) => m2.provider === "anthropic") || models[0];
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: true,
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
- setFlowState("inputting");
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pensar/apex",
3
- "version": "0.0.104",
3
+ "version": "0.0.105",
4
4
  "description": "AI-powered penetration testing CLI tool with terminal UI",
5
5
  "module": "src/tui/index.tsx",
6
6
  "main": "build/index.js",