@wangkh/skill-sync-cli 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -262,6 +262,11 @@ working include `https://gh-proxy.com/`, `https://ghproxy.net/`, and
262
262
  `https://ghfast.top/`. To speed up the `skills` CLI download itself on a fresh
263
263
  machine, configure an npm registry mirror such as `https://registry.npmmirror.com`.
264
264
 
265
+ Child `skills` commands run with `DO_NOT_TRACK=1`, so telemetry stays off. A
266
+ known Windows exit crash in the `skills` CLI after a completed install is
267
+ tolerated: when the files are in place, `sync` treats the group as installed
268
+ instead of failing.
269
+
265
270
  For project-scoped skills, set:
266
271
 
267
272
  ```json
@@ -279,6 +284,21 @@ location. From the target application project, run:
279
284
  npx @wangkh/skill-sync-cli sync --config /path/to/my-skills/skills.json
280
285
  ```
281
286
 
287
+ ## Agent Skill
288
+
289
+ The repository ships an agent skill (`skills/skill-sync/SKILL.md`) that teaches
290
+ an agent how to use this CLI. Install it from the repository:
291
+
292
+ ```bash
293
+ npx skills add yudaiyan/skill-sync-cli
294
+ ```
295
+
296
+ Or declare it in the manifest and let `sync` install it:
297
+
298
+ ```json
299
+ { "name": "skill-sync", "source": "yudaiyan/skill-sync-cli" }
300
+ ```
301
+
282
302
  ## Run Before the First Release
283
303
 
284
304
  From a source checkout, the following commands work without installing project
package/README.zh-CN.md CHANGED
@@ -132,6 +132,8 @@ npx @wangkh/skill-sync-cli sync --github-mirror https://gh-proxy.com/
132
132
 
133
133
  镜像通过 git 的 `insteadOf` 重写注入,只对本次命令生效,不会修改全局 git 配置。实测可用的免费公益镜像包括 `https://gh-proxy.com/`、`https://ghproxy.net/`、`https://ghfast.top/`。新机器上如果 `skills` CLI 下载慢,可以配置 npm 镜像源 `https://registry.npmmirror.com`。
134
134
 
135
+ wrapper 会以 `DO_NOT_TRACK=1` 运行 `skills` CLI(关闭遥测)。它在 Windows 上安装完成后偶发退出崩溃(0xC0000409);只要文件已就位,`sync` 会把该组视为安装成功,不再误判失败。
136
+
135
137
  只预览,或者在单个 Skill 失败后继续处理其他条目:
136
138
 
137
139
  ```bash
@@ -186,6 +188,20 @@ Git 负责在机器之间传递清单,`sync` 根据本地清单安装 Skills
186
188
 
187
189
  清单是这个脚本定义的格式;脚本读取后逐项调用官方 `skills` CLI。上游的 `.skill-lock.json` 继续由官方 CLI 维护。
188
190
 
191
+ ## 给 agent 用的 skill
192
+
193
+ 仓库自带一个 agent skill(`skills/skill-sync/SKILL.md`),用来告诉 agent 如何使用本 CLI。可以直接安装:
194
+
195
+ ```bash
196
+ npx skills add yudaiyan/skill-sync-cli
197
+ ```
198
+
199
+ 也可以加进清单,交给 `sync` 安装:
200
+
201
+ ```json
202
+ { "name": "skill-sync", "source": "yudaiyan/skill-sync-cli" }
203
+ ```
204
+
189
205
  ## 发布前使用
190
206
 
191
207
  获取项目源码后,可以在源码目录直接运行,无需安装项目依赖:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wangkh/skill-sync-cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Sync declared agent skills across machines through the skills CLI",
5
5
  "author": "wkh",
6
6
  "repository": {
@@ -27,6 +27,7 @@
27
27
  "bin",
28
28
  "src",
29
29
  "schemas",
30
+ "skills",
30
31
  "README.md",
31
32
  "README.zh-CN.md",
32
33
  "RELEASING.md",
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: skill-sync
3
+ description: >-
4
+ Manage the user's portable agent-skill manifest with the skill-sync CLI
5
+ (@wangkh/skill-sync-cli). Use when the user wants to sync, back up, or
6
+ restore agent skills across machines ("同步我的 skills", "恢复 skill 环境",
7
+ "新电脑安装 skills"), add or remove a skill in their manifest
8
+ ("把 skill 加到清单"), preview or validate the manifest, or install skills
9
+ when GitHub is unreachable. Also use when a skill installation fails and the
10
+ user asks why or how to retry.
11
+ ---
12
+
13
+ # skill-sync
14
+
15
+ `@wangkh/skill-sync-cli` keeps a portable JSON manifest of third-party agent
16
+ skills and installs them through the official `skills` CLI. The manifest is the
17
+ single source of truth; the tool only writes it during `init`.
18
+
19
+ ## When to use
20
+
21
+ - Sync or restore skills on a machine: `sync`
22
+ - Add a skill to the manifest after finding it: edit the manifest, then `sync`
23
+ - Preview or validate before installing: `plan`, `validate`
24
+ - GitHub is blocked or slow: run `sync --github-mirror https://gh-proxy.com/`
25
+ - An install failed: check retries, the mirror, or `--continue-on-error`
26
+
27
+ ## Commands
28
+
29
+ Run through npx so no global install is needed:
30
+
31
+ ```bash
32
+ npx @wangkh/skill-sync-cli init # create the manifest (keeps an existing one)
33
+ npx @wangkh/skill-sync-cli path # print the manifest path in use
34
+ npx @wangkh/skill-sync-cli validate # parse and validate without network
35
+ npx @wangkh/skill-sync-cli plan # print the exact skills commands
36
+ npx @wangkh/skill-sync-cli sync # install or update declared skills
37
+ ```
38
+
39
+ Useful options:
40
+
41
+ | Option | Meaning |
42
+ | --- | --- |
43
+ | `-c, --config <file>` | Use another manifest file (all commands) |
44
+ | `--from <url>` | `init` from a published manifest URL |
45
+ | `--dry-run` | Preview without installing |
46
+ | `--continue-on-error` | Keep going after a failure; exit code stays non-zero |
47
+ | `--retries <n>` | Retry failed installs (default 2) |
48
+ | `--github-mirror <url>` | Route GitHub clones and update checks through a mirror |
49
+ | `--force` | `init`: replace the file; `sync`: reinstall even if unchanged |
50
+
51
+ ## Manifest
52
+
53
+ Default location:
54
+
55
+ - Windows: `%USERPROFILE%\.config\skill-sync\skills.json`
56
+ - macOS/Linux: `~/.config/skill-sync/skills.json`
57
+
58
+ Skill entries require `name` (the upstream skill name) and `source`
59
+ (`owner/repo`, Git URL, skill URL, or archive). Optional fields are
60
+ `description`, `ref`, `enabled`, `agents`, `scope`, and `copy`; shared
61
+ defaults live under `defaults`, and the `skills` CLI version is pinned under
62
+ `cli`.
63
+
64
+ To add a skill, append an entry and run `sync`. Confirm the upstream name
65
+ first:
66
+
67
+ ```bash
68
+ npx --yes skills@1.5.22 add <owner>/<repo> --list
69
+ ```
70
+
71
+ ## Behavior worth knowing
72
+
73
+ - Entries sharing `source`, `ref`, `agents`, `scope`, and `copy` install with
74
+ one `skills add` call; a failed batch falls back to installing each skill.
75
+ - `sync` records revisions in `~/.config/skill-sync/state.json` and skips
76
+ groups whose revision and installed files are unchanged. `--force`
77
+ overrides the skip.
78
+ - When the update check cannot reach the remote but the installed copy still
79
+ exists, `sync` keeps it instead of failing.
80
+ - GitHub unreachable: `--github-mirror https://gh-proxy.com/` (alternatives:
81
+ `https://ghproxy.net/`, `https://ghfast.top/`). For the `skills` CLI
82
+ download itself, configure an npm registry mirror such as
83
+ `https://registry.npmmirror.com`.
84
+
85
+ ## Security
86
+
87
+ A skill is agent instructions and may run scripts; review third-party skills
88
+ before adding them. Prefer trusted repositories and immutable commit refs.
89
+
90
+ Full documentation lives in the project README and
91
+ `schemas/skills-sync.schema.json`.
package/src/commands.mjs CHANGED
@@ -30,6 +30,9 @@ import { downloadManifest } from "./remote.mjs"
30
30
 
31
31
  export const DEFAULT_RETRIES = 2
32
32
  const DEFAULT_RETRY_DELAY_MS = 2000
33
+ // The skills CLI occasionally aborts on exit after a completed install on
34
+ // Windows (libuv teardown assertion). These are the observed exit codes.
35
+ const POST_INSTALL_CRASH_CODES = new Set([3221226505, -1073740791])
33
36
 
34
37
  const SAMPLE_MANIFEST = {
35
38
  version: 1,
@@ -171,11 +174,21 @@ export async function syncCommand(manifestFilename, options = {}) {
171
174
 
172
175
  const key = stateKey(group.skills)
173
176
  const entry = stateEntry(state, filename, key)
174
- const installedHere = allInstalled(group.skills, {
177
+ const installScope = {
175
178
  global: group.skills[0].scope === "global",
176
179
  cwd,
177
180
  home,
178
- })
181
+ }
182
+ const installedHere = allInstalled(group.skills, installScope)
183
+ // A completed install followed by the known exit crash counts as success.
184
+ const executeTolerant = (command, runOptions) => {
185
+ const result = execute(command, runOptions)
186
+ if (POST_INSTALL_CRASH_CODES.has(statusCode(result)) && allInstalled(group.skills, installScope)) {
187
+ console.error(`[${sourceLabel(group.skills)}] the skills CLI crashed after installing (known Windows bug); treating the install as complete`)
188
+ return { status: 0 }
189
+ }
190
+ return result
191
+ }
179
192
  // Only a previous install can be skipped, so check the remote before
180
193
  // installing only when there is a record and the files are still present.
181
194
  // A first install records the revision afterwards.
@@ -202,7 +215,7 @@ export async function syncCommand(manifestFilename, options = {}) {
202
215
  if (group.skills.length === 1) {
203
216
  const skill = group.skills[0]
204
217
  printDescriptions(group.skills)
205
- const result = await runWithRetries(execute, group.command, {
218
+ const result = await runWithRetries(executeTolerant, group.command, {
206
219
  cwd: options.cwd,
207
220
  env: gitEnv,
208
221
  retries,
@@ -219,7 +232,7 @@ export async function syncCommand(manifestFilename, options = {}) {
219
232
  // A batched command shares one fetch. Since a failure could come from a
220
233
  // single bad name or a transient error, retry each entry individually
221
234
  // when the batch does not succeed.
222
- const batch = execute(group.command, { cwd: options.cwd, env: gitEnv })
235
+ const batch = executeTolerant(group.command, { cwd: options.cwd, env: gitEnv })
223
236
  if (statusCode(batch) !== 0) {
224
237
  if (batch.signal) {
225
238
  failures += group.skills.length
@@ -229,7 +242,7 @@ export async function syncCommand(manifestFilename, options = {}) {
229
242
  } else {
230
243
  console.error(`[${sourceLabel(group.skills)}] batch install failed; retrying each skill individually`)
231
244
  for (const skill of group.skills) {
232
- const result = await runWithRetries(execute, commandFor(skill, manifest.cli), {
245
+ const result = await runWithRetries(executeTolerant, commandFor(skill, manifest.cli), {
233
246
  cwd: options.cwd,
234
247
  env: gitEnv,
235
248
  retries,
package/src/runner.mjs CHANGED
@@ -89,6 +89,13 @@ function windowsNpxCli(env) {
89
89
  return filename
90
90
  }
91
91
 
92
+ // The skills CLI can crash on exit on some Windows setups (a libuv teardown
93
+ // assertion) while its telemetry flush is pending. DO_NOT_TRACK disables that
94
+ // flush so the process exits cleanly; it is also a privacy default.
95
+ export function childEnv(env = process.env) {
96
+ return { ...env, DO_NOT_TRACK: "1" }
97
+ }
98
+
92
99
  export function runCommand(command, { cwd, env = process.env, timeout } = {}) {
93
100
  try {
94
101
  // Windows cannot spawn .cmd files directly. Run npx's JS entry point so
@@ -97,7 +104,7 @@ export function runCommand(command, { cwd, env = process.env, timeout } = {}) {
97
104
  return spawnSync(useNode ? process.execPath : command.executable,
98
105
  useNode ? [windowsNpxCli(env), ...command.args] : command.args, {
99
106
  cwd,
100
- env,
107
+ env: childEnv(env),
101
108
  timeout,
102
109
  stdio: "inherit",
103
110
  windowsHide: true,