@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.
- package/commands/alloy/apply.md +222 -430
- package/commands/alloy/archive.md +156 -132
- package/commands/alloy/discard.md +26 -11
- package/commands/alloy/finish.md +212 -116
- package/commands/alloy/fix.md +102 -247
- package/commands/alloy/plan.md +204 -301
- package/commands/alloy/references/apply-precheck.md +21 -0
- package/commands/alloy/references/apply-rationalizations.md +18 -0
- package/commands/alloy/references/apply-subagent-commit.md +49 -0
- package/commands/alloy/references/apply-worktree.md +130 -0
- package/commands/alloy/references/archive-rationalizations.md +16 -0
- package/commands/alloy/references/archive-worktree-cleanup.md +94 -0
- package/commands/alloy/references/artifact-hash-commit.md +49 -0
- package/commands/alloy/references/branch-naming.md +65 -0
- package/commands/alloy/references/branch-validation.md +36 -0
- package/commands/alloy/references/fix-precommit-check.md +58 -0
- package/commands/alloy/references/interaction-style.md +34 -1
- package/commands/alloy/references/main-branch-detection.md +3 -6
- package/commands/alloy/references/phase-downgrade-path.md +27 -0
- package/commands/alloy/references/plan-rollback.md +84 -0
- package/commands/alloy/references/spec-sync.md +62 -0
- package/commands/alloy/references/start-rationalizations.md +18 -0
- package/commands/alloy/start.md +178 -238
- package/dist/cli/commands/completion.js +13 -2
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/internal/artifact.d.ts +7 -0
- package/dist/cli/commands/internal/artifact.js +70 -0
- package/dist/cli/commands/internal/artifact.js.map +1 -0
- package/dist/cli/commands/internal/guard.js +204 -2
- package/dist/cli/commands/internal/guard.js.map +1 -1
- package/dist/cli/commands/internal/progress.d.ts +10 -0
- package/dist/cli/commands/internal/progress.js +70 -0
- package/dist/cli/commands/internal/progress.js.map +1 -0
- package/dist/cli/commands/internal/spec-audit.d.ts +42 -0
- package/dist/cli/commands/internal/spec-audit.js +363 -0
- package/dist/cli/commands/internal/spec-audit.js.map +1 -0
- package/dist/cli/commands/internal/state.js +4 -0
- package/dist/cli/commands/internal/state.js.map +1 -1
- package/dist/cli/index.js +30 -0
- package/dist/cli/index.js.map +1 -1
- package/package.json +2 -1
package/commands/alloy/plan.md
CHANGED
|
@@ -3,368 +3,245 @@ name: "Alloy: Plan"
|
|
|
3
3
|
description: Alloy 规划阶段 - draft.md 完成后进入
|
|
4
4
|
category: Workflow
|
|
5
5
|
tags: [alloy, workflow]
|
|
6
|
+
spec: 01-product-spec/02-plan-spec.md
|
|
7
|
+
behaviors:
|
|
8
|
+
preconditions: 7
|
|
9
|
+
hard_stops: 10
|
|
10
|
+
user_gates: 7
|
|
11
|
+
warns: 1
|
|
12
|
+
artifacts: [proposal, design, specs, tasks, plans]
|
|
13
|
+
transitions_to: planned
|
|
14
|
+
external_calls: [opsx:continue, superpowers:writing-plans]
|
|
6
15
|
---
|
|
7
16
|
|
|
8
17
|
# alloy-plan
|
|
9
18
|
|
|
10
|
-
你是 Alloy
|
|
19
|
+
你是 Alloy 的规划阶段编排器。按 OpenSpec schema DAG 依赖顺序,制品生成设计文档,每步生成后提供审查窗口。
|
|
11
20
|
|
|
12
|
-
|
|
21
|
+
```
|
|
22
|
+
[HARD_STOP] NO DIRECT EDITING OF GENERATED ARTIFACTS + NO SKIP REVIEW WINDOW
|
|
23
|
+
5 个制品 = 5 个审查窗口;已生成制品禁止直接编辑,必须重新生成
|
|
24
|
+
违反字面 = 违反精神:哪怕"只改一个错别字直接编辑"、"已经看过 draft 后面跳过审查"、或用户主动说"后面不用看了一次性过",也算违反 Iron Law。审查窗口不可跳过——用户要求跳过不算授权。
|
|
25
|
+
```
|
|
13
26
|
|
|
14
|
-
|
|
27
|
+
**核心原则:按 schema DAG 依赖顺序逐一产出制品,每步有审查闸门,不跳过上游直接产下游。** 5 制品(proposal/design/specs/tasks/plans)以 hash-lock + 单独 commit 入 records,禁直接编辑,禁互相替代。
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
**交互规则:** `🔴 STOP` 等价 `USER_GATE`,必须用 `AskUserQuestion`(`commands/alloy/references/interaction-style.md`,含"沉默 ≠ 授权"通用禁令——禁批量打包、禁基于内容跳过、禁 agent 回填精确字符串)。跳过任何 USER_GATE = 违反 Iron Law。
|
|
17
30
|
|
|
18
|
-
|
|
19
|
-
- 用户说"一次性生成"就直接出全部制品——跳过了 5 个审查窗口,失去了需求验证的时机
|
|
20
|
-
- 用户说"太慢了"就加速跳过审查——审查时间远小于返工时间
|
|
21
|
-
- 用户说"我看过 draft 了,内容都对"就松懈——draft 审查不能替代 proposal/design/specs/tasks 的逐级审查
|
|
31
|
+
**状态符号:** `⛔` = HARD_STOP / PRECONDITION_FAIL,`🔴` = USER_GATE,`⚠️` = WARN(视觉规范 §七)。
|
|
22
32
|
|
|
23
|
-
|
|
33
|
+
**调用外部命令或技能前,先输出标题和状态描述,再执行操作。**
|
|
24
34
|
|
|
25
|
-
|
|
26
|
-
|------|------|
|
|
27
|
-
| "一次性生成全部制品,提高效率" | plan 不提供一键生成。5 个制品 = 5 个审查窗口。每步审查的价值远大于省下的几秒。跳过审查 = 跳过需求验证。 |
|
|
28
|
-
| "太慢了,直接出全部吧" | 审查时间远小于后期返工时间。一个未审查的 specs 缺陷到 apply 阶段才发现,代价是重做全部代码。 |
|
|
29
|
-
| "我看过 draft 了,后面的不用看了" | draft 是方案设计,proposal 是提案范围,design 是技术方案,specs 是行为契约——四个层面不可互相替代。 |
|
|
30
|
-
| "这个项目很小,不需要那么正式" | 小项目和大项目的闸门完全一样。不存在"规模分级的保护等级"。 |
|
|
31
|
-
|
|
32
|
-
**捕获阶段启动时间**(命令调用后第一时间,前置检查之前,幂等——重入时返回已有值):
|
|
35
|
+
**捕获阶段启动时间**(幂等,重入时返回已有值):
|
|
33
36
|
```bash
|
|
34
37
|
PHASE_START=$(alloy _state timestamp ensure openspec/changes/<name> plan)
|
|
35
38
|
```
|
|
36
39
|
|
|
37
40
|
---
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
1. 确认 change 目录 `openspec/changes/<name>/` 存在且 `.alloy.yaml` phase 为 `started`(由 `/alloy:start` 完成),否则报错
|
|
42
|
-
2. 若 change 目录存在但 `draft.md` 缺失 → 异常状态,提示重新运行 `/alloy:start`
|
|
43
|
-
3. 若指定 `[name]` 参数但 change 不存在 → "未找到 change '<name>',请先运行 `/alloy:start <name>` 创建 change"
|
|
44
|
-
4. **Skill / 命令预检:** 确认以下依赖可用:
|
|
45
|
-
cmd: opsx/continue
|
|
46
|
-
skill: writing-plans
|
|
42
|
+
### Red Flags(第三层防御——任一借口出现即 STOP)
|
|
47
43
|
|
|
48
|
-
|
|
44
|
+
| 借口 | 现实 |
|
|
45
|
+
|------|------|
|
|
46
|
+
| "一次性生成全部制品,提高效率" | ⛔ HARD_STOP:5 个制品 = 5 个审查窗口,禁 agent 一次性生成。跳过审查 = 跳过需求验证,后期返工代价远大于审查时间(Iron Law 第一层)。 |
|
|
47
|
+
| "太慢了,直接出全部吧" | 审查时间远小于后期返工。未审查的 specs 缺陷到 apply 才发现 = 重做全部代码。 |
|
|
48
|
+
| "我看过 draft 了,后面的不用看了" | draft 是方案设计,proposal 是提案范围,design 是技术方案,specs 是行为契约——四个层面不可互相替代(⛔ HARD_STOP)。即使用户主动说"后面不用看了",审查窗口也不可跳过。 |
|
|
49
|
+
| "只是改个错别字,直接编辑文件吧" | 已生成制品禁止直接编辑——哪怕错别字也必须重新生成(违反字面 = 违反精神)。 |
|
|
50
|
+
| "用户要加功能,我重置 proposal 重新生成就行" | 功能变更必须回溯清理所有下游制品——重置单个制品 = 上下游需求不一致。`alloy _artifact reset` 仅限措辞/格式修正。 |
|
|
51
|
+
| "需求变更了,直接回溯清理吧" | 回溯是不可逆删除——必须让用户看到两条路径后主动选择 + 已自动打 snapshot tag(task #15)。 |
|
|
52
|
+
| "需求变更和轻量修正差不多,先 reset 试试看" | ⛔ HARD_STOP:分类不清前禁执行 `_artifact reset`。需求变更 = 删除全部 plan 制品,轻量修正 = 只重置一个制品。后果完全不同。 |
|
|
53
|
+
| "draft 的 commit message 看着像是确认了,跳过 hash 校验吧" | ⛔ PRECONDITION_FAIL:draft 来源必须 `alloy _record check` 验证 hash 链(task #16),commit msg 字符串解析不可靠。 |
|
|
54
|
+
| "rollback 失败了,git reset --hard 清场重来" | ⛔ HARD_STOP:rollback 失败时禁 reset --hard / checkout . / stash drop(§3.5.1 git 自救禁令)。退出 skill 让用户处理。 |
|
|
55
|
+
| "phase 推进失败但 plans 已生成,git reset 回退一下" | ⛔ HARD_STOP:phase 推进路径 B 降级——手动 `alloy _state set` 回退 phase,禁 git reset 清场(§5.2.3)。 |
|
|
56
|
+
| "用户在等,分类先按轻量修正走,错了再说" | 分类不清 = 默认需求变更(plan-rollback.md 已写)。USER_GATE 必须用户明确选择。 |
|
|
57
|
+
| "这个项目很小,不需要那么正式" | 小项目和大项目的闸门完全一样。不存在"规模分级的保护等级"。 |
|
|
49
58
|
|
|
50
59
|
---
|
|
51
60
|
|
|
52
|
-
### [Step
|
|
61
|
+
### [Step 0/3] 前置检查
|
|
53
62
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
│ 启动时间: $PHASE_START
|
|
58
|
-
└──────────────────────────────────────┘
|
|
59
|
-
|
|
60
|
-
[Step 1/3] 确认 Change
|
|
61
|
-
──────────────────────────────────────
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
1. 确认 `openspec/changes/<name>/draft.md` 存在,并验证来源:
|
|
65
|
-
```bash
|
|
66
|
-
git log -1 --format="%s" -- openspec/changes/<name>/draft.md
|
|
67
|
-
```
|
|
68
|
-
若 commit message 不含 `docs(<name>): draft 已确认`→ ⚠️ draft.md 可能未经过完整 `/alloy:start` 流程(手工创建),提示用户确认是否继续。不阻断——但给用户知情权。
|
|
69
|
-
2. 确认 `.alloy.yaml` phase 为 `started`:
|
|
70
|
-
```bash
|
|
71
|
-
alloy _state check openspec/changes/<name> started
|
|
72
|
-
```
|
|
73
|
-
3. 确认 git 仓库可用:
|
|
74
|
-
```bash
|
|
75
|
-
git rev-parse --git-dir
|
|
76
|
-
```
|
|
77
|
-
若失败 → HARD STOP:"项目还不是 git 仓库。请先运行 `/alloy:start` 完成初始化(包含 git init)。"
|
|
63
|
+
1. **change 目录存在 + draft.md 存在**(⛔ PRECONDITION_FAIL):
|
|
64
|
+
- change 不存在 → 引导 `/alloy:start <name>` 创建
|
|
65
|
+
- draft.md 缺失 → 异常状态,引导重新运行 `/alloy:start`
|
|
78
66
|
|
|
79
|
-
|
|
67
|
+
2. **phase 校验**(⛔ PRECONDITION_FAIL):`alloy _guard precheck openspec/changes/<name> started`
|
|
68
|
+
- phase ≠ started 时读取 `commands/alloy/references/phase-routing.md` 自动跳转
|
|
69
|
+
- 路由不到合法状态 → ⛔ PRECONDITION_FAIL
|
|
80
70
|
|
|
81
|
-
|
|
71
|
+
3. **git 仓库检查**(⛔ PRECONDITION_FAIL):`git rev-parse --git-dir`,失败 → 引导初始化或退出。
|
|
82
72
|
|
|
83
|
-
|
|
73
|
+
4. **Skill 预检**(⛔ PRECONDITION_FAIL):cmd: opsx/continue, skill: writing-plans
|
|
74
|
+
读取 `commands/alloy/references/skill-precheck.md` 检测。任一不可用 → 引导 `alloy init`,不存在降级。
|
|
84
75
|
|
|
85
|
-
|
|
86
|
-
→ 引导用户先运行 `/alloy:start <name>` 创建 change。这是唯一保留 HARD STOP 的场景——前序阶段完全没做。
|
|
76
|
+
5. **draft 来源验证**(⛔ PRECONDITION_FAIL,task #16):用 hash 链验证 draft 完整性,**禁用 commit msg 字符串解析**:
|
|
87
77
|
|
|
88
|
-
|
|
78
|
+
```bash
|
|
79
|
+
if ! alloy _record check openspec/changes/<name> draft 2>/dev/null; then
|
|
80
|
+
echo "⛔ PRECONDITION_FAIL: draft hash 验证失败"
|
|
81
|
+
echo " 原因:draft.md 内容与 records 中记录的 hash 不一致"
|
|
82
|
+
echo " 可能:draft 被手动编辑 / records 被破坏 / 未经完整 start 流程"
|
|
83
|
+
echo " 禁止:agent 自动接受不一致的 draft 继续生成下游制品"
|
|
84
|
+
echo ""
|
|
85
|
+
echo "🔴 USER_GATE: 选择处理路径"
|
|
86
|
+
echo " (a) 回溯到 /alloy:start 重新确认 draft"
|
|
87
|
+
echo " (b) 强制继续——下游制品将基于不可信 draft 生成(不推荐)"
|
|
88
|
+
fi
|
|
89
|
+
```
|
|
89
90
|
|
|
90
|
-
|
|
91
|
+
`_record check` 命令已存在并被 archive/apply/finish 使用,参照实现保持一致。
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
──────────────────────────────────────
|
|
93
|
+
6. **多 change 并行检查**(⚠️ WARN):扫描其他 change 是否处于 plan/apply 阶段,提示用户 plan 阶段是单 change 串行(避免 schema DAG 跨 change 干扰):
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
```bash
|
|
96
|
+
ACTIVE=$(find openspec/changes -maxdepth 2 -name '.alloy.yaml' -exec grep -l 'phase: \(started\|planned\|applied\)' {} \; 2>/dev/null | wc -l | tr -d ' ')
|
|
97
|
+
if [ "$ACTIVE" -gt 1 ]; then
|
|
98
|
+
echo "⚠️ WARN: 检测到 $ACTIVE 个活跃 change,建议串行处理"
|
|
99
|
+
fi
|
|
100
|
+
```
|
|
96
101
|
|
|
97
|
-
|
|
102
|
+
前置检查通过:draft.md ✓ phase=started ✓ git ✓ 技能 ✓ draft hash ✓
|
|
98
103
|
|
|
99
|
-
|
|
104
|
+
---
|
|
100
105
|
|
|
101
|
-
|
|
106
|
+
### [Step 1/3] 确认 Change
|
|
102
107
|
|
|
103
|
-
**制品 DAG 及依赖关系:**
|
|
104
108
|
```
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
┌──────────────────────────────────────┐
|
|
110
|
+
│ Alloy [2/5] · Phase: Plan │
|
|
111
|
+
│ 启动时间: $PHASE_START
|
|
112
|
+
└──────────────────────────────────────┘
|
|
108
113
|
```
|
|
109
114
|
|
|
110
|
-
|
|
111
|
-
|------|------|--------|
|
|
112
|
-
| proposal | draft.md | design, specs |
|
|
113
|
-
| design | proposal + draft.md | specs, tasks |
|
|
114
|
-
| specs | proposal(只读 Capabilities) | tasks |
|
|
115
|
-
| tasks | specs + design | plans |
|
|
116
|
-
| plans | tasks | — |
|
|
115
|
+
draft.md 来源已在 Step 0 完成 hash 验证(task #16)。本步聚焦 phase 校验和路由:
|
|
117
116
|
|
|
118
|
-
|
|
117
|
+
1. 阶段校验:`alloy _guard precheck openspec/changes/<name> started`(已在 Step 0 通过,本步幂等重检)
|
|
118
|
+
2. **若 phase 不匹配:** 读取 `commands/alloy/references/phase-routing.md` 自动跳转到对应 skill。
|
|
119
|
+
3. **若 change 不存在或 draft.md 缺失:** 引导 `/alloy:start <name>`——前序阶段完全没做时保留 ⛔ PRECONDITION_FAIL。
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
前置检查通过:draft.md ✓ phase=started ✓ git ✓ 技能 ✓ draft hash ✓
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
---
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
# 扫描已完成制品
|
|
126
|
-
for artifact in proposal design specs tasks plans; do
|
|
127
|
-
if alloy _record check openspec/changes/<name> "$artifact" 2>/dev/null; then
|
|
128
|
-
echo " $artifact ✓"
|
|
129
|
-
else
|
|
130
|
-
echo " $artifact ✗"
|
|
131
|
-
fi
|
|
132
|
-
done
|
|
133
|
-
```
|
|
125
|
+
### [Step 2/3] 制品生成 · /opsx:continue + writing-plans
|
|
134
126
|
|
|
135
|
-
|
|
127
|
+
**每个制品必须通过 `/opsx:continue` 生成。禁止手动编写制品文件。**
|
|
136
128
|
|
|
137
|
-
|
|
138
|
-
制品进度扫描:
|
|
139
|
-
proposal ✓ hash 有效 → 跳过
|
|
140
|
-
design ✓ hash 有效 → 跳过
|
|
141
|
-
specs ✗ → 从 specs 开始生成
|
|
129
|
+
使用 Skill 工具加载 `opsx:continue`,传入 change name。`/opsx:continue` 自动获取 schema 指令并生成制品——不要自行编写,不要一次生成多个。
|
|
142
130
|
|
|
143
|
-
|
|
131
|
+
```bash
|
|
132
|
+
alloy _skill log openspec/changes/<name> plan opsx:continue
|
|
144
133
|
```
|
|
145
134
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
**不要输出全局制品进度**(如"0/8 artifacts 完成")。[N/M] 是阶段内局部编号(M=5),不反映全局进度。全局进度由 `alloy status` 命令管理。
|
|
149
|
-
|
|
150
|
-
### 正常推进:逐个制品的审查流程
|
|
135
|
+
**制品 DAG:** `proposal → design → specs → tasks → plans`(specs 还依赖 proposal 只读 Capabilities)
|
|
151
136
|
|
|
152
|
-
|
|
137
|
+
**git add 规则(§5.2.1 内嵌约束,HARD_STOP):** 每个制品 commit 必须用精确路径(`openspec/changes/<name>/`),禁 `-A`/`-a`/`.`。违反字面 = 违反精神:哪怕"反正只改一个 markdown 文件",也禁止 `-A`——agent 看不到的副作用文件可能被一并提交。
|
|
153
138
|
|
|
154
|
-
|
|
139
|
+
**git 自救禁令(§3.5.1 内嵌约束,HARD_STOP):** 制品生成或 commit 失败时禁 `git checkout .` / `git restore .` / `git reset --hard` / `git stash` / `git clean -fd`——退出 skill 让用户处理是唯一合法路径。
|
|
155
140
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
>
|
|
162
|
-
> → 下一个:design(依赖 proposal + draft.md)
|
|
163
|
-
>
|
|
164
|
-
> → (a) 确认,锁定 proposal 并继续 design
|
|
165
|
-
> → (b) 需要调整 — 说明修改点
|
|
166
|
-
|
|
167
|
-
**制品 [2/5] design:**
|
|
141
|
+
**制品进度扫描**(调用 `/opsx:continue` 之前):
|
|
142
|
+
```bash
|
|
143
|
+
alloy _progress artifacts openspec/changes/<name>
|
|
144
|
+
```
|
|
145
|
+
从第一个缺失/hash-mismatch 的制品开始生成。全部 done 时 🔴 USER_GATE:所有制品已锁定,确认推进 phase(确认 / 重新审查某个制品——指定制品名)。
|
|
168
146
|
|
|
169
|
-
>
|
|
170
|
-
>
|
|
171
|
-
> [展示 design.md 完整内容]
|
|
172
|
-
>
|
|
173
|
-
> → 下一个:specs(依赖 proposal)
|
|
174
|
-
>
|
|
175
|
-
> → (a) 确认,锁定 design 并继续 specs
|
|
176
|
-
> → (b) 需要调整 — 说明修改点
|
|
147
|
+
> [N/M] 是阶段内局部编号(M=5),不输出全局制品进度。全局进度由 `alloy status` 管理。
|
|
177
148
|
|
|
178
|
-
|
|
149
|
+
### 逐个制品审查流程
|
|
179
150
|
|
|
180
|
-
|
|
181
|
-
>
|
|
182
|
-
> [展示 specs/ 完整内容]
|
|
183
|
-
>
|
|
184
|
-
> → 下一个:tasks(依赖 specs + design)
|
|
185
|
-
>
|
|
186
|
-
> → (a) 确认,锁定 specs 并继续 tasks
|
|
187
|
-
> → (b) 需要调整 — 说明修改点
|
|
151
|
+
**[HARD_STOP] 即使用户主动说"后面不用看了"、"一次性过完"、"效率太低了",审查窗口也不可跳过。** 5 个制品 = 5 个审查窗口——用户要求跳过不算授权。
|
|
188
152
|
|
|
189
|
-
|
|
153
|
+
每个制品生成后,展示完整内容 + 🔴 USER_GATE 审查窗口:
|
|
190
154
|
|
|
191
|
-
> 制品 [
|
|
192
|
-
>
|
|
193
|
-
>
|
|
194
|
-
>
|
|
195
|
-
> → 下一个:plans(依赖 tasks)
|
|
196
|
-
>
|
|
197
|
-
> → (a) 确认,锁定 tasks 并继续生成 plans
|
|
198
|
-
> → (b) 需要调整 — 说明修改点
|
|
155
|
+
> 制品 [N/5] \<artifact\> ✓ 完成
|
|
156
|
+
> [展示制品完整内容]
|
|
157
|
+
> 🔴 USER_GATE: 确认锁定 <artifact>(确认并继续 / 需要调整)
|
|
199
158
|
|
|
200
|
-
|
|
159
|
+
- **选 (a):** hash 锁定 + commit(详见 `commands/alloy/references/artifact-hash-commit.md`):
|
|
160
|
+
```bash
|
|
161
|
+
HASH=$(alloy _record compute openspec/changes/<name> <artifact>)
|
|
162
|
+
APPROVED_AT=$(date "+%Y-%m-%d %H:%M:%S")
|
|
163
|
+
APPROVER=$(alloy _record approver openspec/changes/<name>)
|
|
164
|
+
alloy _record write openspec/changes/<name> <artifact> "$HASH" "$APPROVED_AT" "$APPROVER"
|
|
165
|
+
# §5.2.1 git add 限路径
|
|
166
|
+
git add openspec/changes/<name>/
|
|
167
|
+
git commit -m "docs(<name>): <artifact> 已确认"
|
|
168
|
+
```
|
|
201
169
|
|
|
202
|
-
|
|
203
|
-
>
|
|
204
|
-
> [展示 plans.md 完整内容]
|
|
205
|
-
>
|
|
206
|
-
> → plan 阶段完成
|
|
207
|
-
>
|
|
208
|
-
> → (a) 确认,锁定 plans 并完成 plan 阶段
|
|
209
|
-
> → (b) 需要调整 — 说明修改点
|
|
170
|
+
生成下一制品前校验上游 hash:`alloy _record check openspec/changes/<name> <upstream>`,失败 → ⛔ PRECONDITION_FAIL(上游被破坏,必须修复后才能继续生成下游)。
|
|
210
171
|
|
|
211
|
-
|
|
172
|
+
- **选 (b):** 用户提出修改后,**先分类再行动**:
|
|
212
173
|
|
|
213
|
-
|
|
214
|
-
|
|
174
|
+
> [HARD_STOP] 分类不清前禁执行 `alloy _artifact reset`。
|
|
175
|
+
> 违反字面 = 违反精神:哪怕"看起来像措辞修正",分类不清就是分类不清——必须 USER_GATE 让用户明确。
|
|
215
176
|
|
|
216
|
-
|
|
217
|
-
> → (b) 取消变更,继续当前审查
|
|
177
|
+
- **需求变更**(功能增删、行为变更、用户主动提出"加入/删除/修改"功能)→ 🔴 USER_GATE:选择处理路径:
|
|
218
178
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
179
|
+
> AskUserQuestion: 检测到需求变更,选择处理路径
|
|
180
|
+
> (a) 回溯到 brainstorming 重新讨论(删除所有 plan 制品,保留 draft.md)
|
|
181
|
+
> (b) 取消调整,继续当前审查
|
|
182
|
+
>
|
|
183
|
+
> 注意:选 (a) 会自动打 snapshot tag `rollback-<name>-<timestamp>`,
|
|
184
|
+
> 事后可用 `git checkout <tag> -- openspec/changes/<name>/` 恢复(task #15)。
|
|
222
185
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
用户选 (b) → 回到当前审查窗口,重新展示 (a) 确认 / (b) 需要调整 选项。
|
|
186
|
+
选 (a):执行回溯清理(详见 `commands/alloy/references/plan-rollback.md`),然后加载 `superpowers:brainstorming` 重新讨论。**此类场景禁止使用 `alloy _artifact reset`。**
|
|
187
|
+
选 (b):回到审查窗口,重新展示制品内容。
|
|
226
188
|
|
|
227
|
-
|
|
228
|
-
- 只问了一句"看起来可以吗?"没有展示实际内容
|
|
229
|
-
- 用户说"继续"但没有明确说"确认"
|
|
230
|
-
- 用户不明确表态时催促用户给出 (a) 或 (b)
|
|
189
|
+
- **轻量修正**(措辞/格式,不改变功能边界)→ 🔴 USER_GATE:确认走轻量修正路径(仅限用户明确说"措辞/格式调整")。确认后:`alloy _artifact reset openspec/changes/<name> <artifact>` → `/opsx:continue` 重新生成 → **diff 审查窗口(见下方"轻量修正 diff USER_GATE")** → 重新审查。下游已锁定制品保持不变。
|
|
231
190
|
|
|
232
|
-
|
|
191
|
+
**判断规则:** 用户主动提出"加入/删除/修改功能"= 需求变更,直接回溯,不问路径。只有用户明确说"措辞/格式调整"才走轻量修正(且需 🔴 USER_GATE 确认)。不确定时默认需求变更。
|
|
233
192
|
|
|
234
|
-
|
|
193
|
+
**无论哪条路径,都不直接编辑已生成的制品文件**(违反字面 = 违反精神:制品禁直接编辑)。
|
|
235
194
|
|
|
236
|
-
|
|
237
|
-
```bash
|
|
238
|
-
alloy _skill log openspec/changes/<name> plan opsx:continue
|
|
239
|
-
```
|
|
195
|
+
**轻量修正 diff USER_GATE(HARD_STOP,task L3):** reset + 重新生成后、重新审查前,必须采集 diff 并让用户物理确认——agent 不得基于 `/opsx:continue` 返回成功直接进入审查窗口。
|
|
240
196
|
|
|
241
197
|
```bash
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
alloy _record write openspec/changes/<name> <artifact> "$HASH" "$APPROVED_AT" "$APPROVER"
|
|
246
|
-
git add openspec/changes/<name>/
|
|
247
|
-
git commit -m "docs(<name>): <artifact> 已确认"
|
|
198
|
+
# 重新生成后,先 diff 再审查
|
|
199
|
+
DIFF_OLD=$(git show HEAD:"openspec/changes/<name>/<artifact>.md" 2>/dev/null)
|
|
200
|
+
DIFF_NEW=$(cat "openspec/changes/<name>/<artifact>.md" 2>/dev/null)
|
|
248
201
|
```
|
|
249
202
|
|
|
250
|
-
|
|
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
|
-
```
|
|
203
|
+
🔴 USER_GATE(必须 AskUserQuestion):
|
|
263
204
|
|
|
264
|
-
|
|
205
|
+
> 轻量修正 diff:
|
|
206
|
+
> ```
|
|
207
|
+
> [git diff HEAD -- openspec/changes/<name>/<artifact>.md | head -100]
|
|
208
|
+
> ```
|
|
209
|
+
> 确认变更仅涉及措辞/格式(不改变功能边界):
|
|
210
|
+
> (a) 确认——仅措辞/格式,继续锁 hash
|
|
211
|
+
> (b) 发现功能变更——放弃轻量修正,回到需求变更路径重新分类
|
|
212
|
+
> (c) 放弃调整——回退到 reset 前状态(`git checkout HEAD -- openspec/changes/<name>/<artifact>.md`)
|
|
265
213
|
|
|
266
|
-
|
|
267
|
-
```bash
|
|
268
|
-
alloy _record check openspec/changes/<name> <upstream-artifact>
|
|
269
|
-
```
|
|
270
|
-
若 check 返回非零 → HARD STOP,hash 不匹配意味着有未审批的篡改。
|
|
214
|
+
**[HARD_STOP]** agent 不得基于 "diff 看起来没改功能" 自动选 (a)——必须用户物理选择(interaction-style.md "沉默 ≠ 授权")。diff 必须截前 100 行防爆量,但禁 agent 基于 "diff 短" 跳过调用。(违反字面 = 违反精神:制品禁直接编辑)。
|
|
271
215
|
|
|
272
|
-
|
|
273
|
-
|--------------|------------|
|
|
274
|
-
| design | proposal |
|
|
275
|
-
| specs | proposal |
|
|
276
|
-
| tasks | specs, design |
|
|
277
|
-
| plans | tasks |
|
|
216
|
+
**审查窗口只展示制品内容,不打印 schema instructions 模板。**
|
|
278
217
|
|
|
279
|
-
### tasks
|
|
218
|
+
### tasks 审批后 → writing-plans
|
|
280
219
|
|
|
281
|
-
tasks 审批通过并 commit
|
|
220
|
+
tasks 审批通过并 commit 后,加载 `superpowers:writing-plans` 生成 plans.md:
|
|
282
221
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
> alloy 不在 plan 阶段额外询问策略选择——writing-plans 的决策直接保留在 frontmatter 中,apply 阶段再读取并给用户确认。
|
|
222
|
+
- 传入 tasks + specs + design 作为上下文
|
|
223
|
+
- **遵循 writing-plans 完整原始流程**——从任务拆解到执行交接
|
|
224
|
+
- 保存路径:`openspec/changes/<name>/plans.md`(非默认的 `docs/superpowers/plans/`)
|
|
225
|
+
- writing-plans 自行决定执行策略,写入 frontmatter(`strategy` + `reason`)
|
|
288
226
|
|
|
289
|
-
**技能加载后立即记录:**
|
|
290
227
|
```bash
|
|
291
228
|
alloy _skill log openspec/changes/<name> plan superpowers:writing-plans
|
|
292
229
|
```
|
|
293
230
|
|
|
294
|
-
|
|
295
|
-
|
|
231
|
+
plans.md frontmatter 格式:
|
|
296
232
|
```yaml
|
|
297
233
|
---
|
|
298
234
|
strategy: sdd
|
|
299
235
|
reason: <writing-plans 执行交接环节的策略分析理由>
|
|
300
236
|
---
|
|
301
|
-
# 执行计划
|
|
302
|
-
...
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
plans.md 生成后展示审查窗口,审批通过后先写入 phase_timings.completed_at,再 hash 锁定并 commit(phase_timings 作为元数据附着在 plans 制品提交上,不单独 commit)。
|
|
306
|
-
|
|
307
|
-
### 回溯修改:修改已确认的上游制品
|
|
308
|
-
|
|
309
|
-
plan 阶段处理的是"构建什么"——任何制品一旦审批通过,不允许就地修改。需求/设计层面的调整都应从 draft 根重新审视,而非打补丁。
|
|
310
|
-
|
|
311
|
-
**规则——统一回到 brainstorming:**
|
|
312
|
-
|
|
313
|
-
| 要修改的制品 | 行为 |
|
|
314
|
-
|------------|------|
|
|
315
|
-
| draft / proposal / design / specs / tasks / plans | 清理 plan 制品 → 回到 brainstorming |
|
|
316
|
-
|
|
317
|
-
> apply 阶段的需求变更见 apply.md 的"需求变更处理"闸门——以 tasks.md checkbox 状态判断是否允许回溯。verify/retrospective 验证"代码是否匹配规格",发现问题修正代码,不改变需求/设计。
|
|
318
|
-
|
|
319
|
-
**回溯清理步骤:**
|
|
320
|
-
|
|
321
|
-
```bash
|
|
322
|
-
# 1. 删除 plan 制品文件(保留 draft.md)
|
|
323
|
-
rm -f openspec/changes/<name>/proposal.md
|
|
324
|
-
rm -f openspec/changes/<name>/design.md
|
|
325
|
-
rm -f openspec/changes/<name>/tasks.md
|
|
326
|
-
rm -f openspec/changes/<name>/plans.md
|
|
327
|
-
rm -rf openspec/changes/<name>/specs/
|
|
328
|
-
|
|
329
|
-
# 2. 清理 records(只保留 draft)
|
|
330
|
-
DRAFT_RECORD=$(alloy _state read openspec/changes/<name> records | python3 -c "
|
|
331
|
-
import sys,json
|
|
332
|
-
content = sys.stdin.read().strip()
|
|
333
|
-
records = json.loads(content) if content and content != 'null' else []
|
|
334
|
-
draft = [r for r in records if r.get('artifact') == 'draft']
|
|
335
|
-
print(json.dumps(draft))
|
|
336
|
-
")
|
|
337
|
-
alloy _state write openspec/changes/<name> records "$DRAFT_RECORD"
|
|
338
|
-
|
|
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。
|
|
342
|
-
TIMINGS=$(alloy _state read openspec/changes/<name> phase_timings 2>/dev/null || echo "{}")
|
|
343
|
-
echo "$TIMINGS" | python3 -c "
|
|
344
|
-
import sys,json
|
|
345
|
-
content = sys.stdin.read().strip()
|
|
346
|
-
d = json.loads(content) if content and content != 'null' else {}
|
|
347
|
-
for k in ['plan','apply','archive','finish']:
|
|
348
|
-
d.pop(k, None)
|
|
349
|
-
if 'start' in d:
|
|
350
|
-
d['start']['completed_at'] = None
|
|
351
|
-
print(json.dumps(d))
|
|
352
|
-
" | while read -r val; do alloy _state write openspec/changes/<name> phase_timings "$val"; done
|
|
353
|
-
|
|
354
|
-
git add openspec/changes/<name>/
|
|
355
|
-
git commit -m "chore(<name>): 回溯——清理 plan 制品,回到 brainstorming"
|
|
356
237
|
```
|
|
357
238
|
|
|
358
|
-
|
|
359
|
-
→ 制品已清理(仅保留 draft),records/phase_timings 已重置
|
|
360
|
-
→ 请运行 /alloy:start <name> 重新走需求确认流程
|
|
361
|
-
```
|
|
239
|
+
plans 审批通过后,phase_timings + hash-lock 合并为**一个 commit**(详见 `commands/alloy/references/artifact-hash-commit.md`"阶段最后一个制品"部分)。
|
|
362
240
|
|
|
363
241
|
---
|
|
364
242
|
|
|
365
243
|
### [Step 3/3] 完成
|
|
366
244
|
|
|
367
|
-
先读取所有 record 的时间戳用于汇总展示:
|
|
368
245
|
```bash
|
|
369
246
|
alloy _state read openspec/changes/<name> records
|
|
370
247
|
```
|
|
@@ -372,51 +249,77 @@ alloy _state read openspec/changes/<name> records
|
|
|
372
249
|
```
|
|
373
250
|
┌──────────────────────────────────────┐
|
|
374
251
|
│ Alloy [2/5] · Phase: Plan — DONE │
|
|
375
|
-
│ 启动时间:
|
|
376
|
-
│ 完成时间:
|
|
377
|
-
│ 耗时: completed_at - started_at
|
|
252
|
+
│ 启动时间: phase_timings.plan.started_at
|
|
253
|
+
│ 完成时间: phase_timings.plan.completed_at
|
|
254
|
+
│ 耗时: completed_at - started_at
|
|
378
255
|
└──────────────────────────────────────┘
|
|
379
256
|
|
|
380
|
-
→ Change: <name>
|
|
381
|
-
→
|
|
257
|
+
→ Change: <name> Phase: planned
|
|
258
|
+
→ 制品: draft ✓ proposal ✓ design ✓ specs ✓ tasks ✓ plans ✓
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**hash 链尾扫(⛔ HARD_STOP,task L2):** 在 phase 推进前对全部 6 个制品(draft + proposal + design + specs + tasks + plans)逐条执行 `alloy _record check`——这是 phase 锁定前最后一次完整性校验,任何 hash 不匹配都必须暴露给用户。
|
|
382
262
|
|
|
383
|
-
|
|
263
|
+
```bash
|
|
264
|
+
ALL_PASS=true
|
|
265
|
+
for ARTIFACT in draft proposal design specs tasks plans; do
|
|
266
|
+
if [ ! -f "openspec/changes/<name>/${ARTIFACT}.md" ]; then
|
|
267
|
+
echo " ✗ $ARTIFACT: 文件缺失"
|
|
268
|
+
ALL_PASS=false
|
|
269
|
+
elif alloy _record check "openspec/changes/<name>" "$ARTIFACT" 2>/dev/null; then
|
|
270
|
+
echo " ✓ $ARTIFACT: hash 一致"
|
|
271
|
+
else
|
|
272
|
+
echo " ✗ $ARTIFACT: hash 不匹配"
|
|
273
|
+
ALL_PASS=false
|
|
274
|
+
fi
|
|
275
|
+
done
|
|
384
276
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
277
|
+
echo "---"
|
|
278
|
+
if [ "$ALL_PASS" = "true" ]; then
|
|
279
|
+
echo "✓ 全部 6 个制品 hash 链完整"
|
|
280
|
+
else
|
|
281
|
+
echo "⛔ HARD_STOP: hash 链断裂,禁止推进 phase"
|
|
282
|
+
echo " 制品文件被编辑后 hash 重算可能在单制品审查中漏过,"
|
|
283
|
+
echo " 尾扫是最后一道防线——必须逐条检查全部制品。"
|
|
284
|
+
echo ""
|
|
285
|
+
echo " 禁止:agent 自动补 _record write 修复 hash——"
|
|
286
|
+
echo " 必须 🔴 USER_GATE 让用户选择处理路径。"
|
|
287
|
+
exit 1
|
|
288
|
+
fi
|
|
393
289
|
```
|
|
394
290
|
|
|
395
|
-
|
|
291
|
+
`$ALL_PASS` = false → ⛔ HARD_STOP,🔴 USER_GATE:
|
|
292
|
+
- (a) 回溯到对应制品重新审查(显示哪个制品 hash 不匹配,让用户决定回退到哪个制品重新生成)
|
|
293
|
+
- (b) 显示 git log 让用户排查(`git log --oneline openspec/changes/<name>/`)
|
|
294
|
+
- (c) 中止 plan 阶段退出 skill
|
|
396
295
|
|
|
397
|
-
|
|
296
|
+
**[HARD_STOP]** agent 不得基于 "_guard 也会校验" 跳过尾扫——_guard 校验与尾扫是独立防线,尾扫逐条命名文件确保"全量 6/6",_guard 内部实现可能只校验 records 中存在的条目(文件存但 records 不存的 tainted artifact 会漏掉)。
|
|
398
297
|
|
|
298
|
+
**记录完成时间并推进 phase:**
|
|
399
299
|
```bash
|
|
300
|
+
COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
|
|
301
|
+
alloy _state merge openspec/changes/<name> phase_timings "{\"plan\":{\"completed_at\":\"${COMPLETED_AT:-$(date '+%Y-%m-%d %H:%M:%S')}\"}}"
|
|
400
302
|
alloy _guard openspec/changes/<name> planned --apply
|
|
303
|
+
git add openspec/changes/<name>/
|
|
304
|
+
git commit -m "chore(<name>): 记录 plan 阶段完成时间,推进到 planned"
|
|
401
305
|
```
|
|
402
306
|
|
|
403
|
-
|
|
307
|
+
`_guard` 校验 hash 一致性后推进 phase。返回非零时检查缺哪个制品或 hash 不匹配。
|
|
404
308
|
|
|
405
|
-
|
|
406
|
-
制品文件禁止手动修改。如需变更,回到 brainstorming 在当前 change 内重新讨论。
|
|
309
|
+
**§5.2.3 路径 B 降级(HARD_STOP):** 如果 guard --apply 推进 phase 成功,但后续命令意外失败(不可恢复状态),**禁 agent 运行 `git reset --hard` / `git checkout .` 清场**。降级路径:
|
|
407
310
|
|
|
408
|
-
|
|
311
|
+
```bash
|
|
312
|
+
# 手动回退 phase(仅限用户确认后执行)
|
|
313
|
+
alloy _state set openspec/changes/<name> phase started
|
|
314
|
+
# 不要 reset 已 commit 的制品——hash 链保留,用户可重入 plan 阶段决定下一步
|
|
409
315
|
```
|
|
410
316
|
|
|
411
|
-
|
|
317
|
+
违反字面 = 违反精神:哪怕"只是为了让流程干净",也禁 reset 清场——制品 hash 链是用户的工作记录。
|
|
318
|
+
|
|
319
|
+
**plans 完成后不要自动进入 apply** — 给用户空间审视完整规划。
|
|
412
320
|
|
|
413
|
-
|
|
321
|
+
```
|
|
322
|
+
制品文件禁止手动修改。如需变更,回到 brainstorming 在当前 change 内重新讨论。
|
|
323
|
+
准备好后,运行 /alloy:apply 进入执行阶段。
|
|
324
|
+
```
|
|
414
325
|
|
|
415
|
-
- **git add 只用精确路径** — 永远不用 `-A`、`-a`、`.`。
|
|
416
|
-
反例:`git add .` 或 `git commit -am "fix"` 会把 `todo.py`、`tasks.json` 等意外文件一起提交
|
|
417
|
-
- **始终分步,不提供一键生成** —— 每个制品必须单独审查确认后才能继续。跳过审查等于跳过需求验证,后期返工代价远大于审查时间
|
|
418
|
-
- **每制品审批后必须 hash 锁定 + commit** —— 不可篡改追踪,确保审计链完整
|
|
419
|
-
- **制品生成完成后必须通过 alloy _guard 校验** —— 脚本检查 started→planned 转换的合法性及 hash 一致性
|
|
420
|
-
- **plans 完成后不要自动进入 apply** —— 给用户空间审视完整规划
|
|
421
|
-
- **plan 阶段调整统一回 brainstorming** —— 需求/设计层面的任何变更从 draft 根重新审视,不做就地修补。typo/措辞修正除外。apply 阶段的 verify/retrospective 只修代码不改规格
|
|
422
|
-
- **不输出全局制品进度** — [N/M] 是阶段内局部编号(M=5),不要输出"N/8 artifacts 完成"。全局进度由 `alloy status` 管理
|