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.
- package/README.md +68 -61
- package/dist/cli.mjs +22 -9
- 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
|
-
#
|
|
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
|
-
[](https://www.npmjs.com/package/agent-file-stash)
|
|
10
|
-
[](https://nodejs.org)
|
|
11
|
-
[](./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
|
|
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
|
-
|
|
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: ["
|
|
698
|
+
args: ["agent-file-stash", "serve"]
|
|
694
699
|
};
|
|
695
700
|
const opencodeMcpEntry = {
|
|
696
701
|
type: "local",
|
|
697
|
-
command: ["npx", "
|
|
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: {
|
|
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(`
|
|
765
|
+
console.log(`agent-file-stash - Agent file stash with diff tracking
|
|
753
766
|
|
|
754
767
|
Usage:
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
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
|
+
"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",
|