From acb9edb0da2a598bce489a3be05eb6ba149b0aae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 12:28:03 +0000 Subject: [PATCH 1/5] Initial plan From a1cb7b180cf1ba755d2119295bee30bef10fb834 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 12:38:25 +0000 Subject: [PATCH 2/5] Plan: Add temporary ID support to assign_milestone safe output Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 4e7e9a0d876..0baf5dc664f 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( charm.land/bubbletea/v2 v2.0.2 charm.land/lipgloss/v2 v2.0.2 github.com/charmbracelet/huh v0.8.0 + github.com/charmbracelet/lipgloss v1.1.1-0.20250319133953-166f707985bc github.com/charmbracelet/x/exp/golden v0.0.0-20251215102626-e0db08df7383 github.com/cli/go-gh/v2 v2.13.0 github.com/creack/pty v1.1.24 @@ -42,7 +43,6 @@ require ( github.com/charmbracelet/bubbletea v1.3.10 // indirect github.com/charmbracelet/colorprofile v0.4.2 // indirect github.com/charmbracelet/harmonica v0.2.0 // indirect - github.com/charmbracelet/lipgloss v1.1.1-0.20250319133953-166f707985bc // indirect github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 // indirect github.com/charmbracelet/x/ansi v0.11.6 // indirect github.com/charmbracelet/x/cellbuf v0.0.15 // indirect From f5903d9af4ba4e5a1d74d175c2dc6a87345d5f2c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 12:47:36 +0000 Subject: [PATCH 3/5] feat: add temporary ID support to assign_milestone safe output Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_milestone.cjs | 36 ++++++++++++++-- actions/setup/js/assign_milestone.test.cjs | 41 +++++++++++++++++++ actions/setup/js/safe_outputs_tools.json | 2 +- pkg/workflow/js/safe_outputs_tools.json | 2 +- .../safe_outputs_validation_config.go | 2 +- 5 files changed, 77 insertions(+), 6 deletions(-) diff --git a/actions/setup/js/assign_milestone.cjs b/actions/setup/js/assign_milestone.cjs index b10b7c3c960..42482c3d2ea 100644 --- a/actions/setup/js/assign_milestone.cjs +++ b/actions/setup/js/assign_milestone.cjs @@ -8,6 +8,7 @@ const { getErrorMessage } = require("./error_helpers.cjs"); const { logStagedPreviewInfo } = require("./staged_preview.cjs"); const { createAuthenticatedGitHubClient } = require("./handler_auth.cjs"); +const { resolveRepoIssueTarget } = require("./temporary_id.cjs"); /** @type {string} Safe output type handled by this module */ const HANDLER_TYPE = "assign_milestone"; @@ -37,6 +38,9 @@ async function main(config = {}) { // Cache milestones to avoid fetching multiple times let allMilestones = null; + // Map of temporary IDs resolved so far (accumulated across handler calls) + const temporaryIdMap = new Map(); + /** * Message handler function that processes a single assign_milestone message * @param {Object} message - The assign_milestone message to process @@ -55,12 +59,31 @@ async function main(config = {}) { processedCount++; + // Merge resolved temporary IDs from the handler manager into our local map + if (resolvedTemporaryIds) { + for (const [tempId, resolved] of Object.entries(resolvedTemporaryIds)) { + if (!temporaryIdMap.has(tempId)) { + temporaryIdMap.set(tempId, resolved); + } + } + } + const item = message; - const issueNumber = Number(item.issue_number); - const milestoneNumber = Number(item.milestone_number); + // Resolve issue_number, which may be a temporary ID (e.g. "aw_abc123") or a plain number + const resolvedIssueTarget = resolveRepoIssueTarget(item.issue_number, temporaryIdMap, context.repo.owner, context.repo.repo); + + // If the issue_number is a temporary ID that hasn't been resolved yet, defer processing + if (resolvedIssueTarget.wasTemporaryId && !resolvedIssueTarget.resolved) { + core.info(`Deferring assign_milestone: unresolved temporary ID (${item.issue_number})`); + return { + success: false, + deferred: true, + error: resolvedIssueTarget.errorMessage || `Unresolved temporary ID: ${item.issue_number}`, + }; + } - if (isNaN(issueNumber) || issueNumber <= 0) { + if (resolvedIssueTarget.errorMessage || !resolvedIssueTarget.resolved) { core.error(`Invalid issue_number: ${item.issue_number}`); return { success: false, @@ -68,6 +91,13 @@ async function main(config = {}) { }; } + const issueNumber = resolvedIssueTarget.resolved.number; + if (resolvedIssueTarget.wasTemporaryId) { + core.info(`Resolved temporary ID '${item.issue_number}' to issue #${issueNumber}`); + } + + const milestoneNumber = Number(item.milestone_number); + if (isNaN(milestoneNumber) || milestoneNumber <= 0) { core.error(`Invalid milestone_number: ${item.milestone_number}`); return { diff --git a/actions/setup/js/assign_milestone.test.cjs b/actions/setup/js/assign_milestone.test.cjs index 2a05d251c9d..2545aa2b74b 100644 --- a/actions/setup/js/assign_milestone.test.cjs +++ b/actions/setup/js/assign_milestone.test.cjs @@ -209,4 +209,45 @@ describe("assign_milestone (Handler Factory Architecture)", () => { expect(result.success).toBe(false); expect(result.error).toContain("Invalid milestone_number"); }); + + it("should resolve a temporary ID for issue_number", async () => { + mockGithub.rest.issues.update.mockResolvedValue({}); + + const message = { + type: "assign_milestone", + issue_number: "aw_abc123", + milestone_number: 5, + }; + + const resolvedTemporaryIds = { + aw_abc123: { repo: "test-owner/test-repo", number: 42 }, + }; + + const result = await handler(message, resolvedTemporaryIds); + + expect(result.success).toBe(true); + expect(result.issue_number).toBe(42); + expect(result.milestone_number).toBe(5); + expect(mockGithub.rest.issues.update).toHaveBeenCalledWith({ + owner: "test-owner", + repo: "test-repo", + issue_number: 42, + milestone: 5, + }); + }); + + it("should defer when temporary ID is not yet resolved", async () => { + const message = { + type: "assign_milestone", + issue_number: "aw_pending1", + milestone_number: 5, + }; + + // No resolved temporary IDs provided + const result = await handler(message, {}); + + expect(result.success).toBe(false); + expect(result.deferred).toBe(true); + expect(mockGithub.rest.issues.update).not.toHaveBeenCalled(); + }); }); diff --git a/actions/setup/js/safe_outputs_tools.json b/actions/setup/js/safe_outputs_tools.json index d3ca5669257..b907d4e37b9 100644 --- a/actions/setup/js/safe_outputs_tools.json +++ b/actions/setup/js/safe_outputs_tools.json @@ -567,7 +567,7 @@ "properties": { "issue_number": { "type": ["number", "string"], - "description": "Issue number to assign to the milestone. This is the numeric ID from the GitHub URL (e.g., 567 in github.com/owner/repo/issues/567)." + "description": "Issue number to assign to the milestone. This is the numeric ID from the GitHub URL (e.g., 567 in github.com/owner/repo/issues/567). Can also be a temporary_id (e.g., 'aw_abc123') from a previously created issue in the same workflow run." }, "milestone_number": { "type": ["number", "string"], diff --git a/pkg/workflow/js/safe_outputs_tools.json b/pkg/workflow/js/safe_outputs_tools.json index 6523fa8349c..6c79e6d4d40 100644 --- a/pkg/workflow/js/safe_outputs_tools.json +++ b/pkg/workflow/js/safe_outputs_tools.json @@ -663,7 +663,7 @@ "number", "string" ], - "description": "Issue number to assign to the milestone. This is the numeric ID from the GitHub URL (e.g., 567 in github.com/owner/repo/issues/567)." + "description": "Issue number to assign to the milestone. This is the numeric ID from the GitHub URL (e.g., 567 in github.com/owner/repo/issues/567). Can also be a temporary_id (e.g., 'aw_abc123') from a previously created issue in the same workflow run." }, "milestone_number": { "type": [ diff --git a/pkg/workflow/safe_outputs_validation_config.go b/pkg/workflow/safe_outputs_validation_config.go index 86ad14581fb..30342a63a44 100644 --- a/pkg/workflow/safe_outputs_validation_config.go +++ b/pkg/workflow/safe_outputs_validation_config.go @@ -99,7 +99,7 @@ var ValidationConfig = map[string]TypeValidationConfig{ "assign_milestone": { DefaultMax: 1, Fields: map[string]FieldValidation{ - "issue_number": {IssueOrPRNumber: true}, + "issue_number": {IssueNumberOrTemporaryID: true}, "milestone_number": {Required: true, PositiveInteger: true}, "repo": {Type: "string", MaxLength: 256}, // Optional: target repository in format "owner/repo" }, From 23fe2f7407fda081661b4b612246413215b46f59 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 14:33:04 +0000 Subject: [PATCH 4/5] refactor: use loadTemporaryIdMapFromResolved in assign_milestone handler Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_milestone.cjs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/actions/setup/js/assign_milestone.cjs b/actions/setup/js/assign_milestone.cjs index 42482c3d2ea..f35178b07a9 100644 --- a/actions/setup/js/assign_milestone.cjs +++ b/actions/setup/js/assign_milestone.cjs @@ -8,7 +8,7 @@ const { getErrorMessage } = require("./error_helpers.cjs"); const { logStagedPreviewInfo } = require("./staged_preview.cjs"); const { createAuthenticatedGitHubClient } = require("./handler_auth.cjs"); -const { resolveRepoIssueTarget } = require("./temporary_id.cjs"); +const { loadTemporaryIdMapFromResolved, resolveRepoIssueTarget } = require("./temporary_id.cjs"); /** @type {string} Safe output type handled by this module */ const HANDLER_TYPE = "assign_milestone"; @@ -38,9 +38,6 @@ async function main(config = {}) { // Cache milestones to avoid fetching multiple times let allMilestones = null; - // Map of temporary IDs resolved so far (accumulated across handler calls) - const temporaryIdMap = new Map(); - /** * Message handler function that processes a single assign_milestone message * @param {Object} message - The assign_milestone message to process @@ -59,17 +56,11 @@ async function main(config = {}) { processedCount++; - // Merge resolved temporary IDs from the handler manager into our local map - if (resolvedTemporaryIds) { - for (const [tempId, resolved] of Object.entries(resolvedTemporaryIds)) { - if (!temporaryIdMap.has(tempId)) { - temporaryIdMap.set(tempId, resolved); - } - } - } - const item = message; + // Convert resolvedTemporaryIds to a normalized Map for resolveRepoIssueTarget + const temporaryIdMap = loadTemporaryIdMapFromResolved(resolvedTemporaryIds); + // Resolve issue_number, which may be a temporary ID (e.g. "aw_abc123") or a plain number const resolvedIssueTarget = resolveRepoIssueTarget(item.issue_number, temporaryIdMap, context.repo.owner, context.repo.repo); From f83ccf564a3bffe8f2fea6ba06b1813b2886134d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Mar 2026 15:34:29 +0000 Subject: [PATCH 5/5] fix: merge main and update wasm golden files to fix CI test failures Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../TestWasmGolden_CompileFixtures/basic-copilot.golden | 2 ++ .../TestWasmGolden_CompileFixtures/smoke-copilot.golden | 2 ++ .../TestWasmGolden_CompileFixtures/with-imports.golden | 2 ++ 3 files changed, 6 insertions(+) diff --git a/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/basic-copilot.golden b/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/basic-copilot.golden index 9941798c1f8..b94e8647f84 100644 --- a/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/basic-copilot.golden +++ b/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/basic-copilot.golden @@ -54,6 +54,8 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); await main(core, context); - name: Validate COPILOT_GITHUB_TOKEN secret diff --git a/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/smoke-copilot.golden b/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/smoke-copilot.golden index 51a6929101f..319f7225f14 100644 --- a/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/smoke-copilot.golden +++ b/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/smoke-copilot.golden @@ -68,6 +68,8 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); await main(core, context); - name: Validate COPILOT_GITHUB_TOKEN secret diff --git a/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/with-imports.golden b/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/with-imports.golden index 3bc88456e4d..5ba4435f829 100644 --- a/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/with-imports.golden +++ b/pkg/workflow/testdata/wasm_golden/TestWasmGolden_CompileFixtures/with-imports.golden @@ -54,6 +54,8 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | + const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs'); await main(core, context); - name: Validate COPILOT_GITHUB_TOKEN secret