diff --git a/pkg/cli/dependency_graph.go b/pkg/cli/dependency_graph.go index a9062cf43c..11a56f8eeb 100644 --- a/pkg/cli/dependency_graph.go +++ b/pkg/cli/dependency_graph.go @@ -133,19 +133,24 @@ func (g *DependencyGraph) addWorkflow(workflowPath string, compiler *workflow.Co // extractImportsFromFile extracts imports directly from a workflow file func (g *DependencyGraph) extractImportsFromFile(workflowPath string) ([]string, error) { + depGraphLog.Printf("Extracting imports from file: %s", workflowPath) // Read the file content, err := os.ReadFile(workflowPath) if err != nil { + depGraphLog.Printf("Failed to read file %s: %v", workflowPath, err) return nil, err } // Parse frontmatter result, err := parser.ExtractFrontmatterFromContent(string(content)) if err != nil { + depGraphLog.Printf("Failed to parse frontmatter from %s: %v", workflowPath, err) return nil, err } - return g.extractImportsFromFrontmatter(workflowPath, result.Frontmatter), nil + imports := g.extractImportsFromFrontmatter(workflowPath, result.Frontmatter) + depGraphLog.Printf("Extracted %d imports from %s", len(imports), workflowPath) + return imports, nil } // extractImportsFromFrontmatter extracts the list of imported file paths from frontmatter @@ -154,14 +159,18 @@ func (g *DependencyGraph) extractImportsFromFrontmatter(workflowPath string, fro // Get frontmatter to extract imports if frontmatter == nil { + depGraphLog.Printf("No frontmatter found in %s", workflowPath) return imports } importsField, exists := frontmatter["imports"] if !exists { + depGraphLog.Printf("No imports field in frontmatter for %s", workflowPath) return imports } + depGraphLog.Printf("Processing imports field from %s", workflowPath) + // Parse imports field - can be array of strings or objects with path workflowDir := filepath.Dir(workflowPath) switch v := importsField.(type) { @@ -227,20 +236,24 @@ func (g *DependencyGraph) resolveImportPath(importPath string, baseDir string) s // findGitRoot finds the git repository root func (g *DependencyGraph) findGitRoot() string { + depGraphLog.Printf("Finding git root starting from: %s", g.workflowsDir) // Start from workflows directory and walk up dir := g.workflowsDir for { gitDir := filepath.Join(dir, ".git") if _, err := os.Stat(gitDir); err == nil { + depGraphLog.Printf("Found git root at: %s", dir) return dir } parent := filepath.Dir(dir) if parent == dir { // Reached filesystem root + depGraphLog.Printf("Reached filesystem root, no .git directory found") break } dir = parent } + depGraphLog.Printf("Using fallback git root: %s", g.workflowsDir) return g.workflowsDir // Fallback to workflows dir } diff --git a/pkg/cli/enable.go b/pkg/cli/enable.go index 916809124c..00e4496ef2 100644 --- a/pkg/cli/enable.go +++ b/pkg/cli/enable.go @@ -19,11 +19,13 @@ var enableLog = logger.New("cli:enable") // EnableWorkflowsByNames enables workflows by specific names, or all if no names provided func EnableWorkflowsByNames(workflowNames []string, repoOverride string) error { + enableLog.Printf("EnableWorkflowsByNames called: workflow_count=%d, repo=%s", len(workflowNames), repoOverride) return toggleWorkflowsByNames(workflowNames, true, repoOverride) } // DisableWorkflowsByNames disables workflows by specific names, or all if no names provided func DisableWorkflowsByNames(workflowNames []string, repoOverride string) error { + enableLog.Printf("DisableWorkflowsByNames called: workflow_count=%d, repo=%s", len(workflowNames), repoOverride) return toggleWorkflowsByNames(workflowNames, false, repoOverride) } @@ -94,11 +96,14 @@ func toggleWorkflowsByNames(workflowNames []string, enable bool, repoOverride st } // Get GitHub workflows status for comparison; warn but continue if unavailable + enableLog.Print("Fetching GitHub workflows status for comparison") githubWorkflows, err := fetchGitHubWorkflows("", false) if err != nil { + enableLog.Printf("Failed to fetch GitHub workflows: %v", err) fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Unable to fetch GitHub workflows (gh CLI may not be authenticated): %v", err))) githubWorkflows = make(map[string]*GitHubWorkflow) } + enableLog.Printf("Retrieved %d GitHub workflows from remote", len(githubWorkflows)) // Internal target model to support enabling by ID or lock filename type workflowTarget struct { @@ -178,6 +183,7 @@ func toggleWorkflowsByNames(workflowNames []string, enable bool, repoOverride st // Report any workflows that weren't found if len(notFoundNames) > 0 { + enableLog.Printf("Workflows not found: %v", notFoundNames) suggestions := []string{ fmt.Sprintf("Run '%s status' to see all available workflows", string(constants.CLIExtensionPrefix)), "Check for typos in the workflow names", @@ -200,10 +206,12 @@ func toggleWorkflowsByNames(workflowNames []string, enable bool, repoOverride st // If no targets after filtering, everything was already in the desired state if len(targets) == 0 { + enableLog.Printf("No workflows need to be %sd - all already in desired state", action) fmt.Fprintf(os.Stderr, "All specified workflows are already %sd\n", action) return nil } + enableLog.Printf("Proceeding to %s %d workflows", action, len(targets)) // Show what will be changed fmt.Fprintf(os.Stderr, "The following workflows will be %sd:\n", action) for _, t := range targets { diff --git a/pkg/cli/spec.go b/pkg/cli/spec.go index f65f2f420a..6f772d05b6 100644 --- a/pkg/cli/spec.go +++ b/pkg/cli/spec.go @@ -81,30 +81,38 @@ func parseRepoSpec(repoSpec string) (*RepoSpec, error) { var version string if len(parts) == 2 { version = parts[1] + specLog.Printf("Version specified: %s", version) } // Check if this is a GitHub URL if strings.HasPrefix(repo, "https://github.com/") || strings.HasPrefix(repo, "http://github.com/") { + specLog.Print("Detected GitHub URL format") // Parse GitHub URL: https://github.com/owner/repo repoURL, err := url.Parse(repo) if err != nil { + specLog.Printf("Failed to parse GitHub URL: %v", err) return nil, fmt.Errorf("invalid GitHub URL: %w", err) } // Extract owner/repo from path pathParts := strings.Split(strings.Trim(repoURL.Path, "/"), "/") if len(pathParts) != 2 || pathParts[0] == "" || pathParts[1] == "" { + specLog.Printf("Invalid GitHub URL path parts: %v", pathParts) return nil, fmt.Errorf("invalid GitHub URL: must be https://github.com/owner/repo. Example: https://github.com/githubnext/gh-aw") } repo = fmt.Sprintf("%s/%s", pathParts[0], pathParts[1]) + specLog.Printf("Extracted repo from URL: %s", repo) } else if repo == "." { + specLog.Print("Resolving current directory as repo") // Handle current directory as repo (local workflow) currentRepo, err := GetCurrentRepoSlug() if err != nil { + specLog.Printf("Failed to get current repo: %v", err) return nil, fmt.Errorf("failed to get current repository info: %w", err) } repo = currentRepo + specLog.Printf("Resolved current repo: %s", repo) } else { // Validate repository format (org/repo) repoParts := strings.Split(repo, "/") @@ -118,6 +126,7 @@ func parseRepoSpec(repoSpec string) (*RepoSpec, error) { Version: version, } + specLog.Printf("Parsed repo spec successfully: repo=%s, version=%s", repo, version) return spec, nil } @@ -131,22 +140,28 @@ func parseRepoSpec(repoSpec string) (*RepoSpec, error) { // - https://raw.githubusercontent.com/owner/repo/COMMIT_SHA/path/to/workflow.md // - https://raw.githubusercontent.com/owner/repo/refs/tags/tag/path/to/workflow.md func parseGitHubURL(spec string) (*WorkflowSpec, error) { + specLog.Printf("Parsing GitHub URL: %s", spec) // First validate that this is a GitHub URL (github.com or raw.githubusercontent.com) parsedURL, err := url.Parse(spec) if err != nil { + specLog.Printf("Failed to parse URL: %v", err) return nil, fmt.Errorf("invalid URL: %w", err) } // Must be a GitHub URL if parsedURL.Host != "github.com" && parsedURL.Host != "raw.githubusercontent.com" { + specLog.Printf("Invalid host: %s", parsedURL.Host) return nil, fmt.Errorf("URL must be from github.com or raw.githubusercontent.com") } owner, repo, ref, filePath, err := parser.ParseRepoFileURL(spec) if err != nil { + specLog.Printf("Failed to parse repo file URL: %v", err) return nil, err } + specLog.Printf("Parsed GitHub URL: owner=%s, repo=%s, ref=%s, path=%s", owner, repo, ref, filePath) + // Ensure the file path ends with .md if !strings.HasSuffix(filePath, ".md") { return nil, fmt.Errorf("GitHub URL must point to a .md file") @@ -271,17 +286,22 @@ func parseWorkflowSpec(spec string) (*WorkflowSpec, error) { // parseLocalWorkflowSpec parses a local workflow specification starting with "./" func parseLocalWorkflowSpec(spec string) (*WorkflowSpec, error) { + specLog.Printf("Parsing local workflow spec: %s", spec) // Validate that it's a .md file if !strings.HasSuffix(spec, ".md") { + specLog.Printf("Invalid extension for local workflow: %s", spec) return nil, fmt.Errorf("local workflow specification must end with '.md' extension: %s", spec) } // Get current repository info repoInfo, err := GetCurrentRepoSlug() if err != nil { + specLog.Printf("Failed to get current repo slug: %v", err) return nil, fmt.Errorf("failed to get current repository info for local workflow: %w", err) } + specLog.Printf("Parsed local workflow: repo=%s, path=%s", repoInfo, spec) + return &WorkflowSpec{ RepoSpec: RepoSpec{ RepoSlug: repoInfo, diff --git a/pkg/workflow/claude_tools.go b/pkg/workflow/claude_tools.go index d4086c3713..77659dc7d4 100644 --- a/pkg/workflow/claude_tools.go +++ b/pkg/workflow/claude_tools.go @@ -14,6 +14,7 @@ var claudeToolsLog = logger.New("workflow:claude_tools") // expandNeutralToolsToClaudeTools converts neutral tool names to Claude-specific tool configurations func (e *ClaudeEngine) expandNeutralToolsToClaudeTools(tools map[string]any) map[string]any { + claudeToolsLog.Printf("Starting neutral tools expansion: input_tools=%d", len(tools)) result := make(map[string]any) neutralToolCount := 0 @@ -110,6 +111,7 @@ func (e *ClaudeEngine) expandNeutralToolsToClaudeTools(tools map[string]any) map claudeSection["allowed"] = claudeAllowed result["claude"] = claudeSection + claudeToolsLog.Printf("Expansion complete: result_tools=%d, claude_allowed=%d", len(result), len(claudeAllowed)) return result } @@ -136,10 +138,12 @@ func (e *ClaudeEngine) computeAllowedClaudeToolsString(tools map[string]any, saf // Enforce that only neutral tools are provided - fail if claude section is present if _, hasClaudeSection := tools["claude"]; hasClaudeSection { + claudeToolsLog.Print("ERROR: Claude section found in input tools, should only contain neutral tools") panic("computeAllowedClaudeToolsString should only receive neutral tools, not claude section tools") } // Convert neutral tools to Claude-specific tools + claudeToolsLog.Print("Converting neutral tools to Claude-specific format") tools = e.expandNeutralToolsToClaudeTools(tools) defaultClaudeTools := []string{ diff --git a/pkg/workflow/script_registry.go b/pkg/workflow/script_registry.go index 74e98cafa6..efbd978c7b 100644 --- a/pkg/workflow/script_registry.go +++ b/pkg/workflow/script_registry.go @@ -89,6 +89,7 @@ type ScriptRegistry struct { // NewScriptRegistry creates a new empty script registry. func NewScriptRegistry() *ScriptRegistry { + registryLog.Print("Creating new script registry") return &ScriptRegistry{ scripts: make(map[string]*scriptEntry), } @@ -198,8 +199,14 @@ func (r *ScriptRegistry) GetActionPath(name string) string { entry, exists := r.scripts[name] if !exists { + if registryLog.Enabled() { + registryLog.Printf("GetActionPath: script not found: %s", name) + } return "" } + if registryLog.Enabled() && entry.actionPath != "" { + registryLog.Printf("GetActionPath: returning action path for %s: %s", name, entry.actionPath) + } return entry.actionPath } @@ -353,6 +360,7 @@ func GetScriptWithMode(name string, mode RuntimeMode) string { // This is used by the build system to discover which files need to be embedded in custom actions. // The returned list includes all .cjs files found in pkg/workflow/js/, including dependencies. func GetAllScriptFilenames() []string { + registryLog.Print("Getting all script filenames from JavaScript sources") sources := GetJavaScriptSources() filenames := make([]string, 0, len(sources)) @@ -363,6 +371,8 @@ func GetAllScriptFilenames() []string { } } + registryLog.Printf("Found %d .cjs files in JavaScript sources", len(filenames)) + // Sort for consistency sortedFilenames := make([]string, len(filenames)) copy(sortedFilenames, filenames)