port the JS runtimes: node, bun and pm2 installed rather than offered

Not a choice. Officer does not run without them, so asking would be asking
whether to install Officer — which was settled by running the script. They are
installed and reported, with the reason each is load-bearing stated once:

  node  pm2 is a Node application, and officer-pty compiles node-pty against
        whatever Node is installed. There is no Linux prebuild, so this is not
        an ABI question — it is a build dependency on every machine.
  bun   the platform itself and nineteen of the twenty pm2 apps.
  pm2   supervises all of them, and the ecosystem files are written for it.

Node now tracks the current LTS, asked of nodejs.org, rather than the pinned
setup_22.x the original used — which ages into "the version we happened to pick"
the moment a new LTS lands. Resolves to v24.19.0 (Krypton) today, and NodeSource
publishes setup_24.x, checked with a HEAD request before anything is piped into a
shell.

Deno is the one genuine choice and stays optional, defaulting to no. Nothing in
Officer imports it — verified across the whole tree, the only references left are
in the old setup script — so the prompt says that outright and offers it for the
user's own work rather than pretending it is part of the platform.

bun is installed as the account and then symlinked into /usr/local/bin. pm2
started at boot by systemd has no login shell and therefore no ~/.bun/bin on
PATH; without the symlink every bun-based sidecar fails on reboot and works when
started by hand, which is a miserable thing to debug.

Every install is verified after it runs rather than trusting an exit status. A
NodeSource run can succeed while apt holds an older nodejs back, and reporting
the version asked for instead of the one present is how a machine ends up
disagreeing with its own setup log. Tested with an installer stubbed to succeed
and change nothing: both report failure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 21:08:41 +00:00
co-authored by Claude Opus 5
parent 999362948f
commit 00e58931ff
2 changed files with 170 additions and 1 deletions
+70
View File
@@ -170,3 +170,73 @@ nvim_clone_config() {
[[ "$repo" == *LazyVim/starter* ]] && sudo -u "$USERNAME" rm -rf "${dest}/.git"
return 0
}
# -----------------------------------------------------------------------------
# JavaScript runtimes
# -----------------------------------------------------------------------------
#
# Three of these are not optional, and it is worth being precise about why,
# because "we run on Bun" suggests Node could go and it cannot:
#
# node pm2 is a Node application (#!/usr/bin/env node), and pm2 supervises
# every process here. officer-pty imports node-pty, a native addon with
# no Linux prebuild — it compiles against the installed Node on every
# machine. Either one alone makes Node load-bearing.
# bun the platform itself and nineteen of the twenty pm2 apps.
# pm2 the process manager the ecosystem files are written for.
#
# Deno is not. Nothing in the platform imports it — checked across the whole
# tree — and it is offered only because it was in the original script and
# somebody may still want it.
# The current LTS major, asked of nodejs.org rather than hardcoded. The original
# pinned setup_22.x, which ages into "the version we happened to pick" the moment
# a new LTS lands.
node_lts_major() {
curl -fsSL https://nodejs.org/dist/index.json 2>/dev/null |
jq -r '[.[] | select(.lts != false)][0].version // empty' | sed 's/^v//; s/\..*//'
}
node_lts_label() {
curl -fsSL https://nodejs.org/dist/index.json 2>/dev/null |
jq -r '[.[] | select(.lts != false)][0] | "\(.version) (\(.lts))" // empty'
}
node_installed_major() { node -v 2>/dev/null | sed 's/^v//; s/\..*//'; }
install_node() {
local major="$1"
# NodeSource publishes one setup script per major. Checked before it is piped
# into a shell, because a 404 page piped to bash is a confusing way to fail.
curl -fsS -o /dev/null "https://deb.nodesource.com/setup_${major}.x" || {
warn "NodeSource has no setup script for Node ${major}"
return 1
}
curl -fsSL "https://deb.nodesource.com/setup_${major}.x" | bash - >/dev/null 2>&1
pkg_install_now nodejs
# Global installs land in /usr/local rather than in a path only root can write,
# so `npm i -g` works the same for the owner and for root.
npm config set prefix /usr/local >/dev/null 2>&1 || true
}
bun_installed() { command -v bun &>/dev/null; }
# Installed as the account, then symlinked system-wide. pm2 started at boot by
# systemd has no login shell and therefore no ~/.bun/bin on PATH — without the
# symlink every bun-based sidecar fails to start on reboot and works fine when
# started by hand, which is a miserable thing to debug.
install_bun() {
(cd / && sudo -H -u "$USERNAME" bash -c 'curl -fsSL https://bun.sh/install | bash') >/dev/null 2>&1
local bin="${USER_HOME}/.bun/bin/bun"
[[ -x "$bin" ]] || return 1
ln -sf "$bin" /usr/local/bin/bun
}
pm2_installed() { command -v pm2 &>/dev/null; }
install_pm2() { npm install -g pm2 >/dev/null 2>&1; }
deno_installed() { command -v deno &>/dev/null || [[ -x "${USER_HOME}/.deno/bin/deno" ]]; }
install_deno() {
(cd / && sudo -H -u "$USERNAME" bash -c 'curl -fsSL https://deno.land/install.sh | sh') >/dev/null 2>&1
[[ -x "${USER_HOME}/.deno/bin/deno" ]]
}