发布一个 coding agent 不是把 dist/cli.js 丢到 npm 就结束。真正要交付的是一个可安装、可升级、可扩展、可回滚、能被团队配置约束的生态入口。
Pi 的发布和插件生态给了清晰参考:@earendil-works/pi-coding-agent 通过 package.json 暴露 bin、exports、files 和 prepublishOnly;package manager 支持 npm、git、本地路径和项目级 .pi/settings.json;DefaultResourceLoader 把 packages、extensions、skills、prompts、themes 统一解析;extension API 提供工具、事件、命令、UI、provider 和 session state 扩展点。你的 forge-code alpha 版也应该沿着这几层设计。
阶段五前半部分已经有评测、trace replay 和 prompt 工程。现在要把原型交给团队试用,会遇到新的问题:
- CLI 怎样安装?是
npm i -g forge-code,还是内部 registry,还是 bun binary? - 用户升级后旧配置怎么办?
settings.json字段重命名如何迁移? - 企业团队怎样统一 provider、skills、权限策略和 npm wrapper?
- 插件是直接复制
.ts文件,还是发布为 npm package? - skills marketplace 如何筛选、启用、禁用和版本锁定?
- 扩展 API 给多大能力?工具、命令、事件、UI、配置都开放,还是只开放一部分?
这节课的目标是从“我能本地运行”走到“团队能安装、审计、升级和扩展”。
发布与插件生态可以拆成四层:
第一层是发行物。它回答“用户拿到什么”:npm 包、二进制、Docker 镜像、内部包、源码 checkout。对 Node CLI 来说,最小发行物是 package.json 的 bin、exports、files、build 脚本和 prepublishOnly。
第二层是配置生命周期。它回答“旧版本如何升级”:默认值、settings schema、字段迁移、项目级配置、用户级配置、企业固定配置。配置迁移必须可重复运行,不能依赖“用户手动删文件”。
第三层是资源生态。它回答“能力怎么扩展”:extensions、skills、prompts、themes、packages。资源可以来自 npm、git、本地路径,也可以是项目 .pi/ 自动发现。
第四层是治理边界。它回答“团队怎么安全使用”:允许哪些 package source、锁定哪些版本、用哪个 npmCommand、是否禁用三方 extension、哪些 skills 进入 marketplace、企业默认 provider 和权限模式是什么。
1. 从 package.json 读发行物
Section titled “1. 从 package.json 读发行物”打开 /Users/ryanchen/codespace/external-sources/pi/packages/coding-agent/package.json。重点看这些字段:
name/version:包身份和版本。bin:把pi命令映射到dist/cli.js。main/types/exports:SDK 和 extension 作者从哪里 import。files:npm tarball 里包含哪些目录。scripts.build:编译 TypeScript 并复制主题、assets、HTML export 模板。prepublishOnly:发布前强制 clean、build、shrinkwrap。engines.node:运行时 Node 版本边界。
对 forge-code 来说,alpha 版至少要做到:安装后命令可执行、SDK 类型可 import、插件 API 可 import、包里不漏源代码秘密、不缺 runtime assets。
2. 设计 CLI 发布检查表
Section titled “2. 设计 CLI 发布检查表”课程 lab starter /Users/ryanchen/codespace/pi-agent-course-lab/src/21-release-checklist.ts 已经列出四项:
typecheck -> package smoke -> config migration -> extension compatibility这四项代表发布前的最低门槛。typecheck 保证类型层不坏;npm pack --dry-run 检查 tarball 内容;配置迁移保证旧用户能启动;extension compatibility 保证生态不被破坏。
3. 读 package manager 的资源模型
Section titled “3. 读 package manager 的资源模型”Pi 的 package manager 支持三种 source:
npm:@scope/pkg@1.2.3git:github.com/user/repo@v1/absolute/path/to/package或./relative/path
这些 source 进入 settings 后,DefaultPackageManager.resolve() 会解析 installed package,再收集 extensions、skills、prompts、themes。版本化 npm spec 和 pinned git ref 是团队治理的关键:企业环境不应该默认追随最新 package。
4. 读资源加载和 extension API
Section titled “4. 读资源加载和 extension API”DefaultResourceLoader.reload() 会先 reload settings,再通过 package manager resolve resources,随后加载 extensions、skills、prompts、themes、AGENTS/CLAUDE context files 和 system prompt。
extension API 是生态能力的主边界。extensions.md 和 extensions/types.ts 显示 extension 可以:
- 监听 agent、session、tool、model、resource lifecycle event。
- 注册 LLM-callable tool。
- 注册 slash command、shortcut、flag。
- 使用 UI dialog、status、widget、custom component。
- 修改 tool call、message end、compaction、provider 等行为。
这很强,也意味着 extension 必须被当作代码执行权限来治理,而不是普通配置。
5. 设计 skills marketplace
Section titled “5. 设计 skills marketplace”skills marketplace 不只是“有一个列表”。至少要有:
- skill 元数据:name、description、version、source、适用场景。
- 安装来源:npm、git、本地、企业镜像。
- 启用范围:user-level 或 project-level。
- 冲突策略:同名 skill 谁优先。
- 审核状态:官方、团队批准、实验性、禁用。
- 兼容性:支持的
forge-code版本和所需工具权限。
Pi 的 packages.md 提供了 package gallery 和 pi-package keyword 的思路;你的内部 marketplace 可以先用一个 JSON index 实现,再逐步接入 UI。
6. 设计企业配置
Section titled “6. 设计企业配置”企业配置要避免“每个开发者自己配一遍”。最小方案是:
- 公司内部 npm registry 或 git mirror。
- 项目级
.pi/settings.json或forge-code.settings.json。 - 固定
packages、skills、prompts、provider、model allowlist。 - 设置
npmCommand,确保 package install 走公司指定 Node/npm wrapper。 - 禁用或审批未知 extension source。
- 发布前用
npm pack --dry-run和 smoke project 验证真实安装路径。
本课 lab starter 是 /Users/ryanchen/codespace/pi-agent-course-lab/src/21-release-checklist.ts。它目前只返回 required checks。课堂上要把它升级成 release gate:每个 check 有命令、证据、失败处理和是否阻断发布。
发布 forge-code 内部 alpha 版可以先定义这样一条流水线:
npm run typechecknpm run testnpm pack --dry-runnode dist/cli.js --versionnode dist/cli.js task create --helprun config migration fixturerun extension compatibility fixture每一步都要产生 evidence。没有 evidence 的发布只是“我觉得可以发”。
课堂代码推演
Section titled “课堂代码推演”从 starter 的 ReleaseCheck 开始,增加执行状态:
type ReleaseCheck = { name: string; required: boolean; command?: string; evidence?: string;};
type ReleaseResult = { publishable: boolean; blockers: string[]; warnings: string[];};
function evaluateRelease(checks: ReleaseCheck[]): ReleaseResult { const blockers: string[] = []; const warnings: string[] = [];
for (const check of checks) { const passed = Boolean(check.evidence);
if (!passed && check.required) { blockers.push(check.name); continue; }
if (!passed) { warnings.push(check.name); } }
return { publishable: blockers.length === 0, blockers, warnings, };}这段代码的教学重点不是数组遍历,而是发布决策的变量流:
required决定失败是否阻断发布。command是 evidence 的来源,但不是所有检查都有命令;配置迁移可能来自 fixture 结果。evidence是发布审计的材料。npm pack --dry-run的输出、migration fixture 的旧配置输入和新配置输出都应该被保存。publishable只由 blockers 决定,warnings 可以进入 release note 或 alpha 限制说明。
再把 package 生态放进 checklist:
const alphaChecks: ReleaseCheck[] = [ { name: "typecheck", required: true, command: "npm run typecheck", evidence: "0 errors" }, { name: "package smoke", required: true, command: "npm pack --dry-run", evidence: "dist/cli.js included" }, { name: "config migration", required: true, evidence: "settings-v1 -> settings-v2 fixture passed" }, { name: "extension compatibility", required: false },];课堂上会让学生解释:为什么 extension compatibility 在 alpha 可以是 warning,但到了企业 beta 应该升级为 required。答案是生态承诺变了:alpha 允许破坏扩展,beta 开始要求稳定 API。
/Users/ryanchen/codespace/pi-agent-course-lab/src/21-release-checklist.ts:本课 lab starter,用发布检查表建立 release gate。/Users/ryanchen/codespace/external-sources/pi/packages/coding-agent/package.jsonat61babc2:CLI npm 包的bin、exports、files、build、binary build、prepublishOnly、runtime dependencies。/Users/ryanchen/codespace/external-sources/pi/packages/coding-agent/src/package-manager-cli.tsat61babc2:pi install、pi remove、pi list、pi update的 CLI 入口。/Users/ryanchen/codespace/external-sources/pi/packages/coding-agent/src/core/package-manager.tsat61babc2:npm/git/local package source、settings 持久化、安装路径、manifest、resource filtering、pinned ref 处理。/Users/ryanchen/codespace/external-sources/pi/packages/coding-agent/src/core/resource-loader.tsat61babc2:把 packages、extensions、skills、prompts、themes 和 context files 装载进 runtime。/Users/ryanchen/codespace/external-sources/pi/packages/coding-agent/src/core/extensions/types.tsat61babc2:extension API 的主要类型边界。/Users/ryanchen/codespace/external-sources/pi/packages/coding-agent/docs/packages.mdat61babc2:Pi package 的安装来源、package manifest、gallery metadata、resource filtering、scope 和 deduplication 说明。/Users/ryanchen/codespace/external-sources/pi/packages/coding-agent/docs/extensions.mdat61babc2:extension 能力、加载位置、runtime dependency、事件和 API 说明。/Users/ryanchen/codespace/external-sources/pi/packages/coding-agent/docs/skills.mdat61babc2:skills 规范、加载、冲突和校验规则。/Users/ryanchen/codespace/external-sources/pi/packages/coding-agent/test/package-manager.test.tsat61babc2:package manager 行为测试锚点。/Users/ryanchen/codespace/external-sources/pi/packages/coding-agent/test/extensions-runner.test.tsat61babc2:extension runner 行为测试锚点。
学完本课后,你应该能做到:
- 解释一个 agent CLI npm 包的最小发布面:
bin、exports、files、build、publish gate。 - 设计
npm pack --dry-run、CLI smoke、typecheck、migration fixture、extension compatibility 组成的 release checklist。 - 说明 Pi packages 如何从 npm、git、本地路径进入 settings,再被 resource loader 加载。
- 区分 extension、skill、prompt template、theme 的职责和风险等级。
- 为内部 skills marketplace 设计元数据、版本锁定、启用范围、审核状态和冲突策略。
- 为企业配置设计 user-level、project-level、registry、
npmCommand、provider allowlist 和未知 extension 审批策略。
- 实践题:扩展
/Users/ryanchen/codespace/pi-agent-course-lab/src/21-release-checklist.ts,实现evaluateRelease(),要求输出publishable、blockers、warnings,并为npm pack --dry-run增加一条 evidence 示例。 - 思考题:为什么 extension package 应该被当成“可执行代码”治理,而 skill marketplace 也不能只看 Markdown 内容是否友好?