package cmd import ( "os" "path/filepath" "testing" "time" "github.com/spf13/cobra" "github.com/warrenronsiek/ctask/internal/workspace" ) // Tests in this file mutate runWorkspaceEntry. Do not run with t.Parallel(). func TestAttachCommandRegistered(t *testing.T) { var found *cobra.Command for _, c := range rootCmd.Commands() { if c.Name() == "attach" { found = c break } } if found == nil { t.Fatal("attach command not registered") } } func TestAttachRefusesDirectFlag(t *testing.T) { for _, c := range rootCmd.Commands() { if c.Name() != "attach" { continue } if c.Flags().Lookup("direct") != nil { t.Error("--direct flag must NOT exist on attach (always-tmux)") } if c.ValidArgsFunction == nil { t.Error("attach must have ValidArgsFunction for tab completion") } return } t.Fatal("attach command not registered") } // attach must call runWorkspaceEntry with AlwaysPersistent: true, // Shell: false (defaults to agent), and CommandName: "attach". We use a // fresh workspace fixture so resolveOne returns a real workspace, then // stub runWorkspaceEntry to capture the opts. func TestAttachForwardsToEntryHelperWithAlwaysPersistent(t *testing.T) { root := t.TempDir() wsDir := filepath.Join(root, "general", "2026-05-08_attach-fwd-demo") if err := os.MkdirAll(wsDir, 0755); err != nil { t.Fatalf("mkdir: %v", err) } now := time.Now().UTC().Truncate(time.Second) meta := &workspace.TaskMeta{ ID: "t", Slug: "attach-fwd-demo", Title: "attach-fwd-demo", CreatedAt: now, UpdatedAt: now, Status: "active", Category: "general", Type: "task", Mode: "local", Agent: workspace.AgentSpec{Type: "claude"}, } if err := workspace.WriteMeta(filepath.Join(wsDir, "task.yaml"), meta); err != nil { t.Fatalf("WriteMeta: %v", err) } prevRoot := os.Getenv("CTASK_ROOT") os.Setenv("CTASK_ROOT", root) t.Cleanup(func() { if prevRoot == "" { os.Unsetenv("CTASK_ROOT") } else { os.Setenv("CTASK_ROOT", prevRoot) } }) var captured WorkspaceEntryOptions orig := runWorkspaceEntry runWorkspaceEntry = func(opts WorkspaceEntryOptions) error { captured = opts return nil } t.Cleanup(func() { runWorkspaceEntry = orig }) prevAgent, prevForce := attachAgent, attachForce attachAgent, attachForce = "", false t.Cleanup(func() { attachAgent = prevAgent attachForce = prevForce }) if err := runAttach(attachCmd, []string{"attach-fwd-demo"}); err != nil { t.Fatalf("runAttach: %v", err) } if !captured.AlwaysPersistent { t.Error("attach must set AlwaysPersistent=true") } if captured.Shell { t.Error("attach defaults to agent, Shell must be false") } if captured.CommandName != "attach" { t.Errorf("CommandName: got %q, want %q", captured.CommandName, "attach") } }