@heihei0299/matt-skills 1.1.1 → 1.1.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.
@@ -24,12 +24,15 @@ Prompt: verify idempotent init without --force
24
24
  Command: `init` twice without `--force`, second with local edit to `AGENTS.md`
25
25
  Expected: second stdout `模板已存在.*跳过`, `上游技能:已装 0、跳过 22`; local edit preserved; exit 0.
26
26
 
27
- ### 3. Init --force with backup
28
- Prompt: verify forced init backs up
27
+ ### 3. Init --force with direct overwrite
28
+ Prompt: verify forced init directly overwrites
29
29
  Command: `init --force --dest <tmp>` after local edit
30
- Expected: stdout `已备份` + `备份 22`; `AGENTS.md.bak` exists with local edit; `AGENTS.md` restored from template; `.agents/skills/tdd.bak` exists; exit 0.
30
+ Expected: stdout `已覆盖` + `已装 22`; `AGENTS.md.bak` exists with local edit; `AGENTS.md` restored from template; no `.agents/skills/*.bak`; no `.opencode.bak`/`.pi.bak`; exit 0.
31
31
 
32
32
  ### 4. Sync on existing
33
+ Prompt: verify sync directly updates existing project
34
+ Command: `sync --dest <tmp>` after local edit
35
+ Expected: stdout `同步` + `已同步`/`已更新`; `AGENTS.md.bak` exists; `.agents/skills/tdd` updated; exit 0.
33
36
  Prompt: verify sync backs up existing project
34
37
  Command: `sync --dest <tmp>` after local edit
35
38
  Expected: stdout `同步` + `已备份`; `AGENTS.md.bak` exists; exit 0.
package/README.md CHANGED
@@ -31,16 +31,16 @@ npx @heihei0299/matt-skills init
31
31
  1. 复制 `template/` 快照(`AGENTS.md`、`.opencode/`、`.pi/`)到当前目录;
32
32
  2. 把上游技能(engineering 17 个 + productivity 5 个)复制到 `.agents/skills/`。
33
33
 
34
- 选项:`--dest <path>` 指定目标目录(默认当前目录);`--force` 覆盖已存在的文件并自动备份被覆盖文件到 `.bak`(默认跳过)。
34
+ 选项:`--dest <path>` 指定目标目录(默认当前目录);`--force` 覆盖已存在的文件(直接覆盖,`AGENTS.md` 会备份到 `.bak`)(默认跳过)。
35
35
 
36
36
  **增量同步(已有项目)**:已有项目更新到最新模板与技能:
37
37
 
38
38
  ```sh
39
- npx @heihei0299/matt-skills sync # 增量同步,备份被覆盖文件到 .bak
40
- npx @heihei0299/matt-skills sync --force # 覆盖不备份
39
+ npx @heihei0299/matt-skills sync # 增量同步,直接更新
40
+ npx @heihei0299/matt-skills sync --force # 同上(直接覆盖)
41
41
  ```
42
42
 
43
- `sync` 专为已有项目设计:自动检测 `AGENTS.md` 是否存在,存在则增量更新模板与上游技能并备份,不存在则等同全新 `init`。与 `init --force` 的区别:`sync` 默认即备份、语义更明确,建议已有项目优先用 `sync`。
43
+ `sync` 专为已有项目设计:自动检测 `AGENTS.md` 是否存在,存在则增量更新模板与上游技能(直接覆盖,`AGENTS.md` 会备份),不存在则等同全新 `init`。与 `init --force` 的区别:`sync` 语义更明确,建议已有项目优先用 `sync`。
44
44
 
45
45
  上游没有 `tdd-implement`、`grill-to-spec`、`diagnose-fix`、`commit-check`,复制天然不冲突。目标仓库会话即自动加载全部技能(上游在 `.agents/skills/`、独有在 `.opencode/skills/`;pi 侧独有在 `.pi/skills/`)与项目级全局配置(行为路由表、分文件约定);`issue-audit` 以子代理 + 命令形式分发(`.opencode/agents/`、`.opencode/commands/`);9 个显式触发技能注册为 opencode 命令(`.opencode/commands/`,`/命令名` 触发)。
46
46
 
@@ -116,13 +116,13 @@ pi 下对应能力以内置工具或已装扩展为准(`AGENTS.md`「能力边
116
116
 
117
117
  ```sh
118
118
  node bin/cli.js init [--dest <dir>] [--force] # 初始化项目:template + 上游技能
119
- node bin/cli.js sync [--dest <dir>] [--force] # 同步已有项目到最新(备份到 .bak)
119
+ node bin/cli.js sync [--dest <dir>] [--force] # 同步已有项目到最新(直接覆盖)
120
120
  node bin/cli.js list [--json] # 列出 .agents/skills/ 下全部技能及描述
121
121
  node bin/cli.js install [选项] # 把技能复制到目标工具目录(交互式选择)
122
122
  ```
123
123
 
124
- `init` 选项:`--dest <dir>` 指定目标目录(默认当前目录);`--force` 覆盖已存在的文件并备份到 `.bak`(默认跳过),见「初始化」。
125
- `sync` 选项:`--dest <dir>` 指定目标目录;`--force` 覆盖不备份(默认备份),见「初始化」增量同步。
124
+ `init` 选项:`--dest <dir>` 指定目标目录(默认当前目录);`--force` 覆盖已存在的文件(直接覆盖,`AGENTS.md` 会备份到 `.bak`)(默认跳过),见「初始化」。
125
+ `sync` 选项:`--dest <dir>` 指定目标目录;`--force` 直接覆盖(与默认一致),见「初始化」增量同步。
126
126
 
127
127
  `install` 选项:
128
128
 
package/bin/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { readdir, readFile, cp, stat, writeFile, mkdir } from 'node:fs/promises';
2
+ import { readdir, readFile, cp, stat } from 'node:fs/promises';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
@@ -17,17 +17,17 @@ const HELP = `matt-skills — install and manage this skill collection
17
17
 
18
18
  Usage:
19
19
  matt-skills init [options] Initialize a project: template + upstream skills
20
- matt-skills sync [options] Sync existing project to latest template + skills (backs up overwritten files to .bak)
20
+ matt-skills sync [options] Sync existing project to latest template + skills
21
21
  matt-skills list [--json] List available skills and their descriptions
22
22
  matt-skills install [options] Install skills (interactive by default)
23
23
  matt-skills --help Show this help
24
24
 
25
25
  Init options:
26
26
  --dest <path> Target directory (default: current directory)
27
- --force Overwrite existing files (backs up to .bak)
27
+ --force Overwrite existing files
28
28
  Sync options:
29
29
  --dest <path> Target directory (default: current directory)
30
- --force Overwrite without backup (default: backup to .bak)
30
+ --force Overwrite existing files
31
31
 
32
32
  Install options:
33
33
  --tools <a,b> Install for the given tools (codex, pi, opencode, claude); skips tool selection
@@ -88,21 +88,6 @@ async function backupIfExists(p) {
88
88
  return bak;
89
89
  }
90
90
 
91
- async function ensureSkillsGitignore(skillsDir) {
92
- try {
93
- await mkdir(skillsDir, { recursive: true });
94
- const gi = path.join(skillsDir, '.gitignore');
95
- const content = '# matt-skills backup — pi skips .bak via explicit filter + this fallback\n*.bak\n*.bak/\n';
96
- if (await pathExists(gi)) {
97
- const cur = await readFile(gi, 'utf8');
98
- if (cur.includes('*.bak')) return;
99
- await writeFile(gi, cur.endsWith('\n') ? `${cur}${content}` : `${cur}\n${content}`);
100
- } else {
101
- await writeFile(gi, content);
102
- }
103
- } catch {}
104
- }
105
-
106
91
  const TOOLS = ['codex', 'pi', 'opencode', 'claude'];
107
92
 
108
93
  const PROJECT_DIRS = {
@@ -188,15 +173,13 @@ async function initCommand({ dest, force }) {
188
173
  const target = dest ? path.resolve(process.cwd(), dest) : process.cwd();
189
174
  const marker = path.join(target, 'AGENTS.md');
190
175
  if (!force && (await pathExists(marker))) {
191
- process.stdout.write('模板已存在(AGENTS.md),跳过;用 --force 覆盖(自动备份到 .bak)\n');
176
+ process.stdout.write('模板已存在(AGENTS.md),跳过;用 --force 覆盖\n');
192
177
  } else {
193
178
  if (force && (await pathExists(marker))) {
194
- for (const name of ['AGENTS.md', '.opencode', '.pi']) {
195
- const cur = path.join(target, name);
196
- if (await pathExists(cur)) await backupIfExists(cur);
197
- }
179
+ const cur = path.join(target, 'AGENTS.md');
180
+ if (await pathExists(cur)) await backupIfExists(cur);
198
181
  await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
199
- process.stdout.write('模板:已备份到 .bak 并覆盖(AGENTS.md、.opencode/、.pi/)\n');
182
+ process.stdout.write('模板:已覆盖(AGENTS.md、.opencode/、.pi/)\n');
200
183
  } else {
201
184
  await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
202
185
  process.stdout.write('模板:已复制(AGENTS.md、.opencode/、.pi/)\n');
@@ -210,7 +193,6 @@ async function initCommand({ dest, force }) {
210
193
  const skillsDir = path.join(target, '.agents', 'skills');
211
194
  let installed = 0;
212
195
  let skipped = 0;
213
- let backedUp = 0;
214
196
  for (const name of upstream) {
215
197
  const src = path.join(SKILLS_DIR, name);
216
198
  const dst = path.join(skillsDir, name);
@@ -222,19 +204,10 @@ async function initCommand({ dest, force }) {
222
204
  skipped++;
223
205
  continue;
224
206
  }
225
- if (force && (await pathExists(dst))) {
226
- await backupIfExists(dst);
227
- backedUp++;
228
- }
229
207
  await cp(src, dst, { recursive: true, force: true });
230
208
  installed++;
231
209
  }
232
- if (force && backedUp > 0) {
233
- process.stdout.write(`上游技能:已装 ${installed}、跳过 ${skipped}、备份 ${backedUp} 到 .bak\n`);
234
- } else {
235
- process.stdout.write(`上游技能:已装 ${installed}、跳过 ${skipped}\n`);
236
- }
237
- await ensureSkillsGitignore(skillsDir);
210
+ process.stdout.write(`上游技能:已装 ${installed}、跳过 ${skipped}\n`);
238
211
  process.stdout.write(`目标路径:${target}\n`);
239
212
  }
240
213
 
@@ -247,15 +220,13 @@ async function syncCommand({ dest, force }) {
247
220
  await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
248
221
  process.stdout.write('模板:已复制(AGENTS.md、.opencode/、.pi/)\n');
249
222
  } else {
250
- process.stdout.write('同步:检测到现有项目,将增量更新并备份被覆盖文件到 .bak\n');
223
+ process.stdout.write('同步:检测到现有项目,将增量更新\n');
251
224
  if (backup) {
252
- for (const name of ['AGENTS.md', '.opencode', '.pi']) {
253
- const cur = path.join(target, name);
254
- if (await pathExists(cur)) await backupIfExists(cur);
255
- }
225
+ const cur = path.join(target, 'AGENTS.md');
226
+ if (await pathExists(cur)) await backupIfExists(cur);
256
227
  }
257
228
  await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
258
- process.stdout.write(backup ? '模板:已备份并同步(AGENTS.md、.opencode/、.pi/)\n' : '模板:已覆盖(AGENTS.md、.opencode/、.pi/)\n');
229
+ process.stdout.write(backup ? '模板:已同步(AGENTS.md、.opencode/、.pi/)\n' : '模板:已覆盖(AGENTS.md、.opencode/、.pi/)\n');
259
230
  }
260
231
  const entries = await readdir(SKILLS_DIR, { withFileTypes: true });
261
232
  const upstream = entries
@@ -265,7 +236,6 @@ async function syncCommand({ dest, force }) {
265
236
  const skillsDir = path.join(target, '.agents', 'skills');
266
237
  let installed = 0;
267
238
  let updated = 0;
268
- let backedUp = 0;
269
239
  for (const name of upstream) {
270
240
  const src = path.join(SKILLS_DIR, name);
271
241
  const dst = path.join(skillsDir, name);
@@ -275,10 +245,6 @@ async function syncCommand({ dest, force }) {
275
245
  }
276
246
  const exists = await pathExists(dst);
277
247
  if (exists) {
278
- if (backup) {
279
- await backupIfExists(dst);
280
- backedUp++;
281
- }
282
248
  await cp(src, dst, { recursive: true, force: true });
283
249
  updated++;
284
250
  } else {
@@ -286,12 +252,7 @@ async function syncCommand({ dest, force }) {
286
252
  installed++;
287
253
  }
288
254
  }
289
- if (backup) {
290
- process.stdout.write(`上游技能:新增 ${installed}、更新 ${updated}(已备份 ${backedUp} 到 .bak)\n`);
291
- } else {
292
- process.stdout.write(`上游技能:新增 ${installed}、更新 ${updated}\n`);
293
- }
294
- await ensureSkillsGitignore(skillsDir);
255
+ process.stdout.write(`上游技能:新增 ${installed}、更新 ${updated}\n`);
295
256
  process.stdout.write(`目标路径:${target}\n`);
296
257
  }
297
258
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heihei0299/matt-skills",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Agent skills + 项目配置模板:一条命令初始化 opencode / pi-agent 项目(含 mattpocock/skills 上游技能)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -24,12 +24,15 @@ Prompt: verify idempotent init without --force
24
24
  Command: `init` twice without `--force`, second with local edit to `AGENTS.md`
25
25
  Expected: second stdout `模板已存在.*跳过`, `上游技能:已装 0、跳过 22`; local edit preserved; exit 0.
26
26
 
27
- ### 3. Init --force with backup
28
- Prompt: verify forced init backs up
27
+ ### 3. Init --force with direct overwrite
28
+ Prompt: verify forced init directly overwrites
29
29
  Command: `init --force --dest <tmp>` after local edit
30
- Expected: stdout `已备份` + `备份 22`; `AGENTS.md.bak` exists with local edit; `AGENTS.md` restored from template; `.agents/skills/tdd.bak` exists; exit 0.
30
+ Expected: stdout `已覆盖` + `已装 22`; `AGENTS.md.bak` exists with local edit; `AGENTS.md` restored from template; no `.agents/skills/*.bak`; no `.opencode.bak`/`.pi.bak`; exit 0.
31
31
 
32
32
  ### 4. Sync on existing
33
+ Prompt: verify sync directly updates existing project
34
+ Command: `sync --dest <tmp>` after local edit
35
+ Expected: stdout `同步` + `已同步`/`已更新`; `AGENTS.md.bak` exists; `.agents/skills/tdd` updated; exit 0.
33
36
  Prompt: verify sync backs up existing project
34
37
  Command: `sync --dest <tmp>` after local edit
35
38
  Expected: stdout `同步` + `已备份`; `AGENTS.md.bak` exists; exit 0.
@@ -24,12 +24,15 @@ Prompt: verify idempotent init without --force
24
24
  Command: `init` twice without `--force`, second with local edit to `AGENTS.md`
25
25
  Expected: second stdout `模板已存在.*跳过`, `上游技能:已装 0、跳过 22`; local edit preserved; exit 0.
26
26
 
27
- ### 3. Init --force with backup
28
- Prompt: verify forced init backs up
27
+ ### 3. Init --force with direct overwrite
28
+ Prompt: verify forced init directly overwrites
29
29
  Command: `init --force --dest <tmp>` after local edit
30
- Expected: stdout `已备份` + `备份 22`; `AGENTS.md.bak` exists with local edit; `AGENTS.md` restored from template; `.agents/skills/tdd.bak` exists; exit 0.
30
+ Expected: stdout `已覆盖` + `已装 22`; `AGENTS.md.bak` exists with local edit; `AGENTS.md` restored from template; no `.agents/skills/*.bak`; no `.opencode.bak`/`.pi.bak`; exit 0.
31
31
 
32
32
  ### 4. Sync on existing
33
+ Prompt: verify sync directly updates existing project
34
+ Command: `sync --dest <tmp>` after local edit
35
+ Expected: stdout `同步` + `已同步`/`已更新`; `AGENTS.md.bak` exists; `.agents/skills/tdd` updated; exit 0.
33
36
  Prompt: verify sync backs up existing project
34
37
  Command: `sync --dest <tmp>` after local edit
35
38
  Expected: stdout `同步` + `已备份`; `AGENTS.md.bak` exists; exit 0.