Function bodies 244 total
cmd.completeWorktreeNames function · go · L62-L80 (19 LOC)cmd/completion.go
func completeWorktreeNames(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if gitClient == nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
worktrees, err := gitClient.WorktreeList(repoRoot)
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
var names []string
for _, wt := range worktrees {
if wt.Path == repoRoot {
continue
}
names = append(names, wt.Branch)
}
return names, cobra.ShellCompDirectiveNoFileComp
}cmd.completeBranchNames function · go · L83-L93 (11 LOC)cmd/completion.go
func completeBranchNames(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if gitClient == nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
branches, err := gitClient.BranchList(repoRoot)
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return branches, cobra.ShellCompDirectiveNoFileComp
}cmd.defaultConfigDir function · go · L21-L27 (7 LOC)cmd/config.go
func defaultConfigDir() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, ".config", "wt"), nil
}cmd.init function · go · L64-L70 (7 LOC)cmd/config.go
func init() {
configInitCmd.Flags().BoolVar(&configForce, "force", false, "Overwrite existing config file")
configCmd.AddCommand(configInitCmd)
configCmd.AddCommand(configShowCmd)
configCmd.AddCommand(configEditCmd)
rootCmd.AddCommand(configCmd)
}cmd.configFilePath function · go · L96-L102 (7 LOC)cmd/config.go
func configFilePath() (string, error) {
dir, err := configDirFunc()
if err != nil {
return "", err
}
return filepath.Join(dir, "config.yaml"), nil
}cmd.configInitRun function · go · L104-L157 (54 LOC)cmd/config.go
func configInitRun() error {
cfgPath, err := configFilePath()
if err != nil {
return err
}
// Check if file already exists
if _, err := os.Stat(cfgPath); err == nil {
if !configForce {
return fmt.Errorf("config file already exists: %s (use --force to overwrite)", cfgPath)
}
output.Warning("Overwriting existing config file")
}
// Build template data from current viper values
data := configTemplateData{
BaseBranch: viper.GetString("base_branch"),
Rebase: viper.GetBool("rebase"),
NoClaude: viper.GetBool("no_claude"),
StateDir: viper.GetString("state_dir"),
}
tmpl, err := template.New("config").Parse(configTemplate)
if err != nil {
return fmt.Errorf("template parse error: %w", err)
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
return fmt.Errorf("template execute error: %w", err)
}
if dryRun {
output.DryRunMsg("Would create config file: %s", cfgPath)
_, _ = fmt.Fprintln(output.Out)
_, _ = fmt.Fprint(output.Ocmd.configShowRun function · go · L172-L196 (25 LOC)cmd/config.go
func configShowRun() error {
cfgPath, err := configFilePath()
if err != nil {
return err
}
// Check if config file exists
if _, err := os.Stat(cfgPath); err == nil {
output.Info("Config file: %s", cfgPath)
} else {
output.Info("Config file: (none)")
}
_, _ = fmt.Fprintln(output.Out)
// Read config file values to determine file source
fileValues := readConfigFileValues(cfgPath)
for _, k := range configKeys {
val := viper.Get(k.Key)
source := detectSource(k.Key, k.EnvVar, fileValues)
_, _ = fmt.Fprintf(output.Out, " %-14s %v %s\n", k.Key, val, source)
}
return nil
}Repobility analyzer · published findings · https://repobility.com
cmd.readConfigFileValues function · go · L199-L216 (18 LOC)cmd/config.go
func readConfigFileValues(path string) map[string]bool {
result := make(map[string]bool)
data, err := os.ReadFile(path)
if err != nil {
return result
}
var parsed map[string]any
if err := yaml.Unmarshal(data, &parsed); err != nil {
return result
}
for key := range parsed {
result[key] = true
}
return result
}cmd.detectSource function · go · L219-L227 (9 LOC)cmd/config.go
func detectSource(key, envVar string, fileValues map[string]bool) string {
if _, ok := os.LookupEnv(envVar); ok {
return fmt.Sprintf("(env: %s)", envVar)
}
if fileValues[key] {
return "(file)"
}
return "(default)"
}cmd.configEditRun function · go · L229-L257 (29 LOC)cmd/config.go
func configEditRun() error {
editor := os.Getenv("EDITOR")
if editor == "" {
editor = os.Getenv("VISUAL")
}
if editor == "" {
return fmt.Errorf("$EDITOR is not set — set it to your preferred editor (e.g. export EDITOR=vim)")
}
cfgPath, err := configFilePath()
if err != nil {
return err
}
if _, err := os.Stat(cfgPath); os.IsNotExist(err) {
return fmt.Errorf("config file not found: %s (run 'wt config init' first)", cfgPath)
}
if dryRun {
output.DryRunMsg("Would open %s in %s", cfgPath, editor)
return nil
}
cmd := exec.Command(editor, cfgPath)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}cmd.init function · go · L29-L35 (7 LOC)cmd/create.go
func init() {
createCmd.Flags().StringVar(&createBase, "base", "", "Base branch (default from config)")
createCmd.Flags().BoolVar(&createNoClaude, "no-claude", false, "Don't auto-launch claude in top pane")
createCmd.Flags().BoolVar(&createExisting, "existing", false, "Use existing branch instead of creating new")
_ = createCmd.RegisterFlagCompletionFunc("base", completeBranchNames)
rootCmd.AddCommand(createCmd)
}cmd.createRun function · go · L37-L62 (26 LOC)cmd/create.go
func createRun(branch string) error {
baseBranch := createBase
if baseBranch == "" {
baseBranch = viper.GetString("base_branch")
}
noClaude := createNoClaude || viper.GetBool("no_claude")
result, err := lcMgr.Create(lifecycle.CreateOptions{
RepoPath: repoRoot,
Branch: branch,
BaseBranch: baseBranch,
NoClaude: noClaude,
Existing: createExisting,
DryRun: dryRun,
})
if err != nil {
return err
}
if result.Created {
_, _ = fmt.Fprintln(output.Out)
output.Success("Worktree ready: %s", ui.Cyan(result.WtPath))
}
return nil
}cmd.defaultPrompt function · go · L29-L34 (6 LOC)cmd/delete.go
func defaultPrompt(msg string) bool {
_, _ = fmt.Fprintf(output.ErrOut, "%s [y/N] ", msg)
var answer string
_, _ = fmt.Fscanln(os.Stdin, &answer)
return strings.ToLower(strings.TrimSpace(answer)) == "y"
}cmd.defaultPromptYes function · go · L36-L42 (7 LOC)cmd/delete.go
func defaultPromptYes(msg string) bool {
_, _ = fmt.Fprintf(output.ErrOut, "%s [Y/n] ", msg)
var answer string
_, _ = fmt.Fscanln(os.Stdin, &answer)
answer = strings.ToLower(strings.TrimSpace(answer))
return answer == "" || answer == "y"
}cmd.init function · go · L61-L66 (6 LOC)cmd/delete.go
func init() {
deleteCmd.Flags().BoolVar(&deleteForce, "force", false, "Force removal, skip safety checks")
deleteCmd.Flags().BoolVar(&deleteBranchFlag, "delete-branch", false, "Also delete the git branch")
deleteCmd.Flags().BoolVar(&deleteAll, "all", false, "Delete all worktrees")
rootCmd.AddCommand(deleteCmd)
}Repobility — same analyzer, your code, free for public repos · /scan/
cmd.checkWorktreeSafety function · go · L70-L101 (32 LOC)cmd/delete.go
func checkWorktreeSafety(wtPath, dirname string) bool {
dirty, err := gitClient.IsWorktreeDirty(wtPath)
if err != nil {
output.VerboseLog("Could not check worktree status: %v", err)
}
if dirty {
output.Warning("'%s' has uncommitted changes", dirname)
if dryRun {
output.DryRunMsg("Would prompt for confirmation (uncommitted changes)")
return true
}
return promptFunc(fmt.Sprintf("Delete '%s' with uncommitted changes?", dirname))
}
baseBranch := viper.GetString("base_branch")
unpushed, err := gitClient.HasUnpushedCommits(wtPath, baseBranch)
if err != nil {
output.VerboseLog("Could not check unpushed commits: %v", err)
}
if unpushed {
output.Warning("'%s' has unpushed commits", dirname)
if dryRun {
output.DryRunMsg("Would prompt for confirmation (unpushed commits)")
return true
}
return promptFunc(fmt.Sprintf("Delete '%s' with unpushed commits?", dirname))
}
return true
}cmd.deleteRun function · go · L103-L146 (44 LOC)cmd/delete.go
func deleteRun(branch string) error {
wtPath, err := gitClient.ResolveWorktree(repoRoot, branch)
if err != nil {
return err
}
dirname := filepath.Base(wtPath)
// Build safety check callback
safetyCheck := func(checkPath string) (bool, error) {
checkDirname := filepath.Base(checkPath)
if !checkWorktreeSafety(checkPath, checkDirname) {
return false, nil
}
return true, nil
}
// Build cleanup callback using lifecycle manager
cleanup := func(cleanupWtPath, cleanupBranch string) error {
return lcMgr.Delete(lifecycle.DeleteOptions{
RepoPath: repoRoot,
WtPath: cleanupWtPath,
Branch: cleanupBranch,
Force: deleteForce,
DeleteBranch: deleteBranchFlag,
DryRun: dryRun,
})
}
output.Info("Deleting worktree '%s'", ui.Cyan(dirname))
if err := ops.Delete(gitClient, opsLogger, ops.DeleteOptions{
RepoPath: repoRoot,
WtPath: wtPath,
Branch: branch,
Force: deleteForce,
DeleteBranch: deleteBranchFcmd.deleteAllRun function · go · L148-L184 (37 LOC)cmd/delete.go
func deleteAllRun() error {
// Build safety check callback
safetyCheck := func(checkPath string) (bool, error) {
checkDirname := filepath.Base(checkPath)
if !checkWorktreeSafety(checkPath, checkDirname) {
return false, nil
}
return true, nil
}
// Build cleanup callback using lifecycle manager
cleanup := func(cleanupWtPath, cleanupBranch string) error {
return lcMgr.Delete(lifecycle.DeleteOptions{
RepoPath: repoRoot,
WtPath: cleanupWtPath,
Branch: cleanupBranch,
Force: deleteForce,
DeleteBranch: deleteBranchFlag,
DryRun: dryRun,
})
}
deleted, err := ops.DeleteAll(gitClient, opsLogger, ops.DeleteOptions{
RepoPath: repoRoot,
Force: deleteForce,
DeleteBranch: deleteBranchFlag,
DryRun: dryRun,
}, safetyCheck, cleanup)
if err != nil {
return err
}
if deleted > 0 {
_, _ = fmt.Fprintln(output.Out)
}
return nil
}cmd.discoverRun function · go · L30-L72 (43 LOC)cmd/discover.go
func discoverRun() error {
// Build state checker callback
stateCheck := func(path string) (bool, error) {
ws, _ := stateMgr.GetWorktree(path)
return ws != nil, nil
}
// Build state adopter callback
stateAdopt := func(path, repo, branch string) error {
return stateMgr.SetWorktree(path, &state.WorktreeState{
Repo: repo,
Branch: branch,
CreatedAt: state.FlexTime{Time: time.Now().UTC()},
})
}
result, err := ops.Discover(gitClient, opsLogger, ops.DiscoverOptions{
RepoPath: repoRoot,
Adopt: discoverAdopt,
DryRun: dryRun,
}, stateCheck, stateAdopt)
if err != nil {
return err
}
// Print colored output for unmanaged worktrees (ops layer doesn't have UI colors)
if len(result.Unmanaged) > 0 {
_, _ = fmt.Fprintln(output.Out)
for _, wt := range result.Unmanaged {
output.Info(" %s %s (%s)", ui.Cyan(wt.Branch), wt.Path, wt.Source)
}
_, _ = fmt.Fprintln(output.Out)
if !discoverAdopt {
output.Info("Run 'wt discover --adopt' to crcmd.listRun function · go · L33-L189 (157 LOC)cmd/list.go
func listRun() error {
repoName, err := gitClient.RepoName(repoRoot)
if err != nil {
return err
}
// Prune stale state
pruned, err := stateMgr.Prune()
if err != nil {
output.Warning("Failed to prune state: %v", err)
}
if pruned > 0 {
output.Info("Pruned %d stale state entries", pruned)
}
_, _ = fmt.Fprintf(output.Out, "Worktrees for %s\n\n", ui.Cyan(repoName))
worktrees, err := gitClient.WorktreeList(repoRoot)
if err != nil {
return err
}
termWidth := ui.TermWidth()
baseBranch := viper.GetString("base_branch")
wtDir, err := gitClient.WorktreesDir(repoRoot)
if err != nil {
output.VerboseLog("Could not get worktrees dir: %v", err)
}
// Budget column widths based on terminal size.
// Table overhead: 7 border chars + 12 padding chars (1 each side × 6 cols) = 19
// Fixed columns: SOURCE(8) + WINDOW(6) + STATUS(15) + AGE(4) = 33
const tableOverhead = 19
const fixedCols = 33
available := termWidth - tableOverhead - fixedCols
if available < 20 {
availcmd.truncRight function · go · L192-L200 (9 LOC)cmd/list.go
func truncRight(s string, max int) string {
if len(s) <= max {
return s
}
if max <= 1 {
return "…"
}
return s[:max-1] + "…"
}cmd.truncLeft function · go · L203-L211 (9 LOC)cmd/list.go
func truncLeft(s string, max int) string {
if len(s) <= max {
return s
}
if max <= 1 {
return "…"
}
return "…" + s[len(s)-(max-1):]
}cmd.formatAge function · go · L213-L222 (10 LOC)cmd/list.go
func formatAge(d time.Duration) string {
switch {
case d < time.Hour:
return fmt.Sprintf("%dm", int(d.Minutes()))
case d < 24*time.Hour:
return fmt.Sprintf("%dh", int(d.Hours()))
default:
return fmt.Sprintf("%dd", int(d.Hours()/24))
}
}All rows above produced by Repobility · https://repobility.com
cmd.worktreeSource function · go · L226-L235 (10 LOC)cmd/list.go
func worktreeSource(wtPath, standardDir string, ws *state.WorktreeState) string {
inStandardDir := standardDir != "" && strings.HasPrefix(wtPath, standardDir+"/")
if inStandardDir {
return "wt"
}
if ws != nil {
return "adopted"
}
return "external"
}cmd.init function · go · L67-L72 (6 LOC)cmd/mcp.go
func init() {
mcpCmd.AddCommand(mcpServeCmd)
mcpCmd.AddCommand(mcpInstallCmd)
mcpCmd.AddCommand(mcpStatusCmd)
rootCmd.AddCommand(mcpCmd)
}cmd.mcpServeRun function · go · L74-L96 (23 LOC)cmd/mcp.go
func mcpServeRun() error {
gc := gitops.NewClient()
// For the MCP server, create a minimal state manager.
// The state file location matches initDeps() in root.go.
home, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("get home directory: %w", err)
}
stateDir := filepath.Join(home, ".config", "wt")
sm := state.NewManager(filepath.Join(stateDir, "state.json"))
// iTerm client uses the existing package-level itermClient if initialized,
// but for MCP serve we need to create our own since cobra.OnInitialize
// may not have run for the MCP command's deps.
initDeps()
cfg := wmcp.Config{
BaseBranch: viper.GetString("base_branch"),
}
srv := wmcp.NewServer(gc, itermClient, sm, cfg)
return srv.ServeStdio(context.Background())
}cmd.mcpInstallRun function · go · L98-L154 (57 LOC)cmd/mcp.go
func mcpInstallRun() error {
home, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("get home directory: %w", err)
}
claudeJSON := filepath.Join(home, ".claude.json")
// Get the full path to the current executable
exePath, err := os.Executable()
if err != nil {
return fmt.Errorf("get executable path: %w", err)
}
exePath, err = filepath.EvalSymlinks(exePath)
if err != nil {
return fmt.Errorf("resolve executable path: %w", err)
}
// Read existing config or start fresh
config := make(map[string]any)
if data, err := os.ReadFile(claudeJSON); err == nil {
if err := json.Unmarshal(data, &config); err != nil {
return fmt.Errorf("parse %s: %w", claudeJSON, err)
}
}
// Merge mcpServers.wt entry
servers, ok := config["mcpServers"].(map[string]any)
if !ok {
servers = make(map[string]any)
}
servers["wt"] = map[string]any{
"command": exePath,
"args": []string{"mcp"},
}
config["mcpServers"] = servers
// Write back
data, err := json.MarshalIncmd.mcpStatusRun function · go · L156-L174 (19 LOC)cmd/mcp.go
func mcpStatusRun() error {
home, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("get home directory: %w", err)
}
// Check ~/.claude.json
claudeJSON := filepath.Join(home, ".claude.json")
checkWTMCPConfig("~/.claude.json", claudeJSON)
// Check .mcp.json in cwd
cwd, _ := os.Getwd()
if cwd != "" {
mcpJSON := filepath.Join(cwd, ".mcp.json")
checkWTMCPConfig(".mcp.json (cwd)", mcpJSON)
}
return nil
}cmd.checkWTMCPConfig function · go · L176-L209 (34 LOC)cmd/mcp.go
func checkWTMCPConfig(label, path string) {
data, err := os.ReadFile(path)
if err != nil {
output.Info("%s: not found", label)
return
}
var config map[string]any
if err := json.Unmarshal(data, &config); err != nil {
output.Warning("%s: invalid JSON", label)
return
}
servers, ok := config["mcpServers"].(map[string]any)
if !ok {
output.Info("%s: no mcpServers configured", label)
return
}
wt, ok := servers["wt"]
if !ok {
output.Info("%s: wt not configured (other servers present)", label)
return
}
wtConfig, ok := wt.(map[string]any)
if !ok {
output.Warning("%s: wt entry has unexpected format", label)
return
}
cmd, _ := wtConfig["command"].(string)
output.Success("%s: wt configured (command: %s)", label, cmd)
}cmd.init function · go · L46-L58 (13 LOC)cmd/merge.go
func init() {
mergeCmd.Flags().BoolVar(&mergePR, "pr", false, "Create PR instead of local merge")
mergeCmd.Flags().BoolVar(&mergeNoCleanup, "no-cleanup", false, "Keep worktree after merge")
mergeCmd.Flags().StringVar(&mergeBase, "base", "", "Target branch (default from config)")
mergeCmd.Flags().StringVar(&mergeTitle, "title", "", "PR title (--pr only)")
mergeCmd.Flags().StringVar(&mergeBody, "body", "", "PR body (--pr only, uses --fill if empty)")
mergeCmd.Flags().BoolVar(&mergeDraft, "draft", false, "Create draft PR (--pr only)")
mergeCmd.Flags().BoolVar(&mergeForce, "force", false, "Skip safety checks")
mergeCmd.Flags().BoolVar(&mergeRebase, "rebase", false, "Use rebase-then-fast-forward instead of merge")
mergeCmd.Flags().BoolVar(&mergeMerge, "merge", false, "Use merge (overrides config rebase default)")
_ = mergeCmd.RegisterFlagCompletionFunc("base", completeBranchNames)
rootCmd.AddCommand(mergeCmd)
}cmd.mergeRun function · go · L60-L115 (56 LOC)cmd/merge.go
func mergeRun(branch string) error {
// Resolve worktree
wtPath, err := gitClient.ResolveWorktree(repoRoot, branch)
if err != nil {
return err
}
// Get branch name from state or fall back to input
branchName := branch
ws, _ := stateMgr.GetWorktree(wtPath)
if ws != nil && ws.Branch != "" {
branchName = ws.Branch
}
baseBranch := mergeBase
if baseBranch == "" {
baseBranch = viper.GetString("base_branch")
}
// Build cleanup callback using lifecycle manager
cleanup := func(cleanupWtPath, cleanupBranch string) error {
return lcMgr.Delete(lifecycle.DeleteOptions{
RepoPath: repoRoot,
WtPath: cleanupWtPath,
Branch: cleanupBranch,
Force: true,
DeleteBranch: !mergePR, // delete branch for local merge, not for PR
DryRun: dryRun,
})
}
result, err := ops.Merge(gitClient, opsLogger, ops.MergeOptions{
RepoPath: repoRoot,
BaseBranch: baseBranch,
Branch: branchName,
WtPath: wtPath,
Strategy: resolveStrategy(meRepobility (the analyzer behind this table) · https://repobility.com
cmd.openRun function · go · L31-L53 (23 LOC)cmd/open.go
func openRun(branch string) error {
// Resolve worktree path
wtPath, err := gitClient.ResolveWorktree(repoRoot, branch)
if err != nil {
// Worktree not found — offer to create it
output.Warning("Worktree not found: %s", branch)
if promptDefaultYes(fmt.Sprintf("Create worktree '%s'?", branch)) {
return createRun(branch)
}
return nil
}
noClaude := openNoClaude || viper.GetBool("no_claude")
_, err = lcMgr.Open(lifecycle.OpenOptions{
RepoPath: repoRoot,
WtPath: wtPath,
Branch: branch,
NoClaude: noClaude,
DryRun: dryRun,
})
return err
}cmd.pruneRun function · go · L24-L46 (23 LOC)cmd/prune.go
func pruneRun() error {
// Build trust pruner (nil-safe)
var trustPrune ops.TrustPruner
if claudeTrust != nil {
trustPrune = func(dir string) (int, error) {
return claudeTrust.PruneProjects(dir)
}
}
result, err := ops.Prune(gitClient, opsLogger, ops.PruneOptions{
RepoPath: repoRoot,
DryRun: dryRun,
}, stateMgr.Prune, trustPrune)
if err != nil {
return err
}
totalPruned := result.StatePruned + result.TrustPruned
if totalPruned > 0 {
_, _ = fmt.Fprintln(output.Out)
}
return nil
}cmd.Execute function · go · L64-L74 (11 LOC)cmd/root.go
func Execute(version, commit, date string) {
// Set version info for the version subcommand
buildVersion = version
buildCommit = commit
buildDate = date
if err := rootCmd.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}cmd.init function · go · L76-L81 (6 LOC)cmd/root.go
func init() {
cobra.OnInitialize(initConfig, initDeps)
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Verbose output")
rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "n", false, "Show what would happen without making changes")
}cmd.initConfig function · go · L83-L106 (24 LOC)cmd/root.go
func initConfig() {
home, err := os.UserHomeDir()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: cannot find home directory: %v\n", err)
os.Exit(1)
}
configDir := filepath.Join(home, ".config", "wt")
viper.AddConfigPath(configDir)
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.SetEnvPrefix("WT")
viper.AutomaticEnv()
// Defaults via viper.SetDefault()
viper.SetDefault("state_dir", configDir)
viper.SetDefault("base_branch", "main")
viper.SetDefault("no_claude", false)
viper.SetDefault("rebase", false)
// Read config file if it exists (optional)
_ = viper.ReadInConfig()
}cmd.initDeps function · go · L108-L131 (24 LOC)cmd/root.go
func initDeps() {
output = ui.New()
output.Verbose = verbose
output.DryRun = dryRun
stateDir := viper.GetString("state_dir")
statePath := filepath.Join(stateDir, "state.json")
stateMgr = state.NewManager(statePath)
gitClient = gitops.NewClient()
itermClient = iterm.NewClient()
if claudePath, err := claude.DefaultPath(); err == nil {
claudeTrust = claude.NewTrustManager(claudePath)
}
// Resolve repo root from CWD once at startup
if root, err := gitClient.RepoRoot("."); err == nil {
repoRoot = root
}
opsLogger = &uiLogger{u: output}
lcMgr = lifecycle.NewManager(gitClient, itermClient, stateMgr, claudeTrust, opsLogger)
}cmd.resolveStrategy function · go · L135-L146 (12 LOC)cmd/root.go
func resolveStrategy(rebaseFlag, mergeFlag bool) string {
if rebaseFlag {
return "rebase"
}
if mergeFlag {
return "merge"
}
if viper.GetBool("rebase") {
return "rebase"
}
return "merge"
}cmd.switchRun function · go · L27-L64 (38 LOC)cmd/switch.go
func switchRun(branch string) error {
wtPath, err := gitClient.ResolveWorktree(repoRoot, branch)
if err != nil {
return err
}
ws, err := stateMgr.GetWorktree(wtPath)
if err != nil {
return err
}
if ws == nil || ws.ClaudeSessionID == "" {
output.Warning("No iTerm2 session recorded for this worktree")
output.Info("Use 'wt open %s' to create a window", branch)
return fmt.Errorf("no iTerm2 session for worktree")
}
if dryRun {
output.DryRunMsg("Would focus iTerm2 window for session %s", ws.ClaudeSessionID)
return nil
}
if err := itermClient.EnsureRunning(); err != nil {
return err
}
if itermClient.SessionExists(ws.ClaudeSessionID) {
if err := itermClient.FocusWindow(ws.ClaudeSessionID); err != nil {
return err
}
output.Success("Focused iTerm2 window for '%s'", ui.Cyan(filepath.Base(wtPath)))
} else {
output.Warning("iTerm2 window no longer exists")
output.Info("Use 'wt open %s' to create a new window", branch)
}
return nil
}Repobility analyzer · published findings · https://repobility.com
cmd.init function · go · L37-L45 (9 LOC)cmd/sync.go
func init() {
syncCmd.Flags().StringVar(&syncBase, "base", "", "Base branch to sync from (default from config)")
syncCmd.Flags().BoolVar(&syncForce, "force", false, "Skip dirty worktree safety check")
syncCmd.Flags().BoolVar(&syncAll, "all", false, "Sync all worktrees")
syncCmd.Flags().BoolVar(&syncRebase, "rebase", false, "Use rebase instead of merge")
syncCmd.Flags().BoolVar(&syncMerge, "merge", false, "Use merge (overrides config rebase default)")
_ = syncCmd.RegisterFlagCompletionFunc("base", completeBranchNames)
rootCmd.AddCommand(syncCmd)
}cmd.syncRun function · go · L47-L76 (30 LOC)cmd/sync.go
func syncRun(branch string) error {
// Resolve worktree
wtPath, err := gitClient.ResolveWorktree(repoRoot, branch)
if err != nil {
return err
}
// Get branch name from state or fall back to input
branchName := branch
ws, _ := stateMgr.GetWorktree(wtPath)
if ws != nil && ws.Branch != "" {
branchName = ws.Branch
}
baseBranch := syncBase
if baseBranch == "" {
baseBranch = viper.GetString("base_branch")
}
_, err = ops.Sync(gitClient, opsLogger, ops.SyncOptions{
RepoPath: repoRoot,
BaseBranch: baseBranch,
Branch: branchName,
WtPath: wtPath,
Strategy: resolveStrategy(syncRebase, syncMerge),
Force: syncForce,
DryRun: dryRun,
})
return err
}cmd.syncAllRun function · go · L78-L100 (23 LOC)cmd/sync.go
func syncAllRun() error {
baseBranch := syncBase
if baseBranch == "" {
baseBranch = viper.GetString("base_branch")
}
results, err := ops.SyncAll(gitClient, opsLogger, ops.SyncOptions{
RepoPath: repoRoot,
BaseBranch: baseBranch,
Strategy: resolveStrategy(syncRebase, syncMerge),
Force: syncForce,
DryRun: dryRun,
})
if err != nil {
return err
}
// Print blank line before summary if there were results
if len(results) > 0 {
_, _ = fmt.Fprintln(output.Out)
}
return nil
}mcp.NewServer function · go · L33-L43 (11 LOC)internal/mcp/server.go
func NewServer(gc gitops.Client, ic iterm.Client, sm *state.Manager, cfg Config) *Server {
if cfg.BaseBranch == "" {
cfg.BaseBranch = "main"
}
return &Server{
git: gc,
iterm: ic,
state: sm,
cfg: cfg,
}
}mcp.Server.MCPServer method · go · L46-L57 (12 LOC)internal/mcp/server.go
func (s *Server) MCPServer() *server.MCPServer {
srv := server.NewMCPServer("wt", "1.0.0", server.WithToolCapabilities(true))
srv.AddTool(s.listTool())
srv.AddTool(s.createTool())
srv.AddTool(s.openTool())
srv.AddTool(s.deleteTool())
srv.AddTool(s.syncTool())
srv.AddTool(s.mergeTool())
return srv
}mcp.Server.listTool method · go · L71-L77 (7 LOC)internal/mcp/server.go
func (s *Server) listTool() (mcp.Tool, server.ToolHandlerFunc) {
tool := mcp.NewTool("wt_list",
mcp.WithDescription("List worktrees for a repository with iTerm2 window status, git status, and age."),
mcp.WithString("repo_path", mcp.Required(), mcp.Description("Absolute path to the git repository")),
)
return tool, s.handleList
}mcp.Server.handleList method · go · L79-L154 (76 LOC)internal/mcp/server.go
func (s *Server) handleList(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
repoPath, err := request.RequireString("repo_path")
if err != nil {
return mcp.NewToolResultError("missing required parameter: repo_path"), nil
}
repoName, err := s.git.RepoName(repoPath)
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("failed to get repo name: %v", err)), nil
}
repoRoot, err := s.git.RepoRoot(repoPath)
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("failed to get repo root: %v", err)), nil
}
worktrees, err := s.git.WorktreeList(repoPath)
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("failed to list worktrees: %v", err)), nil
}
type wtOut struct {
Branch string `json:"branch"`
Path string `json:"path"`
WindowStatus string `json:"window_status"`
GitStatus string `json:"git_status"`
Age string `json:"age,omitempty"`
}
var out []wtOut
for _, wt := range worktrees {
imcp.Server.createTool method · go · L157-L166 (10 LOC)internal/mcp/server.go
func (s *Server) createTool() (mcp.Tool, server.ToolHandlerFunc) {
tool := mcp.NewTool("wt_create",
mcp.WithDescription("Create a new worktree + branch + iTerm2 window. If the branch already exists, uses it instead of creating a new one."),
mcp.WithString("repo_path", mcp.Required(), mcp.Description("Absolute path to the git repository")),
mcp.WithString("branch", mcp.Required(), mcp.Description("Branch name for the worktree")),
mcp.WithString("base", mcp.Description("Base branch to create from (default: main)")),
mcp.WithBoolean("no_claude", mcp.Description("Don't auto-launch claude in top pane")),
)
return tool, s.handleCreate
}Repobility — same analyzer, your code, free for public repos · /scan/
mcp.Server.handleCreate method · go · L168-L253 (86 LOC)internal/mcp/server.go
func (s *Server) handleCreate(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
repoPath, err := request.RequireString("repo_path")
if err != nil {
return mcp.NewToolResultError("missing required parameter: repo_path"), nil
}
branch, err := request.RequireString("branch")
if err != nil {
return mcp.NewToolResultError("missing required parameter: branch"), nil
}
baseBranch := request.GetString("base", s.cfg.BaseBranch)
noClaude := request.GetBool("no_claude", false)
repoName, err := s.git.RepoName(repoPath)
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("failed to get repo name: %v", err)), nil
}
wtDir, err := s.git.WorktreesDir(repoPath)
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("failed to get worktrees dir: %v", err)), nil
}
dirname := gitops.BranchToDirname(branch)
wtPath := filepath.Join(wtDir, dirname)
// Create worktrees directory if needed
if err := os.MkdirAll(wtDir, 0755); err != nil {
remcp.Server.openTool method · go · L256-L264 (9 LOC)internal/mcp/server.go
func (s *Server) openTool() (mcp.Tool, server.ToolHandlerFunc) {
tool := mcp.NewTool("wt_open",
mcp.WithDescription("Open or focus an iTerm2 window for an existing worktree."),
mcp.WithString("repo_path", mcp.Required(), mcp.Description("Absolute path to the git repository")),
mcp.WithString("branch", mcp.Required(), mcp.Description("Branch name of the worktree to open")),
mcp.WithBoolean("no_claude", mcp.Description("Don't auto-launch claude in top pane")),
)
return tool, s.handleOpen
}mcp.Server.handleOpen method · go · L266-L343 (78 LOC)internal/mcp/server.go
func (s *Server) handleOpen(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
repoPath, err := request.RequireString("repo_path")
if err != nil {
return mcp.NewToolResultError("missing required parameter: repo_path"), nil
}
branch, err := request.RequireString("branch")
if err != nil {
return mcp.NewToolResultError("missing required parameter: branch"), nil
}
noClaude := request.GetBool("no_claude", false)
repoName, err := s.git.RepoName(repoPath)
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("failed to get repo name: %v", err)), nil
}
// Find the worktree path
wtPath, err := s.resolveWorktreePath(repoPath, branch)
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("worktree not found for branch '%s': %v", branch, err)), nil
}
// Check if window already exists and focus it
ws, _ := s.state.GetWorktree(wtPath)
if ws != nil && ws.ClaudeSessionID != "" {
if s.iterm.IsRunning() && s.iterm.SessionExists(ws.Claupage 1 / 5next ›