npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@easbot/skills

v0.3.23

Published

Skills management system for EAS Agent ecosystem (add / remove / list / find / update / sync / use)

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.md frontmatter 的 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:各自维护独立技能目录
  • 安装矩阵 / 后安装核对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.sh partner audit 上报、OpenClaw 风险提示、遥测可冲刷(flushTelemetry
  • 统一交互 Prompt(Session 4):所有交互走 @easbot/terminal.Prompt namespace —— 取消语义收口(Prompt.cancelnever + 内置 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/agenteasbot 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 !== 0

easbot skillspackages/agent/src/cli/commands/skills.tsregisterSkillsCommand() 中注册,通过 Commander.js skills.<subcommand> 把 flag 转为 argv 后 dispatch 给 handleSkillsCliskills 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() 优先级(测试隔离):

  1. process.env.EASBOT_TEST_HOME测试专用最高优先级)
  2. 注入的 Global.Path.home
  3. 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-risks flag 可跳过)

交互提示规范(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/promisesnode:osnode:pathnode:child_process),不能在浏览器运行。
  • 依赖 simple-git@easbot/terminal(统一交互 Prompt + 颜色主题 + 图标)、xdg-basedirzodyaml 等。
    • 再依赖 @clack/prompts / picocolors —— 全部收敛到 @easbot/terminal(见 Session 4 决策)
  • engines.node >= 22.22.3 — Node 22 LTS 推荐。

许可证

MIT