package hooks import ( "os" "path/filepath" "strings" "testing" "github.com/ajhahnde/eeco/internal/cockpit" "github.com/ajhahnde/eeco/internal/config" "github.com/ajhahnde/eeco/internal/playbooks" ) // orientCfg builds a config with a workspace + private user dir for the // SessionStart orient blocks (no git: LatestSemverTag degrades to ""). func orientCfg(t *testing.T) *config.Config { t.Helper() root := t.TempDir() ws := filepath.Join(root, "tester", ".eeco") if err := os.MkdirAll(filepath.Join(ws, "state"), 0o755); err != nil { t.Fatal(err) } return &config.Config{ RepoRoot: root, UserDir: filepath.Join(root, "tester"), WorkspaceName: ".eeco", Workspace: ws, } } func TestLiveStateBlock_ShowsNewestNote(t *testing.T) { cfg := orientCfg(t) notesDir := filepath.Join(cfg.Workspace, "notes") if err := os.MkdirAll(notesDir, 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(notesDir, "2026-06-05-150000-resume.md"), []byte("resume here next time"), 0o644); err != nil { t.Fatal(err) } got := liveStateBlock(cfg) if !strings.Contains(got, "newest handover") || !strings.Contains(got, "resume here next time") { t.Errorf("liveStateBlock missing the handover note: %q", got) } } func TestLiveStateBlock_EmptyWhenNothing(t *testing.T) { if got := liveStateBlock(orientCfg(t)); got != "" { t.Errorf("liveStateBlock should be empty with no tag/note, got %q", got) } } func TestNewestHandover_GlobWins(t *testing.T) { cfg := orientCfg(t) if err := os.WriteFile(filepath.Join(cfg.RepoRoot, "HANDOVER.md"), []byte("x"), 0o644); err != nil { t.Fatal(err) } cfg.HandoverGlob = "HANDOVER*.md" if got := newestHandover(cfg); got != "HANDOVER.md" { t.Errorf("newestHandover with glob = %q, want HANDOVER.md", got) } } func TestDriftBlock_SilentThenFlagsDrift(t *testing.T) { cfg := orientCfg(t) // No cockpit generated → silent (empty-ledger gate). if got := driftBlock(cfg); got != "" { t.Errorf("driftBlock should be silent on an unused cockpit, got %q", got) } // Narrow the selection to handover so generating it alone leaves no // "missing" findings for the other playbooks (the default selection is all). if err := cockpit.SaveSelection(cfg, cockpit.Selection{Targets: []string{"claude"}, Playbooks: []string{"handover"}}); err != nil { t.Fatal(err) } pb, err := playbooks.Get("handover") if err != nil { t.Fatal(err) } if _, err := cockpit.Generate(cfg, pb, "claude"); err != nil { t.Fatal(err) } // Clean → still silent. if got := driftBlock(cfg); got != "" { t.Errorf("driftBlock should be silent when clean, got %q", got) } // Hand-edit → drift surfaces. dst := filepath.Join(cfg.UserDir, ".claude", "skills", "handover", "SKILL.md") if err := os.WriteFile(dst, []byte("edited\n"), 0o644); err != nil { t.Fatal(err) } if got := driftBlock(cfg); !strings.Contains(got, "cockpit drift") { t.Errorf("driftBlock should report drift after a hand-edit, got %q", got) } }