From 96bfe4e652709c2320a2cfd2811ade640f561719 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 13:09:47 +0000 Subject: [PATCH 01/12] Initial plan From f082b4ac75e4730054568b3ad4d122670cdf0ca1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 13:28:38 +0000 Subject: [PATCH 02/12] Add update-release safe output: schema, types, validation, and JS implementation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/js/collect_ndjson_output.cjs | 26 ++ .../js/collect_ndjson_output.test.cjs | 33 +++ .../js/types/safe-outputs-config.d.ts | 9 + pkg/workflow/js/types/safe-outputs.d.ts | 17 +- pkg/workflow/js/update_release.cjs | 126 ++++++++ pkg/workflow/js/update_release.test.cjs | 273 ++++++++++++++++++ schemas/agent-output.json | 30 +- 7 files changed, 512 insertions(+), 2 deletions(-) create mode 100644 pkg/workflow/js/update_release.cjs create mode 100644 pkg/workflow/js/update_release.test.cjs diff --git a/pkg/workflow/js/collect_ndjson_output.cjs b/pkg/workflow/js/collect_ndjson_output.cjs index d6b5e222d7..efe4ff5ba2 100644 --- a/pkg/workflow/js/collect_ndjson_output.cjs +++ b/pkg/workflow/js/collect_ndjson_output.cjs @@ -35,6 +35,8 @@ async function main() { return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -585,6 +587,30 @@ async function main() { item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + // Validate tag + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + // Validate operation + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + // Validate body + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + // Sanitize content + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/pkg/workflow/js/collect_ndjson_output.test.cjs b/pkg/workflow/js/collect_ndjson_output.test.cjs index 28d64dac77..8b65620399 100644 --- a/pkg/workflow/js/collect_ndjson_output.test.cjs +++ b/pkg/workflow/js/collect_ndjson_output.test.cjs @@ -448,6 +448,39 @@ describe("collect_ndjson_output.cjs", () => { expect(parsedOutput.errors[0]).toContain("side' must be 'LEFT' or 'RIGHT'"); }); + it("should validate required fields for update_release type", async () => { + const testFile = "/tmp/gh-aw/test-ndjson-output.txt"; + const ndjsonContent = `{"type": "update_release", "tag": "v1.0.0", "operation": "replace", "body": "New release notes"} +{"type": "update_release", "tag": "v1.0.0", "operation": "invalid", "body": "Notes"} +{"type": "update_release", "tag": "v1.0.0", "body": "Missing operation"} +{"type": "update_release", "operation": "replace", "body": "Missing tag"} +{"type": "update_release", "tag": "v1.0.0", "operation": "append"}`; + + fs.writeFileSync(testFile, ndjsonContent); + process.env.GH_AW_SAFE_OUTPUTS = testFile; + const __config = '{"update_release": {"max": 10}}'; + const configPath = "/tmp/gh-aw/safeoutputs/config.json"; + fs.mkdirSync("/tmp/gh-aw/safeoutputs", { recursive: true }); + fs.writeFileSync(configPath, __config); + + await eval(`(async () => { ${collectScript} })()`); + + const setOutputCalls = mockCore.setOutput.mock.calls; + const outputCall = setOutputCalls.find(call => call[0] === "output"); + expect(outputCall).toBeDefined(); + + const parsedOutput = JSON.parse(outputCall[1]); + expect(parsedOutput.items).toHaveLength(1); // Only the first valid item + expect(parsedOutput.items[0].tag).toBe("v1.0.0"); + expect(parsedOutput.items[0].operation).toBe("replace"); + expect(parsedOutput.items[0].body).toBeDefined(); + expect(parsedOutput.errors).toHaveLength(4); // 4 invalid items + expect(parsedOutput.errors.some(e => e.includes("operation' must be 'replace' or 'append'"))).toBe(true); + expect(parsedOutput.errors.some(e => e.includes("requires an 'operation' string field"))).toBe(true); + expect(parsedOutput.errors.some(e => e.includes("requires a 'tag' string field"))).toBe(true); + expect(parsedOutput.errors.some(e => e.includes("requires a 'body' string field"))).toBe(true); + }); + it("should respect max limits for create-pull-request-review-comment from config", async () => { const testFile = "/tmp/gh-aw/test-ndjson-output.txt"; const items = []; diff --git a/pkg/workflow/js/types/safe-outputs-config.d.ts b/pkg/workflow/js/types/safe-outputs-config.d.ts index a891cd7a8d..9a433f59ab 100644 --- a/pkg/workflow/js/types/safe-outputs-config.d.ts +++ b/pkg/workflow/js/types/safe-outputs-config.d.ts @@ -92,6 +92,13 @@ interface UploadAssetConfig extends SafeOutputConfig { "allowed-exts"?: string[]; } +/** + * Configuration for updating releases + */ +interface UpdateReleaseConfig extends SafeOutputConfig { + target?: string; +} + /** * Configuration for reporting missing tools */ @@ -146,6 +153,7 @@ type SpecificSafeOutputConfig = | UpdateIssueConfig | PushToPullRequestBranchConfig | UploadAssetConfig + | UpdateReleaseConfig | MissingToolConfig | ThreatDetectionConfig; @@ -165,6 +173,7 @@ export { UpdateIssueConfig, PushToPullRequestBranchConfig, UploadAssetConfig, + UpdateReleaseConfig, MissingToolConfig, ThreatDetectionConfig, SpecificSafeOutputConfig, diff --git a/pkg/workflow/js/types/safe-outputs.d.ts b/pkg/workflow/js/types/safe-outputs.d.ts index db8b3e680e..2511fe4203 100644 --- a/pkg/workflow/js/types/safe-outputs.d.ts +++ b/pkg/workflow/js/types/safe-outputs.d.ts @@ -158,6 +158,19 @@ interface UploadAssetItem extends BaseSafeOutputItem { file_path: string; } +/** + * JSONL item for updating a release + */ +interface UpdateReleaseItem extends BaseSafeOutputItem { + type: "update_release"; + /** Tag name of the release to update */ + tag: string; + /** Update operation: 'replace' or 'append' */ + operation: "replace" | "append"; + /** Content to set or append to the release body */ + body: string; +} + /** * Union type of all possible safe output items */ @@ -172,7 +185,8 @@ type SafeOutputItem = | UpdateIssueItem | PushToPrBranchItem | MissingToolItem - | UploadAssetItem; + | UploadAssetItem + | UpdateReleaseItem; /** * Sanitized safe output items @@ -196,6 +210,7 @@ export { PushToPrBranchItem, MissingToolItem, UploadAssetItem, + UpdateReleaseItem, SafeOutputItem, SafeOutputItems, }; diff --git a/pkg/workflow/js/update_release.cjs b/pkg/workflow/js/update_release.cjs new file mode 100644 index 0000000000..2357ab2b03 --- /dev/null +++ b/pkg/workflow/js/update_release.cjs @@ -0,0 +1,126 @@ +// @ts-check +/// + +const { loadAgentOutput } = require("./load_agent_output.cjs"); +const { generateStagedPreview } = require("./staged_preview.cjs"); + +async function main() { + // Check if we're in staged mode + const isStaged = process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true"; + + const result = loadAgentOutput(); + if (!result.success) { + return; + } + + // Find all update-release items + const updateItems = result.items.filter(/** @param {any} item */ item => item.type === "update_release"); + if (updateItems.length === 0) { + core.info("No update-release items found in agent output"); + return; + } + + core.info(`Found ${updateItems.length} update-release item(s)`); + + // If in staged mode, emit step summary instead of updating releases + if (isStaged) { + await generateStagedPreview({ + title: "Update Releases", + description: "The following release updates would be applied if staged mode was disabled:", + items: updateItems, + renderItem: (item, index) => { + let content = `### Release Update ${index + 1}\n`; + content += `**Tag:** ${item.tag}\n`; + content += `**Operation:** ${item.operation}\n\n`; + content += `**Body Content:**\n${item.body}\n\n`; + return content; + }, + }); + return; + } + + // Get workflow run URL for AI attribution + const workflowName = process.env.GH_AW_WORKFLOW_NAME || "GitHub Agentic Workflow"; + const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + + const updatedReleases = []; + + // Process each update item + for (let i = 0; i < updateItems.length; i++) { + const updateItem = updateItems[i]; + core.info(`Processing update-release item ${i + 1}/${updateItems.length}`); + + try { + // Get the release by tag + core.info(`Fetching release with tag: ${updateItem.tag}`); + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: context.repo.owner, + repo: context.repo.repo, + tag: updateItem.tag, + }); + + core.info(`Found release: ${release.name || release.tag_name} (ID: ${release.id})`); + + // Determine new body based on operation + let newBody; + if (updateItem.operation === "replace") { + // Replace: just use the new content + newBody = updateItem.body; + core.info("Operation: replace (full body replacement)"); + } else { + // Append: add horizontal line, content, and AI footer + const aiFooter = `\n\n> AI generated by [${workflowName}](${runUrl})`; + const appendSection = `\n\n---\n\n${updateItem.body}${aiFooter}`; + newBody = (release.body || "") + appendSection; + core.info("Operation: append (add to end with separator)"); + } + + // Update the release + const { data: updatedRelease } = await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.id, + body: newBody, + }); + + core.info(`Successfully updated release: ${updatedRelease.html_url}`); + + updatedReleases.push({ + tag: updateItem.tag, + url: updatedRelease.html_url, + id: updatedRelease.id, + }); + + // Set outputs for the first release + if (i === 0) { + core.setOutput("release_id", updatedRelease.id); + core.setOutput("release_url", updatedRelease.html_url); + core.setOutput("release_tag", updatedRelease.tag_name); + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + core.error(`Failed to update release with tag ${updateItem.tag}: ${errorMessage}`); + + // Check for specific error cases + if (errorMessage.includes("Not Found")) { + core.error(`Release with tag '${updateItem.tag}' not found. Please ensure the tag exists.`); + } + + core.setFailed(`Failed to update release: ${errorMessage}`); + return; + } + } + + // Generate step summary + let summaryContent = `## ✅ Release Updates Complete\n\n`; + summaryContent += `Updated ${updatedReleases.length} release(s):\n\n`; + + for (const rel of updatedReleases) { + summaryContent += `- **${rel.tag}**: [View Release](${rel.url})\n`; + } + + await core.summary.addRaw(summaryContent).write(); +} + +// Call the main function +await main(); diff --git a/pkg/workflow/js/update_release.test.cjs b/pkg/workflow/js/update_release.test.cjs new file mode 100644 index 0000000000..55b6505065 --- /dev/null +++ b/pkg/workflow/js/update_release.test.cjs @@ -0,0 +1,273 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; +import fs from "fs"; +import path from "path"; + +// Mock the global objects that GitHub Actions provides +const mockCore = { + debug: vi.fn(), + info: vi.fn(), + warning: vi.fn(), + error: vi.fn(), + setFailed: vi.fn(), + setOutput: vi.fn(), + summary: { + addRaw: vi.fn().mockReturnThis(), + write: vi.fn().mockResolvedValue(), + }, +}; + +const mockGithub = { + rest: { + repos: { + getReleaseByTag: vi.fn(), + updateRelease: vi.fn(), + }, + }, +}; + +const mockContext = { + repo: { + owner: "test-owner", + repo: "test-repo", + }, + serverUrl: "https://github.com", + runId: 123456, +}; + +// Set up global mocks before importing the module +global.core = mockCore; +global.github = mockGithub; +global.context = mockContext; + +describe("update_release", () => { + let updateReleaseScript; + let tempFilePath; + + // Helper function to set agent output via file + const setAgentOutput = data => { + tempFilePath = path.join("/tmp", `test_agent_output_${Date.now()}_${Math.random().toString(36).slice(2)}.json`); + const content = typeof data === "string" ? data : JSON.stringify(data); + fs.writeFileSync(tempFilePath, content); + process.env.GH_AW_AGENT_OUTPUT = tempFilePath; + }; + + beforeEach(() => { + // Reset mocks before each test + vi.clearAllMocks(); + delete process.env.GH_AW_SAFE_OUTPUTS_STAGED; + delete process.env.GH_AW_AGENT_OUTPUT; + delete process.env.GH_AW_WORKFLOW_NAME; + + // Read the script + const scriptPath = path.join(__dirname, "update_release.cjs"); + updateReleaseScript = fs.readFileSync(scriptPath, "utf8"); + }); + + afterEach(() => { + // Clean up temporary file + if (tempFilePath && fs.existsSync(tempFilePath)) { + fs.unlinkSync(tempFilePath); + tempFilePath = undefined; + } + }); + + it("should handle empty agent output", async () => { + setAgentOutput({ items: [], errors: [] }); + + // Execute the script + await eval(`(async () => { ${updateReleaseScript} })()`); + + expect(mockCore.info).toHaveBeenCalledWith("No update-release items found in agent output"); + expect(mockGithub.rest.repos.getReleaseByTag).not.toHaveBeenCalled(); + }); + + it("should handle replace operation", async () => { + const mockRelease = { + id: 1, + tag_name: "v1.0.0", + name: "Release v1.0.0", + body: "Old release notes", + html_url: "https://github.com/test-owner/test-repo/releases/tag/v1.0.0", + }; + + const mockUpdatedRelease = { + ...mockRelease, + body: "New release notes", + }; + + mockGithub.rest.repos.getReleaseByTag.mockResolvedValue({ data: mockRelease }); + mockGithub.rest.repos.updateRelease.mockResolvedValue({ data: mockUpdatedRelease }); + + setAgentOutput({ + items: [ + { + type: "update_release", + tag: "v1.0.0", + operation: "replace", + body: "New release notes", + }, + ], + errors: [], + }); + process.env.GH_AW_WORKFLOW_NAME = "Test Workflow"; + + // Execute the script + await eval(`(async () => { ${updateReleaseScript} })()`); + + expect(mockGithub.rest.repos.getReleaseByTag).toHaveBeenCalledWith({ + owner: "test-owner", + repo: "test-repo", + tag: "v1.0.0", + }); + + expect(mockGithub.rest.repos.updateRelease).toHaveBeenCalledWith({ + owner: "test-owner", + repo: "test-repo", + release_id: 1, + body: "New release notes", + }); + + expect(mockCore.setOutput).toHaveBeenCalledWith("release_id", 1); + expect(mockCore.setOutput).toHaveBeenCalledWith("release_url", mockUpdatedRelease.html_url); + expect(mockCore.setOutput).toHaveBeenCalledWith("release_tag", "v1.0.0"); + expect(mockCore.summary.addRaw).toHaveBeenCalled(); + }); + + it("should handle append operation", async () => { + const mockRelease = { + id: 2, + tag_name: "v2.0.0", + name: "Release v2.0.0", + body: "Original release notes", + html_url: "https://github.com/test-owner/test-repo/releases/tag/v2.0.0", + }; + + const expectedBody = + "Original release notes\n\n---\n\nAdditional notes\n\n> AI generated by [Test Workflow](https://github.com/test-owner/test-repo/actions/runs/123456)"; + + const mockUpdatedRelease = { + ...mockRelease, + body: expectedBody, + }; + + mockGithub.rest.repos.getReleaseByTag.mockResolvedValue({ data: mockRelease }); + mockGithub.rest.repos.updateRelease.mockResolvedValue({ data: mockUpdatedRelease }); + + setAgentOutput({ + items: [ + { + type: "update_release", + tag: "v2.0.0", + operation: "append", + body: "Additional notes", + }, + ], + errors: [], + }); + process.env.GH_AW_WORKFLOW_NAME = "Test Workflow"; + + // Execute the script + await eval(`(async () => { ${updateReleaseScript} })()`); + + expect(mockGithub.rest.repos.updateRelease).toHaveBeenCalledWith({ + owner: "test-owner", + repo: "test-repo", + release_id: 2, + body: expectedBody, + }); + + expect(mockCore.info).toHaveBeenCalledWith("Operation: append (add to end with separator)"); + }); + + it("should handle staged mode", async () => { + process.env.GH_AW_SAFE_OUTPUTS_STAGED = "true"; + setAgentOutput({ + items: [ + { + type: "update_release", + tag: "v1.0.0", + operation: "replace", + body: "New notes", + }, + ], + errors: [], + }); + + // Execute the script + await eval(`(async () => { ${updateReleaseScript} })()`); + + expect(mockCore.summary.addRaw).toHaveBeenCalled(); + expect(mockGithub.rest.repos.getReleaseByTag).not.toHaveBeenCalled(); + expect(mockGithub.rest.repos.updateRelease).not.toHaveBeenCalled(); + }); + + it("should handle release not found error", async () => { + mockGithub.rest.repos.getReleaseByTag.mockRejectedValue(new Error("Not Found")); + + setAgentOutput({ + items: [ + { + type: "update_release", + tag: "v99.99.99", + operation: "replace", + body: "New notes", + }, + ], + errors: [], + }); + + // Execute the script + await eval(`(async () => { ${updateReleaseScript} })()`); + + expect(mockCore.error).toHaveBeenCalledWith(expect.stringContaining("Failed to update release")); + expect(mockCore.error).toHaveBeenCalledWith(expect.stringContaining("not found")); + expect(mockCore.setFailed).toHaveBeenCalled(); + }); + + it("should handle multiple release updates", async () => { + const mockRelease1 = { + id: 1, + tag_name: "v1.0.0", + body: "Release 1", + html_url: "https://github.com/test-owner/test-repo/releases/tag/v1.0.0", + }; + + const mockRelease2 = { + id: 2, + tag_name: "v2.0.0", + body: "Release 2", + html_url: "https://github.com/test-owner/test-repo/releases/tag/v2.0.0", + }; + + mockGithub.rest.repos.getReleaseByTag.mockResolvedValueOnce({ data: mockRelease1 }).mockResolvedValueOnce({ data: mockRelease2 }); + + mockGithub.rest.repos.updateRelease + .mockResolvedValueOnce({ data: { ...mockRelease1, body: "Updated 1" } }) + .mockResolvedValueOnce({ data: { ...mockRelease2, body: "Updated 2" } }); + + setAgentOutput({ + items: [ + { + type: "update_release", + tag: "v1.0.0", + operation: "replace", + body: "Updated 1", + }, + { + type: "update_release", + tag: "v2.0.0", + operation: "replace", + body: "Updated 2", + }, + ], + errors: [], + }); + + // Execute the script + await eval(`(async () => { ${updateReleaseScript} })()`); + + expect(mockGithub.rest.repos.getReleaseByTag).toHaveBeenCalledTimes(2); + expect(mockGithub.rest.repos.updateRelease).toHaveBeenCalledTimes(2); + expect(mockCore.summary.addRaw).toHaveBeenCalledWith(expect.stringContaining("Updated 2 release(s)")); + }); +}); diff --git a/schemas/agent-output.json b/schemas/agent-output.json index 2f4cdc82da..83bf6194a1 100644 --- a/schemas/agent-output.json +++ b/schemas/agent-output.json @@ -37,7 +37,8 @@ {"$ref": "#/$defs/CreateDiscussionOutput"}, {"$ref": "#/$defs/MissingToolOutput"}, {"$ref": "#/$defs/CreateCodeScanningAlertOutput"}, - {"$ref": "#/$defs/UpdateProjectOutput"} + {"$ref": "#/$defs/UpdateProjectOutput"}, + {"$ref": "#/$defs/UpdateReleaseOutput"} ] }, "CreateIssueOutput": { @@ -357,6 +358,33 @@ }, "required": ["type", "project"], "additionalProperties": false + }, + "UpdateReleaseOutput": { + "title": "Update Release Output", + "description": "Output for updating a GitHub release description", + "type": "object", + "properties": { + "type": { + "const": "update_release" + }, + "tag": { + "type": "string", + "description": "Tag name of the release to update", + "minLength": 1 + }, + "operation": { + "type": "string", + "description": "Update operation: 'replace' or 'append'", + "enum": ["replace", "append"] + }, + "body": { + "type": "string", + "description": "Content to set or append to the release body", + "minLength": 1 + } + }, + "required": ["type", "tag", "operation", "body"], + "additionalProperties": false } } } \ No newline at end of file From 04ab595354d2f0fc4c8c173a755ebb160a66a0a4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 13:37:04 +0000 Subject: [PATCH 03/12] Add Go implementation for update-release safe output Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/ai-triage-campaign.lock.yml | 22 +++++ .github/workflows/archie.lock.yml | 22 +++++ .github/workflows/artifacts-summary.lock.yml | 22 +++++ .github/workflows/audit-workflows.lock.yml | 22 +++++ .github/workflows/blog-auditor.lock.yml | 22 +++++ .github/workflows/brave.lock.yml | 22 +++++ .github/workflows/changeset.lock.yml | 22 +++++ .github/workflows/ci-doctor.lock.yml | 22 +++++ .../cli-consistency-checker.lock.yml | 22 +++++ .../workflows/cli-version-checker.lock.yml | 22 +++++ .github/workflows/cloclo.lock.yml | 22 +++++ .../commit-changes-analyzer.lock.yml | 22 +++++ .../workflows/copilot-agent-analysis.lock.yml | 22 +++++ .../copilot-pr-nlp-analysis.lock.yml | 22 +++++ .../copilot-pr-prompt-analysis.lock.yml | 22 +++++ .../copilot-session-insights.lock.yml | 22 +++++ .github/workflows/craft.lock.yml | 22 +++++ .github/workflows/daily-code-metrics.lock.yml | 22 +++++ .github/workflows/daily-doc-updater.lock.yml | 22 +++++ .github/workflows/daily-file-diet.lock.yml | 22 +++++ .../workflows/daily-firewall-report.lock.yml | 22 +++++ .../daily-multi-device-docs-tester.lock.yml | 22 +++++ .github/workflows/daily-news.lock.yml | 22 +++++ .../workflows/daily-repo-chronicle.lock.yml | 22 +++++ .github/workflows/daily-team-status.lock.yml | 22 +++++ .../workflows/dependabot-go-checker.lock.yml | 22 +++++ .github/workflows/dev-hawk.lock.yml | 22 +++++ .github/workflows/dev.lock.yml | 22 +++++ .../developer-docs-consolidator.lock.yml | 22 +++++ .github/workflows/dictation-prompt.lock.yml | 22 +++++ .github/workflows/docs-noob-tester.lock.yml | 22 +++++ .../duplicate-code-detector.lock.yml | 22 +++++ .../example-workflow-analyzer.lock.yml | 22 +++++ .../github-mcp-tools-report.lock.yml | 22 +++++ .github/workflows/go-logger.lock.yml | 22 +++++ .../workflows/go-pattern-detector.lock.yml | 22 +++++ .github/workflows/grumpy-reviewer.lock.yml | 22 +++++ .../workflows/instructions-janitor.lock.yml | 22 +++++ .github/workflows/issue-classifier.lock.yml | 22 +++++ .github/workflows/lockfile-stats.lock.yml | 22 +++++ .github/workflows/mcp-inspector.lock.yml | 22 +++++ .github/workflows/mergefest.lock.yml | 22 +++++ .../workflows/notion-issue-summary.lock.yml | 22 +++++ .github/workflows/pdf-summary.lock.yml | 22 +++++ .github/workflows/plan.lock.yml | 22 +++++ .github/workflows/poem-bot.lock.yml | 22 +++++ .../workflows/pr-nitpick-reviewer.lock.yml | 22 +++++ .../prompt-clustering-analysis.lock.yml | 22 +++++ .github/workflows/python-data-charts.lock.yml | 22 +++++ .github/workflows/q.lock.yml | 22 +++++ .github/workflows/repo-tree-map.lock.yml | 22 +++++ .../repository-quality-improver.lock.yml | 22 +++++ .github/workflows/research.lock.yml | 22 +++++ .github/workflows/safe-output-health.lock.yml | 22 +++++ .../schema-consistency-checker.lock.yml | 22 +++++ .github/workflows/scout.lock.yml | 22 +++++ .github/workflows/security-fix-pr.lock.yml | 22 +++++ .../semantic-function-refactor.lock.yml | 22 +++++ .github/workflows/smoke-claude.lock.yml | 22 +++++ .github/workflows/smoke-codex.lock.yml | 22 +++++ .github/workflows/smoke-copilot.lock.yml | 22 +++++ .github/workflows/smoke-detector.lock.yml | 22 +++++ .../workflows/static-analysis-report.lock.yml | 22 +++++ .github/workflows/super-linter.lock.yml | 22 +++++ .../workflows/technical-doc-writer.lock.yml | 22 +++++ .../test-ollama-threat-detection.lock.yml | 22 +++++ .github/workflows/tidy.lock.yml | 22 +++++ .github/workflows/typist.lock.yml | 22 +++++ .github/workflows/unbloat-docs.lock.yml | 22 +++++ .github/workflows/video-analyzer.lock.yml | 22 +++++ .../workflows/weekly-issue-summary.lock.yml | 22 +++++ pkg/workflow/compiler.go | 1 + pkg/workflow/compiler_jobs.go | 18 +++++ pkg/workflow/safe_outputs.go | 6 ++ pkg/workflow/scripts.go | 23 ++++++ pkg/workflow/update_release.go | 81 +++++++++++++++++++ 76 files changed, 1691 insertions(+) create mode 100644 pkg/workflow/update_release.go diff --git a/.github/workflows/ai-triage-campaign.lock.yml b/.github/workflows/ai-triage-campaign.lock.yml index ba1809363d..ff8b7e3bde 100644 --- a/.github/workflows/ai-triage-campaign.lock.yml +++ b/.github/workflows/ai-triage-campaign.lock.yml @@ -1692,6 +1692,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2234,6 +2236,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index bdf7e82133..94ac075635 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -2767,6 +2767,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3309,6 +3311,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index 3f836e09b4..5f24592be5 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -1638,6 +1638,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2180,6 +2182,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index 8863ac2de4..a553202544 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -2680,6 +2680,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3222,6 +3224,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml index 2c6ec0da8e..d542a98978 100644 --- a/.github/workflows/blog-auditor.lock.yml +++ b/.github/workflows/blog-auditor.lock.yml @@ -2026,6 +2026,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2568,6 +2570,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index b1be5defd5..478c352647 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -2614,6 +2614,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3156,6 +3158,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index 024bff837f..962249e531 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -2306,6 +2306,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2848,6 +2850,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index e72328edd7..ef420b1e66 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -2122,6 +2122,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2664,6 +2666,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index 9e9c18b9be..e98f34ae17 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -1676,6 +1676,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2218,6 +2220,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index fc17cd3ba4..6076eab4d2 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -1852,6 +1852,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2394,6 +2396,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index e3229960d3..e2996d3465 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -3161,6 +3161,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3703,6 +3705,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml index 015e0c8e7f..13f4bf1bdf 100644 --- a/.github/workflows/commit-changes-analyzer.lock.yml +++ b/.github/workflows/commit-changes-analyzer.lock.yml @@ -1957,6 +1957,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2499,6 +2501,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index 848e041a53..0f13b6afc1 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -2320,6 +2320,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2862,6 +2864,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index fb1b5a47b3..424b946826 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -2413,6 +2413,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2955,6 +2957,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index 8c51ddce95..ca2544a859 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -1979,6 +1979,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2521,6 +2523,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index 5643dc8005..05a8661682 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -3229,6 +3229,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3771,6 +3773,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index 3a643301b5..56aafe2e1d 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -2768,6 +2768,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3310,6 +3312,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index ebd5115ed6..2a73763811 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -2300,6 +2300,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2842,6 +2844,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index 97e40c7ab2..65f9e4bb7f 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -1886,6 +1886,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2428,6 +2430,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index 17f898be63..2aeae46fcd 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -1787,6 +1787,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2329,6 +2331,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index e1af752947..42983be934 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -2396,6 +2396,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2938,6 +2940,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml index 525eef7b91..31ac5f8e21 100644 --- a/.github/workflows/daily-multi-device-docs-tester.lock.yml +++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml @@ -1810,6 +1810,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2352,6 +2354,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index b28b4030dc..58eff785ca 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -2405,6 +2405,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2947,6 +2949,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index 8ae783b991..bfebda31bb 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -2249,6 +2249,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2791,6 +2793,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml index ac25dde138..2e5ec352ba 100644 --- a/.github/workflows/daily-team-status.lock.yml +++ b/.github/workflows/daily-team-status.lock.yml @@ -1569,6 +1569,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2111,6 +2113,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml index eed1aea9b5..cd911c4c8e 100644 --- a/.github/workflows/dependabot-go-checker.lock.yml +++ b/.github/workflows/dependabot-go-checker.lock.yml @@ -1710,6 +1710,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2252,6 +2254,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index acb2afa314..21be2a4f64 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -2013,6 +2013,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2555,6 +2557,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index bad5f3c118..9b07b2aaf3 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -1535,6 +1535,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2077,6 +2079,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index 0a76d475f1..6dfb207e6e 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -2437,6 +2437,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2979,6 +2981,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index ea82821a41..2e81172a42 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -1633,6 +1633,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2175,6 +2177,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index 0d1aab8478..569a3db41f 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -1689,6 +1689,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2231,6 +2233,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index 472891a9bd..a668bba20a 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -1707,6 +1707,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2249,6 +2251,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml index a7cd65313c..3dd02751a8 100644 --- a/.github/workflows/example-workflow-analyzer.lock.yml +++ b/.github/workflows/example-workflow-analyzer.lock.yml @@ -1739,6 +1739,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2281,6 +2283,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index 85aef0b4ad..45067dab1a 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -2259,6 +2259,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2801,6 +2803,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index cf86adedf1..ba4066e1a2 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -2005,6 +2005,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2547,6 +2549,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml index 2a4aa7f79c..7bfaaa8c94 100644 --- a/.github/workflows/go-pattern-detector.lock.yml +++ b/.github/workflows/go-pattern-detector.lock.yml @@ -1779,6 +1779,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2321,6 +2323,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index d3fcf66dde..fdd6a659e1 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -2669,6 +2669,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3211,6 +3213,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index 569713115e..63b62d7e11 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -1884,6 +1884,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2426,6 +2428,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index e7c8e829e2..dbdfe52d2b 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -2311,6 +2311,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2853,6 +2855,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml index 97d2e0b599..5184407221 100644 --- a/.github/workflows/lockfile-stats.lock.yml +++ b/.github/workflows/lockfile-stats.lock.yml @@ -2094,6 +2094,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2636,6 +2638,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index 5d5d7e30e9..a76811d0ce 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -2211,6 +2211,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2753,6 +2755,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index d6b8d0d122..62073b8444 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -2192,6 +2192,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2734,6 +2736,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/notion-issue-summary.lock.yml b/.github/workflows/notion-issue-summary.lock.yml index aec3ec5d29..9c3772a71f 100644 --- a/.github/workflows/notion-issue-summary.lock.yml +++ b/.github/workflows/notion-issue-summary.lock.yml @@ -1492,6 +1492,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2034,6 +2036,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index 1fc24f4dd4..b2cb6914aa 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -2720,6 +2720,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3262,6 +3264,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index f910784002..f6ba65b6f5 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -2195,6 +2195,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2737,6 +2739,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index da48f96a89..2d128b9578 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -2991,6 +2991,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3533,6 +3535,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 7c48c3d59f..228dbdcc3a 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -2772,6 +2772,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3314,6 +3316,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index 74da3f37ad..33e8946344 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -2434,6 +2434,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2976,6 +2978,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index adabbfe469..e53d16125f 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -2569,6 +2569,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3111,6 +3113,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index 14ce079a58..9ac010f53d 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -3061,6 +3061,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3603,6 +3605,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml index 6bb78d6a39..e30391f47d 100644 --- a/.github/workflows/repo-tree-map.lock.yml +++ b/.github/workflows/repo-tree-map.lock.yml @@ -1668,6 +1668,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2210,6 +2212,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index cec6b69412..05db53df76 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -2186,6 +2186,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2728,6 +2730,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml index 4bd8e511c9..76bfb64c7b 100644 --- a/.github/workflows/research.lock.yml +++ b/.github/workflows/research.lock.yml @@ -1602,6 +1602,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2144,6 +2146,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml index 5e8ec8eea5..0e4380334b 100644 --- a/.github/workflows/safe-output-health.lock.yml +++ b/.github/workflows/safe-output-health.lock.yml @@ -2227,6 +2227,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2769,6 +2771,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml index f3c8a01ec2..1516042402 100644 --- a/.github/workflows/schema-consistency-checker.lock.yml +++ b/.github/workflows/schema-consistency-checker.lock.yml @@ -2100,6 +2100,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2642,6 +2644,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index 598ca276fc..232fe86da2 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -3175,6 +3175,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3717,6 +3719,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/security-fix-pr.lock.yml b/.github/workflows/security-fix-pr.lock.yml index 9dd2e5f420..beecfc9cce 100644 --- a/.github/workflows/security-fix-pr.lock.yml +++ b/.github/workflows/security-fix-pr.lock.yml @@ -1832,6 +1832,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2374,6 +2376,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml index 5a271114ed..0d0e3986a0 100644 --- a/.github/workflows/semantic-function-refactor.lock.yml +++ b/.github/workflows/semantic-function-refactor.lock.yml @@ -2188,6 +2188,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2730,6 +2732,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 802c4d0a45..1ac0088e3a 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -1747,6 +1747,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2289,6 +2291,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index 57c82be58e..a82bc9e678 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -1449,6 +1449,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -1991,6 +1993,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 4cdc7a4a00..f2372a9094 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -1519,6 +1519,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2061,6 +2063,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/smoke-detector.lock.yml b/.github/workflows/smoke-detector.lock.yml index 1620a04ec0..038e39e124 100644 --- a/.github/workflows/smoke-detector.lock.yml +++ b/.github/workflows/smoke-detector.lock.yml @@ -2818,6 +2818,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3360,6 +3362,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml index e8cbcc36a7..c8cd645152 100644 --- a/.github/workflows/static-analysis-report.lock.yml +++ b/.github/workflows/static-analysis-report.lock.yml @@ -2115,6 +2115,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2657,6 +2659,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index 668c2e67ef..0257858db4 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -1741,6 +1741,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2283,6 +2285,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index f1f63c65fa..d361b9a113 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -2412,6 +2412,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2954,6 +2956,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/test-ollama-threat-detection.lock.yml b/.github/workflows/test-ollama-threat-detection.lock.yml index b27102294b..276f808b2c 100644 --- a/.github/workflows/test-ollama-threat-detection.lock.yml +++ b/.github/workflows/test-ollama-threat-detection.lock.yml @@ -1464,6 +1464,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2006,6 +2008,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index b2e44f99e4..eb28c883d4 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -1995,6 +1995,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2537,6 +2539,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index 91a94fd4fc..a32518091d 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -2258,6 +2258,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2800,6 +2802,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index a12590f97f..8de8014cb2 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -2914,6 +2914,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -3456,6 +3458,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml index 8232d38142..e9e45918b7 100644 --- a/.github/workflows/video-analyzer.lock.yml +++ b/.github/workflows/video-analyzer.lock.yml @@ -1755,6 +1755,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2297,6 +2299,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index ef5fbf7436..435cba4215 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -2157,6 +2157,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; default: return 1; } @@ -2699,6 +2701,26 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (!item.tag || typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + item.tag = sanitizeContent(item.tag, 256); + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); diff --git a/pkg/workflow/compiler.go b/pkg/workflow/compiler.go index 87c0a5c532..56d20f4ea6 100644 --- a/pkg/workflow/compiler.go +++ b/pkg/workflow/compiler.go @@ -261,6 +261,7 @@ type SafeOutputsConfig struct { UpdateIssues *UpdateIssuesConfig `yaml:"update-issues,omitempty"` PushToPullRequestBranch *PushToPullRequestBranchConfig `yaml:"push-to-pull-request-branch,omitempty"` UploadAssets *UploadAssetsConfig `yaml:"upload-assets,omitempty"` + UpdateRelease *UpdateReleaseConfig `yaml:"update-release,omitempty"` // Update GitHub release descriptions CreateAgentTasks *CreateAgentTaskConfig `yaml:"create-agent-task,omitempty"` // Create GitHub Copilot agent tasks UpdateProjects *UpdateProjectConfig `yaml:"update-project,omitempty"` // Smart project board management (create/add/update) MissingTool *MissingToolConfig `yaml:"missing-tool,omitempty"` // Optional for reporting missing functionality diff --git a/pkg/workflow/compiler_jobs.go b/pkg/workflow/compiler_jobs.go index 143435224b..0294babe89 100644 --- a/pkg/workflow/compiler_jobs.go +++ b/pkg/workflow/compiler_jobs.go @@ -357,6 +357,24 @@ func (c *Compiler) buildSafeOutputsJobs(data *WorkflowData, jobName, markdownPat safeOutputJobNames = append(safeOutputJobNames, uploadAssetsJob.Name) } + // Build update_release job if output.update-release is configured + if data.SafeOutputs.UpdateRelease != nil { + updateReleaseJob, err := c.buildCreateOutputUpdateReleaseJob(data, jobName) + if err != nil { + return fmt.Errorf("failed to build update_release job: %w", err) + } + // Safe-output jobs should depend on agent job (always) AND detection job (if enabled) + if threatDetectionEnabled { + updateReleaseJob.Needs = append(updateReleaseJob.Needs, constants.DetectionJobName) + // Add detection success check to the job condition + updateReleaseJob.If = AddDetectionSuccessCheck(updateReleaseJob.If) + } + if err := c.jobManager.AddJob(updateReleaseJob); err != nil { + return fmt.Errorf("failed to add update_release job: %w", err) + } + safeOutputJobNames = append(safeOutputJobNames, updateReleaseJob.Name) + } + // Build create_agent_task job if output.create-agent-task is configured if data.SafeOutputs.CreateAgentTasks != nil { createAgentTaskJob, err := c.buildCreateOutputAgentTaskJob(data, jobName) diff --git a/pkg/workflow/safe_outputs.go b/pkg/workflow/safe_outputs.go index 56f5559543..702d818192 100644 --- a/pkg/workflow/safe_outputs.go +++ b/pkg/workflow/safe_outputs.go @@ -402,6 +402,12 @@ func (c *Compiler) extractSafeOutputsConfig(frontmatter map[string]any) *SafeOut config.UploadAssets = uploadAssetsConfig } + // Handle update-release + updateReleaseConfig := c.parseUpdateReleaseConfig(outputMap) + if updateReleaseConfig != nil { + config.UpdateRelease = updateReleaseConfig + } + // Handle missing-tool (parse configuration if present, or enable by default) missingToolConfig := c.parseMissingToolConfig(outputMap) if missingToolConfig != nil { diff --git a/pkg/workflow/scripts.go b/pkg/workflow/scripts.go index 35bdb60145..fa78a62968 100644 --- a/pkg/workflow/scripts.go +++ b/pkg/workflow/scripts.go @@ -32,6 +32,9 @@ var createDiscussionScriptSource string //go:embed js/update_issue.cjs var updateIssueScriptSource string +//go:embed js/update_release.cjs +var updateReleaseScriptSource string + //go:embed js/create_code_scanning_alert.cjs var createCodeScanningAlertScriptSource string @@ -87,6 +90,9 @@ var ( updateIssueScript string updateIssueScriptOnce sync.Once + updateReleaseScript string + updateReleaseScriptOnce sync.Once + createCodeScanningAlertScript string createCodeScanningAlertScriptOnce sync.Once @@ -259,6 +265,23 @@ func getUpdateIssueScript() string { return updateIssueScript } +// 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 +} + // getCreateCodeScanningAlertScript returns the bundled create_code_scanning_alert script // Bundling is performed on first access and cached for subsequent calls func getCreateCodeScanningAlertScript() string { diff --git a/pkg/workflow/update_release.go b/pkg/workflow/update_release.go new file mode 100644 index 0000000000..27ced9ee2d --- /dev/null +++ b/pkg/workflow/update_release.go @@ -0,0 +1,81 @@ +package workflow + +import ( + "fmt" +) + +// UpdateReleaseConfig holds configuration for updating GitHub releases from agent output +type UpdateReleaseConfig struct { + BaseSafeOutputConfig `yaml:",inline"` + TargetRepoSlug string `yaml:"target-repo,omitempty"` // Target repository for cross-repo operations +} + +// buildCreateOutputUpdateReleaseJob creates the update_release job using the shared builder +func (c *Compiler) buildCreateOutputUpdateReleaseJob(data *WorkflowData, mainJobName string) (*Job, error) { + if data.SafeOutputs == nil || data.SafeOutputs.UpdateRelease == nil { + return nil, fmt.Errorf("safe-outputs.update-release configuration is required") + } + + // Build custom environment variables specific to update-release + var customEnvVars []string + customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_WORKFLOW_NAME: %q\n", data.Name)) + + // Add common safe output job environment variables (staged/target repo) + customEnvVars = append(customEnvVars, buildSafeOutputJobEnvVars( + c.trialMode, + c.trialLogicalRepoSlug, + data.SafeOutputs.Staged, + data.SafeOutputs.UpdateRelease.TargetRepoSlug, + )...) + + // Get token from config + var token string + if data.SafeOutputs.UpdateRelease != nil { + token = data.SafeOutputs.UpdateRelease.GitHubToken + } + + // Create outputs for the job + outputs := map[string]string{ + "release_id": "${{ steps.update_release.outputs.release_id }}", + "release_url": "${{ steps.update_release.outputs.release_url }}", + "release_tag": "${{ steps.update_release.outputs.release_tag }}", + } + + // Use the shared builder function to create the job + return c.buildSafeOutputJob(data, SafeOutputJobConfig{ + JobName: "update_release", + StepName: "Update Release", + StepID: "update_release", + MainJobName: mainJobName, + CustomEnvVars: customEnvVars, + Script: getUpdateReleaseScript(), + Permissions: NewPermissionsContentsWrite(), + Outputs: outputs, + Token: token, + TargetRepoSlug: data.SafeOutputs.UpdateRelease.TargetRepoSlug, + }) +} + +// parseUpdateReleaseConfig handles update-release configuration +func (c *Compiler) parseUpdateReleaseConfig(outputMap map[string]any) *UpdateReleaseConfig { + if configData, exists := outputMap["update-release"]; exists { + updateReleaseConfig := &UpdateReleaseConfig{} + updateReleaseConfig.Max = 1 // Default max is 1 + + if configMap, ok := configData.(map[string]any); ok { + // Parse common base fields with default max of 1 + c.parseBaseSafeOutputConfig(configMap, &updateReleaseConfig.BaseSafeOutputConfig, 1) + + // Parse target-repo using shared helper + targetRepoSlug := parseTargetRepoFromConfig(configMap) + updateReleaseConfig.TargetRepoSlug = targetRepoSlug + } else { + // If configData is nil or not a map, still set the default max + updateReleaseConfig.Max = 1 + } + + return updateReleaseConfig + } + + return nil +} From 72bcf34fec6d438a3340696e683d843626ddd4e3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 13:41:50 +0000 Subject: [PATCH 04/12] Add test workflows and workflow schema for update-release Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../workflows/test-claude-update-release.md | 34 +++++++++++++++++++ .../workflows/test-codex-update-release.md | 34 +++++++++++++++++++ .../workflows/test-copilot-update-release.md | 34 +++++++++++++++++++ pkg/parser/schemas/main_workflow_schema.json | 31 +++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 pkg/cli/workflows/test-claude-update-release.md create mode 100644 pkg/cli/workflows/test-codex-update-release.md create mode 100644 pkg/cli/workflows/test-copilot-update-release.md diff --git a/pkg/cli/workflows/test-claude-update-release.md b/pkg/cli/workflows/test-claude-update-release.md new file mode 100644 index 0000000000..2ab53810e8 --- /dev/null +++ b/pkg/cli/workflows/test-claude-update-release.md @@ -0,0 +1,34 @@ +--- +on: + workflow_dispatch: +permissions: + contents: read + actions: read +engine: claude +safe-outputs: + update-release: + max: 1 +timeout-minutes: 5 +--- + +# Test Claude Update Release + +Test the update-release safe output with the Claude engine. + +Find the latest release in this repository and update its description using the **append** operation. + +Add this content to the release notes: + +## Test Update from Claude + +This section was added by an automated test workflow to verify the update-release functionality. + +**Test Details:** +- Engine: Claude +- Operation: append +- Timestamp: Current date and time + +Output as JSONL format: +``` +{"type": "update_release", "tag": "", "operation": "append", "body": ""} +``` diff --git a/pkg/cli/workflows/test-codex-update-release.md b/pkg/cli/workflows/test-codex-update-release.md new file mode 100644 index 0000000000..83e56ad872 --- /dev/null +++ b/pkg/cli/workflows/test-codex-update-release.md @@ -0,0 +1,34 @@ +--- +on: + workflow_dispatch: +permissions: + contents: read + actions: read +engine: codex +safe-outputs: + update-release: + max: 1 +timeout-minutes: 5 +--- + +# Test Codex Update Release + +Test the update-release safe output with the Codex engine. + +Find the latest release in this repository and update its description using the **replace** operation. + +Replace the release notes with this content: + +## Updated Release Notes (Codex Test) + +This release description was updated by an automated test workflow to verify the update-release functionality. + +**Test Configuration:** +- Engine: Codex +- Operation: replace +- Timestamp: Current date and time + +Output as JSONL format: +``` +{"type": "update_release", "tag": "", "operation": "replace", "body": ""} +``` diff --git a/pkg/cli/workflows/test-copilot-update-release.md b/pkg/cli/workflows/test-copilot-update-release.md new file mode 100644 index 0000000000..42d3bdf19d --- /dev/null +++ b/pkg/cli/workflows/test-copilot-update-release.md @@ -0,0 +1,34 @@ +--- +on: + workflow_dispatch: +permissions: + contents: read + actions: read +engine: copilot +safe-outputs: + update-release: + max: 1 +timeout-minutes: 5 +--- + +# Test Copilot Update Release + +Test the update-release safe output with the Copilot engine. + +Find the latest release in this repository and update its description using the **append** operation. + +Add this content to the release notes: + +## Test Update from Copilot + +This section was added by an automated test workflow to verify the update-release functionality. + +**Test Information:** +- Engine: Copilot +- Operation: append +- Timestamp: Current date and time + +Output as JSONL format: +``` +{"type": "update_release", "tag": "", "operation": "append", "body": ""} +``` diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json index 0c3f4f21af..d3f56f8700 100644 --- a/pkg/parser/schemas/main_workflow_schema.json +++ b/pkg/parser/schemas/main_workflow_schema.json @@ -2872,6 +2872,37 @@ } ] }, + "update-release": { + "oneOf": [ + { + "type": "object", + "description": "Configuration for updating GitHub release descriptions", + "properties": { + "max": { + "type": "integer", + "description": "Maximum number of releases to update (default: 1)", + "minimum": 1, + "maximum": 10, + "default": 1 + }, + "target-repo": { + "type": "string", + "description": "Target repository for cross-repo release updates (format: owner/repo). If not specified, updates releases in the workflow's repository.", + "pattern": "^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$" + }, + "github-token": { + "$ref": "#/$defs/github_token", + "description": "GitHub token to use for this specific output type. Overrides global github-token if specified." + } + }, + "additionalProperties": false + }, + { + "type": "null", + "description": "Enable release updates with default configuration" + } + ] + }, "staged": { "type": "boolean", "description": "If true, emit step summary messages instead of making GitHub API calls (preview mode)", From 4ac20ed33d34ac63fd14383720b212464770aa04 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 13:44:46 +0000 Subject: [PATCH 05/12] Update generated schema documentation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../docs/reference/frontmatter-full.md | 22 +++++++++++++++++++ pkg/workflow/compiler.go | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/src/content/docs/reference/frontmatter-full.md b/docs/src/content/docs/reference/frontmatter-full.md index d3ef4f9e52..ae03889de1 100644 --- a/docs/src/content/docs/reference/frontmatter-full.md +++ b/docs/src/content/docs/reference/frontmatter-full.md @@ -1707,6 +1707,28 @@ safe-outputs: # Option 2: Enable asset publishing with default configuration upload-assets: null + # (optional) + # This field supports multiple formats (oneOf): + + # Option 1: Configuration for updating GitHub release descriptions + update-release: + # Maximum number of releases to update (default: 1) + # (optional) + max: 1 + + # Target repository for cross-repo release updates (format: owner/repo). If not + # specified, updates releases in the workflow's repository. + # (optional) + target-repo: "example-value" + + # GitHub token to use for this specific output type. Overrides global github-token + # if specified. + # (optional) + github-token: "${{ secrets.GITHUB_TOKEN }}" + + # Option 2: Enable release updates with default configuration + update-release: null + # If true, emit step summary messages instead of making GitHub API calls (preview # mode) # (optional) diff --git a/pkg/workflow/compiler.go b/pkg/workflow/compiler.go index 56d20f4ea6..17b82a7d5f 100644 --- a/pkg/workflow/compiler.go +++ b/pkg/workflow/compiler.go @@ -261,7 +261,7 @@ type SafeOutputsConfig struct { UpdateIssues *UpdateIssuesConfig `yaml:"update-issues,omitempty"` PushToPullRequestBranch *PushToPullRequestBranchConfig `yaml:"push-to-pull-request-branch,omitempty"` UploadAssets *UploadAssetsConfig `yaml:"upload-assets,omitempty"` - UpdateRelease *UpdateReleaseConfig `yaml:"update-release,omitempty"` // Update GitHub release descriptions + UpdateRelease *UpdateReleaseConfig `yaml:"update-release,omitempty"` // Update GitHub release descriptions CreateAgentTasks *CreateAgentTaskConfig `yaml:"create-agent-task,omitempty"` // Create GitHub Copilot agent tasks UpdateProjects *UpdateProjectConfig `yaml:"update-project,omitempty"` // Smart project board management (create/add/update) MissingTool *MissingToolConfig `yaml:"missing-tool,omitempty"` // Optional for reporting missing functionality From 817c0a09401cd2e4a20ce01fce81bc77c88dceec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 14:09:22 +0000 Subject: [PATCH 06/12] Add prepend operation, release context support, and update dev.md workflow - Added "prepend" operation to update-release safe output - Prepend adds content at the start with horizontal line separator and AI footer - Updated compute_text.cjs to handle release events and workflow_dispatch inputs - Added support for release_url and release_id inputs in workflow_dispatch - Updated dev.md workflow to trigger on release events and prepend summaries - All tests updated and passing (7 update_release tests, 1005 total JS tests) Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/ai-triage-campaign.lock.yml | 4 +- .github/workflows/archie.lock.yml | 48 +- .github/workflows/artifacts-summary.lock.yml | 4 +- .github/workflows/audit-workflows.lock.yml | 4 +- .github/workflows/blog-auditor.lock.yml | 4 +- .github/workflows/brave.lock.yml | 48 +- .github/workflows/changeset.lock.yml | 48 +- .github/workflows/ci-doctor.lock.yml | 4 +- .../cli-consistency-checker.lock.yml | 4 +- .../workflows/cli-version-checker.lock.yml | 4 +- .github/workflows/cloclo.lock.yml | 48 +- .../commit-changes-analyzer.lock.yml | 4 +- .../workflows/copilot-agent-analysis.lock.yml | 4 +- .../copilot-pr-nlp-analysis.lock.yml | 4 +- .../copilot-pr-prompt-analysis.lock.yml | 4 +- .../copilot-session-insights.lock.yml | 4 +- .github/workflows/craft.lock.yml | 48 +- .github/workflows/daily-code-metrics.lock.yml | 4 +- .github/workflows/daily-doc-updater.lock.yml | 4 +- .github/workflows/daily-file-diet.lock.yml | 4 +- .../workflows/daily-firewall-report.lock.yml | 4 +- .../daily-multi-device-docs-tester.lock.yml | 4 +- .github/workflows/daily-news.lock.yml | 4 +- .../workflows/daily-repo-chronicle.lock.yml | 4 +- .github/workflows/daily-team-status.lock.yml | 4 +- .../workflows/dependabot-go-checker.lock.yml | 4 +- .github/workflows/dev-hawk.lock.yml | 4 +- .github/workflows/dev.lock.yml | 616 +++++++++++++++++- .github/workflows/dev.md | 54 +- .../developer-docs-consolidator.lock.yml | 4 +- .github/workflows/dictation-prompt.lock.yml | 4 +- .github/workflows/docs-noob-tester.lock.yml | 4 +- .../duplicate-code-detector.lock.yml | 4 +- .../example-workflow-analyzer.lock.yml | 4 +- .../github-mcp-tools-report.lock.yml | 4 +- .github/workflows/go-logger.lock.yml | 4 +- .../workflows/go-pattern-detector.lock.yml | 4 +- .github/workflows/grumpy-reviewer.lock.yml | 48 +- .../workflows/instructions-janitor.lock.yml | 4 +- .github/workflows/issue-classifier.lock.yml | 48 +- .github/workflows/lockfile-stats.lock.yml | 4 +- .github/workflows/mcp-inspector.lock.yml | 4 +- .github/workflows/mergefest.lock.yml | 4 +- .../workflows/notion-issue-summary.lock.yml | 4 +- .github/workflows/pdf-summary.lock.yml | 48 +- .github/workflows/plan.lock.yml | 48 +- .github/workflows/poem-bot.lock.yml | 48 +- .../workflows/pr-nitpick-reviewer.lock.yml | 4 +- .../prompt-clustering-analysis.lock.yml | 4 +- .github/workflows/python-data-charts.lock.yml | 4 +- .github/workflows/q.lock.yml | 48 +- .github/workflows/repo-tree-map.lock.yml | 4 +- .../repository-quality-improver.lock.yml | 4 +- .github/workflows/research.lock.yml | 4 +- .github/workflows/safe-output-health.lock.yml | 4 +- .../schema-consistency-checker.lock.yml | 4 +- .github/workflows/scout.lock.yml | 48 +- .github/workflows/security-fix-pr.lock.yml | 4 +- .../semantic-function-refactor.lock.yml | 4 +- .github/workflows/smoke-claude.lock.yml | 4 +- .github/workflows/smoke-codex.lock.yml | 4 +- .github/workflows/smoke-copilot.lock.yml | 4 +- .github/workflows/smoke-detector.lock.yml | 4 +- .../workflows/static-analysis-report.lock.yml | 4 +- .github/workflows/super-linter.lock.yml | 4 +- .../workflows/technical-doc-writer.lock.yml | 4 +- .../test-ollama-threat-detection.lock.yml | 4 +- .github/workflows/tidy.lock.yml | 4 +- .github/workflows/typist.lock.yml | 4 +- .github/workflows/unbloat-docs.lock.yml | 4 +- .github/workflows/video-analyzer.lock.yml | 4 +- .../workflows/weekly-issue-summary.lock.yml | 4 +- pkg/workflow/js/collect_ndjson_output.cjs | 4 +- .../js/collect_ndjson_output.test.cjs | 6 +- pkg/workflow/js/compute_text.cjs | 51 ++ pkg/workflow/js/update_release.cjs | 8 +- pkg/workflow/js/update_release.test.cjs | 46 ++ schemas/agent-output.json | 4 +- 78 files changed, 1396 insertions(+), 201 deletions(-) diff --git a/.github/workflows/ai-triage-campaign.lock.yml b/.github/workflows/ai-triage-campaign.lock.yml index ff8b7e3bde..6dd0bb4dc8 100644 --- a/.github/workflows/ai-triage-campaign.lock.yml +++ b/.github/workflows/ai-triage-campaign.lock.yml @@ -2245,8 +2245,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index 94ac075635..9578e75f5e 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -416,6 +416,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3320,8 +3364,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index 5f24592be5..a5cb43597f 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -2191,8 +2191,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index a553202544..8b195cce75 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -3233,8 +3233,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml index d542a98978..c099b09f38 100644 --- a/.github/workflows/blog-auditor.lock.yml +++ b/.github/workflows/blog-auditor.lock.yml @@ -2579,8 +2579,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index 478c352647..4c969871d1 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -397,6 +397,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3167,8 +3211,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index 962249e531..c017ba5af3 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -400,6 +400,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2859,8 +2903,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index ef420b1e66..38155a1df9 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -2675,8 +2675,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index e98f34ae17..ae552f8622 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -2229,8 +2229,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index 6076eab4d2..dda7ef7045 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -2405,8 +2405,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index e2996d3465..bf8fc7c58e 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -447,6 +447,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3714,8 +3758,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml index 13f4bf1bdf..401327df42 100644 --- a/.github/workflows/commit-changes-analyzer.lock.yml +++ b/.github/workflows/commit-changes-analyzer.lock.yml @@ -2510,8 +2510,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index 0f13b6afc1..e1744c3a01 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -2873,8 +2873,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index 424b946826..b5cf1a579d 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -2966,8 +2966,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index ca2544a859..4c0a8ff469 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -2532,8 +2532,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index 05a8661682..6a399dc3ef 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -3782,8 +3782,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index 56aafe2e1d..f48cc8c65e 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -398,6 +398,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3321,8 +3365,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index 2a73763811..77646cf589 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -2853,8 +2853,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index 65f9e4bb7f..7078d5ab08 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -2439,8 +2439,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index 2aeae46fcd..cd25494dd3 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -2340,8 +2340,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index 42983be934..b0dff6cade 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -2949,8 +2949,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml index 31ac5f8e21..064c546ade 100644 --- a/.github/workflows/daily-multi-device-docs-tester.lock.yml +++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml @@ -2363,8 +2363,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index 58eff785ca..40ea01d0ff 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -2958,8 +2958,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index bfebda31bb..e865f5d7ea 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -2802,8 +2802,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml index 2e5ec352ba..ad1bd4e9f8 100644 --- a/.github/workflows/daily-team-status.lock.yml +++ b/.github/workflows/daily-team-status.lock.yml @@ -2122,8 +2122,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml index cd911c4c8e..6e116549f7 100644 --- a/.github/workflows/dependabot-go-checker.lock.yml +++ b/.github/workflows/dependabot-go-checker.lock.yml @@ -2263,8 +2263,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index 21be2a4f64..2b76f9ecff 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -2566,8 +2566,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index 9b07b2aaf3..f8a055c8f8 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -12,7 +12,10 @@ # agent["agent"] # detection["detection"] # missing_tool["missing_tool"] +# pre_activation["pre_activation"] # push_to_pull_request_branch["push_to_pull_request_branch"] +# update_release["update_release"] +# pre_activation --> activation # activation --> agent # agent --> detection # agent --> missing_tool @@ -20,6 +23,8 @@ # agent --> push_to_pull_request_branch # activation --> push_to_pull_request_branch # detection --> push_to_pull_request_branch +# agent --> update_release +# detection --> update_release # ``` # # Pinned GitHub Actions: @@ -36,10 +41,24 @@ name: "Dev" "on": - workflow_dispatch: null + release: + types: + - created + - edited + - published + workflow_dispatch: + inputs: + release_id: + description: Release ID + required: false + type: string + release_url: + description: Release URL (e.g., https://github.com/owner/repo/releases/tag/v1.0.0) + required: false + type: string permissions: - contents: read + contents: write issues: read pull-requests: read @@ -51,9 +70,13 @@ run-name: "Dev" jobs: activation: + needs: pre_activation + if: needs.pre_activation.outputs.activated == 'true' runs-on: ubuntu-slim permissions: contents: read + outputs: + text: ${{ steps.compute-text.outputs.text }} steps: - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 @@ -142,12 +165,295 @@ jobs: main().catch(error => { core.setFailed(error instanceof Error ? error.message : String(error)); }); + - name: Compute current body text + id: compute-text + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + function extractDomainsFromUrl(url) { + if (!url || typeof url !== "string") { + return []; + } + try { + const urlObj = new URL(url); + const hostname = urlObj.hostname.toLowerCase(); + const domains = [hostname]; + if (hostname === "github.com") { + domains.push("api.github.com"); + domains.push("raw.githubusercontent.com"); + domains.push("*.githubusercontent.com"); + } + else if (!hostname.startsWith("api.")) { + domains.push("api." + hostname); + domains.push("raw." + hostname); + } + return domains; + } catch (e) { + return []; + } + } + function sanitizeContent(content, maxLength) { + if (!content || typeof content !== "string") { + return ""; + } + const allowedDomainsEnv = process.env.GH_AW_ALLOWED_DOMAINS; + const defaultAllowedDomains = ["github.com", "github.io", "githubusercontent.com", "githubassets.com", "github.dev", "codespaces.new"]; + let allowedDomains = allowedDomainsEnv + ? allowedDomainsEnv + .split(",") + .map(d => d.trim()) + .filter(d => d) + : defaultAllowedDomains; + const githubServerUrl = process.env.GITHUB_SERVER_URL; + const githubApiUrl = process.env.GITHUB_API_URL; + if (githubServerUrl) { + const serverDomains = extractDomainsFromUrl(githubServerUrl); + allowedDomains = allowedDomains.concat(serverDomains); + } + if (githubApiUrl) { + const apiDomains = extractDomainsFromUrl(githubApiUrl); + allowedDomains = allowedDomains.concat(apiDomains); + } + allowedDomains = [...new Set(allowedDomains)]; + let sanitized = content; + sanitized = neutralizeCommands(sanitized); + sanitized = neutralizeMentions(sanitized); + sanitized = removeXmlComments(sanitized); + sanitized = convertXmlTags(sanitized); + sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, ""); + sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, ""); + sanitized = sanitizeUrlProtocols(sanitized); + sanitized = sanitizeUrlDomains(sanitized); + const lines = sanitized.split("\n"); + const maxLines = 65000; + maxLength = maxLength || 524288; + if (lines.length > maxLines) { + const truncationMsg = "\n[Content truncated due to line count]"; + const truncatedLines = lines.slice(0, maxLines).join("\n") + truncationMsg; + if (truncatedLines.length > maxLength) { + sanitized = truncatedLines.substring(0, maxLength - truncationMsg.length) + truncationMsg; + } else { + sanitized = truncatedLines; + } + } else if (sanitized.length > maxLength) { + sanitized = sanitized.substring(0, maxLength) + "\n[Content truncated due to length]"; + } + sanitized = neutralizeBotTriggers(sanitized); + return sanitized.trim(); + function sanitizeUrlDomains(s) { + s = s.replace(/\bhttps:\/\/([^\s\])}'"<>&\x00-\x1f,;]+)/gi, (match, rest) => { + const hostname = rest.split(/[\/:\?#]/)[0].toLowerCase(); + const isAllowed = allowedDomains.some(allowedDomain => { + const normalizedAllowed = allowedDomain.toLowerCase(); + return hostname === normalizedAllowed || hostname.endsWith("." + normalizedAllowed); + }); + if (isAllowed) { + return match; + } + const domain = hostname; + const truncated = domain.length > 12 ? domain.substring(0, 12) + "..." : domain; + core.info(`Redacted URL: ${truncated}`); + core.debug(`Redacted URL (full): ${match}`); + const urlParts = match.split(/([?&#])/); + let result = "(redacted)"; + for (let i = 1; i < urlParts.length; i++) { + if (urlParts[i].match(/^[?&#]$/)) { + result += urlParts[i]; + } else { + result += sanitizeUrlDomains(urlParts[i]); + } + } + return result; + }); + return s; + } + function sanitizeUrlProtocols(s) { + return s.replace(/(?&\x00-\x1f]+/g, (match, protocol) => { + if (protocol.toLowerCase() === "https") { + return match; + } + if (match.includes("::")) { + return match; + } + if (match.includes("://")) { + const domainMatch = match.match(/^[^:]+:\/\/([^\/\s?#]+)/); + const domain = domainMatch ? domainMatch[1] : match; + const truncated = domain.length > 12 ? domain.substring(0, 12) + "..." : domain; + core.info(`Redacted URL: ${truncated}`); + core.debug(`Redacted URL (full): ${match}`); + return "(redacted)"; + } + const dangerousProtocols = ["javascript", "data", "vbscript", "file", "about", "mailto", "tel", "ssh", "ftp"]; + if (dangerousProtocols.includes(protocol.toLowerCase())) { + const truncated = match.length > 12 ? match.substring(0, 12) + "..." : match; + core.info(`Redacted URL: ${truncated}`); + core.debug(`Redacted URL (full): ${match}`); + return "(redacted)"; + } + return match; + }); + } + function neutralizeCommands(s) { + const commandName = process.env.GH_AW_COMMAND; + if (!commandName) { + return s; + } + const escapedCommand = commandName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + return s.replace(new RegExp(`^(\\s*)/(${escapedCommand})\\b`, "i"), "$1`/$2`"); + } + function neutralizeMentions(s) { + return s.replace( + /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g, + (_m, p1, p2) => `${p1}\`@${p2}\`` + ); + } + function removeXmlComments(s) { + return s.replace(//g, "").replace(//g, ""); + } + function convertXmlTags(s) { + const allowedTags = ["details", "summary", "code", "em", "b"]; + s = s.replace(//g, (match, content) => { + const convertedContent = content.replace(/<(\/?[A-Za-z][A-Za-z0-9]*(?:[^>]*?))>/g, "($1)"); + return `(![CDATA[${convertedContent}]])`; + }); + return s.replace(/<(\/?[A-Za-z!][^>]*?)>/g, (match, tagContent) => { + const tagNameMatch = tagContent.match(/^\/?\s*([A-Za-z][A-Za-z0-9]*)/); + if (tagNameMatch) { + const tagName = tagNameMatch[1].toLowerCase(); + if (allowedTags.includes(tagName)) { + return match; + } + } + return `(${tagContent})`; + }); + } + function neutralizeBotTriggers(s) { + return s.replace(/\b(fixes?|closes?|resolves?|fix|close|resolve)\s+#(\w+)/gi, (match, action, ref) => `\`${action} #${ref}\``); + } + } + async function main() { + let text = ""; + const actor = context.actor; + const { owner, repo } = context.repo; + const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: owner, + repo: repo, + username: actor, + }); + const permission = repoPermission.data.permission; + core.info(`Repository permission level: ${permission}`); + if (permission !== "admin" && permission !== "maintain") { + core.setOutput("text", ""); + return; + } + switch (context.eventName) { + case "issues": + if (context.payload.issue) { + const title = context.payload.issue.title || ""; + const body = context.payload.issue.body || ""; + text = `${title}\n\n${body}`; + } + break; + case "pull_request": + if (context.payload.pull_request) { + const title = context.payload.pull_request.title || ""; + const body = context.payload.pull_request.body || ""; + text = `${title}\n\n${body}`; + } + break; + case "pull_request_target": + if (context.payload.pull_request) { + const title = context.payload.pull_request.title || ""; + const body = context.payload.pull_request.body || ""; + text = `${title}\n\n${body}`; + } + break; + case "issue_comment": + if (context.payload.comment) { + text = context.payload.comment.body || ""; + } + break; + case "pull_request_review_comment": + if (context.payload.comment) { + text = context.payload.comment.body || ""; + } + break; + case "pull_request_review": + if (context.payload.review) { + text = context.payload.review.body || ""; + } + break; + case "discussion": + if (context.payload.discussion) { + const title = context.payload.discussion.title || ""; + const body = context.payload.discussion.body || ""; + text = `${title}\n\n${body}`; + } + break; + case "discussion_comment": + if (context.payload.comment) { + text = context.payload.comment.body || ""; + } + break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; + default: + text = ""; + break; + } + const sanitizedText = sanitizeContent(text); + core.info(`text: ${sanitizedText}`); + core.setOutput("text", sanitizedText); + } + await main(); agent: needs: activation runs-on: ubuntu-latest permissions: - contents: read + contents: write issues: read pull-requests: read concurrency: @@ -874,38 +1180,29 @@ jobs: mkdir -p "$PROMPT_DIR" # shellcheck disable=SC2006,SC2287 cat > "$GH_AW_PROMPT" << 'PROMPT_EOF' - # Generate a Poem - - Create or update a `poem.md` file with a creative poem about GitHub Agentic Workflows and push the changes to the pull request branch. + # Release Summary Prepender - **Instructions**: + **Context:** This workflow is triggered when a release is created/edited or manually dispatched with a release URL/ID. - Use the `edit` tool to either create a new `poem.md` file or update the existing one if it already exists. Write a creative, engaging poem that celebrates the power and capabilities of GitHub Agentic Workflows. + The release content is available in the context: "${GH_AW_EXPR_0BABF60D}" - The poem should be: - - Creative and fun - - Related to automation, AI agents, or GitHub workflows - - At least 8 lines long - - Written in a poetic style (rhyming, rhythm, or free verse) + **Task:** Analyze the release description and prepend a concise AI-generated summary to it. - Commit your changes. + **Instructions:** - Call the `push-to-pull-request-branch` tool after making your changes. + 1. Read the release content from the context above + 2. Generate a clear, concise summary (2-4 sentences) highlighting the key changes or features + 3. Use the `update_release` safe output with the **prepend** operation to add your summary at the top - **Example poem file structure:** - ```markdown - # Poem for GitHub Agentic Workflows + **Output format:** + ```jsonl + {"type": "update_release", "tag": "TAG_NAME_HERE", "operation": "prepend", "body": "## AI Summary\n\n[Your 2-4 sentence summary here]"} + ``` - In the realm of code where automation flows, - An agent awakens, its purpose it knows. - Through pull requests and issues it goes, - Analyzing, creating, whatever it shows. + For release events, use tag: `${GH_AW_EXPR_8CC9E4EE}` + For manual workflow dispatch with release URL/ID, extract the tag from the fetched release data. - With LlamaGuard watching for threats in the night, - And Ollama scanning to keep things right. - The workflows are running, efficient and bright, - GitHub Agentic magic, a developer's delight. - ``` + **Note:** The summary will be automatically prepended with a horizontal line separator and AI attribution footer. PROMPT_EOF - name: Append XPIA security instructions to prompt @@ -1039,6 +1336,8 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_EXPR_8CC9E4EE: ${{ github.event.release.tag_name }} + GH_AW_EXPR_0BABF60D: ${{ needs.activation.outputs.text }} with: script: | const fs = require("fs"); @@ -2088,8 +2387,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { @@ -4173,6 +4472,86 @@ jobs: core.setFailed(`Error processing missing-tool reports: ${error}`); }); + pre_activation: + runs-on: ubuntu-slim + outputs: + activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} + steps: + - name: Check team membership for workflow + id: check_membership + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_REQUIRED_ROLES: admin,maintainer,write + with: + script: | + async function main() { + const { eventName } = context; + const actor = context.actor; + const { owner, repo } = context.repo; + const requiredPermissionsEnv = process.env.GH_AW_REQUIRED_ROLES; + const requiredPermissions = requiredPermissionsEnv ? requiredPermissionsEnv.split(",").filter(p => p.trim() !== "") : []; + if (eventName === "workflow_dispatch") { + const hasWriteRole = requiredPermissions.includes("write"); + if (hasWriteRole) { + core.info(`✅ Event ${eventName} does not require validation (write role allowed)`); + core.setOutput("is_team_member", "true"); + core.setOutput("result", "safe_event"); + return; + } + core.info(`Event ${eventName} requires validation (write role not allowed)`); + } + const safeEvents = ["schedule"]; + if (safeEvents.includes(eventName)) { + core.info(`✅ Event ${eventName} does not require validation`); + core.setOutput("is_team_member", "true"); + core.setOutput("result", "safe_event"); + return; + } + if (!requiredPermissions || requiredPermissions.length === 0) { + core.warning("❌ Configuration error: Required permissions not specified. Contact repository administrator."); + core.setOutput("is_team_member", "false"); + core.setOutput("result", "config_error"); + core.setOutput("error_message", "Configuration error: Required permissions not specified"); + return; + } + try { + core.info(`Checking if user '${actor}' has required permissions for ${owner}/${repo}`); + core.info(`Required permissions: ${requiredPermissions.join(", ")}`); + const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: owner, + repo: repo, + username: actor, + }); + const permission = repoPermission.data.permission; + core.info(`Repository permission level: ${permission}`); + for (const requiredPerm of requiredPermissions) { + if (permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain")) { + core.info(`✅ User has ${permission} access to repository`); + core.setOutput("is_team_member", "true"); + core.setOutput("result", "authorized"); + core.setOutput("user_permission", permission); + return; + } + } + core.warning(`User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}`); + core.setOutput("is_team_member", "false"); + core.setOutput("result", "insufficient_permissions"); + core.setOutput("user_permission", permission); + core.setOutput( + "error_message", + `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` + ); + } catch (repoError) { + const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); + core.warning(`Repository permission check failed: ${errorMessage}`); + core.setOutput("is_team_member", "false"); + core.setOutput("result", "api_error"); + core.setOutput("error_message", `Repository permission check failed: ${errorMessage}`); + return; + } + } + await main(); + push_to_pull_request_branch: needs: - agent @@ -4676,3 +5055,182 @@ jobs: } await main(); + update_release: + needs: + - agent + - detection + if: > + (((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'update_release'))) && + (needs.detection.outputs.success == 'true') + runs-on: ubuntu-slim + permissions: + contents: write + timeout-minutes: 10 + outputs: + release_id: ${{ steps.update_release.outputs.release_id }} + release_tag: ${{ steps.update_release.outputs.release_tag }} + release_url: ${{ steps.update_release.outputs.release_url }} + steps: + - name: Download agent output artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 + with: + name: agent_output.json + path: /tmp/gh-aw/safeoutputs/ + - name: Setup agent output environment variable + run: | + mkdir -p /tmp/gh-aw/safeoutputs/ + find "/tmp/gh-aw/safeoutputs/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Update Release + id: update_release + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Dev" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const fs = require("fs"); + function loadAgentOutput() { + const agentOutputFile = process.env.GH_AW_AGENT_OUTPUT; + if (!agentOutputFile) { + core.info("No GH_AW_AGENT_OUTPUT environment variable found"); + return { success: false }; + } + let outputContent; + try { + outputContent = fs.readFileSync(agentOutputFile, "utf8"); + } catch (error) { + const errorMessage = `Error reading agent output file: ${error instanceof Error ? error.message : String(error)}`; + core.error(errorMessage); + return { success: false, error: errorMessage }; + } + if (outputContent.trim() === "") { + core.info("Agent output content is empty"); + return { success: false }; + } + core.info(`Agent output content length: ${outputContent.length}`); + let validatedOutput; + try { + validatedOutput = JSON.parse(outputContent); + } catch (error) { + const errorMessage = `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}`; + core.error(errorMessage); + return { success: false, error: errorMessage }; + } + if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { + core.info("No valid items found in agent output"); + return { success: false }; + } + return { success: true, items: validatedOutput.items }; + } + async function generateStagedPreview(options) { + const { title, description, items, renderItem } = options; + let summaryContent = `## 🎭 Staged Mode: ${title} Preview\n\n`; + summaryContent += `${description}\n\n`; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + summaryContent += renderItem(item, i); + summaryContent += "---\n\n"; + } + try { + await core.summary.addRaw(summaryContent).write(); + core.info(summaryContent); + core.info(`📝 ${title} preview written to step summary`); + } catch (error) { + core.setFailed(error instanceof Error ? error : String(error)); + } + } + async function main() { + const isStaged = process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true"; + const result = loadAgentOutput(); + if (!result.success) { + return; + } + const updateItems = result.items.filter( item => item.type === "update_release"); + if (updateItems.length === 0) { + core.info("No update-release items found in agent output"); + return; + } + core.info(`Found ${updateItems.length} update-release item(s)`); + if (isStaged) { + await generateStagedPreview({ + title: "Update Releases", + description: "The following release updates would be applied if staged mode was disabled:", + items: updateItems, + renderItem: (item, index) => { + let content = `### Release Update ${index + 1}\n`; + content += `**Tag:** ${item.tag}\n`; + content += `**Operation:** ${item.operation}\n\n`; + content += `**Body Content:**\n${item.body}\n\n`; + return content; + }, + }); + return; + } + const workflowName = process.env.GH_AW_WORKFLOW_NAME || "GitHub Agentic Workflow"; + const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + const updatedReleases = []; + for (let i = 0; i < updateItems.length; i++) { + const updateItem = updateItems[i]; + core.info(`Processing update-release item ${i + 1}/${updateItems.length}`); + try { + core.info(`Fetching release with tag: ${updateItem.tag}`); + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: context.repo.owner, + repo: context.repo.repo, + tag: updateItem.tag, + }); + core.info(`Found release: ${release.name || release.tag_name} (ID: ${release.id})`); + let newBody; + if (updateItem.operation === "replace") { + newBody = updateItem.body; + core.info("Operation: replace (full body replacement)"); + } else if (updateItem.operation === "prepend") { + const aiFooter = `\n\n> AI generated by [${workflowName}](${runUrl})`; + const prependSection = `${updateItem.body}${aiFooter}\n\n---\n\n`; + newBody = prependSection + (release.body || ""); + core.info("Operation: prepend (add to start with separator)"); + } else { + const aiFooter = `\n\n> AI generated by [${workflowName}](${runUrl})`; + const appendSection = `\n\n---\n\n${updateItem.body}${aiFooter}`; + newBody = (release.body || "") + appendSection; + core.info("Operation: append (add to end with separator)"); + } + const { data: updatedRelease } = await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.id, + body: newBody, + }); + core.info(`Successfully updated release: ${updatedRelease.html_url}`); + updatedReleases.push({ + tag: updateItem.tag, + url: updatedRelease.html_url, + id: updatedRelease.id, + }); + if (i === 0) { + core.setOutput("release_id", updatedRelease.id); + core.setOutput("release_url", updatedRelease.html_url); + core.setOutput("release_tag", updatedRelease.tag_name); + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + core.error(`Failed to update release with tag ${updateItem.tag}: ${errorMessage}`); + if (errorMessage.includes("Not Found")) { + core.error(`Release with tag '${updateItem.tag}' not found. Please ensure the tag exists.`); + } + core.setFailed(`Failed to update release: ${errorMessage}`); + return; + } + } + let summaryContent = `## ✅ Release Updates Complete\n\n`; + summaryContent += `Updated ${updatedReleases.length} release(s):\n\n`; + for (const rel of updatedReleases) { + summaryContent += `- **${rel.tag}**: [View Release](${rel.url})\n`; + } + await core.summary.addRaw(summaryContent).write(); + } + await main(); + diff --git a/.github/workflows/dev.md b/.github/workflows/dev.md index f437d972b1..8f3a2a5d92 100644 --- a/.github/workflows/dev.md +++ b/.github/workflows/dev.md @@ -1,6 +1,17 @@ --- on: workflow_dispatch: + inputs: + release_url: + description: 'Release URL (e.g., https://github.com/owner/repo/releases/tag/v1.0.0)' + required: false + type: string + release_id: + description: 'Release ID' + required: false + type: string + release: + types: [created, edited, published] concurrency: group: dev-workflow-${{ github.ref }} cancel-in-progress: true @@ -8,12 +19,14 @@ name: Dev description: Test workflow for development and experimentation purposes engine: copilot permissions: - contents: read + contents: write issues: read pull-requests: read tools: edit: safe-outputs: + update-release: + max: 1 threat-detection: engine: false steps: @@ -332,35 +345,26 @@ safe-outputs: timeout-minutes: 20 --- -# Generate a Poem +# Release Summary Prepender -Create or update a `poem.md` file with a creative poem about GitHub Agentic Workflows and push the changes to the pull request branch. +**Context:** This workflow is triggered when a release is created/edited or manually dispatched with a release URL/ID. -**Instructions**: +The release content is available in the context: "${{ needs.activation.outputs.text }}" -Use the `edit` tool to either create a new `poem.md` file or update the existing one if it already exists. Write a creative, engaging poem that celebrates the power and capabilities of GitHub Agentic Workflows. +**Task:** Analyze the release description and prepend a concise AI-generated summary to it. -The poem should be: -- Creative and fun -- Related to automation, AI agents, or GitHub workflows -- At least 8 lines long -- Written in a poetic style (rhyming, rhythm, or free verse) +**Instructions:** -Commit your changes. +1. Read the release content from the context above +2. Generate a clear, concise summary (2-4 sentences) highlighting the key changes or features +3. Use the `update_release` safe output with the **prepend** operation to add your summary at the top -Call the `push-to-pull-request-branch` tool after making your changes. - -**Example poem file structure:** -```markdown -# Poem for GitHub Agentic Workflows +**Output format:** +```jsonl +{"type": "update_release", "tag": "TAG_NAME_HERE", "operation": "prepend", "body": "## AI Summary\n\n[Your 2-4 sentence summary here]"} +``` -In the realm of code where automation flows, -An agent awakens, its purpose it knows. -Through pull requests and issues it goes, -Analyzing, creating, whatever it shows. +For release events, use tag: `${{ github.event.release.tag_name }}` +For manual workflow dispatch with release URL/ID, extract the tag from the fetched release data. -With LlamaGuard watching for threats in the night, -And Ollama scanning to keep things right. -The workflows are running, efficient and bright, -GitHub Agentic magic, a developer's delight. -``` +**Note:** The summary will be automatically prepended with a horizontal line separator and AI attribution footer. diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index 6dfb207e6e..1ee1c32283 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -2990,8 +2990,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index 2e81172a42..4e2d92aa06 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -2186,8 +2186,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index 569a3db41f..42321a9327 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -2242,8 +2242,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index a668bba20a..74577b508f 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -2260,8 +2260,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml index 3dd02751a8..90723c5e85 100644 --- a/.github/workflows/example-workflow-analyzer.lock.yml +++ b/.github/workflows/example-workflow-analyzer.lock.yml @@ -2292,8 +2292,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index 45067dab1a..06833ffdd4 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -2812,8 +2812,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index ba4066e1a2..4ae8ce3be6 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -2558,8 +2558,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml index 7bfaaa8c94..e64bee8f3e 100644 --- a/.github/workflows/go-pattern-detector.lock.yml +++ b/.github/workflows/go-pattern-detector.lock.yml @@ -2332,8 +2332,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index fdd6a659e1..e681eec22a 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -403,6 +403,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3222,8 +3266,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index 63b62d7e11..5da50d8dab 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -2437,8 +2437,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index dbdfe52d2b..fb5d2cd2a9 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -389,6 +389,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2864,8 +2908,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml index 5184407221..94e894bebf 100644 --- a/.github/workflows/lockfile-stats.lock.yml +++ b/.github/workflows/lockfile-stats.lock.yml @@ -2647,8 +2647,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index a76811d0ce..8479a4aed9 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -2764,8 +2764,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index 62073b8444..606a1c2092 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -2745,8 +2745,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/notion-issue-summary.lock.yml b/.github/workflows/notion-issue-summary.lock.yml index 9c3772a71f..0fa2d5a866 100644 --- a/.github/workflows/notion-issue-summary.lock.yml +++ b/.github/workflows/notion-issue-summary.lock.yml @@ -2045,8 +2045,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index b2cb6914aa..b64c4bc48c 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -419,6 +419,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3273,8 +3317,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index f6ba65b6f5..54f5d03727 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -398,6 +398,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2748,8 +2792,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index 2d128b9578..0eaa72d2be 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -434,6 +434,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3544,8 +3588,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 228dbdcc3a..45264eaa57 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -3325,8 +3325,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index 33e8946344..aafa51c642 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -2987,8 +2987,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index e53d16125f..119643c4d5 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -3122,8 +3122,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index 9ac010f53d..19dbb0fa49 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -442,6 +442,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3614,8 +3658,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml index e30391f47d..7bb581b387 100644 --- a/.github/workflows/repo-tree-map.lock.yml +++ b/.github/workflows/repo-tree-map.lock.yml @@ -2221,8 +2221,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index 05db53df76..780e5a7b56 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -2739,8 +2739,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml index 76bfb64c7b..ef5c09f21d 100644 --- a/.github/workflows/research.lock.yml +++ b/.github/workflows/research.lock.yml @@ -2155,8 +2155,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml index 0e4380334b..8237757e2f 100644 --- a/.github/workflows/safe-output-health.lock.yml +++ b/.github/workflows/safe-output-health.lock.yml @@ -2780,8 +2780,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml index 1516042402..7b264a6662 100644 --- a/.github/workflows/schema-consistency-checker.lock.yml +++ b/.github/workflows/schema-consistency-checker.lock.yml @@ -2653,8 +2653,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index 232fe86da2..019dac30d4 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -445,6 +445,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3728,8 +3772,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/security-fix-pr.lock.yml b/.github/workflows/security-fix-pr.lock.yml index beecfc9cce..632e4e3cfb 100644 --- a/.github/workflows/security-fix-pr.lock.yml +++ b/.github/workflows/security-fix-pr.lock.yml @@ -2385,8 +2385,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml index 0d0e3986a0..f3b52721f9 100644 --- a/.github/workflows/semantic-function-refactor.lock.yml +++ b/.github/workflows/semantic-function-refactor.lock.yml @@ -2741,8 +2741,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 1ac0088e3a..cf016a0fd0 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -2300,8 +2300,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index a82bc9e678..2ab2522b71 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -2002,8 +2002,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index f2372a9094..e41a5a0af7 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -2072,8 +2072,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/smoke-detector.lock.yml b/.github/workflows/smoke-detector.lock.yml index 038e39e124..224cd21641 100644 --- a/.github/workflows/smoke-detector.lock.yml +++ b/.github/workflows/smoke-detector.lock.yml @@ -3371,8 +3371,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml index c8cd645152..a15e34456e 100644 --- a/.github/workflows/static-analysis-report.lock.yml +++ b/.github/workflows/static-analysis-report.lock.yml @@ -2668,8 +2668,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index 0257858db4..c6af4a1d63 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -2294,8 +2294,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index d361b9a113..7d7e5abda8 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -2965,8 +2965,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/test-ollama-threat-detection.lock.yml b/.github/workflows/test-ollama-threat-detection.lock.yml index 276f808b2c..67cab7b026 100644 --- a/.github/workflows/test-ollama-threat-detection.lock.yml +++ b/.github/workflows/test-ollama-threat-detection.lock.yml @@ -2017,8 +2017,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index eb28c883d4..7f1ce5fc0d 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -2548,8 +2548,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index a32518091d..711f876199 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -2811,8 +2811,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index 8de8014cb2..2de22b2329 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -3467,8 +3467,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml index e9e45918b7..7a6d475bd8 100644 --- a/.github/workflows/video-analyzer.lock.yml +++ b/.github/workflows/video-analyzer.lock.yml @@ -2308,8 +2308,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index 435cba4215..b69b4c9e78 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -2710,8 +2710,8 @@ jobs: errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } if (!item.body || typeof item.body !== "string") { diff --git a/pkg/workflow/js/collect_ndjson_output.cjs b/pkg/workflow/js/collect_ndjson_output.cjs index efe4ff5ba2..24a73806f2 100644 --- a/pkg/workflow/js/collect_ndjson_output.cjs +++ b/pkg/workflow/js/collect_ndjson_output.cjs @@ -598,8 +598,8 @@ async function main() { errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); continue; } - if (item.operation !== "replace" && item.operation !== "append") { - errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace' or 'append'`); + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); continue; } // Validate body diff --git a/pkg/workflow/js/collect_ndjson_output.test.cjs b/pkg/workflow/js/collect_ndjson_output.test.cjs index 8b65620399..c133a9d941 100644 --- a/pkg/workflow/js/collect_ndjson_output.test.cjs +++ b/pkg/workflow/js/collect_ndjson_output.test.cjs @@ -451,6 +451,7 @@ describe("collect_ndjson_output.cjs", () => { it("should validate required fields for update_release type", async () => { const testFile = "/tmp/gh-aw/test-ndjson-output.txt"; const ndjsonContent = `{"type": "update_release", "tag": "v1.0.0", "operation": "replace", "body": "New release notes"} +{"type": "update_release", "tag": "v1.0.0", "operation": "prepend", "body": "Prepended notes"} {"type": "update_release", "tag": "v1.0.0", "operation": "invalid", "body": "Notes"} {"type": "update_release", "tag": "v1.0.0", "body": "Missing operation"} {"type": "update_release", "operation": "replace", "body": "Missing tag"} @@ -470,12 +471,13 @@ describe("collect_ndjson_output.cjs", () => { expect(outputCall).toBeDefined(); const parsedOutput = JSON.parse(outputCall[1]); - expect(parsedOutput.items).toHaveLength(1); // Only the first valid item + expect(parsedOutput.items).toHaveLength(2); // Valid replace and prepend items expect(parsedOutput.items[0].tag).toBe("v1.0.0"); expect(parsedOutput.items[0].operation).toBe("replace"); + expect(parsedOutput.items[1].operation).toBe("prepend"); expect(parsedOutput.items[0].body).toBeDefined(); expect(parsedOutput.errors).toHaveLength(4); // 4 invalid items - expect(parsedOutput.errors.some(e => e.includes("operation' must be 'replace' or 'append'"))).toBe(true); + expect(parsedOutput.errors.some(e => e.includes("operation' must be 'replace', 'append', or 'prepend'"))).toBe(true); expect(parsedOutput.errors.some(e => e.includes("requires an 'operation' string field"))).toBe(true); expect(parsedOutput.errors.some(e => e.includes("requires a 'tag' string field"))).toBe(true); expect(parsedOutput.errors.some(e => e.includes("requires a 'body' string field"))).toBe(true); diff --git a/pkg/workflow/js/compute_text.cjs b/pkg/workflow/js/compute_text.cjs index 9a8d7065cf..ea057a396e 100644 --- a/pkg/workflow/js/compute_text.cjs +++ b/pkg/workflow/js/compute_text.cjs @@ -95,6 +95,57 @@ async function main() { } break; + case "release": + // For releases: name + body + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + + case "workflow_dispatch": + // For workflow dispatch: check for release_url or release_id in inputs + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + + // If release_url is provided, extract owner/repo/tag + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + // If release_id is provided, fetch the release + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; + default: // Default: empty text text = ""; diff --git a/pkg/workflow/js/update_release.cjs b/pkg/workflow/js/update_release.cjs index 2357ab2b03..1145dd2534 100644 --- a/pkg/workflow/js/update_release.cjs +++ b/pkg/workflow/js/update_release.cjs @@ -67,8 +67,14 @@ async function main() { // Replace: just use the new content newBody = updateItem.body; core.info("Operation: replace (full body replacement)"); + } else if (updateItem.operation === "prepend") { + // Prepend: add content, AI footer, and horizontal line at the start + const aiFooter = `\n\n> AI generated by [${workflowName}](${runUrl})`; + const prependSection = `${updateItem.body}${aiFooter}\n\n---\n\n`; + newBody = prependSection + (release.body || ""); + core.info("Operation: prepend (add to start with separator)"); } else { - // Append: add horizontal line, content, and AI footer + // Append: add horizontal line, content, and AI footer at the end const aiFooter = `\n\n> AI generated by [${workflowName}](${runUrl})`; const appendSection = `\n\n---\n\n${updateItem.body}${aiFooter}`; newBody = (release.body || "") + appendSection; diff --git a/pkg/workflow/js/update_release.test.cjs b/pkg/workflow/js/update_release.test.cjs index 55b6505065..4832e76cf7 100644 --- a/pkg/workflow/js/update_release.test.cjs +++ b/pkg/workflow/js/update_release.test.cjs @@ -179,6 +179,52 @@ describe("update_release", () => { expect(mockCore.info).toHaveBeenCalledWith("Operation: append (add to end with separator)"); }); + it("should handle prepend operation", async () => { + const mockRelease = { + id: 3, + tag_name: "v3.0.0", + name: "Release v3.0.0", + body: "Existing release notes", + html_url: "https://github.com/test-owner/test-repo/releases/tag/v3.0.0", + }; + + const expectedBody = + "Prepended notes\n\n> AI generated by [Test Workflow](https://github.com/test-owner/test-repo/actions/runs/123456)\n\n---\n\nExisting release notes"; + + const mockUpdatedRelease = { + ...mockRelease, + body: expectedBody, + }; + + mockGithub.rest.repos.getReleaseByTag.mockResolvedValue({ data: mockRelease }); + mockGithub.rest.repos.updateRelease.mockResolvedValue({ data: mockUpdatedRelease }); + + setAgentOutput({ + items: [ + { + type: "update_release", + tag: "v3.0.0", + operation: "prepend", + body: "Prepended notes", + }, + ], + errors: [], + }); + process.env.GH_AW_WORKFLOW_NAME = "Test Workflow"; + + // Execute the script + await eval(`(async () => { ${updateReleaseScript} })()`); + + expect(mockGithub.rest.repos.updateRelease).toHaveBeenCalledWith({ + owner: "test-owner", + repo: "test-repo", + release_id: 3, + body: expectedBody, + }); + + expect(mockCore.info).toHaveBeenCalledWith("Operation: prepend (add to start with separator)"); + }); + it("should handle staged mode", async () => { process.env.GH_AW_SAFE_OUTPUTS_STAGED = "true"; setAgentOutput({ diff --git a/schemas/agent-output.json b/schemas/agent-output.json index 83bf6194a1..4cbabb8cf4 100644 --- a/schemas/agent-output.json +++ b/schemas/agent-output.json @@ -374,8 +374,8 @@ }, "operation": { "type": "string", - "description": "Update operation: 'replace' or 'append'", - "enum": ["replace", "append"] + "description": "Update operation: 'replace', 'append', or 'prepend'", + "enum": ["replace", "append", "prepend"] }, "body": { "type": "string", From 703a604988467fb58213488e488c852afc45ae4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 16:42:55 +0000 Subject: [PATCH 07/12] Make tag optional and infer from release event context - Made 'tag' field optional in UpdateReleaseOutput schema - Updated TypeScript types to reflect optional tag - Modified update_release.cjs to infer tag from event context when missing: - From github.event.release.tag_name for release events - From release_url input by parsing URL for workflow_dispatch - From release_id input by fetching release for workflow_dispatch - Updated validation to accept omitted tag field - Added tests for tag inference from event context - Added test for graceful failure when tag cannot be inferred - Updated dev.md workflow example to show optional tag usage - All tests passing (9 update_release tests, 1007 total JS tests) Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/ai-triage-campaign.lock.yml | 8 +- .github/workflows/archie.lock.yml | 8 +- .github/workflows/artifacts-summary.lock.yml | 8 +- .github/workflows/audit-workflows.lock.yml | 8 +- .github/workflows/blog-auditor.lock.yml | 8 +- .github/workflows/brave.lock.yml | 8 +- .github/workflows/changeset.lock.yml | 8 +- .github/workflows/ci-doctor.lock.yml | 8 +- .../cli-consistency-checker.lock.yml | 8 +- .../workflows/cli-version-checker.lock.yml | 8 +- .github/workflows/cloclo.lock.yml | 8 +- .../commit-changes-analyzer.lock.yml | 8 +- .../workflows/copilot-agent-analysis.lock.yml | 8 +- .../copilot-pr-nlp-analysis.lock.yml | 8 +- .../copilot-pr-prompt-analysis.lock.yml | 8 +- .../copilot-session-insights.lock.yml | 8 +- .github/workflows/craft.lock.yml | 8 +- .github/workflows/daily-code-metrics.lock.yml | 8 +- .github/workflows/daily-doc-updater.lock.yml | 8 +- .github/workflows/daily-file-diet.lock.yml | 8 +- .../workflows/daily-firewall-report.lock.yml | 8 +- .../daily-multi-device-docs-tester.lock.yml | 8 +- .github/workflows/daily-news.lock.yml | 8 +- .../workflows/daily-repo-chronicle.lock.yml | 8 +- .github/workflows/daily-team-status.lock.yml | 8 +- .../workflows/dependabot-go-checker.lock.yml | 8 +- .github/workflows/dev-hawk.lock.yml | 8 +- .github/workflows/dev.lock.yml | 61 ++++++++++---- .github/workflows/dev.md | 7 +- .../developer-docs-consolidator.lock.yml | 8 +- .github/workflows/dictation-prompt.lock.yml | 8 +- .github/workflows/docs-noob-tester.lock.yml | 8 +- .../duplicate-code-detector.lock.yml | 8 +- .../example-workflow-analyzer.lock.yml | 8 +- .../github-mcp-tools-report.lock.yml | 8 +- .github/workflows/go-logger.lock.yml | 8 +- .../workflows/go-pattern-detector.lock.yml | 8 +- .github/workflows/grumpy-reviewer.lock.yml | 8 +- .../workflows/instructions-janitor.lock.yml | 8 +- .github/workflows/issue-classifier.lock.yml | 8 +- .github/workflows/lockfile-stats.lock.yml | 8 +- .github/workflows/mcp-inspector.lock.yml | 8 +- .github/workflows/mergefest.lock.yml | 8 +- .../workflows/notion-issue-summary.lock.yml | 8 +- .github/workflows/pdf-summary.lock.yml | 8 +- .github/workflows/plan.lock.yml | 8 +- .github/workflows/poem-bot.lock.yml | 8 +- .../workflows/pr-nitpick-reviewer.lock.yml | 8 +- .../prompt-clustering-analysis.lock.yml | 8 +- .github/workflows/python-data-charts.lock.yml | 8 +- .github/workflows/q.lock.yml | 8 +- .github/workflows/repo-tree-map.lock.yml | 8 +- .../repository-quality-improver.lock.yml | 8 +- .github/workflows/research.lock.yml | 8 +- .github/workflows/safe-output-health.lock.yml | 8 +- .../schema-consistency-checker.lock.yml | 8 +- .github/workflows/scout.lock.yml | 8 +- .github/workflows/security-fix-pr.lock.yml | 8 +- .../semantic-function-refactor.lock.yml | 8 +- .github/workflows/smoke-claude.lock.yml | 8 +- .github/workflows/smoke-codex.lock.yml | 8 +- .github/workflows/smoke-copilot.lock.yml | 8 +- .github/workflows/smoke-detector.lock.yml | 8 +- .../workflows/static-analysis-report.lock.yml | 8 +- .github/workflows/super-linter.lock.yml | 8 +- .../workflows/technical-doc-writer.lock.yml | 8 +- .../test-ollama-threat-detection.lock.yml | 8 +- .github/workflows/tidy.lock.yml | 8 +- .github/workflows/typist.lock.yml | 8 +- .github/workflows/unbloat-docs.lock.yml | 8 +- .github/workflows/video-analyzer.lock.yml | 8 +- .../workflows/weekly-issue-summary.lock.yml | 8 +- pkg/workflow/js/collect_ndjson_output.cjs | 10 ++- .../js/collect_ndjson_output.test.cjs | 9 +- pkg/workflow/js/types/safe-outputs.d.ts | 8 +- pkg/workflow/js/update_release.cjs | 51 ++++++++++-- pkg/workflow/js/update_release.test.cjs | 82 +++++++++++++++++++ schemas/agent-output.json | 2 +- 78 files changed, 541 insertions(+), 249 deletions(-) diff --git a/.github/workflows/ai-triage-campaign.lock.yml b/.github/workflows/ai-triage-campaign.lock.yml index 6dd0bb4dc8..327b7c0f8a 100644 --- a/.github/workflows/ai-triage-campaign.lock.yml +++ b/.github/workflows/ai-triage-campaign.lock.yml @@ -2237,8 +2237,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2253,7 +2253,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index 9578e75f5e..cf7de4acd6 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -3356,8 +3356,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3372,7 +3372,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index a5cb43597f..6883c4daac 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -2183,8 +2183,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2199,7 +2199,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index 8b195cce75..26fb1f76e5 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -3225,8 +3225,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3241,7 +3241,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml index c099b09f38..770387dce8 100644 --- a/.github/workflows/blog-auditor.lock.yml +++ b/.github/workflows/blog-auditor.lock.yml @@ -2571,8 +2571,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2587,7 +2587,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index 4c969871d1..2cf0d7c6b1 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -3203,8 +3203,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3219,7 +3219,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index c017ba5af3..a31978dcf7 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -2895,8 +2895,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2911,7 +2911,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index 38155a1df9..c2823bb3ab 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -2667,8 +2667,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2683,7 +2683,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index ae552f8622..6353c938e8 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -2221,8 +2221,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2237,7 +2237,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index dda7ef7045..dbf53b794f 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -2397,8 +2397,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2413,7 +2413,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index bf8fc7c58e..5d930e25cc 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -3750,8 +3750,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3766,7 +3766,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml index 401327df42..8757fee33a 100644 --- a/.github/workflows/commit-changes-analyzer.lock.yml +++ b/.github/workflows/commit-changes-analyzer.lock.yml @@ -2502,8 +2502,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2518,7 +2518,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index e1744c3a01..6a0c7698b4 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -2865,8 +2865,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2881,7 +2881,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index b5cf1a579d..1701c2b86c 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -2958,8 +2958,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2974,7 +2974,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index 4c0a8ff469..b571026732 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -2524,8 +2524,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2540,7 +2540,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index 6a399dc3ef..386385e2ac 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -3774,8 +3774,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3790,7 +3790,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index f48cc8c65e..913bab8557 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -3357,8 +3357,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3373,7 +3373,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index 77646cf589..488c7d24fa 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -2845,8 +2845,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2861,7 +2861,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index 7078d5ab08..2851b7554a 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -2431,8 +2431,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2447,7 +2447,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index cd25494dd3..bf4024d6e2 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -2332,8 +2332,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2348,7 +2348,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index b0dff6cade..1801cefb1b 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -2941,8 +2941,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2957,7 +2957,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml index 064c546ade..fd078ba7ef 100644 --- a/.github/workflows/daily-multi-device-docs-tester.lock.yml +++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml @@ -2355,8 +2355,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2371,7 +2371,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index 40ea01d0ff..593b0385b2 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -2950,8 +2950,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2966,7 +2966,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index e865f5d7ea..4cda313c90 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -2794,8 +2794,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2810,7 +2810,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml index ad1bd4e9f8..86b9359c6b 100644 --- a/.github/workflows/daily-team-status.lock.yml +++ b/.github/workflows/daily-team-status.lock.yml @@ -2114,8 +2114,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2130,7 +2130,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml index 6e116549f7..de051650d6 100644 --- a/.github/workflows/dependabot-go-checker.lock.yml +++ b/.github/workflows/dependabot-go-checker.lock.yml @@ -2255,8 +2255,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2271,7 +2271,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index 2b76f9ecff..a7b008f7a4 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -2558,8 +2558,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2574,7 +2574,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index f8a055c8f8..e868b15514 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -1196,13 +1196,10 @@ jobs: **Output format:** ```jsonl - {"type": "update_release", "tag": "TAG_NAME_HERE", "operation": "prepend", "body": "## AI Summary\n\n[Your 2-4 sentence summary here]"} + {"type": "update_release", "operation": "prepend", "body": "## AI Summary\n\n[Your 2-4 sentence summary here]"} ``` - For release events, use tag: `${GH_AW_EXPR_8CC9E4EE}` - For manual workflow dispatch with release URL/ID, extract the tag from the fetched release data. - - **Note:** The summary will be automatically prepended with a horizontal line separator and AI attribution footer. + **Note:** The tag field is optional and will be automatically inferred from the release event context (`github.event.release.tag_name`) or from workflow dispatch inputs (`release_url` or `release_id`). The summary will be prepended with a horizontal line separator and AI attribution footer. PROMPT_EOF - name: Append XPIA security instructions to prompt @@ -1336,7 +1333,6 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_EXPR_8CC9E4EE: ${{ github.event.release.tag_name }} GH_AW_EXPR_0BABF60D: ${{ needs.activation.outputs.text }} with: script: | @@ -2379,8 +2375,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2395,7 +2391,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": @@ -5161,7 +5159,7 @@ jobs: items: updateItems, renderItem: (item, index) => { let content = `### Release Update ${index + 1}\n`; - content += `**Tag:** ${item.tag}\n`; + content += `**Tag:** ${item.tag || "(inferred from event context)"}\n`; content += `**Operation:** ${item.operation}\n\n`; content += `**Body Content:**\n${item.body}\n\n`; return content; @@ -5176,11 +5174,43 @@ jobs: const updateItem = updateItems[i]; core.info(`Processing update-release item ${i + 1}/${updateItems.length}`); try { - core.info(`Fetching release with tag: ${updateItem.tag}`); + let releaseTag = updateItem.tag; + if (!releaseTag) { + if (context.eventName === "release" && context.payload.release && context.payload.release.tag_name) { + releaseTag = context.payload.release.tag_name; + core.info(`Inferred release tag from event context: ${releaseTag}`); + } else if (context.eventName === "workflow_dispatch" && context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/[^\/]+\/[^\/]+\/releases\/tag\/([^\/\?#]+)/); + if (urlMatch && urlMatch[1]) { + releaseTag = decodeURIComponent(urlMatch[1]); + core.info(`Inferred release tag from release_url input: ${releaseTag}`); + } + } + if (!releaseTag && context.payload.inputs.release_id) { + const releaseId = context.payload.inputs.release_id; + core.info(`Fetching release with ID: ${releaseId}`); + const { data: release } = await github.rest.repos.getRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: parseInt(releaseId, 10), + }); + releaseTag = release.tag_name; + core.info(`Inferred release tag from release_id input: ${releaseTag}`); + } + } + if (!releaseTag) { + core.error("No tag provided and unable to infer from event context"); + core.setFailed("Release tag is required but not provided and cannot be inferred from event context"); + return; + } + } + core.info(`Fetching release with tag: ${releaseTag}`); const { data: release } = await github.rest.repos.getReleaseByTag({ owner: context.repo.owner, repo: context.repo.repo, - tag: updateItem.tag, + tag: releaseTag, }); core.info(`Found release: ${release.name || release.tag_name} (ID: ${release.id})`); let newBody; @@ -5206,7 +5236,7 @@ jobs: }); core.info(`Successfully updated release: ${updatedRelease.html_url}`); updatedReleases.push({ - tag: updateItem.tag, + tag: releaseTag, url: updatedRelease.html_url, id: updatedRelease.id, }); @@ -5217,9 +5247,10 @@ jobs: } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); - core.error(`Failed to update release with tag ${updateItem.tag}: ${errorMessage}`); + const tagInfo = updateItem.tag || "inferred from context"; + core.error(`Failed to update release with tag ${tagInfo}: ${errorMessage}`); if (errorMessage.includes("Not Found")) { - core.error(`Release with tag '${updateItem.tag}' not found. Please ensure the tag exists.`); + core.error(`Release with tag '${tagInfo}' not found. Please ensure the tag exists.`); } core.setFailed(`Failed to update release: ${errorMessage}`); return; diff --git a/.github/workflows/dev.md b/.github/workflows/dev.md index 8f3a2a5d92..80eb56be2f 100644 --- a/.github/workflows/dev.md +++ b/.github/workflows/dev.md @@ -361,10 +361,7 @@ The release content is available in the context: "${{ needs.activation.outputs.t **Output format:** ```jsonl -{"type": "update_release", "tag": "TAG_NAME_HERE", "operation": "prepend", "body": "## AI Summary\n\n[Your 2-4 sentence summary here]"} +{"type": "update_release", "operation": "prepend", "body": "## AI Summary\n\n[Your 2-4 sentence summary here]"} ``` -For release events, use tag: `${{ github.event.release.tag_name }}` -For manual workflow dispatch with release URL/ID, extract the tag from the fetched release data. - -**Note:** The summary will be automatically prepended with a horizontal line separator and AI attribution footer. +**Note:** The tag field is optional and will be automatically inferred from the release event context (`github.event.release.tag_name`) or from workflow dispatch inputs (`release_url` or `release_id`). The summary will be prepended with a horizontal line separator and AI attribution footer. diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index 1ee1c32283..ace9ab6f97 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -2982,8 +2982,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2998,7 +2998,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index 4e2d92aa06..22b7e295d4 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -2178,8 +2178,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2194,7 +2194,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index 42321a9327..8ba283e02f 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -2234,8 +2234,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2250,7 +2250,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index 74577b508f..a2be31a9d0 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -2252,8 +2252,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2268,7 +2268,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml index 90723c5e85..a488b30f82 100644 --- a/.github/workflows/example-workflow-analyzer.lock.yml +++ b/.github/workflows/example-workflow-analyzer.lock.yml @@ -2284,8 +2284,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2300,7 +2300,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index 06833ffdd4..e11b2aa8f9 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -2804,8 +2804,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2820,7 +2820,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index 4ae8ce3be6..d7c539b8dd 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -2550,8 +2550,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2566,7 +2566,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml index e64bee8f3e..a11ec75cf2 100644 --- a/.github/workflows/go-pattern-detector.lock.yml +++ b/.github/workflows/go-pattern-detector.lock.yml @@ -2324,8 +2324,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2340,7 +2340,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index e681eec22a..bb46503476 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -3258,8 +3258,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3274,7 +3274,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index 5da50d8dab..232ea1829d 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -2429,8 +2429,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2445,7 +2445,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index fb5d2cd2a9..2b8bb6219d 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -2900,8 +2900,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2916,7 +2916,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml index 94e894bebf..f7159b2b8f 100644 --- a/.github/workflows/lockfile-stats.lock.yml +++ b/.github/workflows/lockfile-stats.lock.yml @@ -2639,8 +2639,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2655,7 +2655,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index 8479a4aed9..34381190c2 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -2756,8 +2756,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2772,7 +2772,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index 606a1c2092..681686a4b0 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -2737,8 +2737,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2753,7 +2753,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/notion-issue-summary.lock.yml b/.github/workflows/notion-issue-summary.lock.yml index 0fa2d5a866..e84d6b3aa2 100644 --- a/.github/workflows/notion-issue-summary.lock.yml +++ b/.github/workflows/notion-issue-summary.lock.yml @@ -2037,8 +2037,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2053,7 +2053,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index b64c4bc48c..30cf8f4797 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -3309,8 +3309,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3325,7 +3325,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index 54f5d03727..bdd2daa8ae 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -2784,8 +2784,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2800,7 +2800,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index 0eaa72d2be..b922e4ddee 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -3580,8 +3580,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3596,7 +3596,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 45264eaa57..1d7e5889da 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -3317,8 +3317,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3333,7 +3333,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index aafa51c642..89d5b103fe 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -2979,8 +2979,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2995,7 +2995,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index 119643c4d5..5fd731c4a1 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -3114,8 +3114,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3130,7 +3130,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index 19dbb0fa49..42930a0649 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -3650,8 +3650,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3666,7 +3666,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml index 7bb581b387..b25a630c62 100644 --- a/.github/workflows/repo-tree-map.lock.yml +++ b/.github/workflows/repo-tree-map.lock.yml @@ -2213,8 +2213,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2229,7 +2229,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index 780e5a7b56..f9882a5ddd 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -2731,8 +2731,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2747,7 +2747,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml index ef5c09f21d..30878ab592 100644 --- a/.github/workflows/research.lock.yml +++ b/.github/workflows/research.lock.yml @@ -2147,8 +2147,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2163,7 +2163,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml index 8237757e2f..dfa5049ab9 100644 --- a/.github/workflows/safe-output-health.lock.yml +++ b/.github/workflows/safe-output-health.lock.yml @@ -2772,8 +2772,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2788,7 +2788,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml index 7b264a6662..7b925aebbc 100644 --- a/.github/workflows/schema-consistency-checker.lock.yml +++ b/.github/workflows/schema-consistency-checker.lock.yml @@ -2645,8 +2645,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2661,7 +2661,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index 019dac30d4..0b3ad9af57 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -3764,8 +3764,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3780,7 +3780,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/security-fix-pr.lock.yml b/.github/workflows/security-fix-pr.lock.yml index 632e4e3cfb..994c5a481e 100644 --- a/.github/workflows/security-fix-pr.lock.yml +++ b/.github/workflows/security-fix-pr.lock.yml @@ -2377,8 +2377,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2393,7 +2393,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml index f3b52721f9..c2db45d9b7 100644 --- a/.github/workflows/semantic-function-refactor.lock.yml +++ b/.github/workflows/semantic-function-refactor.lock.yml @@ -2733,8 +2733,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2749,7 +2749,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index cf016a0fd0..a402e180b6 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -2292,8 +2292,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2308,7 +2308,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index 2ab2522b71..8b0cfe8137 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -1994,8 +1994,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2010,7 +2010,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index e41a5a0af7..31390bb594 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -2064,8 +2064,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2080,7 +2080,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/smoke-detector.lock.yml b/.github/workflows/smoke-detector.lock.yml index 224cd21641..8c532b4f25 100644 --- a/.github/workflows/smoke-detector.lock.yml +++ b/.github/workflows/smoke-detector.lock.yml @@ -3363,8 +3363,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3379,7 +3379,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml index a15e34456e..94467c896e 100644 --- a/.github/workflows/static-analysis-report.lock.yml +++ b/.github/workflows/static-analysis-report.lock.yml @@ -2660,8 +2660,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2676,7 +2676,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index c6af4a1d63..7e466a95fc 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -2286,8 +2286,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2302,7 +2302,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index 7d7e5abda8..48d73472eb 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -2957,8 +2957,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2973,7 +2973,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/test-ollama-threat-detection.lock.yml b/.github/workflows/test-ollama-threat-detection.lock.yml index 67cab7b026..4ca0ec334b 100644 --- a/.github/workflows/test-ollama-threat-detection.lock.yml +++ b/.github/workflows/test-ollama-threat-detection.lock.yml @@ -2009,8 +2009,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2025,7 +2025,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index 7f1ce5fc0d..a91042bd37 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -2540,8 +2540,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2556,7 +2556,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index 711f876199..2f67de4f5a 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -2803,8 +2803,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2819,7 +2819,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index 2de22b2329..2298c2301c 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -3459,8 +3459,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -3475,7 +3475,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml index 7a6d475bd8..30eca70843 100644 --- a/.github/workflows/video-analyzer.lock.yml +++ b/.github/workflows/video-analyzer.lock.yml @@ -2300,8 +2300,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2316,7 +2316,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index b69b4c9e78..ffbba9defd 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -2702,8 +2702,8 @@ jobs: } break; case "update_release": - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } if (!item.operation || typeof item.operation !== "string") { @@ -2718,7 +2718,9 @@ jobs: errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); continue; } - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/pkg/workflow/js/collect_ndjson_output.cjs b/pkg/workflow/js/collect_ndjson_output.cjs index 24a73806f2..e9fb684812 100644 --- a/pkg/workflow/js/collect_ndjson_output.cjs +++ b/pkg/workflow/js/collect_ndjson_output.cjs @@ -588,9 +588,9 @@ async function main() { } break; case "update_release": - // Validate tag - if (!item.tag || typeof item.tag !== "string") { - errors.push(`Line ${i + 1}: update_release requires a 'tag' string field`); + // Validate tag (optional - will be inferred from context if missing) + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); continue; } // Validate operation @@ -608,7 +608,9 @@ async function main() { continue; } // Sanitize content - item.tag = sanitizeContent(item.tag, 256); + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } item.body = sanitizeContent(item.body, maxBodyLength); break; case "upload_asset": diff --git a/pkg/workflow/js/collect_ndjson_output.test.cjs b/pkg/workflow/js/collect_ndjson_output.test.cjs index c133a9d941..b256d6f87d 100644 --- a/pkg/workflow/js/collect_ndjson_output.test.cjs +++ b/pkg/workflow/js/collect_ndjson_output.test.cjs @@ -452,9 +452,9 @@ describe("collect_ndjson_output.cjs", () => { const testFile = "/tmp/gh-aw/test-ndjson-output.txt"; const ndjsonContent = `{"type": "update_release", "tag": "v1.0.0", "operation": "replace", "body": "New release notes"} {"type": "update_release", "tag": "v1.0.0", "operation": "prepend", "body": "Prepended notes"} +{"type": "update_release", "operation": "replace", "body": "Tag omitted - will be inferred"} {"type": "update_release", "tag": "v1.0.0", "operation": "invalid", "body": "Notes"} {"type": "update_release", "tag": "v1.0.0", "body": "Missing operation"} -{"type": "update_release", "operation": "replace", "body": "Missing tag"} {"type": "update_release", "tag": "v1.0.0", "operation": "append"}`; fs.writeFileSync(testFile, ndjsonContent); @@ -471,15 +471,16 @@ describe("collect_ndjson_output.cjs", () => { expect(outputCall).toBeDefined(); const parsedOutput = JSON.parse(outputCall[1]); - expect(parsedOutput.items).toHaveLength(2); // Valid replace and prepend items + expect(parsedOutput.items).toHaveLength(3); // Valid replace, prepend, and tag-omitted items expect(parsedOutput.items[0].tag).toBe("v1.0.0"); expect(parsedOutput.items[0].operation).toBe("replace"); expect(parsedOutput.items[1].operation).toBe("prepend"); + expect(parsedOutput.items[2].tag).toBeUndefined(); // Tag omitted + expect(parsedOutput.items[2].operation).toBe("replace"); expect(parsedOutput.items[0].body).toBeDefined(); - expect(parsedOutput.errors).toHaveLength(4); // 4 invalid items + expect(parsedOutput.errors).toHaveLength(3); // 3 invalid items expect(parsedOutput.errors.some(e => e.includes("operation' must be 'replace', 'append', or 'prepend'"))).toBe(true); expect(parsedOutput.errors.some(e => e.includes("requires an 'operation' string field"))).toBe(true); - expect(parsedOutput.errors.some(e => e.includes("requires a 'tag' string field"))).toBe(true); expect(parsedOutput.errors.some(e => e.includes("requires a 'body' string field"))).toBe(true); }); diff --git a/pkg/workflow/js/types/safe-outputs.d.ts b/pkg/workflow/js/types/safe-outputs.d.ts index 2511fe4203..9a4e558942 100644 --- a/pkg/workflow/js/types/safe-outputs.d.ts +++ b/pkg/workflow/js/types/safe-outputs.d.ts @@ -163,10 +163,10 @@ interface UploadAssetItem extends BaseSafeOutputItem { */ interface UpdateReleaseItem extends BaseSafeOutputItem { type: "update_release"; - /** Tag name of the release to update */ - tag: string; - /** Update operation: 'replace' or 'append' */ - operation: "replace" | "append"; + /** Tag name of the release to update (optional - inferred from context if missing) */ + tag?: string; + /** Update operation: 'replace', 'append', or 'prepend' */ + operation: "replace" | "append" | "prepend"; /** Content to set or append to the release body */ body: string; } diff --git a/pkg/workflow/js/update_release.cjs b/pkg/workflow/js/update_release.cjs index 1145dd2534..dccde38ed5 100644 --- a/pkg/workflow/js/update_release.cjs +++ b/pkg/workflow/js/update_release.cjs @@ -30,7 +30,7 @@ async function main() { items: updateItems, renderItem: (item, index) => { let content = `### Release Update ${index + 1}\n`; - content += `**Tag:** ${item.tag}\n`; + content += `**Tag:** ${item.tag || "(inferred from event context)"}\n`; content += `**Operation:** ${item.operation}\n\n`; content += `**Body Content:**\n${item.body}\n\n`; return content; @@ -51,12 +51,50 @@ async function main() { core.info(`Processing update-release item ${i + 1}/${updateItems.length}`); try { + // Infer tag from event context if not provided + let releaseTag = updateItem.tag; + if (!releaseTag) { + // Try to get tag from release event context + if (context.eventName === "release" && context.payload.release && context.payload.release.tag_name) { + releaseTag = context.payload.release.tag_name; + core.info(`Inferred release tag from event context: ${releaseTag}`); + } else if (context.eventName === "workflow_dispatch" && context.payload.inputs) { + // Try to extract from release_url input + const releaseUrl = context.payload.inputs.release_url; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/[^\/]+\/[^\/]+\/releases\/tag\/([^\/\?#]+)/); + if (urlMatch && urlMatch[1]) { + releaseTag = decodeURIComponent(urlMatch[1]); + core.info(`Inferred release tag from release_url input: ${releaseTag}`); + } + } + // Try to fetch from release_id input + if (!releaseTag && context.payload.inputs.release_id) { + const releaseId = context.payload.inputs.release_id; + core.info(`Fetching release with ID: ${releaseId}`); + const { data: release } = await github.rest.repos.getRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: parseInt(releaseId, 10), + }); + releaseTag = release.tag_name; + core.info(`Inferred release tag from release_id input: ${releaseTag}`); + } + } + + if (!releaseTag) { + core.error("No tag provided and unable to infer from event context"); + core.setFailed("Release tag is required but not provided and cannot be inferred from event context"); + return; + } + } + // Get the release by tag - core.info(`Fetching release with tag: ${updateItem.tag}`); + core.info(`Fetching release with tag: ${releaseTag}`); const { data: release } = await github.rest.repos.getReleaseByTag({ owner: context.repo.owner, repo: context.repo.repo, - tag: updateItem.tag, + tag: releaseTag, }); core.info(`Found release: ${release.name || release.tag_name} (ID: ${release.id})`); @@ -92,7 +130,7 @@ async function main() { core.info(`Successfully updated release: ${updatedRelease.html_url}`); updatedReleases.push({ - tag: updateItem.tag, + tag: releaseTag, url: updatedRelease.html_url, id: updatedRelease.id, }); @@ -105,11 +143,12 @@ async function main() { } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); - core.error(`Failed to update release with tag ${updateItem.tag}: ${errorMessage}`); + const tagInfo = updateItem.tag || "inferred from context"; + core.error(`Failed to update release with tag ${tagInfo}: ${errorMessage}`); // Check for specific error cases if (errorMessage.includes("Not Found")) { - core.error(`Release with tag '${updateItem.tag}' not found. Please ensure the tag exists.`); + core.error(`Release with tag '${tagInfo}' not found. Please ensure the tag exists.`); } core.setFailed(`Failed to update release: ${errorMessage}`); diff --git a/pkg/workflow/js/update_release.test.cjs b/pkg/workflow/js/update_release.test.cjs index 4832e76cf7..5c35a08cdd 100644 --- a/pkg/workflow/js/update_release.test.cjs +++ b/pkg/workflow/js/update_release.test.cjs @@ -316,4 +316,86 @@ describe("update_release", () => { expect(mockGithub.rest.repos.updateRelease).toHaveBeenCalledTimes(2); expect(mockCore.summary.addRaw).toHaveBeenCalledWith(expect.stringContaining("Updated 2 release(s)")); }); + + it("should infer tag from release event context", async () => { + // Set up release event context + mockContext.eventName = "release"; + mockContext.payload = { + release: { + tag_name: "v1.5.0", + name: "Version 1.5.0", + body: "Original release body", + }, + }; + + const mockRelease = { + id: 1, + tag_name: "v1.5.0", + body: "Original release body", + html_url: "https://github.com/test-owner/test-repo/releases/tag/v1.5.0", + }; + + mockGithub.rest.repos.getReleaseByTag.mockResolvedValue({ data: mockRelease }); + mockGithub.rest.repos.updateRelease.mockResolvedValue({ data: { ...mockRelease, body: "Updated body" } }); + + // Agent output without tag field + setAgentOutput({ + items: [ + { + type: "update_release", + operation: "replace", + body: "Updated body", + }, + ], + errors: [], + }); + + // Execute the script + await eval(`(async () => { ${updateReleaseScript} })()`); + + expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("Inferred release tag from event context: v1.5.0")); + expect(mockGithub.rest.repos.getReleaseByTag).toHaveBeenCalledWith({ + owner: "test-owner", + repo: "test-repo", + tag: "v1.5.0", + }); + expect(mockGithub.rest.repos.updateRelease).toHaveBeenCalledWith({ + owner: "test-owner", + repo: "test-repo", + release_id: 1, + body: "Updated body", + }); + + // Clean up + delete mockContext.eventName; + delete mockContext.payload; + }); + + it("should fail gracefully when tag is missing and cannot be inferred", async () => { + // Set up context without release info + mockContext.eventName = "push"; + mockContext.payload = {}; + + // Agent output without tag field + setAgentOutput({ + items: [ + { + type: "update_release", + operation: "replace", + body: "Updated body", + }, + ], + errors: [], + }); + + // Execute the script + await eval(`(async () => { ${updateReleaseScript} })()`); + + expect(mockCore.error).toHaveBeenCalledWith("No tag provided and unable to infer from event context"); + expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("Release tag is required")); + + // Clean up + delete mockContext.eventName; + delete mockContext.payload; + }); }); diff --git a/schemas/agent-output.json b/schemas/agent-output.json index 4cbabb8cf4..6bf975fced 100644 --- a/schemas/agent-output.json +++ b/schemas/agent-output.json @@ -383,7 +383,7 @@ "minLength": 1 } }, - "required": ["type", "tag", "operation", "body"], + "required": ["type", "operation", "body"], "additionalProperties": false } } From 89b68d3e791d2a62cabbea41c1ac7ab1764a7521 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 19:42:07 +0000 Subject: [PATCH 08/12] Add update_release to safe outputs tools.json and update tests - Added update_release tool definition to safe_outputs_tools.json - Tool supports three operations: replace, append, prepend - Tag field is optional and inferred from event context - Updated test expectations to include update_release tool - All tests passing (including TestGetSafeOutputsToolsJSON) Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/js/safe_outputs_tools.json | 24 ++++++++++++++++++++++++ pkg/workflow/safe_outputs_tools_test.go | 1 + 2 files changed, 25 insertions(+) diff --git a/pkg/workflow/js/safe_outputs_tools.json b/pkg/workflow/js/safe_outputs_tools.json index 53a35a6d2c..0a2e8e2f6d 100644 --- a/pkg/workflow/js/safe_outputs_tools.json +++ b/pkg/workflow/js/safe_outputs_tools.json @@ -229,6 +229,30 @@ "additionalProperties": false } }, + { + "name": "update_release", + "description": "Update a GitHub release description", + "inputSchema": { + "type": "object", + "required": ["operation", "body"], + "properties": { + "tag": { + "type": "string", + "description": "Release tag name (optional - inferred from event context if omitted)" + }, + "operation": { + "type": "string", + "enum": ["replace", "append", "prepend"], + "description": "Update operation: 'replace' (full replacement), 'append' (add at end with separator), or 'prepend' (add at start with separator)" + }, + "body": { + "type": "string", + "description": "Release body content to set, append, or prepend" + } + }, + "additionalProperties": false + } + }, { "name": "missing_tool", "description": "Report a missing tool or functionality needed to complete tasks", diff --git a/pkg/workflow/safe_outputs_tools_test.go b/pkg/workflow/safe_outputs_tools_test.go index 54d3ccce28..94893268ee 100644 --- a/pkg/workflow/safe_outputs_tools_test.go +++ b/pkg/workflow/safe_outputs_tools_test.go @@ -277,6 +277,7 @@ func TestGetSafeOutputsToolsJSON(t *testing.T) { "update_issue", "push_to_pull_request_branch", "upload_asset", + "update_release", "missing_tool", } From 25d3c78566e45f5ffa7f13496ada06d2842ccbd2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 23:45:55 +0000 Subject: [PATCH 09/12] Update dev.md workflow per review feedback - Changed permissions from contents: write to contents: read - Removed JSONL output format example from instructions - Added requirement to fail if update_release tool is missing - All workflows recompiled successfully Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/dev.lock.yml | 10 +++------- .github/workflows/dev.md | 8 ++------ 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index e868b15514..fb901ebe14 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -58,7 +58,7 @@ name: "Dev" type: string permissions: - contents: write + contents: read issues: read pull-requests: read @@ -453,7 +453,7 @@ jobs: needs: activation runs-on: ubuntu-latest permissions: - contents: write + contents: read issues: read pull-requests: read concurrency: @@ -1193,11 +1193,7 @@ jobs: 1. Read the release content from the context above 2. Generate a clear, concise summary (2-4 sentences) highlighting the key changes or features 3. Use the `update_release` safe output with the **prepend** operation to add your summary at the top - - **Output format:** - ```jsonl - {"type": "update_release", "operation": "prepend", "body": "## AI Summary\n\n[Your 2-4 sentence summary here]"} - ``` + 4. **CRITICAL:** If the `update_release` tool is not available, fail immediately with an error message **Note:** The tag field is optional and will be automatically inferred from the release event context (`github.event.release.tag_name`) or from workflow dispatch inputs (`release_url` or `release_id`). The summary will be prepended with a horizontal line separator and AI attribution footer. diff --git a/.github/workflows/dev.md b/.github/workflows/dev.md index 80eb56be2f..6c5f5dd4dd 100644 --- a/.github/workflows/dev.md +++ b/.github/workflows/dev.md @@ -19,7 +19,7 @@ name: Dev description: Test workflow for development and experimentation purposes engine: copilot permissions: - contents: write + contents: read issues: read pull-requests: read tools: @@ -358,10 +358,6 @@ The release content is available in the context: "${{ needs.activation.outputs.t 1. Read the release content from the context above 2. Generate a clear, concise summary (2-4 sentences) highlighting the key changes or features 3. Use the `update_release` safe output with the **prepend** operation to add your summary at the top - -**Output format:** -```jsonl -{"type": "update_release", "operation": "prepend", "body": "## AI Summary\n\n[Your 2-4 sentence summary here]"} -``` +4. **CRITICAL:** If the `update_release` tool is not available, fail immediately with an error message **Note:** The tag field is optional and will be automatically inferred from the release event context (`github.event.release.tag_name`) or from workflow dispatch inputs (`release_url` or `release_id`). The summary will be prepended with a horizontal line separator and AI attribution footer. From dbc8037c16ddd27a215e41caa81b981d14ef2cac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Nov 2025 00:35:30 +0000 Subject: [PATCH 10/12] Fix directory creation in collect_ndjson_output.cjs - Changed fs.mkdirSync from "/tmp" to "/tmp/gh-aw" to ensure parent directory exists - This fixes the file write error when creating agent_output.json - All tests passing (1007 JS tests) Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/js/collect_ndjson_output.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/workflow/js/collect_ndjson_output.cjs b/pkg/workflow/js/collect_ndjson_output.cjs index e9fb684812..0cab307ee7 100644 --- a/pkg/workflow/js/collect_ndjson_output.cjs +++ b/pkg/workflow/js/collect_ndjson_output.cjs @@ -720,7 +720,7 @@ async function main() { const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); From 3e0eac6a9821b956d8b1b32731d004d50d40ef3a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Nov 2025 00:59:28 +0000 Subject: [PATCH 11/12] Merge main and recompile workflows - Merged origin/main into copilot/add-update-release-output branch - Resolved conflicts in schemas and TypeScript type files - Added both UpdateReleaseOutput and NoOpOutput to schema - Regenerated all workflow lock files with updated compiler - All tests passing (1028 JS tests, all Go tests) - Workflows compiled successfully (80 workflows, 0 errors) Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/ai-triage-campaign.lock.yml | 26 +- .github/workflows/archie.lock.yml | 70 +- .github/workflows/artifacts-summary.lock.yml | 26 +- .github/workflows/audit-workflows.lock.yml | 26 +- .github/workflows/blog-auditor.lock.yml | 26 +- .github/workflows/brave.lock.yml | 70 +- .github/workflows/changeset.lock.yml | 70 +- .github/workflows/ci-doctor.lock.yml | 26 +- .../cli-consistency-checker.lock.yml | 26 +- .../workflows/cli-version-checker.lock.yml | 26 +- .github/workflows/cloclo.lock.yml | 70 +- .../commit-changes-analyzer.lock.yml | 26 +- .../workflows/copilot-agent-analysis.lock.yml | 26 +- .../copilot-pr-nlp-analysis.lock.yml | 26 +- .../copilot-pr-prompt-analysis.lock.yml | 26 +- .../copilot-session-insights.lock.yml | 26 +- .github/workflows/craft.lock.yml | 70 +- .github/workflows/daily-code-metrics.lock.yml | 26 +- .github/workflows/daily-doc-updater.lock.yml | 26 +- .github/workflows/daily-file-diet.lock.yml | 26 +- .../workflows/daily-firewall-report.lock.yml | 26 +- .../daily-multi-device-docs-tester.lock.yml | 26 +- .github/workflows/daily-news.lock.yml | 26 +- .../workflows/daily-repo-chronicle.lock.yml | 26 +- .github/workflows/daily-team-status.lock.yml | 26 +- .../workflows/dependabot-go-checker.lock.yml | 26 +- .github/workflows/dev-hawk.lock.yml | 26 +- .github/workflows/dev.lock.yml | 665 +++++++++++++++++- .../developer-docs-consolidator.lock.yml | 26 +- .github/workflows/dictation-prompt.lock.yml | 26 +- .github/workflows/docs-noob-tester.lock.yml | 26 +- .../duplicate-code-detector.lock.yml | 26 +- .../example-workflow-analyzer.lock.yml | 26 +- .../github-mcp-tools-report.lock.yml | 26 +- .github/workflows/go-logger.lock.yml | 26 +- .../workflows/go-pattern-detector.lock.yml | 26 +- .github/workflows/grumpy-reviewer.lock.yml | 70 +- .../workflows/instructions-janitor.lock.yml | 26 +- .github/workflows/issue-classifier.lock.yml | 70 +- .github/workflows/lockfile-stats.lock.yml | 26 +- .github/workflows/mcp-inspector.lock.yml | 26 +- .github/workflows/mergefest.lock.yml | 26 +- .../workflows/notion-issue-summary.lock.yml | 26 +- .github/workflows/pdf-summary.lock.yml | 70 +- .github/workflows/plan.lock.yml | 70 +- .github/workflows/poem-bot.lock.yml | 70 +- .../workflows/pr-nitpick-reviewer.lock.yml | 26 +- .../prompt-clustering-analysis.lock.yml | 26 +- .github/workflows/python-data-charts.lock.yml | 26 +- .github/workflows/q.lock.yml | 70 +- .github/workflows/repo-tree-map.lock.yml | 26 +- .../repository-quality-improver.lock.yml | 26 +- .github/workflows/research.lock.yml | 26 +- .github/workflows/safe-output-health.lock.yml | 26 +- .../schema-consistency-checker.lock.yml | 26 +- .github/workflows/scout.lock.yml | 70 +- .github/workflows/security-fix-pr.lock.yml | 26 +- .../semantic-function-refactor.lock.yml | 26 +- .github/workflows/smoke-claude.lock.yml | 26 +- .github/workflows/smoke-codex.lock.yml | 26 +- .github/workflows/smoke-copilot.lock.yml | 26 +- .github/workflows/smoke-detector.lock.yml | 26 +- .../workflows/static-analysis-report.lock.yml | 26 +- .github/workflows/super-linter.lock.yml | 26 +- .../workflows/technical-doc-writer.lock.yml | 26 +- .../test-ollama-threat-detection.lock.yml | 26 +- .github/workflows/tidy.lock.yml | 26 +- .github/workflows/typist.lock.yml | 26 +- .github/workflows/unbloat-docs.lock.yml | 26 +- .github/workflows/video-analyzer.lock.yml | 26 +- .../workflows/weekly-issue-summary.lock.yml | 26 +- 71 files changed, 2915 insertions(+), 98 deletions(-) diff --git a/.github/workflows/ai-triage-campaign.lock.yml b/.github/workflows/ai-triage-campaign.lock.yml index 5685e35535..bb8e7c4203 100644 --- a/.github/workflows/ai-triage-campaign.lock.yml +++ b/.github/workflows/ai-triage-campaign.lock.yml @@ -1701,6 +1701,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2245,6 +2247,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2359,7 +2383,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index 13d8c96583..2771b00e21 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -420,6 +420,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2771,6 +2815,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3315,6 +3361,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3429,7 +3497,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index df1acb41b4..15e26e12e7 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -1647,6 +1647,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2191,6 +2193,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2305,7 +2329,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index acc3ea3f43..fa0a0eec14 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -2690,6 +2690,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3234,6 +3236,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3348,7 +3372,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml index 4bd7278de4..ca7129d5ef 100644 --- a/.github/workflows/blog-auditor.lock.yml +++ b/.github/workflows/blog-auditor.lock.yml @@ -2035,6 +2035,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2579,6 +2581,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2693,7 +2717,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index 6f7c34283b..0005c63627 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -401,6 +401,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2618,6 +2662,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3162,6 +3208,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3276,7 +3344,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index 5070e0af9f..7aae9fb257 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -409,6 +409,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2315,6 +2359,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2859,6 +2905,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2973,7 +3041,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index 0e4cef2a97..2ac96c0a1f 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -2132,6 +2132,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2676,6 +2678,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2790,7 +2814,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index 0f56355a7c..bb24be6801 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -1685,6 +1685,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2229,6 +2231,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2343,7 +2367,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index 5ccab34582..84b1689dad 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -1875,6 +1875,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2419,6 +2421,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2533,7 +2557,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index ae28028da5..339e4012cc 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -451,6 +451,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3165,6 +3209,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3709,6 +3755,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3823,7 +3891,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml index 031c697381..58e4301efe 100644 --- a/.github/workflows/commit-changes-analyzer.lock.yml +++ b/.github/workflows/commit-changes-analyzer.lock.yml @@ -1966,6 +1966,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2510,6 +2512,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2624,7 +2648,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index cb0a31419f..0f157a9435 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -2329,6 +2329,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2873,6 +2875,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2987,7 +3011,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index e8ce2c6394..0b9c0e3960 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -2422,6 +2422,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2966,6 +2968,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3080,7 +3104,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index 874628de86..e04d61ece0 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -1988,6 +1988,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2532,6 +2534,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2646,7 +2670,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index 7220b91b25..088368d59c 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -3239,6 +3239,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3783,6 +3785,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3897,7 +3921,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index 2f81636638..09d6c77fd8 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -402,6 +402,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2772,6 +2816,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3316,6 +3362,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3430,7 +3498,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index 296a7d1b15..e2d945afe5 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -2309,6 +2309,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2853,6 +2855,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2967,7 +2991,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index f30b9128d8..e0bb865650 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -1895,6 +1895,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2439,6 +2441,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2553,7 +2577,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index 4e50b38aa4..5375ff72b1 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -1801,6 +1801,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2345,6 +2347,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2459,7 +2483,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index 37889fe423..209ef87fe5 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -2406,6 +2406,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2950,6 +2952,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3064,7 +3088,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml index 7dfb4684b9..c56811afbf 100644 --- a/.github/workflows/daily-multi-device-docs-tester.lock.yml +++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml @@ -1820,6 +1820,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2364,6 +2366,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2478,7 +2502,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index 76fa48c0bd..bebde30e43 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -2415,6 +2415,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2959,6 +2961,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3073,7 +3097,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index 31360bd840..85bb540d30 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -2259,6 +2259,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2803,6 +2805,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2917,7 +2941,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml index 322193e923..dca6693c46 100644 --- a/.github/workflows/daily-team-status.lock.yml +++ b/.github/workflows/daily-team-status.lock.yml @@ -1578,6 +1578,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2122,6 +2124,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2236,7 +2260,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml index dd48096a0a..3df8dc2784 100644 --- a/.github/workflows/dependabot-go-checker.lock.yml +++ b/.github/workflows/dependabot-go-checker.lock.yml @@ -1719,6 +1719,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2263,6 +2265,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2377,7 +2401,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index 033d1de988..90bd144403 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -2022,6 +2022,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2566,6 +2568,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2680,7 +2704,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index 880231f13d..82139d074a 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -14,12 +14,16 @@ # detection["detection"] # missing_tool["missing_tool"] # noop["noop"] +# pre_activation["pre_activation"] # push_to_pull_request_branch["push_to_pull_request_branch"] +# update_release["update_release"] +# pre_activation --> activation # activation --> agent # agent --> conclusion # activation --> conclusion # push_to_pull_request_branch --> conclusion # missing_tool --> conclusion +# update_release --> conclusion # noop --> conclusion # agent --> detection # agent --> missing_tool @@ -29,6 +33,8 @@ # agent --> push_to_pull_request_branch # activation --> push_to_pull_request_branch # detection --> push_to_pull_request_branch +# agent --> update_release +# detection --> update_release # ``` # # Pinned GitHub Actions: @@ -45,7 +51,21 @@ name: "Dev" "on": - workflow_dispatch: null + release: + types: + - created + - edited + - published + workflow_dispatch: + inputs: + release_id: + description: Release ID + required: false + type: string + release_url: + description: Release URL (e.g., https://github.com/owner/repo/releases/tag/v1.0.0) + required: false + type: string permissions: contents: read @@ -60,9 +80,13 @@ run-name: "Dev" jobs: activation: + needs: pre_activation + if: needs.pre_activation.outputs.activated == 'true' runs-on: ubuntu-slim permissions: contents: read + outputs: + text: ${{ steps.compute-text.outputs.text }} steps: - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 @@ -151,6 +175,289 @@ jobs: main().catch(error => { core.setFailed(error instanceof Error ? error.message : String(error)); }); + - name: Compute current body text + id: compute-text + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + script: | + function extractDomainsFromUrl(url) { + if (!url || typeof url !== "string") { + return []; + } + try { + const urlObj = new URL(url); + const hostname = urlObj.hostname.toLowerCase(); + const domains = [hostname]; + if (hostname === "github.com") { + domains.push("api.github.com"); + domains.push("raw.githubusercontent.com"); + domains.push("*.githubusercontent.com"); + } + else if (!hostname.startsWith("api.")) { + domains.push("api." + hostname); + domains.push("raw." + hostname); + } + return domains; + } catch (e) { + return []; + } + } + function sanitizeContent(content, maxLength) { + if (!content || typeof content !== "string") { + return ""; + } + const allowedDomainsEnv = process.env.GH_AW_ALLOWED_DOMAINS; + const defaultAllowedDomains = ["github.com", "github.io", "githubusercontent.com", "githubassets.com", "github.dev", "codespaces.new"]; + let allowedDomains = allowedDomainsEnv + ? allowedDomainsEnv + .split(",") + .map(d => d.trim()) + .filter(d => d) + : defaultAllowedDomains; + const githubServerUrl = process.env.GITHUB_SERVER_URL; + const githubApiUrl = process.env.GITHUB_API_URL; + if (githubServerUrl) { + const serverDomains = extractDomainsFromUrl(githubServerUrl); + allowedDomains = allowedDomains.concat(serverDomains); + } + if (githubApiUrl) { + const apiDomains = extractDomainsFromUrl(githubApiUrl); + allowedDomains = allowedDomains.concat(apiDomains); + } + allowedDomains = [...new Set(allowedDomains)]; + let sanitized = content; + sanitized = neutralizeCommands(sanitized); + sanitized = neutralizeMentions(sanitized); + sanitized = removeXmlComments(sanitized); + sanitized = convertXmlTags(sanitized); + sanitized = sanitized.replace(/\x1b\[[0-9;]*[mGKH]/g, ""); + sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, ""); + sanitized = sanitizeUrlProtocols(sanitized); + sanitized = sanitizeUrlDomains(sanitized); + const lines = sanitized.split("\n"); + const maxLines = 65000; + maxLength = maxLength || 524288; + if (lines.length > maxLines) { + const truncationMsg = "\n[Content truncated due to line count]"; + const truncatedLines = lines.slice(0, maxLines).join("\n") + truncationMsg; + if (truncatedLines.length > maxLength) { + sanitized = truncatedLines.substring(0, maxLength - truncationMsg.length) + truncationMsg; + } else { + sanitized = truncatedLines; + } + } else if (sanitized.length > maxLength) { + sanitized = sanitized.substring(0, maxLength) + "\n[Content truncated due to length]"; + } + sanitized = neutralizeBotTriggers(sanitized); + return sanitized.trim(); + function sanitizeUrlDomains(s) { + s = s.replace(/\bhttps:\/\/([^\s\])}'"<>&\x00-\x1f,;]+)/gi, (match, rest) => { + const hostname = rest.split(/[\/:\?#]/)[0].toLowerCase(); + const isAllowed = allowedDomains.some(allowedDomain => { + const normalizedAllowed = allowedDomain.toLowerCase(); + return hostname === normalizedAllowed || hostname.endsWith("." + normalizedAllowed); + }); + if (isAllowed) { + return match; + } + const domain = hostname; + const truncated = domain.length > 12 ? domain.substring(0, 12) + "..." : domain; + core.info(`Redacted URL: ${truncated}`); + core.debug(`Redacted URL (full): ${match}`); + const urlParts = match.split(/([?&#])/); + let result = "(redacted)"; + for (let i = 1; i < urlParts.length; i++) { + if (urlParts[i].match(/^[?&#]$/)) { + result += urlParts[i]; + } else { + result += sanitizeUrlDomains(urlParts[i]); + } + } + return result; + }); + return s; + } + function sanitizeUrlProtocols(s) { + return s.replace(/(?&\x00-\x1f]+/g, (match, protocol) => { + if (protocol.toLowerCase() === "https") { + return match; + } + if (match.includes("::")) { + return match; + } + if (match.includes("://")) { + const domainMatch = match.match(/^[^:]+:\/\/([^\/\s?#]+)/); + const domain = domainMatch ? domainMatch[1] : match; + const truncated = domain.length > 12 ? domain.substring(0, 12) + "..." : domain; + core.info(`Redacted URL: ${truncated}`); + core.debug(`Redacted URL (full): ${match}`); + return "(redacted)"; + } + const dangerousProtocols = ["javascript", "data", "vbscript", "file", "about", "mailto", "tel", "ssh", "ftp"]; + if (dangerousProtocols.includes(protocol.toLowerCase())) { + const truncated = match.length > 12 ? match.substring(0, 12) + "..." : match; + core.info(`Redacted URL: ${truncated}`); + core.debug(`Redacted URL (full): ${match}`); + return "(redacted)"; + } + return match; + }); + } + function neutralizeCommands(s) { + const commandName = process.env.GH_AW_COMMAND; + if (!commandName) { + return s; + } + const escapedCommand = commandName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + return s.replace(new RegExp(`^(\\s*)/(${escapedCommand})\\b`, "i"), "$1`/$2`"); + } + function neutralizeMentions(s) { + return s.replace( + /(^|[^\w`])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?(?:\/[A-Za-z0-9._-]+)?)/g, + (_m, p1, p2) => `${p1}\`@${p2}\`` + ); + } + function removeXmlComments(s) { + return s.replace(//g, "").replace(//g, ""); + } + function convertXmlTags(s) { + const allowedTags = ["details", "summary", "code", "em", "b"]; + s = s.replace(//g, (match, content) => { + const convertedContent = content.replace(/<(\/?[A-Za-z][A-Za-z0-9]*(?:[^>]*?))>/g, "($1)"); + return `(![CDATA[${convertedContent}]])`; + }); + return s.replace(/<(\/?[A-Za-z!][^>]*?)>/g, (match, tagContent) => { + const tagNameMatch = tagContent.match(/^\/?\s*([A-Za-z][A-Za-z0-9]*)/); + if (tagNameMatch) { + const tagName = tagNameMatch[1].toLowerCase(); + if (allowedTags.includes(tagName)) { + return match; + } + } + return `(${tagContent})`; + }); + } + function neutralizeBotTriggers(s) { + return s.replace(/\b(fixes?|closes?|resolves?|fix|close|resolve)\s+#(\w+)/gi, (match, action, ref) => `\`${action} #${ref}\``); + } + } + async function main() { + let text = ""; + const actor = context.actor; + const { owner, repo } = context.repo; + const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: owner, + repo: repo, + username: actor, + }); + const permission = repoPermission.data.permission; + core.info(`Repository permission level: ${permission}`); + if (permission !== "admin" && permission !== "maintain") { + core.setOutput("text", ""); + return; + } + switch (context.eventName) { + case "issues": + if (context.payload.issue) { + const title = context.payload.issue.title || ""; + const body = context.payload.issue.body || ""; + text = `${title}\n\n${body}`; + } + break; + case "pull_request": + if (context.payload.pull_request) { + const title = context.payload.pull_request.title || ""; + const body = context.payload.pull_request.body || ""; + text = `${title}\n\n${body}`; + } + break; + case "pull_request_target": + if (context.payload.pull_request) { + const title = context.payload.pull_request.title || ""; + const body = context.payload.pull_request.body || ""; + text = `${title}\n\n${body}`; + } + break; + case "issue_comment": + if (context.payload.comment) { + text = context.payload.comment.body || ""; + } + break; + case "pull_request_review_comment": + if (context.payload.comment) { + text = context.payload.comment.body || ""; + } + break; + case "pull_request_review": + if (context.payload.review) { + text = context.payload.review.body || ""; + } + break; + case "discussion": + if (context.payload.discussion) { + const title = context.payload.discussion.title || ""; + const body = context.payload.discussion.body || ""; + text = `${title}\n\n${body}`; + } + break; + case "discussion_comment": + if (context.payload.comment) { + text = context.payload.comment.body || ""; + } + break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; + default: + text = ""; + break; + } + const sanitizedText = sanitizeContent(text); + core.info(`text: ${sanitizedText}`); + core.setOutput("text", sanitizedText); + } + await main(); agent: needs: activation @@ -883,38 +1190,22 @@ jobs: mkdir -p "$PROMPT_DIR" # shellcheck disable=SC2006,SC2287 cat > "$GH_AW_PROMPT" << 'PROMPT_EOF' - # Generate a Poem - - Create or update a `poem.md` file with a creative poem about GitHub Agentic Workflows and push the changes to the pull request branch. - - **Instructions**: - - Use the `edit` tool to either create a new `poem.md` file or update the existing one if it already exists. Write a creative, engaging poem that celebrates the power and capabilities of GitHub Agentic Workflows. + # Release Summary Prepender - The poem should be: - - Creative and fun - - Related to automation, AI agents, or GitHub workflows - - At least 8 lines long - - Written in a poetic style (rhyming, rhythm, or free verse) + **Context:** This workflow is triggered when a release is created/edited or manually dispatched with a release URL/ID. - Commit your changes. + The release content is available in the context: "${GH_AW_EXPR_0BABF60D}" - Call the `push-to-pull-request-branch` tool after making your changes. + **Task:** Analyze the release description and prepend a concise AI-generated summary to it. - **Example poem file structure:** - ```markdown - # Poem for GitHub Agentic Workflows + **Instructions:** - In the realm of code where automation flows, - An agent awakens, its purpose it knows. - Through pull requests and issues it goes, - Analyzing, creating, whatever it shows. + 1. Read the release content from the context above + 2. Generate a clear, concise summary (2-4 sentences) highlighting the key changes or features + 3. Use the `update_release` safe output with the **prepend** operation to add your summary at the top + 4. **CRITICAL:** If the `update_release` tool is not available, fail immediately with an error message - With LlamaGuard watching for threats in the night, - And Ollama scanning to keep things right. - The workflows are running, efficient and bright, - GitHub Agentic magic, a developer's delight. - ``` + **Note:** The tag field is optional and will be automatically inferred from the release event context (`github.event.release.tag_name`) or from workflow dispatch inputs (`release_url` or `release_id`). The summary will be prepended with a horizontal line separator and AI attribution footer. PROMPT_EOF - name: Append XPIA security instructions to prompt @@ -1048,6 +1339,7 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt + GH_AW_EXPR_0BABF60D: ${{ needs.activation.outputs.text }} with: script: | const fs = require("fs"); @@ -1544,6 +1836,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2088,6 +2382,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2202,7 +2518,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); @@ -3535,6 +3851,7 @@ jobs: - activation - push_to_pull_request_branch - missing_tool + - update_release - noop if: (always()) && (needs.agent.result != 'skipped') runs-on: ubuntu-slim @@ -4440,6 +4757,86 @@ jobs: } await main(); + pre_activation: + runs-on: ubuntu-slim + outputs: + activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} + steps: + - name: Check team membership for workflow + id: check_membership + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_REQUIRED_ROLES: admin,maintainer,write + with: + script: | + async function main() { + const { eventName } = context; + const actor = context.actor; + const { owner, repo } = context.repo; + const requiredPermissionsEnv = process.env.GH_AW_REQUIRED_ROLES; + const requiredPermissions = requiredPermissionsEnv ? requiredPermissionsEnv.split(",").filter(p => p.trim() !== "") : []; + if (eventName === "workflow_dispatch") { + const hasWriteRole = requiredPermissions.includes("write"); + if (hasWriteRole) { + core.info(`✅ Event ${eventName} does not require validation (write role allowed)`); + core.setOutput("is_team_member", "true"); + core.setOutput("result", "safe_event"); + return; + } + core.info(`Event ${eventName} requires validation (write role not allowed)`); + } + const safeEvents = ["schedule"]; + if (safeEvents.includes(eventName)) { + core.info(`✅ Event ${eventName} does not require validation`); + core.setOutput("is_team_member", "true"); + core.setOutput("result", "safe_event"); + return; + } + if (!requiredPermissions || requiredPermissions.length === 0) { + core.warning("❌ Configuration error: Required permissions not specified. Contact repository administrator."); + core.setOutput("is_team_member", "false"); + core.setOutput("result", "config_error"); + core.setOutput("error_message", "Configuration error: Required permissions not specified"); + return; + } + try { + core.info(`Checking if user '${actor}' has required permissions for ${owner}/${repo}`); + core.info(`Required permissions: ${requiredPermissions.join(", ")}`); + const repoPermission = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: owner, + repo: repo, + username: actor, + }); + const permission = repoPermission.data.permission; + core.info(`Repository permission level: ${permission}`); + for (const requiredPerm of requiredPermissions) { + if (permission === requiredPerm || (requiredPerm === "maintainer" && permission === "maintain")) { + core.info(`✅ User has ${permission} access to repository`); + core.setOutput("is_team_member", "true"); + core.setOutput("result", "authorized"); + core.setOutput("user_permission", permission); + return; + } + } + core.warning(`User permission '${permission}' does not meet requirements: ${requiredPermissions.join(", ")}`); + core.setOutput("is_team_member", "false"); + core.setOutput("result", "insufficient_permissions"); + core.setOutput("user_permission", permission); + core.setOutput( + "error_message", + `Access denied: User '${actor}' is not authorized. Required permissions: ${requiredPermissions.join(", ")}` + ); + } catch (repoError) { + const errorMessage = repoError instanceof Error ? repoError.message : String(repoError); + core.warning(`Repository permission check failed: ${errorMessage}`); + core.setOutput("is_team_member", "false"); + core.setOutput("result", "api_error"); + core.setOutput("error_message", `Repository permission check failed: ${errorMessage}`); + return; + } + } + await main(); + push_to_pull_request_branch: needs: - agent @@ -4943,3 +5340,215 @@ jobs: } await main(); + update_release: + needs: + - agent + - detection + if: > + (((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'update_release'))) && + (needs.detection.outputs.success == 'true') + runs-on: ubuntu-slim + permissions: + contents: write + timeout-minutes: 10 + outputs: + release_id: ${{ steps.update_release.outputs.release_id }} + release_tag: ${{ steps.update_release.outputs.release_tag }} + release_url: ${{ steps.update_release.outputs.release_url }} + steps: + - name: Download agent output artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6 + with: + name: agent_output.json + path: /tmp/gh-aw/safeoutputs/ + - name: Setup agent output environment variable + run: | + mkdir -p /tmp/gh-aw/safeoutputs/ + find "/tmp/gh-aw/safeoutputs/" -type f -print + echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Update Release + id: update_release + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Dev" + with: + github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const fs = require("fs"); + function loadAgentOutput() { + const agentOutputFile = process.env.GH_AW_AGENT_OUTPUT; + if (!agentOutputFile) { + core.info("No GH_AW_AGENT_OUTPUT environment variable found"); + return { success: false }; + } + let outputContent; + try { + outputContent = fs.readFileSync(agentOutputFile, "utf8"); + } catch (error) { + const errorMessage = `Error reading agent output file: ${error instanceof Error ? error.message : String(error)}`; + core.error(errorMessage); + return { success: false, error: errorMessage }; + } + if (outputContent.trim() === "") { + core.info("Agent output content is empty"); + return { success: false }; + } + core.info(`Agent output content length: ${outputContent.length}`); + let validatedOutput; + try { + validatedOutput = JSON.parse(outputContent); + } catch (error) { + const errorMessage = `Error parsing agent output JSON: ${error instanceof Error ? error.message : String(error)}`; + core.error(errorMessage); + return { success: false, error: errorMessage }; + } + if (!validatedOutput.items || !Array.isArray(validatedOutput.items)) { + core.info("No valid items found in agent output"); + return { success: false }; + } + return { success: true, items: validatedOutput.items }; + } + async function generateStagedPreview(options) { + const { title, description, items, renderItem } = options; + let summaryContent = `## 🎭 Staged Mode: ${title} Preview\n\n`; + summaryContent += `${description}\n\n`; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + summaryContent += renderItem(item, i); + summaryContent += "---\n\n"; + } + try { + await core.summary.addRaw(summaryContent).write(); + core.info(summaryContent); + core.info(`📝 ${title} preview written to step summary`); + } catch (error) { + core.setFailed(error instanceof Error ? error : String(error)); + } + } + async function main() { + const isStaged = process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true"; + const result = loadAgentOutput(); + if (!result.success) { + return; + } + const updateItems = result.items.filter( item => item.type === "update_release"); + if (updateItems.length === 0) { + core.info("No update-release items found in agent output"); + return; + } + core.info(`Found ${updateItems.length} update-release item(s)`); + if (isStaged) { + await generateStagedPreview({ + title: "Update Releases", + description: "The following release updates would be applied if staged mode was disabled:", + items: updateItems, + renderItem: (item, index) => { + let content = `### Release Update ${index + 1}\n`; + content += `**Tag:** ${item.tag || "(inferred from event context)"}\n`; + content += `**Operation:** ${item.operation}\n\n`; + content += `**Body Content:**\n${item.body}\n\n`; + return content; + }, + }); + return; + } + const workflowName = process.env.GH_AW_WORKFLOW_NAME || "GitHub Agentic Workflow"; + const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + const updatedReleases = []; + for (let i = 0; i < updateItems.length; i++) { + const updateItem = updateItems[i]; + core.info(`Processing update-release item ${i + 1}/${updateItems.length}`); + try { + let releaseTag = updateItem.tag; + if (!releaseTag) { + if (context.eventName === "release" && context.payload.release && context.payload.release.tag_name) { + releaseTag = context.payload.release.tag_name; + core.info(`Inferred release tag from event context: ${releaseTag}`); + } else if (context.eventName === "workflow_dispatch" && context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/[^\/]+\/[^\/]+\/releases\/tag\/([^\/\?#]+)/); + if (urlMatch && urlMatch[1]) { + releaseTag = decodeURIComponent(urlMatch[1]); + core.info(`Inferred release tag from release_url input: ${releaseTag}`); + } + } + if (!releaseTag && context.payload.inputs.release_id) { + const releaseId = context.payload.inputs.release_id; + core.info(`Fetching release with ID: ${releaseId}`); + const { data: release } = await github.rest.repos.getRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: parseInt(releaseId, 10), + }); + releaseTag = release.tag_name; + core.info(`Inferred release tag from release_id input: ${releaseTag}`); + } + } + if (!releaseTag) { + core.error("No tag provided and unable to infer from event context"); + core.setFailed("Release tag is required but not provided and cannot be inferred from event context"); + return; + } + } + core.info(`Fetching release with tag: ${releaseTag}`); + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: context.repo.owner, + repo: context.repo.repo, + tag: releaseTag, + }); + core.info(`Found release: ${release.name || release.tag_name} (ID: ${release.id})`); + let newBody; + if (updateItem.operation === "replace") { + newBody = updateItem.body; + core.info("Operation: replace (full body replacement)"); + } else if (updateItem.operation === "prepend") { + const aiFooter = `\n\n> AI generated by [${workflowName}](${runUrl})`; + const prependSection = `${updateItem.body}${aiFooter}\n\n---\n\n`; + newBody = prependSection + (release.body || ""); + core.info("Operation: prepend (add to start with separator)"); + } else { + const aiFooter = `\n\n> AI generated by [${workflowName}](${runUrl})`; + const appendSection = `\n\n---\n\n${updateItem.body}${aiFooter}`; + newBody = (release.body || "") + appendSection; + core.info("Operation: append (add to end with separator)"); + } + const { data: updatedRelease } = await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.id, + body: newBody, + }); + core.info(`Successfully updated release: ${updatedRelease.html_url}`); + updatedReleases.push({ + tag: releaseTag, + url: updatedRelease.html_url, + id: updatedRelease.id, + }); + if (i === 0) { + core.setOutput("release_id", updatedRelease.id); + core.setOutput("release_url", updatedRelease.html_url); + core.setOutput("release_tag", updatedRelease.tag_name); + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + const tagInfo = updateItem.tag || "inferred from context"; + core.error(`Failed to update release with tag ${tagInfo}: ${errorMessage}`); + if (errorMessage.includes("Not Found")) { + core.error(`Release with tag '${tagInfo}' not found. Please ensure the tag exists.`); + } + core.setFailed(`Failed to update release: ${errorMessage}`); + return; + } + } + let summaryContent = `## ✅ Release Updates Complete\n\n`; + summaryContent += `Updated ${updatedReleases.length} release(s):\n\n`; + for (const rel of updatedReleases) { + summaryContent += `- **${rel.tag}**: [View Release](${rel.url})\n`; + } + await core.summary.addRaw(summaryContent).write(); + } + await main(); + diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index b4a5d97a5a..2f71a70610 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -2447,6 +2447,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2991,6 +2993,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3105,7 +3129,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index a1f2639fe9..c8bb04be02 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -1642,6 +1642,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2186,6 +2188,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2300,7 +2324,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index d734a28728..f49d75f2c4 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -1699,6 +1699,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2243,6 +2245,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2357,7 +2381,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index ce00c9116f..222613e5fd 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -1716,6 +1716,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2260,6 +2262,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2374,7 +2398,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml index 1d39e20cb2..f6c70ba2d6 100644 --- a/.github/workflows/example-workflow-analyzer.lock.yml +++ b/.github/workflows/example-workflow-analyzer.lock.yml @@ -1748,6 +1748,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2292,6 +2294,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2406,7 +2430,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index ee95debefc..36ce05fe8c 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -2269,6 +2269,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2813,6 +2815,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2927,7 +2951,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index 37d4267468..7919a2bfd4 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -2014,6 +2014,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2558,6 +2560,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2672,7 +2696,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml index 69c44edbe1..1f94138392 100644 --- a/.github/workflows/go-pattern-detector.lock.yml +++ b/.github/workflows/go-pattern-detector.lock.yml @@ -1788,6 +1788,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2332,6 +2334,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2446,7 +2470,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index 54fe4dfbc1..a113db4a09 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -407,6 +407,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2673,6 +2717,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3217,6 +3263,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3331,7 +3399,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index d206a3bc1d..695a767b98 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -1893,6 +1893,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2437,6 +2439,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2551,7 +2575,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index 8937930b67..0a68df9e8d 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -398,6 +398,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2320,6 +2364,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2864,6 +2910,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2978,7 +3046,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml index 0a9ce3407a..caf80e6bf9 100644 --- a/.github/workflows/lockfile-stats.lock.yml +++ b/.github/workflows/lockfile-stats.lock.yml @@ -2103,6 +2103,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2647,6 +2649,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2761,7 +2785,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index a794388f8b..2e998bc534 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -2220,6 +2220,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2764,6 +2766,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2878,7 +2902,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index 00c23b15f2..56fd711bef 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -2196,6 +2196,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2740,6 +2742,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2854,7 +2878,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/notion-issue-summary.lock.yml b/.github/workflows/notion-issue-summary.lock.yml index 9133e98164..db5b40d7af 100644 --- a/.github/workflows/notion-issue-summary.lock.yml +++ b/.github/workflows/notion-issue-summary.lock.yml @@ -1495,6 +1495,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2039,6 +2041,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2153,7 +2177,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index 413b6c14f0..209bf9bd73 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -423,6 +423,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2724,6 +2768,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3268,6 +3314,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3382,7 +3450,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index 1c6cc43f68..7df20659d8 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -402,6 +402,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2199,6 +2243,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2743,6 +2789,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2857,7 +2925,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index 440285ee72..ac8531df7f 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -438,6 +438,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -2995,6 +3039,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3539,6 +3585,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3653,7 +3721,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index d3e5a1d744..4c9e7ef699 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -2776,6 +2776,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3320,6 +3322,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3434,7 +3458,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index 568145a3f4..f24d76074d 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -2443,6 +2443,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2987,6 +2989,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3101,7 +3125,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index 84e823064c..ab136dbac1 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -2579,6 +2579,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3123,6 +3125,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3237,7 +3261,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index 1f84150496..27d2878952 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -446,6 +446,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3065,6 +3109,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3609,6 +3655,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3723,7 +3791,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml index 9ad62acf43..0086529c3e 100644 --- a/.github/workflows/repo-tree-map.lock.yml +++ b/.github/workflows/repo-tree-map.lock.yml @@ -1677,6 +1677,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2221,6 +2223,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2335,7 +2359,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index be9dc67da1..cfda9751ec 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -2195,6 +2195,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2739,6 +2741,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2853,7 +2877,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml index 58c28f69ac..0b62165668 100644 --- a/.github/workflows/research.lock.yml +++ b/.github/workflows/research.lock.yml @@ -1611,6 +1611,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2155,6 +2157,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2269,7 +2293,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml index 0b00d3c0d1..30a74be84e 100644 --- a/.github/workflows/safe-output-health.lock.yml +++ b/.github/workflows/safe-output-health.lock.yml @@ -2236,6 +2236,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2780,6 +2782,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2894,7 +2918,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml index 4d24ae464a..b8048e8007 100644 --- a/.github/workflows/schema-consistency-checker.lock.yml +++ b/.github/workflows/schema-consistency-checker.lock.yml @@ -2109,6 +2109,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2653,6 +2655,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2767,7 +2791,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index 2b5213ecfe..23907f0fe7 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -449,6 +449,50 @@ jobs: text = context.payload.comment.body || ""; } break; + case "release": + if (context.payload.release) { + const name = context.payload.release.name || context.payload.release.tag_name || ""; + const body = context.payload.release.body || ""; + text = `${name}\n\n${body}`; + } + break; + case "workflow_dispatch": + if (context.payload.inputs) { + const releaseUrl = context.payload.inputs.release_url; + const releaseId = context.payload.inputs.release_id; + if (releaseUrl) { + const urlMatch = releaseUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\/releases\/tag\/([^\/]+)/); + if (urlMatch) { + const [, urlOwner, urlRepo, tag] = urlMatch; + try { + const { data: release } = await github.rest.repos.getReleaseByTag({ + owner: urlOwner, + repo: urlRepo, + tag: tag, + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release from URL: ${error instanceof Error ? error.message : String(error)}`); + } + } + } else if (releaseId) { + try { + const { data: release } = await github.rest.repos.getRelease({ + owner: owner, + repo: repo, + release_id: parseInt(releaseId, 10), + }); + const name = release.name || release.tag_name || ""; + const body = release.body || ""; + text = `${name}\n\n${body}`; + } catch (error) { + core.warning(`Failed to fetch release by ID: ${error instanceof Error ? error.message : String(error)}`); + } + } + } + break; default: text = ""; break; @@ -3179,6 +3223,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3723,6 +3769,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3837,7 +3905,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/security-fix-pr.lock.yml b/.github/workflows/security-fix-pr.lock.yml index 1543e722be..048172a6c1 100644 --- a/.github/workflows/security-fix-pr.lock.yml +++ b/.github/workflows/security-fix-pr.lock.yml @@ -1841,6 +1841,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2385,6 +2387,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2499,7 +2523,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml index 40795a0845..7598c5619a 100644 --- a/.github/workflows/semantic-function-refactor.lock.yml +++ b/.github/workflows/semantic-function-refactor.lock.yml @@ -2197,6 +2197,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2741,6 +2743,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2855,7 +2879,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index cc2bd27ac9..24a65ac3f0 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -1756,6 +1756,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2300,6 +2302,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2414,7 +2438,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index 86575b9a45..19b3b9ef92 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -1458,6 +1458,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2002,6 +2004,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2116,7 +2140,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index ce98c2aa77..75a132f170 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -1528,6 +1528,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2072,6 +2074,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2186,7 +2210,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/smoke-detector.lock.yml b/.github/workflows/smoke-detector.lock.yml index a33f730d55..248f0579b7 100644 --- a/.github/workflows/smoke-detector.lock.yml +++ b/.github/workflows/smoke-detector.lock.yml @@ -2822,6 +2822,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3366,6 +3368,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3480,7 +3504,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml index 255fcaedd9..efb2dee3f7 100644 --- a/.github/workflows/static-analysis-report.lock.yml +++ b/.github/workflows/static-analysis-report.lock.yml @@ -2124,6 +2124,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2668,6 +2670,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2782,7 +2806,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index a368dea512..3d62be631c 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -1750,6 +1750,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2294,6 +2296,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2408,7 +2432,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index adf3dfe88e..48183f541d 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -2423,6 +2423,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2967,6 +2969,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3081,7 +3105,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/test-ollama-threat-detection.lock.yml b/.github/workflows/test-ollama-threat-detection.lock.yml index cabb5c638a..a3563d5574 100644 --- a/.github/workflows/test-ollama-threat-detection.lock.yml +++ b/.github/workflows/test-ollama-threat-detection.lock.yml @@ -1473,6 +1473,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2017,6 +2019,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2131,7 +2155,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index 3a19751463..8037e61235 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -1999,6 +1999,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2543,6 +2545,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2657,7 +2681,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index b4b0c2857b..886af8173a 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -2267,6 +2267,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2811,6 +2813,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2925,7 +2949,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index 40573a2993..5eb63d3387 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -2918,6 +2918,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -3462,6 +3464,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -3576,7 +3600,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml index 66603ae481..eb5e0558eb 100644 --- a/.github/workflows/video-analyzer.lock.yml +++ b/.github/workflows/video-analyzer.lock.yml @@ -1764,6 +1764,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2308,6 +2310,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2422,7 +2446,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index d340000d25..17e24dd64b 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -2167,6 +2167,8 @@ jobs: return 40; case "upload_asset": return 10; + case "update_release": + return 1; case "noop": return 1; default: @@ -2711,6 +2713,28 @@ jobs: item.alternatives = sanitizeContent(item.alternatives, 512); } break; + case "update_release": + if (item.tag !== undefined && typeof item.tag !== "string") { + errors.push(`Line ${i + 1}: update_release 'tag' must be a string if provided`); + continue; + } + if (!item.operation || typeof item.operation !== "string") { + errors.push(`Line ${i + 1}: update_release requires an 'operation' string field`); + continue; + } + if (item.operation !== "replace" && item.operation !== "append" && item.operation !== "prepend") { + errors.push(`Line ${i + 1}: update_release 'operation' must be 'replace', 'append', or 'prepend'`); + continue; + } + if (!item.body || typeof item.body !== "string") { + errors.push(`Line ${i + 1}: update_release requires a 'body' string field`); + continue; + } + if (item.tag) { + item.tag = sanitizeContent(item.tag, 256); + } + item.body = sanitizeContent(item.body, maxBodyLength); + break; case "upload_asset": if (!item.path || typeof item.path !== "string") { errors.push(`Line ${i + 1}: upload_asset requires a 'path' string field`); @@ -2825,7 +2849,7 @@ jobs: const agentOutputFile = "/tmp/gh-aw/agent_output.json"; const validatedOutputJson = JSON.stringify(validatedOutput); try { - fs.mkdirSync("/tmp", { recursive: true }); + fs.mkdirSync("/tmp/gh-aw", { recursive: true }); fs.writeFileSync(agentOutputFile, validatedOutputJson, "utf8"); core.info(`Stored validated output to: ${agentOutputFile}`); core.exportVariable("GH_AW_AGENT_OUTPUT", agentOutputFile); From bc7c250ed5e8df13ea744389acdac3b185c33235 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Nov 2025 04:41:09 +0000 Subject: [PATCH 12/12] Add update_release to safe outputs config generation - Added update_release configuration to generateSafeOutputsConfig() - Added update_release tool to generateFilteredToolsJSON() - Also added missing noop configuration to generateSafeOutputsConfig() - This fixes the ingestion error where update_release tool was rejected - All tests passing, 80 workflows compiled successfully Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/ai-triage-campaign.lock.yml | 2 +- .github/workflows/archie.lock.yml | 2 +- .github/workflows/artifacts-summary.lock.yml | 2 +- .github/workflows/audit-workflows.lock.yml | 2 +- .github/workflows/blog-auditor.lock.yml | 2 +- .github/workflows/brave.lock.yml | 2 +- .github/workflows/changeset.lock.yml | 2 +- .github/workflows/ci-doctor.lock.yml | 2 +- .../workflows/cli-consistency-checker.lock.yml | 2 +- .github/workflows/cli-version-checker.lock.yml | 2 +- .github/workflows/cloclo.lock.yml | 2 +- .../workflows/commit-changes-analyzer.lock.yml | 2 +- .../workflows/copilot-agent-analysis.lock.yml | 2 +- .../workflows/copilot-pr-nlp-analysis.lock.yml | 2 +- .../copilot-pr-prompt-analysis.lock.yml | 2 +- .../workflows/copilot-session-insights.lock.yml | 2 +- .github/workflows/craft.lock.yml | 2 +- .github/workflows/daily-code-metrics.lock.yml | 2 +- .github/workflows/daily-doc-updater.lock.yml | 2 +- .github/workflows/daily-file-diet.lock.yml | 2 +- .../workflows/daily-firewall-report.lock.yml | 2 +- .../daily-multi-device-docs-tester.lock.yml | 2 +- .github/workflows/daily-news.lock.yml | 2 +- .github/workflows/daily-repo-chronicle.lock.yml | 2 +- .github/workflows/daily-team-status.lock.yml | 2 +- .../workflows/dependabot-go-checker.lock.yml | 2 +- .github/workflows/dev-hawk.lock.yml | 2 +- .github/workflows/dev.lock.yml | 4 ++-- .../developer-docs-consolidator.lock.yml | 2 +- .github/workflows/dictation-prompt.lock.yml | 2 +- .github/workflows/docs-noob-tester.lock.yml | 2 +- .../workflows/duplicate-code-detector.lock.yml | 2 +- .../example-workflow-analyzer.lock.yml | 2 +- .../workflows/github-mcp-tools-report.lock.yml | 2 +- .github/workflows/go-logger.lock.yml | 2 +- .github/workflows/go-pattern-detector.lock.yml | 2 +- .github/workflows/grumpy-reviewer.lock.yml | 2 +- .github/workflows/instructions-janitor.lock.yml | 2 +- .github/workflows/issue-classifier.lock.yml | 2 +- .github/workflows/lockfile-stats.lock.yml | 2 +- .github/workflows/mcp-inspector.lock.yml | 2 +- .github/workflows/mergefest.lock.yml | 2 +- .github/workflows/pdf-summary.lock.yml | 2 +- .github/workflows/plan.lock.yml | 2 +- .github/workflows/poem-bot.lock.yml | 2 +- .github/workflows/pr-nitpick-reviewer.lock.yml | 2 +- .../prompt-clustering-analysis.lock.yml | 2 +- .github/workflows/python-data-charts.lock.yml | 2 +- .github/workflows/q.lock.yml | 2 +- .github/workflows/repo-tree-map.lock.yml | 2 +- .../repository-quality-improver.lock.yml | 2 +- .github/workflows/research.lock.yml | 2 +- .github/workflows/safe-output-health.lock.yml | 2 +- .../schema-consistency-checker.lock.yml | 2 +- .github/workflows/scout.lock.yml | 2 +- .github/workflows/security-fix-pr.lock.yml | 2 +- .../semantic-function-refactor.lock.yml | 2 +- .github/workflows/smoke-claude.lock.yml | 2 +- .github/workflows/smoke-codex.lock.yml | 2 +- .github/workflows/smoke-copilot.lock.yml | 2 +- .github/workflows/smoke-detector.lock.yml | 2 +- .../workflows/static-analysis-report.lock.yml | 2 +- .github/workflows/super-linter.lock.yml | 2 +- .github/workflows/technical-doc-writer.lock.yml | 2 +- .../test-ollama-threat-detection.lock.yml | 2 +- .github/workflows/tidy.lock.yml | 2 +- .github/workflows/typist.lock.yml | 2 +- .github/workflows/unbloat-docs.lock.yml | 2 +- .github/workflows/video-analyzer.lock.yml | 2 +- .github/workflows/weekly-issue-summary.lock.yml | 2 +- pkg/workflow/safe_outputs.go | 17 +++++++++++++++++ 71 files changed, 88 insertions(+), 71 deletions(-) diff --git a/.github/workflows/ai-triage-campaign.lock.yml b/.github/workflows/ai-triage-campaign.lock.yml index bb8e7c4203..034dfe89cc 100644 --- a/.github/workflows/ai-triage-campaign.lock.yml +++ b/.github/workflows/ai-triage-campaign.lock.yml @@ -260,7 +260,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"missing_tool":{},"update_project":{"max":20}} + {"missing_tool":{},"noop":{"max":1},"update_project":{"max":20}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index 2771b00e21..d077442ea8 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -1334,7 +1334,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1},"missing_tool":{}} + {"add_comment":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index 15e26e12e7..e24c43083f 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -265,7 +265,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index fa0a0eec14..541382c6bc 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -447,7 +447,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{},"upload_asset":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml index ca7129d5ef..f5f2ed8978 100644 --- a/.github/workflows/blog-auditor.lock.yml +++ b/.github/workflows/blog-auditor.lock.yml @@ -368,7 +368,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index 0005c63627..c42f27d188 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -1297,7 +1297,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1},"missing_tool":{}} + {"add_comment":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index 7aae9fb257..be080dbd4e 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -910,7 +910,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"missing_tool":{},"push_to_pull_request_branch":{}} + {"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Push changes to a pull request branch","inputSchema":{"additionalProperties":false,"properties":{"branch":{"description":"Optional branch name. Do not provide this parameter if you want to push changes from the current branch. If not provided, the current branch will be used.","type":"string"},"message":{"description":"Commit message","type":"string"},"pull_request_number":{"description":"Optional pull request number for target '*'","type":["number","string"]}},"required":["message"],"type":"object"},"name":"push_to_pull_request_branch"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index 2ac96c0a1f..e9136a994e 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -717,7 +717,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1},"create_issue":{"max":1},"missing_tool":{}} + {"add_comment":{"max":1},"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index bb24be6801..0a1d05ee9e 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -266,7 +266,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":5},"missing_tool":{}} + {"create_issue":{"max":5},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index 84b1689dad..e3addf9ff3 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -293,7 +293,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{}} + {"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index 339e4012cc..bb8dab84a4 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -1509,7 +1509,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1},"create_pull_request":{},"missing_tool":{},"push_to_pull_request_branch":{}} + {"add_comment":{"max":1},"create_pull_request":{},"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Push changes to a pull request branch","inputSchema":{"additionalProperties":false,"properties":{"branch":{"description":"Optional branch name. Do not provide this parameter if you want to push changes from the current branch. If not provided, the current branch will be used.","type":"string"},"message":{"description":"Commit message","type":"string"},"pull_request_number":{"description":"Optional pull request number for target '*'","type":["number","string"]}},"required":["message"],"type":"object"},"name":"push_to_pull_request_branch"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml index 58e4301efe..9c1986b2a9 100644 --- a/.github/workflows/commit-changes-analyzer.lock.yml +++ b/.github/workflows/commit-changes-analyzer.lock.yml @@ -371,7 +371,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index 0f157a9435..91289b5c6d 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -403,7 +403,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index 0b9c0e3960..6e324929e9 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -332,7 +332,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index e04d61ece0..2e0106382d 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -302,7 +302,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index 088368d59c..4cf365e5d9 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -443,7 +443,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{},"upload_asset":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index 09d6c77fd8..b1968c7e02 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -1302,7 +1302,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1},"missing_tool":{},"push_to_pull_request_branch":{}} + {"add_comment":{"max":1},"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Push changes to a pull request branch","inputSchema":{"additionalProperties":false,"properties":{"branch":{"description":"Optional branch name. Do not provide this parameter if you want to push changes from the current branch. If not provided, the current branch will be used.","type":"string"},"message":{"description":"Commit message","type":"string"},"pull_request_number":{"description":"Optional pull request number for target '*'","type":["number","string"]}},"required":["message"],"type":"object"},"name":"push_to_pull_request_branch"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index e2d945afe5..8a5753b0f0 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -388,7 +388,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index e0bb865650..fb48e30c0c 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -387,7 +387,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_pull_request":{},"missing_tool":{}} + {"create_pull_request":{},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index 5375ff72b1..5811cbb113 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -289,7 +289,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{}} + {"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index 209ef87fe5..5489526e64 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -330,7 +330,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{},"upload_asset":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml index c56811afbf..518bcf8901 100644 --- a/.github/workflows/daily-multi-device-docs-tester.lock.yml +++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml @@ -376,7 +376,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{},"upload_asset":{}} + {"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index bebde30e43..da59218433 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -336,7 +336,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{},"upload_asset":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index 85bb540d30..fc97379378 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -323,7 +323,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{},"upload_asset":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml index dca6693c46..2c51cb6f49 100644 --- a/.github/workflows/daily-team-status.lock.yml +++ b/.github/workflows/daily-team-status.lock.yml @@ -271,7 +271,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml index 3df8dc2784..77f04aa3c7 100644 --- a/.github/workflows/dependabot-go-checker.lock.yml +++ b/.github/workflows/dependabot-go-checker.lock.yml @@ -260,7 +260,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":5},"missing_tool":{}} + {"create_issue":{"max":5},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index 90bd144403..55164ca6c8 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -684,7 +684,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1,"target":"*"},"missing_tool":{}} + {"add_comment":{"max":1,"target":"*"},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index 82139d074a..e08c75f601 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -562,10 +562,10 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"missing_tool":{},"push_to_pull_request_branch":{}} + {"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{},"update_release":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' - [{"description":"Push changes to a pull request branch","inputSchema":{"additionalProperties":false,"properties":{"branch":{"description":"Optional branch name. Do not provide this parameter if you want to push changes from the current branch. If not provided, the current branch will be used.","type":"string"},"message":{"description":"Commit message","type":"string"},"pull_request_number":{"description":"Optional pull request number for target '*'","type":["number","string"]}},"required":["message"],"type":"object"},"name":"push_to_pull_request_branch"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] + [{"description":"Push changes to a pull request branch","inputSchema":{"additionalProperties":false,"properties":{"branch":{"description":"Optional branch name. Do not provide this parameter if you want to push changes from the current branch. If not provided, the current branch will be used.","type":"string"},"message":{"description":"Commit message","type":"string"},"pull_request_number":{"description":"Optional pull request number for target '*'","type":["number","string"]}},"required":["message"],"type":"object"},"name":"push_to_pull_request_branch"},{"description":"Update a GitHub release description","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Release body content to set, append, or prepend","type":"string"},"operation":{"description":"Update operation: 'replace' (full replacement), 'append' (add at end with separator), or 'prepend' (add at start with separator)","enum":["replace","append","prepend"],"type":"string"},"tag":{"description":"Release tag name (optional - inferred from event context if omitted)","type":"string"}},"required":["operation","body"],"type":"object"},"name":"update_release"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] EOF cat > /tmp/gh-aw/safeoutputs/mcp-server.cjs << 'EOF' const fs = require("fs"); diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index 2f71a70610..85a499cbfd 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -423,7 +423,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"create_pull_request":{},"missing_tool":{}} + {"create_discussion":{"max":1},"create_pull_request":{},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index c8bb04be02..d1cccc2f72 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -260,7 +260,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_pull_request":{},"missing_tool":{}} + {"create_pull_request":{},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index f49d75f2c4..37e382365c 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -270,7 +270,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{},"upload_asset":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index 222613e5fd..d4867c2b46 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -283,7 +283,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":3},"missing_tool":{}} + {"create_issue":{"max":3},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml index f6c70ba2d6..06b20d7f24 100644 --- a/.github/workflows/example-workflow-analyzer.lock.yml +++ b/.github/workflows/example-workflow-analyzer.lock.yml @@ -377,7 +377,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index 36ce05fe8c..55dfca368e 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -399,7 +399,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"create_pull_request":{},"missing_tool":{}} + {"create_discussion":{"max":1},"create_pull_request":{},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index 7919a2bfd4..d47343a76e 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -404,7 +404,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_pull_request":{},"missing_tool":{}} + {"create_pull_request":{},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml index 1f94138392..b672d5dc8b 100644 --- a/.github/workflows/go-pattern-detector.lock.yml +++ b/.github/workflows/go-pattern-detector.lock.yml @@ -374,7 +374,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{}} + {"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index a113db4a09..221eb252a9 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -1321,7 +1321,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1},"create_pull_request_review_comment":{"max":5},"missing_tool":{}} + {"add_comment":{"max":1},"create_pull_request_review_comment":{"max":5},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Create a review comment on a GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body content","type":"string"},"line":{"description":"Line number for the comment","type":["number","string"]},"path":{"description":"File path for the review comment","type":"string"},"side":{"description":"Optional side of the diff: LEFT or RIGHT","enum":["LEFT","RIGHT"],"type":"string"},"start_line":{"description":"Optional start line for multi-line comments","type":["number","string"]}},"required":["path","line","body"],"type":"object"},"name":"create_pull_request_review_comment"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index 695a767b98..70167f1a25 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -387,7 +387,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_pull_request":{},"missing_tool":{}} + {"create_pull_request":{},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index 0a68df9e8d..aee68150b0 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -1135,7 +1135,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_labels":{"allowed":["bug","feature","enhancement","documentation"],"max":1},"missing_tool":{}} + {"add_labels":{"allowed":["bug","feature","enhancement","documentation"],"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add labels to a GitHub issue or pull request","inputSchema":{"additionalProperties":false,"properties":{"item_number":{"description":"Issue or PR number (optional for current context)","type":"number"},"labels":{"description":"Labels to add","items":{"type":"string"},"type":"array"}},"required":["labels"],"type":"object"},"name":"add_labels"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml index caf80e6bf9..c434f65ae2 100644 --- a/.github/workflows/lockfile-stats.lock.yml +++ b/.github/workflows/lockfile-stats.lock.yml @@ -390,7 +390,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index 2e998bc534..6eed714963 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -357,7 +357,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{},"notion-add-comment":{"description":"Add a comment to a Notion page","inputs":{"comment":{"description":"The comment text to add","required":true,"type":"string"}},"output":"Comment added to Notion successfully!"},"post-to-slack-channel":{"description":"Post a message to a Slack channel. Message must be 200 characters or less. Supports basic Slack markdown: *bold*, _italic_, ~strike~, `code`, ```code block```, \u003equote, and links \u003curl|text\u003e. Requires GH_AW_SLACK_CHANNEL_ID environment variable to be set.","inputs":{"message":{"description":"The message to post (max 200 characters, supports Slack markdown)","required":true,"type":"string"}},"output":"Message posted to Slack successfully!"}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1},"notion-add-comment":{"description":"Add a comment to a Notion page","inputs":{"comment":{"description":"The comment text to add","required":true,"type":"string"}},"output":"Comment added to Notion successfully!"},"post-to-slack-channel":{"description":"Post a message to a Slack channel. Message must be 200 characters or less. Supports basic Slack markdown: *bold*, _italic_, ~strike~, `code`, ```code block```, \u003equote, and links \u003curl|text\u003e. Requires GH_AW_SLACK_CHANNEL_ID environment variable to be set.","inputs":{"message":{"description":"The message to post (max 200 characters, supports Slack markdown)","required":true,"type":"string"}},"output":"Message posted to Slack successfully!"}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index 56fd711bef..5e9a76e348 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -603,7 +603,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"missing_tool":{},"push_to_pull_request_branch":{}} + {"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Push changes to a pull request branch","inputSchema":{"additionalProperties":false,"properties":{"branch":{"description":"Optional branch name. Do not provide this parameter if you want to push changes from the current branch. If not provided, the current branch will be used.","type":"string"},"message":{"description":"Commit message","type":"string"},"pull_request_number":{"description":"Optional pull request number for target '*'","type":["number","string"]}},"required":["message"],"type":"object"},"name":"push_to_pull_request_branch"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index 209bf9bd73..444c3f2d78 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -1345,7 +1345,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1},"missing_tool":{}} + {"add_comment":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index 7df20659d8..b6e81a239e 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -889,7 +889,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":5},"missing_tool":{}} + {"create_issue":{"max":5},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index ac8531df7f..7b0701e403 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -1641,7 +1641,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":3,"target":"*"},"add_labels":{"allowed":["poetry","creative","automation","ai-generated","epic","haiku","sonnet","limerick"],"max":5},"create_issue":{"max":2},"create_pull_request":{},"create_pull_request_review_comment":{"max":2},"missing_tool":{},"push_to_pull_request_branch":{},"update_issue":{"max":2},"upload_asset":{}} + {"add_comment":{"max":3,"target":"*"},"add_labels":{"allowed":["poetry","creative","automation","ai-generated","epic","haiku","sonnet","limerick"],"max":5},"create_issue":{"max":2},"create_pull_request":{},"create_pull_request_review_comment":{"max":2},"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{},"update_issue":{"max":2},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Create a review comment on a GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body content","type":"string"},"line":{"description":"Line number for the comment","type":["number","string"]},"path":{"description":"File path for the review comment","type":"string"},"side":{"description":"Optional side of the diff: LEFT or RIGHT","enum":["LEFT","RIGHT"],"type":"string"},"start_line":{"description":"Optional start line for multi-line comments","type":["number","string"]}},"required":["path","line","body"],"type":"object"},"name":"create_pull_request_review_comment"},{"description":"Add labels to a GitHub issue or pull request","inputSchema":{"additionalProperties":false,"properties":{"item_number":{"description":"Issue or PR number (optional for current context)","type":"number"},"labels":{"description":"Labels to add","items":{"type":"string"},"type":"array"}},"required":["labels"],"type":"object"},"name":"add_labels"},{"description":"Update a GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Optional new issue body","type":"string"},"issue_number":{"description":"Optional issue number for target '*'","type":["number","string"]},"status":{"description":"Optional new issue status","enum":["open","closed"],"type":"string"},"title":{"description":"Optional new issue title","type":"string"}},"type":"object"},"name":"update_issue"},{"description":"Push changes to a pull request branch","inputSchema":{"additionalProperties":false,"properties":{"branch":{"description":"Optional branch name. Do not provide this parameter if you want to push changes from the current branch. If not provided, the current branch will be used.","type":"string"},"message":{"description":"Commit message","type":"string"},"pull_request_number":{"description":"Optional pull request number for target '*'","type":["number","string"]}},"required":["message"],"type":"object"},"name":"push_to_pull_request_branch"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 4c9e7ef699..fb6f62225f 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -1074,7 +1074,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":3},"create_discussion":{"max":1},"create_pull_request_review_comment":{"max":10},"missing_tool":{}} + {"add_comment":{"max":3},"create_discussion":{"max":1},"create_pull_request_review_comment":{"max":10},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Create a review comment on a GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body content","type":"string"},"line":{"description":"Line number for the comment","type":["number","string"]},"path":{"description":"File path for the review comment","type":"string"},"side":{"description":"Optional side of the diff: LEFT or RIGHT","enum":["LEFT","RIGHT"],"type":"string"},"start_line":{"description":"Optional start line for multi-line comments","type":["number","string"]}},"required":["path","line","body"],"type":"object"},"name":"create_pull_request_review_comment"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index f24d76074d..8a9b351b69 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -441,7 +441,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index ab136dbac1..c2892369df 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -328,7 +328,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{},"upload_asset":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index 27d2878952..d9514909fa 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -1391,7 +1391,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1},"create_pull_request":{},"missing_tool":{}} + {"add_comment":{"max":1},"create_pull_request":{},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml index 0086529c3e..d0236c9083 100644 --- a/.github/workflows/repo-tree-map.lock.yml +++ b/.github/workflows/repo-tree-map.lock.yml @@ -259,7 +259,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index cfda9751ec..4910bfbb7b 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -306,7 +306,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml index 0b62165668..7d2f07b293 100644 --- a/.github/workflows/research.lock.yml +++ b/.github/workflows/research.lock.yml @@ -271,7 +271,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml index 30a74be84e..9aaa97b0c5 100644 --- a/.github/workflows/safe-output-health.lock.yml +++ b/.github/workflows/safe-output-health.lock.yml @@ -416,7 +416,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml index b8048e8007..3988774ebc 100644 --- a/.github/workflows/schema-consistency-checker.lock.yml +++ b/.github/workflows/schema-consistency-checker.lock.yml @@ -390,7 +390,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index 23907f0fe7..60e4ce1424 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -1484,7 +1484,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1},"missing_tool":{}} + {"add_comment":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/security-fix-pr.lock.yml b/.github/workflows/security-fix-pr.lock.yml index 048172a6c1..3c85be360c 100644 --- a/.github/workflows/security-fix-pr.lock.yml +++ b/.github/workflows/security-fix-pr.lock.yml @@ -385,7 +385,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_pull_request":{},"missing_tool":{}} + {"create_pull_request":{},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml index 7598c5619a..e2c409a3af 100644 --- a/.github/workflows/semantic-function-refactor.lock.yml +++ b/.github/workflows/semantic-function-refactor.lock.yml @@ -393,7 +393,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{}} + {"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 24a65ac3f0..de5315b261 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -378,7 +378,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{}} + {"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index 19b3b9ef92..1a7e17fbbc 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -265,7 +265,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{}} + {"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 75a132f170..18f64cc449 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -273,7 +273,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{}} + {"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/smoke-detector.lock.yml b/.github/workflows/smoke-detector.lock.yml index 248f0579b7..e0f86b94dc 100644 --- a/.github/workflows/smoke-detector.lock.yml +++ b/.github/workflows/smoke-detector.lock.yml @@ -1191,7 +1191,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1,"target":"*"},"create_issue":{"max":1},"missing_tool":{}} + {"add_comment":{"max":1,"target":"*"},"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml index efb2dee3f7..cb68ba540d 100644 --- a/.github/workflows/static-analysis-report.lock.yml +++ b/.github/workflows/static-analysis-report.lock.yml @@ -409,7 +409,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index 3d62be631c..a4d59b1f2a 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -296,7 +296,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{}} + {"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index 48183f541d..385a3e77b0 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -735,7 +735,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1},"create_pull_request":{},"missing_tool":{},"upload_asset":{}} + {"add_comment":{"max":1},"create_pull_request":{},"missing_tool":{},"noop":{"max":1},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/test-ollama-threat-detection.lock.yml b/.github/workflows/test-ollama-threat-detection.lock.yml index a3563d5574..8605044aa6 100644 --- a/.github/workflows/test-ollama-threat-detection.lock.yml +++ b/.github/workflows/test-ollama-threat-detection.lock.yml @@ -255,7 +255,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{}} + {"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index 8037e61235..7bd82c5552 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -631,7 +631,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_pull_request":{},"missing_tool":{},"push_to_pull_request_branch":{}} + {"create_pull_request":{},"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Push changes to a pull request branch","inputSchema":{"additionalProperties":false,"properties":{"branch":{"description":"Optional branch name. Do not provide this parameter if you want to push changes from the current branch. If not provided, the current branch will be used.","type":"string"},"message":{"description":"Commit message","type":"string"},"pull_request_number":{"description":"Optional pull request number for target '*'","type":["number","string"]}},"required":["message"],"type":"object"},"name":"push_to_pull_request_branch"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index 886af8173a..53de5bcfba 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -393,7 +393,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index 5eb63d3387..c14e31dacc 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -1178,7 +1178,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":1},"create_pull_request":{},"missing_tool":{},"upload_asset":{}} + {"add_comment":{"max":1},"create_pull_request":{},"missing_tool":{},"noop":{"max":1},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Add a comment to a GitHub issue, pull request, or discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Comment body/content","type":"string"},"item_number":{"description":"Issue, pull request or discussion number","type":"number"}},"required":["body","item_number"],"type":"object"},"name":"add_comment"},{"description":"Create a new GitHub pull request","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Pull request body/description","type":"string"},"branch":{"description":"Optional branch name. If not provided, the current branch will be used.","type":"string"},"labels":{"description":"Optional labels to add to the PR","items":{"type":"string"},"type":"array"},"title":{"description":"Pull request title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_pull_request"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml index eb5e0558eb..b9da591f0e 100644 --- a/.github/workflows/video-analyzer.lock.yml +++ b/.github/workflows/video-analyzer.lock.yml @@ -270,7 +270,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"max":1},"missing_tool":{}} + {"create_issue":{"max":1},"missing_tool":{},"noop":{"max":1}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub issue","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Issue body/description","type":"string"},"labels":{"description":"Issue labels","items":{"type":"string"},"type":"array"},"parent":{"description":"Parent issue number to create this issue as a sub-issue of","type":"number"},"title":{"description":"Issue title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_issue"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index 17e24dd64b..76616cf63e 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -276,7 +276,7 @@ jobs: run: | mkdir -p /tmp/gh-aw/safeoutputs cat > /tmp/gh-aw/safeoutputs/config.json << 'EOF' - {"create_discussion":{"max":1},"missing_tool":{},"upload_asset":{}} + {"create_discussion":{"max":1},"missing_tool":{},"noop":{"max":1},"upload_asset":{}} EOF cat > /tmp/gh-aw/safeoutputs/tools.json << 'EOF' [{"description":"Create a new GitHub discussion","inputSchema":{"additionalProperties":false,"properties":{"body":{"description":"Discussion body/content","type":"string"},"category":{"description":"Discussion category","type":"string"},"title":{"description":"Discussion title","type":"string"}},"required":["title","body"],"type":"object"},"name":"create_discussion"},{"description":"Publish a file as a URL-addressable asset to an orphaned git branch","inputSchema":{"additionalProperties":false,"properties":{"path":{"description":"Path to the file to publish as an asset. Must be a file under the current workspace or /tmp directory. By default, images (.png, .jpg, .jpeg) are allowed, but can be configured via workflow settings.","type":"string"}},"required":["path"],"type":"object"},"name":"upload_asset"},{"description":"Report a missing tool or functionality needed to complete tasks","inputSchema":{"additionalProperties":false,"properties":{"alternatives":{"description":"Possible alternatives or workarounds (max 256 characters)","type":"string"},"reason":{"description":"Why this tool is needed (max 256 characters)","type":"string"},"tool":{"description":"Name of the missing tool (max 128 characters)","type":"string"}},"required":["tool","reason"],"type":"object"},"name":"missing_tool"},{"description":"Log a message for transparency when no significant actions are needed. Use this to ensure workflows produce human-visible artifacts even when no other actions are taken (e.g., 'Analysis complete - no issues found').","inputSchema":{"additionalProperties":false,"properties":{"message":{"description":"Message to log for transparency","type":"string"}},"required":["message"],"type":"object"},"name":"noop"}] diff --git a/pkg/workflow/safe_outputs.go b/pkg/workflow/safe_outputs.go index 0341967594..bb29a61d3a 100644 --- a/pkg/workflow/safe_outputs.go +++ b/pkg/workflow/safe_outputs.go @@ -840,6 +840,20 @@ func generateSafeOutputsConfig(data *WorkflowData) string { } safeOutputsConfig["update_project"] = updateProjectConfig } + if data.SafeOutputs.UpdateRelease != nil { + updateReleaseConfig := map[string]any{} + if data.SafeOutputs.UpdateRelease.Max > 0 { + updateReleaseConfig["max"] = data.SafeOutputs.UpdateRelease.Max + } + safeOutputsConfig["update_release"] = updateReleaseConfig + } + if data.SafeOutputs.NoOp != nil { + noopConfig := map[string]any{} + if data.SafeOutputs.NoOp.Max > 0 { + noopConfig["max"] = data.SafeOutputs.NoOp.Max + } + safeOutputsConfig["noop"] = noopConfig + } } // Add safe-jobs configuration from SafeOutputs.Jobs @@ -943,6 +957,9 @@ func generateFilteredToolsJSON(data *WorkflowData) (string, error) { if data.SafeOutputs.MissingTool != nil { enabledTools["missing_tool"] = true } + if data.SafeOutputs.UpdateRelease != nil { + enabledTools["update_release"] = true + } if data.SafeOutputs.NoOp != nil { enabledTools["noop"] = true }