From 07901c7612bd6106f61534fe84d42cee0bc9f675 Mon Sep 17 00:00:00 2001 From: Tomasz Mazur Date: Sun, 30 Aug 2026 22:01:36 +0200 Subject: [PATCH] feat: install the mounted project's pinned tools at provision time #12 made mise read the project's mise.toml; this installs what it asks for. mise auto-installs a missing tool the first time a shim runs it (auto_install defaults to true), so the versions were never permanently absent -- the problem is when they arrive. Left alone, the download lands on whoever first types `ruby`, minutes after orbx reported the machine ready, with nothing on the provisioning log they were watching. An agent driving `orbx run` cannot tell that from a hang, and the first person to hit it in practice just ran `mise install` by hand, which is precisely the step automated here. The project path is discovered rather than passed in: this template never learns it, since orbx::mount_target only rewrites paths under $HOME and a project outside it keeps an absolute path the template cannot guess. OrbStack surfaces every host share as a virtiofs mount, so the mount table is exactly the set of directories that came from the host. That same table is how the trust gap noted in #12 could later be closed, but this change deliberately leaves trust alone. Reads the project, never writes it. `mise install` resolves versions into ~/.local/share/mise and touches the repo only when lockfiles are enabled, which they are not by default. The mount is the user's real working tree, so it has to come back clean. Verified on a fresh machine pinning ruby 4.0.5, node 24.16.0 and yarn 1.22.22: the provisioning log records the step, `mise ls` reports all three installed with no shim ever invoked and no manual install, an interactive shell warns about nothing, and the host directory is byte-identical afterwards. --- templates/default.yaml | 28 ++++++++++++++++++++++++++++ test/template.bats | 14 ++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/templates/default.yaml b/templates/default.yaml index 712f01f..6dd732c 100644 --- a/templates/default.yaml +++ b/templates/default.yaml @@ -441,6 +441,34 @@ write_files: "$HOME/.local/bin/mise" exec -- git lfs install --skip-repo \ || log "git lfs install failed" + # Install the mounted project's OWN pinned tools, not just the global + # ones above. mise auto-installs a missing tool the first time a shim + # runs it (auto_install defaults to true), so this is not about whether + # the versions ever arrive -- it is about when. Left alone, the download + # lands on whoever first types `ruby`, minutes AFTER orbx reported the + # machine ready, with no output on the provisioning log they were + # watching. An agent driving `orbx run` cannot tell that from a hang. + # Do it here, where the wait is expected and logged. + # + # The project path is discovered rather than passed in: this template + # never learns it (see orbx::mount_target, which only rewrites paths + # under $HOME). OrbStack surfaces every host share as a virtiofs mount, + # and that is exactly the set of directories that came from the host. + # + # Reads the project, never writes it: `mise install` resolves versions + # into ~/.local/share/mise and touches the repo only if lockfiles are + # enabled, which they are not by default. The mount is the user's real + # working tree, so it must come back clean. + while read -r projdir; do + for f in mise.toml .mise.toml .tool-versions; do + [ -f "$projdir/$f" ] || continue + log "Installing project tools pinned by $projdir/$f..." + ( cd "$projdir" && "$HOME/.local/bin/mise" install ) \ + || log "mise install failed in $projdir (continuing)" + break + done + done < <(awk '$3 == "virtiofs" { print $2 }' /proc/mounts) + # Claude Code (native installer -- self-updating, no Node dependency). # Alternative: mise exec -- npm install -g @anthropic-ai/claude-code log "Installing Claude Code..." diff --git a/test/template.bats b/test/template.bats index cdbb52f..9586b4e 100644 --- a/test/template.bats +++ b/test/template.bats @@ -188,6 +188,20 @@ load helpers/test_helper [ "$status" -eq 0 ] } +@test "default template installs the mounted project's pinned tools" { + # Without this the versions still arrive -- mise auto-installs on first shim + # use -- but the download lands minutes after orbx reported ready, off the + # provisioning log, where an agent cannot tell it from a hang. + run grep -E 'cd "\$projdir" && "\$HOME/\.local/bin/mise" install' \ + "$ORBX_TEST_ROOT/templates/default.yaml" + [ "$status" -eq 0 ] + + # The path is discovered from the mount table, never passed in: the template + # does not know where the project landed. + run grep -F 'virtiofs' "$ORBX_TEST_ROOT/templates/default.yaml" + [ "$status" -eq 0 ] +} + @test "default template registers git-lfs filters, not just the binary" { # Installing git-lfs is not enough: until `git lfs install` writes the # clean/smudge filters, cloning an LFS repo silently yields pointer files.