@pentoshi/clai 0.10.5 → 0.11.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 +32 -0
- package/dist/agent/runner.js +41 -3
- package/dist/agent/runner.js.map +1 -1
- package/dist/commands/providers.js +28 -0
- package/dist/commands/providers.js.map +1 -1
- package/dist/commands/search-providers.d.ts +50 -0
- package/dist/commands/search-providers.js +134 -0
- package/dist/commands/search-providers.js.map +1 -0
- package/dist/commands/update.js +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/llm/provider.js +9 -6
- package/dist/llm/provider.js.map +1 -1
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.js +6 -0
- package/dist/prompts/index.js.map +1 -1
- package/dist/safety/classifier.js +40 -0
- package/dist/safety/classifier.js.map +1 -1
- package/dist/store/config.d.ts +5 -0
- package/dist/store/config.js +7 -0
- package/dist/store/config.js.map +1 -1
- package/dist/store/keys.d.ts +65 -0
- package/dist/store/keys.js +164 -28
- package/dist/store/keys.js.map +1 -1
- package/dist/tools/http.d.ts +12 -1
- package/dist/tools/http.js +8 -43
- package/dist/tools/http.js.map +1 -1
- package/dist/tools/registry.js +52 -0
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/shell.d.ts +25 -0
- package/dist/tools/shell.js +155 -6
- package/dist/tools/shell.js.map +1 -1
- package/dist/tools/web/audit.d.ts +154 -0
- package/dist/tools/web/audit.js +147 -0
- package/dist/tools/web/audit.js.map +1 -0
- package/dist/tools/web/budget.d.ts +76 -0
- package/dist/tools/web/budget.js +187 -0
- package/dist/tools/web/budget.js.map +1 -0
- package/dist/tools/web/capture.d.ts +201 -0
- package/dist/tools/web/capture.js +380 -0
- package/dist/tools/web/capture.js.map +1 -0
- package/dist/tools/web/fetch-core.d.ts +66 -0
- package/dist/tools/web/fetch-core.js +1123 -0
- package/dist/tools/web/fetch-core.js.map +1 -0
- package/dist/tools/web/fetch.d.ts +42 -0
- package/dist/tools/web/fetch.js +115 -0
- package/dist/tools/web/fetch.js.map +1 -0
- package/dist/tools/web/providers/brave.d.ts +46 -0
- package/dist/tools/web/providers/brave.js +263 -0
- package/dist/tools/web/providers/brave.js.map +1 -0
- package/dist/tools/web/providers/duckduckgo.d.ts +47 -0
- package/dist/tools/web/providers/duckduckgo.js +248 -0
- package/dist/tools/web/providers/duckduckgo.js.map +1 -0
- package/dist/tools/web/providers/provider.d.ts +99 -0
- package/dist/tools/web/providers/provider.js +38 -0
- package/dist/tools/web/providers/provider.js.map +1 -0
- package/dist/tools/web/providers/tavily.d.ts +52 -0
- package/dist/tools/web/providers/tavily.js +285 -0
- package/dist/tools/web/providers/tavily.js.map +1 -0
- package/dist/tools/web/readable.d.ts +67 -0
- package/dist/tools/web/readable.js +248 -0
- package/dist/tools/web/readable.js.map +1 -0
- package/dist/tools/web/redact.d.ts +120 -0
- package/dist/tools/web/redact.js +155 -0
- package/dist/tools/web/redact.js.map +1 -0
- package/dist/tools/web/search.d.ts +51 -0
- package/dist/tools/web/search.js +389 -0
- package/dist/tools/web/search.js.map +1 -0
- package/dist/tools/web/ssrf-guard.d.ts +85 -0
- package/dist/tools/web/ssrf-guard.js +265 -0
- package/dist/tools/web/ssrf-guard.js.map +1 -0
- package/dist/tools/web/types.d.ts +331 -0
- package/dist/tools/web/types.js +71 -0
- package/dist/tools/web/types.js.map +1 -0
- package/dist/ui/spinner.js +87 -14
- package/dist/ui/spinner.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSRF guard — classifies an address (or a hostname literal) as belonging
|
|
3
|
+
* to a private/loopback/link-local/cloud-metadata/CGNAT range.
|
|
4
|
+
*
|
|
5
|
+
* The structured {@link classify} / {@link classifyHost} helpers are used
|
|
6
|
+
* by the `web.fetch` pipeline (synchronous classifier branch + per-hop
|
|
7
|
+
* resolution check) and by the safety classifier in
|
|
8
|
+
* `src/safety/classifier.ts`.
|
|
9
|
+
*
|
|
10
|
+
* The boolean {@link isBlockedAddress} re-export preserves the legacy shape
|
|
11
|
+
* used by `src/tools/http.ts` so existing `http.fetch` semantics are
|
|
12
|
+
* unchanged.
|
|
13
|
+
*
|
|
14
|
+
* Per the design (see `.kiro/specs/web-search-and-fetch/design.md`,
|
|
15
|
+
* "Sequencing of changes" step 2 and "Safety classifier integration"), this
|
|
16
|
+
* module is the single source of truth for address classification — both
|
|
17
|
+
* the legacy `http.fetch` SSRF check and the new `web.fetch` checks
|
|
18
|
+
* delegate here.
|
|
19
|
+
*/
|
|
20
|
+
import net from "node:net";
|
|
21
|
+
/**
|
|
22
|
+
* Return `true` iff `url` parses as an absolute URL whose scheme is exactly
|
|
23
|
+
* `http:` or `https:`. Returns `false` for any other scheme (including
|
|
24
|
+
* `ftp:`, `file:`, `data:`, `javascript:`, `gopher:`), for empty strings,
|
|
25
|
+
* for malformed inputs that fail `new URL()` parsing, and for non-string
|
|
26
|
+
* inputs.
|
|
27
|
+
*
|
|
28
|
+
* This is the synchronous half of the "scheme allowlist" check enforced
|
|
29
|
+
* by the `web.fetch` pipeline (see Requirement 5.4 / 2.1). It is the
|
|
30
|
+
* single source of truth for the scheme allow-list so the safety
|
|
31
|
+
* classifier branch and the fetch-core argument validator stay in sync.
|
|
32
|
+
*/
|
|
33
|
+
export function isAllowedScheme(url) {
|
|
34
|
+
if (typeof url !== "string" || url.length === 0)
|
|
35
|
+
return false;
|
|
36
|
+
let parsed;
|
|
37
|
+
try {
|
|
38
|
+
parsed = new URL(url);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Hostname literals that are known to refer to the local host without any
|
|
47
|
+
* DNS lookup. Lower-cased for case-insensitive comparison.
|
|
48
|
+
*/
|
|
49
|
+
const LOOPBACK_HOSTNAMES = new Set([
|
|
50
|
+
"localhost",
|
|
51
|
+
"localhost.localdomain",
|
|
52
|
+
"ip6-localhost",
|
|
53
|
+
"ip6-loopback",
|
|
54
|
+
]);
|
|
55
|
+
/** IPv4 cloud-metadata address (AWS EC2, GCP, Azure all share this). */
|
|
56
|
+
const IPV4_CLOUD_METADATA = "169.254.169.254";
|
|
57
|
+
/**
|
|
58
|
+
* Classify a literal IP address (IPv4 or IPv6).
|
|
59
|
+
*
|
|
60
|
+
* Returns `{ class }` when the address falls into one of the
|
|
61
|
+
* {@link AddressClass} buckets, or `null` when the input is a
|
|
62
|
+
* globally-routable address (or fails to parse as either family).
|
|
63
|
+
*
|
|
64
|
+
* The check is fully synchronous and never performs DNS.
|
|
65
|
+
*/
|
|
66
|
+
export function classify(ip) {
|
|
67
|
+
if (typeof ip !== "string" || ip.length === 0)
|
|
68
|
+
return null;
|
|
69
|
+
if (net.isIPv4(ip))
|
|
70
|
+
return classifyIpv4(ip);
|
|
71
|
+
if (net.isIPv6(ip))
|
|
72
|
+
return classifyIpv6(ip);
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Classify a hostname or IP literal without performing DNS resolution.
|
|
77
|
+
*
|
|
78
|
+
* - For literal IPv4/IPv6 addresses (with or without surrounding `[…]`
|
|
79
|
+
* brackets), this delegates to {@link classify}.
|
|
80
|
+
* - For known-bad hostname literals (`localhost`, `localhost.localdomain`,
|
|
81
|
+
* `ip6-localhost`, `ip6-loopback`), this returns `{ class: "loopback" }`.
|
|
82
|
+
* - For every other hostname, this returns `null` (the caller is
|
|
83
|
+
* responsible for the DNS-resolved second pass; see
|
|
84
|
+
* `src/tools/web/fetch-core.ts`).
|
|
85
|
+
*/
|
|
86
|
+
export function classifyHost(hostname) {
|
|
87
|
+
if (typeof hostname !== "string" || hostname.length === 0)
|
|
88
|
+
return null;
|
|
89
|
+
// Strip IPv6 brackets if the caller passed `[::1]` style.
|
|
90
|
+
const stripped = hostname.replace(/^\[|\]$/g, "");
|
|
91
|
+
const lower = stripped.toLowerCase();
|
|
92
|
+
if (LOOPBACK_HOSTNAMES.has(lower))
|
|
93
|
+
return { class: "loopback" };
|
|
94
|
+
return classify(stripped);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Legacy boolean shape preserved for the existing `http.fetch` SSRF check.
|
|
98
|
+
*
|
|
99
|
+
* Returns `true` whenever {@link classifyHost} would return a non-null
|
|
100
|
+
* classification, plus a small additional set of historically-blocked
|
|
101
|
+
* ranges (currently `0.0.0.0/8`, the "this network" range) that are kept
|
|
102
|
+
* for backward compatibility with the previous `http.ts` implementation
|
|
103
|
+
* but are not enumerated in the public {@link AddressClass} list.
|
|
104
|
+
*/
|
|
105
|
+
export function isBlockedAddress(host) {
|
|
106
|
+
if (classifyHost(host) !== null)
|
|
107
|
+
return true;
|
|
108
|
+
// Preserve legacy semantics: `0.0.0.0/8` was blocked by the previous
|
|
109
|
+
// implementation in `src/tools/http.ts`. It is not exposed via the
|
|
110
|
+
// public `classify` enum because it is rarely useful as a fetch target
|
|
111
|
+
// and is not called out by Requirement 5.3, but we keep blocking it.
|
|
112
|
+
const stripped = host.replace(/^\[|\]$/g, "");
|
|
113
|
+
if (net.isIPv4(stripped)) {
|
|
114
|
+
const first = Number(stripped.split(".")[0]);
|
|
115
|
+
if (Number.isInteger(first) && first === 0)
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
if (net.isIPv6(stripped)) {
|
|
119
|
+
const hextets = ipv6Hextets(stripped);
|
|
120
|
+
if (hextets) {
|
|
121
|
+
// ::ffff:<v4> with embedded `0.x.x.x` legacy block.
|
|
122
|
+
if (hextets[0] === 0 &&
|
|
123
|
+
hextets[1] === 0 &&
|
|
124
|
+
hextets[2] === 0 &&
|
|
125
|
+
hextets[3] === 0 &&
|
|
126
|
+
hextets[4] === 0 &&
|
|
127
|
+
hextets[5] === 0xffff) {
|
|
128
|
+
const embeddedFirstOctet = (hextets[6] >> 8) & 0xff;
|
|
129
|
+
if (embeddedFirstOctet === 0)
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
// Internals
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
function classifyIpv4(ip) {
|
|
140
|
+
const parts = ip.split(".").map((p) => Number(p));
|
|
141
|
+
if (parts.length !== 4 ||
|
|
142
|
+
parts.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
// Cloud-metadata literal must win over the broader 169.254.0.0/16
|
|
146
|
+
// link-local range so the class returned is the most specific one.
|
|
147
|
+
if (ip === IPV4_CLOUD_METADATA)
|
|
148
|
+
return { class: "cloud-metadata" };
|
|
149
|
+
const [a, b] = parts;
|
|
150
|
+
if (a === 127)
|
|
151
|
+
return { class: "loopback" };
|
|
152
|
+
if (a === 10)
|
|
153
|
+
return { class: "rfc1918" };
|
|
154
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
155
|
+
return { class: "rfc1918" };
|
|
156
|
+
if (a === 192 && b === 168)
|
|
157
|
+
return { class: "rfc1918" };
|
|
158
|
+
if (a === 169 && b === 254)
|
|
159
|
+
return { class: "ipv4-link-local" };
|
|
160
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
161
|
+
return { class: "cgnat" };
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
function classifyIpv6(ip) {
|
|
165
|
+
const hextets = ipv6Hextets(ip);
|
|
166
|
+
if (!hextets)
|
|
167
|
+
return null;
|
|
168
|
+
// ::1 (loopback): all-zero except last hextet === 1.
|
|
169
|
+
if (hextets[0] === 0 &&
|
|
170
|
+
hextets[1] === 0 &&
|
|
171
|
+
hextets[2] === 0 &&
|
|
172
|
+
hextets[3] === 0 &&
|
|
173
|
+
hextets[4] === 0 &&
|
|
174
|
+
hextets[5] === 0 &&
|
|
175
|
+
hextets[6] === 0 &&
|
|
176
|
+
hextets[7] === 1) {
|
|
177
|
+
return { class: "loopback" };
|
|
178
|
+
}
|
|
179
|
+
// IPv4-mapped IPv6 (::ffff:0:0/96): recurse on the embedded v4 address
|
|
180
|
+
// so the embedded address gets the most specific class.
|
|
181
|
+
if (hextets[0] === 0 &&
|
|
182
|
+
hextets[1] === 0 &&
|
|
183
|
+
hextets[2] === 0 &&
|
|
184
|
+
hextets[3] === 0 &&
|
|
185
|
+
hextets[4] === 0 &&
|
|
186
|
+
hextets[5] === 0xffff) {
|
|
187
|
+
const a = (hextets[6] >> 8) & 0xff;
|
|
188
|
+
const b = hextets[6] & 0xff;
|
|
189
|
+
const c = (hextets[7] >> 8) & 0xff;
|
|
190
|
+
const d = hextets[7] & 0xff;
|
|
191
|
+
return classifyIpv4(`${a}.${b}.${c}.${d}`);
|
|
192
|
+
}
|
|
193
|
+
// IPv6 cloud-metadata literal `fd00:ec2::254` must be checked before the
|
|
194
|
+
// generic ULA match, otherwise it would be classified as rfc1918.
|
|
195
|
+
if (hextets[0] === 0xfd00 &&
|
|
196
|
+
hextets[1] === 0x0ec2 &&
|
|
197
|
+
hextets[2] === 0 &&
|
|
198
|
+
hextets[3] === 0 &&
|
|
199
|
+
hextets[4] === 0 &&
|
|
200
|
+
hextets[5] === 0 &&
|
|
201
|
+
hextets[6] === 0 &&
|
|
202
|
+
hextets[7] === 0x0254) {
|
|
203
|
+
return { class: "cloud-metadata" };
|
|
204
|
+
}
|
|
205
|
+
// fe80::/10 (IPv6 link-local): top 10 bits == 1111 1110 10.
|
|
206
|
+
if ((hextets[0] & 0xffc0) === 0xfe80) {
|
|
207
|
+
return { class: "ipv6-link-local" };
|
|
208
|
+
}
|
|
209
|
+
// fc00::/7 (Unique Local Addresses, the IPv6 cousin of RFC1918).
|
|
210
|
+
if ((hextets[0] & 0xfe00) === 0xfc00) {
|
|
211
|
+
return { class: "rfc1918" };
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Expand an IPv6 address (string form) into its 8 hextets as integers.
|
|
217
|
+
*
|
|
218
|
+
* Supports `::` compression and the IPv4-in-last-32-bits form
|
|
219
|
+
* (e.g. `::ffff:127.0.0.1`). Returns `null` if the input does not parse
|
|
220
|
+
* as a valid IPv6 address.
|
|
221
|
+
*/
|
|
222
|
+
function ipv6Hextets(addr) {
|
|
223
|
+
if (!net.isIPv6(addr))
|
|
224
|
+
return null;
|
|
225
|
+
let normalized = addr.toLowerCase();
|
|
226
|
+
// Translate any embedded IPv4 dotted-quad in the last 32 bits into two
|
|
227
|
+
// hextets so the rest of the parser can deal with a uniform format.
|
|
228
|
+
const v4Match = normalized.match(/^(.*:)([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})$/);
|
|
229
|
+
if (v4Match) {
|
|
230
|
+
const prefix = v4Match[1];
|
|
231
|
+
const v4Parts = v4Match[2].split(".").map((p) => Number(p));
|
|
232
|
+
if (v4Parts.length !== 4 ||
|
|
233
|
+
v4Parts.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
const hex1 = ((v4Parts[0] << 8) | v4Parts[1]).toString(16);
|
|
237
|
+
const hex2 = ((v4Parts[2] << 8) | v4Parts[3]).toString(16);
|
|
238
|
+
normalized = `${prefix}${hex1}:${hex2}`;
|
|
239
|
+
}
|
|
240
|
+
const parts = normalized.split("::");
|
|
241
|
+
if (parts.length > 2)
|
|
242
|
+
return null;
|
|
243
|
+
const head = parts[0].length > 0 ? parts[0].split(":") : [];
|
|
244
|
+
const tail = parts.length === 2 && parts[1].length > 0 ? parts[1].split(":") : [];
|
|
245
|
+
const hasCompression = parts.length === 2;
|
|
246
|
+
if (!hasCompression && head.length !== 8)
|
|
247
|
+
return null;
|
|
248
|
+
const missing = 8 - head.length - tail.length;
|
|
249
|
+
if (missing < 0)
|
|
250
|
+
return null;
|
|
251
|
+
if (hasCompression && missing < 1)
|
|
252
|
+
return null;
|
|
253
|
+
const middle = hasCompression ? Array(missing).fill("0") : [];
|
|
254
|
+
const all = [...head, ...middle, ...tail];
|
|
255
|
+
if (all.length !== 8)
|
|
256
|
+
return null;
|
|
257
|
+
const hextets = [];
|
|
258
|
+
for (const h of all) {
|
|
259
|
+
if (!/^[0-9a-f]{1,4}$/.test(h))
|
|
260
|
+
return null;
|
|
261
|
+
hextets.push(parseInt(h, 16));
|
|
262
|
+
}
|
|
263
|
+
return hextets;
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=ssrf-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf-guard.js","sourceRoot":"","sources":["../../../src/tools/web/ssrf-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared TypeScript types for the `web.search` and `web.fetch` tools.
|
|
3
|
+
*
|
|
4
|
+
* Field shapes, ranges, and defaults match the "Data Models" section of
|
|
5
|
+
* `.kiro/specs/web-search-and-fetch/design.md` and the acceptance
|
|
6
|
+
* criteria in Requirements 1, 2, and 7.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Identifier of a search provider supported by the Web_Search_Tool.
|
|
10
|
+
*
|
|
11
|
+
* The set is intentionally independent of the LLM `ProviderId` union so the
|
|
12
|
+
* two keyspaces stay decoupled.
|
|
13
|
+
*/
|
|
14
|
+
export type SearchProviderId = "brave" | "tavily" | "duckduckgo";
|
|
15
|
+
/** Convenience tuple form of the {@link SearchProviderId} union. */
|
|
16
|
+
export declare const searchProviderIds: readonly SearchProviderId[];
|
|
17
|
+
/**
|
|
18
|
+
* Arguments accepted by the `web.search` tool.
|
|
19
|
+
*
|
|
20
|
+
* - `query`: 1..400 chars after trimming leading/trailing whitespace
|
|
21
|
+
* (Requirement 1.1).
|
|
22
|
+
* - `maxResults`: integer in `[1, 20]`; defaults to 5 when omitted
|
|
23
|
+
* (Requirement 1.2).
|
|
24
|
+
*/
|
|
25
|
+
export interface WebSearchArgs {
|
|
26
|
+
query: string;
|
|
27
|
+
maxResults?: number;
|
|
28
|
+
}
|
|
29
|
+
/** Default value applied when `WebSearchArgs.maxResults` is omitted. */
|
|
30
|
+
export declare const DEFAULT_MAX_RESULTS = 5;
|
|
31
|
+
/** Inclusive minimum allowed for `WebSearchArgs.maxResults`. */
|
|
32
|
+
export declare const MIN_MAX_RESULTS = 1;
|
|
33
|
+
/** Inclusive maximum allowed for `WebSearchArgs.maxResults`. */
|
|
34
|
+
export declare const MAX_MAX_RESULTS = 20;
|
|
35
|
+
/** Inclusive minimum allowed for `WebSearchArgs.query` length after trim. */
|
|
36
|
+
export declare const MIN_QUERY_LENGTH = 1;
|
|
37
|
+
/** Inclusive maximum allowed for `WebSearchArgs.query` length after trim. */
|
|
38
|
+
export declare const MAX_QUERY_LENGTH = 400;
|
|
39
|
+
/**
|
|
40
|
+
* A single search hit returned by `web.search`.
|
|
41
|
+
*
|
|
42
|
+
* - `title`: 1..512 chars (Requirement 1.3).
|
|
43
|
+
* - `url`: absolute URL with scheme `http://` or `https://`, no whitespace,
|
|
44
|
+
* no ASCII control characters (Requirements 1.3, 7.1, 7.3).
|
|
45
|
+
* - `snippet`: 0..2048 chars (Requirement 1.3).
|
|
46
|
+
*/
|
|
47
|
+
export interface SearchResult {
|
|
48
|
+
title: string;
|
|
49
|
+
url: string;
|
|
50
|
+
snippet: string;
|
|
51
|
+
}
|
|
52
|
+
/** Inclusive minimum allowed for `SearchResult.title` length. */
|
|
53
|
+
export declare const MIN_TITLE_LENGTH = 1;
|
|
54
|
+
/** Inclusive maximum allowed for `SearchResult.title` length. */
|
|
55
|
+
export declare const MAX_TITLE_LENGTH = 512;
|
|
56
|
+
/** Inclusive minimum allowed for `SearchResult.snippet` length. */
|
|
57
|
+
export declare const MIN_SNIPPET_LENGTH = 0;
|
|
58
|
+
/** Inclusive maximum allowed for `SearchResult.snippet` length. */
|
|
59
|
+
export declare const MAX_SNIPPET_LENGTH = 2048;
|
|
60
|
+
/**
|
|
61
|
+
* Categorical kinds of failures the `web.search` pipeline can surface.
|
|
62
|
+
*
|
|
63
|
+
* The mapping to acceptance criteria is:
|
|
64
|
+
* - `auth` → Requirement 6.1 (401/403)
|
|
65
|
+
* - `rate-limit` → Requirement 6.2 (429)
|
|
66
|
+
* - `network` → Requirement 6.3 (DNS/connect/TLS)
|
|
67
|
+
* - `parse` → Requirement 6.5 (bad provider response)
|
|
68
|
+
* - `server` → Requirement 6.6 (5xx)
|
|
69
|
+
* - `http` → Requirement 1.9 (other non-2xx)
|
|
70
|
+
* - `timeout` → Requirement 1.8 (>15 s elapsed)
|
|
71
|
+
* - `missing-key` → Requirement 3.4
|
|
72
|
+
* - `validation` → Requirements 1.5, 1.6
|
|
73
|
+
*/
|
|
74
|
+
export type WebSearchErrorKind = "auth" | "rate-limit" | "network" | "parse" | "server" | "http" | "timeout" | "missing-key" | "validation";
|
|
75
|
+
/** Structured failure detail accompanying an `ok=false` search outcome. */
|
|
76
|
+
export interface WebSearchError {
|
|
77
|
+
kind: WebSearchErrorKind;
|
|
78
|
+
provider: SearchProviderId;
|
|
79
|
+
status?: number;
|
|
80
|
+
message: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Internal typed result of a `web.search` invocation, prior to being
|
|
84
|
+
* adapted into a `ToolResult` by the registry handler.
|
|
85
|
+
*/
|
|
86
|
+
export interface WebSearchOutcome {
|
|
87
|
+
ok: boolean;
|
|
88
|
+
provider: SearchProviderId;
|
|
89
|
+
/** At most `maxResults` entries; may be empty (Requirement 1.7). */
|
|
90
|
+
results: SearchResult[];
|
|
91
|
+
error?: WebSearchError;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Mode controlling how the `web.fetch` tool emits the response body.
|
|
95
|
+
*
|
|
96
|
+
* - `readable`: HTML/XHTML stripped to text; non-HTML text passed through
|
|
97
|
+
* (Requirements 2.4, 2.5, 2.28).
|
|
98
|
+
* - `raw`: response bytes decoded as UTF-8 with replacement, truncated to
|
|
99
|
+
* `maxBytes` (Requirement 2.29).
|
|
100
|
+
*/
|
|
101
|
+
export type ResponseMode = "readable" | "raw";
|
|
102
|
+
/** Allowed values for `WebFetchArgs.responseMode`. */
|
|
103
|
+
export declare const RESPONSE_MODES: readonly ResponseMode[];
|
|
104
|
+
/**
|
|
105
|
+
* Arguments accepted by the `web.fetch` tool.
|
|
106
|
+
*
|
|
107
|
+
* Defaults applied when an optional argument is omitted:
|
|
108
|
+
* - `maxBytes` → {@link DEFAULT_MAX_BYTES} (Requirement 2.2)
|
|
109
|
+
* - `includeHeaders` → `true` (Requirement 2.15)
|
|
110
|
+
* - `includeTls` → `true` for `https://`, `false` for `http://`
|
|
111
|
+
* (Requirement 2.16)
|
|
112
|
+
* - `includeTiming` → `true` (Requirement 2.17)
|
|
113
|
+
* - `includeRedirectChain` → `true` (Requirement 2.18)
|
|
114
|
+
* - `responseMode` → `"readable"` (Requirement 2.19)
|
|
115
|
+
* - `redactSensitive` → `true` (Requirement 2.20)
|
|
116
|
+
*/
|
|
117
|
+
export interface WebFetchArgs {
|
|
118
|
+
url: string;
|
|
119
|
+
maxBytes?: number;
|
|
120
|
+
includeHeaders?: boolean;
|
|
121
|
+
includeTls?: boolean;
|
|
122
|
+
includeTiming?: boolean;
|
|
123
|
+
includeRedirectChain?: boolean;
|
|
124
|
+
responseMode?: ResponseMode;
|
|
125
|
+
redactSensitive?: boolean;
|
|
126
|
+
}
|
|
127
|
+
/** Default value applied when `WebFetchArgs.maxBytes` is omitted. */
|
|
128
|
+
export declare const DEFAULT_MAX_BYTES = 262144;
|
|
129
|
+
/** Inclusive minimum allowed for `WebFetchArgs.maxBytes`. */
|
|
130
|
+
export declare const MIN_MAX_BYTES = 1024;
|
|
131
|
+
/** Inclusive maximum allowed for `WebFetchArgs.maxBytes`. */
|
|
132
|
+
export declare const MAX_MAX_BYTES = 1048576;
|
|
133
|
+
/** Default value applied when `WebFetchArgs.includeHeaders` is omitted. */
|
|
134
|
+
export declare const DEFAULT_INCLUDE_HEADERS = true;
|
|
135
|
+
/** Default value applied when `WebFetchArgs.includeTiming` is omitted. */
|
|
136
|
+
export declare const DEFAULT_INCLUDE_TIMING = true;
|
|
137
|
+
/** Default value applied when `WebFetchArgs.includeRedirectChain` is omitted. */
|
|
138
|
+
export declare const DEFAULT_INCLUDE_REDIRECT_CHAIN = true;
|
|
139
|
+
/** Default value applied when `WebFetchArgs.responseMode` is omitted. */
|
|
140
|
+
export declare const DEFAULT_RESPONSE_MODE: ResponseMode;
|
|
141
|
+
/** Default value applied when `WebFetchArgs.redactSensitive` is omitted. */
|
|
142
|
+
export declare const DEFAULT_REDACT_SENSITIVE = true;
|
|
143
|
+
/** Maximum number of redirect hops followed per `web.fetch` invocation. */
|
|
144
|
+
export declare const MAX_REDIRECT_HOPS = 5;
|
|
145
|
+
/** Maximum number of `Set-Cookie` entries captured per invocation. */
|
|
146
|
+
export declare const MAX_COOKIES_CAPTURED = 32;
|
|
147
|
+
/** Per-header-value character cap before `[...truncated]` is appended. */
|
|
148
|
+
export declare const MAX_HEADER_VALUE_LENGTH = 4096;
|
|
149
|
+
/** Marker appended to any header value or body preview shortened by the tool. */
|
|
150
|
+
export declare const TRUNCATION_MARKER = "[...truncated]";
|
|
151
|
+
/** Literal placeholder used wherever sensitive values are redacted. */
|
|
152
|
+
export declare const REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
153
|
+
/** Combined serialized-size cap for fetch metadata in bytes. */
|
|
154
|
+
export declare const METADATA_BUDGET_BYTES = 65536;
|
|
155
|
+
/** Maximum size in bytes of the `bodyPreview` returned for HTTP errors. */
|
|
156
|
+
export declare const HTTP_ERROR_BODY_PREVIEW_BYTES = 4096;
|
|
157
|
+
/** Total wall-clock timeout in milliseconds for a `web.fetch` invocation. */
|
|
158
|
+
export declare const FETCH_TIMEOUT_MS = 30000;
|
|
159
|
+
/** Total wall-clock timeout in milliseconds for a `web.search` invocation. */
|
|
160
|
+
export declare const SEARCH_TIMEOUT_MS = 15000;
|
|
161
|
+
/**
|
|
162
|
+
* Lower-cased map of HTTP response header names to string values.
|
|
163
|
+
*
|
|
164
|
+
* Each value is truncated to {@link MAX_HEADER_VALUE_LENGTH} characters with
|
|
165
|
+
* the literal {@link TRUNCATION_MARKER} appended when shortened. Repeat
|
|
166
|
+
* headers per RFC 7230 are joined with `", "`. (Requirement 2.21.)
|
|
167
|
+
*/
|
|
168
|
+
export type HeaderMap = Record<string, string>;
|
|
169
|
+
/**
|
|
170
|
+
* TLS session details captured from the final hop of an `https://` fetch.
|
|
171
|
+
*
|
|
172
|
+
* Populated only when the request used `https://` and the user did not opt
|
|
173
|
+
* out via `includeTls=false` (Requirements 2.23, 2.24).
|
|
174
|
+
*/
|
|
175
|
+
export interface TlsInfo {
|
|
176
|
+
/** Negotiated protocol version, e.g. `"TLSv1.3"`. */
|
|
177
|
+
protocol: string;
|
|
178
|
+
/** Cipher suite name, e.g. `"TLS_AES_128_GCM_SHA256"`. */
|
|
179
|
+
cipher: string;
|
|
180
|
+
/** Subject Common Name from the leaf certificate. */
|
|
181
|
+
subjectCN: string;
|
|
182
|
+
/** Issuer Common Name from the leaf certificate. */
|
|
183
|
+
issuerCN: string;
|
|
184
|
+
/** Subject Alternative Names parsed from the leaf certificate. */
|
|
185
|
+
subjectAltNames: string[];
|
|
186
|
+
/** ISO 8601 timestamp from the leaf certificate's `notBefore` field. */
|
|
187
|
+
notBefore: string;
|
|
188
|
+
/** ISO 8601 timestamp from the leaf certificate's `notAfter` field. */
|
|
189
|
+
notAfter: string;
|
|
190
|
+
/**
|
|
191
|
+
* Lowercase, colon-separated SHA-256 fingerprint of the leaf certificate's
|
|
192
|
+
* DER bytes (e.g. `"ab:cd:..."`).
|
|
193
|
+
*/
|
|
194
|
+
fingerprintSha256: string;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* One hop in the {@link RedirectChain}.
|
|
198
|
+
*
|
|
199
|
+
* - `url`: the URL that was requested at this hop.
|
|
200
|
+
* - `status`: integer HTTP status returned by that request.
|
|
201
|
+
* - `location`: value of the `Location` header on the redirect response, if
|
|
202
|
+
* the response was a redirect that produced a subsequent hop.
|
|
203
|
+
*/
|
|
204
|
+
export interface RedirectHop {
|
|
205
|
+
url: string;
|
|
206
|
+
status: number;
|
|
207
|
+
location?: string;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Ordered list of redirect hops, capped at {@link MAX_REDIRECT_HOPS}.
|
|
211
|
+
*
|
|
212
|
+
* The first entry is the originally requested URL; the last entry is the URL
|
|
213
|
+
* whose response body is returned to the caller. (Requirement 2.26.)
|
|
214
|
+
*/
|
|
215
|
+
export type RedirectChain = RedirectHop[];
|
|
216
|
+
/**
|
|
217
|
+
* Per-phase millisecond timing measurements captured during a fetch.
|
|
218
|
+
*
|
|
219
|
+
* `tlsMs` is present iff the requested URL used `https://`
|
|
220
|
+
* (Requirement 2.25).
|
|
221
|
+
*/
|
|
222
|
+
export interface TimingInfo {
|
|
223
|
+
dnsMs: number;
|
|
224
|
+
tcpMs: number;
|
|
225
|
+
tlsMs?: number;
|
|
226
|
+
ttfbMs: number;
|
|
227
|
+
totalMs: number;
|
|
228
|
+
}
|
|
229
|
+
/** Allowed values for {@link CookieInfo.sameSite}. */
|
|
230
|
+
export type CookieSameSite = "Strict" | "Lax" | "None";
|
|
231
|
+
/**
|
|
232
|
+
* Public-attribute view of a cookie observed in a `Set-Cookie` header during
|
|
233
|
+
* the fetch. Cookie values are replaced with {@link REDACTED_PLACEHOLDER}
|
|
234
|
+
* when `redactSensitive=true` (Requirement 2.32).
|
|
235
|
+
*/
|
|
236
|
+
export interface CookieInfo {
|
|
237
|
+
name: string;
|
|
238
|
+
/** Raw cookie value; equals {@link REDACTED_PLACEHOLDER} when redacted. */
|
|
239
|
+
value: string;
|
|
240
|
+
domain?: string;
|
|
241
|
+
path?: string;
|
|
242
|
+
/** ISO 8601 timestamp from the `Expires` attribute, when present. */
|
|
243
|
+
expires?: string;
|
|
244
|
+
/** Numeric `Max-Age` attribute in seconds, when present. */
|
|
245
|
+
maxAge?: number;
|
|
246
|
+
httpOnly?: boolean;
|
|
247
|
+
secure?: boolean;
|
|
248
|
+
sameSite?: CookieSameSite;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Structured metadata describing a completed `web.fetch` invocation.
|
|
252
|
+
*
|
|
253
|
+
* The `headers`, `tls`, `timing`, `redirectChain`, and `cookies` fields are
|
|
254
|
+
* jointly capped at {@link METADATA_BUDGET_BYTES} when serialized
|
|
255
|
+
* (Requirement 2.35), with the truncation order defined in
|
|
256
|
+
* `design.md` "Truncation order at the 64 KiB cap".
|
|
257
|
+
*/
|
|
258
|
+
export interface WebFetchMetadata {
|
|
259
|
+
/** URL exactly as requested by the caller. */
|
|
260
|
+
requestedUrl: string;
|
|
261
|
+
/** URL that returned the body (after any redirects). */
|
|
262
|
+
finalUrl: string;
|
|
263
|
+
/** Integer HTTP status code of the final response. */
|
|
264
|
+
status: number;
|
|
265
|
+
/** Final response `Content-Type`, when the server returned one. */
|
|
266
|
+
contentType?: string;
|
|
267
|
+
/** IP address contacted on the final hop (Requirement 2.27). */
|
|
268
|
+
resolvedIp: string;
|
|
269
|
+
/** Hostname of `finalUrl` (Requirement 2.27). */
|
|
270
|
+
finalHostname: string;
|
|
271
|
+
/** Effective response mode used to build `body`. */
|
|
272
|
+
mode: ResponseMode;
|
|
273
|
+
/** Number of body bytes the tool actually received. */
|
|
274
|
+
bytesReceived: number;
|
|
275
|
+
/** True iff `bytesReceived` reached `maxBytes` and the body was cut. */
|
|
276
|
+
truncated: boolean;
|
|
277
|
+
/** Byte offset at which truncation occurred, when `truncated=true`. */
|
|
278
|
+
truncatedAt?: number;
|
|
279
|
+
headers?: HeaderMap;
|
|
280
|
+
tls?: TlsInfo;
|
|
281
|
+
timing?: TimingInfo;
|
|
282
|
+
redirectChain?: RedirectChain;
|
|
283
|
+
/** At most {@link MAX_COOKIES_CAPTURED} entries (Requirement 2.31). */
|
|
284
|
+
cookies?: CookieInfo[];
|
|
285
|
+
/** Bookkeeping for the 64 KiB metadata cap. */
|
|
286
|
+
budget: {
|
|
287
|
+
metadataBytes: number;
|
|
288
|
+
cap: typeof METADATA_BUDGET_BYTES;
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Categorical kinds of failures the `web.fetch` pipeline can surface.
|
|
293
|
+
*
|
|
294
|
+
* The mapping to acceptance criteria is:
|
|
295
|
+
* - `validation` → Requirements 2.12, 2.13, 2.33, 2.34
|
|
296
|
+
* - `blocked-scheme` → Requirements 2.1 / 5.4
|
|
297
|
+
* - `blocked-address` → Requirements 2.8 / 5.3
|
|
298
|
+
* - `binary-content` → Requirements 2.9, 2.30
|
|
299
|
+
* - `redirect-limit` → Requirement 2.14
|
|
300
|
+
* - `timeout` → Requirement 2.10
|
|
301
|
+
* - `http-error` → Requirement 6.4 (4xx/5xx terminal)
|
|
302
|
+
* - `network` → Requirement 6.3 (DNS/connect/TLS underlying failure)
|
|
303
|
+
* - `decode` → raw decode failed (rare)
|
|
304
|
+
*/
|
|
305
|
+
export type WebFetchErrorKind = "validation" | "blocked-scheme" | "blocked-address" | "binary-content" | "redirect-limit" | "timeout" | "http-error" | "network" | "decode";
|
|
306
|
+
/** Structured failure detail accompanying an `ok=false` fetch outcome. */
|
|
307
|
+
export interface WebFetchError {
|
|
308
|
+
kind: WebFetchErrorKind;
|
|
309
|
+
message: string;
|
|
310
|
+
status?: number;
|
|
311
|
+
/** Last URL attempted before the failure surfaced. */
|
|
312
|
+
url?: string;
|
|
313
|
+
/**
|
|
314
|
+
* Up to {@link HTTP_ERROR_BODY_PREVIEW_BYTES} bytes of the failing
|
|
315
|
+
* response body, included for `http-error` outcomes (Requirement 6.4).
|
|
316
|
+
*/
|
|
317
|
+
bodyPreview?: string;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Internal typed result of a `web.fetch` invocation, prior to being adapted
|
|
321
|
+
* into a `ToolResult` by the registry handler.
|
|
322
|
+
*
|
|
323
|
+
* `body` carries either readable text or raw decoded UTF-8, depending on the
|
|
324
|
+
* resolved {@link ResponseMode}.
|
|
325
|
+
*/
|
|
326
|
+
export interface WebFetchOutcome {
|
|
327
|
+
ok: boolean;
|
|
328
|
+
metadata: WebFetchMetadata;
|
|
329
|
+
body: string;
|
|
330
|
+
error?: WebFetchError;
|
|
331
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared TypeScript types for the `web.search` and `web.fetch` tools.
|
|
3
|
+
*
|
|
4
|
+
* Field shapes, ranges, and defaults match the "Data Models" section of
|
|
5
|
+
* `.kiro/specs/web-search-and-fetch/design.md` and the acceptance
|
|
6
|
+
* criteria in Requirements 1, 2, and 7.
|
|
7
|
+
*/
|
|
8
|
+
/** Convenience tuple form of the {@link SearchProviderId} union. */
|
|
9
|
+
export const searchProviderIds = [
|
|
10
|
+
"brave",
|
|
11
|
+
"tavily",
|
|
12
|
+
"duckduckgo",
|
|
13
|
+
];
|
|
14
|
+
/** Default value applied when `WebSearchArgs.maxResults` is omitted. */
|
|
15
|
+
export const DEFAULT_MAX_RESULTS = 5;
|
|
16
|
+
/** Inclusive minimum allowed for `WebSearchArgs.maxResults`. */
|
|
17
|
+
export const MIN_MAX_RESULTS = 1;
|
|
18
|
+
/** Inclusive maximum allowed for `WebSearchArgs.maxResults`. */
|
|
19
|
+
export const MAX_MAX_RESULTS = 20;
|
|
20
|
+
/** Inclusive minimum allowed for `WebSearchArgs.query` length after trim. */
|
|
21
|
+
export const MIN_QUERY_LENGTH = 1;
|
|
22
|
+
/** Inclusive maximum allowed for `WebSearchArgs.query` length after trim. */
|
|
23
|
+
export const MAX_QUERY_LENGTH = 400;
|
|
24
|
+
/** Inclusive minimum allowed for `SearchResult.title` length. */
|
|
25
|
+
export const MIN_TITLE_LENGTH = 1;
|
|
26
|
+
/** Inclusive maximum allowed for `SearchResult.title` length. */
|
|
27
|
+
export const MAX_TITLE_LENGTH = 512;
|
|
28
|
+
/** Inclusive minimum allowed for `SearchResult.snippet` length. */
|
|
29
|
+
export const MIN_SNIPPET_LENGTH = 0;
|
|
30
|
+
/** Inclusive maximum allowed for `SearchResult.snippet` length. */
|
|
31
|
+
export const MAX_SNIPPET_LENGTH = 2048;
|
|
32
|
+
/** Allowed values for `WebFetchArgs.responseMode`. */
|
|
33
|
+
export const RESPONSE_MODES = [
|
|
34
|
+
"readable",
|
|
35
|
+
"raw",
|
|
36
|
+
];
|
|
37
|
+
/** Default value applied when `WebFetchArgs.maxBytes` is omitted. */
|
|
38
|
+
export const DEFAULT_MAX_BYTES = 262_144;
|
|
39
|
+
/** Inclusive minimum allowed for `WebFetchArgs.maxBytes`. */
|
|
40
|
+
export const MIN_MAX_BYTES = 1024;
|
|
41
|
+
/** Inclusive maximum allowed for `WebFetchArgs.maxBytes`. */
|
|
42
|
+
export const MAX_MAX_BYTES = 1_048_576;
|
|
43
|
+
/** Default value applied when `WebFetchArgs.includeHeaders` is omitted. */
|
|
44
|
+
export const DEFAULT_INCLUDE_HEADERS = true;
|
|
45
|
+
/** Default value applied when `WebFetchArgs.includeTiming` is omitted. */
|
|
46
|
+
export const DEFAULT_INCLUDE_TIMING = true;
|
|
47
|
+
/** Default value applied when `WebFetchArgs.includeRedirectChain` is omitted. */
|
|
48
|
+
export const DEFAULT_INCLUDE_REDIRECT_CHAIN = true;
|
|
49
|
+
/** Default value applied when `WebFetchArgs.responseMode` is omitted. */
|
|
50
|
+
export const DEFAULT_RESPONSE_MODE = "readable";
|
|
51
|
+
/** Default value applied when `WebFetchArgs.redactSensitive` is omitted. */
|
|
52
|
+
export const DEFAULT_REDACT_SENSITIVE = true;
|
|
53
|
+
/** Maximum number of redirect hops followed per `web.fetch` invocation. */
|
|
54
|
+
export const MAX_REDIRECT_HOPS = 5;
|
|
55
|
+
/** Maximum number of `Set-Cookie` entries captured per invocation. */
|
|
56
|
+
export const MAX_COOKIES_CAPTURED = 32;
|
|
57
|
+
/** Per-header-value character cap before `[...truncated]` is appended. */
|
|
58
|
+
export const MAX_HEADER_VALUE_LENGTH = 4096;
|
|
59
|
+
/** Marker appended to any header value or body preview shortened by the tool. */
|
|
60
|
+
export const TRUNCATION_MARKER = "[...truncated]";
|
|
61
|
+
/** Literal placeholder used wherever sensitive values are redacted. */
|
|
62
|
+
export const REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
63
|
+
/** Combined serialized-size cap for fetch metadata in bytes. */
|
|
64
|
+
export const METADATA_BUDGET_BYTES = 65_536;
|
|
65
|
+
/** Maximum size in bytes of the `bodyPreview` returned for HTTP errors. */
|
|
66
|
+
export const HTTP_ERROR_BODY_PREVIEW_BYTES = 4096;
|
|
67
|
+
/** Total wall-clock timeout in milliseconds for a `web.fetch` invocation. */
|
|
68
|
+
export const FETCH_TIMEOUT_MS = 30_000;
|
|
69
|
+
/** Total wall-clock timeout in milliseconds for a `web.search` invocation. */
|
|
70
|
+
export const SEARCH_TIMEOUT_MS = 15_000;
|
|
71
|
+
//# sourceMappingURL=types.js.map
|