flower-trellis 0.1.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 +113 -0
- package/bin/flower-trellis.js +4 -0
- package/enhancements/0.5/.agents/skills/trellis-analyze-task/SKILL.md +142 -0
- package/enhancements/0.5/.agents/skills/trellis-check-all/SKILL.md +324 -0
- package/enhancements/0.5/.agents/skills/trellis-create-command/SKILL.md +258 -0
- package/enhancements/0.5/.agents/skills/trellis-create-prd/SKILL.md +197 -0
- package/enhancements/0.5/.agents/skills/trellis-draw-uml/SKILL.md +148 -0
- package/enhancements/0.5/.agents/skills/trellis-migrate-skill/SKILL.md +216 -0
- package/enhancements/0.5/.agents/skills/trellis-plan-version/SKILL.md +140 -0
- package/enhancements/0.5/.agents/skills/trellis-push/SKILL.md +240 -0
- package/enhancements/0.5/.agents/skills/trellis-re-implement/SKILL.md +166 -0
- package/enhancements/0.5/.agents/skills/trellis-route/SKILL.md +159 -0
- package/enhancements/0.5/.agents/skills/trellis-run-full-chain/SKILL.md +402 -0
- package/enhancements/0.5/.agents/skills/trellis-sync-prd/SKILL.md +150 -0
- package/enhancements/0.5/.agents/skills/trellis-verify-prd/SKILL.md +217 -0
- package/enhancements/0.5/.claude/skills/trellis-analyze-task/SKILL.md +142 -0
- package/enhancements/0.5/.claude/skills/trellis-check-all/SKILL.md +324 -0
- package/enhancements/0.5/.claude/skills/trellis-create-command/SKILL.md +258 -0
- package/enhancements/0.5/.claude/skills/trellis-create-prd/SKILL.md +197 -0
- package/enhancements/0.5/.claude/skills/trellis-draw-uml/SKILL.md +148 -0
- package/enhancements/0.5/.claude/skills/trellis-migrate-skill/SKILL.md +216 -0
- package/enhancements/0.5/.claude/skills/trellis-plan-version/SKILL.md +140 -0
- package/enhancements/0.5/.claude/skills/trellis-push/SKILL.md +240 -0
- package/enhancements/0.5/.claude/skills/trellis-re-implement/SKILL.md +166 -0
- package/enhancements/0.5/.claude/skills/trellis-route/SKILL.md +159 -0
- package/enhancements/0.5/.claude/skills/trellis-run-full-chain/SKILL.md +402 -0
- package/enhancements/0.5/.claude/skills/trellis-sync-prd/SKILL.md +150 -0
- package/enhancements/0.5/.claude/skills/trellis-verify-prd/SKILL.md +217 -0
- package/enhancements/0.5/overrides/trellis-route.md +52 -0
- package/enhancements/0.6/.agents/skills/trellis-check-all/SKILL.md +342 -0
- package/enhancements/0.6/.agents/skills/trellis-create-command/SKILL.md +293 -0
- package/enhancements/0.6/.agents/skills/trellis-draw-uml/SKILL.md +148 -0
- package/enhancements/0.6/.agents/skills/trellis-extract-prd/SKILL.md +197 -0
- package/enhancements/0.6/.agents/skills/trellis-plan-version/SKILL.md +140 -0
- package/enhancements/0.6/.agents/skills/trellis-push/SKILL.md +316 -0
- package/enhancements/0.6/.agents/skills/trellis-route/SKILL.md +159 -0
- package/enhancements/0.6/.agents/skills/trellis-run-full-chain/SKILL.md +402 -0
- package/enhancements/0.6/.agents/skills/trellis-verify-task/SKILL.md +360 -0
- package/enhancements/0.6/.claude/skills/trellis-check-all/SKILL.md +342 -0
- package/enhancements/0.6/.claude/skills/trellis-create-command/SKILL.md +293 -0
- package/enhancements/0.6/.claude/skills/trellis-draw-uml/SKILL.md +148 -0
- package/enhancements/0.6/.claude/skills/trellis-extract-prd/SKILL.md +197 -0
- package/enhancements/0.6/.claude/skills/trellis-plan-version/SKILL.md +140 -0
- package/enhancements/0.6/.claude/skills/trellis-push/SKILL.md +316 -0
- package/enhancements/0.6/.claude/skills/trellis-route/SKILL.md +159 -0
- package/enhancements/0.6/.claude/skills/trellis-run-full-chain/SKILL.md +402 -0
- package/enhancements/0.6/.claude/skills/trellis-verify-task/SKILL.md +360 -0
- package/enhancements/0.6/overrides/workflow-states/in_progress-inline.md +5 -0
- package/enhancements/0.6/overrides/workflow-states/in_progress.md +7 -0
- package/enhancements/0.6/overrides/workflow-states/no_task.md +6 -0
- package/enhancements/0.6/overrides/workflow-states/planning.md +6 -0
- package/enhancements/0.6/overrides/workflow.md +53 -0
- package/enhancements/MANIFEST.json +109 -0
- package/enhancements/old/.agents/skills/analyze-task/SKILL.md +143 -0
- package/enhancements/old/.agents/skills/check-all/SKILL.md +128 -0
- package/enhancements/old/.agents/skills/check-impl/SKILL.md +159 -0
- package/enhancements/old/.agents/skills/check-prd/SKILL.md +219 -0
- package/enhancements/old/.agents/skills/check-prd-impl/SKILL.md +190 -0
- package/enhancements/old/.agents/skills/create-prd/SKILL.md +154 -0
- package/enhancements/old/.agents/skills/draw-uml/SKILL.md +148 -0
- package/enhancements/old/.agents/skills/plan-version/SKILL.md +140 -0
- package/enhancements/old/.agents/skills/push/SKILL.md +191 -0
- package/enhancements/old/.agents/skills/re-implement/SKILL.md +166 -0
- package/enhancements/old/.agents/skills/sync-prd/SKILL.md +146 -0
- package/enhancements/old/.claude/commands/trellis/analyze-task.md +139 -0
- package/enhancements/old/.claude/commands/trellis/check-all.md +124 -0
- package/enhancements/old/.claude/commands/trellis/check-impl.md +154 -0
- package/enhancements/old/.claude/commands/trellis/check-prd-impl.md +186 -0
- package/enhancements/old/.claude/commands/trellis/check-prd.md +215 -0
- package/enhancements/old/.claude/commands/trellis/create-prd.md +150 -0
- package/enhancements/old/.claude/commands/trellis/draw-uml.md +144 -0
- package/enhancements/old/.claude/commands/trellis/plan-version.md +136 -0
- package/enhancements/old/.claude/commands/trellis/push.md +187 -0
- package/enhancements/old/.claude/commands/trellis/re-implement.md +162 -0
- package/enhancements/old/.claude/commands/trellis/sync-prd.md +142 -0
- package/package.json +39 -0
- package/src/cli.js +151 -0
- package/src/commands/init.js +66 -0
- package/src/commands/uninstall.js +85 -0
- package/src/commands/update.js +42 -0
- package/src/constants.js +50 -0
- package/src/lib/apply-enhancements.js +133 -0
- package/src/lib/banner.js +45 -0
- package/src/lib/codex-tweaks.js +112 -0
- package/src/lib/copy-skills.js +91 -0
- package/src/lib/fs-utils.js +60 -0
- package/src/lib/legacy-blocks.js +70 -0
- package/src/lib/manifest.js +32 -0
- package/src/lib/paths.js +16 -0
- package/src/lib/pick-platforms.js +57 -0
- package/src/lib/trellis-runner.js +190 -0
- package/src/lib/variant.js +40 -0
- package/src/lib/versions.js +30 -0
- package/src/lib/workflow-inject.js +193 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# 二次实现 - 需求变更后重新调用 Implement Agent
|
|
2
|
+
|
|
3
|
+
当任务实施过程中出现需求漂移或变动时,重新调用 Implement Agent 实现更新后的需求。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 使用场景
|
|
8
|
+
|
|
9
|
+
- 任务已通过 `/trellis:start` 完成了首次实现
|
|
10
|
+
- 实施过程中需求发生了变更或补充
|
|
11
|
+
- PRD 已更新,需要 Implement Agent 根据新需求重新实现
|
|
12
|
+
- 用户在 check 或测试阶段发现需要调整方向
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 前置条件
|
|
17
|
+
|
|
18
|
+
- 当前任务已激活(`.trellis/.current-task` 已设置)
|
|
19
|
+
- 任务目录下存在 `prd.md`(已更新为最新需求)
|
|
20
|
+
- 任务目录下存在 `implement.jsonl`(code-spec context 配置)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 执行步骤
|
|
25
|
+
|
|
26
|
+
### Step 1: 确认当前任务状态 `[AI]`
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
python3 ./.trellis/scripts/get_context.py
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
确认:
|
|
33
|
+
- 当前任务存在且已激活
|
|
34
|
+
- 任务目录路径
|
|
35
|
+
|
|
36
|
+
如果没有激活的任务,提示用户先通过 `/trellis:start` 开始任务。
|
|
37
|
+
|
|
38
|
+
### Step 2: 了解变更内容 `[AI]`
|
|
39
|
+
|
|
40
|
+
读取当前 PRD 和已有代码变更,理解上下文:
|
|
41
|
+
|
|
42
|
+
1. 读取 `prd.md` 了解当前需求
|
|
43
|
+
2. 运行 `git diff --name-only` 了解已有代码变更
|
|
44
|
+
3. 询问用户:需求哪里变了?
|
|
45
|
+
|
|
46
|
+
### Step 3: 更新 PRD `[AI]`
|
|
47
|
+
|
|
48
|
+
根据用户描述的变更,更新 `prd.md`:
|
|
49
|
+
|
|
50
|
+
- 在 `## Requirements` 中标注新增/修改/删除的需求
|
|
51
|
+
- 更新 `## Acceptance Criteria`
|
|
52
|
+
- 在 `## Technical Notes` 中记录变更原因
|
|
53
|
+
|
|
54
|
+
**格式建议**(在 PRD 中追加):
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
## 变更记录
|
|
58
|
+
|
|
59
|
+
### 变更 1: <变更标题> (YYYY-MM-DD)
|
|
60
|
+
- **原需求**: <原来是什么>
|
|
61
|
+
- **新需求**: <现在要什么>
|
|
62
|
+
- **原因**: <为什么要改>
|
|
63
|
+
- **影响范围**: <哪些已实现的代码需要调整>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Step 4: 评估是否需要更新 Context 配置 `[AI]`
|
|
67
|
+
|
|
68
|
+
判断变更是否涉及新的模块或规范:
|
|
69
|
+
|
|
70
|
+
- 如果**不涉及新模块**:直接进入 Step 5
|
|
71
|
+
- 如果**涉及新模块**:先补充 context 配置
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# 需要时追加 code-spec context
|
|
75
|
+
python3 ./.trellis/scripts/task.py add-context "$TASK_DIR" implement "<新路径>" "<原因>"
|
|
76
|
+
python3 ./.trellis/scripts/task.py add-context "$TASK_DIR" check "<新路径>" "<原因>"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Step 5: 调用 Implement Agent `[AI]`
|
|
80
|
+
|
|
81
|
+
调用 Implement Agent 执行二次实现(code-spec context 由 hook 自动注入):
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
Agent(
|
|
85
|
+
subagent_type: "implement",
|
|
86
|
+
prompt: "基于更新后的 prd.md 重新实现任务。
|
|
87
|
+
|
|
88
|
+
注意:这是一次需求变更后的二次实现。
|
|
89
|
+
- 阅读 prd.md 中的「变更记录」章节,理解哪些需求发生了变化
|
|
90
|
+
- 保留已有的正确实现,只修改需要调整的部分
|
|
91
|
+
- 如果变更涉及已实现的逻辑,确保修改后不破坏原有功能
|
|
92
|
+
- 遵循所有已注入的 code-spec 规范
|
|
93
|
+
- 完成后报告修改/新增的文件列表",
|
|
94
|
+
model: "opus"
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Step 6: 调用 Check Agent `[AI]`
|
|
99
|
+
|
|
100
|
+
实现完成后,调用 Check Agent 验证(code-spec context 由 hook 自动注入):
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
Agent(
|
|
104
|
+
subagent_type: "check",
|
|
105
|
+
prompt: "检查所有代码变更是否符合 code-spec 规范。
|
|
106
|
+
|
|
107
|
+
重点关注:
|
|
108
|
+
- 二次实现是否正确反映了 prd.md 中的变更需求
|
|
109
|
+
- 新旧代码之间是否存在不一致
|
|
110
|
+
- 修改是否引入了回归问题
|
|
111
|
+
- 直接修复发现的问题
|
|
112
|
+
- 确保 lint 和 typecheck 通过",
|
|
113
|
+
model: "opus"
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Step 7: 报告结果 `[AI]`
|
|
118
|
+
|
|
119
|
+
输出二次实现的结果摘要:
|
|
120
|
+
|
|
121
|
+
```markdown
|
|
122
|
+
## 二次实现完成
|
|
123
|
+
|
|
124
|
+
### 需求变更
|
|
125
|
+
- <变更点 1>
|
|
126
|
+
- <变更点 2>
|
|
127
|
+
|
|
128
|
+
### 代码变更
|
|
129
|
+
- <修改的文件 1>: <做了什么>
|
|
130
|
+
- <修改的文件 2>: <做了什么>
|
|
131
|
+
|
|
132
|
+
### 验证状态
|
|
133
|
+
- [ ] Lint 通过
|
|
134
|
+
- [ ] Typecheck 通过
|
|
135
|
+
- [ ] Check Agent 验证通过
|
|
136
|
+
|
|
137
|
+
### 下一步
|
|
138
|
+
- 测试变更
|
|
139
|
+
- 确认无误后提交
|
|
140
|
+
- 运行 `/trellis:finish-work` 检查清单
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 与其他命令的关系
|
|
146
|
+
|
|
147
|
+
| 命令 | 阶段 | 说明 |
|
|
148
|
+
|------|------|------|
|
|
149
|
+
| `/trellis:start` | 首次实现 | 完整流程:Research → Context → Implement → Check |
|
|
150
|
+
| `/trellis:re-implement` | 二次实现 | 需求变更后:更新 PRD → Implement → Check |
|
|
151
|
+
| `/trellis:finish-work` | 完成 | 提交前检查清单 |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 核心原则
|
|
156
|
+
|
|
157
|
+
| 原则 | 说明 |
|
|
158
|
+
|------|------|
|
|
159
|
+
| **增量修改** | 保留正确的已有实现,只改变需要调整的部分 |
|
|
160
|
+
| **PRD 先行** | 先更新 PRD 再调 Implement Agent,确保上下文准确 |
|
|
161
|
+
| **Context 自动注入** | implement.jsonl + prd.md 由 hook 自动注入,无需手动传递 |
|
|
162
|
+
| **记录变更原因** | 在 PRD 变更记录中说明为什么改、改了什么 |
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# 同步 PRD - 代码/需求变更后回补 PRD
|
|
2
|
+
|
|
3
|
+
当你直接修改了任务相关的代码或需求,但没有同步更新任务的 `prd.md` 时,使用此命令将 PRD 与实际变更对齐。
|
|
4
|
+
|
|
5
|
+
**时机**:代码或需求已变更,但 PRD 未同步更新
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 使用场景
|
|
10
|
+
|
|
11
|
+
- 直接改了代码逻辑,但没更新 PRD 中的需求描述
|
|
12
|
+
- 用户口头调整了需求,代码已改但 PRD 仍是旧版本
|
|
13
|
+
- Code Review 后修改了实现方式,PRD 未反映
|
|
14
|
+
- 多次小修改累积后,PRD 与实际实现已出现偏差
|
|
15
|
+
- 任务完成前的最终检查,确认 PRD 是文档真实来源
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 执行步骤
|
|
20
|
+
|
|
21
|
+
### Step 1: 确认当前任务 `[AI]`
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
python3 ./.trellis/scripts/get_context.py
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
确认:
|
|
28
|
+
- 当前有激活的任务(`.trellis/.current-task` 已设置)
|
|
29
|
+
- 任务目录路径和 PRD 文件存在
|
|
30
|
+
|
|
31
|
+
如果没有激活的任务,询问用户要同步哪个任务的 PRD。
|
|
32
|
+
|
|
33
|
+
### Step 2: 读取现有 PRD `[AI]`
|
|
34
|
+
|
|
35
|
+
读取任务目录下的 `prd.md`,理解当前文档化的需求。
|
|
36
|
+
|
|
37
|
+
### Step 3: 收集实际变更 `[AI]`
|
|
38
|
+
|
|
39
|
+
从多个来源收集实际变更信息:
|
|
40
|
+
|
|
41
|
+
**3a. 代码变更**(如有):
|
|
42
|
+
```bash
|
|
43
|
+
# 查看当前未提交的变更
|
|
44
|
+
cd srm-boot && git diff --name-only && git diff --cached --name-only
|
|
45
|
+
# 查看最近与任务相关的提交
|
|
46
|
+
cd srm-boot && git log --oneline -20
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**3b. 用户描述**:
|
|
50
|
+
- 询问用户:"相比 PRD 中记录的内容,实际做了哪些不同的变更?"
|
|
51
|
+
- 提供多选引导:
|
|
52
|
+
- 需求范围变了(增加/删减了功能点)
|
|
53
|
+
- 实现方式变了(技术方案调整)
|
|
54
|
+
- 接口/字段变了(API、数据库、DTO 等)
|
|
55
|
+
- 业务规则变了(校验逻辑、流程等)
|
|
56
|
+
- 其他
|
|
57
|
+
|
|
58
|
+
### Step 4: 对比分析 `[AI]`
|
|
59
|
+
|
|
60
|
+
将 PRD 内容与实际变更进行对比,识别差异:
|
|
61
|
+
|
|
62
|
+
```markdown
|
|
63
|
+
## PRD 偏差分析
|
|
64
|
+
|
|
65
|
+
### 新增(PRD 中没有,但实际已实现)
|
|
66
|
+
- <变更 1>
|
|
67
|
+
|
|
68
|
+
### 删除(PRD 中有,但实际未实现或已移除)
|
|
69
|
+
- <变更 2>
|
|
70
|
+
|
|
71
|
+
### 修改(PRD 描述与实际实现不一致)
|
|
72
|
+
- <变更 3>: PRD 说 X,实际是 Y
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
将分析结果展示给用户确认。
|
|
76
|
+
|
|
77
|
+
### Step 5: 更新 PRD `[AI]`
|
|
78
|
+
|
|
79
|
+
经用户确认后,更新 `prd.md`:
|
|
80
|
+
|
|
81
|
+
1. **更新主体内容**:修改 Goal、Requirements、Acceptance Criteria 等章节,使其反映实际状态
|
|
82
|
+
2. **追加变更记录**:在文末追加变更日志
|
|
83
|
+
|
|
84
|
+
**变更记录格式**:
|
|
85
|
+
|
|
86
|
+
```markdown
|
|
87
|
+
## 变更记录
|
|
88
|
+
|
|
89
|
+
### 变更 <N>: <简要描述> (YYYY-MM-DD)
|
|
90
|
+
- **变更类型**: 需求变更 / 实现调整 / 范围变更
|
|
91
|
+
- **变更内容**: <具体改了什么>
|
|
92
|
+
- **原因**: <为什么改>
|
|
93
|
+
- **PRD 同步方式**: 事后回补(代码先行)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Step 6: 报告结果 `[AI]`
|
|
97
|
+
|
|
98
|
+
```markdown
|
|
99
|
+
## PRD 同步完成
|
|
100
|
+
|
|
101
|
+
### 偏差摘要
|
|
102
|
+
- 新增 <N> 项需求/实现
|
|
103
|
+
- 删除 <N> 项需求/实现
|
|
104
|
+
- 修改 <N> 项描述
|
|
105
|
+
|
|
106
|
+
### 更新的章节
|
|
107
|
+
- <章节 1>: <做了什么调整>
|
|
108
|
+
- <章节 2>: <做了什么调整>
|
|
109
|
+
|
|
110
|
+
### 下一步
|
|
111
|
+
- 确认 PRD 内容准确
|
|
112
|
+
- 如有后续开发,PRD 已可作为最新参考
|
|
113
|
+
- 如任务已完成,可运行 `/trellis:finish-work`
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 与其他命令的关系
|
|
119
|
+
|
|
120
|
+
| 命令 | 阶段 | 说明 |
|
|
121
|
+
|------|------|------|
|
|
122
|
+
| `/trellis:brainstorm` | 需求梳理 | PRD 从零创建,边讨论边完善 |
|
|
123
|
+
| `/trellis:re-implement` | 需求变更 | 先更新 PRD,再调 Implement Agent |
|
|
124
|
+
| `/trellis:sync-prd` | 事后回补 | 代码已改,PRD 未同步,回补文档 |
|
|
125
|
+
| `/trellis:finish-work` | 完成检查 | 提交前整体检查清单 |
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
典型流程:
|
|
129
|
+
PRD → 实现 → PRD 同步 # 理想流程(re-implement)
|
|
130
|
+
PRD → 实现 → 偏差 → sync-prd # 补救流程(本命令)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 核心原则
|
|
136
|
+
|
|
137
|
+
| 原则 | 说明 |
|
|
138
|
+
|------|------|
|
|
139
|
+
| **PRD 是真实来源** | PRD 应始终反映任务的最新状态,而非初始计划 |
|
|
140
|
+
| **事后回补优于不补** | 即使是事后同步,也比让 PRD 过时不管要好 |
|
|
141
|
+
| **记录变更原因** | 追加变更记录,让后续开发者理解演变过程 |
|
|
142
|
+
| **用户确认为准** | 对比分析需经用户确认后再更新,避免错误同步 |
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "flower-trellis",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "一键安装/升级 Trellis 并自动融合 skill-garden 强化包(默认 Claude + agents)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"flower-trellis": "./bin/flower-trellis.js",
|
|
8
|
+
"ftl": "./bin/flower-trellis.js"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=18.17.0"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@mindfoldhq/trellis": "0.6.0-beta.8",
|
|
15
|
+
"chalk": "^5.6.2",
|
|
16
|
+
"figlet": "^1.11.0",
|
|
17
|
+
"inquirer": "^9.3.8",
|
|
18
|
+
"node-pty": "^1.1.0"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"bin",
|
|
22
|
+
"src",
|
|
23
|
+
"enhancements",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"sync": "node scripts/sync-enhancements.mjs",
|
|
28
|
+
"prepublishOnly": "node scripts/sync-enhancements.mjs"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"trellis",
|
|
32
|
+
"skill-garden",
|
|
33
|
+
"ai",
|
|
34
|
+
"workflow",
|
|
35
|
+
"claude",
|
|
36
|
+
"cli"
|
|
37
|
+
],
|
|
38
|
+
"license": "MIT"
|
|
39
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { flowerVersion, trellisVersion } from "./lib/versions.js";
|
|
4
|
+
import { selectVariant } from "./lib/variant.js";
|
|
5
|
+
import { runTrellis } from "./lib/trellis-runner.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* flower-trellis CLI 主入口。
|
|
9
|
+
*
|
|
10
|
+
* 手动解析 argv(不引入 commander):分离子命令、flower 自有 flag、透传参数。
|
|
11
|
+
* - init / update / uninstall → 走增强逻辑;
|
|
12
|
+
* - 其它子命令 → 兜底透传给 trellis(覆盖现有及未来命令)。
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** 打印版本:flower-trellis 自身 + 捆绑的 Trellis;若在 Trellis 项目内附带项目版本。 */
|
|
16
|
+
function printVersion(cwd) {
|
|
17
|
+
console.log(`flower-trellis ${flowerVersion()}`);
|
|
18
|
+
console.log(`trellis (bundled) ${trellisVersion()}`);
|
|
19
|
+
try {
|
|
20
|
+
if (fs.existsSync(path.join(cwd, ".trellis", ".version"))) {
|
|
21
|
+
const { version } = selectVariant(cwd);
|
|
22
|
+
if (version) console.log(`project .trellis ${version}`);
|
|
23
|
+
}
|
|
24
|
+
} catch {
|
|
25
|
+
// 忽略:版本读取失败不应影响 -v 输出
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function printHelp() {
|
|
30
|
+
console.log(`flower-trellis — 一键装/升级 Trellis 并融合 skill-garden 强化包
|
|
31
|
+
|
|
32
|
+
用法:
|
|
33
|
+
flower-trellis [init] [trellis flags] [flower flags] 安装 + 叠加强化包(默认命令)
|
|
34
|
+
flower-trellis update [trellis flags] [flower flags] 升级 + 按新版本重新叠加
|
|
35
|
+
flower-trellis uninstall [-y | --dry-run] 卸载 + 清理强化残留
|
|
36
|
+
flower-trellis <其它命令> [...] 透传给 trellis(面向未来)
|
|
37
|
+
flower-trellis -v 打印版本
|
|
38
|
+
|
|
39
|
+
flower 自有 flag:
|
|
40
|
+
--no-enhance 只跑 trellis,不叠加强化包
|
|
41
|
+
--enhance-only 跳过 trellis,只叠加(用于已有项目)
|
|
42
|
+
--skills <a,b,...> 只装指定技能(支持去 trellis- 前缀匹配)
|
|
43
|
+
--variant <old|0.5|0.6> 强制强化包变体(默认按 .trellis/.version 自动选)
|
|
44
|
+
--target <dir> 目标目录(默认当前目录)
|
|
45
|
+
|
|
46
|
+
平台选择:未指定平台时,交互模式会弹出多选菜单(默认勾 Claude Code + Codex);
|
|
47
|
+
也可直接传 --claude / --codex / --cursor 等指定,或用 -y 跳过菜单(默认 codex + claude)。
|
|
48
|
+
其余 flag 原样透传给 trellis(如 -u <name> -f --registry --template 等)。`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** 解析 argv → { command, ctx }。 */
|
|
52
|
+
function parse(argv) {
|
|
53
|
+
let command = null;
|
|
54
|
+
let enhance = true;
|
|
55
|
+
let enhanceOnly = false;
|
|
56
|
+
let variant = null;
|
|
57
|
+
let target = process.cwd();
|
|
58
|
+
const skills = [];
|
|
59
|
+
const passthrough = [];
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < argv.length; i++) {
|
|
62
|
+
const a = argv[i];
|
|
63
|
+
// 第一个非 flag token 视为子命令
|
|
64
|
+
if (command === null && !a.startsWith("-")) {
|
|
65
|
+
command = a;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
switch (a) {
|
|
69
|
+
case "--no-enhance":
|
|
70
|
+
enhance = false;
|
|
71
|
+
break;
|
|
72
|
+
case "--enhance-only":
|
|
73
|
+
enhanceOnly = true;
|
|
74
|
+
break;
|
|
75
|
+
case "--skills": {
|
|
76
|
+
const v = argv[++i] || "";
|
|
77
|
+
skills.push(...v.split(/[,\s]+/).filter(Boolean));
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
case "--variant":
|
|
81
|
+
variant = argv[++i] || null;
|
|
82
|
+
break;
|
|
83
|
+
case "--target":
|
|
84
|
+
target = path.resolve(argv[++i] || ".");
|
|
85
|
+
break;
|
|
86
|
+
default:
|
|
87
|
+
passthrough.push(a);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
command,
|
|
93
|
+
ctx: {
|
|
94
|
+
target: path.resolve(target),
|
|
95
|
+
passthrough,
|
|
96
|
+
enhance,
|
|
97
|
+
enhanceOnly,
|
|
98
|
+
skills,
|
|
99
|
+
variant,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function main() {
|
|
105
|
+
// Ctrl+C:父进程也立即退出,绝不在子进程被取消后继续叠加
|
|
106
|
+
process.on("SIGINT", () => process.exit(130));
|
|
107
|
+
|
|
108
|
+
const argv = process.argv.slice(2);
|
|
109
|
+
|
|
110
|
+
// 顶层 -v / -h 仅在作为首个参数时拦截;子命令的 --help/--version 透传给 trellis
|
|
111
|
+
if (argv[0] === "-v" || argv[0] === "--version") {
|
|
112
|
+
printVersion(process.cwd());
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (argv[0] === "-h" || argv[0] === "--help" || argv[0] === "help") {
|
|
116
|
+
printHelp();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const { command, ctx } = parse(argv);
|
|
121
|
+
const cmd = command || "init"; // 裸跑等同 init
|
|
122
|
+
|
|
123
|
+
// 互斥校验
|
|
124
|
+
if (ctx.enhanceOnly && !ctx.enhance) {
|
|
125
|
+
console.error("❌ --enhance-only 与 --no-enhance 互斥");
|
|
126
|
+
process.exit(2);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
if (cmd === "init") {
|
|
131
|
+
const { init } = await import("./commands/init.js");
|
|
132
|
+
await init(ctx);
|
|
133
|
+
} else if (cmd === "update") {
|
|
134
|
+
const { update } = await import("./commands/update.js");
|
|
135
|
+
await update(ctx);
|
|
136
|
+
} else if (cmd === "uninstall") {
|
|
137
|
+
const { uninstall } = await import("./commands/uninstall.js");
|
|
138
|
+
await uninstall(ctx);
|
|
139
|
+
} else {
|
|
140
|
+
// 兜底透传:flower-trellis <其它命令> → trellis <其它命令>
|
|
141
|
+
const code = await runTrellis([cmd, ...ctx.passthrough], ctx.target);
|
|
142
|
+
process.exit(code);
|
|
143
|
+
}
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.error(`❌ ${err.message}`);
|
|
146
|
+
if (process.env.DEBUG || process.env.FLOWER_DEBUG) console.error(err.stack);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
main();
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { runTrellisPty } from "../lib/trellis-runner.js";
|
|
3
|
+
import { applyEnhancements } from "../lib/apply-enhancements.js";
|
|
4
|
+
import { pickPlatforms } from "../lib/pick-platforms.js";
|
|
5
|
+
import { printBanner, getDeveloper } from "../lib/banner.js";
|
|
6
|
+
import { PLATFORM_FLAGS } from "../constants.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* flower-trellis init:驱动 `trellis init`,随后叠加强化包。
|
|
10
|
+
*
|
|
11
|
+
* - 非交互(-y):打印简短提示,平台默认 codex + claude(或用户显式平台)。
|
|
12
|
+
* - 交互:打印 flower 品牌头部;未指定平台则弹 flower 平台多选菜单(默认勾 codex+claude)。
|
|
13
|
+
*
|
|
14
|
+
* trellis init 在伪终端(pty)里运行,**保留它原生的模板 / monorepo 等交互**,
|
|
15
|
+
* 同时由 flower 过滤掉它重复打印的启动 banner / Developer。
|
|
16
|
+
*
|
|
17
|
+
* @param {object} ctx 见 cli.js 的 parse()
|
|
18
|
+
*/
|
|
19
|
+
export async function init(ctx) {
|
|
20
|
+
const { target } = ctx;
|
|
21
|
+
if (!fs.existsSync(target) || !fs.statSync(target).isDirectory()) {
|
|
22
|
+
throw new Error(`目标目录不存在:${target}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const passthrough = [...ctx.passthrough];
|
|
26
|
+
const hasPlatform = passthrough.some((a) => PLATFORM_FLAGS.includes(a));
|
|
27
|
+
const nonInteractive =
|
|
28
|
+
passthrough.includes("-y") || passthrough.includes("--yes");
|
|
29
|
+
|
|
30
|
+
// 交互模式打印一次 flower 品牌头部(非交互/脚本场景不打扰)
|
|
31
|
+
if (!nonInteractive) {
|
|
32
|
+
printBanner(getDeveloper(passthrough, target));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!hasPlatform) {
|
|
36
|
+
if (nonInteractive) {
|
|
37
|
+
passthrough.push("--codex", "--claude");
|
|
38
|
+
console.log("· 非交互(-y):默认平台 codex + claude");
|
|
39
|
+
} else {
|
|
40
|
+
// flower 自己出平台菜单(默认勾 codex + claude),选完转 flag 透传给 trellis
|
|
41
|
+
const picked = await pickPlatforms();
|
|
42
|
+
const flags = picked.length ? picked : ["--codex", "--claude"];
|
|
43
|
+
passthrough.push(...flags);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!ctx.enhanceOnly) {
|
|
48
|
+
// 伪终端运行:保留 trellis 的模板 / monorepo 交互 + 过滤其重复 banner
|
|
49
|
+
const code = await runTrellisPty(["init", ...passthrough], target, {
|
|
50
|
+
stripBanner: true,
|
|
51
|
+
});
|
|
52
|
+
if (code !== 0) {
|
|
53
|
+
throw new Error(`trellis init 失败(退出码 ${code}),已中止,未叠加强化包`);
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
console.log("· --enhance-only:跳过 trellis init,仅叠加强化包");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (ctx.enhance) {
|
|
60
|
+
applyEnhancements(target, { variant: ctx.variant, skills: ctx.skills });
|
|
61
|
+
} else {
|
|
62
|
+
console.log("· --no-enhance:跳过强化包叠加");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log(`\n🌸 flower-trellis init 完成 → ${target}`);
|
|
66
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { runTrellis } from "../lib/trellis-runner.js";
|
|
4
|
+
import { selectVariant } from "../lib/variant.js";
|
|
5
|
+
import { ENHANCEMENTS_ROOT } from "../lib/paths.js";
|
|
6
|
+
import { listDirs, listFiles, rmrf } from "../lib/fs-utils.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* flower-trellis uninstall:卸载 Trellis 并清理强化包残留。
|
|
10
|
+
*
|
|
11
|
+
* 背景(实读 Trellis uninstall.ts):trellis uninstall 只删它 manifest
|
|
12
|
+
* (.trellis/.template-hashes.json)记录的文件 + 整个 .trellis/。强化包铺的
|
|
13
|
+
* .claude/skills/trellis-*、.agents/skills/trellis-*、old 的 commands 不在
|
|
14
|
+
* manifest 里,会残留 —— 故卸载后由本命令补删(workflow.md/.bak 随 .trellis/ 已删)。
|
|
15
|
+
*
|
|
16
|
+
* 流程:① 卸载前(.version 还在)读变体并列出强化清单 → ② 透传 trellis uninstall
|
|
17
|
+
* → ③ 退出码 0 且非 dry-run 时,删除目标里名字精确匹配清单的强化条目。
|
|
18
|
+
*
|
|
19
|
+
* @param {object} ctx 见 cli.js 的 parse()
|
|
20
|
+
*/
|
|
21
|
+
export async function uninstall(ctx) {
|
|
22
|
+
const { target } = ctx;
|
|
23
|
+
const dryRun = ctx.passthrough.includes("--dry-run");
|
|
24
|
+
|
|
25
|
+
// 1. 卸载前确定要清理的强化条目(此时 .trellis/.version 仍存在)
|
|
26
|
+
const { variant } = selectVariant(target);
|
|
27
|
+
const variantDir = path.join(ENHANCEMENTS_ROOT, variant);
|
|
28
|
+
const skillNames = new Set([
|
|
29
|
+
...listDirs(path.join(variantDir, ".agents", "skills")),
|
|
30
|
+
...listDirs(path.join(variantDir, ".claude", "skills")),
|
|
31
|
+
]);
|
|
32
|
+
const cmdFiles = listFiles(
|
|
33
|
+
path.join(variantDir, ".claude", "commands", "trellis"),
|
|
34
|
+
".md",
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// 2. 透传 trellis uninstall
|
|
38
|
+
const code = await runTrellis(["uninstall", ...ctx.passthrough], target);
|
|
39
|
+
if (code !== 0) {
|
|
40
|
+
throw new Error(`trellis uninstall 失败(退出码 ${code}),未清理强化残留`);
|
|
41
|
+
}
|
|
42
|
+
if (dryRun) {
|
|
43
|
+
console.log("· --dry-run:trellis 仅预览,强化残留清理一并跳过");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 3. 补删强化残留(只删名字精确匹配强化清单的,避免误删用户文件)
|
|
48
|
+
let removed = 0;
|
|
49
|
+
for (const name of skillNames) {
|
|
50
|
+
for (const base of [".agents/skills", ".claude/skills"]) {
|
|
51
|
+
const p = path.join(target, ...base.split("/"), name);
|
|
52
|
+
if (fs.existsSync(p)) {
|
|
53
|
+
rmrf(p);
|
|
54
|
+
removed++;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const file of cmdFiles) {
|
|
59
|
+
const p = path.join(target, ".claude", "commands", "trellis", file);
|
|
60
|
+
if (fs.existsSync(p)) {
|
|
61
|
+
rmrf(p);
|
|
62
|
+
removed++;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 清理可能因此变空的目录(深到浅)
|
|
67
|
+
for (const d of [
|
|
68
|
+
".agents/skills",
|
|
69
|
+
".agents",
|
|
70
|
+
".claude/commands/trellis",
|
|
71
|
+
".claude/commands",
|
|
72
|
+
".claude/skills",
|
|
73
|
+
]) {
|
|
74
|
+
const abs = path.join(target, ...d.split("/"));
|
|
75
|
+
try {
|
|
76
|
+
if (fs.readdirSync(abs).length === 0) fs.rmdirSync(abs);
|
|
77
|
+
} catch {
|
|
78
|
+
// 不存在或非空,忽略
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log(
|
|
83
|
+
`\n🌸 flower-trellis uninstall 完成:补清理 ${removed} 个强化残留 → ${target}`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { runTrellisPty } from "../lib/trellis-runner.js";
|
|
2
|
+
import { applyEnhancements } from "../lib/apply-enhancements.js";
|
|
3
|
+
import { printBanner, getDeveloper } from "../lib/banner.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* flower-trellis update:驱动 `trellis update`,随后按(可能已升级的)版本重新叠加强化包。
|
|
7
|
+
*
|
|
8
|
+
* 打印 flower 品牌头部;trellis update 在伪终端(pty)里运行,保留其冲突处理等交互,
|
|
9
|
+
* 同时过滤掉它重复打印的启动 banner / Developer。
|
|
10
|
+
* `--dry-run` 时只让 trellis 预览,叠加阶段跳过。
|
|
11
|
+
*
|
|
12
|
+
* @param {object} ctx 见 cli.js 的 parse()
|
|
13
|
+
*/
|
|
14
|
+
export async function update(ctx) {
|
|
15
|
+
const { target } = ctx;
|
|
16
|
+
const dryRun = ctx.passthrough.includes("--dry-run");
|
|
17
|
+
|
|
18
|
+
printBanner(getDeveloper(ctx.passthrough, target));
|
|
19
|
+
|
|
20
|
+
if (!ctx.enhanceOnly) {
|
|
21
|
+
const code = await runTrellisPty(["update", ...ctx.passthrough], target, {
|
|
22
|
+
stripBanner: true,
|
|
23
|
+
});
|
|
24
|
+
if (code !== 0) {
|
|
25
|
+
throw new Error(`trellis update 失败(退出码 ${code}),已中止,未重新叠加`);
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
console.log("· --enhance-only:跳过 trellis update,仅重新叠加强化包");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (ctx.enhance) {
|
|
32
|
+
if (dryRun) {
|
|
33
|
+
console.log("· --dry-run:跳过强化包叠加(仅预览 trellis update)");
|
|
34
|
+
} else {
|
|
35
|
+
applyEnhancements(target, { variant: ctx.variant, skills: ctx.skills });
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
console.log("· --no-enhance:跳过强化包叠加");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log(`\n🌸 flower-trellis update 完成 → ${target}`);
|
|
42
|
+
}
|