team-skills 1.3.6 → 1.3.8

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 CHANGED
@@ -7,6 +7,25 @@
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.3.8] - 2026-06-27
11
+
12
+ ### 新增
13
+
14
+ - 编排器 Iron Law 强化:不得自己写实现代码、子 Skill 不可用不得自动降级
15
+ - Step 2/3/4/5 子 Skill 可用性 GATE 检查(team-spec/impl/test/review),不可用时 H3 请示用户
16
+ - H4 前协作文档完整性 GATE(full 11 文件 / compact 9 文件),不通过则 ROLLBACK 对应 Step
17
+
18
+ ### 修复
19
+
20
+ - compact 模式文档计数 11→12,补齐 `12-asset-update.md`
21
+ - 引用段落更新(Step 3/4/5 → Step 2/3/4/5)
22
+
23
+ ## [1.3.7] - 2026-06-26
24
+
25
+ ### 修复
26
+
27
+ - 安装时自检:目标与源为同一文件时跳过删除/复制,防止误删源文件(`createSymlinkSafe` + `installSkillsProject` + `verifyGlobalSymlinks`)
28
+
10
29
  ## [1.3.6] - 2026-06-26
11
30
 
12
31
  ### 修复
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "team-skills",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "AI Agent Skills framework — Spec-Driven development with directed-graph rollback and quality gates",
5
5
  "type": "module",
6
6
  "bin": {
@@ -43,6 +43,8 @@ flowchart TD
43
43
  - testAgent 发现 bug → 回退 implAgent;spec 遗漏 → 回退 specAgent
44
44
  - 同一阶段回退 ≤ 2 次
45
45
  - H1/H4 任何模式下不可省略
46
+ - 编排器不得自己写实现代码(必须 dispatch 子 Skill,不可亲自实现)
47
+ - 子 Skill 不可用时不得自动降级为自我执行,必须 H3 请示用户
46
48
  ```
47
49
 
48
50
  ### 路由推理检查点
@@ -246,7 +248,7 @@ NO AGENT DISPATCH WITHOUT H1 HUMAN CONFIRMATION FIRST
246
248
 
247
249
  | 级别 | 典型场景 | 推荐模式 | 预期文档产出 |
248
250
  | ---- | -------- | -------- | ------------ |
249
- | Small | 修 bug、改文案、加字段、调样式 | `--compact` 精简模式 | 11 个文档(03-04 + 06-13 + task-rules) |
251
+ | Small | 修 bug、改文案、加字段、调样式 | `--compact` 精简模式 | 12 个文档(03-04 + 06-13 + task-rules) |
250
252
  | Medium | 新增功能模块、重构组件、加 API | 完整模式(默认) | 全部 17 文件 |
251
253
  | Large | 跨系统重构、架构变更、多模块联动 | 完整模式 + 多期分期 | 全部 17 文件 + 多期迭代 |
252
254
 
@@ -283,6 +285,8 @@ NO AGENT DISPATCH WITHOUT H1 HUMAN CONFIRMATION FIRST
283
285
 
284
286
  **IF** 工具支持 Agent tool 并行调度 → 可在不相互依赖的阶段使用并行执行(如 Step 6 的一致性检查),但 spec→impl→test→review 主链路必须顺序执行。
285
287
 
288
+ **子 Skill 可用性**:编排器在调度前必须检查子 Skill 是否存在。不可用时不得自动降级为自我执行——必须通过 **H3** 由用户决定降级方案。参见 Step 2/3/4/5 的 GATE 检查。
289
+
286
290
  ### 断点续传机制
287
291
 
288
292
  > 当 session 中断或跨 session 继续任务时,通过 checkpoint 文件恢复流程位置。
@@ -426,6 +430,14 @@ NO AGENT DISPATCH WITHOUT H1 HUMAN CONFIRMATION FIRST
426
430
 
427
431
  > 规格是所有下游 Agent 的唯一输入源。规格质量直接决定 impl/test/review 的返工率。宁可在此多花时间,不可带着模糊规格进入实现。
428
432
 
433
+ **GATE** 子 Skill 可用性检查(进入 Step 2 前强制执行):
434
+
435
+ - **CHECK** `team-spec` skill 是否存在(`/team-spec` 是否可调用)
436
+ - **IF** 不可用 → **H3**,向用户展示 3 个选项:
437
+ - (a) 安装 team-spec skill 后继续
438
+ - (b) 由编排器手动编写规格,但承诺补全 01-05 规划文档
439
+ - (c) 终止任务
440
+
429
441
  **ROUTE** `team-spec`
430
442
 
431
443
  调用方式取决于工具能力:
@@ -486,6 +498,15 @@ NO AGENT DISPATCH WITHOUT H1 HUMAN CONFIRMATION FIRST
486
498
 
487
499
  > TRAP:你会倾向于信任 implAgent 的 `DONE` 状态而跳过 TDD 证据验证。`DONE` 只表示"自认为完成"——必须验证 `06-tdd-log.md` 中 RED→GREEN 顺序和失败输出。
488
500
 
501
+ **GATE** 子 Skill 可用性检查(进入 Step 3 前强制执行):
502
+
503
+ - **CHECK** `team-impl` skill 是否存在(`/team-impl` 是否可调用)
504
+ - **IF** 不可用 → **H3**,向用户展示 3 个选项:
505
+ - (a) 安装 team-impl skill 后继续
506
+ - (b) 由编排器手动执行实现,但承诺补全 06-08 协作文档
507
+ - (c) 终止任务
508
+ - **IF** 用户选择 (b) → 编排器执行实现,但**必须**在进入 Step 4 前产出 06-08
509
+
489
510
  **ROUTE** `team-impl`
490
511
 
491
512
  调用方式取决于工具能力:
@@ -542,6 +563,11 @@ TDD 强制要求:每个功能点必须先 git commit 失败测试(test: {功
542
563
 
543
564
  > SIGNAL:testAgent 报告 `spec 遗漏` 通常意味着 SDD 的边界条件或异常场景章节不完整,不是 implAgent 的问题——回退到 specAgent 而非 implAgent。
544
565
 
566
+ **GATE** 子 Skill 可用性检查:
567
+
568
+ - **CHECK** `team-test` skill 是否存在
569
+ - **IF** 不可用 → **H3**,展示选项:(a) 安装后继续 (b) 编排器手动执行但承诺补全 09-10 (c) 终止
570
+
545
571
  **ROUTE** `team-test`
546
572
 
547
573
  调用方式取决于工具能力:
@@ -595,6 +621,11 @@ TDD 强制要求:每个功能点必须先 git commit 失败测试(test: {功
595
621
 
596
622
  > TRAP:reviewAgent 返回 `DONE_WITH_CONCERNS` 时,你会倾向于视为"基本完成"而继续流程。必须将 concerns 完整展示给用户,由用户决定是否继续。
597
623
 
624
+ **GATE** 子 Skill 可用性检查:
625
+
626
+ - **CHECK** `team-review` skill 是否存在
627
+ - **IF** 不可用 → **H3**,展示选项:(a) 安装后继续 (b) 编排器手动执行但承诺补全 11-13 + task-rules (c) 终止
628
+
598
629
  **ROUTE** `team-review`
599
630
 
600
631
  调用方式取决于工具能力:
@@ -759,6 +790,20 @@ TDD 强制要求:每个功能点必须先 git commit 失败测试(test: {功
759
790
 
760
791
  > H4 是用户对整个交付物的最终确认,不可省略。展示内容必须让用户在不读代码的情况下做出有效判断。
761
792
 
793
+ **GATE** 协作文档完整性检查(进入 H4 前强制执行):
794
+
795
+ **IF** `mode == full`:
796
+
797
+ - **FOR** `file` **IN** [`06-tdd-log.md`, `07-prompt-log.md`, `08-ai-decisions.md`, `09-test-matrix.md`, `10-test-report.md`, `11-review.md`, `12-asset-update.md`, `13-retrospective.md`, `14-team.md`, `15-brief.md`, `task-rules.md`]:
798
+ - **ASSERT** `{file} EXISTS` && `有效行数 >= 5`
799
+ - 任一不通过 → **ROLLBACK** 对应 Step(06-08 → Step 3;09-10 → Step 4;11-13/task-rules → Step 5;14-15 → Step 6),附缺失文件名
800
+
801
+ **ELSE**(`mode == compact`):
802
+
803
+ - **FOR** `file` **IN** [`06-tdd-log.md`, `07-prompt-log.md`, `08-ai-decisions.md`, `09-test-matrix.md`, `10-test-report.md`, `11-review.md`, `12-asset-update.md`, `13-retrospective.md`, `task-rules.md`]:
804
+ - **ASSERT** `{file} EXISTS` && `有效行数 >= 5`
805
+ - 任一不通过 → **ROLLBACK** 对应 Step
806
+
762
807
  **WRITE**(对话中)向用户展示:交付物清单 + 代码 diff 摘要。
763
808
 
764
809
  - **IF** `mode == full` → 还展示 `14-team.md` 和 `15-brief.md` 核心内容
@@ -901,6 +946,7 @@ TDD 强制要求:每个功能点必须先 git commit 失败测试(test: {功
901
946
  - **延迟**回退("先记着后面一起修")
902
947
  - **信任** Agent 自我声明而不验证产出
903
948
  - **超出**预算却不砍范围
949
+ - **编排器自己写实现代码**(必须 dispatch 子 Skill,不得亲自实现。编排器的价值在于协调,不是执行)
904
950
 
905
951
  ## Constitutional Rules 遵守
906
952
 
@@ -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
  }
@@ -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
- verify(`${t.label} Skill: ${skill.name}`, join(t.dir, skill.name));
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
- verify(`${t.label} Rule: ${rule.name}`, join(t.dir, '_team-rules', rule.name));
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
- if (existsSync(dest)) rmSync(dest, { recursive: true });
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) copyFileSync(r.path, join(rulesDst, r.name));
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
  }