@easynet/agent-tool 1.0.61 → 1.0.62
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/api/adapters/LangChainToolsHub.d.ts.map +1 -1
- package/dist/api/expose/extension-init/initExtension.d.ts.map +1 -1
- package/dist/api/main.cjs +29 -13
- package/dist/api/main.d.ts +34 -0
- package/dist/api/main.d.ts.map +1 -1
- package/dist/api/main.js +2 -2
- package/dist/api/runtimeFromConfig.d.ts +2 -5
- package/dist/api/runtimeFromConfig.d.ts.map +1 -1
- package/dist/api/runtimeFromConfig.helpers.d.ts +12 -0
- package/dist/api/runtimeFromConfig.helpers.d.ts.map +1 -0
- package/dist/build.cjs +1 -0
- package/dist/build.js +1 -0
- package/dist/chunk-DEDDPMBU.js +3 -0
- package/dist/chunk-DEDDPMBU.js.map +1 -0
- package/dist/chunk-FWWN4D2F.js +3 -0
- package/dist/chunk-FWWN4D2F.js.map +1 -0
- package/dist/chunk-ICHSEIZN.cjs +4 -0
- package/dist/chunk-ICHSEIZN.cjs.map +1 -0
- package/dist/{chunk-HK4GTFTQ.cjs → chunk-M2GEHWPN.cjs} +41 -40
- package/dist/chunk-M2GEHWPN.cjs.map +1 -0
- package/dist/chunk-NKYFYALQ.js +181 -0
- package/dist/chunk-NKYFYALQ.js.map +1 -0
- package/dist/chunk-NOGGIM7B.cjs +4 -0
- package/dist/chunk-NOGGIM7B.cjs.map +1 -0
- package/dist/chunk-R55NXJIH.cjs +184 -0
- package/dist/chunk-R55NXJIH.cjs.map +1 -0
- package/dist/{chunk-NVT4X4CB.js → chunk-RJAF5XY6.js} +40 -39
- package/dist/chunk-RJAF5XY6.js.map +1 -0
- package/dist/{chunk-ZH5MH3AK.cjs → chunk-U67QDQFQ.cjs} +73 -41
- package/dist/chunk-U67QDQFQ.cjs.map +1 -0
- package/dist/chunk-WO4LZKPQ.cjs +359 -0
- package/dist/chunk-WO4LZKPQ.cjs.map +1 -0
- package/dist/chunk-YL6RC7HQ.cjs +4 -0
- package/dist/chunk-YL6RC7HQ.cjs.map +1 -0
- package/dist/chunk-YLWTSNTT.js +3 -0
- package/dist/chunk-YLWTSNTT.js.map +1 -0
- package/dist/{chunk-QPKBEU64.js → chunk-YMHUDRYE.js} +59 -31
- package/dist/chunk-YMHUDRYE.js.map +1 -0
- package/dist/chunk-YPGF5Y2Y.js +341 -0
- package/dist/chunk-YPGF5Y2Y.js.map +1 -0
- package/dist/core/index.cjs +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/runtime.cjs +1 -0
- package/dist/core/runtime.js +1 -0
- package/dist/extension.cjs +54 -355
- package/dist/extension.cjs.map +1 -1
- package/dist/extension.js +3 -339
- package/dist/extension.js.map +1 -1
- package/dist/index.cjs +96 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +50 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +59 -7
- package/dist/index.js.map +1 -1
- package/dist/security.cjs +11 -178
- package/dist/security.cjs.map +1 -1
- package/dist/security.js +2 -179
- package/dist/security.js.map +1 -1
- package/dist/utils/cli/help.d.ts +2 -0
- package/dist/utils/cli/help.d.ts.map +1 -0
- package/dist/utils/cli/index.cjs +95 -73
- package/dist/utils/cli/index.cjs.map +1 -1
- package/dist/utils/cli/index.d.ts.map +1 -1
- package/dist/utils/cli/index.js +84 -62
- package/dist/utils/cli/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-HK4GTFTQ.cjs.map +0 -1
- package/dist/chunk-NVT4X4CB.js.map +0 -1
- package/dist/chunk-QPKBEU64.js.map +0 -1
- package/dist/chunk-ZH5MH3AK.cjs.map +0 -1
package/dist/security.js
CHANGED
|
@@ -1,182 +1,5 @@
|
|
|
1
|
+
export { isIpInBlockedCidrs, validateUrl } from './chunk-NKYFYALQ.js';
|
|
1
2
|
export { resolveSandboxedPath, setSandboxValidationEnabled } from './chunk-QXQ4477T.js';
|
|
2
|
-
import
|
|
3
|
-
import { lookup } from 'dns/promises';
|
|
4
|
-
|
|
5
|
-
async function validateUrl(url, options) {
|
|
6
|
-
let parsed;
|
|
7
|
-
try {
|
|
8
|
-
parsed = new URL(url);
|
|
9
|
-
} catch {
|
|
10
|
-
throw createTaggedError(
|
|
11
|
-
"HTTP_DISALLOWED_HOST",
|
|
12
|
-
`Invalid URL: ${url}`,
|
|
13
|
-
{ url }
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
17
|
-
throw createTaggedError(
|
|
18
|
-
"HTTP_DISALLOWED_HOST",
|
|
19
|
-
`Protocol not allowed: ${parsed.protocol}. Only http: and https: are supported.`,
|
|
20
|
-
{ url, protocol: parsed.protocol }
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
const hostname = parsed.hostname;
|
|
24
|
-
if (!isHostAllowed(hostname, options.allowedHosts)) {
|
|
25
|
-
throw createTaggedError(
|
|
26
|
-
"HTTP_DISALLOWED_HOST",
|
|
27
|
-
`Host "${hostname}" is not in the allowed hosts list`,
|
|
28
|
-
{ url, hostname, allowedHosts: options.allowedHosts }
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
if (isHostBlocked(hostname, options.blockedHosts)) {
|
|
32
|
-
throw createTaggedError(
|
|
33
|
-
"HTTP_DISALLOWED_HOST",
|
|
34
|
-
`Host "${hostname}" is in the blocked hosts list`,
|
|
35
|
-
{ url, hostname, blockedHosts: options.blockedHosts }
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
try {
|
|
39
|
-
const { address } = await lookup(hostname);
|
|
40
|
-
if (isIpInBlockedCidrs(address, options.blockedCidrs)) {
|
|
41
|
-
throw createTaggedError(
|
|
42
|
-
"HTTP_DISALLOWED_HOST",
|
|
43
|
-
`Host "${hostname}" resolves to blocked IP: ${address}`,
|
|
44
|
-
{ url, hostname, resolvedIp: address }
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
} catch (err) {
|
|
48
|
-
if (err instanceof Error && err.kind === "HTTP_DISALLOWED_HOST") {
|
|
49
|
-
throw err;
|
|
50
|
-
}
|
|
51
|
-
throw createTaggedError(
|
|
52
|
-
"HTTP_DISALLOWED_HOST",
|
|
53
|
-
`DNS resolution failed for host "${hostname}": ${err instanceof Error ? err.message : String(err)}`,
|
|
54
|
-
{ url, hostname }
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
return parsed;
|
|
58
|
-
}
|
|
59
|
-
function isHostAllowed(hostname, allowedHosts) {
|
|
60
|
-
for (const pattern of allowedHosts) {
|
|
61
|
-
if (pattern === "*") {
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
|
-
if (pattern.startsWith("*.")) {
|
|
65
|
-
const suffix = pattern.slice(1);
|
|
66
|
-
if (hostname.endsWith(suffix) || hostname === pattern.slice(2)) {
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
} else if (hostname === pattern) {
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
function isHostBlocked(hostname, blockedHosts) {
|
|
76
|
-
for (const pattern of blockedHosts) {
|
|
77
|
-
if (pattern === "*") {
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
if (pattern.startsWith("*.")) {
|
|
81
|
-
const suffix = pattern.slice(1);
|
|
82
|
-
if (hostname.endsWith(suffix) || hostname === pattern.slice(2)) {
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
} else if (hostname === pattern) {
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
function isIpInBlockedCidrs(ip, cidrs) {
|
|
92
|
-
const normalizedIp = normalizeIp(ip);
|
|
93
|
-
if (!normalizedIp) return false;
|
|
94
|
-
for (const cidr of cidrs) {
|
|
95
|
-
if (cidr.includes(":")) {
|
|
96
|
-
if (!ip.includes(":")) continue;
|
|
97
|
-
if (isIpv6InCidr(ip, cidr)) return true;
|
|
98
|
-
} else {
|
|
99
|
-
if (isIpv4InCidr(normalizedIp, cidr)) return true;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
function normalizeIp(ip) {
|
|
105
|
-
if (ip.startsWith("::ffff:")) {
|
|
106
|
-
return ip.slice(7);
|
|
107
|
-
}
|
|
108
|
-
if (/^\d+\.\d+\.\d+\.\d+$/.test(ip)) {
|
|
109
|
-
return ip;
|
|
110
|
-
}
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
function isIpv4InCidr(ip, cidr) {
|
|
114
|
-
const [cidrIp, prefixStr] = cidr.split("/");
|
|
115
|
-
if (!cidrIp || !prefixStr) return false;
|
|
116
|
-
const prefix = parseInt(prefixStr, 10);
|
|
117
|
-
if (isNaN(prefix) || prefix < 0 || prefix > 32) return false;
|
|
118
|
-
const ipNum = ipv4ToNum(ip);
|
|
119
|
-
const cidrNum = ipv4ToNum(cidrIp);
|
|
120
|
-
if (ipNum === null || cidrNum === null) return false;
|
|
121
|
-
const mask = prefix === 0 ? 0 : -1 << 32 - prefix >>> 0;
|
|
122
|
-
return (ipNum & mask) === (cidrNum & mask);
|
|
123
|
-
}
|
|
124
|
-
function ipv4ToNum(ip) {
|
|
125
|
-
const parts = ip.split(".");
|
|
126
|
-
if (parts.length !== 4) return null;
|
|
127
|
-
let num = 0;
|
|
128
|
-
for (const part of parts) {
|
|
129
|
-
const n = parseInt(part, 10);
|
|
130
|
-
if (isNaN(n) || n < 0 || n > 255) return null;
|
|
131
|
-
num = num << 8 | n;
|
|
132
|
-
}
|
|
133
|
-
return num >>> 0;
|
|
134
|
-
}
|
|
135
|
-
function isIpv6InCidr(ip, cidr) {
|
|
136
|
-
const [cidrIp, prefixStr] = cidr.split("/");
|
|
137
|
-
if (!cidrIp || !prefixStr) return false;
|
|
138
|
-
const prefix = parseInt(prefixStr, 10);
|
|
139
|
-
if (isNaN(prefix)) return false;
|
|
140
|
-
const ipBytes = expandIpv6(ip);
|
|
141
|
-
const cidrBytes = expandIpv6(cidrIp);
|
|
142
|
-
if (!ipBytes || !cidrBytes) return false;
|
|
143
|
-
const fullBytes = Math.floor(prefix / 8);
|
|
144
|
-
for (let i = 0; i < fullBytes && i < 16; i++) {
|
|
145
|
-
if (ipBytes[i] !== cidrBytes[i]) return false;
|
|
146
|
-
}
|
|
147
|
-
const remainingBits = prefix % 8;
|
|
148
|
-
if (remainingBits > 0 && fullBytes < 16) {
|
|
149
|
-
const mask = -1 << 8 - remainingBits & 255;
|
|
150
|
-
if ((ipBytes[fullBytes] & mask) !== (cidrBytes[fullBytes] & mask)) return false;
|
|
151
|
-
}
|
|
152
|
-
return true;
|
|
153
|
-
}
|
|
154
|
-
function expandIpv6(ip) {
|
|
155
|
-
const zoneIdx = ip.indexOf("%");
|
|
156
|
-
if (zoneIdx !== -1) ip = ip.slice(0, zoneIdx);
|
|
157
|
-
const parts = ip.split("::");
|
|
158
|
-
if (parts.length > 2) return null;
|
|
159
|
-
const bytes = new Array(16).fill(0);
|
|
160
|
-
const expandGroup = (group) => {
|
|
161
|
-
if (!group) return [];
|
|
162
|
-
return group.split(":").flatMap((hex) => {
|
|
163
|
-
const val = parseInt(hex || "0", 16);
|
|
164
|
-
return [val >> 8 & 255, val & 255];
|
|
165
|
-
});
|
|
166
|
-
};
|
|
167
|
-
if (parts.length === 1) {
|
|
168
|
-
const expanded = expandGroup(parts[0]);
|
|
169
|
-
if (expanded.length !== 16) return null;
|
|
170
|
-
return expanded;
|
|
171
|
-
}
|
|
172
|
-
const left = expandGroup(parts[0]);
|
|
173
|
-
const right = expandGroup(parts[1]);
|
|
174
|
-
if (left.length + right.length > 16) return null;
|
|
175
|
-
for (let i = 0; i < left.length; i++) bytes[i] = left[i];
|
|
176
|
-
for (let i = 0; i < right.length; i++) bytes[16 - right.length + i] = right[i];
|
|
177
|
-
return bytes;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
export { isIpInBlockedCidrs, validateUrl };
|
|
3
|
+
import './chunk-RZTTO5MQ.js';
|
|
181
4
|
//# sourceMappingURL=security.js.map
|
|
182
5
|
//# sourceMappingURL=security.js.map
|
package/dist/security.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/security/ssrf.ts"],"names":[],"mappings":"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","file":"security.js","sourcesContent":["import { lookup } from \"node:dns/promises\";\nimport { createTaggedError } from \"../core/runtime/Retry.js\";\n\n/**\n * Options for validateUrl. Unified rule: allow iff host is in allowedHosts AND not in blockedHosts.\n * - \"Default allow all + blocklist\": allowedHosts: [\"*\"], blockedHosts: [\"*.internal\", ...]\n * - \"Default disallow all + allowlist\": allowedHosts: [\"api.github.com\", ...], blockedHosts: []\n */\nexport interface ValidateUrlOptions {\n /** Allow only these hosts. Use [\"*\"] for allow-all. Supports \"*.example.com\", exact host. */\n allowedHosts: string[];\n /** Block these hosts even if allowed. Supports \"*.internal\", exact host. Merged with allowlist. */\n blockedHosts: string[];\n /** CIDR ranges to block (resolved IP). */\n blockedCidrs: string[];\n}\n\n/**\n * Validate a URL: allow iff (host in allowedHosts) AND (host not in blockedHosts). Then check blockedCidrs on resolved IP.\n *\n * @throws HTTP_DISALLOWED_HOST if the URL is blocked\n */\nexport async function validateUrl(url: string, options: ValidateUrlOptions): Promise<URL> {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw createTaggedError(\n \"HTTP_DISALLOWED_HOST\",\n `Invalid URL: ${url}`,\n { url },\n );\n }\n\n // Only allow http/https\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n throw createTaggedError(\n \"HTTP_DISALLOWED_HOST\",\n `Protocol not allowed: ${parsed.protocol}. Only http: and https: are supported.`,\n { url, protocol: parsed.protocol },\n );\n }\n\n const hostname = parsed.hostname;\n\n if (!isHostAllowed(hostname, options.allowedHosts)) {\n throw createTaggedError(\n \"HTTP_DISALLOWED_HOST\",\n `Host \"${hostname}\" is not in the allowed hosts list`,\n { url, hostname, allowedHosts: options.allowedHosts },\n );\n }\n if (isHostBlocked(hostname, options.blockedHosts)) {\n throw createTaggedError(\n \"HTTP_DISALLOWED_HOST\",\n `Host \"${hostname}\" is in the blocked hosts list`,\n { url, hostname, blockedHosts: options.blockedHosts },\n );\n }\n\n // DNS resolve and check against blocked CIDRs\n try {\n const { address } = await lookup(hostname);\n if (isIpInBlockedCidrs(address, options.blockedCidrs)) {\n throw createTaggedError(\n \"HTTP_DISALLOWED_HOST\",\n `Host \"${hostname}\" resolves to blocked IP: ${address}`,\n { url, hostname, resolvedIp: address },\n );\n }\n } catch (err) {\n // Re-throw our tagged errors\n if (err instanceof Error && (err as any).kind === \"HTTP_DISALLOWED_HOST\") {\n throw err;\n }\n // DNS resolution failure — block by default\n throw createTaggedError(\n \"HTTP_DISALLOWED_HOST\",\n `DNS resolution failed for host \"${hostname}\": ${err instanceof Error ? err.message : String(err)}`,\n { url, hostname },\n );\n }\n\n return parsed;\n}\n\n/**\n * Check if a hostname matches any entry in the allowed hosts list.\n * Supports: exact \"*\" (allow any host), wildcard prefix (e.g. \"*.github.com\"), or exact host.\n */\nfunction isHostAllowed(hostname: string, allowedHosts: string[]): boolean {\n for (const pattern of allowedHosts) {\n if (pattern === \"*\") {\n return true;\n }\n if (pattern.startsWith(\"*.\")) {\n const suffix = pattern.slice(1); // \".github.com\"\n if (hostname.endsWith(suffix) || hostname === pattern.slice(2)) {\n return true;\n }\n } else if (hostname === pattern) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Check if a hostname matches any entry in the blocked hosts list (same pattern rules as allowlist).\n */\nfunction isHostBlocked(hostname: string, blockedHosts: string[]): boolean {\n for (const pattern of blockedHosts) {\n if (pattern === \"*\") {\n return true;\n }\n if (pattern.startsWith(\"*.\")) {\n const suffix = pattern.slice(1);\n if (hostname.endsWith(suffix) || hostname === pattern.slice(2)) {\n return true;\n }\n } else if (hostname === pattern) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Check if an IPv4 address falls within any blocked CIDR range.\n */\nexport function isIpInBlockedCidrs(ip: string, cidrs: string[]): boolean {\n // Handle IPv4-mapped IPv6\n const normalizedIp = normalizeIp(ip);\n if (!normalizedIp) return false;\n\n for (const cidr of cidrs) {\n if (cidr.includes(\":\")) {\n // IPv6 CIDR — skip for IPv4 addresses\n if (!ip.includes(\":\")) continue;\n if (isIpv6InCidr(ip, cidr)) return true;\n } else {\n if (isIpv4InCidr(normalizedIp, cidr)) return true;\n }\n }\n return false;\n}\n\nfunction normalizeIp(ip: string): string | null {\n // Handle IPv4-mapped IPv6 (e.g. \"::ffff:127.0.0.1\")\n if (ip.startsWith(\"::ffff:\")) {\n return ip.slice(7);\n }\n // Pure IPv4\n if (/^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(ip)) {\n return ip;\n }\n return null;\n}\n\nfunction isIpv4InCidr(ip: string, cidr: string): boolean {\n const [cidrIp, prefixStr] = cidr.split(\"/\");\n if (!cidrIp || !prefixStr) return false;\n\n const prefix = parseInt(prefixStr, 10);\n if (isNaN(prefix) || prefix < 0 || prefix > 32) return false;\n\n const ipNum = ipv4ToNum(ip);\n const cidrNum = ipv4ToNum(cidrIp);\n if (ipNum === null || cidrNum === null) return false;\n\n const mask = prefix === 0 ? 0 : (~0 << (32 - prefix)) >>> 0;\n return (ipNum & mask) === (cidrNum & mask);\n}\n\nfunction ipv4ToNum(ip: string): number | null {\n const parts = ip.split(\".\");\n if (parts.length !== 4) return null;\n let num = 0;\n for (const part of parts) {\n const n = parseInt(part, 10);\n if (isNaN(n) || n < 0 || n > 255) return null;\n num = (num << 8) | n;\n }\n return num >>> 0;\n}\n\nfunction isIpv6InCidr(ip: string, cidr: string): boolean {\n // Simplified IPv6 CIDR matching for common cases (::1, fc00::, fe80::)\n const [cidrIp, prefixStr] = cidr.split(\"/\");\n if (!cidrIp || !prefixStr) return false;\n\n const prefix = parseInt(prefixStr, 10);\n if (isNaN(prefix)) return false;\n\n const ipBytes = expandIpv6(ip);\n const cidrBytes = expandIpv6(cidrIp);\n if (!ipBytes || !cidrBytes) return false;\n\n // Compare prefix bits\n const fullBytes = Math.floor(prefix / 8);\n for (let i = 0; i < fullBytes && i < 16; i++) {\n if (ipBytes[i] !== cidrBytes[i]) return false;\n }\n\n const remainingBits = prefix % 8;\n if (remainingBits > 0 && fullBytes < 16) {\n const mask = (~0 << (8 - remainingBits)) & 0xff;\n if ((ipBytes[fullBytes]! & mask) !== (cidrBytes[fullBytes]! & mask)) return false;\n }\n\n return true;\n}\n\nfunction expandIpv6(ip: string): number[] | null {\n // Remove zone ID\n const zoneIdx = ip.indexOf(\"%\");\n if (zoneIdx !== -1) ip = ip.slice(0, zoneIdx);\n\n const parts = ip.split(\"::\");\n if (parts.length > 2) return null;\n\n const bytes: number[] = new Array(16).fill(0);\n\n const expandGroup = (group: string): number[] => {\n if (!group) return [];\n return group.split(\":\").flatMap((hex) => {\n const val = parseInt(hex || \"0\", 16);\n return [(val >> 8) & 0xff, val & 0xff];\n });\n };\n\n if (parts.length === 1) {\n const expanded = expandGroup(parts[0]!);\n if (expanded.length !== 16) return null;\n return expanded;\n }\n\n const left = expandGroup(parts[0]!);\n const right = expandGroup(parts[1]!);\n\n if (left.length + right.length > 16) return null;\n\n for (let i = 0; i < left.length; i++) bytes[i] = left[i]!;\n for (let i = 0; i < right.length; i++) bytes[16 - right.length + i] = right[i]!;\n\n return bytes;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"security.js"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/utils/cli/help.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,GAAG,SAAe,GAAG,IAAI,CA2ClD"}
|
package/dist/utils/cli/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var chunkNMZ4IMEW_cjs = require('../../chunk-NMZ4IMEW.cjs');
|
|
5
|
-
var
|
|
5
|
+
var chunkM2GEHWPN_cjs = require('../../chunk-M2GEHWPN.cjs');
|
|
6
6
|
var chunkUUNG3GL3_cjs = require('../../chunk-UUNG3GL3.cjs');
|
|
7
7
|
require('../../chunk-OG5ZSXQ5.cjs');
|
|
8
8
|
require('../../chunk-JNIWNSCQ.cjs');
|
|
@@ -40,9 +40,8 @@ var fs__namespace = /*#__PURE__*/_interopNamespace(fs$1);
|
|
|
40
40
|
function toPackageName(name) {
|
|
41
41
|
return name.trim().toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
42
42
|
}
|
|
43
|
-
function
|
|
44
|
-
return {
|
|
45
|
-
"package.json": `{
|
|
43
|
+
function packageJsonTemplate(packageName) {
|
|
44
|
+
return `{
|
|
46
45
|
"name": "${packageName}",
|
|
47
46
|
"version": "0.0.1",
|
|
48
47
|
"description": "Tools extension for @easynet/agent-tool",
|
|
@@ -77,8 +76,10 @@ function templates(packageName) {
|
|
|
77
76
|
},
|
|
78
77
|
"license": "MIT"
|
|
79
78
|
}
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
`;
|
|
80
|
+
}
|
|
81
|
+
function tsconfigTemplate() {
|
|
82
|
+
return `{
|
|
82
83
|
"compilerOptions": {
|
|
83
84
|
"target": "ES2022",
|
|
84
85
|
"module": "NodeNext",
|
|
@@ -97,23 +98,29 @@ function templates(packageName) {
|
|
|
97
98
|
"include": ["./**/*.ts"],
|
|
98
99
|
"exclude": ["node_modules", "dist", "**/dist/**"]
|
|
99
100
|
}
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
`;
|
|
102
|
+
}
|
|
103
|
+
function tsconfigBuildTemplate() {
|
|
104
|
+
return `{
|
|
102
105
|
"extends": "./tsconfig.json",
|
|
103
106
|
"compilerOptions": { "rootDir": ".", "outDir": "dist" },
|
|
104
107
|
"include": ["./**/*.ts"],
|
|
105
108
|
"exclude": ["node_modules", "dist", "**/dist/**", "**/tsconfig*.json", "**/*.test.ts", "test", "scripts", "generate-manifest.ts"]
|
|
106
109
|
}
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
`;
|
|
111
|
+
}
|
|
112
|
+
function generateManifestTemplate() {
|
|
113
|
+
return `/**
|
|
109
114
|
* Build step: run framework generateManifest (scan src, emit manifest).
|
|
110
115
|
* Tool names in the manifest are the exported function names.
|
|
111
116
|
*/
|
|
112
117
|
import { generateManifest } from "@easynet/agent-tool/extension";
|
|
113
118
|
|
|
114
119
|
generateManifest(process.cwd());
|
|
115
|
-
|
|
116
|
-
|
|
120
|
+
`;
|
|
121
|
+
}
|
|
122
|
+
function extensionIndexTemplate() {
|
|
123
|
+
return `import { createExtension } from "@easynet/agent-tool/extension";
|
|
117
124
|
import type { ToolRegistry, ToolAdapter } from "@easynet/agent-tool/runtime";
|
|
118
125
|
|
|
119
126
|
const ext = createExtension({ importMeta: import.meta });
|
|
@@ -128,8 +135,10 @@ export function register(
|
|
|
128
135
|
|
|
129
136
|
export const getExtensionContext = ext.getContext;
|
|
130
137
|
export const runWithExtensionContext = ext.runWith;
|
|
131
|
-
|
|
132
|
-
|
|
138
|
+
`;
|
|
139
|
+
}
|
|
140
|
+
function helloWorldTemplate() {
|
|
141
|
+
return `/**
|
|
133
142
|
* A simple hello-world tool.
|
|
134
143
|
* @tool
|
|
135
144
|
* @effect none
|
|
@@ -147,8 +156,10 @@ export async function helloWorld(_args: Record<string, unknown>) {
|
|
|
147
156
|
],
|
|
148
157
|
};
|
|
149
158
|
}
|
|
150
|
-
|
|
151
|
-
|
|
159
|
+
`;
|
|
160
|
+
}
|
|
161
|
+
function readmeTemplate(packageName) {
|
|
162
|
+
return `# ${packageName}
|
|
152
163
|
|
|
153
164
|
Scaffolded by \`agent-tool init ${packageName}\`.
|
|
154
165
|
|
|
@@ -172,7 +183,17 @@ tools:
|
|
|
172
183
|
\`\`\`
|
|
173
184
|
|
|
174
185
|
Or publish and use: \`npm:@your-scope/${packageName}\`
|
|
175
|
-
|
|
186
|
+
`;
|
|
187
|
+
}
|
|
188
|
+
function templates(packageName) {
|
|
189
|
+
return {
|
|
190
|
+
"package.json": packageJsonTemplate(packageName),
|
|
191
|
+
"tsconfig.json": tsconfigTemplate(),
|
|
192
|
+
"tsconfig.build.json": tsconfigBuildTemplate(),
|
|
193
|
+
"generate-manifest.ts": generateManifestTemplate(),
|
|
194
|
+
"index.ts": extensionIndexTemplate(),
|
|
195
|
+
"src/helloWorld.ts": helloWorldTemplate(),
|
|
196
|
+
"README.md": readmeTemplate(packageName)
|
|
176
197
|
};
|
|
177
198
|
}
|
|
178
199
|
async function initExtension(options) {
|
|
@@ -197,6 +218,52 @@ async function initExtension(options) {
|
|
|
197
218
|
return { targetPath, filesCreated };
|
|
198
219
|
}
|
|
199
220
|
|
|
221
|
+
// src/utils/cli/help.ts
|
|
222
|
+
function printHelp(bin = "agent-tool") {
|
|
223
|
+
process.stdout.write(`
|
|
224
|
+
Usage: ${bin} <command> [options] [args]
|
|
225
|
+
|
|
226
|
+
Primary commands:
|
|
227
|
+
ls List all tools (scope, name, description).
|
|
228
|
+
describe <tool path> Show tool details (schema, capabilities, etc.).
|
|
229
|
+
run <tool path> [params] Run a tool. Params: JSON, e.g. '{"path":"README.md"}'
|
|
230
|
+
start mcp Start MCP server (default: Streamable HTTP; use --stdio for stdio).
|
|
231
|
+
start http Start OpenAPI HTTP server (API + Swagger).
|
|
232
|
+
|
|
233
|
+
Other commands:
|
|
234
|
+
init [extension name] Create extension scaffold (folder + src + hello-world + generate-manifest + index + package.json). With no name: create MCP project in --path. Then: cd <folder> && npm install && npm run build.
|
|
235
|
+
build Scan folder for @tool / SKILL / n8n, generate MCP npm package.
|
|
236
|
+
serve Start the generated MCP server (stdio) for testing.
|
|
237
|
+
list Alias for ls.
|
|
238
|
+
show <tool> Alias for describe.
|
|
239
|
+
help Show this help.
|
|
240
|
+
|
|
241
|
+
Options:
|
|
242
|
+
--path, -p <path> For init/build/serve: path (default: cwd).
|
|
243
|
+
--scope, -s <scope> For init [extension name]: npm package scope (e.g. wallee \u2192 @wallee/<name>).
|
|
244
|
+
--out, -o <path> For build: output directory.
|
|
245
|
+
--include, -i <glob> For build: glob for TS files.
|
|
246
|
+
--include-n8n For build: include n8n workflow tools.
|
|
247
|
+
--verbose, -v Print step logs (config load, cache, tools registered).
|
|
248
|
+
--stdio For start mcp: use stdio transport (default: Streamable HTTP).
|
|
249
|
+
--port <number> For start mcp/http: port (default: 3000).
|
|
250
|
+
--host <string> For start mcp/http: host (default: 127.0.0.1).
|
|
251
|
+
--help, -h Show this help.
|
|
252
|
+
|
|
253
|
+
Examples:
|
|
254
|
+
${bin} ls
|
|
255
|
+
${bin} describe core.fs.readText
|
|
256
|
+
${bin} run core.fs.readText '{"path":"README.md"}'
|
|
257
|
+
${bin} start mcp
|
|
258
|
+
${bin} start mcp --stdio
|
|
259
|
+
${bin} start http --port 3000
|
|
260
|
+
${bin} build --path . --out dist
|
|
261
|
+
${bin} init my-extension
|
|
262
|
+
|
|
263
|
+
For agent run (ReAct + agent.yaml): npx @easynet/agent-orchestra run "task" -c agent.yaml
|
|
264
|
+
`);
|
|
265
|
+
}
|
|
266
|
+
|
|
200
267
|
// src/utils/cli/index.ts
|
|
201
268
|
var DEFAULT_CORE_CONFIG = {
|
|
202
269
|
sandboxRoot: process.cwd(),
|
|
@@ -207,10 +274,10 @@ async function getRuntimeWithTools(pathOpt, verbose = false) {
|
|
|
207
274
|
const stepLog = verbose ? (msg) => process.stderr.write(`[agent-tool] ${msg}
|
|
208
275
|
`) : void 0;
|
|
209
276
|
if (stepLog) stepLog(`Loading tool config from ${searchDir}`);
|
|
210
|
-
const config =
|
|
277
|
+
const config = chunkM2GEHWPN_cjs.findAndLoadToolConfig(searchDir);
|
|
211
278
|
let sandboxRoot = cwd;
|
|
212
279
|
if (config.sandboxedPath && typeof config.sandboxedPath === "string" && config.configPath) {
|
|
213
|
-
sandboxRoot =
|
|
280
|
+
sandboxRoot = chunkM2GEHWPN_cjs.resolveSandboxedPath(config.configPath, config.sandboxedPath);
|
|
214
281
|
}
|
|
215
282
|
if (stepLog) {
|
|
216
283
|
if (config.configPath) {
|
|
@@ -225,7 +292,7 @@ async function getRuntimeWithTools(pathOpt, verbose = false) {
|
|
|
225
292
|
enableSandboxValidation: config.enableSandboxValidation ?? DEFAULT_CORE_CONFIG.enableSandboxValidation,
|
|
226
293
|
allowedHosts: []
|
|
227
294
|
};
|
|
228
|
-
const result = await
|
|
295
|
+
const result = await chunkM2GEHWPN_cjs.createRuntimeFromConfig({
|
|
229
296
|
coreTools: coreConfig,
|
|
230
297
|
configFilePath: config.configPath,
|
|
231
298
|
stepLog
|
|
@@ -313,51 +380,6 @@ function parseArgv(argv) {
|
|
|
313
380
|
}
|
|
314
381
|
return { command, startSub, help, verbose, mcpStdio, pathOpt, extensionName, scope, outDir, include, includeN8n, toolName, toolArgsJson, port, host };
|
|
315
382
|
}
|
|
316
|
-
function printHelp() {
|
|
317
|
-
const bin = "agent-tool";
|
|
318
|
-
process.stdout.write(`
|
|
319
|
-
Usage: ${bin} <command> [options] [args]
|
|
320
|
-
|
|
321
|
-
Primary commands:
|
|
322
|
-
ls List all tools (scope, name, description).
|
|
323
|
-
describe <tool path> Show tool details (schema, capabilities, etc.).
|
|
324
|
-
run <tool path> [params] Run a tool. Params: JSON, e.g. '{"path":"README.md"}'
|
|
325
|
-
start mcp Start MCP server (default: Streamable HTTP; use --stdio for stdio).
|
|
326
|
-
start http Start OpenAPI HTTP server (API + Swagger).
|
|
327
|
-
|
|
328
|
-
Other commands:
|
|
329
|
-
init [extension name] Create extension scaffold (folder + src + hello-world + generate-manifest + index + package.json). With no name: create MCP project in --path. Then: cd <folder> && npm install && npm run build.
|
|
330
|
-
build Scan folder for @tool / SKILL / n8n, generate MCP npm package.
|
|
331
|
-
serve Start the generated MCP server (stdio) for testing.
|
|
332
|
-
list Alias for ls.
|
|
333
|
-
show <tool> Alias for describe.
|
|
334
|
-
help Show this help.
|
|
335
|
-
|
|
336
|
-
Options:
|
|
337
|
-
--path, -p <path> For init/build/serve: path (default: cwd).
|
|
338
|
-
--scope, -s <scope> For init [extension name]: npm package scope (e.g. wallee \u2192 @wallee/<name>).
|
|
339
|
-
--out, -o <path> For build: output directory.
|
|
340
|
-
--include, -i <glob> For build: glob for TS files.
|
|
341
|
-
--include-n8n For build: include n8n workflow tools.
|
|
342
|
-
--verbose, -v Print step logs (config load, cache, tools registered).
|
|
343
|
-
--stdio For start mcp: use stdio transport (default: Streamable HTTP).
|
|
344
|
-
--port <number> For start mcp/http: port (default: 3000).
|
|
345
|
-
--host <string> For start mcp/http: host (default: 127.0.0.1).
|
|
346
|
-
--help, -h Show this help.
|
|
347
|
-
|
|
348
|
-
Examples:
|
|
349
|
-
${bin} ls
|
|
350
|
-
${bin} describe core.fs.readText
|
|
351
|
-
${bin} run core.fs.readText '{"path":"README.md"}'
|
|
352
|
-
${bin} start mcp
|
|
353
|
-
${bin} start mcp --stdio
|
|
354
|
-
${bin} start http --port 3000
|
|
355
|
-
${bin} build --path . --out dist
|
|
356
|
-
${bin} init my-extension
|
|
357
|
-
|
|
358
|
-
For agent run (ReAct + agent.yaml): npx @easynet/agent-orchestra run "task" -c agent.yaml
|
|
359
|
-
`);
|
|
360
|
-
}
|
|
361
383
|
async function cmdInitExtension(extensionName, pathOpt, scope) {
|
|
362
384
|
try {
|
|
363
385
|
const parentDir = pathOpt ? path2__namespace.default.resolve(process.cwd(), pathOpt) : void 0;
|
|
@@ -434,7 +456,7 @@ var LS_DESC_MAX = 72;
|
|
|
434
456
|
function formatLsOutput(specs) {
|
|
435
457
|
const rows = specs.map((spec) => {
|
|
436
458
|
const { name } = parseToolName(spec.name);
|
|
437
|
-
const scope =
|
|
459
|
+
const scope = chunkM2GEHWPN_cjs.getDisplayScope(spec.name, spec.kind, spec.version);
|
|
438
460
|
const desc = (spec.description ?? "").replace(/\n/g, " ").trim().slice(0, LS_DESC_MAX);
|
|
439
461
|
return { scope, name, description: desc || "(no description)" };
|
|
440
462
|
});
|
|
@@ -461,7 +483,7 @@ function formatLsOutput(specs) {
|
|
|
461
483
|
}
|
|
462
484
|
function formatDescribeOutput(spec) {
|
|
463
485
|
const { name: localName } = parseToolName(spec.name);
|
|
464
|
-
const scope =
|
|
486
|
+
const scope = chunkM2GEHWPN_cjs.getDisplayScope(spec.name, spec.kind, spec.version);
|
|
465
487
|
const sections = [];
|
|
466
488
|
sections.push("\u250C\u2500 Tool");
|
|
467
489
|
sections.push(`\u2502 name: ${spec.name}`);
|
|
@@ -497,7 +519,7 @@ async function cmdLs(pathOpt, verbose = false) {
|
|
|
497
519
|
process.stdout.write("No tools registered.\n");
|
|
498
520
|
const cwd = process.cwd();
|
|
499
521
|
const searchDir = path2__namespace.default.resolve(cwd, pathOpt ?? ".");
|
|
500
|
-
const config =
|
|
522
|
+
const config = chunkM2GEHWPN_cjs.findAndLoadToolConfig(searchDir);
|
|
501
523
|
const hasNpmTools = Array.isArray(config.tools) && config.tools.some((t) => typeof t === "string" && t.startsWith("npm:"));
|
|
502
524
|
if (hasNpmTools) {
|
|
503
525
|
process.stdout.write(
|
|
@@ -522,7 +544,7 @@ async function cmdDescribe(toolName, pathOpt, verbose = false) {
|
|
|
522
544
|
}
|
|
523
545
|
try {
|
|
524
546
|
const { registry } = await getRuntimeWithTools(pathOpt, verbose);
|
|
525
|
-
const registryName =
|
|
547
|
+
const registryName = chunkM2GEHWPN_cjs.resolveToolDescriptor(toolName.trim());
|
|
526
548
|
const spec = registry.get(registryName);
|
|
527
549
|
if (!spec) {
|
|
528
550
|
process.stderr.write(`Tool not found: ${toolName}
|
|
@@ -571,7 +593,7 @@ async function cmdRun(toolName, toolArgsJson, pathOpt, verbose = false) {
|
|
|
571
593
|
}
|
|
572
594
|
try {
|
|
573
595
|
const { runtime, registry } = await getRuntimeWithTools(pathOpt, verbose);
|
|
574
|
-
const registryName =
|
|
596
|
+
const registryName = chunkM2GEHWPN_cjs.resolveToolDescriptor(toolName.trim());
|
|
575
597
|
if (!registry.get(registryName)) {
|
|
576
598
|
process.stderr.write(`Tool not found: ${toolName}
|
|
577
599
|
`);
|
|
@@ -599,10 +621,10 @@ async function cmdStartMcp(pathOpt, verbose = false, stdio = false, port = 3e3,
|
|
|
599
621
|
try {
|
|
600
622
|
const { runtime } = await getRuntimeWithTools(pathOpt, verbose);
|
|
601
623
|
if (stdio) {
|
|
602
|
-
await
|
|
624
|
+
await chunkM2GEHWPN_cjs.runMCPServerOverStdio(runtime);
|
|
603
625
|
return 0;
|
|
604
626
|
}
|
|
605
|
-
const streamable = await
|
|
627
|
+
const streamable = await chunkM2GEHWPN_cjs.createMCPServerStreamableHttp(runtime, { port, host, path: "/mcp" });
|
|
606
628
|
const { url, port: actualPort } = await streamable.listen(port, host);
|
|
607
629
|
process.stdout.write(`MCP Streamable HTTP: ${url}
|
|
608
630
|
`);
|
|
@@ -618,7 +640,7 @@ async function cmdStartMcp(pathOpt, verbose = false, stdio = false, port = 3e3,
|
|
|
618
640
|
async function cmdStartHttp(port, host, pathOpt, verbose = false) {
|
|
619
641
|
try {
|
|
620
642
|
const { runtime } = await getRuntimeWithTools(pathOpt, verbose);
|
|
621
|
-
const http = await
|
|
643
|
+
const http = await chunkM2GEHWPN_cjs.createHttpService(runtime);
|
|
622
644
|
const { port: actualPort, host: actualHost } = await http.listen({ port, host });
|
|
623
645
|
const base = `http://${actualHost}:${actualPort}`;
|
|
624
646
|
process.stdout.write(`API: ${base}/invoke (POST), ${base}/tools (GET)
|