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

skill-kits

v1.0.5

Published

Agent Skill 脚手架与编译工具链,让 Skill 开发工程化

Readme

skill-kits

Skill 工程化 —— 用 TypeScript 写 Agent Skill,编译为单文件 ESM,零依赖运行。
产物遵循 agentskills.io 规范,运行需 Node.js >= 18。

Why skill-kits?

| 痛点 | 解法 | | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | 公共模块无法复用 | skill-kits/runtime 内置 HTTP、路由、输出、错误等工具,直接 import;init 生成的 monorepo 自带 packages/shared,esbuild 自动内联产物 | | 没有标准模版 | pnpm new <name> 生成对齐规范的 SKILL.md + 工程骨架 | | JS 无类型补全,TS 又依赖 tsc/bun | 用 TS 写 Skill 享受类型补全;pnpm build 用 esbuild 秒级打包为单文件 main.mjs,产物零依赖,Agent 端只需 Node 即可运行 | | 缺乏质量检测 | pnpm lint 校验 SKILL.md 的 name/dir 一致性、行数、引用合法性、description 触发性;build 默认先跑 lint |

安装

npx skill-kits init my-skills   # 或在当前目录:npx skill-kits init
cd my-skills && pnpm install

init 生成一个 pnpm monorepo:

my-skills/
├── pnpm-workspace.yaml
├── package.json
└── packages/
    ├── shared/        # 跨 Skill 复用的业务公共模块(@skills/shared)
    └── skills/        # 每个 Skill 一个子包,由 new 生成
        └── daily-report/

快速开始

pnpm new daily-report              # 新增 Skill
pnpm dev daily-report --out ~/.agent/skills   # watch + 同步到 agent 目录
pnpm build daily-report            # 编译(自动 lint + zip)

写 TS,跑 JS

      源码                                 产物
┌──────────────────┐           ┌──────────────────────────┐
│  src/main.ts     │           │  dist/                   │
│  src/commands/   │  build    │  ├── <skill-name>/       │
│  references/     │ ───────►  │  │   ├── SKILL.md        │
│  assets/         │  esbuild  │  │   ├── scripts/        │
│  SKILL.md        │           │  │   │   └── main.mjs    │
└──────────────────┘           │  │   ├── references/     │
                               │  │   └── assets/         │
                               │  └── <skill-name>.zip    │
                               └──────────────────────────┘
  TypeScript + runtime import      单文件 ESM,零依赖
                                   Agent: node scripts/main.mjs

CLI

init 生成的 workspace 里,已挂载 pnpm new / dev / build / lint 脚本,下表写法等价。

| 命令 | 作用 | | --------------------------- | ------------------------------------------------------------ | | npx skill-kits init [dir] | 生成 Skill 工作区骨架(缺省为当前目录) | | pnpm new <name> | 新增一个 Skill(含 references/ assets/ 占位) | | pnpm build [name] | 编译 → 默认 lint + pack 成 dist/<name>.zip | | pnpm dev <name> | watch 模式,src/ + SKILL.md + references/ + assets/ 即时同步 | | pnpm lint [name] | 单独校验 SKILL.md |

选项

| 命令 | 选项 | 说明 | | ------- | ------------------- | -------------------------------------------------------------- | | init | -n, --name <name> | 项目名称,缺省取目标目录名 | | build | --minify | 压缩产物 JS | | | --no-lint | 跳过构建前 lint | | | --no-pack | 跳过构建后打包 zip | | dev | --out <dir> | 产物输出到 <dir>/<name>/,常用于直接同步到 agent skills 目录 | | | --no-sourcemap | 关闭 sourcemap(默认 inline) | | | --run [args] | 重编后自动 node <bundle> [args],用于本地快速回归 | | lint | --strict | 把 warn 视作 error | | 所有 | --cwd <dir> | workspace 根目录(默认当前目录) |

运行时 API

skill-kits/runtime 导入,编译时自动内联进产物。

命令路由

createRouter 自动处理 --help、必填参数校验、错误归一化:

import { createRouter, writeResult } from "skill-kits/runtime";

const router = createRouter({
  name: "daily-report",
  description: "...",
  commonArgs: {
    // 每个子命令都自动注入的公共参数
    domain: { type: "string", required: true, desc: "平台域名" },
    token: { type: "string", required: true, desc: "SSO token" },
  },
});

router.command({
  name: "fetch",
  description: "拉取昨日数据",
  args: {
    date: { type: "string", required: true, desc: "YYYY-MM-DD" },
    limit: { type: "number", default: 100, desc: "条数上限" },
    tag: { type: "list", desc: "过滤标签,可重复" },
    env: { type: "string", choices: ["boe", "online"] as const, desc: "环境" },
    filter: { type: "json", desc: "复杂过滤条件,JSON 自动解析" },
  },
  async handler({ date, limit, tag, env, filter, domain, token }) {
    // env 类型为 "boe" | "online"(choices 推断),filter 已自动 JSON.parse
    writeResult({ ok: true, items: [] });
  },
});

router.run(process.argv.slice(2));

args / commonArgs 支持 5 种类型:string / number / boolean / list / jsonrequired 缺失时自动抛 UserInputErrorchoices 限定枚举值并提供类型推断;type: "json" 自动 JSON.parse

输出

writeResult(payload)                                  // stdout,单行 JSON,供 Agent 消费
writeError(errorOrMessage, { code?, extra? })         // stderr + exitCode=1
notify(message)                                       // stderr,进度/阶段提示(ℹ️ 前缀)
handleCliError(error)                                 // 顶层 catch 兜底,自动识别 SkillError 子类

HTTP

零依赖,基于全局 fetch(Node 18+)。不抛错——网络异常 / 非 2xx 都通过 res.ok 表达,业务自行决定如何处理:

import { httpGet, httpPost } from "skill-kits/runtime";

const res = await httpGet<UserInfo>("https://api.example.com/me", {
  headers: { authorization: `Bearer ${token}` },
  query: { fields: "id,name" },
  timeoutMs: 10_000,
});
if (!res.ok) throw new HttpError(res.status, url, res.statusText);
console.log(res.data?.name);

HttpRequestOptionsheaders / query / body / signal / timeoutMs / redirect

环境变量

读取环境变量工具方法,requireEnv 缺失时统一抛 USER_INPUT_ERROR(code=MISSING_ENV),LLM 可据此引导用户配置:

import { requireEnv, optionalEnv } from "skill-kits/runtime";

const token = requireEnv("OPENAPI_TOKEN", {
  hint: "申请地址:https://example.com/get-token",
});
// 未设置 → stderr: { "ok": false, "code": "USER_INPUT_ERROR", "error": "缺少环境变量 OPENAPI_TOKEN。申请地址:..." }

const pat = optionalEnv("FIGMA_PERSONAL_ACCESS_TOKEN"); // string | null

轮询心跳

长轮询场景(D2C 生码、SSO 回调等)可以用 sleepWithHeartbeat 替代 setTimeout,每 5 秒往 stderr 写一次进度,防止 Agent 误判 idle 杀进程:

import { sleepWithHeartbeat } from "skill-kits/runtime";

await sleepWithHeartbeat(60_000, {
  message: (rem) => `等待生码... 剩余 ${rem}s`,
});
// stderr 每 5s: ℹ️ 等待生码... 剩余 55s
// stderr 每 5s: ℹ️ 等待生码... 剩余 50s
// ...

SleepWithHeartbeatOptionsintervalMs / message(字符串或函数)。

错误体系

所有业务错误继承 SkillErrorhandleCliError 会自动识别子类并输出结构化 JSON 到 stderr。内置错误码供 LLM 匹配对应处理策略:

| 类 | code | 场景 | | ------------------ | ------------------ | ------------------------ | | UserInputError | USER_INPUT_ERROR | 参数缺失 / 格式错误 | | AuthError | AUTH_ERROR | Token 过期 / 权限不足 | | HttpError | HTTP_ERROR | 上游 HTTP 非 2xx | | BusinessApiError | BIZ_<code> | HTTP 200 但业务 code ≠ 0 |

import {
  SkillError,
  UserInputError,
  BusinessApiError,
} from "skill-kits/runtime";

// UserInputError:参数校验失败
throw new UserInputError("activityId 不能为空", { field: "activityId" });
// stderr → {"ok":false,"code":"USER_INPUT_ERROR","error":"activityId 不能为空","details":{"field":"activityId"}}

// 自定义 BusinessApiError 错误
throw new BusinessApiError(-10000, "token 过期", {
  hintMap: { [-10000]: "请重新登录", [-14]: "记录不存在" },
});
// stderr → {"ok":false,"code":"BIZ_-10000","error":"[code=-10000] token 过期(请重新登录)"}

// 自定义业务错误:继承 SkillError,code 自由命名
class RateLimitError extends SkillError {
  constructor(retryAfterSec?: number) {
    super("RATE_LIMIT", "请求过于频繁", { retryAfterSec });
  }
}
throw new RateLimitError(30);
// stderr → {"ok":false,"code":"RATE_LIMIT","error":"请求过于频繁","details":{"retryAfterSec":30}}

业务公共模块

runtime 解决基础设施复用,业务领域的工具/常量/客户端走 packages/shared

# 在 Skill 子包的 package.json 中加依赖
# "dependencies": { "@skills/shared": "workspace:*" }
pnpm install
import { greet } from "@skills/shared";

构建时 esbuild 把 @skills/shared 内联进产物,依旧是零依赖单文件。不需要则保持空目录即可。

渐进式披露

长文档放 references/、资产放 assets/,Agent 在 SKILL.md 中按需引用,避免一次性加载污染上下文。引用方式参见 agentskills.io 规范

配置

在 workspace 根目录放 .skillkitrc.json 可自定义 lint 行为:

{
  "lint": {
    "triggerHints": ["何时", "trigger", "use when"],
    "negativeHints": ["不要", "do not"],
    "descriptionMinChars": 80,
    "bodyLinesWarn": 400,
    "bodyLinesFail": 500
  }
}

Lint 规则

| 规则 | 级别 | 说明 | | ------------------------- | ------------ | ------------------------------------------ | | name-matches-dir | error | name 必须等于父目录名 | | body-line-limit | error | SKILL.md body > 500 行 | | body-line-soft | warn | SKILL.md body > 400 行,建议拆 references/ | | ref-relative | error | 引用必须是相对路径 | | ref-depth | error / warn | ../ 报 error;>1 层目录报 warn | | description-length | warn | description < 80 字符,过短易欠触发 | | description-trigger | info | description 缺少「何时触发」线索 | | description-negative | info | 建议补充「不要触发」反例 | | frontmatter-unknown-key | warn | 出现规范未定义的 frontmatter key |

License

MIT