agent-file-stash 0.2.3 → 0.2.4

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.
Files changed (3) hide show
  1. package/README.md +68 -61
  2. package/dist/cli.mjs +22 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,41 +2,12 @@
2
2
  <img src="logo.svg" alt="agent-file-stash" width="200" />
3
3
  </p>
4
4
 
5
- # agent-file-stash
6
-
7
- > File stash with diff tracking for AI coding agents. Drop-in replacement for file reads that cuts token usage in half.
8
-
9
- [![npm version](https://img.shields.io/npm/v/agent-file-stash)](https://www.npmjs.com/package/agent-file-stash)
10
- [![Node.js >=24](https://img.shields.io/badge/node-%3E%3D24-brightgreen)](https://nodejs.org)
11
- [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
12
-
13
- ## Highlights
14
-
15
- - **50% fewer tokens** on repeated file reads — verified on real codebases
16
- - **Zero config** — one command auto-configures Claude Code, Cursor, and OpenCode
17
- - **No external services** — SQLite backed by Node.js 24 built-ins, no network required
18
- - **Partial-read aware** — stashes line ranges independently; returns `[unchanged in lines 50-59]` when only other parts changed
19
- - **Agents adopt it on their own** — tool descriptions alone are enough; no explicit instructions needed
20
-
21
- ## Table of Contents
22
-
23
- - [How it works](#how-it-works)
24
- - [Prerequisites](#prerequisites)
25
- - [Installation](#installation)
26
- - [Usage](#usage)
27
- - [As an MCP server](#as-an-mcp-server-recommended)
28
- - [As a CLI](#as-a-cli)
29
- - [As an SDK](#as-an-sdk)
30
- - [Benchmark](#benchmark)
31
- - [Project Structure](#project-structure)
32
- - [Architecture](#architecture)
33
- - [FAQ](#faq)
34
- - [License](#license)
35
-
36
- ## How it works
5
+ # Agent-File-Stash
37
6
 
38
7
  Agents waste most of their token budget re-reading files they've already seen. agent-file-stash fixes this: on first read it stashes the file, on subsequent reads it returns either "unchanged" (one line instead of the whole file) or a compact diff of what changed.
39
8
 
9
+ agent-file-stash is based on [cachebro](https://github.com/glommer/cachebro), an earlier tool with the same goal. cachebro required [Turso](https://turso.tech) as an external database dependency and lacked per-line-range stashing, meaning partial reads always returned the full file. agent-file-stash replaces Turso with `node:sqlite` — a built-in available since Node.js 24 — eliminating all external runtime dependencies. It also tracks partial reads independently by line range, so a re-read of lines 50–60 returns `[unchanged]` even if line 200 was edited. Additional improvements include a `readFileFull` method to force a full re-read and reset session tracking, proactive cache eviction when files are deleted via an optional file watcher, and a more accurate token estimate (`ceil(chars / 4)` vs the original `chars * 0.75`).
10
+
40
11
  ```
41
12
  First read: agent reads src/auth.ts → stashes content + hash → returns full file
42
13
  Second read: agent reads src/auth.ts → hash unchanged → returns "[unchanged, 245 lines, 1,837 tokens saved]"
@@ -46,6 +17,13 @@ Partial read: agent reads lines 50-60 → edit changed line 200 → returns "[un
46
17
 
47
18
  The stash persists in a local SQLite database (Node.js built-in `node:sqlite`, WAL mode). Content hashing (SHA-256) detects changes. No network, no external services, no configuration beyond a file path.
48
19
 
20
+ ## Highlights
21
+
22
+ - **50% fewer tokens** on repeated file reads — verified on real codebases
23
+ - **Zero config** — one command auto-configures Claude Code, Cursor, and OpenCode
24
+ - **No external services** — SQLite backed by Node.js 24 built-ins, no network required
25
+ - **Partial-read aware** — stashes line ranges independently; returns `[unchanged in lines 50-59]` when only other parts changed
26
+ - **Agents adopt it on their own** — tool descriptions alone are enough; no explicit instructions needed
49
27
  ## Prerequisites
50
28
 
51
29
  - **Node.js 24 or later** — agent-file-stash uses `node:sqlite`, a built-in module available from Node.js 24
@@ -86,13 +64,62 @@ The MCP server exposes 4 tools that agents discover and use automatically:
86
64
 
87
65
  ### As a CLI
88
66
 
67
+ #### `init`
68
+
69
+ ```bash
70
+ npx agent-file-stash init
71
+ ```
72
+
73
+ Detects installed editors and writes the MCP server entry into each config file it finds:
74
+
75
+ | Editor | Config file |
76
+ |--------|-------------|
77
+ | Claude Code | `~/.claude.json` |
78
+ | Cursor | `~/.cursor/mcp.json` |
79
+ | OpenCode | `$XDG_CONFIG_HOME/opencode/opencode.json` |
80
+
81
+ If the `agent-file-stash` key already exists in a config, that entry is left unchanged and reported as "already configured". After running, restart your editor to pick up the new server.
82
+
83
+ ```
84
+ Claude Code: configured (/Users/you/.claude.json)
85
+ OpenCode: already configured
86
+
87
+ Done! Restart your editor to pick up filestash.
88
+ ```
89
+
90
+ #### `serve`
91
+
92
+ ```bash
93
+ npx agent-file-stash serve
94
+ # or just: npx agent-file-stash
95
+ ```
96
+
97
+ Starts the MCP server over stdio. This is the command editors invoke automatically — you don't normally run it yourself. The server registers four tools (`read_file`, `read_files`, `stash_status`, `stash_clear`) and keeps the stash database open for the lifetime of the process.
98
+
99
+ The stash database is created at `$FILESTASH_DIR/stash.db` (defaults to `.file-stash/stash.db` relative to the working directory the editor uses when launching the server).
100
+
101
+ #### `status`
102
+
103
+ ```bash
104
+ npx agent-file-stash status
105
+ ```
106
+
107
+ Prints lifetime stats from the local stash database. Exits with a message if no database exists yet.
108
+
109
+ ```
110
+ filestash status:
111
+ Files tracked: 12
112
+ Tokens saved (total): ~53,851
113
+ ```
114
+
115
+ #### `help`
116
+
89
117
  ```bash
90
- agent-file-stash init # Auto-configure for Claude Code, Cursor, OpenCode
91
- agent-file-stash serve # Start the MCP server (default when no command given)
92
- agent-file-stash status # Show stash statistics
93
- agent-file-stash help # Show help
118
+ npx agent-file-stash help
94
119
  ```
95
120
 
121
+ Prints a short usage summary with all available commands.
122
+
96
123
  **Environment variables:**
97
124
 
98
125
  | Variable | Default | Description |
@@ -236,34 +263,14 @@ The SDK has no external dependencies — it uses only Node.js built-ins (`node:s
236
263
  | `stats` | Global token-savings counter |
237
264
  | `session_stats` | Per-session token-savings counter |
238
265
 
239
- Multiple sessions and branch switches are handled correctly — each session independently tracks which file version it last read, so switching branches or running multiple agents in parallel produces correct diffs for each.
266
+ `file_versions` is content-addressed: each row is a unique `(path, hash)` pair storing the full file content and its diff relative to the previous version at that path. When a file is read, its current content is hashed. If a matching row exists, no write occurs — the read is free. If the hash is new, a new row is inserted and the diff is computed and stored alongside it.
267
+
268
+ `session_reads` is a lightweight pointer table. Each row is a `(sessionId, path, hash)` triple recording which version of a file a given session last saw. On re-read, the engine joins `session_reads` against `file_versions` to decide what to return: same hash → `[unchanged]` label; different hash → stored diff; no prior entry → full content. This means two agents running in parallel, or an agent reading across a branch switch, each get correct diffs scoped to their own session.
269
+
270
+ WAL mode is enabled so concurrent reads never block each other and reads never block writes — important when multiple MCP tool calls fire in quick succession.
240
271
 
241
272
  **Change detection:** On every read, the current file content is hashed (SHA-256, truncated to 16 hex chars). Same hash = unchanged. Different hash = compute diff, update stash. No polling or watchers required for correctness — the hash is the source of truth. File watchers are optional and only used to proactively evict deleted files.
242
273
 
243
274
  **Diff algorithm:** Line-based unified diff (`computeDiff`). Groups changed lines into hunks with context lines, identical to the output of `git diff`. Diffs are stored as strings and returned verbatim to the agent.
244
275
 
245
276
  **Token estimation:** `ceil(characters / 4)`. Rough but directionally correct for code. Used only for the "tokens saved" metric — never affects correctness.
246
-
247
- ## FAQ
248
-
249
- **Does it work with agents other than Claude?**
250
- Yes. agent-file-stash is an MCP server — any MCP-compatible agent (Cursor, OpenCode, etc.) can use it.
251
-
252
- **Where is the stash database stored?**
253
- By default in `.file-stash/stash.db` inside the current working directory. Set `FILESTASH_DIR` to change this.
254
-
255
- **Is the stash shared across sessions?**
256
- File content is shared (content-addressed, so identical files are stored once). Read state is tracked per `sessionId` — each session independently knows which file version it last saw, so two agents running in parallel get correct diffs independently.
257
-
258
- **What happens when I switch git branches?**
259
- agent-file-stash detects the new file content via hashing and returns a diff automatically on the next read. No manual reset needed.
260
-
261
- **Does clearing the stash affect my source files?**
262
- No. `stash_clear` (or `stash.clear()`) only removes the stash database contents. Your source files are never modified.
263
-
264
- **What Node.js version do I need?**
265
- Node.js 24 or later. The `node:sqlite` module was stabilized in Node.js 24.
266
-
267
- ## License
268
-
269
- [MIT](./LICENSE)
package/dist/cli.mjs CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // packages/sdk/src/stash.ts
4
- import { DatabaseSync } from "node:sqlite";
5
4
  import { readFileSync, statSync } from "node:fs";
6
5
  import { resolve } from "node:path";
7
6
  import { createHash } from "node:crypto";
@@ -197,6 +196,7 @@ var StashStore = class {
197
196
  }
198
197
  async init() {
199
198
  if (this.initialized) return;
199
+ const { DatabaseSync } = await import("node:sqlite");
200
200
  this.db = new DatabaseSync(this.dbPath);
201
201
  this.db.exec("PRAGMA journal_mode=WAL");
202
202
  this.db.exec(SCHEMA);
@@ -670,6 +670,11 @@ Use this to verify filestash is working and see how many tokens it has saved.`
670
670
  }
671
671
 
672
672
  // packages/cli/src/index.ts
673
+ var _origEmitWarning = process.emitWarning;
674
+ process.emitWarning = function(msg, ...args) {
675
+ if (typeof msg === "string" && msg.includes("SQLite")) return;
676
+ return _origEmitWarning.apply(process, [msg, ...args]);
677
+ };
673
678
  var CLI_STATUS_SESSION = "cli-status";
674
679
  async function runStatus() {
675
680
  const stashDir = resolve4(process.env.FILESTASH_DIR ?? ".file-stash");
@@ -690,11 +695,11 @@ async function runInit() {
690
695
  const home = homedir();
691
696
  const mcpServersEntry = {
692
697
  command: "npx",
693
- args: ["filestash", "serve"]
698
+ args: ["agent-file-stash", "serve"]
694
699
  };
695
700
  const opencodeMcpEntry = {
696
701
  type: "local",
697
- command: ["npx", "filestash", "serve"]
702
+ command: ["npx", "agent-file-stash", "serve"]
698
703
  };
699
704
  const xdgConfig = process.env.XDG_CONFIG_HOME || join2(home, ".config");
700
705
  const targets = [
@@ -742,20 +747,28 @@ async function runInit() {
742
747
  }
743
748
  if (configured === 0) {
744
749
  console.log("No supported tools detected. You can manually add filestash to your MCP config:");
745
- console.log(JSON.stringify({ mcpServers: { filestash: mcpServersEntry } }, null, 2));
750
+ console.log(JSON.stringify({ mcpServers: { "agent-file-stash": mcpServersEntry } }, null, 2));
746
751
  } else {
747
752
  console.log(`
748
753
  Done! Restart your editor to pick up filestash.`);
754
+ console.log(`
755
+ Available MCP tools:`);
756
+ console.log(` read_file Read a file, returning only a diff if unchanged since last read`);
757
+ console.log(` read_files Batch read multiple files at once`);
758
+ console.log(` stash_status Show files tracked and tokens saved`);
759
+ console.log(` stash_clear Reset the stash (re-sends full file contents on next read)`);
760
+ console.log(`
761
+ Stash location: FILESTASH_DIR env var (default: .file-stash in cwd)`);
749
762
  }
750
763
  }
751
764
  function runHelp() {
752
- console.log(`filestash - Agent file stash with diff tracking
765
+ console.log(`agent-file-stash - Agent file stash with diff tracking
753
766
 
754
767
  Usage:
755
- filestash init Auto-configure filestash for your editor
756
- filestash serve Start the MCP server (default)
757
- filestash status Show stash statistics
758
- filestash help Show this help message
768
+ agent-file-stash init Auto-configure for your editor
769
+ agent-file-stash serve Start the MCP server (default)
770
+ agent-file-stash status Show stash statistics
771
+ agent-file-stash help Show this help message
759
772
 
760
773
  Environment:
761
774
  FILESTASH_DIR Stash directory (default: .file-stash)`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-file-stash",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "mcpName": "io.github.atilio-ts/agent-file-stash",
5
5
  "description": "File stash with diff tracking for AI coding agents. Drop-in replacement for file reads that saves tokens.",
6
6
  "type": "module",