From df7acde0efa06a272a496c554ffe0712ed2beeb4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Apr 2026 19:10:36 +0000 Subject: [PATCH 1/4] Initial plan From 81b305d2d6e4b29267d9e34f06e4cedad1027a27 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Apr 2026 19:19:37 +0000 Subject: [PATCH 2/4] fix: resolve #temporary_id references in dispatch_workflow inputs before dispatching Agent-Logs-Url: https://github.com/github/gh-aw/sessions/91f6e2a0-d8c5-43ae-a2b9-b8760ef6161d Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/dispatch_workflow.cjs | 32 +++- actions/setup/js/dispatch_workflow.test.cjs | 171 ++++++++++++++++++++ 2 files changed, 200 insertions(+), 3 deletions(-) diff --git a/actions/setup/js/dispatch_workflow.cjs b/actions/setup/js/dispatch_workflow.cjs index 27d54615690..74485dfd8e5 100644 --- a/actions/setup/js/dispatch_workflow.cjs +++ b/actions/setup/js/dispatch_workflow.cjs @@ -14,6 +14,7 @@ const { resolveTargetRepoConfig, parseRepoSlug, validateTargetRepo } = require(" const { logStagedPreviewInfo } = require("./staged_preview.cjs"); const { isStagedMode } = require("./safe_output_helpers.cjs"); const { buildAwContext } = require("./aw_context.cjs"); +const { loadTemporaryIdMapFromResolved, resolveNumberFromTemporaryId, replaceTemporaryIdReferences } = require("./temporary_id.cjs"); /** * Main handler factory for dispatch_workflow @@ -175,18 +176,43 @@ async function main(config = {}) { core.info(`Dispatching workflow: ${workflowName}`); // Prepare inputs - convert all values to strings as required by workflow_dispatch + // and resolve any #temporary_id references before dispatching /** @type {Record} */ const inputs = {}; if (message.inputs && typeof message.inputs === "object") { + // Build a Map from resolvedTemporaryIds for use with replaceTemporaryIdReferences + const temporaryIdMap = loadTemporaryIdMapFromResolved(resolvedTemporaryIds); + for (const [key, value] of Object.entries(message.inputs)) { // Convert value to string + let strValue; if (value === null || value === undefined) { - inputs[key] = ""; + strValue = ""; } else if (typeof value === "object") { - inputs[key] = JSON.stringify(value); + strValue = JSON.stringify(value); } else { - inputs[key] = String(value); + strValue = String(value); + } + + // Resolve temporary ID references in string input values. + // If the entire value is a pure temporary ID (e.g. "#aw_slosync"), resolve it + // to just the issue number so the dispatched workflow receives the real value. + // For text values with embedded references (e.g. "See #aw_xxx"), replace each + // reference with its cross-repository link (owner/repo#number). + if (strValue !== "") { + const pureIdResult = resolveNumberFromTemporaryId(strValue, resolvedTemporaryIds); + if (pureIdResult.wasTemporaryId) { + if (pureIdResult.errorMessage) { + core.warning(`Unresolved temporary ID in input "${key}": ${pureIdResult.errorMessage}`); + } else { + strValue = String(pureIdResult.resolved); + } + } else if (temporaryIdMap.size > 0) { + strValue = replaceTemporaryIdReferences(strValue, temporaryIdMap, resolvedRepoSlug); + } } + + inputs[key] = strValue; } } diff --git a/actions/setup/js/dispatch_workflow.test.cjs b/actions/setup/js/dispatch_workflow.test.cjs index 55d3f555c86..8123367bc60 100644 --- a/actions/setup/js/dispatch_workflow.test.cjs +++ b/actions/setup/js/dispatch_workflow.test.cjs @@ -860,4 +860,175 @@ describe("dispatch_workflow handler factory", () => { }) ); }); + + describe("temporary ID resolution in inputs", () => { + const baseConfig = { + workflows: ["create-pr"], + workflow_files: { "create-pr": ".lock.yml" }, + }; + + it("should resolve a pure temporary ID input value to the issue number", async () => { + const handler = await main(baseConfig); + + const resolvedTemporaryIds = { + aw_slosync: { repo: "test-owner/test-repo", number: 6499 }, + }; + + const message = { + type: "dispatch_workflow", + workflow_name: "create-pr", + inputs: { + issue_number: "#aw_slosync", + }, + }; + + const result = await handler(message, resolvedTemporaryIds); + + expect(result.success).toBe(true); + expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith( + expect.objectContaining({ + inputs: expect.objectContaining({ + issue_number: "6499", + }), + }) + ); + }); + + it("should resolve temporary ID without hash prefix", async () => { + const handler = await main(baseConfig); + + const resolvedTemporaryIds = { + aw_myissue: { repo: "test-owner/test-repo", number: 42 }, + }; + + const message = { + type: "dispatch_workflow", + workflow_name: "create-pr", + inputs: { + item_number: "aw_myissue", + }, + }; + + const result = await handler(message, resolvedTemporaryIds); + + expect(result.success).toBe(true); + expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith( + expect.objectContaining({ + inputs: expect.objectContaining({ + item_number: "42", + }), + }) + ); + }); + + it("should replace embedded temporary ID references in text input values", async () => { + const handler = await main(baseConfig); + + const resolvedTemporaryIds = { + aw_track: { repo: "test-owner/test-repo", number: 100 }, + }; + + const message = { + type: "dispatch_workflow", + workflow_name: "create-pr", + inputs: { + description: "Tracking issue is #aw_track", + }, + }; + + const result = await handler(message, resolvedTemporaryIds); + + expect(result.success).toBe(true); + const callArgs = github.rest.actions.createWorkflowDispatch.mock.calls[0][0]; + // Embedded references are replaced with cross-reference format (e.g. #100 or owner/repo#100) + expect(callArgs.inputs.description).toContain("100"); + expect(callArgs.inputs.description).not.toContain("#aw_track"); + }); + + it("should warn and keep original value when temporary ID is unresolved", async () => { + const handler = await main(baseConfig); + + const message = { + type: "dispatch_workflow", + workflow_name: "create-pr", + inputs: { + issue_number: "#aw_missing", + }, + }; + + const result = await handler(message, {}); + + expect(result.success).toBe(true); + expect(core.warning).toHaveBeenCalledWith(expect.stringContaining("aw_missing")); + // Original value kept when unresolved + expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith( + expect.objectContaining({ + inputs: expect.objectContaining({ + issue_number: "#aw_missing", + }), + }) + ); + }); + + it("should leave non-temporary-ID values unchanged", async () => { + const handler = await main(baseConfig); + + const resolvedTemporaryIds = { + aw_slosync: { repo: "test-owner/test-repo", number: 6499 }, + }; + + const message = { + type: "dispatch_workflow", + workflow_name: "create-pr", + inputs: { + issue_number: "123", + label: "bug", + count: 5, + }, + }; + + const result = await handler(message, resolvedTemporaryIds); + + expect(result.success).toBe(true); + expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith( + expect.objectContaining({ + inputs: expect.objectContaining({ + issue_number: "123", + label: "bug", + count: "5", + }), + }) + ); + }); + + it("should handle multiple temporary ID inputs in a single dispatch", async () => { + const handler = await main(baseConfig); + + const resolvedTemporaryIds = { + aw_issue1: { repo: "test-owner/test-repo", number: 10 }, + aw_issue2: { repo: "test-owner/test-repo", number: 20 }, + }; + + const message = { + type: "dispatch_workflow", + workflow_name: "create-pr", + inputs: { + parent_issue: "#aw_issue1", + child_issue: "#aw_issue2", + }, + }; + + const result = await handler(message, resolvedTemporaryIds); + + expect(result.success).toBe(true); + expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith( + expect.objectContaining({ + inputs: expect.objectContaining({ + parent_issue: "10", + child_issue: "20", + }), + }) + ); + }); + }); }); From 8df1ed892411af51543069edab29587572c2b034 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Apr 2026 21:19:48 +0000 Subject: [PATCH 3/4] fix: use resolveIssueNumber for cross-repo temp ID awareness in dispatch_workflow inputs Agent-Logs-Url: https://github.com/github/gh-aw/sessions/71ad961b-3ecc-4a79-aa5d-48afa6f3725a Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/dispatch_workflow.cjs | 12 +++++--- actions/setup/js/dispatch_workflow.test.cjs | 32 +++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/actions/setup/js/dispatch_workflow.cjs b/actions/setup/js/dispatch_workflow.cjs index 74485dfd8e5..8f260b97921 100644 --- a/actions/setup/js/dispatch_workflow.cjs +++ b/actions/setup/js/dispatch_workflow.cjs @@ -14,7 +14,7 @@ const { resolveTargetRepoConfig, parseRepoSlug, validateTargetRepo } = require(" const { logStagedPreviewInfo } = require("./staged_preview.cjs"); const { isStagedMode } = require("./safe_output_helpers.cjs"); const { buildAwContext } = require("./aw_context.cjs"); -const { loadTemporaryIdMapFromResolved, resolveNumberFromTemporaryId, replaceTemporaryIdReferences } = require("./temporary_id.cjs"); +const { loadTemporaryIdMapFromResolved, resolveIssueNumber, replaceTemporaryIdReferences } = require("./temporary_id.cjs"); /** * Main handler factory for dispatch_workflow @@ -196,16 +196,20 @@ async function main(config = {}) { // Resolve temporary ID references in string input values. // If the entire value is a pure temporary ID (e.g. "#aw_slosync"), resolve it - // to just the issue number so the dispatched workflow receives the real value. + // using the full temporaryIdMap (which retains repo context) so we can emit + // just the number for same-repo targets and "owner/repo#number" for cross-repo, + // consistent with how replaceTemporaryIdReferences handles embedded references. // For text values with embedded references (e.g. "See #aw_xxx"), replace each // reference with its cross-repository link (owner/repo#number). if (strValue !== "") { - const pureIdResult = resolveNumberFromTemporaryId(strValue, resolvedTemporaryIds); + const pureIdResult = resolveIssueNumber(strValue, temporaryIdMap); if (pureIdResult.wasTemporaryId) { if (pureIdResult.errorMessage) { core.warning(`Unresolved temporary ID in input "${key}": ${pureIdResult.errorMessage}`); + } else if (pureIdResult.resolved.repo === resolvedRepoSlug) { + strValue = String(pureIdResult.resolved.number); } else { - strValue = String(pureIdResult.resolved); + strValue = `${pureIdResult.resolved.repo}#${pureIdResult.resolved.number}`; } } else if (temporaryIdMap.size > 0) { strValue = replaceTemporaryIdReferences(strValue, temporaryIdMap, resolvedRepoSlug); diff --git a/actions/setup/js/dispatch_workflow.test.cjs b/actions/setup/js/dispatch_workflow.test.cjs index 8123367bc60..ea69e3f5907 100644 --- a/actions/setup/js/dispatch_workflow.test.cjs +++ b/actions/setup/js/dispatch_workflow.test.cjs @@ -1030,5 +1030,37 @@ describe("dispatch_workflow handler factory", () => { }) ); }); + + it("should use owner/repo#number format when pure temporary ID resolves to a different repo", async () => { + // The dispatch target is the context repo (test-owner/test-repo). + // The temp ID was created in a different repo. The resolved value should carry + // full cross-repo reference so the dispatched workflow knows which repo the + // issue belongs to, rather than silently passing a bare number that would be + // misinterpreted as an issue in the dispatch-target repo. + const handler = await main(baseConfig); + + const resolvedTemporaryIds = { + aw_crossrepo: { repo: "other-org/other-repo", number: 999 }, + }; + + const message = { + type: "dispatch_workflow", + workflow_name: "create-pr", + inputs: { + tracking_issue: "#aw_crossrepo", + }, + }; + + const result = await handler(message, resolvedTemporaryIds); + + expect(result.success).toBe(true); + expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith( + expect.objectContaining({ + inputs: expect.objectContaining({ + tracking_issue: "other-org/other-repo#999", + }), + }) + ); + }); }); }); From a5b62b814c0e2bf0ec366771d26a92c841459d10 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Apr 2026 21:38:39 +0000 Subject: [PATCH 4/4] fix: add null guard for pureIdResult.resolved to satisfy TypeScript typecheck Agent-Logs-Url: https://github.com/github/gh-aw/sessions/ed0f0f52-0bb9-495a-87c4-2aba43154618 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/dispatch_workflow.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/setup/js/dispatch_workflow.cjs b/actions/setup/js/dispatch_workflow.cjs index 8f260b97921..5d1d52c5269 100644 --- a/actions/setup/js/dispatch_workflow.cjs +++ b/actions/setup/js/dispatch_workflow.cjs @@ -204,7 +204,7 @@ async function main(config = {}) { if (strValue !== "") { const pureIdResult = resolveIssueNumber(strValue, temporaryIdMap); if (pureIdResult.wasTemporaryId) { - if (pureIdResult.errorMessage) { + if (pureIdResult.errorMessage || !pureIdResult.resolved) { core.warning(`Unresolved temporary ID in input "${key}": ${pureIdResult.errorMessage}`); } else if (pureIdResult.resolved.repo === resolvedRepoSlug) { strValue = String(pureIdResult.resolved.number);