@pensar/apex 0.0.99 → 0.0.100-canary.ba3e689f

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.99",
11
+ version: "0.0.100-canary.ba3e689f",
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.99",
31974
+ version: "0.0.100-canary.ba3e689f",
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",
@@ -194042,7 +194036,7 @@ function createAllTools(ctx4) {
194042
194036
  get_page: getPage(ctx4)
194043
194037
  };
194044
194038
  }
194045
- var ALL_TOOL_NAMES;
194039
+ var ALL_TOOL_NAMES, PLAN_MODE_TOOL_NAMES;
194046
194040
  var init_tools = __esm(() => {
194047
194041
  init_browserTools();
194048
194042
  init_sandboxPlaywright();
@@ -194151,6 +194145,40 @@ var init_tools = __esm(() => {
194151
194145
  "web_search",
194152
194146
  "get_page"
194153
194147
  ];
194148
+ PLAN_MODE_TOOL_NAMES = [
194149
+ "browser_navigate",
194150
+ "browser_snapshot",
194151
+ "browser_screenshot",
194152
+ "browser_click",
194153
+ "browser_fill",
194154
+ "browser_evaluate",
194155
+ "browser_console",
194156
+ "browser_get_cookies",
194157
+ "execute_command",
194158
+ "http_request",
194159
+ "read_file",
194160
+ "list_files",
194161
+ "grep",
194162
+ "authenticate_session",
194163
+ "delegate_to_auth_subagent",
194164
+ "create_attack_surface_report",
194165
+ "complete_authentication",
194166
+ "run_attack_surface",
194167
+ "spawn_pentest_swarm",
194168
+ "spawn_coding_agent",
194169
+ "provide_comparison_results",
194170
+ "add_memory",
194171
+ "list_memories",
194172
+ "get_memory",
194173
+ "email_list_inboxes",
194174
+ "email_list_messages",
194175
+ "email_get_message",
194176
+ "email_search_messages",
194177
+ "email_get_attachments",
194178
+ "email_mark_read",
194179
+ "web_search",
194180
+ "get_page"
194181
+ ];
194154
194182
  });
194155
194183
 
194156
194184
  // src/core/agents/offSecAgent/tools/response.ts
@@ -194892,7 +194920,11 @@ var init_offensiveSecurityAgent = __esm(() => {
194892
194920
  }
194893
194921
  const hasEmail = (input.session.config?.emailIntegration?.inboxes?.length ?? 0) > 0;
194894
194922
  const emailToolSet = new Set(EMAIL_TOOL_NAMES);
194895
- const activeTools = hasEmail ? input.activeTools : input.activeTools.filter((t3) => !emailToolSet.has(t3));
194923
+ let activeTools = hasEmail ? input.activeTools : input.activeTools.filter((t3) => !emailToolSet.has(t3));
194924
+ if (input.mode === "plan") {
194925
+ const planSet = new Set(PLAN_MODE_TOOL_NAMES);
194926
+ activeTools = activeTools.filter((t3) => planSet.has(t3));
194927
+ }
194896
194928
  const messagesDir = input.messagesDir ?? input.session.rootPath;
194897
194929
  if (!existsSync21(messagesDir)) {
194898
194930
  mkdirSync10(messagesDir, { recursive: true });
@@ -276318,6 +276350,37 @@ var providerOrder = [
276318
276350
  "bedrock",
276319
276351
  "local"
276320
276352
  ];
276353
+ function setsAreEqual(a, b2) {
276354
+ return a.size === b2.size && [...a].every((value) => b2.has(value));
276355
+ }
276356
+ function PickerRow({
276357
+ children,
276358
+ id,
276359
+ paddingLeft,
276360
+ paddingRight,
276361
+ backgroundColor,
276362
+ flexDirection = "row",
276363
+ gap = 0
276364
+ }) {
276365
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
276366
+ id,
276367
+ width: "100%",
276368
+ overflow: "hidden",
276369
+ flexDirection,
276370
+ paddingLeft,
276371
+ paddingRight,
276372
+ backgroundColor,
276373
+ gap,
276374
+ children
276375
+ }, undefined, false, undefined, this);
276376
+ }
276377
+ function getNavItemId(item) {
276378
+ if (item.type === "provider")
276379
+ return `provider-${item.provider}`;
276380
+ if (item.type === "model")
276381
+ return `model-${item.model.id}`;
276382
+ return `local-input-${item.field}`;
276383
+ }
276321
276384
  function ModelPicker({
276322
276385
  config: config3,
276323
276386
  selectedModel,
@@ -276328,6 +276391,7 @@ function ModelPicker({
276328
276391
  isModelUserSelected = false
276329
276392
  }) {
276330
276393
  const { colors: colors2 } = useTheme();
276394
+ const scrollBoxRef = import_react34.useRef(null);
276331
276395
  const [availableModels, setAvailableModels] = import_react34.useState([]);
276332
276396
  const [searchQuery, setSearchQuery] = import_react34.useState("");
276333
276397
  const [expandedProviders, setExpandedProviders] = import_react34.useState(new Set(["anthropic"]));
@@ -276340,17 +276404,29 @@ function ModelPicker({
276340
276404
  setLocalModelName(config3?.localModelName ?? "");
276341
276405
  }, [config3?.localModelUrl, config3?.localModelName]);
276342
276406
  import_react34.useEffect(() => {
276343
- if (config3) {
276344
- const models = getAvailableModels(config3);
276345
- setAvailableModels(models);
276346
- if (models.length > 0) {
276347
- const currentModel = models.find((m2) => m2.id === selectedModel.id) || models[0];
276348
- if (currentModel) {
276349
- setExpandedProviders(new Set([currentModel.provider]));
276350
- }
276351
- }
276407
+ if (!config3) {
276408
+ setAvailableModels([]);
276409
+ return;
276352
276410
  }
276353
- }, [config3, selectedModel.id]);
276411
+ setAvailableModels(getAvailableModels(config3));
276412
+ }, [config3]);
276413
+ import_react34.useEffect(() => {
276414
+ const availableProviders = new Set(availableModels.map((model) => model.provider));
276415
+ setExpandedProviders((prev) => {
276416
+ if (availableProviders.size === 0) {
276417
+ return prev.size === 0 ? prev : new Set;
276418
+ }
276419
+ const preservedProviders = new Set([...prev].filter((provider) => availableProviders.has(provider)));
276420
+ if (preservedProviders.size > 0) {
276421
+ return setsAreEqual(prev, preservedProviders) ? prev : preservedProviders;
276422
+ }
276423
+ const fallbackProvider = availableProviders.has(selectedModel.provider) ? selectedModel.provider : availableModels[0]?.provider;
276424
+ if (!fallbackProvider) {
276425
+ return prev.size === 0 ? prev : new Set;
276426
+ }
276427
+ return prev.size === 1 && prev.has(fallbackProvider) ? prev : new Set([fallbackProvider]);
276428
+ });
276429
+ }, [availableModels, selectedModel.provider]);
276354
276430
  const groupedModels = import_react34.useMemo(() => {
276355
276431
  const groups = {};
276356
276432
  const query = searchQuery.toLowerCase().trim();
@@ -276403,6 +276479,12 @@ function ModelPicker({
276403
276479
  import_react34.useEffect(() => {
276404
276480
  setFocusedIndex((prev) => Math.min(prev, Math.max(0, navigationItems.length - 1)));
276405
276481
  }, [navigationItems.length]);
276482
+ import_react34.useEffect(() => {
276483
+ const item = navigationItems[focusedIndex];
276484
+ if (!item)
276485
+ return;
276486
+ scrollToChild(scrollBoxRef.current, getNavItemId(item));
276487
+ }, [focusedIndex, navigationItems]);
276406
276488
  const commitLocalConfig = import_react34.useCallback((url2, modelName) => {
276407
276489
  if (!onConfigUpdate)
276408
276490
  return;
@@ -276510,169 +276592,206 @@ function ModelPicker({
276510
276592
  useKeyboard((key) => {
276511
276593
  handleKeyboard(key);
276512
276594
  });
276595
+ const isProviderFocused = (provider) => navigationItems[focusedIndex]?.type === "provider" && navigationItems[focusedIndex].provider === provider;
276596
+ const isModelFocused = (modelId) => navigationItems[focusedIndex]?.type === "model" && navigationItems[focusedIndex].model.id === modelId;
276597
+ const isLocalFieldFocused = (field) => navigationItems[focusedIndex]?.type === "local-input" && navigationItems[focusedIndex].field === field;
276513
276598
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
276514
276599
  flexDirection: "column",
276515
276600
  gap: 0,
276601
+ width: "100%",
276602
+ flexGrow: 1,
276603
+ flexShrink: 1,
276604
+ overflow: "hidden",
276516
276605
  children: [
276517
- searchQuery ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276518
- fg: colors2.text,
276519
- children: [
276520
- "Search: ",
276521
- searchQuery,
276522
- "_"
276523
- ]
276524
- }, undefined, true, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276525
- fg: colors2.textMuted,
276526
- children: "Type to search models..."
276606
+ searchQuery ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PickerRow, {
276607
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276608
+ fg: colors2.text,
276609
+ children: [
276610
+ "Search: ",
276611
+ searchQuery
276612
+ ]
276613
+ }, undefined, true, undefined, this)
276614
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PickerRow, {
276615
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276616
+ fg: colors2.textMuted,
276617
+ children: "Type to search models..."
276618
+ }, undefined, false, undefined, this)
276527
276619
  }, undefined, false, undefined, this),
276528
- providerOrder.map((provider) => {
276529
- const isExpanded = expandedProviders.has(provider);
276530
- const providerName = providerNames[provider] || provider;
276531
- const isProviderFocused = navigationItems[focusedIndex]?.type === "provider" && navigationItems[focusedIndex].provider === provider;
276532
- if (provider === "local") {
276533
- const localModels = groupedModels["local"];
276534
- const modelCount = localModels?.length ?? 0;
276535
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
276536
- flexDirection: "column",
276537
- gap: 0,
276538
- children: [
276539
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276540
- fg: isProviderFocused ? colors2.primary : isExpanded ? colors2.text : colors2.textMuted,
276620
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("scrollbox", {
276621
+ ref: scrollBoxRef,
276622
+ style: {
276623
+ rootOptions: {
276624
+ flexGrow: 1,
276625
+ flexShrink: 1,
276626
+ width: "100%",
276627
+ overflow: "hidden"
276628
+ },
276629
+ contentOptions: {
276630
+ flexDirection: "column"
276631
+ },
276632
+ scrollbarOptions: {
276633
+ visible: false
276634
+ }
276635
+ },
276636
+ stickyScroll: false,
276637
+ children: providerOrder.flatMap((provider) => {
276638
+ const isExpanded = expandedProviders.has(provider);
276639
+ const providerName = providerNames[provider] || provider;
276640
+ const isFocused = isProviderFocused(provider);
276641
+ if (provider === "local") {
276642
+ const localModels = groupedModels["local"];
276643
+ const modelCount = localModels?.length ?? 0;
276644
+ const elements2 = [];
276645
+ elements2.push(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PickerRow, {
276646
+ id: "provider-local",
276647
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276648
+ fg: isFocused ? colors2.primary : isExpanded ? colors2.text : colors2.textMuted,
276541
276649
  children: [
276542
- isProviderFocused ? "❯" : isExpanded ? "▾" : "▸",
276650
+ isFocused ? "❯" : isExpanded ? "▾" : "▸",
276543
276651
  " ",
276544
276652
  providerName,
276545
276653
  modelCount > 0 ? ` (${modelCount})` : ""
276546
276654
  ]
276547
- }, undefined, true, undefined, this),
276548
- isExpanded && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
276549
- flexDirection: "column",
276550
- gap: 0,
276551
- paddingLeft: 2,
276552
- children: [
276553
- (() => {
276554
- const isUrlFocused = navigationItems[focusedIndex]?.type === "local-input" && navigationItems[focusedIndex].field === "url";
276555
- const isUrlEditing = editingLocalField === "url";
276556
- if (isUrlEditing) {
276557
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
276558
- flexDirection: "row",
276559
- children: [
276560
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276561
- fg: colors2.primary,
276562
- children: " URL: "
276563
- }, undefined, false, undefined, this),
276564
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
276565
- focused: true,
276566
- value: localUrl,
276567
- backgroundColor: "transparent",
276568
- cursorColor: colors2.textMuted,
276569
- onInput: (v2) => setLocalUrl(typeof v2 === "string" ? v2 : ""),
276570
- onPaste: (event) => {
276571
- const cleaned = String(event.text).replace(/\r?\n/g, "");
276572
- setLocalUrl((prev) => `${prev}${cleaned}`);
276573
- },
276574
- onSubmit: finishEditing
276575
- }, undefined, false, undefined, this)
276576
- ]
276577
- }, undefined, true, undefined, this);
276578
- }
276579
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276580
- fg: isUrlFocused ? colors2.primary : colors2.textMuted,
276581
- children: ` URL: ${localUrl || "(press Enter to set)"}`
276582
- }, undefined, false, undefined, this);
276583
- })(),
276584
- (() => {
276585
- const isModelFocused = navigationItems[focusedIndex]?.type === "local-input" && navigationItems[focusedIndex].field === "model";
276586
- const isModelEditing = editingLocalField === "model";
276587
- if (isModelEditing) {
276588
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
276589
- flexDirection: "row",
276590
- children: [
276591
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276592
- fg: colors2.primary,
276593
- children: " Model: "
276594
- }, undefined, false, undefined, this),
276595
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
276596
- focused: true,
276597
- value: localModelName,
276598
- backgroundColor: "transparent",
276599
- cursorColor: colors2.textMuted,
276600
- onInput: (v2) => setLocalModelName(typeof v2 === "string" ? v2 : ""),
276601
- onPaste: (event) => {
276602
- const cleaned = String(event.text).replace(/\r?\n/g, "");
276603
- setLocalModelName((prev) => `${prev}${cleaned}`);
276604
- },
276605
- onSubmit: finishEditing
276606
- }, undefined, false, undefined, this)
276607
- ]
276608
- }, undefined, true, undefined, this);
276609
- }
276610
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276611
- fg: isModelFocused ? colors2.primary : colors2.textMuted,
276612
- children: ` Model: ${localModelName || "(press Enter to set)"}`
276613
- }, undefined, false, undefined, this);
276614
- })(),
276615
- localModels?.map((m2) => {
276616
- const isSelected = m2.id === selectedModel.id;
276617
- const isFocused = navigationItems[focusedIndex]?.type === "model" && navigationItems[focusedIndex].model.id === m2.id;
276618
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276619
- fg: isFocused ? colors2.primary : colors2.textMuted,
276655
+ }, undefined, true, undefined, this)
276656
+ }, "local", false, undefined, this));
276657
+ if (isExpanded) {
276658
+ const isUrlFocused = isLocalFieldFocused("url");
276659
+ const isUrlEditing = editingLocalField === "url";
276660
+ if (isUrlEditing) {
276661
+ elements2.push(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PickerRow, {
276662
+ id: "local-input-url",
276663
+ paddingLeft: 2,
276664
+ children: [
276665
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276666
+ fg: colors2.primary,
276667
+ children: " URL: "
276668
+ }, undefined, false, undefined, this),
276669
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
276670
+ focused: true,
276671
+ value: localUrl,
276672
+ backgroundColor: "transparent",
276673
+ cursorColor: colors2.textMuted,
276674
+ onInput: (v2) => setLocalUrl(typeof v2 === "string" ? v2 : ""),
276675
+ onPaste: (event) => {
276676
+ const cleaned = String(event.text).replace(/\r?\n/g, "");
276677
+ setLocalUrl((prev) => `${prev}${cleaned}`);
276678
+ },
276679
+ onSubmit: finishEditing
276680
+ }, undefined, false, undefined, this)
276681
+ ]
276682
+ }, "local-url", true, undefined, this));
276683
+ } else {
276684
+ elements2.push(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PickerRow, {
276685
+ id: "local-input-url",
276686
+ paddingLeft: 2,
276687
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276688
+ fg: isUrlFocused ? colors2.primary : colors2.textMuted,
276689
+ children: ` URL: ${localUrl || "(press Enter to set)"}`
276690
+ }, undefined, false, undefined, this)
276691
+ }, "local-url", false, undefined, this));
276692
+ }
276693
+ const isModelFieldFocused = isLocalFieldFocused("model");
276694
+ const isModelEditing = editingLocalField === "model";
276695
+ if (isModelEditing) {
276696
+ elements2.push(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PickerRow, {
276697
+ id: "local-input-model",
276698
+ paddingLeft: 2,
276699
+ children: [
276700
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276701
+ fg: colors2.primary,
276702
+ children: " Model: "
276703
+ }, undefined, false, undefined, this),
276704
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
276705
+ focused: true,
276706
+ value: localModelName,
276707
+ backgroundColor: "transparent",
276708
+ cursorColor: colors2.textMuted,
276709
+ onInput: (v2) => setLocalModelName(typeof v2 === "string" ? v2 : ""),
276710
+ onPaste: (event) => {
276711
+ const cleaned = String(event.text).replace(/\r?\n/g, "");
276712
+ setLocalModelName((prev) => `${prev}${cleaned}`);
276713
+ },
276714
+ onSubmit: finishEditing
276715
+ }, undefined, false, undefined, this)
276716
+ ]
276717
+ }, "local-model", true, undefined, this));
276718
+ } else {
276719
+ elements2.push(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PickerRow, {
276720
+ id: "local-input-model",
276721
+ paddingLeft: 2,
276722
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276723
+ fg: isModelFieldFocused ? colors2.primary : colors2.textMuted,
276724
+ children: ` Model: ${localModelName || "(press Enter to set)"}`
276725
+ }, undefined, false, undefined, this)
276726
+ }, "local-model", false, undefined, this));
276727
+ }
276728
+ if (localModels) {
276729
+ for (const m2 of localModels) {
276730
+ const isSelected = m2.id === selectedModel.id;
276731
+ const isMFocused = isModelFocused(m2.id);
276732
+ elements2.push(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PickerRow, {
276733
+ id: `model-${m2.id}`,
276734
+ paddingLeft: 2,
276735
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276736
+ fg: isMFocused ? colors2.primary : colors2.textMuted,
276620
276737
  children: [
276621
276738
  isSelected ? "●" : "○",
276622
276739
  " ",
276623
276740
  m2.name
276624
276741
  ]
276625
- }, m2.id, true, undefined, this);
276626
- })
276627
- ]
276628
- }, undefined, true, undefined, this)
276629
- ]
276630
- }, "local", true, undefined, this);
276631
- }
276632
- const models = groupedModels[provider];
276633
- if (!models || models.length === 0)
276634
- return null;
276635
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
276636
- flexDirection: "column",
276637
- gap: 0,
276638
- children: [
276639
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276640
- fg: isProviderFocused ? colors2.primary : isExpanded ? colors2.text : colors2.textMuted,
276742
+ }, undefined, true, undefined, this)
276743
+ }, m2.id, false, undefined, this));
276744
+ }
276745
+ }
276746
+ }
276747
+ return elements2;
276748
+ }
276749
+ const models = groupedModels[provider];
276750
+ if (!models || models.length === 0)
276751
+ return [];
276752
+ const elements = [];
276753
+ elements.push(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PickerRow, {
276754
+ id: `provider-${provider}`,
276755
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276756
+ fg: isFocused ? colors2.primary : isExpanded ? colors2.text : colors2.textMuted,
276641
276757
  children: [
276642
- isProviderFocused ? "❯" : isExpanded ? "▾" : "▸",
276758
+ isFocused ? "❯" : isExpanded ? "▾" : "▸",
276643
276759
  " ",
276644
276760
  providerName,
276645
- " ",
276646
- "(",
276761
+ " (",
276647
276762
  models.length,
276648
276763
  ")"
276649
276764
  ]
276650
- }, undefined, true, undefined, this),
276651
- isExpanded && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
276652
- flexDirection: "column",
276653
- gap: 0,
276654
- paddingLeft: 2,
276655
- children: models.map((m2) => {
276656
- const isSelected = m2.id === selectedModel.id;
276657
- const isFocused = navigationItems[focusedIndex]?.type === "model" && navigationItems[focusedIndex].model.id === m2.id;
276658
- const isDefault = m2.id === "claude-haiku-4-5" || m2.id === "gpt-4o-mini";
276659
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276660
- fg: isFocused ? colors2.primary : colors2.textMuted,
276765
+ }, undefined, true, undefined, this)
276766
+ }, provider, false, undefined, this));
276767
+ if (isExpanded) {
276768
+ for (const m2 of models) {
276769
+ const isSelected = m2.id === selectedModel.id;
276770
+ const isMFocused = isModelFocused(m2.id);
276771
+ const isDefault = m2.id === "claude-haiku-4-5" || m2.id === "gpt-4o-mini";
276772
+ elements.push(/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PickerRow, {
276773
+ id: `model-${m2.id}`,
276774
+ paddingLeft: 2,
276775
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276776
+ fg: isMFocused ? colors2.primary : colors2.textMuted,
276661
276777
  children: [
276662
276778
  isSelected ? "●" : "○",
276663
276779
  " ",
276664
276780
  m2.name,
276665
276781
  isDefault && !isModelUserSelected && isSelected ? " [default]" : ""
276666
276782
  ]
276667
- }, m2.id, true, undefined, this);
276668
- })
276669
- }, undefined, false, undefined, this)
276670
- ]
276671
- }, provider, true, undefined, this);
276672
- }),
276673
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276674
- fg: colors2.textMuted,
276675
- children: editingLocalField ? "Type or paste | Enter/Esc to confirm" : "↑/↓ navigate | ←/→ collapse/expand | Type to search"
276783
+ }, undefined, true, undefined, this)
276784
+ }, m2.id, false, undefined, this));
276785
+ }
276786
+ }
276787
+ return elements;
276788
+ })
276789
+ }, undefined, false, undefined, this),
276790
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PickerRow, {
276791
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
276792
+ fg: colors2.textMuted,
276793
+ children: editingLocalField ? "Type or paste | Enter/Esc to confirm" : "↑/↓ navigate | ←/→ collapse/expand | Type to search"
276794
+ }, undefined, false, undefined, this)
276676
276795
  }, undefined, false, undefined, this)
276677
276796
  ]
276678
276797
  }, undefined, true, undefined, this);
@@ -276847,7 +276966,8 @@ function ConfigView({ config: config3, onBack, onStart }) {
276847
276966
  borderColor: focusedField === "model" ? colors2.primary : colors2.border,
276848
276967
  paddingLeft: 1,
276849
276968
  paddingRight: 1,
276850
- maxHeight: 8,
276969
+ height: 8,
276970
+ overflow: "hidden",
276851
276971
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ModelPicker, {
276852
276972
  config: config3,
276853
276973
  selectedModel,
@@ -280254,6 +280374,13 @@ function HelpDialog() {
280254
280374
  }, undefined, false, undefined, this);
280255
280375
  }
280256
280376
  // src/tui/components/commands/models-display.tsx
280377
+ function ClippedLine({ children }) {
280378
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
280379
+ width: "100%",
280380
+ overflow: "hidden",
280381
+ children
280382
+ }, undefined, false, undefined, this);
280383
+ }
280257
280384
  function ModelsDisplay() {
280258
280385
  const { colors: colors2 } = useTheme();
280259
280386
  const route = useRoute();
@@ -280281,42 +280408,52 @@ function ModelsDisplay() {
280281
280408
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
280282
280409
  flexDirection: "column",
280283
280410
  width: "100%",
280411
+ height: "100%",
280284
280412
  paddingLeft: 4,
280413
+ paddingRight: 4,
280285
280414
  paddingTop: 2,
280415
+ overflow: "hidden",
280286
280416
  children: [
280287
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
280288
- children: [
280289
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280290
- fg: colors2.primary,
280291
- children: "█ "
280292
- }, undefined, false, undefined, this),
280293
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280294
- fg: colors2.text,
280295
- children: "Select AI Model"
280296
- }, undefined, false, undefined, this),
280297
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280298
- fg: colors2.textMuted,
280299
- children: [
280300
- " (",
280301
- model.name,
280302
- ")"
280303
- ]
280304
- }, undefined, true, undefined, this),
280305
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280306
- fg: colors2.textMuted,
280307
- children: [
280308
- " ",
280309
- "[",
280310
- isModelUserSelected ? "user" : "default",
280311
- "]"
280312
- ]
280313
- }, undefined, true, undefined, this)
280314
- ]
280315
- }, undefined, true, undefined, this),
280417
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ClippedLine, {
280418
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
280419
+ children: [
280420
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280421
+ fg: colors2.primary,
280422
+ children: "█ "
280423
+ }, undefined, false, undefined, this),
280424
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280425
+ fg: colors2.text,
280426
+ children: "Select AI Model"
280427
+ }, undefined, false, undefined, this),
280428
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280429
+ fg: colors2.textMuted,
280430
+ children: [
280431
+ " (",
280432
+ model.name,
280433
+ ")"
280434
+ ]
280435
+ }, undefined, true, undefined, this),
280436
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280437
+ fg: colors2.textMuted,
280438
+ children: [
280439
+ " ",
280440
+ "[",
280441
+ isModelUserSelected ? "user" : "default",
280442
+ "]"
280443
+ ]
280444
+ }, undefined, true, undefined, this)
280445
+ ]
280446
+ }, undefined, true, undefined, this)
280447
+ }, undefined, false, undefined, this),
280316
280448
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
280317
280449
  flexDirection: "column",
280450
+ width: "100%",
280318
280451
  paddingLeft: 2,
280452
+ paddingRight: 2,
280319
280453
  marginTop: 1,
280454
+ flexGrow: 1,
280455
+ flexShrink: 1,
280456
+ overflow: "hidden",
280320
280457
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ModelPicker, {
280321
280458
  config: config3.data,
280322
280459
  selectedModel: model,
@@ -280331,66 +280468,72 @@ function ModelsDisplay() {
280331
280468
  flexDirection: "column",
280332
280469
  marginTop: 2,
280333
280470
  children: [
280334
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
280335
- children: [
280336
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280337
- fg: colors2.primary,
280338
- children: "█ "
280339
- }, undefined, false, undefined, this),
280340
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280341
- fg: colors2.textMuted,
280342
- children: "Press "
280343
- }, undefined, false, undefined, this),
280344
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280345
- fg: colors2.text,
280346
- children: "[Enter]"
280347
- }, undefined, false, undefined, this),
280348
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280349
- fg: colors2.textMuted,
280350
- children: " to confirm"
280351
- }, undefined, false, undefined, this)
280352
- ]
280353
- }, undefined, true, undefined, this),
280354
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
280355
- children: [
280356
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280357
- fg: colors2.primary,
280358
- children: "█ "
280359
- }, undefined, false, undefined, this),
280360
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280361
- fg: colors2.textMuted,
280362
- children: "Press "
280363
- }, undefined, false, undefined, this),
280364
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280365
- fg: colors2.text,
280366
- children: "[ESC]"
280367
- }, undefined, false, undefined, this),
280368
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280369
- fg: colors2.textMuted,
280370
- children: " to go back"
280371
- }, undefined, false, undefined, this)
280372
- ]
280373
- }, undefined, true, undefined, this),
280374
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
280375
- children: [
280376
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280377
- fg: colors2.primary,
280378
- children: "█ "
280379
- }, undefined, false, undefined, this),
280380
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280381
- fg: colors2.textMuted,
280382
- children: "Press "
280383
- }, undefined, false, undefined, this),
280384
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280385
- fg: colors2.text,
280386
- children: "[Ctrl+P]"
280387
- }, undefined, false, undefined, this),
280388
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280389
- fg: colors2.textMuted,
280390
- children: " to connect provider"
280391
- }, undefined, false, undefined, this)
280392
- ]
280393
- }, undefined, true, undefined, this)
280471
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ClippedLine, {
280472
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
280473
+ children: [
280474
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280475
+ fg: colors2.primary,
280476
+ children: "█ "
280477
+ }, undefined, false, undefined, this),
280478
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280479
+ fg: colors2.textMuted,
280480
+ children: "Press "
280481
+ }, undefined, false, undefined, this),
280482
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280483
+ fg: colors2.text,
280484
+ children: "[Enter]"
280485
+ }, undefined, false, undefined, this),
280486
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280487
+ fg: colors2.textMuted,
280488
+ children: " to confirm"
280489
+ }, undefined, false, undefined, this)
280490
+ ]
280491
+ }, undefined, true, undefined, this)
280492
+ }, undefined, false, undefined, this),
280493
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ClippedLine, {
280494
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
280495
+ children: [
280496
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280497
+ fg: colors2.primary,
280498
+ children: "█ "
280499
+ }, undefined, false, undefined, this),
280500
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280501
+ fg: colors2.textMuted,
280502
+ children: "Press "
280503
+ }, undefined, false, undefined, this),
280504
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280505
+ fg: colors2.text,
280506
+ children: "[ESC]"
280507
+ }, undefined, false, undefined, this),
280508
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280509
+ fg: colors2.textMuted,
280510
+ children: " to go back"
280511
+ }, undefined, false, undefined, this)
280512
+ ]
280513
+ }, undefined, true, undefined, this)
280514
+ }, undefined, false, undefined, this),
280515
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ClippedLine, {
280516
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
280517
+ children: [
280518
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280519
+ fg: colors2.primary,
280520
+ children: "█ "
280521
+ }, undefined, false, undefined, this),
280522
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280523
+ fg: colors2.textMuted,
280524
+ children: "Press "
280525
+ }, undefined, false, undefined, this),
280526
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280527
+ fg: colors2.text,
280528
+ children: "[Ctrl+P]"
280529
+ }, undefined, false, undefined, this),
280530
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
280531
+ fg: colors2.textMuted,
280532
+ children: " to connect provider"
280533
+ }, undefined, false, undefined, this)
280534
+ ]
280535
+ }, undefined, true, undefined, this)
280536
+ }, undefined, false, undefined, this)
280394
280537
  ]
280395
280538
  }, undefined, true, undefined, this)
280396
280539
  ]
@@ -286458,8 +286601,10 @@ function resolveKeyboardShortcut(key, status, inputValue, hasPendingApprovals, d
286458
286601
  return { type: "toggle-verbose" };
286459
286602
  if (key.ctrl && key.name === "l")
286460
286603
  return { type: "toggle-expanded-logs" };
286461
- if (key.name === "tab" && key.shift)
286604
+ if (key.name === "tab" && key.shift && key.meta)
286462
286605
  return { type: "toggle-approval" };
286606
+ if (key.name === "tab" && key.shift)
286607
+ return { type: "toggle-mode" };
286463
286608
  if (status === "waiting" && hasPendingApprovals && (key.name === "y" || key.raw === "Y")) {
286464
286609
  return { type: "approve" };
286465
286610
  }
@@ -286474,7 +286619,9 @@ function resolveAbortAction(commandCancelled, cancelCommand) {
286474
286619
  }
286475
286620
  return { type: "kill-agent" };
286476
286621
  }
286477
- function buildOperatorSystemPrompt(target, operatorState) {
286622
+ function buildOperatorSystemPrompt(target, operatorState, agentMode) {
286623
+ const modeNote = agentMode === "plan" ? `
286624
+ Agent mode: PLAN — read-only tools only, no mutations allowed` : "";
286478
286625
  return `${BASE_SYSTEM_PROMPT}
286479
286626
 
286480
286627
  # Operator Mode
@@ -286483,7 +286630,7 @@ You are operating in interactive operator mode. The human operator will guide yo
286483
286630
 
286484
286631
  Target: ${target || "unknown"}
286485
286632
  Stage: ${operatorState.currentStage}
286486
- Command approval: ${operatorState.requireApproval ? "enabled — the operator will approve each tool call" : "disabled — tool calls execute automatically"}`;
286633
+ Command approval: ${operatorState.requireApproval ? "enabled — the operator will approve each tool call" : "disabled — tool calls execute automatically"}${modeNote}`;
286487
286634
  }
286488
286635
  function resolveInputFocused(status, dialogStackLength, externalDialogOpen) {
286489
286636
  return status !== "running" && dialogStackLength === 0 && !externalDialogOpen;
@@ -286653,6 +286800,7 @@ function OperatorDashboard({
286653
286800
  const [lastApprovedAction, setLastApprovedAction] = import_react79.useState(null);
286654
286801
  const [verboseMode, setVerboseMode] = import_react79.useState(false);
286655
286802
  const [expandedLogs, setExpandedLogs] = import_react79.useState(false);
286803
+ const [agentMode, setAgentMode] = import_react79.useState("default");
286656
286804
  const tokenUsageRef = import_react79.useRef(tokenUsage);
286657
286805
  import_react79.useEffect(() => {
286658
286806
  tokenUsageRef.current = tokenUsage;
@@ -287095,7 +287243,10 @@ function OperatorDashboard({
287095
287243
  messages: nextMessages,
287096
287244
  stopWhen: [stepCountIs(1e4)],
287097
287245
  target: initialConfig?.target,
287098
- activeTools: [...ALL_TOOL_NAMES],
287246
+ activeTools: [
287247
+ ...agentMode === "plan" ? PLAN_MODE_TOOL_NAMES : ALL_TOOL_NAMES
287248
+ ],
287249
+ mode: agentMode,
287099
287250
  abortSignal: controller.signal,
287100
287251
  authConfig: buildAuthConfig(config3.data),
287101
287252
  approvalGate: approvalGateRef.current,
@@ -287111,7 +287262,7 @@ function OperatorDashboard({
287111
287262
  if (session) {
287112
287263
  agentResult = await runOffensiveSecurityAgent({
287113
287264
  ...commonInput,
287114
- system: buildOperatorSystemPrompt(initialConfig?.target, operatorState),
287265
+ system: buildOperatorSystemPrompt(initialConfig?.target, operatorState, agentMode),
287115
287266
  session
287116
287267
  });
287117
287268
  } else {
@@ -287127,7 +287278,7 @@ function OperatorDashboard({
287127
287278
  };
287128
287279
  agentResult = await runOffensiveSecurityAgent({
287129
287280
  ...commonInput,
287130
- system: buildOperatorSystemPrompt(initialConfig?.target, operatorState),
287281
+ system: buildOperatorSystemPrompt(initialConfig?.target, operatorState, agentMode),
287131
287282
  sessionConfig,
287132
287283
  onNameGenerated: (name26) => {
287133
287284
  pendingNameRef.current = name26;
@@ -287192,6 +287343,7 @@ function OperatorDashboard({
287192
287343
  model.id,
287193
287344
  config3.data,
287194
287345
  operatorState,
287346
+ agentMode,
287195
287347
  addTokenUsage,
287196
287348
  appendText,
287197
287349
  addStreamingToolCall,
@@ -287382,6 +287534,9 @@ function OperatorDashboard({
287382
287534
  return { ...prev, requireApproval: newVal };
287383
287535
  });
287384
287536
  }, []);
287537
+ const toggleMode = import_react79.useCallback(() => {
287538
+ setAgentMode((prev) => prev === "default" ? "plan" : "default");
287539
+ }, []);
287385
287540
  useKeyboard((key) => {
287386
287541
  if (status === "running" && queuedMessages.length > 0 && !inputValue.trim()) {
287387
287542
  if (key.name === "up") {
@@ -287453,6 +287608,9 @@ function OperatorDashboard({
287453
287608
  case "toggle-approval":
287454
287609
  toggleApproval();
287455
287610
  return;
287611
+ case "toggle-mode":
287612
+ toggleMode();
287613
+ return;
287456
287614
  case "approve":
287457
287615
  handleApprove();
287458
287616
  return;
@@ -287548,6 +287706,10 @@ function OperatorDashboard({
287548
287706
  flexDirection: "row",
287549
287707
  gap: 2,
287550
287708
  children: [
287709
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
287710
+ fg: agentMode === "plan" ? colors2.warning : colors2.primary,
287711
+ children: agentMode === "plan" ? "PLAN" : "DEFAULT"
287712
+ }, undefined, false, undefined, this),
287551
287713
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
287552
287714
  fg: operatorState.requireApproval ? colors2.warning : colors2.primary,
287553
287715
  children: operatorState.requireApproval ? "APPROVAL ON" : "APPROVAL OFF"
@@ -287591,7 +287753,7 @@ function OperatorDashboard({
287591
287753
  focused: status === "running" ? selectedQueueIndex < 0 : resolveInputFocused(status, stack.length, externalDialogOpen),
287592
287754
  status: status === "waiting" ? "running" : status,
287593
287755
  mode: "operator",
287594
- operatorMode: operatorState.mode,
287756
+ operatorMode: agentMode === "plan" ? "plan" : operatorState.mode,
287595
287757
  verboseMode,
287596
287758
  expandedLogs,
287597
287759
  pendingApproval: currentPending,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pensar/apex",
3
- "version": "0.0.99",
3
+ "version": "0.0.100-canary.ba3e689f",
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",