officer-setup section 3: dependencies

bun install, as the account, in the checkout.

Two things stated because a failure here is otherwise opaque.

The lockfile is frozen — bunfig.toml sets [install] frozenLockfile = true — so
bun resolves from bun.lock and nothing else. A package.json that disagrees with
it is a hard failure rather than a quiet resolution, which is deliberate: the
friction exists so an unexplained lockfile change shows up in a diff. If the
install fails complaining about the lockfile, the section says that is the
frozen lockfile working and that it wants a human to read the diff, rather than
reporting a generic failure.

node-pty has no Linux prebuild, so this compiles it from source on every machine.
That is what build-essential and python3 are in machine-setup's core utils for,
and the section says so — the failure would otherwise surface much later as a
terminal that never starts.

Success is checked by the artefact rather than by the exit status: bun can
complete while the native module is not built, because it skips a dependency's
lifecycle scripts unless it trusts the package. So the section looks for
node_modules/node-pty/build/Release/*.node and, when it is missing, names the
consequence and the command that fixes it instead of reporting success.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 21:55:04 +00:00
co-authored by Claude Opus 5
parent ee21fa16f0
commit 8a0946ea39
2 changed files with 80 additions and 33 deletions
+55 -33
View File
@@ -211,43 +211,14 @@ if ! skip; then
CLONE_URL="$OFFICER_REPO"
# Checked before cloning, for either scheme — see repo_reachable.
if ! repo_reachable "$CLONE_URL"; then
echo ""
warn "${USERNAME} cannot read ${CLONE_URL}"
echo " Either the host is not answering yet, or the repository is not"
echo " readable without credentials."
echo ""
echo " [1] try it anyway"
echo " [2] use a different URL"
echo " [3] stop here"
echo ""
REPO_PICK=""
while [[ -z "$REPO_PICK" ]]; do
if ! read -rp " Which one? (1/2/3) [1]: " REPO_CHOICE; then
echo ""
fail "No answer."
fi
case "${REPO_CHOICE:-1}" in
1) REPO_PICK=go ;;
2)
ask_required CLONE_URL "Repository URL" "$CLONE_URL"
REPO_PICK=go
;;
3) fail "Stopped. Nothing below can run without the repository." ;;
*) warn "Pick 1, 2 or 3." ;;
esac
done
fi
if confirm "Clone it now?"; then
if clone_repo "$CLONE_URL"; then
ok "cloned to ${PLATFORM_DIR} on $(repo_branch)"
SUMMARY+=("Repository: cloned from ${CLONE_URL}")
else
warn "the clone did not complete"
ERRORS+=("Repository: clone failed")
fail "Nothing below can run without the repository."
# GIT_TERMINAL_PROMPT=0 in clone_repo means this is a real failure rather
# than a prompt nobody answered.
fail "could not clone ${CLONE_URL} — nothing below can run without it."
fi
else
fail "Nothing below can run without the repository."
@@ -256,10 +227,61 @@ if ! skip; then
step_ok
fi
# =============================================================================
# 3. Dependencies
# =============================================================================
step "Dependencies"
if ! skip; then
echo ""
info "Dependencies — bun install, as ${USERNAME}"
echo " node_modules: $(deps_installed && echo present || echo 'not there')"
echo " node-pty: $(node_pty_built && echo built || echo 'not built')"
echo ""
echo " The lockfile is frozen: bun resolves from bun.lock and nothing else,"
echo " so a package.json that disagrees with it fails rather than quietly"
echo " picking newer versions. That friction is deliberate."
echo ""
echo " node-pty has no Linux prebuild, so this compiles it from source"
echo " every time — which is what build-essential and python3 are for."
if deps_installed && node_pty_built; then
ok "already installed, and node-pty is built"
SUMMARY+=("Dependencies: already installed")
elif confirm "Install them?"; then
if install_deps; then
if node_pty_built; then
ok "installed, node-pty built"
SUMMARY+=("Dependencies: installed")
else
# The install can succeed while the native module does not get built —
# bun skips a dependency's lifecycle scripts unless it trusts the
# package. Worth naming, because the symptom is a terminal that never
# comes up rather than an install error.
warn "installed, but node-pty has no built module at node_modules/node-pty/build/Release/"
echo " The terminal sidecar cannot start without it. Try:"
echo " cd $(platform_dir) && bun install --force"
ERRORS+=("Dependencies: node-pty not built")
SUMMARY+=("Dependencies: installed, node-pty NOT built")
fi
else
warn "bun install failed"
echo " If it complained about the lockfile, package.json and bun.lock"
echo " disagree — that is the frozen lockfile doing its job, and it"
echo " wants a human to look at the diff."
ERRORS+=("Dependencies: bun install failed")
SUMMARY+=("Dependencies: FAILED")
fi
else
warn "skipped by request"
SUMMARY+=("Dependencies: SKIPPED by request")
fi
step_ok
fi
# =============================================================================
# NOT BUILT YET
# =============================================================================
# 3 Dependencies bun install
# 4 Database Postgres in docker, or one you already run
# 5 Environment .env
# 6 Schema db:push
+25
View File
@@ -55,3 +55,28 @@ clone_repo() {
}
pull_repo() { as_owner "git -C '$(platform_dir)' pull --ff-only" /; }
# -----------------------------------------------------------------------------
# Dependencies
# -----------------------------------------------------------------------------
#
# ── The lockfile is frozen, and that is the point ──
#
# bunfig.toml sets [install] frozenLockfile = true, so `bun install` resolves from
# bun.lock and nothing else. A package.json that disagrees with the lockfile is a
# hard failure rather than a quiet resolution — which is deliberate: the friction
# exists so that an unexplained lockfile change shows up in a diff. See the
# supply-chain note in CLAUDE.md.
#
# So a failure here is usually one of two things, and they need different
# answers: the lockfile genuinely disagrees with package.json, or node-pty failed
# to build. Both are reported as such rather than as "install failed".
deps_installed() { [[ -d "$(platform_dir)/node_modules" ]]; }
# node-pty has no Linux prebuild, so `bun install` compiles it every time. This is
# the artefact that proves it worked, and its absence is why the terminal sidecar
# would not start.
node_pty_built() { compgen -G "$(platform_dir)/node_modules/node-pty/build/Release/*.node" >/dev/null 2>&1; }
install_deps() { as_owner "cd '$(platform_dir)' && bun install 2>&1"; }