codebase-snapshot 0.9.0 → 0.9.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/CHANGELOG.md +229 -1
- package/README.md +141 -127
- package/SECURITY.md +6 -2
- package/dist/bin.js +2544 -507
- package/dist/chunk-EWZYK3VX.js +2577 -0
- package/dist/{chunk-FJ4RQYY2.js → chunk-FCWD4LY7.js} +493 -362
- package/dist/cli.cjs +2451 -436
- package/dist/cli.d.cts +11 -1
- package/dist/cli.d.ts +11 -1
- package/dist/cli.js +68 -750
- package/dist/index.cjs +481 -360
- package/dist/index.d.cts +111 -5
- package/dist/index.d.ts +111 -5
- package/dist/index.js +1 -1
- package/dist/mcp.cjs +9398 -0
- package/dist/mcp.d.cts +399 -0
- package/dist/mcp.d.ts +399 -0
- package/dist/mcp.js +4 -0
- package/docs/agent.md +36 -0
- package/docs/cli.md +85 -14
- package/docs/codebase-token-budget.md +98 -0
- package/docs/configuration.md +12 -2
- package/docs/how-to-feed-a-repo-to-claude.md +4 -2
- package/docs/install.md +39 -11
- package/docs/mcp.md +149 -0
- package/docs/stale-context-is-your-bug.md +118 -0
- package/docs/troubleshooting.md +13 -0
- package/docs/vs-repomix.md +4 -2
- package/package.json +32 -16
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,234 @@ All notable changes to `codebase-snapshot`.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## A note on version numbers
|
|
8
|
+
|
|
9
|
+
This package started its public life as `@ankurhalder/codebase-snapshot`, which reached 4.4.1. It
|
|
10
|
+
moved to the unscoped name and **restarted at 0.9.0**, so the numbers below are not a continuation of
|
|
11
|
+
the old line — `0.9.0` is newer than `4.4.1`, not older. 1.0.0 is reserved for when the CLI surface
|
|
12
|
+
is settled.
|
|
13
|
+
|
|
14
|
+
Two versions exist on the registry that are not releases, and both are deprecated:
|
|
15
|
+
|
|
16
|
+
| Version | What it is |
|
|
17
|
+
| :-- | :-- |
|
|
18
|
+
| `codebase-snapshot@4.5.0` | Published for about an hour under the new name before the scheme was reset to 0.9.0. Withdrawn, never the supported version. |
|
|
19
|
+
| `codebase-snapshot@0.0.0-stage` | npm's own staging placeholder, created automatically during the first publish of the name. Not a release. |
|
|
20
|
+
|
|
21
|
+
Deleting them requires account-level rights that the release pipeline does not have, so they are
|
|
22
|
+
deprecated with an explanatory message instead. `latest` has pointed at 0.9.0 since it existed.
|
|
23
|
+
|
|
24
|
+
## 0.9.4
|
|
25
|
+
|
|
26
|
+
### The snapshot is now something an agent can ask for
|
|
27
|
+
|
|
28
|
+
`codebase-snapshot mcp` serves the repository over the Model Context Protocol on stdio. Seven
|
|
29
|
+
tools, each answering one question an agent actually asks, and nothing that only looks useful:
|
|
30
|
+
|
|
31
|
+
| Tool | Question |
|
|
32
|
+
| :-- | :-- |
|
|
33
|
+
| `snapshot_status` | Is there a snapshot here, and what does it cover? |
|
|
34
|
+
| `snapshot_plan` | What *would* a generate at this budget include, and what would it drop? |
|
|
35
|
+
| `snapshot_generate` | Build it. The only tool that writes. |
|
|
36
|
+
| `snapshot_validate` | Is the context I was given still current? |
|
|
37
|
+
| `snapshot_locate` | Which part holds this symbol, route or file? |
|
|
38
|
+
| `snapshot_read` | Give me this window of this file. |
|
|
39
|
+
| `snapshot_explain` | Why is this path missing? |
|
|
40
|
+
|
|
41
|
+
Six are marked `readOnlyHint`, so clients can run them without a prompt; `snapshot_generate` is the
|
|
42
|
+
only one that asks.
|
|
43
|
+
|
|
44
|
+
### Both protocol eras, because they are not the same protocol
|
|
45
|
+
|
|
46
|
+
Revision `2026-07-28` removed the `initialize` handshake: requests carry their protocol version and
|
|
47
|
+
client capabilities in `_meta`, `server/discover` is mandatory, every result carries `resultType`,
|
|
48
|
+
and `ping` no longer exists. Every client shipping today speaks the older handshake. The server
|
|
49
|
+
answers whichever arrives first and never mixes them.
|
|
50
|
+
|
|
51
|
+
The eras also disagree about an unsupported version, and getting it backwards breaks one while
|
|
52
|
+
looking correct in the other: **legacy negotiates down** (the server answers with a revision it does
|
|
53
|
+
speak), **modern rejects with `-32022`** and lists what it supports so the client can retry. Both
|
|
54
|
+
paths have their own tests.
|
|
55
|
+
|
|
56
|
+
### Zero dependencies, including the protocol
|
|
57
|
+
|
|
58
|
+
`@modelcontextprotocol/sdk` is 4.5 MB unpacked with Express, Hono, Ajv, JOSE and Zod behind it. The
|
|
59
|
+
transport here is newline-delimited JSON-RPC in about 400 readable lines, which keeps the package's
|
|
60
|
+
single-dependency property intact and means the whole server can be audited in one sitting.
|
|
61
|
+
|
|
62
|
+
### Reads come from the snapshot, never from the working tree
|
|
63
|
+
|
|
64
|
+
`snapshot_read` extracts a file's section from the emitted part. That is why an excluded `.env`
|
|
65
|
+
cannot be read back, a redacted credential stays redacted, and a large file returns the bounded
|
|
66
|
+
preview the snapshot actually contains. The test asserts the strongest available property: the
|
|
67
|
+
secret value appears in no artifact the server serves.
|
|
68
|
+
|
|
69
|
+
### The contract does not lie about the server either
|
|
70
|
+
|
|
71
|
+
`describe --format json` gained an `mcp` block — tools, arguments, prompts, resources, protocol
|
|
72
|
+
versions — generated from the same objects the server serves. A test opens a live session, calls
|
|
73
|
+
`tools/list`, and compares it against the CLI's output, so a tool that exists on one side and not the
|
|
74
|
+
other fails the build.
|
|
75
|
+
|
|
76
|
+
### Known limitation, measured rather than assumed
|
|
77
|
+
|
|
78
|
+
Generation is synchronous. On this repository a `generate` takes **1.1 s**; on a synthetic
|
|
79
|
+
3,000-file tree it takes **7.5 s**, during which the server answers nothing else. That is under every
|
|
80
|
+
client's request timeout and well under a real monorepo's worth of files, so 0.9.4 runs it inline.
|
|
81
|
+
The number is in the docs, and a worker thread is the next change if reports come back that clients
|
|
82
|
+
time out.
|
|
83
|
+
|
|
84
|
+
### Ships alongside
|
|
85
|
+
|
|
86
|
+
- The README was cut from 2,311 to 1,814 tokens (measured by `readme-lint`, which counts URLs and
|
|
87
|
+
code blocks too). The narrative lost about a third of its length; the command table, the preset
|
|
88
|
+
names and the links stayed, because they are what a reader scans for.
|
|
89
|
+
- A `codebase-snapshot/mcp` subpath so another tool can mount the server in-process.
|
|
90
|
+
- `snapshot://` resources: the manifest, each part, the three reports, the contract and the skill,
|
|
91
|
+
plus `snapshot://parts/{index}` as a template.
|
|
92
|
+
- Two prompts, `orient` and `keep-current`, both about order of operations rather than features.
|
|
93
|
+
- `--cwd` is the only directory the server may read; a `root` argument can name a sub-directory of
|
|
94
|
+
it and nothing outside. `includeSensitiveFiles` is deliberately not a tool argument.
|
|
95
|
+
|
|
96
|
+
It does not install packages, write a config file, speak HTTP, or fetch a remote repository.
|
|
97
|
+
|
|
98
|
+
## 0.9.3
|
|
99
|
+
|
|
100
|
+
### The project now says what it is
|
|
101
|
+
|
|
102
|
+
Everything here already worked; none of it was visible. The pitch was "turn a repository into
|
|
103
|
+
an LLM-ready snapshot", which is the pitch every packer uses, so the one thing that is actually
|
|
104
|
+
ours — you can check the result — was buried in the fourth bullet of the second section.
|
|
105
|
+
|
|
106
|
+
The line is now **a snapshot you can prove is current**, and the mark is a frame closing on a
|
|
107
|
+
fingerprint. Both are consequences of the same idea rather than decoration: the artefact is
|
|
108
|
+
bounded, it is identifiable, and it can be compared later.
|
|
109
|
+
|
|
110
|
+
- **README**: a centred hero with the mark and the line, five badges, one command, and a
|
|
111
|
+
diagram that draws the argument — a dump that was silently truncated beside a snapshot with a
|
|
112
|
+
manifest and a validator. Nav links under the fold; the CLI reference moved to the site.
|
|
113
|
+
- **Brand assets** in `docs/assets/`: mark in light and dark ink, a favicon that carries its own
|
|
114
|
+
plate so it survives both colour schemes, an iOS touch icon, and a 1200×630 social card. The
|
|
115
|
+
design tokens and the reason each variant exists are written down beside them.
|
|
116
|
+
- **Two new pages**, both about problems we can name precisely: [stale LLM context is a
|
|
117
|
+
bug](docs/stale-context-is-your-bug.md) and [how many tokens a codebase
|
|
118
|
+
is](docs/codebase-token-budget.md).
|
|
119
|
+
|
|
120
|
+
### The site stopped being invisible when shared
|
|
121
|
+
|
|
122
|
+
Measured before the fix: twelve pages, every one declaring `twitter:card=summary_large_image`
|
|
123
|
+
with **no `og:image` at all** — so every share on X, LinkedIn, Reddit, Slack or Discord rendered
|
|
124
|
+
as a blank card — and no favicon anywhere.
|
|
125
|
+
|
|
126
|
+
- `og:image`, `og:image:alt`, dimensions, `og:site_name`, `twitter:image`, an author, a theme
|
|
127
|
+
colour and a favicon set on every page.
|
|
128
|
+
- Titles rewritten query-first instead of `<heading> — codebase-snapshot`, which spent the part
|
|
129
|
+
of a result a reader actually scans on a brand nobody is searching for yet.
|
|
130
|
+
- Descriptions written by hand at 90–165 characters; they used to be the page's first sentence
|
|
131
|
+
cut mid-word at 158.
|
|
132
|
+
- JSON-LD gains `BreadcrumbList` everywhere, `author` on every node, `sameAs` to npm and the
|
|
133
|
+
author's site, and an `image`.
|
|
134
|
+
- `llms-full.txt`: every page in one file, one fetch for a crawler that wants the corpus.
|
|
135
|
+
- The author's own site is now linked from every page (`rel="author"`), so the project hangs off
|
|
136
|
+
a person rather than a repository.
|
|
137
|
+
|
|
138
|
+
### Two gates, because these defects survive builds
|
|
139
|
+
|
|
140
|
+
`npm run verify` now fails if either is violated:
|
|
141
|
+
|
|
142
|
+
- **`scripts/audit-site.mjs`** — title and description lengths, canonical identity, `og:image`
|
|
143
|
+
present *and* the file it names exists at 1200×630, twitter card, exactly one `<h1>`, alt text
|
|
144
|
+
on every image, parseable JSON-LD with a breadcrumb, favicon, sitemap coverage, and no page
|
|
145
|
+
that renders `undefined`.
|
|
146
|
+
- **`scripts/readme-lint.mjs`** — a hero in the first lines, at least five badges, in-page
|
|
147
|
+
navigation, alt text, and every relative link resolving to a real file.
|
|
148
|
+
|
|
149
|
+
### `snapshot` is the command now, and a first run sets the project up
|
|
150
|
+
|
|
151
|
+
*(Prepared as 0.9.2, which was never published — everything in it ships here.)*
|
|
152
|
+
|
|
153
|
+
Installing globally used to give `codebase-snapshot` plus a `snap` alias — a word that
|
|
154
|
+
collides with Ubuntu's snapd and with an npm package of the same name. `snap` is gone and
|
|
155
|
+
**`snapshot`** replaces it, pointing at the same file. The long name stays the canonical one, and
|
|
156
|
+
the bare word is what a global install puts on `PATH`.
|
|
157
|
+
|
|
158
|
+
The bare command is no longer a synonym for `generate`. In a project with no configuration it now
|
|
159
|
+
recognises the project, says **what it keyed on** — `Detected nextjs` / `Because next.config.ts` —
|
|
160
|
+
and offers the recommended setup in one keystroke: config, `.gitignore`, npm scripts,
|
|
161
|
+
devDependency, install, generate. Or it walks through every setting, with each question starting
|
|
162
|
+
on its answer, so pressing enter through the lot is the recommended setup spelled out. When
|
|
163
|
+
nothing matches, it lists the manifests it looked for and asks which preset is closest.
|
|
164
|
+
|
|
165
|
+
A project that already has a config, or that this tool generated before, skips all of it and just
|
|
166
|
+
generates — nobody is walked through setup twice.
|
|
167
|
+
|
|
168
|
+
**A first run never guesses.** With no terminal and no `--autopilot`, it exits `2` and names the
|
|
169
|
+
three ways forward instead of generating with defaults nobody chose.
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
snapshot # guided first run, then generate
|
|
173
|
+
snapshot --autopilot # same, no questions
|
|
174
|
+
npx codebase-snapshot # same, from a project dependency
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### New: `--autopilot`
|
|
178
|
+
|
|
179
|
+
The whole setup with no prompts, from the default command: detect the preset, write the config and
|
|
180
|
+
`.gitignore`, add the npm scripts and devDependency, install with the project's own package
|
|
181
|
+
manager, then generate. It keeps an existing config, `--no-install` skips the install, and it
|
|
182
|
+
refuses an empty directory (there is nothing to snapshot and nothing to install into).
|
|
183
|
+
|
|
184
|
+
`--autopilot` and `setup` are one implementation with two entry points, so they cannot drift.
|
|
185
|
+
`--autopilot --no-config` is a usage error: one writes a config, the other promises to ignore one.
|
|
186
|
+
|
|
187
|
+
### Detection reports its evidence
|
|
188
|
+
|
|
189
|
+
`detect()` returns the signal that fired instead of a boolean, so every preset can say why it
|
|
190
|
+
matched — a filename, a dependency, a manifest line — and the setup prints it. A detection you
|
|
191
|
+
cannot check is a detection you have to take on faith. The fallback preset is now explicit
|
|
192
|
+
(`fallback: true`) rather than a detector that always returns true, which is what makes "I could
|
|
193
|
+
not tell what this is" a state the tool can be in and report.
|
|
194
|
+
|
|
195
|
+
### Other
|
|
196
|
+
|
|
197
|
+
- `naming the command still means exactly that`: `snapshot generate` runs on the documented
|
|
198
|
+
defaults and writes nothing but the snapshot, as it always has.
|
|
199
|
+
- The wizard's part-size question now starts on the preset's recommended budget instead of a fixed
|
|
200
|
+
120 KB, so a Next.js project no longer silently gets a third of the budget it was detected for.
|
|
201
|
+
- `describe` and the bundled skill state the non-interactive rule, the two bin names, and that
|
|
202
|
+
`--autopilot` is the unattended path.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
## 0.9.1
|
|
206
|
+
|
|
207
|
+
### The documentation now derives its version from `package.json`
|
|
208
|
+
|
|
209
|
+
A documented version is a promise about the release, and every one of them was hand-written — so they
|
|
210
|
+
rotted silently at each bump. The README still described a `0.x` line whose numbers appeared nowhere
|
|
211
|
+
in it, `SECURITY.md` advertised **"4.x supported"** on a project whose latest release was 0.9.0, and
|
|
212
|
+
both `setup` examples printed `4.4.0` and `4.1.1` as the dependency the command adds.
|
|
213
|
+
|
|
214
|
+
Versions now live in exactly one place, and `scripts/sync-docs.mjs` writes them into the documentation:
|
|
215
|
+
|
|
216
|
+
- Prose carries marked spans — `<!--@majorMinor-->0.9<!--/@majorMinor-->` — which GitHub renders as
|
|
217
|
+
the value and hides as a comment.
|
|
218
|
+
- Code-block examples are matched by shape instead, because inside a fence an HTML comment is literal
|
|
219
|
+
text and the marker syntax would leak into the page.
|
|
220
|
+
- `npm run verify` fails when anything is out of step, and `npm run site` and `prepack` both sync
|
|
221
|
+
first, so the docs site and the published README cannot contradict the package they describe.
|
|
222
|
+
|
|
223
|
+
Changelog history is deliberately excluded. It records what happened at each version, and rewriting a
|
|
224
|
+
past entry would falsify that record rather than maintain it.
|
|
225
|
+
|
|
226
|
+
### Other corrections in this pass
|
|
227
|
+
|
|
228
|
+
- `SECURITY.md` supported versions: 0.9.x, with a sentence explaining why 0.9.0 is newer than 4.4.1.
|
|
229
|
+
- The README states the pre-1.0 contract once, in wording that does not go stale.
|
|
230
|
+
- The changelog opens with a note on the version numbering, so the registry's three versions are not
|
|
231
|
+
a mystery to anyone reading them.
|
|
232
|
+
- The `v4.5.0` release and git tag were deleted; that version no longer exists on npm.
|
|
233
|
+
|
|
234
|
+
---
|
|
7
235
|
## 0.9.0
|
|
8
236
|
|
|
9
237
|
### The package is now `codebase-snapshot`, unscoped
|
|
@@ -41,7 +269,7 @@ name on the next run, so an existing snapshot keeps working and is upgraded in p
|
|
|
41
269
|
|
|
42
270
|
### Documentation site
|
|
43
271
|
|
|
44
|
-
The docs now have a crawlable home at <https://codebase-snapshot
|
|
272
|
+
The docs now have a crawlable home at <https://ankurhalder.github.io/codebase-snapshot/>, generated from
|
|
45
273
|
`README.md` and `docs/` in this repository, with a sitemap, its own `robots.txt`, an `llms.txt` at
|
|
46
274
|
the site root and a Markdown twin per page. GitHub's `robots.txt` blocks directory-tree and raw-file
|
|
47
275
|
paths and publishes no repository sitemap, so `docs/` had no crawlable entry point before this.
|
package/README.md
CHANGED
|
@@ -1,99 +1,114 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/ankurhalder/codebase-snapshot/main/docs/assets/favicon.svg" width="64" height="64" alt="codebase-snapshot">
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
parts, indexed by a JSON manifest, with a secret audit — in one command.**
|
|
4
|
+
<h1>codebase-snapshot</h1>
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
<p><b>A snapshot you can prove is current.</b><br>
|
|
7
|
+
Plain-text parts under a hard byte budget, an index of every file and every skipped<br>
|
|
8
|
+
file with the reason, and a <code>validate</code> command that fails when the code moves.</p>
|
|
9
|
+
|
|
10
|
+
<p>
|
|
11
|
+
<a href="https://www.npmjs.com/package/codebase-snapshot"><img alt="npm version" src="https://img.shields.io/npm/v/codebase-snapshot.svg"></a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/codebase-snapshot"><img alt="weekly downloads" src="https://img.shields.io/npm/dw/codebase-snapshot.svg"></a>
|
|
13
|
+
<a href="#license"><img alt="license: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
|
|
14
|
+
<a href="https://nodejs.org"><img alt="node: 18 or newer" src="https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg"></a>
|
|
15
|
+
<a href="https://ankurhalder.github.io/codebase-snapshot/"><img alt="documentation" src="https://img.shields.io/badge/docs-read-1a7f37"></a>
|
|
16
|
+
</p>
|
|
17
|
+
</div>
|
|
10
18
|
|
|
11
19
|
```bash
|
|
12
|
-
|
|
20
|
+
snapshot # detects the project, sets it up, generates
|
|
21
|
+
npx codebase-snapshot generate # or no install at all, straight to the snapshot
|
|
13
22
|
```
|
|
14
23
|
|
|
15
|
-
That writes `./snapshot/` — a directory you can drop into a chat, a prompt, a RAG pipeline or
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
That writes `./snapshot/` — a directory you can drop into a chat, a prompt, a RAG pipeline or a
|
|
25
|
+
repository review. TypeScript and JavaScript first, but also Python, Go, Rust, Java/Kotlin,
|
|
26
|
+
C#/.NET, PHP, Ruby, C/C++, Vue, Svelte and Astro, without configuration.
|
|
27
|
+
|
|
28
|
+

|
|
18
30
|
|
|
19
|
-
|
|
31
|
+
<p align="center">
|
|
32
|
+
<a href="#install">Install</a> ·
|
|
33
|
+
<a href="#quick-start">Quick start</a> ·
|
|
34
|
+
<a href="#built-to-be-trusted">Trust</a> ·
|
|
35
|
+
<a href="#for-ai-agents">AI agents</a> ·
|
|
36
|
+
<a href="#documentation">Docs</a> ·
|
|
37
|
+
<a href="https://ankurhalder.github.io/codebase-snapshot/">Site</a>
|
|
38
|
+
</p>
|
|
20
39
|
|
|
21
40
|
---
|
|
22
41
|
|
|
23
42
|
## Why
|
|
24
43
|
|
|
25
|
-
Feeding a real repository to a model is awkward: files are too big, context windows are too
|
|
26
|
-
|
|
27
|
-
deterministically:
|
|
44
|
+
Feeding a real repository to a model is awkward: files are too big, context windows are too small,
|
|
45
|
+
and choosing what matters by hand neither scales nor repeats. This does it deterministically.
|
|
28
46
|
|
|
29
|
-
- **
|
|
30
|
-
|
|
31
|
-
|
|
47
|
+
- **A hard ceiling, not a target.** `maxPartBytes` is a limit. A file bigger than the budget is cut
|
|
48
|
+
with an explicit omission marker naming the budget, and above `largeFileBytes` it becomes a
|
|
49
|
+
head/tail excerpt instead — nothing silently overflows the window you sized.
|
|
32
50
|
- **An index, not just text.** `manifest.json` lists every included file with its layer, kind,
|
|
33
|
-
language, part, hash and a structural summary
|
|
34
|
-
- **Provably current.** `validate` re-hashes the repository against the snapshot and exits
|
|
35
|
-
|
|
36
|
-
- **
|
|
37
|
-
`
|
|
38
|
-
`manifest.fingerprint`. Only `manifest.json`, the snapshot's `README.md`,
|
|
39
|
-
`reports/audit.md` and `.codebase-snapshot` change between runs, because they carry
|
|
40
|
-
timestamps, a run id and a pid.
|
|
41
|
-
- **Safe by default.** Credential files are skipped unless asked for, secret-shaped strings are
|
|
42
|
-
redacted, and a mistyped output directory cannot delete source code.
|
|
43
|
-
- **Usable by agents, not just humans.** A machine-readable contract and an installable skill
|
|
44
|
-
let an agent with no prior knowledge drive the whole thing.
|
|
51
|
+
language, part, hash and a structural summary, and every *excluded* file with the reason.
|
|
52
|
+
- **Provably current.** `validate` re-hashes the repository against the snapshot and exits non-zero
|
|
53
|
+
on any drift, so a pipeline can gate on the context being fresh.
|
|
54
|
+
- **Repeatable.** Two runs over unchanged input give byte-identical parts and the same
|
|
55
|
+
`manifest.fingerprint`; only the artifacts that carry a timestamp, run id or pid differ.
|
|
45
56
|
|
|
46
57
|
## Install
|
|
47
58
|
|
|
48
59
|
```bash
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
npm install -g codebase-snapshot # puts `snapshot` on your PATH
|
|
61
|
+
npx codebase-snapshot generate # or no install at all, one-off
|
|
62
|
+
npm install -D codebase-snapshot # or add it to a project
|
|
51
63
|
```
|
|
52
64
|
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
`codebase-snapshot` is the canonical name to script against; `snapshot` is the short command a
|
|
66
|
+
global install provides, and from a project dependency the same binary is `npx snapshot` or the
|
|
67
|
+
`npm run snapshot` script `init` writes.
|
|
55
68
|
|
|
56
|
-
|
|
69
|
+
Requires **Node.js 18+**. Any npm client works — npm, yarn (classic and Berry with strict PnP), pnpm
|
|
70
|
+
and bun. Published from GitHub Actions with [build
|
|
71
|
+
provenance](https://docs.npmjs.com/generating-provenance-statements), so `npm audit signatures`
|
|
72
|
+
verifies the tarball came from this repository at a tagged commit.
|
|
73
|
+
|
|
74
|
+
This is a **<!--@major-->0<!--/@major-->.x** release: the CLI surface may still change in a minor
|
|
75
|
+
release until 1.0.0, so pin an exact version if you need a fixed surface today.
|
|
57
76
|
|
|
58
77
|
→ [Installation guide](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/install.md)
|
|
59
78
|
|
|
60
79
|
## Quick start
|
|
61
80
|
|
|
62
|
-
|
|
63
|
-
npm scripts and the devDependency, installs it, and generates the snapshot:
|
|
81
|
+
Type it. That is the whole first run.
|
|
64
82
|
|
|
65
83
|
```bash
|
|
66
|
-
|
|
84
|
+
snapshot
|
|
67
85
|
```
|
|
68
86
|
|
|
87
|
+
It recognises the project and says what it keyed on — `Detected nextjs` / `Because next.config.ts`
|
|
88
|
+
— then offers the recommended setup in one keystroke, or a walk through every setting with each
|
|
89
|
+
question starting on its default. Either way it writes the config, adds the npm scripts and the
|
|
90
|
+
devDependency, installs with your package manager, and generates. A project that already has a
|
|
91
|
+
config just generates.
|
|
92
|
+
|
|
93
|
+
Nothing to press — CI, a container, an agent:
|
|
94
|
+
|
|
69
95
|
```bash
|
|
70
|
-
|
|
71
|
-
npx codebase-snapshot init --yes # config + scripts + devDependency + .gitignore
|
|
72
|
-
npm install # the package, into node_modules
|
|
73
|
-
npm run snapshot # generate
|
|
74
|
-
npm run snapshot:validate # exit 0 = current with disk
|
|
96
|
+
npx codebase-snapshot --autopilot
|
|
75
97
|
```
|
|
76
98
|
|
|
77
|
-
|
|
78
|
-
|
|
99
|
+
**A first run never guesses.** With no terminal and no `--autopilot` it exits `2` and names the
|
|
100
|
+
three ways forward, because a snapshot built from settings nobody chose is a snapshot nobody can
|
|
101
|
+
check.
|
|
79
102
|
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
- Tracked files: 128
|
|
86
|
-
- Total lines: 9,431
|
|
87
|
-
- Total size: 0.41 MB
|
|
88
|
-
- Parts written: 3 under snapshot/parts/
|
|
89
|
-
- Reports: snapshot/reports/ (project-tree, navigation, audit)
|
|
90
|
-
- Manifest: snapshot/manifest.json
|
|
91
|
-
- Fingerprint: e4607b570268c8def0911babbace97e4a0196d9eaf2cac22c8847500883d70aa
|
|
92
|
-
- Integrity: passed
|
|
103
|
+
```bash
|
|
104
|
+
npx codebase-snapshot init --yes # config + scripts + devDependency + .gitignore
|
|
105
|
+
npm install # the package, into node_modules
|
|
106
|
+
npm run snapshot # generate
|
|
107
|
+
npm run snapshot:validate # exit 0 = current with disk
|
|
93
108
|
```
|
|
94
109
|
|
|
95
|
-
The fingerprint is printed in full — all 64 hex characters, never elided — and it is the same
|
|
96
|
-
|
|
110
|
+
The fingerprint is printed in full — all 64 hex characters, never elided — and it is the same value
|
|
111
|
+
as `manifest.fingerprint`.
|
|
97
112
|
|
|
98
113
|
## What you get
|
|
99
114
|
|
|
@@ -114,34 +129,29 @@ Every artifact can be turned off (`--skip-artifacts`, `--only-artifacts`, or the
|
|
|
114
129
|
|
|
115
130
|
## Built to be trusted with a whole repository
|
|
116
131
|
|
|
117
|
-
A snapshot is only useful if you can believe it, so the tool is explicit about
|
|
118
|
-
|
|
132
|
+
A snapshot is only useful if you can believe it, so the tool is explicit about what it does *not*
|
|
133
|
+
contain.
|
|
119
134
|
|
|
120
135
|
- **Nothing is dropped silently.** Every excluded path is recorded in `manifest.skipped[]` with a
|
|
121
|
-
reason — `binary`, `gitignore`, `
|
|
122
|
-
|
|
123
|
-
answers the same question for any single path.
|
|
124
|
-
- **Encoding is stated, not guessed.** UTF-16 files are transcoded instead of vanishing as
|
|
125
|
-
"binary"; a file that is not valid UTF-8 is kept but labelled `utf-8-lossy` with the count of
|
|
126
|
-
undecodable bytes, so you never mistake mojibake for source.
|
|
136
|
+
reason — `binary`, `gitignore`, `sensitive-file`, `symlink`, `read-error`, `excluded` and the
|
|
137
|
+
rest — and `explain <path>` answers the same question for any single file.
|
|
127
138
|
- **Counts describe what was emitted.** `includedBytes` and `includedLines` are measured from the
|
|
128
|
-
block in the part, not from the file on disk.
|
|
139
|
+
block in the part, not from the file on disk. A file that is not valid UTF-8 is kept and labelled
|
|
140
|
+
`utf-8-lossy` rather than vanishing as "binary".
|
|
129
141
|
- **Drift is checked, not assumed.** `validate` compares every file's hash *and* a digest of the
|
|
130
|
-
settings the snapshot was generated with, so a changed budget
|
|
131
|
-
|
|
132
|
-
- **
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
the run refuses rather than quietly scanning something different, and `--discovery walk` is the
|
|
139
|
-
documented escape hatch.
|
|
142
|
+
settings the snapshot was generated with, so a changed budget or secret pattern is drift rather
|
|
143
|
+
than silence.
|
|
144
|
+
- **The output directory is the tool's.** Each run is written to a scratch directory and swapped in
|
|
145
|
+
atomically, and it refuses to replace a directory it did not create — `--out-dir src` cannot
|
|
146
|
+
destroy source code.
|
|
147
|
+
- **Credential files are excluded by default** — `.env`, `*.pem`, `.npmrc`, `id_rsa`, `*.tfstate`
|
|
148
|
+
and more — and secret-shaped strings inside ordinary files are redacted by masking only the
|
|
149
|
+
matched span, never the whole line.
|
|
140
150
|
|
|
141
151
|
## Supported projects
|
|
142
152
|
|
|
143
|
-
25 presets, detected
|
|
144
|
-
|
|
153
|
+
25 presets, detected from the repository — each contributing layers, kinds, ecosystem ignore
|
|
154
|
+
patterns and a recommended part budget.
|
|
145
155
|
|
|
146
156
|
| | | | |
|
|
147
157
|
| :--- | :--- | :--- | :--- |
|
|
@@ -153,11 +163,9 @@ ecosystem ignore patterns and a recommended part budget.
|
|
|
153
163
|
| Laravel (PHP) | Rails (Ruby) | Terraform / Docker infra | Docs-only |
|
|
154
164
|
| generic fallback | | | |
|
|
155
165
|
|
|
156
|
-
Non-TypeScript languages get import/export/class/function summaries rather than being treated
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
Python, for example, is a line-scan `heuristic`, while JSON and Markdown get `structural`
|
|
160
|
-
shapes.
|
|
166
|
+
Non-TypeScript languages get import/export/class/function summaries rather than being treated as
|
|
167
|
+
opaque text, and every summary is labelled `ast`, `structural` or `heuristic` so you know how much
|
|
168
|
+
to trust it.
|
|
161
169
|
|
|
162
170
|
→ [Preset table and detection rules](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/configuration.md#project-presets)
|
|
163
171
|
|
|
@@ -165,7 +173,9 @@ shapes.
|
|
|
165
173
|
|
|
166
174
|
| Command | Does |
|
|
167
175
|
| :--- | :--- |
|
|
168
|
-
|
|
|
176
|
+
| *(none)* | The guided first run. Asks once when the project has no config; generates otherwise. |
|
|
177
|
+
| `generate` *(default)* | Write the snapshot. `--autopilot` sets the project up first, unasked. |
|
|
178
|
+
| `setup` | Config, npm scripts, devDependency, install and generate, in one command. |
|
|
169
179
|
| `validate` / `check` | Compare the snapshot with the repository; exit `1` on drift. |
|
|
170
180
|
| `report` | Snapshot health, layer metrics, secret audit. |
|
|
171
181
|
| `init` | Interactive (or `--yes`) setup that writes a self-documenting config. |
|
|
@@ -173,35 +183,39 @@ shapes.
|
|
|
173
183
|
| `diff <a> <b>` | Compare two snapshots. |
|
|
174
184
|
| `describe` | The machine-readable contract (`--format json`). |
|
|
175
185
|
| `skill` | Print or install the agent skill. |
|
|
186
|
+
| `mcp` | Serve the repository to an MCP client over stdio. |
|
|
176
187
|
|
|
177
|
-
Exit codes: `0` success · `1` drift
|
|
188
|
+
Exit codes: `0` success · `1` drift, refused generation, or nothing to snapshot · `2` usage error,
|
|
189
|
+
or a first run with no terminal and no `--autopilot`.
|
|
178
190
|
|
|
179
191
|
→ [Full CLI reference](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/cli.md)
|
|
180
192
|
|
|
181
193
|
## For AI agents
|
|
182
194
|
|
|
183
|
-
Everything an agent needs is available as data, and the tool can install its own skill
|
|
195
|
+
Everything an agent needs is available as data, and the tool can install its own skill.
|
|
184
196
|
|
|
185
197
|
```bash
|
|
186
|
-
#
|
|
187
|
-
npx codebase-snapshot
|
|
188
|
-
|
|
189
|
-
# Install the skill into the registries agent tools read: .claude/skills/, .cursor/rules/
|
|
190
|
-
# (it adds those files to .gitignore, and never touches your own AGENTS.md)
|
|
191
|
-
npx codebase-snapshot skill --install
|
|
198
|
+
npx codebase-snapshot describe --format json # contract: workflow, options, exit codes
|
|
199
|
+
npx codebase-snapshot skill --install # into .claude/skills + .cursor/rules
|
|
200
|
+
npx -y codebase-snapshot@0.9.4 mcp # or serve it over MCP
|
|
192
201
|
```
|
|
193
202
|
|
|
194
|
-
An agent told only "use `npx codebase-snapshot`" can read the contract, follow its
|
|
195
|
-
|
|
203
|
+
An agent told only "use `npx codebase-snapshot`" can read the contract, follow its ordered
|
|
204
|
+
workflow, and produce a validated snapshot unaided — that path is covered by a test.
|
|
196
205
|
|
|
197
|
-
|
|
206
|
+
The MCP server exposes seven tools — status, plan, generate, validate, locate, read, explain — plus
|
|
207
|
+
`snapshot://` resources and two prompts. Its reads come from the snapshot rather than the working
|
|
208
|
+
tree, so an excluded file stays excluded and a redacted value stays redacted, and
|
|
209
|
+
`snapshot_validate` answers the question an agent otherwise cannot ask: is the context I was given
|
|
210
|
+
still true?
|
|
211
|
+
|
|
212
|
+
→ [Using this with an AI agent](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/agent.md) · [MCP server](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/mcp.md) · [AGENTS.md](https://github.com/ankurhalder/codebase-snapshot/blob/main/AGENTS.md) · [llms.txt](https://github.com/ankurhalder/codebase-snapshot/blob/main/llms.txt)
|
|
198
213
|
|
|
199
214
|
## Configuration
|
|
200
215
|
|
|
201
|
-
`snapshot.config.ts` (or `.mjs`) is written by `init` with **every** setting at its current
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
`import/no-anonymous-default-export`, on by default in `eslint-config-next`.
|
|
216
|
+
`snapshot.config.ts` (or `.mjs`) is written by `init` with **every** setting at its current value,
|
|
217
|
+
commented and grouped, so it doubles as the reference. Deleting any line is safe: the defaults are
|
|
218
|
+
real.
|
|
205
219
|
|
|
206
220
|
```js
|
|
207
221
|
const config = {
|
|
@@ -230,8 +244,9 @@ const manifest = generateSnapshot(config);
|
|
|
230
244
|
const validation = validateSnapshot(config);
|
|
231
245
|
```
|
|
232
246
|
|
|
233
|
-
CommonJS works too (`require("codebase-snapshot")`), with type definitions for
|
|
234
|
-
|
|
247
|
+
CommonJS works too (`require("codebase-snapshot")`), with type definitions for both. The CLI, the
|
|
248
|
+
API and the MCP server share one implementation, so anything one of them does is available in the
|
|
249
|
+
others.
|
|
235
250
|
|
|
236
251
|
## Documentation
|
|
237
252
|
|
|
@@ -242,36 +257,35 @@ both. The CLI and the API share one implementation, so anything the CLI does is
|
|
|
242
257
|
| [Configuration](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/configuration.md) | Every setting, all 25 presets, budgets, hooks, secrets |
|
|
243
258
|
| [Snapshot output](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/output.md) | Directory layout and the full manifest schema |
|
|
244
259
|
| [AI agents](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/agent.md) | The contract, the skill, what an agent should avoid |
|
|
260
|
+
| [MCP server](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/mcp.md) | Seven tools, resources, both protocol eras |
|
|
245
261
|
| [Troubleshooting](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/troubleshooting.md) | Every message and what to do about it |
|
|
246
262
|
| [Changelog](https://github.com/ankurhalder/codebase-snapshot/blob/main/CHANGELOG.md) | Release history and breaking changes |
|
|
247
263
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
- **Credential files are excluded by default** — `.env`, `*.pem`, `*.key`, `.npmrc`, `.netrc`,
|
|
261
|
-
`.git-credentials`, `id_rsa`, `.kube/config`, `*.tfstate` — and listed in
|
|
262
|
-
`manifest.skipped[]` with the reason.
|
|
263
|
-
- **Secrets are redacted** inside ordinary files: only the matched span is masked, never the
|
|
264
|
-
whole line, and no excerpt reaches any artifact.
|
|
265
|
-
- **The output directory is owned by the tool.** Each run is written to a scratch directory and
|
|
266
|
-
swapped in atomically; the previous snapshot survives a failure.
|
|
267
|
-
- **It refuses to replace a directory it did not create**, so `--out-dir src` cannot destroy
|
|
268
|
-
source code.
|
|
264
|
+
Guides: [feeding a codebase to ChatGPT, Claude or
|
|
265
|
+
Cursor](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/how-to-feed-a-repo-to-claude.md)
|
|
266
|
+
· [stale LLM context is a
|
|
267
|
+
bug](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/stale-context-is-your-bug.md) ·
|
|
268
|
+
[how many tokens a codebase
|
|
269
|
+
is](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/codebase-token-budget.md) ·
|
|
270
|
+
[budgeting a context
|
|
271
|
+
window](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/how-to-context-budget.md) ·
|
|
272
|
+
[vs repomix](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/vs-repomix.md) · [vs
|
|
273
|
+
gitingest](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/vs-gitingest.md) · [vs
|
|
274
|
+
code2prompt](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/vs-code2prompt.md)
|
|
269
275
|
|
|
270
276
|
## Contributing
|
|
271
277
|
|
|
272
|
-
Issues and pull requests are welcome — see
|
|
273
|
-
[
|
|
278
|
+
Issues and pull requests are welcome — see
|
|
279
|
+
[CONTRIBUTING.md](https://github.com/ankurhalder/codebase-snapshot/blob/main/CONTRIBUTING.md) and the
|
|
280
|
+
[code of conduct](https://github.com/ankurhalder/codebase-snapshot/blob/main/CODE_OF_CONDUCT.md).
|
|
281
|
+
Security reports: [SECURITY.md](https://github.com/ankurhalder/codebase-snapshot/blob/main/SECURITY.md).
|
|
274
282
|
|
|
275
283
|
## License
|
|
276
284
|
|
|
277
285
|
[MIT](https://github.com/ankurhalder/codebase-snapshot/blob/main/LICENSE) © Ankur Halder
|
|
286
|
+
|
|
287
|
+
<p align="center">
|
|
288
|
+
<sub>Built by <a href="https://ankurhalder.com" rel="author">Ankur Halder</a> ·
|
|
289
|
+
<a href="https://ankurhalder.github.io/codebase-snapshot/">documentation</a> ·
|
|
290
|
+
<a href="https://www.npmjs.com/package/codebase-snapshot">npm</a></sub>
|
|
291
|
+
</p>
|
package/SECURITY.md
CHANGED
|
@@ -6,8 +6,12 @@ Only the latest published release receives security fixes.
|
|
|
6
6
|
|
|
7
7
|
| Version | Supported |
|
|
8
8
|
| :--- | :--- |
|
|
9
|
-
|
|
|
10
|
-
|
|
|
9
|
+
| <!--@majorMinor-->0.9<!--/@majorMinor-->.x | ✅ |
|
|
10
|
+
| anything older | ❌ |
|
|
11
|
+
|
|
12
|
+
The number line restarted at 0.9.0 when the package moved to the unscoped `codebase-snapshot` name,
|
|
13
|
+
so <!--@majorMinor-->0.9<!--/@majorMinor-->.x is newer than 4.4.1, not older. That is explained in full in the
|
|
14
|
+
[changelog](CHANGELOG.md#a-note-on-version-numbers).
|
|
11
15
|
|
|
12
16
|
## Reporting a vulnerability
|
|
13
17
|
|