@easbot/skills
v0.3.23
Published
Skills management system for EAS Agent ecosystem (add / remove / list / find / update / sync / use)
Maintainers
Readme
English | 中文
@easbot/skills
EASBot 技能管理子系统。负责技能(SKILL.md)的发现、安装、移除、搜索、更新、一次性使用(use)、模板初始化(init),以及 store / cache / index 的运维管理。同时承担 Plugin Source 注册中心角色(决策 0044),把 well-known / marketplace / 本地 plugins 等源抽象为 PluginSource,供 @easbot/agent 注入 PluginDefinition.skills。
既可作为独立 CLI(easbot-skills),也可被 @easbot/agent 主 CLI 通过 Commander.js 委派调用,easbot skills ... 与 easbot-skills ... 等价。
版本
v0.3.13
目标文件
包中只操作 SKILL.md(以及可选的本地 plugin.json):
- 技能名来自
SKILL.mdfrontmatter 的name字段 - 插件清单来自
plugin.json(若存在,否则默认为*.md)
特性
- 类型安全:完整 TypeScript 类型 + Zod frontmatter 校验 + Zod remote-skill payload 校验
- 多源支持:GitHub 仓库 shorthand(
owner/repo)/ HTTPS / SSH / Well-Known 索引 / 本地路径 / GitHub API blob 回退 - 多 Agent 兼容:72+ 个 Agent 类型(
easbot,claude-code,cursor,codex,amp,eve,gemini-cli,github-copilot,opencode,qwen-code,trae,trae-cn,windsurf,zed,roo,cline,iflow-cli,kimi-code-cli,augment,devin,goose,dexto等)- Universal 共享路径:
eve/amp/gemini-cli/github-copilot/qwen-code/roo/windsurf/zed/claude-code等 16 个 agent 通过"universal"作用域共享.agents/skills目录 - Non-universal agent:各自维护独立技能目录
- Universal 共享路径:
- 安装矩阵 / 后安装核对:
AgentInstallMatrix(agent × skill 二维表,probeCell逐单元格判定),安装后对每个 cell 做 reconcile(缺失补链接,多余移除) - 依赖注入(决策 0043):通过
setGlobalAdapter/setInstanceAdapter/setAgentAdapter注入IGlobal.Path/IInstance.directory,让 skills 统一使用宿主的 XDG 数据树 - 增量同步:基于本地 SHA-256 密文锁文件的
add/remove/update/store增量操作(skill-lock.ts/local-lock.ts) - store 视角运维(决策 36A):
skills store list / clean / update / remove管理 store 物理 + index + cache,不动 agent 前端分发 - local 源硬保护:
store clean --force/store remove对 local 源拒绝删 cache / 用户原目录 - i18n:内置 zh-CN / en-US 两套翻译;所有用户简文走
t(),未命中 key 时回退英文原文 - 遥测 + 安全审计:内置
skills.shpartner audit 上报、OpenClaw 风险提示、遥测可冲刷(flushTelemetry) - 统一交互 Prompt(Session 4):所有交互走
@easbot/terminal.Promptnamespace —— 取消语义收口(Prompt.cancel是never+ 内置process.exit(0)),图标统一来自Symbol命名空间(禁止硬编码✓✗◆),颜色统一走theme.colorize()
安装
pnpm add @easbot/skills或作为 monorepo 工作区依赖:
{
"dependencies": {
"@easbot/skills": "workspace:*"
}
}目录结构
src/
├── types.ts # AgentType, Skill, AgentConfig, ParsedSource, RemoteSkill
├── agents.ts # Agent 配置矩阵(72+ 个)与分类函数
├── skills.ts # 技能发现: parseSkillMd, discoverSkills, filterSkills
├── constants.ts # AGENTS_DIR / SKILLS_SUBDIR / UNIVERSAL_SKILLS_DIR
├── frontmatter.ts # YAML frontmatter 解析
├── hash.ts # 哈希工具: computeFromDir / computeSnapshotHash
├── source-parser.ts # 来源标准化: parseSource, parseOwnerRepo, sanitizeSubpath, isRepoPrivate
├── interfaces.ts # 依赖注入: setGlobalAdapter / setInstanceAdapter / setAgentAdapter
├── detect-agent.ts # 探测运行的 AI Agent: detectAgent / isRunningInAgent
├── sanitize.ts # 控制字符净化: sanitizeMetadata / stripTerminalEscapes
├── telemetry.ts # 遥测: track / flushTelemetry / fetchAuditData / setVersion
├── git.ts # 仓库克隆 / cleanupTempDir / parseGitHubRepoUrl
├── blob.ts # GitHub API 回退: fetchRepoTree / tryBlobInstall / toSkillSlug
├── skill-lock.ts # 全局安装锁定文件读写 (skill-lock.json)
├── local-lock.ts # 项目级锁定文件 (skills-lock.json) 与文件夹 SHA-256
├── installer/
│ ├── installer.ts # 物理安装: installSkillForAgent / installRemoteSkillForAgent / installBlobSkillForAgent / installWellKnownSkillForAgent / linkSkillDir / copySkillDir / listInstalledSkills / getInstallPath / getCanonicalPath / sanitizeName
│ ├── post-install.ts # 安装后核对矩阵: planActions / buildMatrix / probeCell / runPostInstallReconcile
│ ├── store.ts # 三层 source / cache / install 收敛: acquireSourceClone / ensureCachedSource / cleanCache / getCacheRepoDir / getStoreDir
│ └── store-types.ts # 共享类型: StoreSourceType / SkillEntry / PluginDefinition / MarketDefinition / SkillLocation / STORE_INDEX_VERSION / parsePluginId / storePathForSkillLock
├── add.ts # 添加技能主流程
├── find.ts # 搜索技能 (skills.sh / fuzzy filter / 本地 store 查询)
├── list.ts # 列出已安装技能 (项目/全局/按 agent 过滤)
├── remove.ts # 移除技能
├── update.ts # 增量更新 (按 filter 更新一个或多个技能)
├── use.ts # 一次性使用: materializeUseSkill / buildUsePrompt / launchAgentInteractively
├── doctor.ts # 检查 + 清理断链与坏符号链接
├── store-cmd.ts # store 运维子命令 (list / clean / update / remove)
├── init-template.ts # 根据 locale 模板创建新技能
├── providers/
│ ├── wellknown.ts # WellKnownProvider: fetch index + scan + 加载
│ └── registry.ts # Provider 注册中心 + HostProvider 接口
├── sources/ # Plugin Source 注册中心 (决策 0044)
│ ├── index.ts # PluginSource 入口: createWellKnownSource / createLocalPluginSource 工厂
│ ├── registry.ts # 注册中心: registerSource / listSources / findSource / listAllEntries
│ ├── wellknown.ts # wellknown 源适配
│ ├── local.ts # 本地插件目录 (plugin.json) 适配
│ └── types.ts # PluginSource / PluginSourceCategory / PluginSourceEntry 接口
├── i18n/ # 国际化全套 (zh-CN / en-US)
├── utils/ # 辅助工具
│ ├── ansi.ts # 硬编码 SGR 常量 (RESET / BOLD / DIM / TEXT / CYAN / YELLOW / MAGENTA)
│ ├── format.ts # 标签工具: pBgLabel / pErrorBadge (Agent badge + ERROR badge)
│ ├── color.ts # picocolors 形态兼容层 (dim/red/green/yellow/cyan/bold/... → @easbot/terminal.colorize + theme)
│ └── output.ts # 人类输出统一封装: printHuman / wrapJson / emitJson / formatListTruncated
├── cli.ts # 独立 CLI 入口 (easbot-skills)
└── cli-handler.ts # CLI 处理器 (供 agent 复用)CLI 用法
独立 CLI
# 添加技能
easbot-skills add houjallen/agent-skills
easbot-skills add https://github.com/houjallen/agent-skills -g
# 搜索 (交互式搜索多选)
easbot-skills find typescript --owner houjallen
# 列出已安装 (项目级/全局)
easbot-skills list --json
easbot-skills ls -g -a claude-code
# 移除
easbot-skills remove my-skill -y
easbot-skills rm --agent claude-code my-skill
# 更新
easbot-skills update -g
easbot-skills update my-skill --all
# 一次性使用 (不写锁定文件)
easbot-skills use houjallen/agent-skills@houjallen
easbot-skills use --skill my-skill --agent claude
# store 视角运维 (store + cache + index)
easbot-skills store list [keyword] # 列出 store skills (按 name 过滤)
easbot-skills store list --json # 完整 index 为 JSON
easbot-skills store clean # 重置 store (删 store 物理 + 清 index)
easbot-skills store clean --force # 同上 + 清 cache (local 源保护)
easbot-skills store remove <sourceKey> # 移除 source
easbot-skills store remove <sourceKey> --force # 额外清 cache
# 健康检查 (检查 + 清理断链符号链接)
easbot-skills doctor
easbot-skills doctor -a easbot -y # 检查一个 agent + 自动清理
easbot-skills dr -g # 仅全局范围
# 模板初始化 (创建新技能的 SKILL.md)
easbot-skills init my-skill
easbot-skills init # 在 cwd/<basename>/SKILL.md 创建子命令清单(独立 CLI 实际行为)
easbot-skills add <source> # 添加技能 (alias: a / install / i)
easbot-skills find [query] # 搜索技能 (alias: search / f / s)
easbot-skills list # 列出已安装 (alias: ls)
easbot-skills remove [skills...] # 移除 (alias: rm / r)
easbot-skills update [skills...] # 增量更新 (alias: upgrade / check)
easbot-skills use <source[@skill]> # 一次性使用
easbot-skills init [name] # 模板初始化
easbot-skills doctor # 健康检查 (alias: dr)
easbot-skills store <subcommand> # store 视角运维 (list / clean / update / remove)store 子命令族(决策 0049-yyy)
# 列出 store 内的所有 source(人类可读模式展示完整 64 位 hex sourceKey,便于后续 update / remove)
easbot-skills store list
easbot-skills store list [keyword] # 按 skill name 过滤
# 重置 store(默认重置物理 + index.json;--force 额外清 cache 物理)
easbot-skills store clean
easbot-skills store clean --force
# 重新拉取 store(不动 agent 前端分发)
# 不传 source-key → 全量 store 重新拉
# 传 source-key(64 位 hex,从 `store list` 输出取)→ 仅该 source 整 source 重新拉
easbot-skills store update
easbot-skills store update <full-source-key> # 决策 0049-yyy:[keyword] → [source-key]
# 移除单个 store source(--force 额外清 cache;local 源 cache = 用户原目录,永远不删)
easbot-skills store remove <source-key>
easbot-skills store remove <source-key> --force核心语义:
store操作的是整 source 镜像(不是单 skill)—— store 真源 = source cp 产物; 要么整 source 重拉,要么不动;不存在"只更新 store 某个 skill"的语义。update <skill-name>想"按 skill 触发整 source 拉 + agent 分发"——交给skills update <name>, 不该塞进store update(避免语义重叠)。store list输出完整 sourceKey(决策 0049-yyy:之前是 8 位截断 → 用户无法直接复用)。
被宿主 CLI 委派
@easbot/agent 的 easbot skills ... 负责通过 handleSkillsCli(args, deps) 实现全子命令复用:
import { handleSkillsCli, setAgentAdapter } from '@easbot/skills';
setAgentAdapter({
global: Global, // IGlobal
instance: Instance, // IInstance
// subAgentRunner / localAgentRunner / triggerEvent 可选
});
const result = await handleSkillsCli(['add', 'houjallen/agent-skills', '-y'], {
version: ctx.programVersion,
cwd: ctx.config.directory,
});
// process.exit(result.code) if result.code !== 0easbot skills 在 packages/agent/src/cli/commands/skills.ts 的 registerSkillsCommand() 中注册,通过 Commander.js skills.<subcommand> 把 flag 转为 argv 后 dispatch 给 handleSkillsCli。skills store 子族也在同一模块注册。
API(按模块)
所有导出均从
@easbot/skills顶层入口(src/index.ts)按主题分组暴露。
1. 核心类型
import type { AgentType, Skill, AgentConfig, ParsedSource, RemoteSkill } from '@easbot/skills';| 类型 | 说明 |
|---|---|
| AgentType | 70+ Agent 联合类型(含 universal 虚拟类型) |
| Skill | 技能模型(name / path / frontmatter / pluginName / subpath 等) |
| AgentConfig | Agent 配置(name / displayName / skillsDir / globalSkillsDir / detectInstalled) |
| ParsedSource | 来源描述(type / url / ref / subpath) |
| RemoteSkill | 远程技能模型 |
2. Agent 体系
import {
agents, // Record<AgentType, AgentConfig>
EVE_SUBAGENTS_DIR, // 'agent/subagents'
PROJECT_SKILLS_DIR_PATTERN, // /^\.[^/]+\/skills$/
detectInstalledAgents,
getAgentConfig,
getAgentGlobalSkillDirs, // 项目级 agent 的全局技能目录列表
getAgentProjectSkillDirs,
getAgentProjectSkillContainerPrefixes,
getAgentSkillDirs,
getEveSubagents,
getNonUniversalAgents, // 非 universal agent 列表
getOpenClawGlobalSkillsDir,
getUniversalAgents,
isUniversalAgent,
matchesUniversalScope,
} from '@easbot/skills';
import type { AgentSkillDirsResult, UniversalScope } from '@easbot/skills';3. 技能发现 / 安装
import {
discoverSkills, filterSkills, getSkillDisplayName,
isSubpathSafe, parseSkillMd, shouldInstallInternalSkills,
installSkillForAgent, installRemoteSkillForAgent, installBlobSkillForAgent,
installWellKnownSkillForAgent,
linkSkillDir, copySkillDir,
getAgentBaseDir, getCanonicalPath, getCanonicalSkillsDir,
getEveSubagentSkillsDir, getInstallPath,
isSkillInstalled, listInstalledSkills, sanitizeName,
} from '@easbot/skills';
import type { DiscoverSkillsOptions, InstallMode, InstalledSkill } from '@easbot/skills';
// Post-install 矩阵
import { applyActions, buildMatrix, planActions, probeCell, runPostInstallReconcile } from '@easbot/skills';
import type { AgentInstallMatrix, CellAction, CellScope, InstallCell, InstallState,
PostInstallInput, PostInstallResult } from '@easbot/skills';4. 来源解析
import { parseSource, parseOwnerRepo, getOwnerRepo, isRepoPrivate, sanitizeSubpath } from '@easbot/skills';5. 命令入口(CLI 子命令的 run* + parse*)
import { runAdd, parseAddOptions, initTelemetry } from '@easbot/skills';
import type { AddOptions } from '@easbot/skills';
import { runFind, parseFindOptions, searchSkillsAPI } from '@easbot/skills';
import type { FindOptions, ParseFindOptionsResult, SearchSkill } from '@easbot/skills';
import { runList, parseListOptions } from '@easbot/skills';
import { removeCommand, parseRemoveOptions } from '@easbot/skills';
import type { RemoveOptions } from '@easbot/skills';
import { runUpdate, parseUpdateOptions, hasProjectSkills, matchesSkillFilter, resolveUpdateScope } from '@easbot/skills';
import type { UpdateCheckOptions, UpdateScope } from '@easbot/skills';
import { runUse, parseUseOptions, buildUsePrompt, materializeUseSkill, launchAgentInteractively } from '@easbot/skills';
import type { AgentProcess, AgentSpawn, MaterializedUseSkill, ParseUseOptionsResult, UseOptions, UseSkill } from '@easbot/skills';
import { runDoctor } from '@easbot/skills';
import { runStore, parseStoreOptions, runStoreList, runStoreClean, runStoreUpdate, runStoreRemove } from '@easbot/skills';
import type { StoreOptions } from '@easbot/skills';6. 锁文件 / 哈希
import {
readSkillLock, writeSkillLock, addSkillToLock, removeSkillFromLock, getSkillFromLock,
getGitHubToken, getAllLockedSkills, getSkillsBySource,
getSkillLockPath, computeContentHash, storePathFromLockEntry,
dismissPrompt, isPromptDismissed, resetGhAuthWarning,
} from '@easbot/skills';
import type { DismissedPrompts, SkillLockEntry, SkillLockFile } from '@easbot/skills';
import {
readLocalLock, writeLocalLock, addSkillToLocalLock, removeSkillFromLocalLock,
getLocalLockPath, storePathFromLocalLockEntry,
} from '@easbot/skills';
import type { LocalSkillLockEntry, LocalSkillLockFile } from '@easbot/skills';
import { computeFromDir, computeSnapshotHash } from '@easbot/skills';7. Git / Blob 集成
import {
DEFAULT_CLONE_TIMEOUT, GitCloneError,
cloneRepo, cleanupTempDir, parseGitHubRepoUrl,
isGitHubHttpsCloneUrl, isGitHubSsoAuthError,
} from '@easbot/skills';
import {
BLOB_ALLOWED_REPOS, // Record<string, { downloadUrl }>
toSkillSlug,
fetchRepoTree, findSkillMdPaths, getSkillFolderHashFromTree,
resetRepoTreeAuthState, tryBlobInstall,
} from '@easbot/skills';
import type { BlobInstallResult, BlobSkill, RepoTree, SkillDownloadResponse, SkillSnapshotFile, TreeEntry } from '@easbot/skills';8. Installer 支撑层(三层 source / cache / install)
import {
acquireSourceClone, ensureCachedSource, installFromCache, cleanCache, cleanCachedRepo,
getCacheRepoDir, getCacheRoot, getSourceDir,
} from '@easbot/skills';
import type { InstallScope } from '@easbot/skills';
// store-types 共享类型
export type {
StoreSourceType, SkillScope,
SkillEntry, PluginDefinition, MarketDefinition, SkillLocation,
DefaultPluginConfig, StoreIndex,
STORE_INDEX_VERSION,
parsePluginId, pluginDirFromPluginId, storePathForSkillLock,
} from '@easbot/skills';9. 安全 / 遥测 / Agent 探测
import {
track, flushTelemetry, fetchAuditData, setVersion, setDetectedAgent,
} from '@easbot/skills';
import type { AuditResponse, PartnerAudit, SkillAuditData } from '@easbot/skills';
import { sanitizeMetadata, stripTerminalEscapes } from '@easbot/skills';
import { detectAgent, getAgentName, getAgentType, isRunningInAgent } from '@easbot/skills';10. Provider 抽象
import { wellKnownProvider, WellKnownProvider } from '@easbot/skills';
import type {
WellKnownIndex, WellKnownIndexV1, WellKnownIndexV2,
WellKnownSkill, WellKnownSkillEntry, WellKnownSkillEntryV1, WellKnownSkillEntryV2,
WellKnownFileContent,
} from '@easbot/skills';
import { findProvider, getProviders, registerProvider, registry } from '@easbot/skills';
import type { HostProvider, ProviderMatch, ProviderRegistry, RemoteSkill as ProviderRemoteSkill } from '@easbot/skills';11. 常量与辅助
import { AGENTS_DIR, SKILLS_SUBDIR, UNIVERSAL_SKILLS_DIR, parseFrontmatter } from '@easbot/skills';12. CLI 桥接(供 @easbot/agent 复用)
import { handleSkillsCli, renderBanner, renderHelp } from '@easbot/skills';
import type { SkillsCliDeps, SkillsCliResult } from '@easbot/skills';13. 接口注入(宿主 → skills)
import {
setGlobalAdapter, setInstanceAdapter, setAgentAdapter,
resetGlobalAdapter, resetInstanceAdapter,
getGlobal, getInstance, getAgentAdapter, getHomeDir,
getXdgConfig, getXdgData, getXdgState, getXdgCache,
getProjectDirectory,
hasAgentAdapter, requireAgentAdapter,
} from '@easbot/skills';
import type { SkillsAgentAdapter } from '@easbot/skills';
import type { IGlobal, IInstance, ISubAgentRunner } from '@easbot/skills';14. Plugin Source 注册中心(决策 0044)
import { registerSource, unregisterSource, listSources, findSource, findSourcesByCategory, listAllEntries,
createWellKnownSource, createLocalPluginSource } from '@easbot/skills';
import type {
PluginSource, PluginSourceCategory, PluginSourceEntry, PluginSourceLoadResult,
WellKnownSourceOptions, LocalPluginSourceOptions,
} from '@easbot/skills';import { registerSource, createWellKnownSource, createLocalPluginSource } from '@easbot/skills';
// 1) 注册 well-known endpoint 作为 plugin source
registerSource(createWellKnownSource({
url: 'https://mintlify.com/docs',
}));
// 2) 注册本地 plugin.json 作为 plugin source
registerSource(createLocalPluginSource({
basePath: process.cwd(),
}));
// 3) @easbot/agent bootstrap 时拉取所有 source
import { listSources } from '@easbot/skills';
for (const source of listSources()) {
const entries = await source.fetch();
for (const entry of entries) {
const { skills } = await source.load(entry);
// → 注入 PluginDefinition.skills
}
}支持的 Agent 列表(完整)
agents.ts 中的 AgentType 联合类型包含 72 个 Agent(含虚拟类型 universal):
easbot, claude-code, cursor, codex, eve, opencode, aider-desk, amp, antigravity, astrbot, augment, autohand-code, bob, openclaw, cline, codearts-agent, codebuddy, codemaker, codestudio, command-code, continue, cortex, crush, deepagents, devin, dexto, droid, firebender, forgecode, gemini-cli, github-copilot, goose, hermes-agent, inference-sh, iflow-cli, jazz, junie, kilo, kimi-code-cli, kiro-cli, kode, lingma, loaf, zanbura, mistral-vibe, moxby, mux, neovate, openhands, om, pi, qoder, qoder-cn, qwen-code, replit, reasonix, roo, rovodev, tabnine-cli, terramind, tinycloud, trae, trae-cn, warp, windsurf, zed, zencoder, zenflow, pochi, promptscript, adal, antigravity-cli, mistral,以及虚拟类型 universal。
Universal 共享 .agents/skills 目录(16 个 agent):eve / amp / gemini-cli / github-copilot / qwen-code / roo / windsurf / zed / claude-code 等。
所有这些 Agent 的配置(displayName / skillsDir / globalSkillsDir / 是否导入 universal / 安装判断函数 / detectInstalled)都在 src/agents.ts 中定义。
全局路径依赖注入
为避免与宿主(agent / gateway)抢 XDG / home 目录,@easbot/skills 默认通过依赖注入获取路径:
import {
setAgentAdapter, // 推荐:一站式注入(global + instance + 可选 subAgentRunner 等)
setGlobalAdapter, // 注入 IGlobal.Path
setInstanceAdapter, // 注入 IInstance.directory / worktree
getHomeDir,
getXdgConfig,
getXdgData,
getProjectDirectory,
} from '@easbot/skills';
setAgentAdapter({
global: {
Path: {
home: '/Users/me',
data: '/Users/me/.local/share/easbot',
config: '/Users/me/.config/easbot',
state: '/Users/me/.local/state/easbot',
cache: '/Users/me/.cache/easbot',
log: '/Users/me/.local/state/easbot/log',
bin: '/Users/me/.local/bin',
},
},
instance: {
directory: '/repo',
worktree: '/repo',
},
// 可选
subAgentRunner: ...,
triggerEvent: async (event, input, ctx) => ({ success: true, output: undefined, modified: false }),
});未注入时,skills 包回退到 xdg-basedir + homedir(),与 v1 独立 CLI 完全兼容。
getHomeDir() 优先级(测试隔离):
process.env.EASBOT_TEST_HOME(测试专用最高优先级)- 注入的
Global.Path.home os.homedir()兜底
数据目录约定
注入场景下,所有
getXdgData / getXdgCache / ...都走Global.Path.*;默认场景走xdg-basedir + easbot段。
| 路径 | 用途 | 实现位置 |
|---|---|---|
| ${getXdgData()}/skills/ | Agent 运行时加载的技能目录(运行时扫描) | installer/store.ts |
| ${getXdgData()}/skills/.skill-lock.json | 全局安装锁定文件(与 store 同根) | skill-lock.ts |
| ${getXdgData()}/skills/store/<sourceKey>/ | store 物理目录(按 sourceKey hash 归一化源;add 写一次,update 复用) | installer/store.ts::getStoreDir |
| ${getXdgData()}/skills/store/index.json | store defs 索引(记录每个 store skill 的 registryKey / type / url / skillPath / computedHash) | installer/store.ts::getStoreDefinitionsFile |
| ${getXdgCache()}/skills/cache/<type>/<owner/repo>/ | cache 物理(remote 源下载 / 物化缓存;local 源 = 用户原目录) | installer/store.ts::getCacheRepoDir |
| <cwd>/.easbot/skills/<skill>/ | EASBot 项目级(universal agent 不命中此路径) | agents.ts |
| <cwd>/.agents/skills/<skill>/ | claude-code / cursor / gemini-cli 等 universal 项目级 | agents.ts |
| <cwd>/<agent-glob>/skills/<skill>/ | 各 agent 自定义项目级(如 ~/.trae/skills/) | agents.ts |
| <cwd>/skills-lock.json | 项目级锁定文件 | local-lock.ts |
| ${getXdgConfig()}/easbot/skills/ | EASBot 全局技能目录(注入场景) | agents.ts::easbot.globalSkillsDir |
| ~/.config/easbot/skills/ | EASBot 全局技能目录(默认场景 fallback) | 同上 |
当被
@easbot/agent委派时,所有路径落到{Global.Path.data}这颗统一数据树下,与 Gateway / MCP / Session / Contact 等模块并列。
链接标头外部审核反馈(skills.sh)
telemetry.ts 会往回向 skills.sh 发送遥测 / 审计数据(可配置 SKILLS_API_URL),用于:
- 技能审计(
fetchAuditData返回技能级的PartnerAudit信息) - 安全 gate 检查(
.dangerously-accept-openclaw-risksflag 可跳过)
交互提示规范(Session 4 改造)
所有 CLI 交互(select / confirm / multiselect / spinner / intro / outro / cancel / Log)统一走 @easbot/terminal.Prompt namespace:
import { Prompt, Symbol as Glyph } from '@easbot/terminal';
// 取消语义收口:Prompt.cancel 是 `never`,内置 process.exit(0)
const v = await Prompt.select({ message: '选择范围', options: [...] });
if (Prompt.isCancel(v)) await cleanup();
Prompt.cancel('用户取消');
// 图标统一(**禁止**硬编码 ✓✗◆ 等字面量)
console.log(`${Glyph.statusIcon('success')} 操作成功`); // ✓ green
console.log(`${Glyph.colorize(Glyph.bar.bullet, 'error')} bullet`);
// 状态流(统一配色到 terminal theme)
Prompt.Log.info('Installing...');
Prompt.Log.warn('警告');
Prompt.Log.error('失败');
Prompt.Log.step('步骤');
Prompt.Log.message('普通消息');业务方不直接调 pc.green('✓') 等;不调 console.log(p.theme.error(...))。所有这些都已收敛到 utils/color.ts 的 picocolors 兼容层(过渡)和 Glyph.* / Prompt.Log.*。
开发
# 安装依赖
pnpm install
# 构建 (产出 dist/ + .d.ts)
pnpm build
# 监听构建
pnpm dev
# 测试 (vitest)
pnpm test
pnpm test:run
# 代码质量
pnpm lint # biome check .
pnpm lint:fix # biome check --write .
pnpm format # biome format .
pnpm format:fix # biome format --write .
# 类型检查
pnpm type-check
# 清理
pnpm clean发布
# Linux / macOS
bash scripts/publish.sh
# Windows PowerShell
powershell -ExecutionPolicy Bypass -File scripts/publish.ps1
# 等价手动
pnpm build
pnpm publish --access public --git-checks false --registry https://registry.npmjs.org浏览器 / 跨运行时说明
- 使用 Node 内置模块(
fs/promises、node:os、node:path、node:child_process),不能在浏览器运行。 - 依赖
simple-git、@easbot/terminal(统一交互 Prompt + 颜色主题 + 图标)、xdg-basedir、zod、yaml等。- 不再依赖
@clack/prompts/picocolors—— 全部收敛到@easbot/terminal(见 Session 4 决策)
- 不再依赖
engines.node >= 22.22.3— Node 22 LTS 推荐。
许可证
MIT
