@burtson-labs/host-kit 0.3.2 → 0.4.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 +5 -3
- package/dist/hooks.d.ts +9 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +19 -1
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +64 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +179 -3
- package/dist/memory.js.map +1 -1
- package/dist/memoryIndex.d.ts +35 -1
- package/dist/memoryIndex.d.ts.map +1 -1
- package/dist/memoryIndex.js +207 -23
- package/dist/memoryIndex.js.map +1 -1
- package/dist/securityGuard.d.ts +29 -0
- package/dist/securityGuard.d.ts.map +1 -0
- package/dist/securityGuard.js +164 -0
- package/dist/securityGuard.js.map +1 -0
- package/dist/tools/readMemoryTool.d.ts.map +1 -1
- package/dist/tools/readMemoryTool.js +11 -9
- package/dist/tools/readMemoryTool.js.map +1 -1
- package/package.json +2 -2
package/dist/memoryIndex.js
CHANGED
|
@@ -33,31 +33,52 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.MEMORY_INDEX_FILE = exports.MEMORY_DIR = exports.MAX_MEMORY_FILE_BYTES = exports.MAX_INDEX_BYTES = void 0;
|
|
36
|
+
exports.BANDIT_MEMORY_INDEX_FILE = exports.BANDIT_MEMORY_DIR = exports.BANDIT_DIR = exports.MEMORY_INDEX_FILE = exports.MEMORY_DIR = exports.MAX_MEMORY_FILE_BYTES = exports.MAX_INDEX_BYTES = void 0;
|
|
37
37
|
exports.renderMemoryIndexBlock = renderMemoryIndexBlock;
|
|
38
38
|
exports.loadMemoryIndex = loadMemoryIndex;
|
|
39
|
+
exports.writeMemoryTopic = writeMemoryTopic;
|
|
40
|
+
exports.migrateMemoryToBanditDir = migrateMemoryToBanditDir;
|
|
39
41
|
/**
|
|
40
42
|
* Lazy-load topic memory.
|
|
41
43
|
*
|
|
42
|
-
*
|
|
43
|
-
* pointing at a markdown file in a sibling `memory/` directory. The index
|
|
44
|
-
* itself goes into the system prompt every turn (small — capped at 4 KB).
|
|
45
|
-
* The linked files are NOT preloaded; the agent reads them via the
|
|
46
|
-
* `read_memory` tool when it decides a topic is relevant.
|
|
44
|
+
* ## Path layout (new — v0.4)
|
|
47
45
|
*
|
|
48
|
-
*
|
|
46
|
+
* Preferred location (new repos / post-migration):
|
|
47
|
+
* .bandit/memory/MEMORY.md ← index file
|
|
48
|
+
* .bandit/memory/<slug>.md ← topic files
|
|
49
|
+
*
|
|
50
|
+
* Legacy location (back-compat for repos that already have them):
|
|
51
|
+
* MEMORY.md ← index file (root)
|
|
52
|
+
* memory/<slug>.md ← topic files (root)
|
|
53
|
+
*
|
|
54
|
+
* Both locations are searched at read time; entries are merged, with
|
|
55
|
+
* `.bandit/memory/` winning on slug collisions. WRITES always go to
|
|
56
|
+
* `.bandit/memory/`.
|
|
57
|
+
*
|
|
58
|
+
* ## Index entry format
|
|
49
59
|
*
|
|
50
60
|
* - [Topic title](memory/file.md) — one-line hook for relevance matching
|
|
51
61
|
*
|
|
52
62
|
* The hook is what the agent sees and reasons about. Pick hooks that name
|
|
53
63
|
* the situation ("when editing auth code", "when the user mentions X").
|
|
64
|
+
*
|
|
65
|
+
* Note: the link path inside MEMORY.md is ALWAYS written as `memory/file.md`
|
|
66
|
+
* regardless of which physical MEMORY.md is hosting it — the `read_memory`
|
|
67
|
+
* tool resolves the slug against its originating directory.
|
|
54
68
|
*/
|
|
55
69
|
const fs = __importStar(require("fs"));
|
|
56
70
|
const path = __importStar(require("path"));
|
|
57
71
|
exports.MAX_INDEX_BYTES = 4 * 1024;
|
|
58
72
|
exports.MAX_MEMORY_FILE_BYTES = 32 * 1024;
|
|
73
|
+
// ── Legacy root paths (back-compat) ────────────────────────────────────────
|
|
59
74
|
exports.MEMORY_DIR = 'memory';
|
|
60
75
|
exports.MEMORY_INDEX_FILE = 'MEMORY.md';
|
|
76
|
+
// ── Preferred .bandit/memory/ paths ────────────────────────────────────────
|
|
77
|
+
exports.BANDIT_DIR = '.bandit';
|
|
78
|
+
exports.BANDIT_MEMORY_DIR = '.bandit/memory';
|
|
79
|
+
exports.BANDIT_MEMORY_INDEX_FILE = '.bandit/memory/MEMORY.md';
|
|
80
|
+
// Matches em-dash, en-dash, or double-hyphen as the separator.
|
|
81
|
+
// The link path is always `memory/<file>` regardless of which MEMORY.md hosts it.
|
|
61
82
|
const ENTRY_RE = /^[-*]\s*\[([^\]]+)\]\(memory\/([^)]+)\)\s*(?:[—–-]+)\s*(.+)$/;
|
|
62
83
|
function slugFromFilename(file) {
|
|
63
84
|
return file.replace(/\.md$/i, '');
|
|
@@ -82,23 +103,28 @@ function renderMemoryIndexBlock(index) {
|
|
|
82
103
|
...lines
|
|
83
104
|
].join('\n');
|
|
84
105
|
}
|
|
85
|
-
async function
|
|
86
|
-
|
|
106
|
+
async function parseIndexFile(abs,
|
|
107
|
+
/** Physical directory that contains the `memory/` subfolder for this index. */
|
|
108
|
+
physicalMemoryDir,
|
|
109
|
+
/** Prefix to use in relPath (e.g. "memory" or ".bandit/memory"). */
|
|
110
|
+
relDirPrefix, warn) {
|
|
87
111
|
let raw;
|
|
88
112
|
try {
|
|
89
113
|
raw = await fs.promises.readFile(abs);
|
|
90
114
|
}
|
|
91
115
|
catch {
|
|
92
|
-
return
|
|
116
|
+
return null;
|
|
93
117
|
}
|
|
94
118
|
if (raw.byteLength === 0) {
|
|
95
119
|
return { indexContent: '', entries: [], source: abs };
|
|
96
120
|
}
|
|
97
121
|
const truncated = raw.byteLength > exports.MAX_INDEX_BYTES;
|
|
98
122
|
const text = raw.subarray(0, exports.MAX_INDEX_BYTES).toString('utf-8');
|
|
99
|
-
const indexContent = truncated
|
|
123
|
+
const indexContent = truncated
|
|
124
|
+
? `${text}\n… (truncated — MEMORY.md exceeds ${exports.MAX_INDEX_BYTES} bytes; split topics into smaller files)`
|
|
125
|
+
: text;
|
|
100
126
|
const entries = [];
|
|
101
|
-
const
|
|
127
|
+
const seenInFile = new Set();
|
|
102
128
|
for (const line of text.split(/\r?\n/)) {
|
|
103
129
|
const match = ENTRY_RE.exec(line.trim());
|
|
104
130
|
if (!match)
|
|
@@ -109,8 +135,8 @@ async function loadMemoryIndex(cwd, warn = defaultWarn) {
|
|
|
109
135
|
warn(`skipped entry "${title}" — invalid memory/ path "${file}"`);
|
|
110
136
|
continue;
|
|
111
137
|
}
|
|
112
|
-
const relPath =
|
|
113
|
-
const absPath = path.resolve(
|
|
138
|
+
const relPath = `${relDirPrefix}/${file}`;
|
|
139
|
+
const absPath = path.resolve(physicalMemoryDir, file);
|
|
114
140
|
let exists = false;
|
|
115
141
|
try {
|
|
116
142
|
const stat = await fs.promises.stat(absPath);
|
|
@@ -124,19 +150,177 @@ async function loadMemoryIndex(cwd, warn = defaultWarn) {
|
|
|
124
150
|
continue;
|
|
125
151
|
}
|
|
126
152
|
const name = slugFromFilename(file);
|
|
127
|
-
if (
|
|
153
|
+
if (seenInFile.has(name)) {
|
|
128
154
|
warn(`duplicate slug "${name}" — keeping first occurrence`);
|
|
129
155
|
continue;
|
|
130
156
|
}
|
|
131
|
-
|
|
132
|
-
entries.push({
|
|
133
|
-
name,
|
|
134
|
-
title: title.trim(),
|
|
135
|
-
hook: hookRaw.trim(),
|
|
136
|
-
relPath,
|
|
137
|
-
absPath
|
|
138
|
-
});
|
|
157
|
+
seenInFile.add(name);
|
|
158
|
+
entries.push({ name, title: title.trim(), hook: hookRaw.trim(), relPath, absPath });
|
|
139
159
|
}
|
|
140
160
|
return { indexContent, entries, source: abs };
|
|
141
161
|
}
|
|
162
|
+
// ── Public: merged loader ───────────────────────────────────────────────────
|
|
163
|
+
/**
|
|
164
|
+
* Load the memory index, searching both `.bandit/memory/MEMORY.md` (preferred)
|
|
165
|
+
* and the legacy root `MEMORY.md`. Entries from `.bandit/memory/` win on slug
|
|
166
|
+
* collisions. Returns a merged MemoryIndex.
|
|
167
|
+
*/
|
|
168
|
+
async function loadMemoryIndex(cwd, warn = defaultWarn) {
|
|
169
|
+
// 1. Try preferred location: .bandit/memory/MEMORY.md
|
|
170
|
+
const banditIndexAbs = path.resolve(cwd, exports.BANDIT_MEMORY_INDEX_FILE);
|
|
171
|
+
const banditMemDirAbs = path.resolve(cwd, exports.BANDIT_MEMORY_DIR);
|
|
172
|
+
const banditResult = await parseIndexFile(banditIndexAbs, banditMemDirAbs, exports.BANDIT_MEMORY_DIR, warn);
|
|
173
|
+
// 2. Try legacy location: root MEMORY.md / memory/
|
|
174
|
+
const rootIndexAbs = path.resolve(cwd, exports.MEMORY_INDEX_FILE);
|
|
175
|
+
const rootMemDirAbs = path.resolve(cwd, exports.MEMORY_DIR);
|
|
176
|
+
const rootResult = await parseIndexFile(rootIndexAbs, rootMemDirAbs, exports.MEMORY_DIR, warn);
|
|
177
|
+
// Neither found
|
|
178
|
+
if (!banditResult && !rootResult) {
|
|
179
|
+
return { indexContent: '', entries: [], source: null };
|
|
180
|
+
}
|
|
181
|
+
// Merge: preferred (.bandit/memory) wins on slug collision
|
|
182
|
+
const seen = new Set();
|
|
183
|
+
const entries = [];
|
|
184
|
+
// Add preferred entries first
|
|
185
|
+
if (banditResult) {
|
|
186
|
+
for (const e of banditResult.entries) {
|
|
187
|
+
if (seen.has(e.name)) {
|
|
188
|
+
warn(`duplicate slug "${e.name}" — keeping first occurrence`);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
seen.add(e.name);
|
|
192
|
+
entries.push(e);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Add legacy root entries (skip slugs already covered by preferred)
|
|
196
|
+
if (rootResult) {
|
|
197
|
+
for (const e of rootResult.entries) {
|
|
198
|
+
if (seen.has(e.name)) {
|
|
199
|
+
// Root has the same slug — silently skip (preferred wins)
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
seen.add(e.name);
|
|
203
|
+
entries.push(e);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// indexContent: combine both if both exist; preferred first
|
|
207
|
+
let indexContent = '';
|
|
208
|
+
if (banditResult?.indexContent) {
|
|
209
|
+
indexContent = banditResult.indexContent;
|
|
210
|
+
if (rootResult?.indexContent) {
|
|
211
|
+
indexContent += '\n\n<!-- legacy root MEMORY.md -->\n' + rootResult.indexContent;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else if (rootResult?.indexContent) {
|
|
215
|
+
indexContent = rootResult.indexContent;
|
|
216
|
+
}
|
|
217
|
+
// source: preferred if present, else root
|
|
218
|
+
const source = banditResult?.source ?? rootResult?.source ?? null;
|
|
219
|
+
return { indexContent, entries, source };
|
|
220
|
+
}
|
|
221
|
+
// ── Write helpers ───────────────────────────────────────────────────────────
|
|
222
|
+
/**
|
|
223
|
+
* Write a new topic file + update the index. Always writes to `.bandit/memory/`.
|
|
224
|
+
*
|
|
225
|
+
* @param cwd Workspace root
|
|
226
|
+
* @param slug Plain slug, e.g. "auth-conventions"
|
|
227
|
+
* @param title Human label for the index entry
|
|
228
|
+
* @param hook One-line hook (when is this relevant?)
|
|
229
|
+
* @param body Full markdown body for the topic file
|
|
230
|
+
* @returns The absolute path of the written topic file
|
|
231
|
+
*/
|
|
232
|
+
async function writeMemoryTopic(cwd, slug, title, hook, body) {
|
|
233
|
+
if (!slug || slug.includes('/') || slug.includes('..') || path.isAbsolute(slug)) {
|
|
234
|
+
throw new Error(`writeMemoryTopic: invalid slug "${slug}"`);
|
|
235
|
+
}
|
|
236
|
+
const safeSlug = slug.replace(/\.md$/i, '');
|
|
237
|
+
const memDir = path.resolve(cwd, exports.BANDIT_MEMORY_DIR);
|
|
238
|
+
await fs.promises.mkdir(memDir, { recursive: true });
|
|
239
|
+
const topicPath = path.resolve(memDir, `${safeSlug}.md`);
|
|
240
|
+
await fs.promises.writeFile(topicPath, body, 'utf-8');
|
|
241
|
+
// Update the index
|
|
242
|
+
const indexPath = path.resolve(cwd, exports.BANDIT_MEMORY_INDEX_FILE);
|
|
243
|
+
let existing = '';
|
|
244
|
+
try {
|
|
245
|
+
existing = await fs.promises.readFile(indexPath, 'utf-8');
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
existing = '# Memory Index\n\n';
|
|
249
|
+
}
|
|
250
|
+
const newLine = `- [${title}](memory/${safeSlug}.md) — ${hook}`;
|
|
251
|
+
// If slug already in index, replace the line; otherwise append
|
|
252
|
+
const slugPattern = new RegExp(`^[-*]\\s*\\[[^\\]]*\\]\\(memory\\/${safeSlug}\\.md\\).*$`, 'm');
|
|
253
|
+
let next;
|
|
254
|
+
if (slugPattern.test(existing)) {
|
|
255
|
+
next = existing.replace(slugPattern, newLine);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
next = existing.endsWith('\n') ? `${existing}${newLine}\n` : `${existing}\n${newLine}\n`;
|
|
259
|
+
}
|
|
260
|
+
await fs.promises.writeFile(indexPath, next, 'utf-8');
|
|
261
|
+
return topicPath;
|
|
262
|
+
}
|
|
263
|
+
// ── Migration ───────────────────────────────────────────────────────────────
|
|
264
|
+
/**
|
|
265
|
+
* One-time, idempotent migration: moves root `MEMORY.md` + `memory/` into
|
|
266
|
+
* `.bandit/memory/`. Safe to call on every startup — bails out early if:
|
|
267
|
+
* - the target `.bandit/memory/MEMORY.md` already exists, OR
|
|
268
|
+
* - the source root `MEMORY.md` does not exist.
|
|
269
|
+
*
|
|
270
|
+
* Steps:
|
|
271
|
+
* 1. Creates `.bandit/memory/` if needed.
|
|
272
|
+
* 2. Copies each `memory/<slug>.md` to `.bandit/memory/<slug>.md`.
|
|
273
|
+
* 3. Copies (rewrites) `MEMORY.md` to `.bandit/memory/MEMORY.md`.
|
|
274
|
+
* 4. Does NOT delete the originals (safe — caller can clean up if desired).
|
|
275
|
+
*
|
|
276
|
+
* @returns Array of absolute paths written (empty when migration is skipped).
|
|
277
|
+
*/
|
|
278
|
+
async function migrateMemoryToBanditDir(cwd) {
|
|
279
|
+
const targetIndex = path.resolve(cwd, exports.BANDIT_MEMORY_INDEX_FILE);
|
|
280
|
+
// Idempotent: already migrated
|
|
281
|
+
try {
|
|
282
|
+
await fs.promises.access(targetIndex);
|
|
283
|
+
return []; // target exists — skip
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// Target doesn't exist — proceed
|
|
287
|
+
}
|
|
288
|
+
const sourceIndex = path.resolve(cwd, exports.MEMORY_INDEX_FILE);
|
|
289
|
+
try {
|
|
290
|
+
await fs.promises.access(sourceIndex);
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
return []; // Source doesn't exist — nothing to migrate
|
|
294
|
+
}
|
|
295
|
+
const targetDir = path.resolve(cwd, exports.BANDIT_MEMORY_DIR);
|
|
296
|
+
await fs.promises.mkdir(targetDir, { recursive: true });
|
|
297
|
+
const written = [];
|
|
298
|
+
// Copy topic files
|
|
299
|
+
const sourceMemDir = path.resolve(cwd, exports.MEMORY_DIR);
|
|
300
|
+
let topicFiles = [];
|
|
301
|
+
try {
|
|
302
|
+
const entries = await fs.promises.readdir(sourceMemDir);
|
|
303
|
+
topicFiles = entries.filter((f) => f.toLowerCase().endsWith('.md'));
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
// No memory/ dir — fine, just copy the index
|
|
307
|
+
}
|
|
308
|
+
for (const file of topicFiles) {
|
|
309
|
+
const src = path.resolve(sourceMemDir, file);
|
|
310
|
+
const dst = path.resolve(targetDir, file);
|
|
311
|
+
try {
|
|
312
|
+
const content = await fs.promises.readFile(src);
|
|
313
|
+
await fs.promises.writeFile(dst, content);
|
|
314
|
+
written.push(dst);
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
// Skip files we can't read
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
// Copy the index
|
|
321
|
+
const indexContent = await fs.promises.readFile(sourceIndex);
|
|
322
|
+
await fs.promises.writeFile(targetIndex, indexContent);
|
|
323
|
+
written.push(targetIndex);
|
|
324
|
+
return written;
|
|
325
|
+
}
|
|
142
326
|
//# sourceMappingURL=memoryIndex.js.map
|
package/dist/memoryIndex.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memoryIndex.js","sourceRoot":"","sources":["../src/memoryIndex.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"memoryIndex.js","sourceRoot":"","sources":["../src/memoryIndex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface SecurityGuardSettings {
|
|
2
|
+
/** Master switch. Off by default. Set in `.bandit/settings.json` (or the
|
|
3
|
+
* global `~/.bandit/settings.json`) under `security.guard`. */
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
/** Extra command-substring patterns (regex source) to block, on top of the
|
|
6
|
+
* built-ins. */
|
|
7
|
+
blockCommands?: string[];
|
|
8
|
+
/** Extra absolute/`~` path prefixes to protect from writes. */
|
|
9
|
+
protectPaths?: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface SecurityGuardContext {
|
|
12
|
+
workspaceRoot?: string;
|
|
13
|
+
homeDir?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface SecurityGuardDecision {
|
|
16
|
+
allow: boolean;
|
|
17
|
+
reason?: string;
|
|
18
|
+
/** Identifier of the rule that fired (for logging / tests). */
|
|
19
|
+
rule?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Evaluate a tool call against the guard. Returns `{allow:true}` when the guard
|
|
23
|
+
* is disabled or nothing matches. Never throws.
|
|
24
|
+
*/
|
|
25
|
+
export declare function evaluateSecurityGuard(call: {
|
|
26
|
+
name: string;
|
|
27
|
+
params: Record<string, string>;
|
|
28
|
+
}, settings: SecurityGuardSettings | undefined, ctx?: SecurityGuardContext): SecurityGuardDecision;
|
|
29
|
+
//# sourceMappingURL=securityGuard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"securityGuard.d.ts","sourceRoot":"","sources":["../src/securityGuard.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,qBAAqB;IACpC;oEACgE;IAChE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;qBACiB;IACjB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA6ED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,EACtD,QAAQ,EAAE,qBAAqB,GAAG,SAAS,EAC3C,GAAG,GAAE,oBAAyB,GAC7B,qBAAqB,CA8BvB"}
|
|
@@ -0,0 +1,164 @@
|
|
|
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.evaluateSecurityGuard = evaluateSecurityGuard;
|
|
37
|
+
/**
|
|
38
|
+
* Built-in pre-tool security guard — an in-process, no-shell-spawn safety net
|
|
39
|
+
* that blocks the handful of tool calls that are almost never legitimate
|
|
40
|
+
* (catastrophic `rm`, piping a remote script into a shell, writing to system /
|
|
41
|
+
* credential paths, exfiltrating an SSH/cloud key over the network, …).
|
|
42
|
+
*
|
|
43
|
+
* It runs in `beforeToolExecute` BEFORE the user's own PreToolUse hooks and the
|
|
44
|
+
* permission policy, so it's the first line of defense against the *model*
|
|
45
|
+
* footgunning (prompt injection, a hallucinated `rm -rf /`) — NOT a sandbox and
|
|
46
|
+
* NOT protection against a malicious user (who controls the settings).
|
|
47
|
+
*
|
|
48
|
+
* Opt-in, OFF by default (`security.guard.enabled`). Deliberately conservative:
|
|
49
|
+
* every rule targets a pattern that legitimate agent work essentially never
|
|
50
|
+
* produces, so false positives stay rare. Shared by the CLI and the IDE host.
|
|
51
|
+
*/
|
|
52
|
+
const path = __importStar(require("path"));
|
|
53
|
+
const os = __importStar(require("os"));
|
|
54
|
+
const WRITE_TOOLS = new Set(['write_file', 'apply_edit', 'replace_range', 'apply_patch', 'delete_file']);
|
|
55
|
+
/** Recursive+force `rm` aimed at `/`, `~`, `$HOME`, or `/*`. */
|
|
56
|
+
function isCatastrophicRm(cmd) {
|
|
57
|
+
if (!/\brm\b/.test(cmd))
|
|
58
|
+
return false;
|
|
59
|
+
const recursive = /(^|\s)-[a-zA-Z]*r[a-zA-Z]*\b/.test(cmd) || /--recursive\b/.test(cmd);
|
|
60
|
+
const force = /(^|\s)-[a-zA-Z]*f[a-zA-Z]*\b/.test(cmd) || /--force\b/.test(cmd) || /--no-preserve-root\b/.test(cmd);
|
|
61
|
+
if (!(recursive && force))
|
|
62
|
+
return false;
|
|
63
|
+
if (/--no-preserve-root\b/.test(cmd))
|
|
64
|
+
return true;
|
|
65
|
+
// A bare root/home/glob-of-root target (slash/tilde/$HOME/`/*` followed by
|
|
66
|
+
// end, whitespace, or another slash/star — so `/tmp/x` is NOT matched).
|
|
67
|
+
return /(\s|=|["'])(\/|~|\$\{?HOME\}?|\/\*)(\s|$|["']|\/(?:\*|\s|$)|\*)/.test(cmd)
|
|
68
|
+
|| /\s\/\s*$/.test(cmd) || /\s~\s*$/.test(cmd) || /\s\/\*/.test(cmd);
|
|
69
|
+
}
|
|
70
|
+
const COMMAND_RULES = [
|
|
71
|
+
{ id: 'rm-root', reason: 'recursive force-delete of a root/home path', test: isCatastrophicRm },
|
|
72
|
+
{ id: 'curl-pipe-shell', reason: 'a downloaded script piped straight into a shell', test: (c) => /(?:curl|wget|fetch)\b[\s\S]*?\|\s*(?:sudo\s+)?(?:sh|bash|zsh|dash|python[0-9.]*|perl|ruby|node)\b/i.test(c) },
|
|
73
|
+
{ id: 'fork-bomb', reason: 'a fork bomb', test: (c) => /:\s*\(\s*\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;\s*:/.test(c) },
|
|
74
|
+
{ id: 'disk-destroy', reason: 'a raw write to a block device / filesystem', test: (c) => /\bmkfs(?:\.\w+)?\b/i.test(c) || /\bdd\b[\s\S]*\bof=\/dev\/(?:sd|nvme|hd|disk|mmcblk|vd)/i.test(c) || />\s*\/dev\/(?:sd|nvme|hd|disk|mmcblk|vd)/i.test(c) },
|
|
75
|
+
{ id: 'chmod-chown-root', reason: 'a recursive permission/owner change on `/`', test: (c) => /\bchmod\s+(?:-[a-z]*R[a-z]*\s+)?0?[0-7]{3}\s+\/(?:\s|$)/i.test(c) || /\bchown\s+-[a-z]*R[a-z]*\b[\s\S]*\s\/(?:\s|$)/i.test(c) },
|
|
76
|
+
{ id: 'redirect-sensitive', reason: 'output redirected into a system / credential path', test: (c) => />>?\s*(?:["']?)(?:\/etc\/|\/usr\/|\/bin\/|\/sbin\/|\/boot\/|~\/?\.ssh\/|\$HOME\/\.ssh\/|\.ssh\/authorized_keys|\/root\/)/i.test(c) },
|
|
77
|
+
{
|
|
78
|
+
id: 'secret-exfil',
|
|
79
|
+
reason: 'a credential file read AND sent over the network in one command',
|
|
80
|
+
test: (c) => {
|
|
81
|
+
const secretRead = /(?:\.ssh\/[\w.-]*(?:id_[a-z0-9]+|_rsa|_ed25519|_ecdsa|_dsa)\b|\bid_rsa\b|\.aws\/credentials|\.netrc\b|\.kube\/config\b|\.docker\/config\.json\b|\.gnupg\/)/i.test(c);
|
|
82
|
+
const netEgress = /\b(?:curl|wget|nc|netcat|ncat|telnet|scp|sftp)\b|https?:\/\//i.test(c);
|
|
83
|
+
return secretRead && netEgress;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
];
|
|
87
|
+
const SENSITIVE_WRITE_PREFIXES = [
|
|
88
|
+
'/etc/', '/usr/', '/bin/', '/sbin/', '/boot/', '/sys/', '/proc/', '/dev/', '/root/',
|
|
89
|
+
'/System/', '/Library/'
|
|
90
|
+
];
|
|
91
|
+
const SENSITIVE_WRITE_SUFFIXES = [
|
|
92
|
+
'/.ssh/', '/.aws/', '/.gnupg/', '/.kube/config', '/.docker/config.json',
|
|
93
|
+
'/.bashrc', '/.zshrc', '/.profile', '/.bash_profile'
|
|
94
|
+
];
|
|
95
|
+
function checkWritePath(rawPath, ctx, extraProtected) {
|
|
96
|
+
const home = ctx.homeDir ?? os.homedir();
|
|
97
|
+
const expanded = rawPath.trim().replace(/^~(?=\/|$)/, home);
|
|
98
|
+
const norm = expanded.replace(/\\/g, '/');
|
|
99
|
+
for (const prefix of [...SENSITIVE_WRITE_PREFIXES, ...extraProtected]) {
|
|
100
|
+
if (norm === prefix.replace(/\/$/, '') || norm.startsWith(prefix)) {
|
|
101
|
+
return { allow: false, rule: 'write-sensitive', reason: `writing to a protected system/credential path (${prefix})` };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const suffix of SENSITIVE_WRITE_SUFFIXES) {
|
|
105
|
+
if (norm.includes(suffix)) {
|
|
106
|
+
return { allow: false, rule: 'write-sensitive', reason: `writing to a protected credential path (${suffix})` };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Path traversal outside the workspace (only when we know the root and the
|
|
110
|
+
// path isn't an unrelated absolute temp path the host already allows).
|
|
111
|
+
if (ctx.workspaceRoot) {
|
|
112
|
+
const resolved = path.resolve(ctx.workspaceRoot, expanded);
|
|
113
|
+
const root = path.resolve(ctx.workspaceRoot);
|
|
114
|
+
if (resolved !== root && !resolved.startsWith(root + path.sep)) {
|
|
115
|
+
// Only flag when the original path explicitly traverses up; bare absolute
|
|
116
|
+
// temp paths (e.g. /tmp/x) aren't the guard's job and the host gates them.
|
|
117
|
+
if (/(^|\/)\.\.(\/|$)/.test(rawPath)) {
|
|
118
|
+
return { allow: false, rule: 'write-escape', reason: 'writing outside the workspace root via `..` traversal' };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { allow: true };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Evaluate a tool call against the guard. Returns `{allow:true}` when the guard
|
|
126
|
+
* is disabled or nothing matches. Never throws.
|
|
127
|
+
*/
|
|
128
|
+
function evaluateSecurityGuard(call, settings, ctx = {}) {
|
|
129
|
+
if (!settings?.enabled)
|
|
130
|
+
return { allow: true };
|
|
131
|
+
try {
|
|
132
|
+
const name = call.name;
|
|
133
|
+
const params = call.params ?? {};
|
|
134
|
+
if (name === 'run_command') {
|
|
135
|
+
const cmd = `${params.cmd ?? ''} ${params.args ?? ''}`.trim();
|
|
136
|
+
if (!cmd)
|
|
137
|
+
return { allow: true };
|
|
138
|
+
for (const rule of COMMAND_RULES) {
|
|
139
|
+
if (rule.test(cmd))
|
|
140
|
+
return { allow: false, rule: rule.id, reason: rule.reason };
|
|
141
|
+
}
|
|
142
|
+
for (const extra of settings.blockCommands ?? []) {
|
|
143
|
+
try {
|
|
144
|
+
if (new RegExp(extra, 'i').test(cmd))
|
|
145
|
+
return { allow: false, rule: 'custom-command', reason: `matched a configured blockCommands pattern (${extra})` };
|
|
146
|
+
}
|
|
147
|
+
catch { /* invalid user regex — ignore */ }
|
|
148
|
+
}
|
|
149
|
+
return { allow: true };
|
|
150
|
+
}
|
|
151
|
+
if (WRITE_TOOLS.has(name)) {
|
|
152
|
+
const target = params.path ?? '';
|
|
153
|
+
if (!target)
|
|
154
|
+
return { allow: true };
|
|
155
|
+
return checkWritePath(target, ctx, settings.protectPaths ?? []);
|
|
156
|
+
}
|
|
157
|
+
return { allow: true };
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// The guard must never break a turn — fail open.
|
|
161
|
+
return { allow: true };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=securityGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"securityGuard.js","sourceRoot":"","sources":["../src/securityGuard.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +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,
|
|
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,CAqE/C"}
|
|
@@ -35,11 +35,11 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.buildReadMemoryTool = buildReadMemoryTool;
|
|
37
37
|
/**
|
|
38
|
-
* `read_memory` — load a single topic file from
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* pull the full file into context.
|
|
38
|
+
* `read_memory` — load a single topic file from `.bandit/memory/<name>.md`
|
|
39
|
+
* (preferred) or the legacy `memory/<name>.md` on demand. Paired with
|
|
40
|
+
* `loadMemoryIndex` (the MEMORY.md index injected into the system prompt
|
|
41
|
+
* every turn). The agent decides whether a topic is relevant by reading the
|
|
42
|
+
* index's hook, then calls this tool to pull the full file into context.
|
|
43
43
|
*
|
|
44
44
|
* Rejects path traversal (`..`, absolute paths). On miss, the error
|
|
45
45
|
* lists the available slugs so the model can self-correct.
|
|
@@ -50,11 +50,11 @@ const memoryIndex_1 = require("../memoryIndex");
|
|
|
50
50
|
function buildReadMemoryTool() {
|
|
51
51
|
return {
|
|
52
52
|
name: 'read_memory',
|
|
53
|
-
description: 'Read a single topic memory file by slug. Use this when
|
|
53
|
+
description: 'Read a single topic memory file by slug. Use this when the memory index (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
54
|
parameters: [
|
|
55
55
|
{
|
|
56
56
|
name: 'name',
|
|
57
|
-
description: 'Memory file slug (no `memory/` prefix, no `.md` suffix). Example: "auth-conventions" loads memory/auth-conventions.md.',
|
|
57
|
+
description: 'Memory file slug (no `memory/` prefix, no `.md` suffix). Example: "auth-conventions" loads .bandit/memory/auth-conventions.md (or the legacy memory/auth-conventions.md).',
|
|
58
58
|
required: true
|
|
59
59
|
}
|
|
60
60
|
],
|
|
@@ -82,8 +82,10 @@ function buildReadMemoryTool() {
|
|
|
82
82
|
if (!entry) {
|
|
83
83
|
const available = index.entries.map((e) => e.name);
|
|
84
84
|
if (available.length === 0) {
|
|
85
|
+
const banditIndexPath = path.resolve(ctx.workspaceRoot, memoryIndex_1.BANDIT_MEMORY_DIR, 'MEMORY.md');
|
|
86
|
+
const rootIndexPath = path.resolve(ctx.workspaceRoot, 'MEMORY.md');
|
|
85
87
|
return {
|
|
86
|
-
output: `No memory index found. MEMORY.md is missing
|
|
88
|
+
output: `No memory index found. MEMORY.md is missing from both ${banditIndexPath} and ${rootIndexPath}.`,
|
|
87
89
|
isError: true
|
|
88
90
|
};
|
|
89
91
|
}
|
|
@@ -105,7 +107,7 @@ function buildReadMemoryTool() {
|
|
|
105
107
|
catch (err) {
|
|
106
108
|
const msg = err instanceof Error ? err.message : String(err);
|
|
107
109
|
return {
|
|
108
|
-
output: `Could not read ${
|
|
110
|
+
output: `Could not read ${entry.relPath}: ${msg}`,
|
|
109
111
|
isError: true
|
|
110
112
|
};
|
|
111
113
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readMemoryTool.js","sourceRoot":"","sources":["../../src/tools/readMemoryTool.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBA,
|
|
1
|
+
{"version":3,"file":"readMemoryTool.js","sourceRoot":"","sources":["../../src/tools/readMemoryTool.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burtson-labs/host-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Host-agnostic building blocks for the Bandit agent framework — memory files, hooks, mentions, and the extra tool set (todo_write, web_fetch).",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dist"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@burtson-labs/agent-core": "1.6.
|
|
20
|
+
"@burtson-labs/agent-core": "1.6.16"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/node": "^20.11.0",
|