Skip to content

fix(scripts): normalise MinGW/MSYS/Cygwin uname for POSIX launcher#161

Open
hypn4 wants to merge 2 commits into
ory:mainfrom
hypn4:fix/run-mingw-windows-normalization
Open

fix(scripts): normalise MinGW/MSYS/Cygwin uname for POSIX launcher#161
hypn4 wants to merge 2 commits into
ory:mainfrom
hypn4:fix/run-mingw-windows-normalization

Conversation

@hypn4
Copy link
Copy Markdown
Contributor

@hypn4 hypn4 commented May 13, 2026

Summary

  • The POSIX launcher (scripts/run) used uname -s lower-cased verbatim as the
    OS slug. On Git Bash / MSYS2 / Cygwin that produces mingw64_nt-10.0-26200,
    not windows — so the launcher skipped the already-installed
    bin/lumen-windows-amd64.exe and tried to download a non-existent
    lumen-X.Y.Z-mingw64_nt-...-amd64 asset from releases.
  • Result: a hook_non_blocking_error on every Claude Code SessionStart whenever
    shell:true dispatched the hook through Git Bash instead of cmd.exe
    (curl: (22) The requested URL returned error: 404, ~2.7 s per session start).
  • Normalise mingw*|msys*|cygwin*windows + .exe, matching what
    scripts/run.cmd, asset_name in test_run.sh, and the goreleaser asset
    names on GitHub already assume. Preserve the extensionless bin/lumen
    dev-build path so make build-local still works on Windows.

Root cause

scripts/run had three places that assumed $OS was already a valid GitHub
asset OS token:

"${PLUGIN_ROOT}/bin/lumen-${OS}-${ARCH}"
ASSET="lumen-${VERSION#v}-${OS}-${ARCH}"

On Git Bash, uname -s returns MINGW64_NT-10.0-26200. Lower-casing leaves the
token unchanged for our purposes, so the launcher:

  1. Looked for bin/lumen and bin/lumen-mingw64_nt-10.0-26200-amd64 — neither
    matches the installed bin/lumen-windows-amd64.exe.
  2. Constructed
    https://github.com/ory/lumen/releases/download/v0.0.40/lumen-0.0.40-mingw64_nt-10.0-26200-amd64
    — 404.
  3. Hit the GitHub API fallback, resolved the same tag, retried the same
    filename — 404 again.
  4. Exited with curl's 22.

scripts/run.cmd is correct because it hard-codes -windows- and .exe. The
gap is only on the POSIX path that runs on Git Bash dispatch.

Evidence (from a live Claude Code 2.1.140 session)

{
  "type": "hook_non_blocking_error",
  "hookName": "SessionStart:startup",
  "stderr": "Failed with non-blocking status code: Downloading lumen v0.0.40 for mingw64_nt-10.0-26200/amd64...\ncurl: (22) The requested URL returned error: 404\n\nVersion v0.0.40 not found, resolving latest release...\nFalling back to v0.0.40...\ncurl: (22) The requested URL returned error: 404",
  "exitCode": 22,
  "command": "\"${CLAUDE_PLUGIN_ROOT}/scripts/run\" hook session-start lumen --host claude",
  "durationMs": 2773
}

After this fix the same session emits a normal Lumen index ready: … line.

Changes

scripts/run

  • Normalise mingw*|msys*|cygwin*OS=windows; derive EXT=.exe when
    $OS = windows.
  • Apply ${EXT} consistently to the bin candidate list, the post-download
    $BINARY, and both $ASSET constructions (manifest and GitHub-API fallback).
  • Keep the extensionless bin/lumen candidate so make build-local (which
    runs go build -o bin/lumen . — Go does not auto-append .exe when -o is
    explicit) is still discovered on Windows ahead of falling through to a
    download.

scripts/test_run.sh

  • Add normalise_os helper + 7 table-driven cases covering mingw64/mingw32/
    msys/cygwin/windows passthrough/linux/darwin.
  • Add 3 candidate-ordering cases (windows .exe, mingw normalised, linux) so a
    future change that drops the dev-build path is caught by tests.
  • Align the two stdio integration tests' _EXPECTED_BINARY with the new
    normalisation (otherwise they pass on Linux but fail on Git Bash).

Test plan

  • bash scripts/test_run.sh39 passed, 2 failed vs. main's
    29/2. Both pre-existing failures are the candidate-priority [ -x ]
    checks on Git Bash (touch + chmod +x doesn't produce an exec bit
    for extensionless files on MSYS2), unrelated to this PR.
  • golangci-lint run0 issues.
  • go vet ./... — same external-dependency warnings as main (CGO
    tree-sitter constraint messages, called out as OK in CLAUDE.md).
  • Verified Go behavior: go build -o bin/lumen . does not append
    .exe on Windows, confirming the dev-build regression risk the second
    commit guards against.
  • Manual: bash scripts/run hook session-start lumen --host claude
    exit 0, valid hookSpecificOutput JSON.
  • End-to-end: ran a fresh Claude Code session against the patched plugin
    cache; the hook_non_blocking_error is gone and the SessionStart
    additional context (Lumen index ready: …) appears as designed.

Notes / out of scope

  • The original two-candidate list (bin/lumen, bin/lumen-${OS}-${ARCH}) was
    designed to let make build-local win over a downloaded artefact. This PR
    preserves that ordering on every platform by introducing ${EXT} rather
    than rewriting it.
  • Separately observed: the MCP index_status handler bypasses
    merkle.IsRootUnindexable and walks the user's home directory anyway,
    triggering Windows file-lock errors on AppData\Local\Temp\*.scratch. That
    is unrelated to launcher dispatch and will be filed/sent separately.

Summary by CodeRabbit

  • Bug Fixes

    • Improved binary resolution for Windows environments, including MinGW, MSYS, and Cygwin.
    • Enhanced binary search to check multiple candidate filenames.
  • Tests

    • Expanded test coverage for cross-platform OS normalization and Windows executable handling.

Review Change Stack

hypn4 added 2 commits May 13, 2026 23:47
Git Bash, MSYS2, and Cygwin all report `uname -s` strings like
`MINGW64_NT-10.0-26200`, `MSYS_NT-10.0`, or `CYGWIN_NT-10.0`. The
POSIX launcher lower-cased that string and used it verbatim as the
OS slug, so on Windows it looked for `bin/lumen-mingw64_nt-...-amd64`
(skipping the already-installed `bin/lumen-windows-amd64.exe`) and
then tried to download `lumen-X.Y.Z-mingw64_nt-...-amd64` from
GitHub releases, where no such asset exists. The result was a
non-blocking SessionStart hook failure on every Claude Code session
start whenever shell:true dispatched through Git Bash instead of
cmd.exe (curl exit 22, 404).

Map the three Windows POSIX environments to `windows` and append
`.exe`, matching scripts/run.cmd and the goreleaser asset names.
Add table-driven coverage in scripts/test_run.sh and align the two
integration tests' expected binary path with the new normalisation.
Local development uses `make build-local`, which runs
`go build -o bin/lumen .`. Go does NOT append `.exe` when `-o` is
explicit, so on Windows the dev build is written to `bin/lumen` (no
extension). The previous commit only looked for `bin/lumen.exe` and
`bin/lumen-windows-amd64.exe`, which would silently fall through to a
GitHub download path during `claude --plugin-dir .` development —
regressing the dev workflow that the original two-candidate list was
designed to preserve.

Add `bin/lumen` (without EXT) as the middle candidate so the priority
on Windows becomes: .exe dev build → extensionless dev build →
downloaded artefact. Linux/macOS retain their existing two-candidate
behavior (the duplicate is a no-op there).

Add three table-driven tests covering the candidate ordering across
windows (.exe), mingw-normalised, and linux configurations.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4c00e622-a7b1-40a5-917c-326ceaa15529

📥 Commits

Reviewing files that changed from the base of the PR and between e310ed0 and 7c727b7.

📒 Files selected for processing (2)
  • scripts/run
  • scripts/test_run.sh

📝 Walkthrough

Walkthrough

The launcher scripts/run now detects Windows-like environments (MinGW, MSYS, Cygwin), normalizes them to a canonical windows OS value with .exe file extension, expands binary search candidates, and updates release asset filenames to include the platform-specific extension. Corresponding tests validate this normalization and ensure expected artifact filenames across local and downloaded scenarios.

Changes

Cross-platform binary resolution with Windows executable suffix handling

Layer / File(s) Summary
Platform normalization and binary candidate resolution
scripts/run
Launcher detects Windows-like OS variants (MinGW/MSYS/Cygwin), normalizes to windows, maps architectures to amd64/arm64, sets EXT=.exe on Windows, and expands binary search candidates to include base and OS/arch-suffixed variants under bin/.
Download and asset filename resolution
scripts/run
Download target and release asset filenames are computed using OS/arch-suffixed names with the platform extension, applied to both manifest-pinned and fallback latest-release paths.
Test infrastructure and OS normalization validation
scripts/test_run.sh
Test suite introduces normalise_os helper to validate MinGW/MSYS/Cygwin→windows mapping with .exe suffixing, adds expected_candidates helper for binary candidate priority validation, and updates integration/e2e test expectations to compute artifact filenames using the same platform normalization logic.

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • ory/lumen#157: Modifies launcher download/filename resolution in scripts/run with Windows-specific asset filename handling that aligns with this PR's cross-OS binary naming expectations.

Suggested reviewers

  • aeneasr
🚥 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 accurately and concisely describes the main change: normalizing MinGW/MSYS/Cygwin OS detection for the POSIX launcher.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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 and usage tips.

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