diff --git a/pkg/cli/mcp_list_tools.go b/pkg/cli/mcp_list_tools.go index cf48692b3c4..78dc1a6d7f9 100644 --- a/pkg/cli/mcp_list_tools.go +++ b/pkg/cli/mcp_list_tools.go @@ -48,7 +48,7 @@ func ListToolsForMCP(workflowFile string, mcpServerName string, verbose bool) er } if verbose { - fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Looking for MCP server '%s' in: %s", mcpServerName, workflowPath))) + fmt.Fprintln(os.Stderr, console.FormatInfoMessageStderr(fmt.Sprintf("Looking for MCP server '%s' in: %s", mcpServerName, workflowPath))) } // Parse the workflow file and extract MCP configurations @@ -74,9 +74,8 @@ func ListToolsForMCP(workflowFile string, mcpServerName string, verbose bool) er // Show available servers if len(mcpConfigs) > 0 { - fmt.Fprintf(os.Stderr, "Available MCP servers: ") serverNames := sliceutil.Map(mcpConfigs, func(config parser.RegistryMCPServerConfig) string { return config.Name }) - fmt.Fprintf(os.Stderr, "%s\n", strings.Join(serverNames, ", ")) + fmt.Fprintln(os.Stderr, console.FormatInfoMessageStderr("Available MCP servers: "+strings.Join(serverNames, ", "))) } return nil } @@ -84,7 +83,7 @@ func ListToolsForMCP(workflowFile string, mcpServerName string, verbose bool) er mcpListToolsLog.Printf("Found MCP server: name=%s, type=%s", targetConfig.Name, targetConfig.Type) // Connect to the MCP server and get its tools - fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("šŸ“” Connecting to MCP server: %s (%s)", + fmt.Fprintln(os.Stderr, console.FormatInfoMessageStderr(fmt.Sprintf("šŸ“” Connecting to MCP server: %s (%s)", targetConfig.Name, targetConfig.Type))) @@ -96,7 +95,7 @@ func ListToolsForMCP(workflowFile string, mcpServerName string, verbose bool) er mcpListToolsLog.Printf("Connected to MCP server: tools=%d", len(info.Tools)) if verbose { - fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Successfully connected to MCP server")) + fmt.Fprintln(os.Stderr, console.FormatSuccessMessageStderr("Successfully connected to MCP server")) } // Display the tools @@ -131,9 +130,13 @@ func findWorkflowsWithMCPServer(workflowsDir string, mcpServerName string, verbo } // Display matching workflows and suggest using one - fmt.Fprintf(os.Stderr, "Found MCP server '%s' in %d workflow(s): %s\n", - mcpServerName, len(matchingWorkflows), strings.Join(matchingWorkflows, ", ")) - fmt.Fprintf(os.Stderr, "\nRun 'gh aw mcp list-tools --server %s' to list tools for a specific workflow\n", mcpServerName) + fmt.Fprintln(os.Stderr, console.FormatInfoMessageStderr( + fmt.Sprintf("Found MCP server '%s' in %d workflow(s): %s", mcpServerName, len(matchingWorkflows), strings.Join(matchingWorkflows, ", ")), + )) + fmt.Fprintln(os.Stderr, "") + fmt.Fprintln(os.Stderr, console.FormatInfoMessageStderr( + fmt.Sprintf("Run 'gh aw mcp list-tools --server %s' to list tools for a specific workflow", mcpServerName), + )) return nil } @@ -145,7 +148,8 @@ func displayToolsList(info *parser.MCPServerInfo, verbose bool) { return } - fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("\nšŸ› ļø Available Tools (%d total)", len(info.Tools)))) + fmt.Fprintln(os.Stderr, "") + fmt.Fprintln(os.Stderr, console.FormatInfoMessageStderr(fmt.Sprintf("šŸ› ļø Available Tools (%d total)", len(info.Tools)))) // Configure options based on verbose flag opts := MCPToolTableOptions{ diff --git a/pkg/cli/org_runner.go b/pkg/cli/org_runner.go index 81f0491d081..dd4e4eb51bc 100644 --- a/pkg/cli/org_runner.go +++ b/pkg/cli/org_runner.go @@ -83,24 +83,24 @@ type orgRunCallbacks struct { } func renderOrgActionSummary(preview orgRepoPreview, action string) { - fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Ready to "+action)) - fmt.Fprintf(os.Stderr, " - Repository: %s\n", preview.Repo) + fmt.Fprintln(os.Stderr, console.FormatInfoMessageStderr("Ready to "+action)) + fmt.Fprintln(os.Stderr, console.FormatListItemStderr("Repository: "+preview.Repo)) if preview.TotalWorkflows > 0 { - fmt.Fprintf(os.Stderr, " - Workflows: %d\n", preview.TotalWorkflows) + fmt.Fprintln(os.Stderr, console.FormatListItemStderr(fmt.Sprintf("Workflows: %d", preview.TotalWorkflows))) } if len(preview.Workflows) > 0 { - fmt.Fprintln(os.Stderr, " - Pending workflow updates:") + fmt.Fprintln(os.Stderr, console.FormatListItemStderr("Pending workflow updates:")) for _, wf := range preview.Workflows { - fmt.Fprintf(os.Stderr, " - %s: %s -> %s\n", wf.Name, wf.CurrentRef, wf.LatestRef) + fmt.Fprintln(os.Stderr, console.FormatListItemStderr(fmt.Sprintf("%s: %s -> %s", wf.Name, wf.CurrentRef, wf.LatestRef))) } } currentVersion := normalizeDisplayVersion(preview.CurrentVersion) targetVersion := normalizeDisplayVersion(GetVersion()) if currentVersion != "" { if targetVersion != "" && targetVersion != currentVersion { - fmt.Fprintf(os.Stderr, " - Compiler version: %s -> %s\n", currentVersion, targetVersion) + fmt.Fprintln(os.Stderr, console.FormatListItemStderr(fmt.Sprintf("Compiler version: %s -> %s", currentVersion, targetVersion))) } else { - fmt.Fprintf(os.Stderr, " - Compiler version: %s\n", currentVersion) + fmt.Fprintln(os.Stderr, console.FormatListItemStderr("Compiler version: "+currentVersion)) } } } diff --git a/pkg/cli/stderr_console_formatting_test.go b/pkg/cli/stderr_console_formatting_test.go new file mode 100644 index 00000000000..ed910951275 --- /dev/null +++ b/pkg/cli/stderr_console_formatting_test.go @@ -0,0 +1,69 @@ +//go:build !integration + +package cli + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/github/gh-aw/pkg/console" + "github.com/github/gh-aw/pkg/constants" + "github.com/github/gh-aw/pkg/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRenderOrgActionSummaryUsesConsoleFormatListItemStderr(t *testing.T) { + preview := orgRepoPreview{ + Repo: "octo/repo", + TotalWorkflows: 2, + Workflows: []orgWorkflowPreview{ + {Name: "repo-assist", CurrentRef: "v1.0.0", LatestRef: "v1.1.0"}, + }, + } + + _, stderr := captureOutput(t, func() error { + renderOrgActionSummary(preview, "update") + return nil + }) + + lines := strings.Split(strings.TrimSuffix(stderr, "\n"), "\n") + require.Len(t, lines, 5) + assert.Equal(t, console.FormatInfoMessageStderr("Ready to update"), lines[0]) + assert.Equal(t, console.FormatListItemStderr("Repository: octo/repo"), lines[1]) + assert.Equal(t, console.FormatListItemStderr("Workflows: 2"), lines[2]) + assert.Equal(t, console.FormatListItemStderr("Pending workflow updates:"), lines[3]) + assert.Equal(t, console.FormatListItemStderr("repo-assist: v1.0.0 -> v1.1.0"), lines[4]) +} + +func TestFindWorkflowsWithMCPServerUsesConsoleFormatInfoMessageStderr(t *testing.T) { + tmpDir := testutil.TempDir(t, "test-*") + workflowsDir := filepath.Join(tmpDir, constants.GetWorkflowDir()) + require.NoError(t, os.MkdirAll(workflowsDir, 0o755)) + require.NoError(t, os.WriteFile(filepath.Join(workflowsDir, "workflow1.md"), []byte(`--- +tools: + github: + allowed: ["create_issue"] +--- +# Workflow 1 +`), 0o644)) + + originalDir, err := os.Getwd() + require.NoError(t, err) + defer func() { + _ = os.Chdir(originalDir) + }() + require.NoError(t, os.Chdir(tmpDir)) + + _, stderr := captureOutput(t, func() error { + return findWorkflowsWithMCPServer(workflowsDir, "github", false) + }) + + lines := strings.Split(strings.TrimSuffix(stderr, "\n"), "\n") + require.Len(t, lines, 3) + assert.Equal(t, console.FormatInfoMessageStderr("Found MCP server 'github' in 1 workflow(s): workflow1"), lines[0]) + assert.Empty(t, lines[1]) + assert.Equal(t, console.FormatInfoMessageStderr("Run 'gh aw mcp list-tools --server github' to list tools for a specific workflow"), lines[2]) +}