Tags: geodro/lerd
Tags
release: v1.21.1 (#391) * release: v1.21.1 A targeted fix for npm install -g under lerd's node shim. Binaries went into a fnm version-specific bin directory that nothing has on PATH, so npm install -g pm2 succeeded but the resulting pm2 was unreachable from the user's shell. lerd now points npm's prefix at a stable per-user path under ~/.local/share/lerd/node-global/ and writes small wrapper scripts for every global binary into ~/.local/bin/, which is already on PATH because that is where the lerd binary itself lives. Wrappers exec the real bin through fnm exec --using=default so globally installed tools resolve their #!/usr/bin/env node shebang against the fnm-managed default node from any directory. npm uninstall -g cleans the wrapper alongside the package, and files in ~/.local/bin/ that lerd did not write are never touched. The node, npm, and npx shell shims in ~/.local/share/lerd/bin/ now route through the lerd binary first so the new behaviour applies to bare npm install -g and not only to lerd npm install -g, falling back to a direct fnm invocation in containers where the glibc lerd binary cannot exec. The friendly "No Node.js version available via lerd. Run: lerd node:install 22" hint surfaces through both paths. Closes #390. * fix: write npm global wrappers to lerd's bin dir instead of ~/.local/bin The first pass landed wrappers in ~/.local/bin, which is only on PATH for users whose distro defaults add it (most XDG-aware Linux distros do) or who set it up by hand. On macOS that directory is not on PATH by default, and Homebrew installs of lerd live at /opt/homebrew/bin/lerd without ever needing ~/.local/bin to exist, so npm install -g pm2 would succeed but pm2 would stay command-not-found. The wrappers now go to config.BinDir() (~/.local/share/lerd/bin/), the directory lerd install already adds to PATH via the user's shell rc on every supported platform. The foreign-file marker check skips the existing node, npm, npx, php, composer, laravel, fnm, and mkcert shims that share the directory, so they are never overwritten by a global of the same name, and the head-only marker check still keeps the cleanup pass from removing native binaries. * feat(composer): write composer-global wrappers to lerd's bin dir composer global require had the same shape as npm install -g before this branch: composer global require psy/psysh succeeded but psysh ended up under ~/.config/composer/vendor/bin/ which is not guaranteed on PATH, especially on macOS Homebrew installs. The flow now mirrors the npm one. A new lerd composer subcommand wraps the existing lerd php composer.phar invocation and, after composer exits, syncs $COMPOSER_HOME/vendor/bin/ to ~/.local/share/lerd/bin/ as small wrapper scripts that exec the real bin through lerd php so #!/usr/bin/env php shebangs always resolve against the FPM container. The shell composer shim delegates to lerd composer first when the lerd binary is reachable, falling back to lerd php composer.phar otherwise. The two syncs coexist in the same target directory because each category uses its own marker substring (lerd-managed npm global shim and lerd-managed composer global shim). A category's cleanup pass only removes wrappers that carry its own marker, so npm and composer sync runs cannot remove each other's files. The hand-written laravel shim that lerd install drops in by default has no marker and so is treated as a foreign file by composer sync, preserving its behaviour for users who relied on it. To make sync run on every composer exit path including failed composer global remove, RunPHP grows a non-exiting sister RunPHPCapture that returns the child exit code instead of calling os.Exit. RunPHP keeps its existing exit semantics for lerd php, sail, and vendor-bin callers, and runComposer uses RunPHPCapture so the sync runs before the parent shell exit code is set. The npm-side sync helper is extracted into a generic shimSync struct in shim_sync.go that takes a marker and a wrapper-body function. syncNodeGlobalBins and the new syncComposerGlobalBins both build on it, so the marker-and-shebang protection that keeps native binaries and foreign shell scripts safe is shared.
release: v1.21.0 (#388) The 1.21.0 line graduates from beta with eight follow-up commits on top of v1.21.0-beta.1. A LAN-exposure audit closes three dashboard endpoints that were reachable on lan:expose installs (raw .env, push-test, an unauthenticated mailpit webhook) and adds path-traversal validation for the new public_dir override (#382). mysql and mariadb pick up catatonit as PID 1 via a new init flag on the preset schema, so podman stop returns in around a second instead of timing out at 30s and lerd service restart stops wedging at the 30-90s mark (#383, closes #380). Host workers stopped via the UI or lerd worker stop no longer resurrect on the next fsnotify event or launchd heal tick, and the same fix puts lerd's bin directory on PATH for npm-spawned subprocesses so wayfinder and friends can find php (#375, #376, closes #381). The PHP-FPM runtime stage gets git back after the multi-stage split in #364 dropped it (#377), restoring VCS-typed composer repositories. Notification clicks land on the right tab now: worker_failed deep-links via the site's primary domain and dump arrivals jump straight to the Dumps sub-tab (#384). The .lerd.yaml container block accepts a target field for multi-stage Containerfiles, with the cache key mixing target in so flipping stages on an unchanged file actually rebuilds (#385, addresses #379), and the MCP service_add tool picks up the matching init argument so agent-driven flows reach feature parity with the YAML path (#386). And a security pass bumps jwt-go to 5.2.2, svelte to 5.55.8, and kysely to 0.28.17 closing one high-severity JWT header-parsing flaw, three medium svelte XSS paths, and one high kysely JSON-path traversal injection (#387).
PreviousNext