Skip to content

fix: native Windows auto-update, PATH cap, and Ctrl+C terminal restore - #124

Merged
KooshaPari merged 2 commits into
mainfrom
fix/windows-updater-fork-main
Aug 2, 2026
Merged

fix: native Windows auto-update, PATH cap, and Ctrl+C terminal restore#124
KooshaPari merged 2 commits into
mainfrom
fix/windows-updater-fork-main

Conversation

@KooshaPari

@KooshaPari KooshaPari commented Aug 2, 2026

Copy link
Copy Markdown
Owner

User description

Summary

Fixes two issues found on the user's machines (Windows auto-update failure + zsh Ctrl+C session corruption). This PR is a fork-internal integration of the fixes ??? not intended for upstream merge.

Changes

1. Windows auto-update: 'curl' is not recognized as an internal or external command

  • crates/forge_main/src/update.rs ??? the updater previously ran curl -fsSL https://forgecode.dev/cli | sh via cmd.exe /C, which is POSIX-only and breaks on native Windows (no sh, and PATH pollution past cmd.exe's ~2 KB resolution limit makes curl unresolvable). Now it branches per-platform: Windows uses a native PowerShell command (absolute powershell.exe path) that downloads forge-{arch}-pc-windows-msvc.exe from GitHub releases and atomically swaps the binary through a detached .cmd helper.
  • crates/forge_infra/src/executor.rs ??? every Windows child process now gets a sanitized PATH: System32, Wbem, and PowerShell v1.0 are always present first, entries are deduped case-insensitively, and the total is capped at 1900 chars. This fixes command resolution for spawned cmd.exe even when the user PATH is polluted beyond the batch-parser limit.

2. zsh Ctrl+C corrupts the session (broken input, raw mode left on)

  • crates/forge_select/src/preview.rs + signal-hook dependency ??? a process-wide SIGINT safety-net flag restores the terminal (cursor, viewport, raw mode) before the picker returns, so Ctrl+C in raw mode can no longer strand the shell with broken input. Coexists with the existing tokio::signal::ctrl_c() in the main UI (signal-hook chains handlers).
  • shell-plugin/lib/helpers.zsh ??? _forge_exec_interactive now runs the interactive forge in its own process group (zle -I, setopt LOCAL_OPTIONS MONITOR, background &, then fg with a fg || wait $! fallback). Ctrl+C targets forge only, never the ZLE widget, so _forge_reset always runs and ZLE state stays clean.
  • shell-plugin/lib/dispatcher.zsh ??? forge-accept-line installs a function-scoped INT trap (setopt LOCAL_TRAPS) that restores the buffer/prompt if a stray signal reaches the widget, auto-clearing on every exit path (including early returns).

Files

  • crates/forge_main/src/update.rs
  • crates/forge_infra/src/executor.rs
  • crates/forge_select/src/preview.rs
  • crates/forge_select/Cargo.toml
  • Cargo.lock
  • shell-plugin/lib/helpers.zsh
  • shell-plugin/lib/dispatcher.zsh

Validation

  • cargo check -p forge_select -p forge_infra -p forge_main ??? passes
  • cargo test -p forge_main --lib update:: ??? passes
  • zsh -n on both modified plugin files ??? passes (rc 0)
  • Windows updater download path validated against the live release asset (forge-x86_64-pc-windows-msvc.exe, valid MZ PE header)
  • Root causes reproduced live on the user's machine (9,772-char PATH breaking cmd.exe command resolution; no signal handler on SIGINT)

CodeAnt-AI Description

Fix Windows updates and prevent terminal corruption after Ctrl+C

What Changed

  • Windows auto-update now downloads the matching release executable and replaces it after Forge exits, instead of running a Unix-only shell installer.
  • Windows child commands receive a cleaned, length-limited PATH so tools such as PowerShell and system utilities remain discoverable.
  • Ctrl+C during interactive Forge actions now isolates the child process and restores the shell prompt, cursor, and terminal input state.
  • The selection interface safely exits and restores the terminal when it receives an interrupt signal.

Impact

✅ Working native Windows auto-updates
✅ Fewer command failures with long Windows PATH values
✅ Usable terminal after Ctrl+C

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Copilot AI review requested due to automatic review settings August 2, 2026 21:03
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@codeant-ai

codeant-ai Bot commented Aug 2, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR 55e8ef0 Aug 02, 2026 · 21:03 21:06

@codeant-ai

codeant-ai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codeant-ai codeant-ai Bot added the size:L label Aug 2, 2026
@mergify mergify Bot added rust labels Aug 2, 2026
Comment on lines +60 to +62
#[cfg(windows)]
if let Some(path) = sanitize_windows_path() {
command.env("PATH", path);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: This replaces the inherited Windows PATH for every shell command and silently drops all entries after the 1900-character cap. Commands relying on a user-installed executable located later in an otherwise valid PATH will now fail, even when no PATH pollution exists. Restrict the sanitized PATH to the updater or preserve required entries through a more targeted resolution strategy. [api mismatch]

Severity Level: Major ⚠️
- ❌ Windows shell commands outside the retained PATH fail to resolve.
- ⚠️ UI shell actions and update-related commands lose user tools.
- ⚠️ Commands after the cap fail only under long PATH configurations.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** crates/forge_infra/src/executor.rs
**Line:** 60:62
**Comment:**
	*Api Mismatch: This replaces the inherited Windows `PATH` for every shell command and silently drops all entries after the 1900-character cap. Commands relying on a user-installed executable located later in an otherwise valid PATH will now fail, even when no PATH pollution exists. Restrict the sanitized PATH to the updater or preserve required entries through a more targeted resolution strategy.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +74 to +77
let primary = std::env::var("HELIOSLITE_UPDATE_URL")
.unwrap_or_else(|_| "https://helioslite.dev/cli".to_string());
let fallback = "https://forgecode.dev/cli";
format!("(curl -fsSL {primary} || curl -fsSL {fallback}) | sh")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Untrusted environment data is interpolated directly into a shell command executed by execute_shell_command_raw. A value such as a URL containing shell metacharacters can terminate the curl command or add another command, resulting in arbitrary command execution whenever update checking runs. Validate the URL and pass it without shell interpolation, or quote it safely. [security]

Severity Level: Critical 🚨
- ❌ Update checking can execute attacker-controlled shell commands.
- ❌ Compromised environment configuration enables arbitrary local code execution.
- ⚠️ The documented update URL override expands the attack surface.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** crates/forge_main/src/update.rs
**Line:** 74:77
**Comment:**
	*Security: Untrusted environment data is interpolated directly into a shell command executed by `execute_shell_command_raw`. A value such as a URL containing shell metacharacters can terminate the `curl` command or add another command, resulting in arbitrary command execution whenever update checking runs. Validate the URL and pass it without shell interpolation, or quote it safely.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +97 to +99
let install_dir = format!(r"{local_app_data}\Programs\Forge");
let new_exe = format!(r"{install_dir}\forge.exe.new");
let exe = format!(r"{install_dir}\forge.exe");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The Windows updater hardcodes %LOCALAPPDATA%\Programs\Forge\forge.exe, but this fork's packaging installs forge-dev.exe under %LOCALAPPDATA%\forge-dev\bin. The updater will download into an unrelated directory, leave the actual installed binary unchanged, and attempt to relaunch a nonexistent executable. Derive the executable and install directory from the running binary or the packaging contract. [api mismatch]

Severity Level: Major ⚠️
- ❌ Packaged Windows HeliosLite installations remain outdated.
- ❌ Auto-update launches an unrelated or nonexistent `forge.exe`.
- ⚠️ Downloaded update files accumulate outside the actual install directory.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** crates/forge_main/src/update.rs
**Line:** 97:99
**Comment:**
	*Api Mismatch: The Windows updater hardcodes `%LOCALAPPDATA%\Programs\Forge\forge.exe`, but this fork's packaging installs `forge-dev.exe` under `%LOCALAPPDATA%\forge-dev\bin`. The updater will download into an unrelated directory, leave the actual installed binary unchanged, and attempt to relaunch a nonexistent executable. Derive the executable and install directory from the running binary or the packaging contract.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +111 to +116
%SystemRoot%\\System32\\tasklist.exe /FI \"IMAGENAME eq forge.exe\" 2>nul | %SystemRoot%\\System32\\find.exe /I \"forge.exe\" >nul\r\n\
if not errorlevel 1 (\r\n\
%SystemRoot%\\System32\\timeout.exe /t 1 /nobreak >nul\r\n\
goto wait\r\n\
)\r\n\
move /Y \"{new_exe}\" \"{exe}\"\r\n\

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The swap helper waits for any process named forge.exe, not the Forge process that launched the update. If another Forge instance or stale process is running, the helper waits for up to 900 seconds and then deletes the downloaded binary. The deferred failure is invisible because the parent only observes the PowerShell launch status. Track the specific parent process or use a process-specific synchronization mechanism. [possible bug]

Severity Level: Major ⚠️
- ❌ Concurrent Forge sessions can prevent Windows updates.
- ❌ The staged binary is deleted after the 900-second timeout.
- ⚠️ The parent reports success before deferred swapping completes.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** crates/forge_main/src/update.rs
**Line:** 111:116
**Comment:**
	*Possible Bug: The swap helper waits for any process named `forge.exe`, not the Forge process that launched the update. If another Forge instance or stale process is running, the helper waits for up to 900 seconds and then deletes the downloaded binary. The deferred failure is invisible because the parent only observes the PowerShell launch status. Track the specific parent process or use a process-specific synchronization mechanism.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 55e8ef04cd

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +97 to +99
let install_dir = format!(r"{local_app_data}\Programs\Forge");
let new_exe = format!(r"{install_dir}\forge.exe.new");
let exe = format!(r"{install_dir}\forge.exe");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Target the actual Windows install location

When users install with the repository's Windows installer, install.ps1 places helioslite.exe under %LOCALAPPDATA%\helioslite\bin (or HELIOSLITE_INSTALL_DIR) and only creates forge.exe as an alias there, but this updater writes to %LOCALAPPDATA%\Programs\Forge\forge.exe and relaunches that separate path. In the standard Windows install this reports a successful auto-update while the PATH entry still points at the old helioslite.exe/alias, so the next invocation remains stale; derive the directory and executable name from the running binary or the installer setting instead.

Useful? React with 👍 / 👎.

$dir = Join-Path $env:LOCALAPPDATA 'Programs\Forge'
New-Item -ItemType Directory -Force -Path $dir | Out-Null
$arch = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') {{ 'aarch64' }} else {{ 'x86_64' }}
$repo = if ($env:HELIOSLITE_REPO) { $env:HELIOSLITE_REPO } else { 'KooshaPari/forgecode' }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Escape the PowerShell braces for Windows builds

On Windows this #[cfg(windows)] branch is compiled, and the single { ... } blocks in the format! string are parsed as Rust formatting placeholders rather than literal PowerShell braces (unlike the escaped braces on the preceding line). That makes the Windows updater fail to compile before it can run; escape these braces with {{/}} or avoid format! for the literal script.

Useful? React with 👍 / 👎.

@socket-security

Copy link
Copy Markdown

Dependency limit exceeded — report not shown.

This pull request scan exceeded the 10,000-dependency limit applied to this scan, so the results are incomplete and may be inaccurate. To avoid reporting false positives, Socket has not posted a report.

Upgrade your plan to raise the dependency limit and get complete reports, or view the partial scan in the dashboard.

Socket is always free for open source. If this is a non-commercial open source project, contact us to request a free Team account.

@KooshaPari
KooshaPari merged commit e484fdb into main Aug 2, 2026
26 checks passed
@KooshaPari
KooshaPari deleted the fix/windows-updater-fork-main branch August 2, 2026 21:17
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