From d95d05ebe1a439913798d471983d959161603d28 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 17:40:23 +0000 Subject: [PATCH 1/3] Initial plan From 06f18431d11878babae2151758c2e9780e7a878f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 17:59:38 +0000 Subject: [PATCH 2/3] fix: avoid duplicate token usage section in MCP gateway summary Agent-Logs-Url: https://github.com/github/gh-aw/sessions/33877792-b58e-434e-b075-1cdc46ba043c Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/parse_mcp_gateway_log.cjs | 9 +-- .../setup/js/parse_mcp_gateway_log.test.cjs | 74 +++++++++++++++++++ 2 files changed, 76 insertions(+), 7 deletions(-) diff --git a/actions/setup/js/parse_mcp_gateway_log.cjs b/actions/setup/js/parse_mcp_gateway_log.cjs index aae854a8961..a4b65537c4f 100644 --- a/actions/setup/js/parse_mcp_gateway_log.cjs +++ b/actions/setup/js/parse_mcp_gateway_log.cjs @@ -167,9 +167,8 @@ function generateTokenUsageSummary(summary) { } /** - * Appends the token usage section to the step summary if data is present, then writes it. - * Also exports GH_AW_EFFECTIVE_TOKENS as a GitHub Actions environment variable so - * subsequent steps can display the ET value in generated footers. + * Writes the step summary and exports GH_AW_EFFECTIVE_TOKENS when token usage data exists. + * Token Usage rendering is handled by parse_token_usage.cjs to avoid duplicate sections. * This is the final call in each main() exit path — it consolidates the summary write * so callers don't need to chain addRaw() + write() themselves. * @param {typeof import('@actions/core')} coreObj - The GitHub Actions core object @@ -182,10 +181,6 @@ function writeStepSummaryWithTokenUsage(coreObj) { if (content?.trim()) { coreObj.info(`Found token-usage.jsonl (${content.length} bytes)`); const parsedSummary = parseTokenUsageJsonl(content); - const markdown = generateTokenUsageSummary(parsedSummary); - if (markdown.length > 0) { - coreObj.summary.addDetails("Token Usage", "\n\n" + markdown); - } // Export total effective tokens as a GitHub Actions env var for use in // generated footers (GH_AW_EFFECTIVE_TOKENS is read by messages_footer.cjs) if (parsedSummary && parsedSummary.totalEffectiveTokens > 0) { diff --git a/actions/setup/js/parse_mcp_gateway_log.test.cjs b/actions/setup/js/parse_mcp_gateway_log.test.cjs index b75a171a5b9..e7de1112a68 100644 --- a/actions/setup/js/parse_mcp_gateway_log.test.cjs +++ b/actions/setup/js/parse_mcp_gateway_log.test.cjs @@ -335,6 +335,80 @@ Some content here.`; fs.rmSync(tmpDir, { recursive: true, force: true }); } }); + + test("does not append token usage details when token usage file exists", async () => { + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-test-")); + const gatewayMdPath = path.join(tmpDir, "gateway.md"); + const tokenUsagePath = path.join(tmpDir, "token-usage.jsonl"); + + try { + fs.writeFileSync(gatewayMdPath, "# Gateway Summary\n\nSome markdown content"); + fs.writeFileSync( + tokenUsagePath, + JSON.stringify({ + model: "claude-haiku-4-5-20251001", + input_tokens: 42, + output_tokens: 2765, + cache_read_tokens: 141738, + cache_write_tokens: 38170, + duration_ms: 26500, + }) + ); + + const mockCore = { + info: vi.fn(), + debug: vi.fn(), + startGroup: vi.fn(), + endGroup: vi.fn(), + notice: vi.fn(), + warning: vi.fn(), + error: vi.fn(), + setFailed: vi.fn(), + exportVariable: vi.fn(), + setOutput: vi.fn(), + summary: { + addRaw: vi.fn().mockReturnThis(), + addDetails: vi.fn().mockReturnThis(), + write: vi.fn(), + }, + }; + + const originalExistsSync = fs.existsSync; + const originalReadFileSync = fs.readFileSync; + + fs.existsSync = vi.fn(filepath => { + if (filepath === "/tmp/gh-aw/mcp-logs/gateway.md") return true; + if (filepath === "/tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl") return true; + return originalExistsSync(filepath); + }); + + fs.readFileSync = vi.fn((filepath, encoding) => { + if (filepath === "/tmp/gh-aw/mcp-logs/gateway.md") { + return fs.readFileSync(gatewayMdPath, encoding); + } + if (filepath === "/tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl") { + return fs.readFileSync(tokenUsagePath, encoding); + } + return originalReadFileSync(filepath, encoding); + }); + + global.core = mockCore; + + const { main } = require("./parse_mcp_gateway_log.cjs"); + await main(); + + expect(mockCore.summary.addRaw).toHaveBeenCalledWith(expect.stringContaining("Gateway Summary")); + expect(mockCore.summary.addDetails).not.toHaveBeenCalledWith("Token Usage", expect.any(String)); + expect(mockCore.exportVariable).toHaveBeenCalledWith("GH_AW_EFFECTIVE_TOKENS", expect.any(String)); + expect(mockCore.summary.write).toHaveBeenCalled(); + + fs.existsSync = originalExistsSync; + fs.readFileSync = originalReadFileSync; + delete global.core; + } finally { + fs.rmSync(tmpDir, { recursive: true, force: true }); + } + }); }); describe("printAllGatewayFiles", () => { From 90162da6fce85153068b478e5b0831687213e878 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 19:32:48 +0000 Subject: [PATCH 3/3] test: fix fs mock re-entrancy and cleanup leakage in gateway parser test Agent-Logs-Url: https://github.com/github/gh-aw/sessions/957ae36f-3fbf-4138-ba0f-60599a8dff97 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/parse_mcp_gateway_log.test.cjs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/actions/setup/js/parse_mcp_gateway_log.test.cjs b/actions/setup/js/parse_mcp_gateway_log.test.cjs index e7de1112a68..8b78b176f87 100644 --- a/actions/setup/js/parse_mcp_gateway_log.test.cjs +++ b/actions/setup/js/parse_mcp_gateway_log.test.cjs @@ -340,6 +340,8 @@ Some content here.`; const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-test-")); const gatewayMdPath = path.join(tmpDir, "gateway.md"); const tokenUsagePath = path.join(tmpDir, "token-usage.jsonl"); + const originalExistsSync = fs.existsSync; + const originalReadFileSync = fs.readFileSync; try { fs.writeFileSync(gatewayMdPath, "# Gateway Summary\n\nSome markdown content"); @@ -373,9 +375,6 @@ Some content here.`; }, }; - const originalExistsSync = fs.existsSync; - const originalReadFileSync = fs.readFileSync; - fs.existsSync = vi.fn(filepath => { if (filepath === "/tmp/gh-aw/mcp-logs/gateway.md") return true; if (filepath === "/tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl") return true; @@ -384,10 +383,10 @@ Some content here.`; fs.readFileSync = vi.fn((filepath, encoding) => { if (filepath === "/tmp/gh-aw/mcp-logs/gateway.md") { - return fs.readFileSync(gatewayMdPath, encoding); + return originalReadFileSync(gatewayMdPath, encoding); } if (filepath === "/tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl") { - return fs.readFileSync(tokenUsagePath, encoding); + return originalReadFileSync(tokenUsagePath, encoding); } return originalReadFileSync(filepath, encoding); }); @@ -401,11 +400,10 @@ Some content here.`; expect(mockCore.summary.addDetails).not.toHaveBeenCalledWith("Token Usage", expect.any(String)); expect(mockCore.exportVariable).toHaveBeenCalledWith("GH_AW_EFFECTIVE_TOKENS", expect.any(String)); expect(mockCore.summary.write).toHaveBeenCalled(); - + } finally { fs.existsSync = originalExistsSync; fs.readFileSync = originalReadFileSync; delete global.core; - } finally { fs.rmSync(tmpDir, { recursive: true, force: true }); } });