| 1 | const AGENT_EMAILS = new Set([ |
| 2 | "noreply@anthropic.com", |
| 3 | "claude@anthropic.com", |
| 4 | "noreply@openai.com", |
| 5 | "codex@openai.com", |
| 6 | "cursoragent@cursor.com", |
| 7 | "copilot@github.com", |
| 8 | "noreply@github.com", |
| 9 | ]); |
| 10 | |
| 11 | const GENERATED_BY_AGENT = |
| 12 | /^(?:🤖\s*)?generated (?:with|by)\s+(?:claude(?: code)?|codex|cursor|github copilot|copilot|opencode|grok|antigravity)[.!]?$/i; |
| 13 | |
| 14 | /** Remove standalone agent credits while keeping human signatures and quoted examples. */ |
| 15 | export function removeAgentCredits(message: string): string { |
| 16 | let fence: string | undefined; |
| 17 | let removed = false; |
| 18 | const newline = message.includes("\r\n") ? "\r\n" : "\n"; |
| 19 | const lines = message.split(/\r?\n/).filter((line) => { |
| 20 | if (/^(?: {4}|\t)/.test(line)) return true; |
| 21 | const delimiter = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line); |
| 22 | const marker = delimiter?.[1]; |
| 23 | const remainder = delimiter?.[2] ?? ""; |
| 24 | if (marker !== undefined) { |
| 25 | if (fence === undefined) { |
| 26 | if (marker[0] === "~" || !remainder.includes("`")) fence = marker; |
| 27 | } else if ( |
| 28 | marker[0] === fence[0] && |
| 29 | marker.length >= fence.length && |
| 30 | /^[ \t]*$/.test(remainder) |
| 31 | ) { |
| 32 | fence = undefined; |
| 33 | } |
| 34 | return true; |
| 35 | } |
| 36 | if (fence !== undefined) return true; |
| 37 | const text = line.trim().replace(/^(?:[-*]\s+)/, ""); |
| 38 | const author = /^co-authored-by:\s*(.*?)\s*<([^<>]+)>\s*$/i.exec(text); |
| 39 | // GitHub's generic noreply address is also used by people; require Copilot's name. |
| 40 | const email = author?.[2]?.toLowerCase(); |
| 41 | const agentAuthor = |
| 42 | email !== undefined && |
| 43 | AGENT_EMAILS.has(email) && |
| 44 | (email !== "noreply@github.com" || /^github copilot$|^copilot$/i.test(author![1]!)); |
| 45 | const footer = text.replace( |
| 46 | /\[([^\]]+)\]\(https:\/\/(?:claude\.ai|www\.anthropic\.com|chatgpt\.com|openai\.com|cursor\.com|github\.com|opencode\.ai|x\.ai|antigravity\.google)(?:\/[^\s)]*)?\)/gi, |
| 47 | "$1", |
| 48 | ); |
| 49 | if (!agentAuthor && !GENERATED_BY_AGENT.test(footer)) return true; |
| 50 | removed = true; |
| 51 | return false; |
| 52 | }); |
| 53 | return removed ? lines.join(newline).replace(/(?:\r?\n[ \t]*)+$/, "") : message; |
| 54 | } |