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

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 (41) hide show
  1. package/commands/alloy/apply.md +222 -430
  2. package/commands/alloy/archive.md +156 -132
  3. package/commands/alloy/discard.md +26 -11
  4. package/commands/alloy/finish.md +212 -116
  5. package/commands/alloy/fix.md +102 -247
  6. package/commands/alloy/plan.md +204 -301
  7. package/commands/alloy/references/apply-precheck.md +21 -0
  8. package/commands/alloy/references/apply-rationalizations.md +18 -0
  9. package/commands/alloy/references/apply-subagent-commit.md +49 -0
  10. package/commands/alloy/references/apply-worktree.md +130 -0
  11. package/commands/alloy/references/archive-rationalizations.md +16 -0
  12. package/commands/alloy/references/archive-worktree-cleanup.md +94 -0
  13. package/commands/alloy/references/artifact-hash-commit.md +49 -0
  14. package/commands/alloy/references/branch-naming.md +65 -0
  15. package/commands/alloy/references/branch-validation.md +36 -0
  16. package/commands/alloy/references/fix-precommit-check.md +58 -0
  17. package/commands/alloy/references/interaction-style.md +34 -1
  18. package/commands/alloy/references/main-branch-detection.md +3 -6
  19. package/commands/alloy/references/phase-downgrade-path.md +27 -0
  20. package/commands/alloy/references/plan-rollback.md +84 -0
  21. package/commands/alloy/references/spec-sync.md +62 -0
  22. package/commands/alloy/references/start-rationalizations.md +18 -0
  23. package/commands/alloy/start.md +178 -238
  24. package/dist/cli/commands/completion.js +13 -2
  25. package/dist/cli/commands/completion.js.map +1 -1
  26. package/dist/cli/commands/internal/artifact.d.ts +7 -0
  27. package/dist/cli/commands/internal/artifact.js +70 -0
  28. package/dist/cli/commands/internal/artifact.js.map +1 -0
  29. package/dist/cli/commands/internal/guard.js +204 -2
  30. package/dist/cli/commands/internal/guard.js.map +1 -1
  31. package/dist/cli/commands/internal/progress.d.ts +10 -0
  32. package/dist/cli/commands/internal/progress.js +70 -0
  33. package/dist/cli/commands/internal/progress.js.map +1 -0
  34. package/dist/cli/commands/internal/spec-audit.d.ts +42 -0
  35. package/dist/cli/commands/internal/spec-audit.js +363 -0
  36. package/dist/cli/commands/internal/spec-audit.js.map +1 -0
  37. package/dist/cli/commands/internal/state.js +4 -0
  38. package/dist/cli/commands/internal/state.js.map +1 -1
  39. package/dist/cli/index.js +30 -0
  40. package/dist/cli/index.js.map +1 -1
  41. package/package.json +2 -1
@@ -3,35 +3,74 @@ name: "Alloy: Start"
3
3
  description: 新功能构思或接续已有工作时调用
4
4
  category: Workflow
5
5
  tags: [alloy, workflow]
6
+ spec: 01-product-spec/01-start-spec.md
7
+ behaviors:
8
+ preconditions: 5
9
+ hard_stops: 8
10
+ user_gates: 8
11
+ warns: 2
12
+ artifacts: [draft]
13
+ transitions_to: started
14
+ external_calls: [opsx:explore, opsx:new, superpowers:brainstorming]
6
15
  ---
7
16
 
8
17
  # alloy-start
9
18
 
10
- 你是 Alloy 工作流的智能入口。你的职责是:检测当前状态、路由到正确流程、调度外部技能完成探查和需求设计,最后产出 draft.md。
19
+ 你是 Alloy 工作流的智能入口。检测状态、路由到正确流程、调度外部技能完成探查和需求设计,产出 draft.md。
11
20
 
12
- **核心原则:把实际工作委托给专门的技能,不要自己做。Alloy 是编排器,不是执行者。**
21
+ **核心原则:把实际工作委托给专门的技能,不要自己做。Alloy 是编排器,不是执行者。** draft.md 以 hash-lock + commit 入 records,禁直接编辑。
13
22
 
14
- > **`<TIMESTAMP>` 的含义:** 每次渲染阶段头部框时,执行 `date "+%Y-%m-%d %H:%M:%S"` 获取本地时间,替换 `<TIMESTAMP>`。不要输出字面字符串 `<TIMESTAMP>`。`<START_TIME>` 是"全新开始"路径中捕获的当前时间——agent 捕获 date 命令的输出后,在 header 渲染和 phase_timings 写入时复用该值。`<created_at>` 从 `.alloy.yaml` 的 `created_at` 字段读取。
23
+ ```
24
+ [HARD_STOP] NO WORK ON MAIN BRANCH + NO AUTO ADVANCE
25
+ 每个 change 必须在独立 feature 分支上;start 完成后绝不自动进 plan
26
+ 违反字面 = 违反精神:哪怕"用户在催赶时间在 main 上先建文件"或"用户上次也是接 plan 这次猜跳过 USER_GATE",也算违反 Iron Law
27
+ ```
28
+
29
+ > **`<TIMESTAMP>`:** 每次渲染阶段头部时执行 `date "+%Y-%m-%d %H:%M:%S"` 获取本地时间。`<START_TIME>` 是"全新开始"路径中捕获的时间——agent 捕获后复用于 header 和 phase_timings。`<created_at>` 从 `.alloy.yaml` 读取。
30
+
31
+ **交互规则:** `🔴 STOP` 等价 `USER_GATE`,必须用 `AskUserQuestion`(`commands/alloy/references/interaction-style.md`,含"沉默 ≠ 授权"通用禁令)。跳过任何 USER_GATE / 批量打包 / 基于内容跳过 = 违反 Iron Law。
32
+
33
+ **状态符号:** `⛔` = HARD_STOP / PRECONDITION_FAIL,`🔴` = USER_GATE,`⚠️` = WARN(视觉规范 §七)。
34
+
35
+ ---
36
+
37
+ ### Red Flags(第三层防御——任一借口出现即 STOP)
38
+
39
+ 主文件保留 5 条核心借口,完整 12 条见 `commands/alloy/references/start-rationalizations.md`。
40
+
41
+ | 借口 | 现实 |
42
+ |------|------|
43
+ | "不用建分支了,就在 main 上干吧" | ⛔ HARD_STOP:主分支污染不可逆。建分支只需 2 秒。违反字面 = 违反精神:哪怕"只是先建个目录后面再切"也算(Iron Law 第一层)。 |
44
+ | "不用 brainstorming,直接写代码" | brainstorming 不可跳过。跳过需求设计 = 规格和代码分叉的起点。 |
45
+ | "start 完成了,直接进 plan" / "用户没回复,我先继续" | ⛔ HARD_STOP:start 完成后绝不自动进入 plan。沉默 ≠ 授权(Iron Law 第二层)。替用户做阶段转换 = 剥夺审查机会。 |
46
+ | "openspec/changes/<name>/ 已经有了,直接复用" | ⛔ PRECONDITION_FAIL:目录已存在 = #12 冲突。USER_GATE 让用户决策(改名 / 接续 / 中止),禁 agent 自动复用——可能覆盖用户既有工作。 |
47
+ | "git init 后 reset --hard 一下,把环境清干净" | ⛔ HARD_STOP:git 初始化失败禁 reset --hard / clean -fd / checkout .(§3.5.1 git 自救禁令)。退出 skill 让用户处理。 |
15
48
 
16
49
  ---
17
50
 
18
- ## 状态检测
51
+ ## 状态检测(前置门)
52
+
53
+ **第一步**(⛔ PRECONDITION_FAIL):检查 `openspec/config.yaml` 是否存在——不存在则提示用户 `alloy init`,agent 不得自动初始化(init 会写 `.claude/` / 模板等关键文件,必须由用户主动触发)。
19
54
 
20
- **第一步:检查项目是否就绪。** 检查 `openspec/config.yaml` 是否存在——这是项目已初始化 OpenSpec 的唯一标记。
55
+ **第二步:** 扫描 `openspec/changes/*/.alloy.yaml`,统计 phase != `finished` change,作为路由依据:
56
+ - 0 个活跃 change + 提供 topic → 全新开始
57
+ - 0 个活跃 change + 无 topic → 自由探索
58
+ - 1 个活跃 change → 接续
59
+ - 多个活跃 change → 多选
21
60
 
22
- 如果 `openspec/config.yaml` 不存在,说明项目尚未初始化。引导用户运行 `alloy init` 完成项目级初始化。OpenSpec 技能可以全局共享,但 `openspec/` 目录是每个项目的"身份证"——必须在项目中创建。
61
+ **第三步**(⛔ PRECONDITION_FAIL):「全新开始」与「强制新建」路径强制 Skill 预检——cmd: opsx/explore opsx/new, skill: brainstorming。读取 `commands/alloy/references/skill-precheck.md` 检测,任一不可用 引导 `alloy init`,不存在降级。
23
62
 
24
- **第二步:扫描活跃 change。** 扫描 `openspec/changes/*/.alloy.yaml`,统计 phase != `finished` change
63
+ **第四步**(⛔ PRECONDITION_FAIL):「全新开始」与「强制新建」路径强制 git 仓库就绪——`git rev-parse --git-dir` 失败时尝试 `git init` 兜底(详见全新开始步骤 2);兜底失败 → 退出 skill
25
64
 
26
65
  ---
27
66
 
28
67
  ## 全新开始(无活跃 change + 用户提供了 topic)
29
68
 
30
- **捕获阶段启动时间**(命令调用后第一时间输出当前时间,agent 捕获输出值后在 header 和 phase_timings 中复用):
69
+ **捕获阶段启动时间:**
31
70
  ```bash
32
71
  date "+%Y-%m-%d %H:%M:%S"
33
72
  ```
34
- > 提示:不要混用 bash 变量——bash 状态在两次工具调用间不持久。直接捕获 date 的输出文本,填入 `<START_TIME>`。
73
+ > 不要混用 bash 变量——bash 状态在两次工具调用间不持久。直接捕获 date 输出文本。
35
74
 
36
75
  ```
37
76
  ┌──────────────────────────────────────┐
@@ -40,63 +79,38 @@ date "+%Y-%m-%d %H:%M:%S"
40
79
  └──────────────────────────────────────┘
41
80
  ```
42
81
 
43
- ### [Step 1/2] 上下文探查
44
-
45
- **Skill 预检:** 确认以下依赖可用:
46
- cmd: opsx/explore opsx/new
47
- skill: brainstorming
82
+ > **前置门:** Skill 预检 + git 仓库就绪已在「状态检测」第三/四步完成(⛔ PRECONDITION_FAIL)。本路径假设两者已通过。
48
83
 
49
- 读取 `commands/alloy/references/skill-precheck.md` 了解检测方法。任一不可用 → 引导 `alloy init` → STOP。
50
-
51
- > 正在探查项目上下文和需求空间...
52
-
53
- **立即执行:** 使用 Skill 工具加载 `opsx:explore` 技能。禁止跳过此步骤。
54
-
55
- 技能加载后,按其指引自由探索项目上下文和需求空间。
56
-
57
- **交互风格:** 探查结果反馈给用户时,使用 `AskUserQuestion` 工具呈现结构化选项。详见 `commands/alloy/references/interaction-style.md`。箭头上下选择、Enter 确认——不要用纯文本 "(a)(b)(c)" 让用户打字。
84
+ ### [Step 1/2] 上下文探查
58
85
 
59
- **额外上下文——来自历史 retrospective 的教训:** 在探查阶段,扫描 `openspec/changes/archive/` 下最近 3 个已归档 change 的 `retrospective.md`,提取以下信息作为本次 brainstorming 的参考:
86
+ 加载 `opsx:explore` 技能,按其指引探索项目上下文。
60
87
 
61
- - **§5 意外发现**:上一次有哪些假设被推翻?这次可能也有类似盲区
62
- - **§6 值得推广**:有哪些未勾选的 carry-forward item?这次可以直接勾上
63
- - **§4 技能跳过模式**:如果连续两个 retrospective 中同一技能被 ✗,提醒用户该技能可能不适合本项目
88
+ **交互风格:** 使用 `AskUserQuestion` 工具。详见 `commands/alloy/references/interaction-style.md`。
64
89
 
65
- > 这些信息不是约束——只是在 brainstorming 时提醒 Agent 和用户"上次我们踩了这个坑"。
90
+ **额外上下文:** 扫描 `openspec/changes/archive/` 下最近 3 个 `retrospective.md`,提取 §5 意外发现、§6 值得推广、§4 技能跳过模式,作为本次 brainstorming 参考。
66
91
 
67
92
  ---
68
93
 
69
94
  ### [Step 2/2] 需求设计
70
95
 
71
- > 正在启动 brainstorming...
96
+ 加载 `superpowers:brainstorming` 技能,传入探查结果和主题:
72
97
 
73
- **立即执行:** 使用 Skill 工具加载 `superpowers:brainstorming` 技能。禁止跳过此步骤。
74
-
75
- 将探查结果作为 ARGUMENTS 传入:
76
98
  ```
77
- 探查结果:<Step 1 的关键发现摘要>
99
+ 探查结果:<Step 1 关键发现摘要>
78
100
  主题:<topic>
79
101
  项目类型:<新项目/存量项目>
80
102
 
81
- **Alloy 流程覆盖:** 本调用在 Alloy start 流程内,brainstorming 完成后产出是 draft.md(openspec/changes/<name>/draft.md),**不是** docs/superpowers/specs/ 文件。请跳过 brainstorming checklist 中的"Write design doc"步骤和"Invoke writing-plans"步骤。用户确认方案后直接输出方案内容即可,由 Alloy start 流程负责生成 draft.md。
82
-
83
- **交互风格——使用交互式选择组件,不要用纯文本选项:**
84
-
85
- brainstorming 每个问题都是沟通成本。使用平台的交互式提示工具(Claude Code 中为 `AskUserQuestion`)来降低来回次数。**不要用纯文本 "(a)(b)(c)"——那只是换了格式的开放式提问。**
103
+ **Alloy 流程覆盖:** 本调用在 Alloy start 流程内,brainstorming 完成后产出是 draft.md
104
+ (openspec/changes/<name>/draft.md),不是 docs/superpowers/specs/ 文件。
105
+ 请跳过 brainstorming checklist 中的"Write design doc"和"Invoke writing-plans"步骤。
86
106
 
87
- - **单选用 radio:** `multiSelect: false`,箭头上下导航,Enter 确认。技术选型、架构决策用这个。每个选项的 `description` 写推荐理由,帮用户做决定。
88
- - **多选用 checkbox:** `multiSelect: true`,空格勾选/取消,Enter 提交。功能范围、边界确认用这个。一次确认 3-5 个独立选项,比逐个问 5 个判断题快 5 倍。
89
- - **代码方案对比用 preview:** 如果不同方案涉及代码结构差异,用选项的 `preview` 字段展示代码片段,用户并排对比后选择。
90
- - **每次提问不超过 4 个问题**(`AskUserQuestion` 的上限),相关问题合并到一次调用。不要一个问题调一次——那是文本选项的思维。
91
- - **关键决策单选、范围确认多选:** 架构选择用 radio(互斥),功能范围用 checkbox(独立),不混用。
92
- - **给出默认推荐:** 推荐的选项在 `description` 中标注理由,让用户可以一键确认而不是逐项评估。
107
+ **交互风格:** 使用 AskUserQuestion 组件,不用纯文本 (a)(b)(c)。
108
+ 单选用 radio,多选用 checkbox,代码方案对比用 preview。
109
+ 每次提问不超过 4 个问题,相关问题合并到一次调用。
110
+ 给出默认推荐——推荐选项在 description 中标注理由。
93
111
  ```
94
112
 
95
- 如果 `superpowers:brainstorming` 不可用,引导用户运行 `alloy init` 完成环境初始化。brainstorming 技能内置了审批闸门和 Q&A 深度——普通对话无法复现这些行为。
96
-
97
- **brainstorming 负责"想清楚要做什么"——通过交互式问答明确问题、方案和关键决策。** 用户确认方案后,这一步的产出是 `draft.md`,不是 superpowers spec 文件。
98
-
99
- 用户确认方案后,生成 `draft.md`:
113
+ **用户确认方案后,生成 draft.md**(不是 spec 文件)。用户要求调整时回到 brainstorming 继续。
100
114
 
101
115
  ```markdown
102
116
  # [功能名称]
@@ -108,188 +122,144 @@ brainstorming 每个问题都是沟通成本。使用平台的交互式提示工
108
122
  <!-- 方案概述 -->
109
123
 
110
124
  ## 关键决策
111
- <!-- brainstorming 中确定的关键技术决策及理由,方案对比、架构考量都写在这里 -->
125
+ <!-- brainstorming 中确定的关键技术决策及理由 -->
112
126
 
113
127
  ## 范围与边界
114
128
  <!-- 做什么、明确不做什么 -->
115
129
  ```
116
130
 
117
- **用户明确确认方案之前,不要生成 draft.md。** 如果用户要求调整方案,回到 brainstorming 继续讨论,不要急于产出文件。
131
+ > [HARD_STOP] **用户明确确认方案之前,不要生成 draft.md。**
132
+ > 违反字面 = 违反精神:哪怕"内容已经基本明确再补审查",也算违反——审查窗口是 USER_GATE,不可后置。
118
133
 
119
- **什么算"不够"(反例):**
120
- - brainstorming 完成后生成了 `docs/superpowers/specs/` 文件——draft.md 是 brainstorming 在 alloy 流程中的唯一产出
121
- - brainstorming 完成后 invoke writing-plans——那是独立使用 brainstorming 时的行为,在 alloy:start 中下一步是生成 draft.md
122
- - 用户说"还行"、"可以"就直接生成——追问他是否满意关键决策和范围边界
134
+ ---
123
135
 
124
- ### Red Flags——STOP,不要跳过闸门
136
+ 用户确认方案后,执行以下步骤:
125
137
 
126
- 以下任何一个念头出现,都意味着 start 的闸门正在被绕过:
138
+ > **交互风格恢复(HARD_STOP):** brainstorming 已结束。从此刻起,所有 `🔴 USER_GATE` 必须恢复使用 `AskUserQuestion` 工具(`commands/alloy/references/interaction-style.md`),不用纯文本 (a)(b)(c)。Agent 刚从 brainstorming 的"每次一个问题"模式出来,容易延续纯文本习惯——这是 Iron Law 违规。违反字面 = 违反精神:哪怕"就这一个确认用文本也行",也算违反——USER_GATE 必须 AskUserQuestion。
127
139
 
128
- | 借口 | 现实 |
129
- |------|------|
130
- | "不用建分支了,就在 main 上干吧" | 主分支上直接开发会污染 main 历史。每个 change 必须有独立 feature 分支。拒绝——建分支只需 2 秒。 |
131
- | "已经在某个分支上了,跳过分支步骤" | 在某个分支上 ≠ 在正确的分支上。仍需验证当前分支 ≠ 主分支,并让用户确认。 |
132
- | "分支创建是可选步骤" | 分支创建不是可选的——它是步骤 3 的硬性闸门。没有通过 ⑥ 验证,步骤 4-9 全部禁止执行。 |
133
- | "用户没提分支,继续吧" | 用户没提 ≠ 用户同意跳过。闸门不需要用户主动请求才生效——它默认生效,除非用户明确选择分支。 |
134
- | "项目简单/一个人开发,不需要分支" | 分支隔离保护的是 discard 安全性,不是团队协作。简单项目一样需要独立分支,否则 discard 会丢失主分支上的无关变更。 |
135
- | "不用 brainstorming 了,直接写代码" | brainstorming 不是可选项。跳过需求设计 = 规格和代码分叉的起点。必须加载 superpowers:brainstorming。 |
136
- | "我一个人开发,不用那么正式" | 流程保护的是一致性和可追溯性,不是团队规模。一个人的项目和团队项目的闸门完全一样。 |
137
- | "我看过了,内容都对"(跳过审查) | 用户"看过了"不等于审查到位。必须按流程确认 change name、主分支、feature 分支。 |
138
- | "brainstorming 完成了,写 spec 文件吧" | Alloy start 的产出是 draft.md,不是 docs/superpowers/specs/ 文件。brainstorming 完成后直接输出方案,由 Alloy 流程负责生成 draft.md。 |
139
- | "start 完成了,我帮你直接进 plan" | start 完成后绝不自动进入 plan。即使用户之前说过"赶紧做完",也需要用户在看过 draft.md 后明确运行 /alloy:plan。替用户做阶段转换决定 = 剥夺审查机会。 |
140
- | "用户没回复,我先继续生成 proposal 吧" | 用户沉默 ≠ 授权继续。在审查窗口等待用户明确选 (a) 或 (b)。擅自继续 = 生成的制品未经审查,后期返工代价远大于等待时间。 |
141
- | "draft.md 在 brainstorming 时已经讨论过了,直接 commit 吧" | brainstorming 讨论的是方案概念,draft.md 是最终文本。两者不等价——文本可能有措辞偏差、遗漏细节。必须展示 draft.md 完整内容,等用户确认后才能 commit。 |
140
+ > **git 自救禁令(§3.5.1 内嵌约束,HARD_STOP):** 步骤 2 git init / 步骤 3 分支创建/切换 / 步骤 9 commit 任何环节失败,禁 agent 运行 `git reset --hard` / `git checkout .` / `git restore .` / `git stash` / `git clean -fd` / `git push --force` —— 退出 skill 让用户处理是唯一合法路径。
141
+ >
142
+ > **git add 限路径(§5.2.1 内嵌约束,HARD_STOP):** 所有 commit 用精确路径(`.claude/` `openspec/` `CLAUDE.md` 等明确列举),禁 `-A`/`-a`/`.`。违反字面 = 违反精神:哪怕"反正只改了已知文件",也禁通配——可能把 `.superpowers/` 临时目录或测试残留一并 commit。
142
143
 
143
- ---
144
+ 1. **建议 change name**——kebab-case,🔴 USER_GATE: 确认 change name(建议名 / 自定义)。
144
145
 
145
- 用户确认方案后,执行以下步骤:
146
-
147
- 1. **建议 change name**——根据确认的方案建议 kebab-case 名称,用户确认
146
+ > [HARD_STOP] **未确认时禁止继续步骤 2-9。**
147
+ > 违反字面 = 违反精神:哪怕"name 大概就这个先建分支",也算违反——name 是 directory + branch + records 主键。
148
148
 
149
149
  2. **确保 git 仓库就绪:**
150
-
151
150
  ```bash
152
151
  if ! git rev-parse --git-dir 2>/dev/null; then
153
152
  git init
154
- # 空项目:先提交基础设施作为锚点,确保 HEAD 存在以便后续创建分支
155
153
  git add .claude/ .gitignore openspec/config.yaml openspec/schemas/ 2>/dev/null
156
154
  [ -f CLAUDE.md ] && git add CLAUDE.md 2>/dev/null
157
155
  git commit -m "chore: alloy init 项目初始化"
158
156
  fi
159
157
  ```
160
158
 
161
- 已有项目则跳过(git repo 已存在,HEAD 已有锚点)。
162
-
163
- 3. **分支选择**——在创建 change 目录之前完成分支切换,确保所有制品落在 feature 分支上:
164
-
165
- **① 自动识别主分支:** 读取 `commands/alloy/references/main-branch-detection.md`,按 3 级优先级检测主分支。
159
+ 3. **分支选择**——创建 change 目录之前完成,确保所有制品落在 feature 分支上:
166
160
 
167
- `openspec/config.yaml` 已有 `alloy.main_branch` 记录,直接用记录值,跳过检测和确认。
168
-
169
- **② 确认主分支:** 检测到后让用户确认(Y/n)。确认后写入项目级配置:
170
- ```bash
171
- alloy _config write . main_branch <用户确认的主分支名>
172
- ```主分支是项目级概念,所有 change 共享,不写入 per-change 的 .alloy.yaml。
161
+ **① 主分支检测:** 读取 `commands/alloy/references/main-branch-detection.md`。若 config 已有 `main_branch`,直接用。否则检测后 🔴 USER_GATE: 确认主分支(检测值 / 自定义)。确认后写入并提交(§5.2.1 git add 限路径):
162
+ ```bash
163
+ alloy _config write . main_branch <确认值>
164
+ git add openspec/config.yaml
165
+ git diff --cached --quiet || git commit -m "chore: 配置主分支"
166
+ ```
173
167
 
174
- **③ 检测当前分支:**
168
+ **② 当前分支决策**(🔴 USER_GATE,3 种情况共用同款语义节点):
175
169
  ```bash
176
170
  CURRENT_BRANCH=$(git branch --show-current)
177
- CHANGENAME="<name>"
178
171
  ```
179
172
 
180
- **④ 按当前分支位置决策:**
181
-
182
- - **在主分支上**HARD STOP:"当前在主分支 `<main_branch>`,不允许在主分支开发。commit 会污染主分支历史。" → 只展示"新建分支"选项
183
- - **在 feature 分支上且名称包含 change 名**(如 `feature/<name>` 或 `fix/<name>`)→ 提示"当前已在 `<$CURRENT_BRANCH>`,直接在该分支上继续工作?[Y/n]"
184
- - 选 Y → 使用当前分支,继续步骤 4
185
- - 选 n → 展示选项(见⑤)
186
- - **在非主分支的已有分支上** → 展示选项(见⑤)
173
+ - **在主分支上** → ⛔ HARD_STOP:"不允许在主分支开发。" → 🔴 USER_GATE: 只展示"新建分支"
174
+ - **在 feature 分支且名称含 change 名** → 🔴 USER_GATE: 继续使用当前分支 / 新建分支
175
+ - **在非主分支的已有分支上**🔴 USER_GATE: 切换到已有分支 / 新建分支
187
176
 
188
- **⑤ 展示选项:**
177
+ 无可用本地非主分支时 → 直接新建。
189
178
 
190
- 本地非主分支(排除刚确认的主分支)存在时:
191
- > 选择工作分支
192
- > ──────────────────────────────────────
193
- >
194
- > 当前在 `<$CURRENT_BRANCH>`,主分支:`<main_branch>`
195
- >
196
- > 1. 切换到已有分支 —— 选择非主分支的已有分支
197
- > 2. 新建分支 —— 创建新 feature 分支并切换
179
+ 新建分支命名:默认 `feature/<change-name>`,用户可自定义。
198
180
 
199
- 无可用本地非主分支时直接进入新建分支流程(跳过选项 1)。
181
+ **⛔ PRECONDITION_FAIL 白名单校验**(读取 `commands/alloy/references/branch-naming.md`):自定义分支名必须以 `feature/` `fix/` `docs/` `refactor/` `test/` `chore/` 之一开头,后缀 kebab-case,且不与主分支同名。校验失败 USER_GATE 让用户重新输入合法名称,**禁 agent 自动改写后继续**。
200
182
 
201
- 每个 change 必须有独立的 feature 分支,确保 discard 时可安全清理。
202
-
203
- - **选 1:** 列出本地非主分支(`git branch` 排除主分支),用户选择后执行 `git checkout <branch>`
204
- - **选 2:** 新建分支命名:
205
- - 默认建议:`feature/<change-name>`
206
- - 用户可输入自定义名称
207
- - 校验:不允许与主分支同名
208
- - `git checkout -b <branch-name>`
209
-
210
- **⑥ 分支验证——HARD STOP:** 分支创建/切换后,必须验证才能继续。这是防止在主分支上开发的关键闸门——没有这个检查,步骤 3 的所有逻辑都是空谈。
183
+ 通过校验后:`git checkout -b <branch-name>`
211
184
 
185
+ **③ 分支验证(⛔ HARD_STOP):** 创建/切换后必须验证才能继续:
212
186
  ```bash
213
187
  CURRENT=$(git branch --show-current)
214
188
  echo "当前分支: $CURRENT | 主分支: $MAIN_BRANCH"
215
189
  ```
190
+ `$CURRENT` = `$MAIN_BRANCH` → ⛔ HARD_STOP,返回重新选择
191
+ `$CURRENT` ≠ `$MAIN_BRANCH` → 🔴 USER_GATE: 确认分支状态正确
192
+
193
+ > [HARD_STOP] **未通过验证或用户未确认时,禁止执行步骤 4-9。**
216
194
 
217
- - `$CURRENT` = `$MAIN_BRANCH` → **HARD STOP**——"仍在主分支上,不允许继续。"返回⑤重新选择分支
218
- - `$CURRENT` ≠ `$MAIN_BRANCH` → 验证通过,展示分支状态供用户确认
195
+ 3.5. **opsx:new 目录冲突预检**(⛔ PRECONDITION_FAIL,task #12)
219
196
 
220
- > 分支状态
221
- > ──────────────────────────────────────
222
- > 当前分支: `<$CURRENT>`(主分支: `<$MAIN_BRANCH>`)
223
- >
224
- > 确认,继续创建 change 目录
225
- > → 需要换分支 — 返回分支选择
197
+ ```bash
198
+ if [ -d "openspec/changes/<name>" ]; then
199
+ echo "⛔ PRECONDITION_FAIL: openspec/changes/<name> 已存在"
200
+ echo " 可能原因:name 已被占用 / 旧 change 残留 / 多 session 并发"
201
+ echo " 禁止:agent 自动覆盖(rm -rf)或自动复用——可能丢失用户既有工作"
202
+ fi
203
+ ```
226
204
 
227
- 用户确认后才能继续步骤 4。**未通过验证或用户未确认时,禁止执行步骤 4-9。**
205
+ 🔴 USER_GATE: 选择处理路径
206
+ - (a) 改用其他 name → 回步骤 1 重新建议 change name
207
+ - (b) 接续已有 change → 退出 start,引导用户跑 `/alloy:start`(无 topic)触发"接续"路径
208
+ - (c) 中止本次 /alloy:start
228
209
 
229
- **什么算"跳过闸门"(反例):**
230
- - 分支选择后直接进入步骤 4,不验证当前分支——验证只需 1 git 命令
231
- - 已在 feature 分支上就跳过整个步骤 3——仍需确认当前分支名并记录
232
- - 用户没回复就继续——分支状态必须用户确认
210
+ > [HARD_STOP] agent 不得自动选 (a) / (b) / (c)——必须由用户明确决策。
211
+ > 违反字面 = 违反精神:哪怕"目录看起来是空的"或"看起来是上次中断的",也禁 agent 自动复用。
233
212
 
234
- 4. **调用 `/opsx:new <name>`** 创建 change 目录
213
+ 4. **调用 `/opsx:new <name>`** 创建 change 目录(前置:步骤 3 ③ 验证已通过 + 步骤 3.5 目录冲突已解决)
235
214
 
236
- **前置条件:步骤 3 ⑥ 的分支验证已通过且用户已确认。** 如果当前仍在主分支上,STOP——回到步骤 3 选择分支。
215
+ 调用后验证创建结果:
216
+ ```bash
217
+ if [ ! -f "openspec/changes/<name>/.alloy.yaml" ]; then
218
+ echo "⛔ PRECONDITION_FAIL: /opsx:new 创建失败——.alloy.yaml 缺失"
219
+ echo " 退出 skill 让用户排查 opsx 命令"
220
+ exit 1
221
+ fi
222
+ ```
237
223
 
238
- 5. **批量记录技能使用——** change 目录已创建,将在 Step 1/2 中使用的技能一次性写入 `.alloy.yaml`:
224
+ 5. **批量记录技能使用:**
239
225
  ```bash
240
226
  alloy _skill log openspec/changes/<name> start opsx:explore && \
241
227
  alloy _skill log openspec/changes/<name> start superpowers:brainstorming && \
242
228
  alloy _skill log openspec/changes/<name> start opsx:new
243
229
  ```
244
230
 
245
- 6. **写入 state**——使用 `_state init` 一步创建完整初始状态(包含 `records: []`、正确类型),避免逐字段写入遗漏 records 数组:
231
+ 6. **写入 state:**
246
232
  ```bash
247
233
  alloy _state init openspec/changes/<name>
248
- ```
249
-
250
- **记录阶段启动时间:**
251
- ```bash
252
234
  alloy _state merge openspec/changes/<name> phase_timings "{\"start\":{\"started_at\":\"$(date '+%Y-%m-%d %H:%M:%S')\"}}"
253
235
  ```
254
236
 
255
- 7. **记录分支信息**——将 feature_branch 和 worktree null 写入 state:
237
+ 7. **记录分支信息:**
256
238
  ```bash
257
239
  alloy _state write openspec/changes/<name> feature_branch <branch-name>
258
240
  alloy _state write openspec/changes/<name> worktree null
259
241
  ```
260
242
 
261
- 8. **按模板生成 `draft.md`** 到 `openspec/changes/<name>/draft.md`(直接在 change 目录下生成,无需移动)
243
+ 8. **生成 `draft.md`** 到 `openspec/changes/<name>/draft.md`
262
244
 
263
- **draft.md 审查窗口——这是 start 阶段唯一的制品审查闸门。用户明确确认后才能 commit。**
245
+ **draft.md 审查窗口——start 阶段唯一的制品闸门:**
264
246
 
265
247
  > 制品 draft ✓ 完成
266
- >
267
248
  > [展示 draft.md 完整内容]
268
- >
269
- > → (a) 确认,锁定 draft 并完成 start 阶段
270
- > → (b) 需要调整 — 回到 brainstorming 重新讨论
271
-
272
- - **选 (a)**:继续步骤 9,hash 锁定 + commit
273
- - **选 (b)**:不生成文件、不 commit。回到 Step 2/2 的 brainstorming,基于用户反馈重新讨论方案。brainstorming 完成后重新生成 draft.md,再次进入此审查窗口
249
+ > 🔴 USER_GATE: 确认锁定 draft(确认并继续提交 / 需要调整回 brainstorming)
274
250
 
275
- **什么算"审查不充分"(反例):**
276
- - 只问"看起来可以吗?"不展示 draft.md 实际内容
277
- - 用户说"还行"、"可以"就跳过——必须明确选 (a) 或 (b)
278
- - 把 brainstorming 阶段的方案确认等同于 draft.md 审查——brainstorming 确认的是概念,draft.md 审查的是最终文本
251
+ 选确认 → 步骤 9;选调整 → 回到 Step 2/2 brainstorming。
279
252
 
280
- > 前面步骤写入的 `.alloy.yaml` 变更(init、started_at、feature_branch、worktree)不单独提交——它们在 draft commit 中一并提交。`git add openspec/changes/<name>/` 会覆盖目录内的所有变更。
253
+ 9. **提交——仅用户确认锁定后,执行以下 2 commit:**
281
254
 
282
- 9. **提交(start 阶段唯一 commit)——仅在用户选 (a) 后执行:**
283
-
284
- **alloy init 基础设施提交:**
255
+ **commit 1/2——基础设施(幂等,已提交则跳过;§5.2.1 git add 限路径):**
285
256
  ```bash
286
257
  git add .claude/ .gitignore openspec/config.yaml openspec/schemas/ 2>/dev/null
287
258
  [ -f CLAUDE.md ] && git add CLAUDE.md 2>/dev/null
288
259
  git diff --cached --quiet || git commit -m "chore: alloy init 项目初始化"
289
260
  ```
290
- 已提交过则自动跳过。`.superpowers/` 已在 `.gitignore` 中忽略,不入仓库。
291
261
 
292
- **记录阶段时间 + draft hash-lock + commit:**
262
+ **commit 2/2——draft hash-lock + .alloy.yaml 变更(§5.2.1 git add 限路径):**
293
263
  ```bash
294
264
  COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
295
265
  alloy _state merge openspec/changes/<name> phase_timings "{\"start\":{\"completed_at\":\"${COMPLETED_AT:-$(date '+%Y-%m-%d %H:%M:%S')}\"}}"
@@ -301,6 +271,8 @@ brainstorming 每个问题都是沟通成本。使用平台的交互式提示工
301
271
  git commit -m "docs(<name>): draft 已确认"
302
272
  ```
303
273
 
274
+ 前面步骤写入的 `.alloy.yaml` 变更在 draft commit 中一并提交。
275
+
304
276
  ---
305
277
 
306
278
  ### 完成
@@ -308,42 +280,21 @@ brainstorming 每个问题都是沟通成本。使用平台的交互式提示工
308
280
  ```
309
281
  ┌──────────────────────────────────────┐
310
282
  │ Alloy [1/5] · Phase: Start — DONE │
311
- │ 启动时间: phase_timings.start.started_at 读取 │
312
- │ 完成时间: phase_timings.start.completed_at 读取 │
313
- │ 耗时: (phase_timings.start.completed_at - started_at 计算)
283
+ │ 启动时间: phase_timings.start.started_at
284
+ │ 完成时间: phase_timings.start.completed_at
285
+ │ 耗时: completed_at - started_at
314
286
  └──────────────────────────────────────┘
315
287
 
316
- → Change: <name>
317
- Phase: started
318
-
319
- 所有制品已生成并锁定:
320
-
321
- 制品 状态 Hash 创建时间
322
- ────────────── ──── ──────────── ───────────────────
323
- draft ✓ <hash> <timestamp>
324
-
325
- 准备好后,运行 /alloy:plan 进入规划阶段。
288
+ → Change: <name> Phase: started
289
+ 制品: draft ✓
326
290
  ```
327
291
 
328
- - draft.md 已在 change 目录,项目根目录不再有 draft.md
329
-
330
- **HARD STOP —— start 阶段到此结束。以下行为绝对禁止:**
331
-
332
- - 不要自动运行 `/alloy:plan` 或加载 `alloy-plan` 技能
333
- - 不要生成 proposal.md、design.md、specs/、tasks.md、plans.md 或任何 plan 阶段制品
334
- - 不要调用 `opsx:continue` 或 `superpowers:writing-plans`
335
- - 不要因为"用户没回复"而继续——沉默 ≠ 授权
336
- - 不要因为"这样更高效"而替用户做决定——用户必须自己发起下一阶段
292
+ > [HARD_STOP] **start 阶段到此结束。**
293
+ > 不要自动运行 `/alloy:plan`,不要生成 plan 阶段制品,不要调用 `opsx:continue` 或 `writing-plans`。
294
+ > 违反字面 = 违反精神:哪怕"用户上次也是接 plan 这次猜跳过 USER_GATE"或"draft 已锁定流程很顺",也算违反 Iron Law(NO AUTO ADVANCE)。
295
+ > **你的唯一操作:展示完成信息,等待用户输入下一个命令。**
337
296
 
338
- **你的唯一操作:展示上述完成信息,等待用户输入下一个命令。**
339
-
340
- ---
341
-
342
- ## 闸门规则
343
-
344
- - **git add 只用精确路径** — 永远不用 `-A`、`-a`、`.`。
345
- start 阶段只 add `openspec/changes/<name>/` 和 init 基础设施文件(`.claude/` `.gitignore` `openspec/config.yaml` `openspec/schemas/`);反例:`git add -A` 会把临时文件一起提交
346
- - **draft.md 必须在 change 目录内** — 不在项目根目录产生临时文件
297
+ > **§5.2.3 路径 B 边界说明:** start 是 phase 推进起点(无前序 phase),phase=started 写入失败时降级路径只有"重跑 /alloy:start"——不存在 phase 回退场景。本阶段无 §5.2.3 适用空间。
347
298
 
348
299
  ---
349
300
 
@@ -352,27 +303,31 @@ brainstorming 每个问题都是沟通成本。使用平台的交互式提示工
352
303
  ```
353
304
  ┌──────────────────────────────────────┐
354
305
  │ Alloy [1/5] · Phase: Start │
355
- │ 启动时间: <TIMESTAMP>
306
+ │ 启动时间: <TIMESTAMP>
356
307
  └──────────────────────────────────────┘
357
308
  ```
358
309
 
359
- ### [Step 1/2] 扫描项目上下文
310
+ 扫描项目上下文(README、代码、requirement.md 等)。
311
+
312
+ **有上下文:** 总结项目信息,给 2-3 个建议方向,帮用户明确要做什么。
360
313
 
361
- 扫描项目上下文(README、已有代码、requirement.md、OpenSpec spec 文件等)。
314
+ **空项目:** "项目较新,无上下文。请用 `/alloy:start <topic>` 重新调用,进入完整需求设计流程。"
362
315
 
363
- ### [Step 2/2] 呈现发现与建议
316
+ > 必须让用户重新输入 `/alloy:start <topic>`——只有重新调用命令,alloy:start 技能才会被重新加载。仅输入 topic 文本会导致脱离编排框架,关键闸门被跳过。
364
317
 
365
- **有上下文可读时:** 总结项目信息(技术栈、已有功能、最近变更),基于发现给用户 2-3 个建议方向或追问。目标是帮用户明确他想做什么,而不是抛回一句"请提供主题"。
318
+ **自由探索发现用户有明确 topic 后:**
366
319
 
367
- **空项目无可读上下文时:** 直接告诉用户:"项目较新,没有太多上下文可供参考。请用 `/alloy:start <topic>` 重新调用,我会进入完整的需求设计流程。"
320
+ 🔴 USER_GATE: 检测到明确功能需求,请选择:
321
+ - (a) 以 "<topic>" 进入全新开始(请输入 `/alloy:start <topic>` 正式开始)
322
+ - (b) 继续自由探索
368
323
 
369
- > 关键:必须让用户重新输入 `/alloy:start <topic>`,而不是只输入 topic 文本。只有重新调用命令,alloy:start 技能才会被重新加载并进入"全新开始"路径。如果用户只输入 topic 文本而不带命令,Agent 将脱离 alloy:start 编排框架,导致关键闸门(change name 确认、分支选择、hash commitment)被跳过。
324
+ (a) 时输出提示文本,Agent 不得直接跳转到"全新开始"流程。
370
325
 
371
326
  ---
372
327
 
373
328
  ## 强制新建(--new <topic>)
374
329
 
375
- 无论是否有活跃 change,直接走"全新开始"流程。多个 change 可并行 planning,但不能同时 apply(一个 session 只能有一个工作中的 worktree)。
330
+ 无论是否有活跃 change,直接走"全新开始"流程。多个 change 可并行 planning,但不能同时 apply
376
331
 
377
332
  ---
378
333
 
@@ -381,59 +336,44 @@ brainstorming 每个问题都是沟通成本。使用平台的交互式提示工
381
336
  ```
382
337
  ┌──────────────────────────────────────┐
383
338
  │ Alloy [1/5] · Phase: Start │
384
- │ 启动时间: phase_timings.start.started_at 读取,若无则从 created_at 读取 │
339
+ │ 启动时间: phase_timings.start.started_at created_at
385
340
  └──────────────────────────────────────┘
386
341
 
387
- → 检测到活跃 change:<name>
388
- 当前阶段:<phase>
389
- → 已完成制品:<列出已有文件>
342
+ → 检测到活跃 change:<name>(phase: <phase>)
343
+ 已完成制品:<列出>
390
344
  → 下一步:<建议操作>
391
345
  ```
392
346
 
393
- ### [Step 1/1] 状态展示与自动接续
394
-
395
- 先读取 `.alloy.yaml` 获取 phase 和 worktree 字段,再检查文件系统确认实际制品状态。
396
-
397
- 展示检测结果后,根据 phase 和制品状态决定路由:
347
+ 读取 `.alloy.yaml` + 文件系统确认制品状态,按 phase 路由:
398
348
 
399
349
  | phase | 制品状态 | 路由 |
400
350
  |-------|---------|------|
401
- | started | proposal.md 存在 | alloy-plan(正常接续——plan 制品已有,继续生成) |
402
- | started | proposal.md 不存在 + draft.md 存在且 hash 有效 | **提示用户选择:**(a) 进入 plan 阶段 (b) 回到 brainstorming 修改需求。draft 已确认,默认预期是用户想进 plan——不要默认假设用户想重来。 |
403
- | started | proposal.md 不存在 + draft.md 不存在或 hash 不匹配 | 重新进入 brainstorming(draft 缺失或已被篡改,需重新讨论需求) |
404
- | planned | — | alloy-apply |
405
- | applied | — | alloy-archive |
406
- | archived | — | alloy-finish |
407
- | finished | — | 工作流已完成——如需继续修改,使用自然对话提交新变更 |
408
-
409
- **实现方式:**
410
-
411
- - **需自动加载命令时**(proposal.md 存在 → plan、planned → apply 等):输出对应命令文件的完整指令(`commands/alloy/plan.md` / `apply.md` / `archive.md` / `finish.md`),将 change name 和检测到的进度信息作为上下文传入。Agent 无缝进入对应阶段。
412
- - **需用户选择时**(draft 已确认、proposal 不存在):先校验 draft hash:
413
- ```bash
414
- alloy _record check openspec/changes/<name> draft
415
- ```
416
- hash 有效 → 展示选择:"draft 已确认。 (a) 进入 plan 阶段 (b) 回到 brainstorming 修改需求"。等用户选择后执行对应路由。
417
- hash 不匹配 → 走"draft 不存在或 hash 不匹配"路径。
418
-
419
- 一致性检查(双向):
420
- - worktree 字段有值但磁盘路径不存在 → ⚠️ "worktree 残留:.alloy.yaml 声称有 worktree 但磁盘不存在"
421
- - worktree 字段为 null 但 `.worktrees/<name>/` 目录存在 → ⚠️ "worktree 孤儿:磁盘存在 worktree 但 .alloy.yaml 未记录,建议手动验证并更新状态"
422
- - 发现孤儿 worktree 时,询问用户是否修复 .alloy.yaml:`alloy _state write openspec/changes/<name> worktree ".worktrees/<name>"`
351
+ | started | proposal.md 存在 | 🔴 USER_GATE: 选择继续规划(alloy-plan / 回需求讨论(重新 start) |
352
+ | started | draft.md 存在且 hash 有效 | 🔴 USER_GATE: 选择进 plan / brainstorming |
353
+ | started | draft.md 缺失或 hash 不匹配 | 重新 brainstorming |
354
+ | planned | — | 🔴 USER_GATE: 确认进入 apply 阶段(继续 / 查看状态 / 放弃 change) |
355
+ | applied | — | 🔴 USER_GATE: 确认进入 archive 阶段(继续 / 查看状态 / 放弃 change) |
356
+ | archived | — | 🔴 USER_GATE: 确认进入 finish 阶段(继续 / 查看状态) |
357
+ | finished | — | 工作流已完成 |
423
358
 
424
- ---
359
+ **所有 🔴 USER_GATE 的选项模板(同款语义节点,6 phase 共用):**
360
+ - (a) 进入 `<目标阶段>` 继续
361
+ - (b) 查看状态(/alloy:status)
362
+ - (c) 放弃此 change(/alloy:discard)——仅 planned/applied 阶段可选
425
363
 
426
- ## 多选(有多个活跃 change)
364
+ **自动跳转仅限**:用户明确选择 (a) 后才加载目标命令。
427
365
 
428
- ```
429
- ┌──────────────────────────────────────┐
430
- │ Alloy [1/5] · Phase: Start │
431
- │ 启动时间: 从 phase_timings.start.started_at 读取,若无则从 created_at 读取 │
432
- └──────────────────────────────────────┘
366
+ **需自动加载时:** 输出对应命令文件完整指令,将 change name 和进度信息传入。
433
367
 
434
- 检测到 <N> 个活跃 change,请选择。
435
- ```
368
+ **需用户选择时:** 先校验 draft hash(`alloy _record check openspec/changes/<name> draft`),hash 有效 → 展示选择。
436
369
 
437
- ### [Step 1/1] 展示并选择
370
+ 一致性检查:
371
+ - worktree 字段有值但路径不存在 → ⚠️ WARN 残留
372
+ - worktree 为 null 但 `.worktrees/<name>/` 存在 → ⚠️ WARN 孤儿,询问是否修复
373
+
374
+ ---
375
+
376
+ ## 多选(有多个活跃 change)
438
377
 
439
378
  列出所有活跃 change(名称 + phase + 制品状态),让用户选择接续哪个,或 `--new <topic>` 开新 change。
379
+