clawt 3.4.5 → 3.5.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/.claude/settings.local.json +12 -0
- package/README.md +0 -4
- package/dist/index.js +430 -306
- package/dist/postinstall.js +12 -1
- package/docs/alias.md +7 -1
- package/docs/completion.md +1 -1
- package/docs/config.md +4 -3
- package/docs/cover-validate.md +4 -3
- package/docs/create.md +28 -12
- package/docs/home.md +12 -8
- package/docs/init.md +16 -9
- package/docs/list.md +13 -7
- package/docs/merge.md +12 -12
- package/docs/remove.md +24 -13
- package/docs/reset.md +6 -4
- package/docs/resume.md +3 -4
- package/docs/status.md +75 -30
- package/docs/sync.md +26 -26
- package/docs/validate.md +13 -7
- package/package.json +1 -1
- package/src/commands/init.ts +6 -2
- package/src/commands/tasks.ts +51 -0
- package/src/constants/index.ts +3 -0
- package/src/constants/interactive-panel.ts +6 -0
- package/src/constants/messages/index.ts +4 -2
- package/src/constants/messages/interactive-panel.ts +12 -0
- package/src/constants/messages/tasks.ts +9 -0
- package/src/constants/tasks-template.ts +28 -0
- package/src/index.ts +2 -0
- package/src/types/command.ts +6 -0
- package/src/types/index.ts +1 -1
- package/src/utils/formatter.ts +19 -0
- package/src/utils/git-branch.ts +116 -0
- package/src/utils/git-core.ts +369 -0
- package/src/utils/git-worktree.ts +40 -0
- package/src/utils/git.ts +3 -521
- package/src/utils/index.ts +1 -1
- package/src/utils/interactive-panel-render.ts +12 -6
- package/src/utils/interactive-panel-state.ts +137 -0
- package/src/utils/interactive-panel.ts +44 -188
- package/src/utils/keyboard-controller.ts +48 -0
- package/src/utils/ui-prompts.ts +240 -0
- package/src/utils/worktree-matcher.ts +21 -251
- package/tests/unit/commands/tasks.test.ts +153 -0
- package/tests/unit/utils/formatter.test.ts +26 -1
package/docs/status.md
CHANGED
|
@@ -15,7 +15,7 @@ clawt status [--json] [-i | --interactive]
|
|
|
15
15
|
|
|
16
16
|
**使用场景:**
|
|
17
17
|
|
|
18
|
-
在管理多个 worktree 时,快速了解项目全局状态:主 worktree
|
|
18
|
+
在管理多个 worktree 时,快速了解项目全局状态:主 worktree 当前分支及干净状态、配置的主工作分支信息、所有 worktree 的变更情况和与主分支的同步状态、validate 快照摘要。
|
|
19
19
|
|
|
20
20
|
交互式面板模式适用于需要持续监控项目状态并快速执行操作的场景,无需反复输入命令。
|
|
21
21
|
|
|
@@ -26,6 +26,8 @@ clawt status [--json] [-i | --interactive]
|
|
|
26
26
|
- 获取当前分支名(`getCurrentBranch()`)
|
|
27
27
|
- 检测工作区是否干净(`isWorkingDirClean()`)
|
|
28
28
|
- 获取项目名(`getProjectName()`)
|
|
29
|
+
- 加载项目配置(`loadProjectConfig()`),读取配置的主工作分支名(`clawtMainWorkBranch`)
|
|
30
|
+
- 检测配置的主工作分支是否存在(`checkBranchExists()`)
|
|
29
31
|
3. **收集各 worktree 详细状态**:
|
|
30
32
|
- 获取项目所有 worktree(`getProjectWorktrees()`)
|
|
31
33
|
- 对每个 worktree 收集以下信息:
|
|
@@ -33,7 +35,7 @@ clawt status [--json] [-i | --interactive]
|
|
|
33
35
|
- **行数差异**(新增/删除行数,通过 `getDiffStat()` 获取)
|
|
34
36
|
- **提交差异**(相对于主分支的领先提交数 `getCommitCountAhead()` 和落后提交数 `getCommitCountBehind()`)
|
|
35
37
|
- **快照时间**(validate 快照文件的 mtime,通过 `getSnapshotModifiedTime()` 获取,返回 ISO 8601 时间字符串或 null)
|
|
36
|
-
-
|
|
38
|
+
- **创建时间**(通过 `getWorktreeCreatedTime()` 从文件系统 birthtime 获取 worktree 目录的创建时间)
|
|
37
39
|
4. **收集 validate 快照摘要**:
|
|
38
40
|
- 通过 `getProjectSnapshotBranches()` 扫描快照目录下的 `.tree` 文件获取所有存在快照的分支名
|
|
39
41
|
- 统计快照总数和孤立快照数(对应 worktree 已不存在的快照)
|
|
@@ -46,6 +48,13 @@ clawt status [--json] [-i | --interactive]
|
|
|
46
48
|
|
|
47
49
|
输出分为三个区块:主 Worktree、Worktree 列表、Validate 快照摘要。每个 worktree 条目每行展示一种信息。
|
|
48
50
|
|
|
51
|
+
主 Worktree 区块会显示配置的主工作分支信息,根据状态有以下三种展示:
|
|
52
|
+
- **正常**(灰色):`主工作分支: <branchName>`
|
|
53
|
+
- **当前分支不一致**(黄色):`⚠ 主工作分支: <branchName>(当前分支不一致,如需更新请执行 clawt init)`
|
|
54
|
+
- **分支已不存在**(红色):`✗ 主工作分支: <branchName>(已不存在,请执行 clawt init 重新设置)`
|
|
55
|
+
|
|
56
|
+
注意:当项目未初始化(`configuredMainBranch` 为 null)时不展示配置分支信息;当主 worktree 当前处于验证分支(`VALIDATE_BRANCH_PREFIX` 前缀)时不显示不一致警告。
|
|
57
|
+
|
|
49
58
|
```
|
|
50
59
|
════════════════════════════════════════
|
|
51
60
|
项目状态总览: main-project
|
|
@@ -54,6 +63,7 @@ clawt status [--json] [-i | --interactive]
|
|
|
54
63
|
◆ 主 Worktree
|
|
55
64
|
分支: main
|
|
56
65
|
状态: ✓ 干净
|
|
66
|
+
主工作分支: main
|
|
57
67
|
|
|
58
68
|
────────────────────────────────────────
|
|
59
69
|
|
|
@@ -96,9 +106,9 @@ clawt status [--json] [-i | --interactive]
|
|
|
96
106
|
- 本地提交数(`N 个本地提交`):仅在有提交时展示,独立一行(黄色)
|
|
97
107
|
- 与主分支同步状态:始终展示,独立一行(落后时显示黄色,同步时显示绿色)
|
|
98
108
|
|
|
99
|
-
|
|
109
|
+
**创建时间行:**
|
|
100
110
|
|
|
101
|
-
- 通过 `
|
|
111
|
+
- 通过 `getWorktreeCreatedTime()` 从文件系统 `birthtime` 获取 worktree 目录的创建时间,以 `formatRelativeTime()` 格式化为中文相对时间(如"3 天前"、"2 小时前"、"刚刚")
|
|
102
112
|
- 展示为灰色文本 `创建于 X前`,无法获取时不展示
|
|
103
113
|
|
|
104
114
|
**验证状态行:**
|
|
@@ -119,7 +129,9 @@ clawt status [--json] [-i | --interactive]
|
|
|
119
129
|
"main": {
|
|
120
130
|
"branch": "main",
|
|
121
131
|
"isClean": true,
|
|
122
|
-
"projectName": "main-project"
|
|
132
|
+
"projectName": "main-project",
|
|
133
|
+
"configuredMainBranch": "main",
|
|
134
|
+
"configuredBranchExists": true
|
|
123
135
|
},
|
|
124
136
|
"worktrees": [
|
|
125
137
|
{
|
|
@@ -142,19 +154,40 @@ clawt status [--json] [-i | --interactive]
|
|
|
142
154
|
}
|
|
143
155
|
```
|
|
144
156
|
|
|
157
|
+
`MainWorktreeStatus` 各字段说明:
|
|
158
|
+
|
|
159
|
+
| 字段 | 类型 | 说明 |
|
|
160
|
+
| ----------------------- | ----------------- | ------------------------------------------- |
|
|
161
|
+
| `branch` | `string` | 当前分支名 |
|
|
162
|
+
| `isClean` | `boolean` | 工作区是否干净 |
|
|
163
|
+
| `projectName` | `string` | 项目名 |
|
|
164
|
+
| `configuredMainBranch` | `string \| null` | 配置的主工作分支名(项目未初始化时为 null) |
|
|
165
|
+
| `configuredBranchExists`| `boolean \| null` | 配置的主工作分支是否存在(项目未初始化时为 null)|
|
|
166
|
+
|
|
145
167
|
**实现要点:**
|
|
146
168
|
|
|
147
|
-
- 类型定义在 `src/types/status.ts`:`WorktreeDetailedStatus`(`
|
|
148
|
-
- 消息常量在 `MESSAGES.STATUS_*`
|
|
149
|
-
- `
|
|
169
|
+
- 类型定义在 `src/types/status.ts`:`WorktreeDetailedStatus`(`snapshotTime: string | null`、`createdAt: string | null`)、`MainWorktreeStatus`(包含 `configuredMainBranch` 和 `configuredBranchExists`)、`SnapshotInfo`、`SnapshotSummary`(包含 `total` 和 `orphaned`)、`StatusResult`(`snapshots` 为 `SnapshotSummary` 类型)
|
|
170
|
+
- 消息常量在 `MESSAGES.STATUS_*` 系列:
|
|
171
|
+
- `STATUS_TITLE(projectName)`:标题文本
|
|
172
|
+
- `STATUS_MAIN_SECTION`:主 worktree 区块标题
|
|
173
|
+
- `STATUS_WORKTREES_SECTION`:worktree 列表区块标题
|
|
174
|
+
- `STATUS_SNAPSHOTS_SECTION`:快照区块标题
|
|
175
|
+
- `STATUS_NO_WORKTREES`:无活跃 worktree 提示
|
|
176
|
+
- `STATUS_CHANGE_COMMITTED` / `STATUS_CHANGE_UNCOMMITTED` / `STATUS_CHANGE_CONFLICT` / `STATUS_CHANGE_CLEAN`:变更状态标签
|
|
177
|
+
- `STATUS_LAST_VALIDATED(relativeTime)`:上次验证时间标签
|
|
150
178
|
- `STATUS_NOT_VALIDATED`:未验证红色警示文本(`✗ 未验证`)
|
|
151
|
-
- `STATUS_CREATED_AT
|
|
152
|
-
- `STATUS_SNAPSHOT_ORPHANED
|
|
153
|
-
- `
|
|
154
|
-
- `
|
|
155
|
-
- `
|
|
156
|
-
- `
|
|
157
|
-
- `
|
|
179
|
+
- `STATUS_CREATED_AT(relativeTime)`:创建时间标签
|
|
180
|
+
- `STATUS_SNAPSHOT_ORPHANED(count)`:孤立快照警告(接受数量参数)
|
|
181
|
+
- `STATUS_CONFIGURED_BRANCH(branchName)`:配置的主工作分支(正常状态,灰色)
|
|
182
|
+
- `STATUS_CONFIGURED_BRANCH_DELETED(branchName)`:配置的主工作分支已不存在(红色)
|
|
183
|
+
- `STATUS_CONFIGURED_BRANCH_MISMATCH(branchName)`:当前分支与配置不一致(黄色)
|
|
184
|
+
- `getWorktreeCreatedTime()` 工具函数(在 `src/utils/worktree-matcher.ts`),通过 `fs.statSync().birthtime` 获取 worktree 目录的创建时间,返回 ISO 8601 格式字符串或 null
|
|
185
|
+
- `getSnapshotModifiedTime()` 工具函数(在 `src/utils/validate-snapshot.ts`),通过 `fs.statSync` 获取快照文件的修改时间(mtime),返回 UTC 时区的 ISO 8601 格式字符串(`toISOString()` 格式)或 null
|
|
186
|
+
- `formatRelativeTime()` 格式化函数(在 `src/utils/formatter.ts`),将 ISO 8601 日期字符串转换为中文相对时间描述(如"3 天前"、"2 小时前"、"刚刚"),无效日期时返回 null
|
|
187
|
+
- `getCommitCountBehind()` 工具函数(在 `src/utils/git.ts`),通过 `git rev-list --count <branch>..HEAD` 计算落后提交数
|
|
188
|
+
- `getProjectSnapshotBranches()` 工具函数(在 `src/utils/validate-snapshot.ts`),通过扫描快照目录下的 `.tree` 文件提取分支名列表
|
|
189
|
+
- `loadProjectConfig()` 加载项目配置,读取 `clawtMainWorkBranch` 字段
|
|
190
|
+
- `checkBranchExists()` 检测分支是否存在
|
|
158
191
|
|
|
159
192
|
**交互式面板模式(`-i` / `--interactive`):**
|
|
160
193
|
|
|
@@ -168,6 +201,7 @@ clawt status [--json] [-i | --interactive]
|
|
|
168
201
|
|
|
169
202
|
```
|
|
170
203
|
项目状态总览: my-project
|
|
204
|
+
主工作分支: main
|
|
171
205
|
快照: 3 个(1 个孤立)
|
|
172
206
|
──────── ↑ 更多 worktree... ────────
|
|
173
207
|
════ 2026-03-01(2 天前) ════
|
|
@@ -194,21 +228,26 @@ clawt status [--json] [-i | --interactive]
|
|
|
194
228
|
✗ 未验证
|
|
195
229
|
|
|
196
230
|
──────── ↓ 更多 worktree... ────────
|
|
197
|
-
[v]验证 [m]合并 [d]删除 [r]恢复 [s]同步 [f]刷新 [q]退出 (3s 后刷新)
|
|
231
|
+
[v]验证 [m]合并 [d]删除 [r]恢复 [s]同步 [c]覆盖 [f]刷新 [q]退出 (3s 后刷新)
|
|
198
232
|
```
|
|
199
233
|
|
|
200
234
|
面板从上到下分为以下区域:
|
|
201
235
|
|
|
202
236
|
1. **标题行**:显示项目名(`项目状态总览: <projectName>`)
|
|
203
|
-
2.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
237
|
+
2. **配置分支信息行**:显示配置的主工作分支状态,有以下四种情况:
|
|
238
|
+
- 正常(灰色):`主工作分支: <branchName>`
|
|
239
|
+
- 分支已删除(红色):`✗ 主工作分支: <branchName>(已不存在)`
|
|
240
|
+
- 分支不一致(黄色):`⚠ 主工作分支: <branchName>(不一致)`
|
|
241
|
+
- 未初始化(灰色):`未初始化(执行 clawt init 设置主工作分支)`
|
|
242
|
+
3. **快照摘要行**:显示快照总数和孤立快照数
|
|
243
|
+
4. **顶部分隔线**:当存在向上溢出时,分隔线中间嵌入 `↑ 更多 worktree...` 提示
|
|
244
|
+
5. **Worktree 滚动区域**:按日期分组显示 worktree 列表,支持上下滚动
|
|
245
|
+
6. **底部分隔线**:当存在向下溢出时,分隔线中间嵌入 `↓ 更多 worktree...` 提示
|
|
246
|
+
7. **底栏**:快捷键提示 + 自动刷新倒计时
|
|
208
247
|
|
|
209
248
|
**Worktree 日期分组显示:**
|
|
210
249
|
|
|
211
|
-
Worktree 按创建日期分组(复用 `groupWorktreesByDate()`),每组前显示日期分隔线,格式为 `════ YYYY-MM-DD(相对日期) ════`,相对日期如"今天"、"昨天"、"3 天前"等(通过 `formatRelativeDate()`
|
|
250
|
+
Worktree 按创建日期分组(复用 `groupWorktreesByDate()`),每组前显示日期分隔线,格式为 `════ YYYY-MM-DD(相对日期) ════`,相对日期如"今天"、"昨天"、"3 天前"等(通过 `formatRelativeDate()` 格式化)。无法获取创建日期时归入"未知日期"分组。
|
|
212
251
|
|
|
213
252
|
每个 worktree 条目的渲染内容与文本输出模式一致(分支名 + 变更状态标签、行数差异、本地提交数、同步状态、创建时间、验证状态),选中项前显示 `▶` 指示器(青色),未选中项前显示等宽空格占位。
|
|
214
253
|
|
|
@@ -223,17 +262,18 @@ Worktree 按创建日期分组(复用 `groupWorktreesByDate()`),每组前
|
|
|
223
262
|
| `d` | 对选中 worktree 执行 `clawt remove` |
|
|
224
263
|
| `r` | 对选中 worktree 执行 `clawt resume` |
|
|
225
264
|
| `s` | 对选中 worktree 执行 `clawt sync` |
|
|
265
|
+
| `c` | 执行 `clawt cover`(从当前验证分支自动推导目标分支) |
|
|
226
266
|
| `f` | 手动刷新数据 |
|
|
227
267
|
| `q` | 退出面板 |
|
|
228
268
|
| `Ctrl+C`| 退出面板 |
|
|
229
269
|
|
|
230
270
|
**操作执行流程:**
|
|
231
271
|
|
|
232
|
-
当用户按下操作快捷键(v/m/d/r/s)时,面板会:
|
|
272
|
+
当用户按下操作快捷键(v/m/d/r/s/c)时,面板会:
|
|
233
273
|
|
|
234
274
|
1. 暂停定时器和键盘监听
|
|
235
275
|
2. 退出备选屏幕,恢复终端状态
|
|
236
|
-
3. 以继承 stdio 的方式执行对应的 clawt 子命令(如 `clawt validate -b <branch
|
|
276
|
+
3. 以继承 stdio 的方式执行对应的 clawt 子命令(如 `clawt validate -b <branch>`)。其中 `c`(cover)命令不需要指定分支,直接执行 `clawt cover`
|
|
237
277
|
4. 命令完成后,输出 `按 Enter 返回面板...` 提示
|
|
238
278
|
5. 等待用户按 Enter 键
|
|
239
279
|
6. 重新进入备选屏幕,刷新数据,恢复面板
|
|
@@ -248,7 +288,7 @@ Worktree 按创建日期分组(复用 `groupWorktreesByDate()`),每组前
|
|
|
248
288
|
|
|
249
289
|
**滚动机制:**
|
|
250
290
|
|
|
251
|
-
- 滚动区域高度 = 终端行数 - 固定行数(标题 + 快照摘要 + 顶部分隔线 + 底部分隔线 + 底栏 = `PANEL_FIXED_ROWS + 1`),最小 3 行
|
|
291
|
+
- 滚动区域高度 = 终端行数 - 固定行数(标题 + 配置分支信息 + 快照摘要 + 顶部分隔线 + 底部分隔线 + 底栏 = `PANEL_FIXED_ROWS + 1`),最小 3 行
|
|
252
292
|
- 导航时自动调整滚动偏移(`scrollOffset`),确保选中项及其所属日期分组标题在可见区域内
|
|
253
293
|
- 溢出提示嵌入分隔线中间,不额外占用行数
|
|
254
294
|
- 终端 resize 时自动触发重绘
|
|
@@ -273,13 +313,14 @@ Worktree 按创建日期分组(复用 `groupWorktreesByDate()`),每组前
|
|
|
273
313
|
- `renderSnapshotSummary()`:渲染快照摘要行
|
|
274
314
|
- `renderFooter()`:渲染底栏
|
|
275
315
|
- `calculateVisibleRows()`:计算滚动区域可用行数
|
|
316
|
+
- `renderConfiguredBranchLine()`:渲染配置分支信息行(内部函数,根据 `MainWorktreeStatus` 渲染不同状态)
|
|
276
317
|
- 面板常量定义在 `src/constants/interactive-panel.ts`:
|
|
277
318
|
- `PANEL_REFRESH_INTERVAL_MS`(5000)、`PANEL_COUNTDOWN_INTERVAL_MS`(1000)
|
|
278
319
|
- `SELECTED_INDICATOR`(`▶`)、`UNSELECTED_INDICATOR`(等宽空格)
|
|
279
320
|
- `KEY_ARROW_UP`、`KEY_ARROW_DOWN`、`KEY_CTRL_C`
|
|
280
|
-
- `PANEL_SHORTCUT_KEYS
|
|
321
|
+
- `PANEL_SHORTCUT_KEYS`(快捷键映射对象,包含 `VALIDATE`/`MERGE`/`DELETE`/`RESUME`/`SYNC`/`COVER`/`REFRESH`/`QUIT`)
|
|
281
322
|
- `PANEL_DATE_SEPARATOR_PREFIX`(`════`)
|
|
282
|
-
- `PANEL_FIXED_ROWS`(
|
|
323
|
+
- `PANEL_FIXED_ROWS`(5,固定占用行数:配置分支信息 + 快照摘要 + 顶部分隔线 + 底部分隔线 + 底栏)
|
|
283
324
|
- 面板消息常量定义在 `src/constants/messages/interactive-panel.ts`:
|
|
284
325
|
- `PANEL_FOOTER_SHORTCUTS`:底栏快捷键提示(从 `PANEL_SHORTCUT_KEYS` 自动生成)
|
|
285
326
|
- `PANEL_FOOTER_COUNTDOWN(seconds)`:底栏倒计时文本
|
|
@@ -289,10 +330,14 @@ Worktree 按创建日期分组(复用 `groupWorktreesByDate()`),每组前
|
|
|
289
330
|
- `PANEL_PRESS_ENTER_TO_RETURN`:操作后返回提示
|
|
290
331
|
- `PANEL_NOT_TTY`:非 TTY 降级提示
|
|
291
332
|
- `PANEL_TITLE(projectName)`:面板标题
|
|
333
|
+
- `PANEL_CONFIGURED_BRANCH(branchName)`:配置分支信息(正常状态,灰色)
|
|
334
|
+
- `PANEL_CONFIGURED_BRANCH_DELETED(branchName)`:配置分支信息(分支已删除,红色)
|
|
335
|
+
- `PANEL_CONFIGURED_BRANCH_MISMATCH(branchName)`:配置分支信息(分支不一致,黄色)
|
|
336
|
+
- `PANEL_NOT_INITIALIZED`:未初始化提示(灰色)
|
|
292
337
|
- `PanelLine` 接口(`src/utils/interactive-panel-render.ts`):面板行类型定义,包含 `type`(`'separator'` | `'worktree-content'`)、`text`、可选 `worktreeIndex`
|
|
293
338
|
- `collectStatus()` 函数已改为导出(`export`),以便 `InteractivePanel` 作为数据收集函数引用
|
|
294
|
-
- `handleStatus()`
|
|
295
|
-
- `StatusOptions`
|
|
296
|
-
- 从 `src/utils/worktree-matcher.ts`
|
|
339
|
+
- `handleStatus()` 为 `async` 函数,返回 `Promise<void>`
|
|
340
|
+
- `StatusOptions` 类型包含 `json?: boolean` 和 `interactive?: boolean` 字段
|
|
341
|
+
- 从 `src/utils/worktree-matcher.ts` 导出 `formatRelativeDate()`、`getWorktreeCreatedDate()` 和 `getWorktreeCreatedTime()`,供面板渲染和状态收集使用
|
|
297
342
|
|
|
298
343
|
---
|
package/docs/sync.md
CHANGED
|
@@ -22,10 +22,12 @@ clawt sync
|
|
|
22
22
|
|
|
23
23
|
**运行流程:**
|
|
24
24
|
|
|
25
|
-
1.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
1. **统一前置校验**:调用 `runPreChecks(PRE_CHECK_SYNC)` 执行以下校验:
|
|
26
|
+
- `requireMainWorktree`:校验当前目录是否在主 worktree 根目录
|
|
27
|
+
- `requireHead`:校验 HEAD 是否存在(仓库至少有一次 commit)
|
|
28
|
+
- `requireProjectConfig`:校验项目配置文件是否存在且合法(存在 `clawtMainWorkBranch` 配置)
|
|
29
|
+
- `ensureOnClawtMainWorkBranch`:确保当前处于主工作分支上,不在则自动切换。sync 命令需要从主分支发起合并操作,因此必须保证当前分支状态正确
|
|
30
|
+
2. **解析目标 worktree**:根据 `-b` 参数解析目标 worktree,匹配策略如下:
|
|
29
31
|
- **未传 `-b` 参数**:
|
|
30
32
|
- 获取当前项目所有 worktree
|
|
31
33
|
- 无可用 worktree → 报错退出
|
|
@@ -37,7 +39,7 @@ clawt sync
|
|
|
37
39
|
- 唯一匹配 → 直接使用
|
|
38
40
|
- 多个匹配 → 通过交互式列表让用户从匹配结果中选择
|
|
39
41
|
3. **无匹配** → 报错退出,并列出所有可用分支名
|
|
40
|
-
|
|
42
|
+
3. 调用 `executeSyncForBranch(targetWorktreePath, branch)` 执行核心同步逻辑
|
|
41
43
|
|
|
42
44
|
#### `executeSyncForBranch` — sync 核心操作函数
|
|
43
45
|
|
|
@@ -57,7 +59,7 @@ export interface SyncResult {
|
|
|
57
59
|
|
|
58
60
|
**执行流程:**
|
|
59
61
|
|
|
60
|
-
1.
|
|
62
|
+
1. **获取主 worktree 路径和主分支名**:通过 `getGitTopLevel()` 获取主 worktree 路径(后续传给 `rebuildValidateBranch`),通过项目级配置 `clawtMainWorkBranch` 获取主工作分支名(不再通过 `getCurrentBranch` 动态获取,因为在新架构下主 worktree 可能处于验证分支上)
|
|
61
63
|
2. **自动保存未提交变更**:检查目标 worktree 是否有未提交修改
|
|
62
64
|
- 有修改 → 自动执行 `git add . && git commit -m "<AUTO_SAVE_COMMIT_MESSAGE>"` 保存变更(commit message 由常量 `AUTO_SAVE_COMMIT_MESSAGE` 定义,值为 `chore: auto-save before sync`,同时用于 merge 命令的 squash 检测)
|
|
63
65
|
- 无修改 → 跳过
|
|
@@ -76,21 +78,7 @@ export interface SyncResult {
|
|
|
76
78
|
```
|
|
77
79
|
- 返回 `{ success: false, hasConflict: true }`
|
|
78
80
|
- **无冲突** → 继续
|
|
79
|
-
5.
|
|
80
|
-
示意图:
|
|
81
|
-
场景:将 HEAD(master) 合并到 branchName
|
|
82
|
-
|
|
83
|
-
执行 git checkout branchName && git merge master 后:
|
|
84
|
-
|
|
85
|
-
A -- B -- C (HEAD/master)
|
|
86
|
-
/ \
|
|
87
|
-
* M (branchName, merge commit)
|
|
88
|
-
\ /
|
|
89
|
-
D -- E ----
|
|
90
|
-
|
|
91
|
-
此时执行 git diff HEAD...branchName:
|
|
92
|
-
|
|
93
|
-
- merge-base 变成了 C(因为合并后,HEAD 和 branchName 的最近共同祖先就是 C)
|
|
81
|
+
5. **输出合并成功提示**:`✓ 已将 <mainBranch> 的最新代码同步到 <branchName>`
|
|
94
82
|
6. **重建验证分支**(`rebuildValidateBranch`,async 函数):sync 将主分支合并到目标 worktree 后,目标分支的代码基点发生变化。为保持验证分支与目标分支基点一致,需要重建验证分支。
|
|
95
83
|
- 确保在主工作分支上创建验证分支,处理三种情况:
|
|
96
84
|
- **已在主工作分支上** → 直接重建
|
|
@@ -115,11 +103,23 @@ export interface SyncResult {
|
|
|
115
103
|
# 基于当前主分支 HEAD 重新创建验证分支
|
|
116
104
|
git branch clawt-validate-<branchName>
|
|
117
105
|
```
|
|
118
|
-
7.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
106
|
+
7. **输出验证分支重建提示并返回结果**:输出 `验证分支 clawt-validate-<branchName> 已重建`,返回 `{ success: true, hasConflict: false }`
|
|
107
|
+
|
|
108
|
+
**设计说明 — 保留 validate 快照**:sync 合并成功后,不清除该分支的 validate 快照。因为 validate 使用三点 diff(`main...feature`),sync 后 merge-base 更新为合并提交,三点 diff 仍然只包含 feature 分支自身的修改,旧快照依然有效。增量 validate 时若检测到 HEAD 变化,会自动通过 diff-tree + apply 路径正确恢复暂存区状态。
|
|
109
|
+
示意图:
|
|
110
|
+
场景:将 HEAD(master) 合并到 branchName
|
|
111
|
+
|
|
112
|
+
执行 git checkout branchName && git merge master 后:
|
|
113
|
+
|
|
114
|
+
A -- B -- C (HEAD/master)
|
|
115
|
+
/ \
|
|
116
|
+
* M (branchName, merge commit)
|
|
117
|
+
\ /
|
|
118
|
+
D -- E ----
|
|
119
|
+
|
|
120
|
+
此时执行 git diff HEAD...branchName:
|
|
121
|
+
|
|
122
|
+
- merge-base 变成了 C(因为合并后,HEAD 和 branchName 的最近共同祖先就是 C)
|
|
123
123
|
|
|
124
124
|
#### validate 中自动 sync 的联动
|
|
125
125
|
|
package/docs/validate.md
CHANGED
|
@@ -38,16 +38,18 @@ validate 命令引入了**快照(snapshot)机制**来支持增量对比。
|
|
|
38
38
|
|
|
39
39
|
当指定 `--clean` 选项时,执行清理逻辑后直接返回,不进入常规 validate 流程:
|
|
40
40
|
|
|
41
|
-
1.
|
|
41
|
+
1. **前置校验**:主 worktree 校验 + HEAD 存在性校验 + 项目配置校验(`runPreChecks`)
|
|
42
42
|
2. **解析目标 worktree**:通过模糊匹配解析目标分支(匹配策略同下文常规 validate 流程中的描述)
|
|
43
43
|
3. 如果配置项 `confirmDestructiveOps` 为 `true`,提示确认(显示即将执行的危险指令和操作后果),用户取消则退出
|
|
44
44
|
4. 如果主 worktree 有未提交更改,执行 `git reset --hard` + `git clean -fd` 清空
|
|
45
|
-
5.
|
|
45
|
+
5. 确保当前处于主工作分支上(`ensureOnMainWorkBranch`):如果在验证分支上,清理后切回;如果在其他分支上,交互处理脏工作区后切回
|
|
46
46
|
6. 删除对应分支的快照文件
|
|
47
47
|
7. 输出清理成功提示
|
|
48
48
|
|
|
49
49
|
#### 首次 validate(无历史快照)
|
|
50
50
|
|
|
51
|
+
> 常规 validate(首次和增量)执行前均会先进行前置校验:主 worktree 校验 + HEAD 存在性校验 + 项目配置校验(`runPreChecks`)。
|
|
52
|
+
|
|
51
53
|
##### 步骤 0:解析目标 worktree
|
|
52
54
|
|
|
53
55
|
根据 `-b` 参数解析目标 worktree,匹配策略如下:
|
|
@@ -153,9 +155,9 @@ git restore --staged .
|
|
|
153
155
|
|
|
154
156
|
**实现要点:**
|
|
155
157
|
|
|
156
|
-
- `migrateChangesViaPatch()
|
|
157
|
-
- `handleFirstValidate()` 和 `handleIncrementalValidate()`
|
|
158
|
-
- `handlePatchApplyFailure()
|
|
158
|
+
- `migrateChangesViaPatch()`(`src/utils/validate-core.ts`)返回 `{ success: boolean }`,patch apply 失败时返回 `{ success: false }` 而非抛出异常
|
|
159
|
+
- `handleFirstValidate()` 和 `handleIncrementalValidate()` 为 `async` 函数,支持交互式确认
|
|
160
|
+
- `handlePatchApplyFailure()`(`src/commands/validate.ts`)为异步函数,负责 patch 失败后的交互逻辑
|
|
159
161
|
- 消息常量:`MESSAGES.VALIDATE_CONFIRM_AUTO_SYNC`、`MESSAGES.VALIDATE_AUTO_SYNC_START`、`MESSAGES.VALIDATE_AUTO_SYNC_DECLINED`(`src/constants/messages/validate.ts`)
|
|
160
162
|
|
|
161
163
|
##### 步骤 5:保存快照为 git tree 对象
|
|
@@ -166,6 +168,7 @@ git restore --staged .
|
|
|
166
168
|
git add .
|
|
167
169
|
git write-tree # → 返回 tree hash,写入 ~/.clawt/validate-snapshots/<project>/<branchName>.tree
|
|
168
170
|
git rev-parse HEAD # → 返回验证分支的 HEAD commit hash,写入 ~/.clawt/validate-snapshots/<project>/<branchName>.head
|
|
171
|
+
# 同时写入 ~/.clawt/validate-snapshots/<project>/<branchName>.staged(首次 validate 为空字符串)
|
|
169
172
|
git restore --staged .
|
|
170
173
|
```
|
|
171
174
|
|
|
@@ -279,7 +282,7 @@ clawt validate -b feature-scheme-1 -r "pnpm test & pnpm build"
|
|
|
279
282
|
|
|
280
283
|
- 命令解析:`parseParallelCommands()`(`src/utils/shell.ts`)
|
|
281
284
|
- 并行执行:`runParallelCommands()`(`src/utils/shell.ts`),返回 `ParallelCommandResult[]`
|
|
282
|
-
- 结果汇总:`reportParallelResults()`(`src/
|
|
285
|
+
- 结果汇总:`reportParallelResults()`(`src/utils/validate-runner.ts`)
|
|
283
286
|
- 消息常量:`MESSAGES.VALIDATE_PARALLEL_*` 系列(`src/constants/messages/validate.ts`)
|
|
284
287
|
- 命令解析优先级:`resolveRunCommand()`(`src/commands/validate.ts`)负责解析最终要执行的命令,优先使用 `-r` 参数,否则从项目配置读取 `validateRunCommand`(通过 `getValidateRunCommand()`,`src/utils/project-config.ts`)
|
|
285
288
|
|
|
@@ -324,7 +327,7 @@ git rev-parse HEAD # → currentHeadCommitHash
|
|
|
324
327
|
hasNewChanges = (newTreeHash !== oldTreeHash) || (oldHeadCommitHash !== currentHeadCommitHash)
|
|
325
328
|
```
|
|
326
329
|
|
|
327
|
-
- **无新变更**(tree hash 和 HEAD 均未变化)→
|
|
330
|
+
- **无新变更**(tree hash 和 HEAD 均未变化)→ 不更新快照;如果旧快照记录了 `oldStagedTreeHash`(非空),通过 `git read-tree <oldStagedTreeHash>` 恢复上次 validate 结束时的暂存区状态(恢复失败仅输出 warn 日志,不影响流程);输出提示后返回
|
|
328
331
|
- **有新变更** → 继续步骤 6
|
|
329
332
|
|
|
330
333
|
> 无变更检测避免了重复 validate 时不必要的快照更新和暂存区重载操作。恢复上次暂存区状态后,用户看到的 `git diff` 结果与上次 validate 结束时完全一致。
|
|
@@ -397,8 +400,11 @@ echo <newStagedTreeHash>
|
|
|
397
400
|
|
|
398
401
|
# 增量无变更
|
|
399
402
|
分支 feature-scheme-1 自上次 validate 以来没有新的变更,已恢复到上次验证状态
|
|
403
|
+
✓ 已切换到验证分支 clawt-validate-feature-scheme-1 并应用分支 feature-scheme-1 的变更
|
|
404
|
+
可以开始验证了
|
|
400
405
|
|
|
401
406
|
# 增量降级为全量
|
|
407
|
+
增量对比失败,已降级为全量模式
|
|
402
408
|
✓ 已切换到验证分支 clawt-validate-feature-scheme-1 并应用分支 feature-scheme-1 的变更
|
|
403
409
|
可以开始验证了
|
|
404
410
|
```
|
package/package.json
CHANGED
package/src/commands/init.ts
CHANGED
|
@@ -79,8 +79,12 @@ async function handleInit(options: InitOptions): Promise<void> {
|
|
|
79
79
|
|
|
80
80
|
logger.info(`init 命令执行,主工作分支: ${branchName}`);
|
|
81
81
|
|
|
82
|
-
//
|
|
83
|
-
|
|
82
|
+
// 合并现有配置,仅更新 clawtMainWorkBranch
|
|
83
|
+
const updatedConfig: ProjectConfig = {
|
|
84
|
+
...existingConfig,
|
|
85
|
+
clawtMainWorkBranch: branchName,
|
|
86
|
+
};
|
|
87
|
+
saveProjectConfig(updatedConfig);
|
|
84
88
|
|
|
85
89
|
if (existingConfig) {
|
|
86
90
|
printSuccess(MESSAGES.INIT_UPDATED(existingConfig.clawtMainWorkBranch, branchName));
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { resolve, dirname, join } from 'node:path';
|
|
2
|
+
import { existsSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import type { Command } from 'commander';
|
|
4
|
+
import { MESSAGES, TASK_TEMPLATE_OUTPUT_DIR, TASK_TEMPLATE_FILENAME_PREFIX, TASK_TEMPLATE_CONTENT } from '../constants/index.js';
|
|
5
|
+
import { ClawtError } from '../errors/index.js';
|
|
6
|
+
import { logger } from '../logger/index.js';
|
|
7
|
+
import { printSuccess, printHint, ensureDir, generateTaskFilename } from '../utils/index.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 注册 tasks 命令组及其子命令
|
|
11
|
+
* @param {Command} program - Commander 实例
|
|
12
|
+
*/
|
|
13
|
+
export function registerTasksCommand(program: Command): void {
|
|
14
|
+
const taskCmd = program
|
|
15
|
+
.command('tasks')
|
|
16
|
+
.description('任务文件管理');
|
|
17
|
+
|
|
18
|
+
taskCmd
|
|
19
|
+
.command('init')
|
|
20
|
+
.description('生成任务模板文件')
|
|
21
|
+
.argument('[path]', '输出文件路径')
|
|
22
|
+
.action(async (path?: string) => {
|
|
23
|
+
// 未指定路径时,默认输出到 clawt/tasks/ 目录下
|
|
24
|
+
const filePath = path ?? join(TASK_TEMPLATE_OUTPUT_DIR, generateTaskFilename(TASK_TEMPLATE_FILENAME_PREFIX));
|
|
25
|
+
await handleTasksInit(filePath);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 处理 tasks init 子命令:生成任务模板文件
|
|
31
|
+
* @param {string} filePath - 输出文件路径
|
|
32
|
+
*/
|
|
33
|
+
async function handleTasksInit(filePath: string): Promise<void> {
|
|
34
|
+
const absolutePath = resolve(filePath);
|
|
35
|
+
|
|
36
|
+
logger.info(`tasks init 命令执行,目标文件: ${absolutePath}`);
|
|
37
|
+
|
|
38
|
+
// 检查文件是否已存在
|
|
39
|
+
if (existsSync(absolutePath)) {
|
|
40
|
+
throw new ClawtError(MESSAGES.TASK_INIT_FILE_EXISTS(filePath));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 确保父目录存在
|
|
44
|
+
ensureDir(dirname(absolutePath));
|
|
45
|
+
|
|
46
|
+
// 写入模板内容
|
|
47
|
+
writeFileSync(absolutePath, TASK_TEMPLATE_CONTENT, 'utf-8');
|
|
48
|
+
|
|
49
|
+
printSuccess(MESSAGES.TASK_INIT_SUCCESS(filePath));
|
|
50
|
+
printHint(MESSAGES.TASK_INIT_HINT(filePath));
|
|
51
|
+
}
|
package/src/constants/index.ts
CHANGED
|
@@ -42,5 +42,8 @@ export {
|
|
|
42
42
|
PANEL_SHORTCUT_KEYS,
|
|
43
43
|
PANEL_DATE_SEPARATOR_PREFIX,
|
|
44
44
|
PANEL_FIXED_ROWS,
|
|
45
|
+
PANEL_SEPARATOR_MAX_WIDTH,
|
|
46
|
+
PANEL_DATE_COLOR,
|
|
45
47
|
} from './interactive-panel.js';
|
|
46
48
|
export { PRE_CHECK_CREATE, PRE_CHECK_RUN, PRE_CHECK_DRY_RUN, PRE_CHECK_MERGE, PRE_CHECK_SYNC, PRE_CHECK_RESUME } from './pre-checks.js';
|
|
49
|
+
export { TASK_TEMPLATE_OUTPUT_DIR, TASK_TEMPLATE_FILENAME_PREFIX, TASK_TEMPLATE_CONTENT } from './tasks-template.js';
|
|
@@ -44,3 +44,9 @@ export const PANEL_DATE_SEPARATOR_PREFIX = '════';
|
|
|
44
44
|
|
|
45
45
|
/** 固定占用行数(配置分支信息 + 快照摘要 + 顶部分隔线 + 底部分隔线 + 底栏) */
|
|
46
46
|
export const PANEL_FIXED_ROWS = 5;
|
|
47
|
+
|
|
48
|
+
/** 终端最大显示宽度限制 */
|
|
49
|
+
export const PANEL_SEPARATOR_MAX_WIDTH = 60;
|
|
50
|
+
|
|
51
|
+
/** 日期分隔线高亮颜色(橙色) */
|
|
52
|
+
export const PANEL_DATE_COLOR = '#FF8C00';
|
|
@@ -16,11 +16,12 @@ import { UPDATE_MESSAGES, UPDATE_COMMANDS } from './update.js';
|
|
|
16
16
|
import { INIT_MESSAGES } from './init.js';
|
|
17
17
|
import { COVER_VALIDATE_MESSAGES } from './cover-validate.js';
|
|
18
18
|
import { HOME_MESSAGES } from './home.js';
|
|
19
|
-
import {
|
|
19
|
+
import { TASKS_CMD_MESSAGES } from './tasks.js';
|
|
20
|
+
import { PANEL_FOOTER_SHORTCUTS, PANEL_FOOTER_COUNTDOWN, PANEL_OVERFLOW_DOWN_HINT, PANEL_OVERFLOW_UP_HINT, PANEL_SNAPSHOT_SUMMARY, PANEL_NO_WORKTREES as PANEL_NO_WORKTREES_MSG, PANEL_PRESS_ENTER_TO_RETURN, PANEL_NOT_TTY, PANEL_TITLE, PANEL_CONFIGURED_BRANCH, PANEL_CONFIGURED_BRANCH_DELETED, PANEL_CONFIGURED_BRANCH_MISMATCH, PANEL_NOT_INITIALIZED, PANEL_UNKNOWN_DATE, PANEL_SYNCED_WITH_MAIN, PANEL_COMMITS_AHEAD, PANEL_COMMITS_BEHIND } from './interactive-panel.js';
|
|
20
21
|
|
|
21
22
|
export { CONFIG_ALIAS_DISABLED_HINT };
|
|
22
23
|
export { UPDATE_MESSAGES, UPDATE_COMMANDS };
|
|
23
|
-
export { PANEL_FOOTER_SHORTCUTS, PANEL_FOOTER_COUNTDOWN, PANEL_OVERFLOW_DOWN_HINT, PANEL_OVERFLOW_UP_HINT, PANEL_SNAPSHOT_SUMMARY, PANEL_NO_WORKTREES_MSG, PANEL_PRESS_ENTER_TO_RETURN, PANEL_NOT_TTY, PANEL_TITLE, PANEL_CONFIGURED_BRANCH, PANEL_CONFIGURED_BRANCH_DELETED, PANEL_CONFIGURED_BRANCH_MISMATCH, PANEL_NOT_INITIALIZED };
|
|
24
|
+
export { PANEL_FOOTER_SHORTCUTS, PANEL_FOOTER_COUNTDOWN, PANEL_OVERFLOW_DOWN_HINT, PANEL_OVERFLOW_UP_HINT, PANEL_SNAPSHOT_SUMMARY, PANEL_NO_WORKTREES_MSG, PANEL_PRESS_ENTER_TO_RETURN, PANEL_NOT_TTY, PANEL_TITLE, PANEL_CONFIGURED_BRANCH, PANEL_CONFIGURED_BRANCH_DELETED, PANEL_CONFIGURED_BRANCH_MISMATCH, PANEL_NOT_INITIALIZED, PANEL_UNKNOWN_DATE, PANEL_SYNCED_WITH_MAIN, PANEL_COMMITS_AHEAD, PANEL_COMMITS_BEHIND };
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* 提示消息模板
|
|
@@ -44,4 +45,5 @@ export const MESSAGES = {
|
|
|
44
45
|
...INIT_MESSAGES,
|
|
45
46
|
...COVER_VALIDATE_MESSAGES,
|
|
46
47
|
...HOME_MESSAGES,
|
|
48
|
+
...TASKS_CMD_MESSAGES,
|
|
47
49
|
} as const;
|
|
@@ -87,3 +87,15 @@ export const PANEL_CONFIGURED_BRANCH_MISMATCH = (branchName: string): string =>
|
|
|
87
87
|
|
|
88
88
|
/** 面板配置分支信息(未初始化) */
|
|
89
89
|
export const PANEL_NOT_INITIALIZED = chalk.gray('未初始化(执行 clawt init 设置主工作分支)');
|
|
90
|
+
|
|
91
|
+
/** 交互面板日期分隔线:未知日期文案 */
|
|
92
|
+
export const PANEL_UNKNOWN_DATE = '未知日期';
|
|
93
|
+
|
|
94
|
+
/** 交互面板:与主分支同步 */
|
|
95
|
+
export const PANEL_SYNCED_WITH_MAIN = '与主分支同步';
|
|
96
|
+
|
|
97
|
+
/** 交互面板:本地提交数量提示 */
|
|
98
|
+
export const PANEL_COMMITS_AHEAD = (count: number): string => `${count} 个本地提交`;
|
|
99
|
+
|
|
100
|
+
/** 交互面板:落后主分支提交数量提示 */
|
|
101
|
+
export const PANEL_COMMITS_BEHIND = (count: number): string => `落后主分支 ${count} 个提交`;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** tasks 命令相关提示消息 */
|
|
2
|
+
export const TASKS_CMD_MESSAGES = {
|
|
3
|
+
/** 任务模板文件已存在 */
|
|
4
|
+
TASK_INIT_FILE_EXISTS: (path: string) => `文件已存在: ${path},如需覆盖请先删除`,
|
|
5
|
+
/** 任务模板生成成功 */
|
|
6
|
+
TASK_INIT_SUCCESS: (path: string) => `✓ 任务模板已生成: ${path}`,
|
|
7
|
+
/** 任务模板使用提示 */
|
|
8
|
+
TASK_INIT_HINT: (path: string) => `使用 clawt run -f ${path} 执行任务`,
|
|
9
|
+
} as const;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** 任务模板默认输出目录 */
|
|
2
|
+
export const TASK_TEMPLATE_OUTPUT_DIR = 'clawt/tasks';
|
|
3
|
+
|
|
4
|
+
/** 任务模板文件名前缀 */
|
|
5
|
+
export const TASK_TEMPLATE_FILENAME_PREFIX = 'clawt-tasks';
|
|
6
|
+
|
|
7
|
+
/** 任务模板文件内容 */
|
|
8
|
+
export const TASK_TEMPLATE_CONTENT = `# Clawt 任务文件
|
|
9
|
+
#
|
|
10
|
+
# 使用方法: clawt run -f tasks.md
|
|
11
|
+
# 格式说明: 标签外的文本会被忽略,每个任务用 START/END 标签包裹
|
|
12
|
+
#
|
|
13
|
+
# 规则:
|
|
14
|
+
# 1. 每个任务块用 <!-- CLAWT-TASKS:START --> 和 <!-- CLAWT-TASKS:END --> 包裹
|
|
15
|
+
# 2. 块内 # branch: <分支名> 声明分支名(使用 -b 参数时可省略)
|
|
16
|
+
# 3. 块内其余行为任务描述(支持多行)
|
|
17
|
+
|
|
18
|
+
<!-- CLAWT-TASKS:START -->
|
|
19
|
+
# branch: feat-example-1
|
|
20
|
+
在这里写第一个任务的描述
|
|
21
|
+
<!-- CLAWT-TASKS:END -->
|
|
22
|
+
|
|
23
|
+
<!-- CLAWT-TASKS:START -->
|
|
24
|
+
# branch: feat-example-2
|
|
25
|
+
在这里写第二个任务的描述
|
|
26
|
+
支持多行描述
|
|
27
|
+
<!-- CLAWT-TASKS:END -->
|
|
28
|
+
`;
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { registerProjectsCommand } from './commands/projects.js';
|
|
|
21
21
|
import { registerCompletionCommand } from './commands/completion.js';
|
|
22
22
|
import { registerInitCommand } from './commands/init.js';
|
|
23
23
|
import { registerHomeCommand } from './commands/home.js';
|
|
24
|
+
import { registerTasksCommand } from './commands/tasks.js';
|
|
24
25
|
|
|
25
26
|
// 从 package.json 读取版本号,避免硬编码
|
|
26
27
|
const require = createRequire(import.meta.url);
|
|
@@ -62,6 +63,7 @@ registerProjectsCommand(program);
|
|
|
62
63
|
registerCompletionCommand(program);
|
|
63
64
|
registerInitCommand(program);
|
|
64
65
|
registerHomeCommand(program);
|
|
66
|
+
registerTasksCommand(program);
|
|
65
67
|
|
|
66
68
|
// 加载配置并应用命令别名
|
|
67
69
|
const config = loadConfig();
|
package/src/types/command.ts
CHANGED
package/src/types/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { ClawtConfig, ConfigItemDefinition, ConfigDefinitions } from './config.js';
|
|
2
|
-
export type { CreateOptions, RunOptions, ValidateOptions, MergeOptions, RemoveOptions, ResumeOptions, SyncOptions, ListOptions, StatusOptions, ProjectsOptions, InitOptions } from './command.js';
|
|
2
|
+
export type { CreateOptions, RunOptions, ValidateOptions, MergeOptions, RemoveOptions, ResumeOptions, SyncOptions, ListOptions, StatusOptions, ProjectsOptions, InitOptions, TasksInitOptions } from './command.js';
|
|
3
3
|
export type { WorktreeInfo, WorktreeStatus } from './worktree.js';
|
|
4
4
|
export type { ClaudeCodeResult } from './claudeCode.js';
|
|
5
5
|
export type { TaskResult, TaskSummary } from './taskResult.js';
|
package/src/utils/formatter.ts
CHANGED
|
@@ -230,3 +230,22 @@ export function formatLocalISOString(date: Date): string {
|
|
|
230
230
|
|
|
231
231
|
return `${iso}${sign}${hours}:${minutes}`;
|
|
232
232
|
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* 生成任务模板文件名,格式:clawt-tasks-YYYY-MM-DD-HH-mm-ss.md
|
|
236
|
+
* @param {string} prefix - 文件名前缀
|
|
237
|
+
* @returns {string} 带时间戳的文件名
|
|
238
|
+
*/
|
|
239
|
+
export function generateTaskFilename(prefix: string): string {
|
|
240
|
+
const now = new Date();
|
|
241
|
+
const pad = (n: number) => String(n).padStart(2, '0');
|
|
242
|
+
const timestamp = [
|
|
243
|
+
now.getFullYear(),
|
|
244
|
+
pad(now.getMonth() + 1),
|
|
245
|
+
pad(now.getDate()),
|
|
246
|
+
pad(now.getHours()),
|
|
247
|
+
pad(now.getMinutes()),
|
|
248
|
+
pad(now.getSeconds()),
|
|
249
|
+
].join('-');
|
|
250
|
+
return `${prefix}-${timestamp}.md`;
|
|
251
|
+
}
|