@ankurhalder/codebase-snapshot 2.0.0 → 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.
@@ -38,6 +38,81 @@ export default {
38
38
  };
39
39
  ```
40
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.
41
116
  ## Classification: layers and kinds
42
117
 
43
118
  ```javascript
@@ -60,7 +135,11 @@ Rules are evaluated in order, **first match wins**, with an `other` fallback.
60
135
  `layersMode: "merge"` (the default) keeps the detected preset's rules and lets
61
136
  yours win by being evaluated first. `"replace"` discards the preset entirely.
62
137
 
63
- Presets are auto-detected: **nextjs** → **vite** → **node** → **default**.
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`.
64
143
 
65
144
  ## Sizing: byte budgets
66
145
 
@@ -149,6 +228,13 @@ export default {
149
228
  and `outDir`/`tmpDir` may not contain each other. Writes are atomic: the previous
150
229
  snapshot survives until the new one is fully in place.
151
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
+
152
238
  ## Hooks
153
239
 
154
240
  ```javascript
@@ -164,6 +250,16 @@ export default {
164
250
  A throwing hook becomes a warning on the manifest — it never loses a snapshot
165
251
  that was already written.
166
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
+
167
263
  ---
168
264
 
169
265
  # Commands
@@ -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,6 @@
1
1
  {
2
2
  "name": "@ankurhalder/codebase-snapshot",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Production-grade LLM codebase snapshot generator, auditor, and AST partitioner",
5
5
  "keywords": [
6
6
  "codebase",
@@ -77,7 +77,8 @@
77
77
  "test": "node --test tests/*.test.js",
78
78
  "test:coverage": "node --test --experimental-test-coverage tests/*.test.js",
79
79
  "prepare": "npm run build",
80
- "prepublishOnly": "npm run build"
80
+ "prepublishOnly": "npm run build",
81
+ "publish:create": "npm publish packages/create --access public"
81
82
  },
82
83
  "dependencies": {
83
84
  "typescript": "^5.0.0"