@pensar/apex 0.0.104 → 0.0.105-canary.e76e131d

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-canary.e76e131d",
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
@@ -31880,12 +31880,6 @@ var init_openrouter = __esm(() => {
31880
31880
  var PENSAR_MODELS;
31881
31881
  var init_pensar = __esm(() => {
31882
31882
  PENSAR_MODELS = [
31883
- {
31884
- id: "pensar:anthropic.claude-opus-4-6-v1",
31885
- name: "Claude Opus 4.6 (Pensar)",
31886
- provider: "pensar",
31887
- contextLength: 200000
31888
- },
31889
31883
  {
31890
31884
  id: "pensar:anthropic.claude-sonnet-4-5-20250929-v1:0",
31891
31885
  name: "Claude Sonnet 4.5 (Pensar)",
@@ -31977,7 +31971,7 @@ var package_default2;
31977
31971
  var init_package = __esm(() => {
31978
31972
  package_default2 = {
31979
31973
  name: "@pensar/apex",
31980
- version: "0.0.104",
31974
+ version: "0.0.105-canary.e76e131d",
31981
31975
  description: "AI-powered penetration testing CLI tool with terminal UI",
31982
31976
  module: "src/tui/index.tsx",
31983
31977
  main: "build/index.js",
@@ -162544,7 +162538,7 @@ var require_jwa = __commonJS((exports, module2) => {
162544
162538
  return bufferEqual(a, b2);
162545
162539
  };
162546
162540
  function createHmacVerifier(bits) {
162547
- return function verify(thing, signature, secret) {
162541
+ return function verify2(thing, signature, secret) {
162548
162542
  var computedSig = createHmacSigner(bits)(thing, secret);
162549
162543
  return timingSafeEqual(Buffer4.from(signature), Buffer4.from(computedSig));
162550
162544
  };
@@ -162559,7 +162553,7 @@ var require_jwa = __commonJS((exports, module2) => {
162559
162553
  };
162560
162554
  }
162561
162555
  function createKeyVerifier(bits) {
162562
- return function verify(thing, signature, publicKey) {
162556
+ return function verify2(thing, signature, publicKey) {
162563
162557
  checkIsPublicKey(publicKey);
162564
162558
  thing = normalizeInput(thing);
162565
162559
  signature = toBase64(signature);
@@ -162582,7 +162576,7 @@ var require_jwa = __commonJS((exports, module2) => {
162582
162576
  };
162583
162577
  }
162584
162578
  function createPSSKeyVerifier(bits) {
162585
- return function verify(thing, signature, publicKey) {
162579
+ return function verify2(thing, signature, publicKey) {
162586
162580
  checkIsPublicKey(publicKey);
162587
162581
  thing = normalizeInput(thing);
162588
162582
  signature = toBase64(signature);
@@ -162605,7 +162599,7 @@ var require_jwa = __commonJS((exports, module2) => {
162605
162599
  }
162606
162600
  function createECDSAVerifer(bits) {
162607
162601
  var inner = createKeyVerifier(bits);
162608
- return function verify(thing, signature, publicKey) {
162602
+ return function verify2(thing, signature, publicKey) {
162609
162603
  signature = formatEcdsa.joseToDer(signature, "ES" + bits).toString("base64");
162610
162604
  var result = inner(thing, signature, publicKey);
162611
162605
  return result;
@@ -162617,7 +162611,7 @@ var require_jwa = __commonJS((exports, module2) => {
162617
162611
  };
162618
162612
  }
162619
162613
  function createNoneVerifier() {
162620
- return function verify(thing, signature) {
162614
+ return function verify2(thing, signature) {
162621
162615
  return signature === "";
162622
162616
  };
162623
162617
  }
@@ -162825,7 +162819,7 @@ var require_verify_stream = __commonJS((exports, module2) => {
162825
162819
  }.bind(this));
162826
162820
  }
162827
162821
  util4.inherits(VerifyStream, Stream3);
162828
- VerifyStream.prototype.verify = function verify() {
162822
+ VerifyStream.prototype.verify = function verify2() {
162829
162823
  try {
162830
162824
  var valid = jwsVerify(this.signature.buffer, this.algorithm, this.key.buffer);
162831
162825
  var obj = jwsDecode(this.signature.buffer, this.encoding);
@@ -273082,7 +273076,7 @@ import os6 from "os";
273082
273076
  // src/tui/context/agent.tsx
273083
273077
  init_models();
273084
273078
  init_config();
273085
- var import_react11 = __toESM(require_react(), 1);
273079
+ var import_react12 = __toESM(require_react(), 1);
273086
273080
 
273087
273081
  // src/core/providers/utils.ts
273088
273082
  init_models();
@@ -273135,11 +273129,26 @@ var AVAILABLE_PROVIDERS = [
273135
273129
  id: "pensar",
273136
273130
  name: "Pensar",
273137
273131
  description: "Managed inference via Pensar Console (usage-based billing)",
273138
- requiresAPIKey: true
273132
+ requiresAPIKey: false
273139
273133
  }
273140
273134
  ];
273141
273135
 
273142
273136
  // src/core/providers/utils.ts
273137
+ var PROVIDER_PREFERENCE_ORDER = [
273138
+ "pensar",
273139
+ "anthropic",
273140
+ "openai",
273141
+ "google",
273142
+ "openrouter",
273143
+ "bedrock"
273144
+ ];
273145
+ var PREFERRED_MODEL_BY_PROVIDER = {
273146
+ pensar: "pensar:anthropic.claude-opus-4-1-20250805-v1:0",
273147
+ anthropic: "claude-opus-4-6",
273148
+ openai: "gpt-5.2-pro",
273149
+ google: "gemini-3.1-pro-preview",
273150
+ openrouter: "anthropic/claude-opus-4.6"
273151
+ };
273143
273152
  function getConfiguredProviders(config) {
273144
273153
  return AVAILABLE_PROVIDERS.map((provider) => {
273145
273154
  const configured = isProviderConfigured(provider.id, config);
@@ -273188,6 +273197,30 @@ function getAvailableModels(config) {
273188
273197
  }
273189
273198
  return models;
273190
273199
  }
273200
+ function getDefaultModelForConfig(config) {
273201
+ const available = getAvailableModels(config);
273202
+ if (available.length === 0)
273203
+ return null;
273204
+ const byProvider = new Map;
273205
+ for (const m2 of available) {
273206
+ const list = byProvider.get(m2.provider) || [];
273207
+ list.push(m2);
273208
+ byProvider.set(m2.provider, list);
273209
+ }
273210
+ for (const provider of PROVIDER_PREFERENCE_ORDER) {
273211
+ const models = byProvider.get(provider);
273212
+ if (!models || models.length === 0)
273213
+ continue;
273214
+ const preferredId = PREFERRED_MODEL_BY_PROVIDER[provider];
273215
+ if (preferredId) {
273216
+ const preferred = models.find((m2) => m2.id === preferredId);
273217
+ if (preferred)
273218
+ return preferred;
273219
+ }
273220
+ return models[0];
273221
+ }
273222
+ return available[0] ?? null;
273223
+ }
273191
273224
 
273192
273225
  // src/core/logger/index.ts
273193
273226
  init_session();
@@ -273247,45 +273280,69 @@ ${error40.stack ?? ""}` : String(error40);
273247
273280
  } catch {}
273248
273281
  }
273249
273282
 
273283
+ // src/tui/context/config.tsx
273284
+ init_config2();
273285
+ var import_react11 = __toESM(require_react(), 1);
273286
+
273250
273287
  // node_modules/@opentui/react/jsx-dev-runtime.js
273251
273288
  var import_jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
273252
273289
 
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"
273290
+ // src/tui/context/config.tsx
273291
+ var ctx = import_react11.createContext(null);
273292
+ function ConfigProvider({ children, config: config3 }) {
273293
+ const [appConfig, setAppConfig] = import_react11.useState(config3);
273294
+ const value = import_react11.useMemo(() => ({
273295
+ data: appConfig,
273296
+ update: async (newConfig) => {
273297
+ await config2.update(newConfig);
273298
+ setAppConfig({
273299
+ ...appConfig,
273300
+ ...newConfig
273301
+ });
273302
+ },
273303
+ reload: async () => {
273304
+ const freshConfig = await config2.get();
273305
+ setAppConfig(freshConfig);
273306
+ }
273307
+ }), [appConfig]);
273308
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ctx.Provider, {
273309
+ value,
273310
+ children
273311
+ }, undefined, false, undefined, this);
273312
+ }
273313
+ var useConfig = () => {
273314
+ const config3 = import_react11.useContext(ctx);
273315
+ if (!config3) {
273316
+ throw new Error("useConfig must be called within a ConfigProvider");
273317
+ }
273318
+ return config3;
273259
273319
  };
273260
- var PROVIDER_PREFERENCE = [
273261
- "pensar",
273262
- "anthropic",
273263
- "openai",
273264
- "google",
273265
- "openrouter",
273266
- "bedrock"
273267
- ];
273268
- var AgentContext = import_react11.createContext(null);
273320
+
273321
+ // src/tui/context/agent.tsx
273322
+ var AgentContext = import_react12.createContext(null);
273269
273323
  function useAgent() {
273270
- const context2 = import_react11.useContext(AgentContext);
273324
+ const context2 = import_react12.useContext(AgentContext);
273271
273325
  if (!context2) {
273272
273326
  throw new Error("useAgent must be used within AgentProvider");
273273
273327
  }
273274
273328
  return context2;
273275
273329
  }
273276
273330
  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({
273331
+ const appConfig = useConfig();
273332
+ const [model, setModelInternal] = import_react12.useState(() => {
273333
+ return getDefaultModelForConfig(appConfig.data) ?? AVAILABLE_MODELS[0];
273334
+ });
273335
+ const [isModelUserSelected, setIsModelUserSelected] = import_react12.useState(false);
273336
+ const [tokenUsage, setTokenUsage] = import_react12.useState({
273280
273337
  inputTokens: 0,
273281
273338
  outputTokens: 0,
273282
273339
  totalTokens: 0
273283
273340
  });
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) => {
273341
+ const [hasExecuted, setHasExecuted] = import_react12.useState(false);
273342
+ const [thinking, setThinking] = import_react12.useState(false);
273343
+ const [isExecuting, setIsExecuting] = import_react12.useState(false);
273344
+ const [sessionCwd, setSessionCwd] = import_react12.useState(null);
273345
+ const setModel = import_react12.useCallback((newModel, persist = true) => {
273289
273346
  setModelInternal(newModel);
273290
273347
  if (persist) {
273291
273348
  setIsModelUserSelected(true);
@@ -273294,49 +273351,27 @@ function AgentProvider({ children }) {
273294
273351
  });
273295
273352
  }
273296
273353
  }, []);
273297
- import_react11.useEffect(() => {
273298
- get().then((config3) => {
273299
- const available = getAvailableModels(config3);
273300
- if (available.length === 0)
273354
+ import_react12.useEffect(() => {
273355
+ if (isModelUserSelected)
273356
+ return;
273357
+ const cfg = appConfig.data;
273358
+ const available = getAvailableModels(cfg);
273359
+ if (available.length === 0)
273360
+ return;
273361
+ if (cfg.selectedModelId) {
273362
+ const savedModel = available.find((m2) => m2.id === cfg.selectedModelId);
273363
+ if (savedModel) {
273364
+ setModelInternal(savedModel);
273365
+ setIsModelUserSelected(true);
273301
273366
  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
273367
  }
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
- }
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) => {
273368
+ }
273369
+ const defaultModel = getDefaultModelForConfig(cfg);
273370
+ if (defaultModel) {
273371
+ setModelInternal(defaultModel);
273372
+ }
273373
+ }, [appConfig.data, isModelUserSelected]);
273374
+ const addTokenUsage = import_react12.useCallback((input, output) => {
273340
273375
  setHasExecuted(true);
273341
273376
  setTokenUsage((prev) => ({
273342
273377
  inputTokens: prev.inputTokens + input,
@@ -273344,11 +273379,11 @@ function AgentProvider({ children }) {
273344
273379
  totalTokens: prev.totalTokens + input + output
273345
273380
  }));
273346
273381
  }, []);
273347
- const resetTokenUsage = import_react11.useCallback(() => {
273382
+ const resetTokenUsage = import_react12.useCallback(() => {
273348
273383
  setHasExecuted(false);
273349
273384
  setTokenUsage({ inputTokens: 0, outputTokens: 0, totalTokens: 0 });
273350
273385
  }, []);
273351
- const contextValue = import_react11.useMemo(() => ({
273386
+ const contextValue = import_react12.useMemo(() => ({
273352
273387
  model,
273353
273388
  setModel,
273354
273389
  isModelUserSelected,
@@ -273381,7 +273416,7 @@ function AgentProvider({ children }) {
273381
273416
  }
273382
273417
 
273383
273418
  // src/tui/components/sprites.tsx
273384
- var import_react13 = __toESM(require_react(), 1);
273419
+ var import_react14 = __toESM(require_react(), 1);
273385
273420
 
273386
273421
  // src/tui/theme/registry.ts
273387
273422
  var themes = new Map;
@@ -273401,8 +273436,8 @@ function getAllThemeNames() {
273401
273436
  return Array.from(themes.keys()).sort();
273402
273437
  }
273403
273438
  // src/tui/theme/context.tsx
273404
- var import_react12 = __toESM(require_react(), 1);
273405
- var ThemeContext = import_react12.createContext(null);
273439
+ var import_react13 = __toESM(require_react(), 1);
273440
+ var ThemeContext = import_react13.createContext(null);
273406
273441
  function resolveColor(value, mode) {
273407
273442
  if ("r" in value)
273408
273443
  return value;
@@ -273421,17 +273456,17 @@ function ThemeProvider({
273421
273456
  initialMode = "dark",
273422
273457
  children
273423
273458
  }) {
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) => {
273459
+ const [theme, setThemeState] = import_react13.useState(() => getTheme(initialTheme ?? DEFAULT_THEME_NAME));
273460
+ const [mode, setModeState] = import_react13.useState(initialMode);
273461
+ const colors = import_react13.useMemo(() => resolveThemeColors(theme, mode), [theme, mode]);
273462
+ const setTheme = import_react13.useCallback((name26) => {
273428
273463
  const newTheme = getTheme(name26);
273429
273464
  setThemeState(newTheme);
273430
273465
  }, []);
273431
- const toggleMode = import_react12.useCallback(() => {
273466
+ const toggleMode = import_react13.useCallback(() => {
273432
273467
  setModeState((prev) => prev === "dark" ? "light" : "dark");
273433
273468
  }, []);
273434
- const setMode = import_react12.useCallback((m2) => {
273469
+ const setMode = import_react13.useCallback((m2) => {
273435
273470
  setModeState(m2);
273436
273471
  }, []);
273437
273472
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ThemeContext, {
@@ -273448,10 +273483,10 @@ function ThemeProvider({
273448
273483
  }, undefined, false, undefined, this);
273449
273484
  }
273450
273485
  function useTheme() {
273451
- const ctx = import_react12.useContext(ThemeContext);
273452
- if (!ctx)
273486
+ const ctx2 = import_react13.useContext(ThemeContext);
273487
+ if (!ctx2)
273453
273488
  throw new Error("useTheme() must be used within <ThemeProvider>");
273454
- return ctx;
273489
+ return ctx2;
273455
273490
  }
273456
273491
  // src/tui/theme/colors.ts
273457
273492
  var colors = {
@@ -273492,8 +273527,8 @@ function stopGlobalTick() {
273492
273527
  }
273493
273528
  }
273494
273529
  function useGlobalTick() {
273495
- const [, setTick] = import_react13.useState(0);
273496
- import_react13.useEffect(() => {
273530
+ const [, setTick] = import_react14.useState(0);
273531
+ import_react14.useEffect(() => {
273497
273532
  const listener = () => setTick((t2) => t2 + 1);
273498
273533
  globalListeners.add(listener);
273499
273534
  startGlobalTick();
@@ -273520,11 +273555,11 @@ function SpinnerDots({
273520
273555
 
273521
273556
  // src/tui/context/session.tsx
273522
273557
  init_session();
273523
- var import_react14 = __toESM(require_react(), 1);
273524
- var ctx = import_react14.createContext(null);
273558
+ var import_react15 = __toESM(require_react(), 1);
273559
+ var ctx2 = import_react15.createContext(null);
273525
273560
  function SessionProvider({ children, session }) {
273526
- const [activeSession, setActiveSession] = import_react14.useState(session);
273527
- const value = import_react14.useMemo(() => ({
273561
+ const [activeSession, setActiveSession] = import_react15.useState(session);
273562
+ const value = import_react15.useMemo(() => ({
273528
273563
  active: activeSession,
273529
273564
  load: async (id) => {
273530
273565
  try {
@@ -273545,40 +273580,40 @@ function SessionProvider({ children, session }) {
273545
273580
  return _session;
273546
273581
  }
273547
273582
  }), [activeSession]);
273548
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ctx.Provider, {
273583
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ctx2.Provider, {
273549
273584
  value,
273550
273585
  children
273551
273586
  }, undefined, false, undefined, this);
273552
273587
  }
273553
273588
  var useSession = () => {
273554
- const session = import_react14.useContext(ctx);
273589
+ const session = import_react15.useContext(ctx2);
273555
273590
  if (!session)
273556
273591
  throw new Error("useSession must be called within a SessionProvider");
273557
273592
  return session;
273558
273593
  };
273559
273594
 
273560
273595
  // src/tui/context/route.tsx
273561
- var import_react15 = __toESM(require_react(), 1);
273562
- var ctx2 = import_react15.createContext(null);
273596
+ var import_react16 = __toESM(require_react(), 1);
273597
+ var ctx3 = import_react16.createContext(null);
273563
273598
  function RouteProvider({ children }) {
273564
- const [route, setRoute] = import_react15.useState({
273599
+ const [route, setRoute] = import_react16.useState({
273565
273600
  type: "base",
273566
273601
  path: "home"
273567
273602
  });
273568
- const value = import_react15.useMemo(() => ({
273603
+ const value = import_react16.useMemo(() => ({
273569
273604
  data: route,
273570
273605
  navigate: (newRoute) => {
273571
273606
  console.log("navigating to:", newRoute);
273572
273607
  setRoute(newRoute);
273573
273608
  }
273574
273609
  }), [route]);
273575
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ctx2.Provider, {
273610
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ctx3.Provider, {
273576
273611
  value,
273577
273612
  children
273578
273613
  }, undefined, false, undefined, this);
273579
273614
  }
273580
273615
  var useRoute = () => {
273581
- const route = import_react15.useContext(ctx2);
273616
+ const route = import_react16.useContext(ctx3);
273582
273617
  if (!route) {
273583
273618
  throw new Error("useRoute must be called within a RouteProvider");
273584
273619
  }
@@ -273586,11 +273621,11 @@ var useRoute = () => {
273586
273621
  };
273587
273622
 
273588
273623
  // src/tui/context/input.tsx
273589
- var import_react16 = __toESM(require_react(), 1);
273590
- var InputContext = import_react16.createContext(undefined);
273624
+ var import_react17 = __toESM(require_react(), 1);
273625
+ var InputContext = import_react17.createContext(undefined);
273591
273626
  function InputProvider({ children }) {
273592
- const [inputValue, setInputValue] = import_react16.useState("");
273593
- const clearInput = import_react16.useCallback(() => {
273627
+ const [inputValue, setInputValue] = import_react17.useState("");
273628
+ const clearInput = import_react17.useCallback(() => {
273594
273629
  setInputValue("");
273595
273630
  }, []);
273596
273631
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(InputContext.Provider, {
@@ -273604,7 +273639,7 @@ function InputProvider({ children }) {
273604
273639
  }, undefined, false, undefined, this);
273605
273640
  }
273606
273641
  function useInput() {
273607
- const context2 = import_react16.useContext(InputContext);
273642
+ const context2 = import_react17.useContext(InputContext);
273608
273643
  if (!context2) {
273609
273644
  throw new Error("useInput must be used within InputProvider");
273610
273645
  }
@@ -273744,7 +273779,7 @@ function AgentStatus() {
273744
273779
  }
273745
273780
 
273746
273781
  // src/tui/context/command.tsx
273747
- var import_react17 = __toESM(require_react(), 1);
273782
+ var import_react18 = __toESM(require_react(), 1);
273748
273783
 
273749
273784
  // src/tui/command-router.ts
273750
273785
  class CommandRouter {
@@ -273756,8 +273791,8 @@ class CommandRouter {
273756
273791
  for (const n of names)
273757
273792
  this.nameToCommand.set(n, command);
273758
273793
  }
273759
- registerWithContext(definition, ctx3) {
273760
- const { handler, ...metadata } = definition(ctx3);
273794
+ registerWithContext(definition, ctx4) {
273795
+ const { handler, ...metadata } = definition(ctx4);
273761
273796
  this.register({
273762
273797
  ...metadata,
273763
273798
  handler: (args) => handler(args)
@@ -273781,14 +273816,14 @@ class CommandRouter {
273781
273816
  return { name: null, args };
273782
273817
  return { name: name26, args };
273783
273818
  }
273784
- async execute(input, ctx3) {
273819
+ async execute(input, ctx4) {
273785
273820
  const { name: name26, args } = this.parse(input);
273786
273821
  if (!name26)
273787
273822
  return false;
273788
273823
  const cmd = this.nameToCommand.get(name26);
273789
273824
  if (!cmd)
273790
273825
  return false;
273791
- await cmd.handler(args, ctx3);
273826
+ await cmd.handler(args, ctx4);
273792
273827
  return true;
273793
273828
  }
273794
273829
  }
@@ -274080,18 +274115,18 @@ var commands = [
274080
274115
  },
274081
274116
  { name: "--model", valueHint: "<model>", description: "AI model to use" }
274082
274117
  ],
274083
- handler: async (args, ctx3) => {
274118
+ handler: async (args, ctx4) => {
274084
274119
  const flags = parseWebFlags(args);
274085
274120
  if (flags.target && hasEnoughFlagsToSkipWizard(flags)) {
274086
274121
  const params = buildSwarmSessionConfig(flags);
274087
- ctx3.navigate({
274122
+ ctx4.navigate({
274088
274123
  type: "pentest",
274089
274124
  targets: params.targets,
274090
274125
  sessionConfig: params.config
274091
274126
  });
274092
274127
  return;
274093
274128
  }
274094
- ctx3.openPentestDialog?.({ auto: true, ...flags });
274129
+ ctx4.openPentestDialog?.({ auto: true, ...flags });
274095
274130
  }
274096
274131
  },
274097
274132
  {
@@ -274154,10 +274189,10 @@ var commands = [
274154
274189
  },
274155
274190
  { name: "--model", valueHint: "<model>", description: "AI model to use" }
274156
274191
  ],
274157
- handler: async (args, ctx3) => {
274192
+ handler: async (args, ctx4) => {
274158
274193
  const flags = parseWebFlags(args);
274159
274194
  const params = buildOperatorSessionConfig(flags);
274160
- ctx3.navigate({
274195
+ ctx4.navigate({
274161
274196
  type: "operator",
274162
274197
  nonce: Date.now(),
274163
274198
  initialConfig: {
@@ -274171,8 +274206,8 @@ var commands = [
274171
274206
  name: "help",
274172
274207
  description: "Show help dialog",
274173
274208
  category: "General",
274174
- handler: async (args, ctx3) => {
274175
- ctx3.navigate({
274209
+ handler: async (args, ctx4) => {
274210
+ ctx4.navigate({
274176
274211
  type: "base",
274177
274212
  path: "help"
274178
274213
  });
@@ -274182,8 +274217,8 @@ var commands = [
274182
274217
  name: "config",
274183
274218
  description: "Show config dialog",
274184
274219
  category: "General",
274185
- handler: async (args, ctx3) => {
274186
- ctx3.navigate({
274220
+ handler: async (args, ctx4) => {
274221
+ ctx4.navigate({
274187
274222
  type: "base",
274188
274223
  path: "config"
274189
274224
  });
@@ -274193,8 +274228,8 @@ var commands = [
274193
274228
  name: "models",
274194
274229
  description: "Show available AI models",
274195
274230
  category: "General",
274196
- handler: async (args, ctx3) => {
274197
- ctx3.navigate({
274231
+ handler: async (args, ctx4) => {
274232
+ ctx4.navigate({
274198
274233
  type: "base",
274199
274234
  path: "models"
274200
274235
  });
@@ -274204,8 +274239,8 @@ var commands = [
274204
274239
  name: "providers",
274205
274240
  description: "Manage AI providers and API keys",
274206
274241
  category: "General",
274207
- handler: async (args, ctx3) => {
274208
- ctx3.navigate({
274242
+ handler: async (args, ctx4) => {
274243
+ ctx4.navigate({
274209
274244
  type: "base",
274210
274245
  path: "providers"
274211
274246
  });
@@ -274216,16 +274251,16 @@ var commands = [
274216
274251
  aliases: ["s"],
274217
274252
  description: "Browse previous sessions",
274218
274253
  category: "Pentesting",
274219
- handler: async (_args, ctx3) => {
274220
- ctx3.openSessionsDialog?.();
274254
+ handler: async (_args, ctx4) => {
274255
+ ctx4.openSessionsDialog?.();
274221
274256
  }
274222
274257
  },
274223
274258
  {
274224
274259
  name: "new",
274225
274260
  description: "Start a new operator session",
274226
274261
  category: "Session",
274227
- handler: async (args, ctx3) => {
274228
- ctx3.navigate({ type: "operator", nonce: Date.now() });
274262
+ handler: async (args, ctx4) => {
274263
+ ctx4.navigate({ type: "operator", nonce: Date.now() });
274229
274264
  }
274230
274265
  },
274231
274266
  {
@@ -274234,8 +274269,8 @@ var commands = [
274234
274269
  description: "Open the Chat TUI interface",
274235
274270
  category: "General",
274236
274271
  hidden: true,
274237
- handler: async (args, ctx3) => {
274238
- ctx3.navigate({
274272
+ handler: async (args, ctx4) => {
274273
+ ctx4.navigate({
274239
274274
  type: "base",
274240
274275
  path: "home"
274241
274276
  });
@@ -274256,7 +274291,7 @@ var commands = [
274256
274291
  description: "Toggle or set dark/light mode (dark|light|auto)"
274257
274292
  }
274258
274293
  ],
274259
- handler: async (args, ctx3) => {
274294
+ handler: async (args, ctx4) => {
274260
274295
  if (args[0] === "mode") {
274261
274296
  const modeArg = args[1];
274262
274297
  if (modeArg === "dark" || modeArg === "light") {
@@ -274279,7 +274314,7 @@ var commands = [
274279
274314
  }
274280
274315
  return;
274281
274316
  }
274282
- ctx3.openThemeDialog?.();
274317
+ ctx4.openThemeDialog?.();
274283
274318
  }
274284
274319
  },
274285
274320
  {
@@ -274288,8 +274323,8 @@ var commands = [
274288
274323
  description: "View and manage active tools (session only)",
274289
274324
  category: "Session",
274290
274325
  hidden: true,
274291
- handler: async (args, ctx3) => {
274292
- if (ctx3.route.type !== "pentest") {
274326
+ handler: async (args, ctx4) => {
274327
+ if (ctx4.route.type !== "pentest") {
274293
274328
  return;
274294
274329
  }
274295
274330
  }
@@ -274307,8 +274342,8 @@ var commands = [
274307
274342
  name: "auth",
274308
274343
  description: "Connect to Pensar Console for managed inference",
274309
274344
  category: "General",
274310
- handler: async (args, ctx3) => {
274311
- ctx3.openAuthDialog?.();
274345
+ handler: async (args, ctx4) => {
274346
+ ctx4.openAuthDialog?.();
274312
274347
  }
274313
274348
  },
274314
274349
  {
@@ -274316,8 +274351,8 @@ var commands = [
274316
274351
  aliases: ["buy"],
274317
274352
  description: "Buy credits / check balance",
274318
274353
  category: "General",
274319
- handler: async (args, ctx3) => {
274320
- ctx3.navigate({
274354
+ handler: async (args, ctx4) => {
274355
+ ctx4.navigate({
274321
274356
  type: "base",
274322
274357
  path: "credits"
274323
274358
  });
@@ -274327,20 +274362,20 @@ var commands = [
274327
274362
  name: "create-skill",
274328
274363
  description: "Create a new operator skill",
274329
274364
  category: "Skills",
274330
- handler: async (args, ctx3) => {
274331
- ctx3.navigate({
274365
+ handler: async (args, ctx4) => {
274366
+ ctx4.navigate({
274332
274367
  type: "base",
274333
274368
  path: "create-skill"
274334
274369
  });
274335
274370
  }
274336
274371
  }
274337
274372
  ];
274338
- var commandRegistry = commands.map((config3) => (ctx3) => ({
274373
+ var commandRegistry = commands.map((config3) => (ctx4) => ({
274339
274374
  name: config3.name,
274340
274375
  aliases: config3.aliases,
274341
274376
  description: config3.description,
274342
274377
  handler: async (args) => {
274343
- await config3.handler(args, ctx3);
274378
+ await config3.handler(args, ctx4);
274344
274379
  }
274345
274380
  }));
274346
274381
 
@@ -274435,9 +274470,9 @@ async function skillExists(slug) {
274435
274470
  }
274436
274471
 
274437
274472
  // src/tui/context/command.tsx
274438
- var CommandContext = import_react17.createContext(null);
274473
+ var CommandContext = import_react18.createContext(null);
274439
274474
  function useCommand() {
274440
- const context2 = import_react17.useContext(CommandContext);
274475
+ const context2 = import_react18.useContext(CommandContext);
274441
274476
  if (!context2) {
274442
274477
  throw new Error("useCommand must be used within CommandProvider");
274443
274478
  }
@@ -274451,9 +274486,9 @@ function CommandProvider({
274451
274486
  onOpenPentestDialog
274452
274487
  }) {
274453
274488
  const route = useRoute();
274454
- const [skills, setSkills] = import_react17.useState([]);
274455
- const ctx3 = import_react17.useMemo(() => {
274456
- const ctx4 = {
274489
+ const [skills, setSkills] = import_react18.useState([]);
274490
+ const ctx4 = import_react18.useMemo(() => {
274491
+ const ctx5 = {
274457
274492
  route: route.data,
274458
274493
  navigate: route.navigate,
274459
274494
  openSessionsDialog: onOpenSessionsDialog,
@@ -274461,7 +274496,7 @@ function CommandProvider({
274461
274496
  openAuthDialog: onOpenAuthDialog,
274462
274497
  openPentestDialog: onOpenPentestDialog
274463
274498
  };
274464
- return ctx4;
274499
+ return ctx5;
274465
274500
  }, [
274466
274501
  route,
274467
274502
  onOpenSessionsDialog,
@@ -274469,33 +274504,33 @@ function CommandProvider({
274469
274504
  onOpenAuthDialog,
274470
274505
  onOpenPentestDialog
274471
274506
  ]);
274472
- const refreshSkills = import_react17.useCallback(async () => {
274507
+ const refreshSkills = import_react18.useCallback(async () => {
274473
274508
  const loaded = await loadSkills();
274474
274509
  setSkills(loaded);
274475
274510
  }, []);
274476
- import_react17.useEffect(() => {
274511
+ import_react18.useEffect(() => {
274477
274512
  refreshSkills();
274478
274513
  }, [route.data]);
274479
- const router = import_react17.useMemo(() => {
274514
+ const router = import_react18.useMemo(() => {
274480
274515
  const router2 = new CommandRouter;
274481
274516
  for (const commandDef of commandRegistry) {
274482
- router2.registerWithContext(commandDef, ctx3);
274517
+ router2.registerWithContext(commandDef, ctx4);
274483
274518
  }
274484
274519
  return router2;
274485
274520
  }, []);
274486
- const skillSlugMap = import_react17.useMemo(() => {
274521
+ const skillSlugMap = import_react18.useMemo(() => {
274487
274522
  const map2 = new Map;
274488
274523
  for (const skill of skills) {
274489
274524
  map2.set(slugify(skill.name), skill);
274490
274525
  }
274491
274526
  return map2;
274492
274527
  }, [skills]);
274493
- const resolveSkillContent = import_react17.useCallback((input) => {
274528
+ const resolveSkillContent = import_react18.useCallback((input) => {
274494
274529
  const trimmed = input.trim().replace(/^\/+/, "").toLowerCase();
274495
274530
  const skill = skillSlugMap.get(trimmed);
274496
274531
  return skill?.content ?? null;
274497
274532
  }, [skillSlugMap]);
274498
- const autocompleteOptions = import_react17.useMemo(() => {
274533
+ const autocompleteOptions = import_react18.useMemo(() => {
274499
274534
  const routerCommands = router.getAllCommands();
274500
274535
  const options = [];
274501
274536
  for (const cmd of routerCommands) {
@@ -274539,10 +274574,10 @@ function CommandProvider({
274539
274574
  return a.value.localeCompare(b2.value);
274540
274575
  });
274541
274576
  }, [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(() => ({
274577
+ const executeCommand = import_react18.useCallback(async (input) => {
274578
+ return await router.execute(input, ctx4);
274579
+ }, [router, ctx4]);
274580
+ const value = import_react18.useMemo(() => ({
274546
274581
  router,
274547
274582
  autocompleteOptions,
274548
274583
  executeCommand,
@@ -274565,24 +274600,24 @@ function CommandProvider({
274565
274600
  }
274566
274601
 
274567
274602
  // src/tui/components/commands/sessions-display.tsx
274568
- var import_react24 = __toESM(require_react(), 1);
274603
+ var import_react25 = __toESM(require_react(), 1);
274569
274604
 
274570
274605
  // src/tui/context/focus.tsx
274571
- var import_react18 = __toESM(require_react(), 1);
274572
- var FocusContext = import_react18.createContext(undefined);
274606
+ var import_react19 = __toESM(require_react(), 1);
274607
+ var FocusContext = import_react19.createContext(undefined);
274573
274608
  function FocusProvider({ children }) {
274574
- const promptRef = import_react18.useRef(null);
274575
- const refocusPrompt = import_react18.useCallback(() => {
274609
+ const promptRef = import_react19.useRef(null);
274610
+ const refocusPrompt = import_react19.useCallback(() => {
274576
274611
  setTimeout(() => {
274577
274612
  promptRef.current?.focus();
274578
274613
  }, 1);
274579
274614
  }, []);
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) => {
274615
+ const focusPrompt = import_react19.useCallback(() => promptRef.current?.focus(), []);
274616
+ const blurPrompt = import_react19.useCallback(() => promptRef.current?.blur(), []);
274617
+ const resetPrompt = import_react19.useCallback(() => promptRef.current?.reset(), []);
274618
+ const setPromptValue = import_react19.useCallback((value) => promptRef.current?.setValue(value), []);
274619
+ const getPromptValue = import_react19.useCallback(() => promptRef.current?.getValue() ?? "", []);
274620
+ const registerPromptRef = import_react19.useCallback((ref) => {
274586
274621
  promptRef.current = ref;
274587
274622
  }, []);
274588
274623
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FocusContext.Provider, {
@@ -274600,7 +274635,7 @@ function FocusProvider({ children }) {
274600
274635
  }, undefined, false, undefined, this);
274601
274636
  }
274602
274637
  function useFocus() {
274603
- const context2 = import_react18.useContext(FocusContext);
274638
+ const context2 = import_react19.useContext(FocusContext);
274604
274639
  if (!context2) {
274605
274640
  throw new Error("useFocus must be used within FocusProvider");
274606
274641
  }
@@ -274635,8 +274670,8 @@ function openSessionReport(sessionRootPath) {
274635
274670
  }
274636
274671
 
274637
274672
  // src/tui/context/dimensions.tsx
274638
- var import_react19 = __toESM(require_react(), 1);
274639
- var DimensionsContext = import_react19.createContext(null);
274673
+ var import_react20 = __toESM(require_react(), 1);
274674
+ var DimensionsContext = import_react20.createContext(null);
274640
274675
  function TerminalDimensionsProvider({
274641
274676
  children
274642
274677
  }) {
@@ -274647,14 +274682,14 @@ function TerminalDimensionsProvider({
274647
274682
  }, undefined, false, undefined, this);
274648
274683
  }
274649
274684
  function useDimensions() {
274650
- const ctx3 = import_react19.useContext(DimensionsContext);
274651
- if (!ctx3)
274685
+ const ctx4 = import_react20.useContext(DimensionsContext);
274686
+ if (!ctx4)
274652
274687
  throw new Error("useDimensions() must be used within <TerminalDimensionsProvider>");
274653
- return ctx3;
274688
+ return ctx4;
274654
274689
  }
274655
274690
 
274656
274691
  // src/tui/context/dialog.tsx
274657
- var import_react22 = __toESM(require_react(), 1);
274692
+ var import_react23 = __toESM(require_react(), 1);
274658
274693
  function Dialog({ size = "medium", onClose, children }) {
274659
274694
  const dimensions = useDimensions();
274660
274695
  const renderer = useRenderer();
@@ -274691,14 +274726,14 @@ function Dialog({ size = "medium", onClose, children }) {
274691
274726
  }, undefined, false, undefined, this)
274692
274727
  }, undefined, false, undefined, this);
274693
274728
  }
274694
- var DialogContext = import_react22.createContext(null);
274729
+ var DialogContext = import_react23.createContext(null);
274695
274730
  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);
274731
+ const [stack, setStack] = import_react23.useState([]);
274732
+ const [size, setSize] = import_react23.useState("medium");
274733
+ const [externalDialogOpen, setExternalDialogOpen] = import_react23.useState(false);
274699
274734
  const renderer = useRenderer();
274700
- const focusRef = import_react22.useRef(null);
274701
- const refocus = import_react22.useCallback(() => {
274735
+ const focusRef = import_react23.useRef(null);
274736
+ const refocus = import_react23.useCallback(() => {
274702
274737
  setTimeout(() => {
274703
274738
  const focus = focusRef.current;
274704
274739
  if (!focus)
@@ -274720,7 +274755,7 @@ function DialogProvider({ children }) {
274720
274755
  focus.focus();
274721
274756
  }, 1);
274722
274757
  }, [renderer]);
274723
- const clear = import_react22.useCallback(() => {
274758
+ const clear = import_react23.useCallback(() => {
274724
274759
  for (const item of stack) {
274725
274760
  if (item.onClose)
274726
274761
  item.onClose();
@@ -274729,7 +274764,7 @@ function DialogProvider({ children }) {
274729
274764
  setStack([]);
274730
274765
  refocus();
274731
274766
  }, [stack, refocus]);
274732
- const replace = import_react22.useCallback((element, onClose) => {
274767
+ const replace = import_react23.useCallback((element, onClose) => {
274733
274768
  if (stack.length === 0) {
274734
274769
  focusRef.current = renderer.currentFocusedRenderable;
274735
274770
  }
@@ -274774,7 +274809,7 @@ function DialogProvider({ children }) {
274774
274809
  }, undefined, true, undefined, this);
274775
274810
  }
274776
274811
  function useDialog() {
274777
- const value = import_react22.useContext(DialogContext);
274812
+ const value = import_react23.useContext(DialogContext);
274778
274813
  if (!value) {
274779
274814
  throw new Error("useDialog must be used within a DialogProvider");
274780
274815
  }
@@ -274839,7 +274874,7 @@ function findChildById(scrollBox, id) {
274839
274874
  // src/tui/hooks/use-sessions-list.ts
274840
274875
  init_session();
274841
274876
  init_report();
274842
- var import_react23 = __toESM(require_react(), 1);
274877
+ var import_react24 = __toESM(require_react(), 1);
274843
274878
  import { existsSync as existsSync7, readdirSync } from "fs";
274844
274879
  import { join as join3 } from "path";
274845
274880
  function countFindings(findingsPath) {
@@ -274855,10 +274890,10 @@ function checkHasReport(rootPath) {
274855
274890
  return existsSync7(join3(rootPath, REPORT_FILENAME_MD));
274856
274891
  }
274857
274892
  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 () => {
274893
+ const [allSessions, setAllSessions] = import_react24.useState([]);
274894
+ const [loading, setLoading] = import_react24.useState(true);
274895
+ const [searchTerm, setSearchTerm] = import_react24.useState("");
274896
+ const loadSessions = import_react24.useCallback(async () => {
274862
274897
  setLoading(true);
274863
274898
  try {
274864
274899
  const enriched = [];
@@ -274881,10 +274916,10 @@ function useSessionsList() {
274881
274916
  setLoading(false);
274882
274917
  }
274883
274918
  }, []);
274884
- import_react23.useEffect(() => {
274919
+ import_react24.useEffect(() => {
274885
274920
  loadSessions();
274886
274921
  }, [loadSessions]);
274887
- const deleteSession = import_react23.useCallback(async (id) => {
274922
+ const deleteSession = import_react24.useCallback(async (id) => {
274888
274923
  await sessions.remove({ sessionId: id });
274889
274924
  await loadSessions();
274890
274925
  }, [loadSessions]);
@@ -274943,10 +274978,10 @@ function useSessionsList() {
274943
274978
  function SessionsDisplay({ onClose }) {
274944
274979
  const { colors: colors2 } = useTheme();
274945
274980
  const { refocusPrompt } = useFocus();
274946
- const [selectedIndex, setSelectedIndex] = import_react24.useState(0);
274947
- const [statusMessage, setStatusMessage] = import_react24.useState("");
274981
+ const [selectedIndex, setSelectedIndex] = import_react25.useState(0);
274982
+ const [statusMessage, setStatusMessage] = import_react25.useState("");
274948
274983
  const route = useRoute();
274949
- const scroll = import_react24.useRef(null);
274984
+ const scroll = import_react25.useRef(null);
274950
274985
  const {
274951
274986
  groupedSessions,
274952
274987
  visualOrderSessions,
@@ -274962,7 +274997,7 @@ function SessionsDisplay({ onClose }) {
274962
274997
  setTimeout(() => setStatusMessage(""), 2000);
274963
274998
  }
274964
274999
  }
274965
- import_react24.useEffect(() => {
275000
+ import_react25.useEffect(() => {
274966
275001
  if (visualOrderSessions.length > 0 && selectedIndex >= visualOrderSessions.length) {
274967
275002
  setSelectedIndex(visualOrderSessions.length - 1);
274968
275003
  } else if (visualOrderSessions.length === 0) {
@@ -275244,7 +275279,7 @@ function SessionsDisplay({ onClose }) {
275244
275279
  }
275245
275280
 
275246
275281
  // src/tui/components/commands/config-dialog.tsx
275247
- var import_react27 = __toESM(require_react(), 1);
275282
+ var import_react28 = __toESM(require_react(), 1);
275248
275283
 
275249
275284
  // src/tui/components/alert-dialog.tsx
275250
275285
  function AlertDialog({
@@ -275331,8 +275366,8 @@ function AlertDialog({
275331
275366
  init_config2();
275332
275367
  function ConfigDialog() {
275333
275368
  const route = useRoute();
275334
- const [open, setOpen] = import_react27.useState(false);
275335
- import_react27.useEffect(() => {
275369
+ const [open, setOpen] = import_react28.useState(false);
275370
+ import_react28.useEffect(() => {
275336
275371
  if (route.data.type === "base" && route.data.path === "config") {
275337
275372
  setOpen(true);
275338
275373
  } else {
@@ -275346,8 +275381,8 @@ function ConfigDialog() {
275346
275381
  path: "home"
275347
275382
  });
275348
275383
  };
275349
- const [appConfig, setAppConfig] = import_react27.useState(null);
275350
- import_react27.useEffect(() => {
275384
+ const [appConfig, setAppConfig] = import_react28.useState(null);
275385
+ import_react28.useEffect(() => {
275351
275386
  async function getConfig() {
275352
275387
  const _appConfig = await config2.get();
275353
275388
  setAppConfig(_appConfig);
@@ -275420,39 +275455,6 @@ function ConfigForm({ appConfig }) {
275420
275455
  init_session();
275421
275456
  var import_react38 = __toESM(require_react(), 1);
275422
275457
 
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
275458
  // src/tui/components/chat/home-view.tsx
275457
275459
  var import_react33 = __toESM(require_react(), 1);
275458
275460
 
@@ -276915,18 +276917,25 @@ function ConfigView({ config: config3, onBack, onStart }) {
276915
276917
  const { colors: colors2 } = useTheme();
276916
276918
  const [targetUrl, setTargetUrl] = import_react36.useState("https://");
276917
276919
  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"
276920
+ const [selectedModel, setSelectedModel] = import_react36.useState(() => {
276921
+ if (config3) {
276922
+ const dynamicDefault = getDefaultModelForConfig(config3);
276923
+ if (dynamicDefault)
276924
+ return dynamicDefault;
276925
+ }
276926
+ return {
276927
+ id: "claude-sonnet-4-20250514",
276928
+ name: "Claude Sonnet 4",
276929
+ provider: "anthropic"
276930
+ };
276922
276931
  });
276923
276932
  const [isModelUserSelected, setIsModelUserSelected] = import_react36.useState(false);
276924
276933
  const [focusedField, setFocusedField] = import_react36.useState("url");
276925
276934
  import_react36.useEffect(() => {
276926
- if (config3) {
276935
+ if (config3 && !isModelUserSelected) {
276927
276936
  const models = getAvailableModels(config3);
276928
- if (models.length > 0 && !isModelUserSelected) {
276929
- const defaultModel = models.find((m2) => m2.provider === "anthropic") || models[0];
276937
+ if (models.length > 0) {
276938
+ const defaultModel = getDefaultModelForConfig(config3) ?? models[0];
276930
276939
  setSelectedModel(defaultModel);
276931
276940
  }
276932
276941
  }
@@ -278643,6 +278652,142 @@ function WebWizard({
278643
278652
  // src/tui/components/commands/provider-manager.tsx
278644
278653
  var import_react50 = __toESM(require_react(), 1);
278645
278654
  init_config2();
278655
+ // src/core/providers/verify.ts
278656
+ var VERIFY_TIMEOUT_MS = 15000;
278657
+ async function fetchWithTimeout(url2, init2) {
278658
+ const controller = new AbortController;
278659
+ const timer = setTimeout(() => controller.abort(), VERIFY_TIMEOUT_MS);
278660
+ try {
278661
+ return await fetch(url2, { ...init2, signal: controller.signal });
278662
+ } finally {
278663
+ clearTimeout(timer);
278664
+ }
278665
+ }
278666
+ async function verifyAnthropic(apiKey) {
278667
+ try {
278668
+ const res = await fetchWithTimeout("https://api.anthropic.com/v1/models", {
278669
+ method: "GET",
278670
+ headers: {
278671
+ "x-api-key": apiKey,
278672
+ "anthropic-version": "2023-06-01"
278673
+ }
278674
+ });
278675
+ if (res.ok)
278676
+ return { valid: true };
278677
+ if (res.status === 401)
278678
+ return { valid: false, error: "Invalid API key" };
278679
+ return {
278680
+ valid: false,
278681
+ error: `Anthropic returned HTTP ${res.status}`
278682
+ };
278683
+ } catch (err) {
278684
+ return {
278685
+ valid: false,
278686
+ error: err instanceof DOMException && err.name === "AbortError" ? "Request timed out" : "Could not reach Anthropic API"
278687
+ };
278688
+ }
278689
+ }
278690
+ async function verifyOpenAI(apiKey) {
278691
+ try {
278692
+ const res = await fetchWithTimeout("https://api.openai.com/v1/models", {
278693
+ method: "GET",
278694
+ headers: { Authorization: `Bearer ${apiKey}` }
278695
+ });
278696
+ if (res.ok)
278697
+ return { valid: true };
278698
+ if (res.status === 401)
278699
+ return { valid: false, error: "Invalid API key" };
278700
+ return {
278701
+ valid: false,
278702
+ error: `OpenAI returned HTTP ${res.status}`
278703
+ };
278704
+ } catch (err) {
278705
+ return {
278706
+ valid: false,
278707
+ error: err instanceof DOMException && err.name === "AbortError" ? "Request timed out" : "Could not reach OpenAI API"
278708
+ };
278709
+ }
278710
+ }
278711
+ async function verifyGoogle(apiKey) {
278712
+ try {
278713
+ const res = await fetchWithTimeout(`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(apiKey)}`, { method: "GET" });
278714
+ if (res.ok)
278715
+ return { valid: true };
278716
+ if (res.status === 400 || res.status === 403)
278717
+ return { valid: false, error: "Invalid API key" };
278718
+ return {
278719
+ valid: false,
278720
+ error: `Google returned HTTP ${res.status}`
278721
+ };
278722
+ } catch (err) {
278723
+ return {
278724
+ valid: false,
278725
+ error: err instanceof DOMException && err.name === "AbortError" ? "Request timed out" : "Could not reach Google AI API"
278726
+ };
278727
+ }
278728
+ }
278729
+ async function verifyOpenRouter(apiKey) {
278730
+ try {
278731
+ const res = await fetchWithTimeout("https://openrouter.ai/api/v1/auth/key", {
278732
+ method: "GET",
278733
+ headers: { Authorization: `Bearer ${apiKey}` }
278734
+ });
278735
+ if (res.ok)
278736
+ return { valid: true };
278737
+ if (res.status === 401 || res.status === 403)
278738
+ return { valid: false, error: "Invalid API key" };
278739
+ return {
278740
+ valid: false,
278741
+ error: `OpenRouter returned HTTP ${res.status}`
278742
+ };
278743
+ } catch (err) {
278744
+ return {
278745
+ valid: false,
278746
+ error: err instanceof DOMException && err.name === "AbortError" ? "Request timed out" : "Could not reach OpenRouter API"
278747
+ };
278748
+ }
278749
+ }
278750
+ async function verifyInception(apiKey) {
278751
+ try {
278752
+ const res = await fetchWithTimeout("https://api.inceptionlabs.ai/v1/models", {
278753
+ method: "GET",
278754
+ headers: { Authorization: `Bearer ${apiKey}` }
278755
+ });
278756
+ if (res.ok)
278757
+ return { valid: true };
278758
+ if (res.status === 401 || res.status === 403)
278759
+ return { valid: false, error: "Invalid API key" };
278760
+ return {
278761
+ valid: false,
278762
+ error: `Inception returned HTTP ${res.status}`
278763
+ };
278764
+ } catch (err) {
278765
+ return {
278766
+ valid: false,
278767
+ error: err instanceof DOMException && err.name === "AbortError" ? "Request timed out" : "Could not reach Inception API"
278768
+ };
278769
+ }
278770
+ }
278771
+ async function verifyApiKey(provider, apiKey) {
278772
+ switch (provider) {
278773
+ case "anthropic":
278774
+ return verifyAnthropic(apiKey);
278775
+ case "openai":
278776
+ return verifyOpenAI(apiKey);
278777
+ case "google":
278778
+ return verifyGoogle(apiKey);
278779
+ case "openrouter":
278780
+ return verifyOpenRouter(apiKey);
278781
+ case "inception":
278782
+ return verifyInception(apiKey);
278783
+ case "bedrock":
278784
+ case "local":
278785
+ case "pensar":
278786
+ return { valid: true };
278787
+ default:
278788
+ return { valid: true };
278789
+ }
278790
+ }
278646
278791
  // src/tui/components/commands/provider-selection.tsx
278647
278792
  var import_react45 = __toESM(require_react(), 1);
278648
278793
  function ProviderSelection({
@@ -278816,12 +278961,30 @@ function APIKeyInput({
278816
278961
  }) {
278817
278962
  const { colors: colors2 } = useTheme();
278818
278963
  const [apiKey, setApiKey] = import_react47.useState("");
278964
+ const [verifyState, setVerifyState] = import_react47.useState("idle");
278965
+ const [errorMessage, setErrorMessage] = import_react47.useState("");
278819
278966
  useKeyboard((key) => {
278820
278967
  if (key.name === "escape") {
278968
+ if (verifyState === "verifying")
278969
+ return;
278821
278970
  onCancel();
278822
278971
  return;
278823
278972
  }
278824
278973
  });
278974
+ const handleSubmit = async () => {
278975
+ const key = apiKey.trim();
278976
+ if (!key || verifyState === "verifying")
278977
+ return;
278978
+ setVerifyState("verifying");
278979
+ setErrorMessage("");
278980
+ const result = await verifyApiKey(provider, key);
278981
+ if (result.valid) {
278982
+ onSubmit(key);
278983
+ } else {
278984
+ setVerifyState("error");
278985
+ setErrorMessage(result.error ?? "Invalid API key");
278986
+ }
278987
+ };
278825
278988
  const getProviderInstructions = (provider2) => {
278826
278989
  switch (provider2) {
278827
278990
  case "anthropic":
@@ -278834,8 +278997,6 @@ function APIKeyInput({
278834
278997
  return "Get your API key from openrouter.ai/keys";
278835
278998
  case "bedrock":
278836
278999
  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
279000
  default:
278840
279001
  return "Enter your API key";
278841
279002
  }
@@ -278889,20 +279050,32 @@ function APIKeyInput({
278889
279050
  label: "API Key",
278890
279051
  description: "Your API key will be stored locally in ~/.pensar/config.json",
278891
279052
  value: apiKey,
278892
- focused: true,
279053
+ focused: verifyState !== "verifying",
278893
279054
  onChange: (value) => setApiKey(typeof value === "string" ? value : ""),
278894
279055
  onPaste: (event) => {
278895
279056
  const cleaned = String(event.text);
278896
279057
  setApiKey((prev) => `${prev}${cleaned}`);
278897
279058
  },
278898
- onSubmit: () => {
278899
- const key = apiKey.trim();
278900
- if (key) {
278901
- onSubmit(key);
278902
- }
278903
- }
279059
+ onSubmit: handleSubmit
278904
279060
  }, undefined, false, undefined, this)
278905
279061
  }, undefined, false, undefined, this),
279062
+ verifyState === "verifying" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
279063
+ marginBottom: 1,
279064
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
279065
+ fg: colors2.textMuted,
279066
+ children: "Verifying API key..."
279067
+ }, undefined, false, undefined, this)
279068
+ }, undefined, false, undefined, this),
279069
+ verifyState === "error" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
279070
+ marginBottom: 1,
279071
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
279072
+ fg: colors2.error,
279073
+ children: [
279074
+ "✗ ",
279075
+ errorMessage
279076
+ ]
279077
+ }, undefined, true, undefined, this)
279078
+ }, undefined, false, undefined, this),
278906
279079
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
278907
279080
  marginTop: 1,
278908
279081
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
@@ -279588,7 +279761,11 @@ function ProviderManager() {
279588
279761
  const [selectedProvider, setSelectedProvider] = import_react50.useState(null);
279589
279762
  const handleProviderSelected = (providerId) => {
279590
279763
  setSelectedProvider(providerId);
279591
- setFlowState("inputting");
279764
+ if (providerId === "pensar") {
279765
+ setFlowState("auth");
279766
+ } else {
279767
+ setFlowState("inputting");
279768
+ }
279592
279769
  };
279593
279770
  const handleAPIKeySubmit = async (apiKey) => {
279594
279771
  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-canary.e76e131d",
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",