-
Notifications
You must be signed in to change notification settings - Fork 4
fix: repair shell completion flag handling #27
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
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds an in-process shell-completion subsystem with shell-specific patches and hook delegation, implements interactive flag and argument completions (bash/fish/zsh), wires completion into app initialization, introduces BranchAlreadyExistsError with detection and tests, and applies README formatting refinements. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Shell
participant Hook as "Shell Hook (bash/zsh/fish)"
participant WTP as "wtp CLI"
participant Cfg as "configureCompletionCommand"
User->>Shell: Press TAB
Shell->>Hook: Invoke completion function
Hook-->>Hook: Inspect argv for --generate-shell-completion
alt --generate-shell-completion present
Hook->>WTP: Run wtp with --generate-shell-completion + args
else
Hook->>WTP: Run local hook/dynamic helper
end
WTP->>Cfg: Wrapped action captures stdout
Cfg-->>WTP: Patch output for target shell (bash/fish/zsh)
WTP-->>Hook: Return sanitized candidates
Hook-->>Shell: Provide completions
Shell-->>User: Show suggestions
sequenceDiagram
autonumber
participant CLI as "urfave/cli"
participant FC as "maybeCompleteFlagSuggestions"
participant CmdComp as "command-specific completion"
participant Src as "Data source (git branches/worktrees)"
CLI->>FC: Attempt flag completion (current, previous)
alt Flag candidates emitted
FC-->>CLI: Write flag candidates to writer
else
CLI->>CmdComp: Invoke (cmd *cli.Command) completion
CmdComp->>Src: Query branches/worktrees
Src-->>CmdComp: Candidates
CmdComp-->>CLI: Filter (no dups/current) and emit candidates line-by-line
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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 repairs shell completion flag handling by implementing proper flag completion support and shell script customization. The changes enhance the CLI completion system to handle flag suggestions, normalize completion arguments, and provide shell-specific completion script patches.
- Adds comprehensive flag completion functionality with proper argument parsing and filtering
- Implements shell completion script patching for bash and fish to handle argument descriptions
- Integrates completion argument normalization and flag suggestion handling into existing completion functions
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| cmd/wtp/flag_completion.go | Implements flag completion logic with argument parsing and matching |
| cmd/wtp/completion_config.go | Adds completion configuration, script patching, and argument normalization |
| cmd/wtp/main.go | Integrates completion command configuration and argument normalization |
| cmd/wtp/hook.go | Updates shell hooks to handle completion flags properly |
| cmd/wtp/remove.go | Enhances remove command completion with flag support and duplicate filtering |
| cmd/wtp/cd.go | Enhances cd command completion with flag support and duplicate filtering |
| cmd/wtp/add.go | Adds flag completion support to branch completion |
| cmd/wtp/testdata/completion/*.{sh,fish} | Provides test data for completion script validation |
| cmd/wtp/*_test.go | Adds comprehensive tests for completion functionality |
| README.md | Updates documentation for bash completion requirements |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| func flagCandidateFromOSArgs() (string, bool) { | ||
| index := slices.Index(os.Args, completionFlag) | ||
| if index <= 0 { | ||
| return "", false | ||
| } | ||
|
|
||
| candidate := os.Args[index-1] | ||
| if candidate == "--" { | ||
| if index >= sentinelArgOffset { | ||
| candidate = os.Args[index-2] | ||
| } else { | ||
| return "", false | ||
| } | ||
| } | ||
|
|
||
| return candidate, candidate != "" | ||
| } |
Copilot
AI
Oct 14, 2025
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.
Potential array bounds issue when accessing os.Args[index-2]. The function checks if index >= sentinelArgOffset (which is 2) but doesn't verify that index-2 is within the bounds of os.Args. This could cause a panic if os.Args has fewer elements than expected.
| } | ||
| ` | ||
|
|
||
| script = strings.Replace(script, "__wtp_bash_autocomplete() {", helper+"\n__wtp_bash_autocomplete() {", 1) |
Copilot
AI
Oct 14, 2025
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.
The string replacement approach for patching bash completion scripts is fragile and could break if the function signature changes. Consider using a more robust method like regex patterns or structured parsing to locate and modify the target function.
| return | ||
| } | ||
|
|
||
| currentNormalized := strings.TrimSuffix(current, "*") |
Copilot
AI
Oct 14, 2025
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.
The asterisk trimming logic is duplicated across multiple functions. Consider extracting this into a shared utility function like normalizeCompletionArg(arg string) string to reduce code duplication and ensure consistent behavior.
| if arg == "" || strings.HasPrefix(arg, "-") { | ||
| continue | ||
| } | ||
| key := strings.TrimSuffix(arg, "*") |
Copilot
AI
Oct 14, 2025
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.
The asterisk trimming logic is duplicated across multiple functions. Consider extracting this into a shared utility function like normalizeCompletionArg(arg string) string to reduce code duplication and ensure consistent behavior.
| if _, exists := used[name]; exists { | ||
| continue | ||
| } | ||
| if currentNormalized != "" && name == currentNormalized { |
Copilot
AI
Oct 14, 2025
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.
The asterisk trimming logic is duplicated across multiple functions. Consider extracting this into a shared utility function like normalizeCompletionArg(arg string) string to reduce code duplication and ensure consistent behavior.
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.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting
| func maybeCompleteFlagSuggestions(cmd *cli.Command, current string, previous []string) bool { | ||
| currentNormalized := strings.TrimSuffix(current, "*") | ||
| if tryFlagCompletion(cmd, currentNormalized) { | ||
| return true | ||
| } | ||
|
|
||
| if currentNormalized == "" && len(previous) > 0 { | ||
| last := strings.TrimSuffix(previous[len(previous)-1], "*") | ||
| if tryFlagCompletion(cmd, last) { | ||
| return true |
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.
Stop flag completion from blocking positional suggestions
When maybeCompleteFlagSuggestions runs with no current token it immediately reuses the last argument as a flag candidate (tryFlagCompletion(cmd, last)), so the completion routines for remove and cd exit after printing flag names even when the user has finished typing that flag. For example, wtp remove --force <TAB> now produces flag suggestions again and never reaches the worktree list, making it impossible to complete positional arguments after any flag. The helper should only treat previous as a flag when the cursor is still within that token, not after a trailing space.
Useful? React with 👍 / 👎.
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.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting
| func maybeCompleteFlagSuggestions(cmd *cli.Command, current string, previous []string) bool { | ||
| currentNormalized := strings.TrimSuffix(current, "*") | ||
| if tryFlagCompletion(cmd, currentNormalized) { | ||
| return true | ||
| } | ||
|
|
||
| if currentNormalized == "" && len(previous) > 0 { | ||
| last := strings.TrimSuffix(previous[len(previous)-1], "*") | ||
| if tryFlagCompletion(cmd, last) { | ||
| return true |
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.
Stop flag completion from blocking positional suggestions
When maybeCompleteFlagSuggestions runs with no current token it immediately reuses the last argument as a flag candidate (tryFlagCompletion(cmd, last)), so the completion routines for remove and cd exit after printing flag names even when the user has finished typing that flag. For example, wtp remove --force <TAB> now produces flag suggestions again and never reaches the worktree list, making it impossible to complete positional arguments after any flag. The helper should only treat previous as a flag when the cursor is still within that token, not after a trailing space.
Useful? React with 👍 / 👎.
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
🧹 Nitpick comments (13)
cmd/wtp/add.go (1)
398-403: Filter suggestions by current prefixCurrently prints all branches. Filter by the typed prefix to avoid overwhelming candidates and to align with other completions.
func completeBranches(_ context.Context, cmd *cli.Command) { - current, previous := completionArgsFromCommand(cmd) + current, previous := completionArgsFromCommand(cmd) if maybeCompleteFlagSuggestions(cmd, current, previous) { return } + + prefix := strings.TrimSuffix(current, "*") var buf bytes.Buffer if err := getBranches(&buf); err != nil { return } // Output each line using fmt.Println for urfave/cli compatibility scanner := bufio.NewScanner(&buf) for scanner.Scan() { - fmt.Println(scanner.Text()) + line := scanner.Text() + if prefix != "" && !strings.HasPrefix(line, prefix) { + continue + } + fmt.Println(line) } }Also applies to: 410-414
README.md (1)
255-258: Docs LGTM; optional copyedits for clarityNice update. Optional tightening:
- “No rc edits needed” → “No RC edits needed.”
- “Need to refresh inside an existing shell?” → “To refresh in the current shell, run:”
- Bash note: “Homebrew’s Bash 5.x” → “Homebrew Bash 5.x”
- “You can use it in two ways:” → “Use it in either of two ways:”
- “go install users” → “go-install users”
No functional changes needed. As per coding guidelines.
Also applies to: 260-261, 279-283, 288-290, 303-307, 323-326
cmd/wtp/cd.go (1)
358-370: Add prefix filtering to completion outputYou compute currentNormalized but don’t filter by it. Limit candidates to those starting with the prefix.
func completeWorktreesForCd(_ context.Context, cmd *cli.Command) { current, previous := completionArgsFromCommand(cmd) if maybeCompleteFlagSuggestions(cmd, current, previous) { return } currentNormalized := strings.TrimSuffix(current, "*") if currentNormalized == "" && len(previous) > 0 { return } @@ scanner := bufio.NewScanner(&buf) for scanner.Scan() { raw := scanner.Text() candidate := strings.TrimSuffix(raw, "*") if candidate == "" { continue } + if currentNormalized != "" && !strings.HasPrefix(candidate, currentNormalized) { + continue + } + if _, exists := used[candidate]; exists { continue } if currentNormalized != "" && candidate == currentNormalized { continue } fmt.Println(candidate) } }Also applies to: 388-404
cmd/wtp/testdata/completion/bash_input.sh (1)
14-14: Minor shellcheck nits in fixture (safe to ignore if mirroring upstream)
- Line 14: base is unused (SC2034).
- Line 29: COMPREPLY=($(...)) warns about word splitting (SC2207).
If this file intentionally mirrors upstream input for patching tests, keep as-is. If it ships to users, remove base and consider mapfile/read -a to populate COMPREPLY safely.
Also applies to: 29-29
cmd/wtp/flag_completion_test.go (2)
12-33: Flag completion (long flag) test is solidCovers matching and excludes --generate-shell-completion from output. Consider t.Parallel() for faster suite runs.
35-56: Broaden assertions for single-hyphen caseTest is good. Optionally:
- Add t.Parallel().
- Assert that short alias "-f" or "--force" is present explicitly.
- Also assert exclusion of --generate-shell-completion here for symmetry.
cmd/wtp/testdata/completion/fish_expected.fish (1)
25-41: Fixture looks correctThe dynamic completion helper is fine as an expected artifact. If you see noisy stderr from wtp during completion, consider redirecting stderr in the helper in future iterations, but no change needed for this expected file.
cmd/wtp/completion_config.go (2)
20-44: Restore c.Writer with defer to avoid leaks on early returns/panicsUse a defer to guarantee writer restoration instead of duplicating assignments on both paths.
func configureCompletionCommand(cmd *cli.Command) { @@ cmd.Action = func(ctx context.Context, c *cli.Command) error { writer := c.Writer if writer == nil { writer = os.Stdout } var buf bytes.Buffer c.Writer = &buf + defer func() { c.Writer = writer }() - if err := originalAction(ctx, c); err != nil { - c.Writer = writer - return err - } - - c.Writer = writer + if err := originalAction(ctx, c); err != nil { + return err + } @@ script := patchCompletionScript(shell, buf.String()) _, err := writer.Write([]byte(script)) return err } }
130-136: Quote ${cur} and consider a more robust patch to future-proof against urfave/cli changes
- Quote the compgen arg to avoid word-splitting/globbing (and to satisfy ShellCheck).
- The target match is an exact multi-line string; consider a fallback that patches when indentation or whitespace differs.
-const replacement = " opts=$(eval \"${requestComp}\" 2>/dev/null)\n" + - " opts=$(_wtp_sanitize_completion_list <<<\"${opts}\")\n" + - " COMPREPLY=($(compgen -W \"${opts}\" -- ${cur}))" +const replacement = " opts=$(eval \"${requestComp}\" 2>/dev/null)\n" + + " opts=$(_wtp_sanitize_completion_list <<<\"${opts}\")\n" + + " COMPREPLY=($(compgen -W \"${opts}\" -- \"${cur}\"))"Optional hardening (if target isn’t found): search for the COMPREPLY line by prefix and replace that line only; or use a small regexp. This will make the patch resilient to minor upstream template tweaks. [Chill mode]
cmd/wtp/flag_completion.go (2)
101-107: Optional: simpler hyphen ruleCurrent logic prefixes up to two hyphens based on name length. If you prefer an explicit rule, use 1 hyphen for single-rune names, else 2. Behavior is equivalent for most cases; readability only.
if utf8.RuneCountInString(name) == 1 { return "-" + name } return "--" + name
136-152: go.mod Go version meets slices.Index requirement; optional hyphen rule simplification
- go.mod declares Go 1.24.4, so using slices.Index (Go 1.21+) is valid.
- Optional: simplify flag prefix logic by using “-” for single-rune flags and “--” for longer flags.
cmd/wtp/completion_config_test.go (1)
11-40: Consider tests for completionArgsFromCommand and filterCompletionArgsNice coverage. Add small table-driven tests for:
- completionArgsFromCommand: empty args, only completion flag, several args with completion flag removed.
- filterCompletionArgs: ensure only the completion flag is filtered.
Also applies to: 82-103, 115-137
cmd/wtp/testdata/completion/bash_expected.sh (1)
28-49: Silence ShellCheck warnings: quote ${cur}; drop unused 'base'Optional improvements (will require aligning patch or input template):
- Quote ${cur} in compgen.
- Remove unused local ‘base’.
- local cur opts base words + local cur opts words @@ - COMPREPLY=($(compgen -W "${opts}" -- ${cur})) + COMPREPLY=($(compgen -W "${opts}" -- "${cur}"))If you adopt the quoted ${cur}, also adjust patchBashCompletionScript replacement to emit the quoted form so tests stay green. Based on static analysis hints.
Also applies to: 45-47
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
README.md(6 hunks)cmd/wtp/add.go(1 hunks)cmd/wtp/cd.go(1 hunks)cmd/wtp/completion_config.go(1 hunks)cmd/wtp/completion_config_test.go(1 hunks)cmd/wtp/flag_completion.go(1 hunks)cmd/wtp/flag_completion_test.go(1 hunks)cmd/wtp/hook.go(3 hunks)cmd/wtp/main.go(2 hunks)cmd/wtp/main_test.go(1 hunks)cmd/wtp/remove.go(1 hunks)cmd/wtp/testdata/completion/bash_expected.sh(1 hunks)cmd/wtp/testdata/completion/bash_input.sh(1 hunks)cmd/wtp/testdata/completion/fish_expected.fish(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
cmd/wtp/**
📄 CodeRabbit inference engine (AGENTS.md)
cmd/wtp/**: CLI entrypoint and commands are implemented under cmd/wtp
Update CLI help text to reflect user-facing changes
Command behavior: wtp cd prints only the absolute worktree path with no side effects
Command behavior: wtp completion generates pure completion scripts via urfave/cli
Command behavior: wtp hook emits shell functions that intercept wtp cd; wtp shell-init combines completion and hook output
Files:
cmd/wtp/testdata/completion/fish_expected.fishcmd/wtp/cd.gocmd/wtp/hook.gocmd/wtp/flag_completion.gocmd/wtp/remove.gocmd/wtp/main_test.gocmd/wtp/completion_config_test.gocmd/wtp/testdata/completion/bash_expected.shcmd/wtp/flag_completion_test.gocmd/wtp/testdata/completion/bash_input.shcmd/wtp/add.gocmd/wtp/completion_config.gocmd/wtp/main.go
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Run gofmt and goimports; keep imports grouped and organized; local import prefix follows module path github.com/satococoa/wtp
Adhere to golangci-lint rules configured for the project (vet, staticcheck, gosec, mnd, lll=120, etc.)
Errors should be wrapped with context and must not be ignored
Use snake_case for Go filenames; document exported identifiers when non-trivial
Files:
cmd/wtp/cd.gocmd/wtp/hook.gocmd/wtp/flag_completion.gocmd/wtp/remove.gocmd/wtp/main_test.gocmd/wtp/completion_config_test.gocmd/wtp/flag_completion_test.gocmd/wtp/add.gocmd/wtp/completion_config.gocmd/wtp/main.go
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Unit tests live alongside packages and use *_test.go naming
Prefer table-driven tests and mock git operations in unit tests
Files:
cmd/wtp/main_test.gocmd/wtp/completion_config_test.gocmd/wtp/flag_completion_test.go
README.md
📄 CodeRabbit inference engine (AGENTS.md)
Update README when user-facing behavior changes
Files:
README.md
🧠 Learnings (6)
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : Command behavior: wtp completion <shell> generates pure completion scripts via urfave/cli
Applied to files:
cmd/wtp/testdata/completion/fish_expected.fishcmd/wtp/hook.gocmd/wtp/remove.goREADME.mdcmd/wtp/testdata/completion/bash_expected.shcmd/wtp/testdata/completion/bash_input.shcmd/wtp/completion_config.go
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : Command behavior: wtp hook <shell> emits shell functions that intercept wtp cd; wtp shell-init <shell> combines completion and hook output
Applied to files:
cmd/wtp/testdata/completion/fish_expected.fishcmd/wtp/hook.goREADME.mdcmd/wtp/testdata/completion/bash_expected.shcmd/wtp/testdata/completion/bash_input.sh
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/completion.go : Use getWorktreeNameFromPath() to resolve worktree display names consistently across completion, errors, and parsing
Applied to files:
cmd/wtp/cd.gocmd/wtp/remove.go
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to README.md : Update README when user-facing behavior changes
Applied to files:
README.md
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : Command behavior: wtp cd prints only the absolute worktree path with no side effects
Applied to files:
README.md
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : CLI entrypoint and commands are implemented under cmd/wtp
Applied to files:
cmd/wtp/main.go
🪛 LanguageTool
README.md
[grammar] ~70-~70: There might be a mistake here.
Context: ... - Bash (4+/5.x) with bash-completion v2 - Zsh - Fish ## Releases View all rele...
(QB_NEW_EN)
[grammar] ~256-~256: There might be a mistake here.
Context: ...you press TAB after typing wtp. That lazy call gives you both tab completion ...
(QB_NEW_EN)
[grammar] ~257-~257: There might be a mistake here.
Context: ...ion and the wtp cd integration for the rest of the session—no rc edits needed. ...
(QB_NEW_EN)
[grammar] ~260-~260: There might be a mistake here.
Context: ...shell? Just run wtp shell-init <shell> yourself. #### If installed via go inst...
(QB_NEW_EN)
[grammar] ~265-~265: There might be a mistake here.
Context: ...ation file to enable both completion and shell integration: ```bash # Bash: Add ...
(QB_NEW_EN)
[grammar] ~279-~279: There might be a mistake here.
Context: ...es bash-completion v2. On macOS, install > Homebrew’s Bash 5.x and `bash-completi...
(QB_NEW_EN)
[grammar] ~280-~280: There might be a mistake here.
Context: ...s Bash 5.x and bash-completion@2, then > `source /opt/homebrew/etc/profile.d/ba...
(QB_NEW_EN)
[grammar] ~281-~281: There might be a mistake here.
Context: ...d/bash_completion.sh` (or the path shown > after installation) before enabling th...
(QB_NEW_EN)
[grammar] ~288-~288: There might be a mistake here.
Context: ...te path to a worktree. You can use it in two ways: #### Direct Usage ```bash # ...
(QB_NEW_EN)
[grammar] ~303-~303: There might be a mistake here.
Context: ...the shell hook. wtp shell-init <shell> already bundles it, so Homebrew users ge...
(QB_NEW_EN)
[grammar] ~304-~304: There might be a mistake here.
Context: ...et the hook automatically and go install users get it from the one-liner above. I...
(QB_NEW_EN)
[grammar] ~305-~305: There might be a mistake here.
Context: ...above. If you only want the hook without completions, you can still run `wtp hook...
(QB_NEW_EN)
[grammar] ~323-~323: There might be a mistake here.
Context: ...r. Press TAB after typing wtp and it evaluates wtp shell-init <shell> once ...
(QB_NEW_EN)
[grammar] ~324-~324: There might be a mistake here.
Context: ...once for your session—tab completion and wtp cd just work. ## Worktree Structu...
(QB_NEW_EN)
🪛 Shellcheck (0.11.0)
cmd/wtp/testdata/completion/bash_expected.sh
[warning] 30-30: base appears unused. Verify use (or export if used externally).
(SC2034)
[warning] 46-46: Prefer mapfile or read -a to split command output (or quote to avoid splitting).
(SC2207)
cmd/wtp/testdata/completion/bash_input.sh
[warning] 14-14: base appears unused. Verify use (or export if used externally).
(SC2034)
[warning] 29-29: Prefer mapfile or read -a to split command output (or quote to avoid splitting).
(SC2207)
🔇 Additional comments (4)
cmd/wtp/main_test.go (1)
131-134: Test wiring for completion config looks correctAsserting ConfigureShellCompletionCommand via createApp is appropriate with v3. LGTM.
cmd/wtp/hook.go (1)
76-81: Correctly delegates completion generation from hooksEarly-return delegation on --generate-shell-completion is correct and prevents hook logic from interfering. LGTM.
Also applies to: 103-108, 130-135
cmd/wtp/main.go (1)
24-26: Shell completion wiring + argv normalization look goodEnableShellCompletion and ConfigureShellCompletionCommand are wired correctly; passing normalized args into Run is appropriate. Please just verify normalizeCompletionArgs preserves argv[0] (program name) in non-completion paths to avoid breaking command parsing.
Also applies to: 45-46
cmd/wtp/completion_config.go (1)
58-104: Fish dynamic completion script looks solidUses commandline to build args, sanitizes description suffixes, and registers a single dynamic complete. LGTM.
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: 0
♻️ Duplicate comments (1)
cmd/wtp/completion_config.go (1)
106-137: Make bash patch resilient; also quote ${cur}The exact strings.Replace against a fixed block is brittle across upstream cli changes. Add a regex-based fallback and ensure we always inject the sanitizer before COMPREPLY. Also quote ${cur} to avoid word-splitting.
Apply this diff:
@@ -import ( +import ( "bytes" "context" "os" "strings" "github.com/urfave/cli/v3" + "regexp" ) @@ func patchBashCompletionScript(script string) string { if strings.Contains(script, "_wtp_sanitize_completion_list") { return script } @@ - script = strings.Replace(script, "__wtp_bash_autocomplete() {", helper+"\n__wtp_bash_autocomplete() {", 1) + script = strings.Replace(script, "__wtp_bash_autocomplete() {", helper+"\n__wtp_bash_autocomplete() {", 1) - const target = " opts=$(eval \"${requestComp}\" 2>/dev/null)\n COMPREPLY=($(compgen -W \"${opts}\" -- ${cur}))" - const replacement = " opts=$(WTP_SHELL_COMPLETION=1 eval \"${requestComp}\" 2>/dev/null)\n" + - " opts=$(_wtp_sanitize_completion_list <<<\"${opts}\")\n" + - " COMPREPLY=($(compgen -W \"${opts}\" -- ${cur}))" + const target = " opts=$(eval \"${requestComp}\" 2>/dev/null)\n COMPREPLY=($(compgen -W \"${opts}\" -- ${cur}))" + const replacement = " opts=$(WTP_SHELL_COMPLETION=1 eval \"${requestComp}\" 2>/dev/null)\n" + + " opts=$(_wtp_sanitize_completion_list <<<\"${opts}\")\n" + + " COMPREPLY=($(compgen -W \"${opts}\" -- \"${cur}\"))" - script = strings.Replace(script, target, replacement, 1) + // Try exact block replace first + replaced := strings.Replace(script, target, replacement, 1) + if replaced != script { + return replaced + } + + // Fallback: regex-driven patching (handles whitespace/indent changes) + // 1) Prefix WTP_SHELL_COMPLETION=1 to the opts eval line. + reOpts := regexp.MustCompile(`(?m)^(\s*)opts=\$\(\s*eval\s+("?\$\{requestComp\}"?\s*)2>/dev/null\)\s*$`) + replaced = reOpts.ReplaceAllString(script, `${1}opts=$(WTP_SHELL_COMPLETION=1 eval ${2}2>/dev/null)`) + + // 2) Ensure sanitizer runs immediately before COMPREPLY assignment. + reReply := regexp.MustCompile(`(?m)^(\s*)COMPREPLY=\(\$\(compgen -W\s+"?\$\{opts\}"?\s+--\s+("?)(\$\{?cur\}?)(\2)\)\)\s*$`) + replaced = reReply.ReplaceAllString(replaced, `${1}opts=$(_wtp_sanitize_completion_list <<<"${opts}")`+"\n"+`${0}`) + + return replaced }
🧹 Nitpick comments (5)
cmd/wtp/completion_config.go (3)
58-104: Harden fish output emission (avoid globbing/splitting); use printfecho can glob/split in fish. Prefer printf to emit candidates verbatim.
Apply this diff:
- echo $parts[1] + printf "%s\n" -- $parts[1] ... - echo $line + printf "%s\n" -- $line
130-134: Quote ${cur} in compgenPrevents accidental word-splitting/globbing on current token.
Apply this diff:
- " COMPREPLY=($(compgen -W \"${opts}\" -- ${cur}))" + " COMPREPLY=($(compgen -W \"${opts}\" -- \"${cur}\"))"
20-44: Slight cleanup: defer writer restoreUse defer to guarantee restoration on early returns and reduce repetition.
Apply this diff:
cmd.Action = func(ctx context.Context, c *cli.Command) error { writer := c.Writer if writer == nil { writer = os.Stdout } var buf bytes.Buffer c.Writer = &buf + defer func() { c.Writer = writer }() - if err := originalAction(ctx, c); err != nil { - c.Writer = writer - return err - } - - c.Writer = writer + if err := originalAction(ctx, c); err != nil { + return err + }cmd/wtp/testdata/completion/bash_expected.sh (2)
30-30: Remove unused localbase is unused. Drop it to satisfy shellcheck (SC2034).
Apply this diff:
- local cur opts base words + local cur opts words
46-46: Quote ${cur} in compgenAvoids word-splitting/globbing on the current token.
Apply this diff:
- COMPREPLY=($(compgen -W "${opts}" -- ${cur})) + COMPREPLY=($(compgen -W "${opts}" -- "${cur}"))
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
cmd/wtp/add.go(4 hunks)cmd/wtp/add_test.go(2 hunks)cmd/wtp/completion_config.go(1 hunks)cmd/wtp/completion_config_test.go(1 hunks)cmd/wtp/testdata/completion/bash_expected.sh(1 hunks)cmd/wtp/testdata/completion/fish_expected.fish(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- cmd/wtp/testdata/completion/fish_expected.fish
- cmd/wtp/completion_config_test.go
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Run gofmt and goimports; keep imports grouped and organized; local import prefix follows module path github.com/satococoa/wtp
Adhere to golangci-lint rules configured for the project (vet, staticcheck, gosec, mnd, lll=120, etc.)
Errors should be wrapped with context and must not be ignored
Use snake_case for Go filenames; document exported identifiers when non-trivial
Files:
cmd/wtp/add_test.gocmd/wtp/completion_config.gocmd/wtp/add.go
cmd/wtp/**
📄 CodeRabbit inference engine (AGENTS.md)
cmd/wtp/**: CLI entrypoint and commands are implemented under cmd/wtp
Update CLI help text to reflect user-facing changes
Command behavior: wtp cd prints only the absolute worktree path with no side effects
Command behavior: wtp completion generates pure completion scripts via urfave/cli
Command behavior: wtp hook emits shell functions that intercept wtp cd; wtp shell-init combines completion and hook output
Files:
cmd/wtp/add_test.gocmd/wtp/completion_config.gocmd/wtp/add.gocmd/wtp/testdata/completion/bash_expected.sh
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Unit tests live alongside packages and use *_test.go naming
Prefer table-driven tests and mock git operations in unit tests
Files:
cmd/wtp/add_test.go
🧠 Learnings (2)
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : Command behavior: wtp completion <shell> generates pure completion scripts via urfave/cli
Applied to files:
cmd/wtp/completion_config.gocmd/wtp/testdata/completion/bash_expected.sh
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : Command behavior: wtp hook <shell> emits shell functions that intercept wtp cd; wtp shell-init <shell> combines completion and hook output
Applied to files:
cmd/wtp/testdata/completion/bash_expected.sh
🧬 Code graph analysis (1)
cmd/wtp/add_test.go (1)
cmd/wtp/add.go (1)
BranchAlreadyExistsError(279-282)
🪛 Shellcheck (0.11.0)
cmd/wtp/testdata/completion/bash_expected.sh
[warning] 30-30: base appears unused. Verify use (or export if used externally).
(SC2034)
[warning] 46-46: Prefer mapfile or read -a to split command output (or quote to avoid splitting).
(SC2207)
⏰ 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). (1)
- GitHub Check: Build
🔇 Additional comments (10)
cmd/wtp/add.go (4)
174-179: LGTM! Proper integration of the new error type.The branch-already-exists check is correctly integrated into the error analysis flow, following the same pattern as other error types (WorktreeAlreadyExistsError, PathAlreadyExistsError).
237-240: Helper function logic is sound.The dual-string check (
"branch"AND"already exists") is appropriately specific for Git's error messages while remaining robust across Git versions.
279-295: Well-structured error type with clear guidance.The error message provides actionable solutions that guide users through common scenarios:
- Creating a worktree for the existing branch (without
-b)- Choosing a different branch name
- Deleting the existing branch if appropriate
The implementation follows the same pattern as other custom error types in this file.
428-444: Completion function properly updated for urfave/cli v3.The changes align with the PR's shell completion improvements:
- Updated signature matches urfave/cli v3
ShellCompleteexpectations- Early-exit via
maybeCompleteFlagSuggestionshandles flag completions before branch suggestions- Line-by-line output using
fmt.Printlnimproves compatibility with shell completion systemsBased on learnings about urfave/cli v3.
cmd/wtp/add_test.go (2)
82-116: Comprehensive test coverage for the new error type.The test validates:
- Error message formatting with branch name and guidance
- All three suggested solutions are present
- Original error is included
- Edge case handling (empty branch name)
Follows the same testing pattern as other error types in this file.
914-921: Test case properly extends error analysis coverage.The new test case validates that
analyzeGitWorktreeErrorcorrectly identifies branch-already-exists errors from Git's output and returns the appropriate error type.cmd/wtp/completion_config.go (2)
49-53: Confirm intended deviation from “pure completions” for fishSwitching fish to a custom dynamic script (not the urfave/cli-generated one) deviates from the “pure completion scripts via urfave/cli” guidance. If this is intentional, please update the guideline/docs accordingly; otherwise consider keeping urfave/cli’s generator and layering dynamic calls within its hook points.
Based on learnings
139-159: Args normalization looks goodLogic to preserve the completion flag in shell-completion context is clear and safe.
cmd/wtp/testdata/completion/bash_expected.sh (2)
14-26: Sanitizer function is solidThe colon-suffix stripping with space check matches the bash behavior you want; no issues spotted.
33-44: Mac bash3 fallback is pragmatic; ensure README notes _get_comp_words_by_ref__wtp_init_completion depends on _get_comp_words_by_ref existing. Confirm README clearly states the bash-completion requirement and macOS caveats.
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: 0
♻️ Duplicate comments (2)
cmd/wtp/flag_completion.go (2)
116-140: Early return prevents blocking positional suggestions.The function correctly returns
falsewhencurrentis empty (line 117-119), which allows positional argument completion to proceed. This addresses the concern raised in previous reviews about blocking positional suggestions after flags.The empty block at lines 128-129 is intentional (handles sentinel
--separator) and documented with a comment, so the static analysis warning can be safely ignored.
142-158: Bounds checks are correct.The array access is properly guarded:
- Line 144 ensures
index > 0before accessingos.Args[index-1](line 148)- Line 150 ensures
index >= sentinelArgOffset(which is 2) before accessingos.Args[index-2](line 151)Since
slices.Indexreturns a valid index when the element is found, these checks guarantee safe array access.
🧹 Nitpick comments (2)
cmd/wtp/flag_completion_test.go (2)
55-56: Tighten assertions for consistent formatting.The OR conditions are overly permissive. Based on
formatCompletion, multi-character names like "with-branch" and "force" should always receive double hyphens (--), never single hyphens. The test will pass even if the formatting is incorrect.Apply this diff to use exact assertions:
- require.True(t, strings.Contains(output, "--with-branch") || strings.Contains(output, "-with-branch")) - require.True(t, strings.Contains(output, "--force") || strings.Contains(output, "-force")) + require.Contains(t, output, "--with-branch") + require.Contains(t, output, "--force")
71-82: LGTM!The test validates that single-hyphen sentinels in the
previouslist are correctly ignored. Both test cases confirm proper handling of the sentinel pattern.Consider adding a test case for the double-hyphen sentinel (
--) to ensure complete coverage of the sentinel handling logic at line 128 offlag_completion.go:func TestMaybeCompleteFlagSuggestions_IgnoresDoubleDashSentinel(t *testing.T) { cmd := &cli.Command{ Writer: io.Discard, Flags: []cli.Flag{ &cli.BoolFlag{Name: "force"}, }, } require.False(t, maybeCompleteFlagSuggestions(cmd, "feature", []string{"--"})) require.False(t, maybeCompleteFlagSuggestions(cmd, "", []string{"--"})) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cmd/wtp/flag_completion.go(1 hunks)cmd/wtp/flag_completion_test.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Run gofmt and goimports; keep imports grouped and organized; local import prefix follows module path github.com/satococoa/wtp
Adhere to golangci-lint rules configured for the project (vet, staticcheck, gosec, mnd, lll=120, etc.)
Errors should be wrapped with context and must not be ignored
Use snake_case for Go filenames; document exported identifiers when non-trivial
Files:
cmd/wtp/flag_completion.gocmd/wtp/flag_completion_test.go
cmd/wtp/**
📄 CodeRabbit inference engine (AGENTS.md)
cmd/wtp/**: CLI entrypoint and commands are implemented under cmd/wtp
Update CLI help text to reflect user-facing changes
Command behavior: wtp cd prints only the absolute worktree path with no side effects
Command behavior: wtp completion generates pure completion scripts via urfave/cli
Command behavior: wtp hook emits shell functions that intercept wtp cd; wtp shell-init combines completion and hook output
Files:
cmd/wtp/flag_completion.gocmd/wtp/flag_completion_test.go
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Unit tests live alongside packages and use *_test.go naming
Prefer table-driven tests and mock git operations in unit tests
Files:
cmd/wtp/flag_completion_test.go
🪛 GitHub Check: Lint
cmd/wtp/flag_completion.go
[warning] 128-128:
empty-block: this block is empty, you can remove it (revive)
🔇 Additional comments (6)
cmd/wtp/flag_completion.go (4)
1-17: LGTM!The imports are appropriate for the flag completion functionality, and the constants have clear semantic meaning.
19-55: LGTM!The function correctly handles flag completion with proper validation, filtering, deduplication, and formatting. The separation of concerns with helper functions enhances readability.
57-107: LGTM!All helper functions are well-structured:
commandWriterprovides a clean fallback patternnormalizeCurrentefficiently handles input parsingisFlagVisibleuses proper interface checking for optional visibilityselectMatchingNamecorrectly filters single-char names for double-dash and excludes exact matchesformatCompletionappropriately formats flag names with hyphens
109-114: LGTM!Simple and effective wrapper for flag completion.
cmd/wtp/flag_completion_test.go (2)
13-34: LGTM!The test correctly validates prefix matching for long flags and confirms that hidden flags (like
GenerateShellCompletionFlag) are properly filtered from suggestions.
59-69: LGTM!The test correctly validates that when
currentis empty, the function returnsfalse, allowing positional argument completion to proceed. This confirms the fix for the issue raised in past reviews.
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
♻️ Duplicate comments (1)
cmd/wtp/flag_completion.go (1)
142-158: OS args backtrack is bounds-safe; optional readability tweak.Current guards prevent underflow when accessing
index-2. For clarity, invert the condition to exit early:if candidate == "-" || candidate == "--" { - if index >= sentinelArgOffset { - candidate = os.Args[index-2] - } else { - return "", false - } + if index < sentinelArgOffset { + return "", false + } + candidate = os.Args[index-2] }
🧹 Nitpick comments (1)
cmd/wtp/flag_completion.go (1)
69-75: Broaden visibility check for urfave/cli compatibility.Support both IsVisible() and Visible() to be resilient across versions.
-func isFlagVisible(flag cli.Flag) bool { - if visibility, ok := flag.(interface{ IsVisible() bool }); ok && !visibility.IsVisible() { - return false - } - return true -} +func isFlagVisible(flag cli.Flag) bool { + // urfave/cli variants expose either IsVisible() or Visible(). + if v, ok := any(flag).(interface{ IsVisible() bool }); ok { + return v.IsVisible() + } + if v, ok := any(flag).(interface{ Visible() bool }); ok { + return v.Visible() + } + return true +}Based on learnings.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cmd/wtp/flag_completion.go(1 hunks)cmd/wtp/flag_completion_test.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Run gofmt and goimports; keep imports grouped and organized; local import prefix follows module path github.com/satococoa/wtp
Adhere to golangci-lint rules configured for the project (vet, staticcheck, gosec, mnd, lll=120, etc.)
Errors should be wrapped with context and must not be ignored
Use snake_case for Go filenames; document exported identifiers when non-trivial
Files:
cmd/wtp/flag_completion.gocmd/wtp/flag_completion_test.go
cmd/wtp/**
📄 CodeRabbit inference engine (AGENTS.md)
cmd/wtp/**: CLI entrypoint and commands are implemented under cmd/wtp
Update CLI help text to reflect user-facing changes
Command behavior: wtp cd prints only the absolute worktree path with no side effects
Command behavior: wtp completion generates pure completion scripts via urfave/cli
Command behavior: wtp hook emits shell functions that intercept wtp cd; wtp shell-init combines completion and hook output
Files:
cmd/wtp/flag_completion.gocmd/wtp/flag_completion_test.go
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Unit tests live alongside packages and use *_test.go naming
Prefer table-driven tests and mock git operations in unit tests
Files:
cmd/wtp/flag_completion_test.go
🪛 GitHub Check: Lint
cmd/wtp/flag_completion.go
[warning] 128-128:
empty-block: this block is empty, you can remove it (revive)
🔇 Additional comments (2)
cmd/wtp/flag_completion_test.go (2)
14-35: Good coverage for long‑flag match and hidden completion flag.Assertions correctly ensure visible flags are suggested and
--generate-shell-completionis excluded.
85-98: OS args sentinel handling is well tested.Backtracking over
-and--to pick the real candidate is verified; cleanup ofos.Argsavoids leakage across tests.
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: 0
🧹 Nitpick comments (1)
cmd/wtp/flag_completion_test.go (1)
56-57: Tighten test assertions for multi-character flag names.The
||conditions at lines 56-57 are overly permissive. According toformatCompletion, multi-character flag names like "with-branch" always receive two hyphens ("--with-branch"), never one. The fallback branches ("-with-branch"and"-force") can never be true and may mask bugs.Use separate assertions for short-form aliases (single-char) vs long-form flags, or remove the fallback branches entirely.
Apply this diff to make assertions more precise:
output := buf.String() - require.True(t, strings.Contains(output, "--with-branch") || strings.Contains(output, "-with-branch")) - require.True(t, strings.Contains(output, "--force") || strings.Contains(output, "-force")) + require.Contains(t, output, "--with-branch", "Expected long form of multi-char flag") + // Check for either long form or short alias + require.True(t, + strings.Contains(output, "--force") || strings.Contains(output, "-f"), + "Expected either long form or short alias for force flag")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cmd/wtp/flag_completion.go(1 hunks)cmd/wtp/flag_completion_test.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Run gofmt and goimports; keep imports grouped and organized; local import prefix follows module path github.com/satococoa/wtp
Adhere to golangci-lint rules configured for the project (vet, staticcheck, gosec, mnd, lll=120, etc.)
Errors should be wrapped with context and must not be ignored
Use snake_case for Go filenames; document exported identifiers when non-trivial
Files:
cmd/wtp/flag_completion_test.gocmd/wtp/flag_completion.go
cmd/wtp/**
📄 CodeRabbit inference engine (AGENTS.md)
cmd/wtp/**: CLI entrypoint and commands are implemented under cmd/wtp
Update CLI help text to reflect user-facing changes
Command behavior: wtp cd prints only the absolute worktree path with no side effects
Command behavior: wtp completion generates pure completion scripts via urfave/cli
Command behavior: wtp hook emits shell functions that intercept wtp cd; wtp shell-init combines completion and hook output
Files:
cmd/wtp/flag_completion_test.gocmd/wtp/flag_completion.go
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Unit tests live alongside packages and use *_test.go naming
Prefer table-driven tests and mock git operations in unit tests
Files:
cmd/wtp/flag_completion_test.go
🪛 GitHub Check: Lint
cmd/wtp/flag_completion.go
[warning] 128-128:
empty-block: this block is empty, you can remove it (revive)
🔇 Additional comments (14)
cmd/wtp/flag_completion.go (10)
14-17: LGTM!Constants are well-defined and their purpose is clear from the context.
19-55: LGTM!The completion logic correctly handles nil commands, normalizes input, filters invisible flags, deduplicates suggestions, and returns a boolean indicating whether any matches were found.
57-63: LGTM!Proper fallback logic for retrieving the command writer.
65-67: LGTM!Clean normalization logic that strips hyphens and detects the double-dash form.
69-74: LGTM!Correctly uses type assertion to check the optional visibility method and defaults to visible.
76-99: LGTM!The matching logic correctly handles single-char vs multi-char flag names in double-dash contexts and avoids suggesting exact matches.
101-107: LGTM!Proper Unicode-aware formatting using
utf8.RuneCountInStringwith appropriate hyphen prefix limiting.
109-114: LGTM!Clean delegation that only attempts flag completion when the candidate starts with a hyphen.
116-140: Early return correctly addresses past review concern.The early return at lines 117-118 when
currentis empty ensures that flag completion does not block positional argument suggestions after a completed flag (e.g.,wtp remove --force <TAB>). This addresses the concern raised in previous reviews.The empty block at lines 128-130 is intentional and documented—it explicitly ignores the "--" sentinel separator. The static analysis warning can be safely ignored.
142-158: Bounds checking is correct.The function properly guards array accesses:
- Line 144 ensures
index > 0before accessingos.Args[index-1]at line 148.- Line 150 ensures
index >= 2before accessingos.Args[index-2]at line 151.The Copilot warning about potential bounds issues is a false positive.
cmd/wtp/flag_completion_test.go (4)
14-35: LGTM!The test properly verifies prefix matching and that hidden flags like
GenerateShellCompletionFlagare filtered from completion output.
60-70: LGTM!This test validates the fix for the past review concern—when
currentis empty, the function correctly ignoresprevioustokens and returns false, allowing positional completions to proceed.
72-83: LGTM!Good coverage of sentinel handling in both scenarios (non-empty and empty current).
85-98: LGTM!Proper test hygiene with
t.Cleanupand good coverage of both single-dash and double-dash sentinel handling in OS args parsing.
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: 0
♻️ Duplicate comments (1)
cmd/wtp/completion_config.go (1)
158-166: Make Bash patching resilient to upstream generator changes.Exact-match multi-line replace on requestComp/COMPREPLY is brittle if urfave/cli alters whitespace or variable names. Prefer a regex-based patch over the specific assignment+COMPREPLY block, or add a fallback when the target isn’t found.
Keeps golden tests but reduces future breakage if cli/v3 changes its bash generator.
🧹 Nitpick comments (3)
cmd/wtp/completion_config.go (2)
79-83: Simplify replace loop (fix gosimple S1017).The Contains check is unnecessary. strings.Replace with n=1 is a no-op when target is absent. This also clears the linter warning.
As per coding guidelines and static analysis hints.
- for _, r := range replacements { - if strings.Contains(script, r.target) { - script = strings.Replace(script, r.target, r.replacement, 1) - } - } + for _, r := range replacements { + script = strings.Replace(script, r.target, r.replacement, 1) + }
69-77: Bring long Zsh patterns under lll=120.The inline target/replacement literals exceed 120 chars. Split them with concatenation to satisfy lll without changing behavior.
As per coding guidelines and static analysis hints.
- replacements := []struct { - target string - replacement string - }{ - { - target: `opts=("${(@f)$(${words[@]:0:#words[@]-1} ${current} --generate-shell-completion)}")`, - replacement: `opts=("${(@f)$(env WTP_SHELL_COMPLETION=1 ${words[@]:0:#words[@]-1} ${current} --generate-shell-completion)}")`, - }, - { - target: `opts=("${(@f)$(${words[@]:0:#words[@]-1} --generate-shell-completion)}")`, - replacement: `opts=("${(@f)$(env WTP_SHELL_COMPLETION=1 ${words[@]:0:#words[@]-1} --generate-shell-completion)}")`, - }, - } + // Keep patterns within 120 columns. + zshCurrentTarget := "opts=(\"${(@f)$(" + + "${words[@]:0:#words[@]-1} ${current} --generate-shell-completion)}\")" + zshCurrentReplacement := "opts=(\"${(@f)$(env WTP_SHELL_COMPLETION=1 " + + "${words[@]:0:#words[@]-1} ${current} --generate-shell-completion)}\")" + zshSubCmdTarget := "opts=(\"${(@f)$(" + + "${words[@]:0:#words[@]-1} --generate-shell-completion)}\")" + zshSubCmdReplacement := "opts=(\"${(@f)$(env WTP_SHELL_COMPLETION=1 " + + "${words[@]:0:#words[@]-1} --generate-shell-completion)}\")" + + replacements := []struct { + target string + replacement string + }{ + {target: zshCurrentTarget, replacement: zshCurrentReplacement}, + {target: zshSubCmdTarget, replacement: zshSubCmdReplacement}, + }cmd/wtp/flag_completion.go (1)
126-133: Remove empty block and fold sentinel check.Clean up the no-op branch and satisfy revive’s empty-block warning.
As per coding guidelines and linter.
- if len(previous) > 0 { - last := strings.TrimSuffix(previous[len(previous)-1], "*") - if last == "-" || last == "--" { - // Sentinel separating flags from positionals; ignore for flag completion. - } else if last != "" && last != currentNormalized && tryFlagCompletion(cmd, last) { - return true - } - } + if len(previous) > 0 { + last := strings.TrimSuffix(previous[len(previous)-1], "*") + // Sentinel ("-" or "--") separates flags from positionals; ignore for flag completion. + if last != "-" && last != "--" && + last != "" && last != currentNormalized && + tryFlagCompletion(cmd, last) { + return true + } + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
cmd/wtp/completion_config.go(1 hunks)cmd/wtp/completion_config_test.go(1 hunks)cmd/wtp/flag_completion.go(1 hunks)cmd/wtp/flag_completion_test.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Run gofmt and goimports; keep imports grouped and organized; local import prefix follows module path github.com/satococoa/wtp
Adhere to golangci-lint rules configured for the project (vet, staticcheck, gosec, mnd, lll=120, etc.)
Errors should be wrapped with context and must not be ignored
Use snake_case for Go filenames; document exported identifiers when non-trivial
Files:
cmd/wtp/flag_completion_test.gocmd/wtp/completion_config.gocmd/wtp/completion_config_test.gocmd/wtp/flag_completion.go
cmd/wtp/**
📄 CodeRabbit inference engine (AGENTS.md)
cmd/wtp/**: CLI entrypoint and commands are implemented under cmd/wtp
Update CLI help text to reflect user-facing changes
Command behavior: wtp cd prints only the absolute worktree path with no side effects
Command behavior: wtp completion generates pure completion scripts via urfave/cli
Command behavior: wtp hook emits shell functions that intercept wtp cd; wtp shell-init combines completion and hook output
Files:
cmd/wtp/flag_completion_test.gocmd/wtp/completion_config.gocmd/wtp/completion_config_test.gocmd/wtp/flag_completion.go
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Unit tests live alongside packages and use *_test.go naming
Prefer table-driven tests and mock git operations in unit tests
Files:
cmd/wtp/flag_completion_test.gocmd/wtp/completion_config_test.go
🧠 Learnings (1)
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : Command behavior: wtp completion <shell> generates pure completion scripts via urfave/cli
Applied to files:
cmd/wtp/completion_config.go
🪛 GitHub Check: Lint
cmd/wtp/completion_config.go
[failure] 71-71:
The line is 129 characters long, which exceeds the maximum of 120 characters. (lll)
[failure] 80-80:
S1017: should replace this if statement with an unconditional strings.Replace (gosimple)
cmd/wtp/flag_completion.go
[warning] 128-128:
empty-block: this block is empty, you can remove it (revive)
⏰ 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). (1)
- GitHub Check: E2E Tests (macos-latest)
🔇 Additional comments (3)
cmd/wtp/flag_completion.go (1)
116-121: Good fix: don’t let flags block positional completions.Early return on empty current resolves the “flag suggestions after trailing space” issue.
cmd/wtp/completion_config_test.go (1)
53-133: Solid coverage for fish/zsh/bash patching and goldens.Dynamic fish helper, bash sanitizer injection, zsh env injection, and passthrough behaviors are well tested. Goldens gate regressions effectively.
cmd/wtp/flag_completion_test.go (1)
14-103: LGTM: focused tests for flag completions and sentinel handling.Covers key paths (long/short flags, previous/current, OS arg sentinel) and avoids side effects with t.Cleanup.
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
🧹 Nitpick comments (1)
cmd/wtp/completion_config_test.go (1)
125-127: Remove loop var copy in Go 1.22+ (optional).
tc := tccan be dropped; closures now capture per-iteration values.- tc := tc t.Run(tc.shell, func(t *testing.T) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
cmd/wtp/app.go(1 hunks)cmd/wtp/completion_config_test.go(1 hunks)cmd/wtp/main.go(1 hunks)cmd/wtp/testdata/completion/zsh_expected.zsh(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Run gofmt and goimports; keep imports grouped and organized; local import prefix follows module path github.com/satococoa/wtp
Adhere to golangci-lint rules configured for the project (vet, staticcheck, gosec, mnd, lll=120, etc.)
Errors should be wrapped with context and must not be ignored
Use snake_case for Go filenames; document exported identifiers when non-trivial
Files:
cmd/wtp/main.gocmd/wtp/app.gocmd/wtp/completion_config_test.go
cmd/wtp/**
📄 CodeRabbit inference engine (AGENTS.md)
cmd/wtp/**: CLI entrypoint and commands are implemented under cmd/wtp
Update CLI help text to reflect user-facing changes
Command behavior: wtp cd prints only the absolute worktree path with no side effects
Command behavior: wtp completion generates pure completion scripts via urfave/cli
Command behavior: wtp hook emits shell functions that intercept wtp cd; wtp shell-init combines completion and hook output
Files:
cmd/wtp/main.gocmd/wtp/testdata/completion/zsh_expected.zshcmd/wtp/app.gocmd/wtp/completion_config_test.go
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Unit tests live alongside packages and use *_test.go naming
Prefer table-driven tests and mock git operations in unit tests
Files:
cmd/wtp/completion_config_test.go
🧠 Learnings (3)
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : CLI entrypoint and commands are implemented under cmd/wtp
Applied to files:
cmd/wtp/main.gocmd/wtp/app.go
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : Command behavior: wtp completion <shell> generates pure completion scripts via urfave/cli
Applied to files:
cmd/wtp/testdata/completion/zsh_expected.zsh
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : Command behavior: wtp hook <shell> emits shell functions that intercept wtp cd; wtp shell-init <shell> combines completion and hook output
Applied to files:
cmd/wtp/testdata/completion/zsh_expected.zsh
🧬 Code graph analysis (1)
cmd/wtp/app.go (7)
cmd/wtp/add.go (1)
NewAddCommand(25-46)cmd/wtp/list.go (1)
NewListCommand(50-57)cmd/wtp/remove.go (1)
NewRemoveCommand(68-96)cmd/wtp/init.go (1)
NewInitCommand(21-29)cmd/wtp/cd.go (1)
NewCdCommand(65-81)cmd/wtp/hook.go (1)
NewHookCommand(13-44)cmd/wtp/shell_init.go (1)
NewShellInitCommand(25-56)
🪛 GitHub Actions: CI
cmd/wtp/completion_config_test.go
[error] 137-137: completion script bash_expected.sh mismatch (TestCompletionCommandMatchesGolden/bash): expected length 1437, got 0
[error] 137-137: completion script fish_expected.fish mismatch (TestCompletionCommandMatchesGolden/fish): expected length 862, got 0
[error] 137-137: completion script zsh_expected.zsh mismatch (TestCompletionCommandMatchesGolden/zsh): expected length 900, got 0
🪛 GitHub Actions: E2E Tests
cmd/wtp/completion_config_test.go
[error] 137-137: completion script bash_expected.sh mismatch (expected len 1437, got 0).
[error] 1-1: Test suite failed: completion script fish_expected.fish mismatch (expected len 862, got 0).
[error] 1-1: Test suite failed: completion script zsh_expected.zsh mismatch (expected len 900, got 0).
🪛 GitHub Check: Lint
cmd/wtp/app.go
[failure] 7-7:
File is not properly formatted (gofmt)
cmd/wtp/completion_config_test.go
[failure] 125-125:
The copy of the 'for' variable "tc" can be deleted (Go 1.22+) (copyloopvar)
🔇 Additional comments (2)
cmd/wtp/main.go (1)
17-21: Good: normalize args before Run to preserve completion context.Passing normalized args into app.Run is the right hook point for shell completion behavior; error handling remains correct.
cmd/wtp/testdata/completion/zsh_expected.zsh (1)
1-29: LGTM: zsh golden includes env injection and sourcing guard.Matches tests’ expectations (env WTP_SHELL_COMPLETION=1 and funcstack guard).
cmd/wtp/app.go
Outdated
| Name: "wtp", | ||
| Usage: "Enhanced Git worktree management", | ||
| Description: "wtp (Worktree Plus) simplifies Git worktree creation with automatic branch tracking, " + | ||
| "project-specific setup hooks, and convenient defaults.", | ||
| Version: version, | ||
| EnableShellCompletion: true, | ||
| ConfigureShellCompletionCommand: configureCompletionCommand, | ||
| Flags: []cli.Flag{ | ||
| &cli.BoolFlag{ | ||
| Name: "version", | ||
| Usage: "Show version information", | ||
| }, | ||
| }, | ||
| Commands: []*cli.Command{ | ||
| NewAddCommand(), | ||
| NewListCommand(), | ||
| NewRemoveCommand(), | ||
| NewInitCommand(), | ||
| NewCdCommand(), | ||
| // Built-in completion is automatically provided by urfave/cli | ||
| NewHookCommand(), | ||
| NewShellInitCommand(), | ||
| }, | ||
| } |
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
Completion command likely not writing to app.Writer (tests see 0 bytes).
TestCompletionCommandMatchesGolden sets app.Writer/ErrWriter to a buffer, but observed output length is 0. Ensure your configured "completion" command writes to c.App.Writer (not os.Stdout) and returns errors via c.App.ErrWriter. This will fix the golden tests and E2E failures.
Run only the failing test and inspect output sources:
If the command currently uses fmt.Print* or log.* to stdout/stderr, switch to:
// inside completion Action
_, err := fmt.Fprint(c.App.Writer, patchedScript)
return err🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Narrow to the single test
rg -n 'ConfigureShellCompletionCommand|completion' cmd/wtp
go test ./cmd/wtp -run '^TestCompletionCommandMatchesGolden$' -vLength of output: 20263
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "configureCompletionCommand" -C5 cmd/wtpLength of output: 1969
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "func configureCompletionCommand" -C50 cmd/wtp/completion_config.goLength of output: 1354
Use c.App.Writer (not os.Stdout) in completion Action
In cmd/wtp/completion_config.go’s configureCompletionCommand (around lines 20–44), you’re defaulting to os.Stdout because c.Writer on *cli.Command is nil; tests set app.Writer/ErrWriter. Replace:
writer := c.Writer
if writer == nil {
writer = os.Stdout
}
…
_, err := writer.Write([]byte(script))with something like:
writer := c.App.Writer
if writer == nil {
writer = c.App.ErrWriter
}
…
_, err := fmt.Fprint(writer, script)so the patched script is written to the test buffer rather than os.Stdout.
🧰 Tools
🪛 GitHub Check: Lint
[failure] 7-7:
File is not properly formatted (gofmt)
🤖 Prompt for AI Agents
In cmd/wtp/app.go around lines 7 to 30, the completion Action currently falls
back to writing the generated script to os.Stdout (via c.Writer being nil),
which breaks tests that set app.Writer/ErrWriter; change the logic in
configureCompletionCommand to obtain the writer from c.App.Writer, fallback to
c.App.ErrWriter if nil, stop using os.Stdout directly, and write the script with
a formatted writer call (e.g., fmt.Fprint) so output goes to the app-level test
buffers instead of the real stdout.
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
♻️ Duplicate comments (2)
cmd/wtp/completion_config.go (1)
139-170: String replace is brittle against upstream changes; prefer regex or anchored patternsExact string matching for the bash patch can silently fail on minor upstream formatting changes. Consider regex (e.g., locate the eval/COMPREPLY block by pattern) or generating from a small template with placeholders to make the patch resilient.
cmd/wtp/flag_completion.go (1)
116-137: Don’t block positional completions after a trailing spaceCurrent logic treats the previous token as a flag even when the user has finished it (current is empty after a space), so commands like “wtp remove --force ” keep suggesting flags and never reach worktree names.
Gate previous/OS-args flag completion on “cursor still within the token” (suffix “*”) and avoid using OS-args when we’ve moved past the flag.
Apply:
func maybeCompleteFlagSuggestions(cmd *cli.Command, current string, previous []string) bool { currentNormalized := strings.TrimSuffix(current, "*") if currentNormalized != "" && tryFlagCompletion(cmd, currentNormalized) { return true } - if len(previous) > 0 { - last := strings.TrimSuffix(previous[len(previous)-1], "*") - // Sentinel separating flags from positionals; ignore for flag completion. - if last != "" && last != "-" && last != "--" && last != currentNormalized && tryFlagCompletion(cmd, last) { - return true - } - } + // Only consider the previous token as a flag candidate if the cursor is still inside it (no trailing space). + var prevInWord bool + if len(previous) > 0 { + prevRaw := previous[len(previous)-1] + prevInWord = strings.HasSuffix(prevRaw, "*") + last := strings.TrimSuffix(prevRaw, "*") + // Sentinel separating flags from positionals; ignore for flag completion. + if prevInWord && last != "" && last != "-" && last != "--" && last != currentNormalized && tryFlagCompletion(cmd, last) { + return true + } + } - if candidate, ok := flagCandidateFromOSArgs(); ok { - if candidate != "" && candidate != currentNormalized && tryFlagCompletion(cmd, candidate) { - return true - } - } + // OS-args fallback only when cursor is within a token (or we have a non-empty current). + if candidate, ok := flagCandidateFromOSArgs(); ok { + if (currentNormalized != "" || prevInWord) && + candidate != "" && candidate != currentNormalized && tryFlagCompletion(cmd, candidate) { + return true + } + } return false }This enables positional suggestions after a space and keeps flag completion responsive while typing the flag itself. Based on learnings.
🧹 Nitpick comments (6)
cmd/wtp/testdata/completion/zsh_expected.zsh (1)
1-2: Optional: drop redundant directiveHaving both “#compdef wtp” and “compdef _wtp wtp” is redundant. Keeping only the compdef line is sufficient.
cmd/wtp/completion_config.go (2)
60-89: Same fragility concern for zsh patchzsh patch relies on matching precise lines. Use regex-based replacement (or generate the function body from a template) to avoid breakage when urfave/cli tweaks spacing or quoting.
172-192: Arg normalization is safe but only affects app.Run argsnormalizeCompletionArgs returns a new args slice for app.Run; OS-args fallbacks read from os.Args. If divergence ever matters, consider threading normalized args to the fallback path, or document that OS-args use raw argv by design.
cmd/wtp/completion_config_test.go (3)
19-21: Consider extracting repeated DeepEqual assertions into a helper.The same pattern appears four times. Extracting it would reduce duplication and improve maintainability.
Add a helper function:
func assertEqualSlices(t *testing.T, got, want []string) { t.Helper() if !reflect.DeepEqual(got, want) { t.Fatalf("got %v, want %v", got, want) } }Then replace each occurrence:
- if !reflect.DeepEqual(got, want) { - t.Fatalf("normalizeCompletionArgs() = %v, want %v", got, want) - } + assertEqualSlices(t, got, want)Also applies to: 30-32, 40-42, 49-51
186-187: Consider truncating or diffing large outputs in error messages.Dumping the full expected and actual content (potentially 1400+ bytes each) makes test failures difficult to read. Consider truncating after the first N characters or using a diff format.
Apply this diff to improve error readability:
+ const maxLen = 200 + truncateMsg := func(s string) string { + if len(s) <= maxLen { + return s + } + return s[:maxLen] + fmt.Sprintf("... (%d more bytes)", len(s)-maxLen) + } + - t.Fatalf("completion script %s mismatch (expected len %d, got %d):\n--- expected ---\n%s\n--- got ---\n%s", - name, len(expected), len(got), expected, got) + t.Fatalf("completion script %s mismatch (expected len %d, got %d):\n--- expected (truncated) ---\n%s\n--- got (truncated) ---\n%s", + name, len(expected), len(got), truncateMsg(expected), truncateMsg(got))Alternatively, use a diff library like
github.com/pmezard/go-difflib/difflibto show only the differences.
101-104: Document Fish completion behavior
The “fish” case inpatchCompletionScriptignores itsscriptargument and callsbuildFishCompletionScript()instead. Add a comment incompletion_config.go(or update the CLI docs) clarifying that Fish completions are always generated from scratch.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
cmd/wtp/app.go(1 hunks)cmd/wtp/completion_config.go(1 hunks)cmd/wtp/completion_config_test.go(1 hunks)cmd/wtp/flag_completion.go(1 hunks)cmd/wtp/main.go(1 hunks)cmd/wtp/testdata/completion/zsh_expected.zsh(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
cmd/wtp/**
📄 CodeRabbit inference engine (AGENTS.md)
cmd/wtp/**: CLI entrypoint and commands are implemented under cmd/wtp
Update CLI help text to reflect user-facing changes
Command behavior: wtp cd prints only the absolute worktree path with no side effects
Command behavior: wtp completion generates pure completion scripts via urfave/cli
Command behavior: wtp hook emits shell functions that intercept wtp cd; wtp shell-init combines completion and hook output
Files:
cmd/wtp/testdata/completion/zsh_expected.zshcmd/wtp/app.gocmd/wtp/completion_config_test.gocmd/wtp/completion_config.gocmd/wtp/flag_completion.gocmd/wtp/main.go
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Run gofmt and goimports; keep imports grouped and organized; local import prefix follows module path github.com/satococoa/wtp
Adhere to golangci-lint rules configured for the project (vet, staticcheck, gosec, mnd, lll=120, etc.)
Errors should be wrapped with context and must not be ignored
Use snake_case for Go filenames; document exported identifiers when non-trivial
Files:
cmd/wtp/app.gocmd/wtp/completion_config_test.gocmd/wtp/completion_config.gocmd/wtp/flag_completion.gocmd/wtp/main.go
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Unit tests live alongside packages and use *_test.go naming
Prefer table-driven tests and mock git operations in unit tests
Files:
cmd/wtp/completion_config_test.go
🧠 Learnings (3)
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : Command behavior: wtp completion <shell> generates pure completion scripts via urfave/cli
Applied to files:
cmd/wtp/testdata/completion/zsh_expected.zshcmd/wtp/completion_config.go
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : Command behavior: wtp hook <shell> emits shell functions that intercept wtp cd; wtp shell-init <shell> combines completion and hook output
Applied to files:
cmd/wtp/testdata/completion/zsh_expected.zsh
📚 Learning: 2025-10-07T15:56:11.510Z
Learnt from: CR
PR: satococoa/wtp#0
File: AGENTS.md:0-0
Timestamp: 2025-10-07T15:56:11.510Z
Learning: Applies to cmd/wtp/** : CLI entrypoint and commands are implemented under cmd/wtp
Applied to files:
cmd/wtp/app.gocmd/wtp/main.go
🧬 Code graph analysis (1)
cmd/wtp/app.go (7)
cmd/wtp/add.go (1)
NewAddCommand(25-46)cmd/wtp/list.go (1)
NewListCommand(50-57)cmd/wtp/remove.go (1)
NewRemoveCommand(68-96)cmd/wtp/init.go (1)
NewInitCommand(21-29)cmd/wtp/cd.go (1)
NewCdCommand(65-81)cmd/wtp/hook.go (1)
NewHookCommand(13-44)cmd/wtp/shell_init.go (1)
NewShellInitCommand(25-56)
🪛 GitHub Actions: CI
cmd/wtp/completion_config_test.go
[error] 136-136: TestCompletionCommandMatchesGolden/bash completion script mismatch (expected len 1437, got 0)
[error] 136-136: TestCompletionCommandMatchesGolden/fish completion script mismatch (expected len 862, got 0)
[error] 136-136: TestCompletionCommandMatchesGolden/zsh completion script mismatch (expected len 900, got 0)
🪛 GitHub Actions: E2E Tests
cmd/wtp/completion_config_test.go
[error] 136-136: TestCompletionCommandMatchesGolden bash: completion script mismatch (expected len 1437, got 0).
[error] 136-136: TestCompletionCommandMatchesGolden fish: completion script mismatch (expected len 862, got 0).
[error] 136-136: TestCompletionCommandMatchesGolden zsh: completion script mismatch (expected len 900, got 0).
🔇 Additional comments (11)
cmd/wtp/testdata/completion/zsh_expected.zsh (1)
12-16: Zsh: dynamic invocation looks correctUsing env WTP_SHELL_COMPLETION and passing ${current} only when prefixed with '-' aligns with intended behavior. No issues spotted.
cmd/wtp/main.go (1)
17-21: Good: arg preprocessing before RunRouting through normalizeCompletionArgs is clean and keeps main minimal. LGTM.
cmd/wtp/app.go (1)
5-31: App wiring looks solidShell completion is enabled and configured; commands registered consistently. LGTM.
cmd/wtp/flag_completion.go (1)
139-159: Bounds handled; OS-args fallback is conservativeIndex checks prevent OOB when walking back from the completion flag; sentinel handling (“-”/“--”) is correct. LGTM.
cmd/wtp/completion_config.go (2)
91-137: Fish completion: dynamic approach looks goodBuilds args from commandline, preserves current when flag-like, sets WTP_SHELL_COMPLETION, and sanitizes “value:desc” pairs. LGTM.
14-45: Completion wrapping is correctCapturing generated script, patching per shell, and restoring the writer is clean. LGTM.
cmd/wtp/completion_config_test.go (5)
13-53: LGTM: Thorough test coverage for argument normalization.The test cases cover the essential scenarios: trailing sentinels, completion context with COMP_LINE, flag positioning, and no-op cases. The use of subtests and
t.Setenvfollows Go best practices.
55-77: LGTM: Comprehensive Fish completion patching verification.The test validates dynamic helper injection, description stripping, and legacy code removal with multiple targeted assertions.
79-93: LGTM: Bash sanitization test correctly validates helper injection.The test confirms that the sanitization helper is injected and invoked in the completion flow.
141-162: LGTM: Zsh environment injection test has precise validation.The test correctly verifies that both completion invocations (current word and subcommand) have the environment variable injected, and validates the exact count to prevent under/over-injection.
164-196: LGTM: Test helper functions follow Go conventions.The helpers correctly use
t.Helper(), handle errors appropriately, and support theUPDATE_COMPLETION_GOLDENworkflow for regenerating golden files.
| func TestCompletionCommandMatchesGolden(t *testing.T) { | ||
| cases := []struct { | ||
| shell string | ||
| file string | ||
| }{ | ||
| {shell: "bash", file: "bash_expected.sh"}, | ||
| {shell: "fish", file: "fish_expected.fish"}, | ||
| {shell: "zsh", file: "zsh_expected.zsh"}, | ||
| } | ||
|
|
||
| for _, tc := range cases { | ||
| t.Run(tc.shell, func(t *testing.T) { | ||
| var buf bytes.Buffer | ||
| app := newApp() | ||
| app.Writer = &buf | ||
| app.ErrWriter = &buf | ||
|
|
||
| args := normalizeCompletionArgs([]string{"wtp", "completion", tc.shell}) | ||
| if err := app.Run(context.Background(), args); err != nil { | ||
| t.Fatalf("wtp completion %s failed: %v", tc.shell, err) | ||
| } | ||
|
|
||
| assertCompletionGolden(t, tc.file, buf.String()) | ||
| }) | ||
| } | ||
| } |
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.
Critical: TestCompletionCommandMatchesGolden produces no output.
All three shells (bash, fish, zsh) are returning empty strings when running app.Run(), causing golden file mismatches. This indicates the completion command is either not registered, not writing to app.Writer, or failing silently.
Verify the following:
#!/bin/bash
# Description: Investigate why completion command produces no output.
# 1. Check if completion command is registered in newApp()
ast-grep --pattern $'func newApp() $_ {
$$$
Commands: $$$
$$$
}'
# 2. Verify completion command writes to context writer
rg -nP --type=go -A 15 'Name:\s*"completion"' -g '*.go'
# 3. Check if completion command handler is implemented
ast-grep --pattern $'Action: func($CTX) error {
$$$
fmt.F$_($CTX.$_, $$$)
$$$
}'Additionally, verify the command can be invoked manually:
#!/bin/bash
# Test completion command directly
go run ./cmd/wtp completion bash 2>&1 | head -20
go run ./cmd/wtp completion fish 2>&1 | head -20
go run ./cmd/wtp completion zsh 2>&1 | head -20🧰 Tools
🪛 GitHub Actions: CI
[error] 136-136: TestCompletionCommandMatchesGolden/bash completion script mismatch (expected len 1437, got 0)
[error] 136-136: TestCompletionCommandMatchesGolden/fish completion script mismatch (expected len 862, got 0)
[error] 136-136: TestCompletionCommandMatchesGolden/zsh completion script mismatch (expected len 900, got 0)
🪛 GitHub Actions: E2E Tests
[error] 136-136: TestCompletionCommandMatchesGolden bash: completion script mismatch (expected len 1437, got 0).
[error] 136-136: TestCompletionCommandMatchesGolden fish: completion script mismatch (expected len 862, got 0).
[error] 136-136: TestCompletionCommandMatchesGolden zsh: completion script mismatch (expected len 900, got 0).
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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
cmd/wtp/app.go(1 hunks)cmd/wtp/completion_config.go(1 hunks)cmd/wtp/completion_config_test.go(1 hunks)cmd/wtp/flag_completion.go(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- cmd/wtp/app.go
- cmd/wtp/flag_completion.go
- cmd/wtp/completion_config.go
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Run gofmt and goimports; keep imports grouped and organized; local import prefix follows module path github.com/satococoa/wtp
Adhere to golangci-lint rules configured for the project (vet, staticcheck, gosec, mnd, lll=120, etc.)
Errors should be wrapped with context and must not be ignored
Use snake_case for Go filenames; document exported identifiers when non-trivial
Files:
cmd/wtp/completion_config_test.go
cmd/wtp/**
📄 CodeRabbit inference engine (AGENTS.md)
cmd/wtp/**: CLI entrypoint and commands are implemented under cmd/wtp
Update CLI help text to reflect user-facing changes
Command behavior: wtp cd prints only the absolute worktree path with no side effects
Command behavior: wtp completion generates pure completion scripts via urfave/cli
Command behavior: wtp hook emits shell functions that intercept wtp cd; wtp shell-init combines completion and hook output
Files:
cmd/wtp/completion_config_test.go
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Unit tests live alongside packages and use *_test.go naming
Prefer table-driven tests and mock git operations in unit tests
Files:
cmd/wtp/completion_config_test.go
🔇 Additional comments (8)
cmd/wtp/completion_config_test.go (8)
1-11: LGTM!Package declaration and imports are appropriate for the test functionality.
13-53: LGTM!Test coverage is comprehensive, using appropriate patterns (t.Run sub-tests, t.Setenv for environment isolation, reflect.DeepEqual for slice comparison).
55-93: LGTM!Tests appropriately verify that shell-specific patches are applied (fish dynamic helpers, bash sanitization).
95-130: LGTM!Golden file tests provide regression protection for generated completion scripts. The table-driven approach for TestCompletionCommandMatchesGolden is clean and maintainable.
132-153: LGTM!Test correctly verifies that zsh completion injection replaces original lines and adds the environment marker exactly twice.
198-206: LGTM!Helper correctly reads test data with appropriate error handling.
208-222: LGTM!Golden file assertion helper is well-designed with support for updating golden files via environment variable and informative failure messages.
224-234: LGTM!Helper functions for writing test data and normalizing scripts are correctly implemented.
| func generateCompletionScript(t *testing.T, shell string) string { | ||
| t.Helper() | ||
|
|
||
| app := newApp() | ||
| r, w, err := os.Pipe() | ||
| if err != nil { | ||
| t.Fatalf("failed to create pipe: %v", err) | ||
| } | ||
| defer r.Close() | ||
|
|
||
| app.Writer = w | ||
| app.ErrWriter = w | ||
| oldStdout := os.Stdout | ||
| oldStderr := os.Stderr | ||
| os.Stdout = w | ||
| os.Stderr = w | ||
| defer func() { | ||
| os.Stdout = oldStdout | ||
| os.Stderr = oldStderr | ||
| }() | ||
|
|
||
| args := normalizeCompletionArgs([]string{"wtp", "completion", shell}) | ||
| runErr := app.Run(context.Background(), args) | ||
| if closeErr := w.Close(); closeErr != nil { | ||
| t.Fatalf("failed to close writer: %v", err) | ||
| } | ||
|
|
||
| if runErr != nil { | ||
| t.Fatalf("wtp completion %s failed: %v", shell, runErr) | ||
| } | ||
|
|
||
| data, err := io.ReadAll(r) | ||
| if err != nil { | ||
| t.Fatalf("failed to read completion output: %v", err) | ||
| } | ||
|
|
||
| if len(data) > 0 && data[len(data)-1] != '\n' { | ||
| data = append(data, '\n') | ||
| } | ||
|
|
||
| return string(data) | ||
| } |
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 error variable reference.
Line 179 reports the wrong error variable. When w.Close() fails, the error message reports err (from the pipe creation on line 160) instead of closeErr.
Apply this diff:
runErr := app.Run(context.Background(), args)
if closeErr := w.Close(); closeErr != nil {
- t.Fatalf("failed to close writer: %v", err)
+ t.Fatalf("failed to close writer: %v", closeErr)
}📝 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 generateCompletionScript(t *testing.T, shell string) string { | |
| t.Helper() | |
| app := newApp() | |
| r, w, err := os.Pipe() | |
| if err != nil { | |
| t.Fatalf("failed to create pipe: %v", err) | |
| } | |
| defer r.Close() | |
| app.Writer = w | |
| app.ErrWriter = w | |
| oldStdout := os.Stdout | |
| oldStderr := os.Stderr | |
| os.Stdout = w | |
| os.Stderr = w | |
| defer func() { | |
| os.Stdout = oldStdout | |
| os.Stderr = oldStderr | |
| }() | |
| args := normalizeCompletionArgs([]string{"wtp", "completion", shell}) | |
| runErr := app.Run(context.Background(), args) | |
| if closeErr := w.Close(); closeErr != nil { | |
| t.Fatalf("failed to close writer: %v", err) | |
| } | |
| if runErr != nil { | |
| t.Fatalf("wtp completion %s failed: %v", shell, runErr) | |
| } | |
| data, err := io.ReadAll(r) | |
| if err != nil { | |
| t.Fatalf("failed to read completion output: %v", err) | |
| } | |
| if len(data) > 0 && data[len(data)-1] != '\n' { | |
| data = append(data, '\n') | |
| } | |
| return string(data) | |
| } | |
| runErr := app.Run(context.Background(), args) | |
| if closeErr := w.Close(); closeErr != nil { | |
| t.Fatalf("failed to close writer: %v", closeErr) | |
| } |
🤖 Prompt for AI Agents
In cmd/wtp/completion_config_test.go around lines 155 to 196, the error handling
after closing the writer uses the wrong variable (err) from the earlier pipe
creation instead of the local closeErr; update the t.Fatalf call to log closeErr
(the error returned by w.Close()) so the correct error is reported when closing
the writer fails.
Summary
This PR tightens up shell completion across Bash and Fish while documenting the environment expectations:
wtp remove:Removeno longer appear--generate-shell-completionin place when we proxy args for completion requestsREADME(bash-completion v2 or Bash 4+/5.x) so users know what they needValidation
go tool task dev(gofmt, goimports, golangci-lint, go test -race -cover, build)eval "$(wtp shell-init bash)", hit TAB onwtp removewtp shell-init fish | source, hit TAB onwtp add/wtp cdSummary by CodeRabbit
New Features
Documentation
Tests