Files

250 lines
8.0 KiB
Nix
Raw Permalink Normal View History

{
description = "Worktrunk - A CLI for Git worktree management";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
crane.url = "github:ipetkov/crane";
};
2026-01-11 16:23:26 +01:00
outputs =
{
self,
nixpkgs,
flake-utils,
rust-overlay,
crane,
}:
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
# `eachDefaultSystem` minus x86_64-darwin: nixpkgs drops Intel macOS in
# 26.11, so that system stops evaluating once flake.lock advances past
# it. Release binaries still ship for Intel macOS (dist-workspace.toml);
# this is the Nix surface only.
flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ] (
2026-01-11 16:23:26 +01:00
system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
# Pin to the channel declared in rust-toolchain.toml so rustup and Nix
# stay on the same version. Extensions are dev-shell-only, so we keep
# them here rather than in rust-toolchain.toml (which CI also reads).
toolchainChannel = (builtins.fromTOML (builtins.readFile ./rust-toolchain.toml)).toolchain.channel;
rustToolchain = pkgs.rust-bin.stable.${toolchainChannel}.default.override {
2026-01-11 16:23:26 +01:00
extensions = [
"rust-src"
"rust-analyzer"
];
};
craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain;
# Filter source to include Cargo files, askama templates, and compile-time data.
# Gemini's loader requires its manifest at the repo root (see #2807).
# The benchmark fixture definition stays extensionless so Cargo does not
# auto-discover it as a bench target.
src = pkgs.lib.cleanSourceWith {
src = ./.;
2026-01-11 16:23:26 +01:00
filter =
p: type:
(craneLib.filterCargoSources p type)
|| (pkgs.lib.hasInfix "/templates/" p)
|| (baseNameOf (dirOf p) == "templates")
|| (pkgs.lib.hasInfix "/dev/" p)
|| (baseNameOf (dirOf p) == "dev")
|| (baseNameOf p == "gemini-extension.json")
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
|| (baseNameOf p == "imported-fixture");
};
# Common arguments for crane builds
commonArgs = {
inherit src;
strictDeps = true;
nativeBuildInputs = with pkgs; [
pkg-config
];
2026-01-11 16:23:26 +01:00
buildInputs =
with pkgs;
[
# Required for tree-sitter (syntax-highlighting feature, enabled by default)
tree-sitter
]
++ pkgs.lib.optionals pkgs.stdenv.isDarwin [
libiconv
];
# vergen-gitcl needs git info; VERGEN_IDEMPOTENT makes it emit
# placeholder values when .git isn't available (which is the case
# in Nix builds since the store doesn't include .git)
VERGEN_IDEMPOTENT = "1";
# Optionally provide git describe via environment if flake has rev
2026-01-11 16:23:26 +01:00
VERGEN_GIT_DESCRIBE =
self.shortRev or self.dirtyShortRev or "nix-${self.lastModifiedDate or "unknown"}";
};
# Build just the cargo dependencies for caching.
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
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
# Build the actual package
2026-01-11 16:23:26 +01:00
worktrunk = craneLib.buildPackage (
commonArgs
// {
inherit cargoArtifacts;
# Skip tests during package build - they require snapshot files (insta)
# which bloat the source. Tests should run in CI instead.
2026-01-11 16:23:26 +01:00
doCheck = false;
meta = with pkgs.lib; {
description = "A CLI for Git worktree management, designed for parallel AI agent workflows";
homepage = "https://github.com/max-sixty/worktrunk";
license = with licenses; [
mit
asl20
];
maintainers = [ ];
mainProgram = "wt";
};
}
);
# Build with git-wt feature for Windows compatibility
2026-01-11 16:23:26 +01:00
worktrunk-with-git-wt = craneLib.buildPackage (
commonArgs
// {
inherit cargoArtifacts;
cargoExtraArgs = "--features git-wt";
doCheck = false;
2026-01-11 16:23:26 +01:00
meta = worktrunk.meta // {
description = "Worktrunk with git-wt binary (for 'git wt' subcommand)";
};
}
);
in
{
checks = {
inherit worktrunk;
# Run clippy
2026-01-11 16:23:26 +01:00
worktrunk-clippy = craneLib.cargoClippy (
commonArgs
// {
inherit cargoArtifacts;
cargoClippyExtraArgs = "--all-targets -- --deny warnings";
}
);
# Check formatting
worktrunk-fmt = craneLib.cargoFmt { inherit src; };
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
# Run tests inside the nix sandbox. Catches packaging-environment
# bugs (#2624 is the canonical example) before nixpkgs maintainers
# do — see .github/workflows/nightly.yaml.
#
# Wider src than the package build: tests need .snap files and
# tests/ fixtures (prebuilt _git/ trees, .sh scripts, no-extension
# git database files). Default features only — shell-integration-
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
# tests wants a PTY and more shells than this derivation carries;
# the devShell below is where that set lives (see tests/CLAUDE.md →
# "Feature Flags, Not Runtime Skipping").
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-tests = craneLib.cargoTest (
commonArgs
// {
inherit cargoArtifacts;
src = pkgs.lib.cleanSource ./.;
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
# Tests shell out to a few host tools — `git` for the harness,
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 09:03:03 -07:00
# `python3` for argv-quoting and post-start fixtures, `ps`
# (procps) for the pgid invariant test, `lsof` for the
# `--reap` process-discovery test. Without these on PATH
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
# the sandbox surfaces them as `No such file or directory`.
nativeBuildInputs = commonArgs.nativeBuildInputs ++ [
pkgs.git
pkgs.python3
pkgs.procps
pkgs.lsof
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
];
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
}
);
};
packages = {
default = worktrunk;
inherit worktrunk;
inherit worktrunk-with-git-wt;
};
apps = {
default = flake-utils.lib.mkApp {
drv = worktrunk;
name = "wt";
};
wt = flake-utils.lib.mkApp {
drv = worktrunk;
name = "wt";
};
};
devShells.default = craneLib.devShell {
checks = self.checks.${system};
packages = with pkgs; [
# Rust tooling
cargo-watch
cargo-edit
cargo-outdated
cargo-release
cargo-llvm-cov
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
# Shells the `shell-integration-tests` feature drives, plus the
# `jq` its Claude-hook tests pipe the hook payload through. The
# pre-merge gate runs `--all-features`, so a run here exercises
# every one.
bash
zsh
fish
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
nushell
powershell
jq
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
# Development tools. `git` comes from the `checks` above: crane
# folds each check's `nativeBuildInputs` in via `inputsFrom`.
gh
pre-commit
];
shellHook = ''
echo "Worktrunk development shell"
echo " Build: cargo build"
echo " Test: cargo test"
echo " Lint: cargo clippy"
'';
};
}
)
// {
homeModules = {
default =
{
lib,
config,
pkgs,
...
}:
(import ./nix/home-manager-module.nix) {
inherit lib config pkgs;
worktrunk-pkgs = self.packages.${pkgs.stdenv.hostPlatform.system};
};
};
};
}