Skip to content

feat: --cwd flag + linear-memory hash cache#19

Merged
maastrich merged 2 commits intomainfrom
feat/cli-cwd-flag
Apr 24, 2026
Merged

feat: --cwd flag + linear-memory hash cache#19
maastrich merged 2 commits intomainfrom
feat/cli-cwd-flag

Conversation

@maastrich
Copy link
Copy Markdown
Owner

Summary

Two commits, shipping together as 0.7.0.

feat(cli): add --cwd flag

Run hashup as if from the given directory. Changes where hashup.json is discovered, where relative entry/extras paths resolve, and where --out writes. Defaults to process.cwd().

hashup --cwd ./packages/app
hashup --cwd ./packages/app src/index.ts -o ../dist/app.hash

perf: linear-memory hash cache

HashupCache.hashes now stores each file's own content hash (one 64-char sha256 string) instead of the flattened transitive list. The transitive contribution is reconstructed at combine time by walking cache.deps. Memory drops from O(files × avg closure) to O(unique files).

Measured on a real-world 81-entry glob against a large shared UI graph (bfront webapps/lcm):

Metric 0.6.0 (flattened) New (linear)
Peak RSS ~9.3 GB 125 MB
Wall time ~3 min 1.1 s
Heap flag needed --max-old-space-size=12288 default 4 GB

~74× less memory, ~160× faster.

Hash output changes. Final digest is now sha256(each reachable file's hash, concatenated in sorted-path order). Every unique file contributes exactly once regardless of how many import paths reach it. Any stored 0.6.x hashes must be re-baselined. Side benefit: cycles now hash the same regardless of which member was the entry point (test strengthened to assert this).

Targeted break for direct hashFile callers. Return type is now Promise<string | null> instead of Promise<string[]>. hashup() itself is unchanged — the option surface is additive.

Test plan

  • vp test — 117/117 passing
  • vp check clean
  • Inline snapshot in tests/examples.test.ts updated to the new algorithm's output
  • tests/circular.test.ts strengthened: same hash from any cycle member
  • Verified against the bfront config that OOM'd 0.6.0 — now completes in ~1 s with 125 MB
  • shared-cache.test.ts still passes (shared-cache determinism holds under the new algorithm)

Docs

Updated docs/api/hashup.md, docs/api/utilities.md, docs/guide/how-it-works.md, docs/guide/cli.md (new --cwd option, new algorithm description, caveats refreshed).

🤖 Generated with Claude Code

maastrich and others added 2 commits April 24, 2026 12:21
Run hashup as if invoked from the given directory. Changes where
hashup.json is discovered, where relative entry/extras paths resolve,
and where --out writes. Defaults to process.cwd().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the per-file flattened transitive hash list. Store only each
file's own content hash plus its direct deps; reconstruct the
transitive contribution at combine time by walking cache.deps.

Final digest is now sha256(each reachable file's hash, sorted by path),
so every unique file contributes exactly once regardless of how many
import paths reach it.

Measured on a real monorepo config (81-entry glob against shared UI
code): peak RSS 9.3 GB → 125 MB, wall time ~3 min → 1.1 s.

Hash output changes. Any stored 0.6.x hashes must be re-baselined.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

📖 Docs preview: https://maastrich.github.io/hashup/branches/pr-19/

@maastrich maastrich merged commit 542c5ed into main Apr 24, 2026
3 checks passed
@maastrich maastrich deleted the feat/cli-cwd-flag branch April 24, 2026 10:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant