mirror of
https://github.com/max-sixty/worktrunk.git
synced 2026-09-14 20:00:38 +08:00
codex/remove-codex-cloud-specific-tests
105 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
13bc27e70a |
fix(shell): preview and confirm legacy-file removal on shell install (#3648)
## Problem
`wt config shell install` reclaims its own legacy wrapper paths after
installing to the canonical location — the fish `conf.d/{cmd}.fish`
(#566) and stranded nushell autoload copies (#2878). That reclaim is
deliberate and documented, but the deletion never appeared in anything
the user saw *before* it happened (#3644):
- `--dry-run` returned an empty `legacy_cleanups`, so a preview run
never mentioned the file it would remove.
- The confirmation prompt was passed only the files to *add* — the
legacy removals weren't in the `?` preview.
- When everything was already configured, the cleanup ran and returned
**without prompting at all**, deleting a hand-written `conf.d/wt.fish`
as a silent side effect.
Removals were reported after the fact (`Removed <old> (deprecated; now
using <new>)`), so nothing was silent — but it was after the fact, and
repo policy is that destructive operations get explicit consent.
## Solution
The two cleanup helpers now take a `dry_run` flag: with it set, the same
detection runs but nothing is removed, so the paths a real install
*would* delete can be computed up front. `handle_configure_shell`
collects that list once and threads it into `show_install_preview` and
`prompt_for_install`, so both `--dry-run` and the `?` preview render a
`Will remove <old> (deprecated; now using <new>)` line — the
after-the-fact message in the future tense.
The already-configured branch now prompts (`Remove deprecated shell
integration files?`) when there is anything to remove, and preserves the
file on decline. `--yes` still skips the prompt and removes as before,
so no existing non-interactive flow changes.
## Testing
- New `test_configure_shell_fish_dry_run_previews_legacy_removal` —
`--dry-run` now names the legacy `conf.d` removal on stdout and leaves
the file in place.
- New
`test_configure_shell_fish_legacy_removal_declined_when_already_configured`
— declining the prompt in the already-configured branch exits non-zero
and preserves the file (the core consent gap).
- The existing
`test_configure_shell_fish_dry_run_does_not_delete_legacy` snapshot was
updated to include the new `Will remove …` preview line; its "must NOT
delete" file assertion still holds.
- Verified manually end-to-end (dry-run preview + declined removal both
preserve the file), and ran the full `configure_shell`,
`shell_integration_prompt`, and nushell test suites plus clippy and the
doc-sync test.
---
Closes #3644 — automated triage
---------
Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
|
||
|
|
9032308400 |
refactor(tests): give the PTY test environment one home (#3618)
Follow-up to #3616, which fixed a PTY snapshot flake by adding one env knob — and to add it I had to touch three separate env builders, none of which knew about the others. This consolidates that surface. ## What was there The environment a test subprocess runs in was assembled at nine sites: five copies of the PTY prologue (`env_clear`, HOME, PATH, the Windows block, coverage passthrough) and four partial restatements of the determinism knobs. There was no rule for which belonged where, so adding a knob meant finding every copy, and a missed copy surfaced later as a flake somewhere unrelated. ## What's there now Three named layers, each with one home in `src/testing/mod.rs`: | Layer | Home | Contents | |---|---|---| | Baseline | `STATIC_TEST_ENV_VARS` | knobs every child needs, whatever it's attached to | | Terminal | `PTY_TEST_ENV_VARS` (new) | knobs only a TTY triggers — `WORKTRUNK_TEST_SPINNERS=0` | | Fixture | `pty_env_vars(TestEnvPaths { … })` (new) | the paths that vary per fixture | `configure_cli_command` and `configure_pty_command` apply them by transport. That turns the standing `// NOTE: TERM is intentionally NOT in STATIC_TEST_ENV_VARS` comment into a consequence rather than an exception: `TERM` is transport-level, so it can't sit in a baseline both transports share. `WORKTRUNK_TEST_SPINNERS` stays out of the shared baseline deliberately. It's inert on a pipe, and insta-cmd records the whole environment into every snapshot it writes (`Info::from_std_command` builds it unconditionally from `cmd.get_envs()` — there's no hook to suppress it), so putting it there would add a no-op line to 1043 snapshot files. `configure_pty_command` is now the only place a PTY child's isolation is set up. `shell_command`, `execute_shell_script`, `configure_pty_environment`, `exec_in_pty_shell`, `exec_bash_truly_interactive` and two `wt switch` spawns all delegate to it. `shell_wrapper`'s `STANDARD_TEST_ENV` and `bare_repository`'s hand-rolled `test_env_vars` are gone, as are `configure_shell`'s hand-copied knobs and four redundant `CLICOLOR_FORCE` lines in `switch_picker`. Net −149 lines. One spawn stays outside: the Windows ConPTY smoke test, which runs PowerShell against a deliberately bare environment and isn't a wt child at all. ## Reviewing Start at `src/testing/mod.rs` — the three layers and their doc comments are the whole design. Everything under `tests/` is deletion plus a delegation call. Two snapshots change: `install_preview_with_gutter` and `install_preview_declined` now carry ANSI, because those two tests previously ran without `CLICOLOR_FORCE`. Text is identical. Arguably a fix — the test named "with_gutter" couldn't see the gutter (a background-color block), while its own prompt line was already colored, so the file was internally inconsistent. ## Testing Full `wt hook pre-merge --yes` green: 4601 tests, `--features shell-integration-tests`, `RUSTFLAGS='-D warnings'`, `insta --check`. The knob's delivery path was verified by probe rather than by inspection. With `sleep 6` in the mock `llm`, `test_readme_example_hooks_pre_merge` passes; flipping `PTY_TEST_ENV_VARS` to `"1"` reproduces the original failure byte for byte: ``` +␛[1G␛[J␛[2m↳␛[22m ␛[2mWaiting for the commit generation command (4s)␛[22m␛[1G␛[J␛[2m↳␛[22m ␛[2mWaiting for the commit generation command (5s)␛[22m ``` So the knob reaches the shell-wrapper PTY child through the shared setup, not through a surviving copy. Both probe edits are reverted. > _This was written by Claude Code on behalf of max_ Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
9645e3e132 |
fix(shell): reclaim the legacy wrapper paths instead of inspecting them (#3602)
`wt config shell install` decided whether the file at a legacy location
was worktrunk's by reading it — a substring test for the wrapper header,
falling back to "every code line looks like an integration line".
Anything that didn't match was left in place. Fish sources `conf.d` at
startup, so whatever `conf.d/{cmd}.fish` defines is already loaded by
the time fish would autoload the `functions/{cmd}.fish` the install just
wrote — the stale definition wins and the new wrapper may never load.
Ownership is now the path. `conf.d/{cmd}.fish` and the stranded nushell
`{cmd}.nu` candidates are paths worktrunk itself computes for the
command name being installed, so install takes them back whole without
reading them. Only that exact filename is touched: a neighbour under
another name is not worktrunk's, and each removal is still reported.
`wt config shell uninstall` still reads the header, because it takes no
`--cmd` and so genuinely doesn't know the name — it lists the
shell-owned directories and has to tell our `{cmd}.fish` from the user's
own files beside it. That is the one place ownership can't come from the
path, and it prompts and previews every file before removing it, which
install does neither of. `is_worktrunk_managed_content`'s docstring now
says so; `is_worktrunk_managed_nushell` existed only to gate the
install-time deletion and is gone.
Audited the rest of the surface for the same principle: the OpenCode
plugin (`~/.config/opencode/plugins/worktrunk.ts`) is already removed by
path with no inspection, the Claude plugin delegates to `claude plugin
uninstall`, Gemini installs through `gemini extensions install` and
leaves nothing of ours on disk, and fish is the only shell with a
separate completion file — which uninstall already covers. No other
gaps.
## Data safety
This deliberately widens what install deletes, so it's worth naming: two
tests asserted the old conservatism and now assert the new boundary —
`test_configure_shell_fish_reclaims_conf_d_path` (was
`..._preserves_user_conf_d_file`, from #3589) and
`test_nushell_install_reclaims_only_the_command_name` (was
`..._keeps_unmanaged_legacy_file`, from #2992). Both put a neighbour
file in the same directory to pin that only `{cmd}.{ext}` is taken. The
FAQ's "What can Worktrunk delete?" inventory is updated to describe
path-based ownership rather than the old content-marker rule.
> _This was written by Claude Code on behalf of max_
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
b623d7f951 |
fix(shell): don't delete user data that only mentions the init command
Three places decided whether text was worktrunk's by testing a blob for
substrings. Two of them deleted the user's data when they guessed wrong.
`wt config shell uninstall` asked two unlinked questions of an rc line —
is an exec keyword anywhere in it, and is `<name> config shell init`
anywhere in it — so `alias setup='echo "run: wt config shell init fish |
source"'` classified as worktrunk's and was removed. One question
replaces both: does the line invoke the init command, with the name in
command position? The exec-keyword scan is gone rather than kept
alongside; it read English words out of the whole line and rejected
nothing the positional rule doesn't.
`wt config shell install` had the same defect one file over and one step
worse: `is_worktrunk_managed_content` tested the whole file for
`config shell init` and `| source`, and `cleanup_legacy_fish_conf_d`
deleted a user's own `conf.d/wt.fish` outright — during an install, which
never offered to remove anything. The cmd-agnostic twin beside it already
answered correctly, so the substring version is gone.
Uninstall now prints every line it takes, in the confirmation and again
after removal, since shell quoting stays undecidable without running the
line.
Sweeping for the same shape found it in `az` failure classification,
where `stderr.contains("login")` alone meant "not authenticated" and
`bail!` discarded the real error; `az` states the remedy itself, so its
text now reaches the user. Provider host matching moved from
`contains("github")` to label-boundary comparison, so
`dev.azure.com.attacker.example` and `mygithubmirror.com` no longer
resolve to Azure DevOps and GitHub.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
f9cd38eb88 |
fix(shell): validate command names and tighten install/uninstall detection (#2864)
Two shell-integration correctness fixes plus an uninstall-scope
redesign.
**Command-name validation.** The shell-integration command name comes
from the user-typed `--cmd` flag, or `argv[0]` when `--cmd` is omitted.
A malformed value (an empty string, a leading `-`, or characters like
`;` or whitespace) renders into a broken shell rc line that the user
then has to find and fix. `validate_shell_command_name()` rejects empty,
leading-`-`, and non-`[A-Za-z0-9._-]` names at the CLI entry points, so
a bad value produces a clear error up front instead of a silently broken
config file. This is input hygiene on a value the user already controls,
not a security boundary.
**Noncanonical-line detection on install.** Install recognized only its
exact current canonical line, so a manually-added or older-form
integration line (e.g. `eval "$(wt config shell init zsh)"`) was not
seen as already-present and a duplicate was appended on the next
`install`. It now detects those forms and reports already-configured.
**Uninstall scans every worktrunk-managed file, regardless of cmd.**
Previously `uninstall` located Fish/Nushell wrapper files by name
(`{cmd}.fish` / `{cmd}.nu`), so removing integration installed under an
alternate binary name needed a matching `--cmd`. That symmetry leaked an
implementation detail: uninstall already has a content marker to
recognize worktrunk wrappers regardless of binary name. It now scans the
wrapper directories (`~/.config/fish/functions`, `conf.d`; the nushell
candidates' `vendor/autoload`) and admits every file whose content
matches the cmd-agnostic marker `# worktrunk shell integration for
<shell>` (always emitted by the wrapper templates). A headerless file
(the legacy `conf.d/{cmd}.fish`, which held nothing but the init line)
qualifies only when every non-blank, non-comment line is an integration
line, so a user's own file that runs or merely mentions `wt config shell
init` amid other code survives the scan. Fish completion files carry
their own `# worktrunk completions for` header and are scanned the same
way, so a completion whose wrapper is already gone is still cleaned up.
For Bash/Zsh/PowerShell (line-based),
`is_shell_integration_line_for_uninstall_any_cmd` reads the binary name
off the line rather than pattern-matching it. `config shell init` is a
fixed literal, so the name is the run of command-name characters ending
at it, held to the same `validate_shell_command_name` rule that governs
what worktrunk writes into shell code. The execution-context check that
pairs with it is a line-level property, so it lifts out of the
per-position loop it used to sit in, which is what let both cmd-agnostic
detectors drop their regexes. Since the result asks only whether a line
is worktrunk's, not which install owns it, uninstall also removes
hand-written `git wt config shell init` lines, and it cleans every
matching profile file rather than the first (both PowerShell profiles on
Windows). All detection reads only the code portion of a line: a
trailing `#` comment can mention an integration line without running it,
so uninstall does not delete an unrelated `eval`/`source` line over a
comment, and install does not treat such a mention as
already-configured. The cmd-specific permissive detector lost its last
caller in this cutover and is deleted.
The `--cmd` flag is removed from `wt config shell uninstall`; `install`
keeps it (installing under an alternate name is still a deliberate
per-cmd act). The FAQ's "What can Worktrunk delete?" inventory documents
the widened uninstall surface.
Covered by new integration tests: custom-cmd install + cmd-less
uninstall round-trips for zsh/fish/nushell (verifying scan-all removes
the custom-cmd integration, a hand-written `git wt` line, a stale second
wrapper, and an orphaned completion), a PowerShell uninstall round-trip
on the old pre-`Out-String` line, malformed-name rejection at the CLI
edge (`--cmd` and `argv[0]`), and the older-line dedup case. Unit tests
pin the deletion criterion: worktrunk's own wrappers and the headerless
legacy init file match; a file that mentions the integration, or runs it
amid other code, does not.
> _This was written by Claude Code on behalf of Maximilian Roos_
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Worktrunk Bot <w@worktrunk.dev>
Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
|
||
|
|
a6972e4be0 |
fix(shell): detect the current shell from the process tree, not $SHELL (#3455)
`wt switch` could tell a fish user "shell requires restart" because `$SHELL` (the login shell, say zsh) had the integration line while the shell actually in use didn't. `current_shell()` keyed everything on `$SHELL`, which names the login shell rather than the shell wt was invoked from. **Process-tree detection.** `shell::ancestor_shell()` (src/shell/utils.rs) walks up from wt's parent to the nearest enclosing shell: Linux reads `/proc/<pid>/stat`; macOS parses one `ps -Ao pid=,ppid=,comm=` snapshot. macOS cannot use per-pid `p_comm` (libproc/sysctl): `/bin/sh` re-execs bash via `/var/select/sh`, so an sh script's `p_comm` reads "bash", while `ps`'s comm preserves argv[0]. Verified live and pinned by `test_probe_reports_invoked_name_for_sh`. The walk passes through non-shell wrappers (`git`, `sudo`) and plain script interpreters (`sh`, `dash`); a known-but-unsupported interactive shell (tcsh, ksh) stops the walk so a shell further up can't claim the session. `current_shell()`/`current_shell_name()` consult the walk first and fall back to `$SHELL` / `PSModulePath` (Windows behavior unchanged; Git Bash sets `$SHELL` itself). **Hedged messaging.** The reason string is now "shell integration installed but not active", and the hint presents restart as the likely fix with an escape hatch: "A shell restart usually activates shell integration; if it doesn't, ask an agent to debug with the docs @ https://worktrunk.dev/llms.txt" (the LLM docs index works for any agent; the `/worktrunk` skill exists only for plugin users). Post-install hints are unchanged (restart advice there is unconditional by construction). `wt config show` now prints `Detected shell: <name> (process tree)` next to `$SHELL` in the diagnostic gutter. **Also fixed along the way:** `shell_from_name` requires a word boundary, so `fishd`/`bashtop`/`numactl` no longer classify as shells (`numactl` previously matched Nushell via the bare `nu` prefix); the post-install/uninstall restart hints compare `Shell` values instead of display strings, which never matched process-tree names like `pwsh` or `zsh-5.9`. **Testing.** Integration tests spawn wt under a test harness whose real ancestry (nextest, cargo, the developer's shell) would leak in, so `WORKTRUNK_TEST_PARENT_SHELL` is pinned empty in `STATIC_TEST_ENV_VARS` (and in the two PTY helpers that mirror it by hand, which CI round 1 caught: locally the walk found the dev zsh, on CI the runner's bash) and set per-test to simulate ancestors. New integration tests cover the three detection outcomes (mismatch suppresses restart advice, configured ancestor shows the hedged hint, unsupported ancestor overrides `$SHELL`); unit tests cover the classifier, the walk itself (injectable process-table lookup: wrapper pass-through, transparency, cycle/depth/init terminations), and both OS probes against live processes; `wt config show` is snapshot-tested with an override ancestor and run once unpinned so the production walk executes end-to-end. Known limits, accepted: the walk stops at the nearest supported shell even when it's a non-interactive script interpreter (`bash -c` wrapping wt reports bash), hence the hedged wording; the walk is bounded at 16 hops and any unreadable hop falls back to `$SHELL`. > _This was written by Claude Code on behalf of max_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
3ea7392a65 |
fix: bound config-show's zsh probe and isolate tests from host env (#3165)
Bounds the `wt config show` zsh compinit probe with a 2s kill-on-timeout (the only un-bounded interactive shell spawn in production), matching its twin `shell::detect_zsh_compinit`. Also isolates several tests from host environment: `TZ=UTC` in the statusline helper, `--no-config-file` on the nu probes, and the `wt --help` / `git log` spawns routed through the isolated `wt_command()` / `repo.git_command()` helpers. The macOS PTY-test hang that prompted the audit is fixed structurally in #3161. > _This was written by Claude Code on behalf of max_ Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
9a58ad27e8 |
refactor(output): route --dry-run previews to stdout (#3085)
Adopt one stdout/stderr rule across the CLI: stdout carries the command's answer in whatever format the user selected (human or `--format=json`), including `--dry-run` previews; stderr carries narration (progress, success/warning/error, hints, interactive prompts, `-v`/`-vv`). A `--dry-run` is the answer when nothing mutates, so the preview goes to stdout, matching `wt list` / `wt config show`, the wider ecosystem (`git clean -n`, `rsync -n`, `terraform plan`), and keeping paging working. Five commands had their `--dry-run` human preview moved from stderr to stdout: `wt hook <type>`, `wt step relocate`, `wt step prune`, `wt step copy-ignored`, and `wt config shell install/uninstall`. For split previews the human output mirrors exactly what `--format=json` already puts on stdout; narration the json omits (prune's skipped-young caveat, "nothing to do" no-ops) stays on stderr. The shell preview renderers return a `String` so the caller picks the sink: `--dry-run` to stdout, the interactive `?` re-preview to stderr. Documented in the `writing-user-outputs` skill and `src/commands/CLAUDE.md`. |
||
|
|
5fba0bdc9b | refactor(tests): remove byte-normalization snapshot filters (#3061) | ||
|
|
f2a8cb696d |
refactor(styling): end bash-gutter lines at their content, not a reopened dim (#3056)
Dispatched to fix a reported ANSI dim-bleed after bash-gutter blocks: in committed snapshots, multi-command hook announcements appear to inherit an unclosed `[2m` from the preceding gutter line (e.g. `post_start_named_commands.snap`, where the gutter line ends `'Installing deps'[0m[2m`). Diagnosis: the bleed doesn't exist in real output. Fresh `cat -v` captures of `wt hook pre-merge --yes` and `wt switch --create` with two-key hook tables show every gutter line closing with a full `[0m`, and later `◎ Running …` lines rendering un-dimmed. The snapshots are misleading by construction: the cross-platform filter in `tests/common/mod.rs` deletes every line-final `[0m` before snapshotting, and the formatter reopens dim after the last highlight token before its per-line reset, so filtered snapshots end `[0m[2m` and read exactly like a dangling dim. The change removes that misleading byte pattern at the source: phase 2 of `format_bash_with_gutter_impl` strips the no-op reopened dim (and the lone dim on blank lines) before appending each line's closing reset. Rendering is identical; lines now end at their content plus one reset. Also bundled: - A CAUTION comment on the reset-stripping snapshot filter, so future readers don't diagnose SGR bleed from `.snap` bytes. - `config_show_theme` now binds the standard env redactions; regenerating its snapshot leaked a host `LLVM_PROFILE_FILE` path and tripped `test_no_host_specific_paths_in_snapshots` (pre-existing gap, invisible until regeneration since insta never compares `info:` blocks). - 108 regenerated snapshots. Verified mechanically: ANSI-stripped bodies are byte-identical; raw diffs are confined to line-end SGR sequences plus stale `env:` header refreshes (`RUST_LOG: warn` from an older harness). Possible follow-up, not done here: the line-final-reset filter itself may be vestigial (anstream pass-through suggests piped output is identical across platforms now); removing it would make snapshots byte-truthful but churns nearly every snapshot and needs Windows CI to confirm. The first Windows CI run caught a real latent bug the strip exposed: askama strips a template's final newline, so on a CRLF checkout (Windows autocrlf) the fish wrapper render ends with a lone `\r` that the formatter's pair-wise CRLF normalization missed. The `\r` reached tree-sitter and came back as a trailing token after the highlight closed, defeating the end-of-line cleanup (and historically invisible because insta trims trailing whitespace when comparing). Fixed by trimming trailing `\r` in the formatter's normalization, plus `templates/* text eol=lf` in `.gitattributes` since CRLF templates embedded at compile time would leak `\r` into the shell code Windows-built binaries emit at runtime. 🤖 Generated with [Claude Code](https://claude.com/claude-code) > _This was written by Claude Code on behalf of max_ --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
b75b3cf1a7 |
fix(shell): install nushell wrapper to vendor-autoload dir (#2878) (#2992)
Fixes #2878. Implements the approach agreed in the issue: query `$nu.vendor-autoload-dirs` directly and install to its last (user-writable) entry, with cross-platform tests and stranded-file cleanup on install/uninstall. ## The bug The nushell integration wrote `wt.nu` to `$nu.default-config-dir/vendor/autoload`, which Nushell **never autoloads**. It happened to work on macOS/Windows because there `$nu.default-config-dir == $nu.data-dir`, so the wrong subpath resolved to the real vendor dir; on Linux the wrapper was written but silently never loaded — so `wt` was never wrapped. Verified against `nu` 0.113.1: `$nu.vendor-autoload-dirs | last` is `<data-dir>/vendor/autoload`, and `$nu.default-config-dir/vendor/autoload` is in neither `$nu.vendor-autoload-dirs` nor `$nu.user-autoload-dirs`. ## The fix - **Resolve the install target from `$nu.vendor-autoload-dirs | last`** (one memoised `nu` spawn that also reads `$nu.default-config-dir` for legacy cleanup). - **Fallback when `nu` isn't on PATH** mirrors nushell's own `nu_path::data_dir`: `XDG_DATA_HOME` (when absolute) wins on every platform, otherwise `dirs::data_dir()` — matching nushell on Linux/macOS/Windows. - **Wrapper-based shells now always write to the canonical location** (`paths.first()`), so a wrapper stranded at a legacy path can't become the write target. (No-op for fish, which has a single canonical path.) - **Stranded-file cleanup**: install writes the correct path and removes any worktrunk-managed wrapper left under the legacy `<config-dir>/vendor/autoload` locations; uninstall already iterates every candidate, which now includes those legacy paths. Legacy files are only removed when they carry the `# worktrunk shell integration for nushell` header, so a user's own `wt.nu` is never touched. - `config_line`, the `wt config shell init` manual-setup help, and the FAQ/shell-integration docs now use `$nu.vendor-autoload-dirs | last | path join wt.nu`. ## Tests - New `WORKTRUNK_TEST_NU_VENDOR_AUTOLOAD_DIR` override pins the install dir so the install/uninstall/cleanup tests are **deterministic on Linux, macOS, and Windows** and don't depend on `nu` being installed. - New `test_nushell_install_target_is_a_vendor_autoload_dir` (gated on `shell-integration-tests`, where CI has `nu`) runs the **real `nu` flow** and asserts the wrapper worktrunk wrote is a member of `$nu.vendor-autoload-dirs`. This fails against `main` (the old config-dir path is in neither autoload list) and passes with the fix. - New `test_nushell_install_cleans_stranded_legacy` and a reworked `test_uninstall_nushell_cleans_all_candidate_locations` cover the migration cleanup. - Existing nushell tests updated to the data-dir path; full suite green (`cargo test --lib` + `cargo test --test integration`, and the nushell subset with real `nu` under `--features shell-integration-tests`). ## Not in scope "Not best practice" cleanup flagged in the issue (the overlap between the candidate-building helpers, and the dubious Windows branch) — the helpers here are restructured around the autoload model, but a broader tidy can be a follow-up. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
76754ca076 |
fix(output): correct user-output consistency defects (#2867)
An audit of `wt`'s user-visible strings against the repo's
`writing-user-outputs` skill. Six consistency corrections, each matching
a rule the skill states — and, in most cases, a sibling message that
already follows it:
- `RefCreateConflict` hint: dropped the cross-message pronoun ("it") and
switched to the skill's `"To X, run Y"` command-hint form.
- `"All shells already configured"` and the version-check `"Up to
date"`: `success ✓` → `info ○` — both acknowledge existing state without
changing anything.
- `relocate` summary: keyed the message type on whether anything was
*relocated*, not on whether anything was *skipped* (the same outcome was
rendered two ways).
- `"Diagnostic saved"`: → `success` (a file was created) and the
`@`-before-path convention.
- Removed a stray trailing period — the only single-line message in the
codebase that had one.
`--no-verify` is deliberately untouched (handled in the
`canonical-paths` PR). Snapshot tests updated.
> _This was written by Claude Code on behalf of Maximilian Roos_
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
73f7c48500 | fix(shell): label nu/pwsh as "shell extension & completions" (#2705) | ||
|
|
2b0c0f3f99 | fix(shell): correct shell-extension label inversion for nu/pwsh (#2699) | ||
|
|
5144b1fbdc |
style(output): bold paths in warning messages (#2677)
Two follow-ups from the #2674 review session, plus a coverage fix. `style(output)`: with the cross-platform bold-around-placeholder trap closed in #2674, paths in warning messages can be styled per the `writing-user-outputs` convention. Bolds the path in four warning sites — config-file-not-found (user config load), failed-to-remove-deprecated (legacy fish migration), completions-not-configured and outdated-shell-extension (both in `wt config show`). `refactor(test)`: inlines `setup_snapshot_settings_impl` into its two callers. The wrapper only allocated an empty worktrees map; both callers now call `setup_snapshot_settings_for_paths_with_home` directly. `test(configure-shell)`: covers the legacy fish cleanup remove-failure branch that the styling commit lit up under `codecov/patch`. Unix-only — chmods the conf.d dir read-only so `fs::remove_file` returns EACCES, then asserts the install succeeds and emits the warning. Skips when running as root. --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
302575894a |
fix(output): bold identifiers in skipped/squash/path messages (#2661)
## Summary Several user-facing messages interpolated branch, worktree, file, and path names as plain text. Per the project's `writing-user-outputs` skill, branches and status values should be bolded; in hints, paths use underline. ## Changes - `wt step prune` "Skipped … (younger than X)" lines now bold each branch name. The joined-list variant bolds names individually so commas stay unbold. - `wt step squash`'s "Nothing to squash; no commits ahead of `<branch>`" bolds the branch. - `wt config update`'s "Copied approved commands to `<file>`" bolds the filename. - `ConflictingChanges` hint underlines the path (hint convention). - Config-load warning: `at PATH` → `@ <bold>PATH</>` (matches the codebase `@`-not-`at` convention and bolds the identifier). - Explicit-shell uninstall warnings bold the path so they match the hint counterpart. ## Test plan - [x] `cargo test --test integration` (1634 passing) - [x] `pre-commit run --all-files` (lints + fmt clean) - [x] Snapshots updated via `cargo insta accept` — all diffs are exactly the formatting changes plus cosmetic env-var drift --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
bd11961030 |
test(config): exercise WouldCreate arm in fish legacy migration test (#2607)
## Summary Follow-up to #2591. The codecov/patch miss on the `ConfigAction::WouldAdd | WouldCreate` call site of the new `render_fish_legacy_migration` helper traced to the test that was supposed to cover it (`test_config_show_fish_legacy_with_functions_dir`). The test sets up an empty `functions/` directory plus a legacy `conf.d/wt.fish`, intending fish to be detected as configured-with-`WouldCreate`. But without `WORKTRUNK_TEST_FISH_INSTALLED=1`, fish was treated as not installed and routed into `scan_result.skipped` instead — the migration hint was emitted from the skipped loop, and the configured-WouldCreate call site stayed uncovered. Setting the env var (matching the convention in the adjacent `test_configure_shell_skipped_lists_only_installed_shells`) routes fish into the configured arm, where `ConfigAction::WouldCreate` fires because `functions/wt.fish` doesn't exist. No production code changed; output is identical because the helper produces the same string from either call site, so the only snapshot change is the captured env var flipping from `"0"` to `"1"`. ## Test plan - [x] `cargo run -- hook pre-merge --yes` (all 3492 tests pass, lints pass) - [x] Snapshot diff is just the env-var line; stdout unchanged - [ ] codecov/patch on the WouldCreate arm flips to covered 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
61046fb108 |
fix(config): iterate PowerShell uniformly with other shells (#2581)
## Summary - Adds PowerShell to `default_shells` unconditionally; the `Shell::is_installed()` filter (added in #2574) now hides `Skipped pwsh` on hosts without pwsh, the same way `Skipped fish` is hidden on a stock zsh-only Mac - `should_auto_configure_powershell()` still gates `allow_create`, so users who have pwsh installed but never opened it don't get an unsolicited profile written (issue #885 behavior unchanged) - Removes the iteration asymmetry that left PowerShell invisible in `wt config show` for users who configured a profile but aren't currently in a PS session ## Visible changes | Host state | Before | After | |---|---|---| | pwsh on PATH, profile exists, not in PS session | invisible | shown as `configured` | | pwsh on PATH, no profile, not in PS session | invisible | `Skipped pwsh; profile not found` | | pwsh absent | invisible (iteration gate) | invisible (`is_installed()` filter) | | in PS session, no profile | auto-creates | auto-creates (unchanged) | ## Test plan - [x] `cargo test --test integration` (1622 passed) - [x] `pre-commit run --all-files` - [x] Extended `test_configure_shell_skipped_lists_only_installed_shells` to flag pwsh installed and assert it appears as `Skipped` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
c2e38f6347 |
fix(config): clean up wt config show shell-integration section (#2574)
On a stock zsh-only macOS, `wt config show` listed `bash`, `fish`, and `nu` as `Skipped; ~/.foorc not found` — clutter for shells the user doesn't have installed. The block was the loudest thing in the SHELL INTEGRATION section for users who'd never touch those shells. After this PR, that fresh-user case shows just the warning + install hint with no per-shell clutter. Together with #2572 (which renamed the warning to "not configured" in this state), the section reads: ``` SHELL INTEGRATION ▲ Shell integration not configured ↳ To configure, run wt config shell install Invoked as: … $SHELL: /bin/zsh ``` ## What changed Adds `Shell::is_installed()` (PATH lookup with `WORKTRUNK_TEST_<SHELL>_INSTALLED` env override) and gates the `skipped.push` in `scan_shell_configs`. Shells with rc files still render normally — the filter only affects the "binary absent AND no rc file" case, which is exactly when the entry has no useful information. `nu` and `pwsh` are filtered cleanly because neither ships with macOS/Linux. `bash` and `zsh` on macOS still report (`/bin/bash` and `/bin/zsh` are preinstalled), but that's the honest answer. Side fixes: - Removed a redundant `Err("No shell config files found")` from `scan_shell_configs`. The install command's main.rs handler already covered this case. - Made the blank line between header status and the per-shell list conditional, so the trailing `↳ To configure…` hint stays attached to its subject when no shells render. - Replaced the standalone `is_nushell_available()` helper with `Shell::Nushell.is_installed()` — same semantics, one fewer function. The historical `WORKTRUNK_TEST_NUSHELL_ENV` env-var name is preserved to avoid churning hundreds of recorded snapshots. ## Tests - New `test_configure_shell_skipped_lists_only_installed_shells` pairs with `test_configure_shell_no_files` to cover both arms of the install guard (binary on PATH + rc absent → Skipped; binary absent + rc absent → drop entirely). - Test defaults moved into `STATIC_TEST_ENV_VARS` so PTY tests inherit them through `TestRepo::test_env_vars`. - 50+ snapshot files updated to reflect the merged behavior. Coverage caveat: the `which::which` fallback in `is_installed()` is not exercised by tests (every test sets the env override). Same shape as the prior `is_nushell_available()` helper, documented inline. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
5279d1f671 |
Route --help output to stdout (#2155)
Worktrunk sent all help output to stderr. This is an outlier versus most CLIs (cargo, curl, python, `git <cmd> -h` — all stdout) and versus `--version`, which moved to stdout in #2072 for the same reasons. Move help to stdout and canonicalize the shared pager function so its other callers (`wt config show`, `wt hook show`, `wt config state`) emit on stdout too. The prior rationale — "stdout is reserved for data output" so `wt config show | jq` works — was already self-contradictory: `config show` went through the same pager helper and was landing on stderr. ## What changed - `src/help_pager.rs` — removed the `>&2` pager redirect and switched fallback prints from `std::print!` to the anstream-aware `worktrunk::styling::print`, so piped/redirected output is plain text rather than raw ANSI. Simplified the TTY guard to check stdout only (the `stdout OR stderr` check was a leftover from the redirect era). - `src/help.rs` — DisplayHelp fallback prints via `styling::println`. - `src/commands/config/{show,state}.rs`, `src/commands/hook_commands.rs` — pager fallbacks print to stdout. - Added `test_help_goes_to_stdout` and `test_help_strips_ansi_when_piped` as regression anchors (parallel to existing `test_version_goes_to_stdout`). Verified the ANSI test catches the bug by reverting temporarily. - Updated ~90 snapshots where content moved from the `----- stderr -----` section to `----- stdout -----`. ## User-visible behavior change Scripts that did `wt --help 2>/dev/null | x` previously discarded help and piped nothing; they now pipe the help text. `wt --help > file` captures help instead of leaving the file blank. Both changes align Worktrunk with POSIX conventions. Terminal usage (pager on TTY) is unchanged. > _This was written by Claude Code on behalf of @max-sixty_ --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
dc7f5bca5c | Replace bright-black with underline for inline references in hints (#1285) | ||
|
|
f3ae9a8ac6 | fix: unify config path resolution so config create matches config load (#1135) | ||
|
|
5a10dcc788 |
fix(shell): harden nushell wrapper and improve diagnostics (#1059)
* fix(shell): harden nushell wrapper and improve diagnostics
- Move LAST_EXIT_CODE capture inside do{} block so it reflects the
actual command exit code, not a subsequent operation
- Wrap directive processing in try/catch to ensure temp file cleanup
on error
- Include nushell vendor autoload paths in scan_for_detection_details
so `wt config show` reports nushell integration status
- Add "nu" to the supported shells hint shown on unsupported shells
- Fix detection tests to use actual nushell config line patterns
- Document why non-cd directives delegate to sh -c
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor(shell): remove try/catch from nushell directive cleanup
Drop error-path cleanup for the temp directive file. On error, the file
persists in /tmp as a useful debugging artifact (the OS cleans it up).
This matches bash and fish which already use a single rm on the happy
path with no error wrapping.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
|
||
|
|
f4ce6d1804 |
fix(shell): nushell uninstall cleans all candidate locations, dedup candidates (#1050)
* fix(shell): nushell uninstall cleans all candidate locations, dedup candidates Follow-up fixes to #1038 where config_paths() was changed to return multiple Nushell candidates but not all consumers were updated: - Uninstall now iterates all candidate paths instead of only the first, so config files installed at a different location (e.g., nu was in PATH during install but not during uninstall) get cleaned up - has_config_location checks any candidate's parent directory for auto-detection, not just the first - Removed redundant etcetera entry from nushell_config_candidates() (always duplicated either $XDG_CONFIG_HOME/nushell or ~/.config/nushell) and added HashSet-based dedup for remaining edge cases Co-Authored-By: Claude <noreply@anthropic.com> * refactor(shell): extract remove_config_file helper for uninstall Deduplicate 4 identical remove_file + map_err + format! patterns into a shared remove_config_file() helper. Improves patch coverage by making the nushell uninstall block a simple function call. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
8408c020ff |
fix(test): eliminate spurious blank lines in PTY snapshots (#1040)
* Remove blank lines after prompts; add prompt-aware PTY tests Remove redundant eprintln!() after read_line() in prompt functions — the Enter key echo already provides the line break, so the extra blank line violated "blank before prompts, not after." Add prompt-aware PTY test helpers that wait for the prompt marker before sending input, so captured output matches real terminal behavior. The PTY module now exposes 3 composable functions (build_pty_command + exec_cmd_in_pty / exec_cmd_in_pty_prompted) instead of 8 wrappers. Co-Authored-By: Claude <noreply@anthropic.com> * fix(test): eliminate PTY echo artifact causing blank lines in snapshots portable_pty's UnixMasterWriter::drop() sends \n + EOT to the PTY master. When drop(writer) happened before child.wait(), the terminal echoed this \n as \r\n — producing a spurious blank line in captured output. Fix by reordering: wait for the child first, then drop the writer (echo goes to a dead PTY). Also remove the "collapse consecutive newlines" filter in configure_shell tests that was masking this bug. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
dba80e362d |
fix(shell): auto-detect nushell for install even without vendor/autoload (#1032)
* fix(shell): auto-detect nushell for install even without vendor/autoload When `nu` is in PATH, `wt config shell install` now creates the vendor/autoload directory automatically instead of skipping nushell. The directory was introduced in nushell v0.96.0 and isn't always pre-created, causing install to silently skip nushell users. Follows the existing PowerShell pattern: detect the shell binary, then set should_configure and allow_create so the directory gets created on the user's behalf. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(tests): move nushell env var to configure_cli_command, add assertion Move WORKTRUNK_TEST_NUSHELL_ENV alongside WORKTRUNK_TEST_POWERSHELL_ENV in configure_cli_command for consistency — both are shell detection overrides. Add negative assertion (!contains("Skipped nu")) to directly test the failure mode this fix addresses. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Maximilian Roos <m@maxroos.com> |
||
|
|
c7128ce11b | Add nushell support (#964) | ||
|
|
dc753d0f85 |
fix(shell): auto-configure PowerShell on Windows when SHELL is not set (#898)
* Refactor PowerShell environment detection for auto-config Introduce is_powershell_environment() function to detect PowerShell sessions via PSModulePath env var. Use this detection to auto-configure PowerShell when running `wt config shell install` from a PowerShell session, even if the profile doesn't exist yet (issue #885). On non-Windows, add PowerShell to the default shells list when detected. Rename explicit_shell parameter to allow_create for clarity, representing whether config files can be created for a shell. * fix(shell): restrict PowerShell auto-detect to non-Windows On Windows, PSModulePath is set system-wide (even in Git Bash, cmd), making it unreliable for detecting PowerShell sessions. This caused false positives where `wt config shell install` would create PowerShell profiles when run from Git Bash. Changes: - Restrict is_powershell_environment() to non-Windows only - On Windows, require explicit `install powershell` to create profile - Add Windows-specific hint when PowerShell is skipped - Use var_os() instead of var() for robust env var checking On macOS/Linux, PowerShell Core must be explicitly installed, so PSModulePath being set is a reliable signal for auto-detection. Co-Authored-By: Claude <noreply@anthropic.com> * fix(shell): auto-detect PowerShell on Windows via SHELL absence On Windows, detect Windows-native shells (cmd/PowerShell) by checking if the SHELL env var is NOT set. Git Bash, MSYS2, and Cygwin set SHELL, but cmd.exe and PowerShell don't. When detected, create both PowerShell profile files: - Documents/PowerShell/Microsoft.PowerShell_profile.ps1 (pwsh 7+) - Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1 (5.1) This solves issue #885 where PowerShell users couldn't auto-configure shell integration because PSModulePath detection had false positives. Co-Authored-By: Claude <noreply@anthropic.com> * refactor(shell): rename is_powershell_environment to should_auto_configure_powershell The new name better reflects the function's purpose: it determines whether to auto-configure PowerShell profiles, not whether we're "in" PowerShell. Also adds an integration test for the WORKTRUNK_TEST_POWERSHELL_ENV override that verifies PowerShell profile creation works correctly. Co-Authored-By: Claude <noreply@anthropic.com> * fix(shell): show "shell extension" not "& completions" for PowerShell preview The preview output for `--dry-run` and `?` help was incorrectly showing "shell extension & completions" for PowerShell. Only Bash/Zsh have inline completions; Fish has separate files and PowerShell has no tab completion. This makes the preview consistent with the actual install output. Co-Authored-By: Claude <noreply@anthropic.com> * fix(tests): isolate PowerShell detection in test environment On CI environments: - Linux: PowerShell Core is installed, setting PSModulePath - Windows: Removing SHELL triggers the "SHELL not set" detection Both cause should_auto_configure_powershell() to return true in tests, adding PowerShell to the shell list and triggering the config hint. Fix by: 1. Removing PSModulePath to prevent Linux false positive 2. Setting WORKTRUNK_TEST_POWERSHELL_ENV=0 to disable detection entirely 3. Skip the PowerShell detection test on Windows (Documents folder can't be easily overridden in tests) Tests that need PowerShell detection should set the env var to "1". Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
4bfe85403c |
fix(ci): use compile-time binary path for nextest compatibility (#884)
* fix(ci): build wt binary before running nextest
## Problem
The test `test_switch_with_execute_through_wrapper` was failing on macOS CI with:
```
bash: /Users/runner/work/worktrunk/worktrunk/target/debug/wt: No such file or directory
```
Root cause: `cargo nextest` only builds test binaries, not the main binary. The
shell_wrapper tests use `insta_cmd::get_cargo_bin("wt")` which expects the main
binary to exist at `target/debug/wt`. When running via nextest without building
the binary first, this path doesn't exist, causing the test to fail.
The issue surfaced after commit
|
||
|
|
b1ca0d22f3 |
fix: use format_path_for_display() consistently for user-facing paths (#856)
- Add "Path Formatting" documentation to writing-user-outputs skill - Fix error messages in configure_shell.rs, resolve.rs, user.rs, worktrees.rs to use format_path_for_display() instead of .display() - Add canonicalization in test helpers for macOS /var -> /private/var symlinks - Update snapshot filter to preserve directory names (_PARENT_/$1) Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
ce3d44c4b0 |
fix(test): update PTY filter to handle optional ANSI codes (#844)
After commit
|
||
|
|
2293dee043 |
refactor(tests): unify PTY execution into common/pty module (#675)
* refactor(tests): unify PTY execution into common/pty module Consolidates 6 duplicate PTY execution functions from test files into a shared module at tests/common/pty.rs: - exec_in_pty() - simple PTY execution - exec_in_pty_with_home() - with HOME override for shell config tests - exec_cmd_in_pty() - for pre-configured CommandBuilder - exec_in_pty_multi_input() - for tests requiring multiple inputs Also: - Migrates shell_integration_prompt.rs from manual normalize_output() to insta filters, consistent with other PTY tests - Removes duplicate get_shell_binary() from shell_wrapper.rs Net reduction of ~183 lines of duplicated code. Co-Authored-By: Claude <noreply@anthropic.com> * style: apply cargo fmt formatting * fix: move get_shell_binary import to shared section for Windows --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
ffe2d41b42 |
refactor: simplify test normalization by using insta filters (#672)
* refactor: simplify test normalization by using insta filters - Remove redundant `normalize_newlines()` from shell_wrapper.rs (already handled by `add_pty_filters()`) - Remove dead `add_pty_tmpdir_filters()` from common/mod.rs (no snapshots used [TMPDIR] placeholder) - Convert config_state.rs `normalize_log_path()` to insta filter - Convert configure_shell.rs `normalize_output()` to insta filter via `install_pty_settings()` function Analyzed but kept as-is (appropriate for their use cases): - shell_integration_prompt.rs: Uses `contains()` assertions, not snapshots - select.rs: Requires line-specific manipulation for TUI timing - diagnostic.rs: Complex domain-specific normalization with ordering Net reduction: 46 lines of test code. Co-Authored-By: Claude <noreply@anthropic.com> * fix: restore CRLF normalization in PTY exec functions The insta filter for \r\n wasn't fully equivalent to the String::replace() call. Restore eager normalization to avoid subtle edge cases with ANSI code matching. Also removes redundant set_snapshot_path() since it's inherited from TestRepo's bound settings. Co-Authored-By: Claude <noreply@anthropic.com> * refactor: consolidate CRLF normalization to PTY source Move CRLF normalization from insta filter to PTY exec functions. This follows the principle: normalize once, at the source. Changes: - Add CRLF normalization to all PTY exec functions - Remove CRLF filter from add_pty_filters() - Update snapshots (removes redundant trailing [0m codes) This eliminates subtle ordering issues between filters and ensures consistent data for all downstream processing. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
62dfad1562 |
fix: move fish shell integration to functions/ for Homebrew compatibility (#580)
* fix: move fish shell integration to functions/ for Homebrew compatibility Fish shell integration now installs to ~/.config/fish/functions/wt.fish instead of ~/.config/fish/conf.d/wt.fish. The functions/ directory is autoloaded on first command invocation, ensuring PATH is fully configured (including Homebrew) before the wt function loads. Changes: - Fish template now writes to functions/ (autoloaded on first use) - `wt config show` detects legacy conf.d installations and shows migration hint - `wt config shell install` removes legacy conf.d file during migration - `wt config shell uninstall` cleans up both locations - Fish template now suppresses `type -P` stderr when command not found - Shell count in uninstall output counts unique shells (not files) Fixes #566 Co-Authored-By: Claude <noreply@anthropic.com> * refactor: simplify fish wrapper to match bash/zsh pattern - Reduce fish wrapper from ~30 lines to ~10 lines - Wrapper now just calls `wt config shell init fish | source` - WORKTRUNK_BIN handling moves to the full function (sourced at runtime) - Remove incorrect WORKTRUNK_DIRECTIVE_FILE= checks (never written to files) - Update docs link in wrapper comment - Fix tests to use realistic wrapper content Co-Authored-By: Claude <noreply@anthropic.com> * fix: prevent infinite recursion in fish wrapper when wt not in PATH When `wt` isn't in PATH, `command wt` fails but `source` with empty input succeeds (exit 0). The `or return` wouldn't trigger, causing the wrapper to recurse into itself infinitely. Fix by capturing $pipestatus[1] (the exit status of the first command in the pipeline) and returning that status if non-zero. Co-Authored-By: Claude <noreply@anthropic.com> * test: add test for fish wrapper behavior when wt not in PATH This tests the WRAPPER file (fish_wrapper.fish) specifically, not the full function. The wrapper tries to source the full function at runtime. When wt isn't in PATH, it should return 127 (not infinite loop). The existing test (test_fish_binary_not_found_clear_error) tests the FULL function which has its own WORKTRUNK_BIN check. Co-Authored-By: Claude <noreply@anthropic.com> * refactor: show deprecated message when uninstalling legacy fish conf.d When uninstalling fish shell integration, the deprecated conf.d location now shows a clearer message: ○ Removed ~/.config/fish/conf.d/wt.fish (deprecated; now using ~/.config/fish/functions/wt.fish) Instead of the generic: ✓ Removed shell extension for fish @ ~/.config/fish/conf.d/wt.fish This helps users understand that conf.d was a legacy location. Co-Authored-By: Claude <noreply@anthropic.com> * fix: mock claude in config_show test for CI consistency The test was failing in CI because `claude` isn't installed there, causing a different message format. Now uses mock CI tools to ensure consistent output across all environments. Co-Authored-By: Claude <noreply@anthropic.com> * fix: trim both sides when comparing fish wrapper content The fish wrapper template has a trailing newline. When comparing existing content with expected content, we trim the existing file content but not the generated content. This causes the comparison to fail on Windows where line ending handling differs. Fixes Windows CI failure in test_configure_shell_fish_all_already_configured. Co-Authored-By: Claude <noreply@anthropic.com> * test: add coverage for fish legacy detection with functions/ dir This test covers the code path where fish functions/ directory exists but wt.fish doesn't, while legacy conf.d/wt.fish does exist. This exercises a different code path in render_shell_status() than the existing test_config_show_detects_fish_legacy_conf_d test: - Existing test: functions/ doesn't exist → fish is "skipped" - New test: functions/ exists but empty → fish is "configured" with WouldCreate Both should show the migration hint for the legacy conf.d location. Co-Authored-By: Claude <noreply@anthropic.com> * test: add dry-run install test for fish shell This test exercises show_install_preview() which displays the fish wrapper content and completions with gutter formatting when running: wt config shell install fish --dry-run The test verifies: - "Will create" messages are shown (not "Created") - Fish wrapper content is displayed in gutter - Fish completions content is displayed in gutter - No files are actually created Co-Authored-By: Claude <noreply@anthropic.com> * fix: update fish dry-run snapshot for syntax highlighting change The snapshot had a minor syntax highlighting difference where the fish `or` keyword was highlighted differently. Accept the updated rendering. Co-Authored-By: Claude <noreply@anthropic.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * refactor: make Windows .exe suffix handling Windows-only Use #[cfg(windows)] to compile the .exe suffix check only on Windows, where it's meaningful. This removes dead code from non-Windows builds. Co-Authored-By: Claude <noreply@anthropic.com> * test: update fish dry-run snapshot for or syntax highlighting Co-Authored-By: Claude <noreply@anthropic.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * config: exclude snapshot files from typos checking ANSI escape codes in snapshots create false positives (e.g., the fish shell 'or' keyword wrapped in [34m...[0m gets flagged as a typo for 'ore'). Co-Authored-By: Claude <noreply@anthropic.com> * refactor: simplify error handling in configure_shell - Use .ok() for file reads after exists() check - treat read failures as 'not configured' rather than hard errors (race conditions are rare) - Simplify error messages for write operations - just show path and error - Remove verbose 'Failed to...' prefixes from error messages These error paths are unlikely (permission errors, race conditions) and don't warrant dedicated test coverage. Co-Authored-By: Claude <noreply@anthropic.com> * fix: refactor Windows cfg block to avoid clippy blocks_in_conditions Move the let bindings into a block scope instead of using them in an if-condition block, which clippy on Windows flags as a lint violation. Co-Authored-By: Claude <noreply@anthropic.com> * style: use 'To X, run Y' pattern for migration hints Follow CLI output formatting guidelines - command at end for easy copying. Co-Authored-By: Claude <noreply@anthropic.com> * Fix fish wrapper error handling and legacy cleanup - Add source_status check to fish wrapper to catch sourcing failures - Refactor cleanup_legacy_fish_conf_d with early returns and error handling - Move dry-run check before legacy cleanup to prevent file deletion - Add regression test for dry-run with legacy fish conf.d file --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> |
||
|
|
f0f3e18629 |
test: add GitLab MR status and shell config creation tests (#546)
Add coverage for: - GitLab MR detection via mock glab (passed, failed, running, pending, conflicts, stale, no CI, project ID filtering) - Shell config file creation when targeting a shell explicitly 288 lines of tests for 47 lines of coverage gain. Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
9425c78c59 |
test: add coverage tests for --dry-run flag (#545)
* feat: add --dry-run flag to shell install/uninstall commands Add --dry-run flag to `wt config shell install` and `wt config shell uninstall` commands. When passed, shows what would be changed without prompting or making any modifications. Useful for scripting, CI pipelines, and non-interactive contexts where users want to preview changes without being prompted. Co-Authored-By: Claude <noreply@anthropic.com> * test: add coverage tests for --dry-run flag Add integration tests covering the dry-run code paths for shell install/uninstall commands: - test_configure_shell_dry_run: single shell install preview - test_configure_shell_dry_run_multiple: multiple shells install preview - test_configure_shell_dry_run_already_configured: already configured case - test_uninstall_shell_dry_run: single shell uninstall preview - test_uninstall_shell_dry_run_fish: fish with completions (covers completion_results loop) - test_uninstall_shell_dry_run_multiple: multiple shells uninstall preview All tests verify that --dry-run shows the preview without modifying files. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
b6f88689b2 |
fix(test): normalize PTY blank lines in shell install tests (#499)
* fix(test): apply mtime sleep to all platforms, not just Windows The `test_list_full_working_tree_conflicts` test was failing on Linux CI because git's mtime-based change detection wasn't reliably seeing file modifications. The sleep was previously Windows-only, but CI environments on all platforms can have this issue. Co-Authored-By: Claude <noreply@anthropic.com> * fix(ci): use bot token so Claude commits trigger CI workflows (#491) Add WORKTRUNK_BOT_TOKEN to both checkout and claude-code-action steps in claude-mention.yaml and claude-ci-fix.yaml. This ensures pushed commits trigger CI workflows, since GITHUB_TOKEN is intentionally blocked from triggering workflows to prevent infinite loops. Co-authored-by: Claude <noreply@anthropic.com> * refactor(windows): remove hardcoded fallback, rely on PATH only (#489) * refactor(windows): simplify Git Bash detection with single fallback Simplify Git Bash detection: 1. Primary: Find git.exe in PATH and derive bash.exe location 2. Fallback: Check standard Git for Windows path (C:\Program Files\Git) Removed the other 5 hardcoded paths (Program Files (x86), C:\Git, MSYS2 locations) since they're rare edge cases. The standard path covers GitHub Actions and most installations. Co-Authored-By: Claude <noreply@anthropic.com> * refactor(windows): simplify Git Bash detection with single fallback Simplify Git Bash detection from 6 hardcoded paths to just 1: 1. Primary: find git.exe in PATH and derive bash.exe location 2. Fallback: C:\Program Files\Git\bin\bash.exe The fallback is needed because `which::which("git")` fails in some CI environments even when git is installed (Windows PATH handling quirk). Co-Authored-By: Claude <noreply@anthropic.com> * ci: retry flaky windows test * ci: retry (flaky working_tree_conflicts test) --------- Co-authored-by: Claude <noreply@anthropic.com> * fix(test): replace sleep with polling for racy git detection (#492) Replace the fixed 100ms sleep in test_list_full_working_tree_conflicts with a polling-based approach using the new general `wait_for` helper. The "racy git" problem occurs when file modifications happen within the same filesystem timestamp granularity - git's mtime-based detection may not see the change. Polling with exponential backoff (10ms -> 500ms cap, 15s timeout) is both faster on normal systems and more reliable on slow CI. Co-authored-by: Claude <noreply@anthropic.com> * fix(security): add prompt instruction to prevent secret exposure (#493) Add security instruction to both Claude workflows prohibiting commands that could expose secrets (env, printenv, etc.) and forbidding inclusion of credentials in responses. Co-authored-by: Claude <noreply@anthropic.com> * feat(ci): use OAuth token for Claude Code subscription auth (#494) Switch from ANTHROPIC_API_KEY to CLAUDE_CODE_OAUTH_TOKEN to use subscription-based authentication instead of per-token API pricing. Co-authored-by: Claude <noreply@anthropic.com> * test: verify OAuth token authentication (#495) * feat(ci): use OAuth token for Claude Code subscription auth Switch from ANTHROPIC_API_KEY to CLAUDE_CODE_OAUTH_TOKEN to use subscription-based authentication instead of per-token API pricing. Co-Authored-By: Claude <noreply@anthropic.com> * test: verify OAuth token authentication Co-Authored-By: Claude <noreply@anthropic.com> * fix(ci): use input parameter instead of env var for OAuth token The claude-code-action expects claude_code_oauth_token as an input parameter, not an environment variable. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * fix(test): normalize PTY blank lines in shell install tests PTY echo timing varies between systems, causing blank lines to appear at different positions in the output. On CI macOS, the newline from user input appears after the prompt text rather than before it. Normalize by collapsing consecutive newlines and stripping leading newlines, making the snapshots consistent across all environments. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
928b3017cd |
test: remove verbose assertion messages and doc comments (#458)
* Simplify assert messages by removing redundant descriptions
Remove verbose assertion messages that repeat the condition being tested.
Messages like "Should contain indicator" when asserting `contains("●")` are
redundant since the code is self-documenting. This reduces noise in tests
while maintaining clarity through meaningful assertion failures.
* test: remove verbose assertion messages and doc comments
Removed facile test verbosity across three categories:
1. **Doc comments** (~236 lines): Removed `/// Test X` comments that just
restated test function names. Kept multi-line explanations that add context.
2. **Test names** (9 functions): Shortened overly verbose names by removing
filler words while maintaining clarity:
- test_merge_when_primary_not_on_default_but_default_has_worktree →
test_merge_primary_not_on_default_with_default_worktree
- test_complete_switch_option_prefix_shows_options_not_branches →
test_complete_switch_option_prefix_shows_options
3. **Assertion messages** (19 instances): Removed messages that just restate
the check:
- assert!(path.exists(), "Path should exist") → assert!(path.exists())
- assert!(x.is_file(), "Should be a file") → assert!(x.is_file())
Kept messages that add semantic meaning (e.g., "hook should have run") or
include debugging variables.
Total: 279 lines removed across 31 files. All 723 integration + 401 unit tests
passing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* test: remove unreferenced snapshot files from renamed tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
|
||
|
|
d2051f3ef9 |
Fix CI: PTY echo timing normalization and workflow permissions (#456)
* fix(test): normalize PTY echo timing in shell install snapshot tests
PTY tests capturing interactive install prompt had flaky output due to
timing differences between local and CI environments. The user's input
character ('y' or 'n') would appear either before the prompt or at the
end of the prompt line depending on timing.
Added normalization in `normalize_output()` to:
- Remove echoed input character from end of prompt line
- Remove standalone input lines that appear before the prompt
This ensures consistent snapshots regardless of PTY echo timing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ci): add id-token:write permission to claude-ci-fix workflow
The claude-code-action requires `id-token: write` permission to fetch
an OIDC token for GitHub authentication. Without this, the action fails
with "Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable".
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
|
||
|
|
49c15097ff |
refactor(tests): simplify snapshot testing with auto-bound settings (#396)
* refactor(tests): simplify snapshot testing with auto-bound settings - Auto-bind snapshot settings in TestRepo::new() via _snapshot_guard field - Remove manual setup_snapshot_settings().bind() wrappers from tests - Inline make_snapshot_cmd calls directly in assert_cmd_snapshot! macros - Remove unused helper functions (json_settings, bind, bind_json) - Use auto-naming from test function names (explicit names only for multi-snapshot tests) - Fix directive file guard lifetime in test_remove_internal_mode - Clean up orphaned snapshot files and let git detect renames Net reduction: -183 lines in test files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: update statusline tests for fish-abbreviated paths The auto-bound snapshot settings from TestRepo use `_REPO_` filters for full paths, but the statusline command uses fish-style path abbreviation (e.g., `/p/v/f/.../repo`). These abbreviated paths weren't matched by the existing filters. Updated `claude_code_snapshot_settings()` to: - Filter fish-abbreviated paths ending in `/repo` to `[PATH]` - Strip leading ANSI reset codes from output - Remove unused `repo` parameter 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: normalize statusline paths across platforms The statusline output varies by platform: - Linux: Raw path filtered by auto-bound settings to `_REPO_` - macOS: Fish-style abbreviation bypasses auto-bound filters Updated claude_code_snapshot_settings() to normalize both cases to a consistent `[PATH]` placeholder for cross-platform tests. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
8a9db5f8f0 |
refactor: unify shell restart messages (#381)
* Add shell integration prompt after wt switch When shell integration is not active after `wt switch`, show a one-time interactive prompt asking users if they want to install it. This helps new users discover shell integration without requiring them to read docs. ## Features - Interactive prompt with preview option (?) to see what will be installed - Remembers user choice via `skip-shell-integration-prompt` config flag - Falls back to hint message for non-TTY or after declining ## Decision flow 1. Unsupported shell → hint with supported shells 2. $SHELL not set → hint to run install command 3. Already installed → hint to restart shell 4. Already prompted → hint to run install command 5. TTY available → show interactive prompt 6. Non-TTY → hint to run install command ## Code improvements - Consolidated shell install output into `print_shell_install_result()` - Extracted `print_skipped_shells()` helper to eliminate duplication - Improved hint styling: commands/paths use `<bright-black>` per guidelines 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: install for all shells on prompt accept, skip flag only on decline - Prompt now installs for ALL shells with config files, matching `wt config shell install` behavior - Skip flag only set on explicit decline, not before prompt (Ctrl+C doesn't permanently disable prompts) - Shell detection uses starts_with for versioned binaries (zsh-5.9) - If no config files exist anywhere, show install hint 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: update prompt_accept snapshot for all-shells install The prompt now installs for all shells (same as `wt config shell install`), so the snapshot includes skip messages for shells without config files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: show shell integration warnings for all switch operations Previously, `wt switch` only warned about missing shell integration when switching to existing worktrees without `--execute`. Now warnings are shown consistently: - `SwitchResult::Existing`: warns when shell integration not active - `SwitchResult::Created`: shows success, then warns if shell won't cd - `--execute`: custom message noting command runs but shell stays put Warning reasons are now proper reasons, not suggestions: - "shell requires restart" (configured but not active) - "shell integration not installed" (not configured) For created worktrees, the warning is simplified to avoid repetition: ✓ Created new worktree for feature from main @ ~/repo.feature ▲ Cannot change directory — shell integration not installed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: unify shell restart messages - All restart hints now use "Restart shell to activate" (removed fish/bash/zsh branching that showed source command for bash/zsh) - Warning reasons use statement form: "shell requires restart" and "shell integration not installed" (per em-dash guidelines) - Combined three conditions that showed same hint into single if - Removed "run:" colon per CLI output formatting guidelines 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Replace repo_root with repo_path in wt.toml Update template variable references from repo_root to repo_path to match the current configuration convention. * fix: restore full "shell integration" text in restart hint The abbreviated "Restart shell to activate" was unclear about what was being activated. Restored to "Restart shell to activate shell integration". 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
d21a463430 |
Add shell integration prompt after wt switch (#370)
* Add shell integration prompt after wt switch When shell integration is not active after `wt switch`, show a one-time interactive prompt asking users if they want to install it. This helps new users discover shell integration without requiring them to read docs. ## Features - Interactive prompt with preview option (?) to see what will be installed - Remembers user choice via `skip-shell-integration-prompt` config flag - Falls back to hint message for non-TTY or after declining ## Decision flow 1. Unsupported shell → hint with supported shells 2. $SHELL not set → hint to run install command 3. Already installed → hint to restart shell 4. Already prompted → hint to run install command 5. TTY available → show interactive prompt 6. Non-TTY → hint to run install command ## Code improvements - Consolidated shell install output into `print_shell_install_result()` - Extracted `print_skipped_shells()` helper to eliminate duplication - Improved hint styling: commands/paths use `<bright-black>` per guidelines 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: install for all shells on prompt accept, skip flag only on decline - Prompt now installs for ALL shells with config files, matching `wt config shell install` behavior - Skip flag only set on explicit decline, not before prompt (Ctrl+C doesn't permanently disable prompts) - Shell detection uses starts_with for versioned binaries (zsh-5.9) - If no config files exist anywhere, show install hint 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: update prompt_accept snapshot for all-shells install The prompt now installs for all shells (same as `wt config shell install`), so the snapshot includes skip messages for shells without config files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
7cff9afcaa |
Investigate: Remove compinit warning suppression (#358)
* Remove ZSH_DISABLE_COMPFIX suppression to investigate root cause Remove all compinit warning suppressions to understand: 1. When exactly the "insecure directories" warning appears 2. Whether it's caused by worktrunk or pre-existing in the CI environment 3. Whether the warning appears even when wt hasn't modified shell configs Changes: - Remove ZSH_DISABLE_COMPFIX=true from shell.rs and config.rs - Remove WORKTRUNK_TEST_COMPINIT_CONFIGURED bypass from PTY test - Let the compinit probe run naturally to see actual behavior 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add diagnostic test to prove compinit warning source This test runs `zsh -ic` directly in a PTY without any worktrunk involvement - no custom HOME, no environment changes. If the compinit warning appears here too, it proves the warning is a pre-existing CI environment issue, not something worktrunk causes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Force diagnostic test to panic to show output in CI * Fix diagnostic test to match worktrunk test environment * Add dynamic compinit suppression in PTY tests Restore ZSH_DISABLE_COMPFIX suppression with clear documentation: - shell.rs: Full rationale explaining why suppression is safe - config.rs: Brief reference to shell.rs rationale Implement dynamic suppression in PTY tests: - Add env_needs_compinit_suppression() helper that detects if plain zsh -ic produces the "insecure directories" warning - Only add ZSH_DISABLE_COMPFIX when the environment needs it - Tests work on both clean environments and problematic CI This approach was validated in PR #358 which proved the warning comes from the CI environment's global zsh config, not from worktrunk. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Simplify compinit suppression: clarify rationale, remove unneeded test code Update documentation to explain clearly: - Worktrunk does NOT cause the "insecure directories" warning - Our shell init doesn't modify fpath or call compinit - The warning comes from global zsh configs (e.g., /etc/zsh/zshrc) - We only register completions with compdef if user already set up compinit Remove unnecessary dynamic detection from PTY tests - the library code already handles suppression, so the test just needs a simple env var. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Skip compinit probe in PTY tests to avoid env-specific warnings The compinit probe spawns `zsh -ic` which sources global zshrc configs. On some CI environments (Ubuntu), these configs call compinit which produces "insecure directories" warnings that go to /dev/tty and leak into PTY output despite ZSH_DISABLE_COMPFIX suppression. Use WORKTRUNK_TEST_COMPINIT_MISSING=1 to skip the probe while still testing the compinit advisory output. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
fc425957de |
Fix zsh compinit insecure directories warning on CI (#353)
* Ignore flaky shell install preview test on CI The test_install_preview_with_gutter test fails on GitHub Actions because zsh shows "compinit: insecure directories" warnings that leak into the PTY output. This is an environment-specific issue that doesn't affect the actual functionality being tested. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix zsh compinit insecure directories warning on CI The test_install_preview_with_gutter test was failing on GitHub Actions because zsh's compinit security check would prompt about insecure directories. This warning goes to the TTY (not stderr) so it wasn't suppressed by our stderr(Stdio::null()). Root cause fix: - Set ZSH_DISABLE_COMPFIX=true when spawning zsh to probe compinit - Add stdin(Stdio::null()) to prevent compinit from prompting interactively - Applied to both detect_zsh_compinit() in shell.rs and check_zsh_compinit_missing() in config.rs This properly fixes the flaky test that was temporarily ignored in #352. Also fixes Windows compilation error where <branch> was parsed as a color tag. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
3f74563188 |
fix(list): dim URL for current worktree when health check fails (#350)
* fix(list): dim URL for current worktree when health check fails Update snapshots to show dimmed URLs when dev servers are not running. The health check correctly reports ports as inactive, so URLs should display with dim styling. Previous snapshots incorrectly showed undimmed URLs for the main worktree because CI and test environments don't have servers running on those ports. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test: isolate URL health checks from local environment Add WORKTRUNK_TEST_SKIP_URL_HEALTH_CHECK env var that, when set, makes the URL health check always return inactive. This prevents flaky tests caused by random local processes (like dev servers) listening on ports that happen to match the hash_port values. The env var is set in configure_cli_command() so all test commands get consistent behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test: disable zsh compinit security warning in PTY tests Set ZSH_DISABLE_COMPFIX=true to prevent the "insecure directories" warning from interfering with test output on CI runners. Co-Authored-By: Claude <noreply@anthropic.com> * fix: escape branch placeholder in Windows wt select error The `<branch>` was being interpreted as a cformat! color tag, causing a compilation error on Windows. Use `BRANCH` instead. Co-Authored-By: Claude <noreply@anthropic.com> * fix: use let _ = instead of ? for output::print in Windows wt select error The main() function doesn't return Result, so the ? operator cannot be used. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
471d33188b |
Ignore flaky shell install preview test on CI (#352)
The test_install_preview_with_gutter test fails on GitHub Actions because zsh shows "compinit: insecure directories" warnings that leak into the PTY output. This is an environment-specific issue that doesn't affect the actual functionality being tested. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
14ac1bd9d5 |
Move zsh compinit advisory to after success message
Refactor the zsh compinit detection logic to return a flag in ScanResult instead of printing directly. This moves the advisory message from the configure_shell module to main.rs, allowing it to be displayed after the success summary rather than before the configuration results. Also updates the advisory message text from "Completions won't work" to "Completions require compinit" for clarity. |
||
|
|
81973cffc2 | Replace shell tests with snapshot-based assertions | ||
|
|
bceedcade7 |
Fix test isolation for wt commands and improve test API (#314)
Tests that spawn `wt` must be isolated from the host environment to prevent directive leakage (test commands writing to user's shell directive file), config pollution, and git interference. Changes: - Add `TestRepo::wt_command()` returning pre-configured Command - Rename `clean_cli_env` → `configure_wt_cmd` (parallel to git) - Make `git_command()` consistent (no args, chain `.args()`) - Fix approval_ui.rs and readme_sync.rs missing isolation - Add `#[must_use]` to command builders - Document pattern in tests/CLAUDE.md The public API is now 3 symmetric methods: - `repo.wt_command()` - for wt commands with TestRepo - `repo.git_command()` - for git commands - `wt_command()` - for wt without TestRepo (help tests) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
c1ea17d1b4 |
Replace --force flag with --yes throughout codebase
Update documentation, tests, and snapshots to use the new `--yes` flag instead of `--force`. The `--yes` flag is used to bypass approval prompts and confirmations, while `--force` is now reserved for destructive operations like forced file removal. |