跳到主内容
创建时间:最后更新:作者:白川

打包、安装和复用技能

用显式资源清单打包技能,在临时项目验证安装,并通过 SDK 发现可读取的技能文件。

打包、安装和复用技能

技能准备在不同项目复用时,需要保证分发的不只是 SKILL.md,还包括它引用的脚本、规则和模板。只复制正文,可能在显式调用后才发现关键资源不存在。

本篇沿用完整技能目录。先检查包内文件,再在干净项目安装;最后展示 SDK 资源加载入口,不自动发布 npm 包。

为资源包声明清单

将练习项目的 package.json 整理为:

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 用于这个教学包,避免误发布;它不影响本地资源试用。真正对外分发时需要另行确定包名、版本与许可,不在本篇直接执行发布。

先检查实际文件清单

在包根目录执行:

bash
npm pack --dry-run --json --ignore-scripts

确认技能正文、检查规则、模板和脚本都在清单中,而练习输入、开发检查脚本和个人配置没有被误装进去。README 与 package.json 可能按 npm 规则自动包含,不要求包内恰好只有四个资源文件。

dry-run 不等于已经发布,也不证明安装后的模型行为正确。本轮检查了实际清单,没有执行 npm publish。

在另一个项目记录本地安装

在技能包根目录保存实际路径,再进入新练习项目:

bash
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:

typescript
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 })
}

运行:

bash
node --import tsx src/sdk-discovery.ts

示例隔离工作目录和配置目录,关闭默认技能,只显式加载样例路径。发现后检查文件确实可读,结束时清理临时目录。

在已有 SDK 会话中,将准备好的 loader 作为 resourceLoader 传入,再确保会话具有读取技能与执行必要动作的工具。这里没有创建模型会话,也没有假造虚拟文件路径;只注册元数据而无法读取正文,不能算完成技能接入。

更换宿主时重新验证

目录式 SKILL.md、相对资源引用和清晰环境要求有助于迁移,但命令格式、自动发现、工具名称与权限设置可能不同。轻量 Agent Core 不默认拥有 coding-agent 的技能资源系统。

移植时分别核对格式、发现、文件读取、脚本执行与最终报告。这样可以复用技能内容,而不把某个宿主的实现细节误当成所有 Agent 的共同规则。

参考资料