Add install_node (bun-based) installer and service_books lifecycle module #76
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_skills#76
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
hero_books now has docusaurus-based site generation, which needs
bun(and by extensionnode) available on any machine running the stack. Following the existinginstallers.nu/services/*.nupattern, this belongs inhero_skills, not inhero_booksitself.Why hero_skills and not hero_books
The Hero convention is:
hero_skills/tools/modules/installers.nu— shared tool installers (install_base,install_rust,install_ai,install_py). Ecosystem-wide prerequisites.hero_skills/tools/modules/services/service_*.nu— per-service lifecycle (install | start | stop | status) for every Hero service.--start / --stop / --statusonly.bun is not hero_books-specific — future JS tooling (dioxus bindings, hero_whiteboard, etc.) will want it. It's a shared prerequisite.
Scope
1. Add
install_nodetotools/modules/installers.nuexport def install_node []alongsideinstall_rust/install_py.bunvia the official script:curl -fsSL https://bun.sh/install | bash.bunis already on PATH before installing.install_base.2. Include it in
install_coreinstall_nodeto theinstall_coreorchestrator so a base Hero environment always has bun/node available.3. Add or update
tools/modules/services/service_books.nuservice_proxy.nu/service_router.nu.install | start | stop | statussubcommands.install— clone/pull the repo,cargo build --release, and runbun installinside the docusaurus template directory sonode_modulesis primed.start/stop/status— talk to hero_proc like other service modules.4. Wire into
services.nuhero_booksis listed in thebin_map/ service lists (service_completealready references it) and that the newservice_booksmodule is discoverable.Acceptance criteria
install_coreends up withbun --versionandnode --versionboth reporting successfully.service_books installbuilds hero_books and primes the docusaurus template'snode_modules.service_books startlaunches hero_books via hero_proc;service_books statusreports its state;service_books stopcleanly terminates it.install_nodeon a system that already has bun is a no-op (no reinstall).--start / --stop / --statusonly.Optional split
If the reviewer load is heavy, split into two PRs:
install_node+ inclusion ininstall_core.service_books.nuandservices.nuwiring.Prefer a single PR unless review bandwidth is the bottleneck.
Dependency order
Independent of the hero_books work. Unblocks anyone provisioning a fresh environment and running the full stack.
not correct,
the install can be done in service_books ...
there we can check if bun is there
in installers/... we can make a reusable installer for bun, we can reuse in service_books
Implementation Spec for Issue #76
Objective
Add a reusable, idempotent
install_bunfunction to the Hero Shell installers module, and wireservice_books installto use it (after awhich buncheck) before runningbun installin the docusaurus template directory shipped with hero_books. Per maintainer feedback, bun is NOT added toinstall_core— it is pulled in on demand only by services that need it.Requirements
install_bunexported function intools/modules/installers/installers.nu.bunis already on PATH (i.e.which bun | is-not-empty).brew install oven-sh/bun/bunwhenbrewis available, falling back to the official curl script. On Linux use the officialcurl -fsSL https://bun.sh/install | bashscript. Mirrors the platform-branching pattern used byinstall_chrome/install_onnxruntime.bunis on PATH after install; raises an actionableerror makeif not (the bun installer drops shims into~/.bun/binand appends to~/.bashrc/~/.zshrc; within the same nushell session PATH won't auto-update, so we additionally check~/.bun/bin/bunexists as a fallback before erroring).printoutput, no emojis, no AI attribution.install_coreis NOT modified (rejects original ask).install_bunstands on its own and is callable directly.service_books installcallsinstall_bunifbunis not on PATH, then runsbun installin the docusaurus template directory.{forge_local}/crates/hero_books_docusaurus/src/template_fileswhereforge_localcomes fromforge_ensure_local "lhumina_code/hero_books". This directory containspackage.jsondeclaring@docusaurus/coreand"packageManager": "bun@1.2.5".svc_cargo_installstep (since the source tree must be present).bun installstep idempotently whennode_modulesalready exists in the template_files dir AND--resetwas not passed.which bunfirst, falling back to~/.bun/bin/bun(same-session PATH limitation noted above).template_install_bunintools/modules/installers/template_install.nuis left unchanged. It targets~template/.bunvia thetemplate_runsudo wrapper and the newinstall_buntargets the invoking user's$HOME— they are not interchangeable.packages.nuline 73 (service_booksinstall commented out) is left unchanged. Activatingservice_install_allfor hero_books is out of scope here.Files to Modify/Create
tools/modules/installers/installers.nu— addinstall_bunfunction. Do NOT add it toinstall_core.tools/modules/services/service_books.nu— at the end ofinstall, callinstall_bun(only ifbunmissing) and then runbun installin the docusaurus template_files directory. Add theuse ../installers/installers.nu [install_bun]import at the top.(No new files. No changes to
mod.nu,packages.nu, ortemplate_install.nu.)Implementation Plan
Step 1: Add reusable
install_bunto installers.nuFiles:
tools/modules/installers/installers.nuSubtasks:
install_aifunction add a new exported functioninstall_bun.which bun | is-not-empty, print"bun already installed: <version>"andreturn.which brew | is-not-empty, run^brew install oven-sh/bun/bun. Otherwise fall through to the curl path.^bash -c "curl -fsSL https://bun.sh/install | bash".which bun; if still empty, also check($env.HOME)/.bun/bin/bunexists. If neither resolves, raiseerror makewith:"bun installer exited 0 but 'bun' not on PATH. Open a new shell (or source ~/.bashrc / ~/.zshrc) so ~/.bun/bin is on PATH, then re-run."."bun installed: <version-or-path>".service_books installfor the docusaurus template build, intentionally NOT ininstall_core.install_bundoes NOT appear in theinstall_corebody.Dependencies: none.
Step 2: Wire bun bootstrap +
bun installinto service_books installFiles:
tools/modules/services/service_books.nuSubtasks:
use ../installers/installers.nu [install_bun].installfunction (after thesvc_cargo_install ...call), add a docusaurus bootstrap block:let docs_dir = $"($info.path)/crates/hero_books_docusaurus/src/template_files".($docs_dir | path exists); if not, print a warning andreturn.node_modulesexists andnot $reset, print explanatory line andreturn.which bun | is-empty, print and callinstall_bun.let bun_exec = if (which bun | is-not-empty) { "bun" } else { $"($env.HOME)/.bun/bin/bun" }.bun installin the docusaurus directory; check exit code anderror makewith stderr on failure.Dependencies: Step 1 (uses
install_bun).Acceptance Criteria
install_bunexists ininstallers.nu, is exported, and is idempotent.install_bunworks on macOS (via brew when available) and Linux (via curl script).install_bunraises a clear error if installer succeeds butbunis unreachable.install_coredoes NOT callinstall_bun.service_books installon a fresh machine without bun: detects missing bun, callsinstall_bun, then runsbun installin<hero_books>/crates/hero_books_docusaurus/src/template_files, populatingnode_modules.service_books installon a machine where bun and node_modules already exist: skips both with explanatory print lines (idempotent).service_books install --resetre-runsbun installeven whennode_modulesexists.template_install_bunintemplate_install.nuremains unchanged.Notes
~/.bashrc/~/.zshrc. Within the same nushell session,which bunmay still return empty after install — Step 2 falls back to~/.bun/bin/bunfor the immediatebun installinvocation.package.json(Docusaurus 3.7.0,"packageManager": "bun@1.2.5"),docusaurus.config.ts,sidebars.ts, andbuild.sh/develop.sh.installalready accepts--reset; reuse that flag to drive thebun installre-run.forge_ensure_localis the source of truth for the local hero_books path. Do not hard-code paths./opt/homebrew/bin/bunends up on PATH automatically); on Linux the curl path requires the fallback to~/.bun/bin/bun.Test Results
This is a nushell-module change in
hero_skills; there is nocargo testhere. Validation done:Parse / load checks (local)
tools/modules/installers/installers.nunu -c "use installers.nu install_bun; help install_bun"tools/modules/services/service_books.nunu -c "use service_books.nu; help service_books install"use installers.nu *; use service_books.nu; print 'modules load ok'Static checks
install_corebody (lines 370–405) verified unchanged —install_bunnot called from it.template_install_bunintemplate_install.nuverified unchanged.tools/modules/services/packages.nuverified unchanged (the commented-outservice_booksentry stays commented).tools/modules/services/mod.nuunchanged.is_macos/is_linuxadded to theuse ../platform.nu [...]import list ininstallers.nuso the new code (and pre-existinginstall_chrome/install_onnxruntime/install_docker_btrfscalls) resolve them cleanly.Behavioral coverage (by code reading)
install_bunreturns early whenwhich bun | is-not-empty(idempotent).brew install oven-sh/bun/bunwhen brew is on PATH; falls through to the curl script otherwise.curl -fsSL https://bun.sh/install | bashscript.~/.bun/bin/bunwhenwhich bunis still empty in the same shell session (PATH not refreshed yet).error makewith an actionable message when neither resolves.service_books installskips the docusaurus block whentemplate_files/is missing.bun installwhennode_modules/exists and--resetis not passed.install_bunonly whenwhich bun | is-empty.bun_execto eitherbun(PATH) or~/.bun/bin/bun(fresh install) before runningbun install.bun installexits non-zero.Not run here
service_books installagainst a real hero_books checkout is not done in this PR — that requires a writable hero_books clone and is best validated on a target host whereservice_books installis actually invoked.Implementation Summary
Implemented per the spec above and the maintainer's design feedback.
Files Changed
tools/modules/installers/installers.nuinstall_bunfunction (~38 lines afterinstall_ai). Addedis_macos,is_linuxto the existinguse ../platform.nu [...]import.tools/modules/services/service_books.nuuse ../installers/installers.nu [install_bun]at the top. Updatedinstalldocstring. Appended a docusaurus bootstrap block at the end ofinstall(~33 lines).Files Intentionally NOT Changed
installers.nu::install_core— bun is NOT added (per maintainer feedback: services pull bun on demand).installers/template_install.nu::template_install_bun— left as-is (template-user-only viatemplate_runwrapper; not interchangeable with the new reusable installer).services/packages.nu— the commented-outservice_booksentry stays commented; activatingservice_install_allfor hero_books is out of scope here.services/mod.nu— already re-exportsservice_books, no changes needed.Behavior
install_bun(reusable, callable from anywhere):returns early with version line ifbunis already on PATH.brew install oven-sh/bun/bunif brew is present, otherwise falls through to the curl script.curl -fsSL https://bun.sh/install | bash.~/.bun/bin/bun(since the bun installer modifies~/.bashrc/~/.zshrc, and the same nushell session won't see the new PATH until restarted).error makeif neitherwhich bunnor~/.bun/bin/bunresolves after the install.service_books install(extends the existing flow):svc_cargo_install:<info.path>/crates/hero_books_docusaurus/src/template_files.node_modules/exists and--resetwas not passed.install_bunonly whenwhich bunis empty.bun install(resolved viawhich bunor~/.bun/bin/bunfallback) inside the docusaurus directory.bun installexits non-zero.Acceptance Criteria — Status
install_bunexists ininstallers.nu, is exported, idempotent.bunis unreachable.install_coredoes NOT callinstall_bun(verified —install_corebody unchanged).service_books installon a fresh machine without bun: detects missing bun → callsinstall_bun→ runsbun installin the docusaurus template_files dir.service_books installon a machine with bun andnode_modulespresent: skips both with print lines (idempotent).service_books install --resetre-runsbun installeven whennode_modulesexists (uses the existing--resetflag, no new flag introduced).template_install_bununchanged.Notes / Caveats
service_books installagainst a real hero_books checkout was not done — this is best validated on a target host where the command is actually invoked. Local parse / load checks all pass.is_macos/is_linuxto theuse ../platform.nu [...]import line was needed because the existinginstall_chrome/install_onnxruntime/install_docker_btrfsfunctions also callis_macoswithout it being in scope — a latent bug that would have surfaced on macOS deploys. Fixing it here keepsinstall_buncorrect and patches the existing functions for free.Closing — implementation landed in PR #137 ("Support bun installer"), merged 2026-04-26 14:49 UTC.
Verified on
origin/development:tools/modules/installers/installers.nu:113—export def install_bun [](idempotent; macOS via brew or curl fallback; Linux via curl;~/.bun/bin/bunpost-install fallback).tools/modules/services/service_books.nu:54,217-218—service_books installcallsinstall_bunon demand whenbunis not on PATH, then runsbun installinside the docusaurustemplate_filesdirectory.Per maintainer feedback in the thread,
install_corewas intentionally not changed — services pullbunon demand. All other acceptance criteria from the implementation summary above are satisfied.