桌面应用AI 应用【免费下载链接】Easydict一个简洁优雅的词典翻译 macOS App。开箱即用支持离线 OCR 识别支持有道词典 苹果系统词典 苹果系统翻译OpenAIGeminiDeepLGoogleBing腾讯百度阿里小牛彩云和火山翻译。A concise and elegant Dictionary and Translator macOS App for looking up words and translating text.项目地址https://gitcode.com/gh_mirrors/ea/Easydict点击查看免费下载本文以仓库历史记录 docs/histories/2026-08/2026-08-23-pr-template-linked-issues.md 及其完整执行计划 docs/exec-plans/completed/2026-08/2026-08-23-pr-template-linked-issues.md 为核心结合仓库中实际落地的新增 PR 模板、关联 Issue 解析器、发布后跟进策略与单元测试完整还原“贡献者只写关联、发布流程定结论”的设计闭环。读完你将掌握如何设计一个不依赖 GitHub 自动关闭关键字的 PR 模板、如何在发布后脚本中以确定性方式识别并归一化多种 Issue 引用格式、以及如何用“fixes / related / rejected”三层关联模型完成版本发布后的 Issue 统一检查、通知与关闭。一、背景与目标为什么需要一个“单一关联 Issue”区域在本次变更之前仓库存在两个结构性问题没有默认 PR 模板贡献者提交 PR 时没有统一的结构指引正文中是否提及、以何种格式提及相关 Issue 完全取决于个人习惯无法区分“明确关联”与“普通弱引用”发布后跟进脚本会扫描整个 PR 正文与 commit message但“我在背景里提到某个 Issue”和“这个 PR 就是要解决某个 Issue”在机器看来没有差别容易产生错误候选。因此本次任务的目标被明确为见 执行计划在默认 PR 模板中提供单一“关联 Issue”区域并让发布 skill 将该区域中的有效同仓库引用标记为明确关联同时继续兼容旧 PR 的弱引用。两个关键设计约束贯穿始终不强制贡献者区分fixes还是related贡献者只需要在“关联 Issue”区域说明与哪些 Issue 相关最终判断由发布流程结合 PR 目标和实际改动生成明确不使用 GitHub 自动关闭能力既不用Fixes #123这类 closing keyword也不用 Development 侧栏的自动关闭关联因为 Issue 只在包含该 PR 的版本发布后统一检查、通知和关闭而不是在 PR 合并时提前关闭。从 issue-followup-policy.md 可以印证这一约束的直接后果解析器不依赖任何 closing keyword即使 PR 正文里根本没有Fixes、Closes、Resolves字样只要发布流程判定改动覆盖了 Issue 核心请求仍然可以定性为fixes。二、PR 模板设计双语结构、占位符与“无候选”保证仓库根目录的默认模板位于 .github/pull_request_template.md包含五个固定的二级区域## 背景 / Context ## 变更内容 / Changes ## 关联 Issue / Linked Issues ## 验证 / Verification ## 截图 / Screenshots其中“关联 Issue / Linked Issues”区域是本次设计的核心。模板对该区域的说明原文如下请填写与本 PR 关联的 Issue没有则留空。推荐一行一个但不强制单一格式。 支持 #issue-number、完整 Issue URL 和 owner/repo#issue-number。 请勿使用 GitHub 自动关闭关键字也不要通过 Development 侧栏建立自动关闭关联。 关联的 Issue 将在包含本 PR 的版本发布后统一检查、通知和关闭。 List issues associated with this PR, or leave this section blank. One issue per line is recommended, but no single format is required. Supported forms include #issue-number, full issue URLs, and owner/repo#issue-number. Do not use GitHub auto-closing keywords or the Development sidebar to create an auto-closing link. Associated issues will be checked, notified, and closed after a release containing this PR is published.模板设计上有三个值得注意的细节区域编号可见但格式自由推荐“一行一个”便于机器解析但不强制单一格式#123、完整 URL、owner/repo#123都允许占位符刻意使用非数字区域示例写的是#issue-number而不是#123。这一点在测试 test_release_issues.py 中被明确验证——#issue-number、https://.../issues/issue-number、owner/repo#issue-number三种占位符都不会被解析成候选引用从根本上杜绝了“模板自带假 Issue”的风险模板自身必须是“零引用”的测试 test_repository_pr_template_matches_submit_pr_structure 断言仓库模板不包含任何引用候选、恰好只有一个“关联 Issue”区域且与 agent 侧提交 PR skill 使用的模板 .agents/skills/submit-pr/assets/pull_request_template.md 的二级标题结构完全一致保证人工提 PR 与 Agent 提 PR 走同一套解析规则。三、解析器实现区域边界、三类格式与候选归一化解析逻辑集中在 .agents/skills/release-easydict/scripts/release_issues.py核心是extract_text_references及其配套的linked_issue_ranges。3.1 区域识别从标题到下一个二级标题LINKED_ISSUES_HEADING_PATTERN re.compile( r^##(?!#)[ \t] r(?:关联[ \t]*Issues?|Linked[ \t]Issues?) r(?:[ \t]*/[ \t]*(?:关联[ \t]*Issues?|Linked[ \t]Issues?))? r[ \t]*$, re.IGNORECASE | re.MULTILINE, ) SECOND_LEVEL_HEADING_PATTERN re.compile( r^##(?!#)[ \t].*$, re.MULTILINE, )对应的区域提取函数 linked_issue_ranges 会把“## 关联 Issue / Linked Issues标题之后、下一个##二级标题之前”的文本定义为显式区域。(?!#)用于排除###三级标题这正是测试用例中### Notes下方#1206仍被计入linked_issue的原因——三级标题不终结区域。3.2 三种引用格式与“占用范围”去重extract_text_references 依次扫描三种模式格式正则简化默认 kind完整 Issue URLhttps://github.com/owner/repo/issues/数字issue_url仓库编号owner/repo#数字repository_number裸编号#数字local_number三种格式的匹配结果会被记录为occupied范围后扫描的格式若与已占用范围重叠则跳过避免同一段文本被重复识别。关键逻辑在于if any(start match.start() end for start, end in explicit_ranges): kind linked_issue凡是落在显式“关联 Issue”区域内的引用无论以哪种格式书写统一升级为linked_issue——这是整个设计语义的分水岭linked_issue代表“贡献者明确声明关联”而区域外的local_number/issue_url等只是兼容旧 PR 的弱引用。区域外引用仍需在后续步骤检查是否只是编号碰撞。3.3 候选聚合多种格式只生成一个候选build_candidates 将每个 Issue 号聚合为一个候选source_prs记录所有引用过它的 PR。测试 test_linked_issue_formats_share_one_candidate 验证了同一 PR 正文中同时写#1201和完整 URLhttps://github.com/tisfeng/Easydict/issues/1201最终只生成一个candidate #1201且其引用 kind 全部为linked_issue。引用级别则通过 deduplicate_references 以(pr_number, issue_number, source, kind, reference, context)为键去重。3.4 同仓库过滤与实体解析同仓库判断使用 repository_matches 做 casefold 比较其他仓库的other/repo#99或外站 URL 会被直接丢弃。所有候选编号随后通过 GitHub Issue API 解析测试 test_extracts_existing_weak_reference_forms 同时验证了#1201、owner/repo#1254、带#issuecomment-1锚点的 URL 三种旧格式的兼容性以及外仓库引用被排除。解析时若返回实体带pull_request字段即编号碰撞到了 PR该候选被排除见 fetch_issue。四、发布后跟进策略fixes / related / rejected 三层模型候选发现只解决“可能相关”真正定性在 issue-followup-policy.md。每个候选 Issue 必须为每个引用它的 PR 记录一种关联fixesPR 的目标或实际改动解决了该 Issue。不要求出现Fixes/Closes/Resolves关键字relatedPR 与 Issue 有真实关联但只是背景、相似问题、回归来源或未实现的后续需求rejected编号碰撞、引用的是其他对象或 PR 与 Issue 没有真实关系。每条关联必须附带至少一个 GitHub URL 和简短证据说明不能只凭标题相似度建立关联。对于模板区域产生的linked_issue政策明确贡献者已声明关联、不必进一步区分fixes还是related由发布流程裁决——改动覆盖核心请求且无相反证据时用fixes明确只是背景或未实现需求时用related只有编号碰撞才用rejected。4.1 默认解决规则与反证只要本次 Release 中至少一个PR 被判为fixes该 Issue 默认resolved。以下情况都不能单独推翻默认值Issue 当前是 open、closed或曾在 PR 合并后 reopenPR 使用“防御性修复”“workaround”“难以定位根因”等措辞reporter 没有再次确认缺少自动化测试或 Agent 只有一般性不确定。只有四类明确反证才允许判为not_resolved每条反证必须记录可点击 URL 和具体说明修复合入后Issue 评论或可复现实验明确证明相同问题仍然存在PR 明确说明 Issue 的某个验收条件未实现且本版本没有其他 PR 补齐修复在发布前被 revert、禁用或从最终版本移除实际改动只解决了不同问题不能覆盖核心请求此时通常还应重查关联是否为related。测试 test_not_resolved_requires_explicit_linked_negative_evidence 验证了校验的强制性not_resolved没有反证时validate_decisions必须抛错补上“合并后复现实验证明 bug 仍在”的反证后才通过。4.2 决策结构schema-v3每个候选只生成一条决策必须覆盖全部 source PR测试 test_associations_must_cover_every_source_pr 强制这一点。仓库政策文档给出的完整示例{ issue_number: 1201, source_prs: [1212], associations: [ { pr_number: 1212, relationship: fixes, evidence: [ { url: https://github.com/tisfeng/Easydict/pull/1212, summary: The merged PR restores input focus for the reported case. } ] } ], resolution: resolved, outcome: fixed, language: zh-Hans, negative_evidence: [], reason: The released PR fixes the reported focus loss. }字段约束由 validate_decisions 执行resolution∈{resolved, not_resolved, not_applicable}outcome∈{fixed, implemented, not_applicable}用于通知文案含fixes时必须用resolved或not_resolved只有related/rejected时必须用not_applicablelanguage∈{en, zh-Hans}决定通知评论的语言决策必须与候选快照的source_sha256一致且决策集合必须恰好覆盖全部候选多了少了都报错。五、动作分类与版本通知close_and_notify / notify_only / unresolved_relatedbuild_plan 依据决策与 Issue 实时状态将每个 Issue 归入三类用户可见动作见 issue-followup-policy.md条件分类动作resolved且 Issue 当前 openclose_and_notify关闭 Issue 并发布版本通知resolved且 Issue 当前已 closednotify_only仅发布版本通知not_resolved或只有relatedunresolved_related保留开放附明确原因全部rejected仅机器审计不执行动作不进用户可见汇总关键细节版本通知带隐藏标记防重复评论marker_for 生成!-- easydict-release-notification:version:target:number --形式的 HTML 注释。测试 test_open_issue_with_existing_marker_still_needs_close 验证了一个重要语义已有标记只阻止重复评论不阻止关闭——已经开放且已解决的 Issue 即使评论过仍然要关闭PR 永不关闭没有有效关联的人工 PR 进入独立的“无关联 issue 的 PR 通知”列表只复用版本提示模板发通知测试 test_unlinked_human_pr_gets_separate_notification机器人 PR 直接忽略release_pr_policy.py 将app/dependabot、app/github-actions、dependabot[bot]、github-actions[bot]以及带is_bot标记的作者一律判为ignored不进入 changelog、候选或通知测试 test_bot_pr_is_ignored_and_recorded_for_audit通知文案区分 beta / stable 与中英文release_comment 在 beta 频道会追加“设置 → 通用开启‘包括 Beta 版本’”的指引测试 test_beta_comments_include_update_setting_in_both_languages 覆盖了中英文两种文案。汇总输出固定为四个分组空组也必须输出- 无见 render_summary关闭 issue 并已通知→仅发通知→未关闭的相关 issue→无关联 issue 的 PR 通知每个可见 Issue/PR 均使用 Markdown 链接。六、命令行工作流plan / apply / resume整套能力以 .agents/skills/release-easydict/SKILL.md 中定义的三个动作为入口详细操作见 issue-followup.mdissue-followup plan version重新收集 GitHub 证据并生成计划和固定汇总。允许写入.tmp下被忽略的本地状态不评论、不关闭任何 Issueissue-followup apply version先完整执行一次最新 plan冻结本批次后再评论和关闭用户不需要提前调用独立 plan旧的未执行计划也不能直接作为执行源issue-followup resume version复用中断apply的冻结候选和决策刷新 Issue 当前状态只重试尚未完成的远程动作。状态目录固定为.tmp/release/version/state/issue-followup/依次存放release-content.json、candidates.json、decisions.json、plan.json、summary.md、actions.json。helper 命令从仓库根目录执行完整链路如下mkdir -p .tmp/release/version/state/issue-followup # 1. 捕获已发布 Release 及 PR 条目 python3 .agents/skills/release-easydict/scripts/release_content.py capture \ --repo tisfeng/Easydict \ --version version \ --output .tmp/release/version/state/issue-followup/release-content.json # 2. 收集候选模板区域 linked_issue 旧格式兼容 .agents/skills/release-easydict/scripts/release_issues.py collect \ --repo tisfeng/Easydict \ --version version \ --content .tmp/release/version/state/issue-followup/release-content.json \ --output .tmp/release/version/state/issue-followup/candidates.json # 3. 按策略生成 decisions.json外层格式见 4.2 节 # 4. 校验决策 .agents/skills/release-easydict/scripts/release_issues.py validate \ --candidates .tmp/release/version/state/issue-followup/candidates.json \ --decisions .tmp/release/version/state/issue-followup/decisions.json # 5. 生成计划与汇总 .agents/skills/release-easydict/scripts/release_issues.py plan \ --repo tisfeng/Easydict \ --version version \ --candidates .tmp/release/version/state/issue-followup/candidates.json \ --decisions .tmp/release/version/state/issue-followup/decisions.json \ --plan .tmp/release/version/state/issue-followup/plan.json \ --summary .tmp/release/version/state/issue-followup/summary.md # 6. 预览与执行使用相同参数仅第二次追加 --execute .agents/skills/release-easydict/scripts/release_issues.py apply \ --repo tisfeng/Easydict \ --version version \ --candidates .tmp/release/version/state/issue-followup/candidates.json \ --decisions .tmp/release/version/state/issue-followup/decisions.json \ --plan .tmp/release/version/state/issue-followup/plan.json \ --summary .tmp/release/version/state/issue-followup/summary.md \ --state .tmp/release/version/state/issue-followup/actions.json补充两点执行约束频道由 GitHub Release 实际状态确定prerelease 为beta否则为stable调用方指定频道不一致必须停止apply部分失败时不回滚已发布 Release 或已完成动作而是报告“发布成功但 issue 后续处理未完成”并提示用$release-easydict issue-followup resume version恢复。七、测试与验证把解析语义固化成 24 个用例本次变更新增/更新的单元测试集中在 test_release_issues.py覆盖了模板占位符、区域边界、支持格式、候选归一化和真实模板文件五类场景见 历史记录验证项对应测试模板占位符不产生候选test_linked_issue_template_placeholder_is_not_a_reference区域边界三级标题不终结区域test_linked_issue_section_marks_supported_reference_forms三种格式统一标记 linked_issue同上旧格式兼容与同仓库过滤test_extracts_existing_weak_reference_forms同一 Issue 多格式只生成一个候选test_linked_issue_formats_share_one_candidate仓库模板与 submit-pr 模板结构一致test_repository_pr_template_matches_submit_pr_structure机器人 PR 忽略test_bot_pr_is_ignored_and_recorded_for_audit无关联人工 PR 单独通知test_unlinked_human_pr_gets_separate_notificationnot_resolved必须有反证test_not_resolved_requires_explicit_linked_negative_evidence关联必须覆盖全部 source PRtest_associations_must_cover_every_source_pr已有通知标记不阻止关闭test_open_issue_with_existing_marker_still_needs_close发布记录中的验证结论为release-easydict下 24 个 Python 单元测试全部通过release_issues.pyPython 编译检查通过skill 的quick_validate.py与git diff --check均通过本次变更未创建 PR、未修改 GitHub Release、Issue 评论或 Issue 状态仅本地实现与验证。八、受影响文件与边界根据 历史记录本次变更影响以下路径.github/pull_request_template.md新增双语默认 PR 模板.agents/skills/release-easydict/解析器、策略、测试与 skill 说明docs/agents/skills.mdAgent 技能文档同步docs/user-docs/en/GUIDE.md 与 docs/user-docs/zh/GUIDE.md中英文贡献指南同步docs/exec-plans/completed/2026-08/2026-08-23-pr-template-linked-issues.md执行计划归档。同时执行计划 明确划定了不包含的范围不修改 Issue 模板、不修改 GitHub Actions、不修改已有 PR 正文、不修改发布命令接口、不直接修改真实 GitHub Issue 状态——所有对 GitHub 的写入都严格发生在issue-followup apply/resume且版本发布验证通过之后。从源码结构看这一设计把“PR 与 Issue 的关系声明”与“版本发布后的处理决策”彻底解耦贡献者只需在 模板 的单一区域如实声明关联具体是修复、相关还是拒绝全部交由 release_pr_policy.py 与 release_issues.py 依据 PR 改动与 Issue 状态做确定性裁决并通过 schema-v3 的哈希校验、证据强约束与防重复标记保证整个跟进过程可审计、可重试、可恢复。赞分享桌面应用AI 应用【免费下载链接】Easydict一个简洁优雅的词典翻译 macOS App。开箱即用支持离线 OCR 识别支持有道词典 苹果系统词典 苹果系统翻译OpenAIGeminiDeepLGoogleBing腾讯百度阿里小牛彩云和火山翻译。A concise and elegant Dictionary and Translator macOS App for looking up words and translating text.项目地址https://gitcode.com/gh_mirrors/ea/Easydict点击查看免费下载相关推荐Easydict 发布自动化重构将发布后 Issue 跟进合并进 release-easydict SkillEasydict 发布自动化重构将发布后 Issue 跟进合并进 release easydict Skill 导读 本文介绍 Easydict 仓库中一次围桌面应用AI 应用终极免费IDM激活脚本完整指南3分钟实现永久试用期锁定终极免费IDM激活脚本完整指南3分钟实现永久试用期锁定 还在为Internet Download Manager的30天试用期到期而烦恼吗IDM激活脚本为您桌面应用AI 应用Easydict 发布后 Issue 关联与解决策略候选发现、决策校验与自动化跟进全解析Easydict 发布后 Issue 关联与解决策略候选发现、决策校验与自动化跟进全解析 本文基于 Easydict 仓库中 发布后 Issue 关联与解决策桌面应用AI 应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考