← back to joescharf__wt

Function bodies 244 total

All specs Real LLM only Function bodies
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.O
cmd.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: deleteBranchF
cmd.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 cr
cmd.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 {
		avail
cmd.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.MarshalIn
cmd.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(me
Repobility (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 {
		i
mcp.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 {
		re
mcp.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.Clau
page 1 / 5next ›