diff --git a/src/__tests__/prompts.test.ts b/src/__tests__/prompts.test.ts index b2ec7d4..d7263f1 100644 --- a/src/__tests__/prompts.test.ts +++ b/src/__tests__/prompts.test.ts @@ -35,7 +35,7 @@ describe("formatItem", () => { expect(result).toContain("作者: @alice"); expect(result).toContain("评论: 5"); expect(result).toContain("👍: 3"); - expect(result).toContain("链接: https://github.com/org/repo/issues/1"); + expect(result).toContain("链接: org/repo Issue #1"); expect(result).toContain("摘要: Some body text"); }); diff --git a/src/github.ts b/src/github.ts index 35c4bde..40f41ad 100644 --- a/src/github.ts +++ b/src/github.ts @@ -184,8 +184,18 @@ export async function fetchSkillsData(repo: string): Promise<{ prs: GitHubItem[] const GITHUB_ISSUE_BODY_LIMIT = 65536; const TRUNCATION_NOTICE = "\n\n---\n> ⚠️ 内容超过 GitHub Issue 上限,完整报告见提交的 Markdown 文件。"; +/** + * Break GitHub URLs in issue body to prevent cross-repository references. + * Inserts a zero-width space in "github.com" so GitHub's auto-linker + * won't create "mentioned this issue" notifications on external repos. + */ +function neutralizeGitHubRefs(text: string): string { + return text.replace(/https:\/\/github\.com\//g, "https://github\u200B.com/"); +} + export async function createGitHubIssue(title: string, body: string, label: string): Promise { const digestRepo = process.env["DIGEST_REPO"] ?? ""; + body = neutralizeGitHubRefs(body); if (body.length > GITHUB_ISSUE_BODY_LIMIT) { body = body.slice(0, GITHUB_ISSUE_BODY_LIMIT - TRUNCATION_NOTICE.length) + TRUNCATION_NOTICE; } diff --git a/src/prompts.ts b/src/prompts.ts index d55f778..507ae97 100644 --- a/src/prompts.ts +++ b/src/prompts.ts @@ -39,10 +39,14 @@ export function formatItem(item: GitHubItem, lang: "zh" | "en" = "zh"): string { summary: "Summary", } : { author: "作者", created: "创建", updated: "更新", comments: "评论", url: "链接", summary: "摘要" }; + // Extract "owner/repo" from html_url to avoid full GitHub URLs that trigger cross-references + const repoSlug = item.html_url.replace(/^https:\/\/github\.com\//, "").replace(/\/(issues|pull)\/\d+$/, ""); + const itemKind = item.html_url.includes("/pull/") ? "PR" : "Issue"; + const refStr = `${repoSlug} ${itemKind} #${item.number}`; return [ `#${item.number} [${item.state.toUpperCase()}]${labelStr} ${item.title}`, ` ${t.author}: @${item.user.login} | ${t.created}: ${item.created_at.slice(0, 10)} | ${t.updated}: ${item.updated_at.slice(0, 10)} | ${t.comments}: ${item.comments} | 👍: ${item.reactions?.["+1"] ?? 0}`, - ` ${t.url}: ${item.html_url}`, + ` ${t.url}: ${refStr}`, ` ${t.summary}: ${body}${ellipsis}`, ].join("\n"); }