Skip to content

fix(updater): preserve bleeding-edge setup state - #218

Merged
Nat3z merged 2 commits into
mainfrom
fix/updater-bleeding-edge-flow
Aug 5, 2026
Merged

fix(updater): preserve bleeding-edge setup state#218
Nat3z merged 2 commits into
mainfrom
fix/updater-bleeding-edge-flow

Conversation

@Nat3z

@Nat3z Nat3z commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Description

Persist bleeding-edge branch and commit selection before setup begins, surface setup failures in a native popup, and stop silently launching the previous stable build. Cached repositories now rebase onto the fetched branch first, then stash dirty files and force-align only when rebase cannot complete.

Example

fetch -> checkout -> rebase
                     \ failure -> abort -> stash -> force-align

Next Steps

  • Validate an interactive bleeding-edge build on Linux and Windows.
  • Confirm retrying from the channel picker preserves the selected target.

Summary by CodeRabbit

  • New Features

    • Improved bleeding-edge version setup with normalized branch and commit selections.
    • Selected bleeding-edge versions are saved before building, enabling clearer recovery when builds fail.
    • Added retry handling and consistent error reporting during bleeding-edge setup.
  • Bug Fixes

    • Improved synchronization by rebasing local changes onto remote branches when possible.
    • Safer recovery now preserves tracked and untracked work before aligning with the remote version.
    • Added clearer handling for missing or invalid remote branches.

@Nat3z

Nat3z commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

Review complete for PR #218.

I've submitted my review as a GitHub PR review.

@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
open-game-installer-web Ready Ready Preview Aug 5, 2026 4:19am

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c7c118ff-5e79-4ac4-986f-0ce0240cea01

📥 Commits

Reviewing files that changed from the base of the PR and between ca0c76e and b5ce497.

📒 Files selected for processing (5)
  • updater/src/bleeding-edge-flow.ts
  • updater/src/git-sync.ts
  • updater/src/main.ts
  • updater/test/bleeding-edge-flow.test.ts
  • updater/test/git-sync.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • updater/src/main.ts

📝 Walkthrough

Walkthrough

Changes

The updater adds normalized bleeding-edge selection and persists it before building. GUI and non-GUI setup failures use centralized handling. Git synchronization now verifies remote branches, rebases local branches, and recovers failed synchronization by stashing and force-aligning.

Updater flow

Layer / File(s) Summary
Bleeding-edge selection workflow
updater/src/bleeding-edge-flow.ts, updater/test/bleeding-edge-flow.test.ts
Defines BleedingEdgeSelection, normalizes branch and commit inputs, persists selections before building, and tests failure ordering.
Bleeding-edge setup integration
updater/src/main.ts
Routes GUI and non-GUI bleeding-edge setup through the shared workflow and error handling. GUI setup retries after failures.
Git synchronization recovery
updater/src/git-sync.ts, updater/test/git-sync.test.ts
Verifies remote branches, checks out or creates target branches, rebases local changes, and stashes files before recovery alignment when needed.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GUI
  participant main
  participant selectAndBuildBleedingEdge
  participant persist
  participant build
  participant setupErrorDialog
  GUI->>main: choose bleeding-edge channel
  main->>selectAndBuildBleedingEdge: submit normalized selection
  selectAndBuildBleedingEdge->>persist: save selection
  persist-->>selectAndBuildBleedingEdge: persistence result
  selectAndBuildBleedingEdge->>build: build selection
  build-->>selectAndBuildBleedingEdge: build result or error
  selectAndBuildBleedingEdge-->>main: setup result
  main->>setupErrorDialog: display setup error
Loading
sequenceDiagram
  participant GitSync
  participant fetchedRemoteBranch
  participant targetBranch
  participant stash
  GitSync->>fetchedRemoteBranch: verify selected remote branch
  GitSync->>targetBranch: checkout or create tracking branch
  GitSync->>targetBranch: rebase onto fetched remote branch
  targetBranch-->>GitSync: synchronization result
  GitSync->>stash: stash tracked and untracked files after failure
  GitSync->>targetBranch: force-align with fetched remote branch
Loading

Suggested reviewers: nat-openclaw

Poem

A rabbit trims branches neat,
Saves one choice before the beat.
Git rebases, stashes near,
Errors hop where paths are clear.
“Build,” says Bun, “then we leap!”

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: preserving bleeding-edge setup state during updater initialization.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/updater-bleeding-edge-flow

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.

@nat-openclaw
nat-openclaw force-pushed the fix/updater-bleeding-edge-flow branch from 9bfdfa0 to 0072b32 Compare August 5, 2026 04:08
@Nat3z

Nat3z commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

Review by @nat-openclaw

Summary

The updater changes look solid: they fix the silent launch-on-failure bug, persist bleeding-edge selection before the build starts, and replace blunt force-checkout with a sensible rebase-then-recover flow. Integration tests cover the main git-sync paths.

Verdict

0 critical, 0 important, 0 nits

What Looks Good

  • Early return after setup failure stops launchApp(true) from running on a failed bleeding-edge build — the core bug this
  • Integration tests cover force-push recovery, successful rebase of local commits, and dirty-tree stash-before-align.

Findings (0)

No findings.

@Nat3z

Nat3z commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

I hit an infra error before I could finish:

git worktree add -b pr-agent/pr-218-pr-218-1785902907985-4b9ogh /home/nat/github-pr-agent-work/Nat3z/OpenGameInstaller/.worktrees/pr-218-1785902907985-4b9ogh refs/remotes/pr-head-218/fix/updater-bleeding-edge-flow failed with 128
fatal: invalid reference: refs/remotes/pr-head-218/fix/updater-bleeding-edge-flow

React to this comment with 🚀 to retry.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@updater/src/git-sync.ts`:
- Around line 72-120: The rebase recovery branch currently also handles failed
branch creation, causing force-alignment to run when the remote target branch
may not exist. Update the checkout/rebase flow around checkoutExisting,
checkoutResult, and rebaseResult so recovery and stash/force-align execute only
when an actual rebase fails; preserve and return the checkout error when both
checkout attempts fail.

In `@updater/src/main.ts`:
- Around line 1137-1140: Update the build failure branch in the createWindow
flow around showBleedingEdgeSetupError so a failed GUI setup re-arms the
choose-channel IPC listener before showing the channel picker. Preserve the
existing error display and return behavior, while ensuring the retry choice
starts the build flow again.
- Around line 1123-1126: Update the selection construction so the branch value
is trimmed before fallback evaluation, ensuring whitespace-only input uses
DEFAULT_BLEEDING_EDGE_BRANCH instead of persisting an empty string; preserve the
existing commit normalization and selection behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2adb889d-d1b5-4586-aa5f-5aea957f6bed

📥 Commits

Reviewing files that changed from the base of the PR and between ca0c76e and 9bfdfa0.

📒 Files selected for processing (14)
  • updater/src/bleeding-edge-flow.ts
  • updater/src/git-sync.ts
  • updater/src/main.ts
  • updater/test/bleeding-edge-flow.test.ts
  • updater/test/git-sync.test.ts
  • web/community/fatboy-unpack.md
  • web/community/gemini-search.md
  • web/community/steam-integration.md
  • web/community/steamrip-addon.md
  • web/community/template.md
  • web/src/lib/community-addons.ts
  • web/src/pages/api/community.json.ts
  • web/src/pages/community.astro
  • web/src/pages/docs/for-users/community.md
💤 Files with no reviewable changes (5)
  • web/community/steamrip-addon.md
  • web/community/gemini-search.md
  • web/community/steam-integration.md
  • web/community/template.md
  • web/community/fatboy-unpack.md

Comment thread updater/src/git-sync.ts
Comment on lines +72 to +120
const checkoutExisting = yield* Effect.either(
runCommand('git', ['checkout', targetBranch], { cwd: repoDir })
);
const checkoutResult =
checkoutExisting._tag === 'Right'
? checkoutExisting
: yield* Effect.either(
runCommand(
'git',
['checkout', '--track', '-b', targetBranch, remoteBranch],
{ cwd: repoDir }
)
);
const rebaseResult =
checkoutResult._tag === 'Right'
? yield* Effect.either(
runCommand('git', ['rebase', remoteBranch], { cwd: repoDir })
)
: checkoutResult;

if (rebaseResult._tag === 'Left') {
yield* runCommand('git', ['rebase', '--abort'], {
cwd: repoDir,
}).pipe(Effect.ignore);
yield* withOperation(
'stash',
runCommand(
'git',
[
'stash',
'push',
'--include-untracked',
'-m',
'OpenGameInstaller updater recovery',
],
{ cwd: repoDir }
)
);
// Rebase could not safely preserve the cache. Keep dirty files in the
// stash, then force-align the updater branch to the fetched remote.
yield* withOperation(
'checkout',
runCommand(
'git',
['checkout', '--force', '-B', targetBranch, remoteBranch],
{ cwd: repoDir }
)
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect branch selection and all synchronization callers.
ast-grep outline updater/src --items all --type function --match 'syncBleedingEdgeRepo'
rg -n -C 5 '\bsyncBleedingEdgeRepo\s*\(|\btargetBranch\b|\bdefaultBranch\b' updater/src updater/test

# Inspect existing checkout/rebase failure coverage.
rg -n -C 5 "checkout.*--track|rebase.*origin|missing.*branch|stash.*force" updater/test/git-sync.test.ts

Repository: Nat3z/OpenGameInstaller

Length of output: 13511


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== updater/src/git-sync.ts =="
sed -n '40,135p' updater/src/git-sync.ts

echo
echo "== updater/test/git-sync.test.ts recovery tests =="
sed -n '120,225p' updater/test/git-sync.test.ts

echo
echo "== git commands referenced in relevant source/test =="
python3 - <<'PY'
from pathlib import Path
for p in [Path('updater/src/git-sync.ts'), Path('updater/test/git-sync.test.ts')]:
    print(f'-- {p} --')
    for i,line in enumerate(p.read_text().splitlines(),1):
        if any(x in line for x in ['runCommand(', 'git', 'checkout', 'rebase', 'stash']):
            print(f'{i}: {line}')
PY

Repository: Nat3z/OpenGameInstaller

Length of output: 9960


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== All branch-sync tests in updater/test/git-sync.test.ts =="
python3 - <<'PY'
from pathlib import Path
text = Path('updater/test/git-sync.test.ts').read_text().splitlines()
in_test = False
start = None
for i,line in enumerate(text,1):
    if line.startswith('test(') or line.startswith('describe('):
        if in_test and start:
            print(f'{start}-{i-1}: {text[start-1]}')
        print(f'{i}: {line}')
        in_test = True
        start = i
    elif in_test and start and (line.startswith('});') and text[max(1,i-4):i]) <= 10):
        pass
if in_test and start:
    print(f'{start}-{len(text)}: {text[start-1]}')
PY

echo
echo "== Existing "missing branch"/"removed branch"/"origin/main" missing scenarios =="
rg -n -C 4 "missing|removed|deleted|no such|fatal|origin/main|origin/.*/'" updater/test/git-sync.test.ts

echo
echo "== runCommand failure handling =="
sed -n '20,55p' updater/test/git-sync.test.ts

echo
echo "== Deterministic path outline for current branch selection code =="
python3 - <<'PY'
paths = []
for checkout_existing_tag in ["Left", "Right"]:
    paths.append({"initial_existing_checkout": checkout_existing_tag})
    if checkout_existing_tag == "Left":
        paths[-1]["new_checkout_tag"] = "Left"
        paths[-1].update({"rebase_result_tag": "Left", "path": "stash abort, stash push, checkout --force -B"})
        paths.append({"initial_existing_checkout": checkout_existing_tag})
        paths[-1]["new_checkout_tag"] = "Right"
        paths[-1].update({"rebase_result_tag": "Right", "path": "no stash/force-align"})
    else:
        paths.append({"initial_existing_checkout": checkout_existing_tag})
        paths[-1]["new_checkout_tag"] = "Right"
        paths[-1].update({"rebase_result_tag": "Left", "path": "stash abort, stash push, checkout --force -B"})
        paths.append({"initial_existing_checkout": checkout_existing_tag})
        paths[-1]["new_checkout_tag"] = "Left"
        paths[-1].update({"rebase_result_tag": "Left", "path": "checkout --track failed -> checkoutResult = Left; rebaseResult = checkoutResult -> stash abort, stash push, checkout --force -B"})
for p in paths:
    print(p)
PY

Repository: Nat3z/OpenGameInstaller

Length of output: 448


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== updater/test/git-sync.test.ts line count and tests summary =="
wc -l updater/test/git-sync.test.ts
python3 - <<'PY'
from pathlib import Path
lines = Path('updater/test/git-sync.test.ts').read_text().splitlines()
for i,line in enumerate(lines,1):
    if line.startswith('test('):
        print(f'{i}: {line[:180]}')
PY

echo
echo "== Exact branch-related tests around current suite =="
sed -n '60,195p' updater/test/git-sync.test.ts

echo
echo "== Failure handling in runCommand helper =="
sed -n '30,60p' updater/test/git-sync.test.ts

echo
echo "== Static path analysis for current code shape =="
python3 - <<'PY'
cases = []
for checkout_existing in ["Left", "Right"]:
    if checkout_existing == "Left":
        checkout_track = "Left"
        cases.append({
            "checkout_existing": checkout_existing,
            "checkout_track": checkout_track,
            "rebase_result": checkout_track,
            "stash_abort": True,
            "stash_push": True,
            "force_checkout": checkout_track,
            "path": "checkout --track targetBranch refs/remotes/origin/targetBranch fails -> stash abort, stash push, checkout --force -B targetBranch refs/remotes/origin/targetBranch fails",
        })
        cases.append({
            "checkout_existing": checkout_existing,
            "checkout_track": "Right",
            "rebase_result": "Right",
            "stash_abort": False,
            "stash_push": False,
            "force_checkout": False,
            "path": "checkout existing fails; checkout --track succeeds; no rebase -> no recovery",
        })
    else:
        cases.append({
            "checkout_existing": checkout_existing,
            "checkout_track": "Right",
            "rebase_result": "Left",
            "stash_abort": True,
            "stash_push": True,
            "force_checkout": "Right",
            "path": "checkout existing succeeds; rebase fails -> stash abort, stash push, checkout --force -B targetBranch refs/remotes/origin/targetBranch",
        })
        cases.append({
            "checkout_existing": checkout_existing,
            "checkout_track": "Left",
            "rebase_result": "Left",
            "stash_abort": True,
            "stash_push": True,
            "force_checkout": checkout_track,
            "path": "checkout existing succeeds; rebase not attempted because branch cannot start?; rebaseResult = Left? path = stash abort, stash push, checkout --force -B targetBranch refs/remotes/origin/targetBranch fails",
        })
for c in cases:
    print(c)
PY

Repository: Nat3z/OpenGameInstaller

Length of output: 7582


Separate checkout failure from rebase recovery.

rebaseResult can hold a failed checkout --track result. The rebaseResult._tag === 'Left' path then stashes dirty files and attempts checkout --force -B targetBranch remoteBranch, which also fails when origin/${targetBranch} is missing. Preserve the checkout error for return, or start force-align only after the rebase itself fails.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@updater/src/git-sync.ts` around lines 72 - 120, The rebase recovery branch
currently also handles failed branch creation, causing force-alignment to run
when the remote target branch may not exist. Update the checkout/rebase flow
around checkoutExisting, checkoutResult, and rebaseResult so recovery and
stash/force-align execute only when an actual rebase fails; preserve and return
the checkout error when both checkout attempts fail.

Comment thread updater/src/main.ts Outdated
Comment thread updater/src/main.ts Outdated
@greptile-apps

greptile-apps Bot commented Aug 5, 2026

Copy link
Copy Markdown

Greptile Summary

The PR preserves the selected bleeding-edge target before setup, keeps the GUI channel picker active after setup failures, and changes cached-repository synchronization to attempt a rebase before recovery.

  • Adds normalized bleeding-edge selection and persist-before-build sequencing.
  • Reinstalls the channel-choice listener for every GUI retry and reports setup failures through a native dialog.
  • Rebases cached branches onto the fetched remote, falling back to stash and force-alignment when necessary.
  • Adds focused tests for selection persistence and Git synchronization recovery.

Confidence Score: 5/5

The PR appears safe to merge.

The previously reported retry failure is resolved because each loop iteration registers a new one-shot channel listener before redisplaying the picker, and no blocking failure remains.

Important Files Changed

Filename Overview
updater/src/main.ts Reworks GUI channel selection into a retry loop that registers a fresh listener before each picker display, persists bleeding-edge targets before building, and stops fallback launches after setup failures.
updater/src/bleeding-edge-flow.ts Introduces selection normalization and an Effect-based persist-before-build sequence.
updater/src/git-sync.ts Replaces unconditional branch reset with remote verification, checkout and rebase, followed by stash-and-force recovery on failure.
updater/test/bleeding-edge-flow.test.ts Verifies default-branch normalization and persistence ordering when a build fails.
updater/test/git-sync.test.ts Adds coverage for successful rebases, dirty-cache recovery, missing remotes, and detached-cache fallback.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Show channel picker] --> B[Wait for channel choice]
    B --> C{Selected channel}
    C -->|Stable or unstable| D[Persist channel state]
    D --> E[Continue updater flow]
    C -->|Bleeding edge| F[Persist branch and commit]
    F --> G[Build selected target]
    G -->|Success| H[Launch application]
    G -->|Failure| I[Show native error]
    I --> A
Loading

Reviews (2): Last reviewed commit: "fix(updater): address review feedback" | Re-trigger Greptile

Comment thread updater/src/main.ts Outdated
@Nat3z

Nat3z commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@Nat3z
Nat3z merged commit b3c7c08 into main Aug 5, 2026
9 checks passed
@Nat3z
Nat3z deleted the fix/updater-bleeding-edge-flow branch August 5, 2026 04:29
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.

2 participants