diff --git a/pkg/cli/mcp_inspect.go b/pkg/cli/mcp_inspect.go index 77d3679efb1..4efdd8e6bd0 100644 --- a/pkg/cli/mcp_inspect.go +++ b/pkg/cli/mcp_inspect.go @@ -10,7 +10,6 @@ import ( "time" "github.com/githubnext/gh-aw/pkg/console" - "github.com/githubnext/gh-aw/pkg/constants" "github.com/githubnext/gh-aw/pkg/parser" "github.com/githubnext/gh-aw/pkg/workflow" "github.com/spf13/cobra" @@ -356,14 +355,13 @@ func spawnMCPInspector(workflowFile string, serverFilter string, verbose bool) e // If workflow file is specified, extract MCP configurations and start servers if workflowFile != "" { - workflowsDir := constants.GetWorkflowDir() - - // Normalize the workflow file path - if !strings.HasSuffix(workflowFile, ".md") { - workflowFile += ".md" + // Resolve the workflow file path (supports shared workflows) + workflowPath, err := ResolveWorkflowPath(workflowFile) + if err != nil { + return err } - workflowPath := filepath.Join(workflowsDir, workflowFile) + // Convert to absolute path if needed if !filepath.IsAbs(workflowPath) { cwd, err := os.Getwd() if err != nil { @@ -372,11 +370,6 @@ func spawnMCPInspector(workflowFile string, serverFilter string, verbose bool) e workflowPath = filepath.Join(cwd, workflowPath) } - // Check if file exists - if _, err := os.Stat(workflowPath); os.IsNotExist(err) { - return fmt.Errorf("workflow file not found: %s", workflowPath) - } - // Parse the workflow file to extract MCP configurations content, err := os.ReadFile(workflowPath) if err != nil { diff --git a/pkg/cli/resolver.go b/pkg/cli/resolver.go index 6b542a94cf7..8916ca4b506 100644 --- a/pkg/cli/resolver.go +++ b/pkg/cli/resolver.go @@ -10,31 +10,29 @@ import ( // ResolveWorkflowPath resolves a workflow file path from various formats: // - Absolute path to .md file // - Relative path to .md file -// - Workflow name (adds .md extension and looks in .github/workflows) -// - Workflow name with .md extension +// - Workflow name or subpath (e.g., "a.md" -> ".github/workflows/a.md", "shared/b.md" -> ".github/workflows/shared/b.md") func ResolveWorkflowPath(workflowFile string) (string, error) { workflowsDir := ".github/workflows" - var workflowPath string - if strings.HasSuffix(workflowFile, ".md") { - // If it's already a .md file, use it directly if it exists - if _, err := os.Stat(workflowFile); err == nil { - workflowPath = workflowFile - } else { - // Try in workflows directory - workflowPath = filepath.Join(workflowsDir, workflowFile) - } - } else { - // Add .md extension and look in workflows directory - workflowPath = filepath.Join(workflowsDir, workflowFile+".md") + // Add .md extension if not present + searchPath := workflowFile + if !strings.HasSuffix(searchPath, ".md") { + searchPath += ".md" } - // Verify the workflow file exists - if _, err := os.Stat(workflowPath); os.IsNotExist(err) { - return "", fmt.Errorf("workflow file not found: %s", workflowPath) + // 1. If it's a path that exists as-is (absolute or relative), use it + if _, err := os.Stat(searchPath); err == nil { + return searchPath, nil } - return workflowPath, nil + // 2. Try exact relative path under .github/workflows + workflowPath := filepath.Join(workflowsDir, searchPath) + if _, err := os.Stat(workflowPath); err == nil { + return workflowPath, nil + } + + // No matches found + return "", fmt.Errorf("workflow file not found: %s", workflowPath) } // NormalizeWorkflowFile normalizes a workflow file name by adding .md extension if missing diff --git a/pkg/cli/resolver_test.go b/pkg/cli/resolver_test.go index a2cb464e085..509ba8a1c2f 100644 --- a/pkg/cli/resolver_test.go +++ b/pkg/cli/resolver_test.go @@ -27,18 +27,38 @@ func TestResolveWorkflowPath(t *testing.T) { t.Fatalf("Failed to change to temp directory: %v", err) } - // Create .github/workflows directory + // Create .github/workflows directory structure workflowsDir := filepath.Join(constants.GetWorkflowDir()) if err := os.MkdirAll(workflowsDir, 0755); err != nil { t.Fatalf("Failed to create workflows directory: %v", err) } - // Create test workflow files + sharedDir := filepath.Join(workflowsDir, "shared") + if err := os.MkdirAll(sharedDir, 0755); err != nil { + t.Fatalf("Failed to create shared directory: %v", err) + } + + sharedMCPDir := filepath.Join(sharedDir, "mcp") + if err := os.MkdirAll(sharedMCPDir, 0755); err != nil { + t.Fatalf("Failed to create shared/mcp directory: %v", err) + } + + // Create test workflow files in different locations testWorkflow := filepath.Join(workflowsDir, "test-workflow.md") if err := os.WriteFile(testWorkflow, []byte("# Test"), 0644); err != nil { t.Fatalf("Failed to create test workflow: %v", err) } + sharedWorkflow := filepath.Join(sharedDir, "shared-workflow.md") + if err := os.WriteFile(sharedWorkflow, []byte("# Shared"), 0644); err != nil { + t.Fatalf("Failed to create shared workflow: %v", err) + } + + mcpWorkflow := filepath.Join(sharedMCPDir, "serena.md") + if err := os.WriteFile(mcpWorkflow, []byte("# MCP"), 0644); err != nil { + t.Fatalf("Failed to create MCP workflow: %v", err) + } + tests := []struct { name string input string @@ -46,15 +66,45 @@ func TestResolveWorkflowPath(t *testing.T) { expectError bool }{ { - name: "workflow name without extension", + name: "workflow name without extension in workflows dir", input: "test-workflow", expected: testWorkflow, }, { - name: "workflow name with extension", + name: "workflow name with extension in workflows dir", input: "test-workflow.md", expected: testWorkflow, }, + { + name: "full relative path to shared workflow", + input: "shared/shared-workflow.md", + expected: sharedWorkflow, + }, + { + name: "full relative path to shared workflow without extension", + input: "shared/shared-workflow", + expected: sharedWorkflow, + }, + { + name: "full relative path to shared/mcp workflow", + input: "shared/mcp/serena.md", + expected: mcpWorkflow, + }, + { + name: "full relative path to shared/mcp workflow without extension", + input: "shared/mcp/serena", + expected: mcpWorkflow, + }, + { + name: "basename only (no recursive matching)", + input: "serena", + expectError: true, + }, + { + name: "partial subpath (no recursive matching)", + input: "mcp/serena", + expectError: true, + }, { name: "nonexistent workflow", input: "nonexistent",