-
Notifications
You must be signed in to change notification settings - Fork 10
feat: refactor shell integration architecture #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Separate completion and cd functionality for clarity - Add wtp hook command for shell integration - Add wtp shell-init command for combined setup - Remove WTP_SHELL_INTEGRATION environment variable dependency - Simplify wtp cd to pure path output function Breaking Changes: - wtp cd no longer requires WTP_SHELL_INTEGRATION=1 - wtp completion no longer includes cd functionality 🤖 Generated with Claude Code Co-Authored-By: Claude <[email protected]>
WalkthroughReplaces the custom completion subsystem with urfave/cli built-ins, makes Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant U as User
participant Sh as Shell (bash/zsh/fish)
participant H as Hook (shell function)
participant W as wtp (cd)
participant G as git
U->>Sh: wtp cd <name>
Sh->>H: intercept "wtp" invocation
alt cd subcommand intercepted
H->>W: run "wtp cd <name>"
W->>G: enumerate/resolve worktrees
G-->>W: worktree data
W-->>H: absolute path (stdout)
alt valid path
H->>Sh: cd <absolute path>
else no path / empty
H->>Sh: delegate to original wtp
end
else other subcommands
H->>Sh: delegate to original wtp
end
sequenceDiagram
autonumber
participant U as User
participant SI as wtp shell-init
participant CE as wtp completion (executable)
participant HK as hook printer
U->>SI: wtp shell-init <shell>
SI->>CE: invoke executable "completion <shell>"
CE-->>SI: completion script text
SI->>HK: append print<shell>Hook
HK-->>U: combined completion + hook script
sequenceDiagram
autonumber
participant U as User
participant W as wtp add/remove
participant G as git
U->>W: press [TAB] for completion
W->>G: query branches/worktrees
G-->>W: refs/worktrees
W-->>U: completion items (lines)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60–90 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
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. Comment |
There was a problem hiding this 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 refactors the shell integration architecture by separating completion and shell hook concerns into distinct commands. The main purpose is to simplify the user experience and improve maintainability by removing environment variable dependencies and creating cleaner command boundaries.
Key changes:
- Adds dedicated
wtp hookandwtp shell-initcommands for shell integration - Simplifies
wtp cdto always output absolute paths without environment checks - Removes shell integration logic from completion commands for better separation of concerns
Reviewed Changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
cmd/wtp/shell_init.go |
New command combining completion and hook functionality for one-line setup |
cmd/wtp/hook.go |
New command generating shell functions for cd functionality without legacy dependencies |
cmd/wtp/cd.go |
Simplified to pure path output function, removed WTP_SHELL_INTEGRATION check |
cmd/wtp/completion.go |
Removed shell integration logic, focused purely on tab completion |
cmd/wtp/cd_test.go |
Streamlined tests focusing on core path resolution behavior |
test/e2e/shell_test.go |
Updated tests to verify new simplified cd behavior |
test/e2e/error_test.go |
Updated error handling tests for new cd command behavior |
README.md |
Updated documentation with clearer setup instructions for separate features |
CLAUDE.md |
Added architecture documentation for the new shell integration design |
…t-in - Delete completion.go (750+ lines of custom completion scripts) - Delete completion_test.go and completion_worktrees_test.go - Switch to urfave/cli v3 built-in completion functionality - Enable built-in completion with EnableShellCompletion: true This change eliminates maintenance overhead of custom bash/zsh/fish completion scripts by leveraging the standard library functionality. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Add branch completion to add.go (getBranches + completeBranches) - Add worktree completion to remove.go (getWorktreesForRemove + completeWorktrees) - Add worktree completion to cd.go (getWorktreesForCd + completeWorktreesForCd) Each completion function follows the pattern: - Internal function using io.Writer (testable) - Wrapper function using fmt.Println (urfave/cli compatible) This approach maintains testability while providing urfave/cli compatibility through the ShellComplete field. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Add comprehensive tests for new ShellComplete functions - Test both internal functions (using io.Writer) and wrappers - Update existing tests to work with completion system refactor - Add helper functions where needed (e.g., findSubcommand) - Fix test expectations to match actual filepath behavior All tests maintain the pattern of testing behavior rather than implementation details, ensuring robust coverage. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Reimplement shell-init to work with urfave/cli built-in completion - Use outputCompletion() helper to execute 'wtp completion <shell>' - Combine completion output with hook scripts seamlessly - Support all shells: bash, zsh, fish The shell-init command now provides a complete one-command solution for users to set up both tab completion and cd functionality: eval "$(wtp shell-init bash)" 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
CLAUDE.md (2)
42-49: Update function location reference:getWorktreeNameFromPath()is no longer in completion.go.Doc still says it’s implemented in
cmd/wtp/completion.go, which has been removed in this refactor. Point this to the new shared helper location (or the cd module) to avoid confusion.Suggested change:
-The `getWorktreeNameFromPath()` function in `cmd/wtp/completion.go` implements this logic: +The unified worktree naming helper implements this logic (currently lives alongside the cd command and is used by commands that render names):
116-117: Remove staleWTP_SHELL_INTEGRATION=1mention (behavior changed).Per this PR,
wtp cdno longer depends onWTP_SHELL_INTEGRATION. Replace the quick-test example accordingly:- WTP_SHELL_INTEGRATION=1 go run ../cmd/wtp cd @ + # Either: + cd "$(go run ../cmd/wtp cd @)" + # Or enable hooks once per shell session: + eval "$(go run ../cmd/wtp hook bash)"cmd/wtp/cd.go (1)
39-41: MakeisWorktreeManagedCdpath logic OS-safe.
strings.TrimSuffix(baseDir, "/")is POSIX-only. Usefilepath.Clean.- Checking “outside base” via
strings.HasPrefix(relPath, "..")can misclassify on Windows and edge cases. Prefer an OS-aware check.Patch:
- // Remove trailing slash if it exists - baseDir = strings.TrimSuffix(baseDir, "/") + // Normalize path separators for the current OS + baseDir = filepath.Clean(baseDir) - // If relative path starts with "..", it's outside base directory - return !strings.HasPrefix(relPath, "..") + // If relative path is ".." or starts with ".."+sep, it's outside base directory + sep := string(os.PathSeparator) + return relPath != ".." && !strings.HasPrefix(relPath, ".."+sep)Also applies to: 59-61
cmd/wtp/main_test.go (1)
87-91: Also update help-output expectations to cover new commandsExtend the list so help output assertions cover
hookandshell-inittoo.- expectedCommands := []string{"add", "list", "remove", "init", "cd"} + expectedCommands := []string{"add", "list", "remove", "init", "cd", "hook", "shell-init"}cmd/wtp/cd_test.go (1)
1-306: Address lint failures: gofmt and duplicated blocks
- gofmt: The CI reports this file isn’t formatted. Please run gofmt -s -w and goimports -w (see first comment for commands).
- dupl: Sections 221-255 and 257-289 duplicate logic seen in other test files. Extracting shared helpers to internal/testutil (e.g., WithTempGitDir, CaptureStdout, NewConfigWithBaseDir) will resolve duplication and improve maintainability.
🧹 Nitpick comments (30)
cmd/wtp/add.go (2)
346-394: Generalize remote handling and HEAD filtering ingetBranches.Right now we:
- Trim only
origin/but not other remotes.- Skip only
origin/HEAD(missesupstream/HEAD, etc.).- Don’t guard against bare remote names (e.g., just
origin).This can yield noisy/duplicated suggestions and misses common setups with multiple remotes. Recommend:
- Query remotes via
git remote(best-effort).- Skip
HEADfor any remote and bare remote names.- Strip the
<remote>/prefix for any known remote to dedupe local vs remote.Proposed patch (localized to this function):
func getBranches(w io.Writer) error { // Get current directory cwd, err := os.Getwd() if err != nil { return err } + // Best-effort: gather declared remotes to normalize names + remCmd := exec.Command("git", "remote") + remCmd.Dir = cwd + remOut, _ := remCmd.Output() // ignore error; completion should be resilient + remotes := strings.Fields(strings.TrimSpace(string(remOut))) + // Get all branches using git for-each-ref for better control gitCmd := exec.Command("git", "for-each-ref", "--format=%(refname:short)", "refs/heads", "refs/remotes") gitCmd.Dir = cwd output, err := gitCmd.Output() if err != nil { return err } branches := strings.Split(strings.TrimSpace(string(output)), "\n") // Use a map to avoid duplicates seen := make(map[string]bool) for _, branch := range branches { if branch == "" { continue } - // Skip HEAD references and bare origin - if branch == "origin/HEAD" || branch == "origin" { - continue - } + // Skip HEAD references (local or any remote) and bare remote names + if branch == "HEAD" || strings.HasSuffix(branch, "/HEAD") { + continue + } + isBareRemote := false + for _, r := range remotes { + if branch == r { + isBareRemote = true + break + } + } + if isBareRemote { + continue + } // Remove remote prefix for display, but keep track of what we've seen displayName := branch - if strings.HasPrefix(branch, "origin/") { - // For remote branches, show without the origin/ prefix - displayName = strings.TrimPrefix(branch, "origin/") - } + for _, r := range remotes { + prefix := r + "/" + if strings.HasPrefix(branch, prefix) { + // For remote branches, show without the <remote>/ prefix + displayName = strings.TrimPrefix(branch, prefix) + break + } + } // Skip if already seen (handles case where local and remote have same name) if seen[displayName] { continue } seen[displayName] = true fmt.Fprintln(w, displayName) } return nil }
346-394: Optional: add timeouts to git calls to avoid hung completions on large repos.Use
exec.CommandContextwith a short context deadline (e.g., 200–500ms) so completion never blocks the user. If the deadline hits, just emit nothing.cmd/wtp/add_test.go (1)
968-982: Broaden assertions to catch regressions (optional).Consider asserting that the function writes zero or more lines and never includes
origin/HEADor bare remote names once thegetBrancheschange is applied. This makes the completion contract explicit.CLAUDE.md (1)
251-314: Minor copyedits for clarity (optional).A few bullets use stacked bolds and hyphens that read oddly (“No side effects: …”). Consider consistent bullet structure and parallel phrasing. Not blocking.
cmd/wtp/cd.go (2)
271-294: Avoid duplicate naming logic across commands (optional).
getWorktreeNameFromPathCdmirrors the naming logic used byaddsuccess messaging (getWorktreeNameFromPath). Consider centralizing in a small shared helper (e.g.,internal/naming) so all commands and errors use the same single source of truth.
113-167: Nit: computemainRepoPathonce.
findMainWorktreePath(worktrees)is called twice. Cache it to avoid recomputation and clarify intent.test/e2e/error_test.go (1)
152-165: Strengthen assertion: verify absolute path semanticsSince
wtp cdnow guarantees an absolute path, assert that the output is absolute. This prevents regressions to relative paths.@@ -import ( - "strings" - "testing" - - "github.com/satococoa/wtp/test/e2e/framework" -) +import ( + "path/filepath" + "strings" + "testing" + + "github.com/satococoa/wtp/test/e2e/framework" +) @@ - // Output should be a valid path - outputPath := strings.TrimSpace(output) - framework.AssertTrue(t, strings.Contains(outputPath, "test-branch"), "Should contain worktree name") + // Output should be an absolute path and contain the worktree name + outputPath := strings.TrimSpace(output) + framework.AssertTrue(t, filepath.IsAbs(outputPath), "Path should be absolute: %s", outputPath) + framework.AssertTrue(t, strings.Contains(outputPath, "test-branch"), "Should contain worktree name")cmd/wtp/remove_test.go (4)
853-864: Rename misleading subtest title; it doesn’t test a fallback-on-error path.filepath.Rel rarely errors on POSIX; this case asserts a long relative path, not a “fallback to directory name”. Rename for clarity.
- t.Run("should fallback to directory name on error", func(t *testing.T) { + t.Run("should return relative path when outside base_dir", func(t *testing.T) { @@ - // Use invalid path to trigger error - name := getWorktreeNameFromPath("/completely/different/path", cfg, "/path/to/repo", false) - assert.Equal(t, "../../../../completely/different/path", name) // actual filepath.Rel result + // Path outside base_dir should yield a relative path from base_dir + name := getWorktreeNameFromPath("/completely/different/path", cfg, "/path/to/repo", false) + assert.Equal(t, "../../../../completely/different/path", name)
830-830: Format the file (gofmt).CI reports “File is not properly formatted (gofmt)”. Please run gofmt/goimports.
901-915: Prefer writer-based completion capture to avoid stdout redirection in tests.The test silences os.Stdout to avoid noise. If completeWorktrees writes to cmd.Root().Writer (as other commands do), this redirection is unnecessary. See suggested change in remove.go comment for completeWorktrees.
830-864: Extract and CentralizegetWorktreeNameFromPathTestsRipgrep confirms that the same three scenarios for
getWorktreeNameFromPathare tested in two places:
cmd/wtp/remove_test.go(lines 830–864)cmd/wtp/cd_test.go(lines 221–255)To reduce duplication and maintenance overhead:
• Create a new test file
cmd/wtp/get_worktree_name_test.gocontaining a helper function, e.g.:package wtp import ( "path/filepath" "testing" "github.com/stretchr/testify/assert" "yourmodule/config" ) func testGetWorktreeNameFromPath(t *testing.T) { cfg := &config.Config{ Defaults: config.Defaults{ BaseDir: ".worktrees" } } mainRepo := "/path/to/repo" t.Run("main worktree → @", func(t *testing.T) { name := getWorktreeNameFromPath(mainRepo, cfg, mainRepo, true) assert.Equal(t, "@", name) }) t.Run("non-main worktree → relative path", func(t *testing.T) { p := filepath.Join(mainRepo, ".worktrees/feature/test") name := getWorktreeNameFromPath(p, cfg, mainRepo, false) assert.Equal(t, "feature/test", name) }) t.Run("fallback on error → raw filepath.Rel", func(t *testing.T) { p := "/completely/different/path" rel, _ := filepath.Rel(mainRepo, p) name := getWorktreeNameFromPath(p, cfg, mainRepo, false) assert.Equal(t, rel, name) }) }• In both
remove_test.goandcd_test.go, replace their inline blocks with:func TestGetWorktreeNameFromPath(t *testing.T) { testGetWorktreeNameFromPath(t) }• Delete the duplicated T.Run cases from lines 830–864 in
remove_test.goand 221–255 incd_test.go.This centralization ensures any future change to the naming logic only needs to be updated in one place.
cmd/wtp/remove.go (4)
281-304: Unify base_dir resolution and normalize paths.Use the same resolver used elsewhere (cfg.ResolveWorktreePath) and normalize inputs. This avoids subtle separator issues and keeps behavior consistent across commands.
func getWorktreeNameFromPath(worktreePath string, cfg *config.Config, mainRepoPath string, isMain bool) string { if isMain { return "@" } - // Get base_dir path - baseDir := cfg.Defaults.BaseDir - if !filepath.IsAbs(baseDir) { - baseDir = filepath.Join(mainRepoPath, baseDir) - } + // Resolve and normalize base_dir consistently + baseDir := cfg.ResolveWorktreePath(mainRepoPath, "") + baseDir = filepath.Clean(baseDir) + worktreePath = filepath.Clean(worktreePath) // Calculate relative path from base_dir relPath, err := filepath.Rel(baseDir, worktreePath) if err != nil { // Fallback to directory name return filepath.Base(worktreePath) } return relPath }
41-44: Normalize with filepath.Clean instead of TrimSuffix.TrimSuffix("/") won’t handle Windows separators and can leave redundant components. filepath.Clean is portable and reliable.
- // Remove trailing slash if it exists - baseDir = strings.TrimSuffix(baseDir, "/") + // Normalize path + baseDir = filepath.Clean(baseDir)
350-362: Write completions to the CLI writer for consistency and easier testing.urfave/cli’s ShellComplete prints to stdout, but using Root().Writer with a fallback preserves that behavior and keeps tests simpler.
-func completeWorktrees(_ context.Context, _ *cli.Command) { +func completeWorktrees(_ context.Context, cmd *cli.Command) { var buf bytes.Buffer if err := getWorktreesForRemove(&buf); err != nil { return } - // Output each line using fmt.Println for urfave/cli compatibility - scanner := bufio.NewScanner(&buf) + w := cmd.Root().Writer + if w == nil { + w = os.Stdout + } + // Output each line using fmt.Fprintln for urfave/cli compatibility + scanner := bufio.NewScanner(&buf) for scanner.Scan() { - fmt.Println(scanner.Text()) + fmt.Fprintln(w, scanner.Text()) } }
214-279: Matching priority and error surfaces make sense; consider stable ordering in “available worktrees.”The matching order (branch, basename, relative name) is reasonable. If error messages include availableWorktrees, consider sorting them for deterministic output (low priority).
cmd/wtp/hook_test.go (1)
102-146: Add zsh edge-case coverage to match bash/fish parity.Edge-case handling is verified for bash and fish; include zsh to keep parity.
tests := []struct { name string shell string requiredLogic []string }{ @@ { name: "fish hook handles empty argument", shell: "fish", requiredLogic: []string{ "if test -z \"$argv[2]\"", "echo \"Usage:", "return 1", }, }, + { + name: "zsh hook handles empty argument", + shell: "zsh", + requiredLogic: []string{ + "[[ -z \"$2\" ]]", // zsh supports [[ ... ]] + "echo \"Usage:", + "return 1", + }, + }, } @@ switch tt.shell { case "bash": printBashHook(&buf) case "fish": printFishHook(&buf) + case "zsh": + printZshHook(&buf) }cmd/wtp/shell_init.go (3)
101-119: Consider making completion execution overridable for tests.exec.Command spawns the binary; allowing an overridable runner simplifies unit tests for shell-init without forking a process.
+// test seam +var runCompletion = outputCompletion @@ - if err := outputCompletion(w, "bash"); err != nil { + if err := runCompletion(w, "bash"); err != nil { @@ - if err := outputCompletion(w, "zsh"); err != nil { + if err := runCompletion(w, "zsh"); err != nil { @@ - if err := outputCompletion(w, "fish"); err != nil { + if err := runCompletion(w, "fish"); err != nil {
119-119: Format the file (gofmt).CI reports formatting issues. Please run gofmt/goimports.
47-99: Add unit tests for “shell-init ” to assert combined output.Recommend tests asserting that:
- completion content is present (e.g., bash “complete -F …”)
- hook content is present (e.g., “wtp()” and “cd "$target_dir"”)
- a separating newline exists between the two blocks
I can draft cmd/wtp/shell_init_test.go table tests mirroring hook_test.go if helpful.
test/e2e/shell_test.go (4)
15-28: CD now outputs a path — assert it’s absolute.Strengthen the assertion to ensure the new contract is upheld.
// Output should be a valid path outputPath := strings.TrimSpace(output) - framework.AssertTrue(t, strings.Contains(outputPath, "test-branch"), "Should contain worktree name") + framework.AssertTrue(t, strings.Contains(outputPath, "test-branch"), "Should contain worktree name") + framework.AssertTrue(t, strings.HasPrefix(outputPath, "/") || strings.HasPrefix(outputPath, "\\"), "Should be an absolute path")
54-57: Remove legacy WTP_SHELL_INTEGRATION usage.Env-based integration was removed; these lines are vestigial and can be dropped.
- // Simulate shell integration - os.Setenv("WTP_SHELL_INTEGRATION", "1") - defer os.Unsetenv("WTP_SHELL_INTEGRATION") + // No env-based integration needed; cd always returns a path
136-139: Same here: drop WTP_SHELL_INTEGRATION from completion behavior tests.It no longer affects list/cd; removing reduces confusion.
- os.Setenv("WTP_SHELL_INTEGRATION", "1") - defer os.Unsetenv("WTP_SHELL_INTEGRATION") + // No env-based integration neededAlso applies to: 155-157
68-120: Consider adding E2E for “wtp shell-init ”.Verifies the one-liner UX promised in the PR: output contains both completion and hook parts. This complements the existing completion tests.
cmd/wtp/cd_test.go (7)
17-79: Make absolute-path tests platform-agnostic or skip on WindowsThese cases hardcode POSIX absolute paths and use filepath.IsAbs on them. On Windows runners, these will fail. Either synthesize OS-specific absolute paths or skip on Windows.
Option A (recommended): guard on Windows.
func TestCdCommand_AlwaysOutputsAbsolutePath(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("POSIX paths in test data; skip on Windows.") + } // Setup a realistic worktree scenarioAdd import:
+ "runtime"Option B: construct paths via filepath.Join with a temp root and build worktreeList using filepath.ToSlash when needed. I can draft this if you want.
81-125: Simplify env handling with t.Setenv; avoid manual restoreManual save/restore is verbose and error-prone. t.Setenv restores automatically and makes intent clearer.
- originalEnv := os.Getenv("WTP_SHELL_INTEGRATION") - defer func() { - if originalEnv != "" { - os.Setenv("WTP_SHELL_INTEGRATION", originalEnv) - } else { - os.Unsetenv("WTP_SHELL_INTEGRATION") - } - }() ... for _, env := range envStates { t.Run(env.name, func(t *testing.T) { - if env.value == "" { - os.Unsetenv("WTP_SHELL_INTEGRATION") - } else { - os.Setenv("WTP_SHELL_INTEGRATION", env.value) - } + if env.value == "" { + _ = os.Unsetenv("WTP_SHELL_INTEGRATION") // want truly unset + } else { + t.Setenv("WTP_SHELL_INTEGRATION", env.value) + }
126-160: Consider asserting CLI usage/args metadata for UX consistencyThe error-path test looks good. To enforce the CLI UX contract, add asserts for ArgsUsage and a helpful Description snippet via TestCdCommand_CoreBehavior (see dedicated comment), or include a case for “unknown worktree” to ensure the user gets a clear, actionable error.
162-208: Edge-case tests are good; watch for POSIX path assumptionsThese cover special characters and completion asterisk. Like the main test, they hardcode POSIX paths. If Windows support in CI is planned, use filepath utilities or skip there.
210-218: Strengthen command surface checks (ArgsUsage and Description)To keep CLI UX aligned with README examples (per learnings), assert ArgsUsage and a key Description phrase so regressions are caught.
func TestCdCommand_CoreBehavior(t *testing.T) { cmd := NewCdCommand() assert.Equal(t, "cd", cmd.Name) assert.Equal(t, "Output absolute path to worktree", cmd.Usage) assert.NotNil(t, cmd.ShellComplete) + assert.Equal(t, "<worktree-name>", cmd.ArgsUsage) + assert.Contains(t, cmd.Description, "Output the absolute path") + assert.Contains(t, cmd.Description, "eval \"$(wtp hook") // The rest is implementation detail - what matters is that it works }
221-255: Test name vs expectation mismatch; clarify fallback semantics and make cross-platform
- The subtest title says “fallback to directory name on error,” but it asserts a long relative path. That’s confusing for future readers.
- Per retrieved learnings for worktree naming, the intended fallback is directory name. If that’s still the product decision, both the implementation and this test should expect filepath.Base. If not, rename the test to reflect “relative path” fallback.
- Also, the hardcoded "../../../../..." won’t be correct on Windows.
Option A (keep current behavior; fix name and make OS-agnostic):
- t.Run("should fallback to directory name on error", func(t *testing.T) { + t.Run("should fallback to relative path on error", func(t *testing.T) { ... - // Use invalid path to trigger error - name := getWorktreeNameFromPathCd("/completely/different/path", cfg, "/path/to/repo", false) - assert.Equal(t, "../../../../completely/different/path", name) // actual filepath.Rel result + // Use invalid path to trigger error; compare using filepath.Rel for portability + name := getWorktreeNameFromPathCd("/completely/different/path", cfg, "/path/to/repo", false) + rel, _ := filepath.Rel("/path/to/repo", "/completely/different/path") + assert.Equal(t, rel, name)Option B (align to learnings: fallback to directory name):
// In cmd/wtp/cd.go (implementation change) func getWorktreeNameFromPathCd(path string, cfg *config.Config, repoRoot string, isMain bool) string { if isMain { return "@" } baseDir := cfg.Defaults.BaseDir rel := strings.TrimPrefix(strings.TrimPrefix(path, filepath.Join(repoRoot, baseDir)+string(os.PathSeparator)), string(os.PathSeparator)) if rel != "" && rel != path { return filepath.ToSlash(rel) } // fallback to directory name return filepath.Base(path) }If you choose Option B, update this test to expect "path". I can send a follow-up patch.
257-289: Use require for setup errors and de-duplicate with shared test helpers
- For mkdir/chdir setup, use require.NoError to fail fast.
- Static analysis flagged duplication with add/remove tests. Extract helpers (e.g., withTempGitDir(t), captureStdout(t), newTestConfig(baseDir)) into a small internal/testutil package used by all tests.
err := os.MkdirAll(gitDir, 0755) -assert.NoError(t, err) +require.NoError(t, err) ... err = os.Chdir(tempDir) -assert.NoError(t, err) +require.NoError(t, err)Example helper (new file suggestion):
// internal/testutil/fs.go package testutil import ( "os" "path/filepath" "testing" ) func WithTempGitDir(t *testing.T) string { t.Helper() dir := t.TempDir() require.NoError(t, os.MkdirAll(filepath.Join(dir, ".git"), 0o755)) return dir }I can factor these across test files to address the dupl finding.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (19)
CLAUDE.md(1 hunks)README.md(3 hunks)cmd/wtp/add.go(2 hunks)cmd/wtp/add_test.go(2 hunks)cmd/wtp/cd.go(3 hunks)cmd/wtp/cd_test.go(2 hunks)cmd/wtp/completion.go(0 hunks)cmd/wtp/completion_test.go(0 hunks)cmd/wtp/completion_worktrees_test.go(0 hunks)cmd/wtp/hook.go(1 hunks)cmd/wtp/hook_test.go(1 hunks)cmd/wtp/main.go(1 hunks)cmd/wtp/main_test.go(3 hunks)cmd/wtp/remove.go(2 hunks)cmd/wtp/remove_test.go(2 hunks)cmd/wtp/shell_init.go(1 hunks)cmd/wtp/shell_init_test.go(1 hunks)test/e2e/error_test.go(1 hunks)test/e2e/shell_test.go(1 hunks)
💤 Files with no reviewable changes (3)
- cmd/wtp/completion.go
- cmd/wtp/completion_test.go
- cmd/wtp/completion_worktrees_test.go
🧰 Additional context used
📓 Path-based instructions (5)
cmd/wtp/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Update command help text when adding new features.
Files:
cmd/wtp/main_test.gocmd/wtp/hook_test.gocmd/wtp/add.gocmd/wtp/shell_init_test.gocmd/wtp/remove_test.gocmd/wtp/add_test.gocmd/wtp/hook.gocmd/wtp/main.gocmd/wtp/remove.gocmd/wtp/shell_init.gocmd/wtp/cd_test.gocmd/wtp/cd.go
**/*.go
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.go: Use gofmt and goimports for all Go code formatting
Follow lint rules (vet, staticcheck, gosec, lll=120, avoid ignored errors)
Keep functions focused and small; use Go idioms
Use short, lowercase package names
Files:
cmd/wtp/main_test.gocmd/wtp/hook_test.gotest/e2e/error_test.gocmd/wtp/add.gocmd/wtp/shell_init_test.gocmd/wtp/remove_test.gocmd/wtp/add_test.gotest/e2e/shell_test.gocmd/wtp/hook.gocmd/wtp/main.gocmd/wtp/remove.gocmd/wtp/shell_init.gocmd/wtp/cd_test.gocmd/wtp/cd.go
**/*_test.go
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Write tests as table-driven tests and name test files with *_test.go
Files:
cmd/wtp/main_test.gocmd/wtp/hook_test.gotest/e2e/error_test.gocmd/wtp/shell_init_test.gocmd/wtp/remove_test.gocmd/wtp/add_test.gotest/e2e/shell_test.gocmd/wtp/cd_test.go
cmd/wtp/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Keep CLI UX consistent with README examples and autocompletion behavior
Files:
cmd/wtp/main_test.gocmd/wtp/hook_test.gocmd/wtp/add.gocmd/wtp/shell_init_test.gocmd/wtp/remove_test.gocmd/wtp/add_test.gocmd/wtp/hook.gocmd/wtp/main.gocmd/wtp/remove.gocmd/wtp/shell_init.gocmd/wtp/cd_test.gocmd/wtp/cd.go
README.md
📄 CodeRabbit inference engine (CLAUDE.md)
Update README.md documentation and examples when adding new features.
Files:
README.md
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
PR: satococoa/wtp#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-11T13:56:29.054Z
Learning: Applies to cmd/wtp/** : Keep CLI UX consistent with README examples and autocompletion behavior
📚 Learning: 2025-07-24T14:15:20.744Z
Learnt from: CR
PR: satococoa/wtp#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-24T14:15:20.744Z
Learning: Applies to cmd/wtp/*.go : Update command help text when adding new features.
Applied to files:
cmd/wtp/main_test.gocmd/wtp/hook_test.gocmd/wtp/add.gocmd/wtp/shell_init_test.gocmd/wtp/remove_test.gocmd/wtp/add_test.gocmd/wtp/hook.gocmd/wtp/main.gocmd/wtp/remove.gocmd/wtp/shell_init.gocmd/wtp/cd_test.gocmd/wtp/cd.go
📚 Learning: 2025-08-11T13:56:29.054Z
Learnt from: CR
PR: satococoa/wtp#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-11T13:56:29.054Z
Learning: Applies to cmd/wtp/** : Keep CLI UX consistent with README examples and autocompletion behavior
Applied to files:
cmd/wtp/main_test.goREADME.mdcmd/wtp/main.go
📚 Learning: 2025-07-24T14:15:20.744Z
Learnt from: CR
PR: satococoa/wtp#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-24T14:15:20.744Z
Learning: Applies to cmd/wtp/completion.go : The getWorktreeNameFromPath() function in cmd/wtp/completion.go must implement worktree naming logic: return '@' for main worktree, relative path from base_dir for non-main worktrees, and fall back to directory name if path calculation fails.
Applied to files:
test/e2e/error_test.gocmd/wtp/add.gocmd/wtp/remove_test.gocmd/wtp/add_test.goREADME.mdcmd/wtp/remove.gocmd/wtp/cd_test.gocmd/wtp/cd.go
📚 Learning: 2025-08-11T13:56:29.054Z
Learnt from: CR
PR: satococoa/wtp#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-11T13:56:29.054Z
Learning: Reference AGENTS.md for contributor workflow; cite CLAUDE.md for deep design questions
Applied to files:
CLAUDE.md
📚 Learning: 2025-08-11T13:56:29.054Z
Learnt from: CR
PR: satococoa/wtp#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-11T13:56:29.054Z
Learning: Applies to .wtp.yml : .wtp.yml defines project hooks executed on worktree creation; keep defaults safe
Applied to files:
README.md
🧬 Code graph analysis (14)
cmd/wtp/main_test.go (2)
cmd/wtp/completion_test.go (6)
TestNewCompletionCommand(16-47)TestCompletionScriptGeneration(333-375)TestCompletionBash(49-68)TestCompletionFish(91-110)TestCompletionZsh(70-89)TestCompletionPowerShell(112-123)cmd/wtp/completion.go (1)
NewCompletionCommand(61-167)
cmd/wtp/hook_test.go (1)
cmd/wtp/hook.go (1)
NewHookCommand(13-44)
test/e2e/error_test.go (1)
test/e2e/framework/assertions.go (3)
AssertNoError(68-71)AssertOutputContains(29-32)AssertTrue(144-147)
cmd/wtp/add.go (2)
cmd/wtp/completion_test.go (3)
TestCompleteBranchesFunction(267-298)TestCompleteBranches(125-155)TestPrintBranches(189-204)cmd/wtp/completion.go (1)
printBranches(650-695)
cmd/wtp/shell_init_test.go (1)
cmd/wtp/shell_init.go (1)
NewShellInitCommand(14-45)
cmd/wtp/remove_test.go (1)
internal/config/config.go (2)
Config(12-16)Defaults(19-21)
cmd/wtp/add_test.go (1)
cmd/wtp/completion_test.go (4)
TestCompleteBranchesFunction(267-298)TestCompleteBranches(125-155)TestPrintBranches(189-204)TestCompleteWorktrees(157-187)
test/e2e/shell_test.go (1)
test/e2e/framework/assertions.go (3)
AssertNoError(68-71)AssertOutputContains(29-32)AssertTrue(144-147)
cmd/wtp/hook.go (2)
cmd/wtp/completion_test.go (1)
TestCompletionBash(49-68)cmd/wtp/completion.go (1)
NewCompletionCommand(61-167)
cmd/wtp/main.go (4)
cmd/wtp/hook.go (1)
NewHookCommand(13-44)cmd/wtp/shell_init.go (1)
NewShellInitCommand(14-45)cmd/wtp/completion.go (3)
NewCompletionCommand(61-167)completionBash(169-382)completionZsh(384-602)cmd/wtp/completion_test.go (4)
TestNewCompletionCommand(16-47)TestCompletionBash(49-68)TestHiddenCommands(377-386)TestCompletionScriptGeneration(333-375)
cmd/wtp/remove.go (3)
internal/config/config.go (3)
Config(12-16)Defaults(19-21)LoadConfig(48-78)internal/git/repository.go (1)
NewRepository(16-21)cmd/wtp/completion.go (2)
printWorktriesForRemove(799-808)printWorktrees(707-741)
cmd/wtp/shell_init.go (2)
cmd/wtp/completion.go (1)
NewCompletionCommand(61-167)cmd/wtp/completion_test.go (1)
TestCompletionBash(49-68)
cmd/wtp/cd_test.go (2)
cmd/wtp/cd.go (1)
NewCdCommand(64-80)internal/config/config.go (2)
Config(12-16)Defaults(19-21)
cmd/wtp/cd.go (2)
internal/config/config.go (3)
Config(12-16)Defaults(19-21)LoadConfig(48-78)internal/git/repository.go (1)
NewRepository(16-21)
🪛 GitHub Check: Lint
cmd/wtp/shell_init_test.go
[failure] 14-14:
File is not properly formatted (gofmt)
[warning] 58-58:
unused-parameter: parameter 't' seems to be unused, consider removing or renaming it as _ (revive)
cmd/wtp/remove_test.go
[failure] 837-837:
File is not properly formatted (gofmt)
[failure] 830-830:
830-864 lines are duplicate of cmd/wtp/cd_test.go:221-255 (dupl)
cmd/wtp/add_test.go
[failure] 937-937:
File is not properly formatted (gofmt)
[failure] 934-934:
934-966 lines are duplicate of cmd/wtp/cd_test.go:257-289 (dupl)
cmd/wtp/shell_init.go
[failure] 119-119:
File is not properly formatted (gofmt)
cmd/wtp/cd_test.go
[failure] 228-228:
File is not properly formatted (gofmt)
[failure] 221-221:
221-255 lines are duplicate of cmd/wtp/remove_test.go:830-864 (dupl)
[failure] 257-257:
257-289 lines are duplicate of cmd/wtp/add_test.go:934-966 (dupl)
🪛 LanguageTool
CLAUDE.md
[grammar] ~260-~260: There might be a mistake here.
Context: ...bsolute path to worktree (pure function) - Behavior: Always outputs path, no envi...
(QB_NEW_EN)
[grammar] ~261-~261: There might be a mistake here.
Context: ...uts path, no environment variable checks - No side effects: Does not change direc...
(QB_NEW_EN)
[grammar] ~265-~265: There might be a mistake here.
Context: ...**: Generate pure tab completion scripts - Implementation: Uses urfave/cli v3 sta...
(QB_NEW_EN)
[grammar] ~266-~266: There might be a mistake here.
Context: ...li v3 standard completion where possible - No shell functions: Removed wtp() func...
(QB_NEW_EN)
[grammar] ~270-~270: There might be a mistake here.
Context: ...e shell integration for cd functionality - Implementation: Outputs shell function...
(QB_NEW_EN)
[grammar] ~271-~271: There might be a mistake here.
Context: ... function that intercepts wtp cd calls - Shells supported: bash, zsh, fish **`...
(QB_NEW_EN)
[grammar] ~275-~275: There might be a mistake here.
Context: ...ence command combining completion + hook - Use case: Manual setup and lazy loadin...
(QB_NEW_EN)
[grammar] ~280-~280: There might be a mistake here.
Context: ...od | Tab Completion | cd Functionality | |-------------------|----------------|--...
(QB_NEW_EN)
[grammar] ~281-~281: There might be a mistake here.
Context: ...---|----------------|------------------| | Homebrew | Automatic | `eval "$(wt...
(QB_NEW_EN)
[grammar] ~282-~282: There might be a mistake here.
Context: ...tomatic | eval "$(wtp hook <shell>)" | | go install | `eval "$(wtp completi...
(QB_NEW_EN)
[grammar] ~303-~303: There might be a mistake here.
Context: ... 200+ lines of custom completion scripts 2. Standards Compliance: Uses urfave/cli ...
(QB_NEW_EN)
[grammar] ~304-~304: There might be a mistake here.
Context: ...e**: Uses urfave/cli built-in completion 3. Clear Separation: Completion vs. shell...
(QB_NEW_EN)
[grammar] ~305-~305: There might be a mistake here.
Context: ...etion vs. shell integration are distinct 4. User Choice: Users can choose completi...
(QB_NEW_EN)
[grammar] ~306-~306: There might be a mistake here.
Context: ...oose completion-only or full integration 5. Future-Proof: Standard patterns used t...
(QB_NEW_EN)
[grammar] ~311-~311: There might be a mistake here.
Context: ...g Change**: wtp cd no longer requires WTP_SHELL_INTEGRATION=1 - Migration Path: Replace completion set...
(QB_NEW_EN)
[grammar] ~312-~312: There might be a mistake here.
Context: ...up with separate completion + hook setup - Backward Compatibility: Old completion...
(QB_NEW_EN)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: E2E Tests (macos-latest)
- GitHub Check: E2E Tests (ubuntu-latest)
- GitHub Check: Test (macos-latest, 1.24)
- GitHub Check: Test (ubuntu-latest, 1.24)
🔇 Additional comments (14)
cmd/wtp/add.go (1)
35-41: Nice: dynamic branch completion is wired intowtp add.Hooking
ShellComplete: completeBranchesaligns with the new architecture and improves UX. Keep README examples consistent with this behavior.cmd/wtp/add_test.go (1)
934-966: Fix formatting and remove duplication flagged by the linter.
- gofmt failure at Line 937 indicates formatting drift. Run
gofmt -s -w cmd/wtp/add_test.go(orgo tool task dev) to satisfy the pipeline.- Lines 934–966 duplicate logic also present in
cmd/wtp/cd_test.go:257-289. Extract a tiny helper (e.g., incmd/wtp/testutil) and reuse it in both tests to silence the “dupl” check.Minimal change within this file (use a helper for silencing stdout):
func TestCompleteBranches(t *testing.T) { t.Run("should not panic when called", func(t *testing.T) { cmd := &cli.Command{} - - // Should not panic even without proper git setup - assert.NotPanics(t, func() { - // Capture stdout to avoid noise in tests - oldStdout := os.Stdout - os.Stdout = os.NewFile(0, os.DevNull) - defer func() { os.Stdout = oldStdout }() - - completeBranches(context.Background(), cmd) - }) + // Should not panic even without proper git setup + assert.NotPanics(t, func() { + withSilencedStdout(t, func() { + completeBranches(context.Background(), cmd) + }) + }) }) }Add this helper once and reuse across tests (new file suggestion):
// cmd/wtp/testutil/helpers_test.go package testutil import ( "os" "testing" ) func WithSilencedStdout(t *testing.T, fn func()) { t.Helper() oldStdout := os.Stdout os.Stdout = os.NewFile(0, os.DevNull) defer func() { os.Stdout = oldStdout }() fn() }Then import and call
testutil.WithSilencedStdoutfrom both test files. This addresses both the formatting violation (after gofmt) and the duplication warning.⛔ Skipped due to learnings
Learnt from: CR PR: satococoa/wtp#0 File: CLAUDE.md:0-0 Timestamp: 2025-07-24T14:15:20.744Z Learning: Applies to cmd/wtp/*.go : Update command help text when adding new features.Learnt from: CR PR: satococoa/wtp#0 File: CLAUDE.md:0-0 Timestamp: 2025-07-24T14:15:20.744Z Learning: Applies to cmd/wtp/completion.go : The getWorktreeNameFromPath() function in cmd/wtp/completion.go must implement worktree naming logic: return '@' for main worktree, relative path from base_dir for non-main worktrees, and fall back to directory name if path calculation fails.cmd/wtp/hook.go (1)
12-44: Good UX: clear help text and per-shell subcommands.The help/description text is explicit and aligns with the PR goals (“Less is More” separation). Nice.
cmd/wtp/cd.go (1)
67-79: Help and examples forcdlook good.Clear about printing an absolute path and how to enable hooks. Matches the new architecture.
README.md (3)
253-256: Confirm Homebrew auto-completions actually ship in the tap formula“Tab completion is automatically installed! No manual setup required.” is great if the tap installs bash/zsh/fish completion files into the proper locations. Please verify the Homebrew formula generates and installs completions (including fish) on install/upgrade; otherwise this line can mislead users.
Would you like me to open a follow-up to update the tap formula and add CI to assert the completion files are present after
brew install?
274-286: Docs for wtp cd behavior are clear and align with refactorExplaining that
wtp cdalways prints an absolute path and showing the command-substitution pattern is exactly what users need without the hook. Nice.
315-318: “wtp once” auto-configuration claim needs validation or clarificationAuto-configuring both completion and hooks on first tab-press is a strong claim and non-standard for Homebrew-installed CLIs. If this relies on shell-specific lazy-loading or post-install hooks, please link to the mechanism or adjust wording to avoid overpromising.
If this behavior isn’t guaranteed across shells, propose changing to: “Homebrew users: tab completion is installed automatically. For
wtp cdintegration, run: eval '$(wtp hook )' or use the one-liner: eval '$(wtp shell-init )'.”cmd/wtp/main.go (1)
38-40: Good wiring: adds ‘hook’ and ‘shell-init’; rely on built-in completionReplacing the bespoke completion command with urfave/cli’s built-in completion and introducing focused
hook/shell-initcommands makes the surface area smaller and clearer. LGTM.cmd/wtp/shell_init_test.go (1)
1-76: It looks likegofmt(and possiblyrevive) isn’t installed in this environment, so I can’t automatically verify that the file is properly formatted or lint-clean. Please manually run:gofmt -s -l cmd/wtp/shell_init_test.go revive -config revive.toml ./cmd/wtp/shell_init_test.goand confirm there’s no output (i.e., no formatting or lint issues). Once that’s done, we’ll be sure the fixes have been applied correctly.
cmd/wtp/remove.go (1)
66-95: Help text and flags look solid.Usage, examples, and new flags (with-branch, force-branch) align with the PR’s UX goals and retrieved learnings. Good job.
cmd/wtp/hook_test.go (1)
35-100: Good coverage of hook scripts’ essential behavior.Validates per-shell fragments and ensures we’ve removed legacy WTP_SHELL_INTEGRATION. Nice.
cmd/wtp/shell_init.go (1)
13-45: Solid UX and docs in Description.The one-liner instructions per shell align with the PR objectives and README UX guidance.
test/e2e/shell_test.go (1)
30-49: Branch resolution path checks look good.The relaxed path checks cover both “worktrees/feature/test” and “feature/test”, matching the new behavior. Nice.
cmd/wtp/cd_test.go (1)
3-13: Importrequireand normalize imports/formatting
- In
cmd/wtp/cd_test.go, add the"github.com/stretchr/testify/require"import (right afterassert).- Run the Go formatting tools locally to ensure imports are grouped and ordered correctly:
gofmt -s -w cmd/wtp/cd_test.go goimports -w cmd/wtp/cd_test.goUpdated import block:
import ( "bytes" "context" "os" "path/filepath" "testing" "github.com/satococoa/wtp/internal/config" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/urfave/cli/v3" )
| | Installation Method | Tab Completion | cd Functionality | | ||
| |-------------------|----------------|------------------| | ||
| | **Homebrew** | Automatic | `eval "$(wtp hook <shell>)"` | | ||
| | **go install** | `eval "$(wtp completion <shell>)"` | `eval "$(wtp hook <shell>)"` | | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Reflect the new one-liner shell-init UX in the matrix.
The PR advertises “one-line setup: eval '$(wtp shell-init bash)'”. Add that to the table:
-| **Homebrew** | Automatic | `eval "$(wtp hook <shell>)"` |
-| **go install** | `eval "$(wtp completion <shell>)"` | `eval "$(wtp hook <shell>)"` |
+| **Homebrew** | Automatic | `eval "$(wtp shell-init <shell>)"` |
+| **go install** | `eval "$(wtp shell-init <shell>)"` | Included in `shell-init` |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| | Installation Method | Tab Completion | cd Functionality | | |
| |-------------------|----------------|------------------| | |
| | **Homebrew** | Automatic | `eval "$(wtp hook <shell>)"` | | |
| | **go install** | `eval "$(wtp completion <shell>)"` | `eval "$(wtp hook <shell>)"` | | |
| | Installation Method | Tab Completion | cd Functionality | | |
| |---------------------|----------------|------------------| | |
| | **Homebrew** | Automatic | `eval "$(wtp shell-init <shell>)"` | | |
| | **go install** | `eval "$(wtp shell-init <shell>)"` | Included in `shell-init` | |
🧰 Tools
🪛 LanguageTool
[grammar] ~280-~280: There might be a mistake here.
Context: ...od | Tab Completion | cd Functionality | |-------------------|----------------|--...
(QB_NEW_EN)
[grammar] ~281-~281: There might be a mistake here.
Context: ...---|----------------|------------------| | Homebrew | Automatic | `eval "$(wt...
(QB_NEW_EN)
[grammar] ~282-~282: There might be a mistake here.
Context: ...tomatic | eval "$(wtp hook <shell>)" | | go install | `eval "$(wtp completi...
(QB_NEW_EN)
🤖 Prompt for AI Agents
In CLAUDE.md around lines 280-284, the installation matrix still shows the old
commands for tab completion and cd hook; update the table cells for Homebrew and
go install to reflect the new one-line UX by replacing the existing commands
(e.g. eval "$(wtp completion <shell>)" and eval "$(wtp hook <shell>)") with the
new shell-init one-liner (eval '$(wtp shell-init <shell>)') so the table matches
the PR description.
| func printBashHook(w io.Writer) { | ||
| fmt.Fprintln(w, `# wtp cd command hook for bash | ||
| wtp() { | ||
| if [[ "$1" == "cd" ]]; then | ||
| if [[ -z "$2" ]]; then | ||
| echo "Usage: wtp cd <worktree>" >&2 | ||
| return 1 | ||
| fi | ||
| local target_dir | ||
| target_dir=$(command wtp cd "$2" 2>/dev/null) | ||
| if [[ $? -eq 0 && -n "$target_dir" ]]; then | ||
| cd "$target_dir" | ||
| else | ||
| command wtp cd "$2" | ||
| fi | ||
| else | ||
| command wtp "$@" | ||
| fi | ||
| }`) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Harden bash hook: support “--”, preserve flags, and keep safety.
- Add
--before the worktree to guard against names starting with-. - Current logic drops extra args (e.g.
wtp cd --help). Let those pass through. - Current logic is fine for 1 arg, but forward
"$@"to preserve behavior.
Patch inside the printed script:
wtp() {
if [[ "$1" == "cd" ]]; then
- if [[ -z "$2" ]]; then
+ if [[ -z "$2" ]]; then
echo "Usage: wtp cd <worktree>" >&2
return 1
fi
local target_dir
- target_dir=$(command wtp cd "$2" 2>/dev/null)
+ # Support worktree names that look like flags with `--`
+ target_dir=$(command wtp cd -- "$2" 2>/dev/null)
if [[ $? -eq 0 && -n "$target_dir" ]]; then
cd "$target_dir"
else
- command wtp cd "$2"
+ # Forward flags/help and any extra args to the real command
+ command wtp "$@"
fi
else
command wtp "$@"
fi
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func printBashHook(w io.Writer) { | |
| fmt.Fprintln(w, `# wtp cd command hook for bash | |
| wtp() { | |
| if [[ "$1" == "cd" ]]; then | |
| if [[ -z "$2" ]]; then | |
| echo "Usage: wtp cd <worktree>" >&2 | |
| return 1 | |
| fi | |
| local target_dir | |
| target_dir=$(command wtp cd "$2" 2>/dev/null) | |
| if [[ $? -eq 0 && -n "$target_dir" ]]; then | |
| cd "$target_dir" | |
| else | |
| command wtp cd "$2" | |
| fi | |
| else | |
| command wtp "$@" | |
| fi | |
| }`) | |
| } | |
| func printBashHook(w io.Writer) { | |
| fmt.Fprintln(w, `# wtp cd command hook for bash | |
| wtp() { | |
| if [[ "$1" == "cd" ]]; then | |
| if [[ -z "$2" ]]; then | |
| echo "Usage: wtp cd <worktree>" >&2 | |
| return 1 | |
| fi | |
| local target_dir | |
| # Support worktree names that look like flags with `--` | |
| target_dir=$(command wtp cd -- "$2" 2>/dev/null) | |
| if [[ $? -eq 0 && -n "$target_dir" ]]; then | |
| cd "$target_dir" | |
| else | |
| # Forward flags/help and any extra args to the real command | |
| command wtp "$@" | |
| fi | |
| else | |
| command wtp "$@" | |
| fi | |
| }`) | |
| } |
🤖 Prompt for AI Agents
In cmd/wtp/hook.go around lines 73 to 92, the printed bash hook drops extra
args, fails to protect worktree names starting with '-', and doesn't forward
flags; update the function body so the cd branch preserves all arguments by
checking for at least one arg but forwarding "$@" to command wtp, invoke command
wtp cd with a "--" before the worktree when capturing target_dir to guard names
starting with '-', and when successful cd use the captured target_dir, otherwise
run command wtp cd "$@" (or command wtp "$@") so flags like --help and
additional args are preserved while keeping existing safety checks for empty
args.
| func printZshHook(w io.Writer) { | ||
| fmt.Fprintln(w, `# wtp cd command hook for zsh | ||
| wtp() { | ||
| if [[ "$1" == "cd" ]]; then | ||
| if [[ -z "$2" ]]; then | ||
| echo "Usage: wtp cd <worktree>" >&2 | ||
| return 1 | ||
| fi | ||
| local target_dir | ||
| target_dir=$(command wtp cd "$2" 2>/dev/null) | ||
| if [[ $? -eq 0 && -n "$target_dir" ]]; then | ||
| cd "$target_dir" | ||
| else | ||
| command wtp cd "$2" | ||
| fi | ||
| else | ||
| command wtp "$@" | ||
| fi | ||
| }`) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Apply the same hardening to zsh hook.
Mirror the bash changes in the zsh variant:
wtp() {
if [[ "$1" == "cd" ]]; then
- if [[ -z "$2" ]]; then
+ if [[ -z "$2" ]]; then
echo "Usage: wtp cd <worktree>" >&2
return 1
fi
local target_dir
- target_dir=$(command wtp cd "$2" 2>/dev/null)
+ target_dir=$(command wtp cd -- "$2" 2>/dev/null)
if [[ $? -eq 0 && -n "$target_dir" ]]; then
cd "$target_dir"
else
- command wtp cd "$2"
+ command wtp "$@"
fi
else
command wtp "$@"
fi
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func printZshHook(w io.Writer) { | |
| fmt.Fprintln(w, `# wtp cd command hook for zsh | |
| wtp() { | |
| if [[ "$1" == "cd" ]]; then | |
| if [[ -z "$2" ]]; then | |
| echo "Usage: wtp cd <worktree>" >&2 | |
| return 1 | |
| fi | |
| local target_dir | |
| target_dir=$(command wtp cd "$2" 2>/dev/null) | |
| if [[ $? -eq 0 && -n "$target_dir" ]]; then | |
| cd "$target_dir" | |
| else | |
| command wtp cd "$2" | |
| fi | |
| else | |
| command wtp "$@" | |
| fi | |
| }`) | |
| } | |
| func printZshHook(w io.Writer) { | |
| fmt.Fprintln(w, `# wtp cd command hook for zsh | |
| wtp() { | |
| if [[ "$1" == "cd" ]]; then | |
| if [[ -z "$2" ]]; then | |
| echo "Usage: wtp cd <worktree>" >&2 | |
| return 1 | |
| fi | |
| local target_dir | |
| target_dir=$(command wtp cd -- "$2" 2>/dev/null) | |
| if [[ $? -eq 0 && -n "$target_dir" ]]; then | |
| cd "$target_dir" | |
| else | |
| command wtp "$@" | |
| fi | |
| else | |
| command wtp "$@" | |
| fi | |
| }`) | |
| } |
| func printFishHook(w io.Writer) { | ||
| fmt.Fprintln(w, `# wtp cd command hook for fish | ||
| function wtp | ||
| if test "$argv[1]" = "cd" | ||
| if test -z "$argv[2]" | ||
| echo "Usage: wtp cd <worktree>" >&2 | ||
| return 1 | ||
| end | ||
| set -l target_dir (command wtp cd $argv[2] 2>/dev/null) | ||
| if test $status -eq 0 -a -n "$target_dir" | ||
| cd $target_dir | ||
| else | ||
| command wtp cd $argv[2] | ||
| end | ||
| else | ||
| command wtp $argv | ||
| end | ||
| end`) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Quote expansions and support -- in fish hook.
- Quote
$argv[2]and$target_dirto handle spaces. - Pass
--before$argv[2]to guard against names starting with-. - Forward unknown/extra args back to
wtpfor help/flags.
function wtp
if test "$argv[1]" = "cd"
if test -z "$argv[2]"
echo "Usage: wtp cd <worktree>" >&2
return 1
end
- set -l target_dir (command wtp cd $argv[2] 2>/dev/null)
- if test $status -eq 0 -a -n "$target_dir"
- cd $target_dir
+ set -l target_dir (command wtp cd -- "$argv[2]" 2>/dev/null)
+ if test $status -eq 0 -a -n "$target_dir"
+ cd "$target_dir"
else
- command wtp cd $argv[2]
+ command wtp $argv
end
else
command wtp $argv
end
end📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func printFishHook(w io.Writer) { | |
| fmt.Fprintln(w, `# wtp cd command hook for fish | |
| function wtp | |
| if test "$argv[1]" = "cd" | |
| if test -z "$argv[2]" | |
| echo "Usage: wtp cd <worktree>" >&2 | |
| return 1 | |
| end | |
| set -l target_dir (command wtp cd $argv[2] 2>/dev/null) | |
| if test $status -eq 0 -a -n "$target_dir" | |
| cd $target_dir | |
| else | |
| command wtp cd $argv[2] | |
| end | |
| else | |
| command wtp $argv | |
| end | |
| end`) | |
| } | |
| func printFishHook(w io.Writer) { | |
| fmt.Fprintln(w, `# wtp cd command hook for fish | |
| function wtp | |
| if test "$argv[1]" = "cd" | |
| if test -z "$argv[2]" | |
| echo "Usage: wtp cd <worktree>" >&2 | |
| return 1 | |
| end | |
| set -l target_dir (command wtp cd -- "$argv[2]" 2>/dev/null) | |
| if test $status -eq 0 -a -n "$target_dir" | |
| cd "$target_dir" | |
| else | |
| command wtp $argv | |
| end | |
| else | |
| command wtp $argv | |
| end | |
| end`) | |
| } |
| expectedCommands := []string{"add", "list", "remove", "init", "cd"} | ||
| for _, expected := range expectedCommands { | ||
| assert.True(t, commandNames[expected], "Command %s should exist", expected) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Keep unit test command lists in sync with the real CLI (include hook and shell-init)
The app constructed in tests omits hook and shell-init, so tests won’t catch regressions for these new commands and will drift from the real binary’s UX.
Apply:
- expectedCommands := []string{"add", "list", "remove", "init", "cd"}
+ expectedCommands := []string{"add", "list", "remove", "init", "cd", "hook", "shell-init"}And also include the commands in createApp (see below).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| expectedCommands := []string{"add", "list", "remove", "init", "cd"} | |
| for _, expected := range expectedCommands { | |
| assert.True(t, commandNames[expected], "Command %s should exist", expected) | |
| } | |
| expectedCommands := []string{"add", "list", "remove", "init", "cd", "hook", "shell-init"} | |
| for _, expected := range expectedCommands { | |
| assert.True(t, commandNames[expected], "Command %s should exist", expected) | |
| } |
🤖 Prompt for AI Agents
In cmd/wtp/main_test.go around lines 30 to 33, the test's expectedCommands slice
is missing the new "hook" and "shell-init" commands and the test app used in
createApp also omits them; update the expectedCommands list to include "hook"
and "shell-init", and modify the createApp helper to register the real CLI's
hook and shell-init commands so the test mirrors the real binary's command set.
| // NewCompletionCommand(), // Using built-in completion | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add new commands to the test app to avoid drift
Include the new commands in createApp() so test coverage reflects the real CLI’s command surface.
NewCdCommand(),
- // NewCompletionCommand(), // Using built-in completion
+ // Built-in completion is enabled via EnableShellCompletion
+ NewHookCommand(),
+ NewShellInitCommand(),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // NewCompletionCommand(), // Using built-in completion | |
| }, | |
| NewCdCommand(), | |
| // Built-in completion is enabled via EnableShellCompletion | |
| NewHookCommand(), | |
| NewShellInitCommand(), | |
| }, |
🤖 Prompt for AI Agents
In cmd/wtp/main_test.go around lines 145-146, the test app's createApp() is
missing recently added commands (e.g., the completion command); update
createApp() to register the new CLI commands such as NewCompletionCommand() and
any other commands added to the real CLI so the test harness mirrors the actual
command surface — modify the commands slice/registration in createApp() to
include these constructors and ensure tests exercise them.
| #### With Shell Hook (Recommended) | ||
|
|
||
| For a more seamless experience, enable the shell hook: | ||
|
|
||
| ```bash | ||
| # Bash: Add to ~/.bashrc | ||
| eval "$(wtp hook bash)" | ||
| # Zsh: Add to ~/.zshrc | ||
| eval "$(wtp hook zsh)" | ||
| # Fish: Add to ~/.config/fish/config.fish | ||
| wtp hook fish | source | ||
| ``` | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Recommend adding the “shell-init” one-liner alongside “hook”
You introduced wtp shell-init, but this section only documents wtp hook. For parity and to match the PR goal of “one-line setup,” please include the shell-init variant right here so users don’t miss it.
Apply the following to add an “All-in-one setup” subsection:
@@
#### With Shell Hook (Recommended)
@@
For a more seamless experience, enable the shell hook:
@@
wtp hook fish | source+#### All-in-one Setup (Recommended)
+
+Use wtp shell-init to enable both tab completion and the wtp cd hook in one step:
+
+bash +# Bash: Add to ~/.bashrc +eval "$(wtp shell-init bash)" + +# Zsh: Add to ~/.zshrc +eval "$(wtp shell-init zsh)" + +# Fish: Add to ~/.config/fish/config.fish +wtp shell-init fish | source +
+
Then use the simplified syntax:
<details>
<summary>🤖 Prompt for AI Agents</summary>
In README.md around lines 287 to 301, the "With Shell Hook (Recommended)"
section documents only wtp hook but omits the new wtp shell-init one-liner;
add an "All-in-one Setup (Recommended)" subsection immediately before the line
"Then use the simplified syntax:" that shows the one-liner usage for Bash, Zsh,
and Fish (eval "$(wtp shell-init bash)", eval "$(wtp shell-init zsh)", and wtp
shell-init fish | source respectively) so users can enable both tab completion
and the wtp cd hook in a single step.
</details>
<!-- fingerprinting:phantom:poseidon:chinchilla -->
<!-- This is an auto-generated comment by CodeRabbit -->
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
cmd/wtp/cd.go (3)
28-43: Unify base_dir resolution and path checks; avoid Config.ResolveWorktreePath dependency.Use the same resolution logic as getWorktreeNameFromPathCd and normalize paths with filepath.Clean for cross‑platform correctness. Also removes reliance on a method that may not exist.
Apply:
- // Get base directory - use default config if config is not available - if cfg == nil { - // Create default config when none is available - defaultCfg := &config.Config{ - Defaults: config.Defaults{ - BaseDir: "../worktrees", - }, - } - cfg = defaultCfg - } - - baseDir := cfg.ResolveWorktreePath(mainRepoPath, "") - // Remove trailing slash if it exists - baseDir = strings.TrimSuffix(baseDir, "/") + // Get base directory - use default when cfg is nil + if cfg == nil { + cfg = &config.Config{Defaults: config.Defaults{BaseDir: "../worktrees"}} + } + baseDir := cfg.Defaults.BaseDir + if !filepath.IsAbs(baseDir) { + baseDir = filepath.Join(mainRepoPath, baseDir) + } + baseDir = filepath.Clean(baseDir) @@ - // If relative path starts with "..", it's outside base directory - return !strings.HasPrefix(relPath, "..") + // If relative path starts with "..", it's outside base directory + return !strings.HasPrefix(relPath, "..")Also applies to: 49-62
156-160: Use cd-specific naming for suggestions.Keep naming consistent with cd behavior (relative to base_dir), not any legacy/global variant.
Apply:
- name := getWorktreeNameFromPath(worktrees[i].Path, cfg, mainRepoPath, worktrees[i].IsMain) + name := getWorktreeNameFromPathCd(worktrees[i].Path, cfg, mainRepoPath, worktrees[i].IsMain)
216-221: Bug risk: wrong helper used for direct matches.This should match cd’s naming semantics; otherwise user input that matches cd-style names won’t resolve.
Apply:
- if cfg != nil { - worktreeNameFromPath := getWorktreeNameFromPath(wt.Path, cfg, mainWorktreePath, wt.IsMain) + if cfg != nil { + worktreeNameFromPath := getWorktreeNameFromPathCd(wt.Path, cfg, mainWorktreePath, wt.IsMain)
♻️ Duplicate comments (1)
cmd/wtp/cd_test.go (1)
228-241: Bug: stdout redirection uses invalid FD; open /dev/null for writing.This is a repeat of a prior note; fix to avoid flakiness and resource leaks.
Apply:
@@ assert.NotPanics(t, func() { // Capture stdout to avoid noise in tests - oldStdout := os.Stdout - os.Stdout = os.NewFile(0, os.DevNull) - defer func() { os.Stdout = oldStdout }() + devNull, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0) + require.NoError(t, err) + defer devNull.Close() + oldStdout := os.Stdout + os.Stdout = devNull + defer func() { os.Stdout = oldStdout }() @@ completeWorktreesForCd(context.Background(), cmd) }) })And add the import:
@@ - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require"
🧹 Nitpick comments (16)
.golangci.yml (1)
90-90: Unlimited same-issue reporting is OK; confirm CI noise tolerance.max-same-issues: 0 can create noisy reports on mass violations. If this was intentional for migration, ignore; otherwise consider restoring a small cap (e.g., 50).
cmd/wtp/remove.go (7)
34-39: Use config.DefaultBaseDir for consistency.Hardcoding "../worktrees" diverges from config.DefaultBaseDir used elsewhere. Prefer the constant for one source of truth.
- defaultCfg := &config.Config{ - Defaults: config.Defaults{ - BaseDir: "../worktrees", - }, - } + defaultCfg := &config.Config{ + Defaults: config.Defaults{ + BaseDir: config.DefaultBaseDir, + }, + }
42-45: Normalize baseDir with filepath.Clean instead of trimming "/" (Windows-safe).strings.TrimSuffix(baseDir, "/") misses "" on Windows. Clean once and drop manual trimming.
- baseDir := cfg.ResolveWorktreePath(mainRepoPath, "") - // Remove trailing slash if it exists - baseDir = strings.TrimSuffix(baseDir, "/") + baseDir := filepath.Clean(cfg.ResolveWorktreePath(mainRepoPath, ""))
58-65: Tighten “inside base dir” check to avoid false positives.Prefix test should consider path separator and the exact ".." case.
- // If relative path starts with "..", it's outside base directory - return !strings.HasPrefix(relPath, "..") + // Outside if ".." or starts with "..{sep}" + sep := string(os.PathSeparator) + return relPath != ".." && !strings.HasPrefix(relPath, ".."+sep)
141-149: Guard against empty ExecutionResult to avoid index panic.Executor contracts can change; add a sanity check before indexing Results[0].
result, err := executor.Execute([]command.Command{listCmd}) if err != nil { return errors.GitCommandFailed("git worktree list", err.Error()) } -// Parse worktrees from command output -worktrees := parseWorktreesFromOutput(result.Results[0].Output) +if len(result.Results) == 0 { + return errors.GitCommandFailed("git worktree list", "empty result") +} +// Parse worktrees from command output +worktrees := parseWorktreesFromOutput(result.Results[0].Output)
290-304: Unify name derivation via ResolveWorktreePath and normalize slashes.Keeps behavior consistent with isWorktreeManaged and produces portable display names (forward slashes) across platforms.
- // Get base_dir path - baseDir := cfg.Defaults.BaseDir - if !filepath.IsAbs(baseDir) { - baseDir = filepath.Join(mainRepoPath, baseDir) - } + // Resolve base_dir path consistently with config + baseDir := cfg.ResolveWorktreePath(mainRepoPath, "") // Calculate relative path from base_dir relPath, err := filepath.Rel(baseDir, worktreePath) if err != nil { // Fallback to directory name return filepath.Base(worktreePath) } -return relPath +return filepath.ToSlash(relPath)
338-346: Optional: sort candidates for deterministic completion UX.Sorting names before printing yields stable completion ordering.
- for i := range worktrees { + var names []string + for i := range worktrees { wt := &worktrees[i] if !wt.IsMain && isWorktreeManaged(wt.Path, cfg, mainRepoPath, wt.IsMain) { // Calculate worktree name as relative path from base_dir name := getWorktreeNameFromPath(wt.Path, cfg, mainRepoPath, wt.IsMain) - fmt.Fprintln(w, name) + names = append(names, name) } } + sort.Strings(names) + for _, n := range names { + fmt.Fprintln(w, n) + }
352-363: Surface scanner errors (non-fatal) for easier debugging.Print a debug line on scanner error; keeps ShellComplete signature unchanged.
scanner := bufio.NewScanner(&buf) for scanner.Scan() { fmt.Println(scanner.Text()) } +_ = scanner.Err() // intentionally ignored; consider logging if you add a loggercmd/wtp/shell_init.go (2)
13-22: Capture stderr from completion generation (better diagnostics).Use CombinedOutput so failures include stderr text from the completion command.
var runCompletionCommand = func(shell string) ([]byte, error) { exe, err := os.Executable() if err != nil { // Fallback to "wtp" if we can't find the executable exe = "wtp" } - cmd := exec.Command(exe, "completion", shell) - return cmd.Output() + cmd := exec.Command(exe, "completion", shell) + return cmd.CombinedOutput() }
114-122: Include command output on error to ease troubleshooting.Propagate the captured output when completion generation fails.
func outputCompletion(w io.Writer, shell string) error { output, err := runCompletionCommand(shell) if err != nil { - return fmt.Errorf("failed to generate %s completion: %w", shell, err) + return fmt.Errorf("failed to generate %s completion: %w\n%s", shell, err, string(output)) } _, err = w.Write(output) return err }cmd/wtp/add_test.go (1)
943-947: Fix stdout redirection to /dev/null (fd must be writable; don’t use fd=0).os.NewFile(0, ...) targets stdin. Open /dev/null for writing instead to avoid EBADF on writes.
- oldStdout := os.Stdout - os.Stdout = os.NewFile(0, os.DevNull) - defer func() { os.Stdout = oldStdout }() + oldStdout := os.Stdout + devnull, _ := os.OpenFile(os.DevNull, os.O_WRONLY, 0) + defer func() { + _ = devnull.Close() + os.Stdout = oldStdout + }() + os.Stdout = devnullcmd/wtp/testhelpers_test.go (2)
31-34: Don’t ignore errors from os.Getwd; assert and restore safely.Capture and assert the error from os.Getwd to avoid masking failures.
Apply:
- oldDir, _ := os.Getwd() - t.Cleanup(func() { _ = os.Chdir(oldDir) }) - assert.NoError(t, os.Chdir(tempDir)) + oldDir, err := os.Getwd() + assert.NoError(t, err) + t.Cleanup(func() { _ = os.Chdir(oldDir) }) + assert.NoError(t, os.Chdir(tempDir))
61-67: Make expected relative path robust across platforms.Compute expected via filepath.Rel instead of hard‑coding "../../../../...".
Apply:
- name := fn("/completely/different/path", cfg, "/path/to/repo", false) - assert.Equal(t, "../../../../completely/different/path", name) + baseDir := filepath.Join("/path/to/repo", ".worktrees") + name := fn("/completely/different/path", cfg, "/path/to/repo", false) + expected, err := filepath.Rel(baseDir, "/completely/different/path") + assert.NoError(t, err) + assert.Equal(t, expected, name)cmd/wtp/cd.go (3)
69-80: Expose the new one‑liner in help: reference ‘shell-init’.Align CLI help with the PR objective “eval "$(wtp shell-init bash)"”.
Apply:
Description: "Output the absolute path to the specified worktree.\n\n" + "Usage:\n" + " Direct: cd \"$(wtp cd feature)\"\n" + - " With hook: wtp cd feature\n\n" + - "To enable the hook for easier navigation:\n" + - " Bash: eval \"$(wtp hook bash)\"\n" + - " Zsh: eval \"$(wtp hook zsh)\"\n" + - " Fish: wtp hook fish | source", + " With hook: wtp cd feature\n\n" + + "Setup:\n" + + " One‑liner: eval \"$(wtp shell-init bash)\"\n" + + " Hook only: eval \"$(wtp hook bash)\"",
121-129: Guard against empty executor results to avoid panic.Check Results length before indexing.
Apply:
result, err := executor.Execute([]command.Command{listCmd}) if err != nil { return fmt.Errorf("failed to get worktrees: %w", err) } + if len(result.Results) == 0 { + return fmt.Errorf("failed to get worktrees: no results returned") + } // Parse worktrees from command output worktrees := parseWorktreesFromOutput(result.Results[0].Output)
281-294: Handle relPath == "." gracefully.When a non‑main worktree equals base_dir (edge case), avoid returning "." as a name; fall back to basename.
Apply:
relPath, err := filepath.Rel(baseDir, worktreePath) if err != nil { // Fallback to directory name return filepath.Base(worktreePath) } - return relPath + if relPath == "." { + return filepath.Base(worktreePath) + } + return relPath
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
.golangci.yml(3 hunks)cmd/wtp/add.go(2 hunks)cmd/wtp/add_test.go(2 hunks)cmd/wtp/cd.go(3 hunks)cmd/wtp/cd_test.go(2 hunks)cmd/wtp/init.go(1 hunks)cmd/wtp/list.go(1 hunks)cmd/wtp/list_test.go(1 hunks)cmd/wtp/remove.go(2 hunks)cmd/wtp/remove_test.go(2 hunks)cmd/wtp/shell_init.go(1 hunks)cmd/wtp/shell_init_test.go(1 hunks)cmd/wtp/testhelpers_test.go(1 hunks)internal/hooks/executor_test.go(1 hunks)test/e2e/hook_streaming_test.go(1 hunks)test/e2e/integration_test.go(1 hunks)
✅ Files skipped from review due to trivial changes (5)
- cmd/wtp/list_test.go
- internal/hooks/executor_test.go
- cmd/wtp/list.go
- cmd/wtp/init.go
- test/e2e/hook_streaming_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
- cmd/wtp/shell_init_test.go
- cmd/wtp/remove_test.go
- cmd/wtp/add.go
🧰 Additional context used
📓 Path-based instructions (5)
**/*.go
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.go: Use gofmt and goimports for all Go code formatting
Follow lint rules (vet, staticcheck, gosec, lll=120, avoid ignored errors)
Keep functions focused and small; use Go idioms
Use short, lowercase package names
Files:
test/e2e/integration_test.gocmd/wtp/shell_init.gocmd/wtp/testhelpers_test.gocmd/wtp/add_test.gocmd/wtp/remove.gocmd/wtp/cd_test.gocmd/wtp/cd.go
**/*_test.go
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Write tests as table-driven tests and name test files with *_test.go
Files:
test/e2e/integration_test.gocmd/wtp/testhelpers_test.gocmd/wtp/add_test.gocmd/wtp/cd_test.go
cmd/wtp/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Update command help text when adding new features.
Files:
cmd/wtp/shell_init.gocmd/wtp/testhelpers_test.gocmd/wtp/add_test.gocmd/wtp/remove.gocmd/wtp/cd_test.gocmd/wtp/cd.go
cmd/wtp/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Keep CLI UX consistent with README examples and autocompletion behavior
Files:
cmd/wtp/shell_init.gocmd/wtp/testhelpers_test.gocmd/wtp/add_test.gocmd/wtp/remove.gocmd/wtp/cd_test.gocmd/wtp/cd.go
.golangci.yml
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Respect lint configuration defined in .golangci.yml
Files:
.golangci.yml
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
PR: satococoa/wtp#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-11T13:56:29.054Z
Learning: Applies to cmd/wtp/** : Keep CLI UX consistent with README examples and autocompletion behavior
📚 Learning: 2025-07-24T14:15:20.744Z
Learnt from: CR
PR: satococoa/wtp#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-24T14:15:20.744Z
Learning: Applies to cmd/wtp/*.go : Update command help text when adding new features.
Applied to files:
cmd/wtp/shell_init.gocmd/wtp/testhelpers_test.gocmd/wtp/add_test.gocmd/wtp/remove.gocmd/wtp/cd_test.gocmd/wtp/cd.go
📚 Learning: 2025-07-24T14:15:20.744Z
Learnt from: CR
PR: satococoa/wtp#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-24T14:15:20.744Z
Learning: Before committing any changes, always run 'go tool task dev' to ensure code is formatted, linted, and tested.
Applied to files:
.golangci.yml
📚 Learning: 2025-08-11T13:56:29.054Z
Learnt from: CR
PR: satococoa/wtp#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-11T13:56:29.054Z
Learning: Applies to **/*.go : Follow lint rules (vet, staticcheck, gosec, lll=120, avoid ignored errors)
Applied to files:
.golangci.yml
📚 Learning: 2025-08-11T13:56:29.054Z
Learnt from: CR
PR: satococoa/wtp#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-11T13:56:29.054Z
Learning: Applies to **/*.go : Keep functions focused and small; use Go idioms
Applied to files:
.golangci.yml
📚 Learning: 2025-08-11T13:56:29.054Z
Learnt from: CR
PR: satococoa/wtp#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-11T13:56:29.054Z
Learning: Applies to **/*.go : Use gofmt and goimports for all Go code formatting
Applied to files:
.golangci.yml
📚 Learning: 2025-08-11T13:56:29.054Z
Learnt from: CR
PR: satococoa/wtp#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-11T13:56:29.054Z
Learning: Applies to **/*.go : Use short, lowercase package names
Applied to files:
.golangci.yml
📚 Learning: 2025-08-11T13:56:29.054Z
Learnt from: CR
PR: satococoa/wtp#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-11T13:56:29.054Z
Learning: Applies to **/*_test.go : Write tests as table-driven tests and name test files with *_test.go
Applied to files:
cmd/wtp/testhelpers_test.go
📚 Learning: 2025-07-24T14:15:20.744Z
Learnt from: CR
PR: satococoa/wtp#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-24T14:15:20.744Z
Learning: Applies to cmd/wtp/completion.go : The getWorktreeNameFromPath() function in cmd/wtp/completion.go must implement worktree naming logic: return '@' for main worktree, relative path from base_dir for non-main worktrees, and fall back to directory name if path calculation fails.
Applied to files:
cmd/wtp/add_test.gocmd/wtp/remove.gocmd/wtp/cd_test.gocmd/wtp/cd.go
🧬 Code graph analysis (5)
cmd/wtp/testhelpers_test.go (1)
internal/config/config.go (2)
Config(12-16)Defaults(19-21)
cmd/wtp/add_test.go (1)
cmd/wtp/testhelpers_test.go (1)
RunWriterCommonTests(18-38)
cmd/wtp/remove.go (2)
internal/config/config.go (3)
Config(12-16)Defaults(19-21)LoadConfig(48-78)internal/git/repository.go (1)
NewRepository(16-21)
cmd/wtp/cd_test.go (2)
cmd/wtp/cd.go (1)
NewCdCommand(65-81)cmd/wtp/testhelpers_test.go (2)
RunNameFromPathTests(42-68)RunWriterCommonTests(18-38)
cmd/wtp/cd.go (2)
internal/config/config.go (3)
Config(12-16)Defaults(19-21)LoadConfig(48-78)internal/git/repository.go (1)
NewRepository(16-21)
🔇 Additional comments (13)
.golangci.yml (1)
29-29: goimports local-prefixes looks correct for module path.Matches github.com/satococoa/wtp and will group imports as expected.
cmd/wtp/remove.go (1)
183-190: Confirm error wording for missing worktree name.errors.BranchNameRequired(...) may produce “branch name is required”, which is misleading for remove. Ensure the message guides: “worktree name is required”.
Do we have errors.WorktreeNameRequired or a generic invalid‑argument helper to use here?
cmd/wtp/shell_init.go (1)
24-56: Verify that the root command registers a “completion” subcommand.shell-init shells out to wtp completion . Ensure main wires cli.NewCompletionCommand(); otherwise this will fail at runtime.
test/e2e/integration_test.go (1)
8-10: Import reorder is fine.No behavior change; keeps grouping consistent.
cmd/wtp/add_test.go (1)
933-935: Nice: writer-based helper coverage for getBranches.Uses shared test harness and keeps completion logic decoupled.
cmd/wtp/testhelpers_test.go (1)
15-18: Helpful, reusable test scaffolding.Good use of t.Helper and subtests to centralize common assertions for writer-based functions.
cmd/wtp/cd_test.go (5)
16-77: Core guarantee validated: absolute path output.Nice, focused table tests covering main, branch, dir-name, and nonexistent cases.
80-123: Environment independence verified.Good regression guard against WTP_SHELL_INTEGRATION affecting resolution.
125-159: Clear user-facing error path covered.CLI wiring and error message are asserted appropriately.
161-207: Edge cases look solid.Special chars, completion marker trimming, and empty list handling are exercised.
209-216: Usage string assertion aligns with refactor.Metadata checks are concise and targeted.
cmd/wtp/cd.go (2)
358-369: Completion wrapper is compatible with urfave/cli v3.Buffering then printing line‑by‑line is fine; silent return on error avoids shell noise.
28-43: Config.ResolveWorktreePath exists and is used (no compile issue).internal/config/config.go defines func (c *Config) ResolveWorktreePath(repoRoot, worktreeName string) string; it’s called from cmd/wtp/{cd.go, add.go, list.go, remove.go} and exercised in internal/config/config_test.go. Verify cmd/wtp/completion.go (getWorktreeNameFromPath) uses the same base_dir resolution logic to avoid divergent behavior.
| - github.com/satococoa/wtp | ||
| - github.com/urfave/cli/v3 | ||
| - go.yaml.in/yaml/v3 | ||
| govet: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix depguard allowlist import path for yaml.v3.
The allowed import path is misspelled; it should be gopkg.in/yaml.v3. As-is, depguard can block legitimate imports.
Apply this diff:
- - go.yaml.in/yaml/v3
+ - gopkg.in/yaml.v3📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - github.com/satococoa/wtp | |
| - github.com/urfave/cli/v3 | |
| - go.yaml.in/yaml/v3 | |
| govet: | |
| - github.com/satococoa/wtp | |
| - github.com/urfave/cli/v3 | |
| - gopkg.in/yaml.v3 | |
| govet: |
🤖 Prompt for AI Agents
In .golangci.yml around lines 15 to 18, the depguard allowlist contains the
misspelled import path "go.yaml.in/yaml/v3"; replace that entry with the correct
"gopkg.in/yaml.v3" so legitimate yaml.v3 imports are allowed and depguard won't
block them.
Additional Notes
|
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/errors/errors.go (1)
260-269: Update shell integration guidance towtp shell-init/wtp hook; avoid implyingcdrequires integration.Change the message in internal/errors/errors.go as suggested and replace all remaining "wtp completion" references so messaging and tests remain consistent.
- internal/errors/errors.go (lines ~260-269) — apply the new message (use
wtp shell-init/wtp hook, remove "cd command requires" phrasing).- internal/errors/errors_test.go (lines ~362-364) — update assertions that expect "wtp completion".
- README.md (262-269), CLAUDE.md (264-265), docs/development-history.md (39-41), docs/architecture.md (180-182) — update docs/examples referencing
wtp completion.- cmd/wtp/shell_init.go (29-31, 112-113) — ensure help text/implementation align with
shell-init/hook.Re-run the earlier grep/search to confirm no remaining
wtp completionreferences and update tests accordingly.
🧹 Nitpick comments (5)
internal/errors/errors_test.go (2)
357-365: Update expectations toshell-init.Error copy should reference
wtp shell-init, notwtp completion.Apply:
func TestShellIntegrationRequired(t *testing.T) { err := ShellIntegrationRequired() assert.Error(t, err) assert.Contains(t, err.Error(), "shell integration") assert.Contains(t, err.Error(), "eval") - assert.Contains(t, err.Error(), "wtp completion") + assert.Contains(t, err.Error(), "wtp shell-init") assert.Contains(t, err.Error(), "Setup:") }
433-436: Keep generic “helpful content” test aligned with new command name.Apply:
{ name: "ShellIntegrationRequired contains setup", errorFn: ShellIntegrationRequired, - keywords: []string{"Setup:", "eval", "completion"}, + keywords: []string{"Setup:", "eval", "shell-init"}, },cmd/wtp/remove_test.go (3)
845-849: Fix stdout redirection: using fd 0 (stdin) is wrong; open /dev/null for write.
os.NewFile(0, os.DevNull)targets fd 0 and doesn’t open the path; writes may fail subtly. Openos.DevNullwith O_WRONLY and assign that toos.Stdout.Apply:
- // Capture stdout to avoid noise in tests - oldStdout := os.Stdout - os.Stdout = os.NewFile(0, os.DevNull) - defer func() { os.Stdout = oldStdout }() + // Capture stdout to avoid noise in tests + oldStdout := os.Stdout + devNull, _ := os.OpenFile(os.DevNull, os.O_WRONLY, 0) + defer devNull.Close() + os.Stdout = devNull + defer func() { os.Stdout = oldStdout }()
790-818: Improve mock result sequencing across multiple commands in a single Execute call.Current logic returns the same
m.results[m.callCount]for every command in the batch. If production ever batches >1 command per call, results won’t map 1:1. Safer to advance per-command.Apply:
func (m *mockRemoveCommandExecutor) Execute(commands []command.Command) (*command.ExecutionResult, error) { // Accumulate all commands instead of overwriting m.executedCommands = append(m.executedCommands, commands...) if m.shouldFail && m.callCount > 0 { errorMsg := m.errorMsg if errorMsg == "" { errorMsg = "mock error" } return nil, &mockRemoveError{message: errorMsg} } - results := make([]command.Result, len(commands)) - for i, cmd := range commands { - if m.callCount < len(m.results) { - results[i] = m.results[m.callCount] - results[i].Command = cmd - } else { - results[i] = command.Result{ - Command: cmd, - Output: "", - Error: nil, - } - } - } + results := make([]command.Result, len(commands)) + for i, cmd := range commands { + idx := m.callCount + i + if idx < len(m.results) { + results[i] = m.results[idx] + results[i].Command = cmd + } else { + results[i] = command.Result{Command: cmd} + } + } - m.callCount++ + m.callCount += len(commands) return &command.ExecutionResult{Results: results}, nil }
121-124: This subtest doesn’t validate anything. Either assert real behavior or drop it.It only asserts
true. Consider validating that--force-branchwithout--branchis either rejected or no-ops with a user-facing hint, depending on your intended UX.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
cmd/wtp/remove.go(3 hunks)cmd/wtp/remove_test.go(3 hunks)internal/errors/errors.go(1 hunks)internal/errors/errors_test.go(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- cmd/wtp/remove.go
🧰 Additional context used
📓 Path-based instructions (4)
**/*.go
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.go: Use gofmt and goimports for all Go code formatting
Follow lint rules (vet, staticcheck, gosec, lll=120, avoid ignored errors)
Keep functions focused and small; use Go idioms
Use short, lowercase package names
Files:
internal/errors/errors.gointernal/errors/errors_test.gocmd/wtp/remove_test.go
**/*_test.go
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Write tests as table-driven tests and name test files with *_test.go
Files:
internal/errors/errors_test.gocmd/wtp/remove_test.go
cmd/wtp/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Update command help text when adding new features.
Files:
cmd/wtp/remove_test.go
cmd/wtp/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Keep CLI UX consistent with README examples and autocompletion behavior
Files:
cmd/wtp/remove_test.go
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
PR: satococoa/wtp#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-11T13:56:29.054Z
Learning: Applies to cmd/wtp/** : Keep CLI UX consistent with README examples and autocompletion behavior
📚 Learning: 2025-07-24T14:15:20.744Z
Learnt from: CR
PR: satococoa/wtp#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-24T14:15:20.744Z
Learning: Applies to cmd/wtp/completion.go : The getWorktreeNameFromPath() function in cmd/wtp/completion.go must implement worktree naming logic: return '@' for main worktree, relative path from base_dir for non-main worktrees, and fall back to directory name if path calculation fails.
Applied to files:
internal/errors/errors.gointernal/errors/errors_test.gocmd/wtp/remove_test.go
📚 Learning: 2025-07-24T14:15:20.744Z
Learnt from: CR
PR: satococoa/wtp#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-24T14:15:20.744Z
Learning: Applies to cmd/wtp/*.go : Update command help text when adding new features.
Applied to files:
cmd/wtp/remove_test.go
🧬 Code graph analysis (2)
internal/errors/errors_test.go (1)
internal/errors/errors.go (1)
WorktreeNameRequiredForRemove(59-71)
cmd/wtp/remove_test.go (1)
cmd/wtp/testhelpers_test.go (2)
RunNameFromPathTests(42-68)RunWriterCommonTests(18-38)
🔇 Additional comments (1)
cmd/wtp/remove_test.go (1)
830-836: Nice reuse of shared helpers for name/path and writer safety.Keeps behavior consistent across commands and reduces duplication.
| name: "no worktree name", | ||
| args: []string{}, | ||
| expectedError: "branch name is required", | ||
| expectedError: "worktree name is required", | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Good: error message expectation matches new helper.
Run to ensure no remaining tests still expect --with-branch:
🏁 Script executed:
#!/bin/bash
rg -n "\bwith-branch\b" --type=go -C1Length of output: 1594
Remove remaining --with-branch references and update tests
rg shows live references; remove or update all --with-branch occurrences (help text, flag definition, and tests) in: cmd/wtp/remove.go, cmd/wtp/remove_test.go, internal/errors/errors.go, internal/errors/errors_test.go. Re-run rg -n '\bwith-branch\b' --type=go to confirm no hits.
🤖 Prompt for AI Agents
In cmd/wtp/remove_test.go around lines 307 to 310 and across cmd/wtp/remove.go,
internal/errors/errors.go, internal/errors/errors_test.go, there are leftover
references to the deprecated "--with-branch" flag; update code and tests to
remove or replace all occurrences. Remove the flag definition and any help text
mentioning "--with-branch" from cmd/wtp/remove.go, update tests in
cmd/wtp/remove_test.go and internal/errors/errors_test.go to no longer expect or
assert on that flag or its error messages, and update internal/errors/errors.go
to remove any related error constants/messages; after changes run rg -n
'\bwith-branch\b' --type=go to confirm zero hits and adjust assertions/messages
in tests to the current flag behavior.
| func TestWorktreeNameRequiredForRemove(t *testing.T) { | ||
| err := WorktreeNameRequiredForRemove() | ||
|
|
||
| assert.Error(t, err) | ||
| assert.Contains(t, err.Error(), "worktree name is required") | ||
| assert.Contains(t, err.Error(), "wtp remove") | ||
| assert.Contains(t, err.Error(), "wtp remove --with-branch") | ||
| assert.Contains(t, err.Error(), "wtp list") | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep tests in sync with CLI: expect --branch (not --with-branch).
The product flags are --branch / --force-branch. Update the assertion string accordingly.
Apply:
func TestWorktreeNameRequiredForRemove(t *testing.T) {
err := WorktreeNameRequiredForRemove()
assert.Error(t, err)
assert.Contains(t, err.Error(), "worktree name is required")
assert.Contains(t, err.Error(), "wtp remove")
- assert.Contains(t, err.Error(), "wtp remove --with-branch")
+ assert.Contains(t, err.Error(), "wtp remove --branch")
assert.Contains(t, err.Error(), "wtp list")
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func TestWorktreeNameRequiredForRemove(t *testing.T) { | |
| err := WorktreeNameRequiredForRemove() | |
| assert.Error(t, err) | |
| assert.Contains(t, err.Error(), "worktree name is required") | |
| assert.Contains(t, err.Error(), "wtp remove") | |
| assert.Contains(t, err.Error(), "wtp remove --with-branch") | |
| assert.Contains(t, err.Error(), "wtp list") | |
| } | |
| func TestWorktreeNameRequiredForRemove(t *testing.T) { | |
| err := WorktreeNameRequiredForRemove() | |
| assert.Error(t, err) | |
| assert.Contains(t, err.Error(), "worktree name is required") | |
| assert.Contains(t, err.Error(), "wtp remove") | |
| assert.Contains(t, err.Error(), "wtp remove --branch") | |
| assert.Contains(t, err.Error(), "wtp list") | |
| } |
🤖 Prompt for AI Agents
internal/errors/errors_test.go around lines 91 to 99: the test asserts the CLI
help text contains "wtp remove --with-branch" but the actual product flag is
"--branch" (and companion flag is "--force-branch"); update the assertion to
expect "wtp remove --branch" (and if desired also add an assertion for "wtp
remove --force-branch") so the test matches the current CLI flags.
| func WorktreeNameRequiredForRemove() error { | ||
| msg := `worktree name is required | ||
| Usage: wtp remove <worktree-name> | ||
| Examples: | ||
| • wtp remove feature/auth | ||
| • wtp remove --with-branch feature/auth | ||
| • wtp remove --force feature/auth | ||
| Tip: Run 'wtp list' to see available worktrees` | ||
| return errors.New(msg) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align remove examples with actual flag names (--branch, --force-branch).
The error text shows --with-branch, but the CLI tests and command flags use --branch and --force-branch. This mismatch will confuse users and breaks the “CLI UX consistent with README” guideline.
Apply:
func WorktreeNameRequiredForRemove() error {
- msg := `worktree name is required
+ msg := `worktree name is required
Usage: wtp remove <worktree-name>
Examples:
- • wtp remove feature/auth
- • wtp remove --with-branch feature/auth
- • wtp remove --force feature/auth
+ • wtp remove feature/auth
+ • wtp remove --branch feature/auth
+ • wtp remove --force feature/auth
+ • wtp remove --branch --force-branch feature/auth
Tip: Run 'wtp list' to see available worktrees`
return errors.New(msg)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func WorktreeNameRequiredForRemove() error { | |
| msg := `worktree name is required | |
| Usage: wtp remove <worktree-name> | |
| Examples: | |
| • wtp remove feature/auth | |
| • wtp remove --with-branch feature/auth | |
| • wtp remove --force feature/auth | |
| Tip: Run 'wtp list' to see available worktrees` | |
| return errors.New(msg) | |
| } | |
| func WorktreeNameRequiredForRemove() error { | |
| msg := `worktree name is required | |
| Usage: wtp remove <worktree-name> | |
| Examples: | |
| • wtp remove feature/auth | |
| • wtp remove --branch feature/auth | |
| • wtp remove --force feature/auth | |
| • wtp remove --branch --force-branch feature/auth | |
| Tip: Run 'wtp list' to see available worktrees` | |
| return errors.New(msg) | |
| } |
🤖 Prompt for AI Agents
In internal/errors/errors.go around lines 59 to 71, the usage examples mention
the non-existent flag `--with-branch`; update the error message so examples use
the actual CLI flags `--branch` and `--force-branch` (e.g., replace
`--with-branch` with `--branch` and include an example showing `--force-branch`)
to keep the help text consistent with the command implementation and tests.
Summary
wtp hookcommand for cd shell integration onlywtp shell-initcommand combining completion and hook functionalitywtp cdto always output absolute paths without environment variable dependenciesKey Changes
wtp hookcommand: Generates shell functions for seamlesswtp cdexperiencewtp shell-initcommand: One-stop setup combining completion and hook functionalitywtp cd: Pure path output function without WTP_SHELL_INTEGRATION dependencyTest Plan
User Experience
Before: Complex environment variable setup
After: Simple one-line setup:
eval "$(wtp shell-init bash)"🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Refactor
Tests