@everworker/oneringai 0.2.2 → 0.2.3

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 fs16 = require('fs');
5
+ var fs17 = 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 fs15 = require('fs/promises');
20
+ var fs16 = 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 fs16__namespace = /*#__PURE__*/_interopNamespace(fs16);
48
+ var fs17__namespace = /*#__PURE__*/_interopNamespace(fs17);
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 fs15__namespace = /*#__PURE__*/_interopNamespace(fs15);
58
+ var fs16__namespace = /*#__PURE__*/_interopNamespace(fs16);
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 = fs16__namespace.readFileSync(config.privateKeyPath, "utf8");
676
+ this.privateKey = fs17__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
  }
@@ -1324,10 +1324,10 @@ var init_Logger = __esm({
1324
1324
  initFileStream(filePath) {
1325
1325
  try {
1326
1326
  const dir = path2__namespace.dirname(filePath);
1327
- if (!fs16__namespace.existsSync(dir)) {
1328
- fs16__namespace.mkdirSync(dir, { recursive: true });
1327
+ if (!fs17__namespace.existsSync(dir)) {
1328
+ fs17__namespace.mkdirSync(dir, { recursive: true });
1329
1329
  }
1330
- this.fileStream = fs16__namespace.createWriteStream(filePath, {
1330
+ this.fileStream = fs17__namespace.createWriteStream(filePath, {
1331
1331
  flags: "a",
1332
1332
  // append mode
1333
1333
  encoding: "utf8"
@@ -14664,12 +14664,12 @@ var require_dist = __commonJS({
14664
14664
  throw new Error(`Unknown format "${name}"`);
14665
14665
  return f;
14666
14666
  };
14667
- function addFormats(ajv, list, fs17, exportName) {
14667
+ function addFormats(ajv, list, fs18, exportName) {
14668
14668
  var _a;
14669
14669
  var _b;
14670
14670
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
14671
14671
  for (const f of list)
14672
- ajv.addFormat(f, fs17[f]);
14672
+ ajv.addFormat(f, fs18[f]);
14673
14673
  }
14674
14674
  module.exports = exports$1 = formatsPlugin;
14675
14675
  Object.defineProperty(exports$1, "__esModule", { value: true });
@@ -16723,6 +16723,9 @@ var ToolManager = class extends eventemitter3.EventEmitter {
16723
16723
  if (options.priority !== void 0) existing.priority = options.priority;
16724
16724
  if (options.conditions !== void 0) existing.conditions = options.conditions;
16725
16725
  if (options.permission !== void 0) existing.permission = options.permission;
16726
+ if (options.tags !== void 0) existing.tags = options.tags;
16727
+ if (options.category !== void 0) existing.category = options.category;
16728
+ if (options.source !== void 0) existing.source = options.source;
16726
16729
  return;
16727
16730
  }
16728
16731
  const namespace = options.namespace ?? "default";
@@ -16741,7 +16744,10 @@ var ToolManager = class extends eventemitter3.EventEmitter {
16741
16744
  successCount: 0,
16742
16745
  failureCount: 0
16743
16746
  },
16744
- permission: effectivePermission
16747
+ permission: effectivePermission,
16748
+ tags: options.tags,
16749
+ category: options.category,
16750
+ source: options.source
16745
16751
  };
16746
16752
  this.registry.set(name, registration);
16747
16753
  this.addToNamespace(name, namespace);
@@ -17324,6 +17330,9 @@ var ToolManager = class extends eventemitter3.EventEmitter {
17324
17330
  const namespaces = {};
17325
17331
  const priorities = {};
17326
17332
  const permissions = {};
17333
+ const tags = {};
17334
+ const categories = {};
17335
+ const sources = {};
17327
17336
  for (const [name, reg] of this.registry) {
17328
17337
  enabled[name] = reg.enabled;
17329
17338
  namespaces[name] = reg.namespace;
@@ -17331,8 +17340,17 @@ var ToolManager = class extends eventemitter3.EventEmitter {
17331
17340
  if (reg.permission) {
17332
17341
  permissions[name] = reg.permission;
17333
17342
  }
17343
+ if (reg.tags) {
17344
+ tags[name] = reg.tags;
17345
+ }
17346
+ if (reg.category) {
17347
+ categories[name] = reg.category;
17348
+ }
17349
+ if (reg.source) {
17350
+ sources[name] = reg.source;
17351
+ }
17334
17352
  }
17335
- return { enabled, namespaces, priorities, permissions };
17353
+ return { enabled, namespaces, priorities, permissions, tags, categories, sources };
17336
17354
  }
17337
17355
  /**
17338
17356
  * Load state (restores enabled/disabled, namespaces, priorities, permissions)
@@ -17356,6 +17374,24 @@ var ToolManager = class extends eventemitter3.EventEmitter {
17356
17374
  this.setPermission(name, permission);
17357
17375
  }
17358
17376
  }
17377
+ if (state.tags) {
17378
+ for (const [name, toolTags] of Object.entries(state.tags)) {
17379
+ const reg = this.registry.get(name);
17380
+ if (reg) reg.tags = toolTags;
17381
+ }
17382
+ }
17383
+ if (state.categories) {
17384
+ for (const [name, category] of Object.entries(state.categories)) {
17385
+ const reg = this.registry.get(name);
17386
+ if (reg) reg.category = category;
17387
+ }
17388
+ }
17389
+ if (state.sources) {
17390
+ for (const [name, source] of Object.entries(state.sources)) {
17391
+ const reg = this.registry.get(name);
17392
+ if (reg) reg.source = source;
17393
+ }
17394
+ }
17359
17395
  }
17360
17396
  // ==========================================================================
17361
17397
  // Private Helpers
@@ -20357,7 +20393,7 @@ var FilePersistentInstructionsStorage = class {
20357
20393
  */
20358
20394
  async load() {
20359
20395
  try {
20360
- const raw = await fs16.promises.readFile(this.filePath, "utf-8");
20396
+ const raw = await fs17.promises.readFile(this.filePath, "utf-8");
20361
20397
  const data = JSON.parse(raw);
20362
20398
  if (data.version === 2 && Array.isArray(data.entries)) {
20363
20399
  return data.entries.length > 0 ? data.entries : null;
@@ -20369,7 +20405,7 @@ var FilePersistentInstructionsStorage = class {
20369
20405
  }
20370
20406
  }
20371
20407
  try {
20372
- const content = await fs16.promises.readFile(this.legacyFilePath, "utf-8");
20408
+ const content = await fs17.promises.readFile(this.legacyFilePath, "utf-8");
20373
20409
  const trimmed = content.trim();
20374
20410
  if (!trimmed) return null;
20375
20411
  const now = Date.now();
@@ -20399,11 +20435,11 @@ var FilePersistentInstructionsStorage = class {
20399
20435
  };
20400
20436
  const tempPath = `${this.filePath}.tmp`;
20401
20437
  try {
20402
- await fs16.promises.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
20403
- await fs16.promises.rename(tempPath, this.filePath);
20438
+ await fs17.promises.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
20439
+ await fs17.promises.rename(tempPath, this.filePath);
20404
20440
  } catch (error) {
20405
20441
  try {
20406
- await fs16.promises.unlink(tempPath);
20442
+ await fs17.promises.unlink(tempPath);
20407
20443
  } catch {
20408
20444
  }
20409
20445
  throw error;
@@ -20415,7 +20451,7 @@ var FilePersistentInstructionsStorage = class {
20415
20451
  */
20416
20452
  async delete() {
20417
20453
  try {
20418
- await fs16.promises.unlink(this.filePath);
20454
+ await fs17.promises.unlink(this.filePath);
20419
20455
  } catch (error) {
20420
20456
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
20421
20457
  throw error;
@@ -20428,11 +20464,11 @@ var FilePersistentInstructionsStorage = class {
20428
20464
  */
20429
20465
  async exists() {
20430
20466
  try {
20431
- await fs16.promises.access(this.filePath);
20467
+ await fs17.promises.access(this.filePath);
20432
20468
  return true;
20433
20469
  } catch {
20434
20470
  try {
20435
- await fs16.promises.access(this.legacyFilePath);
20471
+ await fs17.promises.access(this.legacyFilePath);
20436
20472
  return true;
20437
20473
  } catch {
20438
20474
  return false;
@@ -20456,7 +20492,7 @@ var FilePersistentInstructionsStorage = class {
20456
20492
  */
20457
20493
  async ensureDirectory() {
20458
20494
  try {
20459
- await fs16.promises.mkdir(this.directory, { recursive: true });
20495
+ await fs17.promises.mkdir(this.directory, { recursive: true });
20460
20496
  } catch (error) {
20461
20497
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
20462
20498
  throw error;
@@ -20468,7 +20504,7 @@ var FilePersistentInstructionsStorage = class {
20468
20504
  */
20469
20505
  async removeLegacyFile() {
20470
20506
  try {
20471
- await fs16.promises.unlink(this.legacyFilePath);
20507
+ await fs17.promises.unlink(this.legacyFilePath);
20472
20508
  } catch (error) {
20473
20509
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
20474
20510
  console.warn(`Failed to remove legacy instructions file: ${this.legacyFilePath}`);
@@ -28328,7 +28364,7 @@ init_constants();
28328
28364
  throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
28329
28365
  }
28330
28366
  try {
28331
- const content = await fs16.promises.readFile(configPath, "utf-8");
28367
+ const content = await fs17.promises.readFile(configPath, "utf-8");
28332
28368
  let config = JSON.parse(content);
28333
28369
  config = this.interpolateEnvVars(config);
28334
28370
  this.validate(config);
@@ -28349,8 +28385,8 @@ init_constants();
28349
28385
  throw new Error("Configuration file not found. Searched: " + this.DEFAULT_PATHS.join(", "));
28350
28386
  }
28351
28387
  try {
28352
- const fs17 = __require("fs");
28353
- const content = fs17.readFileSync(configPath, "utf-8");
28388
+ const fs18 = __require("fs");
28389
+ const content = fs18.readFileSync(configPath, "utf-8");
28354
28390
  let config = JSON.parse(content);
28355
28391
  config = this.interpolateEnvVars(config);
28356
28392
  this.validate(config);
@@ -28368,7 +28404,7 @@ init_constants();
28368
28404
  static async findConfig() {
28369
28405
  for (const path6 of this.DEFAULT_PATHS) {
28370
28406
  try {
28371
- await fs16.promises.access(path2.resolve(path6));
28407
+ await fs17.promises.access(path2.resolve(path6));
28372
28408
  return path2.resolve(path6);
28373
28409
  } catch {
28374
28410
  }
@@ -28379,10 +28415,10 @@ init_constants();
28379
28415
  * Find configuration file synchronously
28380
28416
  */
28381
28417
  static findConfigSync() {
28382
- const fs17 = __require("fs");
28418
+ const fs18 = __require("fs");
28383
28419
  for (const path6 of this.DEFAULT_PATHS) {
28384
28420
  try {
28385
- fs17.accessSync(path2.resolve(path6));
28421
+ fs18.accessSync(path2.resolve(path6));
28386
28422
  return path2.resolve(path6);
28387
28423
  } catch {
28388
28424
  }
@@ -33938,7 +33974,7 @@ var MCPRegistry = class {
33938
33974
  static async loadFromConfigFile(path6) {
33939
33975
  try {
33940
33976
  const configPath = path2.resolve(path6);
33941
- const content = await fs16.promises.readFile(configPath, "utf-8");
33977
+ const content = await fs17.promises.readFile(configPath, "utf-8");
33942
33978
  const config = JSON.parse(content);
33943
33979
  if (!config.mcp) {
33944
33980
  throw new MCPError("Configuration file does not contain MCP section");
@@ -34543,7 +34579,7 @@ var OpenAISTTProvider = class extends BaseMediaProvider {
34543
34579
  if (Buffer.isBuffer(audio)) {
34544
34580
  return new File([new Uint8Array(audio)], "audio.wav", { type: "audio/wav" });
34545
34581
  } else if (typeof audio === "string") {
34546
- return fs16__namespace.createReadStream(audio);
34582
+ return fs17__namespace.createReadStream(audio);
34547
34583
  } else {
34548
34584
  throw new Error("Invalid audio input: must be Buffer or file path");
34549
34585
  }
@@ -35096,7 +35132,7 @@ var TextToSpeech = class _TextToSpeech {
35096
35132
  */
35097
35133
  async toFile(text, filePath, options) {
35098
35134
  const response = await this.synthesize(text, options);
35099
- await fs15__namespace.writeFile(filePath, response.audio);
35135
+ await fs16__namespace.writeFile(filePath, response.audio);
35100
35136
  }
35101
35137
  // ======================== Introspection Methods ========================
35102
35138
  /**
@@ -35444,7 +35480,7 @@ var SpeechToText = class _SpeechToText {
35444
35480
  * @param options - Optional transcription parameters
35445
35481
  */
35446
35482
  async transcribeFile(filePath, options) {
35447
- const audio = await fs15__namespace.readFile(filePath);
35483
+ const audio = await fs16__namespace.readFile(filePath);
35448
35484
  return this.transcribe(audio, options);
35449
35485
  }
35450
35486
  /**
@@ -35770,7 +35806,7 @@ var OpenAIImageProvider = class extends BaseMediaProvider {
35770
35806
  if (Buffer.isBuffer(image)) {
35771
35807
  return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
35772
35808
  }
35773
- return fs16__namespace.createReadStream(image);
35809
+ return fs17__namespace.createReadStream(image);
35774
35810
  }
35775
35811
  /**
35776
35812
  * Handle OpenAI API errors
@@ -35917,8 +35953,8 @@ var GoogleImageProvider = class extends BaseMediaProvider {
35917
35953
  if (Buffer.isBuffer(image)) {
35918
35954
  imageBytes = image.toString("base64");
35919
35955
  } else {
35920
- const fs17 = await import('fs');
35921
- const buffer = fs17.readFileSync(image);
35956
+ const fs18 = await import('fs');
35957
+ const buffer = fs18.readFileSync(image);
35922
35958
  imageBytes = buffer.toString("base64");
35923
35959
  }
35924
35960
  return {
@@ -36079,7 +36115,7 @@ var GrokImageProvider = class extends BaseMediaProvider {
36079
36115
  if (Buffer.isBuffer(image)) {
36080
36116
  return new File([new Uint8Array(image)], "image.png", { type: "image/png" });
36081
36117
  }
36082
- return fs16__namespace.createReadStream(image);
36118
+ return fs17__namespace.createReadStream(image);
36083
36119
  }
36084
36120
  /**
36085
36121
  * Handle API errors
@@ -37529,8 +37565,8 @@ var OpenAISoraProvider = class extends BaseMediaProvider {
37529
37565
  return new File([new Uint8Array(image)], "input.png", { type: "image/png" });
37530
37566
  }
37531
37567
  if (!image.startsWith("http")) {
37532
- const fs17 = await import('fs');
37533
- const data = fs17.readFileSync(image);
37568
+ const fs18 = await import('fs');
37569
+ const data = fs18.readFileSync(image);
37534
37570
  return new File([new Uint8Array(data)], "input.png", { type: "image/png" });
37535
37571
  }
37536
37572
  const response = await fetch(image);
@@ -37708,7 +37744,7 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
37708
37744
  if (video.videoBytes) {
37709
37745
  buffer = Buffer.from(video.videoBytes, "base64");
37710
37746
  } else if (video.uri) {
37711
- const fs17 = await import('fs/promises');
37747
+ const fs18 = await import('fs/promises');
37712
37748
  const os3 = await import('os');
37713
37749
  const path6 = await import('path');
37714
37750
  const tempDir = os3.tmpdir();
@@ -37719,11 +37755,11 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
37719
37755
  // Pass as GeneratedVideo
37720
37756
  downloadPath: tempFile
37721
37757
  });
37722
- buffer = await fs17.readFile(tempFile);
37723
- await fs17.unlink(tempFile).catch(() => {
37758
+ buffer = await fs18.readFile(tempFile);
37759
+ await fs18.unlink(tempFile).catch(() => {
37724
37760
  });
37725
37761
  } catch (downloadError) {
37726
- await fs17.unlink(tempFile).catch(() => {
37762
+ await fs18.unlink(tempFile).catch(() => {
37727
37763
  });
37728
37764
  throw new ProviderError(
37729
37765
  "google",
@@ -37845,8 +37881,8 @@ var GoogleVeoProvider = class extends BaseMediaProvider {
37845
37881
  if (image.startsWith("http://") || image.startsWith("https://")) {
37846
37882
  return { imageUri: image };
37847
37883
  }
37848
- const fs17 = await import('fs/promises');
37849
- const data = await fs17.readFile(image);
37884
+ const fs18 = await import('fs/promises');
37885
+ const data = await fs18.readFile(image);
37850
37886
  return {
37851
37887
  imageBytes: data.toString("base64")
37852
37888
  };
@@ -38153,8 +38189,8 @@ var GrokImagineProvider = class extends BaseMediaProvider {
38153
38189
  if (image.startsWith("http") || image.startsWith("data:")) {
38154
38190
  return image;
38155
38191
  }
38156
- const fs17 = await import('fs');
38157
- const data = fs17.readFileSync(image);
38192
+ const fs18 = await import('fs');
38193
+ const data = fs18.readFileSync(image);
38158
38194
  const base64 = data.toString("base64");
38159
38195
  const ext = image.split(".").pop()?.toLowerCase() || "png";
38160
38196
  const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : `image/${ext}`;
@@ -39590,7 +39626,7 @@ var DocumentReader = class _DocumentReader {
39590
39626
  async resolveSource(source) {
39591
39627
  switch (source.type) {
39592
39628
  case "file": {
39593
- const buffer = await fs15.readFile(source.path);
39629
+ const buffer = await fs16.readFile(source.path);
39594
39630
  const filename = source.path.split("/").pop() || source.path;
39595
39631
  return { buffer, filename };
39596
39632
  }
@@ -41909,11 +41945,11 @@ var FileContextStorage = class {
41909
41945
  const data = this.prettyPrint ? JSON.stringify(storedSession, null, 2) : JSON.stringify(storedSession);
41910
41946
  const tempPath = `${filePath}.tmp`;
41911
41947
  try {
41912
- await fs16.promises.writeFile(tempPath, data, "utf-8");
41913
- await fs16.promises.rename(tempPath, filePath);
41948
+ await fs17.promises.writeFile(tempPath, data, "utf-8");
41949
+ await fs17.promises.rename(tempPath, filePath);
41914
41950
  } catch (error) {
41915
41951
  try {
41916
- await fs16.promises.unlink(tempPath);
41952
+ await fs17.promises.unlink(tempPath);
41917
41953
  } catch {
41918
41954
  }
41919
41955
  throw error;
@@ -41934,7 +41970,7 @@ var FileContextStorage = class {
41934
41970
  const sanitizedSessionId = sanitizeId(sessionId);
41935
41971
  const filePath = this.getFilePath(sanitizedSessionId);
41936
41972
  try {
41937
- await fs16.promises.unlink(filePath);
41973
+ await fs17.promises.unlink(filePath);
41938
41974
  } catch (error) {
41939
41975
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
41940
41976
  throw error;
@@ -41949,7 +41985,7 @@ var FileContextStorage = class {
41949
41985
  const sanitizedSessionId = sanitizeId(sessionId);
41950
41986
  const filePath = this.getFilePath(sanitizedSessionId);
41951
41987
  try {
41952
- await fs16.promises.access(filePath);
41988
+ await fs17.promises.access(filePath);
41953
41989
  return true;
41954
41990
  } catch {
41955
41991
  return false;
@@ -42014,7 +42050,7 @@ var FileContextStorage = class {
42014
42050
  const sanitizedSessionId = sanitizeId(sessionId);
42015
42051
  const filePath = this.getFilePath(sanitizedSessionId);
42016
42052
  const data = this.prettyPrint ? JSON.stringify(stored, null, 2) : JSON.stringify(stored);
42017
- await fs16.promises.writeFile(filePath, data, "utf-8");
42053
+ await fs17.promises.writeFile(filePath, data, "utf-8");
42018
42054
  await this.updateIndex(stored);
42019
42055
  }
42020
42056
  /**
@@ -42042,13 +42078,13 @@ var FileContextStorage = class {
42042
42078
  */
42043
42079
  async rebuildIndex() {
42044
42080
  await this.ensureDirectory();
42045
- const files = await fs16.promises.readdir(this.sessionsDirectory);
42081
+ const files = await fs17.promises.readdir(this.sessionsDirectory);
42046
42082
  const sessionFiles = files.filter((f) => f.endsWith(".json") && !f.startsWith("_"));
42047
42083
  const entries = [];
42048
42084
  for (const file of sessionFiles) {
42049
42085
  try {
42050
42086
  const filePath = path2.join(this.sessionsDirectory, file);
42051
- const data = await fs16.promises.readFile(filePath, "utf-8");
42087
+ const data = await fs17.promises.readFile(filePath, "utf-8");
42052
42088
  const stored = JSON.parse(data);
42053
42089
  entries.push(this.storedToIndexEntry(stored));
42054
42090
  } catch {
@@ -42070,7 +42106,7 @@ var FileContextStorage = class {
42070
42106
  }
42071
42107
  async ensureDirectory() {
42072
42108
  try {
42073
- await fs16.promises.mkdir(this.sessionsDirectory, { recursive: true });
42109
+ await fs17.promises.mkdir(this.sessionsDirectory, { recursive: true });
42074
42110
  } catch (error) {
42075
42111
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
42076
42112
  throw error;
@@ -42080,7 +42116,7 @@ var FileContextStorage = class {
42080
42116
  async loadRaw(sanitizedSessionId) {
42081
42117
  const filePath = this.getFilePath(sanitizedSessionId);
42082
42118
  try {
42083
- const data = await fs16.promises.readFile(filePath, "utf-8");
42119
+ const data = await fs17.promises.readFile(filePath, "utf-8");
42084
42120
  return JSON.parse(data);
42085
42121
  } catch (error) {
42086
42122
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -42098,7 +42134,7 @@ var FileContextStorage = class {
42098
42134
  return this.index;
42099
42135
  }
42100
42136
  try {
42101
- const data = await fs16.promises.readFile(this.indexPath, "utf-8");
42137
+ const data = await fs17.promises.readFile(this.indexPath, "utf-8");
42102
42138
  this.index = JSON.parse(data);
42103
42139
  return this.index;
42104
42140
  } catch (error) {
@@ -42119,7 +42155,7 @@ var FileContextStorage = class {
42119
42155
  await this.ensureDirectory();
42120
42156
  this.index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
42121
42157
  const data = this.prettyPrint ? JSON.stringify(this.index, null, 2) : JSON.stringify(this.index);
42122
- await fs16.promises.writeFile(this.indexPath, data, "utf-8");
42158
+ await fs17.promises.writeFile(this.indexPath, data, "utf-8");
42123
42159
  }
42124
42160
  async updateIndex(stored) {
42125
42161
  const index = await this.loadIndex();
@@ -42193,11 +42229,11 @@ var FileAgentDefinitionStorage = class {
42193
42229
  const data = this.prettyPrint ? JSON.stringify(definition, null, 2) : JSON.stringify(definition);
42194
42230
  const tempPath = `${filePath}.tmp`;
42195
42231
  try {
42196
- await fs16.promises.writeFile(tempPath, data, "utf-8");
42197
- await fs16.promises.rename(tempPath, filePath);
42232
+ await fs17.promises.writeFile(tempPath, data, "utf-8");
42233
+ await fs17.promises.rename(tempPath, filePath);
42198
42234
  } catch (error) {
42199
42235
  try {
42200
- await fs16.promises.unlink(tempPath);
42236
+ await fs17.promises.unlink(tempPath);
42201
42237
  } catch {
42202
42238
  }
42203
42239
  throw error;
@@ -42219,7 +42255,7 @@ var FileAgentDefinitionStorage = class {
42219
42255
  const agentDir = path2.join(this.baseDirectory, sanitizedId);
42220
42256
  const filePath = path2.join(agentDir, "definition.json");
42221
42257
  try {
42222
- await fs16.promises.unlink(filePath);
42258
+ await fs17.promises.unlink(filePath);
42223
42259
  } catch (error) {
42224
42260
  if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
42225
42261
  throw error;
@@ -42234,7 +42270,7 @@ var FileAgentDefinitionStorage = class {
42234
42270
  const sanitizedId = sanitizeAgentId2(agentId);
42235
42271
  const filePath = path2.join(this.baseDirectory, sanitizedId, "definition.json");
42236
42272
  try {
42237
- await fs16.promises.access(filePath);
42273
+ await fs17.promises.access(filePath);
42238
42274
  return true;
42239
42275
  } catch {
42240
42276
  return false;
@@ -42296,13 +42332,13 @@ var FileAgentDefinitionStorage = class {
42296
42332
  */
42297
42333
  async rebuildIndex() {
42298
42334
  await this.ensureDirectory(this.baseDirectory);
42299
- const entries = await fs16.promises.readdir(this.baseDirectory, { withFileTypes: true });
42335
+ const entries = await fs17.promises.readdir(this.baseDirectory, { withFileTypes: true });
42300
42336
  const agentDirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith("_"));
42301
42337
  const indexEntries = [];
42302
42338
  for (const dir of agentDirs) {
42303
42339
  try {
42304
42340
  const filePath = path2.join(this.baseDirectory, dir.name, "definition.json");
42305
- const data = await fs16.promises.readFile(filePath, "utf-8");
42341
+ const data = await fs17.promises.readFile(filePath, "utf-8");
42306
42342
  const definition = JSON.parse(data);
42307
42343
  indexEntries.push(this.definitionToIndexEntry(definition));
42308
42344
  } catch {
@@ -42320,7 +42356,7 @@ var FileAgentDefinitionStorage = class {
42320
42356
  // ==========================================================================
42321
42357
  async ensureDirectory(dir) {
42322
42358
  try {
42323
- await fs16.promises.mkdir(dir, { recursive: true });
42359
+ await fs17.promises.mkdir(dir, { recursive: true });
42324
42360
  } catch (error) {
42325
42361
  if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
42326
42362
  throw error;
@@ -42330,7 +42366,7 @@ var FileAgentDefinitionStorage = class {
42330
42366
  async loadRaw(sanitizedId) {
42331
42367
  const filePath = path2.join(this.baseDirectory, sanitizedId, "definition.json");
42332
42368
  try {
42333
- const data = await fs16.promises.readFile(filePath, "utf-8");
42369
+ const data = await fs17.promises.readFile(filePath, "utf-8");
42334
42370
  return JSON.parse(data);
42335
42371
  } catch (error) {
42336
42372
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -42348,7 +42384,7 @@ var FileAgentDefinitionStorage = class {
42348
42384
  return this.index;
42349
42385
  }
42350
42386
  try {
42351
- const data = await fs16.promises.readFile(this.indexPath, "utf-8");
42387
+ const data = await fs17.promises.readFile(this.indexPath, "utf-8");
42352
42388
  this.index = JSON.parse(data);
42353
42389
  return this.index;
42354
42390
  } catch (error) {
@@ -42368,7 +42404,7 @@ var FileAgentDefinitionStorage = class {
42368
42404
  await this.ensureDirectory(this.baseDirectory);
42369
42405
  this.index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
42370
42406
  const data = this.prettyPrint ? JSON.stringify(this.index, null, 2) : JSON.stringify(this.index);
42371
- await fs16.promises.writeFile(this.indexPath, data, "utf-8");
42407
+ await fs17.promises.writeFile(this.indexPath, data, "utf-8");
42372
42408
  }
42373
42409
  async updateIndex(definition) {
42374
42410
  const index = await this.loadIndex();
@@ -42426,10 +42462,10 @@ var FileMediaStorage = class {
42426
42462
  }
42427
42463
  async save(data, metadata) {
42428
42464
  const dir = metadata.userId ? path2__namespace.join(this.outputDir, metadata.userId) : this.outputDir;
42429
- await fs15__namespace.mkdir(dir, { recursive: true });
42465
+ await fs16__namespace.mkdir(dir, { recursive: true });
42430
42466
  const filename = metadata.suggestedFilename ?? this.generateFilename(metadata);
42431
42467
  const filePath = path2__namespace.join(dir, filename);
42432
- await fs15__namespace.writeFile(filePath, data);
42468
+ await fs16__namespace.writeFile(filePath, data);
42433
42469
  const format = metadata.format.toLowerCase();
42434
42470
  const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
42435
42471
  return {
@@ -42440,7 +42476,7 @@ var FileMediaStorage = class {
42440
42476
  }
42441
42477
  async read(location) {
42442
42478
  try {
42443
- return await fs15__namespace.readFile(location);
42479
+ return await fs16__namespace.readFile(location);
42444
42480
  } catch (err) {
42445
42481
  if (err.code === "ENOENT") {
42446
42482
  return null;
@@ -42450,7 +42486,7 @@ var FileMediaStorage = class {
42450
42486
  }
42451
42487
  async delete(location) {
42452
42488
  try {
42453
- await fs15__namespace.unlink(location);
42489
+ await fs16__namespace.unlink(location);
42454
42490
  } catch (err) {
42455
42491
  if (err.code === "ENOENT") {
42456
42492
  return;
@@ -42460,7 +42496,7 @@ var FileMediaStorage = class {
42460
42496
  }
42461
42497
  async exists(location) {
42462
42498
  try {
42463
- await fs15__namespace.access(location);
42499
+ await fs16__namespace.access(location);
42464
42500
  return true;
42465
42501
  } catch {
42466
42502
  return false;
@@ -42469,11 +42505,11 @@ var FileMediaStorage = class {
42469
42505
  async list(options) {
42470
42506
  await this.ensureDir();
42471
42507
  let entries = [];
42472
- const files = await fs15__namespace.readdir(this.outputDir);
42508
+ const files = await fs16__namespace.readdir(this.outputDir);
42473
42509
  for (const file of files) {
42474
42510
  const filePath = path2__namespace.join(this.outputDir, file);
42475
42511
  try {
42476
- const stat6 = await fs15__namespace.stat(filePath);
42512
+ const stat6 = await fs16__namespace.stat(filePath);
42477
42513
  if (!stat6.isFile()) continue;
42478
42514
  const ext = path2__namespace.extname(file).slice(1).toLowerCase();
42479
42515
  const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
@@ -42513,7 +42549,7 @@ var FileMediaStorage = class {
42513
42549
  }
42514
42550
  async ensureDir() {
42515
42551
  if (!this.initialized) {
42516
- await fs15__namespace.mkdir(this.outputDir, { recursive: true });
42552
+ await fs16__namespace.mkdir(this.outputDir, { recursive: true });
42517
42553
  this.initialized = true;
42518
42554
  }
42519
42555
  }
@@ -42521,6 +42557,230 @@ var FileMediaStorage = class {
42521
42557
  function createFileMediaStorage(config) {
42522
42558
  return new FileMediaStorage(config);
42523
42559
  }
42560
+ function getDefaultBaseDirectory4() {
42561
+ const platform2 = process.platform;
42562
+ if (platform2 === "win32") {
42563
+ const appData = process.env.APPDATA || process.env.LOCALAPPDATA;
42564
+ if (appData) {
42565
+ return path2.join(appData, "oneringai", "custom-tools");
42566
+ }
42567
+ }
42568
+ return path2.join(os2.homedir(), ".oneringai", "custom-tools");
42569
+ }
42570
+ function sanitizeName(name) {
42571
+ return name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "").toLowerCase() || "default";
42572
+ }
42573
+ var FileCustomToolStorage = class {
42574
+ baseDirectory;
42575
+ indexPath;
42576
+ prettyPrint;
42577
+ index = null;
42578
+ constructor(config = {}) {
42579
+ this.baseDirectory = config.baseDirectory ?? getDefaultBaseDirectory4();
42580
+ this.prettyPrint = config.prettyPrint ?? true;
42581
+ this.indexPath = path2.join(this.baseDirectory, "_index.json");
42582
+ }
42583
+ /**
42584
+ * Save a custom tool definition
42585
+ */
42586
+ async save(definition) {
42587
+ const sanitized = sanitizeName(definition.name);
42588
+ const filePath = path2.join(this.baseDirectory, `${sanitized}.json`);
42589
+ await this.ensureDirectory(this.baseDirectory);
42590
+ const data = this.prettyPrint ? JSON.stringify(definition, null, 2) : JSON.stringify(definition);
42591
+ const tempPath = `${filePath}.tmp`;
42592
+ try {
42593
+ await fs17.promises.writeFile(tempPath, data, "utf-8");
42594
+ await fs17.promises.rename(tempPath, filePath);
42595
+ } catch (error) {
42596
+ try {
42597
+ await fs17.promises.unlink(tempPath);
42598
+ } catch {
42599
+ }
42600
+ throw error;
42601
+ }
42602
+ await this.updateIndex(definition);
42603
+ }
42604
+ /**
42605
+ * Load a custom tool definition by name
42606
+ */
42607
+ async load(name) {
42608
+ const sanitized = sanitizeName(name);
42609
+ const filePath = path2.join(this.baseDirectory, `${sanitized}.json`);
42610
+ try {
42611
+ const data = await fs17.promises.readFile(filePath, "utf-8");
42612
+ return JSON.parse(data);
42613
+ } catch (error) {
42614
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
42615
+ return null;
42616
+ }
42617
+ if (error instanceof SyntaxError) {
42618
+ return null;
42619
+ }
42620
+ throw error;
42621
+ }
42622
+ }
42623
+ /**
42624
+ * Delete a custom tool definition
42625
+ */
42626
+ async delete(name) {
42627
+ const sanitized = sanitizeName(name);
42628
+ const filePath = path2.join(this.baseDirectory, `${sanitized}.json`);
42629
+ try {
42630
+ await fs17.promises.unlink(filePath);
42631
+ } catch (error) {
42632
+ if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
42633
+ throw error;
42634
+ }
42635
+ }
42636
+ await this.removeFromIndex(name);
42637
+ }
42638
+ /**
42639
+ * Check if a custom tool exists
42640
+ */
42641
+ async exists(name) {
42642
+ const sanitized = sanitizeName(name);
42643
+ const filePath = path2.join(this.baseDirectory, `${sanitized}.json`);
42644
+ try {
42645
+ await fs17.promises.access(filePath);
42646
+ return true;
42647
+ } catch {
42648
+ return false;
42649
+ }
42650
+ }
42651
+ /**
42652
+ * List custom tools (summaries only)
42653
+ */
42654
+ async list(options) {
42655
+ const index = await this.loadIndex();
42656
+ let entries = [...index.tools];
42657
+ if (options?.tags && options.tags.length > 0) {
42658
+ entries = entries.filter((e) => {
42659
+ const entryTags = e.tags ?? [];
42660
+ return options.tags.some((t) => entryTags.includes(t));
42661
+ });
42662
+ }
42663
+ if (options?.category) {
42664
+ entries = entries.filter((e) => e.category === options.category);
42665
+ }
42666
+ if (options?.search) {
42667
+ const searchLower = options.search.toLowerCase();
42668
+ entries = entries.filter(
42669
+ (e) => e.name.toLowerCase().includes(searchLower) || e.description.toLowerCase().includes(searchLower)
42670
+ );
42671
+ }
42672
+ entries.sort(
42673
+ (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
42674
+ );
42675
+ if (options?.offset) {
42676
+ entries = entries.slice(options.offset);
42677
+ }
42678
+ if (options?.limit) {
42679
+ entries = entries.slice(0, options.limit);
42680
+ }
42681
+ return entries.map((e) => ({
42682
+ name: e.name,
42683
+ displayName: e.displayName,
42684
+ description: e.description,
42685
+ createdAt: e.createdAt,
42686
+ updatedAt: e.updatedAt,
42687
+ metadata: {
42688
+ tags: e.tags,
42689
+ category: e.category
42690
+ }
42691
+ }));
42692
+ }
42693
+ /**
42694
+ * Update metadata without loading full definition
42695
+ */
42696
+ async updateMetadata(name, metadata) {
42697
+ const definition = await this.load(name);
42698
+ if (!definition) {
42699
+ throw new Error(`Custom tool '${name}' not found`);
42700
+ }
42701
+ definition.metadata = { ...definition.metadata, ...metadata };
42702
+ definition.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
42703
+ await this.save(definition);
42704
+ }
42705
+ /**
42706
+ * Get storage path
42707
+ */
42708
+ getPath() {
42709
+ return this.baseDirectory;
42710
+ }
42711
+ // ==========================================================================
42712
+ // Private Helpers
42713
+ // ==========================================================================
42714
+ async ensureDirectory(dir) {
42715
+ try {
42716
+ await fs17.promises.mkdir(dir, { recursive: true });
42717
+ } catch (error) {
42718
+ if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
42719
+ throw error;
42720
+ }
42721
+ }
42722
+ }
42723
+ async loadIndex() {
42724
+ if (this.index) {
42725
+ return this.index;
42726
+ }
42727
+ try {
42728
+ const data = await fs17.promises.readFile(this.indexPath, "utf-8");
42729
+ this.index = JSON.parse(data);
42730
+ return this.index;
42731
+ } catch (error) {
42732
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
42733
+ this.index = {
42734
+ version: 1,
42735
+ tools: [],
42736
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
42737
+ };
42738
+ return this.index;
42739
+ }
42740
+ throw error;
42741
+ }
42742
+ }
42743
+ async saveIndex() {
42744
+ if (!this.index) return;
42745
+ await this.ensureDirectory(this.baseDirectory);
42746
+ this.index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
42747
+ const data = this.prettyPrint ? JSON.stringify(this.index, null, 2) : JSON.stringify(this.index);
42748
+ await fs17.promises.writeFile(this.indexPath, data, "utf-8");
42749
+ }
42750
+ async updateIndex(definition) {
42751
+ const index = await this.loadIndex();
42752
+ const entry = this.definitionToIndexEntry(definition);
42753
+ const existingIdx = index.tools.findIndex((e) => e.name === definition.name);
42754
+ if (existingIdx >= 0) {
42755
+ index.tools[existingIdx] = entry;
42756
+ } else {
42757
+ index.tools.push(entry);
42758
+ }
42759
+ await this.saveIndex();
42760
+ }
42761
+ async removeFromIndex(name) {
42762
+ const index = await this.loadIndex();
42763
+ index.tools = index.tools.filter((e) => e.name !== name);
42764
+ await this.saveIndex();
42765
+ }
42766
+ definitionToIndexEntry(definition) {
42767
+ return {
42768
+ name: definition.name,
42769
+ displayName: definition.displayName,
42770
+ description: definition.description,
42771
+ createdAt: definition.createdAt,
42772
+ updatedAt: definition.updatedAt,
42773
+ tags: definition.metadata?.tags,
42774
+ category: definition.metadata?.category
42775
+ };
42776
+ }
42777
+ };
42778
+ function createFileCustomToolStorage(config) {
42779
+ return new FileCustomToolStorage(config);
42780
+ }
42781
+
42782
+ // src/domain/entities/CustomToolDefinition.ts
42783
+ var CUSTOM_TOOL_DEFINITION_VERSION = 1;
42524
42784
 
42525
42785
  // src/capabilities/agents/StreamHelpers.ts
42526
42786
  var StreamHelpers = class {
@@ -43617,8 +43877,8 @@ var FileStorage = class {
43617
43877
  }
43618
43878
  async ensureDirectory() {
43619
43879
  try {
43620
- await fs15__namespace.mkdir(this.directory, { recursive: true });
43621
- await fs15__namespace.chmod(this.directory, 448);
43880
+ await fs16__namespace.mkdir(this.directory, { recursive: true });
43881
+ await fs16__namespace.chmod(this.directory, 448);
43622
43882
  } catch (error) {
43623
43883
  }
43624
43884
  }
@@ -43634,13 +43894,13 @@ var FileStorage = class {
43634
43894
  const filePath = this.getFilePath(key);
43635
43895
  const plaintext = JSON.stringify(token);
43636
43896
  const encrypted = encrypt(plaintext, this.encryptionKey);
43637
- await fs15__namespace.writeFile(filePath, encrypted, "utf8");
43638
- await fs15__namespace.chmod(filePath, 384);
43897
+ await fs16__namespace.writeFile(filePath, encrypted, "utf8");
43898
+ await fs16__namespace.chmod(filePath, 384);
43639
43899
  }
43640
43900
  async getToken(key) {
43641
43901
  const filePath = this.getFilePath(key);
43642
43902
  try {
43643
- const encrypted = await fs15__namespace.readFile(filePath, "utf8");
43903
+ const encrypted = await fs16__namespace.readFile(filePath, "utf8");
43644
43904
  const decrypted = decrypt(encrypted, this.encryptionKey);
43645
43905
  return JSON.parse(decrypted);
43646
43906
  } catch (error) {
@@ -43649,7 +43909,7 @@ var FileStorage = class {
43649
43909
  }
43650
43910
  console.error("Failed to read/decrypt token file:", error);
43651
43911
  try {
43652
- await fs15__namespace.unlink(filePath);
43912
+ await fs16__namespace.unlink(filePath);
43653
43913
  } catch {
43654
43914
  }
43655
43915
  return null;
@@ -43658,7 +43918,7 @@ var FileStorage = class {
43658
43918
  async deleteToken(key) {
43659
43919
  const filePath = this.getFilePath(key);
43660
43920
  try {
43661
- await fs15__namespace.unlink(filePath);
43921
+ await fs16__namespace.unlink(filePath);
43662
43922
  } catch (error) {
43663
43923
  if (error.code !== "ENOENT") {
43664
43924
  throw error;
@@ -43668,7 +43928,7 @@ var FileStorage = class {
43668
43928
  async hasToken(key) {
43669
43929
  const filePath = this.getFilePath(key);
43670
43930
  try {
43671
- await fs15__namespace.access(filePath);
43931
+ await fs16__namespace.access(filePath);
43672
43932
  return true;
43673
43933
  } catch {
43674
43934
  return false;
@@ -43679,7 +43939,7 @@ var FileStorage = class {
43679
43939
  */
43680
43940
  async listTokens() {
43681
43941
  try {
43682
- const files = await fs15__namespace.readdir(this.directory);
43942
+ const files = await fs16__namespace.readdir(this.directory);
43683
43943
  return files.filter((f) => f.endsWith(".token")).map((f) => f.replace(".token", ""));
43684
43944
  } catch {
43685
43945
  return [];
@@ -43690,10 +43950,10 @@ var FileStorage = class {
43690
43950
  */
43691
43951
  async clearAll() {
43692
43952
  try {
43693
- const files = await fs15__namespace.readdir(this.directory);
43953
+ const files = await fs16__namespace.readdir(this.directory);
43694
43954
  const tokenFiles = files.filter((f) => f.endsWith(".token"));
43695
43955
  await Promise.all(
43696
- tokenFiles.map((f) => fs15__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
43956
+ tokenFiles.map((f) => fs16__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
43697
43957
  }))
43698
43958
  );
43699
43959
  } catch {
@@ -44120,14 +44380,14 @@ var FileConnectorStorage = class {
44120
44380
  await this.ensureDirectory();
44121
44381
  const filePath = this.getFilePath(name);
44122
44382
  const json = JSON.stringify(stored, null, 2);
44123
- await fs15__namespace.writeFile(filePath, json, "utf8");
44124
- await fs15__namespace.chmod(filePath, 384);
44383
+ await fs16__namespace.writeFile(filePath, json, "utf8");
44384
+ await fs16__namespace.chmod(filePath, 384);
44125
44385
  await this.updateIndex(name, "add");
44126
44386
  }
44127
44387
  async get(name) {
44128
44388
  const filePath = this.getFilePath(name);
44129
44389
  try {
44130
- const json = await fs15__namespace.readFile(filePath, "utf8");
44390
+ const json = await fs16__namespace.readFile(filePath, "utf8");
44131
44391
  return JSON.parse(json);
44132
44392
  } catch (error) {
44133
44393
  const err = error;
@@ -44140,7 +44400,7 @@ var FileConnectorStorage = class {
44140
44400
  async delete(name) {
44141
44401
  const filePath = this.getFilePath(name);
44142
44402
  try {
44143
- await fs15__namespace.unlink(filePath);
44403
+ await fs16__namespace.unlink(filePath);
44144
44404
  await this.updateIndex(name, "remove");
44145
44405
  return true;
44146
44406
  } catch (error) {
@@ -44154,7 +44414,7 @@ var FileConnectorStorage = class {
44154
44414
  async has(name) {
44155
44415
  const filePath = this.getFilePath(name);
44156
44416
  try {
44157
- await fs15__namespace.access(filePath);
44417
+ await fs16__namespace.access(filePath);
44158
44418
  return true;
44159
44419
  } catch {
44160
44420
  return false;
@@ -44180,13 +44440,13 @@ var FileConnectorStorage = class {
44180
44440
  */
44181
44441
  async clear() {
44182
44442
  try {
44183
- const files = await fs15__namespace.readdir(this.directory);
44443
+ const files = await fs16__namespace.readdir(this.directory);
44184
44444
  const connectorFiles = files.filter(
44185
44445
  (f) => f.endsWith(".connector.json") || f === "_index.json"
44186
44446
  );
44187
44447
  await Promise.all(
44188
44448
  connectorFiles.map(
44189
- (f) => fs15__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
44449
+ (f) => fs16__namespace.unlink(path2__namespace.join(this.directory, f)).catch(() => {
44190
44450
  })
44191
44451
  )
44192
44452
  );
@@ -44213,8 +44473,8 @@ var FileConnectorStorage = class {
44213
44473
  async ensureDirectory() {
44214
44474
  if (this.initialized) return;
44215
44475
  try {
44216
- await fs15__namespace.mkdir(this.directory, { recursive: true });
44217
- await fs15__namespace.chmod(this.directory, 448);
44476
+ await fs16__namespace.mkdir(this.directory, { recursive: true });
44477
+ await fs16__namespace.chmod(this.directory, 448);
44218
44478
  this.initialized = true;
44219
44479
  } catch {
44220
44480
  this.initialized = true;
@@ -44225,7 +44485,7 @@ var FileConnectorStorage = class {
44225
44485
  */
44226
44486
  async loadIndex() {
44227
44487
  try {
44228
- const json = await fs15__namespace.readFile(this.indexPath, "utf8");
44488
+ const json = await fs16__namespace.readFile(this.indexPath, "utf8");
44229
44489
  return JSON.parse(json);
44230
44490
  } catch {
44231
44491
  return { connectors: {} };
@@ -44243,8 +44503,8 @@ var FileConnectorStorage = class {
44243
44503
  delete index.connectors[hash];
44244
44504
  }
44245
44505
  const json = JSON.stringify(index, null, 2);
44246
- await fs15__namespace.writeFile(this.indexPath, json, "utf8");
44247
- await fs15__namespace.chmod(this.indexPath, 384);
44506
+ await fs16__namespace.writeFile(this.indexPath, json, "utf8");
44507
+ await fs16__namespace.chmod(this.indexPath, 384);
44248
44508
  }
44249
44509
  };
44250
44510
 
@@ -46699,8 +46959,8 @@ function createMessageWithImages(text, imageUrls, role = "user" /* USER */) {
46699
46959
  var execAsync = util.promisify(child_process.exec);
46700
46960
  function cleanupTempFile(filePath) {
46701
46961
  try {
46702
- if (fs16__namespace.existsSync(filePath)) {
46703
- fs16__namespace.unlinkSync(filePath);
46962
+ if (fs17__namespace.existsSync(filePath)) {
46963
+ fs17__namespace.unlinkSync(filePath);
46704
46964
  }
46705
46965
  } catch {
46706
46966
  }
@@ -46751,7 +47011,7 @@ async function readClipboardImageMac() {
46751
47011
  end try
46752
47012
  `;
46753
47013
  const { stdout } = await execAsync(`osascript -e '${script}'`);
46754
- if (stdout.includes("success") || fs16__namespace.existsSync(tempFile)) {
47014
+ if (stdout.includes("success") || fs17__namespace.existsSync(tempFile)) {
46755
47015
  return await convertFileToDataUri(tempFile);
46756
47016
  }
46757
47017
  return {
@@ -46768,14 +47028,14 @@ async function readClipboardImageLinux() {
46768
47028
  try {
46769
47029
  try {
46770
47030
  await execAsync(`xclip -selection clipboard -t image/png -o > "${tempFile}"`);
46771
- if (fs16__namespace.existsSync(tempFile) && fs16__namespace.statSync(tempFile).size > 0) {
47031
+ if (fs17__namespace.existsSync(tempFile) && fs17__namespace.statSync(tempFile).size > 0) {
46772
47032
  return await convertFileToDataUri(tempFile);
46773
47033
  }
46774
47034
  } catch {
46775
47035
  }
46776
47036
  try {
46777
47037
  await execAsync(`wl-paste -t image/png > "${tempFile}"`);
46778
- if (fs16__namespace.existsSync(tempFile) && fs16__namespace.statSync(tempFile).size > 0) {
47038
+ if (fs17__namespace.existsSync(tempFile) && fs17__namespace.statSync(tempFile).size > 0) {
46779
47039
  return await convertFileToDataUri(tempFile);
46780
47040
  }
46781
47041
  } catch {
@@ -46802,7 +47062,7 @@ async function readClipboardImageWindows() {
46802
47062
  }
46803
47063
  `;
46804
47064
  await execAsync(`powershell -Command "${psScript}"`);
46805
- if (fs16__namespace.existsSync(tempFile) && fs16__namespace.statSync(tempFile).size > 0) {
47065
+ if (fs17__namespace.existsSync(tempFile) && fs17__namespace.statSync(tempFile).size > 0) {
46806
47066
  return await convertFileToDataUri(tempFile);
46807
47067
  }
46808
47068
  return {
@@ -46815,7 +47075,7 @@ async function readClipboardImageWindows() {
46815
47075
  }
46816
47076
  async function convertFileToDataUri(filePath) {
46817
47077
  try {
46818
- const imageBuffer = fs16__namespace.readFileSync(filePath);
47078
+ const imageBuffer = fs17__namespace.readFileSync(filePath);
46819
47079
  const base64Image = imageBuffer.toString("base64");
46820
47080
  const magic = imageBuffer.slice(0, 4).toString("hex");
46821
47081
  let mimeType = "image/png";
@@ -47071,6 +47331,13 @@ __export(tools_exports, {
47071
47331
  bash: () => bash,
47072
47332
  createBashTool: () => createBashTool,
47073
47333
  createCreatePRTool: () => createCreatePRTool,
47334
+ createCustomToolDelete: () => createCustomToolDelete,
47335
+ createCustomToolDraft: () => createCustomToolDraft,
47336
+ createCustomToolList: () => createCustomToolList,
47337
+ createCustomToolLoad: () => createCustomToolLoad,
47338
+ createCustomToolMetaTools: () => createCustomToolMetaTools,
47339
+ createCustomToolSave: () => createCustomToolSave,
47340
+ createCustomToolTest: () => createCustomToolTest,
47074
47341
  createDesktopGetCursorTool: () => createDesktopGetCursorTool,
47075
47342
  createDesktopGetScreenSizeTool: () => createDesktopGetScreenSizeTool,
47076
47343
  createDesktopKeyboardKeyTool: () => createDesktopKeyboardKeyTool,
@@ -47101,6 +47368,12 @@ __export(tools_exports, {
47101
47368
  createWebScrapeTool: () => createWebScrapeTool,
47102
47369
  createWebSearchTool: () => createWebSearchTool,
47103
47370
  createWriteFileTool: () => createWriteFileTool,
47371
+ customToolDelete: () => customToolDelete,
47372
+ customToolDraft: () => customToolDraft,
47373
+ customToolList: () => customToolList,
47374
+ customToolLoad: () => customToolLoad,
47375
+ customToolSave: () => customToolSave,
47376
+ customToolTest: () => customToolTest,
47104
47377
  desktopGetCursor: () => desktopGetCursor,
47105
47378
  desktopGetScreenSize: () => desktopGetScreenSize,
47106
47379
  desktopKeyboardKey: () => desktopKeyboardKey,
@@ -47115,6 +47388,7 @@ __export(tools_exports, {
47115
47388
  desktopWindowList: () => desktopWindowList,
47116
47389
  developerTools: () => developerTools,
47117
47390
  editFile: () => editFile,
47391
+ executeInVM: () => executeInVM,
47118
47392
  executeJavaScript: () => executeJavaScript,
47119
47393
  expandTilde: () => expandTilde,
47120
47394
  getAllBuiltInTools: () => getAllBuiltInTools,
@@ -47129,6 +47403,7 @@ __export(tools_exports, {
47129
47403
  getToolsRequiringConnector: () => getToolsRequiringConnector,
47130
47404
  glob: () => glob,
47131
47405
  grep: () => grep,
47406
+ hydrateCustomTool: () => hydrateCustomTool,
47132
47407
  isBlockedCommand: () => isBlockedCommand,
47133
47408
  isExcludedExtension: () => isExcludedExtension,
47134
47409
  jsonManipulator: () => jsonManipulator,
@@ -47349,7 +47624,7 @@ EXAMPLES:
47349
47624
  };
47350
47625
  }
47351
47626
  const resolvedPath = validation.resolvedPath;
47352
- if (!fs16.existsSync(resolvedPath)) {
47627
+ if (!fs17.existsSync(resolvedPath)) {
47353
47628
  return {
47354
47629
  success: false,
47355
47630
  error: `File not found: ${file_path}`,
@@ -47357,7 +47632,7 @@ EXAMPLES:
47357
47632
  };
47358
47633
  }
47359
47634
  try {
47360
- const stats = await fs15.stat(resolvedPath);
47635
+ const stats = await fs16.stat(resolvedPath);
47361
47636
  if (!stats.isFile()) {
47362
47637
  return {
47363
47638
  success: false,
@@ -47399,7 +47674,7 @@ EXAMPLES:
47399
47674
  } catch {
47400
47675
  }
47401
47676
  }
47402
- const content = await fs15.readFile(resolvedPath, "utf-8");
47677
+ const content = await fs16.readFile(resolvedPath, "utf-8");
47403
47678
  const allLines = content.split("\n");
47404
47679
  const totalLines = allLines.length;
47405
47680
  const startIndex = Math.max(0, offset - 1);
@@ -47504,13 +47779,13 @@ EXAMPLES:
47504
47779
  };
47505
47780
  }
47506
47781
  const resolvedPath = validation.resolvedPath;
47507
- const fileExists = fs16.existsSync(resolvedPath);
47782
+ const fileExists = fs17.existsSync(resolvedPath);
47508
47783
  try {
47509
47784
  const parentDir = path2.dirname(resolvedPath);
47510
- if (!fs16.existsSync(parentDir)) {
47511
- await fs15.mkdir(parentDir, { recursive: true });
47785
+ if (!fs17.existsSync(parentDir)) {
47786
+ await fs16.mkdir(parentDir, { recursive: true });
47512
47787
  }
47513
- await fs15.writeFile(resolvedPath, content, "utf-8");
47788
+ await fs16.writeFile(resolvedPath, content, "utf-8");
47514
47789
  return {
47515
47790
  success: true,
47516
47791
  path: file_path,
@@ -47613,7 +47888,7 @@ EXAMPLES:
47613
47888
  };
47614
47889
  }
47615
47890
  const resolvedPath = validation.resolvedPath;
47616
- if (!fs16.existsSync(resolvedPath)) {
47891
+ if (!fs17.existsSync(resolvedPath)) {
47617
47892
  return {
47618
47893
  success: false,
47619
47894
  error: `File not found: ${file_path}`,
@@ -47621,7 +47896,7 @@ EXAMPLES:
47621
47896
  };
47622
47897
  }
47623
47898
  try {
47624
- const content = await fs15.readFile(resolvedPath, "utf-8");
47899
+ const content = await fs16.readFile(resolvedPath, "utf-8");
47625
47900
  let occurrences = 0;
47626
47901
  let searchIndex = 0;
47627
47902
  while (true) {
@@ -47660,7 +47935,7 @@ EXAMPLES:
47660
47935
  } else {
47661
47936
  newContent = content.replace(old_string, new_string);
47662
47937
  }
47663
- await fs15.writeFile(resolvedPath, newContent, "utf-8");
47938
+ await fs16.writeFile(resolvedPath, newContent, "utf-8");
47664
47939
  const diffPreview = generateDiffPreview(old_string, new_string);
47665
47940
  return {
47666
47941
  success: true,
@@ -47716,7 +47991,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
47716
47991
  return results;
47717
47992
  }
47718
47993
  try {
47719
- const entries = await fs15.readdir(dir, { withFileTypes: true });
47994
+ const entries = await fs16.readdir(dir, { withFileTypes: true });
47720
47995
  for (const entry of entries) {
47721
47996
  if (results.length >= config.maxResults) break;
47722
47997
  const fullPath = path2.join(dir, entry.name);
@@ -47730,7 +48005,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
47730
48005
  } else if (entry.isFile()) {
47731
48006
  if (matchGlobPattern(pattern, relativePath)) {
47732
48007
  try {
47733
- const stats = await fs15.stat(fullPath);
48008
+ const stats = await fs16.stat(fullPath);
47734
48009
  results.push({
47735
48010
  path: relativePath,
47736
48011
  mtime: stats.mtimeMs
@@ -47812,7 +48087,7 @@ WHEN TO USE:
47812
48087
  };
47813
48088
  }
47814
48089
  const resolvedDir = validation.resolvedPath;
47815
- if (!fs16.existsSync(resolvedDir)) {
48090
+ if (!fs17.existsSync(resolvedDir)) {
47816
48091
  return {
47817
48092
  success: false,
47818
48093
  error: `Directory not found: ${searchDir}`
@@ -47867,7 +48142,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
47867
48142
  return files;
47868
48143
  }
47869
48144
  try {
47870
- const entries = await fs15.readdir(dir, { withFileTypes: true });
48145
+ const entries = await fs16.readdir(dir, { withFileTypes: true });
47871
48146
  for (const entry of entries) {
47872
48147
  const fullPath = path2.join(dir, entry.name);
47873
48148
  if (entry.isDirectory()) {
@@ -47900,7 +48175,7 @@ async function findFilesToSearch(dir, baseDir, config, globPattern, fileType, fi
47900
48175
  async function searchFile(filePath, regex, contextBefore, contextAfter) {
47901
48176
  const matches = [];
47902
48177
  try {
47903
- const content = await fs15.readFile(filePath, "utf-8");
48178
+ const content = await fs16.readFile(filePath, "utf-8");
47904
48179
  const lines = content.split("\n");
47905
48180
  for (let i = 0; i < lines.length; i++) {
47906
48181
  const line = lines[i] ?? "";
@@ -48041,7 +48316,7 @@ WHEN TO USE:
48041
48316
  };
48042
48317
  }
48043
48318
  const resolvedPath = validation.resolvedPath;
48044
- if (!fs16.existsSync(resolvedPath)) {
48319
+ if (!fs17.existsSync(resolvedPath)) {
48045
48320
  return {
48046
48321
  success: false,
48047
48322
  error: `Path not found: ${searchPath}`
@@ -48057,7 +48332,7 @@ WHEN TO USE:
48057
48332
  };
48058
48333
  }
48059
48334
  try {
48060
- const stats = await fs15.stat(resolvedPath);
48335
+ const stats = await fs16.stat(resolvedPath);
48061
48336
  let filesToSearch;
48062
48337
  if (stats.isFile()) {
48063
48338
  filesToSearch = [resolvedPath];
@@ -48145,7 +48420,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
48145
48420
  return entries;
48146
48421
  }
48147
48422
  try {
48148
- const dirEntries = await fs15.readdir(dir, { withFileTypes: true });
48423
+ const dirEntries = await fs16.readdir(dir, { withFileTypes: true });
48149
48424
  for (const entry of dirEntries) {
48150
48425
  if (entries.length >= config.maxResults) break;
48151
48426
  const fullPath = path2.join(dir, entry.name);
@@ -48163,7 +48438,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
48163
48438
  }
48164
48439
  if (filter === "directories" && !isDir) continue;
48165
48440
  try {
48166
- const stats = await fs15.stat(fullPath);
48441
+ const stats = await fs16.stat(fullPath);
48167
48442
  const dirEntry = {
48168
48443
  name: entry.name,
48169
48444
  path: relativePath,
@@ -48259,14 +48534,14 @@ EXAMPLES:
48259
48534
  };
48260
48535
  }
48261
48536
  const resolvedPath = validation.resolvedPath;
48262
- if (!fs16.existsSync(resolvedPath)) {
48537
+ if (!fs17.existsSync(resolvedPath)) {
48263
48538
  return {
48264
48539
  success: false,
48265
48540
  error: `Directory not found: ${path6}`
48266
48541
  };
48267
48542
  }
48268
48543
  try {
48269
- const stats = await fs15.stat(resolvedPath);
48544
+ const stats = await fs16.stat(resolvedPath);
48270
48545
  if (!stats.isDirectory()) {
48271
48546
  return {
48272
48547
  success: false,
@@ -52036,6 +52311,498 @@ var desktopTools = [
52036
52311
  desktopWindowFocus
52037
52312
  ];
52038
52313
 
52314
+ // src/tools/custom-tools/customToolDelete.ts
52315
+ function createCustomToolDelete(storage) {
52316
+ return {
52317
+ definition: {
52318
+ type: "function",
52319
+ function: {
52320
+ name: "custom_tool_delete",
52321
+ description: "Delete a custom tool from persistent storage.",
52322
+ parameters: {
52323
+ type: "object",
52324
+ properties: {
52325
+ name: {
52326
+ type: "string",
52327
+ description: "Name of the tool to delete"
52328
+ }
52329
+ },
52330
+ required: ["name"]
52331
+ }
52332
+ }
52333
+ },
52334
+ permission: { scope: "session", riskLevel: "medium" },
52335
+ execute: async (args) => {
52336
+ try {
52337
+ const exists = await storage.exists(args.name);
52338
+ if (!exists) {
52339
+ return { success: false, name: args.name, error: `Custom tool '${args.name}' not found` };
52340
+ }
52341
+ await storage.delete(args.name);
52342
+ return { success: true, name: args.name };
52343
+ } catch (error) {
52344
+ return { success: false, name: args.name, error: error.message };
52345
+ }
52346
+ },
52347
+ describeCall: (args) => args.name
52348
+ };
52349
+ }
52350
+ var customToolDelete = createCustomToolDelete(new FileCustomToolStorage());
52351
+
52352
+ // src/tools/custom-tools/sandboxDescription.ts
52353
+ init_Connector();
52354
+ function formatConnectorEntry2(c) {
52355
+ const parts = [];
52356
+ const serviceOrVendor = c.serviceType ?? c.vendor ?? void 0;
52357
+ if (serviceOrVendor) parts.push(`Service: ${serviceOrVendor}`);
52358
+ if (c.config.description) parts.push(c.config.description);
52359
+ if (c.baseURL) parts.push(`URL: ${c.baseURL}`);
52360
+ const details = parts.map((p) => ` ${p}`).join("\n");
52361
+ return ` \u2022 "${c.name}" (${c.displayName})
52362
+ ${details}`;
52363
+ }
52364
+ function buildConnectorList(context) {
52365
+ const registry = context?.connectorRegistry ?? exports.Connector.asRegistry();
52366
+ const connectors = registry.listAll();
52367
+ if (connectors.length === 0) {
52368
+ return " No connectors registered.";
52369
+ }
52370
+ return connectors.map(formatConnectorEntry2).join("\n\n");
52371
+ }
52372
+ var SANDBOX_API_REFERENCE = `SANDBOX API (available inside custom tool code):
52373
+
52374
+ 1. authenticatedFetch(url, options, connectorName)
52375
+ Makes authenticated HTTP requests using the connector's credentials.
52376
+ Auth headers are added automatically \u2014 DO NOT set Authorization header manually.
52377
+
52378
+ Parameters:
52379
+ \u2022 url: Full URL or path relative to the connector's base URL
52380
+ - Full: "https://api.github.com/user/repos"
52381
+ - Relative: "/user/repos" (resolved against connector's base URL)
52382
+ \u2022 options: Standard fetch options { method, headers, body }
52383
+ - For POST/PUT: set body to JSON.stringify(data) and headers to { 'Content-Type': 'application/json' }
52384
+ \u2022 connectorName: Name of a registered connector (see REGISTERED CONNECTORS below)
52385
+
52386
+ Returns: Promise<Response>
52387
+ \u2022 response.ok \u2014 true if status 200-299
52388
+ \u2022 response.status \u2014 HTTP status code
52389
+ \u2022 await response.json() \u2014 parse JSON body
52390
+ \u2022 await response.text() \u2014 get text body
52391
+
52392
+ 2. fetch(url, options) \u2014 Standard fetch without authentication
52393
+
52394
+ 3. connectors.list() \u2014 Array of available connector names
52395
+ 4. connectors.get(name) \u2014 Connector info: { displayName, description, baseURL, serviceType }
52396
+
52397
+ VARIABLES:
52398
+ \u2022 input \u2014 the tool's input arguments (matches inputSchema)
52399
+ \u2022 output \u2014 SET THIS to return the tool's result to the caller
52400
+
52401
+ GLOBALS: console.log/error/warn, JSON, Math, Date, Buffer, Promise, Array, Object, String, Number, Boolean, setTimeout, setInterval, URL, URLSearchParams, RegExp, Map, Set, Error, TextEncoder, TextDecoder
52402
+
52403
+ LIMITS: No file system access, no require/import. Code runs in async context (await is available).`;
52404
+ function buildDraftDescription(context) {
52405
+ const connectorList = buildConnectorList(context);
52406
+ return `Validate a draft custom tool definition. Checks name format, schema structure, and code syntax.
52407
+
52408
+ When writing the "code" field, you have access to the full VM sandbox:
52409
+
52410
+ ${SANDBOX_API_REFERENCE}
52411
+
52412
+ REGISTERED CONNECTORS:
52413
+ ${connectorList}
52414
+
52415
+ CODE EXAMPLES:
52416
+
52417
+ // Simple data processing tool
52418
+ const items = input.data;
52419
+ output = items.filter(i => i.score > 0.8).sort((a, b) => b.score - a.score);
52420
+
52421
+ // API tool using a connector
52422
+ const resp = await authenticatedFetch('/user/repos', { method: 'GET' }, 'github');
52423
+ const repos = await resp.json();
52424
+ output = repos.map(r => ({ name: r.full_name, stars: r.stargazers_count }));
52425
+
52426
+ // Tool that chains multiple API calls
52427
+ const users = await (await authenticatedFetch('/users', {}, 'my-api')).json();
52428
+ const enriched = await Promise.all(users.map(async u => {
52429
+ const details = await (await authenticatedFetch(\`/users/\${u.id}\`, {}, 'my-api')).json();
52430
+ return { ...u, ...details };
52431
+ }));
52432
+ output = enriched;`;
52433
+ }
52434
+ function buildTestDescription(context) {
52435
+ const connectorList = buildConnectorList(context);
52436
+ return `Test custom tool code by executing it in the VM sandbox with provided test input. Returns execution result, captured logs, and timing.
52437
+
52438
+ The code runs in the same sandbox as execute_javascript:
52439
+
52440
+ ${SANDBOX_API_REFERENCE}
52441
+
52442
+ REGISTERED CONNECTORS:
52443
+ ${connectorList}
52444
+
52445
+ The testInput you provide will be available as the \`input\` variable in the code.
52446
+ Set \`output\` to the value you want returned.`;
52447
+ }
52448
+
52449
+ // src/tools/custom-tools/customToolDraft.ts
52450
+ var NAME_PATTERN = /^[a-z][a-z0-9_]*$/;
52451
+ function createCustomToolDraft() {
52452
+ return {
52453
+ definition: {
52454
+ type: "function",
52455
+ function: {
52456
+ name: "custom_tool_draft",
52457
+ description: "Validate a draft custom tool definition. Checks name format, schema structure, and code syntax.",
52458
+ parameters: {
52459
+ type: "object",
52460
+ properties: {
52461
+ name: {
52462
+ type: "string",
52463
+ description: 'Tool name (lowercase, underscores, must start with letter). Example: "fetch_weather"'
52464
+ },
52465
+ description: {
52466
+ type: "string",
52467
+ description: "What the tool does"
52468
+ },
52469
+ inputSchema: {
52470
+ type: "object",
52471
+ description: 'JSON Schema for the tool input (must have type: "object")'
52472
+ },
52473
+ outputSchema: {
52474
+ type: "object",
52475
+ description: "Optional JSON Schema for the tool output (documentation only)"
52476
+ },
52477
+ code: {
52478
+ type: "string",
52479
+ description: "JavaScript code that reads `input` and sets `output`. Runs in the same sandbox as execute_javascript. See tool description for full API reference."
52480
+ },
52481
+ tags: {
52482
+ type: "array",
52483
+ description: "Optional tags for categorization",
52484
+ items: { type: "string" }
52485
+ },
52486
+ connectorName: {
52487
+ type: "string",
52488
+ description: "Optional connector name if the tool requires API access"
52489
+ }
52490
+ },
52491
+ required: ["name", "description", "inputSchema", "code"]
52492
+ }
52493
+ }
52494
+ },
52495
+ descriptionFactory: (context) => buildDraftDescription(context),
52496
+ permission: { scope: "always", riskLevel: "low" },
52497
+ execute: async (args) => {
52498
+ const errors = [];
52499
+ if (!args.name || typeof args.name !== "string") {
52500
+ errors.push("name is required and must be a string");
52501
+ } else if (!NAME_PATTERN.test(args.name)) {
52502
+ errors.push(
52503
+ `name "${args.name}" is invalid. Must match /^[a-z][a-z0-9_]*$/ (lowercase, underscores, start with letter)`
52504
+ );
52505
+ }
52506
+ if (!args.description || typeof args.description !== "string" || args.description.trim().length === 0) {
52507
+ errors.push("description is required and must be a non-empty string");
52508
+ }
52509
+ if (!args.inputSchema || typeof args.inputSchema !== "object") {
52510
+ errors.push("inputSchema is required and must be an object");
52511
+ } else if (args.inputSchema.type !== "object") {
52512
+ errors.push('inputSchema.type must be "object"');
52513
+ }
52514
+ if (!args.code || typeof args.code !== "string" || args.code.trim().length === 0) {
52515
+ errors.push("code is required and must be a non-empty string");
52516
+ } else {
52517
+ try {
52518
+ new Function(args.code);
52519
+ } catch (e) {
52520
+ errors.push(`code has syntax error: ${e.message}`);
52521
+ }
52522
+ }
52523
+ if (errors.length > 0) {
52524
+ return { success: false, errors };
52525
+ }
52526
+ return {
52527
+ success: true,
52528
+ validated: {
52529
+ name: args.name,
52530
+ description: args.description,
52531
+ inputSchema: args.inputSchema,
52532
+ outputSchema: args.outputSchema,
52533
+ code: args.code,
52534
+ tags: args.tags,
52535
+ connectorName: args.connectorName
52536
+ }
52537
+ };
52538
+ },
52539
+ describeCall: (args) => args.name ?? "unknown"
52540
+ };
52541
+ }
52542
+ var customToolDraft = createCustomToolDraft();
52543
+
52544
+ // src/tools/custom-tools/customToolList.ts
52545
+ function createCustomToolList(storage) {
52546
+ return {
52547
+ definition: {
52548
+ type: "function",
52549
+ function: {
52550
+ name: "custom_tool_list",
52551
+ description: "List saved custom tools from persistent storage. Supports filtering by search text, tags, and category.",
52552
+ parameters: {
52553
+ type: "object",
52554
+ properties: {
52555
+ search: {
52556
+ type: "string",
52557
+ description: "Search text (case-insensitive substring match on name + description)"
52558
+ },
52559
+ tags: {
52560
+ type: "array",
52561
+ description: "Filter by tags (any match)",
52562
+ items: { type: "string" }
52563
+ },
52564
+ category: {
52565
+ type: "string",
52566
+ description: "Filter by category"
52567
+ },
52568
+ limit: {
52569
+ type: "number",
52570
+ description: "Maximum number of results"
52571
+ },
52572
+ offset: {
52573
+ type: "number",
52574
+ description: "Offset for pagination"
52575
+ }
52576
+ }
52577
+ }
52578
+ }
52579
+ },
52580
+ permission: { scope: "always", riskLevel: "low" },
52581
+ execute: async (args) => {
52582
+ const tools = await storage.list({
52583
+ search: args.search,
52584
+ tags: args.tags,
52585
+ category: args.category,
52586
+ limit: args.limit,
52587
+ offset: args.offset
52588
+ });
52589
+ return { tools, total: tools.length };
52590
+ },
52591
+ describeCall: (args) => args.search ?? "all tools"
52592
+ };
52593
+ }
52594
+ var customToolList = createCustomToolList(new FileCustomToolStorage());
52595
+
52596
+ // src/tools/custom-tools/customToolLoad.ts
52597
+ function createCustomToolLoad(storage) {
52598
+ return {
52599
+ definition: {
52600
+ type: "function",
52601
+ function: {
52602
+ name: "custom_tool_load",
52603
+ description: "Load a full custom tool definition from storage (including code). Use this to inspect, modify, or hydrate a saved tool.",
52604
+ parameters: {
52605
+ type: "object",
52606
+ properties: {
52607
+ name: {
52608
+ type: "string",
52609
+ description: "Name of the tool to load"
52610
+ }
52611
+ },
52612
+ required: ["name"]
52613
+ }
52614
+ }
52615
+ },
52616
+ permission: { scope: "always", riskLevel: "low" },
52617
+ execute: async (args) => {
52618
+ const tool = await storage.load(args.name);
52619
+ if (!tool) {
52620
+ return { success: false, error: `Custom tool '${args.name}' not found` };
52621
+ }
52622
+ return { success: true, tool };
52623
+ },
52624
+ describeCall: (args) => args.name
52625
+ };
52626
+ }
52627
+ var customToolLoad = createCustomToolLoad(new FileCustomToolStorage());
52628
+
52629
+ // src/tools/custom-tools/customToolSave.ts
52630
+ function createCustomToolSave(storage) {
52631
+ return {
52632
+ definition: {
52633
+ type: "function",
52634
+ function: {
52635
+ name: "custom_tool_save",
52636
+ description: "Save a custom tool definition to persistent storage. The tool can later be loaded, hydrated, and registered on any agent.",
52637
+ parameters: {
52638
+ type: "object",
52639
+ properties: {
52640
+ name: {
52641
+ type: "string",
52642
+ description: "Tool name (must match /^[a-z][a-z0-9_]*$/)"
52643
+ },
52644
+ description: {
52645
+ type: "string",
52646
+ description: "What the tool does"
52647
+ },
52648
+ displayName: {
52649
+ type: "string",
52650
+ description: "Optional human-readable display name"
52651
+ },
52652
+ inputSchema: {
52653
+ type: "object",
52654
+ description: "JSON Schema for input parameters"
52655
+ },
52656
+ outputSchema: {
52657
+ type: "object",
52658
+ description: "Optional JSON Schema for output"
52659
+ },
52660
+ code: {
52661
+ type: "string",
52662
+ description: "JavaScript code (same sandbox as execute_javascript)"
52663
+ },
52664
+ tags: {
52665
+ type: "array",
52666
+ description: "Tags for categorization",
52667
+ items: { type: "string" }
52668
+ },
52669
+ category: {
52670
+ type: "string",
52671
+ description: "Category grouping"
52672
+ },
52673
+ generationPrompt: {
52674
+ type: "string",
52675
+ description: "The prompt that was used to generate this tool (for reference)"
52676
+ },
52677
+ connectorNames: {
52678
+ type: "array",
52679
+ description: "Connector names this tool uses",
52680
+ items: { type: "string" }
52681
+ }
52682
+ },
52683
+ required: ["name", "description", "inputSchema", "code"]
52684
+ }
52685
+ }
52686
+ },
52687
+ permission: { scope: "session", riskLevel: "medium" },
52688
+ execute: async (args) => {
52689
+ try {
52690
+ const now = (/* @__PURE__ */ new Date()).toISOString();
52691
+ const existing = await storage.load(args.name);
52692
+ const definition = {
52693
+ version: CUSTOM_TOOL_DEFINITION_VERSION,
52694
+ name: args.name,
52695
+ displayName: args.displayName,
52696
+ description: args.description,
52697
+ inputSchema: args.inputSchema,
52698
+ outputSchema: args.outputSchema,
52699
+ code: args.code,
52700
+ createdAt: existing?.createdAt ?? now,
52701
+ updatedAt: now,
52702
+ metadata: {
52703
+ tags: args.tags,
52704
+ category: args.category,
52705
+ generationPrompt: args.generationPrompt,
52706
+ connectorNames: args.connectorNames,
52707
+ requiresConnector: (args.connectorNames?.length ?? 0) > 0
52708
+ }
52709
+ };
52710
+ await storage.save(definition);
52711
+ return {
52712
+ success: true,
52713
+ name: args.name,
52714
+ storagePath: storage.getPath()
52715
+ };
52716
+ } catch (error) {
52717
+ return {
52718
+ success: false,
52719
+ name: args.name,
52720
+ storagePath: storage.getPath(),
52721
+ error: error.message
52722
+ };
52723
+ }
52724
+ },
52725
+ describeCall: (args) => args.name
52726
+ };
52727
+ }
52728
+ var customToolSave = createCustomToolSave(new FileCustomToolStorage());
52729
+
52730
+ // src/tools/custom-tools/customToolTest.ts
52731
+ init_Connector();
52732
+ var DEFAULT_TEST_TIMEOUT = 1e4;
52733
+ var MAX_TEST_TIMEOUT = 3e4;
52734
+ function createCustomToolTest() {
52735
+ return {
52736
+ definition: {
52737
+ type: "function",
52738
+ function: {
52739
+ name: "custom_tool_test",
52740
+ description: "Test custom tool code by executing it in the VM sandbox with provided test input.",
52741
+ parameters: {
52742
+ type: "object",
52743
+ properties: {
52744
+ code: {
52745
+ type: "string",
52746
+ description: "JavaScript code to test. See tool description for full sandbox API reference."
52747
+ },
52748
+ inputSchema: {
52749
+ type: "object",
52750
+ description: "The input schema (for documentation, not enforced at test time)"
52751
+ },
52752
+ testInput: {
52753
+ description: "Test input data \u2014 available as `input` in the code"
52754
+ },
52755
+ connectorName: {
52756
+ type: "string",
52757
+ description: "Optional connector name for authenticated API access"
52758
+ },
52759
+ timeout: {
52760
+ type: "number",
52761
+ description: `Execution timeout in ms. Default: ${DEFAULT_TEST_TIMEOUT}, max: ${MAX_TEST_TIMEOUT}`
52762
+ }
52763
+ },
52764
+ required: ["code", "inputSchema", "testInput"]
52765
+ }
52766
+ },
52767
+ timeout: MAX_TEST_TIMEOUT + 5e3
52768
+ },
52769
+ descriptionFactory: (context) => buildTestDescription(context),
52770
+ permission: { scope: "session", riskLevel: "medium" },
52771
+ execute: async (args, context) => {
52772
+ const logs = [];
52773
+ const startTime = Date.now();
52774
+ const timeout = Math.min(Math.max(args.timeout || DEFAULT_TEST_TIMEOUT, 0), MAX_TEST_TIMEOUT);
52775
+ try {
52776
+ const registry = context?.connectorRegistry ?? exports.Connector.asRegistry();
52777
+ const result = await executeInVM(
52778
+ args.code,
52779
+ args.testInput,
52780
+ timeout,
52781
+ logs,
52782
+ context?.userId,
52783
+ registry
52784
+ );
52785
+ return {
52786
+ success: true,
52787
+ result,
52788
+ logs,
52789
+ executionTime: Date.now() - startTime
52790
+ };
52791
+ } catch (error) {
52792
+ return {
52793
+ success: false,
52794
+ result: null,
52795
+ logs,
52796
+ error: error.message,
52797
+ executionTime: Date.now() - startTime
52798
+ };
52799
+ }
52800
+ },
52801
+ describeCall: (args) => `testing code (${args.code.length} chars)`
52802
+ };
52803
+ }
52804
+ var customToolTest = createCustomToolTest();
52805
+
52039
52806
  // src/tools/registry.generated.ts
52040
52807
  var toolRegistry = [
52041
52808
  {
@@ -52047,6 +52814,60 @@ var toolRegistry = [
52047
52814
  tool: executeJavaScript,
52048
52815
  safeByDefault: false
52049
52816
  },
52817
+ {
52818
+ name: "custom_tool_delete",
52819
+ exportName: "customToolDelete",
52820
+ displayName: "Custom Tool Delete",
52821
+ category: "custom-tools",
52822
+ description: "Delete a custom tool from persistent storage.",
52823
+ tool: customToolDelete,
52824
+ safeByDefault: false
52825
+ },
52826
+ {
52827
+ name: "custom_tool_draft",
52828
+ exportName: "customToolDraft",
52829
+ displayName: "Custom Tool Draft",
52830
+ category: "custom-tools",
52831
+ description: "Validate a draft custom tool definition. Checks name format, schema structure, and code syntax.",
52832
+ tool: customToolDraft,
52833
+ safeByDefault: true
52834
+ },
52835
+ {
52836
+ name: "custom_tool_list",
52837
+ exportName: "customToolList",
52838
+ displayName: "Custom Tool List",
52839
+ category: "custom-tools",
52840
+ description: "List saved custom tools from persistent storage. Supports filtering by search text, tags, and category.",
52841
+ tool: customToolList,
52842
+ safeByDefault: true
52843
+ },
52844
+ {
52845
+ name: "custom_tool_load",
52846
+ exportName: "customToolLoad",
52847
+ displayName: "Custom Tool Load",
52848
+ category: "custom-tools",
52849
+ description: "Load a full custom tool definition from storage (including code).",
52850
+ tool: customToolLoad,
52851
+ safeByDefault: true
52852
+ },
52853
+ {
52854
+ name: "custom_tool_save",
52855
+ exportName: "customToolSave",
52856
+ displayName: "Custom Tool Save",
52857
+ category: "custom-tools",
52858
+ description: "Save a custom tool definition to persistent storage.",
52859
+ tool: customToolSave,
52860
+ safeByDefault: false
52861
+ },
52862
+ {
52863
+ name: "custom_tool_test",
52864
+ exportName: "customToolTest",
52865
+ displayName: "Custom Tool Test",
52866
+ category: "custom-tools",
52867
+ description: "Test custom tool code by executing it in the VM sandbox with provided test input.",
52868
+ tool: customToolTest,
52869
+ safeByDefault: false
52870
+ },
52050
52871
  {
52051
52872
  name: "desktop_get_cursor",
52052
52873
  exportName: "desktopGetCursor",
@@ -52247,6 +53068,61 @@ function getToolCategories() {
52247
53068
  return [...new Set(toolRegistry.map((entry) => entry.category))];
52248
53069
  }
52249
53070
 
53071
+ // src/tools/custom-tools/factories.ts
53072
+ function createCustomToolMetaTools(options) {
53073
+ const storage = options?.storage ?? new FileCustomToolStorage();
53074
+ return [
53075
+ createCustomToolDraft(),
53076
+ createCustomToolTest(),
53077
+ createCustomToolSave(storage),
53078
+ createCustomToolList(storage),
53079
+ createCustomToolLoad(storage),
53080
+ createCustomToolDelete(storage)
53081
+ ];
53082
+ }
53083
+
53084
+ // src/tools/custom-tools/hydrate.ts
53085
+ init_Connector();
53086
+ var DEFAULT_TIMEOUT2 = 1e4;
53087
+ var MAX_TIMEOUT = 3e4;
53088
+ function hydrateCustomTool(definition, options) {
53089
+ const defaultTimeout = options?.defaultTimeout ?? DEFAULT_TIMEOUT2;
53090
+ const maxTimeout = options?.maxTimeout ?? MAX_TIMEOUT;
53091
+ return {
53092
+ definition: {
53093
+ type: "function",
53094
+ function: {
53095
+ name: definition.name,
53096
+ description: definition.description,
53097
+ parameters: definition.inputSchema
53098
+ },
53099
+ timeout: maxTimeout + 5e3
53100
+ },
53101
+ permission: { scope: "session", riskLevel: "medium" },
53102
+ execute: async (args, context) => {
53103
+ const logs = [];
53104
+ const registry = context?.connectorRegistry ?? exports.Connector.asRegistry();
53105
+ const result = await executeInVM(
53106
+ definition.code,
53107
+ args,
53108
+ defaultTimeout,
53109
+ logs,
53110
+ context?.userId,
53111
+ registry
53112
+ );
53113
+ return result;
53114
+ },
53115
+ describeCall: (args) => {
53116
+ if (!args || typeof args !== "object") return definition.name;
53117
+ const firstKey = Object.keys(args)[0];
53118
+ if (!firstKey) return definition.name;
53119
+ const val = args[firstKey];
53120
+ const str = typeof val === "string" ? val : JSON.stringify(val);
53121
+ return str.length > 50 ? str.slice(0, 47) + "..." : str;
53122
+ }
53123
+ };
53124
+ }
53125
+
52250
53126
  // src/tools/ToolRegistry.ts
52251
53127
  init_Connector();
52252
53128
  var ToolRegistry = class {
@@ -52596,6 +53472,7 @@ exports.BaseTextProvider = BaseTextProvider;
52596
53472
  exports.BraveProvider = BraveProvider;
52597
53473
  exports.CONNECTOR_CONFIG_VERSION = CONNECTOR_CONFIG_VERSION;
52598
53474
  exports.CONTEXT_SESSION_FORMAT_VERSION = CONTEXT_SESSION_FORMAT_VERSION;
53475
+ exports.CUSTOM_TOOL_DEFINITION_VERSION = CUSTOM_TOOL_DEFINITION_VERSION;
52599
53476
  exports.CheckpointManager = CheckpointManager;
52600
53477
  exports.ConnectorConfigStore = ConnectorConfigStore;
52601
53478
  exports.ConnectorTools = ConnectorTools;
@@ -52623,6 +53500,7 @@ exports.ExternalDependencyHandler = ExternalDependencyHandler;
52623
53500
  exports.FileAgentDefinitionStorage = FileAgentDefinitionStorage;
52624
53501
  exports.FileConnectorStorage = FileConnectorStorage;
52625
53502
  exports.FileContextStorage = FileContextStorage;
53503
+ exports.FileCustomToolStorage = FileCustomToolStorage;
52626
53504
  exports.FileMediaOutputHandler = FileMediaStorage;
52627
53505
  exports.FileMediaStorage = FileMediaStorage;
52628
53506
  exports.FilePersistentInstructionsStorage = FilePersistentInstructionsStorage;
@@ -52733,6 +53611,13 @@ exports.createAuthenticatedFetch = createAuthenticatedFetch;
52733
53611
  exports.createBashTool = createBashTool;
52734
53612
  exports.createConnectorFromTemplate = createConnectorFromTemplate;
52735
53613
  exports.createCreatePRTool = createCreatePRTool;
53614
+ exports.createCustomToolDelete = createCustomToolDelete;
53615
+ exports.createCustomToolDraft = createCustomToolDraft;
53616
+ exports.createCustomToolList = createCustomToolList;
53617
+ exports.createCustomToolLoad = createCustomToolLoad;
53618
+ exports.createCustomToolMetaTools = createCustomToolMetaTools;
53619
+ exports.createCustomToolSave = createCustomToolSave;
53620
+ exports.createCustomToolTest = createCustomToolTest;
52736
53621
  exports.createDesktopGetCursorTool = createDesktopGetCursorTool;
52737
53622
  exports.createDesktopGetScreenSizeTool = createDesktopGetScreenSizeTool;
52738
53623
  exports.createDesktopKeyboardKeyTool = createDesktopKeyboardKeyTool;
@@ -52749,6 +53634,7 @@ exports.createEstimator = createEstimator;
52749
53634
  exports.createExecuteJavaScriptTool = createExecuteJavaScriptTool;
52750
53635
  exports.createFileAgentDefinitionStorage = createFileAgentDefinitionStorage;
52751
53636
  exports.createFileContextStorage = createFileContextStorage;
53637
+ exports.createFileCustomToolStorage = createFileCustomToolStorage;
52752
53638
  exports.createFileMediaStorage = createFileMediaStorage;
52753
53639
  exports.createGetPRTool = createGetPRTool;
52754
53640
  exports.createGitHubReadFileTool = createGitHubReadFileTool;
@@ -52773,6 +53659,12 @@ exports.createTextToSpeechTool = createTextToSpeechTool;
52773
53659
  exports.createVideoProvider = createVideoProvider;
52774
53660
  exports.createVideoTools = createVideoTools;
52775
53661
  exports.createWriteFileTool = createWriteFileTool;
53662
+ exports.customToolDelete = customToolDelete;
53663
+ exports.customToolDraft = customToolDraft;
53664
+ exports.customToolList = customToolList;
53665
+ exports.customToolLoad = customToolLoad;
53666
+ exports.customToolSave = customToolSave;
53667
+ exports.customToolTest = customToolTest;
52776
53668
  exports.defaultDescribeCall = defaultDescribeCall;
52777
53669
  exports.desktopGetCursor = desktopGetCursor;
52778
53670
  exports.desktopGetScreenSize = desktopGetScreenSize;
@@ -52857,6 +53749,7 @@ exports.globalErrorHandler = globalErrorHandler;
52857
53749
  exports.grep = grep;
52858
53750
  exports.hasClipboardImage = hasClipboardImage;
52859
53751
  exports.hasVendorLogo = hasVendorLogo;
53752
+ exports.hydrateCustomTool = hydrateCustomTool;
52860
53753
  exports.isBlockedCommand = isBlockedCommand;
52861
53754
  exports.isErrorEvent = isErrorEvent;
52862
53755
  exports.isExcludedExtension = isExcludedExtension;