Skip to content

refactor(install): isolate runtime and script state - #1027

Merged
jdx merged 3 commits into
mainfrom
codex/per-install-state
Jul 13, 2026
Merged

refactor(install): isolate runtime and script state#1027
jdx merged 3 commits into
mainfrom
codex/per-install-state

Conversation

@jdx

@jdx jdx commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • scope Node runtime selection to each explicit install invocation
  • scope lifecycle-script settings to each install instead of replacing the process-wide fallback
  • propagate both contexts into spawned fetch and dependency-lifecycle tasks
  • retain process-wide runtime and script settings for non-install CLI commands

Why

OpenCode starts package installations for independent directories concurrently. PR #1026 made explicit-directory installs and their project locks reentrant, but the install pipeline could still share the selected Node runtime and lifecycle-script settings between projects.

This change removes those remaining mutable snapshots from the concurrent install path. Each install receives its own task-local runtime cell and script-settings slot. Spawned work explicitly inherits the owning install's context, while unrelated installs cannot observe or replace it.

This is a prerequisite for #1025. Once merged, the Node-API addon can remove its addon-wide install mutex and allow independent OpenCode installs to execute in parallel.

Validation

  • cargo fmt --check
  • cargo clippy --all-targets -- -D warnings
  • cargo test
  • parallel runtime and script-context isolation tests
  • parallel explicit-directory and guarded-install tests
  • mise run test:bats test/runtime.bats (23 tests)
  • mise run test:bats test/lifecycle_scripts.bats (42 tests)
  • mise run test:bats test/pnpm_install_hooks.bats (21 tests)

Note

Medium Risk
Touches install orchestration, runtime resolution, and script env for all lifecycle/fetch spawns; behavior change is intentional for concurrency but regressions could affect wrong Node binary or script settings under parallel installs.

Overview
Parallel installs no longer share a single process-wide Node runtime or lifecycle script settings. Each install runs inside nested task-local scopes (runtime, aube_scripts, existing dep_chain), with scope_current on spawned fetch and dependency lifecycle tasks so children inherit the owning install’s context. Non-install CLI commands still use the process-wide fallbacks.

The install entry path is run_scoped, which nests those scopes and Box::pins run_inner to avoid Tokio worker stack overflow when scopes stack. aube runtime set re-reads package.json and resolves the lockfile-pinned runtime for its status line instead of trusting a possibly stale process cache. RuntimeContext is now returned as Arc from current / ensure. Isolation is covered by new multi-thread tests; bats expects node … ready (aube) after aube runtime set.

Reviewed by Cursor Bugbot for commit 06641d9. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@jdx, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 27 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 7d708be1-7420-4e30-bab9-bff5df85acc1

📥 Commits

Reviewing files that changed from the base of the PR and between e23dd6a and 06641d9.

📒 Files selected for processing (7)
  • crates/aube-scripts/src/lib.rs
  • crates/aube/src/commands/install/lifecycle.rs
  • crates/aube/src/commands/install/mod.rs
  • crates/aube/src/commands/runtime.rs
  • crates/aube/src/commands/script_settings.rs
  • crates/aube/src/runtime.rs
  • test/runtime_download.bats

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR scopes the Node runtime selection and lifecycle-script settings to each explicit install invocation using Tokio task-locals, preventing concurrent installs from cross-wiring their contexts while retaining process-wide fallbacks for non-install CLI commands.

  • INSTALL_RUNTIME and INSTALL_SCRIPT_SETTINGS task-locals (each backed by an Arc<OnceCell/RwLock>) are introduced alongside the existing process-wide statics; scope / scope_current follow the correct capture-before-spawn pattern so spawned fetch and lifecycle tasks inherit their owning install's context.
  • run_scoped boxes the install state machine before stacking three task-local scope layers, avoiding the worker-stack overflow observed in parallel-install regression tests.
  • run_set in commands/runtime.rs re-reads the manifest and calls ensure() outside the completed install scope to populate the process-wide RUNTIME for its status message, since the install now never writes to the process-wide cell.

Confidence Score: 5/5

Safe to merge; the isolation mechanism is correctly implemented and the new multi-thread tests validate that concurrent installs cannot observe each other's runtime or script-settings contexts.

All changed paths use established Tokio task-local idioms with correct capture-before-spawn sequencing. The scope_current wrappers are applied consistently across fetch and lifecycle spawn sites. The run_set post-install ensure() call correctly targets the process-wide cell after the install scope has exited, and the bats test now asserts the resulting status message. No logic gaps or missing propagation paths were identified.

No files require special attention.

Important Files Changed

Filename Overview
crates/aube/src/runtime.rs Introduces INSTALL_RUNTIME task-local (Arc) alongside the existing process-wide RUNTIME OnceCell; scope/scope_current follow correct capture-before-spawn pattern; current() correctly prefers the install slot first, then the process-wide fallback.
crates/aube-scripts/src/lib.rs Adds INSTALL_SCRIPT_SETTINGS task-local mirroring the runtime pattern; set_script_settings/script_settings correctly route through the install slot when present and fall back to the process-wide lock; new multi-thread test validates isolation and propagation.
crates/aube/src/commands/install/mod.rs run_scoped boxes the install future before stacking three task-local scopes to avoid worker-stack overflow; fetch handle now propagates both runtime and script-settings contexts; lifecycle.rs wraps dep_chain, runtime, and aube_scripts scopes in sequence.
crates/aube/src/commands/runtime.rs run_set re-reads the manifest and calls ensure() outside the install scope after chained install completes, correctly writing to the process-wide RUNTIME for the status message without touching the now-gone install slot.
crates/aube/src/commands/script_settings.rs Adds as_ref() before both and_then() calls on Option<Arc> to avoid consuming the option on the first use; straightforward correctness fix.
crates/aube/src/commands/install/lifecycle.rs Lifecycle task now stacks dep_chain, runtime, and aube_scripts scope_current wrappers before spawning, propagating all three task-local contexts into child tasks.
test/runtime_download.bats Adds an assert_output check for the "node X.Y.Z ready (aube)" message emitted by run_set, validating the new post-install ensure() path produces the expected output.

Reviews (3): Last reviewed commit: "fix(runtime): restore runtime set status" | Re-trigger Greptile

Comment thread crates/aube/src/commands/install/mod.rs Outdated
Comment thread crates/aube/src/commands/install/mod.rs

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 981a00b. Configure here.

Comment thread crates/aube/src/runtime.rs
@jdx
jdx merged commit 730bc4c into main Jul 13, 2026
18 checks passed
@jdx
jdx deleted the codex/per-install-state branch July 13, 2026 22:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant