@burtson-labs/host-kit 0.3.3 → 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 CHANGED
@@ -22,9 +22,11 @@ pnpm add @burtson-labs/host-kit
22
22
 
23
23
  ## <img src="https://api.iconify.design/lucide/puzzle.svg?color=%23a60ee5&width=22" align="absmiddle"> What's in the box
24
24
 
25
- - **Memory loader** — discovers and merges `BANDIT.md` / `CLAUDE.md` / `AGENTS.md` files across workspace + global locations
25
+ - **Memory loader** — discovers and merges `BANDIT.md` / `CLAUDE.md` / `AGENTS.md` files across workspace + global locations; deduplicates overlapping content at load time; `consolidateMemory()` unifies multiple entry files into a single canonical `BANDIT.md` (symlink on macOS/Linux, copy-with-drift-warning on Windows)
26
+ - **Topic memory** — lazy-load index at `.bandit/memory/MEMORY.md` (preferred) with back-compat reads from legacy root `MEMORY.md`; writes always go to `.bandit/memory/`; `migrateMemoryToBanditDir()` moves an existing root `memory/` layout into `.bandit/memory/` idempotently
26
27
  - **`@-mention` expansion** — detects `@path/to/file` in user input and inlines file contents (with secret redaction) or attaches images as base64
27
- - **Hook runner** — executes PreToolUse / PostToolUse / Stop / UserPromptSubmit hooks from `.bandit/settings.json` matching the Claude Code spec
28
+ - **Hook runner** — executes PreToolUse / PostToolUse / Stop / UserPromptSubmit hooks; `loadHookSettings` merges the **global** `~/.bandit/settings.json` under the workspace `.bandit/settings.json` so hooks + permissions + the guard apply across every repo
29
+ - **Pre-tool security guard** — `evaluateSecurityGuard(call, settings, ctx)`: an opt-in, in-process safety net (no shell spawn) that blocks catastrophic tool calls (`rm -rf /`, `curl … | sh`, disk wipes, credential exfil, writes to system/credential paths) before they run. Wired into `beforeToolExecute` in both hosts
28
30
  - **MCP loader** — reads `mcp-servers.json` (global + workspace, workspace wins), auto-injects `BANDIT_API_KEY`, registers servers with the pool
29
31
  - **Turn trace reader** — parses workspace and global `.bandit/turns/*.jsonl` into summaries and markdown timelines for CLI `/trace`, IDE `/trace`, tests, and future bug-bundle export
30
32
  - **Insights** — usage analytics aggregator (CLI sessions → human report)
package/dist/hooks.d.ts CHANGED
@@ -15,6 +15,7 @@
15
15
  * PreToolUse / PostToolUse provide: name, primary (first param value), duration (ms, Post only).
16
16
  * - A non-zero exit code from a PreToolUse hook aborts the tool call.
17
17
  */
18
+ import type { SecurityGuardSettings } from './securityGuard';
18
19
  export type HookEvent = 'PreToolUse' | 'PostToolUse' | 'Stop';
19
20
  export interface HookRule {
20
21
  match?: string;
@@ -29,8 +30,15 @@ export interface PermissionsBlock {
29
30
  export interface HookSettings {
30
31
  hooks?: Partial<Record<HookEvent, HookRule[]>>;
31
32
  permissions?: PermissionsBlock;
33
+ /** Built-in pre-tool security guard (opt-in, off by default). Read under
34
+ * `security.guard`. See securityGuard.ts. */
35
+ security?: {
36
+ guard?: SecurityGuardSettings;
37
+ };
32
38
  }
33
- export declare function loadHookSettings(cwd: string): Promise<HookSettings>;
39
+ export declare function loadHookSettings(cwd: string, opts?: {
40
+ homeDir?: string;
41
+ }): Promise<HookSettings>;
34
42
  /**
35
43
  * Persist an entry in the workspace settings.json permissions.allow list.
36
44
  * Called when the user picks "Always allow" in a permission prompt and wants
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,aAAa,GAAG,MAAM,CAAC;AAE9D,MAAM,WAAW,QAAQ;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC/C,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC;AAID,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAyBzE;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBjF;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,YAAY,EACtB,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,EAAE,CAAC,CAYvB"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,aAAa,GAAG,MAAM,CAAC;AAE9D,MAAM,WAAW,QAAQ;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC/C,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B;kDAC8C;IAC9C,QAAQ,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,qBAAqB,CAAA;KAAE,CAAC;CAC9C;AAID,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CA0CtG;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBjF;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,YAAY,EACtB,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,EAAE,CAAC,CAYvB"}
package/dist/hooks.js CHANGED
@@ -56,9 +56,16 @@ exports.runHooks = runHooks;
56
56
  const cp = __importStar(require("child_process"));
57
57
  const fs = __importStar(require("fs"));
58
58
  const path = __importStar(require("path"));
59
+ const os = __importStar(require("os"));
59
60
  const DEFAULT_TIMEOUT_MS = 10000;
60
- async function loadHookSettings(cwd) {
61
+ async function loadHookSettings(cwd, opts) {
62
+ // Global (~/.bandit) first, then workspace, then workspace .local — later
63
+ // files extend the earlier ones (hook/permission arrays concatenate; the
64
+ // security guard's scalar fields take the last value defined). This is what
65
+ // makes a user's GLOBAL hooks + guard apply to every repo, with per-project
66
+ // overrides on top. `opts.homeDir` overrides the global location (tests).
61
67
  const candidates = [
68
+ path.join(opts?.homeDir ?? os.homedir(), '.bandit', 'settings.json'),
62
69
  path.resolve(cwd, '.bandit/settings.json'),
63
70
  path.resolve(cwd, '.bandit/settings.local.json')
64
71
  ];
@@ -77,6 +84,17 @@ async function loadHookSettings(cwd) {
77
84
  merged.permissions.deny = [...(merged.permissions.deny ?? []), ...(parsed.permissions.deny ?? [])];
78
85
  merged.permissions.ask = [...(merged.permissions.ask ?? []), ...(parsed.permissions.ask ?? [])];
79
86
  }
87
+ if (parsed.security?.guard) {
88
+ const g = parsed.security.guard;
89
+ const cur = merged.security?.guard ?? {};
90
+ merged.security = {
91
+ guard: {
92
+ enabled: g.enabled ?? cur.enabled,
93
+ blockCommands: [...(cur.blockCommands ?? []), ...(g.blockCommands ?? [])],
94
+ protectPaths: [...(cur.protectPaths ?? []), ...(g.protectPaths ?? [])]
95
+ }
96
+ };
97
+ }
80
98
  }
81
99
  catch {
82
100
  // Missing / invalid — skip silently.
package/dist/hooks.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCH,4CA0CC;AAOD,8CAiBC;AAcD,4BAiBC;AA/HD,kDAAoC;AACpC,uCAAyB;AACzB,2CAA6B;AAC7B,uCAAyB;AAyBzB,MAAM,kBAAkB,GAAG,KAAM,CAAC;AAE3B,KAAK,UAAU,gBAAgB,CAAC,GAAW,EAAE,IAA2B;IAC7E,0EAA0E;IAC1E,yEAAyE;IACzE,4EAA4E;IAC5E,4EAA4E;IAC5E,0EAA0E;IAC1E,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC;QACpE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,uBAAuB,CAAC;QAC1C,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,6BAA6B,CAAC;KACjD,CAAC;IACF,MAAM,MAAM,GAAiB,EAAE,KAAK,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC;IAC1F,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YACnD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;YAC/C,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAgB,EAAE,CAAC;oBAC1D,MAAM,CAAC,KAAM,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,KAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;gBAClF,CAAC;YACH,CAAC;YACD,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;gBACvB,MAAM,CAAC,WAAY,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,WAAY,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;gBACxG,MAAM,CAAC,WAAY,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,WAAY,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;gBACrG,MAAM,CAAC,WAAY,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,WAAY,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;YACpG,CAAC;YACD,IAAI,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC;gBAC3B,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAChC,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC;gBACzC,MAAM,CAAC,QAAQ,GAAG;oBAChB,KAAK,EAAE;wBACL,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO;wBACjC,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;wBACzE,YAAY,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;qBACvE;iBACF,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,qCAAqC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACI,KAAK,UAAU,iBAAiB,CAAC,GAAW,EAAE,KAAa;IAChE,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAChD,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,IAAI,QAAQ,GAAiB,EAAE,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACtD,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;IACpD,CAAC;IACD,QAAQ,CAAC,WAAW,GAAG,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC;IAClD,QAAQ,CAAC,WAAW,CAAC,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,IAAI,EAAE,CAAC;IAC9D,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAChD,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AACvF,CAAC;AAcM,KAAK,UAAU,QAAQ,CAC5B,KAAgB,EAChB,QAAsB,EACtB,GAAgB,EAChB,GAAW;IAEX,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC5C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC,QAAQ,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7E,SAAS;QACX,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,IAAI,kBAAkB,CAAC,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,MAAM,CAAC,QAAgB,EAAE,GAAgB;IAChD,OAAO,QAAQ;SACZ,OAAO,CAAC,qBAAqB,EAAE,WAAW,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;SAC/D,OAAO,CAAC,wBAAwB,EAAE,WAAW,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;SACjE,OAAO,CAAC,yBAAyB,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC;AACtE,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe,EAAE,GAAW,EAAE,SAAiB;IAC/D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC9E,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QACrE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE;YACtB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,CAAC,EAAE,QAAQ,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE;YACrB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
- export { loadMemory, loadCombinedMemory, appendMemory, type MemoryBundle } from './memory';
2
- export { loadMemoryIndex, renderMemoryIndexBlock, MAX_INDEX_BYTES, MAX_MEMORY_FILE_BYTES, MEMORY_DIR, MEMORY_INDEX_FILE, type MemoryIndex, type MemoryIndexEntry, type MemoryWarnFn } from './memoryIndex';
1
+ export { loadMemory, loadCombinedMemory, appendMemory, consolidateMemory, type MemoryBundle, type ConsolidationStrategy, type ConsolidationResult } from './memory';
2
+ export { loadMemoryIndex, renderMemoryIndexBlock, writeMemoryTopic, migrateMemoryToBanditDir, MAX_INDEX_BYTES, MAX_MEMORY_FILE_BYTES, MEMORY_DIR, MEMORY_INDEX_FILE, BANDIT_DIR, BANDIT_MEMORY_DIR, BANDIT_MEMORY_INDEX_FILE, type MemoryIndex, type MemoryIndexEntry, type MemoryWarnFn } from './memoryIndex';
3
3
  export { buildReadMemoryTool } from './tools/readMemoryTool';
4
4
  export { loadMcpServersConfig, registerMcpServersFromDisk, globalMcpServersPath, persistMcpActivation, addMcpServerToConfig } from './mcp';
5
5
  export { buildGitHubServerConfig, looksLikeGitHubToken, buildSlackServerConfig, looksLikeSlackToken, looksLikeSlackTeamId, buildGitLabServerConfig, looksLikeGitLabToken, buildGmailServerConfig, looksLikeGmailCredentialsPath, buildCustomServerConfig } from './mcpConnectors';
6
6
  export { loadApprovedMcpFingerprints, approveMcpFingerprint, revokeMcpFingerprint, mcpTrustPath } from './mcpTrust';
7
7
  export { loadMcpToolCache, saveMcpToolEntry, pruneMcpToolCache, mcpToolCachePath } from './mcpToolCache';
8
8
  export { loadHookSettings, persistAllowEntry, runHooks, type HookEvent, type HookRule, type HookSettings, type HookContext, type HookResult, type PermissionsBlock } from './hooks';
9
+ export { evaluateSecurityGuard, type SecurityGuardSettings, type SecurityGuardContext, type SecurityGuardDecision } from './securityGuard';
9
10
  export { expandMentions, type ExpandedPrompt } from './mentions';
10
11
  export { TodoStore, buildTodoWriteTool, buildWebFetchTool, buildWebSearchTool, type WebSearchToolOptions, buildRememberTool } from './tools/extraTools';
11
12
  export { buildTaskTool, buildCheckTaskTool, buildListTasksTool, type TaskToolOptions } from './tools/taskTool';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,18 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.computeInsights = exports.parseTestOutput = exports.buildTestCommand = exports.detectTestFramework = exports.buildTestRunTool = exports.buildListTasksTool = exports.buildCheckTaskTool = exports.buildTaskTool = exports.buildRememberTool = exports.buildWebSearchTool = exports.buildWebFetchTool = exports.buildTodoWriteTool = exports.TodoStore = exports.expandMentions = exports.runHooks = exports.persistAllowEntry = exports.loadHookSettings = exports.mcpToolCachePath = exports.pruneMcpToolCache = exports.saveMcpToolEntry = exports.loadMcpToolCache = exports.mcpTrustPath = exports.revokeMcpFingerprint = exports.approveMcpFingerprint = exports.loadApprovedMcpFingerprints = exports.buildCustomServerConfig = exports.looksLikeGmailCredentialsPath = exports.buildGmailServerConfig = exports.looksLikeGitLabToken = exports.buildGitLabServerConfig = exports.looksLikeSlackTeamId = exports.looksLikeSlackToken = exports.buildSlackServerConfig = exports.looksLikeGitHubToken = exports.buildGitHubServerConfig = exports.addMcpServerToConfig = exports.persistMcpActivation = exports.globalMcpServersPath = exports.registerMcpServersFromDisk = exports.loadMcpServersConfig = exports.buildReadMemoryTool = exports.MEMORY_INDEX_FILE = exports.MEMORY_DIR = exports.MAX_MEMORY_FILE_BYTES = exports.MAX_INDEX_BYTES = exports.renderMemoryIndexBlock = exports.loadMemoryIndex = exports.appendMemory = exports.loadCombinedMemory = exports.loadMemory = void 0;
4
- exports.CheckpointStore = exports.isChatCapable = exports.suggestOllamaMatch = exports.listInstalledOllamaModels = exports.formatTurnTraceMarkdown = exports.summarizeTurnTrace = exports.parseTurnLog = exports.readTurnTraceById = exports.readTurnTrace = exports.listTurnTraces = exports.listTurnTraceFiles = exports.previewText = exports.openTurnLog = exports.SessionPermissionStore = exports.mergePolicies = exports.emptyPolicy = exports.evaluatePermission = exports.InMemoryBackgroundTaskStore = exports.buildInsightsAiCallback = exports.buildAiInput = exports.writeInsightsReport = exports.renderInsightsHtml = void 0;
3
+ exports.buildTaskTool = exports.buildRememberTool = exports.buildWebSearchTool = exports.buildWebFetchTool = exports.buildTodoWriteTool = exports.TodoStore = exports.expandMentions = exports.evaluateSecurityGuard = exports.runHooks = exports.persistAllowEntry = exports.loadHookSettings = exports.mcpToolCachePath = exports.pruneMcpToolCache = exports.saveMcpToolEntry = exports.loadMcpToolCache = exports.mcpTrustPath = exports.revokeMcpFingerprint = exports.approveMcpFingerprint = exports.loadApprovedMcpFingerprints = exports.buildCustomServerConfig = exports.looksLikeGmailCredentialsPath = exports.buildGmailServerConfig = exports.looksLikeGitLabToken = exports.buildGitLabServerConfig = exports.looksLikeSlackTeamId = exports.looksLikeSlackToken = exports.buildSlackServerConfig = exports.looksLikeGitHubToken = exports.buildGitHubServerConfig = exports.addMcpServerToConfig = exports.persistMcpActivation = exports.globalMcpServersPath = exports.registerMcpServersFromDisk = exports.loadMcpServersConfig = exports.buildReadMemoryTool = 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 = exports.migrateMemoryToBanditDir = exports.writeMemoryTopic = exports.renderMemoryIndexBlock = exports.loadMemoryIndex = exports.consolidateMemory = exports.appendMemory = exports.loadCombinedMemory = exports.loadMemory = void 0;
4
+ exports.CheckpointStore = exports.isChatCapable = exports.suggestOllamaMatch = exports.listInstalledOllamaModels = exports.formatTurnTraceMarkdown = exports.summarizeTurnTrace = exports.parseTurnLog = exports.readTurnTraceById = exports.readTurnTrace = exports.listTurnTraces = exports.listTurnTraceFiles = exports.previewText = exports.openTurnLog = exports.SessionPermissionStore = exports.mergePolicies = exports.emptyPolicy = exports.evaluatePermission = exports.InMemoryBackgroundTaskStore = exports.buildInsightsAiCallback = exports.buildAiInput = exports.writeInsightsReport = exports.renderInsightsHtml = exports.computeInsights = exports.parseTestOutput = exports.buildTestCommand = exports.detectTestFramework = exports.buildTestRunTool = exports.buildListTasksTool = exports.buildCheckTaskTool = void 0;
5
5
  var memory_1 = require("./memory");
6
6
  Object.defineProperty(exports, "loadMemory", { enumerable: true, get: function () { return memory_1.loadMemory; } });
7
7
  Object.defineProperty(exports, "loadCombinedMemory", { enumerable: true, get: function () { return memory_1.loadCombinedMemory; } });
8
8
  Object.defineProperty(exports, "appendMemory", { enumerable: true, get: function () { return memory_1.appendMemory; } });
9
+ Object.defineProperty(exports, "consolidateMemory", { enumerable: true, get: function () { return memory_1.consolidateMemory; } });
9
10
  var memoryIndex_1 = require("./memoryIndex");
10
11
  Object.defineProperty(exports, "loadMemoryIndex", { enumerable: true, get: function () { return memoryIndex_1.loadMemoryIndex; } });
11
12
  Object.defineProperty(exports, "renderMemoryIndexBlock", { enumerable: true, get: function () { return memoryIndex_1.renderMemoryIndexBlock; } });
13
+ Object.defineProperty(exports, "writeMemoryTopic", { enumerable: true, get: function () { return memoryIndex_1.writeMemoryTopic; } });
14
+ Object.defineProperty(exports, "migrateMemoryToBanditDir", { enumerable: true, get: function () { return memoryIndex_1.migrateMemoryToBanditDir; } });
12
15
  Object.defineProperty(exports, "MAX_INDEX_BYTES", { enumerable: true, get: function () { return memoryIndex_1.MAX_INDEX_BYTES; } });
13
16
  Object.defineProperty(exports, "MAX_MEMORY_FILE_BYTES", { enumerable: true, get: function () { return memoryIndex_1.MAX_MEMORY_FILE_BYTES; } });
14
17
  Object.defineProperty(exports, "MEMORY_DIR", { enumerable: true, get: function () { return memoryIndex_1.MEMORY_DIR; } });
15
18
  Object.defineProperty(exports, "MEMORY_INDEX_FILE", { enumerable: true, get: function () { return memoryIndex_1.MEMORY_INDEX_FILE; } });
19
+ Object.defineProperty(exports, "BANDIT_DIR", { enumerable: true, get: function () { return memoryIndex_1.BANDIT_DIR; } });
20
+ Object.defineProperty(exports, "BANDIT_MEMORY_DIR", { enumerable: true, get: function () { return memoryIndex_1.BANDIT_MEMORY_DIR; } });
21
+ Object.defineProperty(exports, "BANDIT_MEMORY_INDEX_FILE", { enumerable: true, get: function () { return memoryIndex_1.BANDIT_MEMORY_INDEX_FILE; } });
16
22
  var readMemoryTool_1 = require("./tools/readMemoryTool");
17
23
  Object.defineProperty(exports, "buildReadMemoryTool", { enumerable: true, get: function () { return readMemoryTool_1.buildReadMemoryTool; } });
18
24
  var mcp_1 = require("./mcp");
@@ -46,6 +52,8 @@ var hooks_1 = require("./hooks");
46
52
  Object.defineProperty(exports, "loadHookSettings", { enumerable: true, get: function () { return hooks_1.loadHookSettings; } });
47
53
  Object.defineProperty(exports, "persistAllowEntry", { enumerable: true, get: function () { return hooks_1.persistAllowEntry; } });
48
54
  Object.defineProperty(exports, "runHooks", { enumerable: true, get: function () { return hooks_1.runHooks; } });
55
+ var securityGuard_1 = require("./securityGuard");
56
+ Object.defineProperty(exports, "evaluateSecurityGuard", { enumerable: true, get: function () { return securityGuard_1.evaluateSecurityGuard; } });
49
57
  var mentions_1 = require("./mentions");
50
58
  Object.defineProperty(exports, "expandMentions", { enumerable: true, get: function () { return mentions_1.expandMentions; } });
51
59
  var extraTools_1 = require("./tools/extraTools");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAAA,mCAA2F;AAAlF,oGAAA,UAAU,OAAA;AAAE,4GAAA,kBAAkB,OAAA;AAAE,sGAAA,YAAY,OAAA;AACrD,6CAUuB;AATrB,8GAAA,eAAe,OAAA;AACf,qHAAA,sBAAsB,OAAA;AACtB,8GAAA,eAAe,OAAA;AACf,oHAAA,qBAAqB,OAAA;AACrB,yGAAA,UAAU,OAAA;AACV,gHAAA,iBAAiB,OAAA;AAKnB,yDAA6D;AAApD,qHAAA,mBAAmB,OAAA;AAC5B,6BAMe;AALb,2GAAA,oBAAoB,OAAA;AACpB,iHAAA,0BAA0B,OAAA;AAC1B,2GAAA,oBAAoB,OAAA;AACpB,2GAAA,oBAAoB,OAAA;AACpB,2GAAA,oBAAoB,OAAA;AAEtB,iDAWyB;AAVvB,wHAAA,uBAAuB,OAAA;AACvB,qHAAA,oBAAoB,OAAA;AACpB,uHAAA,sBAAsB,OAAA;AACtB,oHAAA,mBAAmB,OAAA;AACnB,qHAAA,oBAAoB,OAAA;AACpB,wHAAA,uBAAuB,OAAA;AACvB,qHAAA,oBAAoB,OAAA;AACpB,uHAAA,sBAAsB,OAAA;AACtB,8HAAA,6BAA6B,OAAA;AAC7B,wHAAA,uBAAuB,OAAA;AAEzB,uCAKoB;AAJlB,uHAAA,2BAA2B,OAAA;AAC3B,iHAAA,qBAAqB,OAAA;AACrB,gHAAA,oBAAoB,OAAA;AACpB,wGAAA,YAAY,OAAA;AAEd,+CAKwB;AAJtB,gHAAA,gBAAgB,OAAA;AAChB,gHAAA,gBAAgB,OAAA;AAChB,iHAAA,iBAAiB,OAAA;AACjB,gHAAA,gBAAgB,OAAA;AAElB,iCAUiB;AATf,yGAAA,gBAAgB,OAAA;AAChB,0GAAA,iBAAiB,OAAA;AACjB,iGAAA,QAAQ,OAAA;AAQV,uCAAiE;AAAxD,0GAAA,cAAc,OAAA;AACvB,iDAO4B;AAN1B,uGAAA,SAAS,OAAA;AACT,gHAAA,kBAAkB,OAAA;AAClB,+GAAA,iBAAiB,OAAA;AACjB,gHAAA,kBAAkB,OAAA;AAElB,+GAAA,iBAAiB,OAAA;AAEnB,6CAA+G;AAAtG,yGAAA,aAAa,OAAA;AAAE,8GAAA,kBAAkB,OAAA;AAAE,8GAAA,kBAAkB,OAAA;AAC9D,mDAO6B;AAN3B,+GAAA,gBAAgB,OAAA;AAChB,kHAAA,mBAAmB,OAAA;AACnB,+GAAA,gBAAgB,OAAA;AAChB,8GAAA,eAAe,OAAA;AAIjB,uCAaoB;AAZlB,2GAAA,eAAe,OAAA;AACf,8GAAA,kBAAkB,OAAA;AAClB,+GAAA,mBAAmB,OAAA;AACnB,wGAAA,YAAY,OAAA;AACZ,mHAAA,uBAAuB,OAAA;AASzB,qDAM2B;AALzB,8HAAA,2BAA2B,OAAA;AAM7B,6CAOuB;AANrB,iHAAA,kBAAkB,OAAA;AAClB,0GAAA,WAAW,OAAA;AACX,4GAAA,aAAa,OAAA;AACb,qHAAA,sBAAsB,OAAA;AAIxB,qCAgBmB;AAfjB,sGAAA,WAAW,OAAA;AACX,sGAAA,WAAW,OAAA;AACX,6GAAA,kBAAkB,OAAA;AAClB,yGAAA,cAAc,OAAA;AACd,wGAAA,aAAa,OAAA;AACb,4GAAA,iBAAiB,OAAA;AACjB,uGAAA,YAAY,OAAA;AACZ,6GAAA,kBAAkB,OAAA;AAClB,kHAAA,uBAAuB,OAAA;AAQzB,+CAKwB;AAJtB,yHAAA,yBAAyB,OAAA;AACzB,kHAAA,kBAAkB,OAAA;AAClB,6GAAA,aAAa,OAAA;AAGf,6CAKuB;AAJrB,8GAAA,eAAe,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/memory.d.ts CHANGED
@@ -2,6 +2,20 @@
2
2
  * Memory — auto-load workspace-local context files (BANDIT.md / CLAUDE.md)
3
3
  * and inline them into the system prompt so the agent follows project rules
4
4
  * without being re-told on every turn.
5
+ *
6
+ * ## Deduplication (v0.4)
7
+ *
8
+ * When a repo has more than one of BANDIT.md / CLAUDE.md / AGENTS.md (e.g.
9
+ * a migration-in-progress state), loadMemory will skip files whose content
10
+ * is identical — or whose entire text is already present inside a
11
+ * previously-loaded file — so the model doesn't see duplicated context.
12
+ *
13
+ * ## Consolidation
14
+ *
15
+ * `consolidateMemory(cwd)` merges all found entry files into a single
16
+ * canonical BANDIT.md and makes the others point at it. On macOS/Linux a
17
+ * symlink is preferred; on Windows (or when the symlink attempt fails) it
18
+ * writes an exact copy with a drift warning header.
5
19
  */
6
20
  import { type MemoryWarnFn } from './memoryIndex';
7
21
  export interface MemoryBundle {
@@ -10,7 +24,7 @@ export interface MemoryBundle {
10
24
  sources: string[];
11
25
  }
12
26
  /**
13
- * loadMemory + MEMORY.md index, fused into a single bundle the host can
27
+ * loadMemory + topic-memory index, fused into a single bundle the host can
14
28
  * inject as the system-prompt memory block. Always-loaded files come
15
29
  * first; the index follows under its own source marker so the model
16
30
  * knows which entries are full content vs. on-demand topic pointers.
@@ -19,6 +33,19 @@ export interface MemoryBundle {
19
33
  * the `/memory` slash command and boot-status output.
20
34
  */
21
35
  export declare function loadCombinedMemory(cwd: string, warn?: MemoryWarnFn): Promise<MemoryBundle>;
36
+ /**
37
+ * Read and deduplicate memory candidate files.
38
+ *
39
+ * Dedup strategy: after normalising whitespace, if the trimmed content of a
40
+ * candidate is entirely contained within the already-accumulated text (or is
41
+ * byte-identical to a previously loaded file) we skip it. This handles the
42
+ * common case where CLAUDE.md was copied verbatim into BANDIT.md during a
43
+ * migration, or where .bandit/memory.md echoes the root BANDIT.md.
44
+ *
45
+ * We do NOT try to dedupe at the paragraph/section level — that would require
46
+ * NLP and is overkill. The simple containment check catches >90% of real-world
47
+ * cases.
48
+ */
22
49
  export declare function loadMemory(cwd: string): Promise<MemoryBundle>;
23
50
  /**
24
51
  * Append a single fact to project memory so it survives across sessions.
@@ -35,4 +62,40 @@ export declare function loadMemory(cwd: string): Promise<MemoryBundle>;
35
62
  * and needs to see WHERE the fact landed.
36
63
  */
37
64
  export declare function appendMemory(cwd: string, fact: string): Promise<string>;
65
+ export type ConsolidationStrategy = 'symlink-or-copy' | 'copy';
66
+ export interface ConsolidationResult {
67
+ /** Absolute path of the canonical file (root BANDIT.md). */
68
+ canonical: string;
69
+ /** Files that were made to point at the canonical (symlinked or copied). */
70
+ redirected: string[];
71
+ /** 'symlink' when the OS supports it, 'copy' as fallback. */
72
+ method: 'symlink' | 'copy';
73
+ /** Files that were already identical/symlinked (skipped). */
74
+ skipped: string[];
75
+ }
76
+ /**
77
+ * Consolidate multiple memory entry files (BANDIT.md / CLAUDE.md / AGENTS.md)
78
+ * into a single canonical `BANDIT.md`. The canonical file gets the merged
79
+ * content; each other file that previously had unique content becomes a
80
+ * pointer (symlink or copy) to BANDIT.md.
81
+ *
82
+ * ## Symlink vs copy decision
83
+ *
84
+ * - macOS / Linux: the function attempts `fs.symlink(canonical, other)`. If
85
+ * it succeeds, method === 'symlink'.
86
+ * - Windows (or when symlink creation fails with EPERM / ENOTSUP): falls back
87
+ * to writing an exact copy of BANDIT.md into the other file, prefixed with a
88
+ * comment warning that it can drift. method === 'copy'.
89
+ * - Callers can force 'copy' via the `strategy` option to skip the symlink
90
+ * attempt entirely.
91
+ *
92
+ * **Tradeoff**: symlinks are invisible to tools that `cat` the file, so editors
93
+ * show the canonical content transparently. Copies can drift if BANDIT.md is
94
+ * updated without running consolidateMemory again. There is no perfect answer;
95
+ * symlinks are preferred wherever supported.
96
+ *
97
+ * @param cwd Workspace root
98
+ * @param strategy 'symlink-or-copy' (default) | 'copy'
99
+ */
100
+ export declare function consolidateMemory(cwd: string, strategy?: ConsolidationStrategy): Promise<ConsolidationResult>;
38
101
  //# sourceMappingURL=memory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAWvB,MAAM,WAAW,YAAY;IAC3B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAUhG;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAsBnE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkC7E"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAWvB,MAAM,WAAW,YAAY;IAC3B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAUhG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CA+BnE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkC7E;AAID,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,GAAG,MAAM,CAAC;AAE/D,MAAM,WAAW,mBAAmB;IAClC,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,6DAA6D;IAC7D,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,qBAAyC,GAClD,OAAO,CAAC,mBAAmB,CAAC,CAkG9B"}
package/dist/memory.js CHANGED
@@ -3,6 +3,20 @@
3
3
  * Memory — auto-load workspace-local context files (BANDIT.md / CLAUDE.md)
4
4
  * and inline them into the system prompt so the agent follows project rules
5
5
  * without being re-told on every turn.
6
+ *
7
+ * ## Deduplication (v0.4)
8
+ *
9
+ * When a repo has more than one of BANDIT.md / CLAUDE.md / AGENTS.md (e.g.
10
+ * a migration-in-progress state), loadMemory will skip files whose content
11
+ * is identical — or whose entire text is already present inside a
12
+ * previously-loaded file — so the model doesn't see duplicated context.
13
+ *
14
+ * ## Consolidation
15
+ *
16
+ * `consolidateMemory(cwd)` merges all found entry files into a single
17
+ * canonical BANDIT.md and makes the others point at it. On macOS/Linux a
18
+ * symlink is preferred; on Windows (or when the symlink attempt fails) it
19
+ * writes an exact copy with a drift warning header.
6
20
  */
7
21
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
22
  if (k2 === undefined) k2 = k;
@@ -41,7 +55,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
41
55
  exports.loadCombinedMemory = loadCombinedMemory;
42
56
  exports.loadMemory = loadMemory;
43
57
  exports.appendMemory = appendMemory;
58
+ exports.consolidateMemory = consolidateMemory;
44
59
  const fs = __importStar(require("fs"));
60
+ const os = __importStar(require("os"));
45
61
  const path = __importStar(require("path"));
46
62
  const memoryIndex_1 = require("./memoryIndex");
47
63
  const CANDIDATES = [
@@ -53,7 +69,7 @@ const CANDIDATES = [
53
69
  ];
54
70
  const MAX_BYTES = 32 * 1024;
55
71
  /**
56
- * loadMemory + MEMORY.md index, fused into a single bundle the host can
72
+ * loadMemory + topic-memory index, fused into a single bundle the host can
57
73
  * inject as the system-prompt memory block. Always-loaded files come
58
74
  * first; the index follows under its own source marker so the model
59
75
  * knows which entries are full content vs. on-demand topic pointers.
@@ -67,15 +83,30 @@ async function loadCombinedMemory(cwd, warn) {
67
83
  const indexBlock = (0, memoryIndex_1.renderMemoryIndexBlock)(index);
68
84
  if (!indexBlock)
69
85
  return base;
70
- const headed = `<!-- source: ${memoryIndex_1.MEMORY_INDEX_FILE} -->\n${indexBlock}`;
86
+ const headed = `<!-- source: ${memoryIndex_1.BANDIT_MEMORY_INDEX_FILE} -->\n${indexBlock}`;
71
87
  return {
72
88
  content: base.content ? `${base.content}\n\n${headed}` : headed,
73
- sources: index.source ? [...base.sources, memoryIndex_1.MEMORY_INDEX_FILE] : base.sources
89
+ sources: index.source ? [...base.sources, memoryIndex_1.BANDIT_MEMORY_INDEX_FILE] : base.sources
74
90
  };
75
91
  }
92
+ /**
93
+ * Read and deduplicate memory candidate files.
94
+ *
95
+ * Dedup strategy: after normalising whitespace, if the trimmed content of a
96
+ * candidate is entirely contained within the already-accumulated text (or is
97
+ * byte-identical to a previously loaded file) we skip it. This handles the
98
+ * common case where CLAUDE.md was copied verbatim into BANDIT.md during a
99
+ * migration, or where .bandit/memory.md echoes the root BANDIT.md.
100
+ *
101
+ * We do NOT try to dedupe at the paragraph/section level — that would require
102
+ * NLP and is overkill. The simple containment check catches >90% of real-world
103
+ * cases.
104
+ */
76
105
  async function loadMemory(cwd) {
77
106
  const sections = [];
78
107
  const sources = [];
108
+ // Accumulated normalised text for containment checks
109
+ const seen = [];
79
110
  for (const rel of CANDIDATES) {
80
111
  const abs = path.resolve(cwd, rel);
81
112
  try {
@@ -84,8 +115,14 @@ async function loadMemory(cwd) {
84
115
  continue;
85
116
  const truncated = raw.byteLength > MAX_BYTES;
86
117
  const text = raw.subarray(0, MAX_BYTES).toString('utf-8');
118
+ // Dedup: skip if trimmed content is identical to or fully contained
119
+ // within something we've already loaded.
120
+ const normalised = text.trim();
121
+ if (normalised && isDuplicate(normalised, seen))
122
+ continue;
87
123
  sections.push(`<!-- source: ${rel} -->\n${text}${truncated ? '\n… (truncated)' : ''}`);
88
124
  sources.push(rel);
125
+ seen.push(normalised);
89
126
  }
90
127
  catch {
91
128
  // Not present — that's fine.
@@ -148,4 +185,143 @@ async function appendMemory(cwd, fact) {
148
185
  await fs.promises.writeFile(abs, next, 'utf-8');
149
186
  return abs;
150
187
  }
188
+ /**
189
+ * Consolidate multiple memory entry files (BANDIT.md / CLAUDE.md / AGENTS.md)
190
+ * into a single canonical `BANDIT.md`. The canonical file gets the merged
191
+ * content; each other file that previously had unique content becomes a
192
+ * pointer (symlink or copy) to BANDIT.md.
193
+ *
194
+ * ## Symlink vs copy decision
195
+ *
196
+ * - macOS / Linux: the function attempts `fs.symlink(canonical, other)`. If
197
+ * it succeeds, method === 'symlink'.
198
+ * - Windows (or when symlink creation fails with EPERM / ENOTSUP): falls back
199
+ * to writing an exact copy of BANDIT.md into the other file, prefixed with a
200
+ * comment warning that it can drift. method === 'copy'.
201
+ * - Callers can force 'copy' via the `strategy` option to skip the symlink
202
+ * attempt entirely.
203
+ *
204
+ * **Tradeoff**: symlinks are invisible to tools that `cat` the file, so editors
205
+ * show the canonical content transparently. Copies can drift if BANDIT.md is
206
+ * updated without running consolidateMemory again. There is no perfect answer;
207
+ * symlinks are preferred wherever supported.
208
+ *
209
+ * @param cwd Workspace root
210
+ * @param strategy 'symlink-or-copy' (default) | 'copy'
211
+ */
212
+ async function consolidateMemory(cwd, strategy = 'symlink-or-copy') {
213
+ const ENTRY_FILES = ['BANDIT.md', 'CLAUDE.md', 'AGENTS.md'];
214
+ const canonical = path.resolve(cwd, 'BANDIT.md');
215
+ // Gather unique content from all present files
216
+ const present = [];
217
+ for (const rel of ENTRY_FILES) {
218
+ const abs = path.resolve(cwd, rel);
219
+ try {
220
+ const content = await fs.promises.readFile(abs, 'utf-8');
221
+ if (content.trim())
222
+ present.push({ rel, abs, content });
223
+ }
224
+ catch {
225
+ // Not present
226
+ }
227
+ }
228
+ if (present.length === 0) {
229
+ // Nothing to consolidate — return an empty result
230
+ return { canonical, redirected: [], method: 'copy', skipped: [] };
231
+ }
232
+ // Check if all non-canonical files are already symlinks pointing at canonical
233
+ const canonicalEntry = present.find((f) => f.rel === 'BANDIT.md');
234
+ // Build merged content: deduplicate sections from all sources
235
+ const mergedParts = [];
236
+ const mergedSeen = [];
237
+ for (const { rel, content } of present) {
238
+ const normalised = content.trim();
239
+ if (!normalised || isDuplicate(normalised, mergedSeen))
240
+ continue;
241
+ mergedParts.push(content.trimEnd());
242
+ mergedSeen.push(normalised);
243
+ if (rel !== 'BANDIT.md') {
244
+ // Add a provenance comment when merging in content from another file
245
+ mergedParts[mergedParts.length - 1] =
246
+ `<!-- merged from ${rel} -->\n${mergedParts[mergedParts.length - 1]}`;
247
+ }
248
+ }
249
+ // If BANDIT.md doesn't exist yet, provide scaffold
250
+ if (!canonicalEntry) {
251
+ mergedParts.unshift('# Project Memory\n');
252
+ }
253
+ const merged = mergedParts.join('\n\n') + '\n';
254
+ await fs.promises.writeFile(canonical, merged, 'utf-8');
255
+ // Redirect other files to the canonical
256
+ const redirected = [];
257
+ const skipped = [];
258
+ let method = 'copy';
259
+ const useSymlink = strategy === 'symlink-or-copy' && !isWindows();
260
+ for (const { rel, abs } of present) {
261
+ if (rel === 'BANDIT.md')
262
+ continue;
263
+ // Check if already a symlink pointing at canonical
264
+ try {
265
+ const lstat = await fs.promises.lstat(abs);
266
+ if (lstat.isSymbolicLink()) {
267
+ const target = await fs.promises.readlink(abs);
268
+ const resolvedTarget = path.resolve(path.dirname(abs), target);
269
+ if (resolvedTarget === canonical) {
270
+ skipped.push(abs);
271
+ continue;
272
+ }
273
+ }
274
+ }
275
+ catch {
276
+ // Not a symlink — fall through
277
+ }
278
+ if (useSymlink) {
279
+ try {
280
+ // Remove the old file first, then create symlink
281
+ await fs.promises.unlink(abs);
282
+ // Use a relative symlink so the repo is portable
283
+ const rel_target = path.relative(path.dirname(abs), canonical);
284
+ await fs.promises.symlink(rel_target, abs);
285
+ method = 'symlink';
286
+ redirected.push(abs);
287
+ continue;
288
+ }
289
+ catch {
290
+ // Symlink failed — fall through to copy
291
+ }
292
+ }
293
+ // Copy: write a copy with a drift-warning header
294
+ const driftWarning = `<!-- COPY of BANDIT.md — generated by consolidateMemory.\n` +
295
+ ` This file may drift if BANDIT.md is updated without re-running consolidation.\n` +
296
+ ` On macOS/Linux prefer symlinks (strategy: 'symlink-or-copy'). -->\n\n`;
297
+ const copy = await fs.promises.readFile(canonical, 'utf-8');
298
+ await fs.promises.writeFile(abs, driftWarning + copy, 'utf-8');
299
+ redirected.push(abs);
300
+ }
301
+ return { canonical, redirected, method, skipped };
302
+ }
303
+ // ── Internal helpers ────────────────────────────────────────────────────────
304
+ /**
305
+ * Returns true when `candidate` is already represented in `seen`:
306
+ * either as an exact match, or as a substring of an already-loaded block.
307
+ *
308
+ * Normalises runs of whitespace before comparing so minor formatting
309
+ * differences (trailing newlines, blank-line count) don't prevent dedup.
310
+ */
311
+ function normaliseWS(s) {
312
+ return s.replace(/\s+/g, ' ').trim();
313
+ }
314
+ function isDuplicate(candidate, seen) {
315
+ const normCandidate = normaliseWS(candidate);
316
+ for (const s of seen) {
317
+ const normS = normaliseWS(s);
318
+ if (normS === normCandidate || normS.includes(normCandidate)) {
319
+ return true;
320
+ }
321
+ }
322
+ return false;
323
+ }
324
+ function isWindows() {
325
+ return os.platform() === 'win32';
326
+ }
151
327
  //# sourceMappingURL=memory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,9 @@ export declare const MAX_INDEX_BYTES: number;
2
2
  export declare const MAX_MEMORY_FILE_BYTES: number;
3
3
  export declare const MEMORY_DIR = "memory";
4
4
  export declare const MEMORY_INDEX_FILE = "MEMORY.md";
5
+ export declare const BANDIT_DIR = ".bandit";
6
+ export declare const BANDIT_MEMORY_DIR = ".bandit/memory";
7
+ export declare const BANDIT_MEMORY_INDEX_FILE = ".bandit/memory/MEMORY.md";
5
8
  export interface MemoryIndexEntry {
6
9
  /** Slug derived from filename (e.g. "auth-conventions"). Used as the `name` arg to read_memory. */
7
10
  name: string;
@@ -19,7 +22,7 @@ export interface MemoryIndex {
19
22
  indexContent: string;
20
23
  /** Parsed entries; dangling links are dropped (with a warning). */
21
24
  entries: MemoryIndexEntry[];
22
- /** Absolute path of MEMORY.md if found, else null. */
25
+ /** Absolute path of MEMORY.md if found, else null. Prefers .bandit/memory/MEMORY.md. */
23
26
  source: string | null;
24
27
  }
25
28
  /**
@@ -34,5 +37,36 @@ export type MemoryWarnFn = (msg: string) => void;
34
37
  * entries so the caller can `if (block) ...` without a null check.
35
38
  */
36
39
  export declare function renderMemoryIndexBlock(index: MemoryIndex): string;
40
+ /**
41
+ * Load the memory index, searching both `.bandit/memory/MEMORY.md` (preferred)
42
+ * and the legacy root `MEMORY.md`. Entries from `.bandit/memory/` win on slug
43
+ * collisions. Returns a merged MemoryIndex.
44
+ */
37
45
  export declare function loadMemoryIndex(cwd: string, warn?: MemoryWarnFn): Promise<MemoryIndex>;
46
+ /**
47
+ * Write a new topic file + update the index. Always writes to `.bandit/memory/`.
48
+ *
49
+ * @param cwd Workspace root
50
+ * @param slug Plain slug, e.g. "auth-conventions"
51
+ * @param title Human label for the index entry
52
+ * @param hook One-line hook (when is this relevant?)
53
+ * @param body Full markdown body for the topic file
54
+ * @returns The absolute path of the written topic file
55
+ */
56
+ export declare function writeMemoryTopic(cwd: string, slug: string, title: string, hook: string, body: string): Promise<string>;
57
+ /**
58
+ * One-time, idempotent migration: moves root `MEMORY.md` + `memory/` into
59
+ * `.bandit/memory/`. Safe to call on every startup — bails out early if:
60
+ * - the target `.bandit/memory/MEMORY.md` already exists, OR
61
+ * - the source root `MEMORY.md` does not exist.
62
+ *
63
+ * Steps:
64
+ * 1. Creates `.bandit/memory/` if needed.
65
+ * 2. Copies each `memory/<slug>.md` to `.bandit/memory/<slug>.md`.
66
+ * 3. Copies (rewrites) `MEMORY.md` to `.bandit/memory/MEMORY.md`.
67
+ * 4. Does NOT delete the originals (safe — caller can clean up if desired).
68
+ *
69
+ * @returns Array of absolute paths written (empty when migration is skipped).
70
+ */
71
+ export declare function migrateMemoryToBanditDir(cwd: string): Promise<string[]>;
38
72
  //# sourceMappingURL=memoryIndex.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memoryIndex.d.ts","sourceRoot":"","sources":["../src/memoryIndex.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,eAAe,QAAW,CAAC;AACxC,eAAO,MAAM,qBAAqB,QAAY,CAAC;AAC/C,eAAO,MAAM,UAAU,WAAW,CAAC;AACnC,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAE7C,MAAM,WAAW,gBAAgB;IAC/B,mGAAmG;IACnG,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,0FAA0F;IAC1F,YAAY,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,sDAAsD;IACtD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAQD;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;AAMjD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAWjE;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,YAA0B,GAAG,OAAO,CAAC,WAAW,CAAC,CAuDzG"}
1
+ {"version":3,"file":"memoryIndex.d.ts","sourceRoot":"","sources":["../src/memoryIndex.ts"],"names":[],"mappings":"AA+BA,eAAO,MAAM,eAAe,QAAW,CAAC;AACxC,eAAO,MAAM,qBAAqB,QAAY,CAAC;AAG/C,eAAO,MAAM,UAAU,WAAW,CAAC;AACnC,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAG7C,eAAO,MAAM,UAAU,YAAY,CAAC;AACpC,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAClD,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAEnE,MAAM,WAAW,gBAAgB;IAC/B,mGAAmG;IACnG,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,0FAA0F;IAC1F,YAAY,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,wFAAwF;IACxF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAUD;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;AAMjD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAWjE;AAuED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,YAA0B,GAAG,OAAO,CAAC,WAAW,CAAC,CA2DzG;AAID;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CA+BjB;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkD7E"}
@@ -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
- * MEMORY.md at the workspace root is an INDEX one bullet per topic, each
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 (newv0.4)
47
45
  *
48
- * Index entry format:
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 loadMemoryIndex(cwd, warn = defaultWarn) {
86
- const abs = path.resolve(cwd, exports.MEMORY_INDEX_FILE);
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 { indexContent: '', entries: [], source: null };
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 ? `${text}\n… (truncated — MEMORY.md exceeds ${exports.MAX_INDEX_BYTES} bytes; split topics into smaller files)` : text;
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 seen = new Set();
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 = path.posix.join(exports.MEMORY_DIR, file);
113
- const absPath = path.resolve(cwd, exports.MEMORY_DIR, file);
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 (seen.has(name)) {
153
+ if (seenInFile.has(name)) {
128
154
  warn(`duplicate slug "${name}" — keeping first occurrence`);
129
155
  continue;
130
156
  }
131
- seen.add(name);
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
@@ -1 +1 @@
1
- {"version":3,"file":"memoryIndex.js","sourceRoot":"","sources":["../src/memoryIndex.ts"],"names":[],"mappings":"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"}
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,CAmE/C"}
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 `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.
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 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).',
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 or has no entries at ${path.resolve(ctx.workspaceRoot, 'MEMORY.md')}.`,
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 ${memoryIndex_1.MEMORY_DIR}/${slug}.md: ${msg}`,
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,kDAmEC;AAtFD;;;;;;;;;GASG;AACH,uCAAyB;AACzB,2CAA6B;AAE7B,gDAIwB;AAExB,SAAgB,mBAAmB;IACjC,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,WAAW,EACT,+RAA+R;QACjS,UAAU,EAAE;YACV;gBACE,IAAI,EAAE,MAAM;gBACZ,WAAW,EACT,wHAAwH;gBAC1H,QAAQ,EAAE,IAAI;aACf;SACF;QACD,KAAK,CAAC,OAAO,CAAC,MAA8B,EAAE,GAAyB;YACrE,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YAC7C,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,EAAE,MAAM,EAAE,oCAAoC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YACzE,CAAC;YACD,qEAAqE;YACrE,oEAAoE;YACpE,iEAAiE;YACjE,mEAAmE;YACnE,IACE,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC;gBACvB,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACxB,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACxB,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAC1B,CAAC;gBACD,OAAO;oBACL,MAAM,EAAE,+EAA+E,SAAS,GAAG;oBACnG,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC7C,MAAM,KAAK,GAAG,MAAM,IAAA,6BAAe,EAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACvD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YACzD,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBACnD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC3B,OAAO;wBACL,MAAM,EAAE,oEAAoE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,GAAG;wBAC3H,OAAO,EAAE,IAAI;qBACd,CAAC;gBACJ,CAAC;gBACD,OAAO;oBACL,MAAM,EAAE,gBAAgB,IAAI,2BAA2B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;oBAC7E,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACtD,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,GAAG,mCAAqB,CAAC;gBACzD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,mCAAqB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBACtE,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,iCAAiC,mCAAqB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;gBACvG,OAAO;oBACL,MAAM,EAAE,gBAAgB,KAAK,CAAC,OAAO,SAAS,IAAI,EAAE;oBACpD,OAAO,EAAE,KAAK;iBACf,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC7D,OAAO;oBACL,MAAM,EAAE,kBAAkB,wBAAU,IAAI,IAAI,QAAQ,GAAG,EAAE;oBACzD,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
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.3",
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",