Documentation
¶
Index ¶
- func BunPath() string
- func BunVersion() string
- func Bunify(command string) string
- func CommandUsesNode(command string) bool
- func DetectVersion(dir string) (string, error)
- func DiscoverNvmDir() string
- func JSRuntime(dir string) string
- func ListInstalled() []string
- func Managed() bool
- func PackageManager(dir string) string
- func SafeVersion(v string) string
- func ScriptPresent() bool
- func SystemNodeAvailable() bool
- func SystemNodeBinDirs() []string
- func SystemNodeBinDirsFor(version string) []string
- func UnpinnedVersion(dir string) (version, source string)
- func UsesBun(dir string) bool
- func WritesPathShims(m Manager) bool
- type Manager
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BunPath ¶ added in v1.25.0
func BunPath() string
BunPath resolves the host bun binary: the official installer drops it in ~/.bun/bin, which is not on the controlled PATH lerd gives host workers, so check there first and fall back to PATH. Returns "" when bun isn't installed.
func BunVersion ¶ added in v1.25.0
func BunVersion() string
BunVersion returns the host bun version (e.g. "1.3.14"), or "" when bun isn't installed or doesn't run. The exec result is cached for 30s because callers like the UI status snapshot rebuild on every poll and WebSocket push; the version rarely changes within that window (`bun upgrade` reflects on the next refresh).
func Bunify ¶ added in v1.25.0
Bunify rewrites the npm/npx/node command verb to its bun equivalent (npm->bun, npx->bunx, node->bun) for every command in a shell chain, so `npm run build && npm run preview` becomes `bun run build && bun run preview`. Segments are split on the shell operators &&, ||, |, ;, & (operators inside quotes don't split); each segment is rewritten independently.
func CommandUsesNode ¶ added in v1.31.0
CommandUsesNode reports whether any segment of a worker's shell command invokes the Node toolchain, so a missing Node only holds back workers that would actually crash on it (a Go or Python host-proxy command in a repo that happens to carry a package.json must keep running directly).
func DetectVersion ¶
DetectVersion detects the Node.js version for the given directory. It checks, in order:
- .lerd.yaml node_version field (explicit lerd override)
- .nvmrc
- .node-version
- package.json engines.node
- global config default
func DiscoverNvmDir ¶ added in v1.31.0
func DiscoverNvmDir() string
DiscoverNvmDir returns the live nvm location from $NVM_DIR or ~/.nvm, ignoring any persisted node.nvm_dir. Used when recording the path at install/switch time so daemons keep agreeing with the CLI.
func JSRuntime ¶ added in v1.25.0
JSRuntime returns the explicit per-project JS runtime override from .lerd.yaml's js_runtime field, normalized to "bun", "node", or "" (unset / unrecognized, meaning auto-detect). Node aliases (node/nodejs/npm) all map to "node" so a small typo doesn't silently defeat the override and re-force bun.
func ListInstalled ¶ added in v1.23.0
func ListInstalled() []string
ListInstalled returns every Node major version installed under the active version manager, in the order it reports them. Empty when the manager isn't available or the user has no versions installed. Centralises listing so every surface (web UI, MCP, TUI) sees the same list with the same dedupe rules.
func Managed ¶ added in v1.31.0
func Managed() bool
Managed reports whether lerd is managing Node for this host. An explicit node.managed config preference wins; when the field is unset (configs from before it existed), presence of the node PATH shim is the historical signal. With nvm there is no node shim on PATH (nvm already owns node/npm/npx), so the persisted preference is what keeps managed mode visible to the UI/CLI.
func PackageManager ¶ added in v1.29.0
PackageManager reports the JS package manager a project uses: the package.json "packageManager" field (corepack's pin) wins, then the lockfile. Returns "bun", "pnpm", "yarn", or "npm" (the default). bun is normally resolved earlier via UsesBun/BunPath; it is reported here too for callers that want the raw signal.
func SafeVersion ¶ added in v1.31.0
SafeVersion returns v when it could be a version selector, and empty when it could not. The committed .lerd.yaml is repository content, and the version it pins reaches a worker unit's command line, so a value that is not version shaped is dropped rather than passed along.
func ScriptPresent ¶ added in v1.31.0
func ScriptPresent() bool
ScriptPresent reports whether an nvm this host can drive is installed, in either layout. Install and the manager switch ask through here so a Homebrew nvm counts as one.
func SystemNodeAvailable ¶ added in v1.25.0
func SystemNodeAvailable() bool
SystemNodeAvailable reports whether a system Node (outside lerd's own fnm shims) is resolvable, on PATH or in a known version-manager install dir. Used to decide the bun fallback and to surface the active JS runtime in the UI. The dir probe matters for daemon-side callers whose minimal PATH would otherwise hide a shell-hooked Node and flip an npm project onto bun.
func SystemNodeBinDirs ¶ added in v1.31.0
func SystemNodeBinDirs() []string
SystemNodeBinDirs resolves the directories where an unmanaged node and npm actually live, so the host-worker generators can bake them into a unit's PATH. A generated unit never inherits the user's login PATH, so a Node injected by a shell hook (nvm, a self-installed fnm, volta, mise, asdf) or living outside the standard dirs (snap, linuxbrew) is invisible at runtime even though `node` works fine in the user's terminal — issue #1143.
A configured manager lerd does not own comes first: `lerd npm` runs through it, so resolving some other node from PATH would install modules under one Node and run them under another. Otherwise the order mirrors detectSystemNode at install time: the current PATH first (skipping lerd's own shim dir), then the well-known version-manager install layouts, then static locations. Returns nil when nothing usable is found.
func SystemNodeBinDirsFor ¶ added in v1.31.0
SystemNodeBinDirsFor is SystemNodeBinDirs for a site pinned to version (a major like "22", empty for no pin). Only a borrowed manager can honour the pin: it is the version `lerd npm` runs in that directory, so a worker on any other one would run modules that were installed under a different Node. An uninstalled pin falls back rather than installing into the user's manager.
func UnpinnedVersion ¶ added in v1.33.0
UnpinnedVersion resolves the version dir gets while .lerd.yaml carries no node_version, and names where that answer came from. The setup wizard writes that pin, so the version an unanswered field accepts has to be resolved with the pin left out of the order.
func UsesBun ¶ added in v1.25.0
UsesBun reports whether the project in dir should run its JS tooling through bun instead of npm. The .lerd.yaml js_runtime override wins ("bun" forces bun, "node"/"npm" forces Node); otherwise lerd auto-detects bun from a bun.lockb / bun.lock / bunfig.toml file or a packageManager: bun field. (When no Node is available at all, the host-worker path falls back to bun unless js_runtime pins Node; see bunRunnerFor.)
func WritesPathShims ¶ added in v1.31.0
WritesPathShims reports whether this manager should install node/npm/npx wrappers into lerd's bin dir. fnm needs them (nothing else puts fnm on PATH); nvm must not (the user's shell already loads nvm, and lerd shims ahead of it make `nvm ls` / `nvm use` hang).
Types ¶
type Manager ¶ added in v1.31.0
type Manager interface {
// Name is the manager's identifier: "fnm" or "nvm".
Name() string
// Available reports whether the manager is usable on this host.
Available() bool
// List returns the installed Node major versions, deduped.
List() []string
// Install installs the given version (a major like "20" or a full semver).
Install(version string) error
// Uninstall removes the given version.
Uninstall(version string) error
// SetDefault pins version as the manager's default.
SetDefault(version string) error
// HasDefault reports whether a usable default version is set.
HasDefault() bool
// Command builds a command that runs bin (with args) under version. An
// empty version or "default" uses the manager's default. The caller sets
// Dir/Env/streams on the returned command.
Command(version, bin string, args []string) *exec.Cmd
// ApplyEnv makes KEY=VAL pairs take effect for cmd after the manager has
// activated the Node version. Call after setting cmd.Env. fnm appends to
// cmd.Env; nvm embeds `export` statements after `nvm use` inside the bash
// wrapper so vars like npm_config_prefix are not visible during activation
// (nvm aborts when that variable is already set in the process environment).
ApplyEnv(cmd *exec.Cmd, env []string)
// ExecPrefix returns the shell tokens that precede a command so that
// "<ExecPrefix(version)> <command> <args>" runs the command under version.
// Used to build worker units and npm global wrappers.
ExecPrefix(version string) string
// ExecPrefixWithEnv is ExecPrefix with env vars set after Node activation,
// so npm global wrappers see lerd's npm_config_prefix, not the manager's.
ExecPrefixWithEnv(version string, env []string) string
// ShimScript returns the full shell script for a node/npm/npx PATH shim
// named bin. Only used when WritesPathShims is true (fnm). nvm returns a
// stub that explains PATH shims are not installed for that manager.
ShimScript(lerdBin, bin string) string
}
Manager abstracts a Node.js version manager so lerd can install, list, and execute Node without hardcoding one tool. Two implementations exist: fnm (the bundled default binary) and nvm (a user-installed shell function). Callers select one via Active(), which reads the node.manager config setting.
Two flavours of output are exposed because lerd drives the manager from two places: directly from Go (Command, used by the CLI/UI/MCP) and from generated shell scripts where the lerd binary may be unreachable — worker units, launchd guard scripts, and PATH shims (ExecPrefix and ShimScript).
func Active ¶ added in v1.31.0
func Active() Manager
Active returns the Node version manager lerd is configured to drive, honouring the node.manager config setting and defaulting to fnm so configs predating the setting keep the bundled behaviour.
func ManagerByName ¶ added in v1.31.0
ManagerByName returns the manager for an explicit name, defaulting to fnm for anything unrecognised (so a garbled config setting never breaks Node). Used by the node:manager switch to probe a target backend before selecting it.