@easynet/agent-tool-buildin 0.0.1 → 0.0.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.js CHANGED
@@ -150,7 +150,10 @@ function isWithinRoot(path, root) {
150
150
  import { createTaggedError as createTaggedError2 } from "@easynet/agent-tool";
151
151
  var readTextHandler = (async (args) => {
152
152
  const ctx = getBuiltinContext();
153
- const inputPath = args.path;
153
+ const inputPath = (args.path ?? args.filePath)?.trim();
154
+ if (!inputPath) {
155
+ throw createTaggedError2("FS_INVALID", "path is required (pass 'path' or 'filePath')", {});
156
+ }
154
157
  const maxBytes = args.maxBytes ?? ctx.config.maxReadBytes;
155
158
  const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
156
159
  const fileStat = await stat(resolvedPath);
@@ -185,8 +188,11 @@ import { createHash } from "crypto";
185
188
  import { dirname as dirname2 } from "path";
186
189
  var writeTextHandler = (async (args) => {
187
190
  const ctx = getBuiltinContext();
188
- const inputPath = args.path;
189
- const text = args.text;
191
+ const inputPath = (args.path ?? args.filePath)?.trim();
192
+ if (!inputPath) {
193
+ throw new Error("path is required (pass 'path' or 'filePath')");
194
+ }
195
+ const text = args.text ?? args.content ?? "";
190
196
  const overwrite = args.overwrite ?? false;
191
197
  const mkdirp = args.mkdirp ?? true;
192
198
  const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
@@ -232,7 +238,10 @@ import { readdir, stat as stat2 } from "fs/promises";
232
238
  import { resolve as resolve2, join } from "path";
233
239
  var listDirHandler = (async (args) => {
234
240
  const ctx = getBuiltinContext();
235
- const inputPath = args.path;
241
+ const inputPath = (args.path ?? args.filePath ?? args.dir ?? args.directory)?.trim();
242
+ if (!inputPath) {
243
+ throw new Error("path is required (pass 'path', 'filePath', 'dir', or 'directory')");
244
+ }
236
245
  const maxEntries = args.maxEntries ?? 2e3;
237
246
  const includeHidden = args.includeHidden ?? false;
238
247
  const recursive = args.recursive ?? false;
@@ -324,8 +333,14 @@ import { createInterface } from "readline";
324
333
  import { join as join2, relative } from "path";
325
334
  var searchTextHandler = (async (args) => {
326
335
  const ctx = getBuiltinContext();
327
- const rootPath = args.root;
328
- const query = args.query;
336
+ const rootPath = (args.root ?? args.path ?? args.dir ?? args.directory)?.trim();
337
+ if (!rootPath) {
338
+ throw new Error("root is required (pass 'root', 'path', 'dir', or 'directory')");
339
+ }
340
+ const query = (args.query ?? args.q)?.trim();
341
+ if (!query) {
342
+ throw new Error("query is required (pass 'query' or 'q')");
343
+ }
329
344
  const glob = args.glob ?? "**/*.{md,txt,log,json,ts,js,py,java,scala}";
330
345
  const maxMatches = args.maxMatches ?? 100;
331
346
  const maxFiles = args.maxFiles ?? 500;
@@ -444,9 +459,13 @@ function escapeRegExp(str) {
444
459
  import { createReadStream as createReadStream2 } from "fs";
445
460
  import { stat as stat4 } from "fs/promises";
446
461
  import { createHash as createHash2 } from "crypto";
462
+ import { createTaggedError as createTaggedError3 } from "@easynet/agent-tool";
447
463
  var sha256Handler = (async (args) => {
448
464
  const ctx = getBuiltinContext();
449
- const inputPath = args.path;
465
+ const inputPath = (args.path ?? args.filePath)?.trim();
466
+ if (!inputPath) {
467
+ throw createTaggedError3("FS_INVALID", "path is required (pass 'path' or 'filePath')", {});
468
+ }
450
469
  const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
451
470
  const fileStat = await stat4(resolvedPath);
452
471
  const hash = await new Promise((resolve3, reject) => {
@@ -477,7 +496,10 @@ var sha256Handler = (async (args) => {
477
496
  import { rm, unlink, rmdir, stat as stat5 } from "fs/promises";
478
497
  var deletePathHandler = (async (args) => {
479
498
  const ctx = getBuiltinContext();
480
- const inputPath = args.path;
499
+ const inputPath = (args.path ?? args.filePath)?.trim();
500
+ if (!inputPath) {
501
+ throw new Error("path is required (pass 'path' or 'filePath')");
502
+ }
481
503
  const recursive = args.recursive ?? false;
482
504
  const confirm = args.confirm;
483
505
  if (!confirm) {
@@ -526,20 +548,20 @@ var deletePathHandler = (async (args) => {
526
548
 
527
549
  // security/ssrf.ts
528
550
  import { lookup } from "dns/promises";
529
- import { createTaggedError as createTaggedError3 } from "@easynet/agent-tool";
551
+ import { createTaggedError as createTaggedError4 } from "@easynet/agent-tool";
530
552
  async function validateUrl(url, allowedHosts, blockedCidrs) {
531
553
  let parsed;
532
554
  try {
533
555
  parsed = new URL(url);
534
556
  } catch {
535
- throw createTaggedError3(
557
+ throw createTaggedError4(
536
558
  "HTTP_DISALLOWED_HOST",
537
559
  `Invalid URL: ${url}`,
538
560
  { url }
539
561
  );
540
562
  }
541
563
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
542
- throw createTaggedError3(
564
+ throw createTaggedError4(
543
565
  "HTTP_DISALLOWED_HOST",
544
566
  `Protocol not allowed: ${parsed.protocol}. Only http: and https: are supported.`,
545
567
  { url, protocol: parsed.protocol }
@@ -547,7 +569,7 @@ async function validateUrl(url, allowedHosts, blockedCidrs) {
547
569
  }
548
570
  const hostname = parsed.hostname;
549
571
  if (!isHostAllowed(hostname, allowedHosts)) {
550
- throw createTaggedError3(
572
+ throw createTaggedError4(
551
573
  "HTTP_DISALLOWED_HOST",
552
574
  `Host "${hostname}" is not in the allowed hosts list`,
553
575
  { url, hostname, allowedHosts }
@@ -556,7 +578,7 @@ async function validateUrl(url, allowedHosts, blockedCidrs) {
556
578
  try {
557
579
  const { address } = await lookup(hostname);
558
580
  if (isIpInBlockedCidrs(address, blockedCidrs)) {
559
- throw createTaggedError3(
581
+ throw createTaggedError4(
560
582
  "HTTP_DISALLOWED_HOST",
561
583
  `Host "${hostname}" resolves to blocked IP: ${address}`,
562
584
  { url, hostname, resolvedIp: address }
@@ -566,7 +588,7 @@ async function validateUrl(url, allowedHosts, blockedCidrs) {
566
588
  if (err instanceof Error && err.kind === "HTTP_DISALLOWED_HOST") {
567
589
  throw err;
568
590
  }
569
- throw createTaggedError3(
591
+ throw createTaggedError4(
570
592
  "HTTP_DISALLOWED_HOST",
571
593
  `DNS resolution failed for host "${hostname}": ${err instanceof Error ? err.message : String(err)}`,
572
594
  { url, hostname }
@@ -677,10 +699,13 @@ function expandIpv6(ip) {
677
699
  }
678
700
 
679
701
  // http/fetchText.ts
680
- import { createTaggedError as createTaggedError4 } from "@easynet/agent-tool";
702
+ import { createTaggedError as createTaggedError5 } from "@easynet/agent-tool";
681
703
  var fetchTextHandler = (async (args) => {
682
704
  const ctx = getBuiltinContext();
683
- const url = args.url;
705
+ const url = (args.url ?? args.uri)?.trim();
706
+ if (!url) {
707
+ throw createTaggedError5("HTTP_INVALID", "url is required (pass 'url' or 'uri')", {});
708
+ }
684
709
  const method = args.method ?? "GET";
685
710
  const headers = args.headers ?? {};
686
711
  const body = args.body ?? void 0;
@@ -702,13 +727,13 @@ var fetchTextHandler = (async (args) => {
702
727
  });
703
728
  } catch (err) {
704
729
  if (err instanceof Error && err.name === "AbortError") {
705
- throw createTaggedError4(
730
+ throw createTaggedError5(
706
731
  "HTTP_TIMEOUT",
707
732
  `Request to ${url} timed out after ${timeoutMs}ms`,
708
733
  { url, timeoutMs }
709
734
  );
710
735
  }
711
- throw createTaggedError4(
736
+ throw createTaggedError5(
712
737
  "UPSTREAM_ERROR",
713
738
  `Fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
714
739
  { url }
@@ -718,7 +743,7 @@ var fetchTextHandler = (async (args) => {
718
743
  }
719
744
  const contentLength = response.headers.get("content-length");
720
745
  if (contentLength && parseInt(contentLength, 10) > maxBytes) {
721
- throw createTaggedError4(
746
+ throw createTaggedError5(
722
747
  "HTTP_TOO_LARGE",
723
748
  `Response Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
724
749
  { url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
@@ -763,7 +788,7 @@ async function readResponseWithLimit(response, maxBytes, url) {
763
788
  totalBytes += value.byteLength;
764
789
  if (totalBytes > maxBytes) {
765
790
  reader.cancel();
766
- throw createTaggedError4(
791
+ throw createTaggedError5(
767
792
  "HTTP_TOO_LARGE",
768
793
  `Response body exceeded limit of ${maxBytes} bytes while reading from ${url}`,
769
794
  { url, bytesRead: totalBytes, limit: maxBytes }
@@ -779,10 +804,13 @@ async function readResponseWithLimit(response, maxBytes, url) {
779
804
  }
780
805
 
781
806
  // http/fetchJson.ts
782
- import { createTaggedError as createTaggedError5 } from "@easynet/agent-tool";
807
+ import { createTaggedError as createTaggedError6 } from "@easynet/agent-tool";
783
808
  var fetchJsonHandler = (async (args) => {
784
809
  const ctx = getBuiltinContext();
785
- const url = args.url;
810
+ const url = (args.url ?? args.uri)?.trim();
811
+ if (!url) {
812
+ throw createTaggedError6("HTTP_INVALID", "url is required (pass 'url' or 'uri')", {});
813
+ }
786
814
  const method = args.method ?? "GET";
787
815
  const headers = args.headers ?? {};
788
816
  const body = args.body ?? void 0;
@@ -807,13 +835,13 @@ var fetchJsonHandler = (async (args) => {
807
835
  });
808
836
  } catch (err) {
809
837
  if (err instanceof Error && err.name === "AbortError") {
810
- throw createTaggedError5(
838
+ throw createTaggedError6(
811
839
  "HTTP_TIMEOUT",
812
840
  `Request to ${url} timed out after ${timeoutMs}ms`,
813
841
  { url, timeoutMs }
814
842
  );
815
843
  }
816
- throw createTaggedError5(
844
+ throw createTaggedError6(
817
845
  "UPSTREAM_ERROR",
818
846
  `Fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
819
847
  { url }
@@ -823,7 +851,7 @@ var fetchJsonHandler = (async (args) => {
823
851
  }
824
852
  const contentLength = response.headers.get("content-length");
825
853
  if (contentLength && parseInt(contentLength, 10) > maxBytes) {
826
- throw createTaggedError5(
854
+ throw createTaggedError6(
827
855
  "HTTP_TOO_LARGE",
828
856
  `Response Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
829
857
  { url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
@@ -832,7 +860,7 @@ var fetchJsonHandler = (async (args) => {
832
860
  const text = await response.text();
833
861
  const bytes = Buffer.byteLength(text, "utf-8");
834
862
  if (bytes > maxBytes) {
835
- throw createTaggedError5(
863
+ throw createTaggedError6(
836
864
  "HTTP_TOO_LARGE",
837
865
  `Response body ${bytes} bytes exceeds limit of ${maxBytes} bytes`,
838
866
  { url, bytes, limit: maxBytes }
@@ -842,7 +870,7 @@ var fetchJsonHandler = (async (args) => {
842
870
  try {
843
871
  json = JSON.parse(text);
844
872
  } catch {
845
- throw createTaggedError5(
873
+ throw createTaggedError6(
846
874
  "UPSTREAM_ERROR",
847
875
  `Failed to parse JSON response from ${url}: ${text.slice(0, 200)}`,
848
876
  { url, status: response.status, textPreview: text.slice(0, 500) }
@@ -870,11 +898,17 @@ var fetchJsonHandler = (async (args) => {
870
898
  import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
871
899
  import { createHash as createHash3 } from "crypto";
872
900
  import { dirname as dirname3 } from "path";
873
- import { createTaggedError as createTaggedError6 } from "@easynet/agent-tool";
901
+ import { createTaggedError as createTaggedError7 } from "@easynet/agent-tool";
874
902
  var downloadFileHandler = (async (args) => {
875
903
  const ctx = getBuiltinContext();
876
- const url = args.url;
877
- const destPath = args.destPath;
904
+ const url = (args.url ?? args.uri)?.trim();
905
+ if (!url) {
906
+ throw createTaggedError7("HTTP_INVALID", "url is required (pass 'url' or 'uri')", {});
907
+ }
908
+ const destPath = (args.destPath ?? args.destination ?? args.filePath)?.trim();
909
+ if (!destPath) {
910
+ throw createTaggedError7("HTTP_INVALID", "destPath is required (pass 'destPath', 'destination', or 'filePath')", {});
911
+ }
878
912
  const headers = args.headers ?? {};
879
913
  const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
880
914
  const maxBytes = args.maxBytes ?? ctx.config.maxDownloadBytes;
@@ -909,13 +943,13 @@ var downloadFileHandler = (async (args) => {
909
943
  });
910
944
  } catch (err) {
911
945
  if (err instanceof Error && err.name === "AbortError") {
912
- throw createTaggedError6(
946
+ throw createTaggedError7(
913
947
  "HTTP_TIMEOUT",
914
948
  `Download from ${url} timed out after ${timeoutMs}ms`,
915
949
  { url, timeoutMs }
916
950
  );
917
951
  }
918
- throw createTaggedError6(
952
+ throw createTaggedError7(
919
953
  "UPSTREAM_ERROR",
920
954
  `Download failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
921
955
  { url }
@@ -925,14 +959,14 @@ var downloadFileHandler = (async (args) => {
925
959
  }
926
960
  const contentLength = response.headers.get("content-length");
927
961
  if (contentLength && parseInt(contentLength, 10) > maxBytes) {
928
- throw createTaggedError6(
962
+ throw createTaggedError7(
929
963
  "HTTP_TOO_LARGE",
930
964
  `Download Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
931
965
  { url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
932
966
  );
933
967
  }
934
968
  if (!response.body) {
935
- throw createTaggedError6("UPSTREAM_ERROR", `No response body from ${url}`, { url });
969
+ throw createTaggedError7("UPSTREAM_ERROR", `No response body from ${url}`, { url });
936
970
  }
937
971
  const reader = response.body.getReader();
938
972
  const chunks = [];
@@ -945,7 +979,7 @@ var downloadFileHandler = (async (args) => {
945
979
  totalBytes += value.byteLength;
946
980
  if (totalBytes > maxBytes) {
947
981
  reader.cancel();
948
- throw createTaggedError6(
982
+ throw createTaggedError7(
949
983
  "HTTP_TOO_LARGE",
950
984
  `Download from ${url} exceeded limit of ${maxBytes} bytes (received ${totalBytes})`,
951
985
  { url, bytesRead: totalBytes, limit: maxBytes }
@@ -987,10 +1021,13 @@ var downloadFileHandler = (async (args) => {
987
1021
  });
988
1022
 
989
1023
  // http/head.ts
990
- import { createTaggedError as createTaggedError7 } from "@easynet/agent-tool";
1024
+ import { createTaggedError as createTaggedError8 } from "@easynet/agent-tool";
991
1025
  var headHandler = (async (args) => {
992
1026
  const ctx = getBuiltinContext();
993
- const url = args.url;
1027
+ const url = (args.url ?? args.uri)?.trim();
1028
+ if (!url) {
1029
+ throw createTaggedError8("HTTP_INVALID", "url is required (pass 'url' or 'uri')", {});
1030
+ }
994
1031
  const headers = args.headers ?? {};
995
1032
  const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
996
1033
  await validateUrl(url, ctx.config.allowedHosts, ctx.config.blockedCidrs);
@@ -1008,13 +1045,13 @@ var headHandler = (async (args) => {
1008
1045
  });
1009
1046
  } catch (err) {
1010
1047
  if (err instanceof Error && err.name === "AbortError") {
1011
- throw createTaggedError7(
1048
+ throw createTaggedError8(
1012
1049
  "HTTP_TIMEOUT",
1013
1050
  `HEAD request to ${url} timed out after ${timeoutMs}ms`,
1014
1051
  { url, timeoutMs }
1015
1052
  );
1016
1053
  }
1017
- throw createTaggedError7(
1054
+ throw createTaggedError8(
1018
1055
  "UPSTREAM_ERROR",
1019
1056
  `HEAD request failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
1020
1057
  { url }
@@ -1044,13 +1081,13 @@ var headHandler = (async (args) => {
1044
1081
  });
1045
1082
 
1046
1083
  // http/duckduckgoSearch.ts
1047
- import { createTaggedError as createTaggedError8 } from "@easynet/agent-tool";
1084
+ import { createTaggedError as createTaggedError9 } from "@easynet/agent-tool";
1048
1085
  var DUCKDUCKGO_API = "https://api.duckduckgo.com/";
1049
1086
  var duckduckgoSearchHandler = (async (args) => {
1050
1087
  const ctx = getBuiltinContext();
1051
- const query = args.query?.trim();
1088
+ const query = (args.query ?? args.q)?.trim();
1052
1089
  if (!query) {
1053
- throw createTaggedError8("DUCKDUCKGO_INVALID", "query is required", {});
1090
+ throw createTaggedError9("DUCKDUCKGO_INVALID", "query is required (pass 'query' or 'q')", {});
1054
1091
  }
1055
1092
  const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
1056
1093
  const maxResults = args.maxResults ?? 10;
@@ -1068,13 +1105,13 @@ var duckduckgoSearchHandler = (async (args) => {
1068
1105
  } catch (err) {
1069
1106
  clearTimeout(timer);
1070
1107
  if (err instanceof Error && err.name === "AbortError") {
1071
- throw createTaggedError8(
1108
+ throw createTaggedError9(
1072
1109
  "HTTP_TIMEOUT",
1073
1110
  `DuckDuckGo search timed out after ${timeoutMs}ms`,
1074
1111
  { query, timeoutMs }
1075
1112
  );
1076
1113
  }
1077
- throw createTaggedError8(
1114
+ throw createTaggedError9(
1078
1115
  "UPSTREAM_ERROR",
1079
1116
  `DuckDuckGo search failed: ${err instanceof Error ? err.message : String(err)}`,
1080
1117
  { query }
@@ -1085,7 +1122,7 @@ var duckduckgoSearchHandler = (async (args) => {
1085
1122
  const text = await response.text();
1086
1123
  const bytes = Buffer.byteLength(text, "utf-8");
1087
1124
  if (bytes > maxBytes) {
1088
- throw createTaggedError8(
1125
+ throw createTaggedError9(
1089
1126
  "HTTP_TOO_LARGE",
1090
1127
  `DuckDuckGo response ${bytes} bytes exceeds limit of ${maxBytes} bytes`,
1091
1128
  { query, bytes, limit: maxBytes }
@@ -1095,7 +1132,7 @@ var duckduckgoSearchHandler = (async (args) => {
1095
1132
  try {
1096
1133
  raw = JSON.parse(text);
1097
1134
  } catch {
1098
- throw createTaggedError8(
1135
+ throw createTaggedError9(
1099
1136
  "UPSTREAM_ERROR",
1100
1137
  `DuckDuckGo returned invalid JSON`,
1101
1138
  { query, textPreview: text.slice(0, 200) }
@@ -1146,7 +1183,7 @@ var duckduckgoSearchHandler = (async (args) => {
1146
1183
 
1147
1184
  // http/fetchPageMainContent.ts
1148
1185
  import { parse } from "node-html-parser";
1149
- import { createTaggedError as createTaggedError9 } from "@easynet/agent-tool";
1186
+ import { createTaggedError as createTaggedError10 } from "@easynet/agent-tool";
1150
1187
  var MAIN_SELECTORS = [
1151
1188
  "main",
1152
1189
  "article",
@@ -1187,7 +1224,10 @@ function extractMainContent(html) {
1187
1224
  }
1188
1225
  var fetchPageMainContentHandler = (async (args) => {
1189
1226
  const ctx = getBuiltinContext();
1190
- const url = args.url;
1227
+ const url = (args.url ?? args.uri)?.trim();
1228
+ if (!url) {
1229
+ throw createTaggedError10("HTTP_INVALID", "url is required (pass 'url' or 'uri')", {});
1230
+ }
1191
1231
  const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
1192
1232
  const maxBytes = args.maxBytes ?? ctx.config.maxHttpBytes;
1193
1233
  await validateUrl(url, ctx.config.allowedHosts, ctx.config.blockedCidrs);
@@ -1203,13 +1243,13 @@ var fetchPageMainContentHandler = (async (args) => {
1203
1243
  } catch (err) {
1204
1244
  clearTimeout(timer);
1205
1245
  if (err instanceof Error && err.name === "AbortError") {
1206
- throw createTaggedError9(
1246
+ throw createTaggedError10(
1207
1247
  "HTTP_TIMEOUT",
1208
1248
  `Request to ${url} timed out after ${timeoutMs}ms`,
1209
1249
  { url, timeoutMs }
1210
1250
  );
1211
1251
  }
1212
- throw createTaggedError9(
1252
+ throw createTaggedError10(
1213
1253
  "UPSTREAM_ERROR",
1214
1254
  `Fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
1215
1255
  { url }
@@ -1218,7 +1258,7 @@ var fetchPageMainContentHandler = (async (args) => {
1218
1258
  clearTimeout(timer);
1219
1259
  const contentLength = response.headers.get("content-length");
1220
1260
  if (contentLength && parseInt(contentLength, 10) > maxBytes) {
1221
- throw createTaggedError9(
1261
+ throw createTaggedError10(
1222
1262
  "HTTP_TOO_LARGE",
1223
1263
  `Response Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
1224
1264
  { url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
@@ -1227,7 +1267,7 @@ var fetchPageMainContentHandler = (async (args) => {
1227
1267
  const rawText = await response.text();
1228
1268
  const rawBytes = Buffer.byteLength(rawText, "utf-8");
1229
1269
  if (rawBytes > maxBytes) {
1230
- throw createTaggedError9(
1270
+ throw createTaggedError10(
1231
1271
  "HTTP_TOO_LARGE",
1232
1272
  `Response body ${rawBytes} bytes exceeds limit of ${maxBytes} bytes`,
1233
1273
  { url, bytes: rawBytes, limit: maxBytes }
@@ -1269,10 +1309,133 @@ var fetchPageMainContentHandler = (async (args) => {
1269
1309
  };
1270
1310
  });
1271
1311
 
1312
+ // http/yahooFinance.ts
1313
+ import { createTaggedError as createTaggedError11 } from "@easynet/agent-tool";
1314
+ var YAHOO_CHART_BASE = "https://query1.finance.yahoo.com/v8/finance/chart/";
1315
+ var yahooFinanceQuoteHandler = (async (args) => {
1316
+ const ctx = getBuiltinContext();
1317
+ const rawSymbols = args.symbols ?? args.symbol ?? args.tickers;
1318
+ const symbols = Array.isArray(rawSymbols) ? rawSymbols.map((s) => String(s).trim().toUpperCase()).filter(Boolean) : rawSymbols != null ? [String(rawSymbols).trim().toUpperCase()].filter(Boolean) : [];
1319
+ if (symbols.length === 0) {
1320
+ throw createTaggedError11(
1321
+ "YAHOO_INVALID",
1322
+ "At least one symbol is required",
1323
+ {}
1324
+ );
1325
+ }
1326
+ const range = args.range ?? "1d";
1327
+ const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
1328
+ const maxBytes = ctx.config.maxHttpBytes;
1329
+ const quotes = [];
1330
+ for (const symbol of symbols) {
1331
+ const url2 = `${YAHOO_CHART_BASE}${encodeURIComponent(symbol)}?interval=1d&range=${range}`;
1332
+ await validateUrl(url2, ctx.config.allowedHosts, ctx.config.blockedCidrs);
1333
+ const controller = new AbortController();
1334
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
1335
+ let response;
1336
+ try {
1337
+ response = await fetch(url2, {
1338
+ method: "GET",
1339
+ headers: {
1340
+ "User-Agent": ctx.config.httpUserAgent,
1341
+ Accept: "application/json"
1342
+ },
1343
+ signal: controller.signal
1344
+ });
1345
+ } catch (err) {
1346
+ clearTimeout(timer);
1347
+ if (err instanceof Error && err.name === "AbortError") {
1348
+ throw createTaggedError11(
1349
+ "HTTP_TIMEOUT",
1350
+ `Yahoo Finance request for ${symbol} timed out after ${timeoutMs}ms`,
1351
+ { symbol, timeoutMs }
1352
+ );
1353
+ }
1354
+ throw createTaggedError11(
1355
+ "UPSTREAM_ERROR",
1356
+ `Yahoo Finance request failed: ${err instanceof Error ? err.message : String(err)}`,
1357
+ { symbol }
1358
+ );
1359
+ }
1360
+ clearTimeout(timer);
1361
+ const text = await response.text();
1362
+ const bytes = Buffer.byteLength(text, "utf-8");
1363
+ if (bytes > maxBytes) {
1364
+ throw createTaggedError11(
1365
+ "HTTP_TOO_LARGE",
1366
+ `Yahoo Finance response ${bytes} bytes exceeds limit of ${maxBytes} bytes`,
1367
+ { symbol, bytes, limit: maxBytes }
1368
+ );
1369
+ }
1370
+ let data;
1371
+ try {
1372
+ data = JSON.parse(text);
1373
+ } catch {
1374
+ throw createTaggedError11(
1375
+ "UPSTREAM_ERROR",
1376
+ "Yahoo Finance returned invalid JSON",
1377
+ { symbol, textPreview: text.slice(0, 200) }
1378
+ );
1379
+ }
1380
+ const error = data.chart?.error;
1381
+ if (error?.description) {
1382
+ throw createTaggedError11(
1383
+ "YAHOO_ERROR",
1384
+ `Yahoo Finance error for ${symbol}: ${error.description}`,
1385
+ { symbol, code: error.code }
1386
+ );
1387
+ }
1388
+ const result = data.chart?.result?.[0];
1389
+ if (!result) {
1390
+ quotes.push({ symbol });
1391
+ continue;
1392
+ }
1393
+ const meta = result.meta ?? {};
1394
+ const quoteArr = result.indicators?.quote?.[0];
1395
+ const lastIdx = (result.timestamp?.length ?? 1) - 1;
1396
+ const price = meta.regularMarketPrice ?? meta.previousClose ?? quoteArr?.close?.[lastIdx] ?? void 0;
1397
+ const previousClose = meta.previousClose ?? meta.chartPreviousClose ?? quoteArr?.close?.[Math.max(0, lastIdx - 1)] ?? void 0;
1398
+ const change = price != null && previousClose != null ? price - previousClose : void 0;
1399
+ const changePercent = change != null && previousClose != null && previousClose !== 0 ? change / previousClose * 100 : void 0;
1400
+ quotes.push({
1401
+ symbol: meta.symbol ?? symbol,
1402
+ currency: meta.currency,
1403
+ price: price ?? void 0,
1404
+ previousClose: previousClose ?? void 0,
1405
+ change,
1406
+ changePercent,
1407
+ open: quoteArr?.open?.[lastIdx] ?? void 0,
1408
+ high: quoteArr?.high?.[lastIdx] ?? void 0,
1409
+ low: quoteArr?.low?.[lastIdx] ?? void 0,
1410
+ volume: quoteArr?.volume?.[lastIdx] ?? void 0,
1411
+ timestamp: result.timestamp?.[lastIdx]
1412
+ });
1413
+ }
1414
+ const url = `${YAHOO_CHART_BASE}${encodeURIComponent(symbols[0])}?interval=1d&range=${range}`;
1415
+ return {
1416
+ result: {
1417
+ symbols: quotes.map((q) => q.symbol),
1418
+ quotes,
1419
+ range
1420
+ },
1421
+ evidence: [
1422
+ {
1423
+ type: "url",
1424
+ ref: url,
1425
+ summary: `Yahoo Finance quote: ${symbols.join(", ")} (${quotes.length} result(s))`,
1426
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1427
+ }
1428
+ ]
1429
+ };
1430
+ });
1431
+
1272
1432
  // util/jsonSelect.ts
1273
1433
  var jsonSelectHandler = (async (args) => {
1274
1434
  const json = args.json;
1275
- const path = args.path;
1435
+ const path = (args.path ?? args.expression)?.trim();
1436
+ if (path === void 0 || path === "") {
1437
+ throw new Error("path is required (pass 'path' or 'expression')");
1438
+ }
1276
1439
  let jmespath;
1277
1440
  try {
1278
1441
  jmespath = await import("./jmespath-6W7SK7AH.js");
@@ -1429,37 +1592,37 @@ var templateRenderHandler = (async (args) => {
1429
1592
  // exec/runCommand.ts
1430
1593
  import { spawn } from "child_process";
1431
1594
  import { resolve as pathResolve } from "path";
1432
- import { createTaggedError as createTaggedError10 } from "@easynet/agent-tool";
1595
+ import { createTaggedError as createTaggedError12 } from "@easynet/agent-tool";
1433
1596
  var runCommandHandler = (async (args) => {
1434
1597
  const ctx = getBuiltinContext();
1435
1598
  const { allowedCommands, maxCommandOutputBytes, commandTimeoutMs } = ctx.config;
1436
1599
  if (!allowedCommands.length) {
1437
- throw createTaggedError10(
1600
+ throw createTaggedError12(
1438
1601
  "EXEC_DISABLED",
1439
1602
  "Exec is disabled: allowedCommands is empty",
1440
1603
  {}
1441
1604
  );
1442
1605
  }
1443
- const rawCommand = args.command?.trim();
1606
+ const rawCommand = (args.command ?? args.cmd)?.trim();
1444
1607
  if (!rawCommand) {
1445
- throw createTaggedError10("EXEC_INVALID", "command is required", {});
1608
+ throw createTaggedError12("EXEC_INVALID", "command is required (pass 'command' or 'cmd')", {});
1446
1609
  }
1447
1610
  const baseName = rawCommand.replace(/^.*\//, "").trim();
1448
1611
  if (baseName !== rawCommand || /[;&|$`\s]/.test(rawCommand)) {
1449
- throw createTaggedError10(
1612
+ throw createTaggedError12(
1450
1613
  "EXEC_INVALID",
1451
1614
  "command must be a single executable name (no path, no shell chars)",
1452
1615
  { command: rawCommand }
1453
1616
  );
1454
1617
  }
1455
1618
  if (!allowedCommands.includes(baseName)) {
1456
- throw createTaggedError10(
1619
+ throw createTaggedError12(
1457
1620
  "EXEC_NOT_ALLOWED",
1458
1621
  `Command "${baseName}" is not in allowedCommands`,
1459
1622
  { command: baseName, allowed: allowedCommands }
1460
1623
  );
1461
1624
  }
1462
- const cmdArgs = Array.isArray(args.args) ? args.args : [];
1625
+ const cmdArgs = Array.isArray(args.args) ? args.args : Array.isArray(args.arguments) ? args.arguments : [];
1463
1626
  const timeoutMs = args.timeoutMs ?? commandTimeoutMs;
1464
1627
  let cwd = pathResolve(ctx.config.sandboxRoot);
1465
1628
  if (args.cwd != null && args.cwd !== "") {
@@ -1480,7 +1643,7 @@ var runCommandHandler = (async (args) => {
1480
1643
  if (totalBytes + len > maxCommandOutputBytes) {
1481
1644
  proc.kill("SIGKILL");
1482
1645
  rejectPromise(
1483
- createTaggedError10(
1646
+ createTaggedError12(
1484
1647
  "EXEC_OUTPUT_TOO_LARGE",
1485
1648
  `Command output exceeded ${maxCommandOutputBytes} bytes`,
1486
1649
  { maxBytes: maxCommandOutputBytes }
@@ -1518,7 +1681,7 @@ var runCommandHandler = (async (args) => {
1518
1681
  proc.on("error", (err) => {
1519
1682
  clearTimeout(timeout);
1520
1683
  rejectPromise(
1521
- createTaggedError10("EXEC_SPAWN_ERROR", err.message, { command: baseName })
1684
+ createTaggedError12("EXEC_SPAWN_ERROR", err.message, { command: baseName })
1522
1685
  );
1523
1686
  });
1524
1687
  proc.on("close", (code, signal) => {
@@ -1550,7 +1713,7 @@ var CORE_TOOL_MANIFEST = [
1550
1713
  {
1551
1714
  name: "core/fs.readText",
1552
1715
  kind: "core",
1553
- description: "Read a UTF-8 text file from the sandbox",
1716
+ description: "Read a UTF-8 text file from the sandbox. Input: path (or filePath), optional maxBytes.",
1554
1717
  tags: ["filesystem", "read", "core"],
1555
1718
  capabilities: ["read:fs"],
1556
1719
  sideEffect: "none"
@@ -1558,7 +1721,7 @@ var CORE_TOOL_MANIFEST = [
1558
1721
  {
1559
1722
  name: "core/fs.writeText",
1560
1723
  kind: "core",
1561
- description: "Write UTF-8 text to a file in the sandbox",
1724
+ description: "Write UTF-8 text to a file in the sandbox. Input: path (or filePath), text (or content), optional overwrite, mkdirp.",
1562
1725
  tags: ["filesystem", "write", "core"],
1563
1726
  capabilities: ["write:fs"],
1564
1727
  sideEffect: "local_write"
@@ -1566,7 +1729,7 @@ var CORE_TOOL_MANIFEST = [
1566
1729
  {
1567
1730
  name: "core/fs.listDir",
1568
1731
  kind: "core",
1569
- description: "List directory contents in the sandbox",
1732
+ description: "List directory contents in the sandbox. Input: path (or filePath, dir, directory), optional maxEntries, includeHidden, recursive, maxDepth.",
1570
1733
  tags: ["filesystem", "read", "core"],
1571
1734
  capabilities: ["read:fs"],
1572
1735
  sideEffect: "none"
@@ -1574,7 +1737,7 @@ var CORE_TOOL_MANIFEST = [
1574
1737
  {
1575
1738
  name: "core/fs.searchText",
1576
1739
  kind: "core",
1577
- description: "Search for text patterns in files within the sandbox",
1740
+ description: "Search for text patterns in files within the sandbox. Input: root (or path, dir, directory), query (or q), optional glob, maxMatches, maxFiles.",
1578
1741
  tags: ["filesystem", "search", "core"],
1579
1742
  capabilities: ["read:fs"],
1580
1743
  sideEffect: "none"
@@ -1582,7 +1745,7 @@ var CORE_TOOL_MANIFEST = [
1582
1745
  {
1583
1746
  name: "core/fs.sha256",
1584
1747
  kind: "core",
1585
- description: "Compute SHA-256 hash of a file in the sandbox",
1748
+ description: "Compute SHA-256 hash of a file in the sandbox. Input: path (or filePath).",
1586
1749
  tags: ["filesystem", "hash", "core"],
1587
1750
  capabilities: ["read:fs"],
1588
1751
  sideEffect: "none"
@@ -1590,7 +1753,7 @@ var CORE_TOOL_MANIFEST = [
1590
1753
  {
1591
1754
  name: "core/fs.deletePath",
1592
1755
  kind: "core",
1593
- description: "Delete a file or directory in the sandbox (dangerous, requires explicit confirmation)",
1756
+ description: "Delete a file or directory in the sandbox (dangerous, requires explicit confirmation). Input: path (or filePath), confirm=true, optional recursive.",
1594
1757
  tags: ["filesystem", "delete", "dangerous", "core"],
1595
1758
  capabilities: ["danger:destructive", "write:fs"],
1596
1759
  sideEffect: "destructive"
@@ -1599,7 +1762,7 @@ var CORE_TOOL_MANIFEST = [
1599
1762
  {
1600
1763
  name: "core/http.fetchText",
1601
1764
  kind: "core",
1602
- description: "Fetch a URL and return the response as text",
1765
+ description: "Fetch a URL and return the response as text. Input: url (or uri), optional method, headers, body, timeoutMs, maxBytes.",
1603
1766
  tags: ["http", "network", "core"],
1604
1767
  capabilities: ["network"],
1605
1768
  sideEffect: "none"
@@ -1607,7 +1770,7 @@ var CORE_TOOL_MANIFEST = [
1607
1770
  {
1608
1771
  name: "core/http.fetchJson",
1609
1772
  kind: "core",
1610
- description: "Fetch a URL and return the response as parsed JSON",
1773
+ description: "Fetch a URL and return the response as parsed JSON. Input: url (or uri), optional method, headers, body, timeoutMs, maxBytes.",
1611
1774
  tags: ["http", "network", "json", "core"],
1612
1775
  capabilities: ["network"],
1613
1776
  sideEffect: "none"
@@ -1615,7 +1778,7 @@ var CORE_TOOL_MANIFEST = [
1615
1778
  {
1616
1779
  name: "core/http.downloadFile",
1617
1780
  kind: "core",
1618
- description: "Download a file from a URL to the sandbox",
1781
+ description: "Download a file from a URL to the sandbox. Input: url (or uri), destPath (or destination, filePath), optional headers, timeoutMs, maxBytes, overwrite.",
1619
1782
  tags: ["http", "network", "download", "core"],
1620
1783
  capabilities: ["network", "write:fs"],
1621
1784
  sideEffect: "local_write"
@@ -1623,7 +1786,7 @@ var CORE_TOOL_MANIFEST = [
1623
1786
  {
1624
1787
  name: "core/http.head",
1625
1788
  kind: "core",
1626
- description: "Send a HEAD request to get response headers without body",
1789
+ description: "Send a HEAD request to get response headers without body. Input: url (or uri), optional headers, timeoutMs.",
1627
1790
  tags: ["http", "network", "core"],
1628
1791
  capabilities: ["network"],
1629
1792
  sideEffect: "none"
@@ -1631,7 +1794,7 @@ var CORE_TOOL_MANIFEST = [
1631
1794
  {
1632
1795
  name: "core/http.duckduckgoSearch",
1633
1796
  kind: "core",
1634
- description: "Search DuckDuckGo via Instant Answer API (no API key). Add api.duckduckgo.com to allowedHosts.",
1797
+ description: "Search DuckDuckGo via Instant Answer API (no API key). Add api.duckduckgo.com to allowedHosts. Input: use 'query' (or 'q') for the search string, optional 'maxResults'.",
1635
1798
  tags: ["http", "search", "duckduckgo", "core"],
1636
1799
  capabilities: ["network"],
1637
1800
  sideEffect: "none"
@@ -1639,16 +1802,24 @@ var CORE_TOOL_MANIFEST = [
1639
1802
  {
1640
1803
  name: "core/http.fetchPageMainContent",
1641
1804
  kind: "core",
1642
- description: "Fetch a URL and return only the main content (main/article/body text). Strips nav, header, footer, scripts.",
1805
+ description: "Fetch a URL and return only the main content (main/article/body text). Strips nav, header, footer, scripts. Input: url (or uri), optional timeoutMs, maxBytes.",
1643
1806
  tags: ["http", "network", "html", "main-content", "core"],
1644
1807
  capabilities: ["network"],
1645
1808
  sideEffect: "none"
1646
1809
  },
1810
+ {
1811
+ name: "core/http.yahooFinanceQuote",
1812
+ kind: "core",
1813
+ description: "Fetch stock quote(s) from Yahoo Finance chart API (no API key). Add query1.finance.yahoo.com to allowedHosts. Input: symbols (or symbol, tickers), optional range, timeoutMs.",
1814
+ tags: ["http", "finance", "yahoo", "stock", "quote", "core"],
1815
+ capabilities: ["network"],
1816
+ sideEffect: "none"
1817
+ },
1647
1818
  // Utils
1648
1819
  {
1649
1820
  name: "core/util.json.select",
1650
1821
  kind: "core",
1651
- description: "Select fields from JSON data using JMESPath expressions",
1822
+ description: "Select fields from JSON data using JMESPath expressions. Input: json, path (or expression).",
1652
1823
  tags: ["util", "json", "core"],
1653
1824
  capabilities: [],
1654
1825
  sideEffect: "none"
@@ -1689,7 +1860,7 @@ var CORE_TOOL_MANIFEST = [
1689
1860
  {
1690
1861
  name: "core/exec.runCommand",
1691
1862
  kind: "core",
1692
- description: "Run a Linux command in the sandbox (allowlist, timeout, no shell). Command name only; args as array.",
1863
+ description: "Run a Linux command in the sandbox (allowlist, timeout, no shell). Input: command (or cmd), optional args (or arguments), cwd, timeoutMs.",
1693
1864
  tags: ["exec", "shell", "linux", "core"],
1694
1865
  capabilities: ["exec"],
1695
1866
  sideEffect: "local_write"
@@ -1708,6 +1879,7 @@ var CORE_TOOL_HANDLERS = [
1708
1879
  headHandler,
1709
1880
  duckduckgoSearchHandler,
1710
1881
  fetchPageMainContentHandler,
1882
+ yahooFinanceQuoteHandler,
1711
1883
  jsonSelectHandler,
1712
1884
  truncateHandler,
1713
1885
  hashTextHandler,
@@ -1725,14 +1897,15 @@ var fetchTextSpec = createToolSpec(CORE_TOOL_MANIFEST[6]);
1725
1897
  var fetchJsonSpec = createToolSpec(CORE_TOOL_MANIFEST[7]);
1726
1898
  var downloadFileSpec = createToolSpec(CORE_TOOL_MANIFEST[8]);
1727
1899
  var headSpec = createToolSpec(CORE_TOOL_MANIFEST[9]);
1728
- var jsonSelectSpec = createToolSpec(CORE_TOOL_MANIFEST[10]);
1729
- var truncateSpec = createToolSpec(CORE_TOOL_MANIFEST[11]);
1730
- var hashTextSpec = createToolSpec(CORE_TOOL_MANIFEST[12]);
1731
- var nowSpec = createToolSpec(CORE_TOOL_MANIFEST[13]);
1732
- var templateRenderSpec = createToolSpec(CORE_TOOL_MANIFEST[14]);
1733
- var runCommandSpec = createToolSpec(CORE_TOOL_MANIFEST[15]);
1734
- var duckduckgoSearchSpec = createToolSpec(CORE_TOOL_MANIFEST[16]);
1735
- var fetchPageMainContentSpec = createToolSpec(CORE_TOOL_MANIFEST[17]);
1900
+ var duckduckgoSearchSpec = createToolSpec(CORE_TOOL_MANIFEST[10]);
1901
+ var fetchPageMainContentSpec = createToolSpec(CORE_TOOL_MANIFEST[11]);
1902
+ var yahooFinanceQuoteSpec = createToolSpec(CORE_TOOL_MANIFEST[12]);
1903
+ var jsonSelectSpec = createToolSpec(CORE_TOOL_MANIFEST[13]);
1904
+ var truncateSpec = createToolSpec(CORE_TOOL_MANIFEST[14]);
1905
+ var hashTextSpec = createToolSpec(CORE_TOOL_MANIFEST[15]);
1906
+ var nowSpec = createToolSpec(CORE_TOOL_MANIFEST[16]);
1907
+ var templateRenderSpec = createToolSpec(CORE_TOOL_MANIFEST[17]);
1908
+ var runCommandSpec = createToolSpec(CORE_TOOL_MANIFEST[18]);
1736
1909
  var CORE_GROUP_PREFIX = {
1737
1910
  fs: "core/fs.",
1738
1911
  http: "core/http.",
@@ -1786,6 +1959,7 @@ export {
1786
1959
  templateRenderSpec,
1787
1960
  truncateSpec,
1788
1961
  validateUrl,
1789
- writeTextSpec
1962
+ writeTextSpec,
1963
+ yahooFinanceQuoteSpec
1790
1964
  };
1791
1965
  //# sourceMappingURL=index.js.map