From 03f6c99eb97650fbf0377641a8527616a8438f29 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 04:29:41 +0000 Subject: [PATCH 1/2] Add token table rendering to core.info in parse_token_usage.cjs Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/parse_token_usage.cjs | 22 ++++++++++++++++ actions/setup/js/parse_token_usage.test.cjs | 29 +++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/actions/setup/js/parse_token_usage.cjs b/actions/setup/js/parse_token_usage.cjs index 5df4d3add1f..ecfc63577e6 100644 --- a/actions/setup/js/parse_token_usage.cjs +++ b/actions/setup/js/parse_token_usage.cjs @@ -102,6 +102,26 @@ function buildStepSummarySection(title, markdown) { return `### ${title}\n\n
\nPer-request AI credits and token totals\n\n${markdown}
\n\n`; } +/** + * Renders the token usage markdown table as plain text for core.info output. + * Strips markdown table separators, pipes, and bold markers so the table is + * readable in the raw step log. + * @param {string} title + * @param {string} markdown + * @returns {string} + */ +function renderTokenTableAsPlainText(title, markdown) { + const plainText = markdown + .replace(/^\|-+.*-+\|$/gm, "") // Remove table separator lines + .replace(/^\|/gm, "") // Remove leading pipe from table rows + .replace(/\|$/gm, "") // Remove trailing pipe from table rows + .replace(/\s*\|\s*/g, " | ") // Normalize remaining pipes to spaced separators + .replace(/\*\*(.*?)\*\*/g, "$1") // Remove bold markers + .replace(/\n{3,}/g, "\n\n") // Collapse excess blank lines + .trim(); + return `${title}\n\n${plainText}`; +} + /** * Appends the token usage section to GITHUB_STEP_SUMMARY when available. * Falls back to the Actions summary API when the summary path is unavailable. @@ -142,6 +162,7 @@ async function main() { } const markdown = generateTokenUsageSummary(summary); if (markdown.length > 0) { + core.info(renderTokenTableAsPlainText(getSummaryTitle(), markdown)); await appendStepSummarySection(getSummaryTitle(), markdown); } @@ -199,6 +220,7 @@ if (typeof module !== "undefined" && module.exports) { getSummaryTitle, buildStepSummarySection, appendStepSummarySection, + renderTokenTableAsPlainText, TOKEN_USAGE_AUDIT_PATH, TOKEN_USAGE_PATH, TOKEN_USAGE_PATHS, diff --git a/actions/setup/js/parse_token_usage.test.cjs b/actions/setup/js/parse_token_usage.test.cjs index 6cd34123cc4..0afb54b93d9 100644 --- a/actions/setup/js/parse_token_usage.test.cjs +++ b/actions/setup/js/parse_token_usage.test.cjs @@ -12,6 +12,7 @@ const { readDedupedTokenUsage, getSummaryTitle, buildStepSummarySection, + renderTokenTableAsPlainText, TOKEN_USAGE_AUDIT_PATH, TOKEN_USAGE_PATH, TOKEN_USAGE_PATHS, @@ -194,6 +195,9 @@ describe("parse_token_usage", () => { expect(mockCore.summary.addRaw).toHaveBeenCalledWith(expect.stringContaining("| Alias |"), true); expect(mockCore.summary.write).toHaveBeenCalled(); expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("Token usage summary appended")); + // Token table should also be rendered to core.info + expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("Token Usage")); + expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("Alias")); }); test("uses custom summary title when configured", async () => { @@ -536,5 +540,30 @@ describe("parse_token_usage", () => { expect(section).toContain("
"); expect(section).toContain("Per-request AI credits and token totals"); }); + + test("renderTokenTableAsPlainText strips table separator lines and pipes", () => { + const markdown = ["| # | Alias | Input | Output |", "|--:|-------|------:|-------:|", "| 1 | sonnet46 | 100 | 200 |", "| **Total** | | **100** | **200** |", "", "Legend: `Alias` is the model shorthand.", ""].join("\n"); + + const result = renderTokenTableAsPlainText("Token Usage", markdown); + + expect(result).toContain("Token Usage"); + // separator line is removed + expect(result).not.toMatch(/\|--/); + // leading/trailing pipes are stripped + expect(result).not.toMatch(/^\|/m); + expect(result).not.toMatch(/\|$/m); + // bold markers are removed + expect(result).not.toContain("**"); + // data is preserved + expect(result).toContain("sonnet46"); + expect(result).toContain("100"); + expect(result).toContain("200"); + expect(result).toContain("Legend:"); + }); + + test("renderTokenTableAsPlainText prefixes output with title", () => { + const result = renderTokenTableAsPlainText("My Token Usage", "| A |\n|---|\n| 1 |"); + expect(result.startsWith("My Token Usage")).toBe(true); + }); }); }); From 12f615757eb947f00d91bbb5b8803e4de1e9e51e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Jun 2026 05:07:02 +0000 Subject: [PATCH 2/2] Fix separator regex to handle alignment colons; strengthen test assertion Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/parse_token_usage.cjs | 2 +- actions/setup/js/parse_token_usage.test.cjs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actions/setup/js/parse_token_usage.cjs b/actions/setup/js/parse_token_usage.cjs index ecfc63577e6..cae35904ee2 100644 --- a/actions/setup/js/parse_token_usage.cjs +++ b/actions/setup/js/parse_token_usage.cjs @@ -112,7 +112,7 @@ function buildStepSummarySection(title, markdown) { */ function renderTokenTableAsPlainText(title, markdown) { const plainText = markdown - .replace(/^\|-+.*-+\|$/gm, "") // Remove table separator lines + .replace(/^\|(?:[-: ]+\|)+$/gm, "") // Remove table separator lines (handles alignment colons) .replace(/^\|/gm, "") // Remove leading pipe from table rows .replace(/\|$/gm, "") // Remove trailing pipe from table rows .replace(/\s*\|\s*/g, " | ") // Normalize remaining pipes to spaced separators diff --git a/actions/setup/js/parse_token_usage.test.cjs b/actions/setup/js/parse_token_usage.test.cjs index 0afb54b93d9..da63b8dce14 100644 --- a/actions/setup/js/parse_token_usage.test.cjs +++ b/actions/setup/js/parse_token_usage.test.cjs @@ -547,8 +547,8 @@ describe("parse_token_usage", () => { const result = renderTokenTableAsPlainText("Token Usage", markdown); expect(result).toContain("Token Usage"); - // separator line is removed - expect(result).not.toMatch(/\|--/); + // separator line is removed (no dash sequences that leak from separator rows) + expect(result).not.toMatch(/---/); // leading/trailing pipes are stripped expect(result).not.toMatch(/^\|/m); expect(result).not.toMatch(/\|$/m);