From 420ff64c82f5da463f54124c0ae1e3193c50861d Mon Sep 17 00:00:00 2001 From: paxos <121539+paxos@users.noreply.github.com> Date: Fri, 3 Apr 2026 09:03:46 -0700 Subject: [PATCH 1/7] feat: show installed agents in `entire status` output Display which agents have hooks installed on the second line of status output, using the same detection as `entire enable`. Co-Authored-By: Claude Opus 4.6 Entire-Checkpoint: 8066edfd0e03 --- cmd/entire/cli/status.go | 21 ++++++++++++ cmd/entire/cli/status_test.go | 61 +++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/cmd/entire/cli/status.go b/cmd/entire/cli/status.go index fb4cc54c7..9732d428c 100644 --- a/cmd/entire/cli/status.go +++ b/cmd/entire/cli/status.go @@ -13,6 +13,7 @@ import ( "strings" "time" + "github.com/entireio/cli/cmd/entire/cli/agent" "github.com/entireio/cli/cmd/entire/cli/paths" "github.com/entireio/cli/cmd/entire/cli/session" "github.com/entireio/cli/cmd/entire/cli/settings" @@ -161,6 +162,26 @@ func formatSettingsStatusShort(ctx context.Context, s *EntireSettings, sty statu } } + // Show enabled agents + if s.Enabled { + installedNames := GetAgentsWithHooksInstalled(ctx) + if len(installedNames) > 0 { + displayNames := make([]string, 0, len(installedNames)) + for _, name := range installedNames { + if ag, agErr := agent.Get(name); agErr == nil { + displayNames = append(displayNames, string(ag.Type())) + } + } + b.WriteString("\n") + b.WriteString(sty.render(sty.dim, " Hooks installed: ")) + styledNames := make([]string, len(displayNames)) + for i, dn := range displayNames { + styledNames[i] = sty.render(sty.agent, dn) + } + b.WriteString(strings.Join(styledNames, sty.render(sty.dim, ", "))) + } + } + return b.String() } diff --git a/cmd/entire/cli/status_test.go b/cmd/entire/cli/status_test.go index b19006dac..7a5e9d252 100644 --- a/cmd/entire/cli/status_test.go +++ b/cmd/entire/cli/status_test.go @@ -1008,6 +1008,67 @@ func TestFormatSettingsStatusShort_Disabled(t *testing.T) { } } +func TestRunStatus_ShowsEnabledAgents(t *testing.T) { + setupTestRepo(t) + writeSettings(t, testSettingsEnabled) + + // Install Claude Code hooks so GetAgentsWithHooksInstalled finds them + claudeDir := ".claude" + if err := os.MkdirAll(claudeDir, 0o755); err != nil { + t.Fatalf("Failed to create .claude dir: %v", err) + } + claudeSettings := `{ + "hooks": { + "Stop": [{"matcher": "", "hooks": [{"type": "command", "command": "entire hooks claude-code stop"}]}] + } + }` + if err := os.WriteFile(filepath.Join(claudeDir, "settings.json"), []byte(claudeSettings), 0o644); err != nil { + t.Fatalf("Failed to write claude settings: %v", err) + } + + var stdout bytes.Buffer + if err := runStatus(context.Background(), &stdout, false); err != nil { + t.Fatalf("runStatus() error = %v", err) + } + + output := stdout.String() + if !strings.Contains(output, "Hooks installed:") { + t.Errorf("Expected 'Hooks installed:' in output, got: %s", output) + } + if !strings.Contains(output, "Claude Code") { + t.Errorf("Expected 'Claude Code' in output, got: %s", output) + } +} + +func TestRunStatus_DisabledDoesNotShowAgents(t *testing.T) { + setupTestRepo(t) + writeSettings(t, testSettingsDisabled) + + // Install Claude Code hooks + claudeDir := ".claude" + if err := os.MkdirAll(claudeDir, 0o755); err != nil { + t.Fatalf("Failed to create .claude dir: %v", err) + } + claudeSettings := `{ + "hooks": { + "Stop": [{"matcher": "", "hooks": [{"type": "command", "command": "entire hooks claude-code stop"}]}] + } + }` + if err := os.WriteFile(filepath.Join(claudeDir, "settings.json"), []byte(claudeSettings), 0o644); err != nil { + t.Fatalf("Failed to write claude settings: %v", err) + } + + var stdout bytes.Buffer + if err := runStatus(context.Background(), &stdout, false); err != nil { + t.Fatalf("runStatus() error = %v", err) + } + + output := stdout.String() + if strings.Contains(output, "Hooks installed:") { + t.Errorf("Disabled status should not show agents, got: %s", output) + } +} + func TestFormatSettingsStatus_Project(t *testing.T) { t.Parallel() From d2fc3d83996108ba78e96c00c5b86401b5963f9c Mon Sep 17 00:00:00 2001 From: paxos <121539+paxos@users.noreply.github.com> Date: Fri, 3 Apr 2026 09:11:06 -0700 Subject: [PATCH 2/7] refactor: extract InstalledAgentDisplayNames helper Deduplicates the agent.Get + ag.Type() mapping used by both `entire enable` and `entire status`. Co-Authored-By: Claude Opus 4.6 Entire-Checkpoint: 900a53098fa8 --- cmd/entire/cli/config.go | 12 ++++++++++++ cmd/entire/cli/setup.go | 9 +-------- cmd/entire/cli/status.go | 10 +--------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/cmd/entire/cli/config.go b/cmd/entire/cli/config.go index c2cdd8c70..97748f8e8 100644 --- a/cmd/entire/cli/config.go +++ b/cmd/entire/cli/config.go @@ -97,6 +97,18 @@ func GetAgentsWithHooksInstalled(ctx context.Context) []types.AgentName { return installed } +// InstalledAgentDisplayNames returns user-facing display names for agents with hooks installed. +func InstalledAgentDisplayNames(ctx context.Context) []string { + installedNames := GetAgentsWithHooksInstalled(ctx) + displayNames := make([]string, 0, len(installedNames)) + for _, name := range installedNames { + if ag, err := agent.Get(name); err == nil { + displayNames = append(displayNames, string(ag.Type())) + } + } + return displayNames +} + // JoinAgentNames joins agent names into a comma-separated string. func JoinAgentNames(names []types.AgentName) string { strs := make([]string, len(names)) diff --git a/cmd/entire/cli/setup.go b/cmd/entire/cli/setup.go index fabe43053..bd29eb5d9 100644 --- a/cmd/entire/cli/setup.go +++ b/cmd/entire/cli/setup.go @@ -697,14 +697,7 @@ func runEnableInteractive(ctx context.Context, w io.Writer, agents []agent.Agent // printEnabledStatus prints agents and a hint about `entire configure`. func printEnabledStatus(ctx context.Context, w io.Writer) { - installedNames := GetAgentsWithHooksInstalled(ctx) - if len(installedNames) > 0 { - displayNames := make([]string, 0, len(installedNames)) - for _, name := range installedNames { - if ag, agErr := agent.Get(name); agErr == nil { - displayNames = append(displayNames, string(ag.Type())) - } - } + if displayNames := InstalledAgentDisplayNames(ctx); len(displayNames) > 0 { fmt.Fprintf(w, "Agents: %s\n", strings.Join(displayNames, ", ")) } fmt.Fprintln(w, "\nTo add more agents, run `entire configure`.") diff --git a/cmd/entire/cli/status.go b/cmd/entire/cli/status.go index 9732d428c..d9cc24a43 100644 --- a/cmd/entire/cli/status.go +++ b/cmd/entire/cli/status.go @@ -13,7 +13,6 @@ import ( "strings" "time" - "github.com/entireio/cli/cmd/entire/cli/agent" "github.com/entireio/cli/cmd/entire/cli/paths" "github.com/entireio/cli/cmd/entire/cli/session" "github.com/entireio/cli/cmd/entire/cli/settings" @@ -164,14 +163,7 @@ func formatSettingsStatusShort(ctx context.Context, s *EntireSettings, sty statu // Show enabled agents if s.Enabled { - installedNames := GetAgentsWithHooksInstalled(ctx) - if len(installedNames) > 0 { - displayNames := make([]string, 0, len(installedNames)) - for _, name := range installedNames { - if ag, agErr := agent.Get(name); agErr == nil { - displayNames = append(displayNames, string(ag.Type())) - } - } + if displayNames := InstalledAgentDisplayNames(ctx); len(displayNames) > 0 { b.WriteString("\n") b.WriteString(sty.render(sty.dim, " Hooks installed: ")) styledNames := make([]string, len(displayNames)) From 5dda252c0e00059674eef3cafac642cc83420dbb Mon Sep 17 00:00:00 2001 From: paxos <121539+paxos@users.noreply.github.com> Date: Fri, 3 Apr 2026 09:12:16 -0700 Subject: [PATCH 3/7] test: reuse writeClaudeHooksFixture in status tests Co-Authored-By: Claude Opus 4.6 Entire-Checkpoint: 606506ef2c3d --- cmd/entire/cli/status_test.go | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/cmd/entire/cli/status_test.go b/cmd/entire/cli/status_test.go index 7a5e9d252..587efa2cc 100644 --- a/cmd/entire/cli/status_test.go +++ b/cmd/entire/cli/status_test.go @@ -1011,20 +1011,7 @@ func TestFormatSettingsStatusShort_Disabled(t *testing.T) { func TestRunStatus_ShowsEnabledAgents(t *testing.T) { setupTestRepo(t) writeSettings(t, testSettingsEnabled) - - // Install Claude Code hooks so GetAgentsWithHooksInstalled finds them - claudeDir := ".claude" - if err := os.MkdirAll(claudeDir, 0o755); err != nil { - t.Fatalf("Failed to create .claude dir: %v", err) - } - claudeSettings := `{ - "hooks": { - "Stop": [{"matcher": "", "hooks": [{"type": "command", "command": "entire hooks claude-code stop"}]}] - } - }` - if err := os.WriteFile(filepath.Join(claudeDir, "settings.json"), []byte(claudeSettings), 0o644); err != nil { - t.Fatalf("Failed to write claude settings: %v", err) - } + writeClaudeHooksFixture(t) var stdout bytes.Buffer if err := runStatus(context.Background(), &stdout, false); err != nil { @@ -1043,20 +1030,7 @@ func TestRunStatus_ShowsEnabledAgents(t *testing.T) { func TestRunStatus_DisabledDoesNotShowAgents(t *testing.T) { setupTestRepo(t) writeSettings(t, testSettingsDisabled) - - // Install Claude Code hooks - claudeDir := ".claude" - if err := os.MkdirAll(claudeDir, 0o755); err != nil { - t.Fatalf("Failed to create .claude dir: %v", err) - } - claudeSettings := `{ - "hooks": { - "Stop": [{"matcher": "", "hooks": [{"type": "command", "command": "entire hooks claude-code stop"}]}] - } - }` - if err := os.WriteFile(filepath.Join(claudeDir, "settings.json"), []byte(claudeSettings), 0o644); err != nil { - t.Fatalf("Failed to write claude settings: %v", err) - } + writeClaudeHooksFixture(t) var stdout bytes.Buffer if err := runStatus(context.Background(), &stdout, false); err != nil { From 8432370f181eac767205db3633ab5f27e79e57f8 Mon Sep 17 00:00:00 2001 From: paxos <121539+paxos@users.noreply.github.com> Date: Fri, 3 Apr 2026 09:12:52 -0700 Subject: [PATCH 4/7] test: add detailed status tests for hooks-installed line Co-Authored-By: Claude Opus 4.6 Entire-Checkpoint: 4c8616bb51b8 --- cmd/entire/cli/status_test.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/cmd/entire/cli/status_test.go b/cmd/entire/cli/status_test.go index 587efa2cc..09f311b28 100644 --- a/cmd/entire/cli/status_test.go +++ b/cmd/entire/cli/status_test.go @@ -1027,6 +1027,41 @@ func TestRunStatus_ShowsEnabledAgents(t *testing.T) { } } +func TestRunStatus_DetailedShowsEnabledAgents(t *testing.T) { + setupTestRepo(t) + writeSettings(t, testSettingsEnabled) + writeClaudeHooksFixture(t) + + var stdout bytes.Buffer + if err := runStatus(context.Background(), &stdout, true); err != nil { + t.Fatalf("runStatus() error = %v", err) + } + + output := stdout.String() + if !strings.Contains(output, "Hooks installed:") { + t.Errorf("Expected 'Hooks installed:' in detailed output, got: %s", output) + } + if !strings.Contains(output, "Claude Code") { + t.Errorf("Expected 'Claude Code' in detailed output, got: %s", output) + } +} + +func TestRunStatus_DetailedDisabledDoesNotShowAgents(t *testing.T) { + setupTestRepo(t) + writeSettings(t, testSettingsDisabled) + writeClaudeHooksFixture(t) + + var stdout bytes.Buffer + if err := runStatus(context.Background(), &stdout, true); err != nil { + t.Fatalf("runStatus() error = %v", err) + } + + output := stdout.String() + if strings.Contains(output, "Hooks installed:") { + t.Errorf("Disabled detailed status should not show agents, got: %s", output) + } +} + func TestRunStatus_DisabledDoesNotShowAgents(t *testing.T) { setupTestRepo(t) writeSettings(t, testSettingsDisabled) From 89b2f791ccd00be4be7ec2942122ea05472a45bb Mon Sep 17 00:00:00 2001 From: paxos <121539+paxos@users.noreply.github.com> Date: Fri, 3 Apr 2026 09:15:42 -0700 Subject: [PATCH 5/7] test: verify hooks line is hidden when no agents installed Co-Authored-By: Claude Opus 4.6 Entire-Checkpoint: 7a706189c89b --- cmd/entire/cli/status_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cmd/entire/cli/status_test.go b/cmd/entire/cli/status_test.go index 09f311b28..19ae16e9e 100644 --- a/cmd/entire/cli/status_test.go +++ b/cmd/entire/cli/status_test.go @@ -1027,6 +1027,22 @@ func TestRunStatus_ShowsEnabledAgents(t *testing.T) { } } +func TestRunStatus_EnabledNoAgentsHidesHooksLine(t *testing.T) { + setupTestRepo(t) + writeSettings(t, testSettingsEnabled) + // No agent hooks installed + + var stdout bytes.Buffer + if err := runStatus(context.Background(), &stdout, false); err != nil { + t.Fatalf("runStatus() error = %v", err) + } + + output := stdout.String() + if strings.Contains(output, "Hooks installed:") { + t.Errorf("Should not show hooks line when no agents installed, got: %s", output) + } +} + func TestRunStatus_DetailedShowsEnabledAgents(t *testing.T) { setupTestRepo(t) writeSettings(t, testSettingsEnabled) From b01650a503bf0155408c32a8408d5db43145326e Mon Sep 17 00:00:00 2001 From: Patrick Dinger <121539+paxos@users.noreply.github.com> Date: Fri, 3 Apr 2026 09:54:11 -0700 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20update=20agents=20label=20to=20"Age?= =?UTF-8?q?nts=20=C2=B7"=20style=20in=20status=20output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Matches the separator style of the main status line for visual consistency. Co-Authored-By: Claude Opus 4.6 Entire-Checkpoint: e97b579e4b25 --- cmd/entire/cli/status.go | 9 +++------ cmd/entire/cli/status_test.go | 14 +++++++------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/cmd/entire/cli/status.go b/cmd/entire/cli/status.go index d9cc24a43..7dd3b268c 100644 --- a/cmd/entire/cli/status.go +++ b/cmd/entire/cli/status.go @@ -165,12 +165,9 @@ func formatSettingsStatusShort(ctx context.Context, s *EntireSettings, sty statu if s.Enabled { if displayNames := InstalledAgentDisplayNames(ctx); len(displayNames) > 0 { b.WriteString("\n") - b.WriteString(sty.render(sty.dim, " Hooks installed: ")) - styledNames := make([]string, len(displayNames)) - for i, dn := range displayNames { - styledNames[i] = sty.render(sty.agent, dn) - } - b.WriteString(strings.Join(styledNames, sty.render(sty.dim, ", "))) + b.WriteString(sty.render(sty.dim, " Agents · ")) + + b.WriteString(strings.Join(displayNames, ", ")) } } diff --git a/cmd/entire/cli/status_test.go b/cmd/entire/cli/status_test.go index 19ae16e9e..e780f3899 100644 --- a/cmd/entire/cli/status_test.go +++ b/cmd/entire/cli/status_test.go @@ -1019,8 +1019,8 @@ func TestRunStatus_ShowsEnabledAgents(t *testing.T) { } output := stdout.String() - if !strings.Contains(output, "Hooks installed:") { - t.Errorf("Expected 'Hooks installed:' in output, got: %s", output) + if !strings.Contains(output, "agents") { + t.Errorf("Expected 'agents' in output, got: %s", output) } if !strings.Contains(output, "Claude Code") { t.Errorf("Expected 'Claude Code' in output, got: %s", output) @@ -1038,7 +1038,7 @@ func TestRunStatus_EnabledNoAgentsHidesHooksLine(t *testing.T) { } output := stdout.String() - if strings.Contains(output, "Hooks installed:") { + if strings.Contains(output, "agents") { t.Errorf("Should not show hooks line when no agents installed, got: %s", output) } } @@ -1054,8 +1054,8 @@ func TestRunStatus_DetailedShowsEnabledAgents(t *testing.T) { } output := stdout.String() - if !strings.Contains(output, "Hooks installed:") { - t.Errorf("Expected 'Hooks installed:' in detailed output, got: %s", output) + if !strings.Contains(output, "agents") { + t.Errorf("Expected 'agents' in detailed output, got: %s", output) } if !strings.Contains(output, "Claude Code") { t.Errorf("Expected 'Claude Code' in detailed output, got: %s", output) @@ -1073,7 +1073,7 @@ func TestRunStatus_DetailedDisabledDoesNotShowAgents(t *testing.T) { } output := stdout.String() - if strings.Contains(output, "Hooks installed:") { + if strings.Contains(output, "agents") { t.Errorf("Disabled detailed status should not show agents, got: %s", output) } } @@ -1089,7 +1089,7 @@ func TestRunStatus_DisabledDoesNotShowAgents(t *testing.T) { } output := stdout.String() - if strings.Contains(output, "Hooks installed:") { + if strings.Contains(output, "agents") { t.Errorf("Disabled status should not show agents, got: %s", output) } } From 87ec1479a3e3a2f3badd00cc18b1365acea54917 Mon Sep 17 00:00:00 2001 From: Patrick Dinger <121539+paxos@users.noreply.github.com> Date: Fri, 3 Apr 2026 10:05:52 -0700 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20update=20test=20assertions=20to=20ma?= =?UTF-8?q?tch=20"Agents=20=C2=B7"=20label?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 Entire-Checkpoint: 9d54ae3daa05 --- cmd/entire/cli/status_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/entire/cli/status_test.go b/cmd/entire/cli/status_test.go index e780f3899..4fd9d5148 100644 --- a/cmd/entire/cli/status_test.go +++ b/cmd/entire/cli/status_test.go @@ -1019,8 +1019,8 @@ func TestRunStatus_ShowsEnabledAgents(t *testing.T) { } output := stdout.String() - if !strings.Contains(output, "agents") { - t.Errorf("Expected 'agents' in output, got: %s", output) + if !strings.Contains(output, "Agents ·") { + t.Errorf("Expected 'Agents ·' in output, got: %s", output) } if !strings.Contains(output, "Claude Code") { t.Errorf("Expected 'Claude Code' in output, got: %s", output) @@ -1038,7 +1038,7 @@ func TestRunStatus_EnabledNoAgentsHidesHooksLine(t *testing.T) { } output := stdout.String() - if strings.Contains(output, "agents") { + if strings.Contains(output, "Agents ·") { t.Errorf("Should not show hooks line when no agents installed, got: %s", output) } } @@ -1054,8 +1054,8 @@ func TestRunStatus_DetailedShowsEnabledAgents(t *testing.T) { } output := stdout.String() - if !strings.Contains(output, "agents") { - t.Errorf("Expected 'agents' in detailed output, got: %s", output) + if !strings.Contains(output, "Agents ·") { + t.Errorf("Expected 'Agents ·' in detailed output, got: %s", output) } if !strings.Contains(output, "Claude Code") { t.Errorf("Expected 'Claude Code' in detailed output, got: %s", output) @@ -1073,7 +1073,7 @@ func TestRunStatus_DetailedDisabledDoesNotShowAgents(t *testing.T) { } output := stdout.String() - if strings.Contains(output, "agents") { + if strings.Contains(output, "Agents ·") { t.Errorf("Disabled detailed status should not show agents, got: %s", output) } } @@ -1089,7 +1089,7 @@ func TestRunStatus_DisabledDoesNotShowAgents(t *testing.T) { } output := stdout.String() - if strings.Contains(output, "agents") { + if strings.Contains(output, "Agents ·") { t.Errorf("Disabled status should not show agents, got: %s", output) } }