16 Commits

Author SHA1 Message Date
Worktrunk Bot c532d2dabd docs(llm-commits): bump Codex commit-generation model to gpt-5.6-luna (#3430) 2026-07-12 08:15:26 -07:00
Worktrunk Bot 16deb5e6c4 fix: use --safe-mode for Claude commit.generation to preserve apiKeyHelper auth (#3170) 2026-06-23 00:22:25 -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
Maximilian Roos 7d16e63fad refactor(commit-generation): drop the CLAUDECODE= nesting workaround (#2979)
worktrunk stripped `CLAUDECODE` before spawning the
`[commit.generation]` LLM command, and the recommended Claude Code
command carried a leading `CLAUDECODE=`, both to get past Claude Code's
nested-session check that rejected `claude -p` launched from inside
another Claude Code session.

That check is gone. It's absent from the `claude` binary across every
current build (2.1.157 through 2.1.162), and `CLAUDECODE=1 claude -p …`
runs cleanly (exit 0, empty stderr). So the workaround is no longer
needed.

This drops it: `src/llm.rs` no longer calls `.env_remove("CLAUDECODE")`,
and the recommended command loses the `CLAUDECODE=` prefix in the source
of truth (`dev/config.example.toml`), the `wt config --help` text, and
the Taskfile bench command. Docs, the skill reference, and the config
help snapshots are regenerated to match.

Caveat: there's no published guarantee the nested-session check stays
gone, and a Claude Code old enough to still have it (older than roughly
late May 2026) would again block nested commit generation. Since the
check is absent from the implementation across all current builds, that
risk is low.

Tests: 1236 lib + 693 integration pass; fmt and clippy clean.

> _This was written by Claude Code on behalf of max_

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:26:32 -07:00
Worktrunk Bot d65d5028fa docs(commit-generation): bump Codex model to gpt-5.4-mini (#2949) 2026-06-02 00:42:18 -07:00
Worktrunk Bot 33bab089bf docs(taskfile): fix ONGs typo in build-social-cards desc (#2947) 2026-05-31 01:32:30 -07:00
Maximilian Roos eac94579d3 fix(picker): vendor skim-tuikit with write_all in Output::flush (#2226)
## Summary

Fixes intermittent partial-first-render in `wt switch`'s picker — under
tmux PTY pressure, rows past the first ~1024 bytes silently vanished.

Root cause is in `skim-tuikit`: `Output::flush` calls
`stdout.write(&self.buffer)`, which `io::Write::write` is allowed to
satisfy with a short write. The unwritten remainder is then discarded by
the immediate `self.buffer.clear()`. Instrumenting the flush made it
obvious:

```
flush: buf=8464 wrote=1024 dropped=7440
flush: buf=3382 wrote=1024 dropped=2358
flush: buf=6096 wrote=1024 dropped=5072
```

Fix is a one-line `write` → `write_all`. Carried as `[patch.crates-io]`
pointing at `vendor/skim-tuikit/`, which is byte-identical to
`skim-tuikit` 0.6.6 from crates.io except that single line and an added
`LICENSE` file (the crates.io tarball omits it; MIT requires the
notice).

Upstream PR:
[skim-rs/skim#1056](https://github.com/skim-rs/skim/pull/1056). Drop the
vendor once released.

## Notes

- `task vendor-diff` prints the exact patch we carry — makes it easy to
audit.
- `.pre-commit-config.yaml` and `.typos.toml` extended to skip `vendor/`
so upstream source isn't linted against our style.
- `skim-rs/tuikit` (the older pre-rename repo) has the same bug but is
archived; upstream fix targets `skim-rs/skim @ feat/dynamic-header`
where the current `skim-tuikit` 0.6.x crate actually lives.

## Test plan

- [x] `pre-commit run --all-files` passes
- [x] Reproduced original partial render in tmux (intermittent, ~50% of
runs with 14 items at cold start)
- [x] Post-fix: 15/15 reliable full renders in the same repro
- [ ] CI

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 16:19:44 -07:00
Axel H. 4ef64c47ad feat(opencode): add OpenCode integration (activity tracking, plugin, config) (#1807)
This PR adds OpenCode integration: activity tracking markers in `wt
list`, plugin installation via CLI, `wt config show` diagnostics, and
LLM commit generation detection.

Continues the work started in #1295 and #1533 which added OpenCode to
the docs and example config.

## What's included

- **Activity tracking plugin** (`dev/opencode-plugin.ts`): maps
`session.status`/`session.idle`/`session.deleted` to branch markers,
same pattern as Claude Code's plugin
- **`wt config plugins opencode install/uninstall`**: installs the
plugin to `~/.config/opencode/plugins/worktrunk.ts` — source embedded
via `include_str!()`, no npm needed. Sits under `wt config plugins`
alongside Claude Code's `wt config plugins claude`.
- **`wt config show` OPENCODE section**: shows plugin install status
with actionable hints (only when `opencode` is on PATH)
- **`LlmTool::OpenCode` variant**: detected via PATH for commit
generation auto-config

## Docs approach

Kept deliberately low-profile — no dedicated docs page, no README
mention. OpenCode is discoverable via `wt config show` and a mention in
tips-patterns. If it becomes popular, docs prominence can increase.

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

---------

Co-authored-by: Maximilian Roos <m@maxroos.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-04-05 18:44:41 -07:00
Maximilian Roos 5a2895cd03 Add LLM tool commands to example config as single source of truth (#1531)
The Claude/Codex recommended commands were duplicated across 4 locations
(Rust code, llm-commits.md, config.md, Taskfile) with no automated sync
— they were already drifting (missing `CLAUDECODE=` prefix, missing `-c
system_prompt=''`).

Now the double-commented entries in `config.example.toml` are the single
source of truth. `recommended_config()` parses them at runtime via
`include_str!` + `LazyLock`, and a new sync test verifies
`llm-commits.md` matches. Also fixes the existing drift in all copies.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-14 16:08:53 -07:00
Maximilian Roos 9b77ab2d93 fix: add --no-session-persistence to Claude commit generation (#1454)
Without this flag, `claude -p` saves the commit generation conversation
to session history. When the user later runs `claude --continue`, it
resumes that ephemeral commit session instead of their previous working
session.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-11 16:20:00 -07:00
Arnaud Limbourg c7128ce11b Add nushell support (#964) 2026-02-14 08:57:30 -08:00
Maximilian Roos e154b9ee50 Add LLM setup prompt for first-time commit configuration (#867)
* Add LLM setup prompt for first-time commit configuration

Implement one-time interactive prompt when users attempt commit/merge/squash without LLM configuration. Detects available tools (claude, codex) and offers auto-configuration with preview on `?`. Adds `skip-commit-generation-prompt` flag to suppress re-prompting, `set_commit_generation_command()` config method, and reusable `prompt_yes_no_preview()` utility. Updates commit message templates to clarify format requirements, fixes Claude Code command syntax (spaces to equals in flags), and adds visual styling to section headers in documentation.

* Update snapshots for template format changes

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

* Simplify commit template format guidance

Remove redundant trivial-changes line from template format section.
Fix duplicate "# Other" header from merge. Document skip-commit-generation-prompt
in first-run prompts section alongside skip-shell-integration-prompt.

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

* Add unit tests for command detection functions

Cover command_exists() and detect_llm_tool() with basic unit tests
to improve test coverage on the commit generation module.

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

* Add PTY tests for commit generation prompt

Test the interactive prompt flow for LLM commit configuration:
- No tool found → sets skip flag
- User declines → sets skip flag
- User accepts → saves config
- User requests preview → shows preview

Uses fake claude script to test the prompt path that requires
a detected LLM tool.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-26 00:26:38 -08:00
Maximilian Roos cbe65a65ea docs: add Codex config and optimize Claude Code for LLM commits (#837)
* added verbose flag

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

* docs: add Codex config and optimize Claude Code for LLM commits

Add OpenAI Codex CLI as an option for LLM commit message generation.
Configure with gpt-5.1-codex-mini model, low reasoning effort, and
read-only sandbox. Uses jq to parse JSON output.

Update Claude Code config with optimization flags that disable tools,
skills, settings, and system prompt for faster text-only output.

Add bench-llm-commits task to Taskfile for comparing tool performance.

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

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
2026-01-24 12:56:20 -08:00
Maximilian Roos cd8ac3e060 perf(tests): add pre-built fixture to speed up Windows CI (#634)
* perf(tests): add pre-built fixture to speed up Windows CI

Instead of creating repos from scratch for each test, copy a pre-built
fixture with worktrees and remote already configured. This should
significantly reduce test time on Windows where process spawning is slow.

- Add tests/fixtures/standard/ with repo, 3 worktrees, and bare remote
- Update TestRepo to copy fixture instead of running git init/commit
- Add fixture cleanup to doc-generating tests for clean output
- Remove git sample hooks and boilerplate from fixture

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

* fix(tests): correctly clean fixture state for isolated tests

- Change `remove_fixture_worktrees()` to take `&mut self` and clear the
  worktrees map so `add_worktree()` can recreate branches
- Add remote removal to select and approval tests to prevent
  `origin/main` from appearing in snapshots
- Update select snapshots for fixture-based commit hashes

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

* fix(tests): use relative paths in fixture for portability

The fixture gitdir files contained absolute paths to the local
development machine, causing CI failures. Updated to use relative
paths which work after the _git → .git rename during fixture copy.

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

* fix(tests): remove invalid remote from bare repo fixture

The bare repository in the fixture had a remote configured with an
absolute path to the local machine, which wouldn't exist on CI.
Bare repositories don't need remotes configured.

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

* fix(tests): remove origin in approval tests for consistent project_id

Tests manually create approvals using a computed project_id based on
repo path. With the fixture's origin remote, worktrunk computes a
different project_id from the remote URL. Removing origin makes both
use the same fallback (directory path).

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

* fix(tests): improve fixture copy robustness for CI

- Add platform-specific copy: `cp -r` on Unix, `robocopy` on Windows
- Add verification that essential paths exist after copy
- Add verification that origin.git is a valid git repository after rename
- Include stderr in error messages for better debugging

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

* fix(tests): add .gitkeep to preserve empty git directories in fixture

Git doesn't track empty directories, so objects/info, objects/pack, and
refs/tags were missing on CI after checkout. These directories are
required for a valid git repository.

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

* fix(tests): ensure LF line endings in fixture git files

Add .gitattributes to force LF line endings for git internal files
(packed-refs, HEAD, config, etc.) to prevent CRLF corruption on Windows.

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

* fix(tests): handle file copies separately from directories on Windows

robocopy only works with directories, not files. Use Rust's std::fs::copy
for individual files like .gitattributes, and robocopy only for directories.

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

* fix(tests): enable rerere in test git config for consistent output

Git's rerere feature produces "Recorded preimage" messages during
conflicts. Enable this in test config so output is consistent between
local machines and CI.

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

* fix(tests): restore accidentally deleted hook_clear tests

The tests test_hook_clear_no_approvals and test_hook_clear_with_approvals
were accidentally removed during the fixture refactoring. This restores them
with the necessary remote removal so project_identifier matches "repo"
(directory name) instead of the fixture's remote URL.

Also adds remote removal to test_hook_show_approval_status for consistency.

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

* chore: remove unreferenced ping_pong snapshots

These snapshots used feature_a but the tests now use feature, leaving
these orphaned.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-14 18:48:39 -08:00
Maximilian Roos 90564bcc94 Add asset deletion safeguard and refactor demo build setup
Require manual publish when asset files are deleted to prevent
accidental removals. Refactor demo build to only copy starship config
for docs target and simplify setup_demo_output usage.
2026-01-12 14:17:49 -08:00
Maximilian Roos 3669b74f4b refactor: rename Taskfile.yml to Taskfile.yaml 2026-01-11 23:02:55 -08:00