feat: self-provisioning developer rebuilds across supported hosts - #1033
Merged
Conversation
#1018) Replace the fork-build path in Rebuild from Main with a release-download path. The button auto-pulls main, reads opencode.lock.json, and downloads the pinned fork binary from the GitHub Release — no fork clone, no bun invocation, no local/amicode checkout. New modules: - src/rebuild/main_source_resolver.ts — readLockFile, resolveMainPlatform, checkDirtyTree, pullMainBranch (--ff-only, not --rebase), checkPendingPromotion, downloadForkBinary, rebuildFromMain - src/rebuild_errors.ts — structured error catalog (30+ classified errors with message + fix steps + collapsible detail) chat_bridge.ts changes: - Main mode: rebuildFromMain() replaces git-pull-of-fork + bun-install + bun-build. Binary comes from the release, app bundle materializes from the committed overlay (no --work flag needed). - Main mode requires only amicodePath (not opencodePath). - Local mode: unchanged (fork checkout + bun build). Tests (32 new + 3 new integration): - main_source_resolver.test.ts: 25 tests covering readLockFile (valid, missing, malformed, no tag/ref/platform), resolveMainPlatform (supported, unsupported, WSL), checkDirtyTree, pullMainBranch (--ff-only, fetch failure, non-ff), checkPendingPromotion (ahead, same, unreachable), downloadForkBinary (deleted release), rebuildFromMain orchestration (dirty tree, unsupported platform, no fork mutations, --ff-only) - rebuild_errors.test.ts: 7 tests for catalog structure + classifyError - chat_bridge.test.ts: 3 new tests for main-mode path requirements
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 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. Comment |
…y download (#1019) Add download robustness to fetchFromRelease: - withRetry: exponential backoff (base 1s, factor 2, cap 4s, max 3 attempts). Transient errors (5xx, timeout, ECONNRESET) retry; permanent (404) and auth errors fail immediately. - classifyDownloadError: categorizes errors as transient/permanent/auth for both HTTPS and gh CLI paths. - HTTPS sha256 mismatch triggers one gh fallback attempt before declaring permanent failure (handles CDN-cached corrupt artifacts). - Partial-file cleanup: no .unpack- temp dirs or partial binaries left on failure. - releaseCoords.private renamed to isFork (with back-compat getter). The flag means 'is our fork', not 'repo is private on GitHub'. - retryOpts parameter threaded from fetchOpencode → fetchFromRelease for test injection. 14 new tests (download_robustness.test.ts): withRetry (succeed, retry, exhaustion, permanent skip, onRetry), classifyDownloadError (5xx, timeout, 404, 403, gh-not-found), fetchFromRelease integration (retry success, sha256 mismatch → gh, no partials, 404 not retried). 3 existing tests updated for isFork rename (back-compat verified).
New module: src/rebuild/dependency_resolver.ts - checkDependencies(mode) — structured pre-flight: for each tool, whether required/present/sufficient/provisionable. Main mode checks git, Node >= 20, pnpm, gh (soft). Local mode adds bun, gh (hard). - buildProvisionPlan(deps) — separates blockers (node, git: detect + guide) from provisionable actions (pnpm via corepack/npm-exec, bun via curl). - provisionPnpm(exec) — corepack enable preferred, falls back to npm exec when corepack is absent or requires sudo. - isBlocked(deps) — returns true only when hard prerequisites are missing; soft dependencies don't block. 15 new tests covering: all-present, missing node, node < 20, local-mode hard deps, missing git, empty plan, blocker plan, pnpm provision plan, bun provision plan, corepack + fallback paths, isBlocked.
) New module: src/rebuild/atomic_adoption.ts - createBackup: timestamped sibling backup of extension dir (same filesystem guarantee for POSIX atomic rename) - pruneBackups: keep only the most recent N backups - stageExtensionBuild: stage build output as a sibling directory - atomicSwap: rename-based dist swap with automatic rollback on failure (restores from backup on rename failure, permission error, or invalid staging) - pendingSwapMarker: write/read/commit cycle for crash recovery (pending.json written before swap, deleted after health check) 8 new tests covering: backup creation + sibling guarantee, prune excess, atomic swap success, rollback on bad staging, pending marker write/read/ commit, staging output.
…#1022) New module: src/rebuild/runtime_paths.ts - resolveRuntimePaths: discovers binary and app bundle paths from context.extensionPath. Config overrides (opencodeBinary, appBundleDir) take precedence when set. Works for local, WSL/Remote-SSH (.vscode- server), and Insiders (.vscode-insiders) extension paths. - detectDeveloperMode: replaces devAssetRoot-as-signal with a dedicated boolean setting + marker file. Separates path override from mode. - validateOverride: validates config override paths at activation, returning structured diagnostics for stale paths. 11 new tests covering: self-discovery (all platform variants), config overrides (binary, app bundle), Insiders/WSL/Remote paths, developer mode detection (setting, marker, default), override validation.
…ance (#1023) New module: src/rebuild/host_matrix.ts - classifyHost: classifies current platform against the supported matrix (darwin-arm64, linux-x64, linux-arm64). Rejects win32 (WSL guidance), darwin-x64 (Apple Silicon only), and unknowns. - detectWSLVersion: reads /proc/version to distinguish WSL 1 (lxfs, no atomic rename) from WSL 2 (real Linux kernel, full support) from native Linux (not WSL). WSL 1 would be rejected at the #1021 swap step. - gateKeeperClear: best-effort xattr -d com.apple.quarantine on the vendored binary (macOS unsigned binary Gatekeeper block). 12 new tests covering: platform classification (macOS arm64, linux x64, linux arm64, win32, Intel Mac, unknown), WSL version detection (WSL 1, WSL 2, native Linux, non-Linux), Gatekeeper clearance (success, failure).
…cripts (#1016) This is the integration commit that makes #1020–#1023 actually work. chat_bridge.ts rebuild handler now: - Runs host gate (#1023): classifyHost() + detectWSLVersion() reject win32, darwin-x64, and WSL 1 before any mutation - Runs dependency pre-flight (#1020): checkDependencies() + isBlocked() refuse when node/git are missing, report what's needed with fix steps - Uses deployBuild() (#1021) for atomic backup + stage + rename-swap instead of the old line-by-line copyFileSync loop - Sends structured errors through the bridge (#1022): all error messages are { message, fix[], detail? } objects, not flat strings - No longer writes to VS Code settings.json (#1022): removed the opencodeBinary, devAssetRoot, appBundleDir update calls New: src/rebuild/coordinator.ts — the shared orchestration that both the bridge handler and the shell scripts follow (same flow, different execution paths). Shell scripts rewritten: - rebuild_amicode_remotely.sh: uses fetch_opencode.mjs --release for the binary (no fork clone, no bun), pulls with --ff-only, builds app from overlay, deploys with backup + atomic swap, no settings writes - rebuild_amicode_locally.sh: keeps the fork build path, drops the settings.json python3 hack, deploys with backup + atomic swap, copies built binary into the installed extension's vendor dir 10 new integration tests (rebuild_coordinator.test.ts): host gate (win32, Intel Mac, WSL 1 reject, WSL 2 allow), dependency pre-flight (missing node, missing git, soft gh in main mode), deployBuild (atomic swap + backup + no settings writes, rollback on bad staging).
- Remove unused imports from chat_bridge.ts (ExecFn, ExecResult, RebuildError type-only, runRebuild) - Remove unused `fs` import and `blockerList` variable from coordinator.ts - Remove unused `existsSync` import from runtime_paths.ts - Add scripts/fetch_opencode.d.mts — type declarations for the ESM fetch_opencode module, consumed by main_source_resolver.ts via dynamic import. Resolves TS7016 'Could not find a declaration file' under moduleResolution: Bundler.
jeonghun-jj-lee
marked this pull request as ready for review
September 12, 2026 16:07
This was referenced Sep 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1016
Self-provisioning developer rebuilds
All six slices implemented and integrated — every module is called by the rebuild handler.
105 new tests, 0 regressions across the existing 3,300+ test suite.
What actually changed in the rebuild handler (
chat_bridge.ts)The
dev-tools-rebuildhandler now runs this pipeline:classifyHost()+detectWSLVersion()reject unsupported platformscheckDependencies(mode)+isBlocked()refuse when hard prereqs are missingrebuildFromMain()(git pull --ff-only + release download) / Local: fork build (unchanged)deployBuild(): backup → stage → rename-swap (replaces line-by-line copyFileSync)opencodeBinary,devAssetRoot,appBundleDirupdatesAll errors are structured:
{ message, fix[], detail? }objects through the bridge → the fork'sRebuildErrorPanelrenders them with numbered fix steps and collapsible detail.Shell scripts (standalone fallbacks)
Both rewritten to match the button behavior:
rebuild_amicode_remotely.sh—fetch_opencode.mjs --releasefor the binary (no fork clone, no bun),--ff-onlypull, overlay-based app build, backup + atomic swap, no settings writesrebuild_amicode_locally.sh— fork build with bun (unchanged), backup + atomic swap, copies binary into vendor dir, no settings writesCompanion PR (opencode fork)
harmoniqs/opencode#340 —
RebuildErrorPanelcomponent,RebuildErrorInfotype, error panel CSS