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
}