* feat(#323): fish-shell support in post-install PATH suggestion Two additive changes to the post-install PATH-suggestion seam, both scoped to existing functions. A. Projection: add a fish entry to the persist-mode shell-action list in projectPathActionProjection() (src/shell-command-projection.cts). fish has no `export`/`$PATH`-list syntax, so the existing zsh/bash `export PATH=...` commands are inert when pasted. The new entry emits the fish-native `fish_add_path '<dir>'` (fish 3.2+, persists via the universal-variable store, de-duplicating). The directory is single-quoted with the same POSIX literal escaping as the zsh/bash siblings; verified round-tripping through real fish 3.7.0 for paths containing quotes, spaces, `$`, `*`, backticks and unicode. B. Detection: add homePathCoveredByFishConfig() in bin/install.js, called from maybeSuggestPathExport() alongside homePathCoveredByRc(). fish does not use sh-style `export PATH=` rc files, so a fish user whose fish_user_paths already covers the global bin would otherwise get a false-positive "not on your PATH" warning on every install. Two side-effect-free detection routes (no fish subprocess): 1. The universal-variable store (~/.config/fish/fish_variables). fish serializes this with `full_escape`: every byte outside [A-Za-z0-9/_] becomes `\xHH` (space -> \x20, `-` -> \x2d, `.` -> \x2e, `$` -> \x24, unicode -> \uXXXX) and list elements are joined by the literal 4-char token `\x1e` (NOT a raw 0x1e byte). The detector splits on `\x1e`, decodes the escapes, then compares each as an absolute literal — a decoded `$` is part of the directory name, not an unexpanded variable. Verified against real fish 3.7.0 output. 2. config.fish (`fish_add_path`, `set -gx PATH`, `set -Ux fish_user_paths`) — plain shell tokens: HOME forms ($HOME/${HOME}/~) are expanded and a token still holding `$` (e.g. `$PATH`, `$fish_user_paths`) is skipped. Honours $XDG_CONFIG_HOME and always also checks ~/.config/fish. No behaviour change for bash/zsh/PowerShell/cmd/Git-Bash users: their entries and command strings are unchanged; the fish entry is additive and the fish detector only narrows the set of cases that warn. Tests: update the projection length assertion (2 -> 3) and fish escaping in bug-3441; add fish detection + suppression cases in install-path-detection (uvar store with real fish escaping, dot/hyphen/space/$-literal decode regressions, config.fish routes, commented-out, relative-segment guard, unreadable-file fault injection, suppression and emission via maybeSuggestPathExport). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(changeset): add Changed fragment for #323 fish PATH support (#727) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#323): address review — action-only fish docs, decoder property test, win32 guard Addresses @trek-e's review on #727: - docs (blocker): keep the how-to action-only (Diátaxis). Drop the `# fish — persists via …` comment and the internal-mechanism clause naming fish_variables/config.fish; leave one command + the exec-fish directive. - tests (minor): extract decodeFishUniversalValue to a pure, exported module function and add fast-check round-trip properties (decode(fishEscape(p)) === p over arbitrary unicode, abs-path variant, totality). Consolidated into install-path-detection.test.cjs to respect the install test-file-count ratchet. - tests (follow-up): port #721's win32 negative-projection test (no fish action on win32; persist projection is PowerShell/cmd.exe/Git Bash). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#323): address review — drop unused 'after' import, clarify escaping comment Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
4.8 KiB
4.8 KiB