diff --git a/pkg/cli/compile_helpers.go b/pkg/cli/compile_helpers.go index 592b0a2d5f..7f338e4879 100644 --- a/pkg/cli/compile_helpers.go +++ b/pkg/cli/compile_helpers.go @@ -155,7 +155,7 @@ func compileAllWorkflowFiles(compiler *workflow.Compiler, workflowsDir string, v if len(mdFiles) == 0 { compileHelpersLog.Printf("No markdown files found in %s", workflowsDir) if verbose { - fmt.Printf("No markdown files found in %s\n", workflowsDir) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("No markdown files found in %s", workflowsDir))) } return stats, nil } @@ -194,7 +194,7 @@ func compileAllWorkflowFiles(compiler *workflow.Compiler, workflowsDir string, v if successCount > 0 || hasActionCacheEntries { if err := ensureGitAttributes(); err != nil { if verbose { - fmt.Printf("⚠️ Failed to update .gitattributes: %v\n", err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to update .gitattributes: %v", err))) } } } else { @@ -252,7 +252,7 @@ func compileModifiedFiles(compiler *workflow.Compiler, files []string, verbose b if successCount > 0 || hasActionCacheEntries { if err := ensureGitAttributes(); err != nil { if verbose { - fmt.Printf("⚠️ Failed to update .gitattributes: %v\n", err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to update .gitattributes: %v", err))) } } } else { @@ -336,7 +336,7 @@ func compileModifiedFilesWithDependencies(compiler *workflow.Compiler, depGraph if successCount > 0 || hasActionCacheEntries { if err := ensureGitAttributes(); err != nil { if verbose { - fmt.Printf("⚠️ Failed to update .gitattributes: %v\n", err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to update .gitattributes: %v", err))) } } } else { @@ -356,11 +356,11 @@ func handleFileDeleted(mdFile string, verbose bool) { if _, err := os.Stat(orchestratorFile); err == nil { if err := os.Remove(orchestratorFile); err != nil { if verbose { - fmt.Printf("⚠️ Failed to remove orchestrator file %s: %v\n", orchestratorFile, err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to remove orchestrator file %s: %v", orchestratorFile, err))) } } else { if verbose { - fmt.Printf("🗑️ Removed generated orchestrator: %s\n", orchestratorFile) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Removed generated orchestrator: %s", orchestratorFile))) } } } @@ -370,11 +370,11 @@ func handleFileDeleted(mdFile string, verbose bool) { if _, err := os.Stat(orchestratorLockFile); err == nil { if err := os.Remove(orchestratorLockFile); err != nil { if verbose { - fmt.Printf("⚠️ Failed to remove orchestrator lock file %s: %v\n", orchestratorLockFile, err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to remove orchestrator lock file %s: %v", orchestratorLockFile, err))) } } else { if verbose { - fmt.Printf("🗑️ Removed orchestrator lock file: %s\n", orchestratorLockFile) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Removed orchestrator lock file: %s", orchestratorLockFile))) } } } @@ -388,11 +388,11 @@ func handleFileDeleted(mdFile string, verbose bool) { if _, err := os.Stat(lockFile); err == nil { if err := os.Remove(lockFile); err != nil { if verbose { - fmt.Printf("⚠️ Failed to remove lock file %s: %v\n", lockFile, err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to remove lock file %s: %v", lockFile, err))) } } else { if verbose { - fmt.Printf("🗑️ Removed corresponding lock file: %s\n", lockFile) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Removed corresponding lock file: %s", lockFile))) } } } diff --git a/pkg/cli/compile_orchestration.go b/pkg/cli/compile_orchestration.go index 21dc44cc9b..c734dc8ad8 100644 --- a/pkg/cli/compile_orchestration.go +++ b/pkg/cli/compile_orchestration.go @@ -223,7 +223,7 @@ func compileAllFilesInDirectory( compileOrchestrationLog.Printf("Scanning for markdown files in %s", workflowsDir) if config.Verbose { - fmt.Printf("Scanning for markdown files in %s\n", workflowsDir) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Scanning for markdown files in %s", workflowsDir))) } // Find all markdown files @@ -238,7 +238,7 @@ func compileAllFilesInDirectory( compileOrchestrationLog.Printf("Found %d markdown files to compile", len(mdFiles)) if config.Verbose { - fmt.Printf("Found %d markdown files to compile\n", len(mdFiles)) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found %d markdown files to compile", len(mdFiles)))) } // Handle purge logic: collect existing files before compilation diff --git a/pkg/cli/compile_watch.go b/pkg/cli/compile_watch.go index a072017e9c..2d02b47ea3 100644 --- a/pkg/cli/compile_watch.go +++ b/pkg/cli/compile_watch.go @@ -96,9 +96,9 @@ func watchAndCompileWorkflows(markdownFile string, compiler *workflow.Compiler, // Always emit the begin pattern for task integration if markdownFile != "" { - fmt.Printf("Watching for file changes to %s...\n", markdownFile) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Watching for file changes to %s...", markdownFile))) } else { - fmt.Printf("Watching for file changes in %s...\n", workflowsDir) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Watching for file changes in %s...", workflowsDir))) } if verbose { @@ -174,7 +174,7 @@ func watchAndCompileWorkflows(markdownFile string, compiler *workflow.Compiler, compileWatchLog.Printf("Detected change: %s (%s)", event.Name, event.Op.String()) if verbose { - fmt.Printf("📝 Detected change: %s (%s)\n", event.Name, event.Op.String()) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Detected change: %s (%s)", event.Name, event.Op.String()))) } // Handle file operations @@ -211,7 +211,7 @@ func watchAndCompileWorkflows(markdownFile string, compiler *workflow.Compiler, } compileWatchLog.Printf("Watcher error: %v", err) if verbose { - fmt.Printf("⚠️ Watcher error: %v\n", err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Watcher error: %v", err))) } case <-sigChan: diff --git a/pkg/cli/mcp_add.go b/pkg/cli/mcp_add.go index 362aefaeee..2ea66a8e20 100644 --- a/pkg/cli/mcp_add.go +++ b/pkg/cli/mcp_add.go @@ -133,7 +133,7 @@ func AddMCPTool(workflowFile string, mcpServerID string, registryURL string, tra if err := checkAndSuggestSecrets(mcpConfig, verbose); err != nil { // Don't fail the command if secret checking fails, just log a warning if verbose { - fmt.Println(console.FormatWarningMessage(fmt.Sprintf("Could not check repository secrets: %v", err))) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Could not check repository secrets: %v", err))) } } @@ -169,7 +169,7 @@ func createMCPToolConfig(server *MCPRegistryServerForProcessing, preferredTransp case "stdio", "http", "docker": transport = preferredTransport if verbose { - fmt.Println(console.FormatInfoMessage(fmt.Sprintf("Using preferred transport: %s", transport))) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Using preferred transport: %s", transport))) } default: return nil, fmt.Errorf("unsupported transport type: %s (supported: stdio, http, docker)", preferredTransport) diff --git a/pkg/cli/mcp_inspect.go b/pkg/cli/mcp_inspect.go index 3d2581bf15..7363292494 100644 --- a/pkg/cli/mcp_inspect.go +++ b/pkg/cli/mcp_inspect.go @@ -258,16 +258,16 @@ func InspectWorkflowMCP(workflowFile string, serverFilter string, toolFilter str if toolFilter != "" { fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found %d MCP server(s), looking for tool '%s'", len(mcpConfigs), toolFilter))) } else { - fmt.Println(console.FormatInfoMessage(fmt.Sprintf("Found %d MCP server(s) to inspect", len(mcpConfigs)))) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found %d MCP server(s) to inspect", len(mcpConfigs)))) } - fmt.Println() + fmt.Fprintln(os.Stderr) for i, config := range mcpConfigs { if i > 0 { - fmt.Println() + fmt.Fprintln(os.Stderr) } if err := inspectMCPServer(config, toolFilter, verbose, useActionsSecrets); err != nil { - fmt.Println(console.FormatError(console.CompilerError{ + fmt.Fprintln(os.Stderr, console.FormatError(console.CompilerError{ Type: "error", Message: fmt.Sprintf("Failed to inspect MCP server '%s': %v", config.Name, err), })) @@ -298,15 +298,15 @@ func listWorkflowsWithMCP(workflowsDir string, verbose bool) error { } if len(workflowsWithMCP) == 0 { - fmt.Println(console.FormatInfoMessage("No workflows with MCP servers found")) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("No workflows with MCP servers found")) return nil } - fmt.Println(console.FormatInfoMessage("Workflows with MCP servers:")) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Workflows with MCP servers:")) for _, workflow := range workflowsWithMCP { - fmt.Printf(" • %s\n", workflow) + fmt.Fprintf(os.Stderr, " • %s\n", workflow) } - fmt.Printf("\nRun 'gh aw mcp inspect ' to inspect MCP servers in a specific workflow.\n") + fmt.Fprintf(os.Stderr, "\nRun 'gh aw mcp inspect ' to inspect MCP servers in a specific workflow.\n") return nil } @@ -665,7 +665,7 @@ func spawnSafeInputsInspector(workflowFile string, verbose bool) error { fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Safe-inputs HTTP server started successfully")) fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Server running on: http://localhost:%d", port))) - fmt.Println() + fmt.Fprintln(os.Stderr) // Create MCP server config for the safe-inputs server safeInputsMCPConfig := parser.MCPServerConfig{ @@ -741,11 +741,11 @@ func spawnMCPInspector(workflowFile string, serverFilter string, verbose bool) e } if len(mcpConfigs) > 0 { - fmt.Println(console.FormatInfoMessage(fmt.Sprintf("Found %d MCP server(s) in workflow:", len(mcpConfigs)))) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found %d MCP server(s) in workflow:", len(mcpConfigs)))) for _, config := range mcpConfigs { - fmt.Printf(" • %s (%s)\n", config.Name, config.Type) + fmt.Fprintf(os.Stderr, " • %s (%s)\n", config.Name, config.Type) } - fmt.Println() + fmt.Fprintln(os.Stderr) // Start stdio MCP servers in the background stdioServers := []parser.MCPServerConfig{} @@ -756,11 +756,11 @@ func spawnMCPInspector(workflowFile string, serverFilter string, verbose bool) e } if len(stdioServers) > 0 { - fmt.Println(console.FormatInfoMessage("Starting stdio MCP servers...")) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Starting stdio MCP servers...")) for _, config := range stdioServers { if verbose { - fmt.Println(console.FormatInfoMessage(fmt.Sprintf("Starting server: %s", config.Name))) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Starting server: %s", config.Name))) } // Create the command for the MCP server @@ -788,7 +788,7 @@ func spawnMCPInspector(workflowFile string, serverFilter string, verbose bool) e // Start the server process if err := cmd.Start(); err != nil { - fmt.Println(console.FormatWarningMessage(fmt.Sprintf("Failed to start server %s: %v", config.Name, err))) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to start server %s: %v", config.Name, err))) continue } @@ -804,38 +804,38 @@ func spawnMCPInspector(workflowFile string, serverFilter string, verbose bool) e }(cmd, config.Name) if verbose { - fmt.Println(console.FormatSuccessMessage(fmt.Sprintf("Started server: %s (PID: %d)", config.Name, cmd.Process.Pid))) + fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("Started server: %s (PID: %d)", config.Name, cmd.Process.Pid))) } } // Give servers a moment to start up time.Sleep(2 * time.Second) - fmt.Println(console.FormatSuccessMessage("All stdio servers started successfully")) + fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("All stdio servers started successfully")) } fmt.Println(console.FormatInfoMessage("Configuration details for MCP inspector:")) for _, config := range mcpConfigs { - fmt.Printf("\n📡 %s (%s):\n", config.Name, config.Type) + fmt.Fprintf(os.Stderr, "\n📡 %s (%s):\n", config.Name, config.Type) switch config.Type { case "stdio": if config.Container != "" { - fmt.Printf(" Container: %s\n", config.Container) + fmt.Fprintf(os.Stderr, " Container: %s\n", config.Container) } else { - fmt.Printf(" Command: %s\n", config.Command) + fmt.Fprintf(os.Stderr, " Command: %s\n", config.Command) if len(config.Args) > 0 { - fmt.Printf(" Args: %s\n", strings.Join(config.Args, " ")) + fmt.Fprintf(os.Stderr, " Args: %s\n", strings.Join(config.Args, " ")) } } case "http": - fmt.Printf(" URL: %s\n", config.URL) + fmt.Fprintf(os.Stderr, " URL: %s\n", config.URL) } if len(config.Env) > 0 { - fmt.Printf(" Environment Variables: %v\n", config.Env) + fmt.Fprintf(os.Stderr, " Environment Variables: %v\n", config.Env) } } - fmt.Println() + fmt.Fprintln(os.Stderr) } else { - fmt.Println(console.FormatWarningMessage("No MCP servers found in workflow")) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage("No MCP servers found in workflow")) return nil } } @@ -843,11 +843,11 @@ func spawnMCPInspector(workflowFile string, serverFilter string, verbose bool) e // Set up cleanup function for stdio servers defer func() { if len(serverProcesses) > 0 { - fmt.Println(console.FormatInfoMessage("Cleaning up MCP servers...")) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Cleaning up MCP servers...")) for i, cmd := range serverProcesses { if cmd.Process != nil { if err := cmd.Process.Kill(); err != nil && verbose { - fmt.Println(console.FormatWarningMessage(fmt.Sprintf("Failed to kill server process %d: %v", cmd.Process.Pid, err))) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to kill server process %d: %v", cmd.Process.Pid, err))) } } // Give each process a chance to clean up @@ -868,17 +868,17 @@ func spawnMCPInspector(workflowFile string, serverFilter string, verbose bool) e case <-time.After(5 * time.Second): // Timeout waiting for cleanup if verbose { - fmt.Println(console.FormatWarningMessage("Timeout waiting for server cleanup")) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Timeout waiting for server cleanup")) } } } }() - fmt.Println(console.FormatInfoMessage("Launching @modelcontextprotocol/inspector...")) - fmt.Println(console.FormatInfoMessage("Visit http://localhost:5173 after the inspector starts")) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Launching @modelcontextprotocol/inspector...")) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Visit http://localhost:5173 after the inspector starts")) if len(serverProcesses) > 0 { - fmt.Println(console.FormatInfoMessage(fmt.Sprintf("%d stdio MCP server(s) are running in the background", len(serverProcesses)))) - fmt.Println(console.FormatInfoMessage("Configure them in the inspector using the details shown above")) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("%d stdio MCP server(s) are running in the background", len(serverProcesses)))) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Configure them in the inspector using the details shown above")) } cmd := exec.Command("npx", "@modelcontextprotocol/inspector") diff --git a/pkg/cli/mcp_inspect_mcp.go b/pkg/cli/mcp_inspect_mcp.go index 1495a57c51..c595c4915f 100644 --- a/pkg/cli/mcp_inspect_mcp.go +++ b/pkg/cli/mcp_inspect_mcp.go @@ -51,7 +51,7 @@ func (h *headerRoundTripper) RoundTrip(req *http.Request) (*http.Response, error // inspectMCPServer connects to an MCP server and queries its capabilities func inspectMCPServer(config parser.MCPServerConfig, toolFilter string, verbose bool, useActionsSecrets bool) error { mcpInspectServerLog.Printf("Inspecting MCP server: name=%s, type=%s", config.Name, config.Type) - fmt.Printf("%s %s (%s)\n", + fmt.Fprintf(os.Stderr, "%s %s (%s)\n", styles.ServerName.Render("📡 "+config.Name), styles.ServerType.Render(config.Type), styles.ServerType.Render(buildConnectionString(config))) @@ -76,7 +76,7 @@ func inspectMCPServer(config parser.MCPServerConfig, toolFilter string, verbose mcpInspectServerLog.Printf("Successfully connected to MCP server: %s", config.Name) if verbose { - fmt.Println(console.FormatSuccessMessage("✅ Successfully connected to MCP server")) + fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("✅ Successfully connected to MCP server")) } // Display server capabilities @@ -124,7 +124,7 @@ func connectToMCPServer(config parser.MCPServerConfig, verbose bool) (*parser.MC // connectStdioMCPServer connects to a stdio-based MCP server using the Go SDK func connectStdioMCPServer(ctx context.Context, config parser.MCPServerConfig, verbose bool) (*parser.MCPServerInfo, error) { if verbose { - fmt.Println(console.FormatInfoMessage(fmt.Sprintf("Starting stdio MCP server: %s %s", config.Command, strings.Join(config.Args, " ")))) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Starting stdio MCP server: %s %s", config.Command, strings.Join(config.Args, " ")))) } // Validate the command exists @@ -168,7 +168,7 @@ func connectStdioMCPServer(ctx context.Context, config parser.MCPServerConfig, v defer session.Close() if verbose { - fmt.Println(console.FormatSuccessMessage("Successfully connected to MCP server")) + fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Successfully connected to MCP server")) } // Query server capabilities @@ -187,7 +187,7 @@ func connectStdioMCPServer(ctx context.Context, config parser.MCPServerConfig, v toolsResult, err := session.ListTools(listToolsCtx, &mcp.ListToolsParams{}) if err != nil { if verbose { - fmt.Println(console.FormatWarningMessage(fmt.Sprintf("Failed to list tools: %v", err))) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to list tools: %v", err))) } } else { info.Tools = append(info.Tools, toolsResult.Tools...) @@ -200,7 +200,7 @@ func connectStdioMCPServer(ctx context.Context, config parser.MCPServerConfig, v resourcesResult, err := session.ListResources(listResourcesCtx, &mcp.ListResourcesParams{}) if err != nil { if verbose { - fmt.Println(console.FormatWarningMessage(fmt.Sprintf("Failed to list resources: %v", err))) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to list resources: %v", err))) } } else { info.Resources = append(info.Resources, resourcesResult.Resources...) @@ -238,7 +238,7 @@ func connectStdioMCPServer(ctx context.Context, config parser.MCPServerConfig, v // connectHTTPMCPServer connects to an HTTP-based MCP server using the Go SDK func connectHTTPMCPServer(ctx context.Context, config parser.MCPServerConfig, verbose bool) (*parser.MCPServerInfo, error) { if verbose { - fmt.Println(console.FormatInfoMessage(fmt.Sprintf("Connecting to HTTP MCP server: %s", config.URL))) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Connecting to HTTP MCP server: %s", config.URL))) } // Create MCP client @@ -276,7 +276,7 @@ func connectHTTPMCPServer(ctx context.Context, config parser.MCPServerConfig, ve defer session.Close() if verbose { - fmt.Println(console.FormatSuccessMessage("Successfully connected to HTTP MCP server")) + fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Successfully connected to HTTP MCP server")) } // Query server capabilities @@ -295,7 +295,7 @@ func connectHTTPMCPServer(ctx context.Context, config parser.MCPServerConfig, ve toolsResult, err := session.ListTools(listToolsCtx, &mcp.ListToolsParams{}) if err != nil { if verbose { - fmt.Println(console.FormatWarningMessage(fmt.Sprintf("Failed to list tools: %v", err))) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to list tools: %v", err))) } } else { info.Tools = append(info.Tools, toolsResult.Tools...) @@ -308,7 +308,7 @@ func connectHTTPMCPServer(ctx context.Context, config parser.MCPServerConfig, ve resourcesResult, err := session.ListResources(listResourcesCtx, &mcp.ListResourcesParams{}) if err != nil { if verbose { - fmt.Println(console.FormatWarningMessage(fmt.Sprintf("Failed to list resources: %v", err))) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to list resources: %v", err))) } } else { info.Resources = append(info.Resources, resourcesResult.Resources...) @@ -349,7 +349,7 @@ func displayServerCapabilities(info *parser.MCPServerInfo, toolFilter string) { if toolFilter != "" { displayDetailedToolInfo(info, toolFilter) } else { - fmt.Printf("\n%s\n", styles.Header.Render("🛠️ Tool Access Status")) + fmt.Fprintf(os.Stderr, "\n%s\n", styles.Header.Render("🛠️ Tool Access Status")) // Configure options for inspect command // Use a slightly shorter truncation length than list-tools for better fit @@ -369,15 +369,15 @@ func displayServerCapabilities(info *parser.MCPServerInfo, toolFilter string) { } else { if toolFilter != "" { - fmt.Printf("\n%s\n", console.FormatWarningMessage(fmt.Sprintf("Tool '%s' not found", toolFilter))) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatWarningMessage(fmt.Sprintf("Tool '%s' not found", toolFilter))) } else { - fmt.Printf("\n%s\n", console.FormatWarningMessage("No tools available")) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatWarningMessage("No tools available")) } } // Display resources (skip if showing specific tool details) if toolFilter == "" && len(info.Resources) > 0 { - fmt.Printf("\n%s\n", styles.Header.Render("📚 Available Resources")) + fmt.Fprintf(os.Stderr, "\n%s\n", styles.Header.Render("📚 Available Resources")) headers := []string{"URI", "Name", "Description", "MIME Type"} rows := make([][]string, 0, len(info.Resources)) @@ -402,12 +402,12 @@ func displayServerCapabilities(info *parser.MCPServerInfo, toolFilter string) { }) fmt.Print(table) } else if toolFilter == "" { - fmt.Printf("\n%s\n", console.FormatWarningMessage("No resources available")) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatWarningMessage("No resources available")) } // Display roots (skip if showing specific tool details) if toolFilter == "" && len(info.Roots) > 0 { - fmt.Printf("\n%s\n", styles.Header.Render("🌳 Available Roots")) + fmt.Fprintf(os.Stderr, "\n%s\n", styles.Header.Render("🌳 Available Roots")) headers := []string{"URI", "Name"} rows := make([][]string, 0, len(info.Roots)) @@ -422,10 +422,10 @@ func displayServerCapabilities(info *parser.MCPServerInfo, toolFilter string) { }) fmt.Print(table) } else if toolFilter == "" { - fmt.Printf("\n%s\n", console.FormatWarningMessage("No roots available")) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatWarningMessage("No roots available")) } - fmt.Println() + fmt.Fprintln(os.Stderr) } // displayDetailedToolInfo shows detailed information about a specific tool @@ -440,13 +440,13 @@ func displayDetailedToolInfo(info *parser.MCPServerInfo, toolName string) { } if foundTool == nil { - fmt.Printf("\n%s\n", console.FormatWarningMessage(fmt.Sprintf("Tool '%s' not found", toolName))) - fmt.Printf("Available tools: ") + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatWarningMessage(fmt.Sprintf("Tool '%s' not found", toolName))) + fmt.Fprintf(os.Stderr, "Available tools: ") toolNames := make([]string, len(info.Tools)) for i, tool := range info.Tools { toolNames[i] = tool.Name } - fmt.Printf("%s\n", strings.Join(toolNames, ", ")) + fmt.Fprintf(os.Stderr, "%s\n", strings.Join(toolNames, ", ")) return } @@ -459,84 +459,84 @@ func displayDetailedToolInfo(info *parser.MCPServerInfo, toolName string) { } } - fmt.Printf("\n%s\n", styles.Header.Render(fmt.Sprintf("🛠️ Tool Details: %s", foundTool.Name))) + fmt.Fprintf(os.Stderr, "\n%s\n", styles.Header.Render(fmt.Sprintf("🛠️ Tool Details: %s", foundTool.Name))) // Display basic information - fmt.Printf("📋 **Name:** %s\n", foundTool.Name) + fmt.Fprintf(os.Stderr, "📋 **Name:** %s\n", foundTool.Name) // Show title if available and different from name if foundTool.Title != "" && foundTool.Title != foundTool.Name { - fmt.Printf("📄 **Title:** %s\n", foundTool.Title) + fmt.Fprintf(os.Stderr, "📄 **Title:** %s\n", foundTool.Title) } if foundTool.Annotations != nil && foundTool.Annotations.Title != "" && foundTool.Annotations.Title != foundTool.Name && foundTool.Annotations.Title != foundTool.Title { - fmt.Printf("📄 **Annotation Title:** %s\n", foundTool.Annotations.Title) + fmt.Fprintf(os.Stderr, "📄 **Annotation Title:** %s\n", foundTool.Annotations.Title) } - fmt.Printf("📝 **Description:** %s\n", foundTool.Description) + fmt.Fprintf(os.Stderr, "📝 **Description:** %s\n", foundTool.Description) // Display allowance status if isAllowed { - fmt.Printf("✅ **Status:** Allowed\n") + fmt.Fprintf(os.Stderr, "✅ **Status:** Allowed\n") } else { - fmt.Printf("🚫 **Status:** Not allowed (add to 'allowed' list in workflow frontmatter)\n") + fmt.Fprintf(os.Stderr, "🚫 **Status:** Not allowed (add to 'allowed' list in workflow frontmatter)\n") } // Display annotations if available if foundTool.Annotations != nil { - fmt.Printf("\n%s\n", styles.Header.Render("⚙️ Tool Attributes")) + fmt.Fprintf(os.Stderr, "\n%s\n", styles.Header.Render("⚙️ Tool Attributes")) if foundTool.Annotations.ReadOnlyHint { - fmt.Printf("🔒 **Read-only:** This tool does not modify its environment\n") + fmt.Fprintf(os.Stderr, "🔒 **Read-only:** This tool does not modify its environment\n") } else { - fmt.Printf("🔓 **Modifies environment:** This tool can make changes\n") + fmt.Fprintf(os.Stderr, "🔓 **Modifies environment:** This tool can make changes\n") } if foundTool.Annotations.IdempotentHint { - fmt.Printf("🔄 **Idempotent:** Calling with same arguments has no additional effect\n") + fmt.Fprintf(os.Stderr, "🔄 **Idempotent:** Calling with same arguments has no additional effect\n") } if foundTool.Annotations.DestructiveHint != nil { if *foundTool.Annotations.DestructiveHint { - fmt.Printf("⚠️ **Destructive:** May perform destructive updates\n") + fmt.Fprintf(os.Stderr, "⚠️ **Destructive:** May perform destructive updates\n") } else { - fmt.Printf("➕ **Additive:** Performs only additive updates\n") + fmt.Fprintf(os.Stderr, "➕ **Additive:** Performs only additive updates\n") } } if foundTool.Annotations.OpenWorldHint != nil { if *foundTool.Annotations.OpenWorldHint { - fmt.Printf("🌐 **Open world:** Interacts with external entities\n") + fmt.Fprintf(os.Stderr, "🌐 **Open world:** Interacts with external entities\n") } else { - fmt.Printf("🏠 **Closed world:** Domain of interaction is closed\n") + fmt.Fprintf(os.Stderr, "🏠 **Closed world:** Domain of interaction is closed\n") } } } // Display input schema if foundTool.InputSchema != nil { - fmt.Printf("\n%s\n", styles.Header.Render("📥 Input Schema")) + fmt.Fprintf(os.Stderr, "\n%s\n", styles.Header.Render("📥 Input Schema")) if schemaJSON, err := json.MarshalIndent(foundTool.InputSchema, "", " "); err == nil { - fmt.Printf("```json\n%s\n```\n", string(schemaJSON)) + fmt.Fprintf(os.Stderr, "```json\n%s\n```\n", string(schemaJSON)) } else { - fmt.Printf("Error displaying input schema: %v\n", err) + fmt.Fprintf(os.Stderr, "Error displaying input schema: %v\n", err) } } else { - fmt.Printf("\n%s\n", console.FormatInfoMessage("📥 No input schema defined")) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("📥 No input schema defined")) } // Display output schema if foundTool.OutputSchema != nil { - fmt.Printf("\n%s\n", styles.Header.Render("📤 Output Schema")) + fmt.Fprintf(os.Stderr, "\n%s\n", styles.Header.Render("📤 Output Schema")) if schemaJSON, err := json.MarshalIndent(foundTool.OutputSchema, "", " "); err == nil { - fmt.Printf("```json\n%s\n```\n", string(schemaJSON)) + fmt.Fprintf(os.Stderr, "```json\n%s\n```\n", string(schemaJSON)) } else { - fmt.Printf("Error displaying output schema: %v\n", err) + fmt.Fprintf(os.Stderr, "Error displaying output schema: %v\n", err) } } else { - fmt.Printf("\n%s\n", console.FormatInfoMessage("📤 No output schema defined")) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("📤 No output schema defined")) } - fmt.Println() + fmt.Fprintln(os.Stderr) } // displayToolAllowanceHint shows helpful information about how to allow tools in workflow frontmatter @@ -556,18 +556,18 @@ func displayToolAllowanceHint(info *parser.MCPServerInfo) { } if len(blockedTools) > 0 { - fmt.Printf("\n%s\n", console.FormatInfoMessage("💡 To allow blocked tools, add them to your workflow frontmatter:")) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("💡 To allow blocked tools, add them to your workflow frontmatter:")) // Show the frontmatter syntax example - fmt.Printf("\n") - fmt.Printf("```yaml\n") - fmt.Printf("tools:\n") - fmt.Printf(" %s:\n", info.Config.Name) - fmt.Printf(" allowed:\n") + fmt.Fprintf(os.Stderr, "\n") + fmt.Fprintf(os.Stderr, "```yaml\n") + fmt.Fprintf(os.Stderr, "tools:\n") + fmt.Fprintf(os.Stderr, " %s:\n", info.Config.Name) + fmt.Fprintf(os.Stderr, " allowed:\n") // Add currently allowed tools first (if any) for _, allowed := range info.Config.Allowed { - fmt.Printf(" - %s\n", allowed) + fmt.Fprintf(os.Stderr, " - %s\n", allowed) } // Show first few blocked tools as examples (limit to 3 for readability) @@ -577,38 +577,38 @@ func displayToolAllowanceHint(info *parser.MCPServerInfo) { } for i := 0; i < exampleCount; i++ { - fmt.Printf(" - %s\n", blockedTools[i]) + fmt.Fprintf(os.Stderr, " - %s\n", blockedTools[i]) } if len(blockedTools) > 3 { - fmt.Printf(" # ... and %d more tools\n", len(blockedTools)-3) + fmt.Fprintf(os.Stderr, " # ... and %d more tools\n", len(blockedTools)-3) } - fmt.Printf("```\n") + fmt.Fprintf(os.Stderr, "```\n") if len(blockedTools) > 3 { - fmt.Printf("\n%s\n", console.FormatInfoMessage(fmt.Sprintf("📋 All blocked tools: %s", strings.Join(blockedTools, ", ")))) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage(fmt.Sprintf("📋 All blocked tools: %s", strings.Join(blockedTools, ", ")))) } } else if len(info.Config.Allowed) == 0 { // No explicit allowed list - all tools are allowed by default - fmt.Printf("\n%s\n", console.FormatInfoMessage("💡 All tools are currently allowed (no 'allowed' list specified)")) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("💡 All tools are currently allowed (no 'allowed' list specified)")) if len(info.Tools) > 0 { - fmt.Printf("\n%s\n", console.FormatInfoMessage("To restrict tools, add an 'allowed' list to your workflow frontmatter:")) - fmt.Printf("\n") - fmt.Printf("```yaml\n") - fmt.Printf("tools:\n") - fmt.Printf(" %s:\n", info.Config.Name) - fmt.Printf(" allowed:\n") - fmt.Printf(" - %s # Allow only specific tools\n", info.Tools[0].Name) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("To restrict tools, add an 'allowed' list to your workflow frontmatter:")) + fmt.Fprintf(os.Stderr, "\n") + fmt.Fprintf(os.Stderr, "```yaml\n") + fmt.Fprintf(os.Stderr, "tools:\n") + fmt.Fprintf(os.Stderr, " %s:\n", info.Config.Name) + fmt.Fprintf(os.Stderr, " allowed:\n") + fmt.Fprintf(os.Stderr, " - %s # Allow only specific tools\n", info.Tools[0].Name) if len(info.Tools) > 1 { - fmt.Printf(" - %s\n", info.Tools[1].Name) + fmt.Fprintf(os.Stderr, " - %s\n", info.Tools[1].Name) } - fmt.Printf("```\n") + fmt.Fprintf(os.Stderr, "```\n") } } else { // All tools are explicitly allowed - fmt.Printf("\n%s\n", console.FormatSuccessMessage("✅ All available tools are explicitly allowed in your workflow")) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatSuccessMessage("✅ All available tools are explicitly allowed in your workflow")) } - fmt.Printf("\n%s\n", console.FormatInfoMessage("📖 For more information, see: https://github.com/githubnext/gh-aw/blob/main/docs/tools.md")) + fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("📖 For more information, see: https://github.com/githubnext/gh-aw/blob/main/docs/tools.md")) } diff --git a/pkg/cli/packages.go b/pkg/cli/packages.go index 977b450676..93970dc9eb 100644 --- a/pkg/cli/packages.go +++ b/pkg/cli/packages.go @@ -107,7 +107,7 @@ func InstallPackage(repoSpec string, verbose bool) error { func downloadWorkflows(repo, version, targetDir string, verbose bool) error { packagesLog.Printf("Downloading workflows from %s (version: %s) to %s", repo, version, targetDir) if verbose { - fmt.Printf("Downloading workflows from %s/workflows...\n", repo) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Downloading workflows from %s/workflows...", repo))) } // Create a temporary directory for cloning @@ -137,7 +137,7 @@ func downloadWorkflows(repo, version, targetDir string, verbose bool) error { } if verbose { - fmt.Printf("Cloning repository...\n") + fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Cloning repository...")) } // Use helper to execute gh CLI with git fallback @@ -161,7 +161,7 @@ func downloadWorkflows(repo, version, targetDir string, verbose bool) error { return fmt.Errorf("failed to checkout commit %s: %w (output: %s)", version, err, stderr+stdout) } if verbose { - fmt.Printf("Checked out commit: %s\n", version) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Checked out commit: %s", version))) } } @@ -182,7 +182,7 @@ func downloadWorkflows(repo, version, targetDir string, verbose bool) error { } if verbose { - fmt.Printf("Repository commit SHA: %s\n", commitSHA) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Repository commit SHA: %s", commitSHA))) } // Copy all .md files from temp directory to target @@ -230,7 +230,7 @@ func copyMarkdownFiles(sourceDir, targetDir string, verbose bool) error { // Copy file if verbose { - fmt.Printf("Copying: %s -> %s\n", relPath, targetFile) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Copying: %s -> %s", relPath, targetFile))) } content, err := os.ReadFile(path) @@ -348,7 +348,7 @@ func listWorkflowsWithMetadata(repoSlug string, verbose bool) ([]WorkflowInfo, e // Check if this is a valid workflow file if !isValidWorkflowFile(path) { if verbose { - fmt.Printf("Skipping non-workflow file: %s\n", path) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Skipping non-workflow file: %s", path))) } return nil } @@ -379,7 +379,7 @@ func listWorkflowsWithMetadata(repoSlug string, verbose bool) ([]WorkflowInfo, e }) if verbose { - fmt.Printf("Found workflow: %s (ID: %s, Name: %s)\n", relPath, workflowID, name) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found workflow: %s (ID: %s, Name: %s)", relPath, workflowID, name))) } return nil @@ -445,14 +445,14 @@ func findWorkflowInPackageForRepo(workflow *WorkflowSpec, verbose bool) ([]byte, packagesDir, err := getPackagesDir() if err != nil { if verbose { - fmt.Printf("Warning: Failed to get packages directory: %v\n", err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to get packages directory: %v", err))) } return nil, nil, fmt.Errorf("failed to get packages directory: %w", err) } if _, err := os.Stat(packagesDir); os.IsNotExist(err) { if verbose { - fmt.Printf("No packages directory found at %s\n", packagesDir) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("No packages directory found at %s", packagesDir))) } return nil, nil, fmt.Errorf("no packages directory found") } @@ -460,7 +460,7 @@ func findWorkflowInPackageForRepo(workflow *WorkflowSpec, verbose bool) ([]byte, // Handle local workflows (starting with "./") if strings.HasPrefix(workflow.WorkflowPath, "./") { if verbose { - fmt.Printf("Searching local filesystem for workflow: %s\n", workflow.WorkflowPath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Searching local filesystem for workflow: %s", workflow.WorkflowPath))) } // For local workflows, use current directory as packagePath @@ -468,7 +468,7 @@ func findWorkflowInPackageForRepo(workflow *WorkflowSpec, verbose bool) ([]byte, workflowFile := workflow.WorkflowPath if verbose { - fmt.Printf("Looking for local workflow: %s\n", workflowFile) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Looking for local workflow: %s", workflowFile))) } content, err := os.ReadFile(workflowFile) @@ -486,7 +486,7 @@ func findWorkflowInPackageForRepo(workflow *WorkflowSpec, verbose bool) ([]byte, } if verbose { - fmt.Printf("Searching packages in %s for workflow: %s\n", packagesDir, workflow.WorkflowPath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Searching packages in %s for workflow: %s", packagesDir, workflow.WorkflowPath))) } // Check if workflow name contains org/repo prefix @@ -495,7 +495,7 @@ func findWorkflowInPackageForRepo(workflow *WorkflowSpec, verbose bool) ([]byte, workflowFile := filepath.Join(packagePath, workflow.WorkflowPath) if verbose { - fmt.Printf("Looking for qualified workflow: %s\n", workflowFile) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Looking for qualified workflow: %s", workflowFile))) } content, err := os.ReadFile(workflowFile) @@ -509,7 +509,7 @@ func findWorkflowInPackageForRepo(workflow *WorkflowSpec, verbose bool) ([]byte, fallbackWorkflowFile := filepath.Join(packagePath, fallbackPath) if verbose { - fmt.Printf("Initial path not found, trying fallback: %s\n", fallbackWorkflowFile) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Initial path not found, trying fallback: %s", fallbackWorkflowFile))) } var fallbackErr error @@ -518,7 +518,7 @@ func findWorkflowInPackageForRepo(workflow *WorkflowSpec, verbose bool) ([]byte, // Success with fallback path, update workflowFile to the fallback path workflowFile = fallbackWorkflowFile if verbose { - fmt.Printf("Found workflow at fallback path: %s\n", fallbackWorkflowFile) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found workflow at fallback path: %s", fallbackWorkflowFile))) } } else { // Both attempts failed, return the original error @@ -536,10 +536,10 @@ func findWorkflowInPackageForRepo(workflow *WorkflowSpec, verbose bool) ([]byte, if shaBytes, err := os.ReadFile(metadataPath); err == nil { commitSHA = strings.TrimSpace(string(shaBytes)) if verbose { - fmt.Printf("Found commit SHA from metadata: %s\n", commitSHA) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found commit SHA from metadata: %s", commitSHA))) } } else if verbose { - fmt.Printf("Warning: Could not read commit SHA metadata: %v\n", err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Could not read commit SHA metadata: %v", err))) } sourceInfo := &WorkflowSourceInfo{ @@ -558,7 +558,7 @@ func collectPackageIncludeDependencies(content, packagePath string, verbose bool seen := make(map[string]bool) if verbose { - fmt.Printf("Collecting package dependencies from: %s\n", packagePath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Collecting package dependencies from: %s", packagePath))) } err := collectPackageIncludesRecursive(content, packagePath, &dependencies, seen, verbose) @@ -601,14 +601,14 @@ func collectPackageIncludesRecursive(content, baseDir string, dependencies *[]In *dependencies = append(*dependencies, dep) if verbose { - fmt.Printf("Found include dependency: %s -> %s\n", fullSourcePath, filePath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found include dependency: %s -> %s", fullSourcePath, filePath))) } // Read the included file and process its includes recursively includedContent, err := os.ReadFile(fullSourcePath) if err != nil { if verbose { - fmt.Printf("Warning: Could not read include file %s: %v\n", fullSourcePath, err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Could not read include file %s: %v", fullSourcePath, err))) } continue } @@ -617,7 +617,7 @@ func collectPackageIncludesRecursive(content, baseDir string, dependencies *[]In markdownContent, err := parser.ExtractMarkdownContent(string(includedContent)) if err != nil { if verbose { - fmt.Printf("Warning: Could not extract markdown from %s: %v\n", fullSourcePath, err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Could not extract markdown from %s: %v", fullSourcePath, err))) } continue } @@ -626,7 +626,7 @@ func collectPackageIncludesRecursive(content, baseDir string, dependencies *[]In includedDir := filepath.Dir(fullSourcePath) if err := collectPackageIncludesRecursive(markdownContent, includedDir, dependencies, seen, verbose); err != nil { if verbose { - fmt.Printf("Warning: Error processing includes in %s: %v\n", fullSourcePath, err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Error processing includes in %s: %v", fullSourcePath, err))) } } } @@ -653,11 +653,11 @@ func copyIncludeDependenciesFromPackageWithForce(dependencies []IncludeDependenc if dep.IsOptional { // For optional includes, just show an informational message and skip if verbose { - fmt.Printf("Optional include file not found: %s (you can create this file to configure the workflow)\n", dep.TargetPath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Optional include file not found: %s (you can create this file to configure the workflow)", dep.TargetPath))) } continue } - fmt.Printf("Warning: Failed to read include file %s: %v\n", dep.SourcePath, err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to read include file %s: %v", dep.SourcePath, err))) continue } @@ -669,19 +669,19 @@ func copyIncludeDependenciesFromPackageWithForce(dependencies []IncludeDependenc if string(existingContent) == string(sourceContent) { // Contents are the same, skip if verbose { - fmt.Printf("Include file %s already exists with same content, skipping\n", dep.TargetPath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Include file %s already exists with same content, skipping", dep.TargetPath))) } continue } // Contents are different if !force { - fmt.Printf("Include file %s already exists with different content, skipping (use --force to overwrite)\n", dep.TargetPath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Include file %s already exists with different content, skipping (use --force to overwrite)", dep.TargetPath))) continue } // Force is enabled, overwrite - fmt.Printf("Overwriting existing include file: %s\n", dep.TargetPath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Overwriting existing include file: %s", dep.TargetPath))) } // Track the file based on whether it existed before (if tracker is available) @@ -699,7 +699,7 @@ func copyIncludeDependenciesFromPackageWithForce(dependencies []IncludeDependenc } if verbose { - fmt.Printf("Copied include file: %s -> %s\n", dep.SourcePath, targetPath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Copied include file: %s -> %s", dep.SourcePath, targetPath))) } }