fix(cli): handle broken pipes in command output - #2785
Conversation
|
@codex review |
|
I ran a local code review with Sol using medium reasoning effort. << Code review finished >>
• No actionable regressions were found. The focused output-helper tests and affected Rust binaries compile and pass.
Worked for 3m 16s · done 10:44 PM
• Copied Whole response to clipboard |
|
@fengmk2, just a heads-up that I was already working on #2661 after it was assigned to me, but it looks like another PR (#2784) was opened around the same time. I checked #2784 and left some feedback there regarding the process-wide SIGPIPE approach (#2784 (review)). In this PR (#2785), I took a scoped BrokenPipe handling approach instead and added regression snapshots for the reported commands. If the team prefers the direction in #2784, let me know and I'd be happy to close mine. |
|
How can we ensure that subsequent AI Agents will automatically comply with this specification? Avoid similar issues from occurring inadvertently in the future. |
This PR documents our broken-pipe handling policy in AGENTS.md to guide future AI agents toward using the shared output helpers when command output might be piped. The actual enforcement is handled in #2793, which migrates the remaining direct stdout calls and removes the crate-wide clippy::print_stdout allow. That way, if an agent slips up and uses println! or print!, Clippy will catch it in CI. Between the documentation in AGENTS.md and the Clippy check, this should keep regressions from sneaking in. |
This PR follows up on #2785. I updated the remaining print! and println! calls in vp_global_cli and vp_shared so they now use our shared output helper. I also removed the crate-wide attribute that allowed clippy::print_stdout across the board. Now, if an AI agent reading AGENTS.md accidentally adds a direct print call, CI will catch it right away. The main benefit here is that piping commands into tools like head, which close stdout early, will no longer cause a panic and can exit cleanly instead. This change does not affect the actual content or formatting of the output text.
Task cache settings now live under `cache`, and `vp migrate` moves existing task settings for you. `vp lint` and `vp fmt` run from a package directory now pick the same config as your editor, and piped `vp` output exits cleanly. ### Breaking Changes Task cache settings in `run.tasks` now go inside `cache` ([#2813](#2813), [#2814](#2814), [#2823](#2823), [vite-task#749](voidzero-dev/vite-task#749)), by @wan9chi. | Old (top level of a task) | New | | --- | --- | | `env` | `cache.env` | | `untrackedEnv` | `cache.untrackedEnv` | | `input` | `cache.input` | | `output` | `cache.output` | `cache: true` is the same as `cache: {}`. After upgrading, a task that still uses the old top-level fields fails with an error that points to `vp migrate`. Run `vp migrate` to move the fields in `vite.config.*` for the workspace root and every package. It warns about tasks in `vite.config.*` that it cannot rewrite safely. Tasks created in other modules, such as by a shared helper function, are not detected, so move their fields by hand; the error lists every task that still needs it. Projects whose tasks do not use these fields need no changes. See the [task cache migration rules](https://viteplus.dev/guide/migrate-rules#task-cache-configuration) and the [`cache` reference](https://viteplus.dev/config/run#cache). ### Highlights - `vp lint` and `vp fmt` run from a package directory now use the same config as Oxlint, Oxfmt, and the language server, so results match your editor. `vp check` still applies the workspace-root settings ([#2807](#2807)), by @fengmk2. - Global `vp` commands now exit cleanly when piped into a command that closes early, such as `vp --version | head -n 1`, instead of aborting with exit code 134 ([#2785](#2785), [#2793](#2793)), by @naokihaba. - Cached tasks on macOS no longer intermittently fail with `oils I/O error (main): No such process` ([vite-task#703](voidzero-dev/vite-task#703)), by @lifeiscontent. ### Features - The bundled tools update `vite@8.3.0` -> `vite@8.3.1`, `rolldown@1.2.9` -> `rolldown@1.2.11`, and `oxlint-tsgolint@7.0.2002` -> `oxlint-tsgolint@7.0.2003` ([#2805](#2805), [#2812](#2812)), by @voidzero-guard[bot]. ### Fixes & Enhancements - Async `defineConfig` callbacks now type-check lint and format options, such as `'warn'` rule severities, the same way as synchronous callbacks, so configs updated by `vp migrate` no longer fail with `TS2769` ([#2803](#2803)), by @TheAlexLichter. - `vp test --help` now lists the Vitest 5 options `--repeats`, `--injectCjsGlobals`, `--fsModuleCache`, `--fsModuleCachePath`, and `--sharedViteServer` ([#2809](#2809)), by @Marve10s. - On Windows, `vp run` now matches environment variable names regardless of letter case ([vite-task#747](voidzero-dev/vite-task#747)), by @wan9chi. ### Docs - The copy prompt dialog no longer nests scroll areas and shows clearer copy feedback ([#2794](#2794), [#2799](#2799)), by @liangmiQwQ and @Boshen. ### Chore - Snapshot tests share prepared packages and one Chromium process, run faster on every platform, and no longer read the live npm registry in the standalone npm fallback case ([#2771](#2771), [#2786](#2786), [#2797](#2797)), by @fengmk2 and @voidzero-guard[bot]. - The snapshot setup check links the local `vite-plus` package into its reference home instead of installing the version under release from npm, so it passes before that version is published ([#2819](#2819)), by @wan9chi. - The preview migration harness installs a project's committed dependencies before running `vp migrate`, so the Vitest 5 migration can read the original Vitest version ([#2822](#2822)), by @wan9chi. - The standalone install workflow loads the generated environment before running `vp env doctor` ([#2790](#2790)), by @naokihaba. ### Bundled Versions | Tool | Version | Source | | --- | --- | --- | | vite | `8.3.1` | [`39ddf7c`](vitejs/vite@39ddf7c) | | rolldown | `1.2.11` | [`8df4219`](rolldown/rolldown@8df4219) | | tsdown | `0.23.0` | [npm](https://npmx.dev/package/tsdown/v/0.23.0) | | vitest | `5.0.1` | [npm](https://npmx.dev/package/vitest/v/5.0.1) | | oxlint | `1.85.0` | [npm](https://npmx.dev/package/oxlint/v/1.85.0) | | oxlint-tsgolint | `7.0.2003` | [npm](https://npmx.dev/package/oxlint-tsgolint/v/7.0.2003) | | oxfmt | `0.70.0` | [npm](https://npmx.dev/package/oxfmt/v/0.70.0) | ### Upgrade ```bash vp upgrade ``` ### New Contributors @Marve10s **Full Changelog**: v1.0.0-rc.0...v1.0.0-rc.1 --- Merging this PR will trigger the release workflow. --------- Co-authored-by: voidzero-guard[bot] <278573678+voidzero-guard[bot]@users.noreply.github.com> Co-authored-by: wan9chi <me@wan9chi.com>
resolves #2661
Context
Piping commands into tools like
head(such asvp --version | head -n 1) aborted with exit code 134 becauseprintln!panicked onBrokenPipeunderpanic = "abort".To fix this, we added an output helper modeled after Oxc's
print_and_flush. It exits cleanly onBrokenPipe, retriesInterruptedandWouldBlocksafely, and bubbles up other errors.We migrated
--version,env list-remote, and environment cleanup to this helper, added unit and snapshot tests, documented the rule inAGENTS.md, and enabledclippy::print_stdouton these paths to avoid regressions.We considered restoring the default
SIGPIPEhandler instead, but that changes process-wide behavior. It can kill the process before cleanups run, might break IPC if components share the process, and runs too late inside#[tokio::main]to avoid thread race conditions. HandlingBrokenPipeat the write site avoids these global side effects.