@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: Start"
3
- description: Alloy 智能入口 - 自动检测状态,接续或新建 change
3
+ description: 新功能构思或接续已有工作时调用
4
4
  category: Workflow
5
5
  tags: [alloy, workflow]
6
6
  ---
@@ -11,7 +11,7 @@ tags: [alloy, workflow]
11
11
 
12
12
  **核心原则:把实际工作委托给专门的技能,不要自己做。Alloy 是编排器,不是执行者。**
13
13
 
14
- > **`<TIMESTAMP>` 的含义:** 每次渲染阶段头部框时,执行 `date "+%Y-%m-%d %H:%M:%S"` 获取本地时间,替换 `<TIMESTAMP>`。不要输出字面字符串 `<TIMESTAMP>`。`<SESSION_START>` 是"全新开始"路径在 header 渲染前捕获的会话启动时间,后续 step 8 写入 phase_timings 时复用该值。`<created_at>` 从 `.alloy.yaml` 的 `created_at` 字段读取。
14
+ > **`<TIMESTAMP>` 的含义:** 每次渲染阶段头部框时,执行 `date "+%Y-%m-%d %H:%M:%S"` 获取本地时间,替换 `<TIMESTAMP>`。不要输出字面字符串 `<TIMESTAMP>`。`<START_TIME>` 是"全新开始"路径中捕获的当前时间——agent 捕获 date 命令的输出后,在 header 渲染和 phase_timings 写入时复用该值。`<created_at>` 从 `.alloy.yaml` 的 `created_at` 字段读取。
15
15
 
16
16
  ---
17
17
 
@@ -27,28 +27,40 @@ tags: [alloy, workflow]
27
27
 
28
28
  ## 全新开始(无活跃 change + 用户提供了 topic)
29
29
 
30
- **记录会话启动时间**(后续写入 phase_timings.start.started_at):
30
+ **捕获阶段启动时间**(命令调用后第一时间输出当前时间,agent 捕获输出值后在 header 和 phase_timings 中复用):
31
31
  ```bash
32
- echo "SESSION_START=$(date "+%Y-%m-%d %H:%M:%S")"
32
+ date "+%Y-%m-%d %H:%M:%S"
33
33
  ```
34
+ > 提示:不要混用 bash 变量——bash 状态在两次工具调用间不持久。直接捕获 date 的输出文本,填入 `<START_TIME>`。
34
35
 
35
36
  ```
36
37
  ┌──────────────────────────────────────┐
37
38
  │ Alloy [1/5] · Phase: Start │
38
- │ 启动时间: 使用上面 SESSION_START 的值
39
+ │ 启动时间: <START_TIME>
39
40
  └──────────────────────────────────────┘
40
41
  ```
41
42
 
42
43
  ### [Step 1/2] 上下文探查
43
44
 
45
+ **Skill 预检:** 确认以下依赖可用:
46
+ cmd: opsx/explore opsx/new
47
+ skill: brainstorming
48
+
49
+ 读取 `commands/alloy/references/skill-precheck.md` 了解检测方法。任一不可用 → 引导 `alloy init` → STOP。
50
+
44
51
  > 正在探查项目上下文和需求空间...
45
52
 
46
53
  **立即执行:** 使用 Skill 工具加载 `opsx:explore` 技能。禁止跳过此步骤。
47
54
 
48
- 如果 `opsx:explore` 不可用(OpenSpec 未安装或命令不存在),引导用户运行 `alloy init` 完成环境初始化。
49
-
50
55
  技能加载后,按其指引自由探索项目上下文和需求空间。
51
56
 
57
+ **交互风格:** 探查结果反馈给用户时,使用 `AskUserQuestion` 工具呈现结构化选项。详见 `commands/alloy/references/interaction-style.md`。箭头上下选择、Enter 确认——不要用纯文本 "(a)(b)(c)" 让用户打字。
58
+
59
+ **技能加载后立即记录:**
60
+ ```bash
61
+ alloy _skill log openspec/changes/<name> start opsx:explore
62
+ ```
63
+
52
64
  **额外上下文——来自历史 retrospective 的教训:** 在探查阶段,扫描 `openspec/changes/archive/` 下最近 3 个已归档 change 的 `retrospective.md`,提取以下信息作为本次 brainstorming 的参考:
53
65
 
54
66
  - **§5 意外发现**:上一次有哪些假设被推翻?这次可能也有类似盲区
@@ -63,8 +75,6 @@ echo "SESSION_START=$(date "+%Y-%m-%d %H:%M:%S")"
63
75
 
64
76
  > 正在启动 brainstorming...
65
77
 
66
- **前置预检:** 确认 `superpowers:brainstorming` 技能可用。若不可用 → 引导用户运行 `alloy init` 重新安装 → STOP。不在 Step 2 才发现缺失。
67
-
68
78
  **立即执行:** 使用 Skill 工具加载 `superpowers:brainstorming` 技能。禁止跳过此步骤。
69
79
 
70
80
  将探查结果作为 ARGUMENTS 传入:
@@ -72,13 +82,31 @@ echo "SESSION_START=$(date "+%Y-%m-%d %H:%M:%S")"
72
82
  探查结果:<Step 1 的关键发现摘要>
73
83
  主题:<topic>
74
84
  项目类型:<新项目/存量项目>
75
- ```
76
85
 
77
- 技能加载后,按其指引进行交互式需求设计。
86
+ **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。
87
+
88
+ **交互风格——使用交互式选择组件,不要用纯文本选项:**
89
+
90
+ brainstorming 每个问题都是沟通成本。使用平台的交互式提示工具(Claude Code 中为 `AskUserQuestion`)来降低来回次数。**不要用纯文本 "(a)(b)(c)"——那只是换了格式的开放式提问。**
91
+
92
+ - **单选用 radio:** `multiSelect: false`,箭头上下导航,Enter 确认。技术选型、架构决策用这个。每个选项的 `description` 写推荐理由,帮用户做决定。
93
+ - **多选用 checkbox:** `multiSelect: true`,空格勾选/取消,Enter 提交。功能范围、边界确认用这个。一次确认 3-5 个独立选项,比逐个问 5 个判断题快 5 倍。
94
+ - **代码方案对比用 preview:** 如果不同方案涉及代码结构差异,用选项的 `preview` 字段展示代码片段,用户并排对比后选择。
95
+ - **每次提问不超过 4 个问题**(`AskUserQuestion` 的上限),相关问题合并到一次调用。不要一个问题调一次——那是文本选项的思维。
96
+ - **关键决策单选、范围确认多选:** 架构选择用 radio(互斥),功能范围用 checkbox(独立),不混用。
97
+ - **给出默认推荐:** 推荐的选项在 `description` 中标注理由,让用户可以一键确认而不是逐项评估。
98
+ ```
78
99
 
79
100
  如果 `superpowers:brainstorming` 不可用,引导用户运行 `alloy init` 完成环境初始化。brainstorming 技能内置了审批闸门和 Q&A 深度——普通对话无法复现这些行为。
80
101
 
81
- **brainstorming 完成后,你必须等待用户确认方案,然后生成 `draft.md`:**
102
+ **技能加载后立即记录:**
103
+ ```bash
104
+ alloy _skill log openspec/changes/<name> start superpowers:brainstorming
105
+ ```
106
+
107
+ **brainstorming 负责"想清楚要做什么"——通过交互式问答明确问题、方案和关键决策。** 用户确认方案后,这一步的产出是 `draft.md`,不是 superpowers spec 文件。
108
+
109
+ 用户确认方案后,生成 `draft.md`:
82
110
 
83
111
  ```markdown
84
112
  # [功能名称]
@@ -90,33 +118,41 @@ echo "SESSION_START=$(date "+%Y-%m-%d %H:%M:%S")"
90
118
  <!-- 方案概述 -->
91
119
 
92
120
  ## 关键决策
93
- <!-- 关键技术决策及理由 -->
94
- <!-- 将 brainstorming 的详细设计论述写入此章节,不单独产出 superpowers spec 文件 -->
121
+ <!-- brainstorming 中确定的关键技术决策及理由,方案对比、架构考量都写在这里 -->
95
122
 
96
123
  ## 范围与边界
97
124
  <!-- 做什么、明确不做什么 -->
98
125
  ```
99
126
 
100
- **关键:** brainstorming 的所有设计论述(方案对比、技术决策、架构考量)全部写入 draft.md 的"关键决策"章节。不单独在 `docs/superpowers/specs/` 生成文件——draft.md 是 brainstorming 的唯一产出。
101
-
102
127
  **用户明确确认方案之前,不要生成 draft.md。** 如果用户要求调整方案,回到 brainstorming 继续讨论,不要急于产出文件。
103
128
 
104
- **什么算"用户确认了"(反例):**
105
- - 用户说"还行"、"可以"——追问他是否满意关键决策和范围边界
106
- - 用户只确认了部分内容——确保所有关键决策都被明确认可
129
+ **什么算"不够"(反例):**
130
+ - brainstorming 完成后生成了 `docs/superpowers/specs/` 文件——draft.md 是 brainstorming 在 alloy 流程中的唯一产出
131
+ - brainstorming 完成后 invoke writing-plans——那是独立使用 brainstorming 时的行为,在 alloy:start 中下一步是生成 draft.md
132
+ - 用户说"还行"、"可以"就直接生成——追问他是否满意关键决策和范围边界
133
+
134
+ ### Red Flags——STOP,不要跳过闸门
135
+
136
+ 以下任何一个念头出现,都意味着 start 的闸门正在被绕过:
137
+
138
+ | 借口 | 现实 |
139
+ |------|------|
140
+ | "不用建分支了,就在 main 上干吧" | 主分支上直接开发会污染 main 历史。每个 change 必须有独立 feature 分支。拒绝——建分支只需 2 秒。 |
141
+ | "不用 brainstorming 了,直接写代码" | brainstorming 不是可选项。跳过需求设计 = 规格和代码分叉的起点。必须加载 superpowers:brainstorming。 |
142
+ | "我一个人开发,不用那么正式" | 流程保护的是一致性和可追溯性,不是团队规模。一个人的项目和团队项目的闸门完全一样。 |
143
+ | "我看过了,内容都对"(跳过审查) | 用户"看过了"不等于审查到位。必须按流程确认 change name、主分支、feature 分支。 |
144
+ | "brainstorming 完成了,写 spec 文件吧" | Alloy start 的产出是 draft.md,不是 docs/superpowers/specs/ 文件。brainstorming 完成后直接输出方案,由 Alloy 流程负责生成 draft.md。 |
145
+ | "start 完成了,我帮你直接进 plan" | start 完成后绝不自动进入 plan。即使用户之前说过"赶紧做完",也需要用户在看过 draft.md 后明确运行 /alloy:plan。替用户做阶段转换决定 = 剥夺审查机会。 |
146
+ | "用户没回复,我先继续生成 proposal 吧" | 用户沉默 ≠ 授权继续。在审查窗口等待用户明确选 (a) 或 (b)。擅自继续 = 生成的制品未经审查,后期返工代价远大于等待时间。 |
147
+ | "draft.md 在 brainstorming 时已经讨论过了,直接 commit 吧" | brainstorming 讨论的是方案概念,draft.md 是最终文本。两者不等价——文本可能有措辞偏差、遗漏细节。必须展示 draft.md 完整内容,等用户确认后才能 commit。 |
107
148
 
108
149
  ---
109
150
 
110
151
  用户确认方案后,执行以下步骤:
111
152
 
112
153
  1. **建议 change name**——根据确认的方案建议 kebab-case 名称,用户确认
113
- 2. **调用 `/opsx:new <name>`** 创建 change 目录
114
- 3. **按模板生成 `draft.md`** 到 `openspec/changes/<name>/draft.md`(直接在 change 目录下生成,无需移动)
115
- 4. **写入 state**——使用 `_state init` 一步创建完整初始状态(包含 `records: []`、正确类型),避免逐字段写入遗漏 records 数组:
116
- ```bash
117
- alloy _state init openspec/changes/<name>
118
- ```
119
- 5. **确保 git 仓库就绪:**
154
+
155
+ 2. **确保 git 仓库就绪:**
120
156
 
121
157
  ```bash
122
158
  if ! git rev-parse --git-dir 2>/dev/null; then
@@ -130,52 +166,99 @@ echo "SESSION_START=$(date "+%Y-%m-%d %H:%M:%S")"
130
166
 
131
167
  已有项目则跳过(git repo 已存在,HEAD 已有锚点)。
132
168
 
133
- 6. **分支选择**——检测 git 状态,确认工作分支:
169
+ 3. **分支选择**——在创建 change 目录之前完成分支切换,确保所有制品落在 feature 分支上:
134
170
 
135
- 先获取当前分支:
171
+ **① 自动识别主分支:** 读取 `commands/alloy/references/main-branch-detection.md`,按 3 级优先级检测主分支。
172
+
173
+ 若 `openspec/config.yaml` 已有 `alloy.main_branch` 记录,直接用记录值,跳过检测和确认。
174
+
175
+ **② 确认主分支:** 检测到后让用户确认(Y/n)。确认后写入项目级配置:
176
+ ```bash
177
+ alloy _config write . main_branch <用户确认的主分支名>
178
+ ```主分支是项目级概念,所有 change 共享,不写入 per-change 的 .alloy.yaml。
179
+
180
+ **③ 检测当前分支:**
136
181
  ```bash
137
182
  CURRENT_BRANCH=$(git branch --show-current)
138
- echo "当前分支:$CURRENT_BRANCH"
183
+ CHANGENAME="<name>"
139
184
  ```
140
185
 
141
- 展示选项,让用户选择:
186
+ **④ 按当前分支位置决策:**
187
+
188
+ - **在主分支上** → HARD STOP:"当前在主分支 `<main_branch>`,不允许在主分支开发。commit 会污染主分支历史。" → 只展示"新建分支"选项
189
+ - **在 feature 分支上且名称包含 change 名**(如 `feature/<name>` 或 `fix/<name>`)→ 提示"当前已在 `<$CURRENT_BRANCH>`,直接在该分支上继续工作?[Y/n]"
190
+ - 选 Y → 使用当前分支,继续步骤 4
191
+ - 选 n → 展示选项(见⑤)
192
+ - **在非主分支的已有分支上** → 展示选项(见⑤)
142
193
 
194
+ **⑤ 展示选项:**
195
+
196
+ 本地非主分支(排除刚确认的主分支)存在时:
143
197
  > 选择工作分支
144
198
  > ──────────────────────────────────────
145
199
  >
146
- > 当前在 `<$CURRENT_BRANCH>` 分支
147
- >
148
- > 1. 在当前分支继续 —— 直接在此分支开发
149
- > 2. 切换到已有分支 —— 选择一个已有分支
150
- > 3. 新建分支 —— 创建新分支并切换
200
+ > 当前在 `<$CURRENT_BRANCH>`,主分支:`<main_branch>`
151
201
  >
152
- > 建议新建 `<change-name>` 分支,保持 main 干净
202
+ > 1. 切换到已有分支 —— 选择非主分支的已有分支
203
+ > 2. 新建分支 —— 创建新 feature 分支并切换
204
+
205
+ 无可用本地非主分支时 → 直接进入新建分支流程(跳过选项 1)。
206
+
207
+ 每个 change 必须有独立的 feature 分支,确保 discard 时可安全清理。
153
208
 
154
- - **选 1:** 不操作,直接继续
155
- - **选 2:** 展示已有分支列表(`git branch -a`),用户选择后执行 `git checkout <branch>`
156
- - 如果该 change 后续使用 worktree,此分支名仅作参考记录
157
- - **选 3:** 询问用户输入新分支名,执行 `git checkout -b <new-branch>`
158
- - Agent 可建议分支名(如 `<change-name>`),由用户确认
209
+ - **选 1:** 列出本地非主分支(`git branch` 排除主分支),用户选择后执行 `git checkout <branch>`
210
+ - **选 2:** 新建分支命名:
211
+ - 默认建议:`feature/<change-name>`
212
+ - 用户可输入自定义名称
213
+ - 校验:不允许与主分支同名
214
+ - `git checkout -b <branch-name>`
159
215
 
160
- 分支选择完成后,记录到状态:
216
+ 4. **调用 `/opsx:new <name>`** 创建 change 目录(已在 feature 分支上,目录直接落在正确分支)
217
+
218
+ **命令执行后立即记录:**
219
+ ```bash
220
+ alloy _skill log openspec/changes/<name> start opsx:new
221
+ ```
222
+
223
+ 5. **写入 state**——使用 `_state init` 一步创建完整初始状态(包含 `records: []`、正确类型),避免逐字段写入遗漏 records 数组:
161
224
  ```bash
162
- alloy _state write openspec/changes/<name> worktree null
225
+ alloy _state init openspec/changes/<name>
163
226
  ```
164
227
 
165
- > ⚠️ apply 阶段仍会通过 `using-git-worktrees` 再次确认隔离方式。此处的分支选择是给后续阶段一个推荐的开发分支。
166
-
167
- 7. **提交:**
228
+ **记录阶段启动时间:**
229
+ ```bash
230
+ alloy _state merge openspec/changes/<name> phase_timings "{\"start\":{\"started_at\":\"$(date '+%Y-%m-%d %H:%M:%S')\"}}"
231
+ ```
168
232
 
169
- **draft hash + commit:**
233
+ 6. **记录分支信息**——将 feature_branch 和 worktree null 写入 state:
170
234
  ```bash
171
- DRAFT_HASH=$(alloy _record compute openspec/changes/<name> draft)
172
- APPROVED_AT=$(date "+%Y-%m-%d %H:%M:%S")
173
- APPROVER=$(git config user.name)
174
- alloy _record write openspec/changes/<name> draft "$DRAFT_HASH" "$APPROVED_AT" "$APPROVER"
175
- git add openspec/changes/<name>/
176
- git commit -m "feat(<name>): draft 已确认"
235
+ alloy _state write openspec/changes/<name> feature_branch <branch-name>
236
+ alloy _state write openspec/changes/<name> worktree null
177
237
  ```
178
238
 
239
+ 7. **按模板生成 `draft.md`** 到 `openspec/changes/<name>/draft.md`(直接在 change 目录下生成,无需移动)
240
+
241
+ **draft.md 审查窗口——这是 start 阶段唯一的制品审查闸门。用户明确确认后才能 commit。**
242
+
243
+ > 制品 draft ✓ 完成
244
+ >
245
+ > [展示 draft.md 完整内容]
246
+ >
247
+ > → (a) 确认,锁定 draft 并完成 start 阶段
248
+ > → (b) 需要调整 — 回到 brainstorming 重新讨论
249
+
250
+ - **选 (a)**:继续步骤 8,hash 锁定 + commit
251
+ - **选 (b)**:不生成文件、不 commit。回到 Step 2/2 的 brainstorming,基于用户反馈重新讨论方案。brainstorming 完成后重新生成 draft.md,再次进入此审查窗口
252
+
253
+ **什么算"审查不充分"(反例):**
254
+ - 只问"看起来可以吗?"不展示 draft.md 实际内容
255
+ - 用户说"还行"、"可以"就跳过——必须明确选 (a) 或 (b)
256
+ - 把 brainstorming 阶段的方案确认等同于 draft.md 审查——brainstorming 确认的是概念,draft.md 审查的是最终文本
257
+
258
+ > 前面步骤写入的 `.alloy.yaml` 变更(init、started_at、feature_branch、worktree)不单独提交——它们在 draft commit 中一并提交。`git add openspec/changes/<name>/` 会覆盖目录内的所有变更。
259
+
260
+ 8. **提交(start 阶段唯一 commit)——仅在用户选 (a) 后执行:**
261
+
179
262
  **alloy init 基础设施提交:**
180
263
  ```bash
181
264
  git add .claude/ .gitignore openspec/config.yaml openspec/schemas/ 2>/dev/null
@@ -184,14 +267,16 @@ echo "SESSION_START=$(date "+%Y-%m-%d %H:%M:%S")"
184
267
  ```
185
268
  已提交过则自动跳过。`.superpowers/` 已在 `.gitignore` 中忽略,不入仓库。
186
269
 
187
- 8. **记录阶段时间:**
270
+ **记录阶段时间 + draft hash-lock + commit:**
188
271
  ```bash
189
272
  COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
190
- # STARTED_AT 使用步骤开始时捕获的 SESSION_START
191
- STARTED_AT="<SESSION_START>"
192
- alloy _state write openspec/changes/<name> phase_timings "{\"start\":{\"started_at\":\"$STARTED_AT\",\"completed_at\":\"$COMPLETED_AT\"}}"
273
+ alloy _state merge openspec/changes/<name> phase_timings "{\"start\":{\"completed_at\":\"${COMPLETED_AT:-$(date '+%Y-%m-%d %H:%M:%S')}\"}}"
274
+ DRAFT_HASH=$(alloy _record compute openspec/changes/<name> draft)
275
+ APPROVED_AT=$(date "+%Y-%m-%d %H:%M:%S")
276
+ APPROVER=$(git config user.name)
277
+ alloy _record write openspec/changes/<name> draft "$DRAFT_HASH" "$APPROVED_AT" "$APPROVER"
193
278
  git add openspec/changes/<name>/
194
- git commit -m "chore(<name>): 记录 start 阶段完成时间"
279
+ git commit -m "docs(<name>): draft 已确认"
195
280
  ```
196
281
 
197
282
  ---
@@ -203,7 +288,7 @@ echo "SESSION_START=$(date "+%Y-%m-%d %H:%M:%S")"
203
288
  │ Alloy [1/5] · Phase: Start — DONE │
204
289
  │ 启动时间: 从 phase_timings.start.started_at 读取 │
205
290
  │ 完成时间: 从 phase_timings.start.completed_at 读取 │
206
- │ 耗时: XmXs │
291
+ │ 耗时: (phase_timings.start.completed_at - started_at 计算)
207
292
  └──────────────────────────────────────┘
208
293
 
209
294
  → Change: <name>
@@ -219,7 +304,16 @@ echo "SESSION_START=$(date "+%Y-%m-%d %H:%M:%S")"
219
304
  ```
220
305
 
221
306
  - draft.md 已在 change 目录,项目根目录不再有 draft.md
222
- - 完成后不要自动进入 plan
307
+
308
+ **HARD STOP —— start 阶段到此结束。以下行为绝对禁止:**
309
+
310
+ - 不要自动运行 `/alloy:plan` 或加载 `alloy-plan` 技能
311
+ - 不要生成 proposal.md、design.md、specs/、tasks.md、plans.md 或任何 plan 阶段制品
312
+ - 不要调用 `opsx:continue` 或 `superpowers:writing-plans`
313
+ - 不要因为"用户没回复"而继续——沉默 ≠ 授权
314
+ - 不要因为"这样更高效"而替用户做决定——用户必须自己发起下一阶段
315
+
316
+ **你的唯一操作:展示上述完成信息,等待用户输入下一个命令。**
223
317
 
224
318
  ---
225
319
 
@@ -280,16 +374,25 @@ echo "SESSION_START=$(date "+%Y-%m-%d %H:%M:%S")"
280
374
 
281
375
  展示检测结果后,根据 phase 和制品状态决定路由:
282
376
 
283
- | phase | 制品状态 | 自动加载命令 |
284
- |-------|---------|-------------|
377
+ | phase | 制品状态 | 路由 |
378
+ |-------|---------|------|
285
379
  | started | proposal.md 存在 | alloy-plan(正常接续——plan 制品已有,继续生成) |
286
- | started | proposal.md 不存在 | 重新进入 brainstorming(回溯后——以现有 draft.md 为基础重新讨论需求) |
380
+ | started | proposal.md 不存在 + draft.md 存在且 hash 有效 | **提示用户选择:**(a) 进入 plan 阶段 (b) 回到 brainstorming 修改需求。draft 已确认,默认预期是用户想进 plan——不要默认假设用户想重来。 |
381
+ | started | proposal.md 不存在 + draft.md 不存在或 hash 不匹配 | 重新进入 brainstorming(draft 缺失或已被篡改,需重新讨论需求) |
287
382
  | planned | — | alloy-apply |
288
383
  | applied | — | alloy-archive |
289
384
  | archived | — | alloy-finish |
290
385
  | finished | — | 工作流已完成——如需继续修改,使用自然对话提交新变更 |
291
386
 
292
- **实现方式:** 根据 phase 值,输出对应命令文件的完整指令(`commands/alloy/plan.md` / `apply.md` / `archive.md` / `finish.md`),将 change name 和检测到的进度信息作为上下文传入。Agent 无缝进入对应阶段。
387
+ **实现方式:**
388
+
389
+ - **需自动加载命令时**(proposal.md 存在 → plan、planned → apply 等):输出对应命令文件的完整指令(`commands/alloy/plan.md` / `apply.md` / `archive.md` / `finish.md`),将 change name 和检测到的进度信息作为上下文传入。Agent 无缝进入对应阶段。
390
+ - **需用户选择时**(draft 已确认、proposal 不存在):先校验 draft hash:
391
+ ```bash
392
+ alloy _record check openspec/changes/<name> draft
393
+ ```
394
+ hash 有效 → 展示选择:"draft 已确认。 (a) 进入 plan 阶段 (b) 回到 brainstorming 修改需求"。等用户选择后执行对应路由。
395
+ hash 不匹配 → 走"draft 不存在或 hash 不匹配"路径。
293
396
 
294
397
  一致性检查(双向):
295
398
  - worktree 字段有值但磁盘路径不存在 → ⚠️ "worktree 残留:.alloy.yaml 声称有 worktree 但磁盘不存在"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: "Alloy: Status"
3
- description: 查看 Alloy change 的当前阶段、制品状态和下一步操作
3
+ description: 需要查看 change 进度或状态时调用
4
4
  category: Workflow
5
5
  tags: [alloy, workflow]
6
6
  ---
@@ -5,3 +5,4 @@ export interface DoctorResult {
5
5
  }
6
6
  export declare function doctorCommand(projectPath: string): Promise<DoctorResult>;
7
7
  export declare function formatDoctorResult(result: DoctorResult, useJson: boolean): string;
8
+ export declare function printDoctorResult(result: DoctorResult): void;
@@ -3,6 +3,8 @@ import { fileURLToPath } from "node:url";
3
3
  import { existsSync } from "node:fs";
4
4
  import { runHealthCheck } from "../../core/health.js";
5
5
  import { findActiveChanges } from "../utils/state.js";
6
+ import { color } from "../../utils/format.js";
7
+ import { section, check, warn } from "../../utils/output.js";
6
8
  function detectScope(projectPath) {
7
9
  const home = process.env.HOME || process.env.USERPROFILE || "~";
8
10
  const probe = (dir) => existsSync(join(dir, ".claude", "commands", "alloy"));
@@ -74,20 +76,40 @@ export function formatDoctorResult(result, useJson) {
74
76
  return JSON.stringify(result, null, 2);
75
77
  }
76
78
  const lines = [];
77
- lines.push("健康检查:");
79
+ lines.push(color.bold("健康检查:"));
78
80
  for (const r of result.healthResults) {
79
- const mark = r.status === "pass" ? "✓" : r.status === "warn" ? "⚠️" : "✗";
80
- lines.push(` ${mark} ${r.name}: ${r.current}(要求 ${r.required})`);
81
+ const mark = r.status === "pass"
82
+ ? color.green("✓")
83
+ : r.status === "warn"
84
+ ? color.yellow("⚠️")
85
+ : color.red("✗");
86
+ lines.push(` ${mark} ${r.name}: ${color.cyan(r.current)}(要求 ${color.dim(r.required)})`);
81
87
  }
82
88
  if (result.consistencyWarnings.length > 0) {
83
- lines.push("\n文件一致性:");
89
+ lines.push("\n" + color.bold("文件一致性:"));
84
90
  for (const w of result.consistencyWarnings) {
85
- lines.push(` ⚠️ ${w}`);
91
+ lines.push(` ${color.yellow("⚠️")} ${w}`);
86
92
  }
87
93
  }
88
94
  else {
89
- lines.push("\n文件一致性:✓ 无问题");
95
+ lines.push("\n" + color.bold("文件一致性:") + color.green(" ✓ 无问题"));
90
96
  }
91
97
  return lines.join("\n");
92
98
  }
99
+ export function printDoctorResult(result) {
100
+ section("健康检查");
101
+ for (const r of result.healthResults) {
102
+ check(r.name, `${r.current}(要求 ${r.required})`, r.status);
103
+ }
104
+ if (result.consistencyWarnings.length > 0) {
105
+ section("文件一致性");
106
+ for (const w of result.consistencyWarnings) {
107
+ warn(w);
108
+ }
109
+ }
110
+ else {
111
+ section("文件一致性");
112
+ check("一致性", "无问题", "pass");
113
+ }
114
+ }
93
115
  //# sourceMappingURL=doctor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ import { injectClaudeMd } from "../../core/claude-md.js";
9
9
  import { KNOWN_AGENTS } from "../../core/agents.js";
10
10
  import { getPackageRoot } from "../../utils/fs.js";
11
11
  import { promptSelect, promptMultiSelect } from "../../utils/prompt.js";
12
+ import { section, check, success, error, warn, banner, info } from "../../utils/output.js";
12
13
  export async function selectScope(passedScope) {
13
14
  if (passedScope)
14
15
  return passedScope;
@@ -24,7 +25,7 @@ export async function selectTargetAgents() {
24
25
  });
25
26
  return KNOWN_AGENTS.filter((a) => ids.includes(a.id));
26
27
  }
27
- const GITIGNORE_RULES = ["docs/superpowers/", ".worktrees/", "worktrees/", "*.local.*", ".superpowers/"];
28
+ const GITIGNORE_RULES = ["docs/superpowers/", ".claude/worktrees/", ".worktrees/", "worktrees/", ".superpowers/", "*.local.*"];
28
29
  async function ensureGitignore(projectPath) {
29
30
  const gitignorePath = join(projectPath, ".gitignore");
30
31
  let content = "";
@@ -41,85 +42,87 @@ async function ensureGitignore(projectPath) {
41
42
  return;
42
43
  const block = `\n### Alloy + Superpowers 运行时 ###\n${missing.join("\n")}\n`;
43
44
  await writeFile(gitignorePath, content + block, "utf-8");
44
- console.log(` ✓ .gitignore → 已追加 ${missing.length} 条规则`);
45
+ success(`.gitignore → 已追加 ${missing.length} 条规则`);
45
46
  }
46
47
  export async function initCommand(opts) {
47
- console.log("\n 🔍 检测环境...");
48
- // 1. 环境检测
48
+ // 1. 环境检测(detectEnv 是同步操作,无需 spinner)
49
+ section("检测环境...");
49
50
  const env = detectEnv();
50
- console.log(` Node.js ${env.nodeVersion} ✓`);
51
- console.log(` git ${env.gitInstalled ? "" : "未安装"}`);
52
- console.log(` Claude Code ${env.claudeCodeInstalled ? "" : "未检测到 CLI,请确保已安装"}`);
51
+ check("Node.js", env.nodeVersion, "pass");
52
+ check("git", env.gitInstalled ? "已安装" : "未安装", env.gitInstalled ? "pass" : "fail");
53
+ check("Claude Code", env.claudeCodeInstalled ? "已安装" : "未检测到 CLI,请确保已安装", env.claudeCodeInstalled ? "pass" : "warn");
53
54
  if (!env.gitInstalled) {
54
- console.error("\n ❌ 缺少必要依赖,请先安装 git");
55
+ error("❌ 缺少必要依赖,请先安装 git");
55
56
  process.exit(1);
56
57
  }
57
58
  // 2. 安装 OpenSpec CLI(npm 全局包)
58
- console.log("\n 📥 OpenSpec CLI...");
59
+ section("安装 OpenSpec CLI...");
59
60
  const openspecResult = await installOpenSpecCli();
60
61
  if (openspecResult === "installed") {
61
- console.log("@fission-ai/openspec@1 已安装");
62
+ success("@fission-ai/openspec@1 已安装");
62
63
  }
63
64
  else if (openspecResult === "failed") {
64
- console.error("OpenSpec CLI 安装失败");
65
+ error("OpenSpec CLI 安装失败");
65
66
  process.exit(1);
66
67
  }
67
68
  // "skipped" — 函数内部已输出跳过信息
68
69
  // 3. 初始化 OpenSpec 项目结构(openspec/ 目录 + .claude/commands/opsx/)
69
- console.log("\n 📂 初始化 OpenSpec 项目结构...");
70
- const initResult = await initOpenSpecProject(opts.projectPath, opts.scope);
70
+ section("初始化 OpenSpec 项目结构...");
71
+ const initResult = await initOpenSpecProject(opts.projectPath, opts.scope, opts.targetAgents);
71
72
  if (initResult === "failed") {
72
- console.error("OpenSpec 项目初始化失败");
73
+ error("OpenSpec 项目初始化失败");
73
74
  process.exit(1);
74
75
  }
75
76
  // 4. 安装 Superpowers
76
- console.log("\n 📥 Superpowers...");
77
- const superpowersResult = await installSuperpowers(opts.scope);
78
- if (superpowersResult === "installed") {
79
- console.log(" ✓ obra/superpowers@5 已安装");
77
+ section("安装 Superpowers...");
78
+ const claudeAgent = opts.targetAgents.find(a => a.id === "claude-code");
79
+ const superpowersResult = await installSuperpowers(opts.scope, claudeAgent, opts.projectPath);
80
+ if (superpowersResult.status === "installed") {
81
+ success("Superpowers 已安装");
80
82
  }
81
- else if (superpowersResult === "skipped") {
82
- console.log("Superpowers 已安装,跳过");
83
+ else if (superpowersResult.status === "failed") {
84
+ warn("Superpowers 安装失败,请稍后手动运行 alloy init 重试");
83
85
  }
84
- else {
85
- console.log(" ⚠ Superpowers 安装失败,请稍后手动运行 alloy init 重试");
86
+ else if (superpowersResult.status === "skipped") {
87
+ const versionInfo = superpowersResult.version ? ` v${superpowersResult.version}` : "";
88
+ const locationInfo = superpowersResult.location ? `(${superpowersResult.location})` : "";
89
+ success(`Superpowers${versionInfo} 已安装${locationInfo},跳过`);
86
90
  }
87
91
  // 5. 部署 Alloy commands
88
- console.log("\n 🚀 部署 Alloy commands...");
92
+ section("部署 Alloy commands...");
89
93
  if (opts.targetAgents.length === 0) {
90
- console.log("未选择任何 AI 工具,跳过 command 部署");
94
+ warn("未选择任何 AI 工具,跳过 command 部署");
91
95
  }
92
96
  else {
93
97
  try {
94
98
  const paths = await deployCommands(opts);
95
99
  for (const p of paths) {
96
- console.log(` ✓ ${p}`);
100
+ success(p);
97
101
  }
98
102
  }
99
103
  catch (e) {
100
- console.error(`command 部署失败: ${e.message}`);
104
+ error(`command 部署失败: ${e.message}`);
101
105
  process.exit(1);
102
106
  }
103
107
  }
104
108
  const schemaPath = await deploySchema(opts);
105
- console.log(` ✓ 项目 schema → ${schemaPath}`);
109
+ success(`项目 schema → ${schemaPath}`);
106
110
  // 6. 确保 .gitignore 包含 Alloy 运行时目录
107
111
  await ensureGitignore(opts.projectPath);
108
112
  // 7. 注入 CLAUDE.md
109
113
  const injected = await injectClaudeMd(opts);
110
114
  if (injected) {
111
- console.log("CLAUDE.md → 已追加 Alloy 工作流提示");
115
+ success("CLAUDE.md → 已追加 Alloy 工作流提示");
112
116
  }
113
117
  // 8. 兼容性检查
114
- console.log("\n 🩺 兼容性检查...");
118
+ section("兼容性检查...");
115
119
  const packageDir = getPackageRoot();
116
120
  const results = await runHealthCheck(packageDir, opts.projectPath, opts.scope);
117
121
  for (const r of results) {
118
- const mark = r.status === "pass" ? "✓" : r.status === "warn" ? "⚠️" : "✗";
119
- console.log(` ${mark} ${r.name} ${r.current}(要求 ${r.required})`);
122
+ check(r.name, `${r.current}(要求 ${r.required})`, r.status);
120
123
  }
121
124
  // 9. 自动注册 shell 补全(失败不阻断 init)
122
- console.log("\n 🐚 注册 shell 补全...");
125
+ section("注册 shell 补全...");
123
126
  try {
124
127
  const home = process.env.HOME || process.env.USERPROFILE || "~";
125
128
  const shell = process.env.SHELL || "";
@@ -149,20 +152,20 @@ export async function initCommand(opts) {
149
152
  "",
150
153
  ].join("\n");
151
154
  await writeFile(rcFile, rcContent.trimEnd() + block, "utf-8");
152
- console.log(`shell 补全已注册 → ${rcFile}`);
155
+ success(`shell 补全已注册 → ${rcFile}`);
153
156
  }
154
157
  else {
155
- console.log("shell 补全已存在,跳过");
158
+ success("shell 补全已存在,跳过");
156
159
  }
157
160
  }
158
161
  else {
159
- console.log("未检测到 bash/zsh,跳过补全注册");
162
+ warn("未检测到 bash/zsh,跳过补全注册");
160
163
  }
161
164
  }
162
165
  catch {
163
166
  // 注册失败不阻断 init,静默忽略
164
167
  }
165
- console.log("\n ✅ Alloy 就绪!");
166
- console.log(" 在 Claude Code 中输入 /alloy:start <topic> 开始工作\n");
168
+ banner("✅ Alloy 就绪!");
169
+ info("在 Claude Code 中输入 /alloy:start <topic> 开始工作\n");
167
170
  }
168
171
  //# sourceMappingURL=init.js.map