Skip to content

Latest commit

 

History

History
583 lines (381 loc) · 48.1 KB

File metadata and controls

583 lines (381 loc) · 48.1 KB

Changelog

4.2.0 (2026-09-02)

Features

  • update: point the update notice at the owning package manager (#525) (d5d422b), closes #519

Bug Fixes

  • add: say gc collected the channel instead of blaming the user (#515) (15a29b7), closes #450
  • build: add windows/arm64 to the make release target (#524) (e07af8c), closes #517
  • update: refuse to replace a Homebrew or Scoop install (#518) (02f5c09)

4.1.0 (2026-09-02)

Installing with Homebrew or Scoop? 4.1.0 publishes a Homebrew cask and a Scoop manifest, so both now work alongside the install scripts and go install. Homebrew is one command, brew install pedrosousa13/tap/lnpm. Scoop resolves only against buckets you have added, so it is two:

scoop bucket add pedrosousa13 https://github.com/pedrosousa13/scoop-bucket
scoop install lnpm

Do not run lnpm update on an install that came from either one. It replaces the binary in place and has no notion of a package manager, so Homebrew and Scoop go on reporting the version they installed while the binary on PATH is a newer one, and the next brew upgrade overwrites the self-updated binary and puts you back on the version brew recorded. Both commands report success throughout. Use brew upgrade lnpm or scoop update lnpm instead. #508 tracks teaching lnpm update to detect a managed install and refuse.

The macOS binaries are not signed or notarized, so the cask clears the quarantine attribute on install. Without that, the first run reports lnpm as damaged. It also gives up the Gatekeeper check on this binary.

Nothing changes for an existing install. The store format, the database and lnpm.lock are all unchanged from 4.0.0.

Features

  • release: publish a Homebrew cask and a Scoop manifest (#509) (b242f0b)

4.0.0 (2026-09-02)

⚠ BREAKING CHANGES

  • every package hash changes. Store entries, database rows and lnpm.lock entries written by 3.x no longer resolve.

Features

  • 4.0.0 store-format migration — frame the hash, strip before hashing, refuse 3.x state (#498) (8d15f74)

3.1.1 (2026-09-02)

Bug Fixes

  • push: run the scripts npm pack runs, and say how to skip them (#496) (1e6aba8)

3.1.0 (2026-08-28)

Features

  • release: sign release artifacts with a maintainer-held key (#467) (2446032)

Bug Fixes

  • install: resolve a relative install directory before anything cd's (#486) (f963c64), closes #477
  • install: stop the cleanup trap re-evaluating the temp directory path (#485) (ab14514), closes #476
  • update: bound release asset reads before verification (#487) (d3bcde0), closes #478
  • update: cap the release API response before decoding it (#495) (1bacca6), closes #488
  • update: refuse a release redirect that leaves https (#489) (2e13b03), closes #479
  • update: warn that the go-install update path is not signature-verified (#484) (7027958), closes #475

3.0.0 (2026-08-27)

⚠ BREAKING CHANGES

  • remove: lnpm remove no longer runs the package manager's install automatically. Pass --install to keep the old behaviour.
  • pack: package names containing uppercase are now rejected, and names are composed to NFC before they reach the store or the lock file.

Features

  • pack: reject uppercase package names and compose them to NFC (#462) (88c517a), closes #327
  • remove: gate the package-manager install behind --install (#386) (fed8d5e), closes #336

2.4.0 (2026-08-27)

Features

  • cli: add 'lnpm forget' to drop the record of a project whose drive is gone (#455) (9c8d8c2), closes #382
  • pin: keep a rollback until the user moves off it (#451) (b57a06e)

Bug Fixes

  • ci: carry a release's upgrade notes into its published body (#418) (3db6df9)
  • cli: refuse a retreat that would delete through a symlinked node_modules (#414) (31753b2)
  • db: leave a link index entry DeleteLink cannot parse alone (#416) (a782c82)
  • db: stop GetProjectByPath handing back a project it could not parse (#415) (57a2935), closes #391
  • doctor: re-hash stored content instead of only checking an entry is finished (#448) (2b5b03f)
  • gc: say what declining the orphaned-link prompt achieves (#422) (789e224), closes #362
  • hooks: run prepack before prepare, as npm does (#452) (14dcf60)
  • link: verify a reuse candidate's content before carrying it over (#445) (b55273b)
  • pack: expand a directory a wildcard files entry matches, as npm does (#433) (3f1d7ec)
  • pack: hard-reserve the git metadata files so a files entry warns (#430) (f97e34e)
  • pack: let the files field beat an ignore file in the project-rules check (#424) (ca1c913), closes #347
  • pack: never publish a lockfile, matching npm's short list (#417) (39f842d)
  • pack: read a slash run in a files entry the way npm does (#432) (2ff5885)
  • pack: reject Windows-reserved package names and trailing dot or space (#419) (f047e13)
  • pack: skip an unenterable excluded directory instead of aborting (#434) (06826d7)
  • pack: stop a root history.db shipping past a files whitelist (#411) (c1e20c5)
  • pack: warn for a nested hard-reserved files entry written with ./ (#431) (07946cb)
  • shellcmd: make Command and QuoteArg compose on Windows (#413) (32488bb)
  • store: preserve the manifest's mode when stripping lifecycle scripts (#421) (09e04f0)
  • store: write protect an entry's content so a consumer cannot rewrite it (#442) (f7c4f14)
  • tests: give the turborepo fixtures the entry point they declare (#425) (e6032e8), closes #365
  • update: stop a git describe build offering itself an older release (#441) (3a865c8)
  • workspace: refuse members that resolve outside the workspace root (#420) (7e3ef3f)

2.3.0 (2026-08-24)

Using a files field? Three changes land together, and the packed set of an existing package can move in both directions. Check with lnpm publish before relying on it.

A files entry now overrides the built-in "excluded unless you say otherwise" list — but only for a path it names directly. files: [".env.example"] ships that template; files: ["dist"] still keeps dist/.env out, because naming a build directory is not a statement about what landed inside it. A main entry is not a way in: it loses to both built-in lists and warns instead. See #321.

An entry written ./dist used to select nothing, publishing a package that held only package.json. It now selects what dist does. A bare . still selects nothing, which is what npm does with it. See #346.

files entries now glob through the same engine as your ignore patterns, so ** spans zero or more path segments: files: ["lib/**/*.js"] now selects lib/top.js as well as lib/sub/a.js. Brace alternation comes with it, so files: ["weird{a,b}.txt"] matches weirda.txt and weirdb.txt — the file of that literal name is still selected too, by an exact-path compare npm does not have. One gap remains: a files entry ending in a wildcard does not expand a directory it matched into that directory's subtree, where npm does, so ["*"] ships only the package root's own files. See #350 and #406.

A publish no longer aborts on an unreadable directory it already excludes. A root-owned coverage/, or a .cache/ left by a tool running as another user, used to fail the whole publish by name even when your ignore file excluded it. It is now skipped with a warning. A directory that would have been packed still aborts, because a package silently missing a file is worse than a failed command. See #348.

Symlinked your .lnpm directory? Read-only link queries now refuse to resolve through it, closing the same hole #339 closed for writes in 2.2.1. There is no override for this one: the follow_symlinked_node_modules setting governs node_modules, not .lnpm. See #340.

Features

  • push: list the packed files on a steady-state push (#397) (7fdf579), closes #372

Bug Fixes

  • db: report unreadable link data instead of dropping it (#393) (bbf03c1), closes #355
  • gc: stop claiming a package row it did not delete (#395) (30e0ae8), closes #358
  • link: refuse read-only link queries through a symlinked .lnpm (#401) (9fa924e), closes #340
  • pack: glob a "files" entry with the engine ignore patterns use (#350) (50bf8b7)
  • pack: let a files entry override defaultExcludes, or warn when it cannot (#400) (5ecf0a0), closes #321
  • pack: resolve a leading "./" in a "files" entry (#346) (37b3f91)
  • pack: skip an unreadable directory the package already excludes (#348) (6ce2a3b)
  • tests: stop test binaries reading the machine's own config (#396) (f86c2ec), closes #371

2.2.1 (2026-08-23)

Relocated your node_modules? lnpm now refuses to link or unlink through a node_modules — or a node_modules/@scope — that is not a real directory, because a symlink there redirects lnpm's writes and deletes outside your project. If you relocate node_modules deliberately, set follow_symlinked_node_modules: true in ~/.lnpm/config.yaml to restore the previous behaviour. The refusal message names the file and the key. See #339.

Upgrading from 1.x? Store entries written before 2.0.0 carry no completeness marker, and lnpm now checks that marker before serving an entry. The first command that opens your store migrates it in one pass; until then lnpm doctor reports the store as pending rather than damaged. If it reports that the migration cannot run, a directory in your store could not be read — make it readable and run any command again. See #330.

lnpm gc is now more conservative. It will not collect a package whose only consuming project sits on a filesystem that is not mounted where it was linked — an unplugged drive or an unmounted network share no longer costs you the store entry. Those links are reported as skipped. The trade is that a drive gone for good leaves its entries uncollectable for now; see #382.

Bug Fixes

  • cli: write package.json through a temp file and rename (#377) (fb6bbe5), closes #324
  • gc: do not collect when a project's filesystem is not mounted (#383) (9e3ccf6), closes #335
  • link: refuse a symlinked node_modules or scope directory (#388) (4ad8ffb), closes #339
  • pack: reject package names whose segments begin with a dot (#379) (7f1b524), closes #325
  • store: check the completeness marker on the read path (#381) (68b3cb8), closes #330

2.2.0 (2026-08-23)

Packages that excluded package.json: lnpm now always packs the package root's own package.json, whatever your .npmignore, .gitignore or files field says, and refuses to pack at all if the manifest is missing. If one of your packages was excluding its manifest, its content hash changes with this release — the manifest is what carries the version string into the hashed content — so its next publish writes a new store entry instead of updating the old one. Only packages exhibiting the bug are affected. See #301.

Features

  • publish: add --dry-run and print the packed file list (3354320)

Bug Fixes

  • lockfile: bound lock-file and workspace-config size before parsing (032190d)
  • pack: always pack the manifest, whatever the ignore rules say (b47a0c3)

2.1.0 (2026-08-23)

Features

  • check: cover every workspace package, not just the working directory (#337) (0ee3ad5)

Bug Fixes

  • gc: abort when a package's links cannot be read (683f5c8)
  • gc: abort when a project row cannot be read (7445dbe)
  • gc: confirm before deleting orphaned links and report what was removed (ccdcd0b)
  • link: refuse to link through a symlinked .lnpm or scope directory (#341) (d9beea2)
  • pack: anchor the always-included set to the package root (c3dfe77)
  • pack: force-include the main entry point under a files whitelist (2156e15)
  • pack: honour .npmignore and .gitignore in every directory (#352) (a35b938), closes #315
  • pack: implement ** in ignore patterns as zero or more path segments (#351) (faedffa), closes #316
  • pack: make the files whitelist win over .npmignore and .gitignore (#349) (60c85a5), closes #318
  • pack: match the force-exclude guards case-insensitively (e40905e)
  • retreat: validate lock-file package names before deleting the path (#343) (f0ab237)
  • workspace: fail on a broken config in the directory Detect started from (#344) (e1f242c)

2.0.0 (2026-08-21)

Upgrading from 1.9.x or older? Those versions compare version numbers byte-wise, so lnpm update reports Already up to date and will never offer you this release. Reinstall manually with the install script or go install github.com/pedrosousa13/lnpm/cmd/lnpm@latest. 1.10.0 and later upgrade normally. See #297.

This release also migrates the package database on first open and makes gc collect superseded versions, so downgrading to 1.x after running it is not supported.

Features

  • Add lnpm pull to sync linked packages from the store (#264) (fc1c89f)
  • link: relink only the files that changed since the last link (#295) (b60c58c)
  • list: add version history and roll back with add <pkg>@<hash> (#298) (53e73bc)
  • Point add --link at the package's live source directory (#265) (c0fb6e1)
  • Resolve workspace: dependency specifiers when publishing (#266) (718f4d7)
  • restore: add lnpm restore to re-link packages after retreat (#294) (472f1be)

Bug Fixes

  • Abort destructive operations in non-interactive mode instead of auto-confirming (#223) (361672f)
  • add: roll a package back when its package.json update fails in multi-add (#244) (68039f3)
  • add: save the lock file before rewriting package.json (#243) (4c233f1)
  • align build-time ldflags and surface commit and date in --version (#281) (a8b72ac), closes #177
  • chmod linked and cloned files so umask cannot strip mode bits (#274) (54c11fe), closes #139
  • Compare versions with a semver library instead of text ordering (#216) (258156a)
  • fail doctor when it finds issues and print its markers through the icon helpers (#277) (fba8385), closes #162
  • fall back to the user completion directory when the system one refuses the write (#278) (c1439d8), closes #169
  • Fix nil-pointer crash in retreat when lnpm.lock is corrupt (#221) (70971e2)
  • Fix versioned package spec being treated as a content hash in multi-package add (#222) (c82ec62)
  • fsutil: call clonefile with the right signature on macOS (#229) (cfbfa9f), closes #135
  • gc: reclaim temp directories left by an interrupted publish or relink (#289) (e021c81), closes #233
  • give store entries a completeness marker (#273) (6650434), closes #237
  • keep GetDB's init error so every caller sees it (#290) (c73954a), closes #253
  • link: populate a temp directory and rename-swap instead of clearing the live package (#232) (b3f0a47), closes #137
  • Make doctor honor the configured store_path when checking the store (#249) (160ff22)
  • make hooks.skip_post_add actually skip the post-add hook (#280) (7079f81), closes #171
  • Make publish --push fail when every linked-project push fails (#248) (022933e)
  • Normalize root-anchored and directory patterns in the files whitelist (#228) (ba1ea4d)
  • Preserve package.json key order and formatting when editing dependencies (#250) (bf67c59)
  • remove the updater's temp directory and match Go bin dirs by path component (#276) (b29b9da), closes #147
  • remove: keep the lock entry when remove fails to restore package.json (#245) (c13b392)
  • Report a real version for go install builds so they can self-update (#217) (a3e9b48)
  • report scoped packages by full name and clean up emptied scope directories (#279) (ac2b4b9), closes #170 #236
  • Rewrite isExcluded to satisfy gitignore and npm ignore semantics (#220) (793e18a)
  • Run all applicable publish lifecycle scripts, not just the first (#251) (f8159ba)
  • Stop concurrent lnpm invocations from failing with a cryptic database timeout (#254) (24cd438)
  • stop hardlinking source files into the store (#213) (624a3e3)
  • stop three tests from passing without checking their subject (#282) (7ef8a02), closes #186
  • store: never delete the destination before the atomic rename (#238) (f6ebaf7), closes #138
  • stream copies with io.Copy and unlink half-made reflink clones (#275) (9a41948), closes #140
  • treat a degenerate files entry as including everything (#272) (a9f9a52), closes #227
  • update: report update-check failures instead of "Already up to date" (#239) (400cdf1), closes #144
  • update: stage the updated binary next to the target to avoid cross-filesystem rename failures (#240) (6b4e102)
  • Verify release checksums in the install scripts before running the binary (#218) (be7f7d2)
  • workspace: abort ListPackages on a member that will not read or parse (#293) (cd1aca9)
  • workspace: fail expansion when a workspace glob pattern will not parse (#287) (16c83a3), closes #241
  • workspace: subtract negation patterns in publish --all instead of dropping them (#242) (812d21d)

Continuous Integration

  • check PR titles and document the 2.0.0 upgrade path (#299) (89745e9)

1.12.0 (2026-07-23)

Features

  • add lnpm check guard and add --link protocol (#56) (58e1345)

Bug Fixes

  • config: support editor commands with args (#204) (6b1727d)
  • detect bun.lock text lockfile and honor list package argument (#205) (f9b0cfb)

1.11.0 (2026-06-24)

Features

  • cli: NO_COLOR/tty-aware output, rune-safe truncate, consistent confirmations, wire pre/post_publish hooks (#53, #51) (9cd95a2)

Bug Fixes

  • DeletePackage cleans up links + add GetProjectByID (#44) (7d84361)
  • honor store_path config option (#51 partial) (8a2b83d)
  • make content hash correct and deterministic (#45, #46) (0c9450d)
  • make store writes atomic via temp dir + rename (#47) (8324b9c)
  • non-zero exit on partial failure; silence usage on error (#48) (faa800f)
  • reflink dead on Linux — pass FICLONE source fd by value (#38) (4d08c1a)
  • resolve add pkg@version by version; remove dead --tag (#39) (a29a0ad)
  • skip symlinks during packing to prevent file exfiltration (#42) (1451c9b)
  • validate package names to prevent path traversal (#40) (7547650)
  • verify SHA-256 checksum on self-update + add HTTP timeout (#41) (5a57a87)

1.10.0 (2026-03-05)

Features

1.9.0 (2026-01-30)

Features

  • add: support multiple packages in single command (#32) (8d52feb)

1.8.2 (2026-01-19)

Bug Fixes

1.8.1 (2026-01-19)

Performance Improvements

  • push: parallelize link, push, publish ops (#26) (f8a9936)

1.8.0 (2026-01-19)

Features

  • add manage_gitignore config option (cb6f51f)

Bug Fixes

  • ci: skip concurrent package.json write test (79360bb)
  • ci: skip flaky concurrent test in CI (8b11c09)
  • remove unused fmt import (2122a51)
  • revert db path and remove t.Parallel() (0e33339)
  • skip flaky symlink test in CI (dec5411)
  • test failures and permission handling (9c4030b)
  • tests: path normalization & test fixes (f239a04)
  • wrap all unchecked error returns (a8b3431)
  • wrap defer os.Chmod in anonymous functions (ffb08da)
  • wrap defer os.Chmod in store tests (ca75562)

1.7.7 (2026-01-15)

Bug Fixes

1.7.6 (2026-01-15)

Performance Improvements

  • parallel hashing/linking, remove npm pack dep, fix defer errors (342272b)

1.7.5 (2026-01-15)

Bug Fixes

  • correct symlink depth for scoped packages (3d3162d)

1.7.4 (2026-01-15)

Bug Fixes

  • move goreleaser to release-please workflow (2062221)

1.7.3 (2026-01-15)

Bug Fixes

  • merge release workflow into CI, ensure CI blocks release (6b244ff)
  • release-please not running after PR merge (219f321)

1.7.2 (2026-01-15)

Bug Fixes

  • deprecated filepath.HasPrefix, align CI with release-please (a2f7739)

1.7.1 (2026-01-15)

Bug Fixes

1.7.0 (2026-01-15)

Features

1.6.1 (2026-01-15)

Bug Fixes

1.6.0 (2026-01-15)

Features

  • npm pack + tests for all kinds of monorepo (a7c3cb8)

Bug Fixes

1.5.0 (2026-01-15)

Features

  • check files against stage (5b2016b)

1.4.0 (2026-01-15)

Features

  • keep pushing for perf improvements (78ce20b)

Bug Fixes

  • lnpm update should always check for latest version (24ac467)

1.3.0 (2026-01-15)

Features

1.2.0 (2026-01-15)

Features

  • improve perf by using hard links (465b64b)
  • lnpm update command (743e09f)

Added

  • Reflink (Copy-on-Write) support for instant file operations on APFS (macOS) and Btrfs/XFS (Linux)
  • Hard link support during publish - Store operations now use hard links when source and store are on same filesystem
  • Parallel copy operations - Up to 8 concurrent workers for 4-8x faster copying when linking isn't possible
  • Intelligent linking strategy - Automatic priority system: reflink → hardlink → parallel copy
  • Config integration - link_mode configuration option is now properly respected
  • Enhanced user feedback - Clear warnings and tips when falling back from linking to copying
  • Cross-filesystem detection - Automatic detection and helpful messages for cross-filesystem scenarios

Performance

  • Up to 1000x faster for packages with 10,000+ files on modern filesystems (APFS/Btrfs/XFS)
  • Instant publishing when source and store are on same filesystem
  • 4-8x faster copying when cross-filesystem operations are required

1.1.1 (2026-01-15)

Bug Fixes

  • remove unused collectFiles function (64c2bca)

1.1.0 (2026-01-15)

Features

  • progress indicators + perf improvements (82d0571)

1.0.2 (2026-01-15)

Bug Fixes

  • run goreleaser in release-please workflow (9133260)

1.0.1 (2026-01-15)

Bug Fixes

1.0.0 (2026-01-15)

Bug Fixes