mirror of
https://github.com/max-sixty/worktrunk.git
synced 2026-09-14 20:00:38 +08:00
Release v0.77.0 (#4044)
Version bump to 0.77.0 plus the changelog section for this release. **Bump level**: minor. `cargo semver-checks` reports 8 breaking library changes (removed `DeprecationInfo::has_deprecated_patterns`, `Repository::recent_commit_subjects`, `Repository::diff_stats_summary`, `config::detect_deprecations`; arity changes on `compute_migrated_content` and `Progress::record`). Pre-1.0, so a breaking change takes a minor bump. `wt list --format=json` defaulting to schema 2 is a user-facing break on its own. **Validation** - `cargo run -- hook pre-merge --yes` — 4831 tests passed, 1 skipped; clippy, fmt, doc-sync, snapshot and lockfile checks green - Nightly dispatched on the cut-from tip (https://github.com/max-sixty/worktrunk/actions/runs/34272636821): full-tests on linux, macos, windows and git-2.43 all green, alongside release-target ×3, nix-flake, minimal-versions, crate-build, unused-deps and link-check **Changelog** 29 entries. Each was verified against its commit's diff by a separate pass, which caught two uncovered fixes (#4033/#4034 uninstall idempotency), one entry in the wrong section (#4018 is a fix, not an improvement), and three unmentioned machine-visible breaks (`wt list` JSON `marker`/`state`, `copy-ignored --dry-run` dropping `files`/`bytes`, the hidden-column footer wording). One correction to the previous release's notes: the `wt config update --output` entry was filed under `## 0.76.0` by #4021, which landed after v0.76.0 was tagged. It moves to 0.77.0, where it actually ships. **Data-loss surface review** Four independent finders swept the cumulative diff. The destructive core is untouched — no changes in `src/commands/process.rs`, `src/git/remove.rs`, `src/utils.rs`, or `src/commands/remove.rs`. This release removes a loss path: #3984 deletes the fork-PR `git branch -D` rollback that force-deleted a pre-existing branch, and its reflog, when the branch name was already taken. Three follow-ups, none blocking: `run_plugin_removal` reporting success over a failed marketplace removal; the documented-not-fixed `post-commit` window in `wt merge`; and `merge_args_into_command`'s `args` precondition, now dead code since `drop_unsupported_keys` removes the key regardless. > _This was written by Claude Code on behalf of max-sixty_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_0134XuJoGCzwoZ21XXbWujdY Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+58
-6
@@ -1,23 +1,75 @@
|
||||
# Changelog
|
||||
|
||||
## Unreleased
|
||||
## 0.77.0
|
||||
|
||||
### Improved
|
||||
|
||||
- **`wt list --format=json` now defaults to schema 2**: callers get the envelope with repository metadata and orthogonal per-item facts without configuring `[list] json-schema`. `wt list statusline --format=json` follows the same key. Set `json-schema = 1` to retain the original bare-array format. (Breaking.)
|
||||
- **`wt list` sizes and aligns its columns to the terminal width**: one long branch name no longer sizes the Branch column for every row — it caps at 32 characters and elides, so a narrow terminal keeps its other columns instead of degenerating into a branch list. `Remote⇅` stops holding blank space open in a repo with no remote, and alignment now follows the value type. `--format=json` still carries the whole name. ([#3998](https://github.com/max-sixty/worktrunk/pull/3998))
|
||||
|
||||
- **`wt list` names what it hid and marks detached worktrees**: the summary reads `hidden: Path, Commit` instead of counting columns, a detached worktree shows `⊘` rather than borrowing `⚑`, and a prunable row leaves its cells blank instead of showing loading dots that never resolve. ([#3998](https://github.com/max-sixty/worktrunk/pull/3998))
|
||||
|
||||
- **`wt list --format=json` gains a `marker` field and stops reporting `detached` twice**: the branch marker set by `wt config state marker` is now readable without parsing it out of `symbols`, and `state` no longer carries `detached` — the sibling `detached` boolean already does. ([#3998](https://github.com/max-sixty/worktrunk/pull/3998))
|
||||
|
||||
- **`wt list --format=json` now defaults to schema 2**: callers get the envelope with repository metadata and orthogonal per-item facts without configuring `[list] json-schema`. `wt list statusline --format=json` follows the same key. Set `json-schema = 1` to retain the original bare-array format. (Breaking.) ([#4038](https://github.com/max-sixty/worktrunk/pull/4038))
|
||||
|
||||
- **`wt config show` fails on a broken config**: it exits 1 on an unreadable or invalid config, an invalid `[list] columns`, or an invalid `approvals.toml`. Unknown keys and deprecations stay warnings and still exit 0. A new `APPROVALS` section names project commands awaiting approval. (Breaking: it always exited 0 before.) ([#3999](https://github.com/max-sixty/worktrunk/pull/3999))
|
||||
|
||||
- **Config migration output names its destination**: `wt config update --output <path>` writes the migration artifact to that file instead of applying it in place, and `--output=-` writes it to stdout. Output mode includes project config when run from a linked worktree. (Breaking: `--print` was removed.) ([#4021](https://github.com/max-sixty/worktrunk/pull/4021))
|
||||
|
||||
- **Pi joins the agent integrations**: `wt config plugins pi install` writes an activity hook to `~/.omp/agent/hooks/pre/worktrunk.ts`, so Pi sessions show 🤖/💬 markers in `wt list` like Claude Code, Codex, OpenCode, and Gemini. `$PI_CONFIG_DIR`, `$PI_CODING_AGENT_DIR`, and named `$OMP_PROFILE`/`$PI_PROFILE` profiles are honored. [Docs](https://worktrunk.dev/claude-code/) ([#3594](https://github.com/max-sixty/worktrunk/pull/3594), thanks @adity982, and @ortonomy for the request)
|
||||
|
||||
- **`wt config plugins codex install` installs the plugin too**: it no longer just registers the marketplace, instead of ending with a hint to run `/plugins` in Codex yourself. Uninstall follows for both Codex and Claude Code, removing the plugin and then the marketplace, so the two commands are inverses. (Breaking: uninstall previously left an installed plugin alone.) ([#4019](https://github.com/max-sixty/worktrunk/pull/4019))
|
||||
|
||||
- **`wt step copy-ignored` says whether it reflinked or copied**: the summary now reads `(reflinked, no extra disk)`, `(full copy)`, or a partial count, so the same `29.5 GB` line distinguishes a free copy from one that actually wrote the bytes. `--format=json` gains `reflinked` and `written`; a `--dry-run` plan no longer reports `files`/`bytes`. ([#4025](https://github.com/max-sixty/worktrunk/pull/4025))
|
||||
|
||||
- **`wt config update` removes keys its destination cannot hold**: migrating `[select]` or `[commit-generation]` drops keys the new section has no field for, reporting each one, and removes a `[projects."<id>"]` section the removal empties. Otherwise the key landed at a path the user never typed and warned on every command, with no way to clear it. ([#3994](https://github.com/max-sixty/worktrunk/pull/3994))
|
||||
|
||||
### Fixed
|
||||
|
||||
- **`wt switch --execute` now names the directory the program actually starts in**: the `Executing (--execute) @ …` header rendered the worktree the background hooks run in, which the program need not enter — `--no-cd` starts it in the invoking directory, and a switch from a subdirectory keeps that position, so the header pointed one level out. It now names the program's own directory, and omits the path when that is where the user's shell already stands. ([#4042](https://github.com/max-sixty/worktrunk/issues/4042), thanks @yajo for reporting)
|
||||
- **A failed `wt switch pr:<n>` against a fork no longer deletes your branch**: the fork path rolled back by force-deleting the branch on any setup error — including when the branch already existed, so a `pre-switch` hook or a concurrent session claiming the name cost you that branch and any commits only it held. Branch and worktree are now created in one `git worktree add -b`, which writes nothing when the name is taken. ([#3984](https://github.com/max-sixty/worktrunk/pull/3984))
|
||||
|
||||
- **Codex on Windows: the activity hooks no longer fail on every event**: each hook led with a bare `bash`, which `cmd.exe` resolves to the WSL launcher rather than Git Bash; in a sandboxed session it refuses to start, so every event raised a `Hook failed` banner. Each hook now carries a Windows-only command that runs the same `wt.sh` through a `cmd.exe` shim, which finds Git Bash by path rather than by name. ([#4008](https://github.com/max-sixty/worktrunk/pull/4008), fixes [#4007](https://github.com/max-sixty/worktrunk/issues/4007), thanks @McNultyyy for reporting and diagnosing)
|
||||
- **Codex on Windows: the activity hooks no longer fail on every event**: each hook led with a bare `bash`, which `cmd.exe` resolves to the WSL launcher rather than Git Bash, so every event raised a `Hook failed` banner. Hooks now run `wt.sh` through a shim that finds Git Bash by path. ([#4008](https://github.com/max-sixty/worktrunk/pull/4008), fixes [#4007](https://github.com/max-sixty/worktrunk/issues/4007), thanks @McNultyyy for reporting and diagnosing)
|
||||
|
||||
- **Templates leave `branch` unset in a detached worktree**: aliases and hooks rendered `{{ branch }}` as the literal `HEAD`, which git resolves, so an unguarded template ran against the wrong ref — the reported case ended in `git push origin --delete HEAD`. `base` and `target` follow. (Breaking: an unguarded `{{ branch }}` now errors.) ([#4010](https://github.com/max-sixty/worktrunk/pull/4010), fixes [#4009](https://github.com/max-sixty/worktrunk/issues/4009))
|
||||
|
||||
- **The OpenCode plugin loads under OpenCode 2**: OpenCode 2's loader dropped the old bare-function export silently, so activity markers stopped appearing. The plugin now exports both shapes and spawns `wt` through `node:child_process` rather than the Bun shell. Re-run `wt config plugins opencode install` to pick it up; OpenCode below 1.14.19 no longer loads it. ([#4018](https://github.com/max-sixty/worktrunk/pull/4018), thanks @pragmaticivan for the request)
|
||||
|
||||
- **`wt step commit --branch` builds its prompt from the worktree being committed**: prompt-building git plumbing ran in the invoking worktree, so with nothing staged there the generated message described none of the changes it committed. `wt step relocate --commit` had the same bug, and `--dry-run`/`--show-prompt` now preview the worktree `--branch` names. ([#3996](https://github.com/max-sixty/worktrunk/pull/3996))
|
||||
|
||||
- **LLM commit messages keep diffs for quoted paths**: a file whose name git quotes in the `diff --git` header — any non-ASCII name under the default `core.quotePath` — had its whole diff section dropped from the prompt once the diff exceeded the 100 KB budget. ([#4041](https://github.com/max-sixty/worktrunk/pull/4041))
|
||||
|
||||
- **An unparsable user config is reported, not a panic**: `wt config show`, `wt step prune`, `relocate`, `eval`, and `for-each` panicked on a debug build and printed a bare `✗ Command failed` on a release one. They now report `✗ Failed to load config` with the parser's caret diagram. ([#4002](https://github.com/max-sixty/worktrunk/pull/4002))
|
||||
|
||||
- **`wt switch --execute` names the directory the program actually starts in**: the `Executing (--execute) @ …` header rendered the worktree the background hooks run in, not the program's own directory — which differs under `--no-cd` or a switch from a subdirectory. The path is omitted when the shell already stands there. ([#4042](https://github.com/max-sixty/worktrunk/issues/4042), thanks @yajo for reporting)
|
||||
|
||||
- **`wt config plugins claude|codex uninstall` is safe to re-run**: removing an already-absent marketplace reported a failure, and a Claude uninstall that removed the plugin and then failed left the marketplace with no way to clear it. Both now finish a half-done uninstall and succeed when there is nothing left to remove. ([#4033](https://github.com/max-sixty/worktrunk/pull/4033), [#4034](https://github.com/max-sixty/worktrunk/pull/4034))
|
||||
|
||||
- **`wt config state marker` set and clear no-op outside a git repository**: they errored, so an agent plugin's hooks failed on every event in a non-repo directory. ([#3981](https://github.com/max-sixty/worktrunk/pull/3981), thanks @mahirhir)
|
||||
|
||||
- **`wt list` produces output in a bare repo with no worktrees**: it printed nothing at all and exited 0. It now reports `○ No worktrees` with a hint, `--branches` lists the branches, and `--format json` emits the envelope with an empty `items`. ([#3992](https://github.com/max-sixty/worktrunk/pull/3992))
|
||||
|
||||
- **`wt list` warns when it can't parse the project config** rather than ignoring it silently; the listing still succeeds. ([#3993](https://github.com/max-sixty/worktrunk/pull/3993))
|
||||
|
||||
- **Relayed command output no longer prints ahead of the delayed-stream progress line**, and delayed-stream output routes through anstream so color is stripped consistently when redirected. ([#4037](https://github.com/max-sixty/worktrunk/pull/4037), [#3995](https://github.com/max-sixty/worktrunk/pull/3995))
|
||||
|
||||
- **A hook filter that matches nothing names the unconfigured source**, rather than reporting no match without saying which source was empty. ([#3997](https://github.com/max-sixty/worktrunk/pull/3997))
|
||||
|
||||
### Documentation
|
||||
|
||||
- **`wt hook` says that `post-*` hooks from the two sources run concurrently**, so dependent commands belong in one source; `wt merge` records that `post-commit` can't run when the merge removes the worktree it anchors on. ([#4020](https://github.com/max-sixty/worktrunk/pull/4020), [#4026](https://github.com/max-sixty/worktrunk/pull/4026))
|
||||
|
||||
- **`wt step` help pages describe what the commands actually do**: `wt step prune` says it removes branches as well as worktrees, `wt step copy-ignored` documents `--from`/`--to`, and `wt step commit` / `squash` document `--branch`, their hooks, and their no-LLM fallback messages. ([#3997](https://github.com/max-sixty/worktrunk/pull/3997))
|
||||
|
||||
- **The FAQ lists the files Worktrunk writes outside its own config**: the agent-integration plugin and hook paths for Claude Code, Codex, OpenCode, Pi, and Gemini, alongside the existing inventory of what Worktrunk creates and deletes. ([#4036](https://github.com/max-sixty/worktrunk/pull/4036))
|
||||
|
||||
- **`wt step copy-ignored` documents its disk-space benefit** per filesystem, and the bare-repo `worktree-path` example names the bare repo's own location. ([#4022](https://github.com/max-sixty/worktrunk/pull/4022), [#4006](https://github.com/max-sixty/worktrunk/pull/4006))
|
||||
|
||||
- **Terminal examples on the docs site fit a desktop window** rather than overflowing. ([#4039](https://github.com/max-sixty/worktrunk/pull/4039))
|
||||
|
||||
## 0.76.0
|
||||
|
||||
### Improved
|
||||
|
||||
- **Config migration output names its destination**: `wt config update --output <path>` writes the migration artifact to that file instead of applying it in place, and `--output=-` writes it to stdout. Output mode includes project config when run from a linked worktree. (Breaking: `--print` was removed.)
|
||||
|
||||
- **`wt switch --execute` takes a program, not a shell string**: `-x` names one program, with everything after `--` passed as literal argv. Worktrunk spawns it as a child rather than running it in your interactive shell, so shell functions and its `cd` no longer reach you. `-x sh -- -c '…'` recovers shell syntax, not functions. (Breaking: existing `-x` strings, plus `WORKTRUNK_DIRECTIVE_EXEC_FILE` and `WORKTRUNK_SHELL`.) ([#3977](https://github.com/max-sixty/worktrunk/pull/3977), closes [#2860](https://github.com/max-sixty/worktrunk/issues/2860), fixes [#3944](https://github.com/max-sixty/worktrunk/issues/3944), thanks @omgreenfield for testing the migration path)
|
||||
|
||||
- **Worktrunk decides tracking for the branches it creates**: a new branch gets an upstream only when its name matches the remote branch it starts from, whatever `branch.autoSetupMerge` says: `--create release --base origin/release` tracks, `--create feature --base origin/release` does not. Under `autoSetupMerge = false` this previously exited 128 after creating the worktree. ([#3913](https://github.com/max-sixty/worktrunk/pull/3913), [#3950](https://github.com/max-sixty/worktrunk/pull/3950), fixes [#3937](https://github.com/max-sixty/worktrunk/issues/3937), thanks @mjakl for reporting and diagnosing)
|
||||
|
||||
Generated
+1
-1
@@ -4655,7 +4655,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "worktrunk"
|
||||
version = "0.76.0"
|
||||
version = "0.77.0"
|
||||
dependencies = [
|
||||
"ansi-str",
|
||||
"ansi-to-tui",
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ filterset = "test(/readme_sync/)"
|
||||
|
||||
[package]
|
||||
name = "worktrunk"
|
||||
version = "0.76.0"
|
||||
version = "0.77.0"
|
||||
edition = "2024"
|
||||
rust-version = "1.97"
|
||||
build = "build.rs"
|
||||
|
||||
Reference in New Issue
Block a user