用 GitHub Copilot 扩展画布构建发布说明工作台:release-notes-showcase 插件源码解析与使用指南
【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot
导读
本篇文章以 awesome-copilot 仓库中的 release-notes-showcase 扩展为研究对象,深入讲解如何用@github/copilot-sdk构建一个"交互式发布说明画布":它能从本地 Git 历史与 GitHub 仓库数据自动生成发布说明草稿,支持在画布中预览、人工修改、按标签加载历史版本,并把同一份内容一键导出为 HTML / 纯文本邮件。读完本文,你将掌握该扩展的输入数据模型、仓库上下文探测逻辑、Git 提交分类算法、Agent 动作(Action)注册方式,以及内嵌 HTTP 服务器与画布前端如何协作,并可直接照搬这套模式构建你自己的 Copilot 扩展画布。
该图片是 extensions/release-notes-showcase/README.md 中声明的画廊预览资源(
assets/preview.png),由扩展的plugin.json注册为 Copilot 扩展展示 Logo。
功能定位与整体架构
原文档将本扩展定位为 "Interactive canvas for composing, reviewing, and exporting release notes content"(用于编写、审阅和导出发布说明内容的交互式画布)。从实现来看,它远不止一个静态预览页,而是一套完整的"发布说明生产流水线",由四个层次组成:
- SDK 注册层:extension.mjs 仅有三行核心逻辑——导入画布对象后调用
joinSession({ canvases: [releaseNotesShowcaseCanvas] })加入 Copilot 会话,声明依赖@github/copilot-sdk1.0.1(见 package.json)。 - 画布业务层:releaseNotesShowcase.mjs(约 2300 行)是绝对主体,通过
createCanvas(...)注册画布元数据、输入 Schema、两个 Agent 动作以及open/onClose生命周期回调。 - 内嵌 HTTP 服务层:
startServer()在127.0.0.1的随机端口启动 Node HTTP 服务器,对外提供 4 个 REST 端点,既服务画布前端页面,也作为 Agent 动作与前端交互的中枢。 - 发布说明领域层:包括仓库上下文探测、Git 命令封装、提交分类、GitHub REST API 拉取、邮件 HTML/纯文本渲染等纯函数集合。
这种"画布 + 本地服务 + 领域函数"的分层,是该扩展最值得借鉴的架构范式:画布 UI 只负责呈现与交互,所有数据获取、计算与导出逻辑都收敛在后端纯函数中,便于复用与测试。
安装与加载方式
该扩展随 release-notes-showcase 插件 一起分发。插件的 plugin.json(版本 1.0.2)声明了插件元数据、关键词(changelog、email-export、release-notes、contributor-callouts、launch-summary、product-updates)、Copilot 侧 Logo 资源assets/preview.png,以及指向扩展目录的引用./extensions/release-notes-showcase。
按 插件文档 与 docs/README.plugins.md 的说明,在 Copilot CLI 中安装的命令为:
copilot plugin install release-notes-showcase@awesome-copilot也可以在 VS Code 的 Extensions 搜索视图中输入@agentPlugins浏览插件,或打开命令面板执行Chat: Plugins。由于 awesome-copilot 是默认插件市场,无需额外配置即可发现该插件。安装后,在会话中打开该画布(open回调触发),扩展会解析当前会话的输入并启动本地服务,把可访问的url返回给宿主,画布随即渲染。
画布输入数据模型:一次摸清全部字段
画布在open时接收 Agent 传入的输入,其结构由releaseNotesInputSchema(releaseNotesShowcase.mjs)严格约束(additionalProperties: false,非法字段会被拒绝)。这张表是让 Agent 正确驱动画布的"协议契约":
| 字段 | 类型 | 说明 |
|---|---|---|
releaseName | string | 发布名称,默认取自仓库显示名(displayName) |
version | string | 版本号,默认vNext |
releaseDate | string | 发布日期,默认当前"月份 + 年份"(如September 2026) |
tagline | string | 一句话口号,展示在画布 Hero 区 |
summary | string | 发布摘要,同时作为邮件 preheader 的兜底值 |
emailSubject | string | 邮件主题,默认${releaseName} ${version} - release highlights |
emailPreheader | string | 邮件隐藏预读文本,缺省时回退到summary |
heroStats | array | 顶部指标卡,每项{ label, value }必填 |
sections | array | 核心板块,每项{ title, summary }必填,可附加kind(feature/improvement/quality)、metric、bullets(字符串数组) |
contributors | array | 贡献者列表,每项name必填,可附加githubHandle、avatarUrl、profileUrl、area、summary |
communityThanks | array | 社区致谢 GitHub 用户名列表,归一化时自动去除@前缀并剔除空串 |
otherChanges | array | 其他零散改动,每项text必填,可附加label |
callToAction | object | 底部按钮,{ label, url }均必填 |
buildState()(releaseNotesShowcase.mjs)对输入做防御性归一化:所有字符串经pickString()去空白并回落默认值;sections中kind非法时降级为feature,缺少title或summary的板块会被丢弃;heroStats为空时由normalizeHeroStats()依据板块与贡献者数量自动推导四张指标卡(Top features / Core improvements / Contributors / Areas touched)。这意味着 Agent 即使只给出最少的sections与contributors,画布也能呈现完整的仪表盘形态。
仓库上下文自动探测:画布"认识"当前仓库
打开画布时,resolveRepositoryContext()(releaseNotesShowcase.mjs)会尝试自动识别当前所在的 Git 仓库,按优先级依次尝试四个起点:会话工作目录(ctx.session?.workingDirectory)、从会话元数据文件(~/.copilot/session-state/<sessionId>/vscode.metadata.json或workspace.yaml)中正则提取的cwd、进程当前目录、扩展自身目录。
findRepositoryRoot()从起点逐级向上寻找含.git的目录;找到仓库根后,readRemoteOrigin()通过git config --get remote.origin.url读取远程地址,parseRepositorySlug()用正则从 HTTPS 或 SSH 格式中提取owner/repo,最后由humanizeRepoName()把my-awesome-repo之类连字符命名转成 "My Awesome Repo" 作为发布名称。若解析不到远程地址,则回退为目录名,仓库 URL 回退为通用 GitHub 主页——默认数据中heroStats的 Repository 卡与 CTA 按钮都会据此变化。
从 Git 历史自动生成发布说明草稿
画布前端面板 "Release source" 提供两种数据来源(POST /actions/load-release,mode取unreleased或tag),均由buildReleaseFromRepository()(releaseNotesShowcase.mjs)驱动:
1. 标签模式(tag)
- 用
git tag --sort=-creatordate列出全部标签(listReleaseTags()),最新标签作为默认选中项; - 选中标签后自动取其前一个标签作为基线,范围表达式为
${previousTag}..${selectedTag}(无前驱标签时退化为单个标签); - 用
git log -1 --date=short --format=%ad <tag>读取标签提交日期作为发布日期; - 用
git log --max-count=250 --pretty=format:%s%x1f%an <range>拉取最多 250 条提交(readCommitSummaries()),以单元分隔符\x1f切分 subject 与作者; - CTA 指向该标签的 Release 页面。
2. 未发布草稿模式(unreleased)
- 范围表达式为
${latestTag}..HEAD(无标签时为HEAD); - 除本地提交外,还会以最新标签日期为
since基准,调用 GitHub REST API(fetchUnreleasedGithubSignals(),releaseNotesShowcase.mjs)并行拉取最近关闭的 Pull Request(过滤merged_at在基准之后)与 Issue(过滤closed_at在基准之后且非 PR),每类最多 100 条、按更新时间倒序; - 鉴权优先读取
GITHUB_TOKEN环境变量,否则在进程环境中查找COPILOT_GH_ACCOUNT_github_2E_com_*前缀的凭据(getGitHubToken()); - CTA 指向最新标签与 HEAD 的 compare 页面。
提交分类与草稿组装
classifyCommit()(releaseNotesShowcase.mjs)用正则把提交归入三类:feature(feat/feature前缀或包含 add、introduce、support、new)、improvement(fix/perf/refactor前缀或 improv、stabil、reliab、optim)、其余归为quality。提交主题会先经cleanCommitSubject()剥掉 Conventional Commits 类型前缀和尾部的(#123)引用号,保证展示干净。
toReleaseStateFromCommits()(releaseNotesShowcase.mjs)随后组装完整发布状态:合并的 PR 生成 "Merged pull requests" 板块(最多 6 条)、按分类生成三个板块(每个最多 6 条 bullets)、贡献者按提交数降序取前 6 名(area显示提交数)、"Also in this release" 取前 7 条提交并前置最近关闭的 Issue;tagline与邮件 preheader 自动拼出 "N commits, M merged PRs, K closed issues since ..." 的统计句。若范围内没有任何提交,则退回仓库模板状态并明确提示 "No commit changes were detected"。
交互式画布界面:前端如何与后端协作
画布页面由renderHtml()(releaseNotesShowcase.mjs)生成——它是一个自包含的 HTML 文档,内联全部 CSS 与 JavaScript,按卡片式仪表盘组织:
- Hero 区:品牌标记、发布日期眉题、发布名 + 版本徽章、tagline、摘要、Top hit 头条条带,右侧是 "Release dashboard" 指标卡网格(四色轮换调色板
metricPalette); - Release source 面板:标签下拉选择器(
initReleasePicker()启动时请求GET /actions/release-options填充,默认选中最新标签)、"Load selected release" 与 "Draft unreleased" 两个按钮,点击后POST /actions/load-release并在 250ms 后刷新页面; - Top hits:按
kind着色(feature 蓝、improvement 紫、quality 橙)的板块卡片; - Also in this release:带标签徽章的改动列表;
- Contributors:头像(
avatarUrl缺失时用getInitials()生成首字母回退块)、GitHub 句柄、贡献区域与摘要;下方是 "Community thanks" 头像墙(@handle.png?size=64拉取头像); - Email export 面板:实时展示 Subject / Preheader / CTA,提供四个按钮分别"复制 HTML / 复制纯文本 / 下载 HTML / 下载纯文本",全部通过
POST /actions/export-email获取内容,下载文件名由后端fileNameBase(slug 化后的${releaseName}-${version}-release-notes-email)加.html/.txt构成。
值得注意的安全实践:所有插入模板的动态值都经escapeHtml()(releaseNotesShowcase.mjs)转义& < > " ',避免用户或提交内容中的 HTML 注入;页面还内置了 toast 提示(aria-live="polite")与按钮加载态,交互反馈完整。
Agent 动作:把导出能力接入自动化流程
画布通过actions数组向 Agent 暴露两个可编程动作(releaseNotesShowcase.mjs),使"人看画布、Agent 调动作"双向打通:
| 动作名 | 入参 | 返回 |
|---|---|---|
export_email | { format: "html" \| "text" \| "both" } | 邮件主题、preheader、文件名基础名,以及按需生成的html/text |
get_release_snapshot | 无 | 精简快照:{ title, summary, sections: [{title, kind}], contributors: [name] } |
两个动作都依赖会话实例状态:通过servers.get(ctx.instanceId)取得当前画布实例的getState(),若画布尚未打开则抛出CanvasError("canvas_state_missing", "Open the release notes canvas before exporting email content.")给出明确指引——这保证了动作与可见画布内容始终一致。
buildExportPayload()(releaseNotesShowcase.mjs)默认format为both:buildEmailHtml()输出一套完整的内联样式邮件模板(隐藏 preheader、深色渐变页眉、四宫格指标、板块徽章 + 标题 + 摘要 + 指标 + 要点、Contributors in the spotlight 卡片列表、社区致谢、CTA 圆角按钮,宽度 720px 居中);buildEmailText()输出同等信息量的纯文本版本(- 要点列表与@handle致谢格式),可直接粘贴进纯文本邮件或聊天渠道。
画布生命周期与实例管理
扩展用模块级serversMap 按instanceId管理实例(releaseNotesShowcase.mjs):
- open:重新解析仓库上下文并重建默认样本数据;
buildState(ctx.input)生成初始状态;若该实例尚无服务器则startServer()启动(随机端口,返回{ server, url, getState, setState }),否则仅更新状态;最终向宿主返回画布标题、状态文案("N contributors highlighted")与可访问 URL; - onClose:从 Map 中删除实例并
server.close()优雅关闭,避免端口泄漏; - get_release_snapshot / export_email:均从
servers.get(ctx.instanceId)读取实时状态,实现"画布所见即导出所得"。
startServer()(releaseNotesShowcase.mjs)本身是一个 Nodehttp.createServer,仅监听127.0.0.1(不回环外暴露),路由规则为:GET /返回画布 HTML、POST /actions/export-email返回导出载荷、GET /actions/release-options返回标签列表与最新标签、POST /actions/load-release校验 mode 后重建状态(非法 mode 返回 400),未知路径统一 404。前端按钮与 Agent 动作共用这套端点,职责单一、边界清晰。
仓库内相关资源导航
若要在本仓库中进一步研究该扩展的完整实现,推荐按以下路径阅读:
- 扩展说明 —— 本主题的官方入口文档;
- 核心实现 releaseNotesShowcase.mjs —— 画布注册、Schema、Git/GitHub 数据管线、HTTP 服务与邮件渲染全部集中于此;
- SDK 入口 extension.mjs 与 package.json ——
joinSession装配方式与依赖版本; - 插件清单 plugins/release-notes-showcase/plugin.json —— 插件市场元数据与扩展引用关系;
- 插件安装说明 与 插件市场总览 —— 安装命令与浏览方式;
- 画廊预览图 —— 扩展展示用截图资源。
总而言之,release-notes-showcase 是一个结构完整的 Copilot 扩展画布范例:从输入 Schema 到仓库上下文探测,从 Git 提交分类到 GitHub 数据补充,从内嵌服务到 Agent 动作,再到 HTML/纯文本邮件双格式导出,每个环节都有清晰的纯函数边界与可验证的实现。无论你是想直接用它生成发布说明,还是希望借鉴这套 "canvas + actions + local server" 模式构建自己的 Copilot 扩展,本文拆解的数据契约、命令调用链与生命周期管理都可以作为直接参考。
【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考