@flyin-ai/alloy 0.1.0 → 0.2.0-beta.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 (122) 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 +282 -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 +167 -64
  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 +60 -13
  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 +10 -3
  77. package/vendor/superpowers/skills/brainstorming/SKILL.md +164 -0
  78. package/vendor/superpowers/skills/brainstorming/scripts/frame-template.html +214 -0
  79. package/vendor/superpowers/skills/brainstorming/scripts/helper.js +88 -0
  80. package/vendor/superpowers/skills/brainstorming/scripts/server.cjs +354 -0
  81. package/vendor/superpowers/skills/brainstorming/scripts/start-server.sh +148 -0
  82. package/vendor/superpowers/skills/brainstorming/scripts/stop-server.sh +56 -0
  83. package/vendor/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
  84. package/vendor/superpowers/skills/brainstorming/visual-companion.md +287 -0
  85. package/vendor/superpowers/skills/dispatching-parallel-agents/SKILL.md +182 -0
  86. package/vendor/superpowers/skills/executing-plans/SKILL.md +70 -0
  87. package/vendor/superpowers/skills/finishing-a-development-branch/SKILL.md +251 -0
  88. package/vendor/superpowers/skills/receiving-code-review/SKILL.md +213 -0
  89. package/vendor/superpowers/skills/requesting-code-review/SKILL.md +103 -0
  90. package/vendor/superpowers/skills/requesting-code-review/code-reviewer.md +168 -0
  91. package/vendor/superpowers/skills/subagent-driven-development/SKILL.md +279 -0
  92. package/vendor/superpowers/skills/subagent-driven-development/code-quality-reviewer-prompt.md +25 -0
  93. package/vendor/superpowers/skills/subagent-driven-development/implementer-prompt.md +113 -0
  94. package/vendor/superpowers/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
  95. package/vendor/superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -0
  96. package/vendor/superpowers/skills/systematic-debugging/SKILL.md +296 -0
  97. package/vendor/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  98. package/vendor/superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -0
  99. package/vendor/superpowers/skills/systematic-debugging/defense-in-depth.md +122 -0
  100. package/vendor/superpowers/skills/systematic-debugging/find-polluter.sh +63 -0
  101. package/vendor/superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -0
  102. package/vendor/superpowers/skills/systematic-debugging/test-academic.md +14 -0
  103. package/vendor/superpowers/skills/systematic-debugging/test-pressure-1.md +58 -0
  104. package/vendor/superpowers/skills/systematic-debugging/test-pressure-2.md +68 -0
  105. package/vendor/superpowers/skills/systematic-debugging/test-pressure-3.md +69 -0
  106. package/vendor/superpowers/skills/test-driven-development/SKILL.md +371 -0
  107. package/vendor/superpowers/skills/test-driven-development/testing-anti-patterns.md +299 -0
  108. package/vendor/superpowers/skills/using-git-worktrees/SKILL.md +215 -0
  109. package/vendor/superpowers/skills/using-superpowers/SKILL.md +117 -0
  110. package/vendor/superpowers/skills/using-superpowers/references/codex-tools.md +59 -0
  111. package/vendor/superpowers/skills/using-superpowers/references/copilot-tools.md +42 -0
  112. package/vendor/superpowers/skills/using-superpowers/references/gemini-tools.md +51 -0
  113. package/vendor/superpowers/skills/verification-before-completion/SKILL.md +139 -0
  114. package/vendor/superpowers/skills/writing-plans/SKILL.md +152 -0
  115. package/vendor/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
  116. package/vendor/superpowers/skills/writing-skills/SKILL.md +655 -0
  117. package/vendor/superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -0
  118. package/vendor/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  119. package/vendor/superpowers/skills/writing-skills/graphviz-conventions.dot +172 -0
  120. package/vendor/superpowers/skills/writing-skills/persuasion-principles.md +187 -0
  121. package/vendor/superpowers/skills/writing-skills/render-graphs.js +168 -0
  122. package/vendor/superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: "Alloy: Plan"
3
- description: Alloy 规划阶段——将 draft.md 转化为结构化制品,始终分步,每步可审查
3
+ description: Alloy 规划阶段 - draft.md 完成后进入
4
4
  category: Workflow
5
5
  tags: [alloy, workflow]
6
6
  ---
@@ -9,38 +9,52 @@ tags: [alloy, workflow]
9
9
 
10
10
  你是 Alloy 的规划阶段编排器。你的职责是按 OpenSpec schema DAG 依赖顺序,制品生成设计文档,每步生成后提供审查窗口。
11
11
 
12
+ **核心原则:按 schema DAG 依赖顺序逐一产出制品,每步有审查闸门,不跳过上游直接产下游。**
13
+
14
+ **交互风格:** 所有审查窗口和用户选择使用 `AskUserQuestion` 工具(箭头选、Enter 确认),不用纯文本 "(a)(b)"。详见 `commands/alloy/references/interaction-style.md`。
15
+
12
16
  **调用外部命令或技能前,先输出标题和状态描述,再执行操作。不要只出标题然后沉默。**
13
17
 
18
+ **什么算"plan 执行不到位"(反例):**
19
+ - 用户说"一次性生成"就直接出全部制品——跳过了 5 个审查窗口,失去了需求验证的时机
20
+ - 用户说"太慢了"就加速跳过审查——审查时间远小于返工时间
21
+ - 用户说"我看过 draft 了,内容都对"就松懈——draft 审查不能替代 proposal/design/specs/tasks 的逐级审查
22
+
23
+ ### Red Flags——STOP,必须分步审查
24
+
25
+ | 借口 | 现实 |
26
+ |------|------|
27
+ | "一次性生成全部制品,提高效率" | plan 不提供一键生成。5 个制品 = 5 个审查窗口。每步审查的价值远大于省下的几秒。跳过审查 = 跳过需求验证。 |
28
+ | "太慢了,直接出全部吧" | 审查时间远小于后期返工时间。一个未审查的 specs 缺陷到 apply 阶段才发现,代价是重做全部代码。 |
29
+ | "我看过 draft 了,后面的不用看了" | draft 是方案设计,proposal 是提案范围,design 是技术方案,specs 是行为契约——四个层面不可互相替代。 |
30
+ | "这个项目很小,不需要那么正式" | 小项目和大项目的闸门完全一样。不存在"规模分级的保护等级"。 |
31
+
32
+ **捕获阶段启动时间**(命令调用后第一时间,前置检查之前,幂等——重入时返回已有值):
33
+ ```bash
34
+ PHASE_START=$(alloy _state timestamp ensure openspec/changes/<name> plan)
35
+ ```
36
+
37
+ ---
38
+
14
39
  ## 前置检查
15
40
 
16
41
  1. 确认 change 目录 `openspec/changes/<name>/` 存在且 `.alloy.yaml` phase 为 `started`(由 `/alloy:start` 完成),否则报错
17
42
  2. 若 change 目录存在但 `draft.md` 缺失 → 异常状态,提示重新运行 `/alloy:start`
18
43
  3. 若指定 `[name]` 参数但 change 不存在 → "未找到 change '<name>',请先运行 `/alloy:start <name>` 创建 change"
19
- 4. **Skill / 命令预检:** 确认 `opsx:continue` 和 `superpowers:writing-plans` 均可用。任一不可用 → 引导 `alloy init` → STOP。不在生成过程中才暴露缺失。
44
+ 4. **Skill / 命令预检:** 确认以下依赖可用:
45
+ cmd: opsx/continue
46
+ skill: writing-plans
20
47
 
21
- ---
48
+ 读取 `commands/alloy/references/skill-precheck.md` 了解检测方法。任一不可用 → 引导 `alloy init` → STOP。
22
49
 
23
- ## Step 1/3:确认 Change
50
+ ---
24
51
 
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
- ```
52
+ ### [Step 1/3] 确认 Change
39
53
 
40
54
  ```
41
55
  ┌──────────────────────────────────────┐
42
56
  │ Alloy [2/5] · Phase: Plan │
43
- │ 启动时间: 从 phase_timings.plan.started_at 读取
57
+ │ 启动时间: $PHASE_START
44
58
  └──────────────────────────────────────┘
45
59
 
46
60
  [Step 1/3] 确认 Change
@@ -51,7 +65,7 @@ print(json.dumps(d))
51
65
  ```bash
52
66
  git log -1 --format="%s" -- openspec/changes/<name>/draft.md
53
67
  ```
54
- 若 commit message 不含 `feat(<name>): draft 已确认`→ ⚠️ draft.md 可能未经过完整 `/alloy:start` 流程(手工创建),提示用户确认是否继续。不阻断——但给用户知情权。
68
+ 若 commit message 不含 `docs(<name>): draft 已确认`→ ⚠️ draft.md 可能未经过完整 `/alloy:start` 流程(手工创建),提示用户确认是否继续。不阻断——但给用户知情权。
55
69
  2. 确认 `.alloy.yaml` phase 为 `started`:
56
70
  ```bash
57
71
  alloy _state check openspec/changes/<name> started
@@ -60,34 +74,22 @@ print(json.dumps(d))
60
74
  ```bash
61
75
  git rev-parse --git-dir
62
76
  ```
63
- 若失败 → 项目还不是 git 仓库,引导用户初始化:
64
- ```
65
- git init && git add -A && git commit -m "chore: 初始提交"
66
- ```
77
+ 若失败 → HARD STOP:"项目还不是 git 仓库。请先运行 `/alloy:start` 完成初始化(包含 git init)。"
67
78
 
68
- 前置检查通过:draft.md ✓ phase=started ✓ git ✓
79
+ 前置检查通过:draft.md ✓ phase=started ✓ git ✓ 技能 ✓
69
80
 
70
81
  **若 phase 不匹配(phase != started):**
71
82
 
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 和当前进度信息作为上下文传入。
83
+ 读取 `commands/alloy/references/phase-routing.md` 按路由表自动跳转。实现方式:输出对应命令文件的完整指令,将 change name 和当前进度信息作为上下文传入。
82
84
 
83
85
  **若 change 目录不存在或 draft.md 缺失:**
84
86
  → 引导用户先运行 `/alloy:start <name>` 创建 change。这是唯一保留 HARD STOP 的场景——前序阶段完全没做。
85
87
 
86
88
  ---
87
89
 
88
- ## Step 2/3:制品生成 · /opsx:continue + writing-plans
90
+ ### [Step 2/3] 制品生成 · /opsx:continue + writing-plans
89
91
 
90
- **[Step 2/3] 制品生成**
92
+ [Step 2/3] 制品生成
91
93
  ──────────────────────────────────────
92
94
 
93
95
  **每个制品(proposal / design / specs / tasks)必须通过 `/opsx:continue` 生成。禁止手动编写制品文件。** `/opsx:continue` 自动读取 schema DAG,按 `proposal → design → specs → tasks` 顺序依次产出,每次调用生成一个制品。**tasks 是 `/opsx:continue` 生成的最后一个制品。**plans.md 由 `superpowers:writing-plans` 技能生成(见下文)。
@@ -143,19 +145,69 @@ done
143
145
 
144
146
  制品全部完成(plans.md 存在且 hash 有效)时,phase 推进到 planned,提示下一步。
145
147
 
148
+ **不要输出全局制品进度**(如"0/8 artifacts 完成")。[N/M] 是阶段内局部编号(M=5),不反映全局进度。全局进度由 `alloy status` 命令管理。
149
+
146
150
  ### 正常推进:逐个制品的审查流程
147
151
 
148
- 每个制品生成后,展示内容并进入审查窗口。**仅两个选项——不跳过。** 审查窗口使用块引用格式(终端有底色渲染):
152
+ 每个制品生成后,展示内容并进入审查窗口。**仅两个选项——不跳过。**
153
+
154
+ 审查窗口分两步:**先**用 markdown 文本展示制品完整内容(审查窗口块引用),**后**用 `AskUserQuestion` 工具让用户确认(radio,2 个 option)。不要用纯文本 "(a)(b)" 等用户打字。
155
+
156
+ **制品 [1/5] proposal:**
157
+
158
+ > 制品 [1/5] proposal ✓ 完成
159
+ >
160
+ > [展示 proposal.md 完整内容]
161
+ >
162
+ > → 下一个:design(依赖 proposal + draft.md)
163
+ >
164
+ > → (a) 确认,锁定 proposal 并继续 design
165
+ > → (b) 需要调整 — 说明修改点
166
+
167
+ **制品 [2/5] design:**
168
+
169
+ > 制品 [2/5] design ✓ 完成
170
+ >
171
+ > [展示 design.md 完整内容]
172
+ >
173
+ > → 下一个:specs(依赖 proposal)
174
+ >
175
+ > → (a) 确认,锁定 design 并继续 specs
176
+ > → (b) 需要调整 — 说明修改点
177
+
178
+ **制品 [3/5] specs:**
149
179
 
150
180
  > 制品 [3/5] specs ✓ 完成
151
181
  >
152
- > [展示制品完整内容]
182
+ > [展示 specs/ 完整内容]
153
183
  >
154
184
  > → 下一个:tasks(依赖 specs + design)
155
185
  >
156
186
  > → (a) 确认,锁定 specs 并继续 tasks
157
187
  > → (b) 需要调整 — 说明修改点
158
188
 
189
+ **制品 [4/5] tasks:**
190
+
191
+ > 制品 [4/5] tasks ✓ 完成
192
+ >
193
+ > [展示 tasks.md 完整内容]
194
+ >
195
+ > → 下一个:plans(依赖 tasks)
196
+ >
197
+ > → (a) 确认,锁定 tasks 并继续生成 plans
198
+ > → (b) 需要调整 — 说明修改点
199
+
200
+ **制品 [5/5] plans:**
201
+
202
+ > 制品 [5/5] plans ✓ 完成
203
+ >
204
+ > [展示 plans.md 完整内容]
205
+ >
206
+ > → plan 阶段完成
207
+ >
208
+ > → (a) 确认,锁定 plans 并完成 plan 阶段
209
+ > → (b) 需要调整 — 说明修改点
210
+
159
211
  **审查窗口只展示制品内容,不打印 OpenSpec schema 的 instructions 模板。** instructions 是给 Agent 的内部指引,不是给用户审查的输出。
160
212
 
161
213
  - **选 (a)**:当前制品锁定,进入下一个制品或阶段
@@ -169,7 +221,7 @@ done
169
221
  - 需求层面变更(功能增删、行为变更、范围调整)→ 内部标记为需求变更
170
222
 
171
223
  无论 AI 如何判断,始终向用户呈现相同的 (a)/(b) 两个选项。
172
- 用户选 (a) → 执行回溯清理步骤,加载 `superpowers:brainstorming`。
224
+ 用户选 (a) → 执行回溯清理步骤,加载 `superpowers:brainstorming`。brainstorming 负责重新讨论需求,用户确认后回到这里继续生成制品(不是 invoke writing-plans——那是独立使用 brainstorming 时的行为)。
173
225
  用户选 (b) → 回到当前审查窗口,重新展示 (a) 确认 / (b) 需要调整 选项。
174
226
 
175
227
  **什么算"审查不充分"(反例):**
@@ -181,6 +233,11 @@ done
181
233
 
182
234
  每个制品审批通过(用户选 a)后,立即 hash 锁定并 commit:
183
235
 
236
+ **hash 锁定前,记录技能使用:**
237
+ ```bash
238
+ alloy _skill log openspec/changes/<name> plan opsx:continue
239
+ ```
240
+
184
241
  ```bash
185
242
  HASH=$(alloy _record compute openspec/changes/<name> <artifact>)
186
243
  APPROVED_AT=$(date "+%Y-%m-%d %H:%M:%S")
@@ -190,6 +247,20 @@ git add openspec/changes/<name>/
190
247
  git commit -m "docs(<name>): <artifact> 已确认"
191
248
  ```
192
249
 
250
+ **plans 是 plan 阶段最后一个制品。** plans 审批通过后,phase_timings + hash-lock 合并为**一个 commit**——禁止拆成两次提交:
251
+
252
+ ```bash
253
+ # 写入完成时间 + hash 锁定 + 提交,一气呵成
254
+ COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
255
+ alloy _state merge openspec/changes/<name> phase_timings "{\"plan\":{\"completed_at\":\"${COMPLETED_AT:-$(date '+%Y-%m-%d %H:%M:%S')}\"}}"
256
+ HASH=$(alloy _record compute openspec/changes/<name> plans)
257
+ APPROVED_AT=$(date "+%Y-%m-%d %H:%M:%S")
258
+ APPROVER=$(alloy _record approver openspec/changes/<name>)
259
+ alloy _record write openspec/changes/<name> plans "$HASH" "$APPROVED_AT" "$APPROVER"
260
+ git add openspec/changes/<name>/
261
+ git commit -m "docs(<name>): plans 已确认"
262
+ ```
263
+
193
264
  commit message 格式:`docs(<change-name>): <artifact> 已确认`(Conventional Commits `docs` type)。`<artifact>` 为 proposal / design / specs / tasks / plans。
194
265
 
195
266
  **生成下一制品前,校验上游依赖制品的 hash 未被篡改:**
@@ -215,6 +286,11 @@ tasks 审批通过并 commit 后,**加载 `superpowers:writing-plans` 技能**
215
286
  >
216
287
  > alloy 不在 plan 阶段额外询问策略选择——writing-plans 的决策直接保留在 frontmatter 中,apply 阶段再读取并给用户确认。
217
288
 
289
+ **技能加载后立即记录:**
290
+ ```bash
291
+ alloy _skill log openspec/changes/<name> plan superpowers:writing-plans
292
+ ```
293
+
218
294
  writing-plans 完成并保存 plans.md(含 strategy frontmatter)后,直接进入 plans 审查窗口。frontmatter 格式:
219
295
 
220
296
  ```yaml
@@ -226,7 +302,7 @@ reason: <writing-plans 执行交接环节的策略分析理由>
226
302
  ...
227
303
  ```
228
304
 
229
- plans.md 生成后展示审查窗口,审批通过后 hash 锁定并 commit
305
+ plans.md 生成后展示审查窗口,审批通过后先写入 phase_timings.completed_at,再 hash 锁定并 commit(phase_timings 作为元数据附着在 plans 制品提交上,不单独 commit)。
230
306
 
231
307
  ### 回溯修改:修改已确认的上游制品
232
308
 
@@ -253,21 +329,23 @@ rm -rf openspec/changes/<name>/specs/
253
329
  # 2. 清理 records(只保留 draft)
254
330
  DRAFT_RECORD=$(alloy _state read openspec/changes/<name> records | python3 -c "
255
331
  import sys,json
256
- records = json.loads(sys.stdin.read() or '[]')
332
+ content = sys.stdin.read().strip()
333
+ records = json.loads(content) if content and content != 'null' else []
257
334
  draft = [r for r in records if r.get('artifact') == 'draft']
258
335
  print(json.dumps(draft))
259
336
  ")
260
337
  alloy _state write openspec/changes/<name> records "$DRAFT_RECORD"
261
338
 
262
339
  # 3. 清理 phase_timings(清除 plan/apply/archive/finish 记录,重置 start.completed_at)
340
+ # ⚠️ 此处是 phase_timings 唯一允许 _state write 的场景:回溯需要删除 key + 覆盖值,merge 语义不支持。
341
+ # 所有其他 phase_timings 更新必须使用 _state merge,禁止 _state write。
263
342
  TIMINGS=$(alloy _state read openspec/changes/<name> phase_timings 2>/dev/null || echo "{}")
264
343
  echo "$TIMINGS" | python3 -c "
265
344
  import sys,json
266
- d = json.loads(sys.stdin.read() or '{}')
267
- # 清除下游阶段
345
+ content = sys.stdin.read().strip()
346
+ d = json.loads(content) if content and content != 'null' else {}
268
347
  for k in ['plan','apply','archive','finish']:
269
348
  d.pop(k, None)
270
- # 重置 start 完成时间——start 重新变为进行中
271
349
  if 'start' in d:
272
350
  d['start']['completed_at'] = None
273
351
  print(json.dumps(d))
@@ -284,30 +362,13 @@ git commit -m "chore(<name>): 回溯——清理 plan 制品,回到 brainstorm
284
362
 
285
363
  ---
286
364
 
287
- ## Step 3/3:完成
365
+ ### [Step 3/3] 完成
288
366
 
289
367
  先读取所有 record 的时间戳用于汇总展示:
290
368
  ```bash
291
369
  alloy _state read openspec/changes/<name> records
292
370
  ```
293
371
 
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
372
  ```
312
373
  ┌──────────────────────────────────────┐
313
374
  │ Alloy [2/5] · Phase: Plan — DONE │
@@ -358,3 +419,4 @@ guard 校验 hash 一致性后自动推进 phase。如果 guard 返回非零,
358
419
  - **制品生成完成后必须通过 alloy _guard 校验** —— 脚本检查 started→planned 转换的合法性及 hash 一致性
359
420
  - **plans 完成后不要自动进入 apply** —— 给用户空间审视完整规划
360
421
  - **plan 阶段调整统一回 brainstorming** —— 需求/设计层面的任何变更从 draft 根重新审视,不做就地修补。typo/措辞修正除外。apply 阶段的 verify/retrospective 只修代码不改规格
422
+ - **不输出全局制品进度** — [N/M] 是阶段内局部编号(M=5),不要输出"N/8 artifacts 完成"。全局进度由 `alloy status` 管理
@@ -0,0 +1,82 @@
1
+ # Alloy 交互风格指南
2
+
3
+ Alloy 各阶段需要用户输入时,**优先使用平台原生的交互式选择工具**。纯文本 "(a)(b)(c)" 只是换了格式的开放式提问——用户还是要打字。原生交互组件让用户用箭头选、空格勾、Enter 提交,一次按键完成决策。
4
+
5
+ ## 平台工具对照
6
+
7
+ | 平台 | 交互式选择工具 | 能力 |
8
+ |------|-------------|------|
9
+ | **Claude Code** | `AskUserQuestion` | radio(单选)、checkbox(多选)、preview(代码对比) |
10
+ | **Codex** | 无等价工具 | 降级为结构化文本选项 |
11
+ | **Copilot CLI** | 无等价工具 | 降级为结构化文本选项 |
12
+ | **Gemini CLI** | 查平台工具映射 | 查 GEMINI.md 中的工具映射 |
13
+
14
+ **降级策略:** 当平台无原生交互工具时,使用清晰的文本选项格式——但必须结构化(每选项一行,带编号和简短说明),不要让用户猜要输入什么。
15
+
16
+ ## 选择类型与工具映射
17
+
18
+ | 场景 | `AskUserQuestion` 配置 | 示例 |
19
+ |------|----------------------|------|
20
+ | **审查确认** (a/b 二元) | `multiSelect: false`,2 个 option | (a) 确认,锁定并继续 / (b) 需要调整 |
21
+ | **多选一** (3-4 选项) | `multiSelect: false`,3-4 个 option | 分支选择、策略选择、技术方案选型 |
22
+ | **范围确认** (独立选项) | `multiSelect: true`,空格勾选 | 功能范围、carry-forward items、边界确认 |
23
+ | **方案对比** (含代码差异) | `multiSelect: false` + `preview` 字段 | 架构方案 A vs B,preview 展示代码结构差异 |
24
+
25
+ ## 审查窗口标准模式
26
+
27
+ 制品审查是 Alloy 最常见的交互场景。遵循以下模式:
28
+
29
+ 1. **先展示内容**——用 markdown 文本展示制品完整内容(审查窗口本身,不能被交互工具替代)
30
+ 2. **再让用户确认**:
31
+
32
+ **Claude Code(推荐):**
33
+ ```
34
+ AskUserQuestion: {
35
+ questions: [{
36
+ question: "确认并锁定 <制品名>?",
37
+ header: "<制品名>",
38
+ options: [
39
+ { label: "(a) 确认,锁定并继续", description: "hash 锁定 + commit,进入下一制品" },
40
+ { label: "(b) 需要调整", description: "说明修改点" }
41
+ ],
42
+ multiSelect: false
43
+ }]
44
+ }
45
+ ```
46
+
47
+ **其他平台(降级):**
48
+ ```
49
+ > → (a) 确认,锁定 <制品名> 并继续
50
+ > → (b) 需要调整 — 说明修改点
51
+ > 请输入 a 或 b:
52
+ ```
53
+
54
+ **硬规则:凡是技能文件中出现 `AskUserQuestion` JSON 块的,同一位置必须附带降级文本格式。** Agent 执行时先检测当前平台是否支持 `AskUserQuestion` 工具——支持则用原生交互组件,不支持则自动降级为文本选项。两个格式给出相同选项、相同数量,确保不同平台上用户看到的选项一致。
55
+
56
+ **反例:** 审查窗口只用文本 "(a) 确认 (b) 调整" 而不给明确的输入提示——用户不知道是要打字、复制粘贴还是直接说"确认"。
57
+
58
+ ## 不能使用 AskUserQuestion 的场景
59
+
60
+ 以下场景**保持精确文本确认**,因为它们是安全机制而非便利功能:
61
+
62
+ - **破坏性操作确认**(discard、merge 确认):用户必须输入精确字符串 `discard <name>` 或 `merge <branch> into <branch>`
63
+ - **已由外部技能处理的交互**:如 `finishing-a-development-branch` 技能的合并策略选择
64
+
65
+ ## 提问密度
66
+
67
+ - `AskUserQuestion` 一次最多 4 个问题,相关问题**合并到一次调用**
68
+ - 不要一个问题调一次——那是文本选项的思维
69
+ - 每次选项的 `description` 写清楚选这个意味着什么,让用户无需额外思考
70
+
71
+ ## 各阶段适用场景速查
72
+
73
+ | 阶段 | 主要 AskUserQuestion 场景 |
74
+ |------|--------------------------|
75
+ | start | 探查方向选择(radio)、需求范围确认(checkbox)、draft 审查(radio) |
76
+ | plan | 5 个制品审查窗口(radio)、回溯确认(radio) |
77
+ | apply | 分支异常处理(radio)、执行策略选择(radio)、verify/retrospective 审查(radio) |
78
+ | finish | 主分支确认(radio) |
79
+ | fix | 诊断确认(radio)、主分支确认(radio)、hotfix 合并确认(精确文本) |
80
+ | archive | 无用户交互(全自动) |
81
+ | status | 无用户交互(只读) |
82
+ | discard | **不使用**——保持精确文本确认 |
@@ -0,0 +1,32 @@
1
+ # 主分支检测
2
+
3
+ start 和 fix 命令共享的主分支自动检测逻辑。
4
+
5
+ ## 检测优先级(3 级)
6
+
7
+ ```bash
8
+ # 1. remote HEAD(标准默认分支)
9
+ DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
10
+ # 2. 本地 init.defaultBranch 配置
11
+ [ -z "$DEFAULT_BRANCH" ] && DEFAULT_BRANCH=$(git config --get init.defaultBranch 2>/dev/null)
12
+ # 3. 名称匹配(main 或 master)
13
+ [ -z "$DEFAULT_BRANCH" ] && DEFAULT_BRANCH=$(git branch --list 'main' --list 'master' | head -1 | sed 's/[* ]//g')
14
+ ```
15
+
16
+ ## 配置优先
17
+
18
+ 若 `openspec/config.yaml` 已有 `alloy.main_branch` 记录,直接用记录值,跳过检测和确认。
19
+
20
+ ## 确认步骤
21
+
22
+ 检测到主分支后,必须让用户确认(Y/n):
23
+ ```
24
+ 主分支: $DEFAULT_BRANCH。使用此分支作为基础分支?[Y/n]
25
+ ```
26
+
27
+ 选 Y 或直接回车 → 使用检测结果。选 n → 让用户输入自定义名称。
28
+
29
+ 确认后写入项目级配置:
30
+ ```bash
31
+ alloy _config write <project-root> main_branch <用户确认的主分支名>
32
+ ```
@@ -0,0 +1,21 @@
1
+ # Phase 路由表
2
+
3
+ 所有 alloy 阶段命令共享的 phase 自动路由规则。当 `alloy _guard` 检测到 phase 不匹配时,按此表自动跳转到正确阶段。
4
+
5
+ ## 路由表
6
+
7
+ | 当前 phase | 行为 |
8
+ |-----------|------|
9
+ | started | 尚未 plan → 加载 alloy-plan 指令 |
10
+ | planned | 尚未 apply → 加载 alloy-apply 指令 |
11
+ | applied | 尚未 archive → 加载 alloy-archive 指令 |
12
+ | archived | 尚未 finish → 加载 alloy-finish 指令 |
13
+ | finished | 工作流已完成 → STOP |
14
+
15
+ ## 实现方式
16
+
17
+ 输出对应命令文件的完整指令(`commands/alloy/plan.md` / `apply.md` / `archive.md` / `finish.md`),将 change name 和当前进度信息作为上下文传入。Agent 无缝进入对应阶段。
18
+
19
+ ## HARD STOP 保留场景
20
+
21
+ change 目录不存在(前序阶段完全没做)→ 引导用户先运行 `/alloy:start`。这是唯一保留 HARD STOP 的场景。
@@ -0,0 +1,46 @@
1
+ # Skill 预检脚本
2
+
3
+ 所有 alloy 阶段命令共享的技能/命令可用性检测脚本。各命令传入自己的技能列表即可。
4
+
5
+ ## 使用方式
6
+
7
+ 在命令中按以下格式声明所需依赖,然后执行下方预检脚本:
8
+
9
+ ```
10
+ Skill 预检——确认以下可用:
11
+ cmd: opsx/explore opsx/new
12
+ skill: brainstorming
13
+ ```
14
+
15
+ ## 预检脚本
16
+
17
+ 将上面声明的 cmd 和 skill 列表填入脚本中的对应位置:
18
+
19
+ ```bash
20
+ MISSING=0
21
+
22
+ # 检测 command(project → user)
23
+ for cmd in <cmd列表>; do
24
+ if test -f ".claude/commands/$cmd.md"; then echo " ✓ ${cmd//\//:}(项目级 command)"
25
+ elif test -f "$HOME/.claude/commands/$cmd.md"; then echo " ✓ ${cmd//\//:}(用户级 command)"
26
+ else echo " ✗ ${cmd//\//:} — 未找到"; MISSING=$((MISSING+1)); fi
27
+ done
28
+
29
+ # 检测 skill(project skill → user skill → user plugin)
30
+ for skill in <skill列表>; do
31
+ if test -d ".claude/skills/$skill"; then echo " ✓ superpowers:$skill(项目级 skill)"
32
+ elif test -d "$HOME/.claude/skills/$skill"; then echo " ✓ superpowers:$skill(用户级 skill)"
33
+ elif for d in "$HOME/.claude/plugins/cache/superpowers-marketplace/superpowers/"*"/skills/$skill"; do test -d "$d" && break; done 2>/dev/null; then echo " ✓ superpowers:$skill(用户级 plugin)"
34
+ else echo " ✗ superpowers:$skill — 未找到"; MISSING=$((MISSING+1)); fi
35
+ done
36
+
37
+ if [ "$MISSING" -gt 0 ]; then echo ""; echo " 需要先完成环境初始化。请运行: alloy init"; exit 1; fi
38
+ ```
39
+
40
+ ## 检测优先级
41
+
42
+ 项目级 command → 项目级 skill → 用户级 command → 用户级 skill → 用户级 plugin
43
+
44
+ 任一不可用 → 引导 `alloy init` → STOP。
45
+
46
+ **如果某命令只有 command 或只有 skill 依赖,省略对应的 for 循环即可。**