treezip 1.1.1 → 1.1.2

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 (2) hide show
  1. package/README.md +121 -64
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,22 +1,42 @@
1
1
  # treezip
2
2
 
3
- Compressed directory trees for AI prompts. Zero dependencies.
3
+ compressed directory trees for llm prompts. zero dependencies, aggressively de-noised.
4
4
 
5
- `tree` output is verbose — `treezip` compresses it using brace grouping, directory collapsing, and truncation so you can fit more codebase structure into fewer tokens.
5
+ ```bash
6
+ npx treezip ./my-project
7
+ ```
8
+
9
+ ## the problem
10
+
11
+ you paste a `tree` dump into an llm so it understands your codebase. two things go wrong:
12
+
13
+ 1. **it's verbose.** every file gets its own line, its own indent guides, its own copy of the extension. a 400-file repo eats thousands of tokens on pure structure.
14
+ 2. **it's full of junk.** `node_modules`, `DerivedData`, `__pycache__`, `.turbo`, coverage reports, `.DS_Store` — none of it helps the model, all of it costs tokens. one xcode build folder can turn a 100-line tree into an 11,000-line one. (that's a real number — see below.)
15
+
16
+ `treezip` fixes both. it compresses the structure losslessly with brace notation, and it hardcodes a multi-ecosystem noise filter so build artifacts never reach the output in the first place.
17
+
18
+ real-world result on a swift app with a checked-in derived-data dir and agent worktrees lying around:
19
+
20
+ | | lines |
21
+ |---|---|
22
+ | plain `tree` | 11,261 |
23
+ | `treezip` | **98** |
24
+
25
+ same source files visible. 99% less noise.
6
26
 
7
- ## Install
27
+ ## install
8
28
 
9
29
  ```bash
10
30
  npm install -g treezip
11
31
  ```
12
32
 
13
- Or run directly:
33
+ or don't install at all:
14
34
 
15
35
  ```bash
16
36
  npx treezip ./my-project
17
37
  ```
18
38
 
19
- ## Before / After
39
+ ## before / after
20
40
 
21
41
  **`tree` (43 lines):**
22
42
 
@@ -69,7 +89,7 @@ my-project/
69
89
  └── tsconfig.json
70
90
  ```
71
91
 
72
- **`treezip` (17 lines):**
92
+ **`treezip` (12 lines):**
73
93
 
74
94
  ```
75
95
  my-project/
@@ -86,60 +106,29 @@ my-project/
86
106
  └── {Button,Card,Header,Modal,Sidebar}.test.tsx
87
107
  ```
88
108
 
89
- **60% fewer lines.** Same information. Every brace group decompresses to exactly one file per entry.
109
+ every brace group decompresses to exactly one path per entry — the compression is lossless (except explicit `...` truncation, which is marked so the model knows more files exist).
90
110
 
91
- ## How it works
111
+ ## the format
92
112
 
93
- | Pattern | Meaning | Example |
113
+ | pattern | meaning | example |
94
114
  |---|---|---|
95
- | `{a,b,c}.ext` | Siblings sharing an extension | `{Button,Card,Modal}.tsx` |
96
- | `{a.x,b.y}` | Siblings with different extensions | `{README.md,tsconfig.json}` |
97
- | `dir/{stems}.ext` | All files in dir share an extension | `utils/{api,auth,format}.ts` |
98
- | `dir/file` | Single-child directory collapsed | `scripts/build.sh` |
99
- | `{a,b,...}.ext` | Truncated group (more files exist) | `images/{logo,hero,...}.png` |
100
-
101
- ### Compression rules
102
-
103
- 1. **Mixed directories** (files + subdirs): all files grouped into one `{...}` set
104
- 2. **Files-only directories**: grouped by shared extension (compound-aware: `.test.ts`, `.config.js`)
105
- 3. **Inline collapse**: directories that compress to a single item shown inline
106
- 4. **Single-child chain**: `a/b/c.txt` when each level has one child
107
- 5. **Truncation**: groups with >8 items show the first 5 + `...`
108
-
109
- ### Default ignores
110
-
111
- treezip hardcodes an aggressive noise filter tuned for LLM context — build
112
- artifacts, caches, and OS junk never reach the output:
113
-
114
- - **VCS**: `.git` (dir and worktree pointer file), `.hg`, `.svn`, `.jj`, …
115
- - **OS**: `.DS_Store`, `Thumbs.db`, `desktop.ini`, `._*` AppleDouble files, …
116
- - **JS/TS**: `node_modules`, `.next`, `.nuxt`, `.turbo`, `.vite`, `.svelte-kit`,
117
- `.astro`, `coverage`, `.wrangler`, `.vercel`, `*.tsbuildinfo`, …
118
- - **Python**: `__pycache__`, `.venv`/`venv`, `.pytest_cache`, `.mypy_cache`,
119
- `.ruff_cache`, `*.egg-info`, `*.pyc`, …
120
- - **Swift/Xcode**: `DerivedData`, `.build`, `.swiftpm`, `xcuserdata`,
121
- `Index.noindex` and friends, …
122
- - **Others**: `.gradle`, `zig-out`, `_build` (Elixir), `.dart_tool`,
123
- `CMakeFiles`, `cmake-build-*`, `.terraform`, `.idea`, `.vs`, …
124
-
125
- Three smarter rules on top of the basename list:
126
-
127
- 1. **Content markers** — a directory containing `pyvenv.cfg` is a venv, one
128
- containing `Index.noindex` is an Xcode DerivedData root; both are skipped
129
- *whatever they're named* (catches custom `-derivedDataPath` dirs).
130
- 2. **Sibling confirmation** — generic names are only skipped when the
131
- ecosystem is proven: `target/` next to `Cargo.toml`/`pom.xml`, `build/`
132
- next to `build.gradle`, `bin`/`obj` next to a `.csproj`. A docs folder
133
- named `build/` stays visible.
134
- 3. **Scoped rules** — `.claude/worktrees` is hidden but `.claude/skills`
135
- stays; `.yarn/cache` is hidden but `.yarn/patches` stays.
136
-
137
- Meaningful files are never hidden: lockfiles (`package-lock.json`,
138
- `Package.resolved`, `uv.lock`, …), `.env`, `.envrc`, `.vscode`, `.github`.
139
-
140
- ## Output header
141
-
142
- Every output includes a self-documenting header:
115
+ | `{a,b,c}.ext` | siblings sharing an extension | `{Button,Card,Modal}.tsx` |
116
+ | `{a.x,b.y}` | siblings with mixed extensions | `{README.md,tsconfig.json}` |
117
+ | `dir/{stems}.ext` | whole dir shares one extension | `utils/{api,auth,format}.ts` |
118
+ | `dir/file` | single-child chain collapsed | `scripts/build.sh` |
119
+ | `{a,b,...}.ext` | truncated more files exist | `images/{logo,hero,...}.png` |
120
+
121
+ ### compression rules
122
+
123
+ 1. **mixed directories** (files + subdirs): all files fold into one `{...}` set, subdirs listed after
124
+ 2. **files-only directories**: grouped by shared extension, compound-aware `.test.ts` groups separately from `.ts`, `.config.js` from `.js`
125
+ 3. **inline collapse**: a directory that compresses to a single item renders on one line
126
+ 4. **single-child chains**: `a/b/c.txt` when each level has exactly one child
127
+ 5. **truncation**: groups over 8 items show the first 5 + `...`
128
+
129
+ ### self-documenting header
130
+
131
+ every output starts with a 3-line legend:
143
132
 
144
133
  ```
145
134
  # COMPRESSED FILE TREE — AI READ GUIDE
@@ -147,20 +136,88 @@ Every output includes a self-documenting header:
147
136
  # {...}.ext → truncated list (more exist) | decompress: expand braces × each entry = 1 path
148
137
  ```
149
138
 
150
- This lets LLMs interpret the format without extra instructions.
139
+ paste the output anywhere the model gets the decoding instructions for free, no system-prompt setup needed.
140
+
141
+ ## the noise filter
142
+
143
+ this is the part most tree tools don't do. ripgrep, fd, tokei, eza all delegate to `.gitignore` — which is great until the repo has no gitignore, or the junk is inside a worktree, or someone pointed `-derivedDataPath` at a folder inside the repo. `treezip` ships its own opinionated filter, built from the github/gitignore templates, vendor docs, and the default-ignore lists of repomix/gitingest. it works in three layers:
144
+
145
+ ### layer 1 — basename blocklist
146
+
147
+ distinctive names that are noise in any repo, skipped unconditionally:
148
+
149
+ - **vcs internals**: `.git` (dir *and* the worktree/submodule pointer file), `.hg`, `.svn`, `.bzr`, `.jj`, `.sapling`
150
+ - **os junk**: `.DS_Store`, `.Spotlight-V100`, `.Trashes`, `.fseventsd`, `Thumbs.db`, `desktop.ini`, `$RECYCLE.BIN`, `__MACOSX`, `._*` appledouble files
151
+ - **js/ts**: `node_modules`, `.pnpm`, `.next`, `.nuxt`, `.output`, `.turbo`, `.parcel-cache`, `.vite`, `.svelte-kit`, `.astro`, `.angular`, `.docusaurus`, `.expo`, `.wrangler`, `.vercel`, `.netlify`, `.serverless`, `coverage`, `.nyc_output`, `storybook-static`, `*.tsbuildinfo`, `.eslintcache`
152
+ - **python**: `__pycache__`, `.venv`, `venv`, `.tox`, `.nox`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.hypothesis`, `.ipynb_checkpoints`, `*.egg-info`, `htmlcov`, `*.pyc`, `.coverage`
153
+ - **swift/xcode**: `DerivedData`, `.build`, `.swiftpm`, `xcuserdata`, `Carthage`, `SourcePackages`, `Index.noindex`, `ModuleCache.noindex`, `Intermediates.noindex`, `CompilationCache.noindex`, `SDKStatCaches.noindex`
154
+ - **everything else**: `.gradle` (jvm), `zig-cache`/`.zig-cache`/`zig-out`, `_build`/`.elixir_ls` (elixir), `.dart_tool` (flutter), `CMakeFiles`/`_deps`/`cmake-build-*` (cmake), `.vs`/`.idea` (ide caches), `.bundle`/`.yardoc` (ruby), `.terraform`/`.terragrunt-cache`/`.vagrant`/`.direnv` (infra)
151
155
 
152
- ## Programmatic API
156
+ ### layer 2 — content markers
157
+
158
+ build roots can be named *anything*. xcode's `-derivedDataPath` lets you point builds at `.test-app-build/` or `whatever/`; python venvs get called `env`, `myenv`, `env310`. name-matching can't catch these — so `treezip` peeks one level inside every directory:
159
+
160
+ - contains `pyvenv.cfg` → it's a venv, skip it
161
+ - contains `Index.noindex` / `ModuleCache.noindex` / `SDKStatCaches.noindex` / `CompilationCache.noindex` → it's a derived-data root, skip it
162
+
163
+ whatever it's named, however deep it hides.
164
+
165
+ ### layer 3 — context-aware rules
166
+
167
+ generic words like `target` and `build` are dangerous to blanket-ignore — a docs folder named `build/` is real content. so these only get skipped when a sibling file proves the ecosystem:
168
+
169
+ | dir | skipped only next to |
170
+ |---|---|
171
+ | `target/` | `Cargo.toml` or `pom.xml` |
172
+ | `build/` | `build.gradle`, `build.gradle.kts`, `settings.gradle(.kts)` |
173
+ | `deps/` | `mix.exs` |
174
+ | `bin/`, `obj/` | a `.csproj`/`.fsproj`/`.vbproj`/`.sln` |
175
+
176
+ plus parent-scoped rules where a dot-dir is half config, half cache:
177
+
178
+ - `.claude/worktrees` hidden, `.claude/skills` kept
179
+ - `.yarn/cache`, `.yarn/unplugged` hidden, `.yarn/patches`, `.yarn/releases` kept
180
+
181
+ ### what never gets hidden
182
+
183
+ signal stays, always:
184
+
185
+ - lockfiles — `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `bun.lock`, `Cargo.lock`, `Package.resolved`, `poetry.lock`, `uv.lock`
186
+ - `.env`, `.envrc` — you want to *know* those exist
187
+ - `.vscode`, `.github` — committed config, often load-bearing
188
+ - `.xcodeproj` bundles — project definition is source (only the `xcuserdata` inside is junk)
189
+
190
+ ## programmatic api
153
191
 
154
192
  ```ts
155
193
  import { scan, compress, render, countNodes } from "treezip";
156
194
 
157
- const tree = scan("./my-project");
158
- const compressed = compress(tree);
159
- const { dirs, files } = countNodes(tree);
195
+ const tree = scan("./my-project"); // filtered TreeNode
196
+ const compressed = compress(tree); // CompressedItem[]
197
+ const { dirs, files } = countNodes(tree); // post-filter counts
160
198
  const output = render("my-project/", compressed);
161
199
  console.log(output);
162
200
  ```
163
201
 
164
- ## License
202
+ the noise predicates are exported too, if you want the filter without the tree:
203
+
204
+ ```ts
205
+ import { isNoiseDir, isNoiseFile, hasNoiseMarker, NOISE_DIRS, NOISE_FILES } from "treezip";
206
+
207
+ isNoiseDir("node_modules", "my-project", []); // true
208
+ isNoiseDir("build", "repo", ["build.gradle"]); // true (gradle proven)
209
+ isNoiseDir("build", "repo", ["README.md"]); // false (could be real)
210
+ hasNoiseMarker(["pyvenv.cfg", "bin", "lib"]); // true (it's a venv)
211
+ ```
212
+
213
+ ## design notes
214
+
215
+ - **zero dependencies.** stdlib `fs` + `path`, nothing else. install is instant, supply chain is empty.
216
+ - **symlinks are skipped**, so cycles can't happen and the tree never leaves the root.
217
+ - **deterministic output**: files first, then dirs, both alphabetical — same input, same bytes out.
218
+ - **the root is never filtered.** if you explicitly run `treezip ./node_modules`, you get `node_modules` — you asked, treezip answers.
219
+ - releases are automated: every push to `main` runs the test suite, bumps the patch version, tags, and publishes to npm.
220
+
221
+ ## license
165
222
 
166
- MIT
223
+ mit
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "treezip",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Compressed tree output for AI-optimized codebase summaries",
5
5
  "type": "module",
6
6
  "bin": {