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>
This commit is contained in:
Pierre Martin
2026-03-23 13:30:55 +01:00
parent e7ced9c3a3
commit f1dcee0ae2
3 changed files with 283 additions and 1 deletions

115
display_test.go Normal file
View File

@@ -0,0 +1,115 @@
package main
import (
"bytes"
"strings"
"testing"
)
func TestDisplaySessions_WithSessions(t *testing.T) {
sessions := []Session{
{
Process: Process{PID: 100, Cwd: "/home/user/project-a"},
State: Working,
CwdPath: "/home/user/project-a",
GitBranch: "feat-login",
Preview: "Implementing auth...",
},
{
Process: Process{PID: 200, Cwd: "/home/user/project-b"},
State: NeedsInput,
CwdPath: "/home/user/project-b",
GitBranch: "main",
Preview: "What should I do next?",
},
}
var buf bytes.Buffer
DisplaySessions(&buf, sessions, false)
output := buf.String()
for _, want := range []string{
"/home/user/project-a",
"feat-login",
"Working",
"Implementing auth...",
"/home/user/project-b",
"main",
"Needs Input",
"What should I do next?",
} {
if !strings.Contains(output, want) {
t.Errorf("output missing %q", want)
}
}
}
func TestDisplaySessions_NoColor(t *testing.T) {
sessions := []Session{
{
Process: Process{PID: 100, Cwd: "/tmp"},
State: Working,
CwdPath: "/tmp",
GitBranch: "main",
},
}
var buf bytes.Buffer
DisplaySessions(&buf, sessions, true)
output := buf.String()
if strings.Contains(output, "\033") {
t.Errorf("noColor=true but output contains ANSI escape: %q", output)
}
if !strings.Contains(output, "Working") {
t.Error("output missing state label")
}
}
func TestDisplaySessions_Empty(t *testing.T) {
var buf bytes.Buffer
DisplaySessions(&buf, nil, false)
output := buf.String()
want := "No active Claude Code sessions found.\n"
if output != want {
t.Errorf("output = %q, want %q", output, want)
}
}
func TestDisplaySessions_WorktreeDiffers(t *testing.T) {
sessions := []Session{
{
Process: Process{PID: 100, Cwd: "/home/user/repo/src"},
State: Working,
CwdPath: "/home/user/repo/src",
Worktree: "/home/user/repo",
},
}
var buf bytes.Buffer
DisplaySessions(&buf, sessions, true)
output := buf.String()
if !strings.Contains(output, "[worktree: /home/user/repo]") {
t.Errorf("output should show worktree when different from cwd: %q", output)
}
}
func TestDisplaySessions_NoBranch(t *testing.T) {
sessions := []Session{
{
Process: Process{PID: 100, Cwd: "/tmp"},
State: Unknown,
CwdPath: "/tmp",
},
}
var buf bytes.Buffer
DisplaySessions(&buf, sessions, true)
output := buf.String()
if strings.Contains(output, "(") {
t.Errorf("no branch should mean no parentheses: %q", output)
}
}