@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.
- package/README.md +28 -90
- package/commands/alloy/apply.md +274 -119
- package/commands/alloy/archive.md +116 -60
- package/commands/alloy/discard.md +57 -15
- package/commands/alloy/finish.md +92 -70
- package/commands/alloy/fix.md +282 -53
- package/commands/alloy/plan.md +125 -63
- package/commands/alloy/references/interaction-style.md +82 -0
- package/commands/alloy/references/main-branch-detection.md +32 -0
- package/commands/alloy/references/phase-routing.md +21 -0
- package/commands/alloy/references/skill-precheck.md +46 -0
- package/commands/alloy/start.md +167 -64
- package/commands/alloy/status.md +1 -1
- package/dist/cli/commands/doctor.d.ts +1 -0
- package/dist/cli/commands/doctor.js +28 -6
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/init.js +40 -37
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/internal/config.d.ts +1 -0
- package/dist/cli/commands/internal/config.js +45 -0
- package/dist/cli/commands/internal/config.js.map +1 -0
- package/dist/cli/commands/internal/guard.js +2 -41
- package/dist/cli/commands/internal/guard.js.map +1 -1
- package/dist/cli/commands/internal/record.js +10 -47
- package/dist/cli/commands/internal/record.js.map +1 -1
- package/dist/cli/commands/internal/skill-usage.d.ts +1 -0
- package/dist/cli/commands/internal/skill-usage.js +78 -0
- package/dist/cli/commands/internal/skill-usage.js.map +1 -0
- package/dist/cli/commands/internal/state.js +105 -6
- package/dist/cli/commands/internal/state.js.map +1 -1
- package/dist/cli/commands/status.d.ts +1 -0
- package/dist/cli/commands/status.js +50 -11
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/update.js +20 -17
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/index.js +73 -31
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/utils/hash.d.ts +3 -0
- package/dist/cli/utils/hash.js +42 -0
- package/dist/cli/utils/hash.js.map +1 -0
- package/dist/cli/utils/state.d.ts +4 -2
- package/dist/cli/utils/state.js +34 -2
- package/dist/cli/utils/state.js.map +1 -1
- package/dist/core/artifacts.d.ts +3 -0
- package/dist/core/artifacts.js +45 -0
- package/dist/core/artifacts.js.map +1 -0
- package/dist/core/detect-installations.d.ts +19 -0
- package/dist/core/detect-installations.js +65 -0
- package/dist/core/detect-installations.js.map +1 -0
- package/dist/core/openspec.d.ts +2 -1
- package/dist/core/openspec.js +30 -12
- package/dist/core/openspec.js.map +1 -1
- package/dist/core/skills.js +16 -0
- package/dist/core/skills.js.map +1 -1
- package/dist/core/superpowers.d.ts +8 -1
- package/dist/core/superpowers.js +60 -13
- package/dist/core/superpowers.js.map +1 -1
- package/dist/core/types.d.ts +20 -0
- package/dist/utils/format.d.ts +31 -0
- package/dist/utils/format.js +101 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/output.d.ts +16 -0
- package/dist/utils/output.js +38 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/prompt.d.ts +0 -1
- package/dist/utils/prompt.js +11 -83
- package/dist/utils/prompt.js.map +1 -1
- package/openspec/schemas/alloy/instructions/retrospective.md +17 -35
- package/openspec/schemas/alloy/templates/design.md +2 -0
- package/openspec/schemas/alloy/templates/draft.md +2 -0
- package/openspec/schemas/alloy/templates/plans.md +2 -0
- package/openspec/schemas/alloy/templates/proposal.md +2 -0
- package/openspec/schemas/alloy/templates/retrospective.md +39 -19
- package/openspec/schemas/alloy/templates/specs.md +2 -0
- package/openspec/schemas/alloy/templates/tasks.md +2 -0
- package/package.json +10 -3
- package/vendor/superpowers/skills/brainstorming/SKILL.md +164 -0
- package/vendor/superpowers/skills/brainstorming/scripts/frame-template.html +214 -0
- package/vendor/superpowers/skills/brainstorming/scripts/helper.js +88 -0
- package/vendor/superpowers/skills/brainstorming/scripts/server.cjs +354 -0
- package/vendor/superpowers/skills/brainstorming/scripts/start-server.sh +148 -0
- package/vendor/superpowers/skills/brainstorming/scripts/stop-server.sh +56 -0
- package/vendor/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/vendor/superpowers/skills/brainstorming/visual-companion.md +287 -0
- package/vendor/superpowers/skills/dispatching-parallel-agents/SKILL.md +182 -0
- package/vendor/superpowers/skills/executing-plans/SKILL.md +70 -0
- package/vendor/superpowers/skills/finishing-a-development-branch/SKILL.md +251 -0
- package/vendor/superpowers/skills/receiving-code-review/SKILL.md +213 -0
- package/vendor/superpowers/skills/requesting-code-review/SKILL.md +103 -0
- package/vendor/superpowers/skills/requesting-code-review/code-reviewer.md +168 -0
- package/vendor/superpowers/skills/subagent-driven-development/SKILL.md +279 -0
- package/vendor/superpowers/skills/subagent-driven-development/code-quality-reviewer-prompt.md +25 -0
- package/vendor/superpowers/skills/subagent-driven-development/implementer-prompt.md +113 -0
- package/vendor/superpowers/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/vendor/superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/vendor/superpowers/skills/systematic-debugging/SKILL.md +296 -0
- package/vendor/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/vendor/superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/vendor/superpowers/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/vendor/superpowers/skills/systematic-debugging/find-polluter.sh +63 -0
- package/vendor/superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/vendor/superpowers/skills/systematic-debugging/test-academic.md +14 -0
- package/vendor/superpowers/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/vendor/superpowers/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/vendor/superpowers/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/vendor/superpowers/skills/test-driven-development/SKILL.md +371 -0
- package/vendor/superpowers/skills/test-driven-development/testing-anti-patterns.md +299 -0
- package/vendor/superpowers/skills/using-git-worktrees/SKILL.md +215 -0
- package/vendor/superpowers/skills/using-superpowers/SKILL.md +117 -0
- package/vendor/superpowers/skills/using-superpowers/references/codex-tools.md +59 -0
- package/vendor/superpowers/skills/using-superpowers/references/copilot-tools.md +42 -0
- package/vendor/superpowers/skills/using-superpowers/references/gemini-tools.md +51 -0
- package/vendor/superpowers/skills/verification-before-completion/SKILL.md +139 -0
- package/vendor/superpowers/skills/writing-plans/SKILL.md +152 -0
- package/vendor/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
- package/vendor/superpowers/skills/writing-skills/SKILL.md +655 -0
- package/vendor/superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -0
- package/vendor/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
- package/vendor/superpowers/skills/writing-skills/graphviz-conventions.dot +172 -0
- package/vendor/superpowers/skills/writing-skills/persuasion-principles.md +187 -0
- package/vendor/superpowers/skills/writing-skills/render-graphs.js +168 -0
- package/vendor/superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -0
package/commands/alloy/start.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "Alloy: Start"
|
|
3
|
-
description:
|
|
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>`。`<
|
|
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
|
-
|
|
30
|
+
**捕获阶段启动时间**(命令调用后第一时间输出当前时间,agent 捕获输出值后在 header 和 phase_timings 中复用):
|
|
31
31
|
```bash
|
|
32
|
-
|
|
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
|
-
│ 启动时间:
|
|
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
|
-
|
|
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
|
-
|
|
114
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
>
|
|
202
|
+
> 1. 切换到已有分支 —— 选择非主分支的已有分支
|
|
203
|
+
> 2. 新建分支 —— 创建新 feature 分支并切换
|
|
204
|
+
|
|
205
|
+
无可用本地非主分支时 → 直接进入新建分支流程(跳过选项 1)。
|
|
206
|
+
|
|
207
|
+
每个 change 必须有独立的 feature 分支,确保 discard 时可安全清理。
|
|
153
208
|
|
|
154
|
-
- **选 1:**
|
|
155
|
-
- **选 2:**
|
|
156
|
-
-
|
|
157
|
-
|
|
158
|
-
-
|
|
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
|
|
225
|
+
alloy _state init openspec/changes/<name>
|
|
163
226
|
```
|
|
164
227
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
233
|
+
6. **记录分支信息**——将 feature_branch 和 worktree null 写入 state:
|
|
170
234
|
```bash
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
270
|
+
**记录阶段时间 + draft hash-lock + commit:**
|
|
188
271
|
```bash
|
|
189
272
|
COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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 "
|
|
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
|
-
│ 耗时:
|
|
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
|
-
|
|
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 不存在 |
|
|
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
|
-
**实现方式:**
|
|
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 但磁盘不存在"
|
package/commands/alloy/status.md
CHANGED
|
@@ -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"
|
|
80
|
-
|
|
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":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;
|
|
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/", "
|
|
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
|
-
|
|
45
|
+
success(`.gitignore → 已追加 ${missing.length} 条规则`);
|
|
45
46
|
}
|
|
46
47
|
export async function initCommand(opts) {
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
// 1. 环境检测(detectEnv 是同步操作,无需 spinner)
|
|
49
|
+
section("检测环境...");
|
|
49
50
|
const env = detectEnv();
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
55
|
+
error("❌ 缺少必要依赖,请先安装 git");
|
|
55
56
|
process.exit(1);
|
|
56
57
|
}
|
|
57
58
|
// 2. 安装 OpenSpec CLI(npm 全局包)
|
|
58
|
-
|
|
59
|
+
section("安装 OpenSpec CLI...");
|
|
59
60
|
const openspecResult = await installOpenSpecCli();
|
|
60
61
|
if (openspecResult === "installed") {
|
|
61
|
-
|
|
62
|
+
success("@fission-ai/openspec@1 已安装");
|
|
62
63
|
}
|
|
63
64
|
else if (openspecResult === "failed") {
|
|
64
|
-
|
|
65
|
+
error("OpenSpec CLI 安装失败");
|
|
65
66
|
process.exit(1);
|
|
66
67
|
}
|
|
67
68
|
// "skipped" — 函数内部已输出跳过信息
|
|
68
69
|
// 3. 初始化 OpenSpec 项目结构(openspec/ 目录 + .claude/commands/opsx/)
|
|
69
|
-
|
|
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
|
-
|
|
73
|
+
error("OpenSpec 项目初始化失败");
|
|
73
74
|
process.exit(1);
|
|
74
75
|
}
|
|
75
76
|
// 4. 安装 Superpowers
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
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 === "
|
|
82
|
-
|
|
83
|
+
else if (superpowersResult.status === "failed") {
|
|
84
|
+
warn("Superpowers 安装失败,请稍后手动运行 alloy init 重试");
|
|
83
85
|
}
|
|
84
|
-
else {
|
|
85
|
-
|
|
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
|
-
|
|
92
|
+
section("部署 Alloy commands...");
|
|
89
93
|
if (opts.targetAgents.length === 0) {
|
|
90
|
-
|
|
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
|
-
|
|
100
|
+
success(p);
|
|
97
101
|
}
|
|
98
102
|
}
|
|
99
103
|
catch (e) {
|
|
100
|
-
|
|
104
|
+
error(`command 部署失败: ${e.message}`);
|
|
101
105
|
process.exit(1);
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
108
|
const schemaPath = await deploySchema(opts);
|
|
105
|
-
|
|
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
|
-
|
|
115
|
+
success("CLAUDE.md → 已追加 Alloy 工作流提示");
|
|
112
116
|
}
|
|
113
117
|
// 8. 兼容性检查
|
|
114
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
155
|
+
success(`shell 补全已注册 → ${rcFile}`);
|
|
153
156
|
}
|
|
154
157
|
else {
|
|
155
|
-
|
|
158
|
+
success("shell 补全已存在,跳过");
|
|
156
159
|
}
|
|
157
160
|
}
|
|
158
161
|
else {
|
|
159
|
-
|
|
162
|
+
warn("未检测到 bash/zsh,跳过补全注册");
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
catch {
|
|
163
166
|
// 注册失败不阻断 init,静默忽略
|
|
164
167
|
}
|
|
165
|
-
|
|
166
|
-
|
|
168
|
+
banner("✅ Alloy 就绪!");
|
|
169
|
+
info("在 Claude Code 中输入 /alloy:start <topic> 开始工作\n");
|
|
167
170
|
}
|
|
168
171
|
//# sourceMappingURL=init.js.map
|