team-skills 1.3.5 → 1.3.7
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/CHANGELOG.md +18 -0
- package/package.json +1 -1
- package/skills/team-brainstorm/SKILL.md +6 -6
- package/skills/team-finish/SKILL.md +6 -6
- package/skills/team-impl/SKILL.md +1 -1
- package/skills/team-test/SKILL.md +1 -1
- package/skills/team-verify/SKILL.md +4 -4
- package/skills/using-team-skills/SKILL.md +3 -3
- package/src/lib/fs-utils.js +7 -1
- package/src/lib/installers.js +58 -14
package/CHANGELOG.md
CHANGED
|
@@ -7,12 +7,30 @@
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.3.7] - 2026-06-26
|
|
11
|
+
|
|
12
|
+
### 修复
|
|
13
|
+
|
|
14
|
+
- 安装时自检:目标与源为同一文件时跳过删除/复制,防止误删源文件(`createSymlinkSafe` + `installSkillsProject` + `verifyGlobalSymlinks`)
|
|
15
|
+
|
|
16
|
+
## [1.3.6] - 2026-06-26
|
|
17
|
+
|
|
18
|
+
### 修复
|
|
19
|
+
|
|
20
|
+
- D12:移除 4 个 SKILL.md 中 `###` 标题后的 bare `>` 空行(using-team-skills×3、team-brainstorm×6、team-finish×6、team-verify×4),统一为标准空行格式
|
|
21
|
+
- D4:`verify_cmd` RESOLVE 链一致性修复——team-impl 和 team-test 补齐 `Cargo.toml`(与 team-verify/team-feedback 对齐)
|
|
22
|
+
|
|
10
23
|
## [1.3.5] - 2026-06-26
|
|
11
24
|
|
|
12
25
|
### 变更
|
|
13
26
|
|
|
14
27
|
- `team-refine` 每轮新增 Step 4:team-score 满分校验(硬门槛覆盖 + 评分维度覆盖 + 缺口修复),收敛条件同步强化
|
|
15
28
|
- 6 个 SKILL.md 质量修复:移除 bare `>` 空行(brainstorm)、`*none*` → `*default*` 兜底修正(review/security)、GATE 自检补充对抗性自问(brainstorm/orchestrator/score)
|
|
29
|
+
- CLI 模块化重构:提取 `installers.js` 共享模块(5 个函数),命令文件总行数 -278 行
|
|
30
|
+
|
|
31
|
+
### 修复
|
|
32
|
+
|
|
33
|
+
- 项目路径与全局路径重叠时保留 symlinks,跳过文件复制(避免 `update`/`init` 覆盖全局 symlinks)
|
|
16
34
|
|
|
17
35
|
## [1.3.4] - 2026-06-26
|
|
18
36
|
|
package/package.json
CHANGED
|
@@ -67,7 +67,7 @@ NO IMPLEMENTATION WITHOUT USER APPROVED DESIGN FIRST
|
|
|
67
67
|
## 执行步骤
|
|
68
68
|
|
|
69
69
|
### Phase 1:探索
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
> 理解用户要解决的真实问题和项目现状。不要急于构思方案——先确认"问题是什么"比"答案是什么"更重要。
|
|
72
72
|
|
|
73
73
|
1. **READ** 用户需求,提取核心目标和关键词
|
|
@@ -86,7 +86,7 @@ NO IMPLEMENTATION WITHOUT USER APPROVED DESIGN FIRST
|
|
|
86
86
|
8. **EXEC** 创建 `docs/tasks/{slug}/` 目录(**IF** 已存在 → 跳过)→ **ASSERT** `exit_code == 0`
|
|
87
87
|
|
|
88
88
|
### Phase 2:需求澄清(一次性提问)
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
> 挖出用户未说出的假设和隐性约束。好问题比好答案更有价值——问错问题意味着后续全部方向偏移。
|
|
91
91
|
|
|
92
92
|
> TRAP:你会倾向于接受用户的初始框架,不质疑其前提假设。
|
|
@@ -109,7 +109,7 @@ NO IMPLEMENTATION WITHOUT USER APPROVED DESIGN FIRST
|
|
|
109
109
|
- 整合用户回复,进入 Phase 3
|
|
110
110
|
|
|
111
111
|
### Phase 3:方案设计
|
|
112
|
-
|
|
112
|
+
|
|
113
113
|
> 探索根本不同的解决路径,不是同一个想法的三种措辞。每个方案应从不同的设计取舍出发(如性能 vs 简洁、侵入式 vs 非侵入式)。
|
|
114
114
|
|
|
115
115
|
> TRAP:锚定偏差——你会倾向于围绕第一个想到的方案展开变体,而非探索本质不同的路径。
|
|
@@ -136,7 +136,7 @@ NO IMPLEMENTATION WITHOUT USER APPROVED DESIGN FIRST
|
|
|
136
136
|
```
|
|
137
137
|
|
|
138
138
|
### Phase 4:展示设计
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
> 逐段确认而非一次倾倒,每段确认后再展示下一段。目标是让用户在每个维度上做出知情决策,而非被信息量压垮后草率同意(FP-1)。
|
|
141
141
|
|
|
142
142
|
逐段展示设计,每段后等待用户确认:
|
|
@@ -162,7 +162,7 @@ NO IMPLEMENTATION WITHOUT USER APPROVED DESIGN FIRST
|
|
|
162
162
|
- *default* → 向用户澄清确认意图
|
|
163
163
|
|
|
164
164
|
### Phase 5:产出 00-design-brief.md
|
|
165
|
-
|
|
165
|
+
|
|
166
166
|
> 将讨论共识固化为结构化文档。这是下游 Skill 的唯一输入——口头讨论不算数,写下来的才算数。
|
|
167
167
|
|
|
168
168
|
> SIGNAL:方案缺少具体下一步行动 → brainstorm 停留在空想层面,补充可执行的交付物定义。
|
|
@@ -221,7 +221,7 @@ NO IMPLEMENTATION WITHOUT USER APPROVED DESIGN FIRST
|
|
|
221
221
|
- 残留占位符 → 替换为实际值后重新 **WRITE**
|
|
222
222
|
|
|
223
223
|
### Phase 6:Handoff
|
|
224
|
-
|
|
224
|
+
|
|
225
225
|
> 确保 brainstorm 成果顺滑传递给下游 Skill,不丢失上下文。
|
|
226
226
|
|
|
227
227
|
**WRITE**(对话中)slug 目录路径 `docs/tasks/{slug}/`。
|
|
@@ -61,7 +61,7 @@ NO BRANCH COMPLETION WITHOUT TEST VERIFICATION FIRST
|
|
|
61
61
|
## 执行步骤
|
|
62
62
|
|
|
63
63
|
### Step 1:验证测试
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
> 用新鲜执行结果确认代码可交付。"上次跑过了"不是证据——只有当次输出才是。
|
|
66
66
|
|
|
67
67
|
> TRAP:你会倾向于引用上一轮的测试结果来跳过重新执行。Iron Law 不允许——每次进入 finish 都必须重新运行。
|
|
@@ -78,7 +78,7 @@ NO BRANCH COMPLETION WITHOUT TEST VERIFICATION FIRST
|
|
|
78
78
|
> 不可忽略失败继续展示选项(FP-4)。
|
|
79
79
|
|
|
80
80
|
### Step 1.5:凭证泄露扫描
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
> 推送前最后一道安全防线。凭证泄露一旦进入远程仓库,撤回成本极高。
|
|
83
83
|
|
|
84
84
|
**EXEC** `grep -rn -E '(AK|SK|access[_-]?key|secret[_-]?key|api[_-]?key|token|password|passwd|credential)\s*[:=]' .` — 推送前凭证扫描(RL-2)
|
|
@@ -87,7 +87,7 @@ NO BRANCH COMPLETION WITHOUT TEST VERIFICATION FIRST
|
|
|
87
87
|
- **ELSE** → **GOTO** Step 2
|
|
88
88
|
|
|
89
89
|
### Step 2:确定基准分支
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
> 精确找到合并目标。基准错误 = 合并到错误分支,后果比不合并更糟。
|
|
92
92
|
|
|
93
93
|
**RESOLVE** `base_branch`(首个命中即停):
|
|
@@ -105,7 +105,7 @@ NO BRANCH COMPLETION WITHOUT TEST VERIFICATION FIRST
|
|
|
105
105
|
- 失败(分支无公共祖先)→ **BLOCKED**,触发 **H3**
|
|
106
106
|
|
|
107
107
|
### Step 3:展示选项
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
> 让用户在完整信息下做选择。选项列表必须覆盖所有合理路径,不替用户预判。
|
|
110
110
|
|
|
111
111
|
**WRITE**(对话中)选项列表:
|
|
@@ -122,7 +122,7 @@ NO BRANCH COMPLETION WITHOUT TEST VERIFICATION FIRST
|
|
|
122
122
|
```
|
|
123
123
|
|
|
124
124
|
### Step 4:执行选择
|
|
125
|
-
|
|
125
|
+
|
|
126
126
|
> 严格按用户选择执行,不添加未要求的操作。不可逆操作必须二次确认。
|
|
127
127
|
|
|
128
128
|
> TRAP:合并成功后你会倾向于跳过重新测试("刚才不是通过了吗")。合并引入的代码交互可能导致回归——必须重新验证。
|
|
@@ -181,7 +181,7 @@ NO BRANCH COMPLETION WITHOUT TEST VERIFICATION FIRST
|
|
|
181
181
|
- *default* → **WRITE**(对话中)"请选择 A/B/C"
|
|
182
182
|
|
|
183
183
|
### Step 5:清理工作目录
|
|
184
|
-
|
|
184
|
+
|
|
185
185
|
> 操作完成后工作区必须干净。残留的 worktree 或未提交变更是下次操作的隐患。
|
|
186
186
|
|
|
187
187
|
> SIGNAL:`git status` 显示未提交变更 → 提交纪律不完整,有文件遗漏在 commit 之外。
|
|
@@ -277,7 +277,7 @@ NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
|
|
|
277
277
|
1. **RESOLVE** `verify_cmd`(首个命中即停):
|
|
278
278
|
1. `READ("05-risk.md", "§一验证计划")`
|
|
279
279
|
2. `READ("CLAUDE.md").verify_cmd` / `READ(".cursor/rules/")`
|
|
280
|
-
3. `READ("package.json").scripts.test` / `READ("Makefile")` / `READ("CI 配置")`
|
|
280
|
+
3. `READ("package.json").scripts.test` / `READ("Makefile")` / `READ("Cargo.toml")` / `READ("CI 配置")`
|
|
281
281
|
4. *none* → **NEEDS_CONTEXT**:请用户提供验证命令,记录到 `06-tdd-log.md`
|
|
282
282
|
|
|
283
283
|
2. **EXEC** `verify_cmd`(测试)→ **ASSERT** `exit_code == 0` && `failures == 0`
|
|
@@ -124,7 +124,7 @@ Phase 1 只分析,不写测试代码。
|
|
|
124
124
|
|
|
125
125
|
1. `READ("05-risk.md", "§一验证计划")`(精简模式下不存在属于正常)
|
|
126
126
|
2. `READ("CLAUDE.md").verify_cmd` / `READ(".cursor/rules/")`
|
|
127
|
-
3. `READ("package.json").scripts.test` / `READ("Makefile")`
|
|
127
|
+
3. `READ("package.json").scripts.test` / `READ("Makefile")` / `READ("Cargo.toml")`
|
|
128
128
|
4. *none* → **NEEDS_CONTEXT**:请用户提供测试命令
|
|
129
129
|
|
|
130
130
|
### Phase 4:补充测试(填补缺口)
|
|
@@ -53,7 +53,7 @@ NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE FIRST
|
|
|
53
53
|
## 执行步骤
|
|
54
54
|
|
|
55
55
|
### Step 1:确定验证命令
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
> 找到当前项目真正有效的验证命令。"上次用的命令"不等于"现在正确的命令"——项目配置可能已变更。
|
|
58
58
|
|
|
59
59
|
**RESOLVE** `verify_cmd`(首个命中即停):
|
|
@@ -66,7 +66,7 @@ NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE FIRST
|
|
|
66
66
|
- *default* → **NEEDS_CONTEXT**:请用户提供验证命令
|
|
67
67
|
|
|
68
68
|
### Step 2:执行验证
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
> 亲手执行,亲眼看到。"刚才跑过了"是最危险的借口——上一次结果不是当前事实。
|
|
71
71
|
|
|
72
72
|
> TRAP:你会倾向于引用上一轮输出而非重新执行。每次到这一步,默认假设之前的结果已失效。
|
|
@@ -81,7 +81,7 @@ NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE FIRST
|
|
|
81
81
|
- `exit_code != 0` || `failures > 0` → 记录失败详情 → fix → **GOTO** Step 2
|
|
82
82
|
|
|
83
83
|
### Step 3:报告结果
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
> 报告是验证的证据——不是总结感想,而是呈现可追溯的事实。缺少 `exit_code` 或输出摘要的报告等于没有报告。
|
|
86
86
|
|
|
87
87
|
> TRAP:"Tests pass" 不等于 "changed code is tested"。如果测试数量比上次减少了,可能是删除了失败测试而非修复了 bug。
|
|
@@ -123,7 +123,7 @@ NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE FIRST
|
|
|
123
123
|
> ```
|
|
124
124
|
|
|
125
125
|
### Step 4:工具失败恢复
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
> 区分"验证不通过"与"验证命令本身失败"。前者是代码问题,后者是环境问题。修复环境不等于验证通过。
|
|
128
128
|
|
|
129
129
|
> 验证命令本身执行失败(超时、进程崩溃、环境错误),不同于验证不通过。
|
|
@@ -70,7 +70,7 @@ NO SKILL RECOMMENDATION WITHOUT SCENE ANALYSIS FIRST
|
|
|
70
70
|
## 执行步骤
|
|
71
71
|
|
|
72
72
|
### Step 1:分析用户场景
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
> 精准识别用户当前工程阶段,而非表面关键词匹配。错误分诊比慢分诊代价更高。
|
|
75
75
|
|
|
76
76
|
> TRAP:你会倾向于推荐 `team-orchestrator`(最完整的流水线),即使用户只需要一个单点 Skill。
|
|
@@ -101,7 +101,7 @@ NO SKILL RECOMMENDATION WITHOUT SCENE ANALYSIS FIRST
|
|
|
101
101
|
13. *none* → **NEEDS_CONTEXT**:请用户描述当前阶段和目标
|
|
102
102
|
|
|
103
103
|
### Step 2:推荐并说明理由
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
> 推荐的核心是"最短路径"——从用户当前状态到目标状态经过最少的 Skill。过度推荐等于浪费用户时间。
|
|
106
106
|
|
|
107
107
|
> GOOD:`用户报告登录接口 500 错误。当前阶段:调试。推荐:team-debug。理由:已有明确错误现象,需先定位根因再决定是否修改规格或实现。启动方式:/team-debug`
|
|
@@ -115,7 +115,7 @@ NO SKILL RECOMMENDATION WITHOUT SCENE ANALYSIS FIRST
|
|
|
115
115
|
**WRITE**(对话中)推荐结果:推荐 Skill + 推荐理由 + 启动方式
|
|
116
116
|
|
|
117
117
|
### Step 3:可选 — 展示流程图
|
|
118
|
-
|
|
118
|
+
|
|
119
119
|
> 仅在用户主动需要全貌时展示,不主动展开——信息过载是另一种误导。
|
|
120
120
|
|
|
121
121
|
**IF** 用户需要了解全貌 → 展示 Mermaid 流程图
|
package/src/lib/fs-utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
mkdirSync, symlinkSync, unlinkSync, readlinkSync,
|
|
3
3
|
lstatSync, existsSync, readdirSync, statSync,
|
|
4
|
-
copyFileSync, chmodSync, rmSync,
|
|
4
|
+
copyFileSync, chmodSync, rmSync, realpathSync,
|
|
5
5
|
} from 'node:fs';
|
|
6
6
|
import { join, dirname } from 'node:path';
|
|
7
7
|
|
|
@@ -25,6 +25,12 @@ export function createSymlinkSafe(source, target, { force = false, dryRun = fals
|
|
|
25
25
|
if (!force) return 'conflict';
|
|
26
26
|
unlinkSync(target);
|
|
27
27
|
} else if (existsSync(target)) {
|
|
28
|
+
// 目标存在但不是软连接 — 解析真实路径,如果是同一文件则视为已安装
|
|
29
|
+
try {
|
|
30
|
+
if (realpathSync(target) === realpathSync(source)) return 'exists';
|
|
31
|
+
} catch {
|
|
32
|
+
// 任一无法解析,继续走 force 逻辑
|
|
33
|
+
}
|
|
28
34
|
if (!force) return 'conflict';
|
|
29
35
|
rmSync(target, { recursive: true });
|
|
30
36
|
}
|
package/src/lib/installers.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
|
-
import { existsSync, readdirSync, rmSync, copyFileSync } from 'node:fs';
|
|
2
|
+
import { existsSync, readdirSync, rmSync, copyFileSync, realpathSync } from 'node:fs';
|
|
3
3
|
import { createSymlinkSafe, ensureDir, isSymlink, copyRecursive } from './fs-utils.js';
|
|
4
4
|
import { GLOBAL_TARGETS, PROJECT_IDE_DIRS } from './constants.js';
|
|
5
5
|
import * as log from './logger.js';
|
|
@@ -56,21 +56,44 @@ export function verifyGlobalSymlinks(targets, skills, rules) {
|
|
|
56
56
|
log.heading('验证安装');
|
|
57
57
|
let errors = 0;
|
|
58
58
|
|
|
59
|
-
const verify = (label, dest) => {
|
|
60
|
-
if (isSymlink(dest)) {
|
|
61
|
-
log.success(label);
|
|
62
|
-
} else {
|
|
63
|
-
log.error(`${label} 未正确安装`);
|
|
64
|
-
errors++;
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
59
|
for (const t of targets) {
|
|
69
60
|
for (const skill of skills) {
|
|
70
|
-
|
|
61
|
+
const dest = join(t.dir, skill.name);
|
|
62
|
+
const label = `${t.label} Skill: ${skill.name}`;
|
|
63
|
+
if (isSymlink(dest)) {
|
|
64
|
+
log.success(label);
|
|
65
|
+
} else if (existsSync(dest)) {
|
|
66
|
+
try {
|
|
67
|
+
if (realpathSync(dest) === realpathSync(skill.path)) {
|
|
68
|
+
log.skip(`${label}(已存在,跳过)`);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
} catch { /* 忽略解析失败 */ }
|
|
72
|
+
log.error(`${label} 未正确安装`);
|
|
73
|
+
errors++;
|
|
74
|
+
} else {
|
|
75
|
+
log.error(`${label} 未正确安装`);
|
|
76
|
+
errors++;
|
|
77
|
+
}
|
|
71
78
|
}
|
|
72
79
|
for (const rule of rules) {
|
|
73
|
-
|
|
80
|
+
const dest = join(t.dir, '_team-rules', rule.name);
|
|
81
|
+
const label = `${t.label} Rule: ${rule.name}`;
|
|
82
|
+
if (isSymlink(dest)) {
|
|
83
|
+
log.success(label);
|
|
84
|
+
} else if (existsSync(dest)) {
|
|
85
|
+
try {
|
|
86
|
+
if (realpathSync(dest) === realpathSync(rule.path)) {
|
|
87
|
+
log.skip(`${label}(已存在,跳过)`);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
} catch { /* 忽略解析失败 */ }
|
|
91
|
+
log.error(`${label} 未正确安装`);
|
|
92
|
+
errors++;
|
|
93
|
+
} else {
|
|
94
|
+
log.error(`${label} 未正确安装`);
|
|
95
|
+
errors++;
|
|
96
|
+
}
|
|
74
97
|
}
|
|
75
98
|
}
|
|
76
99
|
|
|
@@ -98,7 +121,16 @@ export function installSkillsProject(projectDir, ides, skills, rules, { dryRun,
|
|
|
98
121
|
for (const skill of skills) {
|
|
99
122
|
const dest = join(skillsDst, skill.name);
|
|
100
123
|
if (!dryRun) {
|
|
101
|
-
|
|
124
|
+
// 如果目标就是源文件本身,跳过删除+复制(否则删了就复制不了)
|
|
125
|
+
if (existsSync(dest)) {
|
|
126
|
+
try {
|
|
127
|
+
if (realpathSync(dest) === realpathSync(skill.path)) {
|
|
128
|
+
log.skip(`${tag}Skill: ${skill.name}(自身,跳过)`);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
} catch { /* 忽略解析失败 */ }
|
|
132
|
+
rmSync(dest, { recursive: true });
|
|
133
|
+
}
|
|
102
134
|
copyRecursive(skill.path, dest);
|
|
103
135
|
}
|
|
104
136
|
log.success(`${tag}Skill: ${skill.name}`);
|
|
@@ -108,7 +140,19 @@ export function installSkillsProject(projectDir, ides, skills, rules, { dryRun,
|
|
|
108
140
|
const rulesDst = join(skillsDst, '_team-rules');
|
|
109
141
|
if (!dryRun) ensureDir(rulesDst);
|
|
110
142
|
for (const r of rules) {
|
|
111
|
-
if (!dryRun)
|
|
143
|
+
if (!dryRun) {
|
|
144
|
+
const ruleDest = join(rulesDst, r.name);
|
|
145
|
+
// 如果目标就是源文件本身,跳过复制
|
|
146
|
+
if (existsSync(ruleDest)) {
|
|
147
|
+
try {
|
|
148
|
+
if (realpathSync(ruleDest) === realpathSync(r.path)) {
|
|
149
|
+
log.skip(`${tag}Rule: ${r.name}(自身,跳过)`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
} catch { /* 忽略解析失败 */ }
|
|
153
|
+
}
|
|
154
|
+
copyFileSync(r.path, ruleDest);
|
|
155
|
+
}
|
|
112
156
|
log.success(`${tag}Rule: ${r.name}`);
|
|
113
157
|
count++;
|
|
114
158
|
}
|