Commit Graph

1003 Commits

Author SHA1 Message Date
Maximilian Roos 69b3e47509 docs: add Quick Start section to front page (#851)
* docs: add Quick Start section to front page

Shows the basic workflow with clear directory paths at each stage:
- Create worktree with wt switch --create
- Check status with wt list
- Two merge paths: PR workflow (push + gh pr create + wt remove)
  and local merge (wt merge)
- Parallel agents example with -x flag

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

* docs: improve Quick Start with realistic examples and snapshot sync

- Add snapshot-based output sync for quickstart examples (switch, list, merge)
- Make examples more realistic: 53 lines of auth module changes instead of 9
- Show uncommitted changes in wt list demo (WIP state, not already committed)
- Add wt step commit to PR workflow since changes are now uncommitted
- Remove redundant git push from PR workflow (gh pr create auto-pushes)
- Suppress worktree-path hint in quickstart tests for cleaner output
- Add transform_zola_to_github() for converting HTML terminal markers to plain code blocks

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

* Simplify code block formatting in README and tests

Convert bash code blocks to console format with command prompts and output
in a single block. Update regex pattern to optionally strip redundant bash
preamble when converting AUTO-GENERATED-HTML terminal markers.

* docs: remove redundant bash blocks before terminal examples

The terminal shortcodes already include the command with $ prefix,
so separate bash blocks showing just the command were redundant.

Also fix broken anchor link in config.md.

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

* feat(docs): make terminal prompt non-copyable via CSS

Use CSS ::before pseudo-element to generate the $ prompt, making it
structurally non-copyable. This works with both manual text selection
and copy buttons.

Changes:
- Add .cmd::before { content: "$ "; } to generate prompt via CSS
- Remove explicit <span class="prompt">$</span> from HTML output
- Extract command from snapshot YAML header instead of parsing HTML
- Update expand_command_placeholders for command pages (list.md, etc.)

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

* fix(docs): show commit step in quick start merge example

The merge example now shows staged changes being committed as part of
the wt merge workflow, reflecting a realistic user experience where
code is staged but not yet committed before merging.

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

* style: fix cargo fmt formatting

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

* fix(tests): use cross-platform mock LLM for quickstart_merge test

The quickstart_merge test was using a shell script for the mock LLM
which doesn't work on Windows. Now uses the mock-stub system which
creates a cross-platform mock binary.

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

* fix(test): use to_slash_lossy for Windows path compatibility

Windows paths with backslashes trigger shell metacharacter handling,
which wraps the command in `sh -c`. Bash can't parse Windows paths
like `C:\Users\...`. Converting to forward slashes with
to_slash_lossy() makes the path bash-compatible.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-25 22:26:46 -08:00
Maximilian Roos 86ca666bda docs: simplify skip-shell-integration-prompt documentation (#863)
The previous docs incorrectly presented this as a CI configuration option,
but in CI without TTY the prompt is already suppressed. The config is
actually set automatically when declining the prompt.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-25 22:18:02 -08:00
Maximilian Roos d9ced70893 docs(config): reapply H1 major sections with hero fix (#862)
* docs(config): add H1 major sections with TOC support (#857)

* docs(config): add H1 major sections with TOC support

Add H1 headings for major sections (User Configuration, Project
Configuration, Shell Integration, Environment Variables) to improve
navigation and visual hierarchy.

Theme changes:
- Include H1s in sidebar TOC with divider lines
- Fix H1 link color (was orange due to missing zola-anchor rule)
- Style H1 headings consistently with H2 (underline, size)

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

* docs(config): improve TOC structure and auto-generate Subcommands header

- Auto-insert "# Subcommands" in help.rs before subdoc expansions
- Add "# Other" section containing Environment Variables and Command reference
- Rename "Commands" to "Command config" for clarity
- Fix TOC styling: align H1/H2 text, reduce vertical spacing, use sentence case
- Template: show H2s nested under H1s at same indent as standalone H2s

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

* fix: address codex review feedback

- Add default guard for h.children in TOC template
- Remove ineffective :first-of-type selector

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

* docs: use sentence case for Environment variables

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

* test: update snapshots for config section header changes

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

* test: update help_config_create snapshot

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

---------

Co-authored-by: Claude <noreply@anthropic.com>

* fix(docs): prevent h1 styling from breaking hero layout

The H1 major sections commit added `width: fit-content` and underline
styling to all h1 elements. This broke the hero because:
- fit-content shrinks the element, breaking text-align: center
- The underline appeared on the hero title

Fix by overriding these in .heading-text (used for page titles/hero):
- width: auto to restore centering
- > a::after { display: none } to hide underline

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

* fix(docs): align H1 TOC entries with H2s

Remove left border and custom padding from H1 entries in the sidebar
TOC. H1s are now distinguished only by bolder weight and extra top
margin, creating a cleaner visual hierarchy.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-25 22:05:30 -08:00
Maximilian Roos f173e2a10a fix(docs): add blank line after demo figures for markdown separation (#861)
The `expand_demo_placeholders` function now adds a trailing newline
after `</figure>` elements, ensuring proper paragraph separation in
web docs. Terminal `--help` output is unaffected since HTML comments
are stripped.

Also removes the inconsistent extra blank line from `wt select`'s
demo placeholder in cli.rs.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-25 21:53:39 -08:00
Maximilian Roos 400f22d2c0 Revert "docs(config): add H1 major sections with TOC support (#857)"
This reverts commit 5d831694dd.
2026-01-25 21:10:28 -08:00
Maximilian Roos 5d831694dd docs(config): add H1 major sections with TOC support (#857)
* docs(config): add H1 major sections with TOC support

Add H1 headings for major sections (User Configuration, Project
Configuration, Shell Integration, Environment Variables) to improve
navigation and visual hierarchy.

Theme changes:
- Include H1s in sidebar TOC with divider lines
- Fix H1 link color (was orange due to missing zola-anchor rule)
- Style H1 headings consistently with H2 (underline, size)

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

* docs(config): improve TOC structure and auto-generate Subcommands header

- Auto-insert "# Subcommands" in help.rs before subdoc expansions
- Add "# Other" section containing Environment Variables and Command reference
- Rename "Commands" to "Command config" for clarity
- Fix TOC styling: align H1/H2 text, reduce vertical spacing, use sentence case
- Template: show H2s nested under H1s at same indent as standalone H2s

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

* fix: address codex review feedback

- Add default guard for h.children in TOC template
- Remove ineffective :first-of-type selector

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

* docs: use sentence case for Environment variables

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

* test: update snapshots for config section header changes

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

* test: update help_config_create snapshot

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-25 20:59:44 -08:00
Maximilian Roos 16c29b48bf docs(config): fix project config anchor links
Update anchor links from "worktrunk-project-configuration" to
"project-configuration" across documentation and code files.
2026-01-25 18:47:39 -08:00
Maximilian Roos c4b50bb6a8 Add wt step relocate command (#790)
* Add step relocate command

Adds `wt step relocate` to move worktrees to their expected paths based on
the `worktree-path` template. Supports dry-run preview, filtering by branch
name, and auto-committing dirty worktrees. Handles special case of main
worktree by switching to default branch and creating a new worktree.

* Add `--clobber` flag and cycle resolution to `step relocate`

Implement full swap/cycle handling and non-worktree blocker management for
relocate command. Adds `--clobber` flag to automatically backup blocking
paths, dependency graph processing to handle worktree cycles via temporary
locations, and comprehensive spec documentation.

Key changes:
- Add `--clobber` flag to back up non-worktree paths at target locations
- Implement cycle detection and resolution using temp directory
- Build dependency graph to coordinate multi-worktree moves
- Handle main worktree relocation by creating new worktree + switching
- Add test cases for swap, clobber, and cycle scenarios
- Canonicalize temp home paths on macOS for snapshot consistency

* fix: address Codex review issues in step relocate

- Refuse to clobber existing worktrees (would corrupt git metadata)
- Prefer non-main worktree when breaking cycles (git can't move main)
- Sanitize branch names for temp paths (feature/foo -> feature-foo)
- Track original path for shell cd in temp-relocated worktrees
- Show template errors as warnings instead of silently dropping

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

* test: add coverage for clobber refusing to overwrite worktrees

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

* test: add relocate --commit coverage test

Tests the commit_worktree_changes function by configuring a mock LLM
and verifying that dirty worktrees are auto-committed before relocating.

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

* refactor: simplify step relocate and improve coverage

- Change unreachable defensive code to expect() with explanation
- Simplify multi-line cformat! calls to single-line (improves LLVM coverage)
- Add test_relocate_mixed_success_and_skip to cover "relocated X, skipped Y" path
- Add test_relocate_dirty_with_commit to cover commit_worktree_changes function

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

* refactor: remove shell cd for temp-to-final moves, simplify summary

- Remove shell directory update for temp-to-final worktree moves
  (rare case where user is inside a worktree during cycle resolution)
- Simplify summary pluralization with inline closure
- Remove unused original_path tracking from temp_relocated

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

* refactor: simplify remaining cformat! calls in step_relocate

Extract multi-line cformat! macro calls to single-line variables
to improve LLVM coverage instrumentation.

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

* refactor: remove defensive early return in commit_worktree_changes

The early return when no staged changes was unreachable - if is_dirty()
returned true, git add -A must stage something. Removing improves coverage
and follows fail-fast principles.

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

* refactor: simplify step_relocate for better coverage

- Remove redundant exists() check before create_dir_all
- Extract cformat! to single-line variable in commit_worktree_changes

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

* refactor: revert configure_shell cosmetic changes to reduce diff

Reverts format_path_for_display changes that were unrelated to step relocate
and were reducing coverage percentage since they're in error paths.

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

* fix: harden step relocate against edge cases

Fixes identified by adversarial testing:

1. Empty default branch validation - fails early with actionable error
   instead of confusing "git checkout ''" errors

2. Same-target conflict handling - `is_target_empty` now returns
   `Option<bool>` to gracefully skip when target is unexpectedly
   blocked (TOCTOU race or same-target conflict)

3. Main worktree rollback - if `git worktree add` fails after
   checkout, restore the original branch

Adds test for same-target scenario that previously panicked.

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

* Move step relocate plan to Rust module spec

Moved the comprehensive plan from .claude/plans/step-relocate-spec.md
to a Rust doc comment on the step_relocate function. This makes the
specification more discoverable and keeps it synchronized with the
implementation.

The doc comment now includes:
- Complete flag descriptions
- Detailed algorithm explanation
- Multiple scenario examples (swap, chain, mixed, clobber, main worktree)
- Implementation notes
- Test case list

Co-authored-by: Maximilian Roos <max-sixty@users.noreply.github.com>

* test: add coverage for step relocate edge cases

Add tests for:
- Template expansion error handling (invalid variable)
- Empty default branch validation (non-existent configured branch)

These cover lines 844-847 and 890-895 in step_commands.rs that were
flagged by codecov/patch.

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

* Improve step relocate output messages

- Use gutter formatting for template error details (per output guidelines)
- Fix misleading summary when template errors occurred
- Show source path in temp-relocated worktree success messages
- Use bright-black styling for flags in hints (--commit, --clobber)
- Use concrete example in default branch error message

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

* Use gutter for dry-run preview in step relocate

Per output guidelines: every user-facing message needs symbol or gutter.
The dry-run preview now uses gutter formatting instead of plain indentation.

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

* Fix: use wt command for setting default branch

The error message now suggests 'wt config state default-branch set main'
instead of the raw git config command.

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

* Refactor commit pipeline to accept WorkingTree parameter

Extract commit staging and execution into CommitGenerator to eliminate
duplicate commit logic in step_relocate. Add show_progress parameter to
control progress message display for bulk operations. Add repo() accessor
to WorkingTree for repository access.

* refactor: extract step_relocate into modular pipeline with explicit types

Split the 500-line monolithic step_relocate function into a clean pipeline:
- gather_candidates() finds worktrees not at expected paths
- validate_candidates() checks locked/dirty, handles --commit
- RelocationExecutor encapsulates the dependency graph algorithm

New types document each stage: RelocationCandidate, ValidatedCandidate,
GatherResult, ValidationResult. The complex swap/cycle resolution logic
is now isolated in RelocationExecutor with clear methods for each phase.

Co-authored-by: Claude <noreply@anthropic.com>

* fix: update test to use correct commit.generation config format

The test was using the old `args` field which no longer exists. The
command should be a complete shell string that receives the prompt
via stdin.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Maximilian Roos <max-sixty@users.noreply.github.com>
2026-01-25 16:17:31 -08:00
Maximilian Roos cbce1ab775 docs(config): trim project config section, link to hook.md (#855)
* docs(config): trim project config section, link to hook.md

Reduce duplication by removing hook examples from the project config
section and linking to hook.md instead. Keep only non-hook settings
(list.url and ci.platform) with concise inline comments.

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

* test: update help_config_long snapshot for trimmed project config section

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-25 15:46:34 -08:00
Maximilian Roos 68210a8c0e docs(llm-commits): Update template documentation (#854)
- Remove reference to deprecated template-file options
- Add missing {{ git_diff_stat }} template variable
- Clarify which variables are squash-template only
- Move variables table after example for natural reading order

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-25 15:30:37 -08:00
Maximilian Roos 632c6ca28a docs: Update stale documentation since v0.18.2 (#853)
- Update deprecated [commit-generation] config format to [commit.generation]
  with single command string (per f8aaead5b)
- Add context window gauge (moon phase 🌕→🌑) to statusline docs
- Add remote-only branch CI status detection note for --remotes flag
- Update demo build script to use new config format
- Sync auto-generated docs and skill references

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-25 15:15:34 -08:00
Maximilian Roos 79fe892bfa feat: add per-project hooks with append semantics (#842)
* feat: add per-project hooks with append semantics

Per-project hooks in user config now append to global hooks rather than
replacing them. Execution order: global → per-project → project.

Also:
- Move hooks into OverridableConfig for consistency
- Rename UserConfig.overrides to UserConfig.configs
- Add schemars for deriving valid config keys from JsonSchema
- Replace manual VALID_USER_CONFIG_KEYS with schema-derived function

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

* refactor: unify config validation on JsonSchema

Both UserConfig and ProjectConfig now use JsonSchema-derived keys for
validation instead of serde HashMap catchall. This:

- Removes `unknown` field from ProjectConfig
- Removes `unknown()` method from WorktrunkConfig trait
- Simplifies `is_valid_key` to not need value parameter
- Adds JsonSchema to JSON output types for future schema generation

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

* docs: document per-project hooks in setting overrides section

- Add per-project hooks to Setting overrides (Experimental) section
- Update hook.md table to show execution order with per-project hooks
- Replace JSON context example with one showing complex conditionals
- Keep documentation DRY by linking from hook.md to config.md

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

* docs: use consistent terminology (user config, not settings)

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-24 18:32:17 -08:00
Maximilian Roos d8f7a04cbb docs: add tip for monitoring hook logs (#838)
Add a "Monitor hook logs" section to tips-patterns showing how to follow
background hook output in real-time with `tail -f` and create an alias
for frequent use.

Closes #803

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-24 13:07:34 -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 3dd7657880 docs: clarify user project-specific settings section (#835)
- Restructure intro paragraph as bullet list for clearer context
- Fix casing: "worktrunk" → "Worktrunk"
- Fix command: "wt hook approve --clear" → "wt hook approvals clear"

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-24 12:23:54 -08:00
Maximilian Roos ee029d19f1 docs: clarify user project-specific settings section (#830)
Restructure the per-project settings documentation to better distinguish
between user config and project config. The section now clearly explains
the two-config system before introducing per-project user settings as a
third category.

Key changes:
- Rename section from "Per-project settings" to "User project-specific settings"
- Add intro establishing user/project config dichotomy
- Split into subsections: "Approved hook commands" and "Setting overrides"
- Remove misplaced reference to project config hooks
- Link to project config documentation for clarity

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-23 23:38:59 -08:00
Maximilian Roos 583a43764a feat: add --hook flag to wt config state logs get (#803) (#816)
* feat: add --hook flag to wt config state logs get

Adds a --hook flag to `wt config state logs get` that returns the path
to a specific hook's log file, making it easy to stream logs:

  tail -f "$(wt config state logs get --hook=post-start:server)"

Hook specification formats:
  - <hook-type>:<name> (e.g., post-start:server, post-create:install)
  - <name> (e.g., remove, for hooks without explicit type)

Also adds --worktree flag to get logs for a different branch.

Closes #803

https://claude.ai/code/session_01SuPbdD25Z6BbifGJY1jcRF

* fix: address code review feedback for hook logs feature

- Fix help text: clarify format is `<name>` for simple operations, not `<hook-type>`
- Add missing hook types: pre-remove, post-remove to fallback search
- Replace catch-all `_ =>` with explicit unreachable!() for clarity

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

* fix: rename --worktree to --branch for consistency

Other state commands use --branch (ci-status, marker), so use the same
flag name here for consistency.

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

* refactor: introduce HookLog as single source of truth for log naming

Replace ad-hoc string formatting with a structured HookLog enum that
handles both creation and lookup of log files. The CLI now requires
explicit format: `source:hook-type:name` for hooks or `internal:op`
for internal operations.

- Add HookLog enum with Hook and Internal variants
- Add InternalOp enum for internal operations (currently just Remove)
- Update spawn_detached to take HookLog instead of string
- Update handle_logs_get to use HookLog::parse
- Add strum::EnumString to HookSource for parsing

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

* style: move imports to top of modules

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

* refactor: improve HookLog with to_spec, dynamic valid types, better errors

- Add to_spec() method for roundtrip conversion
- Use strum::IntoEnumIterator to generate valid hook types dynamically
- Inline parse_source/parse_hook_type (thin wrappers)
- Improve "not found" error to show expected filename
- Add roundtrip test for parse(to_spec(x)) == x
- Fix stale doc comment (operation -> internal:op)

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

* docs: update logs get description and add hook docs reference

- Change "List background operation log files" to "Get log file paths"
- Add wt config state logs to hook docs "See also" section

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

* style: use bold styling for dynamic values in error messages

Replace single quotes with <bold> styling for dynamic values in error
messages, per writing-user-outputs guidelines. Also use proper error
context chains for multiline errors.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-23 17:18:13 -08:00
Maximilian Roos eafbb9ee3c docs: add at-a-glance examples to config documentation (#826)
Add concrete TOML examples immediately after the configuration files
table to make it clearer what each config file is for:

- User config: personal preferences (worktree-path, commit-generation)
- Project config: shared team settings (post-create, pre-merge hooks)

This addresses user feedback that the distinction between user and
project config was confusing.

Closes #801

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-23 17:08:25 -08:00
Maximilian Roos f8aaead5b3 refactor: restructure commit-generation config to [commit.generation] (#809)
* refactor: restructure commit-generation config to [commit.generation]

- Move `[commit-generation]` to `[commit.generation]` (nested under commit)
- Replace `command` + `args` with single `command` string (shell execution)
- Add deprecation warning for old format with backward compatibility
- Update docs to present Claude CLI and llm as equal options

The new format uses shell execution (`sh -c`) so environment variables
can be set inline in the command string.

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

* fix: update tests and docs for new commit.generation config format

Fix test regressions identified by Codex review where tests using
WORKTRUNK_COMMIT_GENERATION__ARGS were silently failing because
args is now ignored with the new shell-based command format.

Tests now use the correct pattern:
  WORKTRUNK_COMMIT_GENERATION__COMMAND="cat >/dev/null && echo 'message'"

Also update CLI docs to show:
- New config path: commit.generation.command (not commit-generation.command)
- New env var format: WORKTRUNK_COMMIT__GENERATION__COMMAND
- Remove args documentation (no longer applicable)

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

* fix: update doc comments and add validation for new config path

Address Codex review feedback:
- Update per-project doc example to show new format
  (commit.generation instead of commit-generation)
- Update env var comment to show new format
  (COMMIT__GENERATION__COMMAND instead of COMMIT_GENERATION__COMMAND)
- Add validation for projects.*.commit.generation path
  (was only validating deprecated commit-generation path)

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

* fix: address remaining Codex review issues

- Use ShellConfig for LLM command execution (Windows compatibility)
- Improve error handling when LLM stderr is empty
- Format reproduction commands with conditional sh -c wrapping
- Update tests to use new env var format (WORKTRUNK_COMMIT__GENERATION__)
- Make test assertion more specific ([commit] not just "commit")
- Document cformat safety for shell commands in output guidelines

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

* refactor: use shell_escape crate for reproduction command escaping

Replace manual single-quote escaping with the shell_escape crate
which is already a dependency used elsewhere in the codebase.

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

* feat: unify deprecation handling with single .new migration file

Consolidate all deprecation handling into deprecation.rs:
- Add [commit-generation] → [commit.generation] section migration
- Merge deprecated `args` field into `command` string
- Generate single .new file with all migrations (template vars + sections)
- Skip migration if new section already exists (don't overwrite)
- Skip warning for empty deprecated sections
- Use shell_escape for proper quoting when merging args
- Rename hint from deprecated-project-config to deprecated-config

Remove separate warn_deprecated_commit_generation() from user.rs.

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

* fix: harden commit-generation migration against edge cases

Fixes found during adversarial testing:

1. Args data loss prevention: merge_args_into_command() now validates
   preconditions (args is array, command is string) BEFORE removing
   the args field. Previously, table.remove("args") happened
   unconditionally, losing data if command was missing or non-string.

2. Malformed generation detection: When checking if new [commit.generation]
   exists, now verify it's actually a table (is_table || is_inline_table).
   A malformed value like `generation = "string"` no longer suppresses
   deprecation warnings for the old section.

3. Inline table support: Both detection and migration now handle inline
   table format (e.g., `commit-generation = { command = "..." }`).
   Detection uses as_inline_table() in addition to as_table().
   Migration converts InlineTable to Table via into_table().

Added comprehensive tests for all edge cases.

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

* test: add coverage for project-level inline table migration

Add tests for:
- Project-level inline table migration
- Preserving existing [commit] fields during migration
- Empty inline table detection (should not flag as deprecated)

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

* test: add integration test for commit-generation deprecation warning

Add test that exercises the full deprecation path through check_and_migrate()
for commit-generation section rename and args merge. This improves coverage
on the warning output and migration file generation paths.

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

* test: add integration test for project-level commit-generation deprecation

Add test that exercises the project_keys iteration path in check_and_migrate()
for project-level commit-generation deprecation warnings. This covers the
warning message format that includes project identifiers.

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

* test: add edge case tests for merge_args_into_command

Cover the early-return paths in merge_args_into_command():
- Args without command: args preserved (no command to merge into)
- Non-string command: args preserved (can't merge into non-string)
- Command-only: clean migration without args field

These tests exercise the !can_merge validation path.

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

* test: cover malformed config fallback branches in migration

Add tests for the `_ => None` fallback branches that handle unusual
cases where commit-generation is neither a table nor inline table
(e.g., a string value like `commit-generation = "not a table"`).

These tests exercise lines 264 and 305 in deprecation.rs.

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

* test: add coverage for edge cases in deprecation migration

Add unit tests for:
- Empty command with args: args become the command when command=""
- Invalid TOML parsing: returns content unchanged
- Deduplication path: second call with same path hits early return

These tests cover previously uncovered code paths in deprecation.rs.

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

* test: add unit tests for llm helper functions

Add tests for format_reproduction_command and is_lock_file to improve
code coverage.

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

* test: add unit tests for config merge logic

Add tests for:
- CommitConfig merge when only base/override has generation
- CommitConfig merge when both have generation
- CommitGenerationConfig merge for squash_template fields

These cover previously uncovered branches in the Merge implementations.

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

* test: add validation tests for new commit.generation format

Add tests for validation error paths in the new [commit.generation]
config format (both top-level and per-project).

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

* test: add save_to() tests for commit.generation serialization

Cover the "create from scratch" branch in save_to() which serializes
commit.generation and deprecated commit-generation sections to new files.
Previously only the "update existing file" branch was tested.

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

* docs: fix "Claude CLI" to "Claude Code"

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

* docs: deduplicate LLM setup from config page

Remove Claude Code/llm setup examples from config docs since they
duplicate llm-commits.md. Config page now links to llm-commits.md
for setup and keeps only the custom prompt templates section.

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

* fix: trigger deprecation warnings in `wt config show`

Previously `config show` read files directly without calling the config
loaders, so deprecation warnings weren't shown. Now we call
UserConfig::load() and repo.load_project_config() to trigger warnings
while still displaying invalid configs (the deprecation check runs on
raw content before parsing).

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

* docs: move aichat into Setup section with other options

Move aichat example from "Alternative tools" into the Setup section as
"Option 3: aichat" alongside Claude CLI and llm. Add "Custom scripts"
subsection for the generic example. Remove the now-redundant
"Alternative tools" section.

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

* docs: reframe LLM setup as examples, not numbered options

Change from "Option 1/2/3" to just showing examples of tools that work.
Lead with the concept: any command that reads stdin and outputs a commit
message. Simplify Claude Code example and condense install instructions.

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

* Simplify LLM commit generation setup documentation

Remove redundant setup instructions and tool-specific examples from config templates and documentation. Consolidate guidance to reference the main LLM commits docs page for setup details.

* Skip deprecated section key in unknown fields warning

Skip the "commit-generation" key when warning about unknown fields, since
it's already handled by the deprecated sections warning and this prevents
duplicate warnings in config output.

* Extract DEPRECATED_SECTION_KEYS constant for reuse

Instead of hardcoding "commit-generation" in the skip check, define a
constant that documents which section keys are deprecated. This makes
it easier to add future deprecated sections without forgetting to
update the skip logic.

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

* Remove unused has_args field from CommitGenerationDeprecations

The has_args field was tracked but never used in production code — the
migration logic runs unconditionally and handles both cases (with or
without args). This simplifies the struct and removes a redundant test.

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

* Move deprecated section filtering to callers of warn_unknown_fields

Instead of having warn_unknown_fields know about deprecated sections
and skip them internally, make the constant public and have callers
filter before calling. This is cleaner because:

1. warn_unknown_fields doesn't need to know about the deprecation system
2. Callers already interact with deprecation, so filtering there is natural
3. The coupling is explicit rather than hidden inside the function

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

* fix: use Unix shell escaping for migration hint command

The `mv` command in the migration hint is a Unix command, so use
`shell_escape::unix::escape` instead of the platform-specific `escape`
to get consistent output on all platforms.

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

* fix: normalize path separators before shell escaping

Convert backslashes to forward slashes before shell escaping so the
migration hint command is consistent across platforms. Forward slashes
work in Git Bash on Windows.

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

* fix: remove shell escaping from migration hint paths

Shell escaping was producing different output on Windows vs Unix even
with unix::escape, likely due to some invisible path characteristic.
Since config paths rarely contain special characters, just output the
paths directly with forward slashes.

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

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:04:32 -08:00
Maximilian Roos 54bd3a8ba1 docs: use consistent worktree terminology (#813) 2026-01-22 23:47:03 -08:00
Maximilian Roos c45ff30040 docs: improve subcommand definitions and subdefinitions (#798)
* docs: improve subcommand definitions and subdefinitions

Refine help text for step and config subcommands:
- commit: consolidate definition, drop redundant subdefinition
- squash: restore "since branching" phrasing, simplify subdefinition
- push: add after_long_help with examples and implementation note
- rebase: add after_long_help with examples
- copy-ignored: shorten subdefinition to focus on benefit
- for-each: add concise subdefinition
- default-branch: clarify as "detection and override"
- statusline: remove subdefinition (was redundant with definition)

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

* test: update help snapshots

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-22 00:16:55 -08:00
Maximilian Roos 9a817b6390 docs: improve ci-status documentation clarity (#794)
* docs: improve ci-status documentation clarity

Rewrites the terse 4-line "How it works" section into clear prose
explaining prerequisites, behavior, and caching.

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

* test: update ci-status help snapshot

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-21 23:18:46 -08:00
Maximilian Roos eaadf1314b Fix extra linebreak after demo comments in help output (#795)
Demo HTML comments like `<!-- demo: file.gif -->` had blank lines on both
sides in the source. When the comment was stripped for terminal display,
both blanks remained, creating a double blank line.

Fix by removing the trailing blank after demo comments in cli/mod.rs.
Add a check in snapshot_help() to catch this pattern in all help tests.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-21 22:55:51 -08:00
Maximilian Roos dc0db6f57d fix: include about/long_about in subcommand docs (#793)
Subcommand sections in generated docs (via `--help-page`) were missing
their definition — they only showed `after_long_help` content.

Extract `combine_command_docs()` to share the about + subtitle +
after_long_help assembly logic between `handle_help_page()` (top-level
commands) and `format_subcommand_section()` (subcommands).

Before:
  ## wt step copy-ignored
  Git worktrees share the repository but not untracked files...

After:
  ## wt step copy-ignored
  Copy gitignored files to another worktree. By default copies all...
  Git worktrees share the repository but not untracked files...

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-22 06:46:56 +00:00
Maximilian Roos 1f361b6f45 docs: improve wt remove help text (#792)
- Change subdefinition from "For finished feature branches. Removes the
  current worktree by default." to "Defaults to the current worktree."
- Add Hooks section documenting pre-remove and post-remove hooks

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-21 22:35:16 -08:00
Maximilian Roos 677928d008 Add post-remove hook type (#757)
* Add post-remove hook type

* Add tests for wt hook show filter by hook type

Cover lines 430-432 in hook_commands.rs for post-merge, pre-remove,
and post-remove hook type parsing in handle_hook_show().

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

* Fix post-remove hook compilation and improve pre-remove example

- Fix compilation error: replace user_hook!(post_remove) with
  ctx.config.hooks.post_remove.as_ref() to match other hook types
- Replace pre-remove "git stash" example with more practical
  "archive test results" example that demonstrates pre-remove's
  key feature: access to worktree files before deletion
- Update documentation to clarify pre-remove runs "with access
  to worktree files"

Co-authored-by: Maximilian Roos <max-sixty@users.noreply.github.com>

* Trigger CI rebuild

* Add tests for post-remove hook error paths

- Fix merge conflict: replace removed user_hook! macro with direct access
- Add test for invalid template syntax in post-remove hook
- Add test for name filter that doesn't match any hook

Remaining uncovered lines are defensive code for race conditions:
- worktree/hooks.rs:117 - error during wt remove (config validated at startup)
- handlers.rs:556 - config load failure between command start and hook execution

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

* fix: post-remove template vars reference removed worktree

Template variables ({{ branch }}, {{ worktree_path }}, {{ worktree_name }})
now correctly reference the removed worktree, not the worktree where
commands execute from. This allows cleanup scripts to identify resources
(containers, servers, etc.) associated with the removed worktree.

Changes:
- spawn_post_remove_commands now accepts removed_worktree_path parameter
- Extra vars override built-in template variables with removed worktree info
- Updated documentation to clarify this behavior
- Added test verifying template vars reference the removed worktree

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

* docs: simplify post-remove template variable description

Remove explicit list of variable names; just say "all template variables
reference the removed worktree" which is clearer and less verbose.

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

* test: add post-remove hook test during wt merge

The main production use case for post-remove hooks is during `wt merge`,
which removes the worktree after merging. This test verifies that
post-remove hooks run correctly in this flow.

Found via adversarial testing of the post-remove hook implementation.

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

* fix: capture commit before removal for post-remove hooks

All template variables must reference the removed worktree, not the
execution context. The commit SHA was previously computed from the main
worktree (where hooks execute from), but should reflect the removed
worktree's state.

Changes:
- Add `removed_commit` field to RemoveResult::RemovedWorktree
- Capture commit SHA before removal in prepare_worktree_removal and merge
- Pass commit through to spawn_post_remove_commands
- Add commit and short_commit to extra_vars for post-remove hooks
- Update test to verify commit template variable references removed worktree

This prevents a subtle bug where {{ commit }} would unexpectedly contain
main's HEAD instead of the feature branch's HEAD.

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

* fix: use slash paths for Windows test compatibility

On Windows, hooks run in Git Bash which converts paths to MSYS2 format
(/c/Users/... instead of C:\Users\...). Use to_slash_lossy() for the
expected path comparison so the test passes on Windows.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Maximilian Roos <max-sixty@users.noreply.github.com>
2026-01-20 12:45:17 -08:00
Maximilian Roos 41b241162b feat: add per-project config overrides (#749)
* feat: add worktree-path support to per-project user config

Allow users to specify different worktree path templates for different
projects in their user config, enabling portable dotfiles across
machines with different project structures.

Config format:
```toml
[projects."github.com/user/repo"]
worktree-path = ".worktrees/{{ branch | sanitize }}"
approved-commands = ["npm ci"]
```

Per-project worktree-path takes precedence over global, which falls
back to the default template.

Closes #596

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

* feat: add per-project config for commit-generation, list, commit, and merge

Extend the per-project user config to support overriding more settings:
- [projects."...".commit-generation] - LLM model, args, template
- [projects."...".list] - branches, remotes, full defaults
- [projects."...".commit] - stage mode
- [projects."...".merge] - squash, commit, rebase, remove, verify

Config precedence: CLI arg > project config > global config > default

Implementation:
- Add Merge trait for field-wise config merging (other takes precedence)
- Add effective_* methods to WorktrunkConfig for merged config access
- Add helper methods on CommandEnv/CommandContext for easy access
- Update all commands to use effective configs instead of direct access
- Fix approval clearing to preserve other per-project settings

The approval clearing fix prevents data loss: previously clearing approvals
would wipe all per-project settings (worktree-path, commit-generation, etc).
Now it only clears approved-commands and removes project entries only if
completely empty.

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

* refactor: extract merge_optional helper to reduce duplication

DRY improvement: the effective_list, effective_commit, and effective_merge
methods all had identical 4-way match logic. Extract to a generic helper
function that handles the merge pattern.

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

* docs: simplify per-project config documentation

- Clarify that per-project settings contain approvals + optional overrides
- Put approved-commands first (primary use case)
- Use TOML dotted keys for compact examples (list.full, merge.squash)
- Remove verbose examples that repeated the section header

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

* refactor: drop `effective_` prefix from config accessor methods

The `project: Option<&str>` parameter already indicates merging behavior.
Renamed methods:
- WorktrunkConfig: commit_generation(), list(), commit(), merge()
- CommandEnv/CommandContext: commit_generation(), commit(), merge()

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

* fix: escape brackets in doc comments to avoid rustdoc link errors

Rustdoc interprets `[text]` as intra-doc links. Use backticks to make
them code spans instead.

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

* test: update help snapshots after merge

Updated config help snapshots to reflect per-project config documentation.

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

* test: add validation tests for config edge cases

Add tests for config validation:
- Empty worktree-path (global and per-project)
- Absolute worktree-path (global and per-project)
- Mutual exclusivity of template/template-file options

Extracted validation into a separate `validate()` method to avoid
code duplication between `load()` and test helper.

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

* fix: use platform-appropriate absolute paths in validation tests

On Windows, `/absolute/path` is not considered absolute - Windows uses
`C:\path` style. Use cfg!(windows) to conditionally set the test path.

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

* docs: fix project_id() doc comments to describe path fallback

The doc comments incorrectly stated that project_id() returns None when
there's no remote URL. The actual implementation falls back to the
canonical repository path, only returning None for non-UTF-8 paths.

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

* feat: mark per-project setting overrides as experimental

- Add "(Experimental)" to per-project settings section heading
- Clarify that setting overrides (worktree-path, list, commit, merge) are
  new while approved-commands is stable
- Replace manual PartialEq impl with derive for CommitGenerationConfig

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

* refactor: minor code simplifications

- Replace .to_string().as_str() with &.to_string()
- Replace .is_some() + .unwrap() with tuple pattern match

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

* refactor: fix if-let formatting

Move opening brace to same line as if-let condition to match code style.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-20 05:57:32 +00:00
Maximilian Roos 9d1a8cddac feat: add GitLab MR checkout with mr:<number> syntax (#734)
* feat: add GitLab MR checkout with `mr:<number>` syntax

Add `wt switch mr:101` to checkout the branch for GitLab merge request !101,
mirroring the existing GitHub PR checkout (`pr:<number>`) functionality.

Same-project MRs switch directly to the source branch. Fork MRs fetch
`refs/merge-requests/N/head` and configure `pushRemote` to the fork URL,
enabling `git push` to update the MR.

Requires `glab` CLI to be installed and authenticated.

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

* fix: address code review feedback for GitLab MR checkout

- Use find_remote_by_url for fork MR remote selection instead of primary_remote()
- Use ErrorKind::NotFound for glab detection (cross-platform)
- Add shell escaping and -- to branch rename hints
- Consolidate setup_fork_pr_branch and setup_fork_mr_branch into setup_fork_branch
- Add fork MR integration test

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

* test: add coverage for branch_tracks_mr paths

- Remove specialized rate limit/network error handlers (fall through to
  general error with full stderr)
- Add test for fork MR when branch already tracks the correct MR
- Add test for fork MR when branch tracks a different MR

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

* test: add more MR test coverage

- Add test_switch_mr_fork_existing_no_tracking (branch exists, no tracking)
- Add test_switch_mr_unknown_error (general glab error fallback)

These mirror existing GitHub PR tests for better coverage parity.

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

* refactor: unify PR/MR checkout code with RefType discriminant

- Create shared branch_tracks_ref() function for checking if a branch
  tracks a specific remote ref (PR or MR)
- Add RefType enum with helper methods (symbol, name, syntax) to
  encapsulate platform-specific display logic
- Unify error variants: RefCreateConflict, RefBaseConflict,
  BranchTracksDifferentRef, CliApiError (replacing separate PR/MR versions)

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

* fix: prevent git option injection with branch names starting with -

Add -- separator before branch names in git commands to prevent
external branch names (from GitHub/GitLab APIs) that start with -
from being interpreted as git flags.

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

* docs: add TODOs for known limitations in PR/MR checkout

Document pre-existing issues identified during code review:
- GitRemoteUrl doesn't handle GitLab nested group URLs
- glab stderr parsing is brittle across versions/locales
- branch_tracks_ref only checks merge config, not remote
- Fork MR remote fallback is silent and can pick wrong remote

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-19 11:26:43 -08:00
Maximilian Roos fb011c37dd feat: reduce background hook output verbosity (#740)
* feat: reduce background hook output verbosity (#690)

Background hooks (post-start, post-switch) now show a single-line summary
by default instead of verbose per-hook output with command details:

  ◎ Running post-start hooks @ repo.feature: user:bg, project

Use `-v` to see detailed per-hook output with expanded commands.

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

* fix: update comment to match actual output format

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

* test: add coverage for verbose background hook output

Add test_post_start_verbose_shows_per_hook_output to verify that -v shows
detailed per-hook output with command in gutter format.

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

* docs: document -v flag for background hook verbosity

Adds a note in the hook types section explaining that background hooks
show a single-line summary by default, with -v for expanded details.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-19 19:20:24 +00:00
Maximilian Roos 33971aaf22 docs: lead with post-start hooks instead of post-create (#733)
Reorders documentation to recommend post-start (background) as the default
choice, with post-create (blocking) for when something must complete before
post-start hooks or --execute run.

Changes:
- Hook types table: post-start listed first
- Section order: ### post-start before ### post-create
- Comparison section: renamed to "post-start vs post-create"
- post-start example: now includes copy + server (background tasks)
- post-create example: now shows install + env (things post-start depends on)
- wt step copy-ignored: Setup section uses post-start

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-18 23:40:35 -08:00
Rui Chen 7902f80d92 chore: update brew install to use core tap (#716)
* chore: update brew install to use core tap

Signed-off-by: Rui Chen <rui@chenrui.dev>

* docs: restore shell install step in brew instructions

The previous commit removed `&& wt config shell install` from the
Homebrew install command. This restores it so users get shell
integration set up automatically.

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

---------

Signed-off-by: Rui Chen <rui@chenrui.dev>
Co-authored-by: Maximilian Roos <m@maxroos.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-18 20:18:59 +00:00
Maximilian Roos fd2ae0e882 fix: unset unsafe upstream when creating branch from remote base (#717)
* fix: unset unsafe upstream when creating branch from remote base (#713)

When running `wt switch --create feature --base=origin/main`, git
automatically sets up the new branch to track origin/main. This is
dangerous because `git push` without arguments would push to main
instead of the feature branch.

The fix unsets the upstream tracking after creating a branch from a
remote tracking base (like origin/main), preventing accidental pushes
to the base branch.

Changes:
- Add `Branch::unset_upstream()` method to remove upstream tracking
- Add `Repository::is_remote_tracking_branch()` to detect remote refs
- Modify `execute_switch` to unset upstream when base is a remote branch
- Add test to verify no upstream is set after creating from remote base

Fixes #713

* docs: clarify upstream tracking behavior for --create vs DWIM

Explain that branches created with --create have no upstream tracking
(to prevent accidental pushes to wrong branch), while DWIM switches
preserve standard git tracking behavior.

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

* fix: update help snapshot for upstream tracking docs

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-18 11:43:28 -08:00
Maximilian Roos 2607d64076 fix: add missing article in help text (#715) 2026-01-18 18:04:02 +00:00
Maximilian Roos 1a38c2ace1 feat: add verbose output for template expansion and SemiStrict undefined behavior (#712)
* Merge origin/main into 12

Resolved conflict in src/output/mod.rs:
- Keep library-based verbosity (styling/mod.rs) for library code access
- Add API aliases (set_verbose_level, verbose_level, is_verbose) for compatibility

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

* chore: remove unused verbosity alias functions

After the merge from main, some verbosity API alias functions
(set_verbose_level, verbose_level, is_verbose) were left unused.
The codebase uses set_verbosity() through output:: and accesses
verbosity() directly from styling in library code.

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

* Refactor template expansion verbosity caching

Cache verbosity level in expand_template() to avoid multiple function
calls and remove redundant hint message for template errors. Update
snapshots to reflect removal of hint message.

* test: update snapshots after merge

Update snapshots for:
- switch_execute_template_base_without_create: template error with SemiStrict
- switch_execute_verbose_template: verbose output format
- switch_execute_verbose_multiline_template: verbose output format

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-18 01:38:35 -08:00
Maximilian Roos cb59c33e6c docs: move Arch Linux install below Windows (#709)
* Add Arch Linux install via AUR

* Alias PKGBUILD source to include version

* Add Maintained at line

* Add depends to PKGBUILD

* docs: move Arch Linux install below Windows

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

---------

Co-authored-by: Evan Sosenko <razorx@evansosenko.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-18 00:55:40 -08:00
Rui Chen 9079046127 feat: add completion cmd for completion integration (#701)
* feat: add completion cmd for completion integration

Signed-off-by: Rui Chen <rui@chenrui.dev>

* refactor: move completions command to `wt config shell completions`

- Move from top-level `wt completions` to `wt config shell completions`
- Remove duplicate CompletionShell enum, use existing Shell enum
- Simplify help text to direct users to `wt config shell install`
- Remove Homebrew note from FAQ (no duplication issues found)

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

* docs: add TODO about dynamic completions in fish

Add documentation note explaining why static completions are used
instead of dynamic completions, and reference the fish example as a
potential improvement for future implementation.

* chore: sync generated docs

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

* test: add coverage for static completions command

Tests `wt config shell completions <shell>` for all supported shells
(bash, fish, zsh, powershell) to satisfy codecov/patch coverage.

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

---------

Signed-off-by: Rui Chen <rui@chenrui.dev>
Co-authored-by: Maximilian Roos <m@maxroos.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-17 22:31:16 -08:00
Maximilian Roos d33174a9ac fix: use headRefName directly for fork PR branches (#706)
* fix: use headRefName directly for fork PR branches

Fork PR branches were named `<owner>/<branch>` to avoid collisions,
but this broke `git push` because the local branch name didn't match
the remote branch name on the fork. With `push.default = current`,
git tried to push to a non-existent remote branch.

Now fork PRs use `headRefName` directly (e.g., `feature-fix` instead
of `contributor/feature-fix`). This ensures `git push` works correctly.

The collision case (two forks with same branch name) is handled by
the existing `branch_tracks_pr()` check which errors if a branch
exists but tracks a different PR.

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

* docs: update fork PR documentation and error messages

Update documentation and error messages to reflect new fork PR branch
naming (using headRefName directly instead of owner/branch prefix):

- CLI help: explain that git push works normally with fork PRs
- Error message: clearer wording when local branch conflicts with PR
- Error hint: suggest rename (-old suffix) instead of delete

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-17 21:47:01 -08:00
Maximilian Roos f64c7863b6 refactor: require -vv for debug logging, reserve -v for future use (#702)
Change verbosity threshold from -v to -vv for enabling debug logging and
diagnostic file generation. This frees up -v for other purposes.

Behavior change:
- -v: no effect (reserved for future use)
- -vv: debug logging + verbose.log + diagnostic.md (unchanged)

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-17 13:55:11 -08:00
Maximilian Roos 089ded351d docs: fix documentation correctness issues (#687)
- Add missing `∅` (orphan) symbol to status symbols table
- Add `"orphan"` to main_state JSON values list
- Add `"no_worktree"` to worktree.state JSON field docs
- Add `base` and `base_worktree_path` to TEMPLATE_VARS for --var validation
- Add Unix-only note for wt select (de-emphasized, at bottom)

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-16 12:54:04 -08:00
Maximilian Roos 8ace270377 fix(docs): scroll only demo image, keep caption fixed (#681)
Move overflow-x from figure.demo to the picture element so the
figcaption stays in place while the image scrolls horizontally.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-16 07:10:14 +00:00
Maximilian Roos 2309c07ae1 Reorder FAQ by frequency/importance (#679)
* Simplify Windows support FAQ

Remove feature table and consolidate Windows support info into concise statements about Git for Windows requirement and wt select unavailability.

* Reorder FAQ by frequency/importance

Move most-asked questions to the top:
1. Comparisons (evaluation)
2. Shell setup issues (common friction)
3. Files created / can delete / commands executed (trust)
4. Windows support
5. Default branch detection
6. C compilation errors (rare)
7. Contributing sections

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

* Fix FAQ accuracy: mention gh/glab for CI status

- CI cache is created when either gh or glab CLI is installed
- Clarify that worktrunk also runs git/gh/glab internally

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-15 23:00:04 -08:00
Maximilian Roos f37f7db15a Simplify Windows support FAQ
Remove feature table and consolidate Windows support info into concise statements about Git for Windows requirement and wt select unavailability.
2026-01-15 22:10:40 -08:00
Maximilian Roos 043ed4671c feat(switch): add pr:<number> syntax for switching to GitHub PRs (#673)
* feat(switch): add pr:<number> syntax for switching to GitHub PRs

Adds support for `wt switch pr:123` which resolves a GitHub PR number
to its branch and switches to it. For same-repo PRs, delegates to
normal switch flow. For fork PRs, fetches from refs/pull/N/head and
configures pushRemote to the fork URL.

Implementation:
- Add pr_ref module with fetch_pr_info(), local_branch_name(), fork_remote_url()
- Handle same-repo PRs by delegating to plan_switch_inner with resolved branch
- Handle fork PRs with CreateFromForkPr plan variant
- Add compute_clobber_backup() helper to deduplicate clobber logic
- Show unified "Fetching PR #N from origin..." progress for all network ops
- Warn when --base is used with pr: syntax (ignored since PR determines branch)
- Check for local branch collisions before creating fork PR branch

Closes #657

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

* refactor(switch): unify PR and regular switch paths

Consolidates the patchy pr: implementation into a cleaner design:

- Add CreationMethod enum (Regular vs ForkPr) instead of separate
  SwitchPlan variants
- Extract resolve_switch_target() for early --create/--base validation
- Extract check_existing_worktree() and validate_worktree_creation()
  as shared validation helpers
- Remove plan_switch_from_pr() and plan_switch_inner() in favor of
  unified plan_switch() with clear phases
- Add PrBaseConflict error (--base now fails with pr: instead of warning)
- Extract compute_clobber_backup() helper

The new structure:
  plan_switch()
    → resolve_switch_target()      (pr: handling, flag validation)
    → check_existing_worktree()    (shared)
    → validate_worktree_creation() (shared)
    → SwitchPlan::Create { method: CreationMethod }

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

* fix(switch): add cleanup and PR tracking for fork PRs

Addresses several issues found through adversarial testing:

1. **Cleanup on partial failures**: If branch creation succeeds but
   worktree creation fails, the orphaned branch is now deleted to
   prevent blocking future attempts.

2. **PR tracking verification**: Before erroring on existing branches,
   we now check if the branch is tracking the correct PR. If it tracks
   the same PR, we reuse it. If it tracks a different PR or nothing,
   we error with a helpful message suggesting `git branch -D`.

3. **Improved gh error handling**:
   - Case-insensitive error matching for reliability across gh versions
   - Detection of gh not installed
   - Rate limiting detection
   - Network error detection
   - Better JSON parsing error messages
   - Validation of required fields

New tests cover: --base conflict with pr:, existing branch tracking
same PR (reuse), existing branch tracking different PR (error),
existing branch with no tracking (error).

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

* test(switch): add test for path occupied by missing worktree

Covers the error path where a target worktree path is registered
to an existing worktree whose directory was deleted. This tests
the WorktreeMissing error in validate_worktree_creation().

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

* docs(switch): mark pr:<number> syntax as experimental

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-15 19:25:32 -08:00
Maximilian Roos 01b2b8bf8d docs: add Caddy subdomain routing pattern (#676)
* docs: add Caddy subdomain routing pattern

Add "Subdomain routing with Caddy" section to Tips & Patterns showing how
to get clean URLs like `feature-auth.lvh.me` without port numbers.

The pattern uses Caddy's admin API for dynamic route registration:
- Starts Caddy if not running (idempotent)
- Creates server structure on first run (self-bootstrapping)
- Registers routes via API (no config files needed)

Key detail: requires `automatic_https: disable` since Caddy auto-enables
HTTPS for public domains like lvh.me.

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

* docs: add Caddy subdomain routing pattern

Add pattern for clean URLs like `http://feature-auth.myproject.lvh.me`
using Caddy reverse proxy with dynamic route registration via admin API.

- Routes namespaced by repo to avoid collisions across projects
- pre-remove hook cleans up routes when worktrees deleted
- Idempotent startup: checks Caddy running before starting

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

* docs: refine Caddy subdomain routing explanation

Reorder "How it works" to follow chronological flow:
1. wt switch starts dev server on deterministic port
2. Hook registers Caddy route using same port
3. lvh.me DNS explanation
4. Request flow

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

* chore: sync skill reference file

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-15 19:15:48 -08:00
Maximilian Roos f1b525c5df docs: add Windows install guidance to README (#661)
Add expandable Windows section to Install with:
- Winget as recommended install (ships git-wt by default)
- Alternative: disable Windows Terminal's wt alias

Remove redundant FAQ entry about the wt conflict since Install
now covers it. The "Does Worktrunk work on Windows?" FAQ remains
for feature support details.

Closes #133

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-15 14:19:08 -08:00
Maximilian Roos 2bb6393f93 docs: add tmux session per worktree pattern (#667)
Add a new section to Tips & Patterns showing how to create a dedicated
tmux session for each worktree with a multi-pane layout (shell, backend,
frontend, Claude).

Key patterns:
- post-create hook creates session named after sanitized branch
- pre-remove hook kills session to stop all services
- --execute flag for immediate attach on worktree creation

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-15 12:51:50 -08:00
Maximilian Roos bada0d298d fix: convert bare URLs to proper markdown links in docs (#664)
Replace angle-bracket URLs (<https://...>) with proper markdown links
that render nicely on web while showing descriptive text in CLI help.

- src/cli/mod.rs: Use Zola @/ syntax for internal links
- dev/config.example.toml: Remove angle brackets (plain URLs for TOML)
- .claude-plugin/CLAUDE.md: Use GitHub shorthand for issue link

CLI now shows "LLM commits docs" and "`wt hook` docs" instead of raw URLs.
Web docs render as clickable links with descriptive text.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-15 12:34:22 -08:00
Maximilian Roos 00819d2e34 Reorganize copy-ignored documentation structure
Move "What gets copied" section before example to improve clarity on
behavior before showing configuration. Simplify .worktreeinclude example
by removing .cache/ pattern and updating explanatory text for consistency
across all documentation files.
2026-01-15 09:56:38 -08:00
Maximilian Roos 504c9c2d87 docs: update hook examples and descriptions
Simplify hook documentation with more practical examples and clearer descriptions across post-create, post-start, and post-switch hooks.
2026-01-15 00:22:06 -08:00
Maximilian Roos b71ebed801 Simplify copy-ignored documentation
Remove redundant parenthetical and reference to detailed documentation,
consolidating information into a single clearer sentence across docs
and CLI help text.
2026-01-15 00:19:41 -08:00