Skip to content

Comments

feat: add worktree command execution via wtp exec and wtp add --exec#85

Merged
satococoa merged 5 commits intomainfrom
codex/feat-exec-and-add-exec
Feb 11, 2026
Merged

feat: add worktree command execution via wtp exec and wtp add --exec#85
satococoa merged 5 commits intomainfrom
codex/feat-exec-and-add-exec

Conversation

@satococoa
Copy link
Owner

@satococoa satococoa commented Feb 10, 2026

Summary

  • add new wtp exec <worktree> -- <command> [args...] command
  • add --exec option to wtp add to run a command in the newly created worktree after hooks
  • add interactive command support in command executor with TTY-aware fallback to non-interactive execution
  • share worktree resolution logic between wtp cd and wtp exec

Changes

  • internal/command: add interactive execution mode and TTY detection
  • cmd/wtp: add exec command, resolver extraction, and wire command into app
  • cmd/wtp add: support --exec and error context when post-create command fails
  • README: document new wtp exec and wtp add --exec usage

Testing

  • GOCACHE=$(pwd)/.gocache go test ./...

Summary by CodeRabbit

  • New Features

    • Added wtp exec to run shell commands inside an existing worktree.
    • Added --exec to wtp add to run a command after creating a worktree.
    • Improved interactive terminal handling when running commands.
  • Documentation

    • Expanded README with examples for running commands during worktree creation and executing commands in existing worktrees.

Copilot AI review requested due to automatic review settings February 10, 2026 17:31
@coderabbitai
Copy link

coderabbitai bot commented Feb 10, 2026

📝 Walkthrough

Walkthrough

Adds a new wtp exec subcommand and an --exec flag for wtp add; refactors worktree path resolution into a resolver module; and extends the command execution stack to support interactive I/O and propagate an interactive flag.

Changes

Cohort / File(s) Summary
New Exec Command
cmd/wtp/exec.go, cmd/wtp/exec_test.go, cmd/wtp/main_test.go, cmd/wtp/app.go
Adds wtp exec CLI command and tests; parses worktree + command input, resolves target worktree, and executes the command via the command executor (interactive mode supported). Registers the command in the root CLI.
Add Command Enhancement
cmd/wtp/add.go, cmd/wtp/add_test.go, README.md
Introduces --exec flag to run a shell command after worktree creation and post-create hooks; implements cross-platform execution helper and integrates it into the add flow. Tests and README examples updated.
Worktree Resolution Refactor
cmd/wtp/worktree_resolver.go, cmd/wtp/cd.go, cmd/wtp/cd_test.go
Extracts and centralizes worktree-path resolution into worktree_resolver.go (resolveWorktreePathByName, availableManagedWorktreeNames, etc.), removes older inlined helpers from cd.go, and updates call sites/tests.
Interactive Command Execution
internal/command/types.go, internal/command/shell.go, internal/command/executor.go, internal/command/executor_test.go
Adds Interactive to command model and extends ShellExecutor.Execute signature to accept interactive bool. realShellExecutor detects TTYs and wires stdio for interactive runs; tests and mocks updated.
Tests & Mocks Updates
cmd/wtp/add_test.go, cmd/wtp/exec_test.go, internal/command/*_test.go
New and extended tests and mocks to cover exec flows, interactive propagation, Windows/Unix invocation paths, and sequenced command execution simulation.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI as CLI Parser
    participant Git as Git API
    participant Resolver as Worktree Resolver
    participant Executor as Command Executor
    participant Shell as Shell

    User->>CLI: wtp exec feature/auth -- go test ./...
    CLI->>CLI: parseExecInput()
    CLI->>Git: list worktrees
    Git-->>CLI: worktree list
    CLI->>Resolver: resolveWorktreePathByName()
    Resolver-->>CLI: worktree path
    CLI->>Executor: Execute(name,args,workdir,interactive=true)
    Executor->>Shell: Execute(name,args,workdir,interactive=true)
    Shell->>Shell: hasTerminalIO()
    alt TTY Available
        Shell->>Shell: wire stdin/stdout/stderr (rgba(0,128,0,0.5))
        Shell->>Shell: run command interactively
    else No TTY
        Shell->>Shell: capture output (rgba(128,128,128,0.5))
    end
    Shell-->>Executor: result
    Executor-->>CLI: output/error
    CLI-->>User: command result
Loading
sequenceDiagram
    actor User
    participant CLI as CLI Parser
    participant GitOps as Git Operations
    participant PostHook as Post-Create Hooks
    participant ExecCmd as Exec Helper
    participant Shell as Shell

    User->>CLI: wtp add -b feature/new --exec "npm test"
    CLI->>GitOps: create worktree
    GitOps-->>CLI: worktree created
    CLI->>PostHook: run post-create hooks
    PostHook-->>CLI: hooks completed
    CLI->>ExecCmd: executePostCreateCommand("npm test")
    ExecCmd->>Shell: Execute("npm", ["test"], workdir, interactive=false)
    Shell->>Shell: capture output (rgba(0,0,255,0.5))
    Shell-->>ExecCmd: result
    ExecCmd-->>CLI: output/error
    CLI-->>User: execution complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

codex

Poem

🐰 I hopped through branches, flags in paw,

exec and add, a tidy law,
Paths resolved, then commands run,
Interactive shells — carrot-sun,
A little rabbit clap: job done.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main changes: adding a new wtp exec command and --exec flag to wtp add for executing commands in worktrees.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/feat-exec-and-add-exec

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
cmd/wtp/exec_test.go (1)

173-187: Consider failing on unexpected calls in the mock.

The fallback at line 186 silently returns an empty result if the code under test calls Execute more times than there are predefined results. This could mask bugs. You could return an error or call t.Fatal for out-of-bounds calls. That said, the tests do assert mock.executed length explicitly (e.g., line 80), so this is a minor gap.

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@cmd/wtp/exec.go`:
- Around line 55-65: The code calls executor.Execute and then directly accesses
result.Results[0].Output; add checks to ensure result.Results is non-empty and
to handle an error stored in result.Results[0].Error before calling
parseWorktreesFromOutput. Specifically, after executor.Execute(...) succeeds,
verify len(result.Results) > 0 and if not return an appropriate
errors.GitCommandFailed("git worktree list", "no command results"); then check
result.Results[0].Error and if non-nil return errors.GitCommandFailed("git
worktree list", result.Results[0].Error.Error()); only then call
parseWorktreesFromOutput, findMainWorktreePath and resolveWorktreePathByName.
- Around line 94-120: The parseExecInput function has unreachable code and magic
numbers; refactor it to (1) use named return values (e.g., worktreeName, cmd,
cmdArgs, err) to satisfy the linter, (2) introduce small named constants for
index semantics (e.g., dashIndex = 1, firstCmdIndex = 2, minArgsWithDash = 3)
and remove the unreachable len(args) < 2 branch, and (3) simplify flow: validate
len(args) == 0 and == 1 early, set worktreeName = strings.TrimSpace(args[0]),
then if args[dashIndex] == "--" ensure len(args) >= minArgsWithDash and return
worktreeName, args[firstCmdIndex], args[firstCmdIndex+1:], nil; otherwise return
worktreeName, args[firstCmdIndex-1], args[firstCmdIndex:], nil (using the named
return values).

In `@cmd/wtp/worktree_resolver.go`:
- Around line 19-40: resolveWorktreePathByName currently ignores the error from
config.LoadConfig which can leave cfg nil and skip unified-name matching; update
it to mirror availableManagedWorktreeNames by capturing the error and falling
back to the same default config used there (so cfg is never nil), then proceed
to call tryDirectWorktreeMatches/tryMainWorktreeMatches as before; reference
resolveWorktreePathByName, availableManagedWorktreeNames,
isWorktreeManagedCommon, tryDirectWorktreeMatches and tryMainWorktreeMatches to
locate where to apply the change.
🧹 Nitpick comments (4)
cmd/wtp/main_test.go (1)

125-149: createApp() test helper diverges from newApp() — consider keeping them in sync.

The test helper omits NewHookCommand() and NewShellInitCommand() that are present in the production newApp(). While this pre-dates this PR, adding NewExecCommand() here widens the maintenance surface. Consider calling newApp() directly in tests instead of maintaining a parallel definition, which would prevent future drift.

internal/command/types.go (1)

24-26: Consider passing Command directly to ShellExecutor.Execute to future-proof the interface.

The Execute signature now has 4 parameters — each time a new execution concern is added (e.g., env vars, timeout), every implementation and mock must be updated. Passing the Command struct would make the interface resilient to future additions:

Execute(cmd Command) (string, error)

This is a minor concern for now since the parameter count is still manageable.

cmd/wtp/add_test.go (1)

911-933: sequencedCommandExecutor accumulates all commands but mockCommandExecutor overwrites on each call.

mockCommandExecutor.Execute (Line 936) uses m.executedCommands = commands (assignment), meaning it only records the last call's commands. This is fine for single-call scenarios, but if any test ever calls it twice, earlier commands are silently lost. Consider using append for consistency with sequencedCommandExecutor, or add a comment noting the single-call assumption.

internal/command/shell.go (1)

38-42: hasTerminalIO is clean, but consider whether requiring all three FDs to be TTYs is too strict.

Some commands only need stdout to be a TTY (e.g., for colored output). Requiring all three means that echo hello 2>/dev/null | wtp exec feature -- some-cmd would fall back to non-interactive even if stdout is a TTY. This is the safer default though, so no change needed now.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4617f25d68

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the wtp CLI with the ability to execute arbitrary commands inside an existing or newly created worktree, while enhancing the internal command executor to better support interactive (TTY-wired) commands.

Changes:

  • Add wtp exec <worktree> -- <command> [args...] to run commands inside a resolved worktree.
  • Add wtp add --exec "<command>" to run a post-create command after hooks complete.
  • Introduce interactive execution mode in internal/command with TTY-aware fallback, and refactor shared worktree resolution logic for reuse.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/command/types.go Adds Interactive to Command and extends ShellExecutor.Execute signature.
internal/command/shell.go Implements TTY detection and interactive stdio wiring for command execution.
internal/command/executor.go Passes Interactive through to the shell executor.
internal/command/executor_test.go Updates mocks/tests for the new executor signature and interactive propagation.
cmd/wtp/worktree_resolver.go Extracts shared worktree resolution + suggestion-name logic for cd/exec.
cmd/wtp/exec.go Introduces the exec command and executes a command in a resolved worktree.
cmd/wtp/exec_test.go Adds tests for parsing and exec behavior using a mock executor.
cmd/wtp/cd.go Switches to the shared worktree resolver + shared suggestions function.
cmd/wtp/cd_test.go Updates tests to use the shared resolver function.
cmd/wtp/app.go Registers the new exec command in the application.
cmd/wtp/main_test.go Updates command list expectations to include exec.
cmd/wtp/add.go Adds --exec flag and runs post-create command after hooks.
cmd/wtp/add_test.go Adds coverage for --exec behavior and failure context retention.
README.md Documents wtp exec and wtp add --exec usage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@satococoa satococoa merged commit de2e5d2 into main Feb 11, 2026
7 checks passed
@satococoa satococoa deleted the codex/feat-exec-and-add-exec branch February 11, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant