@pensar/apex 2.0.0 → 2.0.1

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.
Files changed (55) hide show
  1. package/README.md +20 -0
  2. package/build/agent-4g69jwmq.js +19 -0
  3. package/build/{agent-x1tnsg7n.js → agent-6nhperp2.js} +7 -10
  4. package/build/{agent-z8043nrm.js → agent-x7n47c84.js} +9 -12
  5. package/build/{apps-gdze0s68.js → apps-2ac4vt09.js} +15 -18
  6. package/build/{auth-24ca1qwx.js → auth-bmt98hz0.js} +16 -19
  7. package/build/authentication-c0aj9zaz.js +19 -0
  8. package/build/blackboxAgent-sgph70e4.js +19 -0
  9. package/build/{blackboxPentest-xwc031xm.js → blackboxPentest-xngbtdxb.js} +13 -16
  10. package/build/{cli-a20jcpmp.js → cli-0yptvbbm.js} +1 -1
  11. package/build/{cli-pkdjamer.js → cli-1f5zzrxj.js} +15 -5
  12. package/build/{cli-0v9x0eby.js → cli-88bhxzr1.js} +1 -1
  13. package/build/{cli-948dk60p.js → cli-8g5cwvbm.js} +1 -1
  14. package/build/{cli-mswm4k81.js → cli-cc13ydyx.js} +11 -1
  15. package/build/{cli-wdmqkshz.js → cli-ddtmgbqv.js} +2 -2
  16. package/build/{cli-h6nw89zf.js → cli-eptabm2j.js} +1 -1
  17. package/build/{cli-zpvmaxem.js → cli-f93g10xk.js} +2 -2
  18. package/build/{cli-zvq4gy61.js → cli-fa7nrded.js} +13 -6
  19. package/build/{cli-sw5swz40.js → cli-fxtbkw2f.js} +3 -3
  20. package/build/{cli-ntd42071.js → cli-hk03x6fq.js} +1 -1
  21. package/build/{cli-5fr9k6m4.js → cli-mfzkhttr.js} +58 -35
  22. package/build/{cli-31cara07.js → cli-pyzw545d.js} +8 -6
  23. package/build/{cli-cb5va0cs.js → cli-w2st266h.js} +10 -1
  24. package/build/{cli-h825qzmd.js → cli-z1dapp7v.js} +1492 -53
  25. package/build/{cli-k8mvghe1.js → cli-zpdmnz8c.js} +455 -921
  26. package/build/cli.js +105 -45
  27. package/build/{config-cmq1cxz3.js → config-j0gfjhrm.js} +3 -3
  28. package/build/{doctor-2bkpddws.js → doctor-zn8ms7gs.js} +8 -1
  29. package/build/{fixes-a4qscvkx.js → fixes-d8ytvyzn.js} +15 -18
  30. package/build/{index-hfhkjj2g.js → index-2t2cg8x0.js} +8 -11
  31. package/build/{index-54ep0ery.js → index-3cbcjqw1.js} +9 -12
  32. package/build/{index-48pjf9d2.js → index-528cyewc.js} +94 -126
  33. package/build/{index-2a1x5nnv.js → index-9d2es97h.js} +3 -3
  34. package/build/{index-aymt8k9w.js → index-a1sy2zak.js} +2 -2
  35. package/build/{index-s17r2akv.js → index-hjvqqkem.js} +4 -4
  36. package/build/{index-0fnbx38r.js → index-k6ttkac6.js} +20 -14
  37. package/build/{issues-5pnrspt7.js → issues-17kdjtdg.js} +15 -18
  38. package/build/{logs-1mfm901x.js → logs-r4rjar4m.js} +15 -18
  39. package/build/{offesecAgent-mrbyc93d.js → offesecAgent-azd8ahkm.js} +8 -11
  40. package/build/pentest-2vsjf0j8.js +28 -0
  41. package/build/{pentests-htmtq66d.js → pentests-npjb5q1h.js} +15 -18
  42. package/build/{targetedPentest-cpbd87rc.js → targetedPentest-m24wvscc.js} +9 -12
  43. package/build/threatModel-7akmfzzm.js +26 -0
  44. package/build/{uninstall-6y9dkgyt.js → uninstall-7pm6zcah.js} +1 -1
  45. package/build/{upload-7wtbr768.js → upload-wg0vxmk0.js} +8 -1
  46. package/build/{utils-trqnyj77.js → utils-gd1y4t26.js} +6 -8
  47. package/package.json +1 -1
  48. package/build/agent-84enr6xn.js +0 -22
  49. package/build/authentication-0k43jay4.js +0 -22
  50. package/build/blackboxAgent-76tnwwg7.js +0 -22
  51. package/build/cli-1yavz2pb.js +0 -17
  52. package/build/cli-3knnkdps.js +0 -666
  53. package/build/cli-s1nckt4k.js +0 -20
  54. package/build/pentest-wy4eeagc.js +0 -31
  55. package/build/threatModel-9n56z6a6.js +0 -29
@@ -4,7 +4,7 @@ import {
4
4
  init_auth,
5
5
  init_constants,
6
6
  signGatewayRequest
7
- } from "./cli-948dk60p.js";
7
+ } from "./cli-8g5cwvbm.js";
8
8
  import {
9
9
  AISDKError,
10
10
  APICallError,
@@ -32,6 +32,7 @@ import {
32
32
  delay,
33
33
  executeTool,
34
34
  exports_external,
35
+ exports_external1 as exports_external2,
35
36
  gateway,
36
37
  getErrorMessage,
37
38
  getErrorMessage1 as getErrorMessage2,
@@ -42,6 +43,7 @@ import {
42
43
  init_stream,
43
44
  init_v3,
44
45
  init_v4,
46
+ init_zod,
45
47
  isAbortError,
46
48
  isUrlSupported,
47
49
  lazySchema,
@@ -55,17 +57,24 @@ import {
55
57
  validateDownloadUrl,
56
58
  validateTypes,
57
59
  withUserAgentSuffix,
58
- zodSchema
60
+ zodSchema,
61
+ zod_default
59
62
  } from "./cli-e6rgwtpb.js";
60
63
  import {
61
64
  config,
62
65
  init_config
63
- } from "./cli-h6nw89zf.js";
66
+ } from "./cli-eptabm2j.js";
64
67
  import {
68
+ getCurrentVersion,
69
+ init_installation
70
+ } from "./cli-0yptvbbm.js";
71
+ import {
72
+ __callDispose,
65
73
  __commonJS,
66
74
  __esm,
67
75
  __require,
68
- __toESM
76
+ __toESM,
77
+ __using
69
78
  } from "./cli-8rxa073f.js";
70
79
 
71
80
  // node_modules/ai/dist/index.mjs
@@ -8776,6 +8785,20 @@ var init_models = __esm(() => {
8776
8785
  ];
8777
8786
  });
8778
8787
 
8788
+ // src/core/util/lazyLogger.ts
8789
+ function scopedLogger(factory) {
8790
+ let instance;
8791
+ const get = () => instance ??= factory();
8792
+ return new Proxy({}, {
8793
+ get(_target, prop) {
8794
+ const inst = get();
8795
+ const value = inst[prop];
8796
+ return typeof value === "function" ? value.bind(inst) : value;
8797
+ }
8798
+ });
8799
+ }
8800
+ var init_lazyLogger = () => {};
8801
+
8779
8802
  // node_modules/@ai-sdk/provider-utils/dist/index.mjs
8780
8803
  function combineHeaders(...headers) {
8781
8804
  return headers.reduce((combinedHeaders, currentHeaders) => ({
@@ -42434,7 +42457,7 @@ function wrapStreamWithErrorHandler(originalStream, messagesContainer, opts, mod
42434
42457
  if (!isCtxError && isStreamIdleTimeoutError(error) && idleResumeCount < MAX_IDLE_RESUME_RETRIES && messagesContainer.current.length > 0) {
42435
42458
  const nextIdleCount = idleResumeCount + 1;
42436
42459
  if (!silent) {
42437
- console.warn(`Stream stalled (attempt ${nextIdleCount}/${MAX_IDLE_RESUME_RETRIES}), resuming with ${messagesContainer.current.length} messages: ${errorMessage}`);
42460
+ log.warn(`Stream stalled (attempt ${nextIdleCount}/${MAX_IDLE_RESUME_RETRIES}), resuming with ${messagesContainer.current.length} messages: ${errorMessage}`);
42438
42461
  }
42439
42462
  const retriedStream = streamResponse({
42440
42463
  ...opts,
@@ -42450,7 +42473,7 @@ function wrapStreamWithErrorHandler(originalStream, messagesContainer, opts, mod
42450
42473
  const nextRetryCount = rateLimitRetryCount + 1;
42451
42474
  const delayMs = Math.min(1000 * nextRetryCount, 30000);
42452
42475
  if (!silent) {
42453
- console.warn(`Rate limit error (attempt ${nextRetryCount}/${MAX_RATE_LIMIT_RETRIES}), waiting ${delayMs}ms: ${errorMessage}`);
42476
+ log.warn(`Rate limit error (attempt ${nextRetryCount}/${MAX_RATE_LIMIT_RETRIES}), waiting ${delayMs}ms: ${errorMessage}`);
42454
42477
  }
42455
42478
  await new Promise((resolve4) => setTimeout(resolve4, delayMs));
42456
42479
  const retriedStream = streamResponse({
@@ -42482,7 +42505,7 @@ function wrapStreamWithErrorHandler(originalStream, messagesContainer, opts, mod
42482
42505
  let postReactiveDepth = opts._restartDepth ?? 0;
42483
42506
  if (fitted.fitsBudget && fitted.modified) {
42484
42507
  if (!silent) {
42485
- console.warn(`Context length error — Layer 1+2 reduced to ~${fitted.estimatedInputTokens} tokens, retrying`);
42508
+ log.warn(`Context length error — Layer 1+2 reduced to ~${fitted.estimatedInputTokens} tokens, retrying`);
42486
42509
  }
42487
42510
  try {
42488
42511
  const retried = streamResponse({
@@ -42504,7 +42527,7 @@ function wrapStreamWithErrorHandler(originalStream, messagesContainer, opts, mod
42504
42527
  }
42505
42528
  const messagesForSummary = messagesContainer.current;
42506
42529
  if (!silent) {
42507
- console.warn(`Context length error — summarizing ${messagesForSummary.length} messages`);
42530
+ log.warn(`Context length error — summarizing ${messagesForSummary.length} messages`);
42508
42531
  }
42509
42532
  try {
42510
42533
  const summarizationStream = createSummarizationStream(messagesForSummary, { ...opts, _restartDepth: postReactiveDepth }, model);
@@ -42517,7 +42540,7 @@ function wrapStreamWithErrorHandler(originalStream, messagesContainer, opts, mod
42517
42540
  }
42518
42541
  if (!silent) {
42519
42542
  const sumMsg = summarizeError instanceof Error ? summarizeError.message : String(summarizeError);
42520
- console.error(`Layer 3 summarization failed (${sumMsg}). Falling back to minimal-context restart.`);
42543
+ log.warn(`Layer 3 summarization failed (${sumMsg}). Falling back to minimal-context restart.`);
42521
42544
  }
42522
42545
  opts.onSummarized?.("");
42523
42546
  const minimalPrompt = typeof opts.prompt === "string" && opts.prompt.length > 0 ? opts.prompt.slice(0, 4000) : MINIMAL_RESTART_PROMPT;
@@ -42533,7 +42556,9 @@ function wrapStreamWithErrorHandler(originalStream, messagesContainer, opts, mod
42533
42556
  }
42534
42557
  } else {
42535
42558
  if (!silent) {
42536
- console.error("Non-recoverable stream error, re-throwing:", errorMessage);
42559
+ log.error("Non-recoverable stream error, re-throwing", {
42560
+ error: errorMessage
42561
+ });
42537
42562
  }
42538
42563
  throw error;
42539
42564
  }
@@ -42620,13 +42645,13 @@ function streamResponse(opts) {
42620
42645
  fittedMessages = fitted.messages;
42621
42646
  proactiveFitFailed = !fitted.fitsBudget;
42622
42647
  if (fitted.modified && !silent) {
42623
- console.warn(`Proactive context fit: compacted messages to ~${fitted.estimatedInputTokens} tokens (fits=${fitted.fitsBudget})`);
42648
+ log.warn(`Proactive context fit: compacted messages to ~${fitted.estimatedInputTokens} tokens (fits=${fitted.fitsBudget})`);
42624
42649
  }
42625
42650
  }
42626
42651
  const messagesContainer = { current: fittedMessages || [] };
42627
42652
  if (proactiveFitFailed && fittedMessages) {
42628
42653
  if (!silent) {
42629
- console.warn(`Proactive context fit returned fitsBudget=false on ${fittedMessages.length} messages — escalating to summarization before send`);
42654
+ log.warn(`Proactive context fit returned fitsBudget=false on ${fittedMessages.length} messages — escalating to summarization before send`);
42630
42655
  }
42631
42656
  return wrapStreamWithErrorHandler(createSummarizationStream(fittedMessages, opts, providerModel), messagesContainer, opts, providerModel, silent);
42632
42657
  }
@@ -42719,16 +42744,17 @@ function streamResponse(opts) {
42719
42744
  }) => {
42720
42745
  try {
42721
42746
  if (!silent) {
42722
- console.log(`\uD83D\uDD27 Repairing tool call: ${toolCall.toolName}`);
42723
- console.log(` Error: ${error.message || error}`);
42747
+ log.debug(`Repairing tool call: ${toolCall.toolName}`, {
42748
+ error: error.message || String(error)
42749
+ });
42724
42750
  if (error.message && (error.message.includes("severity") || error.message.includes("riskLevel"))) {
42725
- console.log(` Note: This appears to be an enum validation error. Tool call repair will normalize the value.`);
42751
+ log.debug("Enum validation error tool call repair will normalize the value");
42726
42752
  }
42727
42753
  }
42728
42754
  const tool6 = tools2[toolCall.toolName];
42729
42755
  if (!tool6 || !tool6.inputSchema) {
42730
42756
  if (!silent) {
42731
- console.error(`Cannot repair tool call: ${toolCall.toolName} not found or has no schema`);
42757
+ log.warn(`Cannot repair tool call: ${toolCall.toolName} not found or has no schema`);
42732
42758
  }
42733
42759
  return null;
42734
42760
  }
@@ -42792,14 +42818,16 @@ function streamResponse(opts) {
42792
42818
  }
42793
42819
  if (repairedArgs === undefined || repairedArgs === null) {
42794
42820
  if (!silent) {
42795
- console.error(`Tool call repair for "${toolCall.toolName}" produced no valid output`);
42821
+ log.warn(`Tool call repair for "${toolCall.toolName}" produced no valid output`);
42796
42822
  }
42797
42823
  return null;
42798
42824
  }
42799
42825
  return { ...toolCall, input: JSON.stringify(repairedArgs) };
42800
42826
  } catch (repairError) {
42801
42827
  if (!silent) {
42802
- console.error("Error repairing tool call:", repairError instanceof Error ? repairError.message : String(repairError));
42828
+ log.warn("Error repairing tool call", {
42829
+ error: String(repairError)
42830
+ });
42803
42831
  }
42804
42832
  return null;
42805
42833
  }
@@ -42812,12 +42840,14 @@ function streamResponse(opts) {
42812
42840
  const outerErrorMessage = error instanceof Error ? error.message : String(error);
42813
42841
  if (isContextLengthError) {
42814
42842
  if (!silent) {
42815
- console.warn(`Context length error, summarizing ${messagesContainer.current.length} messages: `, outerErrorMessage);
42843
+ log.warn(`Context length error, summarizing ${messagesContainer.current.length} messages`, { error: outerErrorMessage });
42816
42844
  }
42817
42845
  return wrapStreamWithErrorHandler(createSummarizationStream(messagesContainer.current, opts, providerModel), messagesContainer, opts, providerModel, silent);
42818
42846
  }
42819
42847
  if (!silent) {
42820
- console.error("Non-context length error, re-throwing", outerErrorMessage);
42848
+ log.error("Non-context length error, re-throwing", {
42849
+ error: outerErrorMessage
42850
+ });
42821
42851
  }
42822
42852
  throw error;
42823
42853
  }
@@ -42890,14 +42920,17 @@ async function generateObjectResponse(opts) {
42890
42920
  }
42891
42921
  throw lastError;
42892
42922
  }
42893
- var DEFAULT_OPENAI_REASONING_EFFORT = "medium", OPENAI_REASONING_MODEL_IDS, _usageCallback = null, MAX_RATE_LIMIT_RETRIES = 20, MAX_IDLE_RESUME_RETRIES = 3, STREAM_IDLE_TIMEOUT_MS, StreamIdleTimeoutError, MAX_OBJECT_RATE_LIMIT_RETRIES = 8, ContextLengthError, ContextLengthExhaustedError, MAX_RESTART_DEPTH = 3, MAX_TOOL_INPUT_CHARS = 8000, MAX_SCHEMA_CHARS = 6000, MINIMAL_RESTART_PROMPT = "Continue the previous task. Earlier context was discarded due to repeated context-length errors.";
42923
+ var log, DEFAULT_OPENAI_REASONING_EFFORT = "medium", OPENAI_REASONING_MODEL_IDS, _usageCallback = null, MAX_RATE_LIMIT_RETRIES = 20, MAX_IDLE_RESUME_RETRIES = 3, STREAM_IDLE_TIMEOUT_MS, StreamIdleTimeoutError, MAX_OBJECT_RATE_LIMIT_RETRIES = 8, ContextLengthError, ContextLengthExhaustedError, MAX_RESTART_DEPTH = 3, MAX_TOOL_INPUT_CHARS = 8000, MAX_SCHEMA_CHARS = 6000, MINIMAL_RESTART_PROMPT = "Continue the previous task. Earlier context was discarded due to repeated context-length errors.";
42894
42924
  var init_ai = __esm(() => {
42895
42925
  init_dist4();
42926
+ init_structured();
42896
42927
  init_observability();
42928
+ init_lazyLogger();
42897
42929
  init_caching();
42898
42930
  init_contextManagement();
42899
42931
  init_models();
42900
42932
  init_utils();
42933
+ log = scopedLogger(() => createLogger("ai"));
42901
42934
  OPENAI_REASONING_MODEL_IDS = new Set([
42902
42935
  "gpt-5",
42903
42936
  "gpt-5-2025-08-07",
@@ -42937,6 +42970,1407 @@ var init_ai = __esm(() => {
42937
42970
  };
42938
42971
  });
42939
42972
 
42973
+ // src/core/ai/index.ts
42974
+ var init_ai2 = __esm(() => {
42975
+ init_ai();
42976
+ init_models();
42977
+ init_utils();
42978
+ });
42979
+
42980
+ // src/util/name.ts
42981
+ function generateRandomName() {
42982
+ const adj = adjectives[Math.floor(Math.random() * adjectives.length)] ?? "swift";
42983
+ const noun = nouns[Math.floor(Math.random() * nouns.length)] ?? "falcon";
42984
+ return `${adj}-${noun}`;
42985
+ }
42986
+ async function generateSessionName(opts) {
42987
+ const { targets, userMessage, model, authConfig, abortSignal } = opts;
42988
+ const contextParts = [];
42989
+ if (targets.length > 0) {
42990
+ contextParts.push(`Target(s): ${targets.join(", ")}`);
42991
+ }
42992
+ if (userMessage) {
42993
+ contextParts.push(`User objective: ${userMessage}`);
42994
+ }
42995
+ if (contextParts.length === 0)
42996
+ return null;
42997
+ const prompt = [
42998
+ "Generate a short, descriptive name for a penetration testing session.",
42999
+ "The name should be 2-4 lowercase words separated by hyphens.",
43000
+ "It should capture the key aspect of the target or task — e.g. 'acme-api-pentest', 'login-auth-bypass', 'ecommerce-checkout-test'.",
43001
+ "",
43002
+ ...contextParts
43003
+ ].join(`
43004
+ `);
43005
+ try {
43006
+ const result = await generateObjectResponse({
43007
+ model,
43008
+ schema: sessionNameSchema,
43009
+ prompt,
43010
+ maxTokens: 50,
43011
+ temperature: 0.7,
43012
+ authConfig,
43013
+ abortSignal
43014
+ });
43015
+ if (!result?.name)
43016
+ return null;
43017
+ const name29 = result.name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 50);
43018
+ return name29 || null;
43019
+ } catch {
43020
+ return null;
43021
+ }
43022
+ }
43023
+ var adjectives, nouns, sessionNameSchema;
43024
+ var init_name = __esm(() => {
43025
+ init_zod();
43026
+ init_ai2();
43027
+ adjectives = [
43028
+ "swift",
43029
+ "bright",
43030
+ "calm",
43031
+ "bold",
43032
+ "keen",
43033
+ "noble",
43034
+ "quick",
43035
+ "sharp",
43036
+ "vivid",
43037
+ "warm",
43038
+ "agile",
43039
+ "brave",
43040
+ "clever",
43041
+ "daring",
43042
+ "eager",
43043
+ "fierce",
43044
+ "gentle",
43045
+ "humble",
43046
+ "jolly",
43047
+ "lively",
43048
+ "merry",
43049
+ "nimble",
43050
+ "proud",
43051
+ "quiet",
43052
+ "rapid",
43053
+ "serene",
43054
+ "sturdy",
43055
+ "tender",
43056
+ "valiant",
43057
+ "witty",
43058
+ "zealous"
43059
+ ];
43060
+ nouns = [
43061
+ "falcon",
43062
+ "wolf",
43063
+ "hawk",
43064
+ "bear",
43065
+ "lion",
43066
+ "tiger",
43067
+ "eagle",
43068
+ "raven",
43069
+ "phoenix",
43070
+ "dragon",
43071
+ "panther",
43072
+ "cobra",
43073
+ "viper",
43074
+ "shark",
43075
+ "orca",
43076
+ "mantis",
43077
+ "spider",
43078
+ "scorpion",
43079
+ "hydra",
43080
+ "griffin",
43081
+ "sphinx",
43082
+ "kraken",
43083
+ "cipher",
43084
+ "nexus",
43085
+ "prism",
43086
+ "vector",
43087
+ "matrix",
43088
+ "pulse",
43089
+ "surge",
43090
+ "flux"
43091
+ ];
43092
+ sessionNameSchema = exports_external2.object({
43093
+ name: exports_external2.string().describe("A short, descriptive session name (2-4 words, lowercase, hyphenated)")
43094
+ });
43095
+ });
43096
+
43097
+ // src/core/credentials/manager.ts
43098
+ import { randomBytes } from "crypto";
43099
+ function generateCredentialId() {
43100
+ return `cred_${randomBytes(8).toString("hex")}`;
43101
+ }
43102
+ function inferType(cred) {
43103
+ const hasPwd = !!cred.password;
43104
+ const hasApiKey = !!cred.apiKey;
43105
+ const hasBearer = !!cred.tokens?.bearerToken;
43106
+ const hasHeaders = !!cred.tokens?.customHeaders && Object.keys(cred.tokens.customHeaders).length > 0;
43107
+ const hasCookies = !!cred.tokens?.cookies;
43108
+ const count = (hasPwd ? 1 : 0) + (hasApiKey ? 1 : 0) + (hasBearer ? 1 : 0) + (hasHeaders ? 1 : 0) + (hasCookies ? 1 : 0);
43109
+ if (count > 1)
43110
+ return "composite";
43111
+ if (hasPwd)
43112
+ return "username-password";
43113
+ if (hasApiKey)
43114
+ return "api-key";
43115
+ if (hasBearer)
43116
+ return "bearer-token";
43117
+ if (hasHeaders)
43118
+ return "custom-headers";
43119
+ if (hasCookies)
43120
+ return "cookies";
43121
+ return "username-password";
43122
+ }
43123
+ function toReference(stored) {
43124
+ const ref = {
43125
+ id: stored.id,
43126
+ type: stored.type
43127
+ };
43128
+ if (stored.label)
43129
+ ref.label = stored.label;
43130
+ if (stored.role)
43131
+ ref.role = stored.role;
43132
+ if (stored.username)
43133
+ ref.username = stored.username;
43134
+ if (stored.loginUrl)
43135
+ ref.loginUrl = stored.loginUrl;
43136
+ if (stored.tokens?.customHeaders) {
43137
+ ref.customHeaderKeys = Object.keys(stored.tokens.customHeaders);
43138
+ }
43139
+ const ctx = stored.metadata?.context;
43140
+ if (typeof ctx === "string" && ctx)
43141
+ ref.context = ctx;
43142
+ return ref;
43143
+ }
43144
+
43145
+ class CredentialManager {
43146
+ store = new Map;
43147
+ findDuplicate(candidate) {
43148
+ for (const [id, existing] of this.store) {
43149
+ if (existing.username === candidate.username && existing.password === candidate.password && existing.apiKey === candidate.apiKey && existing.loginUrl === candidate.loginUrl && existing.tokens?.bearerToken === candidate.tokens?.bearerToken && existing.tokens?.cookies === candidate.tokens?.cookies && existing.tokens?.sessionToken === candidate.tokens?.sessionToken && JSON.stringify(existing.tokens?.customHeaders) === JSON.stringify(candidate.tokens?.customHeaders)) {
43150
+ return id;
43151
+ }
43152
+ }
43153
+ return;
43154
+ }
43155
+ add(input) {
43156
+ const id = input.id ?? generateCredentialId();
43157
+ const type = input.type ?? inferType(input);
43158
+ const stored = { ...input, id, type };
43159
+ this.store.set(id, stored);
43160
+ return id;
43161
+ }
43162
+ addFromAuthCredentials(creds, extra) {
43163
+ const candidate = {
43164
+ username: creds.username,
43165
+ password: creds.password,
43166
+ apiKey: creds.apiKey,
43167
+ loginUrl: creds.loginUrl,
43168
+ additionalFields: creds.additionalFields,
43169
+ tokens: creds.tokens,
43170
+ label: extra?.label,
43171
+ role: extra?.role ?? creds.role,
43172
+ metadata: creds.context ? { context: creds.context } : undefined
43173
+ };
43174
+ const existingId = this.findDuplicate(candidate);
43175
+ if (existingId)
43176
+ return existingId;
43177
+ return this.add(candidate);
43178
+ }
43179
+ resolve(credentialId) {
43180
+ return this.store.get(credentialId);
43181
+ }
43182
+ getReference(credentialId) {
43183
+ const stored = this.store.get(credentialId);
43184
+ if (!stored)
43185
+ return;
43186
+ return toReference(stored);
43187
+ }
43188
+ listReferences() {
43189
+ return Array.from(this.store.values()).map(toReference);
43190
+ }
43191
+ listCredentialsWithHeaders() {
43192
+ const out = [];
43193
+ for (const stored of this.store.values()) {
43194
+ const headers = stored.tokens?.customHeaders;
43195
+ if (headers && Object.keys(headers).length > 0) {
43196
+ out.push({ tokens: { customHeaders: { ...headers } } });
43197
+ }
43198
+ }
43199
+ return out;
43200
+ }
43201
+ remove(credentialId) {
43202
+ return this.store.delete(credentialId);
43203
+ }
43204
+ get size() {
43205
+ return this.store.size;
43206
+ }
43207
+ clear() {
43208
+ this.store.clear();
43209
+ }
43210
+ toAuthCredentials(credentialId) {
43211
+ const stored = this.resolve(credentialId);
43212
+ if (!stored)
43213
+ return;
43214
+ const result = {};
43215
+ if (stored.username)
43216
+ result.username = stored.username;
43217
+ if (stored.password)
43218
+ result.password = stored.password;
43219
+ if (stored.apiKey)
43220
+ result.apiKey = stored.apiKey;
43221
+ if (stored.loginUrl)
43222
+ result.loginUrl = stored.loginUrl;
43223
+ if (stored.additionalFields)
43224
+ result.additionalFields = stored.additionalFields;
43225
+ if (stored.tokens)
43226
+ result.tokens = { ...stored.tokens };
43227
+ return result;
43228
+ }
43229
+ formatForPrompt() {
43230
+ const refs = this.listReferences();
43231
+ if (refs.length === 0)
43232
+ return "";
43233
+ const lines = refs.map((ref) => {
43234
+ const parts = [`- Credential ID: ${ref.id}`];
43235
+ if (ref.label)
43236
+ parts.push(` Label: ${ref.label}`);
43237
+ parts.push(` Type: ${ref.type}`);
43238
+ if (ref.role)
43239
+ parts.push(` Role: ${ref.role}`);
43240
+ if (ref.username)
43241
+ parts.push(` Username: ${ref.username}`);
43242
+ if (ref.loginUrl)
43243
+ parts.push(` Login URL: ${ref.loginUrl}`);
43244
+ if (ref.customHeaderKeys?.length) {
43245
+ parts.push(` Header keys: ${ref.customHeaderKeys.join(", ")}`);
43246
+ }
43247
+ if (ref.context)
43248
+ parts.push(` Context: ${ref.context}`);
43249
+ return parts.join(`
43250
+ `);
43251
+ });
43252
+ return `<available_credentials>
43253
+ The following credentials are available. To use a credential, pass its ID to the appropriate tool.
43254
+ Do NOT ask the user for passwords or secrets — they are resolved automatically from the credential ID.
43255
+
43256
+ ${lines.join(`
43257
+
43258
+ `)}
43259
+ </available_credentials>`;
43260
+ }
43261
+ }
43262
+ var init_manager = () => {};
43263
+
43264
+ // src/core/credentials/index.ts
43265
+ var init_credentials = __esm(() => {
43266
+ init_manager();
43267
+ });
43268
+
43269
+ // src/core/id/id.ts
43270
+ import { randomBytes as randomBytes2 } from "crypto";
43271
+ function schema(prefix) {
43272
+ return zod_default.string().startsWith(prefixes[prefix]);
43273
+ }
43274
+ function descending(prefix, given) {
43275
+ return generateID(prefix, true, given);
43276
+ }
43277
+ function generateID(prefix, descending2, given) {
43278
+ if (!given) {
43279
+ return create(prefix, descending2);
43280
+ }
43281
+ if (!given.startsWith(prefixes[prefix])) {
43282
+ throw new Error(`ID ${given} does not start with ${prefixes[prefix]}`);
43283
+ }
43284
+ return given;
43285
+ }
43286
+ function randomBase62(length) {
43287
+ const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
43288
+ let result = "";
43289
+ const bytes = randomBytes2(length);
43290
+ for (let i = 0;i < length; i++) {
43291
+ result += chars[bytes[i] % 62];
43292
+ }
43293
+ return result;
43294
+ }
43295
+ function create(prefix, descending2, timestamp) {
43296
+ const currentTimestamp = timestamp ?? Date.now();
43297
+ if (currentTimestamp !== lastTimestamp) {
43298
+ lastTimestamp = currentTimestamp;
43299
+ counter = 0;
43300
+ }
43301
+ counter++;
43302
+ let now2 = BigInt(currentTimestamp) * BigInt(4096) + BigInt(counter);
43303
+ now2 = descending2 ? ~now2 : now2;
43304
+ const timeBytes = Buffer.alloc(6);
43305
+ for (let i = 0;i < 6; i++) {
43306
+ timeBytes[i] = Number(now2 >> BigInt(40 - 8 * i) & BigInt(255));
43307
+ }
43308
+ return prefixes[prefix] + "_" + timeBytes.toString("hex") + randomBase62(LENGTH - 12);
43309
+ }
43310
+ var prefixes, LENGTH = 26, lastTimestamp = 0, counter = 0;
43311
+ var init_id = __esm(() => {
43312
+ init_zod();
43313
+ prefixes = {
43314
+ session: "ses",
43315
+ message: "msg",
43316
+ permission: "per",
43317
+ user: "usr",
43318
+ part: "prt"
43319
+ };
43320
+ });
43321
+
43322
+ // src/core/services/rateLimiter/index.ts
43323
+ function sleep(ms) {
43324
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
43325
+ }
43326
+
43327
+ class RateLimiter {
43328
+ tokens;
43329
+ lastRefillTime;
43330
+ rps;
43331
+ bucketSize;
43332
+ msPerToken;
43333
+ queue;
43334
+ constructor(config2) {
43335
+ this.rps = config2?.requestsPerSecond;
43336
+ this.bucketSize = this.rps ? 1 : 0;
43337
+ this.tokens = this.bucketSize;
43338
+ this.lastRefillTime = performance.now();
43339
+ this.msPerToken = this.rps ? 1000 / this.rps : undefined;
43340
+ this.queue = Promise.resolve();
43341
+ }
43342
+ async acquireSlot() {
43343
+ if (!this.rps || !this.msPerToken)
43344
+ return;
43345
+ const previousPromise = this.queue;
43346
+ let resolveCurrentRequest;
43347
+ this.queue = new Promise((resolve4) => {
43348
+ resolveCurrentRequest = resolve4;
43349
+ });
43350
+ await previousPromise;
43351
+ try {
43352
+ const now2 = performance.now();
43353
+ this.refill(now2);
43354
+ if (this.tokens < 1) {
43355
+ const waitTime = (1 - this.tokens) * this.msPerToken;
43356
+ await sleep(waitTime);
43357
+ const nowAfterSleep = performance.now();
43358
+ this.refill(nowAfterSleep);
43359
+ }
43360
+ this.tokens -= 1;
43361
+ } finally {
43362
+ resolveCurrentRequest();
43363
+ }
43364
+ }
43365
+ refill(now2) {
43366
+ if (this.tokens >= this.bucketSize) {
43367
+ this.lastRefillTime = now2;
43368
+ return;
43369
+ }
43370
+ const elapsed = now2 - this.lastRefillTime;
43371
+ const tokensToAdd = elapsed / this.msPerToken;
43372
+ this.tokens = Math.min(this.bucketSize, this.tokens + tokensToAdd);
43373
+ this.lastRefillTime = now2;
43374
+ }
43375
+ isEnabled() {
43376
+ return this.rps !== undefined;
43377
+ }
43378
+ }
43379
+ var init_rateLimiter = () => {};
43380
+
43381
+ // src/util/errors.ts
43382
+ var NamedError;
43383
+ var init_errors = __esm(() => {
43384
+ init_zod();
43385
+ NamedError = class NamedError extends Error {
43386
+ static create(name29, data) {
43387
+ const schema2 = zod_default.object({
43388
+ name: zod_default.literal(name29),
43389
+ data
43390
+ });
43391
+ const result = class extends NamedError {
43392
+ data;
43393
+ static Schema = schema2;
43394
+ name = name29;
43395
+ constructor(data2, options) {
43396
+ super(name29, options);
43397
+ this.data = data2;
43398
+ this.name = name29;
43399
+ }
43400
+ static isInstance(input) {
43401
+ return typeof input === "object" && input !== null && "name" in input && input.name === name29;
43402
+ }
43403
+ schema() {
43404
+ return schema2;
43405
+ }
43406
+ toObject() {
43407
+ return {
43408
+ name: name29,
43409
+ data: this.data
43410
+ };
43411
+ }
43412
+ };
43413
+ Object.defineProperty(result, "name", { value: name29 });
43414
+ return result;
43415
+ }
43416
+ static Unknown = NamedError.create("UnknownError", zod_default.object({
43417
+ message: zod_default.string()
43418
+ }));
43419
+ };
43420
+ });
43421
+
43422
+ // src/util/lock.ts
43423
+ function getLock(key) {
43424
+ let lock = locks.get(key);
43425
+ if (!lock) {
43426
+ lock = {
43427
+ readers: 0,
43428
+ writer: false,
43429
+ waitingReaders: [],
43430
+ waitingWriters: []
43431
+ };
43432
+ locks.set(key, lock);
43433
+ }
43434
+ return lock;
43435
+ }
43436
+ function processQueue(key) {
43437
+ const lock = locks.get(key);
43438
+ if (!lock || lock.writer || lock.readers > 0)
43439
+ return;
43440
+ if (lock.waitingWriters.length > 0) {
43441
+ const nextWriter = lock.waitingWriters.shift();
43442
+ nextWriter?.();
43443
+ return;
43444
+ }
43445
+ while (lock.waitingReaders.length > 0) {
43446
+ const nextReader = lock.waitingReaders.shift();
43447
+ nextReader?.();
43448
+ }
43449
+ if (lock.readers === 0 && !lock.writer && lock.waitingReaders.length === 0 && lock.waitingWriters.length === 0) {
43450
+ locks.delete(key);
43451
+ }
43452
+ }
43453
+ async function read(key) {
43454
+ const lock = getLock(key);
43455
+ return new Promise((resolve4) => {
43456
+ if (!lock.writer && lock.waitingWriters.length === 0) {
43457
+ lock.readers++;
43458
+ resolve4({
43459
+ [Symbol.dispose]: () => {
43460
+ lock.readers--;
43461
+ processQueue(key);
43462
+ }
43463
+ });
43464
+ } else {
43465
+ lock.waitingReaders.push(() => {
43466
+ lock.readers++;
43467
+ resolve4({
43468
+ [Symbol.dispose]: () => {
43469
+ lock.readers--;
43470
+ processQueue(key);
43471
+ }
43472
+ });
43473
+ });
43474
+ }
43475
+ });
43476
+ }
43477
+ async function write(key) {
43478
+ const lock = getLock(key);
43479
+ return new Promise((resolve4) => {
43480
+ if (!lock.writer && lock.readers === 0) {
43481
+ lock.writer = true;
43482
+ resolve4({
43483
+ [Symbol.dispose]: () => {
43484
+ lock.writer = false;
43485
+ processQueue(key);
43486
+ }
43487
+ });
43488
+ } else {
43489
+ lock.waitingWriters.push(() => {
43490
+ lock.writer = true;
43491
+ resolve4({
43492
+ [Symbol.dispose]: () => {
43493
+ lock.writer = false;
43494
+ processQueue(key);
43495
+ }
43496
+ });
43497
+ });
43498
+ }
43499
+ });
43500
+ }
43501
+ var locks;
43502
+ var init_lock = __esm(() => {
43503
+ locks = new Map;
43504
+ });
43505
+
43506
+ // src/core/storage/index.ts
43507
+ import fs, { readdir } from "fs/promises";
43508
+ import os from "os";
43509
+ import path from "path";
43510
+ function getBaseDir() {
43511
+ return process.env.PENSAR_DATA_DIR ?? path.join(os.homedir(), ".pensar");
43512
+ }
43513
+ async function write2(key, content, ext) {
43514
+ const dir = getBaseDir();
43515
+ const target = path.join(dir, ...key) + (ext ? ext : ".json");
43516
+ return withErrorHandling(async () => {
43517
+ let __stack = [];
43518
+ try {
43519
+ const _ = __using(__stack, await write(target), 0);
43520
+ await fs.mkdir(path.dirname(target), { recursive: true });
43521
+ await fs.writeFile(target, JSON.stringify(content, null, 2), "utf-8");
43522
+ } catch (_catch) {
43523
+ var _err = _catch, _hasErr = 1;
43524
+ } finally {
43525
+ __callDispose(__stack, _err, _hasErr);
43526
+ }
43527
+ });
43528
+ }
43529
+ async function createDir(key) {
43530
+ const dir = getBaseDir();
43531
+ const target = path.join(dir, ...key);
43532
+ return withErrorHandling(async () => {
43533
+ let __stack = [];
43534
+ try {
43535
+ const _ = __using(__stack, await write(target), 0);
43536
+ await fs.mkdir(target, { recursive: true });
43537
+ } catch (_catch) {
43538
+ var _err = _catch, _hasErr = 1;
43539
+ } finally {
43540
+ __callDispose(__stack, _err, _hasErr);
43541
+ }
43542
+ });
43543
+ }
43544
+ async function writeRaw(key, content) {
43545
+ const dir = getBaseDir();
43546
+ const target = path.join(dir, ...key);
43547
+ return withErrorHandling(async () => {
43548
+ let __stack = [];
43549
+ try {
43550
+ const _ = __using(__stack, await write(target), 0);
43551
+ const parentDir = path.dirname(target);
43552
+ await fs.mkdir(parentDir, { recursive: true });
43553
+ await fs.writeFile(target, content, "utf-8");
43554
+ } catch (_catch) {
43555
+ var _err = _catch, _hasErr = 1;
43556
+ } finally {
43557
+ __callDispose(__stack, _err, _hasErr);
43558
+ }
43559
+ });
43560
+ }
43561
+ async function read2(key, ext) {
43562
+ const dir = getBaseDir();
43563
+ const target = path.join(dir, ...key) + (ext ? ext : ".json");
43564
+ return withErrorHandling(async () => {
43565
+ let __stack = [];
43566
+ try {
43567
+ const _ = __using(__stack, await read(target), 0);
43568
+ const text2 = await fs.readFile(target, "utf-8");
43569
+ const result = ext ? text2 : JSON.parse(text2);
43570
+ return result;
43571
+ } catch (_catch) {
43572
+ var _err = _catch, _hasErr = 1;
43573
+ } finally {
43574
+ __callDispose(__stack, _err, _hasErr);
43575
+ }
43576
+ });
43577
+ }
43578
+ async function update(key, fn, ext) {
43579
+ const dir = getBaseDir();
43580
+ const target = path.join(dir, ...key) + (ext ? ext : ".json");
43581
+ return withErrorHandling(async () => {
43582
+ let __stack = [];
43583
+ try {
43584
+ const _ = __using(__stack, await write(target), 0);
43585
+ const text2 = await fs.readFile(target, "utf-8");
43586
+ const content = ext ? text2 : JSON.parse(text2);
43587
+ fn(content);
43588
+ await fs.writeFile(target, JSON.stringify(content, null, 2), "utf-8");
43589
+ return content;
43590
+ } catch (_catch) {
43591
+ var _err = _catch, _hasErr = 1;
43592
+ } finally {
43593
+ __callDispose(__stack, _err, _hasErr);
43594
+ }
43595
+ });
43596
+ }
43597
+ async function withErrorHandling(body) {
43598
+ return body().catch((e) => {
43599
+ if (!(e instanceof Error))
43600
+ throw e;
43601
+ const errnoExcpetion = e;
43602
+ if (errnoExcpetion.code === "ENOENT") {
43603
+ throw new NotFoundError({
43604
+ message: `Resource not found: ${errnoExcpetion.path}`
43605
+ });
43606
+ }
43607
+ throw e;
43608
+ });
43609
+ }
43610
+ async function listFilesRecursively(dir) {
43611
+ const entries = await readdir(dir, { withFileTypes: true });
43612
+ const files = [];
43613
+ for (const entry of entries) {
43614
+ const fullPath = path.join(dir, entry.name);
43615
+ if (entry.isDirectory()) {
43616
+ files.push(...await listFilesRecursively(fullPath));
43617
+ } else {
43618
+ files.push(fullPath);
43619
+ }
43620
+ }
43621
+ return files;
43622
+ }
43623
+ async function list(prefix) {
43624
+ const dir = getBaseDir();
43625
+ const targetDir = path.join(dir, ...prefix);
43626
+ try {
43627
+ const files = await listFilesRecursively(targetDir);
43628
+ const result = files.map((filePath) => {
43629
+ const relativePath = path.relative(targetDir, filePath);
43630
+ return [...prefix, ...relativePath.slice(0, -5).split(path.sep)];
43631
+ });
43632
+ result.sort();
43633
+ return result;
43634
+ } catch {
43635
+ return [];
43636
+ }
43637
+ }
43638
+ var NotFoundError;
43639
+ var init_storage = __esm(() => {
43640
+ init_zod();
43641
+ init_errors();
43642
+ init_lock();
43643
+ NotFoundError = NamedError.create("NotFoundError", zod_default.object({
43644
+ message: zod_default.string()
43645
+ }));
43646
+ });
43647
+
43648
+ // src/core/toolset/index.ts
43649
+ var ToolsetStateSchema;
43650
+ var init_toolset = __esm(() => {
43651
+ init_zod();
43652
+ ToolsetStateSchema = exports_external2.object({
43653
+ baseToolsetId: exports_external2.string(),
43654
+ enabledTools: exports_external2.record(exports_external2.string(), exports_external2.boolean()),
43655
+ lastModified: exports_external2.number()
43656
+ });
43657
+ });
43658
+
43659
+ // src/core/session/index.ts
43660
+ import { existsSync, readFileSync } from "fs";
43661
+ import os2 from "os";
43662
+ import path2 from "path";
43663
+ function resolveSmtpConfig(explicit) {
43664
+ if (explicit)
43665
+ return explicit;
43666
+ const fromAddress = process.env.OUTBOUND_EMAIL;
43667
+ const resendKey = process.env.RESEND_API_KEY;
43668
+ if (resendKey) {
43669
+ return {
43670
+ host: "smtp.resend.com",
43671
+ port: 465,
43672
+ username: "resend",
43673
+ password: resendKey,
43674
+ tls: true,
43675
+ fromAddress
43676
+ };
43677
+ }
43678
+ const host = process.env.SMTP_HOST;
43679
+ const port = process.env.SMTP_PORT;
43680
+ const username = process.env.SMTP_USERNAME;
43681
+ const password = process.env.SMTP_PASSWORD;
43682
+ if (host && port && username && password) {
43683
+ return {
43684
+ host,
43685
+ port: parseInt(port, 10),
43686
+ username,
43687
+ password,
43688
+ tls: process.env.SMTP_TLS !== "false",
43689
+ fromAddress
43690
+ };
43691
+ }
43692
+ return;
43693
+ }
43694
+ function getPensarDir() {
43695
+ return path2.join(os2.homedir(), ".pensar");
43696
+ }
43697
+ function getSessionsDir() {
43698
+ return path2.join(getPensarDir(), "sessions");
43699
+ }
43700
+ function getSessionRoot(id) {
43701
+ return path2.join(getSessionsDir(), id);
43702
+ }
43703
+ async function createSessionDirs(input) {
43704
+ const { session } = input;
43705
+ await createDir(["sessions", session.id]);
43706
+ await createDir(["sessions", session.id, "findings"]);
43707
+ await createDir(["sessions", session.id, "scratchpad"]);
43708
+ await createDir(["sessions", session.id, "logs"]);
43709
+ await createDir(["sessions", session.id, "pocs"]);
43710
+ const startTime = new Date().toISOString();
43711
+ const readme = generateSessionReadme(session);
43712
+ await writeRaw(["sessions", session.id, "README.md"], readme);
43713
+ console.info("created session", session.id);
43714
+ }
43715
+ function generateSessionReadme(session) {
43716
+ return `# Penetration Test Session
43717
+
43718
+ **Session ID:** ${session.id}
43719
+ **Target:** ${session.targets}
43720
+ **Objective:** ${session.config?.outcomeGuidance}
43721
+ **Started:** ${session.time.created}
43722
+
43723
+ ## Directory Structure
43724
+
43725
+ - \`findings/\` - Security findings and vulnerabilities
43726
+ - \`scratchpad/\` - Notes and temporary data during testing
43727
+ - \`logs/\` - Execution logs and command outputs
43728
+ - \`pocs/\` - Proof-of-concept exploit scripts
43729
+ - \`session.json\` - Session metadata
43730
+
43731
+ ## Findings
43732
+
43733
+ Security findings will be documented in the \`findings/\` directory as individual files.
43734
+
43735
+ ## Status
43736
+
43737
+ Testing in progress...
43738
+ `;
43739
+ }
43740
+ function normalizeDeprecatedHeaders(config2) {
43741
+ if (!config2)
43742
+ return config2;
43743
+ if (config2.offensiveHeaders == null) {
43744
+ const { offensiveHeaders: _drop, ...rest2 } = config2;
43745
+ return rest2;
43746
+ }
43747
+ const { offensiveHeaders, ...rest } = config2;
43748
+ const restWithHeaders = rest;
43749
+ if (restWithHeaders.headers !== undefined) {
43750
+ return restWithHeaders;
43751
+ }
43752
+ const oh = offensiveHeaders;
43753
+ if (oh.mode === "none") {
43754
+ return { ...restWithHeaders, headers: {} };
43755
+ }
43756
+ let headers = {};
43757
+ if (oh.mode === "default")
43758
+ headers = { ...DEFAULT_HEADER_RECORD };
43759
+ if (oh.headers)
43760
+ headers = { ...headers, ...oh.headers };
43761
+ return { ...restWithHeaders, headers };
43762
+ }
43763
+ function migrateLegacySessionData(input) {
43764
+ if (!input || typeof input !== "object")
43765
+ return input;
43766
+ const root = input;
43767
+ const config2 = root.config;
43768
+ if (!config2 || typeof config2 !== "object")
43769
+ return input;
43770
+ const cfg = config2;
43771
+ if (!("offensiveHeaders" in cfg))
43772
+ return input;
43773
+ return { ...root, config: normalizeDeprecatedHeaders(cfg) };
43774
+ }
43775
+ async function create2(input) {
43776
+ const name29 = input.name ?? generateRandomName();
43777
+ const normalizedConfig = normalizeDeprecatedHeaders(input.config);
43778
+ const id = `${input.prefix ? input.prefix : ""}` + descending("session", input.id);
43779
+ const rootPath = getSessionRoot(id);
43780
+ const findingsPath = path2.join(rootPath, "findings");
43781
+ const scratchpadPath = path2.join(rootPath, "scratchpad");
43782
+ const logsPath = path2.join(rootPath, "logs");
43783
+ const pocsPath = path2.join(rootPath, "pocs");
43784
+ const rateLimiter = new RateLimiter({
43785
+ requestsPerSecond: normalizedConfig?.requestsPerSecond
43786
+ });
43787
+ let credentialManager;
43788
+ if (normalizedConfig?.authCredentials) {
43789
+ credentialManager = new CredentialManager;
43790
+ const creds = Array.isArray(normalizedConfig.authCredentials) ? normalizedConfig.authCredentials : [normalizedConfig.authCredentials];
43791
+ for (const cred of creds) {
43792
+ credentialManager.addFromAuthCredentials(cred);
43793
+ }
43794
+ }
43795
+ const smtpConfig = resolveSmtpConfig(normalizedConfig?.smtpConfig);
43796
+ let snapshotHeaders;
43797
+ if (normalizedConfig?.headers !== undefined) {
43798
+ snapshotHeaders = { ...normalizedConfig.headers };
43799
+ } else {
43800
+ const { config: appConfig } = await import("./index-9d2es97h.js");
43801
+ const cfg = await appConfig.get();
43802
+ snapshotHeaders = cfg.defaultHeaders ? { ...cfg.defaultHeaders } : { ...DEFAULT_HEADER_RECORD };
43803
+ }
43804
+ const result = {
43805
+ id,
43806
+ version: getCurrentVersion(),
43807
+ targets: input.targets,
43808
+ name: name29,
43809
+ time: {
43810
+ created: Date.now(),
43811
+ updated: Date.now()
43812
+ },
43813
+ config: {
43814
+ ...normalizedConfig,
43815
+ mode: normalizedConfig?.mode || "auto",
43816
+ headers: snapshotHeaders,
43817
+ outcomeGuidance: normalizedConfig?.outcomeGuidance || (normalizedConfig?.exfilMode ? EXFIL_OUTCOME_GUIDANCE : DEFAULT_OUTCOME_GUIDANCE),
43818
+ smtpConfig
43819
+ },
43820
+ _rateLimiter: rateLimiter,
43821
+ credentialManager,
43822
+ rootPath,
43823
+ logsPath,
43824
+ pocsPath,
43825
+ scratchpadPath,
43826
+ findingsPath
43827
+ };
43828
+ const { _rateLimiter, credentialManager: _cm, ...sessionData } = result;
43829
+ await createSessionDirs({ session: result });
43830
+ await write2(["sessions", result.id, "session"], sessionData);
43831
+ if (!input.name && input.model) {
43832
+ generateSessionName({
43833
+ targets: input.targets,
43834
+ userMessage: input.userMessage,
43835
+ model: input.model,
43836
+ authConfig: input.authConfig
43837
+ }).then((aiName) => {
43838
+ if (aiName) {
43839
+ result.name = aiName;
43840
+ update2(result.id, (s) => {
43841
+ s.name = aiName;
43842
+ }).catch(() => {});
43843
+ input.onNameGenerated?.(aiName);
43844
+ }
43845
+ });
43846
+ }
43847
+ return result;
43848
+ }
43849
+ async function update2(id, editor) {
43850
+ const result = await update(["sessions", id, "session"], (draft) => {
43851
+ editor(draft);
43852
+ draft.time.updated = Date.now();
43853
+ });
43854
+ return result;
43855
+ }
43856
+ async function* list2() {
43857
+ const sessionsDir = getSessionsDir();
43858
+ let entries;
43859
+ try {
43860
+ entries = await import("fs/promises").then((fsp) => fsp.readdir(sessionsDir, { withFileTypes: true }));
43861
+ } catch {
43862
+ return;
43863
+ }
43864
+ for (const entry of entries) {
43865
+ if (!entry.isDirectory())
43866
+ continue;
43867
+ try {
43868
+ yield await read2([
43869
+ "sessions",
43870
+ entry.name,
43871
+ "session"
43872
+ ]);
43873
+ } catch {}
43874
+ }
43875
+ }
43876
+ async function loadOperatorState(sessionId) {
43877
+ try {
43878
+ const session = await get(sessionId);
43879
+ const statePath = path2.join(session.rootPath, "messages.json");
43880
+ if (!existsSync(statePath))
43881
+ return null;
43882
+ const data = readFileSync(statePath, "utf-8");
43883
+ const parsed = JSON.parse(data);
43884
+ if (Array.isArray(parsed)) {
43885
+ return {
43886
+ mode: session.config?.operatorSettings?.initialMode ?? "manual",
43887
+ requireApproval: session.config?.operatorSettings?.requireApproval ?? true,
43888
+ currentStage: "recon",
43889
+ messages: parsed,
43890
+ attackSurface: [],
43891
+ credentials: [],
43892
+ verifiedVulns: [],
43893
+ targetState: null,
43894
+ hypotheses: [],
43895
+ evidence: [],
43896
+ actionHistory: [],
43897
+ pausedAt: new Date().toISOString(),
43898
+ lastRunId: ""
43899
+ };
43900
+ }
43901
+ return parsed;
43902
+ } catch (error) {
43903
+ console.error("Error loading operator state:", error);
43904
+ return null;
43905
+ }
43906
+ }
43907
+ function hasOperatorState(session) {
43908
+ const statePath = path2.join(session.rootPath, "messages.json");
43909
+ return existsSync(statePath);
43910
+ }
43911
+ function getResumeMessages(messages, limit = MAX_RESUME_MESSAGES) {
43912
+ if (messages.length <= limit)
43913
+ return messages;
43914
+ let cutIndex = messages.length - limit;
43915
+ while (cutIndex < messages.length) {
43916
+ if (messages[cutIndex].role === "user")
43917
+ break;
43918
+ cutIndex++;
43919
+ }
43920
+ if (cutIndex >= messages.length) {
43921
+ cutIndex = messages.length - limit;
43922
+ }
43923
+ return messages.slice(cutIndex);
43924
+ }
43925
+ function normalizeMessages(messages) {
43926
+ if (messages.length <= 1)
43927
+ return fixToolOutputs(messages);
43928
+ const result = [];
43929
+ for (const msg of messages) {
43930
+ const prev = result[result.length - 1];
43931
+ if (prev && prev.role === "user" && msg.role === "user" && typeof prev.content === "string" && typeof msg.content === "string") {
43932
+ result[result.length - 1] = {
43933
+ ...prev,
43934
+ content: `${prev.content}
43935
+
43936
+ ${msg.content}`
43937
+ };
43938
+ } else if (prev && prev.role === "user" && msg.role === "user") {
43939
+ result[result.length - 1] = msg;
43940
+ } else {
43941
+ result.push(msg);
43942
+ }
43943
+ }
43944
+ return fixToolOutputs(result);
43945
+ }
43946
+ function fixToolOutputs(messages) {
43947
+ let changed = false;
43948
+ const fixed = messages.map((msg) => {
43949
+ if (msg.role !== "tool" || !Array.isArray(msg.content))
43950
+ return msg;
43951
+ let partChanged = false;
43952
+ const fixedContent = msg.content.map((part) => {
43953
+ if (part.type === "tool-result" && typeof part.output === "string") {
43954
+ partChanged = true;
43955
+ return { ...part, output: { type: "text", value: part.output } };
43956
+ }
43957
+ return part;
43958
+ });
43959
+ if (partChanged) {
43960
+ changed = true;
43961
+ return { ...msg, content: fixedContent };
43962
+ }
43963
+ return msg;
43964
+ });
43965
+ return changed ? fixed : messages;
43966
+ }
43967
+ async function updateOperatorSettings(sessionId, settings) {
43968
+ return await update2(sessionId, (session) => {
43969
+ if (!session.config) {
43970
+ session.config = {};
43971
+ }
43972
+ if (!session.config.operatorSettings) {
43973
+ session.config.operatorSettings = {
43974
+ initialMode: "manual",
43975
+ requireApproval: true,
43976
+ enableSuggestions: true
43977
+ };
43978
+ }
43979
+ if (settings.initialMode !== undefined) {
43980
+ session.config.operatorSettings.initialMode = settings.initialMode;
43981
+ }
43982
+ if (settings.requireApproval !== undefined) {
43983
+ session.config.operatorSettings.requireApproval = settings.requireApproval;
43984
+ }
43985
+ if (settings.enableSuggestions !== undefined) {
43986
+ session.config.operatorSettings.enableSuggestions = settings.enableSuggestions;
43987
+ }
43988
+ });
43989
+ }
43990
+ async function updateSessionHeaders(sessionId, headers) {
43991
+ return await update2(sessionId, (session) => {
43992
+ if (!session.config) {
43993
+ session.config = {};
43994
+ }
43995
+ session.config.headers = { ...headers };
43996
+ });
43997
+ }
43998
+ var DEFAULT_OUTCOME_GUIDANCE, EXFIL_OUTCOME_GUIDANCE, DEFAULT_HEADER_RECORD, AuthCredentialsObject, ScopeConstraintsObject, SessionHeadersRecord, OffensiveHeadersConfigObject, OperatorSettingsObject, EmailInboxConfigObject, EmailIntegrationConfigObject, SmtpConfigObject, SessionConfigObject, SessionInfoObject, get = async (id) => {
43999
+ const raw = await read2(["sessions", id, "session"]);
44000
+ const read3 = migrateLegacySessionData(raw);
44001
+ if (read3.config?.requestsPerSecond) {
44002
+ read3._rateLimiter = new RateLimiter({
44003
+ requestsPerSecond: read3.config.requestsPerSecond
44004
+ });
44005
+ } else {
44006
+ delete read3._rateLimiter;
44007
+ }
44008
+ return read3;
44009
+ }, RemoveInput, remove2 = async (input) => {
44010
+ try {
44011
+ const sessionDir = getSessionRoot(input.sessionId);
44012
+ const fsp = await import("fs/promises");
44013
+ await fsp.rm(sessionDir, { recursive: true, force: true });
44014
+ } catch (e) {
44015
+ console.error(e);
44016
+ }
44017
+ }, RemoveMsgInput, MAX_RESUME_MESSAGES = 200, sessions;
44018
+ var init_session = __esm(() => {
44019
+ init_zod();
44020
+ init_name();
44021
+ init_credentials();
44022
+ init_id();
44023
+ init_installation();
44024
+ init_rateLimiter();
44025
+ init_storage();
44026
+ init_toolset();
44027
+ DEFAULT_OUTCOME_GUIDANCE = "Prove the exploit can be run but do not exfiltrate data or cause any harm to the system. " + "Create proof-of-concept exploits that demonstrate the vulnerability exists without causing damage.";
44028
+ EXFIL_OUTCOME_GUIDANCE = "Exfiltrate data to extract the flag value. " + "Create proof-of-concept exploits that successfully extract the flag from the target system.";
44029
+ DEFAULT_HEADER_RECORD = {
44030
+ "User-Agent": "pensar-apex"
44031
+ };
44032
+ AuthCredentialsObject = zod_default.object({
44033
+ username: zod_default.string().optional(),
44034
+ password: zod_default.string().optional(),
44035
+ loginUrl: zod_default.string().optional(),
44036
+ additionalFields: zod_default.record(zod_default.string(), zod_default.string()).optional(),
44037
+ apiKey: zod_default.string().optional(),
44038
+ role: zod_default.string().optional(),
44039
+ context: zod_default.string().optional(),
44040
+ tokens: zod_default.object({
44041
+ bearerToken: zod_default.string().optional(),
44042
+ cookies: zod_default.string().optional(),
44043
+ sessionToken: zod_default.string().optional(),
44044
+ customHeaders: zod_default.record(zod_default.string(), zod_default.string()).optional()
44045
+ }).optional()
44046
+ });
44047
+ ScopeConstraintsObject = zod_default.object({
44048
+ allowedHosts: zod_default.string().array().optional(),
44049
+ allowedPorts: zod_default.number().array().optional(),
44050
+ strictScope: zod_default.boolean().optional()
44051
+ });
44052
+ SessionHeadersRecord = zod_default.record(zod_default.string(), zod_default.string());
44053
+ OffensiveHeadersConfigObject = zod_default.object({
44054
+ mode: zod_default.enum(["none", "default", "custom"]).optional(),
44055
+ headers: SessionHeadersRecord.optional()
44056
+ });
44057
+ OperatorSettingsObject = zod_default.object({
44058
+ initialMode: zod_default.enum(["plan", "manual", "auto"]).default("manual"),
44059
+ requireApproval: zod_default.boolean().default(true),
44060
+ enableSuggestions: zod_default.boolean().default(true)
44061
+ });
44062
+ EmailInboxConfigObject = zod_default.discriminatedUnion("provider", [
44063
+ zod_default.object({
44064
+ provider: zod_default.literal("gmail"),
44065
+ id: zod_default.string(),
44066
+ name: zod_default.string(),
44067
+ emailAddress: zod_default.string(),
44068
+ accessToken: zod_default.string(),
44069
+ refreshToken: zod_default.string(),
44070
+ clientId: zod_default.string().optional(),
44071
+ clientSecret: zod_default.string().optional(),
44072
+ tokenExpiry: zod_default.number().optional()
44073
+ }),
44074
+ zod_default.object({
44075
+ provider: zod_default.literal("outlook"),
44076
+ id: zod_default.string(),
44077
+ name: zod_default.string(),
44078
+ emailAddress: zod_default.string(),
44079
+ accessToken: zod_default.string(),
44080
+ refreshToken: zod_default.string(),
44081
+ clientId: zod_default.string().optional(),
44082
+ clientSecret: zod_default.string().optional(),
44083
+ tokenExpiry: zod_default.number().optional()
44084
+ }),
44085
+ zod_default.object({
44086
+ provider: zod_default.literal("imap"),
44087
+ id: zod_default.string(),
44088
+ name: zod_default.string(),
44089
+ emailAddress: zod_default.string(),
44090
+ imapHost: zod_default.string(),
44091
+ imapPort: zod_default.number(),
44092
+ username: zod_default.string(),
44093
+ password: zod_default.string(),
44094
+ tls: zod_default.boolean()
44095
+ })
44096
+ ]);
44097
+ EmailIntegrationConfigObject = zod_default.object({
44098
+ inboxes: zod_default.array(EmailInboxConfigObject)
44099
+ });
44100
+ SmtpConfigObject = zod_default.object({
44101
+ host: zod_default.string(),
44102
+ port: zod_default.number(),
44103
+ username: zod_default.string(),
44104
+ password: zod_default.string(),
44105
+ tls: zod_default.boolean().default(true),
44106
+ fromAddress: zod_default.string().optional()
44107
+ });
44108
+ SessionConfigObject = zod_default.object({
44109
+ headers: SessionHeadersRecord.optional(),
44110
+ offensiveHeaders: OffensiveHeadersConfigObject.optional(),
44111
+ sessionType: zod_default.enum(["web-app"]).optional(),
44112
+ mode: zod_default.enum(["auto", "driver", "operator"]).optional(),
44113
+ outcomeGuidance: zod_default.string().optional(),
44114
+ scopeConstraints: ScopeConstraintsObject.optional(),
44115
+ authCredentials: zod_default.union([AuthCredentialsObject, zod_default.array(AuthCredentialsObject)]).optional(),
44116
+ authenticationInstructions: zod_default.string().optional(),
44117
+ requestsPerSecond: zod_default.number().optional(),
44118
+ operatorSettings: OperatorSettingsObject.optional(),
44119
+ toolsetState: ToolsetStateSchema.optional(),
44120
+ enumerateSubdomains: zod_default.boolean().optional(),
44121
+ codebasePath: zod_default.string().optional(),
44122
+ emailIntegration: EmailIntegrationConfigObject.optional(),
44123
+ smtpConfig: SmtpConfigObject.optional(),
44124
+ exfilMode: zod_default.boolean().optional(),
44125
+ agentCwd: zod_default.string().optional(),
44126
+ prompt: zod_default.string().optional(),
44127
+ taskDriven: zod_default.boolean().optional(),
44128
+ requirePlan: zod_default.boolean().optional()
44129
+ });
44130
+ SessionInfoObject = zod_default.object({
44131
+ id: schema("session"),
44132
+ name: zod_default.string().optional(),
44133
+ version: zod_default.string(),
44134
+ targets: zod_default.array(zod_default.string()),
44135
+ config: SessionConfigObject.optional(),
44136
+ time: zod_default.object({
44137
+ created: zod_default.number(),
44138
+ updated: zod_default.number()
44139
+ }),
44140
+ rootPath: zod_default.string(),
44141
+ logsPath: zod_default.string(),
44142
+ findingsPath: zod_default.string(),
44143
+ scratchpadPath: zod_default.string(),
44144
+ pocsPath: zod_default.string()
44145
+ });
44146
+ RemoveInput = zod_default.object({
44147
+ sessionId: schema("session")
44148
+ });
44149
+ RemoveMsgInput = zod_default.object({
44150
+ sessionId: schema("session"),
44151
+ messageId: schema("message")
44152
+ });
44153
+ sessions = {
44154
+ getSessionRoot,
44155
+ EXFIL_OUTCOME_GUIDANCE,
44156
+ create: create2,
44157
+ get,
44158
+ remove: remove2,
44159
+ loadOperatorState,
44160
+ hasOperatorState,
44161
+ getResumeMessages,
44162
+ updateOperatorSettings,
44163
+ updateSessionHeaders
44164
+ };
44165
+ });
44166
+
44167
+ // src/core/logger/index.ts
44168
+ import {
44169
+ appendFileSync,
44170
+ existsSync as existsSync2,
44171
+ mkdirSync as mkdirSync2,
44172
+ readFileSync as readFileSync2,
44173
+ writeFileSync as writeFileSync2
44174
+ } from "fs";
44175
+ import os3 from "os";
44176
+ import path3 from "path";
44177
+ function pruneErrorLog() {
44178
+ if (hasPruned)
44179
+ return;
44180
+ hasPruned = true;
44181
+ try {
44182
+ if (!existsSync2(ERROR_LOG_PATH))
44183
+ return;
44184
+ const cutoff = Date.now() - RETENTION_DAYS * 86400000;
44185
+ const raw = readFileSync2(ERROR_LOG_PATH, "utf8");
44186
+ const lines = raw.split(`
44187
+ `);
44188
+ const kept = [];
44189
+ let keeping = true;
44190
+ for (const line of lines) {
44191
+ const match = TIMESTAMP_RE.exec(line);
44192
+ if (match) {
44193
+ keeping = new Date(match[1]).getTime() >= cutoff;
44194
+ }
44195
+ if (keeping) {
44196
+ kept.push(line);
44197
+ }
44198
+ }
44199
+ writeFileSync2(ERROR_LOG_PATH, kept.join(`
44200
+ `), "utf8");
44201
+ } catch {}
44202
+ }
44203
+ function writeErrorLog(error, source, fields) {
44204
+ try {
44205
+ pruneErrorLog();
44206
+ const dir = path3.dirname(ERROR_LOG_PATH);
44207
+ if (!existsSync2(dir)) {
44208
+ mkdirSync2(dir, { recursive: true });
44209
+ }
44210
+ const timestamp = new Date().toISOString();
44211
+ const tag = source ? `[${source}] ` : "";
44212
+ const message = error instanceof Error ? `${error.message}
44213
+ ${error.stack ?? ""}` : String(error);
44214
+ let fieldsStr = "";
44215
+ if (fields && Object.keys(fields).length > 0) {
44216
+ try {
44217
+ fieldsStr = ` ${JSON.stringify(fields)}`;
44218
+ } catch {}
44219
+ }
44220
+ const entry = `${timestamp} - [ERROR] ${tag}${message}${fieldsStr}
44221
+ `;
44222
+ appendFileSync(ERROR_LOG_PATH, entry, "utf8");
44223
+ } catch {}
44224
+ }
44225
+ var ERROR_LOG_PATH, RETENTION_DAYS = 7, TIMESTAMP_RE, hasPruned = false;
44226
+ var init_logger = __esm(() => {
44227
+ init_session();
44228
+ init_structured();
44229
+ ERROR_LOG_PATH = path3.join(os3.homedir(), ".pensar", "error.log");
44230
+ TIMESTAMP_RE = /^(\d{4}-\d{2}-\d{2}T[\d:.]+Z) - /;
44231
+ });
44232
+
44233
+ // src/core/logger/structured.ts
44234
+ function isLevel(v) {
44235
+ return typeof v === "string" && VALID_LEVELS.has(v);
44236
+ }
44237
+ function resolveInitialLevel(env) {
44238
+ const explicit = env.PENSAR_LOG_LEVEL?.trim().toUpperCase();
44239
+ if (isLevel(explicit))
44240
+ return explicit;
44241
+ const debug = env.PENSAR_DEBUG?.toLowerCase();
44242
+ if (debug === "1" || debug === "true")
44243
+ return "DEBUG";
44244
+ return "INFO";
44245
+ }
44246
+ function resolveFormat(env) {
44247
+ const forced = env.PENSAR_LOG_FORMAT?.toLowerCase();
44248
+ if (forced === "json" || forced === "pretty")
44249
+ return forced;
44250
+ return process.stderr.isTTY ? "pretty" : "json";
44251
+ }
44252
+
44253
+ class Logger {
44254
+ level;
44255
+ explicit = false;
44256
+ scope;
44257
+ constructor(scope, level) {
44258
+ this.scope = scope;
44259
+ this.level = level ?? resolveInitialLevel(process.env);
44260
+ }
44261
+ setLevel(level) {
44262
+ this.level = level;
44263
+ this.explicit = true;
44264
+ }
44265
+ getLevel() {
44266
+ return this.level;
44267
+ }
44268
+ child(scope) {
44269
+ const next = this.scope ? `${this.scope}:${scope}` : scope;
44270
+ const child = new Logger(next, this.level);
44271
+ if (this.explicit)
44272
+ child.setLevel(this.level);
44273
+ return child;
44274
+ }
44275
+ debug(msg, fields) {
44276
+ this.emit("DEBUG", msg, fields);
44277
+ }
44278
+ info(msg, fields) {
44279
+ this.emit("INFO", msg, fields);
44280
+ }
44281
+ warn(msg, fields) {
44282
+ this.emit("WARN", msg, fields);
44283
+ }
44284
+ error(msg, errOrFields, fields) {
44285
+ let err;
44286
+ let extra;
44287
+ if (errOrFields instanceof Error) {
44288
+ err = errOrFields;
44289
+ extra = fields;
44290
+ } else if (errOrFields && typeof errOrFields === "object") {
44291
+ extra = errOrFields;
44292
+ }
44293
+ const merged = { ...extra };
44294
+ if (err) {
44295
+ merged.error = err.message;
44296
+ if (err.stack)
44297
+ merged.stack = err.stack;
44298
+ }
44299
+ this.emit("ERROR", msg, merged);
44300
+ if (this.level !== "SILENT") {
44301
+ writeErrorLog(err ?? msg, this.scope, extra);
44302
+ }
44303
+ }
44304
+ emit(level, msg, fields) {
44305
+ if (SEVERITY[level] < SEVERITY[this.level])
44306
+ return;
44307
+ const ts = new Date().toISOString();
44308
+ const format = resolveFormat(process.env);
44309
+ const line = format === "json" ? this.formatJson(ts, level, msg, fields) : this.formatPretty(ts, level, msg, fields);
44310
+ process.stderr.write(`${line}
44311
+ `);
44312
+ }
44313
+ formatJson(ts, level, msg, fields) {
44314
+ const record = { ts, level, msg };
44315
+ if (this.scope)
44316
+ record.scope = this.scope;
44317
+ if (fields) {
44318
+ for (const [k, v] of Object.entries(fields)) {
44319
+ if (k !== "ts" && k !== "level" && k !== "msg" && k !== "scope") {
44320
+ record[k] = v;
44321
+ }
44322
+ }
44323
+ }
44324
+ return safeStringify(record);
44325
+ }
44326
+ formatPretty(ts, level, msg, fields) {
44327
+ const color = COLORS[level];
44328
+ const tag = `${color}${level.padEnd(5)}${RESET}`;
44329
+ const scope = this.scope ? ` ${DIM}[${this.scope}]${RESET}` : "";
44330
+ let rest = "";
44331
+ if (fields && Object.keys(fields).length > 0) {
44332
+ rest = ` ${DIM}${safeStringify(fields)}${RESET}`;
44333
+ }
44334
+ return `${DIM}${ts}${RESET} ${tag}${scope} ${msg}${rest}`;
44335
+ }
44336
+ }
44337
+ function safeStringify(value) {
44338
+ try {
44339
+ return JSON.stringify(value);
44340
+ } catch {
44341
+ return JSON.stringify({ msg: "[unserializable log payload]" });
44342
+ }
44343
+ }
44344
+ function createLogger(scope) {
44345
+ return new Logger(scope);
44346
+ }
44347
+ var SEVERITY, VALID_LEVELS, COLORS, RESET = "\x1B[0m", DIM = "\x1B[2m", logger;
44348
+ var init_structured = __esm(() => {
44349
+ init_logger();
44350
+ SEVERITY = {
44351
+ DEBUG: 10,
44352
+ INFO: 20,
44353
+ WARN: 30,
44354
+ ERROR: 40,
44355
+ SILENT: 50
44356
+ };
44357
+ VALID_LEVELS = new Set([
44358
+ "DEBUG",
44359
+ "INFO",
44360
+ "WARN",
44361
+ "ERROR",
44362
+ "SILENT"
44363
+ ]);
44364
+ COLORS = {
44365
+ DEBUG: "\x1B[90m",
44366
+ INFO: "\x1B[36m",
44367
+ WARN: "\x1B[33m",
44368
+ ERROR: "\x1B[31m",
44369
+ SILENT: ""
44370
+ };
44371
+ logger = new Logger;
44372
+ });
44373
+
42940
44374
  // src/core/ai/providers/pensarFormatters.ts
42941
44375
  function convertToBedrockFormat(modelId, options) {
42942
44376
  if (modelId.includes("anthropic.claude")) {
@@ -43139,11 +44573,9 @@ async function* parseSSE(stream, options = {}) {
43139
44573
  clearTimeout(timeoutId);
43140
44574
  }
43141
44575
  if (result.done) {
43142
- if (DEBUG) {
43143
- console.error(`[parseSSE] stream done: ${chunkCount} chunks, ${totalBytes} bytes, ${eventCount} events yielded, remaining buffer=${buffer.length} chars`);
43144
- if (buffer.length > 0) {
43145
- console.error(`[parseSSE] remaining buffer: ${buffer.slice(0, 500)}`);
43146
- }
44576
+ log2.debug(`stream done: ${chunkCount} chunks, ${totalBytes} bytes, ${eventCount} events yielded, remaining buffer=${buffer.length} chars`);
44577
+ if (buffer.length > 0) {
44578
+ log2.debug(`remaining buffer: ${buffer.slice(0, 500)}`);
43147
44579
  }
43148
44580
  break;
43149
44581
  }
@@ -43151,8 +44583,8 @@ async function* parseSSE(stream, options = {}) {
43151
44583
  chunkCount++;
43152
44584
  totalBytes += value.byteLength;
43153
44585
  const decoded = decoder.decode(value, { stream: true });
43154
- if (DEBUG && chunkCount <= 3) {
43155
- console.error(`[parseSSE] chunk #${chunkCount}: ${value.byteLength} bytes, preview: ${decoded.slice(0, 200)}`);
44586
+ if (chunkCount <= 3) {
44587
+ log2.debug(`chunk #${chunkCount}: ${value.byteLength} bytes, preview: ${decoded.slice(0, 200)}`);
43156
44588
  }
43157
44589
  buffer += decoded;
43158
44590
  const lines = buffer.split(`
@@ -43177,34 +44609,38 @@ async function* parseSSE(stream, options = {}) {
43177
44609
  }
43178
44610
  if (currentData.length > 0) {
43179
44611
  eventCount++;
43180
- if (DEBUG)
43181
- console.error(`[parseSSE] flushing final event: ${currentEvent}`);
44612
+ log2.debug(`flushing final event: ${currentEvent}`);
43182
44613
  yield { event: currentEvent, data: currentData.join(`
43183
44614
  `) };
43184
44615
  }
43185
44616
  if (eventCount === 0) {
43186
- console.error(`[parseSSE] WARNING: stream ended with 0 events! totalBytes=${totalBytes}, chunks=${chunkCount}`);
44617
+ log2.warn(`stream ended with 0 events! totalBytes=${totalBytes}, chunks=${chunkCount}`);
43187
44618
  }
43188
44619
  } finally {
43189
44620
  reader.releaseLock();
43190
44621
  }
43191
44622
  }
43192
- var DEBUG;
44623
+ var log2;
43193
44624
  var init_pensarSSE = __esm(() => {
43194
- DEBUG = process.env.PENSAR_DEBUG === "1" || process.env.PENSAR_DEBUG === "true";
44625
+ init_structured();
44626
+ init_lazyLogger();
44627
+ log2 = scopedLogger(() => createLogger("pensarSSE"));
43195
44628
  });
43196
44629
 
43197
44630
  // src/core/ai/providers/pensar.ts
43198
- function log(...args) {
43199
- if (DEBUG2)
43200
- console.error("[pensar:debug]", ...args);
44631
+ function fmtArgs(args) {
44632
+ return args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
44633
+ }
44634
+ function log3(...args) {
44635
+ structuredLog.debug(fmtArgs(args));
43201
44636
  }
43202
44637
  function logInfo(...args) {
43203
- if (DEBUG2)
43204
- console.error("[pensar]", ...args);
44638
+ structuredLog.debug(fmtArgs(args));
43205
44639
  }
43206
44640
  function logError(...args) {
43207
- console.error("[pensar:error]", ...args);
44641
+ const err = args.find((a) => a instanceof Error);
44642
+ const msg = fmtArgs(args.filter((a) => !(a instanceof Error)));
44643
+ structuredLog.error(msg, err);
43208
44644
  }
43209
44645
  function createPensarModel(bedrockModelId, config2) {
43210
44646
  const modelId = `pensar:${bedrockModelId}`;
@@ -43220,14 +44656,14 @@ function createPensarModel(bedrockModelId, config2) {
43220
44656
  throw new Error("Pensar authentication failed. Run /login to reconnect.");
43221
44657
  }
43222
44658
  headers.Authorization = `Bearer ${result.token.slice(0, 12)}…`;
43223
- log(` auth: ${result.type} token (${result.token.length} chars)`);
44659
+ log3(` auth: ${result.type} token (${result.token.length} chars)`);
43224
44660
  if (config2.workspaceId) {
43225
44661
  headers["X-Workspace-Id"] = config2.workspaceId;
43226
44662
  }
43227
44663
  headers.Authorization = `Bearer ${result.token}`;
43228
44664
  } else {
43229
44665
  headers.Authorization = `Bearer ${config2.apiKey}`;
43230
- log(` auth: apiKey (${config2.apiKey.length} chars)`);
44666
+ log3(` auth: apiKey (${config2.apiKey.length} chars)`);
43231
44667
  if (config2.workspaceId && !config2.apiKey.startsWith("sk-")) {
43232
44668
  headers["X-Workspace-Id"] = config2.workspaceId;
43233
44669
  }
@@ -43336,7 +44772,7 @@ function createPensarModel(bedrockModelId, config2) {
43336
44772
  const body = convertToBedrockFormat(bedrockModelId, options);
43337
44773
  const url = `${config2.baseUrl}/gateway/invoke`;
43338
44774
  logInfo(`doStream → ${bedrockModelId} (${url})`);
43339
- log(` messages: ${body.messages?.length ?? 0}, tools: ${body.tools?.length ?? 0}`);
44775
+ log3(` messages: ${body.messages?.length ?? 0}, tools: ${body.tools?.length ?? 0}`);
43340
44776
  const startTime = Date.now();
43341
44777
  const serializedBody = JSON.stringify({
43342
44778
  modelId: bedrockModelId,
@@ -43349,7 +44785,7 @@ function createPensarModel(bedrockModelId, config2) {
43349
44785
  headers["X-Pensar-Timestamp"] = sig.timestamp;
43350
44786
  headers["X-Pensar-Nonce"] = sig.nonce;
43351
44787
  }
43352
- log(` headers: ${Object.keys(headers).join(", ")}`);
44788
+ log3(` headers: ${Object.keys(headers).join(", ")}`);
43353
44789
  const fetchSignal = buildStreamingFetchSignal(options.abortSignal);
43354
44790
  let response;
43355
44791
  try {
@@ -43426,10 +44862,10 @@ function createPensarModel(bedrockModelId, config2) {
43426
44862
  try {
43427
44863
  parsed = JSON.parse(sse.data);
43428
44864
  } catch {
43429
- log(` SSE event #${eventCount}: unparseable data, skipping`);
44865
+ log3(` SSE event #${eventCount}: unparseable data, skipping`);
43430
44866
  continue;
43431
44867
  }
43432
- log(` SSE event #${eventCount}: ${sse.event} (type=${parsed.type})`);
44868
+ log3(` SSE event #${eventCount}: ${sse.event} (type=${parsed.type})`);
43433
44869
  if (sse.event === "error") {
43434
44870
  const msg = parsed.error ?? "Unknown streaming error";
43435
44871
  logError(` SSE error event: ${msg}`);
@@ -43438,7 +44874,7 @@ function createPensarModel(bedrockModelId, config2) {
43438
44874
  }
43439
44875
  if (sse.event === "pensar:usage") {
43440
44876
  if (parsed.totalCost != null) {
43441
- log(` cost: $${Number(parsed.totalCost).toFixed(6)}`);
44877
+ log3(` cost: $${Number(parsed.totalCost).toFixed(6)}`);
43442
44878
  }
43443
44879
  continue;
43444
44880
  }
@@ -43625,13 +45061,15 @@ function mapStopReason(reason) {
43625
45061
  return "other";
43626
45062
  }
43627
45063
  }
43628
- var DEBUG2;
45064
+ var structuredLog;
43629
45065
  var init_pensar2 = __esm(() => {
45066
+ init_structured();
45067
+ init_lazyLogger();
43630
45068
  init_utils();
43631
45069
  init_pensarFormatters();
43632
45070
  init_pensarSigning();
43633
45071
  init_pensarSSE();
43634
- DEBUG2 = process.env.PENSAR_DEBUG === "1" || process.env.PENSAR_DEBUG === "true";
45072
+ structuredLog = scopedLogger(() => createLogger("pensar"));
43635
45073
  });
43636
45074
 
43637
45075
  // src/core/ai/utils.ts
@@ -43735,9 +45173,7 @@ function getProviderModel(model, authConfig) {
43735
45173
  }
43736
45174
  const gatewayUrl = authConfig?.gatewayUrl || getPensarGatewayUrl();
43737
45175
  const bedrockModelId = model.startsWith("pensar:") ? model.slice(7) : model;
43738
- if (process.env.PENSAR_DEBUG === "1" || process.env.PENSAR_DEBUG === "true") {
43739
- console.log(`[pensar] getProviderModel: ${model} → bedrock:${bedrockModelId} via ${gatewayUrl}`);
43740
- }
45176
+ log4.debug(`getProviderModel: ${model} bedrock:${bedrockModelId} via ${gatewayUrl}`);
43741
45177
  const modelConfig = {
43742
45178
  apiKey: pensarApiKey || authConfig?.accessToken || "",
43743
45179
  baseUrl: gatewayUrl,
@@ -43954,7 +45390,7 @@ function createSummarizationStream(messages, opts, model) {
43954
45390
  }
43955
45391
  };
43956
45392
  }
43957
- var STREAMING_FETCH_TIMEOUT_MS;
45393
+ var log4, STREAMING_FETCH_TIMEOUT_MS;
43958
45394
  var init_utils = __esm(() => {
43959
45395
  init_dist6();
43960
45396
  init_dist7();
@@ -43966,11 +45402,14 @@ var init_utils = __esm(() => {
43966
45402
  init_constants();
43967
45403
  init_auth();
43968
45404
  init_config();
45405
+ init_structured();
45406
+ init_lazyLogger();
43969
45407
  init_ai();
43970
45408
  init_contextManagement();
43971
45409
  init_models();
43972
45410
  init_pensar2();
45411
+ log4 = scopedLogger(() => createLogger("ai:utils"));
43973
45412
  STREAMING_FETCH_TIMEOUT_MS = 15 * 60 * 1000;
43974
45413
  });
43975
45414
 
43976
- export { stepCountIs, hasToolCall, init_dist4 as init_dist, getApexTracer, init_observability, AVAILABLE_MODELS, init_models, require_tslib, buildAuthConfig, init_utils, DEFAULT_OPENAI_REASONING_EFFORT, modelSupportsThinking, modelSupportsOpenAIReasoning, getOpenAIReasoningEfforts, streamResponse, generateObjectResponse, init_ai };
45415
+ export { stepCountIs, hasToolCall, init_dist4 as init_dist, AVAILABLE_MODELS, init_models, require_tslib, scopedLogger, init_lazyLogger, buildAuthConfig, init_utils, init_ai2 as init_ai, generateRandomName, generateSessionName, init_name, CredentialManager, init_credentials, schema, descending, init_id, RateLimiter, init_rateLimiter, NotFoundError, write2 as write, createDir, writeRaw, read2 as read, update, list, init_storage, ToolsetStateSchema, init_toolset, create2 as create, list2 as list1, normalizeMessages, sessions, init_session, writeErrorLog, init_logger, createLogger, logger, init_structured, getApexTracer, init_observability, DEFAULT_OPENAI_REASONING_EFFORT, modelSupportsThinking, modelSupportsOpenAIReasoning, getOpenAIReasoningEfforts, streamResponse, generateObjectResponse, init_ai as init_ai1 };