@agentdocumentformat/cli 0.7.8 → 0.8.0
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/README.md +1 -1
- package/dist/adf.mjs +59 -8
- package/dist/chunks/{APEv2Parser-2CNNHMXV.mjs → APEv2Parser-WIXRJLHB.mjs} +2 -2
- package/dist/chunks/{AiffParser-7BR4RL6G.mjs → AiffParser-ZC4QFOVJ.mjs} +5 -5
- package/dist/chunks/{App-7RIIOHJJ.mjs → App-A5GUFCFJ.mjs} +279 -293
- package/dist/chunks/{DsdiffParser-CMD4AX7A.mjs → DsdiffParser-UAPAJHFX.mjs} +5 -5
- package/dist/chunks/{DsfParser-UOGZDS2M.mjs → DsfParser-NNYZK2QX.mjs} +6 -6
- package/dist/chunks/{FlacParser-HB3T3CD4.mjs → FlacParser-MW2W4LO3.mjs} +6 -6
- package/dist/chunks/{MP4Parser-66HBRUSX.mjs → MP4Parser-Z57SYOOQ.mjs} +4 -4
- package/dist/chunks/{MpegParser-YW6LIUEW.mjs → MpegParser-XIIPAZVM.mjs} +7 -7
- package/dist/chunks/{MusepackParser-PAUSXP7D.mjs → MusepackParser-QWNDEYHJ.mjs} +6 -6
- package/dist/chunks/{OggParser-NUBV3GWC.mjs → OggParser-WRX53F77.mjs} +9 -9
- package/dist/chunks/{WavPackParser-WQAGT7TC.mjs → WavPackParser-MJ7WCSJ5.mjs} +2 -2
- package/dist/chunks/{WaveParser-EWLQVDX4.mjs → WaveParser-RAVLHZ5S.mjs} +7 -7
- package/dist/chunks/{adf-schema-US4NFHMR.mjs → adf-schema-YJSGLMA4.mjs} +2 -2
- package/dist/chunks/auth-manager-AJ32FZWS.mjs +19 -0
- package/dist/chunks/auth-manager-C5OBEQK2.mjs +18 -0
- package/dist/chunks/auth-manager-TBNKCJ45.mjs +17 -0
- package/dist/chunks/{chatgpt-subscription-E4MXTIAT.mjs → chatgpt-subscription-MMGNW5KJ.mjs} +5 -2
- package/dist/chunks/chunk-3UGZFWIF.mjs +26 -0
- package/dist/chunks/{chunk-5PO5PKRV.mjs → chunk-4OGZFUKA.mjs} +126 -67
- package/dist/chunks/{chunk-VN7UH7I5.mjs → chunk-6XQZGYMK.mjs} +246 -67
- package/dist/chunks/{chunk-XNPZBLYL.mjs → chunk-75DC5EWN.mjs} +13 -2
- package/dist/chunks/chunk-AZYOXXVL.mjs +865 -0
- package/dist/chunks/{chunk-6VQEXLE2.mjs → chunk-BHY7QDCM.mjs} +41 -3
- package/dist/chunks/chunk-C2S64Y6F.mjs +203 -0
- package/dist/chunks/chunk-C4GA5SI4.mjs +12799 -0
- package/dist/chunks/chunk-DDTTSKGG.mjs +2443 -0
- package/dist/chunks/{chunk-VAUOM3IN.mjs → chunk-DLWCKKIO.mjs} +1 -1
- package/dist/chunks/{chunk-QPLEAE6V.mjs → chunk-G6NBFYG5.mjs} +152 -824
- package/dist/chunks/{chunk-KXEF4F4E.mjs → chunk-GAZO6UMI.mjs} +1 -1
- package/dist/chunks/{chunk-XYTWGHFS.mjs → chunk-H3XLRWVE.mjs} +1 -1
- package/dist/chunks/{chunk-7T2YMTWL.mjs → chunk-H4C65MTP.mjs} +4 -4
- package/dist/chunks/chunk-HBOFZRUS.mjs +738 -0
- package/dist/chunks/chunk-JVPZIMXW.mjs +976 -0
- package/dist/chunks/{chunk-XYV3VCIX.mjs → chunk-JZFONJSL.mjs} +79 -20
- package/dist/chunks/chunk-KDDVQKCG.mjs +65 -0
- package/dist/chunks/chunk-KRPKWOMB.mjs +290 -0
- package/dist/chunks/{chunk-G6PH7RPW.mjs → chunk-LCMANRYY.mjs} +3 -3
- package/dist/chunks/{chunk-ZESQMP66.mjs → chunk-LGL6ML37.mjs} +3 -3
- package/dist/chunks/chunk-LKFHERRV.mjs +145 -0
- package/dist/chunks/chunk-LTX74NU6.mjs +29 -0
- package/dist/chunks/chunk-M2F7C2UJ.mjs +425 -0
- package/dist/chunks/{chunk-62NE4LG4.mjs → chunk-MQAMI5BF.mjs} +5 -5
- package/dist/chunks/chunk-MZRXFWPQ.mjs +278 -0
- package/dist/chunks/{chunk-PRMGZZM5.mjs → chunk-NZLEPJ5M.mjs} +2 -0
- package/dist/chunks/{chunk-CD3ATSXE.mjs → chunk-NZO5O4VN.mjs} +1 -1
- package/dist/chunks/{chunk-I3UYSITV.mjs → chunk-O7XKQ6CH.mjs} +1 -1
- package/dist/chunks/chunk-P3RG5LQA.mjs +244 -0
- package/dist/chunks/chunk-PAK5JCO2.mjs +48 -0
- package/dist/chunks/chunk-PC63YFB7.mjs +34 -0
- package/dist/chunks/{daemon-control-HKFVSQTQ.mjs → chunk-PRPTKMQW.mjs} +67 -26
- package/dist/chunks/{chunk-LFMB4PAA.mjs → chunk-TKXIH27X.mjs} +974 -113
- package/dist/chunks/{chunk-5W7KES6P.mjs → chunk-UZPDETEU.mjs} +1 -1
- package/dist/chunks/chunk-V2T6NZX2.mjs +517 -0
- package/dist/chunks/chunk-V3MM6PCH.mjs +366 -0
- package/dist/chunks/chunk-WJGPNHGX.mjs +67 -0
- package/dist/chunks/chunk-WVTPPOKK.mjs +290 -0
- package/dist/chunks/{chunk-J74STFKE.mjs → chunk-WX6QCUWI.mjs} +272 -51
- package/dist/chunks/{chunk-Y5ZLKFLE.mjs → chunk-XNNJQCZP.mjs} +196 -165
- package/dist/chunks/{chunk-HDBPBORT.mjs → chunk-XT2BJUFC.mjs} +15 -6
- package/dist/chunks/{chunk-HSBV6YFU.mjs → chunk-YRMKSHW3.mjs} +614 -92
- package/dist/chunks/{chunk-BNXUAOO4.mjs → chunk-ZGXUOAWZ.mjs} +3186 -959
- package/dist/chunks/chunk-ZPB3HYM7.mjs +45 -0
- package/dist/chunks/claude-subscription-33BMZB6I.mjs +29 -0
- package/dist/chunks/{cli-NMFIAR7Z.mjs → cli-I47IFDHJ.mjs} +797 -56
- package/dist/chunks/{commands-KPJWFRUE.mjs → commands-E4EQUHE5.mjs} +4 -3
- package/dist/chunks/{daemon-YDIK3AAM.mjs → daemon-FQ5BV3AP.mjs} +82058 -63958
- package/dist/chunks/daemon-control-L3CLG63P.mjs +59 -0
- package/dist/chunks/{daemon-token-WRSULP7G.mjs → daemon-token-L5QKTHU5.mjs} +3 -1
- package/dist/chunks/{discord-DSP4HUWI.mjs → discord-IR62565M.mjs} +3 -52
- package/dist/chunks/{email-BRG7KUO2.mjs → email-KHHTJBDW.mjs} +4 -2
- package/dist/chunks/{grok-subscription-4PYX7TBF.mjs → grok-subscription-E74FS5EG.mjs} +5 -2
- package/dist/chunks/{lib-N7FCZWKH.mjs → lib-L27L5PXM.mjs} +22 -22
- package/dist/chunks/{open-VAU7PXT6.mjs → open-TLGS2Z3Q.mjs} +4 -4
- package/dist/chunks/{parser-JVY2PWSM.mjs → parser-7GARNT5L.mjs} +1 -1
- package/dist/chunks/{pipeline-executor-O77NTGLP.mjs → pipeline-executor-FD4FBWQA.mjs} +6 -5
- package/dist/chunks/prompt-RRHZX4YT.mjs +13 -0
- package/dist/chunks/remote-access-cli-XXAPQWH6.mjs +268 -0
- package/dist/chunks/remote-hello-UFWUBDQI.mjs +37 -0
- package/dist/chunks/sdk-5FD2ZP7N.mjs +28422 -0
- package/dist/chunks/{slack-OCNNF4DX.mjs → slack-IYC5RAB5.mjs} +3 -4
- package/dist/chunks/{store-HUVDJPYN.mjs → store-ZRN2WCFB.mjs} +6 -3
- package/dist/chunks/tailscale-WLJATFMB.mjs +25 -0
- package/dist/chunks/{theme-SFE3JMA2.mjs → theme-HLBDTF6F.mjs} +1 -1
- package/dist/chunks/{themes-YLXLOIJF.mjs → themes-BQ72P446.mjs} +2 -2
- package/dist/chunks/{token-6G3HCMNX.mjs → token-6D22WECM.mjs} +20 -16
- package/dist/chunks/{token-util-UXYSDQIW.mjs → token-util-YF3ZWBZ4.mjs} +1 -2
- package/dist/chunks/{tui-UQJLK7XI.mjs → tui-SPSPDADM.mjs} +17 -14
- package/dist/chunks/{welcome-XHXFV7SH.mjs → welcome-J5JZZAM5.mjs} +1 -1
- package/dist/chunks/{whatsapp-AJMRQBT7.mjs → whatsapp-YJFFVN4Q.mjs} +9 -9
- package/package.json +1 -1
- package/dist/chunks/chunk-GKKCMXIZ.mjs +0 -94
- package/dist/chunks/chunk-IHDDCZBS.mjs +0 -112
- package/dist/chunks/chunk-KWFOS5WC.mjs +0 -41
- package/dist/chunks/chunk-UEZR2CNS.mjs +0 -65
- package/dist/chunks/chunk-VMHTYDH4.mjs +0 -172
- package/dist/chunks/chunk-Y2QA53AN.mjs +0 -259
- package/dist/chunks/{chunk-NBTUWMGP.mjs → chunk-2MTE22CR.mjs} +3 -3
- package/dist/chunks/{telegram-2EFGKIVK.mjs → telegram-JYY2VDTI.mjs} +5 -5
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
import { createRequire as __adfCreateRequire } from 'node:module';
|
|
2
|
+
import { fileURLToPath as __adfFileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname as __adfDirname } from 'node:path';
|
|
4
|
+
const require = __adfCreateRequire(import.meta.url);
|
|
5
|
+
const __filename = __adfFileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = __adfDirname(__filename);
|
|
7
|
+
import {
|
|
8
|
+
external_exports
|
|
9
|
+
} from "./chunk-ZJKXHM4Q.mjs";
|
|
10
|
+
import {
|
|
11
|
+
__export
|
|
12
|
+
} from "./chunk-M2RX3S2T.mjs";
|
|
13
|
+
|
|
14
|
+
// src/main/utils/ssrf-guard.ts
|
|
15
|
+
import { lookup } from "node:dns/promises";
|
|
16
|
+
import { isIP } from "node:net";
|
|
17
|
+
import { networkInterfaces } from "node:os";
|
|
18
|
+
function embeddedIPv4s(raw) {
|
|
19
|
+
let addr = raw.replace(/^\[|\]$/g, "").split("%")[0].toLowerCase(), tail = /^(.*:)(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(addr);
|
|
20
|
+
if (tail) {
|
|
21
|
+
let o = tail.slice(2, 6).map(Number);
|
|
22
|
+
if (o.some((n) => n > 255)) return [];
|
|
23
|
+
addr = `${tail[1]}${(o[0] << 8 | o[1]).toString(16)}:${(o[2] << 8 | o[3]).toString(16)}`;
|
|
24
|
+
}
|
|
25
|
+
if (isIP(addr) !== 6) return [];
|
|
26
|
+
let g = expandIPv6(addr).split(":").map((x) => parseInt(x, 16)), hi = (x) => x >> 8, lo = (x) => x & 255, quad = (a, b, c, d) => `${a}.${b}.${c}.${d}`, fromGroups = (x, y) => quad(hi(x), lo(x), hi(y), lo(y)), out = [], zero = (from, to) => g.slice(from, to).every((x) => x === 0);
|
|
27
|
+
if (zero(0, 4) && (g[4] === 0 && (g[5] === 0 && g[6] !== 0 || g[5] === 65535) || g[4] === 65535 && g[5] === 0) && out.push(fromGroups(g[6], g[7])), g[0] === 100 && g[1] === 65435 && zero(2, 6) && out.push(fromGroups(g[6], g[7])), g[0] === 100 && g[1] === 65435 && g[2] === 1) {
|
|
28
|
+
let local = [];
|
|
29
|
+
hi(g[4]) === 0 && (lo(g[5]) === 0 && zero(6, 8) && local.push(quad(hi(g[3]), lo(g[3]), lo(g[4]), hi(g[5]))), zero(6, 8) && local.push(quad(lo(g[3]), lo(g[4]), hi(g[5]), lo(g[5]))), lo(g[6]) === 0 && g[7] === 0 && local.push(quad(lo(g[4]), hi(g[5]), lo(g[5]), hi(g[6]))), g[6] === 0 && g[7] === 0 && local.length > 0 || local.push(fromGroups(g[6], g[7]))), out.push(...local);
|
|
30
|
+
}
|
|
31
|
+
return g[0] === 8194 && out.push(fromGroups(g[1], g[2])), g[0] === 8193 && g[1] === 0 && out.push(fromGroups(g[6] ^ 65535, g[7] ^ 65535)), (g[4] === 0 || g[4] === 512) && g[5] === 24318 && out.push(fromGroups(g[6], g[7])), [...new Set(out)];
|
|
32
|
+
}
|
|
33
|
+
var ALLOWED_FETCH_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]), ALLOWED_CONNECT_PROTOCOLS = /* @__PURE__ */ new Set(["ws:", "wss:", "http:", "https:"]), METADATA_IPV4 = /* @__PURE__ */ new Set([
|
|
34
|
+
"169.254.169.254",
|
|
35
|
+
// AWS, GCP, Azure IMDS, OCI, DigitalOcean, …
|
|
36
|
+
"169.254.170.2",
|
|
37
|
+
// AWS ECS task credentials
|
|
38
|
+
"169.254.170.23",
|
|
39
|
+
// AWS EKS Pod Identity agent
|
|
40
|
+
"100.100.100.200",
|
|
41
|
+
// Alibaba Cloud metadata
|
|
42
|
+
"168.63.129.16",
|
|
43
|
+
// Azure WireServer (host agent, platform keys)
|
|
44
|
+
"192.0.0.192"
|
|
45
|
+
// Oracle Cloud (OCI) metadata
|
|
46
|
+
]), METADATA_IPV6 = /* @__PURE__ */ new Set(["fd00:0ec2:0000:0000:0000:0000:0000:0254", "fd00:0ec2:0000:0000:0000:0000:0000:0023"]);
|
|
47
|
+
function isCloudMetadataIp(ip) {
|
|
48
|
+
let bare = ip.replace(/^\[|\]$/g, "").split("%")[0].toLowerCase(), version = isIP(bare);
|
|
49
|
+
return version === 4 ? METADATA_IPV4.has(bare) : version === 6 ? embeddedIPv4s(bare).some((v4) => METADATA_IPV4.has(v4)) ? !0 : METADATA_IPV6.has(expandIPv6(bare)) : !1;
|
|
50
|
+
}
|
|
51
|
+
function expandIPv6(addr) {
|
|
52
|
+
let [head, tail] = addr.includes("::") ? addr.split("::") : [addr, ""], left = head ? head.split(":") : [], right = tail ? tail.split(":") : [], fill = addr.includes("::") ? Array(Math.max(0, 8 - left.length - right.length)).fill("0") : [];
|
|
53
|
+
return [...left, ...fill, ...right].map((g) => g.padStart(4, "0")).join(":");
|
|
54
|
+
}
|
|
55
|
+
function parseLooseIPv4(host) {
|
|
56
|
+
let parts = host.split(".");
|
|
57
|
+
if (parts.length < 1 || parts.length > 4) return null;
|
|
58
|
+
let nums = [];
|
|
59
|
+
for (let part of parts) {
|
|
60
|
+
if (part === "") return null;
|
|
61
|
+
let n;
|
|
62
|
+
if (/^0[xX][0-9a-fA-F]+$/.test(part)) n = parseInt(part.slice(2), 16);
|
|
63
|
+
else if (/^0[0-7]+$/.test(part)) n = parseInt(part.slice(1), 8);
|
|
64
|
+
else if (/^[0-9]+$/.test(part)) n = parseInt(part, 10);
|
|
65
|
+
else return null;
|
|
66
|
+
if (!Number.isFinite(n) || n < 0) return null;
|
|
67
|
+
nums.push(n);
|
|
68
|
+
}
|
|
69
|
+
for (let i = 0; i < nums.length - 1; i++) if (nums[i] > 255) return null;
|
|
70
|
+
let last = nums[nums.length - 1];
|
|
71
|
+
if (last >= Math.pow(256, 4 - nums.length + 1)) return null;
|
|
72
|
+
let value = last;
|
|
73
|
+
for (let i = 0; i < nums.length - 1; i++) value += nums[i] * Math.pow(256, 3 - i);
|
|
74
|
+
return [value >>> 24 & 255, value >>> 16 & 255, value >>> 8 & 255, value & 255].join(".");
|
|
75
|
+
}
|
|
76
|
+
function isBlockedIPv4(ip) {
|
|
77
|
+
let o = ip.split(".").map(Number);
|
|
78
|
+
if (o.length !== 4 || o.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) return !1;
|
|
79
|
+
let [a, b, c] = o;
|
|
80
|
+
return a === 0 || a === 10 || a === 127 || a === 100 && b >= 64 && b <= 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 0 && c === 0 || a === 192 && b === 168 || a === 198 && (b === 18 || b === 19) || a >= 224;
|
|
81
|
+
}
|
|
82
|
+
function isBlockedIPv6(raw) {
|
|
83
|
+
let addr = raw.toLowerCase().replace(/^\[|\]$/g, "").split("%")[0];
|
|
84
|
+
if (addr === "::" || addr === "::1" || /^(0:){7}[01]$/.test(addr) || embeddedIPv4s(addr).some(isBlockedIPv4)) return !0;
|
|
85
|
+
let head = addr.split(":")[0];
|
|
86
|
+
if (!head) return !1;
|
|
87
|
+
let h = parseInt(head, 16);
|
|
88
|
+
return Number.isNaN(h) ? !1 : (h & 65472) === 65152 || (h & 65024) === 64512 || (h & 65280) === 65280;
|
|
89
|
+
}
|
|
90
|
+
function isBlockedIpAddress(ip) {
|
|
91
|
+
let version = isIP(ip.replace(/^\[|\]$/g, ""));
|
|
92
|
+
return version === 4 ? isBlockedIPv4(ip) : version === 6 ? isBlockedIPv6(ip) : !1;
|
|
93
|
+
}
|
|
94
|
+
function isLinkLocalIp(ip) {
|
|
95
|
+
let bare = ip.replace(/^\[|\]$/g, "").split("%")[0], version = isIP(bare);
|
|
96
|
+
if (version === 4) {
|
|
97
|
+
let o = bare.split(".").map(Number);
|
|
98
|
+
return o[0] === 169 && o[1] === 254;
|
|
99
|
+
}
|
|
100
|
+
if (version === 6) {
|
|
101
|
+
let addr = bare.toLowerCase();
|
|
102
|
+
if (embeddedIPv4s(addr).some((v4) => v4.startsWith("169.254."))) return !0;
|
|
103
|
+
let head = addr.split(":")[0], h = parseInt(head, 16);
|
|
104
|
+
return Number.isNaN(h) ? !1 : (h & 65472) === 65152;
|
|
105
|
+
}
|
|
106
|
+
return !1;
|
|
107
|
+
}
|
|
108
|
+
function isLoopbackIp(ip) {
|
|
109
|
+
let bare = ip.replace(/^\[|\]$/g, "").split("%")[0], version = isIP(bare);
|
|
110
|
+
if (version === 4) return bare.split(".").map(Number)[0] === 127;
|
|
111
|
+
if (version === 6) {
|
|
112
|
+
let addr = bare.toLowerCase();
|
|
113
|
+
return addr === "::1" || /^(0:){7}1$/.test(addr) ? !0 : embeddedIPv4s(addr).some((v4) => v4.startsWith("127."));
|
|
114
|
+
}
|
|
115
|
+
return !1;
|
|
116
|
+
}
|
|
117
|
+
function isLoopbackHostname(host) {
|
|
118
|
+
let h = host.toLowerCase().replace(/\.$/, "");
|
|
119
|
+
return h === "localhost" || h === "localhost.localdomain" || h.endsWith(".localhost");
|
|
120
|
+
}
|
|
121
|
+
function isUnspecifiedIp(ip) {
|
|
122
|
+
let bare = ip.replace(/^\[|\]$/g, "").split("%")[0].toLowerCase();
|
|
123
|
+
return bare === "0.0.0.0" || bare === "::" || /^(0{1,4}:){7}0{1,4}$/.test(bare) ? !0 : embeddedIPv4s(bare).includes("0.0.0.0");
|
|
124
|
+
}
|
|
125
|
+
function blockedMessage(target) {
|
|
126
|
+
return `Blocked by the sys_fetch SSRF guard: "${target}" is a private-network address (loopback is allowed by default). Set security.allow_local_fetch: true in your config to permit private/LAN fetches \u2014 an agent-initiated write to that setting raises an owner approval request.`;
|
|
127
|
+
}
|
|
128
|
+
function connectBlockedMessage(target) {
|
|
129
|
+
return `Blocked by the ws_connect SSRF guard: "${target}" is a private-network address (loopback is allowed by default). Set security.allow_local_fetch: true in your config to permit private/LAN connections \u2014 an agent-initiated write to that setting raises an owner approval request.`;
|
|
130
|
+
}
|
|
131
|
+
function comparableIps(ip) {
|
|
132
|
+
let bare = ip.replace(/^\[|\]$/g, "").split("%")[0].toLowerCase(), version = isIP(bare);
|
|
133
|
+
if (version === 4) return [bare];
|
|
134
|
+
if (version !== 6) return [];
|
|
135
|
+
let v4s = embeddedIPv4s(bare);
|
|
136
|
+
return bare.includes(".") ? v4s : [expandIPv6(bare), ...v4s];
|
|
137
|
+
}
|
|
138
|
+
var OWN_ADDRESSES_TTL_MS = 3e4, ownAddressCache = null;
|
|
139
|
+
function isOwnInterfaceIp(ip, now = Date.now()) {
|
|
140
|
+
if (!ownAddressCache || now - ownAddressCache.at > OWN_ADDRESSES_TTL_MS) {
|
|
141
|
+
let set = /* @__PURE__ */ new Set();
|
|
142
|
+
try {
|
|
143
|
+
for (let list of Object.values(networkInterfaces()))
|
|
144
|
+
for (let entry of list ?? [])
|
|
145
|
+
for (let c of comparableIps(entry.address)) set.add(c);
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
ownAddressCache = { at: now, set };
|
|
149
|
+
}
|
|
150
|
+
return comparableIps(ip).some((c) => ownAddressCache.set.has(c));
|
|
151
|
+
}
|
|
152
|
+
function envProxyEnabled(env = process.env, execArgv = process.execArgv) {
|
|
153
|
+
return env.NODE_USE_ENV_PROXY === "1" || execArgv.includes("--use-env-proxy") ? !0 : (env.NODE_OPTIONS ?? "").split(/\s+/).includes("--use-env-proxy");
|
|
154
|
+
}
|
|
155
|
+
function envProxyFor(target, env = process.env, execArgv = process.execArgv) {
|
|
156
|
+
if (!envProxyEnabled(env, execArgv)) return null;
|
|
157
|
+
let url;
|
|
158
|
+
try {
|
|
159
|
+
url = typeof target == "string" ? new URL(target) : target;
|
|
160
|
+
} catch {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
164
|
+
let httpProxy = env.http_proxy || env.HTTP_PROXY || "", proxy = url.protocol === "https:" && (env.https_proxy || env.HTTPS_PROXY) || httpProxy;
|
|
165
|
+
if (!proxy) return null;
|
|
166
|
+
let noProxy = (env.no_proxy ?? env.NO_PROXY ?? "").trim();
|
|
167
|
+
if (noProxy === "*") return null;
|
|
168
|
+
let host = url.hostname.replace(/^\[|\]$/g, "").toLowerCase(), port = url.port || (url.protocol === "https:" ? "443" : "80");
|
|
169
|
+
for (let raw of noProxy.split(/[,\s]+/)) {
|
|
170
|
+
if (!raw) continue;
|
|
171
|
+
let m = /^(.*?)(?::(\d+))?$/.exec(raw.toLowerCase()), entryHost = m[1].replace(/^\[|\]$/g, "");
|
|
172
|
+
if (!(m[2] && m[2] !== port)) {
|
|
173
|
+
if (/^[.*]/.test(entryHost)) {
|
|
174
|
+
if (host.endsWith(entryHost.replace(/^\*/, "")))
|
|
175
|
+
return null;
|
|
176
|
+
} else if (host === entryHost) return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return proxy;
|
|
180
|
+
}
|
|
181
|
+
var proxySkipLogged = !1, PROXY_RESOLVES = /* @__PURE__ */ new Set(["ENOTFOUND", "EAI_AGAIN"]);
|
|
182
|
+
function proxiedHostName(url, host) {
|
|
183
|
+
if (isIP(host) || isLoopbackHostname(host) || parseLooseIPv4(host)) return !1;
|
|
184
|
+
let proxy = envProxyFor(url);
|
|
185
|
+
if (!proxy) return !1;
|
|
186
|
+
if (!proxySkipLogged) {
|
|
187
|
+
proxySkipLogged = !0;
|
|
188
|
+
let via = proxy;
|
|
189
|
+
try {
|
|
190
|
+
via = new URL(proxy).host;
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
193
|
+
console.log(`[Egress] The env proxy is on and this machine cannot look up ${url.hostname}: it is left to the proxy (${via}) to resolve, unchecked (logged once)`);
|
|
194
|
+
}
|
|
195
|
+
return !0;
|
|
196
|
+
}
|
|
197
|
+
function unresolvedMessage(target, reason) {
|
|
198
|
+
return `Blocked: the address of "${target}" could not be looked up (${reason}), so the egress guard could not check it. Check the host name and the network.`;
|
|
199
|
+
}
|
|
200
|
+
async function classifyHost(host) {
|
|
201
|
+
let literal = classifyLiteralHost(host);
|
|
202
|
+
if (literal) return literal;
|
|
203
|
+
let candidates;
|
|
204
|
+
try {
|
|
205
|
+
candidates = (await lookup(host, { all: !0, verbatim: !0 })).map((a) => a.address);
|
|
206
|
+
} catch (err) {
|
|
207
|
+
return { unresolved: err?.code ?? (err instanceof Error ? err.message : String(err)) };
|
|
208
|
+
}
|
|
209
|
+
return candidates.length === 0 ? { unresolved: "no addresses" } : classifyCandidates(candidates, !1);
|
|
210
|
+
}
|
|
211
|
+
function classifyLiteralHost(host) {
|
|
212
|
+
if (isIP(host)) return classifyCandidates([host], !1);
|
|
213
|
+
if (isLoopbackHostname(host)) return classifyCandidates([], !0);
|
|
214
|
+
let loose = parseLooseIPv4(host);
|
|
215
|
+
return loose ? classifyCandidates([loose], !1) : null;
|
|
216
|
+
}
|
|
217
|
+
function classifyCandidates(candidates, loopbackHost) {
|
|
218
|
+
return {
|
|
219
|
+
anyMetadata: candidates.some(isCloudMetadataIp),
|
|
220
|
+
anyLinkLocal: candidates.some(isLinkLocalIp),
|
|
221
|
+
anyLoopback: loopbackHost || candidates.some(isLoopbackIp),
|
|
222
|
+
anyUnspecified: candidates.some(isUnspecifiedIp),
|
|
223
|
+
anyOwnAddress: candidates.some((ip) => isOwnInterfaceIp(ip)),
|
|
224
|
+
// Blocked classes minus loopback (private, CGNAT, unspecified, multicast, …)
|
|
225
|
+
// — loopback itself is allowed by default and only tier-gated per-port.
|
|
226
|
+
// Each IPv4 reading of an address counts on its own: one reading being
|
|
227
|
+
// loopback must not let another, private one through.
|
|
228
|
+
anyNonLoopbackBlocked: candidates.flatMap((ip) => [ip, ...embeddedIPv4s(ip)]).some((ip) => isBlockedIpAddress(ip) && !isLoopbackIp(ip))
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function applyPolicy(target, port, path, cls, opts, overridableMessage) {
|
|
232
|
+
return cls.anyMetadata ? `Blocked: "${target}" is a link-local / cloud-metadata address, which is never fetchable (even with allow_local_fetch).` : cls.anyLinkLocal && !opts.allowLinkLocal ? `Blocked: "${target}" is a link-local / cloud-metadata address, which is never fetchable (even with allow_local_fetch).` : (cls.anyLoopback || cls.anyUnspecified || cls.anyOwnAddress) && opts.daemonPort && port === opts.daemonPort ? `Blocked: "${target}" (port ${port}) is the local ADF daemon control API, which is never fetchable, even with allow_local_fetch.` : opts.ownOrigin && cls.anyLoopback && port === opts.ownOrigin.port && path.startsWith(opts.ownOrigin.pathPrefix) || opts.allowLocal ? null : cls.anyNonLoopbackBlocked ? overridableMessage(target) : null;
|
|
233
|
+
}
|
|
234
|
+
async function checkFetchTarget(rawUrl, opts = { allowLocal: !1 }) {
|
|
235
|
+
let url;
|
|
236
|
+
try {
|
|
237
|
+
url = new URL(rawUrl);
|
|
238
|
+
} catch {
|
|
239
|
+
return `Invalid URL: ${rawUrl}`;
|
|
240
|
+
}
|
|
241
|
+
if (!ALLOWED_FETCH_PROTOCOLS.has(url.protocol))
|
|
242
|
+
return `Blocked by the sys_fetch guard: only http and https URLs may be fetched (got "${url.protocol}").`;
|
|
243
|
+
let host = url.hostname.replace(/^\[|\]$/g, "");
|
|
244
|
+
if (!host) return `Invalid URL: ${rawUrl}`;
|
|
245
|
+
let port = url.port ? Number(url.port) : url.protocol === "https:" ? 443 : 80, cls = await classifyHost(host);
|
|
246
|
+
return "unresolved" in cls ? PROXY_RESOLVES.has(cls.unresolved) && proxiedHostName(url, host) ? null : unresolvedMessage(url.hostname, cls.unresolved) : applyPolicy(url.hostname, port, url.pathname, cls, opts, blockedMessage);
|
|
247
|
+
}
|
|
248
|
+
function checkLiteralConnectTarget(rawUrl, opts = { allowLocal: !1 }) {
|
|
249
|
+
let url;
|
|
250
|
+
try {
|
|
251
|
+
url = new URL(rawUrl);
|
|
252
|
+
} catch {
|
|
253
|
+
return `Invalid URL: ${rawUrl}`;
|
|
254
|
+
}
|
|
255
|
+
if (!ALLOWED_CONNECT_PROTOCOLS.has(url.protocol))
|
|
256
|
+
return `Blocked by the ws_connect guard: only ws, wss, http and https URLs may be connected (got "${url.protocol}").`;
|
|
257
|
+
let host = url.hostname.replace(/^\[|\]$/g, "");
|
|
258
|
+
if (!host) return `Invalid URL: ${rawUrl}`;
|
|
259
|
+
let cls = classifyLiteralHost(host);
|
|
260
|
+
if (!cls) return;
|
|
261
|
+
let secure = url.protocol === "wss:" || url.protocol === "https:", port = url.port ? Number(url.port) : secure ? 443 : 80;
|
|
262
|
+
return applyPolicy(url.hostname, port, url.pathname, cls, opts, connectBlockedMessage);
|
|
263
|
+
}
|
|
264
|
+
async function checkConnectTarget(rawUrl, opts = { allowLocal: !1 }) {
|
|
265
|
+
let url;
|
|
266
|
+
try {
|
|
267
|
+
url = new URL(rawUrl);
|
|
268
|
+
} catch {
|
|
269
|
+
return `Invalid URL: ${rawUrl}`;
|
|
270
|
+
}
|
|
271
|
+
if (!ALLOWED_CONNECT_PROTOCOLS.has(url.protocol))
|
|
272
|
+
return `Blocked by the ws_connect guard: only ws, wss, http and https URLs may be connected (got "${url.protocol}").`;
|
|
273
|
+
let host = url.hostname.replace(/^\[|\]$/g, "");
|
|
274
|
+
if (!host) return `Invalid URL: ${rawUrl}`;
|
|
275
|
+
let secure = url.protocol === "wss:" || url.protocol === "https:", port = url.port ? Number(url.port) : secure ? 443 : 80, cls = await classifyHost(host);
|
|
276
|
+
return "unresolved" in cls ? unresolvedMessage(url.hostname, cls.unresolved) : applyPolicy(url.hostname, port, url.pathname, cls, opts, connectBlockedMessage);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/main/utils/guarded-fetch.ts
|
|
280
|
+
var guarded_fetch_exports = {};
|
|
281
|
+
__export(guarded_fetch_exports, {
|
|
282
|
+
DEFAULT_DAEMON_PORT: () => DEFAULT_DAEMON_PORT,
|
|
283
|
+
MAX_FETCH_REDIRECTS: () => MAX_FETCH_REDIRECTS,
|
|
284
|
+
MCP_HTTP_EGRESS: () => MCP_HTTP_EGRESS,
|
|
285
|
+
addressCheck: () => addressCheck,
|
|
286
|
+
daemonGuardPort: () => daemonGuardPort,
|
|
287
|
+
egressFetch: () => egressFetch,
|
|
288
|
+
guardedFetch: () => guardedFetch,
|
|
289
|
+
guardedLookup: () => guardedLookup,
|
|
290
|
+
isFetchFailure: () => isFetchFailure,
|
|
291
|
+
pinnedFetch: () => pinnedFetch
|
|
292
|
+
});
|
|
293
|
+
import { lookup as dnsLookup } from "node:dns/promises";
|
|
294
|
+
import { Agent as HttpAgent, request as httpRequest } from "node:http";
|
|
295
|
+
import { Agent as HttpsAgent, request as httpsRequest } from "node:https";
|
|
296
|
+
import { pipeline, Readable } from "node:stream";
|
|
297
|
+
import { constants as zlibConstants, createBrotliDecompress, createGunzip, createInflate } from "node:zlib";
|
|
298
|
+
var NATIVE_FETCH = globalThis.fetch;
|
|
299
|
+
function guardedLookup(check) {
|
|
300
|
+
return ((hostname, options, callback) => {
|
|
301
|
+
(async () => {
|
|
302
|
+
let addresses = await dnsLookup(hostname, { all: !0, verbatim: !0 });
|
|
303
|
+
if (addresses.length === 0) throw Object.assign(new Error(`No address for ${hostname}`), { code: "ENOTFOUND" });
|
|
304
|
+
for (let entry of addresses) {
|
|
305
|
+
let refusal = await check(entry.address);
|
|
306
|
+
if (refusal) throw Object.assign(new Error(refusal), { code: "EGUARD" });
|
|
307
|
+
}
|
|
308
|
+
return addresses;
|
|
309
|
+
})().then((addresses) => {
|
|
310
|
+
options?.all ? callback(null, addresses) : callback(null, addresses[0].address, addresses[0].family);
|
|
311
|
+
}, (err) => callback(err));
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
var NULL_BODY = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
|
|
315
|
+
function addressCheck(target, guard, kind = "fetch") {
|
|
316
|
+
let secure = target.protocol === "https:" || target.protocol === "wss:", port = target.port || (secure ? "443" : "80"), check = kind === "connect" ? checkConnectTarget : checkFetchTarget;
|
|
317
|
+
return (address) => {
|
|
318
|
+
let literal = address.includes(":") ? `[${address}]` : address;
|
|
319
|
+
return check(`${target.protocol}//${literal}:${port}${target.pathname}`, guard);
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
function pinnedGet(url, signal, guard) {
|
|
323
|
+
let target = new URL(url), check = addressCheck(target, guard), send = target.protocol === "https:" ? httpsRequest : httpRequest;
|
|
324
|
+
return new Promise((resolve, reject) => {
|
|
325
|
+
let req = send(target, { method: "GET", signal, lookup: guardedLookup(check) }, (res) => {
|
|
326
|
+
let headers = new Headers();
|
|
327
|
+
for (let [name, value] of Object.entries(res.headers))
|
|
328
|
+
if (value !== void 0)
|
|
329
|
+
for (let one of Array.isArray(value) ? value : [value]) headers.append(name, one);
|
|
330
|
+
let status = res.statusCode ?? 502;
|
|
331
|
+
NULL_BODY.has(status) && res.resume(), resolve(new Response(NULL_BODY.has(status) ? null : Readable.toWeb(res), { status, headers }));
|
|
332
|
+
});
|
|
333
|
+
req.on("error", reject), req.end();
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
var REDIRECTS = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]), MAX_FOLLOWED_REDIRECTS = 20, pinnedAgents = /* @__PURE__ */ new Map();
|
|
337
|
+
function pinnedAgent(protocol, guard) {
|
|
338
|
+
let key = `${protocol}|${JSON.stringify(guard, Object.keys(guard).sort())}|${JSON.stringify(guard.ownOrigin ?? null)}`, agent = pinnedAgents.get(key);
|
|
339
|
+
return agent || (agent = protocol === "https:" ? new HttpsAgent({ keepAlive: !0 }) : new HttpAgent({ keepAlive: !0 }), pinnedAgents.set(key, agent)), agent;
|
|
340
|
+
}
|
|
341
|
+
function decodedBody(res) {
|
|
342
|
+
let encodings = String(res.headers["content-encoding"] ?? "").toLowerCase().split(",").map((e) => e.trim()).filter(Boolean), decoders = [];
|
|
343
|
+
for (let encoding of encodings.reverse())
|
|
344
|
+
if (encoding === "gzip" || encoding === "x-gzip") decoders.push(createGunzip({ flush: zlibConstants.Z_SYNC_FLUSH, finishFlush: zlibConstants.Z_SYNC_FLUSH }));
|
|
345
|
+
else if (encoding === "deflate") decoders.push(createInflate({ flush: zlibConstants.Z_SYNC_FLUSH, finishFlush: zlibConstants.Z_SYNC_FLUSH }));
|
|
346
|
+
else if (encoding === "br") decoders.push(createBrotliDecompress({ flush: zlibConstants.BROTLI_OPERATION_FLUSH, finishFlush: zlibConstants.BROTLI_OPERATION_FLUSH }));
|
|
347
|
+
else if (encoding !== "identity") return res;
|
|
348
|
+
return decoders.length === 0 ? res : pipeline([res, ...decoders], () => {
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
function abortReason(signal) {
|
|
352
|
+
return signal.reason ?? new DOMException("This operation was aborted", "AbortError");
|
|
353
|
+
}
|
|
354
|
+
function pinnedRequest(url, method, headers, body, signal, guard) {
|
|
355
|
+
let sent = {};
|
|
356
|
+
headers.forEach((value, name) => {
|
|
357
|
+
sent[name] = value;
|
|
358
|
+
}), sent.accept ??= "*/*", sent["user-agent"] ??= "node", sent["accept-encoding"] ??= "gzip, deflate, br", body && (sent["content-length"] = String(body.length));
|
|
359
|
+
let send = url.protocol === "https:" ? httpsRequest : httpRequest;
|
|
360
|
+
return new Promise((resolve, reject) => {
|
|
361
|
+
let res = null, onAbort = () => {
|
|
362
|
+
let reason = abortReason(signal);
|
|
363
|
+
res && res.destroy(reason), req.destroy(reason);
|
|
364
|
+
}, req = send(url, {
|
|
365
|
+
method,
|
|
366
|
+
headers: sent,
|
|
367
|
+
agent: pinnedAgent(url.protocol, guard),
|
|
368
|
+
lookup: guardedLookup(addressCheck(url, guard))
|
|
369
|
+
}, (incoming) => {
|
|
370
|
+
res = incoming, res.once("close", () => signal.removeEventListener("abort", onAbort));
|
|
371
|
+
let responseHeaders = new Headers();
|
|
372
|
+
for (let [name, value] of Object.entries(res.headers))
|
|
373
|
+
if (value !== void 0)
|
|
374
|
+
for (let one of Array.isArray(value) ? value : [value]) responseHeaders.append(name, one);
|
|
375
|
+
let status = res.statusCode ?? 502, empty = NULL_BODY.has(status) || method === "HEAD";
|
|
376
|
+
empty && res.resume();
|
|
377
|
+
let response = new Response(empty ? null : Readable.toWeb(decodedBody(res)), {
|
|
378
|
+
status,
|
|
379
|
+
statusText: res.statusMessage ?? "",
|
|
380
|
+
headers: responseHeaders
|
|
381
|
+
});
|
|
382
|
+
Object.defineProperty(response, "url", { value: url.toString() }), resolve(response);
|
|
383
|
+
});
|
|
384
|
+
signal.addEventListener("abort", onAbort, { once: !0 }), req.on("error", (err) => {
|
|
385
|
+
res || signal.removeEventListener("abort", onAbort), signal.aborted ? reject(abortReason(signal)) : err.code === "EGUARD" ? reject(new Error(err.message)) : reject(new TypeError("fetch failed", { cause: err }));
|
|
386
|
+
}), req.end(body ?? void 0);
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
function pinnedFetch(guard, opts = {}) {
|
|
390
|
+
return (async (input, init) => {
|
|
391
|
+
let policy = typeof guard == "function" ? guard() : guard, request = new Request(input, init?.body != null ? { ...init, duplex: "half" } : init), signal = request.signal, stopIfAborted = () => {
|
|
392
|
+
if (signal.aborted) throw abortReason(signal);
|
|
393
|
+
};
|
|
394
|
+
stopIfAborted();
|
|
395
|
+
let url = new URL(request.url), method = request.method, headers = new Headers(request.headers), body = request.body ? Buffer.from(await request.arrayBuffer()) : null;
|
|
396
|
+
for (let hop = 0; ; hop++) {
|
|
397
|
+
stopIfAborted();
|
|
398
|
+
let refusal = await checkFetchTarget(url.toString(), policy);
|
|
399
|
+
if (stopIfAborted(), refusal) throw new Error(refusal);
|
|
400
|
+
let viaFetch = (opts.useReplacedFetch && globalThis.fetch !== NATIVE_FETCH ? globalThis.fetch : null) ?? (envProxyFor(url) ? NATIVE_FETCH : null), response = viaFetch ? await viaFetch(url, { method, headers, ...body ? { body } : {}, signal, redirect: "manual" }) : await pinnedRequest(url, method, headers, body, signal, policy);
|
|
401
|
+
if (signal.aborted) {
|
|
402
|
+
try {
|
|
403
|
+
await response.body?.cancel();
|
|
404
|
+
} catch {
|
|
405
|
+
}
|
|
406
|
+
throw abortReason(signal);
|
|
407
|
+
}
|
|
408
|
+
let location = response.headers.get("location");
|
|
409
|
+
if (!REDIRECTS.has(response.status) || !location || request.redirect === "manual") return response;
|
|
410
|
+
try {
|
|
411
|
+
await response.body?.cancel();
|
|
412
|
+
} catch {
|
|
413
|
+
}
|
|
414
|
+
if (stopIfAborted(), request.redirect === "error") throw new TypeError("fetch failed", { cause: new Error(`unexpected redirect to ${location}`) });
|
|
415
|
+
if (hop >= MAX_FOLLOWED_REDIRECTS) throw new TypeError("fetch failed", { cause: new Error("redirect count exceeded") });
|
|
416
|
+
let next = new URL(location, url);
|
|
417
|
+
if (response.status === 303 ? method !== "GET" && method !== "HEAD" : (response.status === 301 || response.status === 302) && method === "POST") {
|
|
418
|
+
method = "GET", body = null;
|
|
419
|
+
for (let name of ["content-type", "content-length", "content-encoding", "content-language", "content-location"]) headers.delete(name);
|
|
420
|
+
}
|
|
421
|
+
if (next.origin !== url.origin) for (let name of ["authorization", "proxy-authorization", "cookie"]) headers.delete(name);
|
|
422
|
+
url = next;
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
function egressFetch(guard) {
|
|
427
|
+
return pinnedFetch(guard, { useReplacedFetch: !0 });
|
|
428
|
+
}
|
|
429
|
+
var DEFAULT_DAEMON_PORT = 7385, MAX_FETCH_REDIRECTS = 3;
|
|
430
|
+
function daemonGuardPort() {
|
|
431
|
+
return Number(process.env.ADF_DAEMON_PORT) || DEFAULT_DAEMON_PORT;
|
|
432
|
+
}
|
|
433
|
+
var MCP_HTTP_EGRESS = () => ({ allowLocal: !0, allowLinkLocal: !0, daemonPort: daemonGuardPort() });
|
|
434
|
+
function isFetchFailure(result) {
|
|
435
|
+
return "error" in result;
|
|
436
|
+
}
|
|
437
|
+
async function readCapped(response, maxBytes) {
|
|
438
|
+
let body = response.body;
|
|
439
|
+
if (!body) return Buffer.alloc(0);
|
|
440
|
+
if (typeof body.getReader != "function") {
|
|
441
|
+
let bytes = Buffer.from(new Uint8Array(await response.arrayBuffer()));
|
|
442
|
+
return bytes.length > maxBytes ? { error: `exceeds ${maxBytes} bytes` } : bytes;
|
|
443
|
+
}
|
|
444
|
+
let reader = body.getReader(), chunks = [], total = 0;
|
|
445
|
+
for (; ; ) {
|
|
446
|
+
let { done, value } = await reader.read();
|
|
447
|
+
if (done) break;
|
|
448
|
+
if (value) {
|
|
449
|
+
if (total += value.byteLength, total > maxBytes) {
|
|
450
|
+
try {
|
|
451
|
+
await reader.cancel();
|
|
452
|
+
} catch {
|
|
453
|
+
}
|
|
454
|
+
return { error: `exceeds ${maxBytes} bytes` };
|
|
455
|
+
}
|
|
456
|
+
chunks.push(Buffer.from(value));
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return Buffer.concat(chunks);
|
|
460
|
+
}
|
|
461
|
+
async function guardedFetch(url, options) {
|
|
462
|
+
let { maxBytes, timeoutMs } = options, maxRedirects = options.maxRedirects ?? MAX_FETCH_REDIRECTS, daemonPort = daemonGuardPort(), current;
|
|
463
|
+
try {
|
|
464
|
+
current = new URL(url).toString();
|
|
465
|
+
} catch {
|
|
466
|
+
return { error: `invalid URL: ${String(url).slice(0, 200)}` };
|
|
467
|
+
}
|
|
468
|
+
let controller = new AbortController(), timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
469
|
+
try {
|
|
470
|
+
for (let hop = 0; ; hop++) {
|
|
471
|
+
let protocol = new URL(current).protocol;
|
|
472
|
+
if (protocol !== "https:" && !(options.allowHttp && protocol === "http:"))
|
|
473
|
+
return { error: `only ${options.allowHttp ? "http(s)" : "https"} URLs may be fetched (got "${protocol}")` };
|
|
474
|
+
let guard = { allowLocal: options.allowLocal === !0, daemonPort, ...options.allowLinkLocal ? { allowLinkLocal: !0 } : {} }, blocked = await checkFetchTarget(current, guard);
|
|
475
|
+
if (blocked) return { error: blocked };
|
|
476
|
+
let response = globalThis.fetch === NATIVE_FETCH && !envProxyFor(current) ? await pinnedGet(current, controller.signal, guard) : await fetch(current, { signal: controller.signal, redirect: "manual" });
|
|
477
|
+
if (response.status >= 300 && response.status <= 399) {
|
|
478
|
+
let location = response.headers.get("location");
|
|
479
|
+
if (!location) return { error: `redirect without a location header (HTTP ${response.status})` };
|
|
480
|
+
if (hop >= maxRedirects) return { error: `too many redirects (>${maxRedirects})` };
|
|
481
|
+
try {
|
|
482
|
+
await response.body?.cancel();
|
|
483
|
+
} catch {
|
|
484
|
+
}
|
|
485
|
+
try {
|
|
486
|
+
current = new URL(location, current).toString();
|
|
487
|
+
} catch {
|
|
488
|
+
return { error: `redirect to an unusable location: ${location.slice(0, 200)}` };
|
|
489
|
+
}
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
if (!response.ok) return { error: `HTTP ${response.status} ${response.statusText}`.trim() };
|
|
493
|
+
let lengthHeader = response.headers.get("content-length"), declared = lengthHeader === null ? NaN : Number(lengthHeader);
|
|
494
|
+
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
495
|
+
try {
|
|
496
|
+
await response.body?.cancel();
|
|
497
|
+
} catch {
|
|
498
|
+
}
|
|
499
|
+
return { error: `exceeds ${maxBytes} bytes` };
|
|
500
|
+
}
|
|
501
|
+
let bytes = await readCapped(response, maxBytes);
|
|
502
|
+
return Buffer.isBuffer(bytes) ? { bytes, contentType: response.headers.get("content-type") ?? "" } : bytes;
|
|
503
|
+
}
|
|
504
|
+
} catch (err) {
|
|
505
|
+
let message = err instanceof Error ? err.message : String(err);
|
|
506
|
+
return { error: err instanceof Error && err.name === "AbortError" ? `request timed out after ${timeoutMs}ms` : message };
|
|
507
|
+
} finally {
|
|
508
|
+
clearTimeout(timer);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// src/shared/utils/context-breakdown.ts
|
|
513
|
+
var context_breakdown_exports = {};
|
|
514
|
+
__export(context_breakdown_exports, {
|
|
515
|
+
DEFAULT_COMPACT_THRESHOLD: () => DEFAULT_COMPACT_THRESHOLD,
|
|
516
|
+
breakdownTags: () => breakdownTags,
|
|
517
|
+
calibrationNote: () => calibrationNote,
|
|
518
|
+
contextCategories: () => contextCategories,
|
|
519
|
+
contextTotal: () => contextTotal,
|
|
520
|
+
estimatedSinceTokens: () => estimatedSinceTokens,
|
|
521
|
+
resolveCompactThreshold: () => resolveCompactThreshold,
|
|
522
|
+
resolveHostThreshold: () => resolveHostThreshold,
|
|
523
|
+
resolveLoopThreshold: () => resolveLoopThreshold
|
|
524
|
+
});
|
|
525
|
+
var DEFAULT_COMPACT_THRESHOLD = 1e5;
|
|
526
|
+
function hostThreshold(config, model) {
|
|
527
|
+
let context = config?.context?.compact_threshold;
|
|
528
|
+
if (context != null) return { value: context, source: "agent" };
|
|
529
|
+
let fromModel = model?.compact_threshold;
|
|
530
|
+
return fromModel != null ? { value: fromModel, source: "model" } : { value: 1e5, source: "default" };
|
|
531
|
+
}
|
|
532
|
+
function resolveCompactThreshold(config, loop) {
|
|
533
|
+
if (!loop || loop === "main") return hostThreshold(config, config?.model);
|
|
534
|
+
let declared = config?.loops?.find((l) => l.name === loop);
|
|
535
|
+
return declared ? declared.compact_threshold != null ? { value: declared.compact_threshold, source: "loop" } : hostThreshold(config, declared.model ?? config?.model) : hostThreshold(config, config?.model);
|
|
536
|
+
}
|
|
537
|
+
function resolveHostThreshold(config) {
|
|
538
|
+
return resolveCompactThreshold(config).value;
|
|
539
|
+
}
|
|
540
|
+
function resolveLoopThreshold(config, loop) {
|
|
541
|
+
return resolveCompactThreshold(config, loop).value;
|
|
542
|
+
}
|
|
543
|
+
function contextTotal(b) {
|
|
544
|
+
return b.system_prompt_tokens + b.tools_total_tokens + b.messages_tokens + b.dynamic_instructions_tokens;
|
|
545
|
+
}
|
|
546
|
+
function estimatedSinceTokens(cal) {
|
|
547
|
+
return Math.max(0, cal.since_last_call_tokens - cal.reply_tokens);
|
|
548
|
+
}
|
|
549
|
+
function breakdownTags(cal) {
|
|
550
|
+
if (!cal) return { part: "\u2248 estimate", recent: "\u2248 estimate", total: "\u2248 estimate" };
|
|
551
|
+
let newer = estimatedSinceTokens(cal) > 0 ? "\u2248 estimate" : "measured";
|
|
552
|
+
return { part: "\u2248 scaled", recent: newer, total: newer };
|
|
553
|
+
}
|
|
554
|
+
function calibrationNote(cal, fmt, approx = "\u2248") {
|
|
555
|
+
if (!cal) return `${approx} estimate: no call to calibrate to (none recorded yet, or the prompt, tools or model changed since).`;
|
|
556
|
+
let head = `Calibrated to the last call: ${fmt(cal.last_call_tokens)} prompt + ${fmt(cal.reply_tokens)} reply, as the gauge shows`, newer = estimatedSinceTokens(cal);
|
|
557
|
+
return newer > 0 ? `${head}; ${approx}${fmt(newer)} added since is an estimate the gauge counts after the next call.` : `${head}.`;
|
|
558
|
+
}
|
|
559
|
+
var byTokens = (list) => [...list].sort((a, b) => b.tokens - a.tokens);
|
|
560
|
+
function contextCategories(b, maxItems = 12) {
|
|
561
|
+
let fileTokens = b.injected_files.reduce((sum, f) => sum + f.tokens, 0), parts = b.system_prompt_parts, cal = b.calibration, basis = cal ? "calibrated" : "estimate", out = [
|
|
562
|
+
{
|
|
563
|
+
id: "system",
|
|
564
|
+
key: "system",
|
|
565
|
+
label: "System prompt",
|
|
566
|
+
tokens: Math.max(0, b.system_prompt_tokens - fileTokens),
|
|
567
|
+
items: parts ? byTokens([
|
|
568
|
+
{ name: "Base prompt and capability sections", tokens: parts.base_and_sections },
|
|
569
|
+
{ name: "Agent instructions", tokens: parts.instructions },
|
|
570
|
+
{ name: "Identity, loop roster, runtime blocks", tokens: parts.runtime_blocks }
|
|
571
|
+
]).filter((i) => i.tokens > 0) : [],
|
|
572
|
+
note: "Base prompt, instructions and runtime blocks: sent with every request."
|
|
573
|
+
}
|
|
574
|
+
];
|
|
575
|
+
b.injected_files.length > 0 && out.push({
|
|
576
|
+
id: "files",
|
|
577
|
+
key: "files",
|
|
578
|
+
label: "Injected files",
|
|
579
|
+
tokens: fileTokens,
|
|
580
|
+
count: b.injected_files.length,
|
|
581
|
+
items: byTokens(b.injected_files.map((f) => ({ name: f.path, tokens: f.tokens }))).slice(0, maxItems),
|
|
582
|
+
note: "{{path}} files rendered into the system prompt."
|
|
583
|
+
});
|
|
584
|
+
let builtIn = b.tool_groups.filter((g) => g.source === "built-in"), builtInTools = builtIn.flatMap((g) => g.tools);
|
|
585
|
+
out.push({
|
|
586
|
+
id: "tools",
|
|
587
|
+
key: "tools",
|
|
588
|
+
label: "Tools",
|
|
589
|
+
tokens: builtIn.reduce((sum, g) => sum + g.tokens, 0),
|
|
590
|
+
count: builtInTools.length,
|
|
591
|
+
items: byTokens(builtInTools).slice(0, maxItems),
|
|
592
|
+
note: "Built-in tool schemas: sent with every request."
|
|
593
|
+
});
|
|
594
|
+
for (let group of b.tool_groups)
|
|
595
|
+
group.source !== "built-in" && out.push({
|
|
596
|
+
id: `mcp:${group.source}`,
|
|
597
|
+
key: "mcp",
|
|
598
|
+
label: `MCP ${group.source}`,
|
|
599
|
+
tokens: group.tokens,
|
|
600
|
+
count: group.tools.length,
|
|
601
|
+
items: byTokens(group.tools).slice(0, maxItems),
|
|
602
|
+
note: `Tool schemas from the ${group.source} MCP server.`
|
|
603
|
+
});
|
|
604
|
+
out.push({
|
|
605
|
+
id: "dynamic",
|
|
606
|
+
key: "dynamic",
|
|
607
|
+
label: "Dynamic instructions",
|
|
608
|
+
tokens: b.dynamic_instructions_tokens,
|
|
609
|
+
items: [],
|
|
610
|
+
note: "Per-turn runtime notes (context pressure, reminders)."
|
|
611
|
+
}), out.push({
|
|
612
|
+
id: "messages",
|
|
613
|
+
key: "messages",
|
|
614
|
+
label: "Conversation",
|
|
615
|
+
tokens: b.messages_tokens - (cal?.since_last_call_tokens ?? 0),
|
|
616
|
+
items: [],
|
|
617
|
+
note: "This loop\u2019s history, compaction summary included."
|
|
618
|
+
});
|
|
619
|
+
let categories = out.map((c) => ({ ...c, basis }));
|
|
620
|
+
return cal && categories.push({
|
|
621
|
+
id: "recent",
|
|
622
|
+
key: "recent",
|
|
623
|
+
label: "Since last call",
|
|
624
|
+
tokens: cal.since_last_call_tokens,
|
|
625
|
+
items: [],
|
|
626
|
+
note: "The last call\u2019s reply (its reported output) plus anything added after it (estimated).",
|
|
627
|
+
basis: estimatedSinceTokens(cal) > 0 ? "estimate" : "measured"
|
|
628
|
+
}), byTokens(categories);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// src/shared/schemas/skills-catalog.schema.ts
|
|
632
|
+
var skills_catalog_schema_exports = {};
|
|
633
|
+
__export(skills_catalog_schema_exports, {
|
|
634
|
+
MAX_CATALOG_BYTES: () => MAX_CATALOG_BYTES,
|
|
635
|
+
MAX_PACKAGE_FILES: () => MAX_PACKAGE_FILES,
|
|
636
|
+
MAX_SKILL_PACKAGE_BYTES: () => MAX_SKILL_PACKAGE_BYTES,
|
|
637
|
+
SKILL_NAME: () => SKILL_NAME,
|
|
638
|
+
SkillCatalogEntrySchema: () => SkillCatalogEntrySchema,
|
|
639
|
+
parseSkillsCatalogDocument: () => parseSkillsCatalogDocument,
|
|
640
|
+
resolvePackageFilePath: () => resolvePackageFilePath
|
|
641
|
+
});
|
|
642
|
+
var SKILL_NAME = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/, PATH_SEGMENT = /^[A-Za-z0-9._-]+$/, MAX_PACKAGE_FILES = 32, MAX_CATALOG_BYTES = 512 * 1024, MAX_SKILL_PACKAGE_BYTES = 256 * 1024, UNSAFE_TEXT = /[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/, safeText = (value) => !UNSAFE_TEXT.test(value), UNSAFE_TEXT_MESSAGE = "must not contain control or bidirectional-override characters";
|
|
643
|
+
function resolvePackageFilePath(name, raw) {
|
|
644
|
+
if (typeof raw != "string") return null;
|
|
645
|
+
let directory = `skills/${name}/`, candidate = raw.trim().replace(/\\/g, "/");
|
|
646
|
+
if (!candidate) return null;
|
|
647
|
+
for (; candidate.startsWith("./"); ) candidate = candidate.slice(2);
|
|
648
|
+
if (candidate.startsWith("/")) return null;
|
|
649
|
+
let relative = candidate.startsWith(directory) ? candidate.slice(directory.length) : candidate;
|
|
650
|
+
return !relative || relative.split("/").some((segment) => segment === "." || segment === ".." || !PATH_SEGMENT.test(segment)) || relative === "SKILL.md" ? null : relative;
|
|
651
|
+
}
|
|
652
|
+
var SkillPackageFileSchema = external_exports.object({
|
|
653
|
+
path: external_exports.string().min(1).refine(safeText, UNSAFE_TEXT_MESSAGE),
|
|
654
|
+
raw_url: external_exports.string().url()
|
|
655
|
+
}), SkillCatalogEntrySchema = external_exports.object({
|
|
656
|
+
name: external_exports.string().regex(SKILL_NAME),
|
|
657
|
+
description: external_exports.string().min(1).max(500).refine(safeText, UNSAFE_TEXT_MESSAGE),
|
|
658
|
+
/** Path inside the publishing repo — display only. */
|
|
659
|
+
path: external_exports.string().min(1).refine(safeText, UNSAFE_TEXT_MESSAGE).optional(),
|
|
660
|
+
/** Where the SKILL.md body is fetched from on install. */
|
|
661
|
+
raw_url: external_exports.string().url(),
|
|
662
|
+
/** Resources installed beside SKILL.md, package-relative after parsing. */
|
|
663
|
+
files: external_exports.array(SkillPackageFileSchema).max(MAX_PACKAGE_FILES).optional()
|
|
664
|
+
}).superRefine((entry, ctx) => {
|
|
665
|
+
if (!entry.files) return;
|
|
666
|
+
let seen = /* @__PURE__ */ new Set();
|
|
667
|
+
entry.files.forEach((file, index) => {
|
|
668
|
+
let relative = resolvePackageFilePath(entry.name, file.path);
|
|
669
|
+
if (!relative) {
|
|
670
|
+
ctx.addIssue({
|
|
671
|
+
code: external_exports.ZodIssueCode.custom,
|
|
672
|
+
path: ["files", index, "path"],
|
|
673
|
+
message: `must stay inside skills/${entry.name}/ and cannot be SKILL.md`
|
|
674
|
+
});
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
if (seen.has(relative)) {
|
|
678
|
+
ctx.addIssue({
|
|
679
|
+
code: external_exports.ZodIssueCode.custom,
|
|
680
|
+
path: ["files", index, "path"],
|
|
681
|
+
message: "duplicate package path"
|
|
682
|
+
});
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
seen.add(relative);
|
|
686
|
+
});
|
|
687
|
+
}).transform((entry) => entry.files ? {
|
|
688
|
+
...entry,
|
|
689
|
+
files: entry.files.map((file) => ({
|
|
690
|
+
...file,
|
|
691
|
+
path: resolvePackageFilePath(entry.name, file.path)
|
|
692
|
+
}))
|
|
693
|
+
} : entry);
|
|
694
|
+
function parseSkillsCatalogDocument(json) {
|
|
695
|
+
if (typeof json != "object" || json === null || Array.isArray(json)) return null;
|
|
696
|
+
let doc = json;
|
|
697
|
+
if (doc.schema !== void 0 && doc.schema !== 1 || !Array.isArray(doc.skills)) return null;
|
|
698
|
+
let entries = [], seen = /* @__PURE__ */ new Set(), dropped = 0;
|
|
699
|
+
for (let raw of doc.skills) {
|
|
700
|
+
let result = SkillCatalogEntrySchema.safeParse(raw);
|
|
701
|
+
if (!result.success || seen.has(result.data.name)) {
|
|
702
|
+
dropped++;
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
seen.add(result.data.name), entries.push(result.data);
|
|
706
|
+
}
|
|
707
|
+
return {
|
|
708
|
+
entries,
|
|
709
|
+
publisher: typeof doc.publisher == "string" ? doc.publisher : void 0,
|
|
710
|
+
repository: typeof doc.repository == "string" ? doc.repository : void 0,
|
|
711
|
+
dropped
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
export {
|
|
716
|
+
isLoopbackIp,
|
|
717
|
+
isLoopbackHostname,
|
|
718
|
+
checkFetchTarget,
|
|
719
|
+
checkLiteralConnectTarget,
|
|
720
|
+
checkConnectTarget,
|
|
721
|
+
guardedLookup,
|
|
722
|
+
addressCheck,
|
|
723
|
+
egressFetch,
|
|
724
|
+
daemonGuardPort,
|
|
725
|
+
MCP_HTTP_EGRESS,
|
|
726
|
+
isFetchFailure,
|
|
727
|
+
guardedFetch,
|
|
728
|
+
guarded_fetch_exports,
|
|
729
|
+
resolveCompactThreshold,
|
|
730
|
+
resolveLoopThreshold,
|
|
731
|
+
contextTotal,
|
|
732
|
+
contextCategories,
|
|
733
|
+
context_breakdown_exports,
|
|
734
|
+
MAX_CATALOG_BYTES,
|
|
735
|
+
MAX_SKILL_PACKAGE_BYTES,
|
|
736
|
+
parseSkillsCatalogDocument,
|
|
737
|
+
skills_catalog_schema_exports
|
|
738
|
+
};
|