From 0c824272654b6c3587762be923e21a5518a550b8 Mon Sep 17 00:00:00 2001 From: Ian Hancock Date: Fri, 31 Jul 2026 11:12:38 -0500 Subject: [PATCH] fix: fall back to Dart on native binary spawn errors; drop retired macOS x64 CI target runNativeBinary() had no handler for spawn() launch failures. On this platform spawn() throws ENOEXEC synchronously for a non-executable cached binary, and other failure modes (EACCES, wrong-arch) surface async via the 'error' event - neither path was covered, so any bad cached binary crashed the CLI instead of falling back to the Dart runtime that main() already implements for the "binary missing" case. Separately, the v0.9.36 release run failed because build-native-binaries (macos-13, x64) can no longer schedule: GitHub retired the macos-13 hosted runner, and current x64 macOS runner images require the paid large-runner tier. create-release requires every build-native-binaries matrix entry to succeed, so that one failure silently skipped create-release for the whole release - npm/pub.dev/vscode all published v0.9.36, but no GitHub Release or binaries were ever created, which is why the npm wrapper's download URLs were 404ing. Dropped the macos-13/x64 matrix entry and its dependents (Homebrew SHA256 + on_intel block) rather than switching to a paid runner label, since that requires org-level runner/billing configuration this repo may not have. npm, VSCode, and IntelliJ already fall back to the Dart runtime when a native binary 404s, so Intel Mac users are unaffected beyond losing the native-binary fast path; Homebrew on Intel now fails formula resolution with Homebrew's standard unsupported-platform error instead of installing a binary that no longer exists. Constraint: macos-13 hosted runner is fully retired, not just deprecated Constraint: current x64 macOS runner labels (macos-14-large, macos-15-large) require paid large-runner tier Rejected: relabel matrix to macos-14/macos-15 without -large | those bare labels are arm64, would silently mislabel an arm64 binary as x64 Rejected: switch to macos-15-large | unconfirmed whether org has large-runner billing/runner-group configured; would fail differently instead of fixing anything Confidence: high Scope-risk: moderate Directive: if Intel Mac native-binary support is restored later, do it via a paid large runner explicitly opted into, not by reusing a bare macos-1x label Not-tested: full release.yml run end-to-end (requires a real v* tag push); validated via YAML syntax check and manual matrix/heredoc diff review only Co-Authored-By: Claude Sonnet 5 --- .github/workflows/release.yml | 11 ----------- packaging/homebrew/flutter-skill.rb | 8 ++++---- packaging/npm/bin/cli.js | 21 +++++++++++++++++++-- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a9af1ce1..e06f8463 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -220,10 +220,8 @@ jobs: run: | cd binaries SHA256_ARM64=$(sha256sum flutter-skill-macos-arm64/flutter-skill-macos-arm64 | cut -d' ' -f1) - SHA256_X64=$(sha256sum flutter-skill-macos-x64/flutter-skill-macos-x64 | cut -d' ' -f1) SHA256_LINUX=$(sha256sum flutter-skill-linux-x64/flutter-skill-linux-x64 | cut -d' ' -f1) echo "sha256_arm64=$SHA256_ARM64" >> $GITHUB_OUTPUT - echo "sha256_x64=$SHA256_X64" >> $GITHUB_OUTPUT echo "sha256_linux=$SHA256_LINUX" >> $GITHUB_OUTPUT - name: Checkout Homebrew tap @@ -237,7 +235,6 @@ jobs: run: | VERSION=${{ needs.prepare.outputs.version }} SHA256_ARM64=${{ steps.sha256.outputs.sha256_arm64 }} - SHA256_X64=${{ steps.sha256.outputs.sha256_x64 }} SHA256_LINUX=${{ steps.sha256.outputs.sha256_linux }} # Write the new formula @@ -253,10 +250,6 @@ jobs: url "https://github.com/ai-dashboad/flutter-skill/releases/download/vVERSION_PLACEHOLDER/flutter-skill-macos-arm64" sha256 "SHA256_ARM64_PLACEHOLDER" end - on_intel do - url "https://github.com/ai-dashboad/flutter-skill/releases/download/vVERSION_PLACEHOLDER/flutter-skill-macos-x64" - sha256 "SHA256_X64_PLACEHOLDER" - end end on_linux do @@ -298,7 +291,6 @@ jobs: # Replace placeholders sed -i "s/VERSION_PLACEHOLDER/${VERSION}/g" homebrew-tap/Formula/flutter-skill.rb sed -i "s/SHA256_ARM64_PLACEHOLDER/${SHA256_ARM64}/g" homebrew-tap/Formula/flutter-skill.rb - sed -i "s/SHA256_X64_PLACEHOLDER/${SHA256_X64}/g" homebrew-tap/Formula/flutter-skill.rb sed -i "s/SHA256_LINUX_PLACEHOLDER/${SHA256_LINUX}/g" homebrew-tap/Formula/flutter-skill.rb - name: Commit and push @@ -319,9 +311,6 @@ jobs: - os: macos-latest arch: arm64 artifact: flutter-skill-macos-arm64 - - os: macos-13 - arch: x64 - artifact: flutter-skill-macos-x64 - os: ubuntu-latest arch: x64 artifact: flutter-skill-linux-x64 diff --git a/packaging/homebrew/flutter-skill.rb b/packaging/homebrew/flutter-skill.rb index 0e1dd056..d2719e82 100644 --- a/packaging/homebrew/flutter-skill.rb +++ b/packaging/homebrew/flutter-skill.rb @@ -5,15 +5,15 @@ class FlutterSkill < Formula license "MIT" # Platform-specific native binaries + # Intel macOS (x64) has no native binary: GitHub retired the macos-13 hosted + # runner used to build it, and current x64 runner images require a paid + # large-runner tier. Intel Mac users should install via npm/pub.dev instead, + # which fall back to the Dart runtime automatically. on_macos do on_arm do url "https://github.com/ai-dashboad/flutter-skill/releases/download/v0.9.36/flutter-skill-macos-arm64" sha256 "PLACEHOLDER_ARM64_SHA256" end - on_intel do - url "https://github.com/ai-dashboad/flutter-skill/releases/download/v0.9.36/flutter-skill-macos-x64" - sha256 "PLACEHOLDER_X64_SHA256" - end end on_linux do diff --git a/packaging/npm/bin/cli.js b/packaging/npm/bin/cli.js index 825cd1f9..d0c33f62 100755 --- a/packaging/npm/bin/cli.js +++ b/packaging/npm/bin/cli.js @@ -122,8 +122,25 @@ function runNativeBinary(binaryPath) { args.push('server'); } - const server = spawn(binaryPath, args, { - stdio: 'inherit' + // spawn() reports launch failures (ENOEXEC, EACCES, ENOENT, wrong-arch, ...) + // inconsistently across platforms/Node versions: some surface synchronously + // as a thrown exception from spawn() itself, others only asynchronously via + // the 'error' event. Without handling both, the failure is uncaught and + // crashes the process instead of ever reaching the Dart fallback. + let server; + try { + server = spawn(binaryPath, args, { + stdio: 'inherit' + }); + } catch (err) { + console.error(`[flutter-skill] Native binary failed to launch (${err.code || err.message}), falling back to Dart runtime`); + runWithDart(); + return; + } + + server.on('error', (err) => { + console.error(`[flutter-skill] Native binary failed to launch (${err.code || err.message}), falling back to Dart runtime`); + runWithDart(); }); server.on('close', (code) => {