@everworker/oneringai 0.3.0 → 0.3.2

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/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  var crypto2 = require('crypto');
4
4
  var jose = require('jose');
5
- var fs17 = require('fs');
5
+ var fs18 = require('fs');
6
6
  var eventemitter3 = require('eventemitter3');
7
7
  var path2 = require('path');
8
8
  var TurndownService = require('turndown');
@@ -17,7 +17,7 @@ var z = require('zod/v4');
17
17
  var spawn = require('cross-spawn');
18
18
  var process2 = require('process');
19
19
  var stream = require('stream');
20
- var fs16 = require('fs/promises');
20
+ var fs17 = require('fs/promises');
21
21
  var simpleIcons = require('simple-icons');
22
22
  var child_process = require('child_process');
23
23
  var util = require('util');
@@ -45,7 +45,7 @@ function _interopNamespace(e) {
45
45
  }
46
46
 
47
47
  var crypto2__namespace = /*#__PURE__*/_interopNamespace(crypto2);
48
- var fs17__namespace = /*#__PURE__*/_interopNamespace(fs17);
48
+ var fs18__namespace = /*#__PURE__*/_interopNamespace(fs18);
49
49
  var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
50
50
  var TurndownService__default = /*#__PURE__*/_interopDefault(TurndownService);
51
51
  var os2__namespace = /*#__PURE__*/_interopNamespace(os2);
@@ -55,7 +55,7 @@ var z4mini__namespace = /*#__PURE__*/_interopNamespace(z4mini);
55
55
  var z__namespace = /*#__PURE__*/_interopNamespace(z);
56
56
  var spawn__default = /*#__PURE__*/_interopDefault(spawn);
57
57
  var process2__default = /*#__PURE__*/_interopDefault(process2);
58
- var fs16__namespace = /*#__PURE__*/_interopNamespace(fs16);
58
+ var fs17__namespace = /*#__PURE__*/_interopNamespace(fs17);
59
59
  var simpleIcons__namespace = /*#__PURE__*/_interopNamespace(simpleIcons);
60
60
  var vm__namespace = /*#__PURE__*/_interopNamespace(vm);
61
61
 
@@ -673,7 +673,7 @@ var init_JWTBearer = __esm({
673
673
  this.privateKey = config.privateKey;
674
674
  } else if (config.privateKeyPath) {
675
675
  try {
676
- this.privateKey = fs17__namespace.readFileSync(config.privateKeyPath, "utf8");
676
+ this.privateKey = fs18__namespace.readFileSync(config.privateKeyPath, "utf8");
677
677
  } catch (error) {
678
678
  throw new Error(`Failed to read private key from ${config.privateKeyPath}: ${error.message}`);
679
679
  }
@@ -1432,10 +1432,10 @@ var init_Logger = __esm({
1432
1432
  initFileStream(filePath) {
1433
1433
  try {
1434
1434
  const dir = path2__namespace.dirname(filePath);
1435
- if (!fs17__namespace.existsSync(dir)) {
1436
- fs17__namespace.mkdirSync(dir, { recursive: true });
1435
+ if (!fs18__namespace.existsSync(dir)) {
1436
+ fs18__namespace.mkdirSync(dir, { recursive: true });
1437
1437
  }
1438
- this.fileStream = fs17__namespace.createWriteStream(filePath, {
1438
+ this.fileStream = fs18__namespace.createWriteStream(filePath, {
1439
1439
  flags: "a",
1440
1440
  // append mode
1441
1441
  encoding: "utf8"
@@ -9165,12 +9165,12 @@ var require_dist = __commonJS({
9165
9165
  throw new Error(`Unknown format "${name}"`);
9166
9166
  return f;
9167
9167
  };
9168
- function addFormats(ajv, list, fs18, exportName) {
9168
+ function addFormats(ajv, list, fs19, exportName) {
9169
9169
  var _a;
9170
9170
  var _b;
9171
9171
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
9172
9172
  for (const f of list)
9173
- ajv.addFormat(f, fs18[f]);
9173
+ ajv.addFormat(f, fs19[f]);
9174
9174
  }
9175
9175
  module.exports = exports$1 = formatsPlugin;
9176
9176
  Object.defineProperty(exports$1, "__esModule", { value: true });
@@ -10173,6 +10173,11 @@ var DEFAULT_ALLOWLIST = [
10173
10173
  "instructions_remove",
10174
10174
  "instructions_list",
10175
10175
  "instructions_clear",
10176
+ // User info tools (user-specific data - safe)
10177
+ "user_info_set",
10178
+ "user_info_get",
10179
+ "user_info_remove",
10180
+ "user_info_clear",
10176
10181
  // Meta-tools (internal coordination)
10177
10182
  "_start_planning",
10178
10183
  "_modify_plan",
@@ -14897,7 +14902,7 @@ var FilePersistentInstructionsStorage = class {
14897
14902
  */
14898
14903
  async load() {
14899
14904
  try {
14900
- const raw = await fs17.promises.readFile(this.filePath, "utf-8");
14905
+ const raw = await fs18.promises.readFile(this.filePath, "utf-8");
14901
14906
  const data = JSON.parse(raw);
14902
14907
  if (data.version === 2 && Array.isArray(data.entries)) {
14903
14908
  return data.entries.length > 0 ? data.entries : null;
@@ -14909,7 +14914,7 @@ var FilePersistentInstructionsStorage = class {
14909
14914
  }
14910
14915
  }
14911
14916
  try {
14912
- const content = await fs17.promises.readFile(this.legacyFilePath, "utf-8");
14917
+ const content = await fs18.promises.readFile(this.legacyFilePath, "utf-8");
14913
14918
  const trimmed = content.trim();
14914
14919
  if (!trimmed) return null;
14915
14920
  const now = Date.now();
@@ -14939,11 +14944,11 @@ var FilePersistentInstructionsStorage = class {
14939
14944
  };
14940
14945
  const tempPath = `${this.filePath}.tmp`;
14941
14946
  try {
14942
- await fs17.promises.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
14943
- await fs17.promises.rename(tempPath, this.filePath);
14947
+ await fs18.promises.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
14948
+ await fs18.promises.rename(tempPath, this.filePath);
14944
14949
  } catch (error) {
14945
14950
  try {
14946
- await fs17.promises.unlink(tempPath);
14951
+ await fs18.promises.unlink(tempPath);
14947
14952
  } catch {
14948
14953
  }
14949
14954
  throw error;
@@ -14955,7 +14960,7 @@ var FilePersistentInstructionsStorage = class {
14955
14960
  */
14956
14961
  async delete() {
14957
14962
  try {
14958
- await fs17.promises.unlink(this.filePath);
14963
+ await fs18.promises.unlink(this.filePath);
14959
14964
  } catch (error) {
14960
14965
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
14961
14966
  throw error;
@@ -14968,11 +14973,11 @@ var FilePersistentInstructionsStorage = class {
14968
14973
  */
14969
14974
  async exists() {
14970
14975
  try {
14971
- await fs17.promises.access(this.filePath);
14976
+ await fs18.promises.access(this.filePath);
14972
14977
  return true;
14973
14978
  } catch {
14974
14979
  try {
14975
- await fs17.promises.access(this.legacyFilePath);
14980
+ await fs18.promises.access(this.legacyFilePath);
14976
14981
  return true;
14977
14982
  } catch {
14978
14983
  return false;
@@ -14996,7 +15001,7 @@ var FilePersistentInstructionsStorage = class {
14996
15001
  */
14997
15002
  async ensureDirectory() {
14998
15003
  try {
14999
- await fs17.promises.mkdir(this.directory, { recursive: true });
15004
+ await fs18.promises.mkdir(this.directory, { recursive: true });
15000
15005
  } catch (error) {
15001
15006
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
15002
15007
  throw error;
@@ -15008,7 +15013,7 @@ var FilePersistentInstructionsStorage = class {
15008
15013
  */
15009
15014
  async removeLegacyFile() {
15010
15015
  try {
15011
- await fs17.promises.unlink(this.legacyFilePath);
15016
+ await fs18.promises.unlink(this.legacyFilePath);
15012
15017
  } catch (error) {
15013
15018
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
15014
15019
  console.warn(`Failed to remove legacy instructions file: ${this.legacyFilePath}`);
@@ -15472,6 +15477,572 @@ ${entry.content}`).join("\n\n");
15472
15477
  };
15473
15478
  }
15474
15479
  };
15480
+ function getDefaultBaseDirectory2() {
15481
+ const platform2 = process.platform;
15482
+ if (platform2 === "win32") {
15483
+ const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
15484
+ if (appData) {
15485
+ return path2.join(appData, "oneringai", "users");
15486
+ }
15487
+ }
15488
+ return path2.join(os2.homedir(), ".oneringai", "users");
15489
+ }
15490
+ var DEFAULT_USER_ID = "default";
15491
+ function sanitizeUserId(userId) {
15492
+ if (!userId) return DEFAULT_USER_ID;
15493
+ return userId.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || DEFAULT_USER_ID;
15494
+ }
15495
+ var FileUserInfoStorage = class {
15496
+ baseDirectory;
15497
+ filename;
15498
+ constructor(config) {
15499
+ this.baseDirectory = config?.baseDirectory ?? getDefaultBaseDirectory2();
15500
+ this.filename = config?.filename ?? "user_info.json";
15501
+ }
15502
+ /**
15503
+ * Get the directory path for a specific user
15504
+ */
15505
+ getUserDirectory(userId) {
15506
+ const sanitizedId = sanitizeUserId(userId);
15507
+ return path2.join(this.baseDirectory, sanitizedId);
15508
+ }
15509
+ /**
15510
+ * Get the file path for a specific user
15511
+ */
15512
+ getUserFilePath(userId) {
15513
+ return path2.join(this.getUserDirectory(userId), this.filename);
15514
+ }
15515
+ /**
15516
+ * Load user info entries from file for a specific user
15517
+ */
15518
+ async load(userId) {
15519
+ const filePath = this.getUserFilePath(userId);
15520
+ try {
15521
+ const raw = await fs18.promises.readFile(filePath, "utf-8");
15522
+ const data = JSON.parse(raw);
15523
+ if (data.version === 1 && Array.isArray(data.entries)) {
15524
+ return data.entries.length > 0 ? data.entries : null;
15525
+ }
15526
+ return null;
15527
+ } catch (error) {
15528
+ if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) {
15529
+ throw error;
15530
+ }
15531
+ return null;
15532
+ }
15533
+ }
15534
+ /**
15535
+ * Save user info entries to file for a specific user
15536
+ * Creates directory if it doesn't exist.
15537
+ */
15538
+ async save(userId, entries) {
15539
+ const directory = this.getUserDirectory(userId);
15540
+ const filePath = this.getUserFilePath(userId);
15541
+ await this.ensureDirectory(directory);
15542
+ const data = {
15543
+ version: 1,
15544
+ userId: userId || DEFAULT_USER_ID,
15545
+ entries
15546
+ };
15547
+ const tempPath = `${filePath}.tmp`;
15548
+ try {
15549
+ await fs18.promises.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
15550
+ await fs18.promises.rename(tempPath, filePath);
15551
+ } catch (error) {
15552
+ try {
15553
+ await fs18.promises.unlink(tempPath);
15554
+ } catch {
15555
+ }
15556
+ throw error;
15557
+ }
15558
+ }
15559
+ /**
15560
+ * Delete user info file for a specific user
15561
+ */
15562
+ async delete(userId) {
15563
+ const filePath = this.getUserFilePath(userId);
15564
+ try {
15565
+ await fs18.promises.unlink(filePath);
15566
+ } catch (error) {
15567
+ if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
15568
+ throw error;
15569
+ }
15570
+ }
15571
+ }
15572
+ /**
15573
+ * Check if user info file exists for a specific user
15574
+ */
15575
+ async exists(userId) {
15576
+ const filePath = this.getUserFilePath(userId);
15577
+ try {
15578
+ await fs18.promises.access(filePath);
15579
+ return true;
15580
+ } catch {
15581
+ return false;
15582
+ }
15583
+ }
15584
+ /**
15585
+ * Get the file path for a specific user (for display/debugging)
15586
+ */
15587
+ getPath(userId) {
15588
+ return this.getUserFilePath(userId);
15589
+ }
15590
+ /**
15591
+ * Ensure the directory exists
15592
+ */
15593
+ async ensureDirectory(directory) {
15594
+ try {
15595
+ await fs18.promises.mkdir(directory, { recursive: true });
15596
+ } catch (error) {
15597
+ if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
15598
+ throw error;
15599
+ }
15600
+ }
15601
+ }
15602
+ };
15603
+
15604
+ // src/core/context-nextgen/plugins/UserInfoPluginNextGen.ts
15605
+ init_StorageRegistry();
15606
+ var DEFAULT_MAX_TOTAL_SIZE = 1e5;
15607
+ var DEFAULT_MAX_ENTRIES2 = 100;
15608
+ var KEY_MAX_LENGTH2 = 100;
15609
+ var KEY_PATTERN2 = /^[a-zA-Z0-9_-]+$/;
15610
+ var USER_INFO_INSTRUCTIONS = `User Info stores key-value information about the current user.
15611
+ Data is user-specific and persists across sessions and agents.
15612
+ User info is automatically shown in context \u2014 no need to call user_info_get every turn.
15613
+
15614
+ **To manage:**
15615
+ - \`user_info_set(key, value, description?)\`: Store/update user information
15616
+ - \`user_info_get(key?)\`: Retrieve one entry by key, or all entries if no key
15617
+ - \`user_info_remove(key)\`: Remove a specific entry
15618
+ - \`user_info_clear(confirm: true)\`: Remove all entries (destructive!)
15619
+
15620
+ **Use for:** User preferences, context, metadata (theme, language, timezone, role, etc.) It is also perfectly fine to search the web and other external sources for information about the user and then store it in user info for future use.
15621
+
15622
+ **Important:** Do not store sensitive information (passwords, tokens, PII) in user info. It is not encrypted and may be accessible to other parts of the system. Always follow best practices for security.
15623
+
15624
+ **Rules after each user message:** If the user provides new information about themselves, update user info accordingly. If they ask to change or remove existing information, do that as well. Always keep user info up to date with the latest information provided by the user. Learn about the user proactively!`;
15625
+ var userInfoSetDefinition = {
15626
+ type: "function",
15627
+ function: {
15628
+ name: "user_info_set",
15629
+ description: `Store or update user information by key. Data persists across sessions.
15630
+ If the key exists, it will be updated. If not, a new entry is created.`,
15631
+ parameters: {
15632
+ type: "object",
15633
+ properties: {
15634
+ key: {
15635
+ type: "string",
15636
+ description: "Unique key for the information (alphanumeric, dash, underscore; max 100 chars)"
15637
+ },
15638
+ value: {
15639
+ description: "Value to store (any JSON-serializable data: string, number, boolean, object, array)"
15640
+ },
15641
+ description: {
15642
+ type: "string",
15643
+ description: "Optional description for self-documentation"
15644
+ }
15645
+ },
15646
+ required: ["key", "value"]
15647
+ }
15648
+ }
15649
+ };
15650
+ var userInfoGetDefinition = {
15651
+ type: "function",
15652
+ function: {
15653
+ name: "user_info_get",
15654
+ description: "Retrieve user information. If key is provided, returns that entry. Otherwise returns all entries.",
15655
+ parameters: {
15656
+ type: "object",
15657
+ properties: {
15658
+ key: {
15659
+ type: "string",
15660
+ description: "Key of the entry to retrieve (optional - omit to get all entries)"
15661
+ }
15662
+ },
15663
+ required: []
15664
+ }
15665
+ }
15666
+ };
15667
+ var userInfoRemoveDefinition = {
15668
+ type: "function",
15669
+ function: {
15670
+ name: "user_info_remove",
15671
+ description: "Remove a specific user information entry by key.",
15672
+ parameters: {
15673
+ type: "object",
15674
+ properties: {
15675
+ key: {
15676
+ type: "string",
15677
+ description: "Key of the entry to remove"
15678
+ }
15679
+ },
15680
+ required: ["key"]
15681
+ }
15682
+ }
15683
+ };
15684
+ var userInfoClearDefinition = {
15685
+ type: "function",
15686
+ function: {
15687
+ name: "user_info_clear",
15688
+ description: "Clear all user information entries (DESTRUCTIVE). Requires confirmation.",
15689
+ parameters: {
15690
+ type: "object",
15691
+ properties: {
15692
+ confirm: {
15693
+ type: "boolean",
15694
+ description: "Must be true to confirm deletion"
15695
+ }
15696
+ },
15697
+ required: ["confirm"]
15698
+ }
15699
+ }
15700
+ };
15701
+ function validateKey2(key) {
15702
+ if (typeof key !== "string") return "Key must be a string";
15703
+ const trimmed = key.trim();
15704
+ if (trimmed.length === 0) return "Key cannot be empty";
15705
+ if (trimmed.length > KEY_MAX_LENGTH2) return `Key exceeds maximum length (${KEY_MAX_LENGTH2} chars)`;
15706
+ if (!KEY_PATTERN2.test(trimmed)) return "Key must contain only alphanumeric characters, dashes, and underscores";
15707
+ return null;
15708
+ }
15709
+ function getValueType(value) {
15710
+ if (value === null) return "null";
15711
+ if (Array.isArray(value)) return "array";
15712
+ return typeof value;
15713
+ }
15714
+ function calculateValueSize(value) {
15715
+ const json = JSON.stringify(value);
15716
+ return Buffer.byteLength(json, "utf-8");
15717
+ }
15718
+ function buildStorageContext(toolContext) {
15719
+ const global2 = exports.StorageRegistry.getContext();
15720
+ if (global2) return global2;
15721
+ if (toolContext?.userId) return { userId: toolContext.userId };
15722
+ return void 0;
15723
+ }
15724
+ function formatValue(value) {
15725
+ if (value === null) return "null";
15726
+ if (typeof value === "string") return value;
15727
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
15728
+ return JSON.stringify(value);
15729
+ }
15730
+ var UserInfoPluginNextGen = class {
15731
+ name = "user_info";
15732
+ _destroyed = false;
15733
+ _storage = null;
15734
+ /** In-memory cache of entries */
15735
+ _entries = /* @__PURE__ */ new Map();
15736
+ /** Whether entries have been loaded from storage */
15737
+ _initialized = false;
15738
+ maxTotalSize;
15739
+ maxEntries;
15740
+ estimator = simpleTokenEstimator;
15741
+ explicitStorage;
15742
+ /** UserId for getContent() and lazy initialization */
15743
+ userId;
15744
+ _tokenCache = null;
15745
+ _instructionsTokenCache = null;
15746
+ constructor(config) {
15747
+ this.maxTotalSize = config?.maxTotalSize ?? DEFAULT_MAX_TOTAL_SIZE;
15748
+ this.maxEntries = config?.maxEntries ?? DEFAULT_MAX_ENTRIES2;
15749
+ this.explicitStorage = config?.storage;
15750
+ this.userId = config?.userId;
15751
+ }
15752
+ // ============================================================================
15753
+ // IContextPluginNextGen Implementation
15754
+ // ============================================================================
15755
+ getInstructions() {
15756
+ return USER_INFO_INSTRUCTIONS;
15757
+ }
15758
+ async getContent() {
15759
+ await this.ensureInitialized();
15760
+ if (this._entries.size === 0) {
15761
+ this._tokenCache = 0;
15762
+ return null;
15763
+ }
15764
+ const rendered = this.renderContent();
15765
+ this._tokenCache = this.estimator.estimateTokens(rendered);
15766
+ return rendered;
15767
+ }
15768
+ getContents() {
15769
+ return new Map(this._entries);
15770
+ }
15771
+ getTokenSize() {
15772
+ return this._tokenCache ?? 0;
15773
+ }
15774
+ getInstructionsTokenSize() {
15775
+ if (this._instructionsTokenCache === null) {
15776
+ this._instructionsTokenCache = this.estimator.estimateTokens(USER_INFO_INSTRUCTIONS);
15777
+ }
15778
+ return this._instructionsTokenCache;
15779
+ }
15780
+ isCompactable() {
15781
+ return false;
15782
+ }
15783
+ async compact(_targetTokensToFree) {
15784
+ return 0;
15785
+ }
15786
+ getTools() {
15787
+ return [
15788
+ this.createUserInfoSetTool(),
15789
+ this.createUserInfoGetTool(),
15790
+ this.createUserInfoRemoveTool(),
15791
+ this.createUserInfoClearTool()
15792
+ ];
15793
+ }
15794
+ destroy() {
15795
+ if (this._destroyed) return;
15796
+ this._entries.clear();
15797
+ this._destroyed = true;
15798
+ this._tokenCache = null;
15799
+ }
15800
+ getState() {
15801
+ return {
15802
+ version: 1,
15803
+ entries: Array.from(this._entries.values()),
15804
+ userId: this.userId
15805
+ };
15806
+ }
15807
+ restoreState(state) {
15808
+ if (!state || typeof state !== "object") return;
15809
+ const s = state;
15810
+ if ("version" in s && s.version === 1 && Array.isArray(s.entries)) {
15811
+ this._entries.clear();
15812
+ for (const entry of s.entries) {
15813
+ this._entries.set(entry.id, entry);
15814
+ }
15815
+ this._initialized = true;
15816
+ this._tokenCache = null;
15817
+ }
15818
+ }
15819
+ // ============================================================================
15820
+ // Public API
15821
+ // ============================================================================
15822
+ /**
15823
+ * Check if initialized
15824
+ */
15825
+ get isInitialized() {
15826
+ return this._initialized;
15827
+ }
15828
+ // ============================================================================
15829
+ // Private Helpers
15830
+ // ============================================================================
15831
+ assertNotDestroyed() {
15832
+ if (this._destroyed) {
15833
+ throw new Error("UserInfoPluginNextGen is destroyed");
15834
+ }
15835
+ }
15836
+ /**
15837
+ * Lazy load entries from storage
15838
+ */
15839
+ async ensureInitialized() {
15840
+ if (this._initialized || this._destroyed) return;
15841
+ try {
15842
+ const storage = this.resolveStorage();
15843
+ const entries = await storage.load(this.userId);
15844
+ this._entries.clear();
15845
+ if (entries) {
15846
+ for (const entry of entries) {
15847
+ this._entries.set(entry.id, entry);
15848
+ }
15849
+ }
15850
+ this._initialized = true;
15851
+ } catch (error) {
15852
+ console.warn(`Failed to load user info for userId '${this.userId ?? "default"}':`, error);
15853
+ this._entries.clear();
15854
+ this._initialized = true;
15855
+ }
15856
+ this._tokenCache = null;
15857
+ }
15858
+ /**
15859
+ * Render entries as markdown for context injection
15860
+ */
15861
+ renderContent() {
15862
+ const sorted = Array.from(this._entries.values()).sort((a, b) => a.createdAt - b.createdAt);
15863
+ return sorted.map((entry) => `### ${entry.id}
15864
+ ${formatValue(entry.value)}`).join("\n\n");
15865
+ }
15866
+ /**
15867
+ * Resolve storage instance (lazy singleton)
15868
+ */
15869
+ resolveStorage(context) {
15870
+ if (this._storage) return this._storage;
15871
+ if (this.explicitStorage) {
15872
+ this._storage = this.explicitStorage;
15873
+ return this._storage;
15874
+ }
15875
+ const factory = exports.StorageRegistry.get("userInfo");
15876
+ if (factory) {
15877
+ this._storage = factory(buildStorageContext(context));
15878
+ return this._storage;
15879
+ }
15880
+ this._storage = new FileUserInfoStorage();
15881
+ return this._storage;
15882
+ }
15883
+ /**
15884
+ * Persist current entries to storage
15885
+ */
15886
+ async persistToStorage(userId) {
15887
+ const storage = this.resolveStorage();
15888
+ if (this._entries.size === 0) {
15889
+ await storage.delete(userId);
15890
+ } else {
15891
+ await storage.save(userId, Array.from(this._entries.values()));
15892
+ }
15893
+ }
15894
+ // ============================================================================
15895
+ // Tool Factories
15896
+ // ============================================================================
15897
+ createUserInfoSetTool() {
15898
+ return {
15899
+ definition: userInfoSetDefinition,
15900
+ execute: async (args, context) => {
15901
+ this.assertNotDestroyed();
15902
+ await this.ensureInitialized();
15903
+ const userId = context?.userId ?? this.userId;
15904
+ const key = args.key;
15905
+ const value = args.value;
15906
+ const description = args.description;
15907
+ const keyError = validateKey2(key);
15908
+ if (keyError) {
15909
+ return { error: keyError };
15910
+ }
15911
+ const trimmedKey = key.trim();
15912
+ if (value === void 0) {
15913
+ return { error: "Value cannot be undefined. Use null for explicit null value." };
15914
+ }
15915
+ if (!this._entries.has(trimmedKey) && this._entries.size >= this.maxEntries) {
15916
+ return { error: `Maximum number of entries reached (${this.maxEntries})` };
15917
+ }
15918
+ const valueSize = calculateValueSize(value);
15919
+ let currentTotal = 0;
15920
+ for (const e of this._entries.values()) {
15921
+ currentTotal += calculateValueSize(e.value);
15922
+ }
15923
+ const existingSize = this._entries.has(trimmedKey) ? calculateValueSize(this._entries.get(trimmedKey).value) : 0;
15924
+ const newTotal = currentTotal - existingSize + valueSize;
15925
+ if (newTotal > this.maxTotalSize) {
15926
+ return { error: `Total size would exceed maximum (${this.maxTotalSize} bytes)` };
15927
+ }
15928
+ const now = Date.now();
15929
+ const existing = this._entries.get(trimmedKey);
15930
+ const entry = {
15931
+ id: trimmedKey,
15932
+ value,
15933
+ valueType: getValueType(value),
15934
+ description,
15935
+ createdAt: existing?.createdAt ?? now,
15936
+ updatedAt: now
15937
+ };
15938
+ this._entries.set(trimmedKey, entry);
15939
+ this._tokenCache = null;
15940
+ await this.persistToStorage(userId);
15941
+ return {
15942
+ success: true,
15943
+ message: existing ? `User info '${trimmedKey}' updated` : `User info '${trimmedKey}' added`,
15944
+ key: trimmedKey,
15945
+ valueType: entry.valueType,
15946
+ valueSize
15947
+ };
15948
+ },
15949
+ permission: { scope: "always", riskLevel: "low" },
15950
+ describeCall: (args) => `set user info '${args.key}'`
15951
+ };
15952
+ }
15953
+ createUserInfoGetTool() {
15954
+ return {
15955
+ definition: userInfoGetDefinition,
15956
+ execute: async (args, _context) => {
15957
+ this.assertNotDestroyed();
15958
+ await this.ensureInitialized();
15959
+ const key = args.key;
15960
+ if (this._entries.size === 0) {
15961
+ return { error: "User info not found" };
15962
+ }
15963
+ if (key !== void 0) {
15964
+ const trimmedKey = key.trim();
15965
+ const entry = this._entries.get(trimmedKey);
15966
+ if (!entry) {
15967
+ return { error: `User info '${trimmedKey}' not found` };
15968
+ }
15969
+ return {
15970
+ key: entry.id,
15971
+ value: entry.value,
15972
+ valueType: entry.valueType,
15973
+ description: entry.description,
15974
+ createdAt: entry.createdAt,
15975
+ updatedAt: entry.updatedAt
15976
+ };
15977
+ }
15978
+ const entries = Array.from(this._entries.values());
15979
+ return {
15980
+ count: entries.length,
15981
+ entries: entries.map((e) => ({
15982
+ key: e.id,
15983
+ value: e.value,
15984
+ valueType: e.valueType,
15985
+ description: e.description,
15986
+ createdAt: e.createdAt,
15987
+ updatedAt: e.updatedAt
15988
+ }))
15989
+ };
15990
+ },
15991
+ permission: { scope: "always", riskLevel: "low" },
15992
+ describeCall: (args) => args.key ? `get user info '${args.key}'` : "get all user info"
15993
+ };
15994
+ }
15995
+ createUserInfoRemoveTool() {
15996
+ return {
15997
+ definition: userInfoRemoveDefinition,
15998
+ execute: async (args, context) => {
15999
+ this.assertNotDestroyed();
16000
+ await this.ensureInitialized();
16001
+ const userId = context?.userId ?? this.userId;
16002
+ const key = args.key;
16003
+ if (!key || typeof key !== "string" || key.trim().length === 0) {
16004
+ return { error: "Key is required" };
16005
+ }
16006
+ const trimmedKey = key.trim();
16007
+ if (!this._entries.has(trimmedKey)) {
16008
+ return { error: `User info '${trimmedKey}' not found` };
16009
+ }
16010
+ this._entries.delete(trimmedKey);
16011
+ this._tokenCache = null;
16012
+ await this.persistToStorage(userId);
16013
+ return {
16014
+ success: true,
16015
+ message: `User info '${trimmedKey}' removed`,
16016
+ key: trimmedKey
16017
+ };
16018
+ },
16019
+ permission: { scope: "always", riskLevel: "low" },
16020
+ describeCall: (args) => `remove user info '${args.key}'`
16021
+ };
16022
+ }
16023
+ createUserInfoClearTool() {
16024
+ return {
16025
+ definition: userInfoClearDefinition,
16026
+ execute: async (args, context) => {
16027
+ this.assertNotDestroyed();
16028
+ const userId = context?.userId ?? this.userId;
16029
+ if (args.confirm !== true) {
16030
+ return { error: "Must pass confirm: true to clear user info" };
16031
+ }
16032
+ this._entries.clear();
16033
+ this._tokenCache = null;
16034
+ const storage = this.resolveStorage(context);
16035
+ await storage.delete(userId);
16036
+ return {
16037
+ success: true,
16038
+ message: "All user information cleared"
16039
+ };
16040
+ },
16041
+ permission: { scope: "once", riskLevel: "medium" },
16042
+ describeCall: () => "clear user info"
16043
+ };
16044
+ }
16045
+ };
15475
16046
 
15476
16047
  // src/core/context-nextgen/AgentContextNextGen.ts
15477
16048
  init_StorageRegistry();
@@ -16120,7 +16691,8 @@ var StrategyRegistry = class {
16120
16691
  var DEFAULT_FEATURES = {
16121
16692
  workingMemory: true,
16122
16693
  inContextMemory: false,
16123
- persistentInstructions: false
16694
+ persistentInstructions: false,
16695
+ userInfo: false
16124
16696
  };
16125
16697
  var DEFAULT_CONFIG2 = {
16126
16698
  responseReserve: 4096,
@@ -16238,6 +16810,13 @@ var AgentContextNextGen = class _AgentContextNextGen extends eventemitter3.Event
16238
16810
  ...piConfig
16239
16811
  }));
16240
16812
  }
16813
+ if (features.userInfo) {
16814
+ const uiConfig = configs.userInfo;
16815
+ this.registerPlugin(new UserInfoPluginNextGen({
16816
+ userId: this._userId,
16817
+ ...uiConfig
16818
+ }));
16819
+ }
16241
16820
  this.validateStrategyDependencies(this._compactionStrategy);
16242
16821
  }
16243
16822
  /**
@@ -22803,7 +23382,7 @@ init_constants();
22803
23382
  throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
22804
23383
  }
22805
23384
  try {
22806
- const content = await fs17.promises.readFile(configPath, "utf-8");
23385
+ const content = await fs18.promises.readFile(configPath, "utf-8");
22807
23386
  let config = JSON.parse(content);
22808
23387
  config = this.interpolateEnvVars(config);
22809
23388
  this.validate(config);
@@ -22824,8 +23403,8 @@ init_constants();
22824
23403
  throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
22825
23404
  }
22826
23405
  try {
22827
- const fs18 = __require("fs");
22828
- const content = fs18.readFileSync(configPath, "utf-8");
23406
+ const fs19 = __require("fs");
23407
+ const content = fs19.readFileSync(configPath, "utf-8");
22829
23408
  let config = JSON.parse(content);
22830
23409
  config = this.interpolateEnvVars(config);
22831
23410
  this.validate(config);
@@ -22843,7 +23422,7 @@ init_constants();
22843
23422
  static async findConfig() {
22844
23423
  for (const path6 of this.DEFAULT_PATHS) {
22845
23424
  try {
22846
- await fs17.promises.access(path2.resolve(path6));
23425
+ await fs18.promises.access(path2.resolve(path6));
22847
23426
  return path2.resolve(path6);
22848
23427
  } catch {
22849
23428
  }
@@ -22854,10 +23433,10 @@ init_constants();
22854
23433
  * Find configuration file synchronously
22855
23434
  */
22856
23435
  static findConfigSync() {
22857
- const fs18 = __require("fs");
23436
+ const fs19 = __require("fs");
22858
23437
  for (const path6 of this.DEFAULT_PATHS) {
22859
23438
  try {
22860
- fs18.accessSync(path2.resolve(path6));
23439
+ fs19.accessSync(path2.resolve(path6));
22861
23440
  return path2.resolve(path6);
22862
23441
  } catch {
22863
23442
  }
@@ -27815,10 +28394,16 @@ function applyServerDefaults(config, defaults) {
27815
28394
  };
27816
28395
  }
27817
28396
 
27818
- // src/infrastructure/mcp/adapters/MCPToolAdapter.ts
28397
+ // src/utils/sanitize.ts
27819
28398
  function sanitizeToolName(name) {
27820
- return name.replace(/[^a-zA-Z0-9_-]/g, "_");
28399
+ let result = name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^[_-]+|[_-]+$/g, "");
28400
+ if (/^[0-9]/.test(result)) {
28401
+ result = `n_${result}`;
28402
+ }
28403
+ return result || "unnamed";
27821
28404
  }
28405
+
28406
+ // src/infrastructure/mcp/adapters/MCPToolAdapter.ts
27822
28407
  function createMCPToolAdapter(tool, client, namespace) {
27823
28408
  const fullName = sanitizeToolName(`${namespace}:${tool.name}`);
27824
28409
  return {
@@ -28425,7 +29010,7 @@ var MCPRegistry = class {
28425
29010
  static async loadFromConfigFile(path6) {
28426
29011
  try {
28427
29012
  const configPath = path2.resolve(path6);
28428
- const content = await fs17.promises.readFile(configPath, "utf-8");
29013
+ const content = await fs18.promises.readFile(configPath, "utf-8");
28429
29014
  const config = JSON.parse(content);
28430
29015
  if (!config.mcp) {
28431
29016
  throw new MCPError("Configuration file does not contain MCP section");
@@ -29030,7 +29615,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
29030
29615
  if (Buffer.isBuffer(audio)) {
29031
29616
  return new File([new Uint8Array(audio)], "audio.wav", { type: "audio/wav" });
29032
29617
  } else if (typeof audio === "string") {
29033
- return fs17__namespace.createReadStream(audio);
29618
+ return fs18__namespace.createReadStream(audio);
29034
29619
  } else {
29035
29620
  throw new Error("Invalid audio input: must be Buffer or file path");
29036
29621
  }
@@ -29583,7 +30168,7 @@ var TextToSpeech = class _TextToSpeech {
29583
30168
  */
29584
30169
  async toFile(text, filePath, options) {
29585
30170
  const response = await this.synthesize(text, options);
29586
- await fs16__namespace.writeFile(filePath, response.audio);
30171
+ await fs17__namespace.writeFile(filePath, response.audio);
29587
30172
  }
29588
30173
  // ======================== Introspection Methods ========================
29589
30174
  /**
@@ -29931,7 +30516,7 @@ var SpeechToText = class _SpeechToText {
29931
30516
  * @param options - Optional transcription parameters
29932
30517
  */
29933
30518
  async transcribeFile(filePath, options) {
29934
- const audio = await fs16__namespace.readFile(filePath);
30519
+ const audio = await fs17__namespace.readFile(filePath);
29935
30520
  return this.transcribe(audio, options);
29936
30521
  }
29937
30522
  /**
@@ -30257,7 +30842,7 @@ var OpenAIImageProvider = class extends BaseMediaProvider {
30257
30842
  if (Buffer.isBuffer(image)) {
30258
30843
  return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
30259
30844
  }
30260
- return fs17__namespace.createReadStream(image);
30845
+ return fs18__namespace.createReadStream(image);
30261
30846
  }
30262
30847
  /**
30263
30848
  * Handle OpenAI API errors
@@ -30404,8 +30989,8 @@ var GoogleImageProvider = class extends BaseMediaProvider {
30404
30989
  if (Buffer.isBuffer(image)) {
30405
30990
  imageBytes = image.toString("base64");
30406
30991
  } else {
30407
- const fs18 = await import('fs');
30408
- const buffer = fs18.readFileSync(image);
30992
+ const fs19 = await import('fs');
30993
+ const buffer = fs19.readFileSync(image);
30409
30994
  imageBytes = buffer.toString("base64");
30410
30995
  }
30411
30996
  return {
@@ -30566,7 +31151,7 @@ var GrokImageProvider = class extends BaseMediaProvider {
30566
31151
  if (Buffer.isBuffer(image)) {
30567
31152
  return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
30568
31153
  }
30569
- return fs17__namespace.createReadStream(image);
31154
+ return fs18__namespace.createReadStream(image);
30570
31155
  }
30571
31156
  /**
30572
31157
  * Handle API errors
@@ -32016,8 +32601,8 @@ var OpenAISoraProvider = class extends BaseMediaProvider {
32016
32601
  return new File([new Uint8Array(image)], "input.png", { type: "image/png" });
32017
32602
  }
32018
32603
  if (!image.startsWith("http")) {
32019
- const fs18 = await import('fs');
32020
- const data = fs18.readFileSync(image);
32604
+ const fs19 = await import('fs');
32605
+ const data = fs19.readFileSync(image);
32021
32606
  return new File([new Uint8Array(data)], "input.png", { type: "image/png" });
32022
32607
  }
32023
32608
  const response = await fetch(image);
@@ -32195,7 +32780,7 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
32195
32780
  if (video.videoBytes) {
32196
32781
  buffer = Buffer.from(video.videoBytes, "base64");
32197
32782
  } else if (video.uri) {
32198
- const fs18 = await import('fs/promises');
32783
+ const fs19 = await import('fs/promises');
32199
32784
  const os3 = await import('os');
32200
32785
  const path6 = await import('path');
32201
32786
  const tempDir = os3.tmpdir();
@@ -32206,11 +32791,11 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
32206
32791
  // Pass as GeneratedVideo
32207
32792
  downloadPath: tempFile
32208
32793
  });
32209
- buffer = await fs18.readFile(tempFile);
32210
- await fs18.unlink(tempFile).catch(() => {
32794
+ buffer = await fs19.readFile(tempFile);
32795
+ await fs19.unlink(tempFile).catch(() => {
32211
32796
  });
32212
32797
  } catch (downloadError) {
32213
- await fs18.unlink(tempFile).catch(() => {
32798
+ await fs19.unlink(tempFile).catch(() => {
32214
32799
  });
32215
32800
  throw new ProviderError(
32216
32801
  "google",
@@ -32332,8 +32917,8 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
32332
32917
  if (image.startsWith("http://") || image.startsWith("https://")) {
32333
32918
  return { imageUri: image };
32334
32919
  }
32335
- const fs18 = await import('fs/promises');
32336
- const data = await fs18.readFile(image);
32920
+ const fs19 = await import('fs/promises');
32921
+ const data = await fs19.readFile(image);
32337
32922
  return {
32338
32923
  imageBytes: data.toString("base64")
32339
32924
  };
@@ -32640,8 +33225,8 @@ var GrokImagineProvider = class extends BaseMediaProvider {
32640
33225
  if (image.startsWith("http") || image.startsWith("data:")) {
32641
33226
  return image;
32642
33227
  }
32643
- const fs18 = await import('fs');
32644
- const data = fs18.readFileSync(image);
33228
+ const fs19 = await import('fs');
33229
+ const data = fs19.readFileSync(image);
32645
33230
  const base64 = data.toString("base64");
32646
33231
  const ext = image.split(".").pop()?.toLowerCase() || "png";
32647
33232
  const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext}`;
@@ -34077,7 +34662,7 @@ var DocumentReader = class _DocumentReader {
34077
34662
  async resolveSource(source) {
34078
34663
  switch (source.type) {
34079
34664
  case "file": {
34080
- const buffer = await fs16.readFile(source.path);
34665
+ const buffer = await fs17.readFile(source.path);
34081
34666
  const filename = source.path.split("/").pop() || source.path;
34082
34667
  return { buffer, filename };
34083
34668
  }
@@ -36344,7 +36929,7 @@ var InMemoryHistoryStorage = class {
36344
36929
  this.summaries = state.summaries ? [...state.summaries] : [];
36345
36930
  }
36346
36931
  };
36347
- function getDefaultBaseDirectory2() {
36932
+ function getDefaultBaseDirectory3() {
36348
36933
  const platform2 = process.platform;
36349
36934
  if (platform2 === "win32") {
36350
36935
  const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
@@ -36367,7 +36952,7 @@ var FileContextStorage = class {
36367
36952
  constructor(config) {
36368
36953
  this.agentId = config.agentId;
36369
36954
  const sanitizedAgentId = sanitizeId(config.agentId);
36370
- const baseDir = config.baseDirectory ?? getDefaultBaseDirectory2();
36955
+ const baseDir = config.baseDirectory ?? getDefaultBaseDirectory3();
36371
36956
  this.prettyPrint = config.prettyPrint ?? true;
36372
36957
  this.sessionsDirectory = path2.join(baseDir, sanitizedAgentId, "sessions");
36373
36958
  this.indexPath = path2.join(this.sessionsDirectory, "_index.json");
@@ -36396,11 +36981,11 @@ var FileContextStorage = class {
36396
36981
  const data = this.prettyPrint ? JSON.stringify(storedSession, null, 2) : JSON.stringify(storedSession);
36397
36982
  const tempPath = `${filePath}.tmp`;
36398
36983
  try {
36399
- await fs17.promises.writeFile(tempPath, data, "utf-8");
36400
- await fs17.promises.rename(tempPath, filePath);
36984
+ await fs18.promises.writeFile(tempPath, data, "utf-8");
36985
+ await fs18.promises.rename(tempPath, filePath);
36401
36986
  } catch (error) {
36402
36987
  try {
36403
- await fs17.promises.unlink(tempPath);
36988
+ await fs18.promises.unlink(tempPath);
36404
36989
  } catch {
36405
36990
  }
36406
36991
  throw error;
@@ -36421,7 +37006,7 @@ var FileContextStorage = class {
36421
37006
  const sanitizedSessionId = sanitizeId(sessionId);
36422
37007
  const filePath = this.getFilePath(sanitizedSessionId);
36423
37008
  try {
36424
- await fs17.promises.unlink(filePath);
37009
+ await fs18.promises.unlink(filePath);
36425
37010
  } catch (error) {
36426
37011
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
36427
37012
  throw error;
@@ -36436,7 +37021,7 @@ var FileContextStorage = class {
36436
37021
  const sanitizedSessionId = sanitizeId(sessionId);
36437
37022
  const filePath = this.getFilePath(sanitizedSessionId);
36438
37023
  try {
36439
- await fs17.promises.access(filePath);
37024
+ await fs18.promises.access(filePath);
36440
37025
  return true;
36441
37026
  } catch {
36442
37027
  return false;
@@ -36501,7 +37086,7 @@ var FileContextStorage = class {
36501
37086
  const sanitizedSessionId = sanitizeId(sessionId);
36502
37087
  const filePath = this.getFilePath(sanitizedSessionId);
36503
37088
  const data = this.prettyPrint ? JSON.stringify(stored, null, 2) : JSON.stringify(stored);
36504
- await fs17.promises.writeFile(filePath, data, "utf-8");
37089
+ await fs18.promises.writeFile(filePath, data, "utf-8");
36505
37090
  await this.updateIndex(stored);
36506
37091
  }
36507
37092
  /**
@@ -36529,13 +37114,13 @@ var FileContextStorage = class {
36529
37114
  */
36530
37115
  async rebuildIndex() {
36531
37116
  await this.ensureDirectory();
36532
- const files = await fs17.promises.readdir(this.sessionsDirectory);
37117
+ const files = await fs18.promises.readdir(this.sessionsDirectory);
36533
37118
  const sessionFiles = files.filter((f) => f.endsWith(".json") && !f.startsWith("_"));
36534
37119
  const entries = [];
36535
37120
  for (const file of sessionFiles) {
36536
37121
  try {
36537
37122
  const filePath = path2.join(this.sessionsDirectory, file);
36538
- const data = await fs17.promises.readFile(filePath, "utf-8");
37123
+ const data = await fs18.promises.readFile(filePath, "utf-8");
36539
37124
  const stored = JSON.parse(data);
36540
37125
  entries.push(this.storedToIndexEntry(stored));
36541
37126
  } catch {
@@ -36557,7 +37142,7 @@ var FileContextStorage = class {
36557
37142
  }
36558
37143
  async ensureDirectory() {
36559
37144
  try {
36560
- await fs17.promises.mkdir(this.sessionsDirectory, { recursive: true });
37145
+ await fs18.promises.mkdir(this.sessionsDirectory, { recursive: true });
36561
37146
  } catch (error) {
36562
37147
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
36563
37148
  throw error;
@@ -36567,7 +37152,7 @@ var FileContextStorage = class {
36567
37152
  async loadRaw(sanitizedSessionId) {
36568
37153
  const filePath = this.getFilePath(sanitizedSessionId);
36569
37154
  try {
36570
- const data = await fs17.promises.readFile(filePath, "utf-8");
37155
+ const data = await fs18.promises.readFile(filePath, "utf-8");
36571
37156
  return JSON.parse(data);
36572
37157
  } catch (error) {
36573
37158
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -36585,7 +37170,7 @@ var FileContextStorage = class {
36585
37170
  return this.index;
36586
37171
  }
36587
37172
  try {
36588
- const data = await fs17.promises.readFile(this.indexPath, "utf-8");
37173
+ const data = await fs18.promises.readFile(this.indexPath, "utf-8");
36589
37174
  this.index = JSON.parse(data);
36590
37175
  return this.index;
36591
37176
  } catch (error) {
@@ -36606,7 +37191,7 @@ var FileContextStorage = class {
36606
37191
  await this.ensureDirectory();
36607
37192
  this.index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
36608
37193
  const data = this.prettyPrint ? JSON.stringify(this.index, null, 2) : JSON.stringify(this.index);
36609
- await fs17.promises.writeFile(this.indexPath, data, "utf-8");
37194
+ await fs18.promises.writeFile(this.indexPath, data, "utf-8");
36610
37195
  }
36611
37196
  async updateIndex(stored) {
36612
37197
  const index = await this.loadIndex();
@@ -36639,7 +37224,7 @@ var FileContextStorage = class {
36639
37224
  function createFileContextStorage(agentId, options) {
36640
37225
  return new FileContextStorage({ agentId, ...options });
36641
37226
  }
36642
- function getDefaultBaseDirectory3() {
37227
+ function getDefaultBaseDirectory4() {
36643
37228
  const platform2 = process.platform;
36644
37229
  if (platform2 === "win32") {
36645
37230
  const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
@@ -36658,7 +37243,7 @@ var FileAgentDefinitionStorage = class {
36658
37243
  prettyPrint;
36659
37244
  index = null;
36660
37245
  constructor(config = {}) {
36661
- this.baseDirectory = config.baseDirectory ?? getDefaultBaseDirectory3();
37246
+ this.baseDirectory = config.baseDirectory ?? getDefaultBaseDirectory4();
36662
37247
  this.prettyPrint = config.prettyPrint ?? true;
36663
37248
  this.indexPath = path2.join(this.baseDirectory, "_agents_index.json");
36664
37249
  }
@@ -36680,11 +37265,11 @@ var FileAgentDefinitionStorage = class {
36680
37265
  const data = this.prettyPrint ? JSON.stringify(definition, null, 2) : JSON.stringify(definition);
36681
37266
  const tempPath = `${filePath}.tmp`;
36682
37267
  try {
36683
- await fs17.promises.writeFile(tempPath, data, "utf-8");
36684
- await fs17.promises.rename(tempPath, filePath);
37268
+ await fs18.promises.writeFile(tempPath, data, "utf-8");
37269
+ await fs18.promises.rename(tempPath, filePath);
36685
37270
  } catch (error) {
36686
37271
  try {
36687
- await fs17.promises.unlink(tempPath);
37272
+ await fs18.promises.unlink(tempPath);
36688
37273
  } catch {
36689
37274
  }
36690
37275
  throw error;
@@ -36706,7 +37291,7 @@ var FileAgentDefinitionStorage = class {
36706
37291
  const agentDir = path2.join(this.baseDirectory, sanitizedId);
36707
37292
  const filePath = path2.join(agentDir, "definition.json");
36708
37293
  try {
36709
- await fs17.promises.unlink(filePath);
37294
+ await fs18.promises.unlink(filePath);
36710
37295
  } catch (error) {
36711
37296
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
36712
37297
  throw error;
@@ -36721,7 +37306,7 @@ var FileAgentDefinitionStorage = class {
36721
37306
  const sanitizedId = sanitizeAgentId2(agentId);
36722
37307
  const filePath = path2.join(this.baseDirectory, sanitizedId, "definition.json");
36723
37308
  try {
36724
- await fs17.promises.access(filePath);
37309
+ await fs18.promises.access(filePath);
36725
37310
  return true;
36726
37311
  } catch {
36727
37312
  return false;
@@ -36783,13 +37368,13 @@ var FileAgentDefinitionStorage = class {
36783
37368
  */
36784
37369
  async rebuildIndex() {
36785
37370
  await this.ensureDirectory(this.baseDirectory);
36786
- const entries = await fs17.promises.readdir(this.baseDirectory, { withFileTypes: true });
37371
+ const entries = await fs18.promises.readdir(this.baseDirectory, { withFileTypes: true });
36787
37372
  const agentDirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith("_"));
36788
37373
  const indexEntries = [];
36789
37374
  for (const dir of agentDirs) {
36790
37375
  try {
36791
37376
  const filePath = path2.join(this.baseDirectory, dir.name, "definition.json");
36792
- const data = await fs17.promises.readFile(filePath, "utf-8");
37377
+ const data = await fs18.promises.readFile(filePath, "utf-8");
36793
37378
  const definition = JSON.parse(data);
36794
37379
  indexEntries.push(this.definitionToIndexEntry(definition));
36795
37380
  } catch {
@@ -36807,7 +37392,7 @@ var FileAgentDefinitionStorage = class {
36807
37392
  // ==========================================================================
36808
37393
  async ensureDirectory(dir) {
36809
37394
  try {
36810
- await fs17.promises.mkdir(dir, { recursive: true });
37395
+ await fs18.promises.mkdir(dir, { recursive: true });
36811
37396
  } catch (error) {
36812
37397
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
36813
37398
  throw error;
@@ -36817,7 +37402,7 @@ var FileAgentDefinitionStorage = class {
36817
37402
  async loadRaw(sanitizedId) {
36818
37403
  const filePath = path2.join(this.baseDirectory, sanitizedId, "definition.json");
36819
37404
  try {
36820
- const data = await fs17.promises.readFile(filePath, "utf-8");
37405
+ const data = await fs18.promises.readFile(filePath, "utf-8");
36821
37406
  return JSON.parse(data);
36822
37407
  } catch (error) {
36823
37408
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -36835,7 +37420,7 @@ var FileAgentDefinitionStorage = class {
36835
37420
  return this.index;
36836
37421
  }
36837
37422
  try {
36838
- const data = await fs17.promises.readFile(this.indexPath, "utf-8");
37423
+ const data = await fs18.promises.readFile(this.indexPath, "utf-8");
36839
37424
  this.index = JSON.parse(data);
36840
37425
  return this.index;
36841
37426
  } catch (error) {
@@ -36855,7 +37440,7 @@ var FileAgentDefinitionStorage = class {
36855
37440
  await this.ensureDirectory(this.baseDirectory);
36856
37441
  this.index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
36857
37442
  const data = this.prettyPrint ? JSON.stringify(this.index, null, 2) : JSON.stringify(this.index);
36858
- await fs17.promises.writeFile(this.indexPath, data, "utf-8");
37443
+ await fs18.promises.writeFile(this.indexPath, data, "utf-8");
36859
37444
  }
36860
37445
  async updateIndex(definition) {
36861
37446
  const index = await this.loadIndex();
@@ -36913,10 +37498,10 @@ var FileMediaStorage = class {
36913
37498
  }
36914
37499
  async save(data, metadata) {
36915
37500
  const dir = metadata.userId ? path2__namespace.join(this.outputDir, metadata.userId) : this.outputDir;
36916
- await fs16__namespace.mkdir(dir, { recursive: true });
37501
+ await fs17__namespace.mkdir(dir, { recursive: true });
36917
37502
  const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
36918
37503
  const filePath = path2__namespace.join(dir, filename);
36919
- await fs16__namespace.writeFile(filePath, data);
37504
+ await fs17__namespace.writeFile(filePath, data);
36920
37505
  const format = metadata.format.toLowerCase();
36921
37506
  const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
36922
37507
  return {
@@ -36927,7 +37512,7 @@ var FileMediaStorage = class {
36927
37512
  }
36928
37513
  async read(location) {
36929
37514
  try {
36930
- return await fs16__namespace.readFile(location);
37515
+ return await fs17__namespace.readFile(location);
36931
37516
  } catch (err) {
36932
37517
  if (err.code === "ENOENT") {
36933
37518
  return null;
@@ -36937,7 +37522,7 @@ var FileMediaStorage = class {
36937
37522
  }
36938
37523
  async delete(location) {
36939
37524
  try {
36940
- await fs16__namespace.unlink(location);
37525
+ await fs17__namespace.unlink(location);
36941
37526
  } catch (err) {
36942
37527
  if (err.code === "ENOENT") {
36943
37528
  return;
@@ -36947,7 +37532,7 @@ var FileMediaStorage = class {
36947
37532
  }
36948
37533
  async exists(location) {
36949
37534
  try {
36950
- await fs16__namespace.access(location);
37535
+ await fs17__namespace.access(location);
36951
37536
  return true;
36952
37537
  } catch {
36953
37538
  return false;
@@ -36956,11 +37541,11 @@ var FileMediaStorage = class {
36956
37541
  async list(options) {
36957
37542
  await this.ensureDir();
36958
37543
  let entries = [];
36959
- const files = await fs16__namespace.readdir(this.outputDir);
37544
+ const files = await fs17__namespace.readdir(this.outputDir);
36960
37545
  for (const file of files) {
36961
37546
  const filePath = path2__namespace.join(this.outputDir, file);
36962
37547
  try {
36963
- const stat6 = await fs16__namespace.stat(filePath);
37548
+ const stat6 = await fs17__namespace.stat(filePath);
36964
37549
  if (!stat6.isFile()) continue;
36965
37550
  const ext = path2__namespace.extname(file).slice(1).toLowerCase();
36966
37551
  const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
@@ -37000,7 +37585,7 @@ var FileMediaStorage = class {
37000
37585
  }
37001
37586
  async ensureDir() {
37002
37587
  if (!this.initialized) {
37003
- await fs16__namespace.mkdir(this.outputDir, { recursive: true });
37588
+ await fs17__namespace.mkdir(this.outputDir, { recursive: true });
37004
37589
  this.initialized = true;
37005
37590
  }
37006
37591
  }
@@ -37008,58 +37593,82 @@ var FileMediaStorage = class {
37008
37593
  function createFileMediaStorage(config) {
37009
37594
  return new FileMediaStorage(config);
37010
37595
  }
37011
- function getDefaultBaseDirectory4() {
37596
+ function getDefaultBaseDirectory5() {
37012
37597
  const platform2 = process.platform;
37013
37598
  if (platform2 === "win32") {
37014
37599
  const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
37015
37600
  if (appData) {
37016
- return path2.join(appData, "oneringai", "custom-tools");
37601
+ return path2.join(appData, "oneringai", "users");
37017
37602
  }
37018
37603
  }
37019
- return path2.join(os2.homedir(), ".oneringai", "custom-tools");
37604
+ return path2.join(os2.homedir(), ".oneringai", "users");
37605
+ }
37606
+ var DEFAULT_USER_ID2 = "default";
37607
+ function sanitizeUserId2(userId) {
37608
+ if (!userId) {
37609
+ return DEFAULT_USER_ID2;
37610
+ }
37611
+ return userId.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || DEFAULT_USER_ID2;
37020
37612
  }
37021
37613
  function sanitizeName(name) {
37022
37614
  return name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || "default";
37023
37615
  }
37024
37616
  var FileCustomToolStorage = class {
37025
37617
  baseDirectory;
37026
- indexPath;
37027
37618
  prettyPrint;
37028
- index = null;
37029
37619
  constructor(config = {}) {
37030
- this.baseDirectory = config.baseDirectory ?? getDefaultBaseDirectory4();
37620
+ this.baseDirectory = config.baseDirectory ?? getDefaultBaseDirectory5();
37031
37621
  this.prettyPrint = config.prettyPrint ?? true;
37032
- this.indexPath = path2.join(this.baseDirectory, "_index.json");
37622
+ }
37623
+ /**
37624
+ * Get the directory path for a specific user's custom tools
37625
+ */
37626
+ getUserDirectory(userId) {
37627
+ const sanitizedId = sanitizeUserId2(userId);
37628
+ return path2.join(this.baseDirectory, sanitizedId, "custom-tools");
37629
+ }
37630
+ /**
37631
+ * Get the index file path for a specific user
37632
+ */
37633
+ getUserIndexPath(userId) {
37634
+ return path2.join(this.getUserDirectory(userId), "_index.json");
37635
+ }
37636
+ /**
37637
+ * Get the tool file path for a specific user
37638
+ */
37639
+ getToolPath(userId, sanitizedName) {
37640
+ return path2.join(this.getUserDirectory(userId), `${sanitizedName}.json`);
37033
37641
  }
37034
37642
  /**
37035
37643
  * Save a custom tool definition
37036
37644
  */
37037
- async save(definition) {
37645
+ async save(userId, definition) {
37646
+ const directory = this.getUserDirectory(userId);
37038
37647
  const sanitized = sanitizeName(definition.name);
37039
- const filePath = path2.join(this.baseDirectory, `${sanitized}.json`);
37040
- await this.ensureDirectory(this.baseDirectory);
37648
+ const filePath = this.getToolPath(userId, sanitized);
37649
+ await this.ensureDirectory(directory);
37041
37650
  const data = this.prettyPrint ? JSON.stringify(definition, null, 2) : JSON.stringify(definition);
37042
37651
  const tempPath = `${filePath}.tmp`;
37043
37652
  try {
37044
- await fs17.promises.writeFile(tempPath, data, "utf-8");
37045
- await fs17.promises.rename(tempPath, filePath);
37653
+ await fs18.promises.writeFile(tempPath, data, "utf-8");
37654
+ await fs18.promises.rename(tempPath, filePath);
37046
37655
  } catch (error) {
37047
37656
  try {
37048
- await fs17.promises.unlink(tempPath);
37657
+ await fs18.promises.unlink(tempPath);
37049
37658
  } catch {
37050
37659
  }
37051
37660
  throw error;
37052
37661
  }
37053
- await this.updateIndex(definition);
37662
+ await this.updateIndex(userId, definition);
37054
37663
  }
37055
37664
  /**
37056
37665
  * Load a custom tool definition by name
37057
37666
  */
37058
- async load(name) {
37667
+ async load(userId, name) {
37059
37668
  const sanitized = sanitizeName(name);
37060
- const filePath = path2.join(this.baseDirectory, `${sanitized}.json`);
37669
+ const filePath = this.getToolPath(userId, sanitized);
37061
37670
  try {
37062
- const data = await fs17.promises.readFile(filePath, "utf-8");
37671
+ const data = await fs18.promises.readFile(filePath, "utf-8");
37063
37672
  return JSON.parse(data);
37064
37673
  } catch (error) {
37065
37674
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -37074,26 +37683,26 @@ var FileCustomToolStorage = class {
37074
37683
  /**
37075
37684
  * Delete a custom tool definition
37076
37685
  */
37077
- async delete(name) {
37686
+ async delete(userId, name) {
37078
37687
  const sanitized = sanitizeName(name);
37079
- const filePath = path2.join(this.baseDirectory, `${sanitized}.json`);
37688
+ const filePath = this.getToolPath(userId, sanitized);
37080
37689
  try {
37081
- await fs17.promises.unlink(filePath);
37690
+ await fs18.promises.unlink(filePath);
37082
37691
  } catch (error) {
37083
37692
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
37084
37693
  throw error;
37085
37694
  }
37086
37695
  }
37087
- await this.removeFromIndex(name);
37696
+ await this.removeFromIndex(userId, name);
37088
37697
  }
37089
37698
  /**
37090
37699
  * Check if a custom tool exists
37091
37700
  */
37092
- async exists(name) {
37701
+ async exists(userId, name) {
37093
37702
  const sanitized = sanitizeName(name);
37094
- const filePath = path2.join(this.baseDirectory, `${sanitized}.json`);
37703
+ const filePath = this.getToolPath(userId, sanitized);
37095
37704
  try {
37096
- await fs17.promises.access(filePath);
37705
+ await fs18.promises.access(filePath);
37097
37706
  return true;
37098
37707
  } catch {
37099
37708
  return false;
@@ -37102,8 +37711,8 @@ var FileCustomToolStorage = class {
37102
37711
  /**
37103
37712
  * List custom tools (summaries only)
37104
37713
  */
37105
- async list(options) {
37106
- const index = await this.loadIndex();
37714
+ async list(userId, options) {
37715
+ const index = await this.loadIndex(userId);
37107
37716
  let entries = [...index.tools];
37108
37717
  if (options?.tags && options.tags.length > 0) {
37109
37718
  entries = entries.filter((e) => {
@@ -37144,62 +37753,59 @@ var FileCustomToolStorage = class {
37144
37753
  /**
37145
37754
  * Update metadata without loading full definition
37146
37755
  */
37147
- async updateMetadata(name, metadata) {
37148
- const definition = await this.load(name);
37756
+ async updateMetadata(userId, name, metadata) {
37757
+ const definition = await this.load(userId, name);
37149
37758
  if (!definition) {
37150
37759
  throw new Error(`Custom tool '${name}' not found`);
37151
37760
  }
37152
37761
  definition.metadata = { ...definition.metadata, ...metadata };
37153
37762
  definition.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
37154
- await this.save(definition);
37763
+ await this.save(userId, definition);
37155
37764
  }
37156
37765
  /**
37157
- * Get storage path
37766
+ * Get storage path for a specific user
37158
37767
  */
37159
- getPath() {
37160
- return this.baseDirectory;
37768
+ getPath(userId) {
37769
+ return this.getUserDirectory(userId);
37161
37770
  }
37162
37771
  // ==========================================================================
37163
37772
  // Private Helpers
37164
37773
  // ==========================================================================
37165
37774
  async ensureDirectory(dir) {
37166
37775
  try {
37167
- await fs17.promises.mkdir(dir, { recursive: true });
37776
+ await fs18.promises.mkdir(dir, { recursive: true });
37168
37777
  } catch (error) {
37169
37778
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
37170
37779
  throw error;
37171
37780
  }
37172
37781
  }
37173
37782
  }
37174
- async loadIndex() {
37175
- if (this.index) {
37176
- return this.index;
37177
- }
37783
+ async loadIndex(userId) {
37784
+ const indexPath = this.getUserIndexPath(userId);
37178
37785
  try {
37179
- const data = await fs17.promises.readFile(this.indexPath, "utf-8");
37180
- this.index = JSON.parse(data);
37181
- return this.index;
37786
+ const data = await fs18.promises.readFile(indexPath, "utf-8");
37787
+ return JSON.parse(data);
37182
37788
  } catch (error) {
37183
37789
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
37184
- this.index = {
37790
+ return {
37185
37791
  version: 1,
37186
37792
  tools: [],
37187
37793
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
37188
37794
  };
37189
- return this.index;
37190
37795
  }
37191
37796
  throw error;
37192
37797
  }
37193
37798
  }
37194
- async saveIndex() {
37195
- if (!this.index) return;
37196
- await this.ensureDirectory(this.baseDirectory);
37197
- this.index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
37198
- const data = this.prettyPrint ? JSON.stringify(this.index, null, 2) : JSON.stringify(this.index);
37199
- await fs17.promises.writeFile(this.indexPath, data, "utf-8");
37799
+ async saveIndex(userId, index) {
37800
+ const directory = this.getUserDirectory(userId);
37801
+ const indexPath = this.getUserIndexPath(userId);
37802
+ await this.ensureDirectory(directory);
37803
+ index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
37804
+ const data = this.prettyPrint ? JSON.stringify(index, null, 2) : JSON.stringify(index);
37805
+ await fs18.promises.writeFile(indexPath, data, "utf-8");
37200
37806
  }
37201
- async updateIndex(definition) {
37202
- const index = await this.loadIndex();
37807
+ async updateIndex(userId, definition) {
37808
+ const index = await this.loadIndex(userId);
37203
37809
  const entry = this.definitionToIndexEntry(definition);
37204
37810
  const existingIdx = index.tools.findIndex((e) => e.name === definition.name);
37205
37811
  if (existingIdx >= 0) {
@@ -37207,12 +37813,12 @@ var FileCustomToolStorage = class {
37207
37813
  } else {
37208
37814
  index.tools.push(entry);
37209
37815
  }
37210
- await this.saveIndex();
37816
+ await this.saveIndex(userId, index);
37211
37817
  }
37212
- async removeFromIndex(name) {
37213
- const index = await this.loadIndex();
37818
+ async removeFromIndex(userId, name) {
37819
+ const index = await this.loadIndex(userId);
37214
37820
  index.tools = index.tools.filter((e) => e.name !== name);
37215
- await this.saveIndex();
37821
+ await this.saveIndex(userId, index);
37216
37822
  }
37217
37823
  definitionToIndexEntry(definition) {
37218
37824
  return {
@@ -38042,7 +38648,7 @@ var ConnectorTools = class {
38042
38648
  const factory = this.factories.get(serviceType);
38043
38649
  const serviceTools = factory(connector, userId);
38044
38650
  for (const tool of serviceTools) {
38045
- tool.definition.function.name = `${connector.name}_${tool.definition.function.name}`;
38651
+ tool.definition.function.name = `${sanitizeToolName(connector.name)}_${tool.definition.function.name}`;
38046
38652
  }
38047
38653
  tools.push(...serviceTools);
38048
38654
  }
@@ -38196,7 +38802,7 @@ var ConnectorTools = class {
38196
38802
  return connectorOrName;
38197
38803
  }
38198
38804
  static createGenericAPITool(connector, options) {
38199
- const toolName = options?.toolName ?? `${connector.name}_api`;
38805
+ const toolName = options?.toolName ?? `${sanitizeToolName(connector.name)}_api`;
38200
38806
  const userId = options?.userId;
38201
38807
  const description = options?.description ?? `Make an authenticated API call to ${connector.displayName}.` + (connector.baseURL ? ` Base URL: ${connector.baseURL}.` : " Provide full URL in endpoint.") + ' IMPORTANT: For POST/PUT/PATCH requests, pass data in the "body" parameter as a JSON object, NOT as query string parameters in the endpoint URL. The body is sent as application/json.';
38202
38808
  return {
@@ -38329,8 +38935,8 @@ var FileStorage = class {
38329
38935
  }
38330
38936
  async ensureDirectory() {
38331
38937
  try {
38332
- await fs16__namespace.mkdir(this.directory, { recursive: true });
38333
- await fs16__namespace.chmod(this.directory, 448);
38938
+ await fs17__namespace.mkdir(this.directory, { recursive: true });
38939
+ await fs17__namespace.chmod(this.directory, 448);
38334
38940
  } catch (error) {
38335
38941
  }
38336
38942
  }
@@ -38346,13 +38952,13 @@ var FileStorage = class {
38346
38952
  const filePath = this.getFilePath(key);
38347
38953
  const plaintext = JSON.stringify(token);
38348
38954
  const encrypted = encrypt(plaintext, this.encryptionKey);
38349
- await fs16__namespace.writeFile(filePath, encrypted, "utf8");
38350
- await fs16__namespace.chmod(filePath, 384);
38955
+ await fs17__namespace.writeFile(filePath, encrypted, "utf8");
38956
+ await fs17__namespace.chmod(filePath, 384);
38351
38957
  }
38352
38958
  async getToken(key) {
38353
38959
  const filePath = this.getFilePath(key);
38354
38960
  try {
38355
- const encrypted = await fs16__namespace.readFile(filePath, "utf8");
38961
+ const encrypted = await fs17__namespace.readFile(filePath, "utf8");
38356
38962
  const decrypted = decrypt(encrypted, this.encryptionKey);
38357
38963
  return JSON.parse(decrypted);
38358
38964
  } catch (error) {
@@ -38361,7 +38967,7 @@ var FileStorage = class {
38361
38967
  }
38362
38968
  console.error("Failed to read/decrypt token file:", error);
38363
38969
  try {
38364
- await fs16__namespace.unlink(filePath);
38970
+ await fs17__namespace.unlink(filePath);
38365
38971
  } catch {
38366
38972
  }
38367
38973
  return null;
@@ -38370,7 +38976,7 @@ var FileStorage = class {
38370
38976
  async deleteToken(key) {
38371
38977
  const filePath = this.getFilePath(key);
38372
38978
  try {
38373
- await fs16__namespace.unlink(filePath);
38979
+ await fs17__namespace.unlink(filePath);
38374
38980
  } catch (error) {
38375
38981
  if (error.code !== "ENOENT") {
38376
38982
  throw error;
@@ -38380,7 +38986,7 @@ var FileStorage = class {
38380
38986
  async hasToken(key) {
38381
38987
  const filePath = this.getFilePath(key);
38382
38988
  try {
38383
- await fs16__namespace.access(filePath);
38989
+ await fs17__namespace.access(filePath);
38384
38990
  return true;
38385
38991
  } catch {
38386
38992
  return false;
@@ -38391,7 +38997,7 @@ var FileStorage = class {
38391
38997
  */
38392
38998
  async listTokens() {
38393
38999
  try {
38394
- const files = await fs16__namespace.readdir(this.directory);
39000
+ const files = await fs17__namespace.readdir(this.directory);
38395
39001
  return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
38396
39002
  } catch {
38397
39003
  return [];
@@ -38402,10 +39008,10 @@ var FileStorage = class {
38402
39008
  */
38403
39009
  async clearAll() {
38404
39010
  try {
38405
- const files = await fs16__namespace.readdir(this.directory);
39011
+ const files = await fs17__namespace.readdir(this.directory);
38406
39012
  const tokenFiles = files.filter((f) => f.endsWith(".token"));
38407
39013
  await Promise.all(
38408
- tokenFiles.map((f) => fs16__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
39014
+ tokenFiles.map((f) => fs17__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
38409
39015
  }))
38410
39016
  );
38411
39017
  } catch {
@@ -38853,14 +39459,14 @@ var FileConnectorStorage = class {
38853
39459
  await this.ensureDirectory();
38854
39460
  const filePath = this.getFilePath(name);
38855
39461
  const json = JSON.stringify(stored, null, 2);
38856
- await fs16__namespace.writeFile(filePath, json, "utf8");
38857
- await fs16__namespace.chmod(filePath, 384);
39462
+ await fs17__namespace.writeFile(filePath, json, "utf8");
39463
+ await fs17__namespace.chmod(filePath, 384);
38858
39464
  await this.updateIndex(name, "add");
38859
39465
  }
38860
39466
  async get(name) {
38861
39467
  const filePath = this.getFilePath(name);
38862
39468
  try {
38863
- const json = await fs16__namespace.readFile(filePath, "utf8");
39469
+ const json = await fs17__namespace.readFile(filePath, "utf8");
38864
39470
  return JSON.parse(json);
38865
39471
  } catch (error) {
38866
39472
  const err = error;
@@ -38873,7 +39479,7 @@ var FileConnectorStorage = class {
38873
39479
  async delete(name) {
38874
39480
  const filePath = this.getFilePath(name);
38875
39481
  try {
38876
- await fs16__namespace.unlink(filePath);
39482
+ await fs17__namespace.unlink(filePath);
38877
39483
  await this.updateIndex(name, "remove");
38878
39484
  return true;
38879
39485
  } catch (error) {
@@ -38887,7 +39493,7 @@ var FileConnectorStorage = class {
38887
39493
  async has(name) {
38888
39494
  const filePath = this.getFilePath(name);
38889
39495
  try {
38890
- await fs16__namespace.access(filePath);
39496
+ await fs17__namespace.access(filePath);
38891
39497
  return true;
38892
39498
  } catch {
38893
39499
  return false;
@@ -38913,13 +39519,13 @@ var FileConnectorStorage = class {
38913
39519
  */
38914
39520
  async clear() {
38915
39521
  try {
38916
- const files = await fs16__namespace.readdir(this.directory);
39522
+ const files = await fs17__namespace.readdir(this.directory);
38917
39523
  const connectorFiles = files.filter(
38918
39524
  (f) => f.endsWith(".connector.json") || f === "_index.json"
38919
39525
  );
38920
39526
  await Promise.all(
38921
39527
  connectorFiles.map(
38922
- (f) => fs16__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
39528
+ (f) => fs17__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
38923
39529
  })
38924
39530
  )
38925
39531
  );
@@ -38946,8 +39552,8 @@ var FileConnectorStorage = class {
38946
39552
  async ensureDirectory() {
38947
39553
  if (this.initialized) return;
38948
39554
  try {
38949
- await fs16__namespace.mkdir(this.directory, { recursive: true });
38950
- await fs16__namespace.chmod(this.directory, 448);
39555
+ await fs17__namespace.mkdir(this.directory, { recursive: true });
39556
+ await fs17__namespace.chmod(this.directory, 448);
38951
39557
  this.initialized = true;
38952
39558
  } catch {
38953
39559
  this.initialized = true;
@@ -38958,7 +39564,7 @@ var FileConnectorStorage = class {
38958
39564
  */
38959
39565
  async loadIndex() {
38960
39566
  try {
38961
- const json = await fs16__namespace.readFile(this.indexPath, "utf8");
39567
+ const json = await fs17__namespace.readFile(this.indexPath, "utf8");
38962
39568
  return JSON.parse(json);
38963
39569
  } catch {
38964
39570
  return { connectors: {} };
@@ -38976,8 +39582,8 @@ var FileConnectorStorage = class {
38976
39582
  delete index.connectors[hash];
38977
39583
  }
38978
39584
  const json = JSON.stringify(index, null, 2);
38979
- await fs16__namespace.writeFile(this.indexPath, json, "utf8");
38980
- await fs16__namespace.chmod(this.indexPath, 384);
39585
+ await fs17__namespace.writeFile(this.indexPath, json, "utf8");
39586
+ await fs17__namespace.chmod(this.indexPath, 384);
38981
39587
  }
38982
39588
  };
38983
39589
 
@@ -41432,8 +42038,8 @@ function createMessageWithImages(text, imageUrls, role = "user" /* USER */) {
41432
42038
  var execAsync = util.promisify(child_process.exec);
41433
42039
  function cleanupTempFile(filePath) {
41434
42040
  try {
41435
- if (fs17__namespace.existsSync(filePath)) {
41436
- fs17__namespace.unlinkSync(filePath);
42041
+ if (fs18__namespace.existsSync(filePath)) {
42042
+ fs18__namespace.unlinkSync(filePath);
41437
42043
  }
41438
42044
  } catch {
41439
42045
  }
@@ -41484,7 +42090,7 @@ async function readClipboardImageMac() {
41484
42090
  end try
41485
42091
  `;
41486
42092
  const { stdout } = await execAsync(`osascript -e '${script}'`);
41487
- if (stdout.includes("success") || fs17__namespace.existsSync(tempFile)) {
42093
+ if (stdout.includes("success") || fs18__namespace.existsSync(tempFile)) {
41488
42094
  return await convertFileToDataUri(tempFile);
41489
42095
  }
41490
42096
  return {
@@ -41501,14 +42107,14 @@ async function readClipboardImageLinux() {
41501
42107
  try {
41502
42108
  try {
41503
42109
  await execAsync(`xclip -selection clipboard -t image/png -o > "${tempFile}"`);
41504
- if (fs17__namespace.existsSync(tempFile) && fs17__namespace.statSync(tempFile).size > 0) {
42110
+ if (fs18__namespace.existsSync(tempFile) && fs18__namespace.statSync(tempFile).size > 0) {
41505
42111
  return await convertFileToDataUri(tempFile);
41506
42112
  }
41507
42113
  } catch {
41508
42114
  }
41509
42115
  try {
41510
42116
  await execAsync(`wl-paste -t image/png > "${tempFile}"`);
41511
- if (fs17__namespace.existsSync(tempFile) && fs17__namespace.statSync(tempFile).size > 0) {
42117
+ if (fs18__namespace.existsSync(tempFile) && fs18__namespace.statSync(tempFile).size > 0) {
41512
42118
  return await convertFileToDataUri(tempFile);
41513
42119
  }
41514
42120
  } catch {
@@ -41535,7 +42141,7 @@ async function readClipboardImageWindows() {
41535
42141
  }
41536
42142
  `;
41537
42143
  await execAsync(`powershell -Command "${psScript}"`);
41538
- if (fs17__namespace.existsSync(tempFile) && fs17__namespace.statSync(tempFile).size > 0) {
42144
+ if (fs18__namespace.existsSync(tempFile) && fs18__namespace.statSync(tempFile).size > 0) {
41539
42145
  return await convertFileToDataUri(tempFile);
41540
42146
  }
41541
42147
  return {
@@ -41548,7 +42154,7 @@ async function readClipboardImageWindows() {
41548
42154
  }
41549
42155
  async function convertFileToDataUri(filePath) {
41550
42156
  try {
41551
- const imageBuffer = fs17__namespace.readFileSync(filePath);
42157
+ const imageBuffer = fs18__namespace.readFileSync(filePath);
41552
42158
  const base64Image = imageBuffer.toString("base64");
41553
42159
  const magic = imageBuffer.slice(0, 4).toString("hex");
41554
42160
  let mimeType = "image/png";
@@ -42097,7 +42703,7 @@ EXAMPLES:
42097
42703
  };
42098
42704
  }
42099
42705
  const resolvedPath = validation.resolvedPath;
42100
- if (!fs17.existsSync(resolvedPath)) {
42706
+ if (!fs18.existsSync(resolvedPath)) {
42101
42707
  return {
42102
42708
  success: false,
42103
42709
  error: `File not found: ${file_path}`,
@@ -42105,7 +42711,7 @@ EXAMPLES:
42105
42711
  };
42106
42712
  }
42107
42713
  try {
42108
- const stats = await fs16.stat(resolvedPath);
42714
+ const stats = await fs17.stat(resolvedPath);
42109
42715
  if (!stats.isFile()) {
42110
42716
  return {
42111
42717
  success: false,
@@ -42147,7 +42753,7 @@ EXAMPLES:
42147
42753
  } catch {
42148
42754
  }
42149
42755
  }
42150
- const content = await fs16.readFile(resolvedPath, "utf-8");
42756
+ const content = await fs17.readFile(resolvedPath, "utf-8");
42151
42757
  const allLines = content.split("\n");
42152
42758
  const totalLines = allLines.length;
42153
42759
  const startIndex = Math.max(0, offset - 1);
@@ -42252,13 +42858,13 @@ EXAMPLES:
42252
42858
  };
42253
42859
  }
42254
42860
  const resolvedPath = validation.resolvedPath;
42255
- const fileExists = fs17.existsSync(resolvedPath);
42861
+ const fileExists = fs18.existsSync(resolvedPath);
42256
42862
  try {
42257
42863
  const parentDir = path2.dirname(resolvedPath);
42258
- if (!fs17.existsSync(parentDir)) {
42259
- await fs16.mkdir(parentDir, { recursive: true });
42864
+ if (!fs18.existsSync(parentDir)) {
42865
+ await fs17.mkdir(parentDir, { recursive: true });
42260
42866
  }
42261
- await fs16.writeFile(resolvedPath, content, "utf-8");
42867
+ await fs17.writeFile(resolvedPath, content, "utf-8");
42262
42868
  return {
42263
42869
  success: true,
42264
42870
  path: file_path,
@@ -42361,7 +42967,7 @@ EXAMPLES:
42361
42967
  };
42362
42968
  }
42363
42969
  const resolvedPath = validation.resolvedPath;
42364
- if (!fs17.existsSync(resolvedPath)) {
42970
+ if (!fs18.existsSync(resolvedPath)) {
42365
42971
  return {
42366
42972
  success: false,
42367
42973
  error: `File not found: ${file_path}`,
@@ -42369,7 +42975,7 @@ EXAMPLES:
42369
42975
  };
42370
42976
  }
42371
42977
  try {
42372
- const content = await fs16.readFile(resolvedPath, "utf-8");
42978
+ const content = await fs17.readFile(resolvedPath, "utf-8");
42373
42979
  let occurrences = 0;
42374
42980
  let searchIndex = 0;
42375
42981
  while (true) {
@@ -42408,7 +43014,7 @@ EXAMPLES:
42408
43014
  } else {
42409
43015
  newContent = content.replace(old_string, new_string);
42410
43016
  }
42411
- await fs16.writeFile(resolvedPath, newContent, "utf-8");
43017
+ await fs17.writeFile(resolvedPath, newContent, "utf-8");
42412
43018
  const diffPreview = generateDiffPreview(old_string, new_string);
42413
43019
  return {
42414
43020
  success: true,
@@ -42464,7 +43070,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
42464
43070
  return results;
42465
43071
  }
42466
43072
  try {
42467
- const entries = await fs16.readdir(dir, { withFileTypes: true });
43073
+ const entries = await fs17.readdir(dir, { withFileTypes: true });
42468
43074
  for (const entry of entries) {
42469
43075
  if (results.length >= config.maxResults) break;
42470
43076
  const fullPath = path2.join(dir, entry.name);
@@ -42478,7 +43084,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
42478
43084
  } else if (entry.isFile()) {
42479
43085
  if (matchGlobPattern(pattern, relativePath)) {
42480
43086
  try {
42481
- const stats = await fs16.stat(fullPath);
43087
+ const stats = await fs17.stat(fullPath);
42482
43088
  results.push({
42483
43089
  path: relativePath,
42484
43090
  mtime: stats.mtimeMs
@@ -42560,7 +43166,7 @@ WHEN TO USE:
42560
43166
  };
42561
43167
  }
42562
43168
  const resolvedDir = validation.resolvedPath;
42563
- if (!fs17.existsSync(resolvedDir)) {
43169
+ if (!fs18.existsSync(resolvedDir)) {
42564
43170
  return {
42565
43171
  success: false,
42566
43172
  error: `Directory not found: ${searchDir}`
@@ -42615,7 +43221,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
42615
43221
  return files;
42616
43222
  }
42617
43223
  try {
42618
- const entries = await fs16.readdir(dir, { withFileTypes: true });
43224
+ const entries = await fs17.readdir(dir, { withFileTypes: true });
42619
43225
  for (const entry of entries) {
42620
43226
  const fullPath = path2.join(dir, entry.name);
42621
43227
  if (entry.isDirectory()) {
@@ -42648,7 +43254,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
42648
43254
  async function searchFile(filePath, regex, contextBefore, contextAfter) {
42649
43255
  const matches = [];
42650
43256
  try {
42651
- const content = await fs16.readFile(filePath, "utf-8");
43257
+ const content = await fs17.readFile(filePath, "utf-8");
42652
43258
  const lines = content.split("\n");
42653
43259
  for (let i = 0; i < lines.length; i++) {
42654
43260
  const line = lines[i] ?? "";
@@ -42789,7 +43395,7 @@ WHEN TO USE:
42789
43395
  };
42790
43396
  }
42791
43397
  const resolvedPath = validation.resolvedPath;
42792
- if (!fs17.existsSync(resolvedPath)) {
43398
+ if (!fs18.existsSync(resolvedPath)) {
42793
43399
  return {
42794
43400
  success: false,
42795
43401
  error: `Path not found: ${searchPath}`
@@ -42805,7 +43411,7 @@ WHEN TO USE:
42805
43411
  };
42806
43412
  }
42807
43413
  try {
42808
- const stats = await fs16.stat(resolvedPath);
43414
+ const stats = await fs17.stat(resolvedPath);
42809
43415
  let filesToSearch;
42810
43416
  if (stats.isFile()) {
42811
43417
  filesToSearch = [resolvedPath];
@@ -42893,7 +43499,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
42893
43499
  return entries;
42894
43500
  }
42895
43501
  try {
42896
- const dirEntries = await fs16.readdir(dir, { withFileTypes: true });
43502
+ const dirEntries = await fs17.readdir(dir, { withFileTypes: true });
42897
43503
  for (const entry of dirEntries) {
42898
43504
  if (entries.length >= config.maxResults) break;
42899
43505
  const fullPath = path2.join(dir, entry.name);
@@ -42911,7 +43517,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
42911
43517
  }
42912
43518
  if (filter === "directories" && !isDir) continue;
42913
43519
  try {
42914
- const stats = await fs16.stat(fullPath);
43520
+ const stats = await fs17.stat(fullPath);
42915
43521
  const dirEntry = {
42916
43522
  name: entry.name,
42917
43523
  path: relativePath,
@@ -43007,14 +43613,14 @@ EXAMPLES:
43007
43613
  };
43008
43614
  }
43009
43615
  const resolvedPath = validation.resolvedPath;
43010
- if (!fs17.existsSync(resolvedPath)) {
43616
+ if (!fs18.existsSync(resolvedPath)) {
43011
43617
  return {
43012
43618
  success: false,
43013
43619
  error: `Directory not found: ${path6}`
43014
43620
  };
43015
43621
  }
43016
43622
  try {
43017
- const stats = await fs16.stat(resolvedPath);
43623
+ const stats = await fs17.stat(resolvedPath);
43018
43624
  if (!stats.isDirectory()) {
43019
43625
  return {
43020
43626
  success: false,
@@ -46783,7 +47389,7 @@ var desktopTools = [
46783
47389
 
46784
47390
  // src/tools/custom-tools/resolveStorage.ts
46785
47391
  init_StorageRegistry();
46786
- function buildStorageContext(toolContext) {
47392
+ function buildStorageContext2(toolContext) {
46787
47393
  const global2 = exports.StorageRegistry.getContext();
46788
47394
  if (global2) return global2;
46789
47395
  if (toolContext?.userId) return { userId: toolContext.userId };
@@ -46793,7 +47399,7 @@ function resolveCustomToolStorage(explicit, toolContext) {
46793
47399
  if (explicit) return explicit;
46794
47400
  const factory = exports.StorageRegistry.get("customTools");
46795
47401
  if (factory) {
46796
- return factory(buildStorageContext(toolContext));
47402
+ return factory(buildStorageContext2(toolContext));
46797
47403
  }
46798
47404
  return new FileCustomToolStorage();
46799
47405
  }
@@ -46821,12 +47427,13 @@ function createCustomToolDelete(storage) {
46821
47427
  permission: { scope: "session", riskLevel: "medium" },
46822
47428
  execute: async (args, context) => {
46823
47429
  try {
47430
+ const userId = context?.userId;
46824
47431
  const s = resolveCustomToolStorage(storage, context);
46825
- const exists = await s.exists(args.name);
47432
+ const exists = await s.exists(userId, args.name);
46826
47433
  if (!exists) {
46827
47434
  return { success: false, name: args.name, error: `Custom tool '${args.name}' not found` };
46828
47435
  }
46829
- await s.delete(args.name);
47436
+ await s.delete(userId, args.name);
46830
47437
  return { success: true, name: args.name };
46831
47438
  } catch (error) {
46832
47439
  return { success: false, name: args.name, error: error.message };
@@ -47067,8 +47674,9 @@ function createCustomToolList(storage) {
47067
47674
  },
47068
47675
  permission: { scope: "always", riskLevel: "low" },
47069
47676
  execute: async (args, context) => {
47677
+ const userId = context?.userId;
47070
47678
  const s = resolveCustomToolStorage(storage, context);
47071
- const tools = await s.list({
47679
+ const tools = await s.list(userId, {
47072
47680
  search: args.search,
47073
47681
  tags: args.tags,
47074
47682
  category: args.category,
@@ -47104,8 +47712,9 @@ function createCustomToolLoad(storage) {
47104
47712
  },
47105
47713
  permission: { scope: "always", riskLevel: "low" },
47106
47714
  execute: async (args, context) => {
47715
+ const userId = context?.userId;
47107
47716
  const s = resolveCustomToolStorage(storage, context);
47108
- const tool = await s.load(args.name);
47717
+ const tool = await s.load(userId, args.name);
47109
47718
  if (!tool) {
47110
47719
  return { success: false, error: `Custom tool '${args.name}' not found` };
47111
47720
  }
@@ -47177,9 +47786,10 @@ function createCustomToolSave(storage) {
47177
47786
  permission: { scope: "session", riskLevel: "medium" },
47178
47787
  execute: async (args, context) => {
47179
47788
  try {
47789
+ const userId = context?.userId;
47180
47790
  const s = resolveCustomToolStorage(storage, context);
47181
47791
  const now = (/* @__PURE__ */ new Date()).toISOString();
47182
- const existing = await s.load(args.name);
47792
+ const existing = await s.load(userId, args.name);
47183
47793
  const definition = {
47184
47794
  version: CUSTOM_TOOL_DEFINITION_VERSION,
47185
47795
  name: args.name,
@@ -47198,17 +47808,17 @@ function createCustomToolSave(storage) {
47198
47808
  requiresConnector: (args.connectorNames?.length ?? 0) > 0
47199
47809
  }
47200
47810
  };
47201
- await s.save(definition);
47811
+ await s.save(userId, definition);
47202
47812
  return {
47203
47813
  success: true,
47204
47814
  name: args.name,
47205
- storagePath: s.getPath()
47815
+ storagePath: s.getPath(userId)
47206
47816
  };
47207
47817
  } catch (error) {
47208
47818
  return {
47209
47819
  success: false,
47210
47820
  name: args.name,
47211
- storagePath: resolveCustomToolStorage(storage, context).getPath(),
47821
+ storagePath: resolveCustomToolStorage(storage, context).getPath(context?.userId),
47212
47822
  error: error.message
47213
47823
  };
47214
47824
  }
@@ -47996,6 +48606,7 @@ exports.FileMediaOutputHandler = FileMediaStorage;
47996
48606
  exports.FileMediaStorage = FileMediaStorage;
47997
48607
  exports.FilePersistentInstructionsStorage = FilePersistentInstructionsStorage;
47998
48608
  exports.FileStorage = FileStorage;
48609
+ exports.FileUserInfoStorage = FileUserInfoStorage;
47999
48610
  exports.FormatDetector = FormatDetector;
48000
48611
  exports.HookManager = HookManager;
48001
48612
  exports.IMAGE_MODELS = IMAGE_MODELS;
@@ -48071,6 +48682,7 @@ exports.ToolPermissionManager = ToolPermissionManager;
48071
48682
  exports.ToolRegistry = ToolRegistry;
48072
48683
  exports.ToolTimeoutError = ToolTimeoutError;
48073
48684
  exports.TruncateCompactor = TruncateCompactor;
48685
+ exports.UserInfoPluginNextGen = UserInfoPluginNextGen;
48074
48686
  exports.VENDORS = VENDORS;
48075
48687
  exports.VENDOR_ICON_MAP = VENDOR_ICON_MAP;
48076
48688
  exports.VIDEO_MODELS = VIDEO_MODELS;
@@ -48279,6 +48891,7 @@ exports.resolveMaxContextTokens = resolveMaxContextTokens;
48279
48891
  exports.resolveModelCapabilities = resolveModelCapabilities;
48280
48892
  exports.resolveRepository = resolveRepository;
48281
48893
  exports.retryWithBackoff = retryWithBackoff;
48894
+ exports.sanitizeToolName = sanitizeToolName;
48282
48895
  exports.scopeEquals = scopeEquals;
48283
48896
  exports.scopeMatches = scopeMatches;
48284
48897
  exports.setMediaOutputHandler = setMediaOutputHandler;