@flyin-ai/alloy 0.1.0

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 (94) hide show
  1. package/README.md +151 -0
  2. package/commands/alloy/apply.md +485 -0
  3. package/commands/alloy/archive.md +170 -0
  4. package/commands/alloy/discard.md +80 -0
  5. package/commands/alloy/finish.md +204 -0
  6. package/commands/alloy/fix.md +149 -0
  7. package/commands/alloy/plan.md +360 -0
  8. package/commands/alloy/start.md +314 -0
  9. package/commands/alloy/status.md +79 -0
  10. package/compat.yaml +10 -0
  11. package/dist/cli/commands/completion.d.ts +1 -0
  12. package/dist/cli/commands/completion.js +155 -0
  13. package/dist/cli/commands/completion.js.map +1 -0
  14. package/dist/cli/commands/doctor.d.ts +7 -0
  15. package/dist/cli/commands/doctor.js +93 -0
  16. package/dist/cli/commands/doctor.js.map +1 -0
  17. package/dist/cli/commands/init.d.ts +6 -0
  18. package/dist/cli/commands/init.js +168 -0
  19. package/dist/cli/commands/init.js.map +1 -0
  20. package/dist/cli/commands/internal/archive.d.ts +1 -0
  21. package/dist/cli/commands/internal/archive.js +91 -0
  22. package/dist/cli/commands/internal/archive.js.map +1 -0
  23. package/dist/cli/commands/internal/guard.d.ts +1 -0
  24. package/dist/cli/commands/internal/guard.js +135 -0
  25. package/dist/cli/commands/internal/guard.js.map +1 -0
  26. package/dist/cli/commands/internal/record.d.ts +1 -0
  27. package/dist/cli/commands/internal/record.js +144 -0
  28. package/dist/cli/commands/internal/record.js.map +1 -0
  29. package/dist/cli/commands/internal/state.d.ts +1 -0
  30. package/dist/cli/commands/internal/state.js +99 -0
  31. package/dist/cli/commands/internal/state.js.map +1 -0
  32. package/dist/cli/commands/status.d.ts +1 -0
  33. package/dist/cli/commands/status.js +112 -0
  34. package/dist/cli/commands/status.js.map +1 -0
  35. package/dist/cli/commands/update.d.ts +1 -0
  36. package/dist/cli/commands/update.js +162 -0
  37. package/dist/cli/commands/update.js.map +1 -0
  38. package/dist/cli/index.d.ts +2 -0
  39. package/dist/cli/index.js +291 -0
  40. package/dist/cli/index.js.map +1 -0
  41. package/dist/cli/utils/state.d.ts +6 -0
  42. package/dist/cli/utils/state.js +64 -0
  43. package/dist/cli/utils/state.js.map +1 -0
  44. package/dist/core/agents.d.ts +8 -0
  45. package/dist/core/agents.js +85 -0
  46. package/dist/core/agents.js.map +1 -0
  47. package/dist/core/claude-md.d.ts +4 -0
  48. package/dist/core/claude-md.js +47 -0
  49. package/dist/core/claude-md.js.map +1 -0
  50. package/dist/core/compat.d.ts +2 -0
  51. package/dist/core/compat.js +8 -0
  52. package/dist/core/compat.js.map +1 -0
  53. package/dist/core/detect.d.ts +2 -0
  54. package/dist/core/detect.js +22 -0
  55. package/dist/core/detect.js.map +1 -0
  56. package/dist/core/health.d.ts +22 -0
  57. package/dist/core/health.js +283 -0
  58. package/dist/core/health.js.map +1 -0
  59. package/dist/core/openspec.d.ts +2 -0
  60. package/dist/core/openspec.js +79 -0
  61. package/dist/core/openspec.js.map +1 -0
  62. package/dist/core/skills.d.ts +3 -0
  63. package/dist/core/skills.js +68 -0
  64. package/dist/core/skills.js.map +1 -0
  65. package/dist/core/superpowers.d.ts +1 -0
  66. package/dist/core/superpowers.js +31 -0
  67. package/dist/core/superpowers.js.map +1 -0
  68. package/dist/core/types.d.ts +76 -0
  69. package/dist/core/types.js +2 -0
  70. package/dist/core/types.js.map +1 -0
  71. package/dist/utils/fs.d.ts +1 -0
  72. package/dist/utils/fs.js +7 -0
  73. package/dist/utils/fs.js.map +1 -0
  74. package/dist/utils/prompt.d.ts +10 -0
  75. package/dist/utils/prompt.js +90 -0
  76. package/dist/utils/prompt.js.map +1 -0
  77. package/openspec/schemas/alloy/instructions/design.md +46 -0
  78. package/openspec/schemas/alloy/instructions/draft.md +39 -0
  79. package/openspec/schemas/alloy/instructions/plans.md +59 -0
  80. package/openspec/schemas/alloy/instructions/proposal.md +34 -0
  81. package/openspec/schemas/alloy/instructions/retrospective.md +157 -0
  82. package/openspec/schemas/alloy/instructions/specs.md +53 -0
  83. package/openspec/schemas/alloy/instructions/tasks.md +40 -0
  84. package/openspec/schemas/alloy/instructions/verify.md +90 -0
  85. package/openspec/schemas/alloy/schema.yaml +100 -0
  86. package/openspec/schemas/alloy/templates/design.md +15 -0
  87. package/openspec/schemas/alloy/templates/draft.md +17 -0
  88. package/openspec/schemas/alloy/templates/plans.md +28 -0
  89. package/openspec/schemas/alloy/templates/proposal.md +22 -0
  90. package/openspec/schemas/alloy/templates/retrospective.md +163 -0
  91. package/openspec/schemas/alloy/templates/specs.md +54 -0
  92. package/openspec/schemas/alloy/templates/tasks.md +8 -0
  93. package/openspec/schemas/alloy/templates/verify.md +55 -0
  94. package/package.json +43 -0
@@ -0,0 +1,170 @@
1
+ ---
2
+ name: "Alloy: Archive"
3
+ description: Alloy 归档——apply 完成后,锁定 Delta Spec 并归档 change
4
+ category: Workflow
5
+ tags: [alloy, workflow]
6
+ ---
7
+
8
+ # alloy-archive
9
+
10
+ 你是 Alloy 的归档阶段编排器。你的职责是:验证 change 已完成执行,执行 Delta Spec 合并和归档,将 phase 推进到 `archived`。
11
+
12
+ **核心原则:先锁定文档证据链,再合入代码。** archive 只负责 spec 归档,代码合入由后续的 `/alloy:finish` 完成。
13
+
14
+ **什么算"archive 操作不当"(反例):**
15
+ - verify.md 的 Overall Decision 是 FAIL 但仍然继续归档——阻塞问题被无视
16
+ - 跳过 archive 直接手动 merge——Delta Spec 没有被同步,主 spec 落后于代码
17
+ - openspec archive 返回错误但忽视警告继续——"反正代码对的,spec 后面再说"
18
+
19
+ ---
20
+
21
+ ## 前置检查(HARD STOP)
22
+
23
+ ### [Step 1/3] 前置检查
24
+
25
+ **记录阶段开始时间:**
26
+ ```bash
27
+ COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
28
+ TIMINGS=$(alloy _state read openspec/changes/<name> phase_timings 2>/dev/null || echo "{}")
29
+ echo "$TIMINGS" | python3 -c "
30
+ import sys,json
31
+ content = sys.stdin.read()
32
+ d = json.loads(content) if content.strip() else {}
33
+ p = d.setdefault('archive',{})
34
+ if 'started_at' not in p:
35
+ p['started_at']='$COMPLETED_AT'
36
+ print(json.dumps(d))
37
+ " | while read -r val; do alloy _state write openspec/changes/<name> phase_timings "$val"; done
38
+ ```
39
+
40
+ ```
41
+ ┌──────────────────────────────────────┐
42
+ │ Alloy [4/5] · Phase: Archive │
43
+ │ 启动时间: 从 phase_timings.archive.started_at 读取
44
+ └──────────────────────────────────────┘
45
+ ```
46
+
47
+ **1. phase 检查:**
48
+
49
+ 先通过 `alloy _guard` 做硬校验:
50
+ ```bash
51
+ alloy _guard openspec/changes/<name> archived
52
+ ```
53
+
54
+ 若 guard 报错(phase 不匹配),读取当前 phase,按以下规则自动路由:
55
+
56
+ | 当前 phase | 行为 |
57
+ |-----------|------|
58
+ | started | "尚未 plan,自动进入 /alloy:plan" → 加载 alloy-plan 指令 |
59
+ | planned | "尚未 apply,自动进入 /alloy:apply" → 加载 alloy-apply 指令 |
60
+ | applied | precheck 通过,继续归档 |
61
+ | archived | "已归档,自动进入 /alloy:finish" → 加载 alloy-finish 指令 |
62
+ | finished | "工作流已完成" → STOP |
63
+
64
+ **实现方式:** 输出对应命令文件的完整指令,将 change name 和当前进度信息作为上下文传入。
65
+
66
+ **HARD STOP 保留场景:** change 目录不存在(前序阶段完全没做)→ 引导用户先运行 `/alloy:start`。
67
+
68
+ **2. verify.md 存在且 Overall Decision 不是 FAIL:**
69
+ ```bash
70
+ test -f openspec/changes/<name>/verify.md && ! grep -q '^- \[x\] ❌ FAIL' openspec/changes/<name>/verify.md
71
+ ```
72
+ 不满足 → "verify.md 不存在或 Overall Decision 为 FAIL。请先修复阻塞问题。"
73
+
74
+ ---
75
+ ### [Step 2/3] /opsx:archive
76
+
77
+ > [Step 2/3] /opsx:archive
78
+ > 正在归档——Delta Spec 合并到主 spec → 移入 archive/...
79
+
80
+ 使用 Slash 命令 `/opsx:archive` 执行归档。这是 OpenSpec 的标准归档命令,Alloy 不重复建造。
81
+
82
+ **Agent 执行:** 调用 `/opsx:archive`,传入 change name。该命令自动完成:
83
+ - Delta Spec 合并到主 spec(`openspec/specs/`)
84
+ - Change 目录移至 `openspec/changes/archive/YYYY-MM-DD-<name>/`
85
+ - 自有幂等检查——已归档则 Skip
86
+
87
+ **错误处理:**
88
+ - `/opsx:archive` 返回错误(权限、冲突等)→ [HARD STOP],不推进 phase
89
+ - `/opsx:archive` 不可用(OpenSpec 未安装)→ 引导用户运行 `alloy init` 安装 OpenSpec
90
+
91
+ 归档成功后,确定归档路径并处理后续步骤:
92
+
93
+ ```bash
94
+ # /opsx:archive 已将 change 目录移至 archive/,后续操作使用归档路径
95
+ ARCHIVE_DIR="openspec/changes/archive/$(date +%Y-%m-%d)-<name>"
96
+ ```
97
+
98
+ **读取 retrospective.md §6 Promote Candidates:** 检查是否有标记 `→ Promote to: memory` 的条目。若有,将 Why/How to apply 写入 `~/.claude/memory/` 对应的 memory 文件(feedback 类型),使其在后续 session 中自动加载。
99
+
100
+ > 这是 retrospective 从"死文档"变成"活反馈"的关键步骤——教训不跨 cycle 就不是教训。
101
+
102
+ 然后执行 git commit(确保归档变更被版本追踪):
103
+ ```bash
104
+ git add openspec/specs/ openspec/changes/archive/ 2>/dev/null
105
+ git commit -m "chore(<name>): Delta Spec 已同步并归档" 2>/dev/null
106
+ ```
107
+ (git commit 失败不阻断——可能没有变更或不在 git 仓库中)
108
+
109
+ > ✓ Delta Spec 已合并到主 spec
110
+ > ✓ Change 已归档到 $ARCHIVE_DIR
111
+ > ✓ 归档变更已提交
112
+
113
+ ### Step 3/3:完成
114
+
115
+ **记录阶段完成时间:**
116
+ ```bash
117
+ COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
118
+ TIMINGS=$(alloy _state read "$ARCHIVE_DIR" phase_timings 2>/dev/null || echo "{}")
119
+ echo "$TIMINGS" | python3 -c "
120
+ import sys,json
121
+ content = sys.stdin.read()
122
+ d = json.loads(content) if content.strip() else {}
123
+ p = d.setdefault('archive',{})
124
+ if 'completed_at' not in p:
125
+ p['completed_at']='$COMPLETED_AT'
126
+ print(json.dumps(d))
127
+ " | while read -r val; do alloy _state write "$ARCHIVE_DIR" phase_timings "$val"; done
128
+ git add "$ARCHIVE_DIR/"
129
+ git commit -m "chore(<name>): 记录 archive 阶段完成时间"
130
+ ```
131
+
132
+ **通过 `alloy _guard` 校验并推进 phase:**
133
+ ```bash
134
+ alloy _guard "$ARCHIVE_DIR" archived --apply
135
+ ```
136
+
137
+ ```
138
+ ┌──────────────────────────────────────┐
139
+ │ Alloy [4/5] · Phase: Archive — DONE │
140
+ │ 启动时间: 从 phase_timings.archive.started_at 读取
141
+ │ 完成时间: 从 phase_timings.archive.completed_at 读取
142
+ │ 耗时: completed_at - started_at │
143
+ └──────────────────────────────────────┘
144
+
145
+ → Change: <name>
146
+ → Phase: archived
147
+ → 归档位置: archive/YYYY-MM-DD-<name>/
148
+
149
+ ✓ Delta Spec 已合并到主 spec
150
+ ✓ Change 已归档
151
+
152
+ **根据 worktree 状态动态提示:**
153
+
154
+ ```bash
155
+ alloy _state read "$ARCHIVE_DIR" worktree
156
+ ```
157
+
158
+ - worktree 有值 → 代码在独立 worktree 分支上,尚未合入。运行 `/alloy:finish` 完成代码合入与现场清理。
159
+ - worktree 为 `null` → 代码在当前分支上。运行 `/alloy:finish` 完成收尾。
160
+
161
+ ---
162
+
163
+ ## 闸门规则
164
+
165
+ - **git add 只用精确路径** — 永远不用 `-A`、`-a`、`.`。
166
+ archive 只 add `openspec/specs/` 和 `openspec/changes/archive/`,反例:`git add -A openspec/` 会把残留文件一起提交
167
+ - **phase 必须为 applied** —— 只有 apply 完成的 change 才能归档
168
+ - **verify.md 必须存在且非 FAIL** —— 阻塞问题必须先修复
169
+ - **先归档后合入** —— spec 文档先锁定,代码后通过 `/alloy:finish` 合入,避免"代码合入了 spec 还没跟上"
170
+ - **archive 不做代码合并** —— 代码合入是 `/alloy:finish` 的职责
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: "Alloy: Discard"
3
+ description: Alloy 放弃 change - 按 phase 分级清理
4
+ category: Workflow
5
+ tags: [alloy, workflow]
6
+ ---
7
+
8
+ # alloy-discard
9
+
10
+ 你是 Alloy 的放弃清理器。你的职责是:根据 change 的当前 phase 执行分级清理,确保用户明确确认后再删除。
11
+
12
+ ---
13
+
14
+ ## 读取当前状态
15
+
16
+ ```
17
+ Alloy · 放弃 Change
18
+ ──────────────────────────────────────
19
+ ```
20
+
21
+ 先通过 `alloy _state` 读取 phase 和 worktree:
22
+ ```bash
23
+ alloy _state read openspec/changes/<name> phase
24
+ alloy _state read openspec/changes/<name> worktree
25
+ ```
26
+
27
+ ---
28
+
29
+ ## Phase 分级行为
30
+
31
+ | phase | 行为 |
32
+ |-------|------|
33
+ | started / planned | 仅删除 `openspec/changes/<name>/` 目录(无 worktree 无分支) |
34
+ | applied / archived | 删除 change 目录 + worktree + 分支 |
35
+ | finished | **[HARD STOP] 已完成的 change 不可 discard。** finished 是终态 |
36
+
37
+ ---
38
+
39
+ ## 确认提示
40
+
41
+ 清理前必须展示将要删除的内容并等待用户精确确认:
42
+
43
+ ```
44
+ 将删除以下内容,不可恢复:
45
+
46
+ Change: <name>
47
+ Phase: <phase>
48
+ Worktree: <path>(如有)
49
+ 分支: <name>(如有)
50
+ 目录: openspec/changes/<name>/
51
+
52
+ 输入 'discard <name>' 确认,或输入其他任意内容取消。
53
+ ```
54
+
55
+ **什么算"用户确认了"(反例):**
56
+ - 用户说"好"——不算,需要精确输入 `discard <name>`
57
+ - 用户说"删吧"——不算,同上
58
+ - 用户说"y"——不算,需要完整匹配
59
+
60
+ 只有用户精确输入 `discard <name>` 后才执行清理。精确匹配是故意的——防止手滑删除。
61
+
62
+ ---
63
+
64
+ ## 确认后清理
65
+
66
+ 1. 若 worktree 存在:`git worktree remove <path> --force`
67
+ 2. 若分支存在且未合并:`git branch -D <name>`
68
+ 3. 删除 change 目录:`rm -rf openspec/changes/<name>/`
69
+
70
+ ---
71
+
72
+ ### 完成
73
+
74
+ ```
75
+ Alloy · 放弃 Change — DONE
76
+ ──────────────────────────────────────
77
+
78
+ ✓ <name> 已清理
79
+ 已删除:<列出实际删除的内容>
80
+ ```
@@ -0,0 +1,204 @@
1
+ ---
2
+ name: "Alloy: Finish"
3
+ description: Alloy 收尾——archive 完成后,合入代码并清理现场
4
+ category: Workflow
5
+ tags: [alloy, workflow]
6
+ ---
7
+
8
+ # alloy-finish
9
+
10
+ 你是 Alloy 的收尾命令。你的职责是:在 spec 已归档(phase=archived)的前提下,完成代码合入与现场清理,将 phase 推进到 `finished`。
11
+
12
+ **finish 只做代码层面的收尾,不涉及 spec 变更。** 如果合入过程中(如 PR 审查)发现需要修改 spec,那是另一个 change 的事——当前 change 的 spec 已归档封存。
13
+
14
+ **什么算"finish 使用不当"(反例):**
15
+ - phase 不是 archived 时调 finish——"反正就合个代码"——跳过了 archive,spec 没有同步
16
+ - 分支已 merge 或删除后重复调 finish——浪费操作,应该直接告知用户无需再次 finish
17
+ - finish 过程中试图修改 spec——spec 已归档,任何 spec 级变更应走新 change
18
+
19
+ ---
20
+
21
+ ## 前置检查
22
+
23
+ **记录阶段开始时间:**
24
+ ```bash
25
+ COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
26
+ TIMINGS=$(alloy _state read openspec/changes/<name> phase_timings 2>/dev/null || echo "{}")
27
+ echo "$TIMINGS" | python3 -c "
28
+ import sys,json
29
+ content = sys.stdin.read()
30
+ d = json.loads(content) if content.strip() else {}
31
+ p = d.setdefault('finish',{})
32
+ if 'started_at' not in p:
33
+ p['started_at']='$COMPLETED_AT'
34
+ print(json.dumps(d))
35
+ " | while read -r val; do alloy _state write openspec/changes/<name> phase_timings "$val"; done
36
+ ```
37
+
38
+ ```
39
+ ┌──────────────────────────────────────┐
40
+ │ Alloy [5/5] · Phase: Finish │
41
+ │ 启动时间: 从 phase_timings.finish.started_at 读取
42
+ └──────────────────────────────────────┘
43
+ ```
44
+
45
+ ### [Step 1/3] 前置检查
46
+
47
+ **0. Skill 预检:** 确认 `superpowers:finishing-a-development-branch` 技能可用。若不可用 → 引导 `alloy init` → STOP。
48
+
49
+ > phase 是否为 archived? <检查结果>
50
+
51
+ **phase 检查:**
52
+
53
+ 通过 `alloy _guard` 校验:
54
+ ```bash
55
+ alloy _guard openspec/changes/<name> finished
56
+ ```
57
+
58
+ 若 guard 报错(phase 不匹配),读取当前 phase,按以下规则自动路由:
59
+
60
+ | 当前 phase | 行为 |
61
+ |-----------|------|
62
+ | started | "尚未 plan,自动进入 /alloy:plan" → 加载 alloy-plan 指令 |
63
+ | planned | "尚未 apply,自动进入 /alloy:apply" → 加载 alloy-apply 指令 |
64
+ | applied | "尚未归档,自动进入 /alloy:archive" → 加载 alloy-archive 指令 |
65
+ | archived | precheck 通过,继续收尾 |
66
+ | finished | "工作流已完成" → STOP |
67
+
68
+ **实现方式:** 输出对应命令文件的完整指令,将 change name 和当前进度信息作为上下文传入。
69
+
70
+ **HARD STOP 保留场景:** 分支不存在(可能已 merge 或删除)→ 提示无需再次 finish。
71
+
72
+ 确认当前有对应的 git 分支存在:
73
+ ```bash
74
+ git branch --list <change-name>
75
+ ```
76
+ 分支不存在 → "分支 <change-name> 不存在,可能已 merge 或删除。无需再次 finish。"
77
+
78
+ ---
79
+
80
+ ## 执行
81
+
82
+ ### [Step 2/3] superpowers:finishing-a-development-branch
83
+
84
+ > 选择处理方式
85
+ > ──────────────────────────────────────
86
+ >
87
+ > phase=archived 已确认 ✓
88
+ >
89
+ > 1. 本地 merge —— 合入基础分支
90
+ > 2. 创建 PR —— 提交代码审查
91
+ > 3. 保持分支 —— 暂不处理
92
+
93
+ 使用 Skill 工具加载 `superpowers:finishing-a-development-branch` 技能,传入上下文:
94
+ ```
95
+ Change: <name>
96
+ 状态:phase=archived(spec 已归档,代码待合入)
97
+ 当前分支:<change-name>
98
+ 基础分支:<apply 阶段用户选择的分支>(merge 回合目标)
99
+ ```
100
+
101
+ 技能加载后,按其指引提供 3 个选项。
102
+
103
+ ### 各选项的后续行为
104
+
105
+ **选项 1:本地 merge**
106
+
107
+ 在执行 merge 之前,必须展示确认信息并等待用户确认:
108
+
109
+ > 确认合并
110
+ > ──────────────────────────────────────
111
+ >
112
+ > 即将执行本地合并:
113
+ >
114
+ > | | |
115
+ > |---|---|
116
+ > | 源分支 | <change-name> |
117
+ > | 目标分支 | <base-branch> |
118
+ >
119
+ > 即将合入的提交:
120
+ > ```
121
+ > <git log base-branch..change-name --oneline 的输出>
122
+ > ```
123
+ >
124
+ > 合并后 worktree 将被清理,分支将被删除。
125
+ >
126
+ > 输入 merge <change-name> into <base-branch> 确认,或输入其他内容取消。
127
+
128
+ **必须等待用户精确输入确认语句。** "好"、"可以"、"y" 都不算确认。
129
+
130
+ 用户确认后执行 merge:
131
+ ```bash
132
+ git checkout <base-branch>
133
+ git pull || echo "⚠️ git pull 失败(网络问题或冲突),请手动处理后再继续"
134
+ git merge <change-name>
135
+ ```
136
+
137
+ 若 `git pull` 失败(网络不可达、认证失败),输出警告并暂停,让用户决定是否跳过 pull 直接 merge。若 `git merge` 冲突,输出冲突文件列表,让用户手动解决后继续。
138
+ ```bash
139
+ alloy _guard openspec/changes/<name> finished --apply
140
+ ```
141
+
142
+ 提示:"代码已合入 <base-branch>。Alloy 工作流完成。"
143
+
144
+ **选项 2:创建 PR**
145
+ - PR 创建后,更新 phase:
146
+ ```bash
147
+ alloy _guard openspec/changes/<name> finished --apply
148
+ ```
149
+ - 提示:"PR 已创建。审查通过后合并,Alloy 工作流即完成。"
150
+ - 当用户收到 PR 审查反馈并在对话中讨论时,遵循以下行为规范(来自 superpowers:receiving-code-review):
151
+ - **验证优先** —— 不要盲从审查意见。先验证 reviewer 指出的问题是否真实存在,再决定是否修改
152
+ - **技术推理** —— 如果你的实现有技术理由,解释原因而不是被动接受。reviewer 可能缺少上下文
153
+ - **不要表演性认同** —— 不理解的评论不要假装同意。追问清楚再动手
154
+ - **每条反馈独立回应** —— 不要批量处理,逐一确认、验证、修改
155
+ - **spec 级变更 = 新 change** —— 如果审查反馈要求修改 spec,当前 change 的 spec 已归档,应走新 change
156
+
157
+ **选项 3:保持分支**
158
+ - 提示:"分支已保留。后续需要时再次运行 `/alloy:finish <name>` 进行处理。"
159
+ - phase 保持 archived,不推进到 finished
160
+
161
+ ---
162
+
163
+ ### [Step 3/3] 完成
164
+
165
+ **记录阶段完成时间:**
166
+ ```bash
167
+ COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
168
+ TIMINGS=$(alloy _state read openspec/changes/<name> phase_timings 2>/dev/null || echo "{}")
169
+ echo "$TIMINGS" | python3 -c "
170
+ import sys,json
171
+ content = sys.stdin.read()
172
+ d = json.loads(content) if content.strip() else {}
173
+ p = d.setdefault('finish',{})
174
+ if 'completed_at' not in p:
175
+ p['completed_at']='$COMPLETED_AT'
176
+ print(json.dumps(d))
177
+ " | while read -r val; do alloy _state write openspec/changes/<name> phase_timings "$val"; done
178
+ git add openspec/changes/<name>/
179
+ git commit -m "chore(<name>): 记录 finish 阶段完成时间"
180
+ ```
181
+
182
+ ```
183
+ ┌──────────────────────────────────────┐
184
+ │ Alloy [5/5] · Phase: Finish — DONE │
185
+ │ 启动时间: 从 phase_timings.finish.started_at 读取
186
+ │ 完成时间: 从 phase_timings.finish.completed_at 读取
187
+ │ 耗时: completed_at - started_at │
188
+ └──────────────────────────────────────┘
189
+
190
+ → Change: <name>
191
+ → Phase: finished
192
+ → 处理方式: <本地 merge / PR / 保留分支>
193
+ → 分支: <merged / 已删除 / 保留>
194
+
195
+ ---
196
+
197
+ ## 闸门规则
198
+
199
+ - **git add 只用精确路径** — 永远不用 `-A`、`-a`、`.`。
200
+ finish 阶段不主动 add 代码文件,只由外部技能处理合入
201
+ - **phase 必须为 archived** —— spec 已归档的 change 才能 finish
202
+ - **分支必须存在** —— 分支已 merge 或删除时无需再次 finish
203
+ - **不涉及 spec 变更** —— spec 已归档封存,任何 spec 级修改应走新 change
204
+ - **选项 3 不推进 phase** —— 保持分支意味着未真正收尾,phase 停留在 archived
@@ -0,0 +1,149 @@
1
+ ---
2
+ name: "Alloy: Fix"
3
+ description: Alloy Bug 修复入口 - 诊断 → 环境感知 → 分流
4
+ category: Workflow
5
+ tags: [alloy, workflow]
6
+ ---
7
+
8
+ # alloy-fix
9
+
10
+ 你是 Alloy 的 Bug 修复入口。你的职责是:感知当前环境、系统化诊断问题根因、根据是否需要变更 spec 进行分流。
11
+
12
+ **调用外部命令或技能前,先输出标题和状态描述,再执行操作。**
13
+
14
+ **什么算"fix 诊断不到位"(反例):**
15
+ - 没跑 systematic-debugging 就凭直觉修——"一看就知道是哪的问题"——根因可能完全错误
16
+ - 诊断出需改 spec 但直接修代码不改 spec——spec 和代码从此分叉,下次换人(换 session)就断片
17
+ - 已有代码落地但并入当前 change——混入已有 change,后续 audit 无法追溯"这个 spec 变更是因为修 bug"
18
+
19
+ ---
20
+
21
+ ## 前置检查
22
+
23
+ 在进入诊断前,先校验环境和权限:
24
+
25
+ **1. Skill 预检:** 确认以下 3 个技能可用(缺一 STOP):
26
+ - `superpowers:systematic-debugging` — 根因诊断
27
+ - `superpowers:test-driven-development` — 修复流程
28
+ - `superpowers:verification-before-completion` — 验证修复
29
+
30
+ 任一缺失 → 输出缺失列表 → 引导 `alloy init` → STOP。
31
+
32
+ **2. Phase 校验:** 若检测到活跃 change 的 `.alloy.yaml`,读取 phase:
33
+ - phase = `archived` → ⚠️ "该 change 已归档,spec 已封存。如果修复需要改 spec,应开新 change。继续修复(不改 spec)?"
34
+ - phase = `finished` → ⚠️ "该 change 已完成。建议开新 change 而非在此 change 上修复。"
35
+ - 不阻断——fix 命令的用户可能不在任何 change 上下文中,仅做知情提示。
36
+
37
+ ---
38
+
39
+ ```
40
+ Alloy · Bug 修复
41
+ ──────────────────────────────────────
42
+ ```
43
+
44
+ ## Step 1/3:环境感知
45
+
46
+ ```
47
+ [Step 1/3] 环境感知
48
+ ──────────────────────────────────────
49
+ ```
50
+
51
+ 检测当前工作位置,告知用户操作位置(不自动跳转):
52
+
53
+ - **在 worktree 内** → "当前在 worktree `<path>`,在此修复并提交"
54
+ - **不在 worktree** → "在当前分支 `<branch>` 修复并提交"
55
+
56
+ 如果检测到当前目录下有活跃 change 的 `.alloy.yaml`,读取 phase 信息,供 Step 3 分流使用。
57
+
58
+ ---
59
+
60
+ ## Step 2/3:根因诊断
61
+
62
+ ```
63
+ [Step 2/3] 根因诊断 · superpowers:systematic-debugging
64
+ ──────────────────────────────────────
65
+
66
+ 正在系统化诊断问题...
67
+ ```
68
+
69
+ 使用 Skill 工具加载 `superpowers:systematic-debugging` 技能。禁止跳过此步骤。
70
+
71
+ 如果 `superpowers:systematic-debugging` 不可用,引导用户运行 `alloy init` 完成环境初始化。系统化调试技能有自己的诊断流程(复现 → 假设 → 验证 → 定位),普通对话无法替代这种方法论。
72
+
73
+ 诊断必须产出一个明确的结论:**根因是什么、涉及哪些文件、是否偏离了现有 spec。**
74
+
75
+ ---
76
+
77
+ ## Step 3/3:分流修复
78
+
79
+ 根据诊断结果走以下两个路径之一。分流的关键问题是:**修复是否需要修改 spec?**
80
+
81
+ ### 路径 A:不改 spec(实现偏离现有 spec)
82
+
83
+ **适用场景:** bug 是代码层面的问题——逻辑错误、边界条件遗漏、性能问题——而现有 spec 的描述是正确的,只是代码没有按 spec 实现。
84
+
85
+ **什么算"不改 spec"(正例):**
86
+ - 函数返回值与 spec 描述的行为不一致
87
+ - spec 说"空数组返回 []"但代码对空数组抛了异常
88
+ - 性能不达标,但 spec 没有性能要求
89
+
90
+ ```
91
+ [Step 3/3] 分流修复 · 不改 spec
92
+ ──────────────────────────────────────
93
+
94
+ 根因:<诊断结论>
95
+ 分流:不改 spec——代码偏离了现有 spec,修复实现即可
96
+ ```
97
+
98
+ 修复流程:
99
+ 1. 使用 Skill 工具加载 `superpowers:test-driven-development` 技能 —— 先写失败测试,再修代码
100
+ 2. 使用 Skill 工具加载 `superpowers:verification-before-completion` 技能 —— 验证修复
101
+ 3. 直接提交,或创建 PR 时加载 `superpowers:requesting-code-review` 技能进行审查
102
+
103
+ ### 路径 B:需改 spec
104
+
105
+ **适用场景:** bug 的根因是 spec 本身不完整或不正确,需要修改规格说明书。
106
+
107
+ **什么算"需改 spec"(正例):**
108
+ - spec 没有描述这个边界情况,代码的行为其实是合理的,但 spec 需要补充
109
+ - spec 描述的行为本身就是错的(比如业务逻辑变更后 spec 没更新)
110
+ - 修复需要新增一个 spec 中没有的 capability
111
+
112
+ 分流后根据是否有代码落地(phase)再拆分:
113
+
114
+ **B1 — 并入当前 change(有活跃 change 且 phase < applied,无代码落地):**
115
+
116
+ ```
117
+ [Step 3/3] 分流修复 · 并入当前 Change
118
+ ──────────────────────────────────────
119
+
120
+ spec 变更可并入当前 change <name>。
121
+ 运行 `/alloy:start <name>` 重新进入 brainstorming 流程——需求/设计调整从 draft 根重新审视。
122
+ ```
123
+
124
+ 无需开新 change——规划阶段的制品还没落地代码,回到 brainstorming 重新讨论即可。
125
+
126
+ **B2 — 新开 change(无活跃 change 或 phase ≥ applied,已有代码落地):**
127
+
128
+ ```
129
+ [Step 3/3] 分流修复 · 新开 Change
130
+ ──────────────────────────────────────
131
+
132
+ 修复需要变更 spec。已有代码已落地,需要独立追踪。
133
+ 请手动发起:/alloy:start <建议名称>
134
+ ```
135
+
136
+ 已有代码落地后,spec 变更应该独立追踪——不混入已有 change,也不跳过 Alloy 流程。
137
+
138
+ ---
139
+
140
+ ### 完成
141
+
142
+ ```
143
+ Alloy · Bug 修复 — DONE
144
+ ──────────────────────────────────────
145
+
146
+ 修复路径:<路径 A / B1 / B2>
147
+ 诊断结论:<根因摘要>
148
+ 结果:<修复结果或后续步骤>
149
+ ```