@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/finish.md
CHANGED
|
@@ -3,41 +3,62 @@ name: "Alloy: Finish"
|
|
|
3
3
|
description: Alloy 收尾阶段 - archive 完成后进入
|
|
4
4
|
category: Workflow
|
|
5
5
|
tags: [alloy, workflow]
|
|
6
|
+
spec: 01-product-spec/05-finish-spec.md
|
|
7
|
+
behaviors:
|
|
8
|
+
preconditions: 5
|
|
9
|
+
hard_stops: 8
|
|
10
|
+
user_gates: 5
|
|
11
|
+
warns: 2
|
|
12
|
+
artifacts: []
|
|
13
|
+
transitions_to: finished
|
|
14
|
+
external_calls: [superpowers:finishing-a-development-branch]
|
|
6
15
|
---
|
|
7
16
|
|
|
8
17
|
# alloy-finish
|
|
9
18
|
|
|
10
|
-
你是 Alloy
|
|
19
|
+
你是 Alloy 的收尾命令。spec 已归档(phase=archived)前提下,完成代码合入与现场清理,推进 phase 到 `finished`。
|
|
11
20
|
|
|
12
|
-
|
|
21
|
+
```
|
|
22
|
+
[HARD_STOP] NO MERGE WITHOUT EXACT CONFIRMATION
|
|
23
|
+
phase != archived / 分支不存在 / merge 精确确认未通过 / spec 已归档需修改 / merge 冲突自动 abort 任一存在 = 拒绝执行
|
|
24
|
+
违反字面 = 违反精神:哪怕"用户口头同意了"、"用户说'可以,合吧'"、"merge 冲突很简单 abort 一下",也算违反 Iron Law。精确字符串确认不可被任何形式的口头同意替代——用户说"合"不算确认,必须亲手输入 merge 指令。
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**核心原则:只做代码合入,不碰 spec。** spec 已归档封存,任何 spec 级变更应走新 change([HARD_STOP])。
|
|
28
|
+
|
|
29
|
+
**交互规则:** `🔴 STOP` 等价 `USER_GATE`,必须用 `AskUserQuestion`(`commands/alloy/references/interaction-style.md`,含"沉默 ≠ 授权"通用禁令——禁批量打包、禁基于内容跳过、禁 agent 回填精确字符串)。跳过任何 USER_GATE = 违反 Iron Law。
|
|
13
30
|
|
|
14
|
-
|
|
31
|
+
**状态符号:** `⛔` = HARD_STOP / PRECONDITION_FAIL,`🔴` = USER_GATE,`⚠️` = WARN(视觉规范 §七)。
|
|
15
32
|
|
|
16
|
-
|
|
33
|
+
**调用外部命令或技能前,先输出标题和状态描述,再执行操作。**
|
|
34
|
+
|
|
35
|
+
**捕获阶段启动时间**(幂等,重入时返回已有值)。
|
|
36
|
+
|
|
37
|
+
> 先解析 archive 路径再调用 `timestamp ensure`——archive 阶段已将 change 移入 `archive/`,
|
|
38
|
+
> `openspec/changes/<name>/` 为空目录,直接调用会误创建残留 `.alloy.yaml`。
|
|
17
39
|
|
|
18
|
-
**捕获阶段启动时间**(命令调用后第一时间,前置检查之前,幂等——重入时返回已有值):
|
|
19
40
|
```bash
|
|
20
|
-
|
|
41
|
+
ARCHIVE_DIR=$(ls -d openspec/changes/archive/*-<name> 2>/dev/null | sort -r | head -1)
|
|
42
|
+
CHANGE_DIR="${ARCHIVE_DIR:-openspec/changes/<name>}"
|
|
43
|
+
PHASE_START=$(alloy _state timestamp ensure "$CHANGE_DIR" finish)
|
|
21
44
|
```
|
|
22
45
|
|
|
23
46
|
---
|
|
24
47
|
|
|
25
|
-
|
|
26
|
-
- phase 不是 archived 时调 finish——"反正就合个代码"——跳过了 archive,spec 没有同步
|
|
27
|
-
- 分支已 merge 或删除后重复调 finish——浪费操作,应该直接告知用户无需再次 finish
|
|
28
|
-
- finish 过程中试图修改 spec——spec 已归档,任何 spec 级变更应走新 change
|
|
29
|
-
|
|
30
|
-
### Red Flags——STOP,不要继续
|
|
31
|
-
|
|
32
|
-
以下任何一个念头出现,都意味着闸门正在被绕过:
|
|
48
|
+
### Red Flags(第三层防御——任一借口出现即 STOP)
|
|
33
49
|
|
|
34
50
|
| 借口 | 现实 |
|
|
35
51
|
|------|------|
|
|
36
|
-
| "phase 不是 archived
|
|
37
|
-
| "分支已经删了,finish 白跑了" |
|
|
38
|
-
| "PR 审查说要改 spec
|
|
39
|
-
| "选'保持分支'
|
|
40
|
-
| "
|
|
52
|
+
| "phase 不是 archived,但代码都写好了,直接合吧" | archive 不可跳过——spec 归档和代码合入是两件事,顺序不可颠倒。 |
|
|
53
|
+
| "分支已经删了,finish 白跑了" | 分支不存在 = 无需再次 finish,直接告知用户。 |
|
|
54
|
+
| "PR 审查说要改 spec,顺手改了吧" | spec 已归档封存。任何 spec 变更 = 新 change。 |
|
|
55
|
+
| "选'保持分支'等于没做完,直接 merge 吧" | 保持分支是合法选项——用户可能有后续计划。替用户选 merge 是越权。 |
|
|
56
|
+
| "用户说了 'y',应该等于 merge 确认吧" | 精确字符串确认不可被口头同意替代。"y"/"好"/"可以"/"合吧"全部不算(§Iron Law)。即使用户说"我同意了,直接合",也不算确认——必须亲手输入 merge 指令。 |
|
|
57
|
+
| "git pull 失败一次,重试一下静默继续" | pull 失败 = 远端状态未知,silent 继续 = 基于过期 main 做 squash,污染主分支历史。必须 USER_GATE。 |
|
|
58
|
+
| "merge --squash 冲突了,git merge --abort 让流程重启" | abort = 撕毁现场,用户的 in-progress 工作消失。退出 skill 让用户处理是唯一合法路径(§3.5.1)。 |
|
|
59
|
+
| "feature_branch 看起来像 main,应该没事" | branch -D 变量未替换或与主分支同名 = 强删主分支引用,灾难性。必须 PRECONDITION_FAIL(task #25)。 |
|
|
60
|
+
| "另一个 change 也在 finish,并行做完更快" | 多 change 并行 finish = squash 顺序与 archive 顺序错配,主分支提交历史错乱。必须串行(task #14)。 |
|
|
61
|
+
| "phase 已经推进到 finished 了,merge 失败让用户自己回退太麻烦" | 推进早于不可逆操作 + 失败 → 用户手动按 §5.2.3 路径 B 回退 phase。agent 不得自动 reset --hard 清场(§3.5.1)。 |
|
|
41
62
|
|
|
42
63
|
---
|
|
43
64
|
|
|
@@ -52,111 +73,154 @@ PHASE_START=$(alloy _state timestamp ensure openspec/changes/<name> finish)
|
|
|
52
73
|
|
|
53
74
|
### [Step 1/3] 前置检查
|
|
54
75
|
|
|
55
|
-
|
|
56
|
-
skill: finishing-a-development-branch
|
|
76
|
+
> finish 仅操作 `feature_branch`。worktree-branch 已在 archive 阶段合入 feature_branch 并清理;finish 看不到 worktree-branch,也不应再去找它(task #26 注释)。
|
|
57
77
|
|
|
58
|
-
|
|
78
|
+
**0. Skill 预检(PRECONDITION_FAIL):** skill: finishing-a-development-branch
|
|
59
79
|
|
|
60
|
-
|
|
80
|
+
读取 `commands/alloy/references/skill-precheck.md` 检测。不可用 → 输出 `⛔ PRECONDITION_FAIL: skill 缺失`,引导 `alloy init` 后退出。**不存在降级处理**——agent 不得自行模拟 finishing-a-development-branch 行为。
|
|
61
81
|
|
|
62
|
-
**phase
|
|
63
|
-
|
|
64
|
-
通过 `alloy _guard` 校验:
|
|
82
|
+
**1. phase 检查(PRECONDITION_FAIL):**
|
|
65
83
|
```bash
|
|
66
|
-
alloy _guard openspec/changes/<name>
|
|
84
|
+
alloy _guard precheck openspec/changes/<name> archived
|
|
67
85
|
```
|
|
86
|
+
不匹配时读取 `commands/alloy/references/phase-routing.md` 自动跳转。phase 必须 = archived,否则 `⛔ PRECONDITION_FAIL`。
|
|
68
87
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
**HARD STOP 保留场景:** 分支不存在(可能已 merge 或删除)→ 提示无需再次 finish。
|
|
72
|
-
|
|
73
|
-
确认当前有对应的 git 分支存在:
|
|
88
|
+
**2. 分支存在检查(PRECONDITION_FAIL):**
|
|
74
89
|
```bash
|
|
75
90
|
git branch --list <feature_branch>
|
|
76
91
|
```
|
|
77
|
-
|
|
92
|
+
返回空 → 输出 `⛔ PRECONDITION_FAIL: 分支已 merge 或删除,无需再次 finish。` 然后退出 skill。**禁止 agent 自动从 reflog 恢复或猜测分支名**(§3.5.1)。
|
|
93
|
+
|
|
94
|
+
**3. 主分支读取(USER_GATE):** `alloy _config read . main_branch`,未配置时读取 `commands/alloy/references/main-branch-detection.md` 检测后 🔴 USER_GATE 确认主分支后写入。
|
|
78
95
|
|
|
79
|
-
|
|
96
|
+
**4. 多 change 并行检查(WARN,task #14):**
|
|
80
97
|
```bash
|
|
81
|
-
alloy
|
|
98
|
+
alloy status --json 2>/dev/null | grep -c '"phase":"archived"' || true
|
|
82
99
|
```
|
|
83
|
-
|
|
100
|
+
|
|
101
|
+
返回 > 1 → 输出:
|
|
102
|
+
> ⚠️ WARN: 检测到多个 change 处于 phase=archived 状态。多个 change 并行 finish 会导致 squash merge 顺序与 archive 顺序错配,建议串行处理。当前 change:`<name>`,其他 archived change 列表见 `alloy status`。继续?
|
|
103
|
+
|
|
104
|
+
WARN 不阻断流程,但提醒用户人工确认顺序后再继续。
|
|
105
|
+
|
|
106
|
+
**5. Retrospective 离场审查(🔴 USER_GATE,task L7):** merge 前最后一道审查窗口——retrospective 中的 §5 意外发现可能包含"应开新 change 的技术债"或"边界 case 发现"等影响合入决策的信息。
|
|
107
|
+
|
|
108
|
+
读取 retrospective.md(路径与 phase 推进取 CHANGE_DIR 一致):
|
|
109
|
+
|
|
84
110
|
```bash
|
|
85
|
-
|
|
111
|
+
ARCHIVE_DIR=$(ls -d openspec/changes/archive/*-<name> 2>/dev/null | sort -r | head -1)
|
|
112
|
+
CHANGE_DIR="${ARCHIVE_DIR:-openspec/changes/<name>}"
|
|
113
|
+
RETRO_FILE="${CHANGE_DIR}/retrospective.md"
|
|
86
114
|
```
|
|
87
115
|
|
|
116
|
+
`$RETRO_FILE` 存在 → 🔴 USER_GATE(必须 AskUserQuestion):
|
|
117
|
+
|
|
118
|
+
> 离场审查:retrospective 关键发现
|
|
119
|
+
>
|
|
120
|
+
> [展示 retrospective.md §5 意外发现全文,以及 §4 技能跳过模式(如有)]
|
|
121
|
+
>
|
|
122
|
+
> §6 Promote Candidates 已在 archive 阶段处理(写入 memory / 跳过记录)。
|
|
123
|
+
>
|
|
124
|
+
> 以上发现是否影响合入决策?
|
|
125
|
+
> (a) 不影响——确认合入,进入 Step 2
|
|
126
|
+
> (b) 有影响——记录待处理项后继续(不影响本次合入,但标注后续 new change)
|
|
127
|
+
> (c) 需要讨论——退出 finish,先处理 retrospective 发现再决定
|
|
128
|
+
|
|
129
|
+
**[HARD_STOP]** agent 不得基于 "retrospective 已在 archive 审过" 跳过此 USER_GATE——archive 审查的是"是否写入 memory",finish 审查的是"是否影响合入决策",两件事不同。
|
|
130
|
+
|
|
131
|
+
`$RETRO_FILE` 不存在 → 跳过本步骤(无 retrospective = 无离场审查内容)。
|
|
132
|
+
|
|
88
133
|
---
|
|
89
134
|
|
|
90
135
|
## 执行
|
|
91
136
|
|
|
92
137
|
### [Step 2/3] superpowers:finishing-a-development-branch
|
|
93
138
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
> 2. 创建 PR —— 提交代码审查
|
|
101
|
-
> 3. 保持分支 —— 暂不处理
|
|
139
|
+
```
|
|
140
|
+
选择处理方式:
|
|
141
|
+
1. 本地 merge —— 合入基础分支
|
|
142
|
+
2. 创建 PR —— 提交代码审查
|
|
143
|
+
3. 保持分支 —— 暂不处理
|
|
144
|
+
```
|
|
102
145
|
|
|
103
|
-
|
|
146
|
+
加载 `superpowers:finishing-a-development-branch` 技能,传入:
|
|
104
147
|
```
|
|
105
148
|
Change: <name>
|
|
106
149
|
状态:phase=archived(spec 已归档,代码待合入)
|
|
107
150
|
当前分支:<feature_branch>
|
|
108
|
-
基础分支:<main_branch
|
|
151
|
+
基础分支:<main_branch>
|
|
109
152
|
```
|
|
110
153
|
|
|
111
|
-
**技能加载后立即记录:**
|
|
112
154
|
```bash
|
|
113
155
|
alloy _skill log openspec/changes/<name> finish superpowers:finishing-a-development-branch
|
|
114
156
|
```
|
|
115
157
|
|
|
116
|
-
|
|
158
|
+
### 选项 1:本地合并(squash)
|
|
117
159
|
|
|
118
|
-
|
|
160
|
+
> [HARD_STOP] 选项 1 的不可逆操作链:phase 推进 → git checkout main → git pull → squash merge → branch -D。
|
|
161
|
+
> 任一步失败时严禁 agent 自动 reset --hard / checkout . / stash drop 清场。
|
|
162
|
+
> 违反字面 = 违反精神:哪怕"先回到干净状态再重试",也算违反 §3.5.1 禁令——必须 USER_GATE 让用户决策。
|
|
119
163
|
|
|
120
|
-
|
|
164
|
+
**合并确认(USER_GATE,精确字符串):**
|
|
121
165
|
|
|
122
|
-
|
|
166
|
+
**[HARD_STOP] 即使用户说"我同意了"、"可以,合吧"、"口头确认过",也不算确认。** 精确字符串不可被任何形式的口头同意替代——用户必须亲手输入 `merge <branch> into <branch>`。
|
|
123
167
|
|
|
124
|
-
>
|
|
125
|
-
> ──────────────────────────────────────
|
|
126
|
-
>
|
|
127
|
-
> 即将执行本地合并:
|
|
128
|
-
>
|
|
129
|
-
> 源分支:<feature_branch>
|
|
130
|
-
> 目标分支:<main_branch>
|
|
131
|
-
>
|
|
168
|
+
> 🔴 USER_GATE: 确认合并:源 `<feature_branch>` → 目标 `<main_branch>`
|
|
132
169
|
> 即将合入的提交:
|
|
133
170
|
> ```
|
|
134
|
-
> <git log main_branch..feature_branch --oneline
|
|
171
|
+
> <git log main_branch..feature_branch --oneline>
|
|
135
172
|
> ```
|
|
173
|
+
> 合并后 worktree 清理,分支删除。
|
|
174
|
+
> 输入 `merge <feature_branch> into <main_branch>` 确认,其他输入取消。
|
|
136
175
|
>
|
|
137
|
-
>
|
|
138
|
-
>
|
|
139
|
-
> 输入 merge <feature_branch> into <main_branch> 确认,或输入其他内容取消。
|
|
140
|
-
|
|
141
|
-
**必须等待用户精确输入确认语句。** "好"、"可以"、"y" 都不算确认。
|
|
176
|
+
> 违反字面 = 违反精神:"y" / "好" / "可以" / "ok" 全部不算确认(§Iron Law)。
|
|
142
177
|
|
|
143
|
-
|
|
178
|
+
确认后执行:
|
|
144
179
|
```bash
|
|
145
|
-
# 确定归档路径(archive 阶段已将目录移至 archive/ 下)
|
|
146
180
|
ARCHIVE_DIR=$(ls -d openspec/changes/archive/*-<name> 2>/dev/null | sort -r | head -1)
|
|
147
181
|
CHANGE_DIR="${ARCHIVE_DIR:-openspec/changes/<name>}"
|
|
148
182
|
|
|
149
|
-
# 记录完成时间 + 推进 phase
|
|
183
|
+
# 记录完成时间 + 推进 phase(在 squash merge 之前——§5.2.3 路径 B)
|
|
184
|
+
# [HARD_STOP] phase 推进早于不可逆操作(squash merge / branch -D),失败时必须有降级路径:
|
|
185
|
+
# - 若 squash merge 后续步骤失败 → 用户须手动回滚 phase:
|
|
186
|
+
# alloy _state set "$CHANGE_DIR" phase archived
|
|
187
|
+
# git checkout HEAD~1 -- "$CHANGE_DIR/.alloy.yaml" # 撤销 phase commit 中的状态变更
|
|
188
|
+
# git reset HEAD~1 # 退回 phase commit
|
|
189
|
+
# - 禁止 agent 自动运行 git reset --hard / git checkout . 清场(详见 §3.5.1)。
|
|
190
|
+
# 详见 docs/reference/alloy-skill-writing-guide.md §5.2.3 路径 B
|
|
150
191
|
COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
|
|
151
192
|
alloy _state merge "$CHANGE_DIR" phase_timings "{\"finish\":{\"completed_at\":\"${COMPLETED_AT:-$(date '+%Y-%m-%d %H:%M:%S')}\"}}"
|
|
152
193
|
alloy _guard "$CHANGE_DIR" finished --apply
|
|
153
|
-
git add
|
|
194
|
+
git add "$CHANGE_DIR" openspec/config.yaml
|
|
154
195
|
git commit -m "chore(<name>): 记录 finish 阶段完成时间"
|
|
155
196
|
|
|
156
197
|
git checkout <main_branch>
|
|
157
|
-
|
|
198
|
+
|
|
199
|
+
# [HARD_STOP] git pull 失败时禁止自动忽略——基于过期 main 做 squash 会污染主分支历史。
|
|
200
|
+
# 禁止 agent 在 pull 失败时运行 git reset --hard / git checkout . / git stash 任何一个。
|
|
201
|
+
# 详见 docs/reference/skill-writing-guide.md §3.5.1
|
|
202
|
+
if ! git pull --ff-only; then
|
|
203
|
+
echo "[PRECONDITION_FAIL] git pull 失败——squash merge 不能基于过期 main"
|
|
204
|
+
echo ""
|
|
205
|
+
echo " 失败原因可能:远端无法访问 / 本地 main 偏离 / 凭证过期"
|
|
206
|
+
echo ""
|
|
207
|
+
echo " 🔴 USER_GATE: 选择处理方式"
|
|
208
|
+
echo " (a) 重试——用户手动修复后再次运行 /alloy:finish"
|
|
209
|
+
echo " (b) 跳过 pull 直接 squash(仅当用户确认 main 已是最新——风险自负)"
|
|
210
|
+
echo " (c) 中止 finish——保持当前分支,回退 phase:"
|
|
211
|
+
echo " alloy _state set \"$CHANGE_DIR\" phase archived"
|
|
212
|
+
echo ""
|
|
213
|
+
echo " 禁止:agent 自动运行 git reset --hard origin/<main_branch> 强制对齐。"
|
|
214
|
+
exit 1
|
|
215
|
+
fi
|
|
216
|
+
|
|
217
|
+
# [HARD_STOP] git merge --squash 冲突时禁止 agent 自动运行:
|
|
218
|
+
# - git merge --abort(撕毁现场,用户 in-progress 修改消失)
|
|
219
|
+
# - git reset --hard <main_branch>(撕毁本地未推送 commit)
|
|
220
|
+
# - git checkout . / git restore .(撕毁工作目录改动)
|
|
221
|
+
# 详见 docs/reference/skill-writing-guide.md §3.5.1
|
|
222
|
+
# 冲突时必须:列出冲突文件 → 退出 skill → 让用户解决 → 用户重新运行 /alloy:finish
|
|
158
223
|
git merge --squash <feature_branch>
|
|
159
|
-
# 抓取被合入分支的完整 commit 列表,生成类似 GitHub squash merge 的 commit message
|
|
160
224
|
COMMIT_LOG=$(git log <main_branch>..<feature_branch> --format="* %s")
|
|
161
225
|
git commit -m "$(cat <<EOF
|
|
162
226
|
chore(<name>): 合入 main(squash merge)
|
|
@@ -164,63 +228,95 @@ chore(<name>): 合入 main(squash merge)
|
|
|
164
228
|
${COMMIT_LOG}
|
|
165
229
|
EOF
|
|
166
230
|
)"
|
|
167
|
-
|
|
231
|
+
|
|
232
|
+
# [task #13 备注] squash merge 产生新 commit hash,但 retrospective.md / verify.md / plans.md 等
|
|
233
|
+
# 制品 hash 已在 archive 阶段被 alloy _record 锁定到 records——records 记录的是制品文件 SHA-256,
|
|
234
|
+
# 而非 git commit hash。git 历史变化(squash / rebase)不影响已归档制品的不可篡改性。
|
|
235
|
+
# 因此 squash 后无需重录任何 hash;finish 阶段不再调 alloy _record write。
|
|
236
|
+
|
|
237
|
+
# [PRECONDITION_FAIL] git branch -D 前必须校验变量——
|
|
238
|
+
# <feature_branch> 是模板占位符,agent 在执行前必须替换为实际分支名。
|
|
239
|
+
# 如果替换缺失或意外指向 main_branch,强删会丢失主分支引用。
|
|
240
|
+
if [ -z "<feature_branch>" ] || [ "<feature_branch>" = "<main_branch>" ] || [ "<feature_branch>" = "main" ] || [ "<feature_branch>" = "master" ]; then
|
|
241
|
+
echo "[PRECONDITION_FAIL] feature_branch 变量未替换或与主分支同名,拒绝执行 git branch -D"
|
|
242
|
+
echo " feature_branch=<feature_branch>"
|
|
243
|
+
echo " main_branch=<main_branch>"
|
|
244
|
+
echo " 禁止:agent 自动猜测分支名继续执行。退出 skill 让用户检查 .alloy.yaml。"
|
|
245
|
+
exit 1
|
|
246
|
+
fi
|
|
168
247
|
git branch -D <feature_branch>
|
|
169
248
|
```
|
|
170
249
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
-
|
|
196
|
-
-
|
|
250
|
+
`git pull` 失败按上述 USER_GATE 三选项(重试 / 跳过 pull / 中止)处理;agent 不得自动绕过。`git merge --squash` 冲突时列出冲突文件让用户手动解决,禁止 `git merge --abort`(详见 §3.5.1)。
|
|
251
|
+
|
|
252
|
+
### 选项 2:创建 PR
|
|
253
|
+
|
|
254
|
+
先记录完成时间并推进 phase:
|
|
255
|
+
```bash
|
|
256
|
+
ARCHIVE_DIR=$(ls -d openspec/changes/archive/*-<name> 2>/dev/null | sort -r | head -1)
|
|
257
|
+
CHANGE_DIR="${ARCHIVE_DIR:-openspec/changes/<name>}"
|
|
258
|
+
COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
|
|
259
|
+
# [§5.2.3 路径 B] phase 推进发生在 PR 创建之前。PR 后续被 close / 不合入时,
|
|
260
|
+
# 用户须手动按以下 3 步回退(与选项 1 同款手动回退路径):
|
|
261
|
+
# alloy _state set "$CHANGE_DIR" phase archived
|
|
262
|
+
# git checkout HEAD~1 -- "$CHANGE_DIR/.alloy.yaml" # 撤销 phase commit 中的状态变更
|
|
263
|
+
# git reset HEAD~1 # 退回 phase commit
|
|
264
|
+
# 禁止 agent 自动 git reset --hard / git checkout . 清场(§3.5.1)。
|
|
265
|
+
alloy _state merge "$CHANGE_DIR" phase_timings "{\"finish\":{\"completed_at\":\"${COMPLETED_AT:-$(date '+%Y-%m-%d %H:%M:%S')}\"}}"
|
|
266
|
+
alloy _guard "$CHANGE_DIR" finished --apply
|
|
267
|
+
# [§5.2.1] git add 路径化——禁用 -A / -a / .,避免误提交 agent 看不到的副作用文件
|
|
268
|
+
git add "$CHANGE_DIR" openspec/config.yaml
|
|
269
|
+
git commit -m "chore(<name>): 记录 finish 阶段完成时间"
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
PR 审查反馈的处理规范:
|
|
273
|
+
- **验证优先** —— 不盲从审查意见,先验证问题是否真实
|
|
274
|
+
- **技术推理** —— 有技术理由时解释而非被动接受
|
|
275
|
+
- **不表演性认同** —— 不理解的追问清楚
|
|
276
|
+
- **每条独立回应** —— 不批量处理
|
|
277
|
+
- **spec 变更 = 新 change(HARD_STOP)** —— 当前 spec 已归档封存。当代码修改可能影响 spec 行为时,必须 🔴 USER_GATE:
|
|
278
|
+
|
|
279
|
+
> AskUserQuestion: PR 审查反馈是否需要 spec 级修改?
|
|
280
|
+
> (a) 不需要——仅代码调整不影响行为
|
|
281
|
+
> (b) 需要——退出 finish,运行 /alloy:start <new-name> 开新 change
|
|
282
|
+
> (c) 暂不决定——保持 PR 不合入,等待澄清
|
|
283
|
+
>
|
|
284
|
+
> 选 (b):[HARD_STOP] 禁止 agent 直接修改已归档 spec。退出 skill。
|
|
285
|
+
|
|
286
|
+
### 选项 3:保持分支
|
|
287
|
+
|
|
288
|
+
记录延期时间戳供后续 `alloy status` 统计:
|
|
289
|
+
```bash
|
|
290
|
+
ARCHIVE_DIR=$(ls -d openspec/changes/archive/*-<name> 2>/dev/null | sort -r | head -1)
|
|
291
|
+
CHANGE_DIR="${ARCHIVE_DIR:-openspec/changes/<name>}"
|
|
292
|
+
DEFERRED_AT=$(date "+%Y-%m-%d %H:%M:%S")
|
|
293
|
+
alloy _state merge "$CHANGE_DIR" phase_timings "{\"finish\":{\"deferred_at\":\"${DEFERRED_AT}\"}}"
|
|
294
|
+
git add "$CHANGE_DIR/.alloy.yaml"
|
|
295
|
+
git commit -m "chore(<name>): finish 延期,分支已保留"
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
> ⚠️ WARN(task #27):finish 延期已记录 deferred_at=${DEFERRED_AT}。
|
|
299
|
+
> 后续 `alloy status` 会基于此提示分支堆积;建议在合适时机重新运行 /alloy:finish 完成合入。
|
|
300
|
+
|
|
301
|
+
提示:"分支已保留。后续需要时再次运行 `/alloy:finish <name>`。" phase 保持 archived,不推进——此选项不破坏不变式:`deferred_at` 仅是观测信号,phase 字段保持 archived 由 `alloy _guard` 校验(task #27)。
|
|
197
302
|
|
|
198
303
|
---
|
|
199
304
|
|
|
200
305
|
### [Step 3/3] 完成
|
|
201
306
|
|
|
202
|
-
完成时间已在 Step 2 的记录 commit 中写入。finish 阶段不产生额外 commit——合入 commit(选项 1)或 PR(选项 2)本身就是终端动作。
|
|
203
|
-
|
|
204
307
|
```
|
|
205
308
|
┌──────────────────────────────────────┐
|
|
206
309
|
│ Alloy [5/5] · Phase: Finish — DONE │
|
|
207
|
-
│ 启动时间:
|
|
208
|
-
│ 完成时间:
|
|
209
|
-
│ 耗时: completed_at - started_at
|
|
310
|
+
│ 启动时间: phase_timings.finish.started_at
|
|
311
|
+
│ 完成时间: phase_timings.finish.completed_at
|
|
312
|
+
│ 耗时: completed_at - started_at
|
|
210
313
|
└──────────────────────────────────────┘
|
|
211
314
|
|
|
212
|
-
→ Change: <name>
|
|
213
|
-
→
|
|
214
|
-
|
|
215
|
-
→ 分支: <merged / 已删除 / 保留>
|
|
315
|
+
→ Change: <name> Phase: finished
|
|
316
|
+
→ 处理方式: <本地 merge / PR / 保留分支> 分支: <merged / 已删除 / 保留>
|
|
317
|
+
```
|
|
216
318
|
|
|
217
|
-
|
|
319
|
+
finish 不产生额外 commit——合入 commit 或 PR 本身就是终端动作。
|
|
218
320
|
|
|
219
|
-
|
|
321
|
+
**git add 路径化(§5.2.1):** 仅用精确路径(`"$CHANGE_DIR" openspec/config.yaml`),禁用 `-A` / `-a` / `.`。违反字面 = 违反精神:哪怕"反正只有一个文件改动",也禁止 `-A`——agent 看不到的副作用文件可能被一并提交。
|
|
220
322
|
|
|
221
|
-
- **git add 只用精确路径** — 永远不用 `-a`、`.`。
|
|
222
|
-
finish 阶段用 `git add -A "$CHANGE_DIR" openspec/config.yaml`(`$CHANGE_DIR` 为当前 change 的归档路径,`-A` 限路径,只追踪 change 目录和 openspec 配置的新增/修改/删除),代码合入由 git merge 处理
|
|
223
|
-
- **phase 必须为 archived** —— spec 已归档的 change 才能 finish
|
|
224
|
-
- **分支必须存在** —— 分支已 merge 或删除时无需再次 finish
|
|
225
|
-
- **不涉及 spec 变更** —— spec 已归档封存,任何 spec 级修改应走新 change
|
|
226
|
-
- **选项 3 不推进 phase** —— 保持分支意味着未真正收尾,phase 停留在 archived
|