diff --git a/actions/setup/js/parse_copilot_log.cjs b/actions/setup/js/parse_copilot_log.cjs index d6c950e71ac..7289e2e6718 100644 --- a/actions/setup/js/parse_copilot_log.cjs +++ b/actions/setup/js/parse_copilot_log.cjs @@ -229,10 +229,12 @@ function parsePrettyPrintFormat(logContent) { const MODEL_BREAKDOWN_RE = /^Breakdown by AI model:/; const MODEL_LINE_RE = /^ +(\S+)\s+([\d.]+k?)\s+in,\s+([\d.]+k?)\s+out(?:,\s+([\d.]+k?)\s+cached)?/; // Recognise both legacy ("Total usage est:" / "API time spent:" / …) and the - // newer Copilot CLI footer ("Changes +N -N", "Duration Ns", "Tokens ↑N ↓N (cached)"). - // The newer footer omits a colon and uses arrow glyphs, so we extend the regex rather than - // relying on the legacy "Total …:" prefix alone. - const USAGE_LINES_RE = /^(?:Total usage est:|API time spent:|Total session time:|Total code changes:|Changes\s+[+-]?\d|Duration\s+\d|Tokens\s+[↑↓])/; + // newer Copilot CLI footer ("Changes +N -N", "Duration Ns", "Tokens ↑N ↓N (cached)", + // "Resume copilot --resume=…"). The newer footer omits a colon and uses arrow glyphs, so we + // extend the regex rather than relying on the legacy "Total …:" prefix alone. The "Resume" + // hint is matched against the exact CLI command syntax to avoid false-positives on prose + // that happens to start with "Resume ". + const USAGE_LINES_RE = /^(?:Total usage est:|API time spent:|Total session time:|Total code changes:|Changes\s+[+-]?\d|Duration\s+\d|Tokens\s+[↑↓]|Resume\s{2,}copilot\s+--resume=)/; const parseTokenCount = s => { const n = parseFloat(s); diff --git a/actions/setup/js/parse_copilot_log.test.cjs b/actions/setup/js/parse_copilot_log.test.cjs index e03da170ce8..7e3dadc86fc 100644 --- a/actions/setup/js/parse_copilot_log.test.cjs +++ b/actions/setup/js/parse_copilot_log.test.cjs @@ -392,6 +392,28 @@ describe("parse_copilot_log.cjs", () => { expect(result.markdown).toContain("375,000"); }); + it("strips the columnar 'Resume' footer hint from rendered pretty-print output", () => { + // Copilot CLI footer includes a "Resume copilot --resume=" line aligned in the + // same column block as Changes/Duration/Tokens. It is CLI chrome, not agent reasoning, + // and must not leak into the rendered reasoning/agent-text section. + const prettyLog = [ + "● Bash", + " └ ok", + "The work is done.", + "", + "Changes +0 -0", + "Duration 1m 0s", + "Tokens ↑ 195.4k (166.2k cached) • ↓ 2.9k", + "Resume copilot --resume=d21d3356-9296-4d1b-a392-49e5069e4e3f", + ].join("\n"); + + const result = parseCopilotLog(prettyLog); + + expect(result.markdown).toContain("The work is done."); + expect(result.markdown).not.toContain("--resume="); + expect(result.markdown).not.toMatch(/^Resume\s+copilot/m); + }); + it("handles the new footer without a cached segment", () => { const prettyLog = ["● Bash", " └ ok", "", "Tokens ↑ 1.2k • ↓ 50"].join("\n");