VS Code Copilot 扩展中 @github/copilot SDK 升级实战:github-copilot-upgrader 技能驱动的完整升级流程
在 VS Code 的 Copilot Chat 扩展(extensions/copilot)中,核心 Agent 能力由 npm 包 @github/copilot(即 Copilot CLI SDK)提供,这个依赖会持续演进,升级它往往牵动类型定义、原生二进制布局和多处调用方代码。本文以仓库中的 Agent 技能文件 SKILL.md 为主体,完整还原其定义的“快照类型定义 → 升级包 → 对比 API 差异 → 编译修复测试循环 → 输出升级报告”流程,并结合 package.json 中的脚本定义与 postinstall.ts 的实现细节,讲清每一步背后为什么这样做。读完本文,你可以按一套可复制的清单完成 SDK 升级,并理解升级后如何验证类型变化与原生二进制清单的完整性。
一、技能文件是什么:一个给编码 Agent 的“升级操作手册”
SKILL.md 位于 extensions/copilot/.agents/skills/github-copilot-upgrader/ 目录下,是一个典型的 Agent 技能(Skill)定义文件。它的 frontmatter 声明了三个元数据:
---
name: github-copilot-upgrader
description: Use this to update the Github Copilot CLI/SDK
model: Claude Opus 4.6
---
即:技能名为 github-copilot-upgrader,用途是“升级 vscode-copilot-chat 项目中的 @github/copilot 包”,并指定了执行该技能的模型。同目录下还有一个姊妹技能 launch/SKILL.md(用 @playwright/cli 通过 CDP 自动化操作 VS Code 界面),两者构成该仓库为编码 Agent 准备的配套技能集。
技能正文开篇把执行者设定为“擅长在 vscode-copilot-chat 项目中升级 @github/copilot npm 包的专家”,随后给出三条总执行纪律:
- 必须先创建 TODO Markdown 文件,列出全部待办项,并在每完成一步后更新该文件;
- 按顺序完成所有 TODO,中途不暂停向用户确认,只有遇到必须用户决策的歧义点才停下;
- TODO 是唯一的进度跟踪机制:每一步开始前必须先重新读取 TODO,据此决定下一步动作。
TODO 的最低内容要求(原样继承自文档):
| # | 待办项 |
|---|---|
| 1 | Snapshot old type definitions(快照旧类型定义) |
| 2 | Update the package(更新包) |
| 3 | Compare differences in type definitions and document them(对比类型定义差异并记录) |
| 4 | Compile(编译) |
| 5 | Fix(修复) |
| 6 | Test(测试) |
| 7 | Repeat steps Compile, fix and tests until all tests are passing(循环编译-修复-测试直至全部通过) |
| 8 | Run integration tests(文档 Note 中又明确“Do not run any integration test”,见后文辨析) |
| 9 | Repeat Compile, Fix, Test until all tests are passing |
| 10 | Create a summary(生成总结报告) |
这套“TODO 驱动 + 顺序执行 + 循环收敛”的结构,本质上是把一次高风险依赖升级拆成状态明确、可断点续做、失败可重试的任务序列。
二、升级背景:@github/copilot 在 Copilot Chat 扩展中的角色
从 package.json 可以看到依赖声明:
"@github/copilot": "^1.0.73"
该包是 Copilot Chat 扩展中 CLI/Agent 会话能力的底层依赖。从源码看,src/extension/chatSessions/copilotcli/ 目录下的多个模块大量从 @github/copilot/sdk 导入类型,例如 copilotcliSessionService.ts 导入 internal, LocalSessionMetadata, SessionContext, SessionEvent, SessionOptions, SweCustomAgent,copilotcliSession.ts 导入 Attachment, SendOptions, SessionOptions, ToolExecutionCompleteEvent, ToolExecutionStartEvent。模块文档 AGENTS.md 也说明:@github/copilot/sdk 负责“会话管理、工具、权限、事件”,且对 Marketplace/VSIX 单独安装的扩展,运行时必须在任何 import('@github/copilot/sdk') 之前执行 shim 逻辑(ensureRipgrepShim()、ensureNodePtyShim()),把 VS Code 自带原生二进制复制到扩展的 SDK 布局中。
这解释了为什么升级流程要特别谨慎:这个包不只是纯 JS 类型依赖,它携带了跨平台的原生二进制与 wasm 资源,升级后布局或清单变化可能直接影响扩展打包与运行。
为什么升级后必须运行 npm run postinstall
SKILL.md 在“Update the package”步骤中强调:执行 npm install @github/copilot@latest 之后必须再运行 npm run postinstall。这个脚本在 package.json 中定义为:
"postinstall": "tsx ./script/postinstall.ts",
"compile": "node .esbuild.mts --dev",
"test:unit": "vitest --run --pool=forks"
阅读 postinstall.ts 的实现可知,postinstall 是 SDK 在 node_modules/@github/copilot 内“落地布局”的关键步骤,main() 主要做了这些事:
- 解析平台包来源(
resolveCopilotCliSourceDir):按process.platform/process.arch生成候选包名(如@github/copilot-linux-x64,Linux 上还会按 glibc 检测结果在linux-*与linuxmusl-*间排序),找到其中存在sdk/index.js的目录作为真正的 SDK 来源; - 物化 SDK 目录结构(
materializeCopilotCliSdkLayout):把来源包中的sdk/以及COPILOT_CLI_TOP_LEVEL_DIRS列出的顶层目录(worker、definitions、builtin-skills、builtin、tgrep、queries、prebuilds、ripgrep、foundry-local-sdk、pvrecorder、mxc-bin、clipboard、copilot-sdk、schemas、preloads)统一拷贝到node_modules/@github/copilot下,并同步根目录的tree-sitter-*.wasm文件; - 补齐
./sdk导出(ensureCopilotSdkExport):直接改写包内package.json的exports,加入'./sdk': { types: './sdk/index.d.ts', import: './sdk/index.js' }——这正是扩展源码中import ... from '@github/copilot/sdk'能解析到类型的前提; - 删除
shims.txt与sdk/worker目录,并把definitions、builtin-skills、tgrep、queries、prebuilds(按白名单过滤.node原生模块)再拷贝进sdk/子树; - 创建
.build目录、压缩 tiktoken 文件、拷贝 tree-sitter 等静态资源到dist,并在非 Windows 平台为.claude/建立指向.github/copilot-instructions.md与.agents/skills的符号链接。
所以“升级包 + postinstall”是一体两面:npm install 只负责把新版本装进 node_modules,而 postinstall 才负责把它整理成本项目预期消费的 SDK 布局。这也意味着任何一次版本升级后跳过 postinstall,都会导致 SDK 布局、导出声明与源码假设不一致。
三、升级流程逐步拆解
3.1 快照旧类型定义
流程第 1 步要求对 node_modules/@github/copilot/sdk/index.d.ts 做快照,留待升级后对比。这个文件正是 postinstall.ts 中 ensureCopilotSdkExport 声明的 types 入口,是扩展源码所能看到的 SDK 公共类型面。有了升级前的快照,后续所有“API 变更、破坏性变更、新增能力”的判断都有了客观基线,而不是凭印象。
(顺带一提,原文档这一句里混入了一个外部 issue 链接文本,属于文档小瑕疵,不影响步骤本身的理解。)
3.2 更新包并立即执行 postinstall
npm install @github/copilot@latest
npm run postinstall
如前节所述,第二条命令不可省略:它重新解析平台包、重建 SDK 目录结构并刷新 ./sdk 导出声明。
3.3 对比类型定义差异并归档
技能要求以 mode=background 方式在后台执行对比任务,完成后只需通知用户“已完成”。后台任务的具体职责是:
- 分析新旧两份
index.d.ts的差异,识别 API 变化、新增特性、破坏性变更; - 将分析结果以清晰、有条理的形式记录到
.build/upgrade-notes.md。
选择 .build/ 作为落盘目录与 postinstall.ts 中 main() 开头即创建 .build 目录(fs.promises.mkdir(path.join(REPO_ROOT, '.build'), { recursive: true }))的做法一致,属于该扩展约定的构建产物区。
3.4 编译、修复、测试循环
编译(Compile)
技能给出的标准命令序列是:
npm run postinstall
npm run compile
npx tsc --noEmit --project tsconfig.json
其中 compile 对应 package.json 中的 node .esbuild.mts --dev(esbuild 开发构建),npx tsc --noEmit --project tsconfig.json 则只做类型检查、不产出文件。技能特别要求:在动手修复之前,必须先对编译错误做深入分析(deep analysis),并且在没有任何编译错误之前,不允许进入测试阶段。这条约束的价值在于——升级引入的类型错误往往集中在少数 SDK 签名变化上,先归类再批量修复,能避免“改一处错一处”的碎片化修补。
测试(Test)
npm run test:unit
test:unit 在 package.json 中定义为 vitest --run --pool=forks。技能对测试环节给出两条硬性规则:
- 禁止为了通过测试而改变代码行为("Do NOT change the behaviour of the code just to make the tests pass");
- 升级导致的测试失败,必须分析它属于“升级引致的真实问题”还是“测试本身的问题”,并确保全部测试通过后才进入下一步。
测试侧的安全网:SDK 升级专用检查
test:unit 中恰好内置了一个为 SDK 升级而生的用例——copilotCLISDKUpgrade.spec.ts。它包含三项检查:
- SDK 可加载:
await import('@github/copilot/sdk')无错误; - 原生二进制清单不变:递归扫描
node_modules/@github/copilot下所有二进制文件,与一份硬编码的“已知二进制清单”双向比对——既不允许出现清单外的新二进制("Unexpected native binary found"),也不允许已知二进制缺失("Expected native binary missing")。清单覆盖 ripgrep/tgrep 各平台可执行文件、cli-native.node、runtime.node(含sdk/子树的第二份)、foundry-local-sdk 与 pvrecorder 的 N-API 模块、以及十余个tree-sitter-*.wasm; - 当前平台豁免:通过
currentCopilotPlatformArch()(同样基于 glibc 检测区分linux与linuxmusl)豁免其他平台的二进制缺失告警,并把sdk/ripgrep/bin下由 ripgrepShim.ts 拷贝生成的文件排除在比对之外。
这个用例的注释直白地说明了它的动机:确保“当 Copilot CLI SDK 升级时,我们清楚它所含原生二进制发生的变化,因为这类变化可能需要更新扩展打包或其他处理”。换句话说,技能的“Test”一步之所以要求跑到全绿,正是因为这套二进制清单测试会在 SDK 升级后第一时间暴露打包影响面。
3.5 输出升级总结
全部编译通过、测试全绿之后,技能要求在 .build/upgrade-notes.md 中输出三部分总结:
- 代码变更总结:升级过程中对代码库做了哪些修改;
- 测试变更总结:测试侧有哪些调整;
- 类型定义差异总结:新旧版本
@github/copilot之间——聚焦新增的 API/特性、引入的破坏性变更、被移除的弃用能力。
upgrade-notes.md 因此同时承载了 3.3 节的差异分析和 3.5 节的最终结论,成为一次升级的可追溯档案。
四、文档中的边界约定与两处值得注意的细节
- 集成测试的矛盾表述:TODO 最低清单的第 8 项写着“Run integration tests”,但紧随其后的 Note 明确“Do not run any integration test.”。从文档结构看,Note 是对 TODO 清单的覆盖性约束,实际执行应理解为不做集成测试,仅以
test:unit(vitest 单测)作为收敛判据。结合仓库脚本看,package.json 中真正的集成类入口是test:extension(vscode-test)与test:sanity,它们依赖启动完整的 VS Code 测试宿主,成本和耗时远高于单测,这也与技能“循环内只做 Compile/Fix/Test 单测”的节奏设计相吻合。 .build/目录的角色:它既由postinstall.ts保证存在,又是upgrade-notes.md的落盘位置,属于构建产物性质,不承载源码;升级总结放在这里,天然与源码变更隔离,便于后续清理或归档。
五、升级流程速查表
| 阶段 | 命令 / 产物 | 说明 |
|---|---|---|
| 前置 | 创建并维护 TODO markdown 文件 | 每步前重读 TODO,顺序执行,遇歧义才暂停 |
| 1 快照 | 拷贝 node_modules/@github/copilot/sdk/index.d.ts |
作为升级后对比基线 |
| 2 升级 | npm install @github/copilot@latest;npm run postinstall |
postinstall 负责重排 SDK 布局、补齐 ./sdk 导出 |
| 3 对比 | 后台任务 diff 新旧 index.d.ts |
结果写入 .build/upgrade-notes.md |
| 4 编译 | npm run postinstall;npm run compile;npx tsc --noEmit --project tsconfig.json |
零编译错误才进入测试 |
| 5 测试 | npm run test:unit(即 vitest --run --pool=forks) |
含 copilotCLISDKUpgrade.spec.ts 的加载与二进制清单检查;禁止为过测试改行为 |
| 6 循环 | 重复“编译-修复-测试”直至全绿 | 失败先归因再修复 |
| 7 总结 | 更新 .build/upgrade-notes.md |
覆盖代码变更、测试变更、类型差异(新增/破坏/移除) |
六、小结
github-copilot-upgrader 技能的价值在于把一次看似琐碎的依赖升级,规范化为基线先行、产物可追溯、失败可循环的工程流程:类型定义快照保证 API 差异有客观依据,postinstall 的强制重跑保证 SDK 布局与源码假设同步,test:unit 中内置的 SDK 加载与原生二进制清单测试则守住了“升级不破坏打包”的底线。对于维护 extensions/copilot 这类深度耦合第三方 SDK 布局的扩展,这套“快照—升级—对比—编译修复循环—二进制校验—报告”的清单,比临时起意的 npm update 加手工修错要可靠得多;其中每一步对应的脚本与测试在仓库中都有明确出处,可直接作为执行与审查时的核对依据。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00