Files
vmux/main.go
Pierre Martin f1dcee0ae2 feat(01-02): add CLI display and main.go for vmux list
- DisplaySessions: colored output with state, cwd, branch, preview
- display_test.go: 5 tests covering color, noColor, empty, worktree, noBranch
- main.go: full pipeline FindClaudeProcesses -> FindSession -> DetectState -> Display
- Supports --no-color flag and NO_COLOR env var
- resolveWorktree via git rev-parse --show-toplevel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:30:55 +01:00

99 lines
2.0 KiB
Go

package main
import (
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
func main() {
noColor := flag.Bool("no-color", false, "Disable colored output")
flag.Parse()
if os.Getenv("NO_COLOR") != "" {
*noColor = true
}
args := flag.Args()
// Also check for --no-color after subcommand (flag stops at first non-flag)
var filteredArgs []string
for _, arg := range args {
if arg == "--no-color" {
*noColor = true
} else {
filteredArgs = append(filteredArgs, arg)
}
}
if len(filteredArgs) == 0 || filteredArgs[0] != "list" {
fmt.Fprintf(os.Stderr, "Usage: vmux list [--no-color]\n")
os.Exit(1)
}
processes, err := FindClaudeProcesses("/proc")
if err != nil {
fmt.Fprintf(os.Stderr, "Error scanning processes: %v\n", err)
os.Exit(1)
}
claudeDir := filepath.Join(os.Getenv("HOME"), ".claude", "projects")
now := time.Now()
var sessions []Session
for _, proc := range processes {
jsonlPath, messages, err := FindSessionForProcess(claudeDir, proc)
if err != nil {
sessions = append(sessions, Session{
Process: proc,
State: Unknown,
CwdPath: proc.Cwd,
})
continue
}
state := DetectState(messages, now)
preview := ExtractPreview(messages)
var sessionID, gitBranch string
for _, msg := range messages {
if msg.SessionID != "" {
sessionID = msg.SessionID
}
if msg.GitBranch != "" {
gitBranch = msg.GitBranch
}
}
worktree := resolveWorktree(proc.Cwd)
_ = jsonlPath
sessions = append(sessions, Session{
Process: proc,
SessionID: sessionID,
GitBranch: gitBranch,
State: state,
Preview: preview,
CwdPath: proc.Cwd,
Worktree: worktree,
})
}
DisplaySessions(os.Stdout, sessions, *noColor)
}
// resolveWorktree uses git to find the worktree root.
// Falls back to cwd if git fails (not a git repo).
func resolveWorktree(cwd string) string {
cmd := exec.Command("git", "-C", cwd, "rev-parse", "--show-toplevel")
out, err := cmd.Output()
if err != nil {
return cwd
}
return strings.TrimSpace(string(out))
}