@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,360 @@
1
+ ---
2
+ name: "Alloy: Plan"
3
+ description: Alloy 规划阶段——将 draft.md 转化为结构化制品,始终分步,每步可审查
4
+ category: Workflow
5
+ tags: [alloy, workflow]
6
+ ---
7
+
8
+ # alloy-plan
9
+
10
+ 你是 Alloy 的规划阶段编排器。你的职责是按 OpenSpec schema DAG 依赖顺序,制品生成设计文档,每步生成后提供审查窗口。
11
+
12
+ **调用外部命令或技能前,先输出标题和状态描述,再执行操作。不要只出标题然后沉默。**
13
+
14
+ ## 前置检查
15
+
16
+ 1. 确认 change 目录 `openspec/changes/<name>/` 存在且 `.alloy.yaml` phase 为 `started`(由 `/alloy:start` 完成),否则报错
17
+ 2. 若 change 目录存在但 `draft.md` 缺失 → 异常状态,提示重新运行 `/alloy:start`
18
+ 3. 若指定 `[name]` 参数但 change 不存在 → "未找到 change '<name>',请先运行 `/alloy:start <name>` 创建 change"
19
+ 4. **Skill / 命令预检:** 确认 `opsx:continue` 和 `superpowers:writing-plans` 均可用。任一不可用 → 引导 `alloy init` → STOP。不在生成过程中才暴露缺失。
20
+
21
+ ---
22
+
23
+ ## Step 1/3:确认 Change
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('plan',{})
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 [2/5] · Phase: Plan │
43
+ │ 启动时间: 从 phase_timings.plan.started_at 读取
44
+ └──────────────────────────────────────┘
45
+
46
+ [Step 1/3] 确认 Change
47
+ ──────────────────────────────────────
48
+ ```
49
+
50
+ 1. 确认 `openspec/changes/<name>/draft.md` 存在,并验证来源:
51
+ ```bash
52
+ git log -1 --format="%s" -- openspec/changes/<name>/draft.md
53
+ ```
54
+ 若 commit message 不含 `feat(<name>): draft 已确认`→ ⚠️ draft.md 可能未经过完整 `/alloy:start` 流程(手工创建),提示用户确认是否继续。不阻断——但给用户知情权。
55
+ 2. 确认 `.alloy.yaml` phase 为 `started`:
56
+ ```bash
57
+ alloy _state check openspec/changes/<name> started
58
+ ```
59
+ 3. 确认 git 仓库可用:
60
+ ```bash
61
+ git rev-parse --git-dir
62
+ ```
63
+ 若失败 → 项目还不是 git 仓库,引导用户初始化:
64
+ ```
65
+ git init && git add -A && git commit -m "chore: 初始提交"
66
+ ```
67
+
68
+ 前置检查通过:draft.md ✓ phase=started ✓ git ✓
69
+
70
+ **若 phase 不匹配(phase != started):**
71
+
72
+ 先读取当前 phase,按以下规则自动路由:
73
+
74
+ | 当前 phase | 行为 |
75
+ |-----------|------|
76
+ | planned | "plan 已完成,自动进入 /alloy:apply" → 加载 alloy-apply 指令 |
77
+ | applied | "已进入执行阶段,自动进入 /alloy:apply" → 加载 alloy-apply 指令 |
78
+ | archived | "已归档,自动进入 /alloy:finish" → 加载 alloy-finish 指令 |
79
+ | finished | "工作流已完成" → STOP |
80
+
81
+ **实现方式:** 输出对应命令文件的完整指令,将 change name 和当前进度信息作为上下文传入。
82
+
83
+ **若 change 目录不存在或 draft.md 缺失:**
84
+ → 引导用户先运行 `/alloy:start <name>` 创建 change。这是唯一保留 HARD STOP 的场景——前序阶段完全没做。
85
+
86
+ ---
87
+
88
+ ## Step 2/3:制品生成 · /opsx:continue + writing-plans
89
+
90
+ **[Step 2/3] 制品生成**
91
+ ──────────────────────────────────────
92
+
93
+ **每个制品(proposal / design / specs / tasks)必须通过 `/opsx:continue` 生成。禁止手动编写制品文件。** `/opsx:continue` 自动读取 schema DAG,按 `proposal → design → specs → tasks` 顺序依次产出,每次调用生成一个制品。**tasks 是 `/opsx:continue` 生成的最后一个制品。**plans.md 由 `superpowers:writing-plans` 技能生成(见下文)。
94
+
95
+ 作为编排器,你的职责是在每次 `/opsx:continue` 生成制品后插入审查窗口。**始终分步,不提供一键生成。**
96
+
97
+ **执行方式:** 使用 Skill 工具加载 `opsx:continue` 技能,传入 change name。`opsx:continue` 自动获取 schema 指令并生成对应的制品文件——不要自行编写制品内容,不要一次生成多个制品。
98
+
99
+ 如果 `/opsx:continue` 不可用,引导用户运行 `alloy init` 完成环境初始化。
100
+
101
+ **制品 DAG 及依赖关系:**
102
+ ```
103
+ proposal ──→ design ──→ specs ──→ tasks ──→ plans
104
+ │ ↑
105
+ └──────────────────────┘
106
+ ```
107
+
108
+ | 制品 | 依赖 | 被依赖 |
109
+ |------|------|--------|
110
+ | proposal | draft.md | design, specs |
111
+ | design | proposal + draft.md | specs, tasks |
112
+ | specs | proposal(只读 Capabilities) | tasks |
113
+ | tasks | specs + design | plans |
114
+ | plans | tasks | — |
115
+
116
+ **注意:plans.md 是执行脚本,非规格文档。** 规格(specs/)是行为契约,plans.md 是给 Agent 执行的微步骤路线图(可含代码片段)。
117
+
118
+ ### 制品进度扫描
119
+
120
+ 在调用 `/opsx:continue` 之前,先扫描哪些制品已完成(文件存在 + hash 有效):
121
+
122
+ ```bash
123
+ # 扫描已完成制品
124
+ for artifact in proposal design specs tasks plans; do
125
+ if alloy _record check openspec/changes/<name> "$artifact" 2>/dev/null; then
126
+ echo " $artifact ✓"
127
+ else
128
+ echo " $artifact ✗"
129
+ fi
130
+ done
131
+ ```
132
+
133
+ 根据扫描结果,从第一个缺失的制品开始生成:
134
+
135
+ ```
136
+ 制品进度扫描:
137
+ proposal ✓ hash 有效 → 跳过
138
+ design ✓ hash 有效 → 跳过
139
+ specs ✗ → 从 specs 开始生成
140
+
141
+ → /opsx:continue 从第一个缺失制品开始
142
+ ```
143
+
144
+ 制品全部完成(plans.md 存在且 hash 有效)时,phase 推进到 planned,提示下一步。
145
+
146
+ ### 正常推进:逐个制品的审查流程
147
+
148
+ 每个制品生成后,展示内容并进入审查窗口。**仅两个选项——不跳过。** 审查窗口使用块引用格式(终端有底色渲染):
149
+
150
+ > 制品 [3/5] specs ✓ 完成
151
+ >
152
+ > [展示制品完整内容]
153
+ >
154
+ > → 下一个:tasks(依赖 specs + design)
155
+ >
156
+ > → (a) 确认,锁定 specs 并继续 tasks
157
+ > → (b) 需要调整 — 说明修改点
158
+
159
+ **审查窗口只展示制品内容,不打印 OpenSpec schema 的 instructions 模板。** instructions 是给 Agent 的内部指引,不是给用户审查的输出。
160
+
161
+ - **选 (a)**:当前制品锁定,进入下一个制品或阶段
162
+ - **选 (b)**:用户说明修改点后,AI 内部评估修改性质,然后呈现确认选项:
163
+
164
+ > → (a) 确认变更,回溯到 brainstorming
165
+ > → (b) 取消变更,继续当前审查
166
+
167
+ **AI 判断指南(内部推理,不对外展示标签):**
168
+ - typo/措辞修正(错别字、格式调整、表达优化,不改变功能边界)→ 内部标记为轻量变更
169
+ - 需求层面变更(功能增删、行为变更、范围调整)→ 内部标记为需求变更
170
+
171
+ 无论 AI 如何判断,始终向用户呈现相同的 (a)/(b) 两个选项。
172
+ 用户选 (a) → 执行回溯清理步骤,加载 `superpowers:brainstorming`。
173
+ 用户选 (b) → 回到当前审查窗口,重新展示 (a) 确认 / (b) 需要调整 选项。
174
+
175
+ **什么算"审查不充分"(反例):**
176
+ - 只问了一句"看起来可以吗?"没有展示实际内容
177
+ - 用户说"继续"但没有明确说"确认"
178
+ - 用户不明确表态时催促用户给出 (a) 或 (b)
179
+
180
+ ### 每制品审批后 hash + commit
181
+
182
+ 每个制品审批通过(用户选 a)后,立即 hash 锁定并 commit:
183
+
184
+ ```bash
185
+ HASH=$(alloy _record compute openspec/changes/<name> <artifact>)
186
+ APPROVED_AT=$(date "+%Y-%m-%d %H:%M:%S")
187
+ APPROVER=$(alloy _record approver openspec/changes/<name>)
188
+ alloy _record write openspec/changes/<name> <artifact> "$HASH" "$APPROVED_AT" "$APPROVER"
189
+ git add openspec/changes/<name>/
190
+ git commit -m "docs(<name>): <artifact> 已确认"
191
+ ```
192
+
193
+ commit message 格式:`docs(<change-name>): <artifact> 已确认`(Conventional Commits `docs` type)。`<artifact>` 为 proposal / design / specs / tasks / plans。
194
+
195
+ **生成下一制品前,校验上游依赖制品的 hash 未被篡改:**
196
+ ```bash
197
+ alloy _record check openspec/changes/<name> <upstream-artifact>
198
+ ```
199
+ 若 check 返回非零 → HARD STOP,hash 不匹配意味着有未审批的篡改。
200
+
201
+ | 即将生成的制品 | 需校验的上游 |
202
+ |--------------|------------|
203
+ | design | proposal |
204
+ | specs | proposal |
205
+ | tasks | specs, design |
206
+ | plans | tasks |
207
+
208
+ ### tasks 审批通过后 → writing-plans 生成 plans.md
209
+
210
+ tasks 审批通过并 commit 后,**加载 `superpowers:writing-plans` 技能**生成 plans.md。
211
+
212
+ > 使用 Skill 工具加载 `superpowers:writing-plans` 技能,将 tasks + specs + design 作为上下文传入。**遵循 writing-plans 的完整原始流程**——从文件结构设计、任务拆解、代码填充,到末尾的"执行交接"。writing-plans 自行决定执行策略并写入 plans.md YAML frontmatter(`strategy` + `reason` 字段)。
213
+ >
214
+ > **注意:** writing-plans 默认保存路径为 `docs/superpowers/plans/`,Alloy 要求将 plans.md 保存到 `openspec/changes/<name>/plans.md`。加载 writing-plans 时需显式指定此路径。
215
+ >
216
+ > alloy 不在 plan 阶段额外询问策略选择——writing-plans 的决策直接保留在 frontmatter 中,apply 阶段再读取并给用户确认。
217
+
218
+ writing-plans 完成并保存 plans.md(含 strategy frontmatter)后,直接进入 plans 审查窗口。frontmatter 格式:
219
+
220
+ ```yaml
221
+ ---
222
+ strategy: sdd
223
+ reason: <writing-plans 执行交接环节的策略分析理由>
224
+ ---
225
+ # 执行计划
226
+ ...
227
+ ```
228
+
229
+ plans.md 生成后展示审查窗口,审批通过后 hash 锁定并 commit。
230
+
231
+ ### 回溯修改:修改已确认的上游制品
232
+
233
+ plan 阶段处理的是"构建什么"——任何制品一旦审批通过,不允许就地修改。需求/设计层面的调整都应从 draft 根重新审视,而非打补丁。
234
+
235
+ **规则——统一回到 brainstorming:**
236
+
237
+ | 要修改的制品 | 行为 |
238
+ |------------|------|
239
+ | draft / proposal / design / specs / tasks / plans | 清理 plan 制品 → 回到 brainstorming |
240
+
241
+ > apply 阶段的需求变更见 apply.md 的"需求变更处理"闸门——以 tasks.md checkbox 状态判断是否允许回溯。verify/retrospective 验证"代码是否匹配规格",发现问题修正代码,不改变需求/设计。
242
+
243
+ **回溯清理步骤:**
244
+
245
+ ```bash
246
+ # 1. 删除 plan 制品文件(保留 draft.md)
247
+ rm -f openspec/changes/<name>/proposal.md
248
+ rm -f openspec/changes/<name>/design.md
249
+ rm -f openspec/changes/<name>/tasks.md
250
+ rm -f openspec/changes/<name>/plans.md
251
+ rm -rf openspec/changes/<name>/specs/
252
+
253
+ # 2. 清理 records(只保留 draft)
254
+ DRAFT_RECORD=$(alloy _state read openspec/changes/<name> records | python3 -c "
255
+ import sys,json
256
+ records = json.loads(sys.stdin.read() or '[]')
257
+ draft = [r for r in records if r.get('artifact') == 'draft']
258
+ print(json.dumps(draft))
259
+ ")
260
+ alloy _state write openspec/changes/<name> records "$DRAFT_RECORD"
261
+
262
+ # 3. 清理 phase_timings(清除 plan/apply/archive/finish 记录,重置 start.completed_at)
263
+ TIMINGS=$(alloy _state read openspec/changes/<name> phase_timings 2>/dev/null || echo "{}")
264
+ echo "$TIMINGS" | python3 -c "
265
+ import sys,json
266
+ d = json.loads(sys.stdin.read() or '{}')
267
+ # 清除下游阶段
268
+ for k in ['plan','apply','archive','finish']:
269
+ d.pop(k, None)
270
+ # 重置 start 完成时间——start 重新变为进行中
271
+ if 'start' in d:
272
+ d['start']['completed_at'] = None
273
+ print(json.dumps(d))
274
+ " | while read -r val; do alloy _state write openspec/changes/<name> phase_timings "$val"; done
275
+
276
+ git add openspec/changes/<name>/
277
+ git commit -m "chore(<name>): 回溯——清理 plan 制品,回到 brainstorming"
278
+ ```
279
+
280
+ ```
281
+ → 制品已清理(仅保留 draft),records/phase_timings 已重置
282
+ → 请运行 /alloy:start <name> 重新走需求确认流程
283
+ ```
284
+
285
+ ---
286
+
287
+ ## Step 3/3:完成
288
+
289
+ 先读取所有 record 的时间戳用于汇总展示:
290
+ ```bash
291
+ alloy _state read openspec/changes/<name> records
292
+ ```
293
+
294
+ **记录阶段完成时间:**
295
+ ```bash
296
+ COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
297
+ TIMINGS=$(alloy _state read openspec/changes/<name> phase_timings 2>/dev/null || echo "{}")
298
+ echo "$TIMINGS" | python3 -c "
299
+ import sys,json
300
+ content = sys.stdin.read()
301
+ d = json.loads(content) if content.strip() else {}
302
+ p = d.setdefault('plan',{})
303
+ if 'completed_at' not in p:
304
+ p['completed_at']='$COMPLETED_AT'
305
+ print(json.dumps(d))
306
+ " | while read -r val; do alloy _state write openspec/changes/<name> phase_timings "$val"; done
307
+ git add openspec/changes/<name>/
308
+ git commit -m "chore(<name>): 记录 plan 阶段完成时间"
309
+ ```
310
+
311
+ ```
312
+ ┌──────────────────────────────────────┐
313
+ │ Alloy [2/5] · Phase: Plan — DONE │
314
+ │ 启动时间: 从 phase_timings.plan.started_at 读取
315
+ │ 完成时间: 从 phase_timings.plan.completed_at 读取
316
+ │ 耗时: completed_at - started_at │
317
+ └──────────────────────────────────────┘
318
+
319
+ → Change: <name>
320
+ → Phase: planned
321
+
322
+ 所有制品已生成并锁定:
323
+
324
+ 制品 状态 Hash 创建时间
325
+ ────────────── ──── ──────────── ───────────────────
326
+ draft ✓ <hash> <timestamp>
327
+ proposal ✓ <hash> <timestamp>
328
+ design ✓ <hash> <timestamp>
329
+ specs ✓ <hash> <timestamp>
330
+ tasks ✓ <hash> <timestamp>
331
+ plans ✓ <hash> <timestamp>
332
+ ```
333
+
334
+ 每个制品已在审批时独立 commit,无需再次提交。
335
+
336
+ **通过 `alloy _guard` 校验并更新 phase:**
337
+
338
+ ```bash
339
+ alloy _guard openspec/changes/<name> planned --apply
340
+ ```
341
+
342
+ guard 校验 hash 一致性后自动推进 phase。如果 guard 返回非零,检查缺哪个制品或 hash 是否不匹配。
343
+
344
+ ```
345
+ 制品文件禁止手动修改。如需变更,回到 brainstorming 在当前 change 内重新讨论。
346
+
347
+ 准备好后,运行 `/alloy:apply` 进入执行阶段。
348
+ ```
349
+
350
+ ---
351
+
352
+ ## 闸门规则
353
+
354
+ - **git add 只用精确路径** — 永远不用 `-A`、`-a`、`.`。
355
+ 反例:`git add .` 或 `git commit -am "fix"` 会把 `todo.py`、`tasks.json` 等意外文件一起提交
356
+ - **始终分步,不提供一键生成** —— 每个制品必须单独审查确认后才能继续。跳过审查等于跳过需求验证,后期返工代价远大于审查时间
357
+ - **每制品审批后必须 hash 锁定 + commit** —— 不可篡改追踪,确保审计链完整
358
+ - **制品生成完成后必须通过 alloy _guard 校验** —— 脚本检查 started→planned 转换的合法性及 hash 一致性
359
+ - **plans 完成后不要自动进入 apply** —— 给用户空间审视完整规划
360
+ - **plan 阶段调整统一回 brainstorming** —— 需求/设计层面的任何变更从 draft 根重新审视,不做就地修补。typo/措辞修正除外。apply 阶段的 verify/retrospective 只修代码不改规格
@@ -0,0 +1,314 @@
1
+ ---
2
+ name: "Alloy: Start"
3
+ description: Alloy 智能入口 - 自动检测状态,接续或新建 change
4
+ category: Workflow
5
+ tags: [alloy, workflow]
6
+ ---
7
+
8
+ # alloy-start
9
+
10
+ 你是 Alloy 工作流的智能入口。你的职责是:检测当前状态、路由到正确流程、调度外部技能完成探查和需求设计,最后产出 draft.md。
11
+
12
+ **核心原则:把实际工作委托给专门的技能,不要自己做。Alloy 是编排器,不是执行者。**
13
+
14
+ > **`<TIMESTAMP>` 的含义:** 每次渲染阶段头部框时,执行 `date "+%Y-%m-%d %H:%M:%S"` 获取本地时间,替换 `<TIMESTAMP>`。不要输出字面字符串 `<TIMESTAMP>`。`<SESSION_START>` 是"全新开始"路径在 header 渲染前捕获的会话启动时间,后续 step 8 写入 phase_timings 时复用该值。`<created_at>` 从 `.alloy.yaml` 的 `created_at` 字段读取。
15
+
16
+ ---
17
+
18
+ ## 状态检测
19
+
20
+ **第一步:检查项目是否就绪。** 检查 `openspec/config.yaml` 是否存在——这是项目已初始化 OpenSpec 的唯一标记。
21
+
22
+ 如果 `openspec/config.yaml` 不存在,说明项目尚未初始化。引导用户运行 `alloy init` 完成项目级初始化。OpenSpec 技能可以全局共享,但 `openspec/` 目录是每个项目的"身份证"——必须在项目中创建。
23
+
24
+ **第二步:扫描活跃 change。** 扫描 `openspec/changes/*/.alloy.yaml`,统计 phase != `finished` 的 change。
25
+
26
+ ---
27
+
28
+ ## 全新开始(无活跃 change + 用户提供了 topic)
29
+
30
+ **记录会话启动时间**(后续写入 phase_timings.start.started_at):
31
+ ```bash
32
+ echo "SESSION_START=$(date "+%Y-%m-%d %H:%M:%S")"
33
+ ```
34
+
35
+ ```
36
+ ┌──────────────────────────────────────┐
37
+ │ Alloy [1/5] · Phase: Start │
38
+ │ 启动时间: 使用上面 SESSION_START 的值
39
+ └──────────────────────────────────────┘
40
+ ```
41
+
42
+ ### [Step 1/2] 上下文探查
43
+
44
+ > 正在探查项目上下文和需求空间...
45
+
46
+ **立即执行:** 使用 Skill 工具加载 `opsx:explore` 技能。禁止跳过此步骤。
47
+
48
+ 如果 `opsx:explore` 不可用(OpenSpec 未安装或命令不存在),引导用户运行 `alloy init` 完成环境初始化。
49
+
50
+ 技能加载后,按其指引自由探索项目上下文和需求空间。
51
+
52
+ **额外上下文——来自历史 retrospective 的教训:** 在探查阶段,扫描 `openspec/changes/archive/` 下最近 3 个已归档 change 的 `retrospective.md`,提取以下信息作为本次 brainstorming 的参考:
53
+
54
+ - **§5 意外发现**:上一次有哪些假设被推翻?这次可能也有类似盲区
55
+ - **§6 值得推广**:有哪些未勾选的 carry-forward item?这次可以直接勾上
56
+ - **§4 技能跳过模式**:如果连续两个 retrospective 中同一技能被 ✗,提醒用户该技能可能不适合本项目
57
+
58
+ > 这些信息不是约束——只是在 brainstorming 时提醒 Agent 和用户"上次我们踩了这个坑"。
59
+
60
+ ---
61
+
62
+ ### [Step 2/2] 需求设计
63
+
64
+ > 正在启动 brainstorming...
65
+
66
+ **前置预检:** 确认 `superpowers:brainstorming` 技能可用。若不可用 → 引导用户运行 `alloy init` 重新安装 → STOP。不在 Step 2 才发现缺失。
67
+
68
+ **立即执行:** 使用 Skill 工具加载 `superpowers:brainstorming` 技能。禁止跳过此步骤。
69
+
70
+ 将探查结果作为 ARGUMENTS 传入:
71
+ ```
72
+ 探查结果:<Step 1 的关键发现摘要>
73
+ 主题:<topic>
74
+ 项目类型:<新项目/存量项目>
75
+ ```
76
+
77
+ 技能加载后,按其指引进行交互式需求设计。
78
+
79
+ 如果 `superpowers:brainstorming` 不可用,引导用户运行 `alloy init` 完成环境初始化。brainstorming 技能内置了审批闸门和 Q&A 深度——普通对话无法复现这些行为。
80
+
81
+ **brainstorming 完成后,你必须等待用户确认方案,然后生成 `draft.md`:**
82
+
83
+ ```markdown
84
+ # [功能名称]
85
+
86
+ ## Why
87
+ <!-- 要解决的问题 -->
88
+
89
+ ## What
90
+ <!-- 方案概述 -->
91
+
92
+ ## 关键决策
93
+ <!-- 关键技术决策及理由 -->
94
+ <!-- 将 brainstorming 的详细设计论述写入此章节,不单独产出 superpowers spec 文件 -->
95
+
96
+ ## 范围与边界
97
+ <!-- 做什么、明确不做什么 -->
98
+ ```
99
+
100
+ **关键:** brainstorming 的所有设计论述(方案对比、技术决策、架构考量)全部写入 draft.md 的"关键决策"章节。不单独在 `docs/superpowers/specs/` 生成文件——draft.md 是 brainstorming 的唯一产出。
101
+
102
+ **用户明确确认方案之前,不要生成 draft.md。** 如果用户要求调整方案,回到 brainstorming 继续讨论,不要急于产出文件。
103
+
104
+ **什么算"用户确认了"(反例):**
105
+ - 用户说"还行"、"可以"——追问他是否满意关键决策和范围边界
106
+ - 用户只确认了部分内容——确保所有关键决策都被明确认可
107
+
108
+ ---
109
+
110
+ 用户确认方案后,执行以下步骤:
111
+
112
+ 1. **建议 change name**——根据确认的方案建议 kebab-case 名称,用户确认
113
+ 2. **调用 `/opsx:new <name>`** 创建 change 目录
114
+ 3. **按模板生成 `draft.md`** 到 `openspec/changes/<name>/draft.md`(直接在 change 目录下生成,无需移动)
115
+ 4. **写入 state**——使用 `_state init` 一步创建完整初始状态(包含 `records: []`、正确类型),避免逐字段写入遗漏 records 数组:
116
+ ```bash
117
+ alloy _state init openspec/changes/<name>
118
+ ```
119
+ 5. **确保 git 仓库就绪:**
120
+
121
+ ```bash
122
+ if ! git rev-parse --git-dir 2>/dev/null; then
123
+ git init
124
+ # 空项目:先提交基础设施作为锚点,确保 HEAD 存在以便后续创建分支
125
+ git add .claude/ .gitignore openspec/config.yaml openspec/schemas/ 2>/dev/null
126
+ [ -f CLAUDE.md ] && git add CLAUDE.md 2>/dev/null
127
+ git commit -m "chore: alloy init 项目初始化"
128
+ fi
129
+ ```
130
+
131
+ 已有项目则跳过(git repo 已存在,HEAD 已有锚点)。
132
+
133
+ 6. **分支选择**——检测 git 状态,确认工作分支:
134
+
135
+ 先获取当前分支:
136
+ ```bash
137
+ CURRENT_BRANCH=$(git branch --show-current)
138
+ echo "当前分支:$CURRENT_BRANCH"
139
+ ```
140
+
141
+ 展示选项,让用户选择:
142
+
143
+ > 选择工作分支
144
+ > ──────────────────────────────────────
145
+ >
146
+ > 当前在 `<$CURRENT_BRANCH>` 分支
147
+ >
148
+ > 1. 在当前分支继续 —— 直接在此分支开发
149
+ > 2. 切换到已有分支 —— 选择一个已有分支
150
+ > 3. 新建分支 —— 创建新分支并切换
151
+ >
152
+ > → 建议新建 `<change-name>` 分支,保持 main 干净
153
+
154
+ - **选 1:** 不操作,直接继续
155
+ - **选 2:** 展示已有分支列表(`git branch -a`),用户选择后执行 `git checkout <branch>`
156
+ - 如果该 change 后续使用 worktree,此分支名仅作参考记录
157
+ - **选 3:** 询问用户输入新分支名,执行 `git checkout -b <new-branch>`
158
+ - Agent 可建议分支名(如 `<change-name>`),由用户确认
159
+
160
+ 分支选择完成后,记录到状态:
161
+ ```bash
162
+ alloy _state write openspec/changes/<name> worktree null
163
+ ```
164
+
165
+ > ⚠️ apply 阶段仍会通过 `using-git-worktrees` 再次确认隔离方式。此处的分支选择是给后续阶段一个推荐的开发分支。
166
+
167
+ 7. **提交:**
168
+
169
+ **draft hash + commit:**
170
+ ```bash
171
+ DRAFT_HASH=$(alloy _record compute openspec/changes/<name> draft)
172
+ APPROVED_AT=$(date "+%Y-%m-%d %H:%M:%S")
173
+ APPROVER=$(git config user.name)
174
+ alloy _record write openspec/changes/<name> draft "$DRAFT_HASH" "$APPROVED_AT" "$APPROVER"
175
+ git add openspec/changes/<name>/
176
+ git commit -m "feat(<name>): draft 已确认"
177
+ ```
178
+
179
+ **alloy init 基础设施提交:**
180
+ ```bash
181
+ git add .claude/ .gitignore openspec/config.yaml openspec/schemas/ 2>/dev/null
182
+ [ -f CLAUDE.md ] && git add CLAUDE.md 2>/dev/null
183
+ git diff --cached --quiet || git commit -m "chore: alloy init 项目初始化"
184
+ ```
185
+ 已提交过则自动跳过。`.superpowers/` 已在 `.gitignore` 中忽略,不入仓库。
186
+
187
+ 8. **记录阶段时间:**
188
+ ```bash
189
+ COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
190
+ # STARTED_AT 使用步骤开始时捕获的 SESSION_START 值
191
+ STARTED_AT="<SESSION_START>"
192
+ alloy _state write openspec/changes/<name> phase_timings "{\"start\":{\"started_at\":\"$STARTED_AT\",\"completed_at\":\"$COMPLETED_AT\"}}"
193
+ git add openspec/changes/<name>/
194
+ git commit -m "chore(<name>): 记录 start 阶段完成时间"
195
+ ```
196
+
197
+ ---
198
+
199
+ ### 完成
200
+
201
+ ```
202
+ ┌──────────────────────────────────────┐
203
+ │ Alloy [1/5] · Phase: Start — DONE │
204
+ │ 启动时间: 从 phase_timings.start.started_at 读取 │
205
+ │ 完成时间: 从 phase_timings.start.completed_at 读取 │
206
+ │ 耗时: XmXs │
207
+ └──────────────────────────────────────┘
208
+
209
+ → Change: <name>
210
+ → Phase: started
211
+
212
+ 所有制品已生成并锁定:
213
+
214
+ 制品 状态 Hash 创建时间
215
+ ────────────── ──── ──────────── ───────────────────
216
+ draft ✓ <hash> <timestamp>
217
+
218
+ 准备好后,运行 /alloy:plan 进入规划阶段。
219
+ ```
220
+
221
+ - draft.md 已在 change 目录,项目根目录不再有 draft.md
222
+ - 完成后不要自动进入 plan
223
+
224
+ ---
225
+
226
+ ## 闸门规则
227
+
228
+ - **git add 只用精确路径** — 永远不用 `-A`、`-a`、`.`。
229
+ start 阶段只 add `openspec/changes/<name>/` 和 init 基础设施文件(`.claude/` `.gitignore` `openspec/config.yaml` `openspec/schemas/`);反例:`git add -A` 会把临时文件一起提交
230
+ - **draft.md 必须在 change 目录内** — 不在项目根目录产生临时文件
231
+
232
+ ---
233
+
234
+ ## 自由探索(无活跃 change + 无 topic)
235
+
236
+ ```
237
+ ┌──────────────────────────────────────┐
238
+ │ Alloy [1/5] · Phase: Start │
239
+ │ 启动时间: <TIMESTAMP> │
240
+ └──────────────────────────────────────┘
241
+ ```
242
+
243
+ ### [Step 1/2] 扫描项目上下文
244
+
245
+ 扫描项目上下文(README、已有代码、requirement.md、OpenSpec spec 文件等)。
246
+
247
+ ### [Step 2/2] 呈现发现与建议
248
+
249
+ **有上下文可读时:** 总结项目信息(技术栈、已有功能、最近变更),基于发现给用户 2-3 个建议方向或追问。目标是帮用户明确他想做什么,而不是抛回一句"请提供主题"。
250
+
251
+ **空项目无可读上下文时:** 直接告诉用户:"项目较新,没有太多上下文可供参考。请用 `/alloy:start <topic>` 重新调用,我会进入完整的需求设计流程。"
252
+
253
+ > 关键:必须让用户重新输入 `/alloy:start <topic>`,而不是只输入 topic 文本。只有重新调用命令,alloy:start 技能才会被重新加载并进入"全新开始"路径。如果用户只输入 topic 文本而不带命令,Agent 将脱离 alloy:start 编排框架,导致关键闸门(change name 确认、分支选择、hash commitment)被跳过。
254
+
255
+ ---
256
+
257
+ ## 强制新建(--new <topic>)
258
+
259
+ 无论是否有活跃 change,直接走"全新开始"流程。多个 change 可并行 planning,但不能同时 apply(一个 session 只能有一个工作中的 worktree)。
260
+
261
+ ---
262
+
263
+ ## 接续(有 1 个活跃 change)
264
+
265
+ ```
266
+ ┌──────────────────────────────────────┐
267
+ │ Alloy [1/5] · Phase: Start │
268
+ │ 启动时间: 从 phase_timings.start.started_at 读取,若无则从 created_at 读取 │
269
+ └──────────────────────────────────────┘
270
+
271
+ → 检测到活跃 change:<name>
272
+ → 当前阶段:<phase>
273
+ → 已完成制品:<列出已有文件>
274
+ → 下一步:<建议操作>
275
+ ```
276
+
277
+ ### [Step 1/1] 状态展示与自动接续
278
+
279
+ 先读取 `.alloy.yaml` 获取 phase 和 worktree 字段,再检查文件系统确认实际制品状态。
280
+
281
+ 展示检测结果后,根据 phase 和制品状态决定路由:
282
+
283
+ | phase | 制品状态 | 自动加载命令 |
284
+ |-------|---------|-------------|
285
+ | started | proposal.md 存在 | alloy-plan(正常接续——plan 制品已有,继续生成) |
286
+ | started | proposal.md 不存在 | 重新进入 brainstorming(回溯后——以现有 draft.md 为基础重新讨论需求) |
287
+ | planned | — | alloy-apply |
288
+ | applied | — | alloy-archive |
289
+ | archived | — | alloy-finish |
290
+ | finished | — | 工作流已完成——如需继续修改,使用自然对话提交新变更 |
291
+
292
+ **实现方式:** 根据 phase 值,输出对应命令文件的完整指令(`commands/alloy/plan.md` / `apply.md` / `archive.md` / `finish.md`),将 change name 和检测到的进度信息作为上下文传入。Agent 无缝进入对应阶段。
293
+
294
+ 一致性检查(双向):
295
+ - worktree 字段有值但磁盘路径不存在 → ⚠️ "worktree 残留:.alloy.yaml 声称有 worktree 但磁盘不存在"
296
+ - worktree 字段为 null 但 `.worktrees/<name>/` 目录存在 → ⚠️ "worktree 孤儿:磁盘存在 worktree 但 .alloy.yaml 未记录,建议手动验证并更新状态"
297
+ - 发现孤儿 worktree 时,询问用户是否修复 .alloy.yaml:`alloy _state write openspec/changes/<name> worktree ".worktrees/<name>"`
298
+
299
+ ---
300
+
301
+ ## 多选(有多个活跃 change)
302
+
303
+ ```
304
+ ┌──────────────────────────────────────┐
305
+ │ Alloy [1/5] · Phase: Start │
306
+ │ 启动时间: 从 phase_timings.start.started_at 读取,若无则从 created_at 读取 │
307
+ └──────────────────────────────────────┘
308
+
309
+ → 检测到 <N> 个活跃 change,请选择。
310
+ ```
311
+
312
+ ### [Step 1/1] 展示并选择
313
+
314
+ 列出所有活跃 change(名称 + phase + 制品状态),让用户选择接续哪个,或 `--new <topic>` 开新 change。