Releases: droid-ash/finalrun-agent
Release list
FinalRun 0.1.14
What's changed in this release
Fixed
- iOS
launchAppcould surface Android's"Cannot launch: <bundleId>, maybe the app is not present"on iOS-only runs. Both platforms started their gRPC port pools at the hardcodedDEFAULT_GRPC_PORT_START(50051), so on a host running both an Android emulator and an iOS simulator they collided on host loopback — whichever bound first held the port and the other platform's gRPC client connected to the wrong driver. Adds a sharedGrpcPortAllocator(mutex + kernel bindability probe). iOS now allocates from50151–50250, disjoint from the Android pool (50051–50150); ports are released back onprepare()failure so per-process leaks are bounded to 100 slots. - iOS
launchAppnow pre-checks the bundle id withxcrun simctl listapps(mirroring Android'sisPackageInstalled) and returns an explicitApp not installed: <bundleId>instead of the prior generic "maybe the app is not present" message.SimctlClient.isAppInstalleddistinguishes a real simctl failure from a clean "not present" result, so transient simctl errors no longer get misreported as missing apps. - Android driver/test-runner APK installs now auto-recover from
INSTALL_FAILED_UPDATE_INCOMPATIBLE(and similar state-conflict failures) by uninstalling the conflicting prior package and retrying once. Recovery is gated on the package already being on the device — if it isn't, the failure is something uninstall can't fix (storage full, ABI mismatch, USB drop) and we skip the retry to fail fast. Behavior is scoped to FinalRun-owned driver APKs via a newAdbClient.installDriverAppmethod; user-APK installs atDeviceNode.installAppkeep no-recovery semantics so a failed user install never silently uninstalls the user's app. finalrun cloud test/suite/upload --app <Foo.app>failed for iOS simulator builds withEISDIR: illegal operation on a directory, readbecause.appis a directory bundle andopenAsBlobtried to stream it.prepareAppForUpload(in@finalrun/cloud-core) now zips a.app/directory on the fly into a temp<name>.app.zip(which the server already accepts) and cleans the temp file infinally. Plain files pass through unchanged. The accepted--appshapes are tightened to.apk,.app.zip, or.app/directory;.ipaand arbitrary.zip/directories are rejected with clear errors instead of producing opaque upload failures downstream.
Changed
finalrun cloud testandfinalrun cloud suitenow forward the resolved non-secretvariables:block from the active env YAML to cloud at submit time. Cloud records them on the run row so users (and the audit trail) can see what env values the run was executed against. Secrets are deliberately not forwarded.- Internal refactor:
CliFilePathUtil+RuntimeAssetStore+ the asset cache moved from@finalrun/finalrun-agentto@finalrun/device-node; therunCheckpipeline (checkRunner,env,appConfig,testLoader,testSelection,workspace,workspacePicker) moved from cli to@finalrun/common. The cli's public API is unchanged via re-exports. The runtime-asset cache directory (~/.finalrun/assets/<version>/) now keys on device-node's version instead of cli's; they release in lockstep so the only consequence is a one-time cache invalidation on dev machines after this release.
FinalRun 0.1.13
What's changed in this release
Fixed
- Local report server never spawned in the Bun-compiled binary.
resolveCliLaunchArgswalked__dirname-relative entrypoint candidates that don't exist on a user's machine and threw "Could not resolve a FinalRun CLI entrypoint for background report server startup."tryStartReportServerswallowed the throw silently, sofinalrun testadvertised a "Report server: …" URL that was actually a leftover process from an unrelated dev session, andfinalrun start-serverfailed outright. The standalone-binary path now spawnsprocess.execPathdirectly. - Browser auto-launch after a test run did nothing. Same root cause: with no live report-server URL, the post-run
open <url>handoff was never reached. Now that the server starts, Chrome (or whatever the macOS default browser is) opens to the run page on completion. finalrun start-serverfailed with "Could not find an open port near 4173" when the 4173–4192 window was occupied by leftover processes. The port-finder now falls back to an OS-assigned ephemeral port instead of erroring out.
Changed
finalrun stop-serveris now a single command with no flags. It reaps every FinalRun report-server process owned by the current user (matched byinternal-report-serverargv marker, so the blast radius is bounded to processes the CLI itself spawns) and clears every leftover.server.jsonunder~/.finalrun/workspaces/. The previous workspace-scoped behavior was fragile — orphans from crashed or older runs accumulated and there was no way to clean them withoutpkill.- Spawn failures from
tryStartReportServerandopenUrlBestEffortnow print to stderr instead of being swallowed, so regressions in the report-server pipeline surface within one run instead of two releases later.
FinalRun 0.1.12
What's changed in this release
Fixed — Planner crashing on Prompt file not found after device setup
After the v0.1.11 fix unblocked device setup, the very next phase failed: Planner call failed: ... Prompt file not found for key "planner". Searched: /home/runner/work/finalrun-agent/finalrun-agent/packages/goal-executor/.... Same class of bug as the existing BUNDLED_CLI_VERSION workaround in runtimePaths.ts — __dirname in a Bun-compiled binary points to the source path on the build machine (the GitHub Actions runner) rather than the deploy machine, so AIAgent._loadPrompt's disk lookups all missed.
Fixed by shipping the AI prompt files (planner.md, grounder.md, the four sub-grounders, etc.) inside the runtime tarball under prompts/, alongside the existing proto/, install-resources/, and report-app/ payloads — and by extending initializeCliRuntimeEnvironment in the CLI to set FINALRUN_PROMPTS_DIR from the runtime root. _loadPrompt already preferred that env var, so no behavior change there. Local dev still works because the __dirname-based fallbacks resolve correctly under tsx/node.
FinalRun 0.1.11
What's changed in this release
Fixed — Android/iOS test runs crashing on first proto load
finalrun test and finalrun suite aborted at device setup with Run setup failed before execution: null is not an object (evaluating 'util.fs.readFileSync') and a SIGKILL'd Android driver process. The crash hit every test run, not just first-install runs — the leading "Failed to clear app data" warning was harmless first-install noise and unrelated to the actual failure.
The root cause was inside protobufjs (transitively required by @grpc/proto-loader when the gRPC client loads driver.proto): it lazy-resolves fs and long via @protobufjs/inquire's eval("require")(name) shim to dodge bundler static analysis. In a Bun-compiled standalone binary that eval'd require can't see the bundle's resolver, so util.fs came back null and any subsequent util.fs.readFileSync(...) blew up. (util.Long had the same shape and would have tripped resolveAll on the first int64 field.) Local development never reproduced because tsx / node / bun run all expose a real require to the eval.
Fixed by introducing packages/device-node/src/grpc/protobufBundlerShim.ts, a side-effect module that statically imports node:fs and long and assigns them onto Protobuf.util. GrpcDriverClient.ts imports the shim before @grpc/proto-loader, so the patch lands before proto-loader's transitive protobufjs/ext/descriptor import calls Root.fromJSON(...).resolveAll() at module-init time. Verified end-to-end against the wikipedia repo on a Bun-compiled darwin-arm64 binary: Connected after 2 attempts (1s) → gRPC connection established successfully.
FinalRun 0.1.10
What's changed in this release
Added — Windows x86_64 support
FinalRun now ships a finalrun-windows-x64.exe binary and a matching finalrun-runtime-0.1.10-windows-x64.tar.gz runtime bundle on every release.
End users on Windows install via PowerShell:
irm https://raw.githubusercontent.com/final-run/finalrun-agent/main/scripts/install.ps1 | iexThe Windows installer (scripts/install.ps1) mirrors the bash installer's structure: downloads the binary, extracts the runtime tarball, wires up the per-user PATH, and walks the user through Android tooling setup (Android Studio detection + scrcpy install via winget with a choco fallback). The iOS prompt is intentionally absent — iOS local execution requires xcodebuild (macOS-only). Cloud commands work the same on Windows for both Android and iOS.
finalrun upgrade now branches on platform: Windows hosts re-run install.ps1 via powershell.exe -Command "irm <url> | iex"; macOS/Linux hosts continue to re-run install.sh via bash -c "curl <url> | bash". Both honor the --ci flag.
Built via Bun's bun-windows-x64 cross-compile target on the existing Linux-based release runner; no new CI infrastructure or code signing pipeline yet (Windows users will see a SmartScreen warning on first run — click "More info → Run anyway"). A new smoke-windows job in the release workflow runs the cross-compiled .exe on a real windows-latest runner before tagging, blocking the release if the binary fails to execute.
Notes
- Windows ARM64 is not supported — Bun does not currently provide a
bun-windows-arm64cross-compile target. scripts/install.shcontinues to reject Windows hosts (Cygwin / MinGW / MSYS / Git Bash). Windows installs go throughinstall.ps1, not the bash installer.- The Windows runtime tarball is byte-equivalent to the Linux x64 tarball (Android-only payload); the existing
isDarwingate inbuildRuntimeTarball.mjscorrectly excludes iOS bundles for non-darwin targets.
FinalRun 0.1.9
What's changed in this release
Changed
finalrun upgradeflag space mirrors the v0.1.8 installer:--cloud-onlyand--full-setupare removed in favor of--ci. When neither is passed, the upgrade mode is inferred from whether the local runtime tarball is currently installed (binary-only if not, full setup if yes).
Fixed
- Cloud submissions (
cloud test,cloud upload) drop the env file when the active environment comes from.finalrun/config.yaml'senv:default. The zip now ships.finalrun/env/<envName>.yamlwhether the env is set via--envor resolved from config defaults. Regression introduced in v0.1.8 — the server-side check would 500 withEnvironment "<name>" was requested, but .finalrun/env does not exist. LocalRuntimeMissingErrorrecovery hint no longer references the removedinstall.sh --full-setupflag — it now points at plaincurl … | bash(full setup is the default).install.shplatform-prompt-exhausted warning no longer suggests "re-run without --ci" (that path is unreachable from--cimode). It now suggests re-running the installer or runningfinalrun doctorto diagnose host tooling.
FinalRun 0.1.8
⚠️ Upgrading from a previous npm installIf you previously installed via
npm install -g @finalrun/finalrun-agent, the npm-installed binary is still onPATHand shadows the new one at~/.finalrun/bin/finalrun. Symptom:finalrun --versionkeeps reporting an old version.Remove the npm version once, then the new binary takes over:
npm uninstall -g @finalrun/finalrun-agent hash -r # bust the shell's command cache which finalrun # should now be ~/.finalrun/bin/finalrun finalrun --version # should now be 0.1.8If
whichstill doesn't point at~/.finalrun/bin/finalrun, open a new terminal (so the PATH append in~/.bashrc/~/.zshrctakes effect) or run:export PATH="$PATH:$HOME/.finalrun/bin"This is a one-time cleanup — v0.1.8 is the first release that ships exclusively as a binary; from here on,
finalrun upgradekeeps the binary current.
Install
One command on macOS or Linux. No Node.js, no npm, nothing else required.
curl -fsSL https://raw.githubusercontent.com/final-run/finalrun-agent/main/scripts/install.sh | bashFor CI / non-interactive environments (binary only, no runtime tarball, no prompts):
curl -fsSL https://raw.githubusercontent.com/final-run/finalrun-agent/main/scripts/install.sh | bash -s -- --ciCI environments (CI=1) get this behavior automatically even without the flag.
Artifacts
| Platform | Binary | Runtime tarball |
|---|---|---|
| macOS Apple Silicon | finalrun-darwin-arm64 |
finalrun-runtime-<version>-darwin-arm64.tar.gz |
| macOS Intel | finalrun-darwin-x64 |
finalrun-runtime-<version>-darwin-x64.tar.gz |
| Linux x86_64 | finalrun-linux-x64 |
finalrun-runtime-<version>-linux-x64.tar.gz |
| Linux ARM64 | finalrun-linux-arm64 |
finalrun-runtime-<version>-linux-arm64.tar.gz |
Each artifact ships with a matching .sha256 sidecar.
Upgrading from a previous version
finalrun upgradeThe CLI re-runs the install script with sensible defaults (auto-detects whether you previously installed the runtime tarball, preserves your install directory).
What's changed in this release
Changed — distribution model
The CLI is no longer published to npm. It now ships as a self-contained Bun-compiled binary plus a per-platform runtime tarball, both uploaded to GitHub Releases. End users install via:
# Full local-dev setup (binary + runtime tarball + platform tools + skills)
curl -fsSL https://raw.githubusercontent.com/final-run/finalrun-agent/main/scripts/install.sh | bash
# CI / non-interactive (binary only)
curl -fsSL https://raw.githubusercontent.com/final-run/finalrun-agent/main/scripts/install.sh | bash -s -- --ciNo Node.js required. CI environments (auto-detected via CI=1) skip the interactive setup automatically even without the --ci flag.
Breaking — installer flags
The first cut of v0.1.8 shipped with --cloud-only and --full-setup flags plus TTY-detection that interacted badly with curl | bash (the script could hang mid-install when exec </dev/tty ran while bash was still reading the script body from the curl pipe). The flags have been simplified to a single --ci toggle and the script is now wrapped in a main() function so the redirect can never collide with bash's own script reading.
Migration:
| Old (will hard-error) | New |
|---|---|
bash -s -- --cloud-only |
bash -s -- --ci |
bash -s -- --full-setup |
bash (full is the default; drop the flag) |
Added
@finalrun/cloud-coreworkspace package: pure cloud-submission logic (zip + multipart POST, app upload), shared by the CLI binary@finalrun/local-runtimeworkspace package: builder for the per-platformfinalrun-runtime-<version>-<platform>.tar.gz(driver bundles, gRPC proto, Vite SPA dist) that ships alongside the binary on GitHub Releasesfinalrun upgradesubcommand: re-runs the install script with sensible defaults (auto-detects whether the runtime tarball was previously installed; preservesFINALRUN_DIR)--cloud-only/--full-setupflags oninstall.shfor explicit override of the TTY auto-detection- 30-minute fetch timeout on cloud submissions and app uploads (overridable via
FINALRUN_SUBMIT_TIMEOUT_MSandFINALRUN_UPLOAD_TIMEOUT_MS); stalled connections surface as a clear "connection stalled" message instead of hung spinners FINALRUN_REPORT_APP_DIRandFINALRUN_RUNTIME_ROOTenv vars for pointing the CLI at custom asset locations- GitHub Actions
Releaseworkflow (manualworkflow_dispatchtrigger) that builds all 4 binaries + 4 runtime tarballs, tags the build commit, and creates the GitHub Release with all 16 artifacts RELEASING.mdrunbook documenting the manual release flow, pre-release tags, re-running failed jobs, local dry-run, and rollback
Changed
FINALRUN_CLOUD_URLdefault switched fromcloud-dev.finalrun.apptocloud.finalrun.app. Override the env var to re-target dev infra.- Cloud
cloud testandcloud uploadnow stream the app file to the multipart body viafs.openAsBlobinstead offs.readFileSync— large APKs/IPAs no longer materialize into a single Buffer in memory - Cloud
cloud testships only the env file matching--env, not every YAML under.finalrun/env/(was leaking other environments' bindings) install.shrewritten: downloads the binary first, TTY-detects, runs interactive setup (platform prompt, brew installs, doctor verification, skills install) only when on a real terminal. Prompts have 30-second read timeouts that fall through to the conservative path. Brew install failures now correctly fail the setup step (previously short-circuited via&& ok).- The CLI's
bin/finalrun.tsnow lazy-loads the heavy modules (testRunner,doctorRunner,reportServer,reportServerManager) so cloud commands don't pull them at startup. Local commands fail fast withLocalRuntimeMissingErrorand a recovery URL when the runtime tarball isn't installed. - Test runner is now a portable Node script (
packages/cli/scripts/runTests.mjs) walkingdist/instead ofnode --test "dist/**/*.test.js"(which needs Node 21+ for native glob; we declare>= 20.19)
Removed
npm install -g @finalrun/finalrun-agent— no longer published.packages/cliisprivate: true. Existing npm-installed copies keep working until usersfinalrun upgradeor re-run the install URL.packages/cli/scripts/installAssets.mjs,preparePackage.mjs,cleanupPackage.mjs— npm-publication scripts no longer neededpackages/cli/package.jsonno longer haspostinstall,prepack,postpack,bundleDependencies, orpublishConfig- Client-side APK/IPA inspection in cloud submissions — server validates platform / packageName / simulator-compatibility authoritatively
Fixed
- Bun-compiled binary's
__dirnameis the build-machine source path; resolvingpackage.jsonvia filesystem walk-up failed on every machine other than the one that built the binary. The CLI version is now read viarequire('../package.json')at module load (compiled to a CJS require by tsc and inlined into the bundle by Bun). - Runtime tarball location now honors
$FINALRUN_DIR(default~/.finalrun), matching the install script's convention. Previously the binary's resolver only checked$HOME/.finalrunregardless of where the install script extracted the tarball. - Cloud submit/upload spinners no longer remain spinning after an unparseable JSON body or a server-side rejection — both paths now
spinner.failbefore rethrowing install.shrejects--cloud-onlyand--full-setuptogether; refuses Windows hosts up front (Cygwin / MinGW / MSYS) instead of 404-ing on a non-existentfinalrun-windows-x64.exe; validates the GitHub/releases/latestredirect target shape before parsing the tag- Release workflow gained a
concurrency:block (two simultaneous "Run workflow" clicks now queue rather than race on tag creation), strict semver regex on the version, origin tag-existence check (not just local), and--latestonly when releasing frommainwith a stable (non-pre-release) version