@ankurhalder/codebase-snapshot 0.0.0-stage → 2.1.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/LICENSE +21 -0
- package/README.md +331 -2
- package/dist/bin.js +5688 -0
- package/dist/chunk-QEIOXPMU.js +5093 -0
- package/dist/cli.cjs +5674 -0
- package/dist/cli.d.cts +48 -0
- package/dist/cli.d.ts +48 -0
- package/dist/cli.js +568 -0
- package/dist/index.cjs +5182 -0
- package/dist/index.d.cts +541 -0
- package/dist/index.d.ts +541 -0
- package/dist/index.js +3 -0
- package/dist/types-CJqkePM4.d.cts +391 -0
- package/dist/types-CJqkePM4.d.ts +391 -0
- package/docs/configuration.md +340 -0
- package/docs/install.md +136 -0
- package/package.json +94 -4
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# Configuration reference
|
|
2
|
+
|
|
3
|
+
Everything `@ankurhalder/codebase-snapshot` can be told to do, in one place.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @ankurhalder/codebase-snapshot init # writes a starter config
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Config files are resolved in this order, first match wins:
|
|
10
|
+
|
|
11
|
+
`snapshot.config.ts` → `.js` → `.mjs` → `.cjs` → `.json` → `.snapshotrc.json` → `.snapshotrc` → `"snapshot"` in `package.json`.
|
|
12
|
+
|
|
13
|
+
> A `.ts` config is only importable natively from Node **22.6+**. `init` writes `.mjs` on older Node, and an unloadable config is reported on stderr rather than ignored.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Scoping: which files get in
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
export default {
|
|
21
|
+
include: ["src/**", "packages/*/src/**"], // allow-list, empty = everything
|
|
22
|
+
excludePatterns: ["**/*.test.ts", "docs"], // narrows what include let through
|
|
23
|
+
};
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`include` runs first, `excludePatterns` narrows the survivors. Both accept globs
|
|
27
|
+
(`**`, `*`, `?`, `{a,b}`, `[abc]`) or plain strings; a plain string matches a
|
|
28
|
+
whole path segment sequence, so `"docs"` matches `docs/a.md` and `src/docs/b.md`
|
|
29
|
+
but not `docsite/c.md`.
|
|
30
|
+
|
|
31
|
+
Every dropped file is recorded in `manifest.skipped` with `reason` and the exact
|
|
32
|
+
pattern responsible (`excluded`, `default-ignore`, `sensitive-file`, `binary`,
|
|
33
|
+
`symlink`, `read-error`, `not-file`).
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
export default {
|
|
37
|
+
includeSensitiveFiles: false, // .env, *.pem, .npmrc, .ssh/, .tfstate …
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Project presets
|
|
42
|
+
|
|
43
|
+
A preset is a detected project shape: layers, kinds, ecosystem ignores and a
|
|
44
|
+
recommended part budget. Detection reads the repository **once** and the first
|
|
45
|
+
matching preset wins, ordered by specificity — so a Next.js app inside a pnpm
|
|
46
|
+
workspace is still a Next.js project.
|
|
47
|
+
|
|
48
|
+
| Preset | Detected from |
|
|
49
|
+
| :--- | :--- |
|
|
50
|
+
| `nextjs` | `next.config.*`, or `next` |
|
|
51
|
+
| `nuxt` | `nuxt.config.*`, or `nuxt` |
|
|
52
|
+
| `sveltekit` | `svelte.config.*`, `@sveltejs/kit` |
|
|
53
|
+
| `remix` | `@remix-run/*` |
|
|
54
|
+
| `astro` | `astro.config.*`, `astro` |
|
|
55
|
+
| `angular` | `angular.json`, `@angular/core` |
|
|
56
|
+
| `solid` | `solid-js` |
|
|
57
|
+
| `vue-vite` | `vue` + vite |
|
|
58
|
+
| `react-vite` | `react` + vite |
|
|
59
|
+
| `nest` | `@nestjs/core` |
|
|
60
|
+
| `node-express` | `express`, `fastify`, `koa` |
|
|
61
|
+
| `node-lib` | any `package.json` |
|
|
62
|
+
| `python-django` | `manage.py`, or django in the manifest |
|
|
63
|
+
| `python-fastapi` | fastapi / flask in the manifest |
|
|
64
|
+
| `python-lib` | `pyproject.toml`, `setup.py`, `.py` files |
|
|
65
|
+
| `go` | `go.mod` |
|
|
66
|
+
| `rust` | `Cargo.toml` |
|
|
67
|
+
| `java-spring` | `pom.xml`, `build.gradle` |
|
|
68
|
+
| `dotnet` | `*.csproj`, `*.sln` |
|
|
69
|
+
| `php-laravel` | `artisan`, `composer.json` |
|
|
70
|
+
| `ruby-rails` | `Gemfile`, `config.ru` |
|
|
71
|
+
| `monorepo` | `pnpm-workspace.yaml`, `workspaces`, `nx.json`, `turbo.json` |
|
|
72
|
+
| `infra` | `*.tf`, `Chart.yaml`, `docker-compose.yml` |
|
|
73
|
+
| `docs` | mostly Markdown, no `package.json` |
|
|
74
|
+
| `generic` | anything else |
|
|
75
|
+
|
|
76
|
+
Force one when detection is wrong:
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
export default {
|
|
80
|
+
preset: "react-vite",
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
An unknown name is an error listing every valid preset — never a silent fallback.
|
|
85
|
+
Each preset also contributes ignore patterns the generic list cannot know
|
|
86
|
+
(`__pycache__`, `target`, `vendor`, `bin`/`obj`, …). The resolved preset is
|
|
87
|
+
recorded in `manifest.config.preset`, so changing it shows up as config drift.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Interactive setup
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm create codebase-snapshot # or: npx @ankurhalder/codebase-snapshot init
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Detects the project, asks seven questions with real defaults, and writes the
|
|
98
|
+
config. It never prompts when either end is not a TTY: every answer has a flag.
|
|
99
|
+
|
|
100
|
+
| Flag | Question it answers |
|
|
101
|
+
| :--- | :--- |
|
|
102
|
+
| `--preset <name>` | project type |
|
|
103
|
+
| `--include <globs>` / `--exclude <globs>` | scope |
|
|
104
|
+
| `--max-part-bytes <size>` | part size |
|
|
105
|
+
| `--skip-artifacts` / `--only-artifacts` | artifacts |
|
|
106
|
+
| `--include-sensitive-files` | safety |
|
|
107
|
+
| `--minimal` | write only what differs from the defaults |
|
|
108
|
+
| `--yes` | accept everything, do not prompt |
|
|
109
|
+
| `--force` | overwrite an existing config |
|
|
110
|
+
| `--dry-run` | print the config, write nothing |
|
|
111
|
+
|
|
112
|
+
The generated config lists **every setting at its current value**, commented and
|
|
113
|
+
grouped. That is deliberate: most people never open the documentation, and a
|
|
114
|
+
config that only records their changes cannot tell them what else exists.
|
|
115
|
+
Deleting any line is safe — the defaults are real.
|
|
116
|
+
## Classification: layers and kinds
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
export default {
|
|
120
|
+
layersMode: "merge", // default: your rules first, then the preset's
|
|
121
|
+
layers: [
|
|
122
|
+
{ name: "billing", match: "src/features/billing/**" },
|
|
123
|
+
{ name: "legacy", match: (p) => p.includes(".legacy.") },
|
|
124
|
+
],
|
|
125
|
+
kinds: [
|
|
126
|
+
{ kind: "route", match: /(^|\/)route\.tsx?$/ },
|
|
127
|
+
{ kind: "hook", match: "src/hooks/**" },
|
|
128
|
+
],
|
|
129
|
+
};
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Rules are evaluated in order, **first match wins**, with an `other` fallback.
|
|
133
|
+
`match` may be a string, a `RegExp`, or a predicate function.
|
|
134
|
+
|
|
135
|
+
`layersMode: "merge"` (the default) keeps the detected preset's rules and lets
|
|
136
|
+
yours win by being evaluated first. `"replace"` discards the preset entirely.
|
|
137
|
+
|
|
138
|
+
Presets are auto-detected by specificity: the first match in descending priority wins,
|
|
139
|
+
and `generic` is the fallback. There are 25 of them — see the table above. A framework
|
|
140
|
+
that depends on `vite` still resolves to `react-vite` / `vue-vite` because those detectors
|
|
141
|
+
outrank `node-lib`, and a Next.js app inside a pnpm workspace is still `nextjs`, not
|
|
142
|
+
`monorepo`.
|
|
143
|
+
|
|
144
|
+
## Sizing: byte budgets
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
export default {
|
|
148
|
+
maxPartBytes: "120k", // hard ceiling per part; default 300 KB, min 4096 B
|
|
149
|
+
largeFileBytes: "200k", // above this a file gets a head/tail preview
|
|
150
|
+
previewHeadLines: 80,
|
|
151
|
+
previewTailLines: 40,
|
|
152
|
+
|
|
153
|
+
budgets: { // optional per-layer overrides
|
|
154
|
+
default: "120k",
|
|
155
|
+
byLayer: { docs: 40_000, core: 300_000 },
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Budgets accept raw bytes (`122880`) or human sizes (`"120k"`, `"1.5mb"`, `"2 GB"`).
|
|
161
|
+
Anything unparseable is an error rather than a silent fallback to the default.
|
|
162
|
+
|
|
163
|
+
Files under different budgets are partitioned separately and the resulting parts
|
|
164
|
+
are re-numbered, so filenames and `Previous:`/`Next:` links stay correct.
|
|
165
|
+
|
|
166
|
+
## Artifacts: what gets written
|
|
167
|
+
|
|
168
|
+
Everything is on by default. Each artifact can be switched off independently —
|
|
169
|
+
`artifacts` in config, or `--skip-artifacts` / `--only-artifacts` on the CLI.
|
|
170
|
+
|
|
171
|
+
| Artifact | Default | File |
|
|
172
|
+
| :--- | :--- | :--- |
|
|
173
|
+
| `readme` | on | `README.md` |
|
|
174
|
+
| `manifest` | on | `manifest.json` — **off breaks `validate` and `report`** |
|
|
175
|
+
| `parts` | on | `parts/part-XXX.md` |
|
|
176
|
+
| `navigation` | on | `reports/navigation.md` — dangles if `parts` is off |
|
|
177
|
+
| `projectTree` | on | `reports/project-tree.md` |
|
|
178
|
+
| `audit` | on | `reports/audit.md` |
|
|
179
|
+
| `monolith` | off | `full-codebase.{json,md}` |
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
export default {
|
|
183
|
+
artifacts: { parts: false, navigation: false }, // reports-only pass
|
|
184
|
+
includeMonolith: false,
|
|
185
|
+
maxMonolithBytes: null,
|
|
186
|
+
};
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Unknown artifact names are rejected, not ignored. The selection is recorded in
|
|
190
|
+
`manifest.config.artifacts`, so changing it later shows up as config drift.
|
|
191
|
+
|
|
192
|
+
The monolith is built from the **pre-partition** contents, so it holds the whole
|
|
193
|
+
file even when a part had to truncate it.
|
|
194
|
+
|
|
195
|
+
## Secrets: redaction rules
|
|
196
|
+
|
|
197
|
+
21 built-in rules cover PEM keys, JWT, AWS, GitHub, Slack, Stripe, Google,
|
|
198
|
+
OpenAI/Anthropic, npm, PyPI, SendGrid, Twilio, DigitalOcean, Azure, database
|
|
199
|
+
URIs, basic-auth URLs and `.env`-style assignments.
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
export default {
|
|
203
|
+
secrets: {
|
|
204
|
+
customPatterns: [
|
|
205
|
+
{ rule: "internal-token", pattern: /CORP-[A-Z0-9]{32}/ },
|
|
206
|
+
{ rule: "from-json", pattern: "ACME_[a-z0-9]{10}" }, // strings allowed
|
|
207
|
+
],
|
|
208
|
+
disableDefaultPatterns: false,
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Only the matched span is replaced; the rest of the line survives. Multi-line PEM
|
|
214
|
+
blocks are masked as a block, including ones cut off before their `END` marker.
|
|
215
|
+
No excerpt of a matched line is ever written to any artifact.
|
|
216
|
+
|
|
217
|
+
## Output layout
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
export default {
|
|
221
|
+
outDir: "snapshot",
|
|
222
|
+
tmpDir: "snapshot.tmp",
|
|
223
|
+
branch: "main", // fallback when git cannot report one
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`outDir` may not be the working directory, an ancestor, or the filesystem root,
|
|
228
|
+
and `outDir`/`tmpDir` may not contain each other. Writes are atomic: the previous
|
|
229
|
+
snapshot survives until the new one is fully in place.
|
|
230
|
+
|
|
231
|
+
Both directories are also **refused if they already exist and this generator did
|
|
232
|
+
not write them** — a typo such as `outDir: "src"` would otherwise replace your
|
|
233
|
+
source tree. Ownership is proved by a `.codebase-snapshot` marker (plus a
|
|
234
|
+
parseable `manifest.json` for older output), never by filenames, so an existing
|
|
235
|
+
`docs/README.md` is never mistaken for a previous snapshot. An empty directory,
|
|
236
|
+
or one holding only `.gitkeep`/`.gitignore`/`.DS_Store`, is always accepted.
|
|
237
|
+
|
|
238
|
+
## Hooks
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
export default {
|
|
242
|
+
hooks: {
|
|
243
|
+
afterGenerate: (manifest) => {
|
|
244
|
+
// runs after a successful generate (and after a dry run)
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
A throwing hook becomes a warning on the manifest — it never loses a snapshot
|
|
251
|
+
that was already written.
|
|
252
|
+
|
|
253
|
+
A hook may write its own files into the output directory. That is safe across
|
|
254
|
+
reruns: ownership of the directory is established by a `.codebase-snapshot`
|
|
255
|
+
marker written before any artifact, not by the set of filenames present, so
|
|
256
|
+
custom artifacts never look like someone else's data.
|
|
257
|
+
|
|
258
|
+
Note that a hook runs in the **process** working directory, so with
|
|
259
|
+
`snap --cwd elsewhere` a relative path resolves against your shell's directory,
|
|
260
|
+
not the target repo. Use the absolute paths on `manifest` (or resolve against
|
|
261
|
+
`outDir` yourself) when passing `--cwd`.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
# Commands
|
|
266
|
+
|
|
267
|
+
| Command | Purpose |
|
|
268
|
+
| :--- | :--- |
|
|
269
|
+
| `generate` *(default)* | Write the snapshot |
|
|
270
|
+
| `validate`, `check` | Re-hash sources and parts, compare config, detect drift |
|
|
271
|
+
| `report` | Print metrics, layer distribution and drift status |
|
|
272
|
+
| `explain <path>` | Show how one path would be treated |
|
|
273
|
+
| `diff <a> <b>` | Compare two snapshots |
|
|
274
|
+
| `init` | Write a starter config |
|
|
275
|
+
|
|
276
|
+
## `explain`
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
$ snap explain src/app/page.tsx
|
|
280
|
+
|
|
281
|
+
src/app/page.tsx
|
|
282
|
+
|
|
283
|
+
included yes
|
|
284
|
+
layer app (rule (p) => p.startsWith("src/app/") || ...)
|
|
285
|
+
kind component (rule (p) => { const base = p.split("/").pop() ...)
|
|
286
|
+
language tsx
|
|
287
|
+
size 48 B, 1 line(s)
|
|
288
|
+
part part-001.md
|
|
289
|
+
inclusion full
|
|
290
|
+
secrets none
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Excluded paths say why:
|
|
294
|
+
|
|
295
|
+
```
|
|
296
|
+
$ snap explain .env
|
|
297
|
+
|
|
298
|
+
.env
|
|
299
|
+
|
|
300
|
+
included no
|
|
301
|
+
reason sensitive-file
|
|
302
|
+
detail credential-bearing file; enable includeSensitiveFiles to emit it
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Exits `0` when the path is included, `1` when it is not. `--format json` emits the
|
|
306
|
+
same data as an object.
|
|
307
|
+
|
|
308
|
+
## `diff`
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
$ snap diff old-snapshot new-snapshot
|
|
312
|
+
|
|
313
|
+
before 2026-11-03T10:00:00.000Z 812 file(s), 4 part(s)
|
|
314
|
+
after 2026-11-03T11:30:00.000Z 820 file(s), 4 part(s)
|
|
315
|
+
|
|
316
|
+
+ 9 added
|
|
317
|
+
- 1 removed
|
|
318
|
+
~ 3 changed
|
|
319
|
+
= 808 unchanged
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Both arguments may be snapshot directories or paths to a `manifest.json`.
|
|
323
|
+
|
|
324
|
+
## `--watch`
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
npx @ankurhalder/codebase-snapshot generate --watch
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Re-generates on every change, ignoring writes into the output and temporary
|
|
331
|
+
directories (including the atomic-swap backup) so it cannot trigger itself.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
# Drift
|
|
336
|
+
|
|
337
|
+
`validate` compares five things: source hashes on disk, the emitted parts (size
|
|
338
|
+
and SHA-256), the manifest's own bookkeeping, the recorded configuration
|
|
339
|
+
(budgets, includes, excludes, artifacts, layers mode), and git state. Changing a
|
|
340
|
+
config value without re-generating is reported as drift, not silently accepted.
|
package/docs/install.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Installation
|
|
2
|
+
|
|
3
|
+
`@ankurhalder/codebase-snapshot` is published to the public npm registry, so it installs
|
|
4
|
+
with **any** npm-compatible client. There is nothing extra to configure and no second
|
|
5
|
+
registry to add.
|
|
6
|
+
|
|
7
|
+
Requires **Node.js 18 or newer**.
|
|
8
|
+
|
|
9
|
+
## One-off use (no install)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @ankurhalder/codebase-snapshot generate
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Equivalent one-liners for other clients:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
yarn dlx -p @ankurhalder/codebase-snapshot snap generate # yarn Berry
|
|
19
|
+
yarn global add @ankurhalder/codebase-snapshot # yarn classic (installs globally)
|
|
20
|
+
pnpm dlx @ankurhalder/codebase-snapshot generate
|
|
21
|
+
bunx @ankurhalder/codebase-snapshot generate
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Add to a project
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install -D @ankurhalder/codebase-snapshot
|
|
28
|
+
yarn add -D @ankurhalder/codebase-snapshot # yarn classic and Berry
|
|
29
|
+
pnpm add -D @ankurhalder/codebase-snapshot
|
|
30
|
+
bun add -d @ankurhalder/codebase-snapshot
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then run it through your client so it resolves from the project's `node_modules`:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx snap generate
|
|
37
|
+
yarn snap generate
|
|
38
|
+
pnpm exec snap generate
|
|
39
|
+
bun run snap generate
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Both `snap` and `codebase-snapshot` are exposed as binaries — pick whichever you prefer.
|
|
43
|
+
|
|
44
|
+
Adding it to `package.json` scripts works the same everywhere:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"scripts": {
|
|
49
|
+
"snapshot": "codebase-snapshot generate",
|
|
50
|
+
"snapshot:validate": "codebase-snapshot validate"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Global install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm install -g @ankurhalder/codebase-snapshot
|
|
59
|
+
pnpm add -g @ankurhalder/codebase-snapshot
|
|
60
|
+
bun add -g @ankurhalder/codebase-snapshot
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
A global install exists for convenience, but pinning the version per project (the
|
|
64
|
+
`-D`/`--save-dev` examples above) is the better default: snapshots are only reproducible
|
|
65
|
+
if the generator version is reproducible.
|
|
66
|
+
|
|
67
|
+
## Version pinning
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx @ankurhalder/codebase-snapshot@2 generate
|
|
71
|
+
pnpm dlx @ankurhalder/codebase-snapshot@2.1.0 generate
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Verified clients
|
|
75
|
+
|
|
76
|
+
Every client below was used to install the published package and run
|
|
77
|
+
`snap --version` successfully. This matrix is enforced in CI
|
|
78
|
+
(`.github/workflows/ci.yml` → `client-install`), so a change that breaks a client fails
|
|
79
|
+
the build rather than a user's terminal.
|
|
80
|
+
|
|
81
|
+
| Client | Version tested | Run installed binary with |
|
|
82
|
+
| :--- | :--- | :--- |
|
|
83
|
+
| npm | 10.x | `npx snap` |
|
|
84
|
+
| yarn (classic) | 1.22.22 | `yarn snap` |
|
|
85
|
+
| yarn (Berry, `nodeLinker: pnp`) | 4.6.0 | `yarn snap` |
|
|
86
|
+
| pnpm | 10.28.0 | `pnpm exec snap` |
|
|
87
|
+
| bun | 1.4.4 | `bun run snap` |
|
|
88
|
+
|
|
89
|
+
Yarn Berry's default **strict PnP** mode works: there is no `node_modules` directory, and
|
|
90
|
+
the runtime `typescript` dependency still resolves through yarn's `.pnp.cjs` loader.
|
|
91
|
+
|
|
92
|
+
## Package manager workspaces
|
|
93
|
+
|
|
94
|
+
The binary is resolved from the workspace it is installed in. In a monorepo, install it
|
|
95
|
+
in the package that runs the snapshot (usually the root), or use any client's one-off
|
|
96
|
+
runner (`npx` / `pnpm dlx` / `yarn dlx` / `bunx`) which works from any subdirectory.
|
|
97
|
+
|
|
98
|
+
## Uninstalling
|
|
99
|
+
|
|
100
|
+
Standard for your client (`npm uninstall`, `yarn remove`, `pnpm remove`, `bun remove`).
|
|
101
|
+
Snapshots already written to `snapshot/` are ordinary files and are left alone.
|
|
102
|
+
|
|
103
|
+
## Not supported yet
|
|
104
|
+
|
|
105
|
+
- **`pip`, `brew`, `scoop`, `docker`, and standalone binaries.** These require shipping a
|
|
106
|
+
prebuilt executable rather than JavaScript, and are tracked as future work in
|
|
107
|
+
[docs/plans/distribution](../plans/distribution/README.md). Until then, any machine
|
|
108
|
+
running the tool needs Node 18+.
|
|
109
|
+
- **Deno.** The API can be imported under Deno's npm compatibility, but running the CLI
|
|
110
|
+
needs a `./bin` subpath export that is not published yet.
|
|
111
|
+
|
|
112
|
+
## Troubleshooting
|
|
113
|
+
|
|
114
|
+
**`snap: command not found`** — when installed locally (not globally), the binary lives
|
|
115
|
+
in `node_modules/.bin` and is only on your `PATH` inside a package script or a client
|
|
116
|
+
runner. Use `npx snap`, `pnpm exec snap`, `yarn snap`, or `bun run snap`.
|
|
117
|
+
|
|
118
|
+
**`Cannot find module 'typescript'`** — the package declares `typescript` as a runtime
|
|
119
|
+
dependency for AST analysis. If your client prunes or externalizes it (some bundlers and
|
|
120
|
+
`--ignore-scripts` CI setups do), rerun a clean install, or pin `typescript@^5` yourself.
|
|
121
|
+
|
|
122
|
+
**CI has no Node** — that is not supported yet; this package is JavaScript and needs a
|
|
123
|
+
Node runtime. See the future-work note above.
|
|
124
|
+
|
|
125
|
+
**`yarn snap` prints extra lines, or breaks a script that parses output** — yarn classic
|
|
126
|
+
wraps everything: it echoes `yarn run 1.22.22`, the resolved command, your tool's output,
|
|
127
|
+
and a `Done in 0.37s.` trailer. For a human that is harmless; for anything that parses
|
|
128
|
+
`snap`'s stdout it is not. In scripts and CI, call the binary directly:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
./node_modules/.bin/snap generate
|
|
132
|
+
npx snap generate # same, without the yarn wrapper
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
This is why the CI job in this repository reads the version from a line that *is* the
|
|
136
|
+
version rather than taking the first or last line of output.
|
package/package.json
CHANGED
|
@@ -1,6 +1,96 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankurhalder/codebase-snapshot",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Production-grade LLM codebase snapshot generator, auditor, and AST partitioner",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"codebase",
|
|
7
|
+
"snapshot",
|
|
8
|
+
"llm",
|
|
9
|
+
"ai",
|
|
10
|
+
"context",
|
|
11
|
+
"ast",
|
|
12
|
+
"audit",
|
|
13
|
+
"codebase-snapshot",
|
|
14
|
+
"code-analysis"
|
|
15
|
+
],
|
|
16
|
+
"author": "Ankur Halder <ankur.halder12345@gmail.com>",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/ankurhalder/codebase-snapshot.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/ankurhalder/codebase-snapshot#readme",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/ankurhalder/codebase-snapshot/issues"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"type": "module",
|
|
30
|
+
"main": "./dist/index.cjs",
|
|
31
|
+
"module": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"bin": {
|
|
35
|
+
"codebase-snapshot": "./dist/bin.js",
|
|
36
|
+
"snap": "./dist/bin.js"
|
|
37
|
+
},
|
|
38
|
+
"exports": {
|
|
39
|
+
".": {
|
|
40
|
+
"import": {
|
|
41
|
+
"types": "./dist/index.d.ts",
|
|
42
|
+
"default": "./dist/index.js"
|
|
43
|
+
},
|
|
44
|
+
"require": {
|
|
45
|
+
"types": "./dist/index.d.cts",
|
|
46
|
+
"default": "./dist/index.cjs"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"./cli": {
|
|
50
|
+
"import": {
|
|
51
|
+
"types": "./dist/cli.d.ts",
|
|
52
|
+
"default": "./dist/cli.js"
|
|
53
|
+
},
|
|
54
|
+
"require": {
|
|
55
|
+
"types": "./dist/cli.d.cts",
|
|
56
|
+
"default": "./dist/cli.cjs"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"./package.json": "./package.json"
|
|
60
|
+
},
|
|
61
|
+
"files": [
|
|
62
|
+
"dist/*.js",
|
|
63
|
+
"dist/*.cjs",
|
|
64
|
+
"dist/*.d.ts",
|
|
65
|
+
"dist/*.d.cts",
|
|
66
|
+
"docs/*.md",
|
|
67
|
+
"README.md",
|
|
68
|
+
"LICENSE"
|
|
69
|
+
],
|
|
70
|
+
"scripts": {
|
|
71
|
+
"build": "tsup",
|
|
72
|
+
"dev": "tsup --watch",
|
|
73
|
+
"typecheck": "tsc --noEmit",
|
|
74
|
+
"lint": "node scripts/lint.mjs",
|
|
75
|
+
"check": "npm run lint && npm run typecheck && npm test",
|
|
76
|
+
"pretest": "npm run build",
|
|
77
|
+
"test": "node --test tests/*.test.js",
|
|
78
|
+
"test:coverage": "node --test --experimental-test-coverage tests/*.test.js",
|
|
79
|
+
"prepare": "npm run build",
|
|
80
|
+
"prepublishOnly": "npm run build",
|
|
81
|
+
"publish:create": "npm publish packages/create --access public"
|
|
82
|
+
},
|
|
83
|
+
"dependencies": {
|
|
84
|
+
"typescript": "^5.0.0"
|
|
85
|
+
},
|
|
86
|
+
"overrides": {
|
|
87
|
+
"esbuild": "^0.28.1"
|
|
88
|
+
},
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@types/node": "^22.0.0",
|
|
91
|
+
"tsup": "^8.3.0"
|
|
92
|
+
},
|
|
93
|
+
"engines": {
|
|
94
|
+
"node": ">=18.0.0"
|
|
95
|
+
}
|
|
96
|
+
}
|