Commit Graph

20 Commits

Author SHA1 Message Date
Maximilian Roos 4d7f8c944e fix(env): drop Intel macOS from the flake, and install pwsh and jq for web setup (#3776)
Three follow-ups from #3768, plus a bug the verification turned up.

**The flake stops declaring outputs for `x86_64-darwin`.** nixpkgs drops
Intel macOS in 26.11: evaluating anything for that system against
`nixos-unstable` (`26.11pre-git`) throws. The rev `flake.lock` pins is
26.05-era, so it still evaluates today, carrying nixpkgs' own warning
that "26.05 will be the last release to support x86_64-darwin". Naming
three systems rather than `eachDefaultSystem` drops Nix support for
Intel Macs now, ahead of that bump. Release binaries are untouched:
`dist-workspace.toml` still ships `x86_64-apple-darwin` and nightly
still tests it on `macos-15-intel`.

**`git` leaves the devShell's `packages`.** It arrives with the
`checks`, which crane folds in via `inputsFrom`, the same mechanism that
already supplied `python3`, `procps` and `lsof`.

**`task setup-web` installs `pwsh` and `jq`.** Without them Claude Code
web can't run `--features shell-integration-tests`, which is what the
pre-merge gate runs. PowerShell comes from the release `.deb` rather
than the tarball, because pwsh aborts at startup without libicu and only
the `.deb` declares that dependency for apt to resolve. The verification
loop runs each tool instead of looking for it on PATH, since the tarball
install left a `pwsh` that was on PATH and still aborted.

**A `set -e` abort found while testing that.** The `sources.list.d`
cleanup was an `&&` chain, and under `set -e` a chain ending false takes
the whole task down. This one ends false on an unmatched glob and on a
`.list` file with no `[` line, so setup was dying before it installed
anything on a stock Debian box as well as an empty one. It's an `if`
now.

## Verification

No `nix` on the machine this was written on, so the flake was checked in
a `nixos/nix` container and the Taskfile block in an amd64 Debian one.

<details>
<summary>flake: three systems evaluate, x86_64-darwin is gone, git
survives its deletion</summary>

```
== devShell evaluates per system ==
x86_64-linux     OK   g172vwl0g339zsxx9l6mz5pca6w9jbcx-nix-shell.drv
aarch64-linux    OK   pgvq71zs48bx3naddncms954jyqpl0bl-nix-shell.drv
aarch64-darwin   OK   d17q1772si0x0hj1lgpnin8wiq4zlpr2-nix-shell.drv
x86_64-darwin    FAIL: flake does not provide attribute 'devShells.x86_64-darwin.default'

== systems the flake declares ==
["aarch64-darwin","aarch64-linux","x86_64-linux"]

== tools in the x86_64-linux devShell ==
  git: present        jq: present         nushell: present
  powershell: present python3: present    procps: present
  lsof: present       fish: present       zsh: present
  bash: present       gh: present         pre-commit: present

== nixfmt --check flake.nix ==
  clean (exit 0)
```

The x86_64-darwin claim, checked against nixpkgs directly rather than
inferred:

```
== nixos-unstable lib.version ==
"26.11pre-git"
== x86_64-darwin eval on nixos-unstable ==
  error, pointing at release-notes#x86_64-darwin-26.11
== x86_64-darwin eval on the pinned rev (flake.lock) ==
evaluation warning: Nixpkgs 26.05 will be the last release to support x86_64-darwin
"hello-2.12.3"
```

Not verified: nothing was built, only evaluated. The nightly `nix-flake`
job runs `nix flake check` on PRs touching `flake.nix`, which covers
that on x86_64-linux.

</details>

<details>
<summary>setup-web: the block run under Task's own interpreter, in an
amd64 Debian container</summary>

The edited block was extracted into a minimal Taskfile and run by `task`
itself, so mvdan/sh parses it rather than bash. `curl` and nushell are
container prereqs, not part of what's under test.

```
=== running the extracted block under Task ===
Installing shell-integration test dependencies...
pwsh installed
bash available
zsh available
fish available
nu available
pwsh available
jq available
task exit: 0

=== does the installed pwsh actually run? ===
7.6.4
jq-1.6
/usr/bin/pwsh

=== rerun is idempotent ===
Installing shell-integration test dependencies...
bash available   zsh available   fish available
nu available     pwsh available  jq available
```

Two earlier runs are why the shape changed. The first died at the
`sources.list.d` glob. The second installed PowerShell from the release
tarball: every tool reported "available" and `pwsh` then aborted with
`Couldn't find a valid ICU package installed on the system`, which is
what moved the install to the `.deb` and the check from `command -v` to
`--version`.

</details>

`cargo run -- hook pre-merge --yes` passes: 4574 tests, 1 skipped.

## Notes

`task setup-web` still requires nushell to be present rather than
installing it, unchanged here.

> _This was written by Claude Code on behalf of max-sixty_

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 14:56:07 -07:00
Maximilian Roos 00ab0ffa26 Canonicalize benchmark fixtures and variants (#3761)
Benchmark fixtures still encoded the benchmark that first needed each
repository state, which left overlapping recipes and variants after the
earlier harness consolidation. This change reduces the fixture catalog
to two provenance-based bases: `Generated` builds an ordinary Git
repository locally, while `Imported` copies the pinned `rust-lang/rust`
corpus. Worktree, branch, and remote-ref populations remain parameters
on `Generated`; prune candidates and backdrop are overlays that work
with either base.

The generated base deliberately combines heterogeneous worktree states,
history-spread branches, and optional remote refs so ordinary list,
completion, picker, first-output, alias, remove, and prune benchmarks
can share it. Imported history-spread branches and clean base-tip
worktrees carry their own commits, preserving the base populations
without making them incidental prune candidates when overlays advance
the default branch.

The benchmark matrix now keeps single-factor contrasts: list scaling
uses the 1- and 8-worktree endpoints; alias dispatch has a startup
floor, two population endpoints, and one warm/cold variable-resolution
pair; completion keeps one full-surface case; remove and prune vary
cache or hook state only where the command exercises it. Historical
recipes, redundant cache rows, and intermediate scaling points are
removed. Manual setup paths live under `target/`, and the benchmark
guide documents the resulting fixture and cache model.

Tests: `cargo run -- hook pre-merge --yes` after merging current `main`
(4,571 tests); targeted Criterion test-mode runs; `cargo test -p
wt-perf`; benchmark check, clippy, formatting, and diff checks.

> _This was written by Codex on behalf of max-sixty_
2026-08-08 13:38:00 -07:00
Maximilian Roos 497551e076 fix(nix): give the devShell every tool the test suite shells out to (#3768)
`devShells.default` listed `bash`, `zsh`, `fish` under a `# For shell
integration tests` comment, but that feature drives two more shells and
shells out to `jq`. So `nix develop` could not run `--features
shell-integration-tests`, which is what the repo's own gate runs
(`.config/wt.toml` → `cargo insta test … --all-features`). This adds
`nushell`, `powershell` and `jq`.

The same dependency claim was stated, wrongly, in three other places.
All four now name the real set:

| Where | Was | Now |
|---|---|---|
| `flake.nix` devShell | bash, zsh, fish | + nushell, powershell, jq |
| `Cargo.toml` feature comment | bash, zsh, fish | + nu, pwsh, jq |
| `tests/CLAUDE.md` | bash/zsh/fish + PTY | + nushell, pwsh, jq |
| `docs/content/faq.md` | bash, zsh, fish, nushell | + pwsh, jq |

`flake.nix` also referenced a `CLAUDE.md → "Shell/PTY Integration
Tests"` heading that exists nowhere in the repo; it now points at the
section that does.

## Verification

There is no `nix` on the machine this was written on, so the two claims
were checked separately rather than by entering the shell.

**Is the list right?** A symlink farm modelling a devShell's `PATH` —
nixpkgs stdenv's own tools plus the candidate list, and nothing else —
with the full `--all-features` suite run under it.
`configure_pty_command` propagates the test process's `PATH` into PTY
children, so this reaches the shell tests.

<details>
<summary>Runs (the control is what makes the failures
attributable)</summary>

| PATH | Result |
|---|---|
| Full ambient PATH (control) | 4572 passed, 0 failed |
| stdenv + every tool the suite needs | 4572 passed, 0 failed |
| …minus `pwsh` | 3 `shell_powershell` tests fail |
| …minus `jq` |
`test_worktree_remove_hook_skips_path_holding_no_worktree` fails |
| …minus `python3` / `lsof` / `ps` | 6 failed: 2 `for_each`/`post_start`
(python3), 1 `remove::test_remove_reap_kills_process` (lsof), 3
pgid/process-probe (ps) |

The control run matters: it establishes that every failure above is
caused by the withheld tool rather than by a local flake.

The last row is about what the *suite* needs, not what the shell was
missing — see the correction below.

</details>

**Does the flake still evaluate?** `nixos/nix` in a container,
evaluating `devShells.<system>.default` for all four systems
`flake-utils` covers, against unmodified `main` as a control. All four
evaluate, and every tool resolves on each.

Not verified: nothing here was *built*, only evaluated, so a package
that evaluates but fails to build would not have been caught. The
nightly `nix-flake` job runs `nix flake check` on PRs touching
`flake.nix`, which covers that on x86_64-linux.

<details>
<summary>A correction: python3/procps/lsof were never missing</summary>

The first version of this PR also added `python3`, `procps` and `lsof`,
claiming the shell could not run a plain `cargo test`. That was wrong,
and worktrunk-bot caught it.

`craneLib.devShell` sets `inputsFrom = builtins.attrValues checks ++
inputsFrom`, and `mkShell` folds each `inputsFrom` derivation's
`nativeBuildInputs` into its own. `checks` includes `worktrunk-tests`,
whose `nativeBuildInputs` already carry `git`, `python3`, `procps` and
`lsof` — so the devShell inherited all four. Evaluating the unmodified
`main` tree confirms it: its `x86_64-linux` devShell derivation already
contains `python3`, `procps` and `lsof`, and contains no `nushell`,
`powershell` or `jq`.

The symlink farm could not have caught this: it modelled stdenv plus the
literal `packages` list, so crane's inherited inputs were invisible to
it by construction. The experiment established what the *suite* needs;
it said nothing about what the *shell already had*.

Those three lines are dropped. `git` remains listed in both places —
pre-existing, and left alone here.

</details>

<details>
<summary>A guard I added and then removed</summary>

`powershell` first went in behind `lib.meta.availableOn`, because
nixos-unstable's PowerShell has no `x86_64-darwin` source. Testing that
guard against nixpkgs HEAD showed the actual cause: nixpkgs 26.11
dropped Intel macOS wholesale, so the entire flake fails to evaluate
there regardless of the guard. On every system nixpkgs still supports,
PowerShell has a build — the guard protected against nothing, and its
comment justified it with the wrong mechanism. Removed; `powershell` is
listed plainly with the other shells.

</details>

## Notes

`task setup-web` checks for `bash zsh fish nu` and not `pwsh`/`jq` — the
same gap in a different environment, left alone here since its install
mechanics are unrelated.

> _This was written by Claude Code on behalf of max-sixty_
2026-08-07 16:56:56 -07:00
Maximilian Roos 970976bd32 Consolidate benchmark recipes and cases (#3721)
Benchmark fixtures had accumulated around individual call sites, leaving
the same repository shapes and command modes expressed several ways.
This change makes repository state the organizing concept: benchmark
groups select semantic `FixtureRecipe`s, share table-driven cases, and
retain separate fixtures only when a controlled contrast, destructive
precondition, or disproportionate setup cost requires one.

The real-repository list benchmarks now share one pinned
`rust-lang/rust` fixture with eight worktrees and fifty branches spread
across history. The list matrix keeps default, branch, warm, and cold
coverage without maintaining several “real” repository handles. Remove
and prune cases share the same case machinery, while the destructive
large-repository prune state remains separate.

The scheduled workflow now converts Criterion estimates directly with
`jq`, removing the one-off Python converter and its tests. The benchmark
guide records the canonical-fixture principle and the remaining
recipe-to-group mapping.

Tests: `cargo run -- hook pre-merge --yes` (4,551 tests); `cargo bench
--bench list large_repository -- --test`; `cargo test -p wt-perf`;
benchmark check, clippy, formatting, and diff checks.

> _This was written by Codex on behalf of max-sixty_.
2026-08-05 10:30:34 -07:00
Maximilian Roos 57b303fda2 fix(nix): provide lsof to the flake's test sandbox (#3410)
The nix-flake job has failed on main since #3396:
`test_remove_reap_kills_process` discovers its child via `lsof -d cwd`,
but the flake's `worktrunk-tests` check didn't provide `lsof`, so
`processes_under` fails to spawn it, returns an empty list forever, and
the test's 5s discovery poll panics with `child <pid> never discovered`.
Failing main run:
https://github.com/max-sixty/worktrunk/actions/runs/29066326142.

Three changes:

- `flake.nix`: add `pkgs.lsof` to the test check's inputs, the same
pattern as `git`/`python3`/`procps`. `ps` (procps) already works in the
sandbox, so /proc-based process inspection is available there and the
test should be genuinely exercised rather than excluded.
- `.github/workflows/nightly.yaml`: add `flake.nix`, `flake.lock`, and
`nix/**` to the trigger paths (push and PR gate). A flake change
couldn't previously trigger the nix-flake job that validates it; this PR
relies on the fixed trigger for its own validation.
- `tests/integration_tests/remove.rs`: point the discovery-timeout panic
message at lsof, so the next environment missing it doesn't need
re-diagnosing.

Validation: nix isn't available locally, so the proof is this PR's own
nightly run going green on the nix-flake job.

> _This was written by Claude Code on behalf of max_

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 23:29:40 -07:00
Maximilian Roos 958b9c188a refactor(picker): migrate to skim 4.8 (ratatui), drop vendored skim-tuikit (#3137)
Migrates the `wt switch` picker from skim 0.20.5 (tuikit backend) to
skim 4.8.0 (ratatui/crossterm), removes the `vendor/skim-tuikit/` patch
tree we carried against the old line, and makes the full test suite
green under the new backend.

## Why the vendor tree goes away

We vendored skim-tuikit for two patches: `alt-<digit>` key parsing and
an `Output::flush` `write_all` fix for dropped bytes under PTY pressure.
Both are moot in 4.8. Key parsing is native — `binds.rs` routes every
single character (digits included) through `KeyCode::Char` rather than a
hardcoded `alt-a..alt-z` arm list. The flush fix is subsumed by stdlib
`BufWriter::flush` in the ratatui backend, which loops over partial
writes correctly. So the migration carries zero vendor patches against
skim, and the build machinery that kept the vendored source alive
(Taskfile `vendor-diff`, flake `vendorSrc`/`extraDummyScript`) is
deleted too.

## The picker rewrite

skim 4.x is a different API. `WorktreeSkimItem::display()` now returns
`ratatui::text::Line` instead of an `AnsiString`. alt-r removal rides
skim's `reload(remove {})` token (the selected row's `output()`,
expanded into the reload command) instead of the old
`as_any().downcast_ref` path (which never worked across compilation
units) plus a signal file. Preview-tab switching and the progressive
list redraw are driven by `Skim::event_sender()` +
`Event::Render`/`Event::RunPreview`.

## The regression that motivated the bulk of this

skim 4.x renders on demand. There is no 100ms tuikit heartbeat
re-rendering the frame, so the progressive `wt switch` list rendered
blank while collection ran in the background — the original report. The
fix pokes `Event::Render` from the list-collect callbacks (throttled to
16ms). The same on-demand model surfaced four more regressions, all
fixed here and verified head-to-head against the 0.20 picker in a
terminal: preview-tab lag, current-row highlight, Shift-Tab back-cycle
(crossterm reports Shift-Tab under three distinct `KeyEvent` shapes, so
all three are bound), and alt-r removal (4.x `execute-silent` is
fire-and-forget and raced its reader).

## Help text and the test harness

Two things the integration suite caught that the unit tests did not (the
prior pass ran `--lib --bins` only):

- **Styled help.** skim 0.20 transitively pulled in
`clap/unstable-markdown`, which renders worktrunk's `///` doc-comments
as styled help. skim 4 with `default-features = false` drops it, so help
reverted to raw text (`[experimental]` → `\[experimental\]`). Restored
by depending on `unstable-markdown` explicitly, keeping help output
identical and the `test_help` / `test_step_alias` /
`test_docs_are_in_sync` snapshots passing unchanged.
- **PTY harness.** skim 4.x queries cursor position (`ESC[6n`) at
startup in partial-height mode and blocks in `select()` for the reply;
`portable_pty` is a bare PTY and never answered, so every
`switch_picker` test failed init with "Cursor position detection timed
out." The Unix harness now answers the query, mirroring the existing
ConPTY responder. skim 4.x also draws the list/preview separator one
column left, so the snapshot panel-split columns shifted to match. The
regenerated picker snapshots show two cosmetic changes: the match
counter no longer overlaps the preview tab header, and the HEAD column
shows the full short-SHA instead of a truncated one.

## Minimal-versions CI

The skim 4.8 dep tree pins tighter floors than our manifests declared,
so the nightly `minimal-versions` job needed updating. It now runs `-Z
direct-minimal-versions` — minimize only our own direct deps and let
transitive crates resolve normally — and the manifests raise each
under-specified floor to the minimum the workspace builds against
(largely mirroring skim 4.8's own requirements). Full `-Z
minimal-versions` would instead drag in skim's transitive TUI/image
stack (ansi-to-tui, ratatui's `instability` macro, color-eyre,
ratatui-image → image/avif), whose crates under-declare their floors and
don't compile at the picked versions; direct minimization confines the
check to floors we own, so no transitive pins are needed. Normal
resolution (the committed `Cargo.lock`) is unchanged. Full floor list
and the `signal-hook` libc-pin detail are in the `ci(min-versions)`
commit message.

## Reviewing

Start at `src/commands/picker/mod.rs` (the `run_skim` entry point, the
action keybinds, and `parse_reload_remove_token`), then
`progressive_handler.rs` (the render pokes) and `items.rs` (the
`Line`-based `display()`). Test-harness changes are in
`tests/common/pty.rs` (the `ESC[6n` responder) and
`tests/integration_tests/switch_picker.rs` (the panel-split columns).
The rest is the dependency swap, the vendor and build-machinery
deletions, and regenerated snapshots.

All 3980 tests pass (`cargo run -- hook pre-merge --yes`), including the
`shell-integration-tests` PTY suite that exercises the picker end-to-end
across the list, previews, scroll, create/remove, and accept flows. No
automated test drives a real terminal; the interactive surface was also
checked by hand against the 0.20 picker.

> _This was written by Claude Code on behalf of max_

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 03:41:20 -07:00
Worktrunk Bot ec62580c29 revert(hooks): keep docs on pre-start/post-start; code accepts both (#2857)
Per @max-sixty's [direction in
#2838](https://github.com/max-sixty/worktrunk/issues/2838#issuecomment-4509447593):
revert the docs portion of #2840 and keep the code. Docs continue to
recommend `pre-start`/`post-start`; both names work in code so anyone
who already followed the briefly-changed docs (e.g. @EcksDy) isn't
stranded once a release ships these aliases.

## User-visible — back to `pre-start`/`post-start`

- README, docs site, skill mirrors, `dev/*.example.toml`,
`plugins/worktrunk/README.md`, `flake.nix`, `.config/wt.toml`
- `src/cli/mod.rs` / `src/cli/config.rs` / `src/cli/step.rs` /
`src/help.rs` after_long_help and example snippets — and the auto-synced
`docs/content/` and `skills/worktrunk/reference/` mirrors
- `wt hook --help` canonical subcommand names; completion advertises
`-start` only
- `HookType` Display via strum, serde `rename`, and clap `ValueEnum`
name — all `pre-start`/`post-start`. The Rust variant identifiers stay
`PreCreate`/`PostCreate` (internal; we already paid for that rename in
#2840, and now the eventual flip is a Display-only change)
- `HooksConfig` serde canonical fields

## `*-create` still works (kept code)

- `wt hook pre-create` / `post-create` — CLI alias on the canonical
subcommand
- `pre-create` / `post-create` in config: top-level, `[hooks.*]`, and
per-project, in string, `[table]`, and `[[array-of-tables]]` form.
Mechanism: serde `alias = ...` on the field, plus a silent in-memory
rename in `migrate_content()` so the round-trip in `unknown_tree`
doesn't flag table forms as schema-unknown.
- The pre-0.32.0 `post-create` fatal-load-error machinery stays removed
— the name is reclaimed, and both forms load without error.

## Smaller bits

- `valid_user_config_keys()` / `valid_project_config_keys()` append
`pre-create` / `post-create` so the unknown-field round-trip skips them.
`test_valid_*_keys_all_deserialize` skips both aliases (they can't sit
alongside the canonical without a duplicate-field error).
- `DEPRECATED_SECTION_KEYS` drops the `pre-start`/`post-start` entries
#2840 added — `pre-start`/`post-start` are canonical again.
- `find_pre_start_from_doc` / `find_post_start_from_doc` /
`find_renamed_hook_key` / `is_non_empty_item` /
`migrate_start_hooks_doc` and their tests are removed; the migration
direction flips via a new `migrate_create_hooks_doc` (silent, mirrors
the prior shape).
- Test files `e2e_shell_post_create.rs` and `post_create_commands.rs`
rename back to `_post_start_` (via `git mv`, so the rename shows as a
rename).

## Testing

`cargo run -- hook pre-merge --yes` — 3806 tests pass; the 10 failures
are all `case_4` of `shell_wrapper::unix_tests::*` (nu-shell case; `nu`
isn't installed in this runner; same failures occur on `main`).

Also manually verified that a fresh `wt switch --create` against a
project config with `[post-create]` loads cleanly with no unknown-field
warning and the hook fires as `post-start`.

## Follow-up

Per @max-sixty: in a couple of weeks, once a release with
both-names-work is out and users have had a chance to upgrade, the docs
flip is straightforward (most of it is in `src/cli/mod.rs`'s
`after_long_help` and the doc-sync test propagates).

Re #2838.

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 16:03:03 +00:00
Maximilian Roos d7e3f88422 feat(hooks): rename worktree-creation hooks to pre-create/post-create (#2840)
Phase 1 of the staged hook rename tracked in #2838: the worktree-creation hooks `pre-start`/`post-start` become `pre-create`/`post-create`. The old names keep working with no deprecation warning yet (Phase 2, months out, adds the warning).

## What changes

- `pre-create`/`post-create` are canonical everywhere: the `HookType` enum, the `HooksConfig` serde fields, the `wt hook` CLI, completion, and all docs.
- Old names keep working: `migrate_content()` rewrites `pre-start`/`post-start` config keys to `-create` before serde, and `parse_hook_type` accepts the old CLI names as silent aliases. `wt config update` rewrites them on disk; `wt config show` shows the migration diff. `wt hook <type>` execution and `wt hook show` both accept the old names; completion and `--help` advertise only the canonical names.
- `detect_deprecations()` flags the old keys so `update`/`show` act on them, but `format_deprecation_warnings()` stays silent (Phase 2 adds the warning). A new empty-warnings guard in `check_and_migrate` keeps a `-start`-only config from emitting a stray hint.
- The dead pre-0.32.0 `post-create` machinery is removed: the fatal `POST_CREATE_REMOVED_MSG` load error, the vestigial `HooksConfig.post_create` merge-fold, and `find_post_create_from_doc`. `post-create` is reclaimed as the canonical background creation hook.

## Semantic flip

Before v0.32.0, the key `post-create` named a *blocking* hook. It now names the *background* one.

Since v0.44.0, a pre-0.32.0 `post-create` config is a fatal load error on the `check_and_migrate` paths: `ProjectConfig::load` and user/system config loading, which fire on essentially every `wt` command. A repo carrying one has been unusable ever since. The one path that skips that check is `project_config_at_ref` (the base-ref read behind `wt switch --create`), which applies only structural migration. A pre-0.32.0 `post-create` surviving solely on a base ref, never checked out into a worktree, would now load as a background hook rather than folding into the blocking `pre-start`. That edge case is accepted: once `post-create` is valid again, reclaiming the name and detecting the dead key are mutually exclusive.

## Reviewing this diff

205 files, but the substance is ~36 files under `src/`. The rest is regenerated snapshots and auto-synced doc mirrors. Start with:

- `src/config/deprecation.rs` — detection (`find_renamed_hook_key`), migration (`rename_hook_key`), removal of the fatal block, the empty-warnings guard, and the `DEPRECATED_SECTION_KEYS` entries that stop unknown-field detection from flagging the migrated keys.
- `src/config/hooks.rs`, `src/git/mod.rs` — the serde field and enum renames.
- `src/config/project.rs` — `ProjectConfig::load` deserializes `check_and_migrate`'s migrated content, so a current-worktree config using the old keys loads into the canonical fields.
- `src/cli/hook.rs`, `src/commands/hook_commands.rs`, `src/completion.rs`, `src/main.rs` — the CLI alias layer; `wt hook show` accepts the old type names as hidden value-parser aliases.
- `src/cli/mod.rs` — the `wt hook` docs, including the soft-deprecation note linking #2838.

The ~93 modified snapshots also pick up deterministic env-block lines (`GIT_*: ""`, `LLVM_PROFILE_FILE`) that pre-existing snapshots already carry. That is stale-snapshot drift surfaced by the regeneration, not a behavior change.

## Testing

Full suite green (3799 tests). New coverage: `snapshot_migrate_start_to_create` (migration preserves value shape and position), `test_deprecated_start_hook_key_runs_silently` and `test_standalone_hook_start_alias_runs_silently` (old config and CLI names run with no warning), `test_config_show_displays_start_hook_migration` (`config show` reveals the diff without an "unknown field" warning), and `test_hook_show_accepts_deprecated_start_hooks` (a current-worktree config using the old keys loads, and `wt hook show` takes both the canonical and the deprecated type arguments).

Part of #2838.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-20 19:31:50 -07:00
Worktrunk Bot f877aeade2 fix(nix): include gemini-extension.json in flake source filter (#2834) 2026-05-20 07:03:44 -07:00
Maximilian Roos 1fe346be42 ci(nightly): re-enable nix-flake job & fix sandbox failures (#2648)
## Summary

Restore the `nix-flake` nightly job (disabled in #2647) and fix the
sandbox-specific test failures it surfaces. With this merged, the
nightly cron run is back to gating against packaging-environment bugs.

## What's in here

- **Build-mode snapshot redaction**: 49 snapshots hardcoded
  `target/debug/wt` in "Invoked as:" and diagnostic output, which broke
  under crane's release builds. Collapse both modes to
  `target/[BUILD_MODE]/wt` in the shared insta filter.
- **Nix sandbox env**: add `pkgs.python3` and `pkgs.procps` to
  `worktrunk-tests`' native build inputs (needed by argv-quoting,
  post-start, and pgid-invariant tests). Replace
  `#!/usr/bin/env python3` with the absolute python path resolved at
  script-write time, since `/usr/bin/env` doesn't exist on NixOS.
- **PTY filter ordering**: extend `add_pty_binary_path_filters`'
  alternation to match the `[BUILD_MODE]` placeholder so PTY snapshots
  still collapse to `[BIN]` after the prelude rewrite runs first
  (caught by worktrunk-bot review).
- **One inherited-CWD test fix**: `test_config_init_already_exists`
  branched on whether the inherited CWD had a project config — pin
  it to a no-config tempdir so the snapshot is deterministic across
  cargo and nix.

## Test plan

- [x] `nix-flake` job passes in CI (1633 / 1633, was 54 failing)
- [x] All required `ci` checks pass
- [x] Auto-reviewer approved

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-08 16:22:53 -07:00
Maximilian Roos 793307aa3d ci(nightly): add nix flake check job (#2630)
## Summary

- Adds a `nix-flake` job to `.github/workflows/nightly.yaml` that runs
`nix flake check`.
- Adds a `worktrunk-tests` flake check that runs `cargo test` (default
features) against `pkgs.lib.cleanSource ./.`, which keeps `tests/`
fixtures and `src/` `.snap` files visible to the test build. The
production package src filter stays narrow.
- Wires the new job into the existing `create-issue-on-nightly-failure`
flow so failures open the standard nightly-failure issue.

## Why

Surfaces packaging-environment bugs before nixpkgs maintainers hit them.
The canonical example is #2624 — a unit test that depends on the process
CWD being inside a git repo, which fails in the nix build sandbox where
source is extracted from a tarball without `.git`.

`shell-integration-tests` is intentionally not enabled — it requires
zsh/fish/nushell + PTY, and nextest's InputHandler conflicts with
interactive shells in CI sandboxes (see CLAUDE.md → "Shell/PTY
Integration Tests"). Worth a follow-up if/when the basic check is
stable.

Cold runs are slow (~10–15 min build + test). Nightly cadence absorbs
the latency. If we want to cut that we can add a binary cache (cachix or
FlakeHub) in a follow-up.

## Test plan

- [ ] First scheduled run (or `workflow_dispatch`) succeeds.
- [ ] If `worktrunk-tests` fails, the failure surfaces against the
existing nightly-failure issue.
- [ ] Locally: `nix flake check` passes on a machine with nix installed
(not validated — no nix on this dev host).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-06 22:07:42 -07:00
Worktrunk Bot 1cff0968bd chore(nix): read Rust channel from rust-toolchain.toml (#2188)
## Summary

Implements the first two proposals from [#2185
(comment)](https://github.com/max-sixty/worktrunk/pull/2185#issuecomment-4234599092):

- **`flake.nix` reads the Rust channel from `rust-toolchain.toml`** —
one source of truth for rustup and Nix. The weekly MSRV bump now
propagates to the Nix toolchain automatically, turning silent drift into
a loud "channel not in locked rust-overlay" error if the lock also falls
behind.
- **Weekly maintenance playbook now runs `nix flake update`** — covers
the residual case where a newly pinned channel is newer than the locked
`rust-overlay` revision. The `flake.nix` row in the files table is gone
since there is nothing to edit there anymore.

Extensions (`rust-src`, `rust-analyzer`) stay in `flake.nix` rather than
moving into `rust-toolchain.toml` — putting them in the toolchain file
would force rustup users and CI to download them too, and they are only
useful inside the Nix dev shell.

Skipped proposal #3 (adding a `nix build` CI job) — that's a bigger
change and worth a separate discussion.

## Test plan

- [ ] `nix build .#worktrunk` succeeds (could not verify in CI runner —
no `nix` installed)
- [ ] `nix develop -c cargo build` succeeds
- [ ] `nix flake check` passes

Co-authored-by: worktrunk-bot <worktrunk-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 23:22:35 -07:00
Nick Dichev b1cea9cae5 fix: use a crane dummy source for the vendored patch to skim (#2265) 2026-04-16 18:36:24 -07:00
Worktrunk Bot 2c602bbfd6 chore: bump MSRV from 1.89 to 1.93 (#2125) 2026-04-12 06:25:48 -07:00
Marius Kimmina c80c8ba874 fix: allow dev directory in flake.nix (#1924)
Fixes #1923

Signed-off-by: Marius Kimmina <marius.kimmina@proton.me>
2026-04-06 11:25:49 -07:00
onelock fe395cb467 fix(nix): evaluation warning system renamed to stdenv.hostPlatform.system (#1336)
I am using the home-manager module and this warning is a bit annoying.
 
```bash
evaluation warning: 'system' has been renamed to/replaced by 'stdenv.hostPlatform.system'
```

---------

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:29:36 -08:00
jan Lemata 966651385a feat: add Nix Home Manager module (#1287) 2026-03-05 11:47:27 -08:00
Maximilian Roos ec64dbebce fix: use WT_TEST_EPOCH instead of SOURCE_DATE_EPOCH for test time control (#767)
* fix: use WT_TEST_EPOCH instead of SOURCE_DATE_EPOCH for test time control

SOURCE_DATE_EPOCH is a reproducible builds standard commonly set by NixOS/direnv
in development shells. When set to a past timestamp (typical for builds), the
Age column in `wt list` incorrectly shows "future" for all commits.

Switch to WT_TEST_EPOCH which is only set by our test harness, leaving
production users unaffected.

Fixes #763

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: restore PTY test snapshots with WT_TEST_EPOCH

The previous commit deleted PTY-based test snapshots that can only be
regenerated in CI (they require Linux/macOS PTY support). This commit
restores those 46 snapshots from main and updates them to use
WT_TEST_EPOCH instead of SOURCE_DATE_EPOCH.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: wrap bare URL in angle brackets for rustdoc

RUSTDOCFLAGS='-Dwarnings' fails on bare URLs in doc comments. Wrap the
GitHub issue link in angle brackets to make it a proper hyperlink.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-20 11:38:22 -08:00
Mattias Sjödin ee29d4a93d fix: remove apple_sdk framework (#525) 2026-01-11 07:23:26 -08:00
marktoda bee58c6681 feat: add Nix flake for packaging (#502)
* feat: add Nix flake for packaging

Use crane for efficient Rust builds with dependency caching.
Provides packages, dev shell, and CI checks (clippy, fmt, tests).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: skip tests in flake build

* fix: anchor Nix result patterns to repo root

Use `/result` instead of `result` to avoid accidentally ignoring
legitimate `result` files/directories in subdirectories.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Maximilian Roos <m@maxroos.com>
2026-01-09 22:51:30 +00:00