@flyin-ai/alloy 0.1.1 → 0.2.0-beta.1

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.
Files changed (76) hide show
  1. package/README.md +28 -90
  2. package/commands/alloy/apply.md +274 -119
  3. package/commands/alloy/archive.md +116 -60
  4. package/commands/alloy/discard.md +57 -15
  5. package/commands/alloy/finish.md +92 -70
  6. package/commands/alloy/fix.md +272 -53
  7. package/commands/alloy/plan.md +125 -63
  8. package/commands/alloy/references/interaction-style.md +82 -0
  9. package/commands/alloy/references/main-branch-detection.md +32 -0
  10. package/commands/alloy/references/phase-routing.md +21 -0
  11. package/commands/alloy/references/skill-precheck.md +46 -0
  12. package/commands/alloy/start.md +187 -62
  13. package/commands/alloy/status.md +1 -1
  14. package/dist/cli/commands/doctor.d.ts +1 -0
  15. package/dist/cli/commands/doctor.js +28 -6
  16. package/dist/cli/commands/doctor.js.map +1 -1
  17. package/dist/cli/commands/init.js +40 -37
  18. package/dist/cli/commands/init.js.map +1 -1
  19. package/dist/cli/commands/internal/config.d.ts +1 -0
  20. package/dist/cli/commands/internal/config.js +45 -0
  21. package/dist/cli/commands/internal/config.js.map +1 -0
  22. package/dist/cli/commands/internal/guard.js +2 -41
  23. package/dist/cli/commands/internal/guard.js.map +1 -1
  24. package/dist/cli/commands/internal/record.js +10 -47
  25. package/dist/cli/commands/internal/record.js.map +1 -1
  26. package/dist/cli/commands/internal/skill-usage.d.ts +1 -0
  27. package/dist/cli/commands/internal/skill-usage.js +78 -0
  28. package/dist/cli/commands/internal/skill-usage.js.map +1 -0
  29. package/dist/cli/commands/internal/state.js +105 -6
  30. package/dist/cli/commands/internal/state.js.map +1 -1
  31. package/dist/cli/commands/status.d.ts +1 -0
  32. package/dist/cli/commands/status.js +50 -11
  33. package/dist/cli/commands/status.js.map +1 -1
  34. package/dist/cli/commands/update.js +20 -17
  35. package/dist/cli/commands/update.js.map +1 -1
  36. package/dist/cli/index.js +73 -31
  37. package/dist/cli/index.js.map +1 -1
  38. package/dist/cli/utils/hash.d.ts +3 -0
  39. package/dist/cli/utils/hash.js +42 -0
  40. package/dist/cli/utils/hash.js.map +1 -0
  41. package/dist/cli/utils/state.d.ts +4 -2
  42. package/dist/cli/utils/state.js +34 -2
  43. package/dist/cli/utils/state.js.map +1 -1
  44. package/dist/core/artifacts.d.ts +3 -0
  45. package/dist/core/artifacts.js +45 -0
  46. package/dist/core/artifacts.js.map +1 -0
  47. package/dist/core/detect-installations.d.ts +19 -0
  48. package/dist/core/detect-installations.js +65 -0
  49. package/dist/core/detect-installations.js.map +1 -0
  50. package/dist/core/openspec.d.ts +2 -1
  51. package/dist/core/openspec.js +30 -12
  52. package/dist/core/openspec.js.map +1 -1
  53. package/dist/core/skills.js +16 -0
  54. package/dist/core/skills.js.map +1 -1
  55. package/dist/core/superpowers.d.ts +8 -1
  56. package/dist/core/superpowers.js +41 -20
  57. package/dist/core/superpowers.js.map +1 -1
  58. package/dist/core/types.d.ts +20 -0
  59. package/dist/utils/format.d.ts +31 -0
  60. package/dist/utils/format.js +101 -0
  61. package/dist/utils/format.js.map +1 -0
  62. package/dist/utils/output.d.ts +16 -0
  63. package/dist/utils/output.js +38 -0
  64. package/dist/utils/output.js.map +1 -0
  65. package/dist/utils/prompt.d.ts +0 -1
  66. package/dist/utils/prompt.js +11 -83
  67. package/dist/utils/prompt.js.map +1 -1
  68. package/openspec/schemas/alloy/instructions/retrospective.md +17 -35
  69. package/openspec/schemas/alloy/templates/design.md +2 -0
  70. package/openspec/schemas/alloy/templates/draft.md +2 -0
  71. package/openspec/schemas/alloy/templates/plans.md +2 -0
  72. package/openspec/schemas/alloy/templates/proposal.md +2 -0
  73. package/openspec/schemas/alloy/templates/retrospective.md +39 -19
  74. package/openspec/schemas/alloy/templates/specs.md +2 -0
  75. package/openspec/schemas/alloy/templates/tasks.md +2 -0
  76. package/package.json +8 -2
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: "Alloy: Apply"
3
- description: Alloy 执行阶段——当 plan.md 完成后,在隔离环境中实现代码并通过双层验证
3
+ description: Alloy 执行阶段 - plan 完成后进入
4
4
  category: Workflow
5
5
  tags: [alloy, workflow]
6
6
  ---
@@ -9,19 +9,44 @@ tags: [alloy, workflow]
9
9
 
10
10
  你是 Alloy 的执行阶段编排器。按 plan.md 任务实现,内部遵循 TDD,执行完毕自动验证和复盘。
11
11
 
12
- **状态标签约定(ANSI 颜色输出):**
13
- - `[PASS]` 绿色 — 检查通过
14
- - `[FAIL]` 红色 检查失败
15
- - `[HALT]` 红色 — 硬阻断,不可继续
16
- - `[WARN]` 黄色 — 警告,可继续但需关注
17
- - `[DONE]` 绿色 — 阶段完成
12
+ **交互风格:** 所有审查窗口、分支选择、策略选择使用 `AskUserQuestion` 工具。详见 `commands/alloy/references/interaction-style.md`。
13
+
14
+ **状态符号:** 使用 `✓`/`✗`/`⚠️` 符号(详见视觉规范 §七)。
18
15
 
19
16
  **调用外部命令或技能前,先输出标题和状态描述,再执行操作。不要只出标题然后沉默。**
20
17
 
18
+ **捕获阶段启动时间**(命令调用后第一时间,前置检查之前,幂等——重入时返回已有值):
19
+ ```bash
20
+ PHASE_START=$(alloy _state timestamp ensure openspec/changes/<name> apply)
21
+ ```
22
+
23
+ ---
24
+
21
25
  **什么算"apply 执行不到位"(反例):**
22
26
  - precheck 发现技能缺失但继续执行——"先跑着,后面可能用不到"——后面会静默丢失 TDD 或 code review
23
27
  - 验证失败后直接改代码跳回验证,不经过 SDD——丢失了 TDD 安全网
24
28
  - retrospective 在没有 verify.md 的情况下生成——复盘建立在不可靠的基础上
29
+ - 在主分支上创建 worktree——"start 已经确认过主分支了"——plan 阶段的 commit 在 feature 分支上,worktree 基于 main 会丢失这些 commit
30
+ - feature_branch 为 null 时静默回退——"回退路径是设计的容错"——null 是状态异常,回退值可能与实际分支不一致
31
+ - 跳过分支验证闸门直接加载 using-git-worktrees——"技能内部会处理 base ref"——技能不知道你的 feature_branch 是什么
32
+
33
+ ### Red Flags——STOP,不要继续
34
+
35
+ 以下任何一个念头出现,都意味着闸门正在被绕过:
36
+
37
+ | 借口 | 现实 |
38
+ |------|------|
39
+ | "用户说了跳过 worktree" | 用户说了不算。隔离是 apply 的硬闸门,用户跳过 worktree 就是跳过安全网。必须明确拒绝并解释风险。 |
40
+ | "先写代码再补测试,加快速度" | TDD 的次序不可颠倒。先写测试再写代码才是安全网,顺序反了等于没网。提速的正确方式是并行子任务,不是砍测试。 |
41
+ | "用户要改需求,我直接改吧" | 需求变更必须通过 tasks.md checkbox 闸门。已开始编码 → 开新 change。未开始 → 回溯 brainstorming。不存在"顺手改了"这个选项。 |
42
+ | "技能缺失没关系,我可以自己搞定" | 技能是闸门,不是加速器。缺失 = HARD STOP。不存在"降级处理"。引导 `alloy init` 修复环境。 |
43
+ | "反正是个小改动,不用那么正式" | 小改动和大改动的闸门完全一样。不存在"大小分级的保护等级"。 |
44
+ | "用户很急,跳过 review 吧" | 跳过 review = 跳过代码质量闸门。急不是绕过流程的理由。 |
45
+ | "start 阶段已经确认过主分支了" | 配置可能已变,确认只需 2 秒。跳过确认 = 在错误的 base 上创建 worktree。 |
46
+ | "feature_branch 是 null,用回退值就行" | null 是状态异常,不是设计的容错。回退值可能与实际分支不一致——交叉验证后才能用。 |
47
+ | "当前在 main 上,直接建 worktree 吧" | 主分支上创建 worktree 丢失 feature 分支的 plan commit。必须先切到 feature 分支。 |
48
+ | "using-git-worktrees 技能内部会处理 base ref" | 技能不知道你的 feature_branch 是什么。base ref 由 apply.md 决定,不是下游技能。 |
49
+ | "先建 worktree 再问用户要不要" | 必须在 consent 前等待。consent 是 before worktree 创建,不是 after。先建后问 = 剥夺用户选择权。加载技能后立即停手,等用户明确回复。 |
25
50
 
26
51
  ## 前置检查
27
52
 
@@ -30,65 +55,27 @@ tags: [alloy, workflow]
30
55
  ```bash
31
56
  alloy _guard openspec/changes/<name> applied
32
57
  ```
33
- 若 guard 报错说明 phase 转换不合法——检查当前 phase
34
-
35
- | 当前 phase | 行为 |
36
- |-----------|------|
37
- | started | "plan 尚未完成,自动进入 /alloy:plan" → 加载 alloy-plan 指令 |
38
- | planned | precheck 通过,继续执行 |
39
- | applied | precheck 通过(重入),步骤幂等处理断点 |
40
- | archived | "已归档,自动进入 /alloy:finish" → 加载 alloy-finish 指令 |
41
- | finished | "工作流已完成" → STOP |
42
-
43
- **实现方式:** 输出对应命令文件的完整指令,将 change name 和当前进度信息作为上下文传入。
58
+ 若 guard 报错说明 phase 转换不合法——读取 `commands/alloy/references/phase-routing.md` 按路由表自动跳转。当前 phase=planned 或 applied 时 precheck 通过(applied 为断点重入)。
44
59
  3. 确认当前目录在 git 仓库内:
45
60
  ```bash
46
61
  git rev-parse --git-dir
47
62
  ```
48
63
  若命令成功 → 继续。
49
- 若命令失败 → 项目还不是 git 仓库,worktree 隔离和版本追踪需要 git。展示选项:
50
- > Git 仓库检测
51
- > ──────────────────────────────────────
52
- >
53
- > 检测到项目还不是 git 仓库。worktree 隔离和版本追踪依赖 git。
54
- >
55
- > 1. 立即初始化 —— 执行 git init 并做一次初始提交(推荐)
56
- > 2. 稍后自行处理 —— 手动初始化后再运行 /alloy:apply
57
-
58
- 选 1:Agent 执行 `git init && git add -A && git commit -m "chore: 初始提交"`,完成后继续
59
- 选 2:STOP,"请手动初始化 git 仓库后重新运行 `/alloy:apply`"
60
-
61
- **记录阶段开始时间:**
64
+ 若命令失败 → HARD STOP:"项目还不是 git 仓库。请先运行 `/alloy:start` 完成初始化(包含 git init)。"
65
+ 4. **Skill 预检:** 确认以下依赖可用:
66
+ cmd: opsx/verify
67
+ skill: using-git-worktrees subagent-driven-development executing-plans test-driven-development requesting-code-review verification-before-completion
62
68
 
63
- ```bash
64
- COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
65
- TIMINGS=$(alloy _state read openspec/changes/<name> phase_timings 2>/dev/null || echo "{}")
66
- echo "$TIMINGS" | python3 -c "
67
- import sys,json
68
- content = sys.stdin.read()
69
- d = json.loads(content) if content.strip() else {}
70
- p = d.setdefault('apply',{})
71
- if 'started_at' not in p:
72
- p['started_at']='$COMPLETED_AT'
73
- print(json.dumps(d))
74
- " | while read -r val; do alloy _state write openspec/changes/<name> phase_timings "$val"; done
75
- ```
76
-
77
- 读取启动时间用于展示:
78
- ```bash
79
- alloy _state read openspec/changes/<name> phase_timings | python3 -c "
80
- import sys,json
81
- print(json.loads(sys.stdin.read() or '{}').get('apply',{}).get('started_at',''))
82
- "
83
- ```
69
+ 读取 `commands/alloy/references/skill-precheck.md` 了解检测方法。任一缺失 → 输出缺失列表 → 引导 `alloy init` → STOP。**不存在降级处理。** 技能是闸门,不是加速器——有则用,无则停。
84
70
 
85
71
  ```
86
72
  ┌──────────────────────────────────────┐
87
73
  │ Alloy [3/5] · Phase: Apply │
88
- │ 启动时间: <上面命令输出的 started_at 值>
74
+ │ 启动时间: $PHASE_START
89
75
  └──────────────────────────────────────┘
90
76
 
91
77
  **提交前置状态(worktree 创建前确保 .alloy.yaml 变更已落地):**
78
+ 后续步骤写入 worktree 的路径和分支名也会进入此快照 commit,确保 worktree 内能看到完整状态。
92
79
 
93
80
  ```bash
94
81
  git add openspec/changes/<name>/.alloy.yaml
@@ -97,25 +84,11 @@ git diff --cached --quiet || git commit -m "chore(<name>): apply 阶段开始前
97
84
 
98
85
  `git diff --cached --quiet` 接续时无变更则跳过,不会产生空 commit。
99
86
 
100
- [Step 0/5] 技能可用性预检(precheck)
101
- ──────────────────────────────────────
102
-
103
- 前置检查通过:plan.md ✓ phase=planned ✓ git仓库 ✓
104
-
105
- 检查以下 6 个 Superpowers 技能是否可用(缺一 STOP,不静默降级):
106
- - [ ] superpowers:using-git-worktrees
107
- - [ ] superpowers:subagent-driven-development
108
- - [ ] superpowers:executing-plans
109
- - [ ] superpowers:test-driven-development
110
- - [ ] superpowers:requesting-code-review
111
- - [ ] superpowers:verification-before-completion
87
+ ---
112
88
 
113
- 任一缺失 输出缺失列表 引导 `alloy init` 重新安装 → STOP
89
+ 前置检查通过:plan.md ✓ phase=planned ✓ git ✓ 技能
114
90
 
115
- 全部通过后:
116
- > precheck 通过:6/6 技能可用 ✓
117
91
  > 共 5 个步骤:隔离 → 任务实现 → 代码验证 → 制品验证 → 复盘
118
- ```
119
92
 
120
93
  ---
121
94
 
@@ -149,6 +122,12 @@ grep -c '\[x\]' openspec/changes/<name>/tasks.md
149
122
 
150
123
  不允许在当前 change 内回溯——已有代码落地,规格和代码不能分叉。
151
124
 
125
+ **什么算"需求变更闸门失效"(反例):**
126
+ - 用户说"需求不对,改一下"就直接改代码——没检查 tasks.md checkbox 状态
127
+ - 已在 [x] 的 change 上做架构级改动(如 JWT→session)——应开新 change
128
+ - 用户说"就改一点点需求"——不存在"一点点",要么未编码可回溯,要么已编码开新 change
129
+ - 在同一 change 上多次反复变更需求——每次变更都应经过闸门判断
130
+
152
131
  ## 执行步骤
153
132
 
154
133
  ### [Step 1/5] 隔离环境设置
@@ -160,10 +139,10 @@ alloy _state read openspec/changes/<name> worktree
160
139
 
161
140
  ```
162
141
  Step 1/5 进度检测:
163
- worktree 值: ".worktrees/<name>/" 路径存在 → ✓ 已完成,跳过此步骤
164
- worktree 值: ".worktrees/<name>/" → 路径不存在 → ⚠️ 残留记录,重新处理
165
- worktree 值: "skipped" → ✓ 用户选择不创建,跳过此步骤
166
- worktree 值: null(从未写入) → ⚠️ 尚未决定,加载 using-git-worktrees
142
+ worktree 值: 有效路径(如 `.claude/worktrees/<name>/` `.worktrees/<name>/`)→ 路径存在 → ✓ 已完成,跳过此步骤
143
+ worktree 值: 有效路径 → 路径不存在 → ⚠️ 残留记录,重新处理
144
+ worktree 值: "skipped" → ✓ 用户选择不创建,跳过此步骤
145
+ worktree 值: null(从未写入) → ⚠️ 尚未决定,加载 using-git-worktrees
167
146
  ```
168
147
 
169
148
  路径存在、"skipped" 时,直接跳过 Step 1,进入 Step 2。
@@ -173,23 +152,146 @@ null 时,先展示摘要,再加载技能:
173
152
  ```
174
153
  > [Step 1/5] 隔离环境设置
175
154
  >
176
- > 源分支: <当前 git branch>
177
- > Worktree 分支: worktree-<change-name>
178
- > Worktree 路径: .claude/worktrees/<change-name>
155
+ > 当前在 `<feature_branch>`。未在隔离 worktree 中。
179
156
  >
180
- > 加载 superpowers:using-git-worktrees...
157
+ > 分支隔离的是提交历史,但同一时间只能有一个分支在工作目录里。
158
+ > Worktree 隔离的是工作目录——每个 worktree 有独立的文件副本,可同时 checkout 不同分支。
159
+ >
160
+ > 如果你的 feature 开发期间要切到其他分支(如修紧急 bug、切 main 查东西),
161
+ > worktree 让你无需 stash/commit 当前进度,直接进另一个目录操作。
162
+ >
163
+ > 正在验证分支位置...
181
164
  ```
182
165
 
183
- 使用 Skill 工具加载 `superpowers:using-git-worktrees` 技能。该技能内置了完整的决策流程,Agent 按其内部指引执行即可。
166
+ **分支验证闸门**(加载 using-git-worktrees 之前必须通过——worktree 的 base ref 取决于当前分支,错误的 base = plan 阶段 commit 丢失):
167
+
168
+ **① 主分支确认:** 读取 `commands/alloy/references/main-branch-detection.md`,按 3 级优先级检测主分支。若 `openspec/config.yaml` 已有 `alloy.main_branch` 记录,直接用记录值,跳过检测和确认。
169
+
170
+ **② 当前分支位置检查:**
171
+ ```bash
172
+ CURRENT_BRANCH=$(git branch --show-current)
173
+ FEATURE_BRANCH=$(alloy _state read openspec/changes/<name> feature_branch)
174
+ MAIN_BRANCH=$(alloy _config read . main_branch 2>/dev/null || echo "$DEFAULT_BRANCH")
175
+ ```
176
+
177
+ - **在主分支上**(`CURRENT_BRANCH === MAIN_BRANCH`)→ HARD STOP:"当前在主分支 `<main_branch>`。不允许从主分支创建 worktree——plan 阶段的 commit 在 feature 分支上,worktree 会丢失这些变更。" → 必须 `git checkout <feature_branch>` 后再继续
178
+ - **当前分支 = feature_branch** → ✓ 位置正确,继续
179
+ - **feature_branch 为 null** → ⚠️ 状态异常,需修复:
180
+ ```
181
+ .alloy.yaml 未记录 feature_branch。这通常是 start 阶段数据写入失败。
182
+
183
+ → (a) 手动指定:输入分支名(如 feature/<name>)
184
+ → (b) 使用当前分支 `<current_branch>` 作为 feature_branch
185
+ → (c) 放弃,回退到 start 阶段修复
186
+ ```
187
+ 用户选择后,`alloy _state write openspec/changes/<name> feature_branch <用户确认的分支>`,然后继续。**null 是状态异常,不是设计的容错——不允许静默回退。**
188
+ - **当前分支 ≠ feature_branch** → 提示切换:
189
+ ```
190
+ 当前在 `<current_branch>`,但 feature_branch 记录为 `<feature_branch>`。
191
+ → (a) 切换到 <feature_branch>(推荐)
192
+ → (b) 使用当前分支 <current_branch>(更新 feature_branch 记录)
193
+ ```
194
+ 选 (a):`git checkout <feature_branch>` → 继续
195
+ 选 (b):`alloy _state write openspec/changes/<name> feature_branch <current_branch>` → 继续
196
+ - **feature_branch 不存在本地** → ⚠️ 分支丢失:
197
+ ```
198
+ feature_branch 记录为 `<feature_branch>`,但本地不存在此分支。
199
+ → (a) 从远程拉取:git fetch origin <feature_branch> && git checkout <feature_branch>
200
+ → (b) 手动指定其他分支
201
+ → (c) 放弃,回退到 start 阶段修复
202
+ ```
203
+
204
+ **③ base ref 锁定:** 创建 worktree 时,必须基于 `feature_branch`(不是 HEAD,不是 main)。
205
+
206
+ 分支验证闸门通过后,**先加载技能获取用户 consent(创建/跳过),不要在 consent 前创建 worktree。**
207
+
208
+ 使用 Skill 工具加载 `superpowers:using-git-worktrees` 技能。传入参数:
209
+
210
+ > 工作目录偏好: .claude/worktrees/<name>
211
+ > 分支命名: worktree-<name>
212
+ > 基于: <feature_branch>
213
+ > **重要:** 仅使用技能的 Step 0(检测+consent 问询)。用户 consent 后,不要使用技能的 Step 1a(EnterWorktree)或 Step 1b(git fallback)创建方法——EnterWorktree 默认从 origin/main 分出,base ref 错误。改用下方的 "base ref 处理策略" 手动创建并进入。
214
+
215
+ 技能加载后,Agent 按其内部指引执行 Step 0(检测+consent)。**必须等待用户明确选择(创建/跳过)后才能继续。**
216
+
217
+ **什么算"consent 没做到"(反例):**
218
+ - 技能加载后直接建 worktree,没等用户回复——"用户没拒绝就等于同意"是错误的
219
+ - 用户说"嗯"、"好吧"、"随便"就当成同意——模糊回复不等于明确同意
220
+ - 先 `git worktree add` 再加载技能——顺序反了,consent 必须在前
221
+
222
+ **技能加载后立即记录:**
223
+ ```bash
224
+ alloy _skill log openspec/changes/<name> apply superpowers:using-git-worktrees
225
+ ```
184
226
 
185
- **when 用户选择不创建 worktree:** 写入 `skipped`(非 null):
227
+ **用户选择不创建:** 写入 `skipped`(非 null),跳过后续创建步骤:
186
228
  ```bash
187
229
  alloy _state write openspec/changes/<name> worktree skipped
188
230
  ```
189
231
 
190
- 技能执行完成后,将结果写入状态文件——这是断点恢复的关键数据:
191
- - 已创建 worktree → `alloy _state write openspec/changes/<name> worktree "<path>"`
192
- - 用户拒绝或已在隔离环境 `alloy _state write openspec/changes/<name> worktree skipped`
232
+ **用户选择创建:** 使用以下方式确保正确的 base ref(不是 origin/main,而是 feature_branch):
233
+
234
+ 1. **优先:** 先手动 `git worktree add .claude/worktrees/<name> -b worktree-<name> <feature_branch>` 创建 worktree(显式指定 base ref),再用 EnterWorktree(path=".claude/worktrees/<name>") 进入
235
+ 2. **回退:** 若 EnterWorktree 支持自定义 base ref(查看工具参数),直接使用并传入 feature_branch
236
+
237
+ **路径偏好说明:** 使用无条件路径 `.claude/worktrees/<name>`,因为 `.claude/` 是 alloy 初始化时的固定目录(存在 commands/skills 等子目录)。显式指定路径后,Agent 在 git worktree fallback(EnterWorktree 不可用时)会直接使用该路径,不会因条件判断错误而回退到 `.worktrees/`。
238
+
239
+ **分支命名说明:** 使用 `worktree-<name>` 命名规范,与 EnterWorktree 的内置命名一致。这确保无论 worktree 由 EnterWorktree 还是 git worktree fallback 创建,分支名格式统一,archive 阶段清理时无需猜测。
240
+
241
+ ```bash
242
+ echo " 正在检测 worktree 实际状态..."
243
+
244
+ # 判断是否已在 worktree 中:GIT_DIR != GIT_COMMON 表示在 linked worktree 中
245
+ GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
246
+ GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
247
+
248
+ if [ "$GIT_DIR" != "$GIT_COMMON" ]; then
249
+ # 已在 worktree 中,获取实际路径和分支名
250
+ WORKTREE_PATH=$(cd "$(git rev-parse --show-toplevel)" 2>/dev/null && pwd -P)
251
+ WORKTREE_BRANCH=$(cd "$WORKTREE_PATH" && git branch --show-current)
252
+ alloy _state write openspec/changes/<name> worktree "$WORKTREE_PATH"
253
+ alloy _state write openspec/changes/<name> worktree_branch "$WORKTREE_BRANCH"
254
+ alloy _state write openspec/changes/<name> worktree_created_at "$(date '+%Y-%m-%d %H:%M:%S')"
255
+ echo " ✓ worktree 已记录: 分支=$WORKTREE_BRANCH 路径=$WORKTREE_PATH"
256
+ # commit 确保断点恢复时 state 不丢失
257
+ git add openspec/changes/<name>/.alloy.yaml
258
+ git diff --cached --quiet || git commit -m "chore(<name>): record worktree state"
259
+ else
260
+ # EnterWorktree 失败后的 git worktree fallback
261
+ # 优先检测 .claude/worktrees/(EnterWorktree 原生路径),回退 .worktrees/
262
+ WT_PATH=""
263
+ for CANDIDATE in ".claude/worktrees/<name>" ".worktrees/<name>"; do
264
+ if [ -d "$CANDIDATE" ]; then
265
+ WT_PATH=$(cd "$CANDIDATE" 2>/dev/null && pwd -P)
266
+ break
267
+ fi
268
+ done
269
+ if [ -n "$WT_PATH" ]; then
270
+ WORKTREE_BRANCH=$(cd "$WT_PATH" && git branch --show-current 2>/dev/null)
271
+ alloy _state write openspec/changes/<name> worktree "$WT_PATH"
272
+ alloy _state write openspec/changes/<name> worktree_branch "$WORKTREE_BRANCH"
273
+ alloy _state write openspec/changes/<name> worktree_created_at "$(date '+%Y-%m-%d %H:%M:%S')"
274
+ echo " ✓ worktree fallback 已记录: 分支=$WORKTREE_BRANCH 路径=$WT_PATH"
275
+ # 提交 source repo 的 state
276
+ git add openspec/changes/<name>/.alloy.yaml
277
+ git diff --cached --quiet || git commit -m "chore(<name>): record worktree state"
278
+ # worktree 内也写入并提交——bash cd 不跨工具调用持久化,
279
+ # 若只在 source repo 写,agent 后续进入 worktree 后读到的 state 仍为 null
280
+ cd "$WT_PATH" && \
281
+ alloy _state write openspec/changes/<name> worktree "$WT_PATH" && \
282
+ alloy _state write openspec/changes/<name> worktree_branch "$WORKTREE_BRANCH" && \
283
+ alloy _state write openspec/changes/<name> worktree_created_at "$(date '+%Y-%m-%d %H:%M:%S')" && \
284
+ git add openspec/changes/<name>/.alloy.yaml && \
285
+ git diff --cached --quiet || git commit -m "chore(<name>): record worktree state (worktree)"
286
+ else
287
+ echo " ℹ 未检测到 worktree,按用户选择记录"
288
+ alloy _state write openspec/changes/<name> worktree skipped
289
+ fi
290
+ fi
291
+
292
+ 技能执行完成后,将结果写入状态文件——这是断点恢复的关键数据(已在上方检测逻辑中自动写入):
293
+ - 已创建 worktree → worktree 路径(已在检测中自动写入到 state)
294
+ - 用户拒绝或已在隔离环境 → `skipped`(已在检测中自动写入到 state)
193
295
 
194
296
  **Step 1/5 完成汇总:**
195
297
 
@@ -200,9 +302,9 @@ alloy _state write openspec/changes/<name> worktree skipped
200
302
 
201
303
  > [Step 1/5] 隔离环境 — 就绪
202
304
  >
203
- > 源分支: feature/<name>
204
- > Worktree 分支: worktree-<name>
205
- > Worktree 路径: .claude/worktrees/<name>
305
+ > 源分支: <由 state.feature_branch 获取>
306
+ > Worktree 分支: <由 state.worktree_branch 获取,无则显示 N/A>
307
+ > Worktree 路径: <由 state.worktree 获取,无则显示 N/A>
206
308
  ```
207
309
 
208
310
  ### [Step 2/5] 任务实现
@@ -232,11 +334,22 @@ TDD 机制天然保证幂等——已实现的 task 对应测试已通过,重
232
334
 
233
335
  任务分析:<N 个任务,哪些独立/哪些耦合>
234
336
 
235
- 推荐方案:<superpowers:subagent-driven-development / superpowers:executing-plans>(规划阶段建议)
337
+ 推荐方案:superpowers:subagent-driven-development(规划阶段建议)
236
338
  理由:<来自 plans.md reason>
237
339
 
238
- 1. superpowers:subagent-driven-development — 派发子 agent 并行执行(推荐)
239
- 2. superpowers:executing-plans — 当前 session 逐步实现
340
+ 选择哪个?
341
+
342
+ subagent-driven-development(推荐)
343
+ 适用场景:
344
+ - 任务多(≥3 个)、相互独立
345
+ - 涉及不同文件/模块,可并行
346
+ - 适合:新功能、多组件改造、跨模块变更
347
+
348
+ executing-plans
349
+ 适用场景:
350
+ - 任务少(1-2 个)、紧密耦合
351
+ - 共享状态或同一文件、不可拆分
352
+ - 适合:小修小改、重构单个模块、快速修复
240
353
  ```
241
354
 
242
355
  **如果 plans.md 有 strategy header:**
@@ -259,31 +372,65 @@ Superpowers 技能内部行为(alloy 仅编排,不替代):
259
372
  - 读取 plan → 分派子 agent → 每个子 agent 独立执行 TDD + code review(transitive 激活)
260
373
  - 子 agent 各自勾选 tasks.md 中对应任务的 checkbox
261
374
 
262
- **superpowers:executing-plans 路径:** 分三步执行,确保不丢 TDD 和 code review 闸门:
375
+ **技能加载后立即记录:**
376
+ ```bash
377
+ alloy _skill log openspec/changes/<name> apply superpowers:subagent-driven-development
378
+ alloy _skill log openspec/changes/<name> apply test-driven-development --via subagent-driven-development
379
+ alloy _skill log openspec/changes/<name> apply spec-compliance-review --via subagent-driven-development
380
+ alloy _skill log openspec/changes/<name> apply code-quality-review --via subagent-driven-development
381
+ ```
382
+
383
+ **superpowers:executing-plans 路径:** 分四步执行,确保不丢 TDD、spec 合规和 code review 闸门:
263
384
 
264
385
  **1. 先加载 `superpowers:test-driven-development` 技能设定 TDD 预期:**
265
386
  - 加载后,TDD 纪律(RED→GREEN→REFACTOR)成为本次执行的硬约束
266
387
  - 不在 executing-plans 内部"顺便做"——先设定预期,再执行
267
388
 
389
+ **技能加载后立即记录:**
390
+ ```bash
391
+ alloy _skill log openspec/changes/<name> apply superpowers:test-driven-development
392
+ ```
393
+
268
394
  **2. 加载 `superpowers:executing-plans` 技能执行 plans.md 微步骤:**
269
395
  - executing-plans 按 plans.md 逐步执行,每步完成后暂停审查
270
396
  - 执行过程中遵循 TDD 流程(先写测试→确认失败→实现→确认通过)
271
397
 
272
- **3. executing-plans 完成后,加载 `superpowers:requesting-code-review` 技能:**
398
+ **技能加载后立即记录:**
399
+ ```bash
400
+ alloy _skill log openspec/changes/<name> apply superpowers:executing-plans
401
+ ```
402
+
403
+ **3. executing-plans 完成后,进行 Spec 合规审查(Agent 自行检查,不加载额外技能):**
404
+ - tasks.md 的每个 checkbox → 代码中是否有对应实现?
405
+ - 代码中是否有 tasks.md 未要求的实现?(over-building)
406
+ - plan.md 中明确排除的范围 → 代码是否碰了?
407
+ - 不通过 → 修复 → 重新审查 → 通过后进入 code review
408
+
409
+ **4. 加载 `superpowers:requesting-code-review` 技能进行代码审查:**
273
410
  - 代码审查闸门——所有代码变更必须经过审查才能进入 Step 3 验证
274
411
 
275
- > superpowers:executing-plans 路径不会 transitive 激活 TDD 或 code review。以上三步通过**显式加载**来补偿——先设定 TDD 预期,再执行,最后审查。
412
+ **技能加载后立即记录:**
413
+ ```bash
414
+ alloy _skill log openspec/changes/<name> apply superpowers:requesting-code-review
415
+ ```
416
+
417
+ > superpowers:executing-plans 路径不会 transitive 激活 TDD、spec 合规或 code review。以上四步通过**显式加载**来补偿——先设定 TDD 预期,再执行,再校验 spec 合规,最后审查。
276
418
 
277
- ### Step 3/5:代码层验证
419
+ ### [Step 3/5] 代码层验证
278
420
 
279
421
  > [Step 3/5] superpowers:verification-before-completion
280
422
  > 正在验证代码行为——测试通过、功能正确...
281
423
 
282
424
  使用 Skill 工具加载 `superpowers:verification-before-completion` 技能 —— 代码行为验证。
283
425
 
426
+ **技能加载后立即记录:**
427
+ ```bash
428
+ alloy _skill log openspec/changes/<name> apply superpowers:verification-before-completion
429
+ ```
430
+
284
431
  验证失败 → 修复代码 → 回到 Step 2/5(SDD),确保修复也有 TDD + code review 安全网。
285
432
 
286
- ### Step 4/5:制品层验证
433
+ ### [Step 4/5] 制品层验证
287
434
 
288
435
  **幂等检查:** 检查 verify.md 是否存在且 hash 有效:
289
436
  ```bash
@@ -308,6 +455,11 @@ alloy _record check openspec/changes/<name> plans
308
455
  若 check 失败 → HARD STOP,plans 可能被未审批修改。
309
456
 
310
457
  1. 调用 `/opsx:verify` 执行结构化的 7 项检查
458
+
459
+ **命令执行后立即记录:**
460
+ ```bash
461
+ alloy _skill log openspec/changes/<name> apply opsx:verify
462
+ ```
311
463
  2. `/opsx:verify` 的输出由 OpenSpec CLI 生成,其语言不由 Agent 控制。Agent 拿到输出后,**必须将 verify.md 重写为与 `instructions/verify.md` 和 `templates/verify.md` 一致的语言**,不得直接透传 CLI 输出
312
464
  3. 检查结果(PASS/FAIL/WARNING)保留作为事实依据
313
465
 
@@ -323,7 +475,7 @@ alloy _record write openspec/changes/<name> tasks "$HASH" "$(date "+%Y-%m-%d %H:
323
475
 
324
476
  **verify.md 生成后,展示审查窗口:**
325
477
 
326
- > 制品 [1/2] verify ✓ 完成
478
+ > 制品 [1/2] verify ✓ 完成([N/M] 是阶段内局部编号,M=2,不是全局 8 制品编号)
327
479
  >
328
480
  > [展示 verify.md 完整内容]
329
481
  >
@@ -343,7 +495,7 @@ git commit -m "docs(<name>): verify 已确认"
343
495
 
344
496
  选 (b):调整 verify 内容后重新展示审查窗口。
345
497
 
346
- ### Step 5/5:复盘
498
+ ### [Step 5/5] 复盘
347
499
 
348
500
  **幂等检查:** 检查 retrospective.md 是否存在且 hash 有效:
349
501
  ```bash
@@ -381,7 +533,7 @@ alloy _record check openspec/changes/<name> verify
381
533
 
382
534
  **§3 Plan Deviations:** 计划 vs 实际变更表格,含 strategy 偏差说明。
383
535
 
384
- **§4 全周期技能审计:** Agent 自报 start/plan/apply 三阶段 11 项技能/命令使用情况(✓/✗)。同一 session 亲历,无需推断。跳过的技能填三问(跳过什么/为什么/如何防复发)。
536
+ **§4 全周期技能审计:** `.alloy.yaml` 的 `skill_usage[]` 字段读取 start/plan/apply/archive/finish 五阶段技能使用记录。`skill_usage[]` 为空(旧 change)→ 对应行填 `—`,不推断。跳过的技能展开三问(跳过什么/为什么/如何防复发)。
385
537
 
386
538
  **§5 Surprises:** 被推翻的假设。
387
539
 
@@ -400,11 +552,16 @@ alloy _record check openspec/changes/<name> verify
400
552
  > → (a) 确认,锁定 retrospective 并完成 apply
401
553
  > → (b) 需要调整 — 说明修改点,修改后重新展示
402
554
 
403
- 选 (a)hash 锁定 retrospective commit:
555
+ 选 (a):补填审批时间 + hash 锁定 + 提交,一个 commit 包含所有累积变更(retrospective + 阶段完成时间 + worktree 状态),不拆开:
404
556
  ```bash
557
+ APPROVAL_TIME=$(date "+%Y-%m-%d %H:%M:%S")
558
+ # 将 §0 表格中 retrospective 行的"待确认"替换为实际审批时间(hash 列保持 "—",避免自指悖论)
559
+ sed -i '' "s/| retrospective |.*| 待确认 |/| retrospective | $(alloy _record approver openspec/changes/<name>) | — | ${APPROVAL_TIME} |/" openspec/changes/<name>/retrospective.md
560
+ COMPLETED_AT="${APPROVAL_TIME}"
561
+ alloy _state merge openspec/changes/<name> phase_timings "{\"apply\":{\"completed_at\":\"${COMPLETED_AT:-$(date '+%Y-%m-%d %H:%M:%S')}\"}}"
405
562
  HASH=$(alloy _record compute openspec/changes/<name> retrospective)
406
- alloy _record write openspec/changes/<name> retrospective "$HASH" "$(date "+%Y-%m-%d %H:%M:%S")" "$(alloy _record approver openspec/changes/<name>)"
407
- git add openspec/changes/<name>/retrospective.md
563
+ alloy _record write openspec/changes/<name> retrospective "$HASH" "$APPROVAL_TIME" "$(alloy _record approver openspec/changes/<name>)"
564
+ git add openspec/changes/<name>/
408
565
  git commit -m "docs(<name>): retrospective 已确认"
409
566
  ```
410
567
 
@@ -414,24 +571,6 @@ git commit -m "docs(<name>): retrospective 已确认"
414
571
 
415
572
  ### 完成
416
573
 
417
- **记录阶段完成时间:**
418
-
419
- ```bash
420
- COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
421
- TIMINGS=$(alloy _state read openspec/changes/<name> phase_timings 2>/dev/null || echo "{}")
422
- echo "$TIMINGS" | python3 -c "
423
- import sys,json
424
- content = sys.stdin.read()
425
- d = json.loads(content) if content.strip() else {}
426
- p = d.setdefault('apply',{})
427
- if 'completed_at' not in p:
428
- p['completed_at']='$COMPLETED_AT'
429
- print(json.dumps(d))
430
- " | while read -r val; do alloy _state write openspec/changes/<name> phase_timings "$val"; done
431
- git add openspec/changes/<name>/
432
- git commit -m "chore(<name>): 记录 apply 阶段完成时间"
433
- ```
434
-
435
574
  ```
436
575
  ┌──────────────────────────────────────┐
437
576
  │ Alloy [3/5] · Phase: Apply — DONE │
@@ -460,11 +599,26 @@ git commit -m "chore(<name>): 记录 apply 阶段完成时间"
460
599
  - 代码变更:SDD 过程中每次成功验证后立即 commit
461
600
  - verify.md / retrospective.md:用户通过审查窗口选 (a) 确认后,hash 锁定 + commit(具体命令已内联在上方各审查窗口中)
462
601
 
463
- **通过 `alloy _guard` 校验并更新 phase:**
602
+ **SDD commit 前检查 untracked 文件:**
603
+
604
+ commit 实现代码前,先检查是否有未跟踪文件:
605
+ ```bash
606
+ UNTRACKED=$(git status --porcelain | grep '^??' | sed 's/^?? //')
607
+ ```
608
+
609
+ 对每个未跟踪文件,判断:
610
+ - **构建产物或临时文件**(`.vite/`、`dist/`、`build/`、`.next/`、`.cache/`、`*.log`、`node_modules/` 等)→ 追加到 `.gitignore`,`git add .gitignore` 一起提交
611
+ - **项目源码**(`.ts`、`.vue`、`.css` 等新创建的文件)→ 按精准路径 `git add`
612
+
613
+ 不需要穷举目录——Agent 根据项目上下文判断即可。比如项目用了 vite,看到 `.vite/` 就知道该 ignore。判断不准时,询问用户确认。
614
+
615
+ **通过 `alloy _guard` 校验并更新 phase(必须在 worktree 中执行,若使用了 worktree):**
464
616
  ```bash
465
617
  alloy _guard openspec/changes/<name> applied --apply
618
+ git add openspec/changes/<name>/.alloy.yaml
619
+ git commit -m "chore(<name>): phase → applied"
466
620
  ```
467
- guard 自动校验 hash 一致性后推进 phase。
621
+ guard 自动校验 hash 一致性后推进 phase。phase 变更必须 commit,否则 worktree 清理时未提交的变更会丢失。
468
622
 
469
623
  ```
470
624
  💡 建议:可以执行 QA 测试或浏览器测试等质量检查,确认后再进入 archive。
@@ -483,3 +637,4 @@ guard 自动校验 hash 一致性后推进 phase。
483
637
  - **retrospective PRECHECK** —— verify.md 不存在或 Overall Decision 是 FAIL 时 STOP
484
638
  - **apply 完成后不要自动进入 archive** —— archive 是人工闸门,留给用户空间做 QA
485
639
  - **每制品独立 commit** — verify 和 retrospective 单独 hash 锁定并 commit
640
+ - **不输出全局制品进度** — [N/M] 是阶段内局部编号(M=2),不要输出"N/8 artifacts 完成"。全局进度由 `alloy status` 管理