@pensar/apex 0.0.28 → 0.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -27213,8 +27213,8 @@ import os2 from "os";
27213
27213
  // src/tui/agentProvider.tsx
27214
27214
  var import_react10 = __toESM(require_react(), 1);
27215
27215
 
27216
- // src/core/ai/models.ts
27217
- var AVAILABLE_MODELS = [
27216
+ // src/core/ai/models/anthropic.ts
27217
+ var ANTHROPIC_MODELS = [
27218
27218
  {
27219
27219
  id: "claude-haiku-4-5",
27220
27220
  name: "Claude Haiku 4.5",
@@ -27298,55 +27298,11 @@ var AVAILABLE_MODELS = [
27298
27298
  name: "Claude 3 Haiku (2024-03-07)",
27299
27299
  provider: "anthropic",
27300
27300
  contextLength: 200000
27301
- },
27302
- {
27303
- id: "gpt-4.5-turbo",
27304
- name: "GPT-4.5 Turbo",
27305
- provider: "openai",
27306
- contextLength: 128000
27307
- },
27308
- {
27309
- id: "gpt-4o",
27310
- name: "GPT-4o",
27311
- provider: "openai",
27312
- contextLength: 128000
27313
- },
27314
- {
27315
- id: "gpt-4o-mini",
27316
- name: "GPT-4o Mini",
27317
- provider: "openai",
27318
- contextLength: 128000
27319
- },
27320
- {
27321
- id: "gpt-4-turbo",
27322
- name: "GPT-4 Turbo",
27323
- provider: "openai",
27324
- contextLength: 128000
27325
- },
27326
- {
27327
- id: "gpt-4",
27328
- name: "GPT-4",
27329
- provider: "openai",
27330
- contextLength: 8192
27331
- },
27332
- {
27333
- id: "gpt-3.5-turbo",
27334
- name: "GPT-3.5 Turbo",
27335
- provider: "openai",
27336
- contextLength: 16385
27337
- },
27338
- {
27339
- id: "o1",
27340
- name: "O1",
27341
- provider: "openai",
27342
- contextLength: 200000
27343
- },
27344
- {
27345
- id: "o1-mini",
27346
- name: "O1 Mini",
27347
- provider: "openai",
27348
- contextLength: 128000
27349
- },
27301
+ }
27302
+ ];
27303
+
27304
+ // src/core/ai/models/openrouter.ts
27305
+ var OPENROUTER_MODELS = [
27350
27306
  {
27351
27307
  id: "anthropic/claude-haiku-4.5",
27352
27308
  name: "Claude Haiku 4.5 (OpenRouter)",
@@ -27466,28 +27422,62 @@ var AVAILABLE_MODELS = [
27466
27422
  name: "Qwen 3 32B Instruct",
27467
27423
  provider: "openrouter",
27468
27424
  contextLength: 256000
27425
+ }
27426
+ ];
27427
+
27428
+ // src/core/ai/models/bedrock.ts
27429
+ var BEDROCK_MODELS = [
27430
+ {
27431
+ id: "anthropic.claude-3-haiku-20240307-v1:0",
27432
+ name: "Claude 3 Haiku (Bedrock)",
27433
+ provider: "bedrock",
27434
+ contextLength: 200000
27469
27435
  },
27470
27436
  {
27471
- id: "anthropic.claude-3-5-sonnet-20240620-v1:0",
27472
- name: "Claude 3.5 Sonnet (Bedrock)",
27437
+ id: "anthropic.claude-3-5-haiku-20241022-v1:0",
27438
+ name: "Claude 3.5 Haiku (Bedrock)",
27473
27439
  provider: "bedrock",
27474
27440
  contextLength: 200000
27475
27441
  },
27476
27442
  {
27477
- id: "anthropic.claude-3-opus-20240229-v1:0",
27478
- name: "Claude 3 Opus (Bedrock)",
27443
+ id: "anthropic.claude-3-7-sonnet-20250219-v1:0",
27444
+ name: "Claude 3.7 Sonnet (Bedrock)",
27479
27445
  provider: "bedrock",
27480
27446
  contextLength: 200000
27481
27447
  },
27482
27448
  {
27483
- id: "anthropic.claude-3-sonnet-20240229-v1:0",
27484
- name: "Claude 3 Sonnet (Bedrock)",
27449
+ id: "anthropic.claude-haiku-4-5-20251001-v1:0",
27450
+ name: "Claude Haiku 4.5 (Bedrock)",
27485
27451
  provider: "bedrock",
27486
27452
  contextLength: 200000
27487
27453
  },
27488
27454
  {
27489
- id: "anthropic.claude-3-haiku-20240307-v1:0",
27490
- name: "Claude 3 Haiku (Bedrock)",
27455
+ id: "anthropic.claude-opus-4-1-20250805-v1:0",
27456
+ name: "Claude Opus 4.1 (Bedrock)",
27457
+ provider: "bedrock",
27458
+ contextLength: 200000
27459
+ },
27460
+ {
27461
+ id: "anthropic.claude-opus-4-5-20251101-v1:0",
27462
+ name: "Claude Opus 4.5 (Bedrock)",
27463
+ provider: "bedrock",
27464
+ contextLength: 200000
27465
+ },
27466
+ {
27467
+ id: "anthropic.claude-opus-4-20250514-v1:0",
27468
+ name: "Claude Opus 4 (Bedrock)",
27469
+ provider: "bedrock",
27470
+ contextLength: 200000
27471
+ },
27472
+ {
27473
+ id: "anthropic.claude-sonnet-4-5-20250929-v1:0",
27474
+ name: "Claude Sonnet 4.5 (Bedrock)",
27475
+ provider: "bedrock",
27476
+ contextLength: 200000
27477
+ },
27478
+ {
27479
+ id: "anthropic.claude-sonnet-4-20250514-v1:0",
27480
+ name: "Claude Sonnet 4 (Bedrock)",
27491
27481
  provider: "bedrock",
27492
27482
  contextLength: 200000
27493
27483
  },
@@ -27528,6 +27518,66 @@ var AVAILABLE_MODELS = [
27528
27518
  contextLength: 128000
27529
27519
  }
27530
27520
  ];
27521
+
27522
+ // src/core/ai/models/openai.ts
27523
+ var OPENAI_MODELS = [
27524
+ {
27525
+ id: "gpt-4.5-turbo",
27526
+ name: "GPT-4.5 Turbo",
27527
+ provider: "openai",
27528
+ contextLength: 128000
27529
+ },
27530
+ {
27531
+ id: "gpt-4o",
27532
+ name: "GPT-4o",
27533
+ provider: "openai",
27534
+ contextLength: 128000
27535
+ },
27536
+ {
27537
+ id: "gpt-4o-mini",
27538
+ name: "GPT-4o Mini",
27539
+ provider: "openai",
27540
+ contextLength: 128000
27541
+ },
27542
+ {
27543
+ id: "gpt-4-turbo",
27544
+ name: "GPT-4 Turbo",
27545
+ provider: "openai",
27546
+ contextLength: 128000
27547
+ },
27548
+ {
27549
+ id: "gpt-4",
27550
+ name: "GPT-4",
27551
+ provider: "openai",
27552
+ contextLength: 8192
27553
+ },
27554
+ {
27555
+ id: "gpt-3.5-turbo",
27556
+ name: "GPT-3.5 Turbo",
27557
+ provider: "openai",
27558
+ contextLength: 16385
27559
+ },
27560
+ {
27561
+ id: "o1",
27562
+ name: "O1",
27563
+ provider: "openai",
27564
+ contextLength: 200000
27565
+ },
27566
+ {
27567
+ id: "o1-mini",
27568
+ name: "O1 Mini",
27569
+ provider: "openai",
27570
+ contextLength: 128000
27571
+ }
27572
+ ];
27573
+
27574
+ // src/core/ai/models/index.ts
27575
+ var AVAILABLE_MODELS = [
27576
+ ...ANTHROPIC_MODELS,
27577
+ ...OPENROUTER_MODELS,
27578
+ ...BEDROCK_MODELS,
27579
+ ...OPENAI_MODELS
27580
+ ];
27531
27581
  function getModelInfo(model) {
27532
27582
  return AVAILABLE_MODELS.find((m) => m.id === model) ?? {
27533
27583
  id: model,
@@ -64633,7 +64683,7 @@ function getProviderModel(model, authConfig) {
64633
64683
  const openRouterAPIKey = authConfig?.openRouterAPIKey || process.env.OPENROUTER_API_KEY;
64634
64684
  const bedrockAccessKeyId = authConfig?.bedrock?.accessKeyId || process.env.AWS_ACCESS_KEY_ID;
64635
64685
  const bedrockSecretAccessKey = authConfig?.bedrock?.secretAccessKey || process.env.AWS_SECRET_ACCESS_KEY;
64636
- const bedrockRegion = authConfig?.bedrock?.region || process.env.AWS_REGION || "us-east-1";
64686
+ const bedrockRegion = authConfig?.bedrock?.region || process.env.AWS_REGION;
64637
64687
  const localBaseURL = authConfig?.local?.baseURL || process.env.LOCAL_MODEL_URL || "http://127.0.0.1:1234/v1";
64638
64688
  let providerModel;
64639
64689
  switch (provider) {
@@ -66474,6 +66524,66 @@ import {
66474
66524
  } from "fs";
66475
66525
  import { join } from "path";
66476
66526
  import { homedir } from "os";
66527
+
66528
+ // src/core/services/rateLimiter/index.ts
66529
+ function sleep(ms) {
66530
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
66531
+ }
66532
+
66533
+ class RateLimiter {
66534
+ tokens;
66535
+ lastRefillTime;
66536
+ rps;
66537
+ bucketSize;
66538
+ msPerToken;
66539
+ queue;
66540
+ constructor(config3) {
66541
+ this.rps = config3?.requestsPerSecond;
66542
+ this.bucketSize = this.rps ? 1 : 0;
66543
+ this.tokens = this.bucketSize;
66544
+ this.lastRefillTime = performance.now();
66545
+ this.msPerToken = this.rps ? 1000 / this.rps : undefined;
66546
+ this.queue = Promise.resolve();
66547
+ }
66548
+ async acquireSlot() {
66549
+ if (!this.rps || !this.msPerToken)
66550
+ return;
66551
+ const previousPromise = this.queue;
66552
+ let resolveCurrentRequest;
66553
+ this.queue = new Promise((resolve4) => {
66554
+ resolveCurrentRequest = resolve4;
66555
+ });
66556
+ await previousPromise;
66557
+ try {
66558
+ const now2 = performance.now();
66559
+ this.refill(now2);
66560
+ if (this.tokens < 1) {
66561
+ const waitTime = (1 - this.tokens) * this.msPerToken;
66562
+ await sleep(waitTime);
66563
+ const nowAfterSleep = performance.now();
66564
+ this.refill(nowAfterSleep);
66565
+ }
66566
+ this.tokens -= 1;
66567
+ } finally {
66568
+ resolveCurrentRequest();
66569
+ }
66570
+ }
66571
+ refill(now2) {
66572
+ if (this.tokens >= this.bucketSize) {
66573
+ this.lastRefillTime = now2;
66574
+ return;
66575
+ }
66576
+ const elapsed = now2 - this.lastRefillTime;
66577
+ const tokensToAdd = elapsed / this.msPerToken;
66578
+ this.tokens = Math.min(this.bucketSize, this.tokens + tokensToAdd);
66579
+ this.lastRefillTime = now2;
66580
+ }
66581
+ isEnabled() {
66582
+ return this.rps !== undefined;
66583
+ }
66584
+ }
66585
+
66586
+ // src/core/agent/sessions/index.ts
66477
66587
  var DEFAULT_OFFENSIVE_HEADERS = {
66478
66588
  "User-Agent": "pensar-apex"
66479
66589
  };
@@ -66508,6 +66618,9 @@ function createSession(target, objective, prefix, config3) {
66508
66618
  startTime: new Date().toISOString(),
66509
66619
  config: config3
66510
66620
  };
66621
+ if (config3?.rateLimiter) {
66622
+ session._rateLimiter = new RateLimiter(config3.rateLimiter);
66623
+ }
66511
66624
  const metadataPath = join(rootPath, "session.json");
66512
66625
  writeFileSync(metadataPath, JSON.stringify(session, null, 2));
66513
66626
  const readmePath = join(rootPath, "README.md");
@@ -66550,16 +66663,26 @@ function getSession(sessionId) {
66550
66663
  const metadata = JSON.parse(readFileSync(metadataPath, "utf-8"));
66551
66664
  return metadata;
66552
66665
  }
66666
+ function extractTimestamp(sessionId) {
66667
+ const parts = sessionId.split("-");
66668
+ const timestampBase36 = parts[parts.length - 1];
66669
+ return parseInt(timestampBase36 || "", 36);
66670
+ }
66553
66671
  function listSessions() {
66554
66672
  const executionsDir = getExecutionsDir();
66555
66673
  if (!existsSync3(executionsDir)) {
66556
66674
  return [];
66557
66675
  }
66558
66676
  const entries = readdirSync(executionsDir);
66559
- return entries.filter((entry) => {
66677
+ const directories = entries.filter((entry) => {
66560
66678
  const fullPath = join(executionsDir, entry);
66561
66679
  return statSync(fullPath).isDirectory();
66562
66680
  });
66681
+ return directories.sort((a, b) => {
66682
+ const timestampA = extractTimestamp(a);
66683
+ const timestampB = extractTimestamp(b);
66684
+ return timestampB - timestampA;
66685
+ });
66563
66686
  }
66564
66687
  function getOffensiveHeaders(session) {
66565
66688
  const config3 = session.config?.offensiveHeaders;
@@ -68931,6 +69054,7 @@ function wrapCommandWithHeaders(command, headers) {
68931
69054
  }
68932
69055
  function createPentestTools(session, model, toolOverride) {
68933
69056
  const offensiveHeaders = getOffensiveHeaders(session);
69057
+ const rateLimiter = session._rateLimiter;
68934
69058
  const executeCommand = tool({
68935
69059
  name: "execute_command",
68936
69060
  description: `Execute a shell command for penetration testing activities.
@@ -68975,6 +69099,9 @@ IMPORTANT: Always analyze results and adjust your approach based on findings.`,
68975
69099
  inputSchema: ExecuteCommandInput,
68976
69100
  execute: async ({ command, timeout = 30000, toolCallDescription }) => {
68977
69101
  try {
69102
+ if (rateLimiter) {
69103
+ await rateLimiter.acquireSlot();
69104
+ }
68978
69105
  if (toolOverride?.execute_command) {
68979
69106
  return toolOverride.execute_command({
68980
69107
  command,
@@ -69031,6 +69158,9 @@ COMMON TESTING PATTERNS:
69031
69158
  inputSchema: HttpRequestInput,
69032
69159
  execute: async ({ url: url2, method, headers, body, followRedirects, timeout, toolCallDescription }) => {
69033
69160
  try {
69161
+ if (rateLimiter) {
69162
+ await rateLimiter.acquireSlot();
69163
+ }
69034
69164
  if (toolOverride?.http_request) {
69035
69165
  return toolOverride.http_request({
69036
69166
  url: url2,
@@ -71681,9 +71811,128 @@ import fs5 from "fs";
71681
71811
 
71682
71812
  // src/core/messages/index.ts
71683
71813
  import fs4 from "fs";
71814
+
71815
+ // src/core/messages/types.ts
71816
+ var ToolMessageObject = exports_external.object({
71817
+ role: exports_external.literal("tool"),
71818
+ status: exports_external.enum(["pending", "completed"]),
71819
+ toolCallId: exports_external.string(),
71820
+ content: exports_external.string(),
71821
+ args: exports_external.record(exports_external.string(), exports_external.any()),
71822
+ toolName: exports_external.string(),
71823
+ createdAt: exports_external.coerce.date()
71824
+ });
71825
+ var SystemModelMessageObject = exports_external.object({
71826
+ role: exports_external.literal("system"),
71827
+ content: exports_external.string(),
71828
+ createdAt: exports_external.coerce.date(),
71829
+ providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
71830
+ });
71831
+ var TextPartObject = exports_external.object({
71832
+ type: exports_external.literal("text"),
71833
+ text: exports_external.string(),
71834
+ providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
71835
+ });
71836
+ var FilePartObject = exports_external.object({
71837
+ type: exports_external.literal("file"),
71838
+ data: exports_external.union([
71839
+ exports_external.string(),
71840
+ exports_external.instanceof(Uint8Array),
71841
+ exports_external.instanceof(ArrayBuffer),
71842
+ exports_external.instanceof(Buffer),
71843
+ exports_external.url()
71844
+ ]),
71845
+ filename: exports_external.string().optional(),
71846
+ mediaType: exports_external.string(),
71847
+ providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
71848
+ });
71849
+ var ReasoningPartObject = exports_external.object({
71850
+ type: exports_external.literal("reasoning"),
71851
+ text: exports_external.string(),
71852
+ providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
71853
+ });
71854
+ var ToolCallPartObject = exports_external.object({
71855
+ type: exports_external.literal("tool-call"),
71856
+ toolCallId: exports_external.string(),
71857
+ toolName: exports_external.string(),
71858
+ input: exports_external.unknown(),
71859
+ providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional(),
71860
+ providerExecuted: exports_external.boolean().optional()
71861
+ });
71862
+ var ToolResultOutputObject = exports_external.discriminatedUnion("type", [
71863
+ exports_external.object({
71864
+ type: exports_external.literal("text"),
71865
+ value: exports_external.string()
71866
+ }),
71867
+ exports_external.object({
71868
+ type: exports_external.literal("json"),
71869
+ value: exports_external.any()
71870
+ }),
71871
+ exports_external.object({
71872
+ type: exports_external.literal("error-text"),
71873
+ value: exports_external.string()
71874
+ }),
71875
+ exports_external.object({
71876
+ type: exports_external.literal("error-json"),
71877
+ value: exports_external.any()
71878
+ }),
71879
+ exports_external.object({
71880
+ type: exports_external.literal("content"),
71881
+ value: exports_external.array(exports_external.discriminatedUnion("type", [
71882
+ exports_external.object({
71883
+ type: exports_external.literal("text"),
71884
+ text: exports_external.string()
71885
+ }),
71886
+ exports_external.object({
71887
+ type: exports_external.literal("media"),
71888
+ data: exports_external.string(),
71889
+ mediaType: exports_external.string()
71890
+ })
71891
+ ]))
71892
+ })
71893
+ ]);
71894
+ var ToolResultPartObject = exports_external.object({
71895
+ type: exports_external.literal("tool-result"),
71896
+ toolCallId: exports_external.string(),
71897
+ toolName: exports_external.string(),
71898
+ output: ToolResultOutputObject,
71899
+ providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
71900
+ });
71901
+ var AssistantModelMessageObject = exports_external.object({
71902
+ role: exports_external.literal("assistant"),
71903
+ content: exports_external.union([
71904
+ exports_external.string(),
71905
+ exports_external.array(exports_external.discriminatedUnion("type", [
71906
+ TextPartObject,
71907
+ FilePartObject,
71908
+ ReasoningPartObject,
71909
+ ToolCallPartObject,
71910
+ ToolResultPartObject
71911
+ ]))
71912
+ ]),
71913
+ createdAt: exports_external.coerce.date(),
71914
+ providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
71915
+ });
71916
+ var UserModelMessageObject = exports_external.object({
71917
+ role: exports_external.literal("user"),
71918
+ content: exports_external.union([
71919
+ exports_external.string(),
71920
+ exports_external.array(exports_external.discriminatedUnion("type", [TextPartObject, FilePartObject]))
71921
+ ]),
71922
+ createdAt: exports_external.coerce.date(),
71923
+ providerOptions: exports_external.record(exports_external.string(), exports_external.any()).optional()
71924
+ });
71925
+ var ModelMessageObject = exports_external.discriminatedUnion("role", [
71926
+ SystemModelMessageObject,
71927
+ UserModelMessageObject,
71928
+ AssistantModelMessageObject,
71929
+ ToolMessageObject
71930
+ ]);
71931
+
71932
+ // src/core/messages/index.ts
71684
71933
  function getMessages(session) {
71685
71934
  const messages = fs4.readFileSync(session.rootPath + "/messages.json", "utf8");
71686
- return JSON.parse(messages);
71935
+ return ModelMessageObject.array().parse(JSON.parse(messages));
71687
71936
  }
71688
71937
  function saveMessages(session, messages) {
71689
71938
  fs4.writeFileSync(session.rootPath + "/messages.json", JSON.stringify(messages, null, 2));
@@ -71711,6 +71960,7 @@ function PentestAgentDisplay() {
71711
71960
  const [isCompleted, setIsCompleted] = import_react20.useState(false);
71712
71961
  const [sessionPath, setSessionPath] = import_react20.useState("");
71713
71962
  const [abortController, setAbortController] = import_react20.useState(null);
71963
+ const [rps, setRps] = import_react20.useState("");
71714
71964
  const [headerMode, setHeaderMode] = import_react20.useState("default");
71715
71965
  const [customHeaders, setCustomHeaders] = import_react20.useState({});
71716
71966
  const [headerInputName, setHeaderInputName] = import_react20.useState("");
@@ -71728,7 +71978,7 @@ function PentestAgentDisplay() {
71728
71978
  isExecuting,
71729
71979
  setIsExecuting
71730
71980
  } = useAgent();
71731
- const inputs = headerMode === "custom" && headerEditMode === "input" ? ["target", "objective", "headerMode", "headerInputName", "headerInputValue"] : ["target", "objective", "headerMode"];
71981
+ const inputs = headerMode === "custom" && headerEditMode === "input" ? ["target", "objective", "rps", "headerMode", "headerInputName", "headerInputValue"] : ["target", "objective", "rps", "headerMode"];
71732
71982
  const headerEntries = Object.entries(customHeaders);
71733
71983
  useKeyboard((key) => {
71734
71984
  if (key.name === "escape") {
@@ -71748,7 +71998,7 @@ function PentestAgentDisplay() {
71748
71998
  if (hasStarted) {
71749
71999
  return;
71750
72000
  }
71751
- if (focusedIndex === 2 && key.name === "up") {
72001
+ if (focusedIndex === 3 && key.name === "up") {
71752
72002
  if (headerMode === "custom" && headerEditMode === "list") {
71753
72003
  if (headerEntries.length > 0) {
71754
72004
  setSelectedHeaderIndex((prev) => (prev - 1 + headerEntries.length) % headerEntries.length);
@@ -71762,7 +72012,7 @@ function PentestAgentDisplay() {
71762
72012
  }
71763
72013
  return;
71764
72014
  }
71765
- if (focusedIndex === 2 && key.name === "down") {
72015
+ if (focusedIndex === 3 && key.name === "down") {
71766
72016
  if (headerMode === "custom" && headerEditMode === "list") {
71767
72017
  if (headerEntries.length > 0) {
71768
72018
  setSelectedHeaderIndex((prev) => (prev + 1) % headerEntries.length);
@@ -71776,7 +72026,7 @@ function PentestAgentDisplay() {
71776
72026
  }
71777
72027
  return;
71778
72028
  }
71779
- if (headerMode === "custom" && focusedIndex === 2) {
72029
+ if (headerMode === "custom" && focusedIndex === 3) {
71780
72030
  if (key.name === "a" && headerEditMode === "list") {
71781
72031
  setHeaderEditMode("input");
71782
72032
  setHeaderInputName("");
@@ -71855,12 +72105,18 @@ function PentestAgentDisplay() {
71855
72105
  setFocusedIndex((prev) => (prev - 1 + inputs.length) % inputs.length);
71856
72106
  return;
71857
72107
  }
71858
- if (key.name === "return" && focusedIndex < 3) {
72108
+ if (key.name === "return" && focusedIndex < 4) {
71859
72109
  if (target && objective) {
72110
+ const parsedRps = rps ? parseInt(rps, 10) : undefined;
71860
72111
  const sessionConfig = {
71861
72112
  offensiveHeaders: {
71862
72113
  mode: headerMode,
71863
72114
  headers: headerMode === "custom" ? customHeaders : undefined
72115
+ },
72116
+ ...parsedRps && !isNaN(parsedRps) && parsedRps > 0 && {
72117
+ rateLimiter: {
72118
+ requestsPerSecond: parsedRps
72119
+ }
71864
72120
  }
71865
72121
  };
71866
72122
  beginExecution(sessionConfig);
@@ -72084,12 +72340,20 @@ Path: ${result.session.rootPath}`,
72084
72340
  onInput: setObjective,
72085
72341
  focused: focusedIndex === 1
72086
72342
  }, undefined, false, undefined, this),
72343
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Input, {
72344
+ label: "Rate Limit (RPS)",
72345
+ description: "Max requests/sec (leave empty for unlimited)",
72346
+ placeholder: "15 (recommended)",
72347
+ value: rps,
72348
+ onInput: setRps,
72349
+ focused: focusedIndex === 2
72350
+ }, undefined, false, undefined, this),
72087
72351
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
72088
72352
  border: true,
72089
72353
  width: "100%",
72090
72354
  borderStyle: "heavy",
72091
72355
  backgroundColor: "black",
72092
- borderColor: focusedIndex === 2 ? "green" : "gray",
72356
+ borderColor: focusedIndex === 3 ? "green" : "gray",
72093
72357
  flexDirection: "column",
72094
72358
  padding: 1,
72095
72359
  children: [
@@ -75307,6 +75571,7 @@ Mode: Pentest (Orchestrator)`,
75307
75571
  function ThoroughPentestAgentDisplay() {
75308
75572
  const [focusedIndex, setFocusedIndex] = import_react23.useState(0);
75309
75573
  const { closeThoroughPentest } = useCommand();
75574
+ const [rps, setRps] = import_react23.useState("");
75310
75575
  const [headerMode, setHeaderMode] = import_react23.useState("default");
75311
75576
  const [customHeaders, setCustomHeaders] = import_react23.useState({});
75312
75577
  const [headerInputName, setHeaderInputName] = import_react23.useState("");
@@ -75329,7 +75594,7 @@ function ThoroughPentestAgentDisplay() {
75329
75594
  beginExecution,
75330
75595
  openReport
75331
75596
  } = useThoroughPentestAgent();
75332
- const inputs = headerMode === "custom" && headerEditMode === "input" ? ["target", "headerMode", "headerInputName", "headerInputValue"] : ["target", "headerMode"];
75597
+ const inputs = headerMode === "custom" && headerEditMode === "input" ? ["target", "rps", "headerMode", "headerInputName", "headerInputValue"] : ["target", "rps", "headerMode"];
75333
75598
  const headerEntries = Object.entries(customHeaders);
75334
75599
  useKeyboard((key) => {
75335
75600
  if (key.name === "escape") {
@@ -75349,7 +75614,7 @@ function ThoroughPentestAgentDisplay() {
75349
75614
  if (hasStarted) {
75350
75615
  return;
75351
75616
  }
75352
- if (focusedIndex === 1 && key.name === "up") {
75617
+ if (focusedIndex === 2 && key.name === "up") {
75353
75618
  if (headerMode === "custom" && headerEditMode === "list") {
75354
75619
  if (headerEntries.length > 0) {
75355
75620
  setSelectedHeaderIndex((prev) => (prev - 1 + headerEntries.length) % headerEntries.length);
@@ -75363,7 +75628,7 @@ function ThoroughPentestAgentDisplay() {
75363
75628
  }
75364
75629
  return;
75365
75630
  }
75366
- if (focusedIndex === 1 && key.name === "down") {
75631
+ if (focusedIndex === 2 && key.name === "down") {
75367
75632
  if (headerMode === "custom" && headerEditMode === "list") {
75368
75633
  if (headerEntries.length > 0) {
75369
75634
  setSelectedHeaderIndex((prev) => (prev + 1) % headerEntries.length);
@@ -75377,7 +75642,7 @@ function ThoroughPentestAgentDisplay() {
75377
75642
  }
75378
75643
  return;
75379
75644
  }
75380
- if (headerMode === "custom" && focusedIndex === 1) {
75645
+ if (headerMode === "custom" && focusedIndex === 2) {
75381
75646
  if (key.name === "a" && headerEditMode === "list") {
75382
75647
  setHeaderEditMode("input");
75383
75648
  setHeaderInputName("");
@@ -75458,12 +75723,18 @@ function ThoroughPentestAgentDisplay() {
75458
75723
  setFocusedIndex((prev) => (prev - 1 + inputs.length) % inputs.length);
75459
75724
  return;
75460
75725
  }
75461
- if (key.name === "return" && focusedIndex < 2) {
75726
+ if (key.name === "return" && focusedIndex < 3) {
75462
75727
  if (target) {
75728
+ const parsedRps = rps ? parseInt(rps, 10) : undefined;
75463
75729
  const sessionConfig = {
75464
75730
  offensiveHeaders: {
75465
75731
  mode: headerMode,
75466
75732
  headers: headerMode === "custom" ? customHeaders : undefined
75733
+ },
75734
+ ...parsedRps && !isNaN(parsedRps) && parsedRps > 0 && {
75735
+ rateLimiter: {
75736
+ requestsPerSecond: parsedRps
75737
+ }
75467
75738
  }
75468
75739
  };
75469
75740
  beginExecution(sessionConfig);
@@ -75582,12 +75853,20 @@ function ThoroughPentestAgentDisplay() {
75582
75853
  onInput: setTarget,
75583
75854
  focused: focusedIndex === 0
75584
75855
  }, undefined, false, undefined, this),
75856
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Input, {
75857
+ label: "Rate Limit (RPS)",
75858
+ description: "Max requests/sec (leave empty for unlimited)",
75859
+ placeholder: "15 (recommended)",
75860
+ value: rps,
75861
+ onInput: setRps,
75862
+ focused: focusedIndex === 1
75863
+ }, undefined, false, undefined, this),
75585
75864
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
75586
75865
  border: true,
75587
75866
  width: "100%",
75588
75867
  borderStyle: "heavy",
75589
75868
  backgroundColor: "black",
75590
- borderColor: focusedIndex === 1 ? "green" : "gray",
75869
+ borderColor: focusedIndex === 2 ? "green" : "gray",
75591
75870
  flexDirection: "column",
75592
75871
  padding: 1,
75593
75872
  children: [