打包、安装和复用技能
用显式资源清单打包技能,在临时项目验证安装,并通过 SDK 发现可读取的技能文件。
打包、安装和复用技能
技能准备在不同项目复用时,需要保证分发的不只是 SKILL.md,还包括它引用的脚本、规则和模板。只复制正文,可能在显式调用后才发现关键资源不存在。
本篇沿用完整技能目录。先检查包内文件,再在干净项目安装;最后展示 SDK 资源加载入口,不自动发布 npm 包。
为资源包声明清单
将练习项目的 package.json 整理为:
{
"name": "code-inspection-skill-example",
"version": "0.0.0",
"private": true,
"type": "module",
"engines": {
"node": ">=22.19.0"
},
"files": [
"skills"
],
"pi": {
"skills": [
"./skills"
]
},
"scripts": {
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@earendil-works/pi-coding-agent": "1.5.0",
"@types/node": "26.6.6",
"tsx": "4.23.15",
"typescript": "7.0.2"
}
}pi.skills 声明宿主从哪里发现技能,files 决定 npm 打包时携带哪些资源。开发用 SDK 和 TypeScript 放在 devDependencies,技能脚本本身只使用 Node 内置模块,没有要求消费方再安装一份模型运行时。
private: true 用于这个教学包,避免误发布;它不影响本地资源试用。真正对外分发时需要另行确定包名、版本与许可,不在本篇直接执行发布。
先检查实际文件清单
在包根目录执行:
npm pack --dry-run --json --ignore-scripts确认技能正文、检查规则、模板和脚本都在清单中,而练习输入、开发检查脚本和个人配置没有被误装进去。README 与 package.json 可能按 npm 规则自动包含,不要求包内恰好只有四个资源文件。
dry-run 不等于已经发布,也不证明安装后的模型行为正确。本轮检查了实际清单,没有执行 npm publish。
在另一个项目记录本地安装
在技能包根目录保存实际路径,再进入新练习项目:
PI_BIN="$(pwd)/node_modules/.bin/pi"
PACKAGE_DIR="$(pwd)"
mkdir ../skill-consumer
cd ../skill-consumer
"$PI_BIN" install --local "$PACKAGE_DIR"
"$PI_BIN" list--local 将声明写入当前项目的 .pi/settings.json,而不是默认个人设置。根据宿主要求处理项目信任后,启动宿主并检查技能是否发现,再使用 /skill:code-inspection 验证。
本地路径资源按实际目录读取,不是独立复制品。修改或删除原目录会影响使用它的项目;要做可追溯分发,可以选择固定版本的 npm 包或固定 Git 引用,并重新验证资源与依赖。
这些命令供独立练习项目使用。本轮安装检查只在临时沙箱进行,没有修改本机真实项目或个人技能配置。
从 SDK 加载同一份技能
创建 src/sdk-discovery.ts:
import { mkdtemp, readFile, rm } from "node:fs/promises"
import { tmpdir } from "node:os"
import { join } from "node:path"
import { fileURLToPath } from "node:url"
import { DefaultResourceLoader, SettingsManager } from "@earendil-works/pi-coding-agent"
const sandbox = await mkdtemp(join(tmpdir(), "skill-loader-"))
const skillPath = fileURLToPath(new URL("../skills/code-inspection", import.meta.url))
try {
const loader = new DefaultResourceLoader({
cwd: sandbox,
agentDir: join(sandbox, "config"),
settingsManager: SettingsManager.inMemory(),
noSkills: true,
additionalSkillPaths: [skillPath],
noExtensions: true,
noPromptTemplates: true,
noThemes: true,
noContextFiles: true,
})
await loader.reload()
const result = loader.getSkills()
const skill = result.skills.find((item) => item.name === "code-inspection")
if (!skill || result.diagnostics.length > 0) {
throw new Error(`技能未正确发现:${JSON.stringify(result.diagnostics)}`)
}
await readFile(skill.filePath, "utf8")
console.log("SDK 已发现技能且文件可读:", skill.filePath)
console.log("未创建模型会话,没有验证自然语言触发。")
} finally {
await rm(sandbox, { recursive: true, force: true })
}运行:
node --import tsx src/sdk-discovery.ts示例隔离工作目录和配置目录,关闭默认技能,只显式加载样例路径。发现后检查文件确实可读,结束时清理临时目录。
在已有 SDK 会话中,将准备好的 loader 作为 resourceLoader 传入,再确保会话具有读取技能与执行必要动作的工具。这里没有创建模型会话,也没有假造虚拟文件路径;只注册元数据而无法读取正文,不能算完成技能接入。
更换宿主时重新验证
目录式 SKILL.md、相对资源引用和清晰环境要求有助于迁移,但命令格式、自动发现、工具名称与权限设置可能不同。轻量 Agent Core 不默认拥有 coding-agent 的技能资源系统。
移植时分别核对格式、发现、文件读取、脚本执行与最终报告。这样可以复用技能内容,而不把某个宿主的实现细节误当成所有 Agent 的共同规则。