@burtson-labs/host-kit 0.3.1
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/LICENSE +201 -0
- package/README.md +55 -0
- package/dist/backgroundTasks.d.ts +113 -0
- package/dist/backgroundTasks.d.ts.map +1 -0
- package/dist/backgroundTasks.js +137 -0
- package/dist/backgroundTasks.js.map +1 -0
- package/dist/checkpoints.d.ts +99 -0
- package/dist/checkpoints.d.ts.map +1 -0
- package/dist/checkpoints.js +227 -0
- package/dist/checkpoints.js.map +1 -0
- package/dist/hooks.d.ts +51 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +152 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/dist/insights.d.ts +398 -0
- package/dist/insights.d.ts.map +1 -0
- package/dist/insights.js +1933 -0
- package/dist/insights.js.map +1 -0
- package/dist/mcp.d.ts +60 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +281 -0
- package/dist/mcp.js.map +1 -0
- package/dist/mcpConnectors.d.ts +108 -0
- package/dist/mcpConnectors.d.ts.map +1 -0
- package/dist/mcpConnectors.js +217 -0
- package/dist/mcpConnectors.js.map +1 -0
- package/dist/mcpToolCache.d.ts +43 -0
- package/dist/mcpToolCache.d.ts.map +1 -0
- package/dist/mcpToolCache.js +150 -0
- package/dist/mcpToolCache.js.map +1 -0
- package/dist/mcpTrust.d.ts +22 -0
- package/dist/mcpTrust.d.ts.map +1 -0
- package/dist/mcpTrust.js +104 -0
- package/dist/mcpTrust.js.map +1 -0
- package/dist/memory.d.ts +38 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +151 -0
- package/dist/memory.js.map +1 -0
- package/dist/memoryIndex.d.ts +38 -0
- package/dist/memoryIndex.d.ts.map +1 -0
- package/dist/memoryIndex.js +142 -0
- package/dist/memoryIndex.js.map +1 -0
- package/dist/mentions.d.ts +33 -0
- package/dist/mentions.d.ts.map +1 -0
- package/dist/mentions.js +126 -0
- package/dist/mentions.js.map +1 -0
- package/dist/ollamaModels.d.ts +36 -0
- package/dist/ollamaModels.d.ts.map +1 -0
- package/dist/ollamaModels.js +83 -0
- package/dist/ollamaModels.js.map +1 -0
- package/dist/permissions.d.ts +72 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +271 -0
- package/dist/permissions.js.map +1 -0
- package/dist/tools/extraTools.d.ts +80 -0
- package/dist/tools/extraTools.d.ts.map +1 -0
- package/dist/tools/extraTools.js +471 -0
- package/dist/tools/extraTools.js.map +1 -0
- package/dist/tools/readMemoryTool.d.ts +3 -0
- package/dist/tools/readMemoryTool.d.ts.map +1 -0
- package/dist/tools/readMemoryTool.js +115 -0
- package/dist/tools/readMemoryTool.js.map +1 -0
- package/dist/tools/taskTool.d.ts +119 -0
- package/dist/tools/taskTool.d.ts.map +1 -0
- package/dist/tools/taskTool.js +466 -0
- package/dist/tools/taskTool.js.map +1 -0
- package/dist/tools/testRunTool.d.ts +59 -0
- package/dist/tools/testRunTool.d.ts.map +1 -0
- package/dist/tools/testRunTool.js +308 -0
- package/dist/tools/testRunTool.js.map +1 -0
- package/dist/turnLog.d.ts +89 -0
- package/dist/turnLog.d.ts.map +1 -0
- package/dist/turnLog.js +469 -0
- package/dist/turnLog.js.map +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Extra tools layered onto the core ToolRegistry for the CLI host:
|
|
4
|
+
* - todo_write: in-agent todo tracking, persisted in-memory for the session
|
|
5
|
+
* - web_fetch: GET a URL and return a trimmed text body
|
|
6
|
+
* - web_search: query a search API (Tavily), return ranked snippets
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.TodoStore = void 0;
|
|
10
|
+
exports.buildTodoWriteTool = buildTodoWriteTool;
|
|
11
|
+
exports.buildRememberTool = buildRememberTool;
|
|
12
|
+
exports.isPrivateHost = isPrivateHost;
|
|
13
|
+
exports.buildWebFetchTool = buildWebFetchTool;
|
|
14
|
+
exports.buildWebSearchTool = buildWebSearchTool;
|
|
15
|
+
const node_dns_1 = require("node:dns");
|
|
16
|
+
const node_net_1 = require("node:net");
|
|
17
|
+
const memory_1 = require("../memory");
|
|
18
|
+
/**
|
|
19
|
+
* Models don't agree on status vocabulary — some emit `"done"`, others
|
|
20
|
+
* `"complete"`, `"completed"`, `"in-progress"`, `"inprogress"`, etc.
|
|
21
|
+
* Normalize to the three statuses the store actually stores so the UI
|
|
22
|
+
* (which only knows `done` / `in_progress` / `pending`) reliably ticks
|
|
23
|
+
* items off. Without this, a model saying `"complete"` leaves items
|
|
24
|
+
* visually stuck on `○` forever despite the plan advancing.
|
|
25
|
+
*/
|
|
26
|
+
function normalizeStatus(raw) {
|
|
27
|
+
const s = typeof raw === 'string' ? raw.trim().toLowerCase().replace(/[-\s]/g, '_') : '';
|
|
28
|
+
if (s === 'done' || s === 'complete' || s === 'completed' || s === 'finished')
|
|
29
|
+
return 'done';
|
|
30
|
+
if (s === 'in_progress' || s === 'inprogress' || s === 'active' || s === 'working' || s === 'running')
|
|
31
|
+
return 'in_progress';
|
|
32
|
+
return 'pending';
|
|
33
|
+
}
|
|
34
|
+
class TodoStore {
|
|
35
|
+
constructor() {
|
|
36
|
+
this.items = [];
|
|
37
|
+
this.nextId = 1;
|
|
38
|
+
}
|
|
39
|
+
snapshot() {
|
|
40
|
+
return [...this.items];
|
|
41
|
+
}
|
|
42
|
+
render() {
|
|
43
|
+
if (this.items.length === 0)
|
|
44
|
+
return '(no todos)';
|
|
45
|
+
return this.items
|
|
46
|
+
.map(t => {
|
|
47
|
+
const mark = t.status === 'done' ? '[x]' : t.status === 'in_progress' ? '[~]' : '[ ]';
|
|
48
|
+
return `${mark} ${t.id}. ${t.content}`;
|
|
49
|
+
})
|
|
50
|
+
.join('\n');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Accepts a JSON array of { content, status? } to replace the list, or a
|
|
54
|
+
* single string 'content' for append. Simple to be forgiving of small models.
|
|
55
|
+
*/
|
|
56
|
+
upsert(raw) {
|
|
57
|
+
const trimmed = raw.trim();
|
|
58
|
+
if (!trimmed)
|
|
59
|
+
return 'No todo payload provided.';
|
|
60
|
+
try {
|
|
61
|
+
const parsed = JSON.parse(trimmed);
|
|
62
|
+
if (Array.isArray(parsed)) {
|
|
63
|
+
// Small models (Qwen 2.5 Coder on S3Api
|
|
64
|
+
// turn) sometimes pass a bare string array — ["Read X", "Edit Y"]
|
|
65
|
+
// — instead of the documented [{content, status}] shape. Treat
|
|
66
|
+
// each string as a pending todo with its content equal to the
|
|
67
|
+
// string. Previous code did String(undefined ?? '') here and
|
|
68
|
+
// rendered N empty bullets in the Plan block.
|
|
69
|
+
//
|
|
70
|
+
// Mark 2026-05-26: when the tool was declared with `type: string`,
|
|
71
|
+
// the agent-core parser stringified each nested {content,status}
|
|
72
|
+
// object on the way in. The array branch then saw a list of
|
|
73
|
+
// JSON-SHAPED STRINGS like '{"content":"Install TypeScript",
|
|
74
|
+
// "status":"done"}' and the string branch below set content
|
|
75
|
+
// to the whole JSON dump — Plan rendered raw JSON instead of
|
|
76
|
+
// a clean checklist. We now detect JSON-object-shaped strings
|
|
77
|
+
// and re-parse them so the legacy path (and any provider that
|
|
78
|
+
// still stringifies nested values) recovers the right shape.
|
|
79
|
+
this.items = parsed.map((entry, i) => {
|
|
80
|
+
if (typeof entry === 'string') {
|
|
81
|
+
const candidate = entry.trim();
|
|
82
|
+
if (candidate.startsWith('{') && candidate.endsWith('}')) {
|
|
83
|
+
try {
|
|
84
|
+
const obj = JSON.parse(candidate);
|
|
85
|
+
if (obj && typeof obj === 'object' && typeof obj.content === 'string') {
|
|
86
|
+
return {
|
|
87
|
+
id: i + 1,
|
|
88
|
+
status: normalizeStatus(obj.status),
|
|
89
|
+
content: obj.content,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
/* fall through to bare-string treatment */
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return { id: i + 1, status: 'pending', content: entry };
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
id: i + 1,
|
|
101
|
+
status: normalizeStatus(entry?.status),
|
|
102
|
+
content: String(entry?.content ?? '')
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
this.nextId = this.items.length + 1;
|
|
106
|
+
return `Todo list updated (${this.items.length} items).`;
|
|
107
|
+
}
|
|
108
|
+
if (parsed && typeof parsed === 'object' && typeof parsed.content === 'string') {
|
|
109
|
+
this.items.push({ id: this.nextId++, status: normalizeStatus(parsed.status), content: parsed.content });
|
|
110
|
+
return `Added todo #${this.items.length}.`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Fall through: treat as plain text append.
|
|
115
|
+
}
|
|
116
|
+
this.items.push({ id: this.nextId++, status: 'pending', content: trimmed });
|
|
117
|
+
return `Added todo #${this.items.length}.`;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* A short progress summary the tool returns so the model reads a
|
|
121
|
+
* clear "update succeeded, here's what's left" signal instead of
|
|
122
|
+
* interpreting the echoed list as a reset. The trailing nudge is
|
|
123
|
+
* deliberately blunt — bandit-core-1 and similar small models have
|
|
124
|
+
* been observed to claim completion without invoking the write
|
|
125
|
+
* tool, and this helper is the most direct place to remind the
|
|
126
|
+
* model of the expectation between tool calls.
|
|
127
|
+
*/
|
|
128
|
+
summary() {
|
|
129
|
+
const done = this.items.filter(t => t.status === 'done').length;
|
|
130
|
+
const inProgress = this.items.filter(t => t.status === 'in_progress').length;
|
|
131
|
+
const pending = this.items.filter(t => t.status === 'pending');
|
|
132
|
+
if (this.items.length === 0)
|
|
133
|
+
return '';
|
|
134
|
+
const nextPending = pending[0];
|
|
135
|
+
const pieces = [
|
|
136
|
+
`${done} of ${this.items.length} complete`,
|
|
137
|
+
inProgress > 0 ? `${inProgress} in progress` : null,
|
|
138
|
+
nextPending ? `next: "${nextPending.content}"` : null
|
|
139
|
+
].filter(Boolean);
|
|
140
|
+
const status = pieces.join(' · ');
|
|
141
|
+
if (done === this.items.length) {
|
|
142
|
+
return `\n\n${status}. Before finalizing, verify the work is actually complete — a todo marked "done" is not proof the underlying change was made.`;
|
|
143
|
+
}
|
|
144
|
+
return `\n\n${status}. Continue the task — DO NOT claim completion in your response until the underlying work (write_file / apply_edit / replace_range / run_command) has actually executed.`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.TodoStore = TodoStore;
|
|
148
|
+
function buildTodoWriteTool(store) {
|
|
149
|
+
return {
|
|
150
|
+
name: 'todo_write',
|
|
151
|
+
description: 'Track progress on the current task. Pass an array of {content, status} objects to replace the list, or a plain string to append one item. Call this whenever you change plans or finish a step.',
|
|
152
|
+
parameters: [
|
|
153
|
+
{
|
|
154
|
+
name: 'items',
|
|
155
|
+
description: 'Array of {content, status} objects, where status is one of "pending" | "in_progress" | "done". Send a real array — do NOT pre-stringify the objects.',
|
|
156
|
+
required: true,
|
|
157
|
+
schema: {
|
|
158
|
+
type: 'array',
|
|
159
|
+
items: {
|
|
160
|
+
type: 'object',
|
|
161
|
+
properties: {
|
|
162
|
+
content: { type: 'string', description: 'The todo item text shown to the user.' },
|
|
163
|
+
status: {
|
|
164
|
+
type: 'string',
|
|
165
|
+
description: 'One of "pending" | "in_progress" | "done".',
|
|
166
|
+
enum: ['pending', 'in_progress', 'done'],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
required: ['content'],
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
}
|
|
173
|
+
],
|
|
174
|
+
async execute(params, _ctx) {
|
|
175
|
+
// params.items may arrive as a real array (native-tools providers
|
|
176
|
+
// honouring the schema), a JSON string (text-tool-loop tool_call
|
|
177
|
+
// parser), or undefined. The interface types params as
|
|
178
|
+
// Record<string,string> but the agent runtime delivers richer
|
|
179
|
+
// shapes when the param schema declares them — cast and normalize.
|
|
180
|
+
// Normalize to a JSON string so the existing store.upsert()
|
|
181
|
+
// text-based parsing keeps working unchanged; if a richer-shaped
|
|
182
|
+
// array arrives, JSON.stringify round-trips it cleanly.
|
|
183
|
+
const raw = params.items;
|
|
184
|
+
const serialized = typeof raw === 'string'
|
|
185
|
+
? raw
|
|
186
|
+
: raw === undefined || raw === null
|
|
187
|
+
? ''
|
|
188
|
+
: JSON.stringify(raw);
|
|
189
|
+
const header = store.upsert(serialized);
|
|
190
|
+
const summary = store.summary();
|
|
191
|
+
return { output: `${header}\n\n${store.render()}${summary}`, isError: false };
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* `remember` tool — persists a single fact to the workspace's BANDIT.md
|
|
197
|
+
* so it survives across sessions. Use case: the user says "remember
|
|
198
|
+
* that all my repos live in ~/Documents/GitHub" and wants the next
|
|
199
|
+
* Bandit session to know that without being re-told.
|
|
200
|
+
*
|
|
201
|
+
* Why a dedicated tool instead of asking the model to apply_edit
|
|
202
|
+
* BANDIT.md directly: small models (gemma4:e4b, qwen 4B) hallucinated
|
|
203
|
+
* the existing file contents when invited to edit it, and even on
|
|
204
|
+
* larger models the apply_edit dance for "append a bullet" was
|
|
205
|
+
* comically inefficient (4-5 turns minimum). This is one tool call
|
|
206
|
+
* with a single string parameter — same shape as todo_write.
|
|
207
|
+
*
|
|
208
|
+
* on the CLI: user said "you should add to your
|
|
209
|
+
* memory where my repos are", model used `todo_write` thinking it was
|
|
210
|
+
* the persistence mechanism, nothing actually landed on disk and the
|
|
211
|
+
* next session knew nothing.
|
|
212
|
+
*/
|
|
213
|
+
function buildRememberTool() {
|
|
214
|
+
return {
|
|
215
|
+
name: 'remember',
|
|
216
|
+
description: 'Persist a single fact to project memory (BANDIT.md at the workspace root) so it survives across sessions. Use this when the user says "remember X", "always do Y", "note that I", or otherwise asks for cross-session persistence — NOT for transient task tracking (use `todo_write` for that). One bullet per call. Examples: "All repos live in ~/Documents/GitHub", "Prefer pnpm over npm", "Local Ollama at http://k3s.lan:11434".',
|
|
217
|
+
parameters: [
|
|
218
|
+
{ name: 'fact', description: 'The single fact to remember. Will be appended as a bullet under the "## Notes" heading in BANDIT.md (file is created with a minimal scaffold if missing).', required: true }
|
|
219
|
+
],
|
|
220
|
+
async execute(params, ctx) {
|
|
221
|
+
const fact = (params.fact ?? '').trim();
|
|
222
|
+
if (!fact)
|
|
223
|
+
return { output: 'Error: fact parameter is required and must be a non-empty string.', isError: true };
|
|
224
|
+
try {
|
|
225
|
+
const abs = await (0, memory_1.appendMemory)(ctx.workspaceRoot, fact);
|
|
226
|
+
return { output: `Saved to project memory: "${fact}"\n\nPersisted to ${abs}. The next Bandit session in this workspace will load this automatically.` };
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
230
|
+
return { output: `Could not write to BANDIT.md: ${msg}`, isError: true };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* SSRF guard for web_fetch — resolves the URL's hostname and refuses to
|
|
237
|
+
* proceed if it lands on a private/loopback/link-local address. This is
|
|
238
|
+
* the difference between "agent can read public docs" and "attacker prompt
|
|
239
|
+
* tricks agent into hitting http://169.254.169.254/latest/meta-data/ or
|
|
240
|
+
* http://localhost:6443 on the user's box."
|
|
241
|
+
*
|
|
242
|
+
* Set BANDIT_ALLOW_PRIVATE_WEB_FETCH=1 to opt out — appropriate when the
|
|
243
|
+
* user is intentionally pointing the agent at internal docs.
|
|
244
|
+
*/
|
|
245
|
+
const PRIVATE_HOSTNAMES = new Set(['localhost', 'ip6-localhost', 'ip6-loopback']);
|
|
246
|
+
function isPrivateIPv4(ip) {
|
|
247
|
+
const parts = ip.split('.').map((p) => Number(p));
|
|
248
|
+
if (parts.length !== 4 || parts.some((p) => !Number.isInteger(p) || p < 0 || p > 255))
|
|
249
|
+
return false;
|
|
250
|
+
const [a, b] = parts;
|
|
251
|
+
if (a === 0)
|
|
252
|
+
return true; // 0.0.0.0/8 — "this network"
|
|
253
|
+
if (a === 10)
|
|
254
|
+
return true; // 10.0.0.0/8 — RFC1918
|
|
255
|
+
if (a === 127)
|
|
256
|
+
return true; // 127.0.0.0/8 — loopback
|
|
257
|
+
if (a === 169 && b === 254)
|
|
258
|
+
return true; // 169.254.0.0/16 — link-local (cloud metadata)
|
|
259
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
260
|
+
return true; // 172.16.0.0/12 — RFC1918
|
|
261
|
+
if (a === 192 && b === 168)
|
|
262
|
+
return true; // 192.168.0.0/16 — RFC1918
|
|
263
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
264
|
+
return true; // 100.64.0.0/10 — CGNAT (often internal)
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
function isPrivateIPv6(ip) {
|
|
268
|
+
const lower = ip.toLowerCase();
|
|
269
|
+
if (lower === '::1' || lower === '::')
|
|
270
|
+
return true;
|
|
271
|
+
// IPv4-mapped IPv6 (::ffff:a.b.c.d) — re-check the embedded IPv4.
|
|
272
|
+
const mapped = lower.match(/^::ffff:([0-9.]+)$/);
|
|
273
|
+
if (mapped && (0, node_net_1.isIP)(mapped[1]) === 4)
|
|
274
|
+
return isPrivateIPv4(mapped[1]);
|
|
275
|
+
if (/^f[cd][0-9a-f]{2}:/.test(lower))
|
|
276
|
+
return true; // fc00::/7 — Unique Local
|
|
277
|
+
if (/^fe[89ab][0-9a-f]:/.test(lower))
|
|
278
|
+
return true; // fe80::/10 — link-local
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
async function isPrivateHost(hostname) {
|
|
282
|
+
// Node's URL.hostname returns IPv6 literals WITH brackets (e.g. "[::1]").
|
|
283
|
+
// Strip them so isIP() classifies the address and DNS doesn't try to
|
|
284
|
+
// resolve a bracketed string.
|
|
285
|
+
const stripped = hostname.startsWith('[') && hostname.endsWith(']')
|
|
286
|
+
? hostname.slice(1, -1)
|
|
287
|
+
: hostname;
|
|
288
|
+
const lower = stripped.toLowerCase();
|
|
289
|
+
if (PRIVATE_HOSTNAMES.has(lower))
|
|
290
|
+
return true;
|
|
291
|
+
const family = (0, node_net_1.isIP)(stripped);
|
|
292
|
+
if (family === 4)
|
|
293
|
+
return isPrivateIPv4(stripped);
|
|
294
|
+
if (family === 6)
|
|
295
|
+
return isPrivateIPv6(stripped);
|
|
296
|
+
try {
|
|
297
|
+
const records = await node_dns_1.promises.lookup(stripped, { all: true, verbatim: true });
|
|
298
|
+
for (const rec of records) {
|
|
299
|
+
if (rec.family === 4 && isPrivateIPv4(rec.address))
|
|
300
|
+
return true;
|
|
301
|
+
if (rec.family === 6 && isPrivateIPv6(rec.address))
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
// DNS resolution failure isn't itself a security signal — let fetch
|
|
308
|
+
// report the network error so the model sees a normal failure path.
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function buildWebFetchTool() {
|
|
313
|
+
return {
|
|
314
|
+
name: 'web_fetch',
|
|
315
|
+
description: 'HTTP GET a URL and return a trimmed plaintext body (up to ~16 KB). Use for docs, RFCs, release notes. No JS execution, no auth.',
|
|
316
|
+
parameters: [
|
|
317
|
+
{ name: 'url', description: 'Absolute http(s) URL', required: true }
|
|
318
|
+
],
|
|
319
|
+
async execute(params, _ctx) {
|
|
320
|
+
const raw = params.url?.trim();
|
|
321
|
+
if (!raw)
|
|
322
|
+
return { output: 'Missing url parameter.', isError: true };
|
|
323
|
+
let url;
|
|
324
|
+
try {
|
|
325
|
+
url = new URL(raw);
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
return { output: `Invalid URL: ${raw}`, isError: true };
|
|
329
|
+
}
|
|
330
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
331
|
+
return { output: `Unsupported protocol: ${url.protocol}`, isError: true };
|
|
332
|
+
}
|
|
333
|
+
if (process.env.BANDIT_ALLOW_PRIVATE_WEB_FETCH !== '1') {
|
|
334
|
+
if (await isPrivateHost(url.hostname)) {
|
|
335
|
+
return {
|
|
336
|
+
output: `Blocked: ${url.hostname} resolves to a private/loopback/link-local address. Set BANDIT_ALLOW_PRIVATE_WEB_FETCH=1 to allow fetches against internal networks.`,
|
|
337
|
+
isError: true
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
try {
|
|
342
|
+
const res = await fetch(url.toString(), {
|
|
343
|
+
redirect: 'follow',
|
|
344
|
+
headers: { 'User-Agent': 'bandit-cli/0.1', Accept: 'text/html,text/plain,application/json;q=0.9,*/*;q=0.5' },
|
|
345
|
+
signal: AbortSignal.timeout(15000)
|
|
346
|
+
});
|
|
347
|
+
const ct = res.headers.get('content-type') ?? '';
|
|
348
|
+
const text = await res.text();
|
|
349
|
+
const body = ct.includes('html') ? stripHtml(text) : text;
|
|
350
|
+
const trimmed = body.length > 16 * 1024 ? body.slice(0, 16 * 1024) + '\n… (truncated)' : body;
|
|
351
|
+
return {
|
|
352
|
+
output: `HTTP ${res.status} ${res.statusText} • ${url.host}\nContent-Type: ${ct || '(unknown)'}\n\n${trimmed}`,
|
|
353
|
+
isError: !res.ok
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
return { output: `Fetch failed: ${err instanceof Error ? err.message : String(err)}`, isError: true };
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function stripHtml(html) {
|
|
363
|
+
return html
|
|
364
|
+
.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, '')
|
|
365
|
+
.replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, '')
|
|
366
|
+
.replace(/<[^>]+>/g, ' ')
|
|
367
|
+
.replace(/ /g, ' ')
|
|
368
|
+
.replace(/&/g, '&')
|
|
369
|
+
.replace(/</g, '<')
|
|
370
|
+
.replace(/>/g, '>')
|
|
371
|
+
.replace(/"/g, '"')
|
|
372
|
+
.replace(/\s+/g, ' ')
|
|
373
|
+
.trim();
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Build a `web_search` tool backed by Tavily (purpose-built for LLM
|
|
377
|
+
* agents — returns ranked snippets, not raw HTML). When TAVILY_API_KEY
|
|
378
|
+
* is unset the tool returns a clear configuration error so the model
|
|
379
|
+
* can fall back to other tools (web_fetch with a known URL, ask the
|
|
380
|
+
* user, etc.) instead of hallucinating results.
|
|
381
|
+
*
|
|
382
|
+
* Why Tavily over scraping or Google CSE:
|
|
383
|
+
* - Generous free tier (1k req/mo at time of writing)
|
|
384
|
+
* - Single API call returns ranked snippets ready for the model
|
|
385
|
+
* - No CAPTCHA / rate-limit roulette like search-result scraping
|
|
386
|
+
* - Optional `answer` field gives the model an LLM-summarized answer
|
|
387
|
+
* directly when one fits the query
|
|
388
|
+
*/
|
|
389
|
+
function buildWebSearchTool(options = {}) {
|
|
390
|
+
const endpoint = options.endpoint ?? 'https://api.tavily.com/search';
|
|
391
|
+
return {
|
|
392
|
+
name: 'web_search',
|
|
393
|
+
description: 'Search the web and return ranked snippets. Use for: looking up library APIs, finding documentation, checking what a CLI flag does, researching error messages. Each result has a title, URL, and a short content snippet — call `web_fetch` on the URL when you need the full page. Requires a Tavily API key (configure via the host or set TAVILY_API_KEY).',
|
|
394
|
+
parameters: [
|
|
395
|
+
{ name: 'query', description: 'The search query — natural language works ("how to configure typescript paths"), keywords work too ("typescript paths config").', required: true },
|
|
396
|
+
{ name: 'num_results', description: 'Number of results to return. Default 5, max 10.', required: false }
|
|
397
|
+
],
|
|
398
|
+
async execute(params, _ctx) {
|
|
399
|
+
const query = params.query?.trim();
|
|
400
|
+
if (!query) {
|
|
401
|
+
return { output: 'Missing query parameter.', isError: true };
|
|
402
|
+
}
|
|
403
|
+
const apiKey = options.apiKey?.trim() || process.env.TAVILY_API_KEY?.trim();
|
|
404
|
+
if (!apiKey) {
|
|
405
|
+
return {
|
|
406
|
+
output: 'web_search is not configured. Set the TAVILY_API_KEY environment variable (free tier: https://tavily.com), or use `web_fetch` with a known URL instead.',
|
|
407
|
+
isError: true
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
const requestedCount = Number.parseInt(params.num_results ?? '', 10);
|
|
411
|
+
const maxResults = Number.isFinite(requestedCount) && requestedCount > 0
|
|
412
|
+
? Math.min(requestedCount, 10)
|
|
413
|
+
: 5;
|
|
414
|
+
try {
|
|
415
|
+
const res = await fetch(endpoint, {
|
|
416
|
+
method: 'POST',
|
|
417
|
+
headers: { 'Content-Type': 'application/json' },
|
|
418
|
+
body: JSON.stringify({
|
|
419
|
+
api_key: apiKey,
|
|
420
|
+
query,
|
|
421
|
+
search_depth: 'basic',
|
|
422
|
+
include_answer: true,
|
|
423
|
+
max_results: maxResults
|
|
424
|
+
}),
|
|
425
|
+
signal: AbortSignal.timeout(15000)
|
|
426
|
+
});
|
|
427
|
+
if (!res.ok) {
|
|
428
|
+
const detail = await res.text().catch(() => '');
|
|
429
|
+
return {
|
|
430
|
+
output: `Search failed: HTTP ${res.status} ${res.statusText}${detail ? ` — ${detail.slice(0, 240)}` : ''}`,
|
|
431
|
+
isError: true
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
const data = (await res.json());
|
|
435
|
+
const results = Array.isArray(data.results) ? data.results : [];
|
|
436
|
+
if (results.length === 0) {
|
|
437
|
+
return {
|
|
438
|
+
output: `No results for "${query}".${data.answer ? `\n\nDirect answer: ${data.answer}` : ''}`,
|
|
439
|
+
isError: false
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
const blocks = [];
|
|
443
|
+
if (data.answer) {
|
|
444
|
+
blocks.push(`Direct answer: ${data.answer}`);
|
|
445
|
+
blocks.push('');
|
|
446
|
+
}
|
|
447
|
+
blocks.push(`Results for "${query}":`);
|
|
448
|
+
results.slice(0, maxResults).forEach((r, idx) => {
|
|
449
|
+
const title = r.title?.trim() || '(untitled)';
|
|
450
|
+
const url = r.url?.trim() || '';
|
|
451
|
+
const snippet = (r.content ?? '').trim();
|
|
452
|
+
const trimmedSnippet = snippet.length > 600 ? snippet.slice(0, 600) + '…' : snippet;
|
|
453
|
+
blocks.push('');
|
|
454
|
+
blocks.push(`${idx + 1}. ${title}`);
|
|
455
|
+
if (url)
|
|
456
|
+
blocks.push(` ${url}`);
|
|
457
|
+
if (trimmedSnippet)
|
|
458
|
+
blocks.push(` ${trimmedSnippet}`);
|
|
459
|
+
});
|
|
460
|
+
return { output: blocks.join('\n'), isError: false };
|
|
461
|
+
}
|
|
462
|
+
catch (err) {
|
|
463
|
+
return {
|
|
464
|
+
output: `Search failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
465
|
+
isError: true
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
//# sourceMappingURL=extraTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extraTools.js","sourceRoot":"","sources":["../../src/tools/extraTools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readMemoryTool.d.ts","sourceRoot":"","sources":["../../src/tools/readMemoryTool.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAoC,MAAM,0BAA0B,CAAC;AAO5F,wBAAgB,mBAAmB,IAAI,SAAS,CAmE/C"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.buildReadMemoryTool = buildReadMemoryTool;
|
|
37
|
+
/**
|
|
38
|
+
* `read_memory` — load a single topic file from `memory/<name>.md` on
|
|
39
|
+
* demand. Paired with `loadMemoryIndex` (the MEMORY.md index injected
|
|
40
|
+
* into the system prompt every turn). The agent decides whether a topic
|
|
41
|
+
* is relevant by reading the index's hook, then calls this tool to
|
|
42
|
+
* pull the full file into context.
|
|
43
|
+
*
|
|
44
|
+
* Rejects path traversal (`..`, absolute paths). On miss, the error
|
|
45
|
+
* lists the available slugs so the model can self-correct.
|
|
46
|
+
*/
|
|
47
|
+
const fs = __importStar(require("fs"));
|
|
48
|
+
const path = __importStar(require("path"));
|
|
49
|
+
const memoryIndex_1 = require("../memoryIndex");
|
|
50
|
+
function buildReadMemoryTool() {
|
|
51
|
+
return {
|
|
52
|
+
name: 'read_memory',
|
|
53
|
+
description: 'Read a single topic memory file by slug. Use this when MEMORY.md (shown in the system prompt) lists a topic whose hook matches the current task. The slug is the part after "memory/" in [Title](memory/<slug>.md) — without the .md suffix. Returns the full file content (capped at 32 KB).',
|
|
54
|
+
parameters: [
|
|
55
|
+
{
|
|
56
|
+
name: 'name',
|
|
57
|
+
description: 'Memory file slug (no `memory/` prefix, no `.md` suffix). Example: "auth-conventions" loads memory/auth-conventions.md.',
|
|
58
|
+
required: true
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
async execute(params, ctx) {
|
|
62
|
+
const requested = (params.name ?? '').trim();
|
|
63
|
+
if (!requested) {
|
|
64
|
+
return { output: 'Error: name parameter is required.', isError: true };
|
|
65
|
+
}
|
|
66
|
+
// Reject path traversal and absolute paths up front — slug must be a
|
|
67
|
+
// plain filename, not a path. The MEMORY.md format only ever yields
|
|
68
|
+
// simple filenames (the parser enforces this on the index side),
|
|
69
|
+
// and any model passing a `..` here is either confused or hostile.
|
|
70
|
+
if (requested.includes('/') ||
|
|
71
|
+
requested.includes('\\') ||
|
|
72
|
+
requested.includes('..') ||
|
|
73
|
+
path.isAbsolute(requested)) {
|
|
74
|
+
return {
|
|
75
|
+
output: `Error: name must be a plain slug like "auth-conventions", not a path. Got: "${requested}"`,
|
|
76
|
+
isError: true
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const slug = requested.replace(/\.md$/i, '');
|
|
80
|
+
const index = await (0, memoryIndex_1.loadMemoryIndex)(ctx.workspaceRoot);
|
|
81
|
+
const entry = index.entries.find((e) => e.name === slug);
|
|
82
|
+
if (!entry) {
|
|
83
|
+
const available = index.entries.map((e) => e.name);
|
|
84
|
+
if (available.length === 0) {
|
|
85
|
+
return {
|
|
86
|
+
output: `No memory index found. MEMORY.md is missing or has no entries at ${path.resolve(ctx.workspaceRoot, 'MEMORY.md')}.`,
|
|
87
|
+
isError: true
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
output: `Memory slug "${slug}" not found. Available: ${available.join(', ')}`,
|
|
92
|
+
isError: true
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const raw = await fs.promises.readFile(entry.absPath);
|
|
97
|
+
const truncated = raw.byteLength > memoryIndex_1.MAX_MEMORY_FILE_BYTES;
|
|
98
|
+
const text = raw.subarray(0, memoryIndex_1.MAX_MEMORY_FILE_BYTES).toString('utf-8');
|
|
99
|
+
const body = truncated ? `${text}\n… (truncated — file exceeds ${memoryIndex_1.MAX_MEMORY_FILE_BYTES} bytes)` : text;
|
|
100
|
+
return {
|
|
101
|
+
output: `<!-- source: ${entry.relPath} -->\n${body}`,
|
|
102
|
+
isError: false
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
107
|
+
return {
|
|
108
|
+
output: `Could not read ${memoryIndex_1.MEMORY_DIR}/${slug}.md: ${msg}`,
|
|
109
|
+
isError: true
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=readMemoryTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readMemoryTool.js","sourceRoot":"","sources":["../../src/tools/readMemoryTool.ts"],"names":[],"mappings":"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"}
|