fix(desktop): surface install failures hidden by curl-pipe exit codes - #2892
Conversation
wesbillman
left a comment
There was a problem hiding this comment.
Reviewed at 9a0a424. Applying pipefail at the shared Unix/Git-Bash command boundary correctly surfaces a failing left-hand fetch while leaving native PowerShell untouched. The inherited PATH fallback is lowest precedence and only activates when no login-shell PATH was obtained; the deterministic shell and policy tests cover activation, suppression, ordering, and healthy pipelines. Current CI is fully green, including Windows Rust. No blocking findings.
wesbillman
left a comment
There was a problem hiding this comment.
Correction after a late independent review finding, validated at 9a0a424d2b21fcc798bca0bf7bf3d3bc02b62649:
The Unix inherited-PATH fallback does not necessarily survive until the install command. install_shell_command() sets the composed fallback with cmd.env("PATH", ...) at desktop/src-tauri/src/commands/agent_discovery.rs:587-608, then starts the shell with -l -c at lines 563-573. Login startup files execute after the process environment is installed and can overwrite or empty PATH before set -o pipefail; <vendor command> runs.
This is reachable through the exact fallback branch: fetch_login_shell_path_inner() (managed_agents/discovery.rs:726-741) returns None when the login shell produces no non-empty PATH line. If the profile contains export PATH=, the probe returns None; the install command receives the inherited fallback through cmd.env, starts the same login shell, and that profile empties PATH again. I reproduced that shell behavior directly with an isolated .bash_profile: HOME=<temp> PATH=/usr/bin:/bin /bin/bash -l -c ... observed an empty PATH and could not resolve curl.
Please make the fallback effective after login initialization (safely set PATH inside the command body), or avoid login initialization for the install execution when the probe failed. Add an isolated-profile regression covering a login profile that clears PATH. The existing composition tests do not exercise startup-file overwrite.
The pipefail behavior itself remains correct and current CI is green, but the PATH half of the stated fix is incomplete. This review supersedes my earlier approval.
Every CLI install command is a `curl … | bash` pipe run through a login
shell without `pipefail`, so the pipeline reported the right-hand side's
status: a `curl` that failed — or was missing from the child's PATH — fed
`bash` an empty stdin, which exits 0. The `cli` step was recorded as
success and the user got an unactionable post-install `verify` error
instead of curl's own stderr.
The install child's PATH could also collapse: `Command::env("PATH", …)`
replaces rather than extends, and the inherited process PATH was appended
only on Windows, so a login shell that exits non-zero or prints nothing
left the child with Buzz's managed Node dirs alone — no `curl`, `sh`, or
`tar`. Appending the inherited PATH whenever no login-shell PATH was
obtained makes that the floor on every OS; entries stay last so managed
dirs keep precedence.
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
build_augmented_path's priority list and the compose_tests module header still described the inherited-PATH fallback as Windows-only, contradicting should_use_inherited after the gate was dropped. A stale contract here is an invitation to re-add the platform gate, since this function feeds every managed-agent spawn and readiness probe. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
cmd.env("PATH", …) installs the process environment before `-l` sources
the user's login startup files, so a profile that assigns PATH discards
the composed one before the vendor command runs. That defeats the
inherited-PATH fallback in exactly its own trigger condition: a profile
containing `export PATH=` is what makes the login-shell probe return
None in the first place. On macOS /etc/zprofile's path_helper reorders
PATH instead of clearing it, costing the managed Node/npm dirs the
precedence the composition promises — no probe failure required.
Passing the path as a positional keeps entries with spaces or quotes
intact; interpolating it into the body would not. The prelude is omitted
when no path was composed, since `export PATH="$1"` with $1 unset sets
an empty PATH.
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
9a0a424 to
b8dea1c
Compare
std::env::join_paths uses the platform separator, so the composed PATH
positional is ";"-joined on Windows while bash splits PATH on ":" —
re-exporting it inside Git Bash collapses every entry into one nonsense
path. Windows is where this bites hardest: login_shell_path() returns
None unconditionally there, so the inherited fallback always fires and
the prelude would be the steady state, silently undoing the fallback
that keeps node/npm/git reachable for the npm .cmd shims.
cmd.env("PATH", …) already delivers the native ";"-form that Git Bash
translates on entry, and Windows has no login startup files doing the
clobbering the prelude defends against, so it buys nothing there.
is_windows is a parameter rather than a #[cfg] so the Windows argument
shape stays asserted on Unix CI.
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
|
Reopening to force GitHub to recompute the pull_request merge ref against current |
…ding-harnesses * origin/main: (47 commits) fix(desktop): remove bundled libsystemd from AppImage (#2353) docs: document required DCO sign-off and add commit-msg sign-off hook (#2993) fix(desktop): make agent definition authoritative for model/provider/prompt (#1968) chore(desktop): delete dead persona catalog UI cluster (#2886) fix(desktop): surface install failures hidden by curl-pipe exit codes (#2892) fix(mobile): validate invite relay destinations (#2986) Refactor managed-agent runtime into cohesive modules (#2974) Refine mobile settings and themes (#2844) Fix formatting in README.md diagram (#2284) fix(desktop): make Linux AppImage GStreamer work on non-Debian distros (#2176) refactor(desktop): remove Agent directory section from Agents page (#2290) fix(desktop): enable arboard Wayland backend so Linux copies reach the Wayland clipboard (#2904) fix(desktop): supervise and re-arm relay-mesh runtime (#2823) fix(agents): run live Databricks discovery instead of the fallback list (#2890) fix(desktop): retire prepend mode on every reader wheel (#2913) fix(desktop): consolidate prepend scroll correction (#2855) docs(buzz-acp): correct agent key generation instructions (#2875) fix(desktop): track concurrent agent turns up to the harness maximum (#2882) docs(contributing): trim to goose-scale minimal intake surface (#2780) fix(relay): preserve reconnect backoff (#2759) ... Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com> # Conflicts: # desktop/src/features/onboarding/ui/SetupStep.tsx
## Buzz Desktop release v0.5.0 ### Changes since v0.4.26: - feat(invites): add use-limited invite links ([#3141](#3141)) ([`d500c2d5c`](d500c2d)) - fix(node): bump Buzz-supplied Node runtimes past OpenClaw's >=24.15.0 floor ([#3218](#3218)) ([`98a7b1334`](98a7b13)) - fix(desktop): preserve thread anchor through layout reflow ([#3212](#3212)) ([`9810d8545`](9810d85)) - feat(search): parse from:/in:/after:/before: and pass them in the filter ([#2871](#2871)) ([`cb2a265b5`](cb2a265)) - fix(desktop): fetch join policies through native networking ([#2862](#2862)) ([`0019f8076`](0019f80)) - fix(desktop): republish agent identity records when a persona rename propagates ([#2607](#2607)) ([`7ca0bbd94`](7ca0bbd)) - fix(desktop): keep project Inbox previews compact ([#3193](#3193)) ([`de1396050`](de13960)) - Inbox refactor ([#2045](#2045)) ([`2bd4c24b7`](2bd4c24)) - Fix composer selection formatting and drop overlay ([#3172](#3172)) ([`99da5b7eb`](99da5b7)) - Refine pending message status ([#3153](#3153)) ([`75588eaff`](75588ea)) - fix(desktop): recover full local storage on startup ([#3182](#3182)) ([`174c38e4b`](174c38e)) - fix(desktop): keep collapsed table separators out of spoilers ([#3169](#3169)) ([`4d8b676bb`](4d8b676)) - feat(desktop): redesign agent runtime settings ([#3093](#3093)) ([`d98da7389`](d98da73)) - fix(desktop): use forward slashes for git credential.helper on Windows ([#3023](#3023)) ([`899531684`](8995316)) - chore(desktop): add AgentCreationPreview file-size override to unblock main CI ([#3154](#3154)) ([`b92a1f4bf`](b92a1f4)) - fix(desktop): make the test loader work on Windows ([#2758](#2758)) ([`8bb43d519`](8bb43d5)) - fix(desktop): make lint and unit-test gates work on Windows ([#2943](#2943)) ([`545bb46b8`](545bb46)) - feat(desktop): add search to agent emoji picker ([#2630](#2630)) ([`313f793c8`](313f793)) - fix(desktop): keep identity key help dialog readable in dark mode ([#2854](#2854)) ([`be275cfc6`](be275cf)) - feat(acp): title agent sessions from the agent and channel name ([#3028](#3028)) ([`f2fe3b63c`](f2fe3b6)) - feat(git): use agent display name as git author name ([#3040](#3040)) ([`18eef633d`](18eef63)) - fix(deps): bump nostr to 0.44.6 for RUSTSEC-2026-0216 (NIP-44 remote DoS) ([#3135](#3135)) ([`31e2de196`](31e2de1)) - fix(desktop): read the newest pair-scoped harness log ([#3134](#3134)) ([`654f38490`](654f384)) - feat(desktop): handle project work from Inbox ([#3117](#3117)) ([`c5c4f390b`](c5c4f39)) - fix(desktop): clarify identity key button when key exists ([#2357](#2357)) ([`87b3fcd3c`](87b3fcd)) - Restore Goose and Buzz Agent to onboarding harness selection ([#2731](#2731)) ([`7fc0cc82d`](7fc0cc8)) - fix(desktop): render rich project work item content ([#3100](#3100)) ([`afb272bb7`](afb272b)) - feat(acp): bring your own harness (BYOH) — generic ACP runtime seam + settings gallery ([#2773](#2773)) ([`95fdf9788`](95fdf97)) - feat(desktop): use collective mesh routing for Auto ([#2825](#2825)) ([`16d4ec335`](16d4ec3)) - fix(desktop): strip legacy baked team instructions from stored prompts ([#3035](#3035)) ([`aee631448`](aee6314)) - feat(agents): lower default agent parallelism from 24 to 10 ([#3038](#3038)) ([`5d8ede446`](5d8ede4)) - Polish community rail and mobile pairing ([#2972](#2972)) ([`e6c90bb7c`](e6c90bb)) - fix(desktop): remove bundled libsystemd from AppImage ([#2353](#2353)) ([`a31fc4d2f`](a31fc4d)) - fix(desktop): make agent definition authoritative for model/provider/prompt ([#1968](#1968)) ([`8c0e8cb16`](8c0e8cb)) - chore(desktop): delete dead persona catalog UI cluster ([#2886](#2886)) ([`8e67cf399`](8e67cf3)) - fix(desktop): surface install failures hidden by curl-pipe exit codes ([#2892](#2892)) ([`166c6655e`](166c665)) - Refactor managed-agent runtime into cohesive modules ([#2974](#2974)) ([`74b63e184`](74b63e1)) - fix(desktop): make Linux AppImage GStreamer work on non-Debian distros ([#2176](#2176)) ([`cc6c4d347`](cc6c4d3)) - refactor(desktop): remove Agent directory section from Agents page ([#2290](#2290)) ([`5d1233e84`](5d1233e)) - fix(desktop): enable arboard Wayland backend so Linux copies reach the Wayland clipboard ([#2904](#2904)) ([`ab7aa8b12`](ab7aa8b)) - fix(desktop): supervise and re-arm relay-mesh runtime ([#2823](#2823)) ([`aa51dab9d`](aa51dab)) - fix(agents): run live Databricks discovery instead of the fallback list ([#2890](#2890)) ([`8eb6e3eb6`](8eb6e3e)) - fix(desktop): retire prepend mode on every reader wheel ([#2913](#2913)) ([`07d0265cf`](07d0265)) - fix(desktop): consolidate prepend scroll correction ([#2855](#2855)) ([`25e7864b3`](25e7864)) - fix(desktop): track concurrent agent turns up to the harness maximum ([#2882](#2882)) ([`20bff5910`](20bff59)) - fix(relay): preserve reconnect backoff ([#2759](#2759)) ([`499c5d349`](499c5d3)) - refactor(relay): expose reconnect timing policy ([#2310](#2310)) ([`2f0041595`](2f00415)) - fix(desktop): clear stale working badges on agent stop/restart ([#2803](#2803)) ([`a64cc71f6`](a64cc71)) - fix(desktop): surface agent rename relay profile sync failure as a warning toast ([#2279](#2279)) ([`5e3d2e484`](5e3d2e4)) - fix(discovery): inject PATH into Codex adapter planning ([#2767](#2767)) ([`6ab3835f3`](6ab3835)) **To release:** merge this PR. The tag and build will happen automatically. Signed-off-by: Wes <wesbillman@users.noreply.github.com>
…two-step shape Windows Defender's ML classifier (Trojan:Win32/Commando.A!ml) flags the bare `irm <url> | iex` command line as a dropper signature and denies the spawn with 'Access is denied. (os error 5)' before PowerShell runs. The block is sticky — Allow does not clear it. Replace all three Windows CLI install commands (Goose, Claude, Codex) with a two-step shape: download the vendor script to a named temp file with Invoke-RestMethod, then execute the file. Two invariants guard against the #2892 regression (success-on-download-failure): - $ErrorActionPreference='Stop' aborts on a failed download instead of falling through to a missing file and exiting 0. - exit $LASTEXITCODE propagates the vendor script's own exit code so a vendor failure of 3 does not flatten to 1. A single macro (windows_install_command!) in a new discovery/windows_install.rs submodule generates all three strings at compile time. One definition means the security shape cannot drift between runtimes as URLs change; a per-runtime literal would let one entry silently regress to irm|iex. Goose and Claude escaped by scoring under the classifier threshold — that is luck, not design. All three are hardened here. The three agent_discovery.rs test fixtures that pinned catalog command strings are updated to the new two-step shape. The routing and argv-parsing tests (is_powershell_command, install_powershell_command) that use irm|iex as representative PS input are unchanged — they test the routing function, not the catalog. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…block#2892) Ubuntu Doctor reports `Install failed at verify: The installer finished, but Buzz still could not use claude-code (observed: CLI missing)` while the `cli` step shows success. The `cli` step is lying. ## The masking Every CLI install command is a pipe — `curl -fsSL https://claude.ai/install.sh | bash` (`managed_agents/discovery.rs:109`), `… | sh` for Codex (`:141`), `… | CONFIGURE=false bash` for Goose (`:75`). `install_shell_command` ran them through `bash -l -c` with no `pipefail`, so the pipeline's exit status was the **right-hand** side's. A `curl` that fails — or that isn't on the child's PATH at all — feeds `bash` an empty stdin, and `bash` with nothing to run exits 0: ``` $ /bin/bash -l -c 'curl -fsSL https://nonexistent.invalid/x.sh | bash'; echo $? curl: (6) Could not resolve host: nonexistent.invalid 0 $ PATH=/tmp/empty /bin/bash -l -c 'curl -fsSL https://claude.ai/install.sh | bash'; echo $? bash: line 1: curl: command not found 0 ``` `run_install_command` records exit 0 as `success: true`, the adapter step then installs fine (it uses Buzz's own bundled Node, no system PATH needed), and `post_install_verification` correctly reports the CLI is absent. The user is handed a `verify` riddle instead of curl's error, which is why diagnosing this required three rounds of guessing. Install commands now run under `set -o pipefail`, so the left-hand side's failure is the step's failure and `InstallStepResult.stderr` carries the vendor's own message. `SHELLOPTS` is not exported by either shell, so the piped-to vendor script still runs with its default options. The Windows PowerShell install path (`install_powershell_command`) bypasses this shell and is untouched. ## The PATH collapse it was hiding `install_shell_command` composes the child's PATH and calls `cmd.env("PATH", …)`, which **replaces** rather than extends. `should_use_inherited` was `is_windows && !had_shell_path && has_local_context`, so on Unix the inherited process PATH was never appended. When `login_shell_path()` returns `None` — a login shell that exits non-zero or prints nothing, which a GUI-launched process can easily hit via `~/.profile` — the child's entire PATH becomes Buzz's two managed Node dirs. There is no `curl`, `sh`, `sha256sum`, or `tar` in either, so every curl-pipe install fails, and before this PR it failed invisibly. The `is_windows` requirement is dropped: the inherited PATH is the floor whenever no login-shell PATH was obtained, on every OS. Both existing suppressions are kept — a login-shell PATH present still suppresses it (no doubling), and no home/exe context still suppresses it (never manufacture a PATH from ambient state alone). Inherited entries stay **last**, so managed dirs keep precedence. The other caller, `build_augmented_path` (`runtime/path.rs:148`, feeding agent spawns and CLI probes), reads correctly under the new rule for the same reason: it only gains the inherited PATH in the case where it would otherwise hand a child a PATH with no native entries. When a login-shell PATH exists — the normal case on macOS and Linux — its output is unchanged, which `unix_shell_path_suppresses_inherited_fallback` pins. ## Scope This fixes the reporting defect and the PATH floor. The specific environment failure on the affected Ubuntu box is still being diagnosed and is deliberately not addressed here; the point of this change is that the next attempt produces the real error instead of a `verify` riddle. One interaction worth noting: `install_failure_is_retryable` retries any failure that carries an exit code, so a pipefail-surfaced curl failure now gets 3 attempts with backoff — correct for transient network blips, and harmless for hard failures. `desktop/scripts/check-file-sizes.mjs` ratchets the `agent_discovery.rs` ceiling 1836 → 1895 for the added tests. --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
## Buzz Desktop release v0.5.0 ### Changes since v0.4.26: - feat(invites): add use-limited invite links ([block#3141](block#3141)) ([`d500c2d5c`](block@d500c2d)) - fix(node): bump Buzz-supplied Node runtimes past OpenClaw's >=24.15.0 floor ([block#3218](block#3218)) ([`98a7b1334`](block@98a7b13)) - fix(desktop): preserve thread anchor through layout reflow ([block#3212](block#3212)) ([`9810d8545`](block@9810d85)) - feat(search): parse from:/in:/after:/before: and pass them in the filter ([block#2871](block#2871)) ([`cb2a265b5`](block@cb2a265)) - fix(desktop): fetch join policies through native networking ([block#2862](block#2862)) ([`0019f8076`](block@0019f80)) - fix(desktop): republish agent identity records when a persona rename propagates ([block#2607](block#2607)) ([`7ca0bbd94`](block@7ca0bbd)) - fix(desktop): keep project Inbox previews compact ([block#3193](block#3193)) ([`de1396050`](block@de13960)) - Inbox refactor ([block#2045](block#2045)) ([`2bd4c24b7`](block@2bd4c24)) - Fix composer selection formatting and drop overlay ([block#3172](block#3172)) ([`99da5b7eb`](block@99da5b7)) - Refine pending message status ([block#3153](block#3153)) ([`75588eaff`](block@75588ea)) - fix(desktop): recover full local storage on startup ([block#3182](block#3182)) ([`174c38e4b`](block@174c38e)) - fix(desktop): keep collapsed table separators out of spoilers ([block#3169](block#3169)) ([`4d8b676bb`](block@4d8b676)) - feat(desktop): redesign agent runtime settings ([block#3093](block#3093)) ([`d98da7389`](block@d98da73)) - fix(desktop): use forward slashes for git credential.helper on Windows ([block#3023](block#3023)) ([`899531684`](block@8995316)) - chore(desktop): add AgentCreationPreview file-size override to unblock main CI ([block#3154](block#3154)) ([`b92a1f4bf`](block@b92a1f4)) - fix(desktop): make the test loader work on Windows ([block#2758](block#2758)) ([`8bb43d519`](block@8bb43d5)) - fix(desktop): make lint and unit-test gates work on Windows ([block#2943](block#2943)) ([`545bb46b8`](block@545bb46)) - feat(desktop): add search to agent emoji picker ([block#2630](block#2630)) ([`313f793c8`](block@313f793)) - fix(desktop): keep identity key help dialog readable in dark mode ([block#2854](block#2854)) ([`be275cfc6`](block@be275cf)) - feat(acp): title agent sessions from the agent and channel name ([block#3028](block#3028)) ([`f2fe3b63c`](block@f2fe3b6)) - feat(git): use agent display name as git author name ([block#3040](block#3040)) ([`18eef633d`](block@18eef63)) - fix(deps): bump nostr to 0.44.6 for RUSTSEC-2026-0216 (NIP-44 remote DoS) ([block#3135](block#3135)) ([`31e2de196`](block@31e2de1)) - fix(desktop): read the newest pair-scoped harness log ([block#3134](block#3134)) ([`654f38490`](block@654f384)) - feat(desktop): handle project work from Inbox ([block#3117](block#3117)) ([`c5c4f390b`](block@c5c4f39)) - fix(desktop): clarify identity key button when key exists ([block#2357](block#2357)) ([`87b3fcd3c`](block@87b3fcd)) - Restore Goose and Buzz Agent to onboarding harness selection ([block#2731](block#2731)) ([`7fc0cc82d`](block@7fc0cc8)) - fix(desktop): render rich project work item content ([block#3100](block#3100)) ([`afb272bb7`](block@afb272b)) - feat(acp): bring your own harness (BYOH) — generic ACP runtime seam + settings gallery ([block#2773](block#2773)) ([`95fdf9788`](block@95fdf97)) - feat(desktop): use collective mesh routing for Auto ([block#2825](block#2825)) ([`16d4ec335`](block@16d4ec3)) - fix(desktop): strip legacy baked team instructions from stored prompts ([block#3035](block#3035)) ([`aee631448`](block@aee6314)) - feat(agents): lower default agent parallelism from 24 to 10 ([block#3038](block#3038)) ([`5d8ede446`](block@5d8ede4)) - Polish community rail and mobile pairing ([block#2972](block#2972)) ([`e6c90bb7c`](block@e6c90bb)) - fix(desktop): remove bundled libsystemd from AppImage ([block#2353](block#2353)) ([`a31fc4d2f`](block@a31fc4d)) - fix(desktop): make agent definition authoritative for model/provider/prompt ([block#1968](block#1968)) ([`8c0e8cb16`](block@8c0e8cb)) - chore(desktop): delete dead persona catalog UI cluster ([block#2886](block#2886)) ([`8e67cf399`](block@8e67cf3)) - fix(desktop): surface install failures hidden by curl-pipe exit codes ([block#2892](block#2892)) ([`166c6655e`](block@166c665)) - Refactor managed-agent runtime into cohesive modules ([block#2974](block#2974)) ([`74b63e184`](block@74b63e1)) - fix(desktop): make Linux AppImage GStreamer work on non-Debian distros ([block#2176](block#2176)) ([`cc6c4d347`](block@cc6c4d3)) - refactor(desktop): remove Agent directory section from Agents page ([block#2290](block#2290)) ([`5d1233e84`](block@5d1233e)) - fix(desktop): enable arboard Wayland backend so Linux copies reach the Wayland clipboard ([block#2904](block#2904)) ([`ab7aa8b12`](block@ab7aa8b)) - fix(desktop): supervise and re-arm relay-mesh runtime ([block#2823](block#2823)) ([`aa51dab9d`](block@aa51dab)) - fix(agents): run live Databricks discovery instead of the fallback list ([block#2890](block#2890)) ([`8eb6e3eb6`](block@8eb6e3e)) - fix(desktop): retire prepend mode on every reader wheel ([block#2913](block#2913)) ([`07d0265cf`](block@07d0265)) - fix(desktop): consolidate prepend scroll correction ([block#2855](block#2855)) ([`25e7864b3`](block@25e7864)) - fix(desktop): track concurrent agent turns up to the harness maximum ([block#2882](block#2882)) ([`20bff5910`](block@20bff59)) - fix(relay): preserve reconnect backoff ([block#2759](block#2759)) ([`499c5d349`](block@499c5d3)) - refactor(relay): expose reconnect timing policy ([block#2310](block#2310)) ([`2f0041595`](block@2f00415)) - fix(desktop): clear stale working badges on agent stop/restart ([block#2803](block#2803)) ([`a64cc71f6`](block@a64cc71)) - fix(desktop): surface agent rename relay profile sync failure as a warning toast ([block#2279](block#2279)) ([`5e3d2e484`](block@5e3d2e4)) - fix(discovery): inject PATH into Codex adapter planning ([block#2767](block#2767)) ([`6ab3835f3`](block@6ab3835)) **To release:** merge this PR. The tag and build will happen automatically. Signed-off-by: Wes <wesbillman@users.noreply.github.com>
## Buzz Desktop release v0.5.0 ### Changes since v0.4.26: - feat(invites): add use-limited invite links ([#3141](block/buzz#3141)) ([`a1a21319c`](block/buzz@a1a2131)) - fix(node): bump Buzz-supplied Node runtimes past OpenClaw's >=24.15.0 floor ([#3218](block/buzz#3218)) ([`c1cc8d9d1`](block/buzz@c1cc8d9)) - fix(desktop): preserve thread anchor through layout reflow ([#3212](block/buzz#3212)) ([`c3e816140`](block/buzz@c3e8161)) - feat(search): parse from:/in:/after:/before: and pass them in the filter ([#2871](block/buzz#2871)) ([`f19d7bbf8`](block/buzz@f19d7bb)) - fix(desktop): fetch join policies through native networking ([#2862](block/buzz#2862)) ([`dfe141fd5`](block/buzz@dfe141f)) - fix(desktop): republish agent identity records when a persona rename propagates ([#2607](block/buzz#2607)) ([`d3b18b48c`](block/buzz@d3b18b4)) - fix(desktop): keep project Inbox previews compact ([#3193](block/buzz#3193)) ([`31663bffc`](block/buzz@31663bf)) - Inbox refactor ([#2045](block/buzz#2045)) ([`e5c883c25`](block/buzz@e5c883c)) - Fix composer selection formatting and drop overlay ([#3172](block/buzz#3172)) ([`9d46311fb`](block/buzz@9d46311)) - Refine pending message status ([#3153](block/buzz#3153)) ([`4f3794b0a`](block/buzz@4f3794b)) - fix(desktop): recover full local storage on startup ([#3182](block/buzz#3182)) ([`ffdaacefd`](block/buzz@ffdaace)) - fix(desktop): keep collapsed table separators out of spoilers ([#3169](block/buzz#3169)) ([`8c50f64a6`](block/buzz@8c50f64)) - feat(desktop): redesign agent runtime settings ([#3093](block/buzz#3093)) ([`293d57357`](block/buzz@293d573)) - fix(desktop): use forward slashes for git credential.helper on Windows ([#3023](block/buzz#3023)) ([`fa4a3190e`](block/buzz@fa4a319)) - chore(desktop): add AgentCreationPreview file-size override to unblock main CI ([#3154](block/buzz#3154)) ([`cba753e4c`](block/buzz@cba753e)) - fix(desktop): make the test loader work on Windows ([#2758](block/buzz#2758)) ([`8c5c0b078`](block/buzz@8c5c0b0)) - fix(desktop): make lint and unit-test gates work on Windows ([#2943](block/buzz#2943)) ([`35391d5d9`](block/buzz@35391d5)) - feat(desktop): add search to agent emoji picker ([#2630](block/buzz#2630)) ([`cc560186a`](block/buzz@cc56018)) - fix(desktop): keep identity key help dialog readable in dark mode ([#2854](block/buzz#2854)) ([`329f2176c`](block/buzz@329f217)) - feat(acp): title agent sessions from the agent and channel name ([#3028](block/buzz#3028)) ([`f5b3743d9`](block/buzz@f5b3743)) - feat(git): use agent display name as git author name ([#3040](block/buzz#3040)) ([`11fdc3dea`](block/buzz@11fdc3d)) - fix(deps): bump nostr to 0.44.6 for RUSTSEC-2026-0216 (NIP-44 remote DoS) ([#3135](block/buzz#3135)) ([`79895680d`](block/buzz@7989568)) - fix(desktop): read the newest pair-scoped harness log ([#3134](block/buzz#3134)) ([`07bfb3139`](block/buzz@07bfb31)) - feat(desktop): handle project work from Inbox ([#3117](block/buzz#3117)) ([`068e33717`](block/buzz@068e337)) - fix(desktop): clarify identity key button when key exists ([#2357](block/buzz#2357)) ([`efc097d6a`](block/buzz@efc097d)) - Restore Goose and Buzz Agent to onboarding harness selection ([#2731](block/buzz#2731)) ([`1eb717304`](block/buzz@1eb7173)) - fix(desktop): render rich project work item content ([#3100](block/buzz#3100)) ([`a5e457d82`](block/buzz@a5e457d)) - feat(acp): bring your own harness (BYOH) — generic ACP runtime seam + settings gallery ([#2773](block/buzz#2773)) ([`84701fecc`](block/buzz@84701fe)) - feat(desktop): use collective mesh routing for Auto ([#2825](block/buzz#2825)) ([`6c0e93e1f`](block/buzz@6c0e93e)) - fix(desktop): strip legacy baked team instructions from stored prompts ([#3035](block/buzz#3035)) ([`02227d761`](block/buzz@02227d7)) - feat(agents): lower default agent parallelism from 24 to 10 ([#3038](block/buzz#3038)) ([`8baed7af9`](block/buzz@8baed7a)) - Polish community rail and mobile pairing ([#2972](block/buzz#2972)) ([`4c47d7af5`](block/buzz@4c47d7a)) - fix(desktop): remove bundled libsystemd from AppImage ([#2353](block/buzz#2353)) ([`05394d35c`](block/buzz@05394d3)) - fix(desktop): make agent definition authoritative for model/provider/prompt ([#1968](block/buzz#1968)) ([`50a3dd7c4`](block/buzz@50a3dd7)) - chore(desktop): delete dead persona catalog UI cluster ([#2886](block/buzz#2886)) ([`7575f8d1c`](block/buzz@7575f8d)) - fix(desktop): surface install failures hidden by curl-pipe exit codes ([#2892](block/buzz#2892)) ([`806feb9ed`](block/buzz@806feb9)) - Refactor managed-agent runtime into cohesive modules ([#2974](block/buzz#2974)) ([`b1a983734`](block/buzz@b1a9837)) - fix(desktop): make Linux AppImage GStreamer work on non-Debian distros ([#2176](block/buzz#2176)) ([`53e1752d3`](block/buzz@53e1752)) - refactor(desktop): remove Agent directory section from Agents page ([#2290](block/buzz#2290)) ([`f756b5828`](block/buzz@f756b58)) - fix(desktop): enable arboard Wayland backend so Linux copies reach the Wayland clipboard ([#2904](block/buzz#2904)) ([`3f2f3964e`](block/buzz@3f2f396)) - fix(desktop): supervise and re-arm relay-mesh runtime ([#2823](block/buzz#2823)) ([`c9607bd0f`](block/buzz@c9607bd)) - fix(agents): run live Databricks discovery instead of the fallback list ([#2890](block/buzz#2890)) ([`7d64ca7a8`](block/buzz@7d64ca7)) - fix(desktop): retire prepend mode on every reader wheel ([#2913](block/buzz#2913)) ([`dba1ba5ae`](block/buzz@dba1ba5)) - fix(desktop): consolidate prepend scroll correction ([#2855](block/buzz#2855)) ([`797933e4d`](block/buzz@797933e)) - fix(desktop): track concurrent agent turns up to the harness maximum ([#2882](block/buzz#2882)) ([`3115a39a0`](block/buzz@3115a39)) - fix(relay): preserve reconnect backoff ([#2759](block/buzz#2759)) ([`cd949e75a`](block/buzz@cd949e7)) - refactor(relay): expose reconnect timing policy ([#2310](block/buzz#2310)) ([`94c91f110`](block/buzz@94c91f1)) - fix(desktop): clear stale working badges on agent stop/restart ([#2803](block/buzz#2803)) ([`da2580e51`](block/buzz@da2580e)) - fix(desktop): surface agent rename relay profile sync failure as a warning toast ([#2279](block/buzz#2279)) ([`4d91195e9`](block/buzz@4d91195)) - fix(discovery): inject PATH into Codex adapter planning ([#2767](block/buzz#2767)) ([`795f2d12e`](block/buzz@795f2d1)) **To release:** merge this PR. The tag and build will happen automatically. Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Ubuntu Doctor reports
Install failed at verify: The installer finished, but Buzz still could not use claude-code (observed: CLI missing)while theclistep shows success. Theclistep is lying.The masking
Every CLI install command is a pipe —
curl -fsSL https://claude.ai/install.sh | bash(managed_agents/discovery.rs:109),… | shfor Codex (:141),… | CONFIGURE=false bashfor Goose (:75).install_shell_commandran them throughbash -l -cwith nopipefail, so the pipeline's exit status was the right-hand side's. Acurlthat fails — or that isn't on the child's PATH at all — feedsbashan empty stdin, andbashwith nothing to run exits 0:run_install_commandrecords exit 0 assuccess: true, the adapter step then installs fine (it uses Buzz's own bundled Node, no system PATH needed), andpost_install_verificationcorrectly reports the CLI is absent. The user is handed averifyriddle instead of curl's error, which is why diagnosing this required three rounds of guessing.Install commands now run under
set -o pipefail, so the left-hand side's failure is the step's failure andInstallStepResult.stderrcarries the vendor's own message.SHELLOPTSis not exported by either shell, so the piped-to vendor script still runs with its default options. The Windows PowerShell install path (install_powershell_command) bypasses this shell and is untouched.The PATH collapse it was hiding
install_shell_commandcomposes the child's PATH and callscmd.env("PATH", …), which replaces rather than extends.should_use_inheritedwasis_windows && !had_shell_path && has_local_context, so on Unix the inherited process PATH was never appended. Whenlogin_shell_path()returnsNone— a login shell that exits non-zero or prints nothing, which a GUI-launched process can easily hit via~/.profile— the child's entire PATH becomes Buzz's two managed Node dirs. There is nocurl,sh,sha256sum, ortarin either, so every curl-pipe install fails, and before this PR it failed invisibly.The
is_windowsrequirement is dropped: the inherited PATH is the floor whenever no login-shell PATH was obtained, on every OS. Both existing suppressions are kept — a login-shell PATH present still suppresses it (no doubling), and no home/exe context still suppresses it (never manufacture a PATH from ambient state alone). Inherited entries stay last, so managed dirs keep precedence.The other caller,
build_augmented_path(runtime/path.rs:148, feeding agent spawns and CLI probes), reads correctly under the new rule for the same reason: it only gains the inherited PATH in the case where it would otherwise hand a child a PATH with no native entries. When a login-shell PATH exists — the normal case on macOS and Linux — its output is unchanged, whichunix_shell_path_suppresses_inherited_fallbackpins.Scope
This fixes the reporting defect and the PATH floor. The specific environment failure on the affected Ubuntu box is still being diagnosed and is deliberately not addressed here; the point of this change is that the next attempt produces the real error instead of a
verifyriddle.One interaction worth noting:
install_failure_is_retryableretries any failure that carries an exit code, so a pipefail-surfaced curl failure now gets 3 attempts with backoff — correct for transient network blips, and harmless for hard failures.desktop/scripts/check-file-sizes.mjsratchets theagent_discovery.rsceiling 1836 → 1895 for the added tests.