Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions DEADCODE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ make fmt
- `compiler.ParseWorkflowString`
- `compiler.CompileToYAML`

**`pkg/console/console_wasm.go`** — this file provides WASM-specific stub implementations of many `pkg/console` functions (gated with `//go:build js || wasm`). Before deleting any function from `pkg/console/`, `grep` for it in `console_wasm.go`. If the function is called there, either inline the logic in `console_wasm.go` or delete the call. Batch 10 mistake: deleted `renderTreeSimple` from `render.go` but `console_wasm.go`'s `RenderTree` still called it, breaking the WASM build. Fix: replaced the `RenderTree` body in `console_wasm.go` with an inlined closure that no longer calls the deleted helper.

**`compiler_test_helpers.go`** — shows 3 dead functions but serves as shared test infrastructure for ≥15 test files. Do not delete.

**Constant/embed rescue** — Some otherwise-dead files contain live constants or `//go:embed` directives. Extract them before deleting the file.
Expand Down Expand Up @@ -163,7 +165,9 @@ For each batch:
- [ ] Delete the function
- [ ] Delete test functions that exclusively call the deleted function (not shared helpers)
- [ ] Check for now-unused imports in edited files
- [ ] If editing `pkg/console/`, check `pkg/console/console_wasm.go` for calls to the deleted functions
- [ ] `go build ./...`
- [ ] `GOARCH=wasm GOOS=js go build ./pkg/console/...` (if `pkg/console/` was touched)
- [ ] `go vet ./...`
- [ ] `go vet -tags=integration ./...`
- [ ] `make fmt`
Expand Down
115 changes: 0 additions & 115 deletions pkg/cli/mcp_tool_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,118 +119,3 @@ func renderMCPToolTable(info *parser.MCPServerInfo, opts MCPToolTableOptions) st

return result
}

// renderMCPHierarchyTree renders all MCP servers and their tools as a tree structure
// This provides a hierarchical view of the MCP configuration
func renderMCPHierarchyTree(configs []parser.MCPServerConfig, serverInfos map[string]*parser.MCPServerInfo) string {
mcpToolTableLog.Printf("Rendering MCP hierarchy tree: server_count=%d", len(configs))

if len(configs) == 0 {
mcpToolTableLog.Print("No MCP servers to render")
return ""
}

// Build tree structure
root := console.TreeNode{
Value: "MCP Servers",
Children: make([]console.TreeNode, 0, len(configs)),
}

for _, config := range configs {
serverNode := console.TreeNode{
Value: fmt.Sprintf("📦 %s (%s)", config.Name, config.Type),
Children: []console.TreeNode{},
}

// Add server info if available
if info, ok := serverInfos[config.Name]; ok && info != nil {
// Create a map for quick lookup of allowed tools
allowedMap := make(map[string]bool)
hasWildcard := false
for _, allowed := range config.Allowed {
if allowed == "*" {
hasWildcard = true
}
allowedMap[allowed] = true
}

// Add tools section
if len(info.Tools) > 0 {
toolsNode := console.TreeNode{
Value: fmt.Sprintf("🛠️ Tools (%d)", len(info.Tools)),
Children: make([]console.TreeNode, 0, len(info.Tools)),
}

for _, tool := range info.Tools {
// Determine if tool is allowed
isAllowed := len(config.Allowed) == 0 || hasWildcard || allowedMap[tool.Name]
allowIcon := "🚫"
if isAllowed {
allowIcon = "✅"
}

// Create tool node with truncated description
toolDesc := tool.Description
if len(toolDesc) > 50 {
toolDesc = toolDesc[:47] + "..."
}

toolValue := fmt.Sprintf("%s %s - %s", allowIcon, tool.Name, toolDesc)
toolsNode.Children = append(toolsNode.Children, console.TreeNode{
Value: toolValue,
Children: []console.TreeNode{},
})
}

serverNode.Children = append(serverNode.Children, toolsNode)
}

// Add resources section
if len(info.Resources) > 0 {
resourcesNode := console.TreeNode{
Value: fmt.Sprintf("📚 Resources (%d)", len(info.Resources)),
Children: make([]console.TreeNode, 0, len(info.Resources)),
}

for _, resource := range info.Resources {
resourceValue := fmt.Sprintf("%s - %s", resource.Name, resource.URI)
resourcesNode.Children = append(resourcesNode.Children, console.TreeNode{
Value: resourceValue,
Children: []console.TreeNode{},
})
}

serverNode.Children = append(serverNode.Children, resourcesNode)
}

// Add roots section
if len(info.Roots) > 0 {
rootsNode := console.TreeNode{
Value: fmt.Sprintf("🌳 Roots (%d)", len(info.Roots)),
Children: make([]console.TreeNode, 0, len(info.Roots)),
}

for _, root := range info.Roots {
rootValue := fmt.Sprintf("%s - %s", root.Name, root.URI)
rootsNode.Children = append(rootsNode.Children, console.TreeNode{
Value: rootValue,
Children: []console.TreeNode{},
})
}

serverNode.Children = append(serverNode.Children, rootsNode)
}
} else {
// Server info not available (error or not yet queried)
serverNode.Children = append(serverNode.Children, console.TreeNode{
Value: "⚠️ Server info not available",
Children: []console.TreeNode{},
})
}

root.Children = append(root.Children, serverNode)
}

// Render the tree
return console.RenderTree(root)
}
112 changes: 0 additions & 112 deletions pkg/cli/mcp_tool_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,115 +255,3 @@ func TestDefaultMCPToolTableOptions(t *testing.T) {
t.Error("Expected default ShowVerboseHint to be false")
}
}

func TestRenderMCPHierarchyTree(t *testing.T) {
// Create test configs
configs := []parser.MCPServerConfig{
{
BaseMCPServerConfig: types.BaseMCPServerConfig{
Type: "stdio",
},
Name: "github",
Allowed: []string{"list_issues", "create_issue"},
},
{
BaseMCPServerConfig: types.BaseMCPServerConfig{
Type: "stdio",
},
Name: "filesystem",
Allowed: []string{"*"},
},
}

// Create test server infos
serverInfos := map[string]*parser.MCPServerInfo{
"github": {
Config: parser.MCPServerConfig{
Name: "github",
Allowed: []string{"list_issues", "create_issue"},
},
Tools: []*mcp.Tool{
{Name: "list_issues", Description: "List GitHub issues"},
{Name: "create_issue", Description: "Create a new GitHub issue"},
{Name: "list_pull_requests", Description: "List pull requests"},
},
Resources: []*mcp.Resource{
{Name: "repo", URI: "github://repo"},
},
Roots: []*mcp.Root{
{Name: "root", URI: "github://root"},
},
},
"filesystem": {
Config: parser.MCPServerConfig{
Name: "filesystem",
Allowed: []string{"*"},
},
Tools: []*mcp.Tool{
{Name: "read_file", Description: "Read a file"},
{Name: "write_file", Description: "Write to a file"},
},
},
}

// Render tree
output := renderMCPHierarchyTree(configs, serverInfos)

// Verify output contains expected elements
expectedStrings := []string{
"MCP Servers",
"github",
"filesystem",
"list_issues",
"create_issue",
"read_file",
"write_file",
"Tools",
"Resources",
"Roots",
}

for _, expected := range expectedStrings {
if !strings.Contains(output, expected) {
t.Errorf("Expected output to contain '%s', but it didn't.\nGot:\n%s", expected, output)
}
}

// Verify output is not empty
if output == "" {
t.Error("renderMCPHierarchyTree returned empty string")
}
}

func TestRenderMCPHierarchyTree_EmptyConfigs(t *testing.T) {
configs := []parser.MCPServerConfig{}
serverInfos := map[string]*parser.MCPServerInfo{}

output := renderMCPHierarchyTree(configs, serverInfos)

if output != "" {
t.Errorf("Expected empty output for empty configs, got: %s", output)
}
}

func TestRenderMCPHierarchyTree_MissingServerInfo(t *testing.T) {
configs := []parser.MCPServerConfig{
{
BaseMCPServerConfig: types.BaseMCPServerConfig{
Type: "stdio",
},
Name: "missing-server",
},
}
serverInfos := map[string]*parser.MCPServerInfo{}

output := renderMCPHierarchyTree(configs, serverInfos)

// Should still render, but with a warning
if !strings.Contains(output, "missing-server") {
t.Errorf("Expected output to contain server name, got: %s", output)
}
if !strings.Contains(output, "Server info not available") {
t.Errorf("Expected output to contain warning about missing info, got: %s", output)
}
}
47 changes: 0 additions & 47 deletions pkg/console/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
"github.com/charmbracelet/lipgloss/tree"
"github.com/github/gh-aw/pkg/logger"
"github.com/github/gh-aw/pkg/styles"
"github.com/github/gh-aw/pkg/tty"
Expand Down Expand Up @@ -200,11 +199,6 @@ func RenderTable(config TableConfig) string {
return output.String()
}

// FormatLocationMessage formats a file/directory location message
func FormatLocationMessage(message string) string {
return applyStyle(styles.Location, "📁 ") + message
}

// FormatCommandMessage formats a command execution message
func FormatCommandMessage(command string) string {
return applyStyle(styles.Command, "⚡ ") + command
Expand All @@ -220,21 +214,11 @@ func FormatPromptMessage(message string) string {
return applyStyle(styles.Prompt, "❓ ") + message
}

// FormatCountMessage formats a count/numeric status message
func FormatCountMessage(message string) string {
return applyStyle(styles.Count, "📊 ") + message
}

// FormatVerboseMessage formats verbose debugging output
func FormatVerboseMessage(message string) string {
return applyStyle(styles.Verbose, "🔍 ") + message
}

// FormatListHeader formats a section header for lists
func FormatListHeader(header string) string {
return applyStyle(styles.ListHeader, header)
}

// FormatListItem formats an item in a list
func FormatListItem(item string) string {
return applyStyle(styles.ListItem, " • "+item)
Expand Down Expand Up @@ -322,34 +306,3 @@ func RenderComposedSections(sections []string) {
fmt.Fprintln(os.Stderr, "")
}
}

// RenderTree renders a hierarchical tree structure using lipgloss/tree package
func RenderTree(root TreeNode) string {
if !isTTY() {
return renderTreeSimple(root, "", true)
}

lipglossTree := buildLipglossTree(root)
return lipglossTree.String()
}

// buildLipglossTree converts our TreeNode structure to lipgloss/tree format
func buildLipglossTree(node TreeNode) *tree.Tree {
t := tree.Root(node.Value).
EnumeratorStyle(styles.TreeEnumerator).
ItemStyle(styles.TreeNode)

if len(node.Children) > 0 {
children := make([]any, len(node.Children))
for i, child := range node.Children {
if len(child.Children) > 0 {
children[i] = buildLipglossTree(child)
} else {
children[i] = child.Value
}
}
t.Child(children...)
}

return t
}
Loading
Loading