diff --git a/.changeset/patch-add-changeset-automation.md b/.changeset/patch-add-changeset-automation.md new file mode 100644 index 00000000000..e444ade16ab --- /dev/null +++ b/.changeset/patch-add-changeset-automation.md @@ -0,0 +1,5 @@ +--- +"gh-aw": patch +--- + +Add automated changeset generation workflow that creates changeset files when pull requests are marked as ready for review diff --git a/pkg/workflow/js.go b/pkg/workflow/js.go index c3488c34b82..7293ea714bb 100644 --- a/pkg/workflow/js.go +++ b/pkg/workflow/js.go @@ -4,7 +4,6 @@ import ( _ "embed" "fmt" "strings" - "sync" "github.com/githubnext/gh-aw/pkg/logger" ) @@ -23,28 +22,17 @@ var addReactionAndEditCommentScript string //go:embed js/check_membership.cjs var checkMembershipScriptSource string -var ( - checkMembershipScript string - checkMembershipScriptOnce sync.Once -) +// init registers scripts from js.go with the DefaultScriptRegistry +func init() { + DefaultScriptRegistry.Register("check_membership", checkMembershipScriptSource) + DefaultScriptRegistry.Register("safe_outputs_mcp_server", safeOutputsMCPServerScriptSource) + DefaultScriptRegistry.Register("update_project", updateProjectScriptSource) + DefaultScriptRegistry.Register("interpolate_prompt", interpolatePromptScript) +} // getCheckMembershipScript returns the bundled check_membership script -// Bundling is performed on first access and cached for subsequent calls func getCheckMembershipScript() string { - checkMembershipScriptOnce.Do(func() { - jsLog.Print("Bundling check_membership script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(checkMembershipScriptSource, sources, "") - if err != nil { - jsLog.Printf("Failed to bundle check_membership script, using source as-is: %v", err) - // If bundling fails, use the source as-is - checkMembershipScript = checkMembershipScriptSource - } else { - jsLog.Printf("Successfully bundled check_membership script: %d bytes", len(bundled)) - checkMembershipScript = bundled - } - }) - return checkMembershipScript + return DefaultScriptRegistry.Get("check_membership") } //go:embed js/check_stop_time.cjs @@ -71,28 +59,9 @@ var missingToolScript string //go:embed js/safe_outputs_mcp_server.cjs var safeOutputsMCPServerScriptSource string -var ( - safeOutputsMCPServerScript string - safeOutputsMCPServerScriptOnce sync.Once -) - // getSafeOutputsMCPServerScript returns the bundled safe_outputs_mcp_server script -// Bundling is performed on first access and cached for subsequent calls func getSafeOutputsMCPServerScript() string { - safeOutputsMCPServerScriptOnce.Do(func() { - jsLog.Print("Bundling safe_outputs_mcp_server script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(safeOutputsMCPServerScriptSource, sources, "") - if err != nil { - jsLog.Printf("Failed to bundle safe_outputs_mcp_server script, using source as-is: %v", err) - // If bundling fails, use the source as-is - safeOutputsMCPServerScript = safeOutputsMCPServerScriptSource - } else { - jsLog.Printf("Successfully bundled safe_outputs_mcp_server script: %d bytes", len(bundled)) - safeOutputsMCPServerScript = bundled - } - }) - return safeOutputsMCPServerScript + return DefaultScriptRegistry.Get("safe_outputs_mcp_server") } //go:embed js/safe_outputs_tools.json @@ -140,28 +109,9 @@ var updateActivationCommentScript string //go:embed js/update_project.cjs var updateProjectScriptSource string -var ( - updateProjectScript string - updateProjectScriptOnce sync.Once -) - // getUpdateProjectScript returns the bundled update_project script -// Bundling is performed on first access and cached for subsequent calls func getUpdateProjectScript() string { - updateProjectScriptOnce.Do(func() { - jsLog.Print("Bundling update_project script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(updateProjectScriptSource, sources, "") - if err != nil { - jsLog.Printf("Failed to bundle update_project script, using source as-is: %v", err) - // If bundling fails, use the source as-is - updateProjectScript = updateProjectScriptSource - } else { - jsLog.Printf("Successfully bundled update_project script: %d bytes", len(bundled)) - updateProjectScript = bundled - } - }) - return updateProjectScript + return DefaultScriptRegistry.Get("update_project") } //go:embed js/generate_footer.cjs diff --git a/pkg/workflow/script_registry.go b/pkg/workflow/script_registry.go new file mode 100644 index 00000000000..53b1818cda3 --- /dev/null +++ b/pkg/workflow/script_registry.go @@ -0,0 +1,190 @@ +// Package workflow provides a ScriptRegistry for managing JavaScript script bundling. +// +// # Script Registry Pattern +// +// The ScriptRegistry eliminates the repetitive sync.Once pattern found throughout +// the codebase for lazy script bundling. Instead of declaring separate variables +// and getter functions for each script, register scripts once and retrieve them +// by name. +// +// # Before (repetitive pattern): +// +// var ( +// createIssueScript string +// createIssueScriptOnce sync.Once +// ) +// +// func getCreateIssueScript() string { +// createIssueScriptOnce.Do(func() { +// sources := GetJavaScriptSources() +// bundled, err := BundleJavaScriptFromSources(createIssueScriptSource, sources, "") +// if err != nil { +// createIssueScript = createIssueScriptSource +// } else { +// createIssueScript = bundled +// } +// }) +// return createIssueScript +// } +// +// # After (using registry): +// +// // Registration at package init +// DefaultScriptRegistry.Register("create_issue", createIssueScriptSource) +// +// // Usage anywhere +// script := DefaultScriptRegistry.Get("create_issue") +// +// # Benefits +// +// - Eliminates ~15 lines of boilerplate per script (variable pair + getter function) +// - Centralizes bundling logic +// - Consistent error handling +// - Thread-safe lazy initialization +// - Easy to add new scripts +package workflow + +import ( + "sync" + + "github.com/githubnext/gh-aw/pkg/logger" +) + +var registryLog = logger.New("workflow:script_registry") + +// scriptEntry holds the source and bundled versions of a script +type scriptEntry struct { + source string + bundled string + once sync.Once +} + +// ScriptRegistry manages lazy bundling of JavaScript scripts. +// It provides a centralized place to register source scripts and retrieve +// bundled versions on-demand with caching. +// +// Thread-safe: All operations use internal synchronization. +// +// Usage: +// +// registry := NewScriptRegistry() +// registry.Register("my_script", myScriptSource) +// bundled := registry.Get("my_script") +type ScriptRegistry struct { + mu sync.RWMutex + scripts map[string]*scriptEntry +} + +// NewScriptRegistry creates a new empty script registry. +func NewScriptRegistry() *ScriptRegistry { + return &ScriptRegistry{ + scripts: make(map[string]*scriptEntry), + } +} + +// Register adds a script source to the registry. +// The script will be bundled lazily on first access via Get(). +// +// Parameters: +// - name: Unique identifier for the script (e.g., "create_issue", "add_comment") +// - source: The raw JavaScript source code (typically from go:embed) +// +// If a script with the same name already exists, it will be overwritten. +// This is useful for testing but should be avoided in production. +func (r *ScriptRegistry) Register(name string, source string) { + r.mu.Lock() + defer r.mu.Unlock() + + if registryLog.Enabled() { + registryLog.Printf("Registering script: %s (%d bytes)", name, len(source)) + } + + r.scripts[name] = &scriptEntry{ + source: source, + } +} + +// Get retrieves a bundled script by name. +// Bundling is performed lazily on first access and cached for subsequent calls. +// +// If bundling fails, the original source is returned as a fallback. +// If the script is not registered, an empty string is returned. +// +// Thread-safe: Multiple goroutines can call Get concurrently. +func (r *ScriptRegistry) Get(name string) string { + r.mu.RLock() + entry, exists := r.scripts[name] + r.mu.RUnlock() + + if !exists { + if registryLog.Enabled() { + registryLog.Printf("Script not found: %s", name) + } + return "" + } + + entry.once.Do(func() { + if registryLog.Enabled() { + registryLog.Printf("Bundling script: %s", name) + } + + sources := GetJavaScriptSources() + bundled, err := BundleJavaScriptFromSources(entry.source, sources, "") + if err != nil { + registryLog.Printf("Bundling failed for %s, using source as-is: %v", name, err) + entry.bundled = entry.source + } else { + if registryLog.Enabled() { + registryLog.Printf("Successfully bundled %s: %d bytes", name, len(bundled)) + } + entry.bundled = bundled + } + }) + + return entry.bundled +} + +// GetSource retrieves the original (unbundled) source for a script. +// Useful for testing or when bundling is not needed. +func (r *ScriptRegistry) GetSource(name string) string { + r.mu.RLock() + defer r.mu.RUnlock() + + entry, exists := r.scripts[name] + if !exists { + return "" + } + return entry.source +} + +// Has checks if a script is registered in the registry. +func (r *ScriptRegistry) Has(name string) bool { + r.mu.RLock() + defer r.mu.RUnlock() + + _, exists := r.scripts[name] + return exists +} + +// Names returns a list of all registered script names. +// Useful for debugging and testing. +func (r *ScriptRegistry) Names() []string { + r.mu.RLock() + defer r.mu.RUnlock() + + names := make([]string, 0, len(r.scripts)) + for name := range r.scripts { + names = append(names, name) + } + return names +} + +// DefaultScriptRegistry is the global script registry used by the workflow package. +// Scripts are registered during package initialization via init() functions. +var DefaultScriptRegistry = NewScriptRegistry() + +// GetScript retrieves a bundled script from the default registry. +// This is a convenience function equivalent to DefaultScriptRegistry.Get(name). +func GetScript(name string) string { + return DefaultScriptRegistry.Get(name) +} diff --git a/pkg/workflow/script_registry_test.go b/pkg/workflow/script_registry_test.go new file mode 100644 index 00000000000..42a07d10455 --- /dev/null +++ b/pkg/workflow/script_registry_test.go @@ -0,0 +1,159 @@ +package workflow + +import ( + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestScriptRegistry_Register(t *testing.T) { + registry := NewScriptRegistry() + + registry.Register("test_script", "console.log('hello');") + + assert.True(t, registry.Has("test_script")) + assert.False(t, registry.Has("nonexistent")) +} + +func TestScriptRegistry_Get_NotFound(t *testing.T) { + registry := NewScriptRegistry() + + result := registry.Get("nonexistent") + + assert.Empty(t, result) +} + +func TestScriptRegistry_Get_BundlesOnce(t *testing.T) { + registry := NewScriptRegistry() + + // Register a simple script that doesn't require bundling + source := "console.log('hello');" + registry.Register("simple", source) + + // Get should bundle and return result + result1 := registry.Get("simple") + result2 := registry.Get("simple") + + // Both calls should return the same result (cached) + assert.Equal(t, result1, result2) + assert.NotEmpty(t, result1) +} + +func TestScriptRegistry_GetSource(t *testing.T) { + registry := NewScriptRegistry() + + source := "const x = 1;" + registry.Register("test", source) + + // GetSource should return original source + assert.Equal(t, source, registry.GetSource("test")) +} + +func TestScriptRegistry_GetSource_NotFound(t *testing.T) { + registry := NewScriptRegistry() + + result := registry.GetSource("nonexistent") + + assert.Empty(t, result) +} + +func TestScriptRegistry_Names(t *testing.T) { + registry := NewScriptRegistry() + + registry.Register("script_a", "a") + registry.Register("script_b", "b") + registry.Register("script_c", "c") + + names := registry.Names() + + assert.Len(t, names, 3) + assert.Contains(t, names, "script_a") + assert.Contains(t, names, "script_b") + assert.Contains(t, names, "script_c") +} + +func TestScriptRegistry_ConcurrentAccess(t *testing.T) { + registry := NewScriptRegistry() + source := "console.log('concurrent test');" + registry.Register("concurrent", source) + + // Test concurrent Get calls + var wg sync.WaitGroup + results := make([]string, 10) + + for i := 0; i < 10; i++ { + wg.Add(1) + go func(idx int) { + defer wg.Done() + results[idx] = registry.Get("concurrent") + }(i) + } + + wg.Wait() + + // All results should be the same (due to Once semantics) + for i := 1; i < 10; i++ { + assert.Equal(t, results[0], results[i], "concurrent access should return consistent results") + } +} + +func TestScriptRegistry_Overwrite(t *testing.T) { + registry := NewScriptRegistry() + + registry.Register("test", "original") + assert.Equal(t, "original", registry.GetSource("test")) + + registry.Register("test", "updated") + assert.Equal(t, "updated", registry.GetSource("test")) +} + +func TestScriptRegistry_Overwrite_AfterGet(t *testing.T) { + registry := NewScriptRegistry() + + // Register initial script + registry.Register("test", "console.log('original');") + + // Trigger bundling by calling Get() + firstResult := registry.Get("test") + assert.NotEmpty(t, firstResult) + assert.Contains(t, firstResult, "original") + + // Overwrite with new source + registry.Register("test", "console.log('updated');") + + // Verify GetSource returns new source + assert.Equal(t, "console.log('updated');", registry.GetSource("test")) + + // Verify Get() returns bundled version of new source + secondResult := registry.Get("test") + assert.NotEmpty(t, secondResult) + assert.Contains(t, secondResult, "updated") + assert.NotContains(t, secondResult, "original") +} + +func TestDefaultScriptRegistry_GetScript(t *testing.T) { + // Create a fresh registry for this test to avoid interference + oldRegistry := DefaultScriptRegistry + DefaultScriptRegistry = NewScriptRegistry() + defer func() { DefaultScriptRegistry = oldRegistry }() + + // Register a test script + DefaultScriptRegistry.Register("test_global", "global test") + + // GetScript should use DefaultScriptRegistry + result := GetScript("test_global") + require.NotEmpty(t, result) +} + +func TestScriptRegistry_Has(t *testing.T) { + registry := NewScriptRegistry() + + assert.False(t, registry.Has("missing")) + + registry.Register("present", "code") + + assert.True(t, registry.Has("present")) + assert.False(t, registry.Has("still_missing")) +} diff --git a/pkg/workflow/scripts.go b/pkg/workflow/scripts.go index 48d690510e3..ef9bed0a734 100644 --- a/pkg/workflow/scripts.go +++ b/pkg/workflow/scripts.go @@ -1,14 +1,18 @@ +// Package workflow provides embedded JavaScript scripts for GitHub Actions workflows. +// +// # Script Registry Pattern +// +// This file uses the ScriptRegistry pattern to manage lazy bundling of JavaScript +// scripts. Instead of having separate sync.Once patterns for each script, all scripts +// are registered with the DefaultScriptRegistry and bundled on-demand. +// +// See script_registry.go for the ScriptRegistry implementation. package workflow import ( _ "embed" - "sync" - - "github.com/githubnext/gh-aw/pkg/logger" ) -var scriptsLog = logger.New("workflow:scripts") - // Source scripts that may contain local requires // //go:embed js/collect_ndjson_output.cjs @@ -91,567 +95,174 @@ var parseCodexLogScriptSource string //go:embed js/parse_copilot_log.cjs var parseCopilotLogScriptSource string -// Bundled scripts (lazily bundled on-demand and cached) -var ( - collectJSONLOutputScript string - collectJSONLOutputScriptOnce sync.Once - - computeTextScript string - computeTextScriptOnce sync.Once - - sanitizeOutputScript string - sanitizeOutputScriptOnce sync.Once - - createIssueScript string - createIssueScriptOnce sync.Once - - addLabelsScript string - addLabelsScriptOnce sync.Once - - addReviewerScript string - addReviewerScriptOnce sync.Once - - assignMilestoneScript string - assignMilestoneScriptOnce sync.Once - - assignToAgentScript string - assignToAgentScriptOnce sync.Once - - createDiscussionScript string - createDiscussionScriptOnce sync.Once - - closeDiscussionScript string - closeDiscussionScriptOnce sync.Once - - closeIssueScript string - closeIssueScriptOnce sync.Once - - closePullRequestScript string - closePullRequestScriptOnce sync.Once - - updateIssueScript string - updateIssueScriptOnce sync.Once - - updateReleaseScript string - updateReleaseScriptOnce sync.Once - - createCodeScanningAlertScript string - createCodeScanningAlertScriptOnce sync.Once - - createPRReviewCommentScript string - createPRReviewCommentScriptOnce sync.Once - - addCommentScript string - addCommentScriptOnce sync.Once - - uploadAssetsScript string - uploadAssetsScriptOnce sync.Once - - parseFirewallLogsScript string - parseFirewallLogsScriptOnce sync.Once - - pushToPullRequestBranchScript string - pushToPullRequestBranchScriptOnce sync.Once - - createPullRequestScript string - createPullRequestScriptOnce sync.Once - - notifyCommentErrorScript string - notifyCommentErrorScriptOnce sync.Once - - noopScriptBundled string - noopScriptBundledOnce sync.Once - - interpolatePromptBundled string - interpolatePromptBundledOnce sync.Once - - parseClaudeLogBundled string - parseClaudeLogBundledOnce sync.Once - - parseCodexLogBundled string - parseCodexLogBundledOnce sync.Once +// init registers all scripts with the DefaultScriptRegistry. +// Scripts are bundled lazily on first access via the getter functions. +func init() { + // Safe output scripts + DefaultScriptRegistry.Register("collect_jsonl_output", collectJSONLOutputScriptSource) + DefaultScriptRegistry.Register("compute_text", computeTextScriptSource) + DefaultScriptRegistry.Register("sanitize_output", sanitizeOutputScriptSource) + DefaultScriptRegistry.Register("create_issue", createIssueScriptSource) + DefaultScriptRegistry.Register("add_labels", addLabelsScriptSource) + DefaultScriptRegistry.Register("add_reviewer", addReviewerScriptSource) + DefaultScriptRegistry.Register("assign_milestone", assignMilestoneScriptSource) + DefaultScriptRegistry.Register("assign_to_agent", assignToAgentScriptSource) + DefaultScriptRegistry.Register("create_discussion", createDiscussionScriptSource) + DefaultScriptRegistry.Register("close_discussion", closeDiscussionScriptSource) + DefaultScriptRegistry.Register("close_issue", closeIssueScriptSource) + DefaultScriptRegistry.Register("close_pull_request", closePullRequestScriptSource) + DefaultScriptRegistry.Register("update_issue", updateIssueScriptSource) + DefaultScriptRegistry.Register("update_release", updateReleaseScriptSource) + DefaultScriptRegistry.Register("create_code_scanning_alert", createCodeScanningAlertScriptSource) + DefaultScriptRegistry.Register("create_pr_review_comment", createPRReviewCommentScriptSource) + DefaultScriptRegistry.Register("add_comment", addCommentScriptSource) + DefaultScriptRegistry.Register("upload_assets", uploadAssetsScriptSource) + DefaultScriptRegistry.Register("parse_firewall_logs", parseFirewallLogsScriptSource) + DefaultScriptRegistry.Register("push_to_pull_request_branch", pushToPullRequestBranchScriptSource) + DefaultScriptRegistry.Register("create_pull_request", createPullRequestScriptSource) + DefaultScriptRegistry.Register("notify_comment_error", notifyCommentErrorScriptSource) + DefaultScriptRegistry.Register("noop", noopScriptSource) + + // Log parser scripts + DefaultScriptRegistry.Register("parse_claude_log", parseClaudeLogScriptSource) + DefaultScriptRegistry.Register("parse_codex_log", parseCodexLogScriptSource) + DefaultScriptRegistry.Register("parse_copilot_log", parseCopilotLogScriptSource) +} - parseCopilotLogBundled string - parseCopilotLogBundledOnce sync.Once -) +// Getter functions for bundled scripts. +// These use the ScriptRegistry for lazy bundling with caching. // getCollectJSONLOutputScript returns the bundled collect_ndjson_output script -// Bundling is performed on first access and cached for subsequent calls func getCollectJSONLOutputScript() string { - collectJSONLOutputScriptOnce.Do(func() { - scriptsLog.Print("Bundling collect_ndjson_output script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(collectJSONLOutputScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for collect_ndjson_output, using source as-is: %v", err) - // If bundling fails, use the source as-is - collectJSONLOutputScript = collectJSONLOutputScriptSource - } else { - scriptsLog.Printf("Successfully bundled collect_ndjson_output script: %d bytes", len(bundled)) - collectJSONLOutputScript = bundled - } - }) - return collectJSONLOutputScript + return DefaultScriptRegistry.Get("collect_jsonl_output") } // getComputeTextScript returns the bundled compute_text script -// Bundling is performed on first access and cached for subsequent calls func getComputeTextScript() string { - computeTextScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(computeTextScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for compute_text, using source as-is: %v", err) - // If bundling fails, use the source as-is - computeTextScript = computeTextScriptSource - } else { - computeTextScript = bundled - } - }) - return computeTextScript + return DefaultScriptRegistry.Get("compute_text") } // getSanitizeOutputScript returns the bundled sanitize_output script -// Bundling is performed on first access and cached for subsequent calls func getSanitizeOutputScript() string { - sanitizeOutputScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(sanitizeOutputScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for sanitize_output, using source as-is: %v", err) - // If bundling fails, use the source as-is - sanitizeOutputScript = sanitizeOutputScriptSource - } else { - sanitizeOutputScript = bundled - } - }) - return sanitizeOutputScript + return DefaultScriptRegistry.Get("sanitize_output") } // getCreateIssueScript returns the bundled create_issue script -// Bundling is performed on first access and cached for subsequent calls func getCreateIssueScript() string { - createIssueScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(createIssueScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for create_issue, using source as-is: %v", err) - // If bundling fails, use the source as-is - createIssueScript = createIssueScriptSource - } else { - createIssueScript = bundled - } - }) - return createIssueScript + return DefaultScriptRegistry.Get("create_issue") } // getAddLabelsScript returns the bundled add_labels script -// Bundling is performed on first access and cached for subsequent calls func getAddLabelsScript() string { - addLabelsScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(addLabelsScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for add_labels, using source as-is: %v", err) - // If bundling fails, use the source as-is - addLabelsScript = addLabelsScriptSource - } else { - addLabelsScript = bundled - } - }) - return addLabelsScript + return DefaultScriptRegistry.Get("add_labels") } // getAddReviewerScript returns the bundled add_reviewer script -// Bundling is performed on first access and cached for subsequent calls func getAddReviewerScript() string { - addReviewerScriptOnce.Do(func() { - scriptsLog.Print("Bundling add_reviewer script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(addReviewerScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for add_reviewer, using source as-is: %v", err) - // If bundling fails, use the source as-is - addReviewerScript = addReviewerScriptSource - } else { - addReviewerScript = bundled - } - }) - return addReviewerScript + return DefaultScriptRegistry.Get("add_reviewer") } // getAssignMilestoneScript returns the bundled assign_milestone script -// Bundling is performed on first access and cached for subsequent calls func getAssignMilestoneScript() string { - assignMilestoneScriptOnce.Do(func() { - scriptsLog.Print("Bundling assign_milestone script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(assignMilestoneScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for assign_milestone, using source as-is: %v", err) - // If bundling fails, use the source as-is - assignMilestoneScript = assignMilestoneScriptSource - } else { - scriptsLog.Printf("Successfully bundled assign_milestone script: %d bytes", len(bundled)) - assignMilestoneScript = bundled - } - }) - return assignMilestoneScript + return DefaultScriptRegistry.Get("assign_milestone") } // getAssignToAgentScript returns the bundled assign_to_agent script -// Bundling is performed on first access and cached for subsequent calls func getAssignToAgentScript() string { - assignToAgentScriptOnce.Do(func() { - scriptsLog.Print("Bundling assign_to_agent script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(assignToAgentScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for assign_to_agent, using source as-is: %v", err) - // If bundling fails, use the source as-is - assignToAgentScript = assignToAgentScriptSource - } else { - scriptsLog.Printf("Successfully bundled assign_to_agent script: %d bytes", len(bundled)) - assignToAgentScript = bundled - } - }) - return assignToAgentScript + return DefaultScriptRegistry.Get("assign_to_agent") } // getParseFirewallLogsScript returns the bundled parse_firewall_logs script -// Bundling is performed on first access and cached for subsequent calls func getParseFirewallLogsScript() string { - parseFirewallLogsScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(parseFirewallLogsScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for parse_firewall_logs, using source as-is: %v", err) - // If bundling fails, use the source as-is - parseFirewallLogsScript = parseFirewallLogsScriptSource - } else { - parseFirewallLogsScript = bundled - } - }) - return parseFirewallLogsScript + return DefaultScriptRegistry.Get("parse_firewall_logs") } // getCreateDiscussionScript returns the bundled create_discussion script -// Bundling is performed on first access and cached for subsequent calls func getCreateDiscussionScript() string { - createDiscussionScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(createDiscussionScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for create_discussion, using source as-is: %v", err) - // If bundling fails, use the source as-is - createDiscussionScript = createDiscussionScriptSource - } else { - createDiscussionScript = bundled - } - }) - return createDiscussionScript + return DefaultScriptRegistry.Get("create_discussion") } // getCloseDiscussionScript returns the bundled close_discussion script -// Bundling is performed on first access and cached for subsequent calls func getCloseDiscussionScript() string { - closeDiscussionScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(closeDiscussionScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for close_discussion, using source as-is: %v", err) - // If bundling fails, use the source as-is - closeDiscussionScript = closeDiscussionScriptSource - } else { - closeDiscussionScript = bundled - } - }) - return closeDiscussionScript + return DefaultScriptRegistry.Get("close_discussion") } // getCloseIssueScript returns the bundled close_issue script -// Bundling is performed on first access and cached for subsequent calls func getCloseIssueScript() string { - closeIssueScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(closeIssueScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for close_issue, using source as-is: %v", err) - // If bundling fails, use the source as-is - closeIssueScript = closeIssueScriptSource - } else { - closeIssueScript = bundled - } - }) - return closeIssueScript + return DefaultScriptRegistry.Get("close_issue") } // getClosePullRequestScript returns the bundled close_pull_request script -// Bundling is performed on first access and cached for subsequent calls func getClosePullRequestScript() string { - closePullRequestScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(closePullRequestScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for close_pull_request, using source as-is: %v", err) - // If bundling fails, use the source as-is - closePullRequestScript = closePullRequestScriptSource - } else { - closePullRequestScript = bundled - } - }) - return closePullRequestScript + return DefaultScriptRegistry.Get("close_pull_request") } // getUpdateIssueScript returns the bundled update_issue script -// Bundling is performed on first access and cached for subsequent calls func getUpdateIssueScript() string { - updateIssueScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(updateIssueScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for update_issue, using source as-is: %v", err) - // If bundling fails, use the source as-is - updateIssueScript = updateIssueScriptSource - } else { - updateIssueScript = bundled - } - }) - return updateIssueScript + return DefaultScriptRegistry.Get("update_issue") } // getUpdateReleaseScript returns the bundled update_release script -// Bundling is performed on first access and cached for subsequent calls func getUpdateReleaseScript() string { - updateReleaseScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(updateReleaseScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for update_release, using source as-is: %v", err) - // If bundling fails, use the source as-is - updateReleaseScript = updateReleaseScriptSource - } else { - updateReleaseScript = bundled - } - }) - return updateReleaseScript + return DefaultScriptRegistry.Get("update_release") } // getCreateCodeScanningAlertScript returns the bundled create_code_scanning_alert script -// Bundling is performed on first access and cached for subsequent calls func getCreateCodeScanningAlertScript() string { - createCodeScanningAlertScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(createCodeScanningAlertScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for create_code_scanning_alert, using source as-is: %v", err) - // If bundling fails, use the source as-is - createCodeScanningAlertScript = createCodeScanningAlertScriptSource - } else { - createCodeScanningAlertScript = bundled - } - }) - return createCodeScanningAlertScript + return DefaultScriptRegistry.Get("create_code_scanning_alert") } // getCreatePRReviewCommentScript returns the bundled create_pr_review_comment script -// Bundling is performed on first access and cached for subsequent calls func getCreatePRReviewCommentScript() string { - createPRReviewCommentScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(createPRReviewCommentScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for create_pr_review_comment, using source as-is: %v", err) - // If bundling fails, use the source as-is - createPRReviewCommentScript = createPRReviewCommentScriptSource - } else { - createPRReviewCommentScript = bundled - } - }) - return createPRReviewCommentScript + return DefaultScriptRegistry.Get("create_pr_review_comment") } // getAddCommentScript returns the bundled add_comment script -// Bundling is performed on first access and cached for subsequent calls func getAddCommentScript() string { - addCommentScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(addCommentScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for add_comment, using source as-is: %v", err) - // If bundling fails, use the source as-is - addCommentScript = addCommentScriptSource - } else { - addCommentScript = bundled - } - }) - return addCommentScript + return DefaultScriptRegistry.Get("add_comment") } // getUploadAssetsScript returns the bundled upload_assets script -// Bundling is performed on first access and cached for subsequent calls func getUploadAssetsScript() string { - uploadAssetsScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(uploadAssetsScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for upload_assets, using source as-is: %v", err) - // If bundling fails, use the source as-is - uploadAssetsScript = uploadAssetsScriptSource - } else { - uploadAssetsScript = bundled - } - }) - return uploadAssetsScript + return DefaultScriptRegistry.Get("upload_assets") } // getPushToPullRequestBranchScript returns the bundled push_to_pull_request_branch script -// Bundling is performed on first access and cached for subsequent calls func getPushToPullRequestBranchScript() string { - pushToPullRequestBranchScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(pushToPullRequestBranchScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for push_to_pull_request_branch, using source as-is: %v", err) - // If bundling fails, use the source as-is - pushToPullRequestBranchScript = pushToPullRequestBranchScriptSource - } else { - pushToPullRequestBranchScript = bundled - } - }) - return pushToPullRequestBranchScript + return DefaultScriptRegistry.Get("push_to_pull_request_branch") } // getCreatePullRequestScript returns the bundled create_pull_request script -// Bundling is performed on first access and cached for subsequent calls func getCreatePullRequestScript() string { - createPullRequestScriptOnce.Do(func() { - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(createPullRequestScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for create_pull_request, using source as-is: %v", err) - // If bundling fails, use the source as-is - createPullRequestScript = createPullRequestScriptSource - } else { - createPullRequestScript = bundled - } - }) - return createPullRequestScript + return DefaultScriptRegistry.Get("create_pull_request") } // getNotifyCommentErrorScript returns the bundled notify_comment_error script -// Bundling is performed on first access and cached for subsequent calls -// This bundles load_agent_output.cjs inline to avoid require() issues in GitHub Actions func getNotifyCommentErrorScript() string { - notifyCommentErrorScriptOnce.Do(func() { - scriptsLog.Print("Bundling notify_comment_error script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(notifyCommentErrorScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for notify_comment_error, using source as-is: %v", err) - // If bundling fails, use the source as-is - notifyCommentErrorScript = notifyCommentErrorScriptSource - } else { - scriptsLog.Printf("Successfully bundled notify_comment_error script: %d bytes", len(bundled)) - notifyCommentErrorScript = bundled - } - }) - return notifyCommentErrorScript + return DefaultScriptRegistry.Get("notify_comment_error") } // getNoOpScript returns the bundled noop script -// Bundling is performed on first access and cached for subsequent calls -// This bundles load_agent_output.cjs inline to avoid require() issues in GitHub Actions func getNoOpScript() string { - noopScriptBundledOnce.Do(func() { - scriptsLog.Print("Bundling noop script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(noopScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for noop, using source as-is: %v", err) - // If bundling fails, use the source as-is - noopScriptBundled = noopScriptSource - } else { - scriptsLog.Printf("Successfully bundled noop script: %d bytes", len(bundled)) - noopScriptBundled = bundled - } - }) - return noopScriptBundled + return DefaultScriptRegistry.Get("noop") } // getInterpolatePromptScript returns the bundled interpolate_prompt script -// Bundling is performed on first access and cached for subsequent calls -// This bundles is_truthy.cjs inline to avoid require() issues in GitHub Actions func getInterpolatePromptScript() string { - interpolatePromptBundledOnce.Do(func() { - scriptsLog.Print("Bundling interpolate_prompt script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(interpolatePromptScript, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for interpolate_prompt, using source as-is: %v", err) - // If bundling fails, use the source as-is - interpolatePromptBundled = interpolatePromptScript - } else { - scriptsLog.Printf("Successfully bundled interpolate_prompt script: %d bytes", len(bundled)) - interpolatePromptBundled = bundled - } - }) - return interpolatePromptBundled + return DefaultScriptRegistry.Get("interpolate_prompt") } // getParseClaudeLogScript returns the bundled parse_claude_log script -// Bundling is performed on first access and cached for subsequent calls -// This bundles log_parser_bootstrap.cjs inline to avoid require() issues in GitHub Actions func getParseClaudeLogScript() string { - parseClaudeLogBundledOnce.Do(func() { - scriptsLog.Print("Bundling parse_claude_log script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(parseClaudeLogScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for parse_claude_log, using source as-is: %v", err) - parseClaudeLogBundled = parseClaudeLogScriptSource - } else { - scriptsLog.Printf("Successfully bundled parse_claude_log script: %d bytes", len(bundled)) - parseClaudeLogBundled = bundled - } - }) - return parseClaudeLogBundled + return DefaultScriptRegistry.Get("parse_claude_log") } // getParseCodexLogScript returns the bundled parse_codex_log script -// Bundling is performed on first access and cached for subsequent calls -// This bundles log_parser_bootstrap.cjs inline to avoid require() issues in GitHub Actions func getParseCodexLogScript() string { - parseCodexLogBundledOnce.Do(func() { - scriptsLog.Print("Bundling parse_codex_log script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(parseCodexLogScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for parse_codex_log, using source as-is: %v", err) - parseCodexLogBundled = parseCodexLogScriptSource - } else { - scriptsLog.Printf("Successfully bundled parse_codex_log script: %d bytes", len(bundled)) - parseCodexLogBundled = bundled - } - }) - return parseCodexLogBundled + return DefaultScriptRegistry.Get("parse_codex_log") } // getParseCopilotLogScript returns the bundled parse_copilot_log script -// Bundling is performed on first access and cached for subsequent calls -// This bundles log_parser_bootstrap.cjs inline to avoid require() issues in GitHub Actions func getParseCopilotLogScript() string { - parseCopilotLogBundledOnce.Do(func() { - scriptsLog.Print("Bundling parse_copilot_log script") - sources := GetJavaScriptSources() - bundled, err := BundleJavaScriptFromSources(parseCopilotLogScriptSource, sources, "") - if err != nil { - scriptsLog.Printf("Bundling failed for parse_copilot_log, using source as-is: %v", err) - parseCopilotLogBundled = parseCopilotLogScriptSource - } else { - scriptsLog.Printf("Successfully bundled parse_copilot_log script: %d bytes", len(bundled)) - parseCopilotLogBundled = bundled - } - }) - return parseCopilotLogBundled + return DefaultScriptRegistry.Get("parse_copilot_log") }