clawt 3.4.6 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/README.md +0 -4
  3. package/dist/index.js +583 -314
  4. package/dist/postinstall.js +37 -2
  5. package/docs/alias.md +7 -1
  6. package/docs/completion.md +1 -1
  7. package/docs/config.md +4 -3
  8. package/docs/cover-validate.md +4 -3
  9. package/docs/create.md +28 -12
  10. package/docs/home.md +12 -8
  11. package/docs/init.md +16 -9
  12. package/docs/list.md +13 -7
  13. package/docs/merge.md +12 -12
  14. package/docs/remove.md +24 -13
  15. package/docs/reset.md +6 -4
  16. package/docs/resume.md +3 -4
  17. package/docs/status.md +75 -30
  18. package/docs/sync.md +26 -26
  19. package/docs/validate.md +13 -7
  20. package/package.json +1 -1
  21. package/src/commands/merge.ts +20 -5
  22. package/src/commands/tasks.ts +51 -0
  23. package/src/constants/ai-prompts.ts +14 -0
  24. package/src/constants/config.ts +9 -0
  25. package/src/constants/index.ts +4 -0
  26. package/src/constants/interactive-panel.ts +6 -0
  27. package/src/constants/messages/index.ts +4 -2
  28. package/src/constants/messages/interactive-panel.ts +12 -0
  29. package/src/constants/messages/merge.ts +15 -0
  30. package/src/constants/messages/tasks.ts +9 -0
  31. package/src/constants/tasks-template.ts +28 -0
  32. package/src/index.ts +2 -0
  33. package/src/types/command.ts +8 -0
  34. package/src/types/config.ts +4 -0
  35. package/src/types/index.ts +1 -1
  36. package/src/utils/conflict-resolver.ts +170 -0
  37. package/src/utils/formatter.ts +19 -0
  38. package/src/utils/git-branch.ts +116 -0
  39. package/src/utils/git-core.ts +417 -0
  40. package/src/utils/git-worktree.ts +40 -0
  41. package/src/utils/git.ts +3 -521
  42. package/src/utils/index.ts +7 -2
  43. package/src/utils/interactive-panel-render.ts +12 -6
  44. package/src/utils/interactive-panel-state.ts +137 -0
  45. package/src/utils/interactive-panel.ts +44 -188
  46. package/src/utils/keyboard-controller.ts +48 -0
  47. package/src/utils/ui-prompts.ts +240 -0
  48. package/src/utils/worktree-matcher.ts +21 -251
  49. package/tests/unit/commands/merge.test.ts +59 -3
  50. package/tests/unit/commands/tasks.test.ts +153 -0
  51. package/tests/unit/utils/conflict-resolver.test.ts +250 -0
  52. package/tests/unit/utils/formatter.test.ts +26 -1
  53. package/src/constants/messages.ts +0 -179
@@ -164,7 +164,22 @@ ${branches.map((b) => ` - ${b}`).join("\n")}`,
164
164
  /** merge 交互选择提示 */
165
165
  MERGE_SELECT_BRANCH: "\u8BF7\u9009\u62E9\u8981\u5408\u5E76\u7684\u5206\u652F",
166
166
  /** merge 模糊匹配到多个结果提示 */
167
- MERGE_MULTIPLE_MATCHES: (name) => `"${name}" \u5339\u914D\u5230\u591A\u4E2A\u5206\u652F\uFF0C\u8BF7\u9009\u62E9\uFF1A`
167
+ MERGE_MULTIPLE_MATCHES: (name) => `"${name}" \u5339\u914D\u5230\u591A\u4E2A\u5206\u652F\uFF0C\u8BF7\u9009\u62E9\uFF1A`,
168
+ /** 询问是否使用 AI 辅助解决冲突 */
169
+ MERGE_CONFLICT_ASK_AI: "\u68C0\u6D4B\u5230\u5408\u5E76\u51B2\u7A81\uFF0C\u662F\u5426\u4F7F\u7528 Claude Code \u81EA\u52A8\u89E3\u51B3\uFF1F",
170
+ /** AI 冲突解决开始 */
171
+ MERGE_CONFLICT_AI_START: (fileCount) => `\u6B63\u5728\u4F7F\u7528 Claude Code \u5206\u6790\u5E76\u89E3\u51B3 ${fileCount} \u4E2A\u51B2\u7A81\u6587\u4EF6...`,
172
+ /** AI 冲突解决成功 */
173
+ MERGE_CONFLICT_AI_SUCCESS: "\u2713 Claude Code \u5DF2\u6210\u529F\u89E3\u51B3\u6240\u6709\u51B2\u7A81",
174
+ /** AI 冲突解决后仍有未解决的冲突 */
175
+ MERGE_CONFLICT_AI_PARTIAL: (remaining) => `Claude Code \u5DF2\u5904\u7406\u51B2\u7A81\u6587\u4EF6\uFF0C\u4F46\u4ECD\u6709 ${remaining} \u4E2A\u6587\u4EF6\u5B58\u5728\u51B2\u7A81
176
+ \u8BF7\u624B\u52A8\u5904\u7406\u5269\u4F59\u51B2\u7A81\u540E\u6267\u884C git add . && git merge --continue`,
177
+ /** AI 冲突解决失败 */
178
+ MERGE_CONFLICT_AI_FAILED: (errorMsg) => `Claude Code \u89E3\u51B3\u51B2\u7A81\u5931\u8D25: ${errorMsg}
179
+ \u8BF7\u624B\u52A8\u5904\u7406\uFF1A
180
+ \u89E3\u51B3\u51B2\u7A81\u540E\u6267\u884C git add . && git merge --continue`,
181
+ /** --auto 模式下的冲突手动解决(配置为 manual) */
182
+ MERGE_CONFLICT_MANUAL: "\u5408\u5E76\u5B58\u5728\u51B2\u7A81\uFF0C\u8BF7\u624B\u52A8\u5904\u7406\uFF1A\n \u89E3\u51B3\u51B2\u7A81\u540E\u6267\u884C git add . && git merge --continue"
168
183
  };
169
184
 
170
185
  // src/constants/messages/validate.ts
@@ -490,6 +505,16 @@ var HOME_MESSAGES = {
490
505
  HOME_SWITCH_SUCCESS: (from, to) => `\u2713 \u5DF2\u4ECE ${from} \u5207\u6362\u5230\u4E3B\u5DE5\u4F5C\u5206\u652F ${to}`
491
506
  };
492
507
 
508
+ // src/constants/messages/tasks.ts
509
+ var TASKS_CMD_MESSAGES = {
510
+ /** 任务模板文件已存在 */
511
+ TASK_INIT_FILE_EXISTS: (path) => `\u6587\u4EF6\u5DF2\u5B58\u5728: ${path}\uFF0C\u5982\u9700\u8986\u76D6\u8BF7\u5148\u5220\u9664`,
512
+ /** 任务模板生成成功 */
513
+ TASK_INIT_SUCCESS: (path) => `\u2713 \u4EFB\u52A1\u6A21\u677F\u5DF2\u751F\u6210: ${path}`,
514
+ /** 任务模板使用提示 */
515
+ TASK_INIT_HINT: (path) => `\u4F7F\u7528 clawt run -f ${path} \u6267\u884C\u4EFB\u52A1`
516
+ };
517
+
493
518
  // src/constants/messages/interactive-panel.ts
494
519
  import chalk from "chalk";
495
520
 
@@ -548,7 +573,8 @@ var MESSAGES = {
548
573
  ...COMPLETION_MESSAGES,
549
574
  ...INIT_MESSAGES,
550
575
  ...COVER_VALIDATE_MESSAGES,
551
- ...HOME_MESSAGES
576
+ ...HOME_MESSAGES,
577
+ ...TASKS_CMD_MESSAGES
552
578
  };
553
579
 
554
580
  // src/constants/terminal.ts
@@ -592,6 +618,15 @@ var CONFIG_DEFINITIONS = {
592
618
  autoUpdate: {
593
619
  defaultValue: true,
594
620
  description: "\u662F\u5426\u542F\u7528\u81EA\u52A8\u66F4\u65B0\u68C0\u67E5\uFF08\u6BCF 24 \u5C0F\u65F6\u68C0\u67E5\u4E00\u6B21 npm registry\uFF09"
621
+ },
622
+ conflictResolveMode: {
623
+ defaultValue: "ask",
624
+ description: "merge \u51B2\u7A81\u65F6\u7684\u89E3\u51B3\u6A21\u5F0F\uFF1Aask\uFF08\u8BE2\u95EE\u662F\u5426\u4F7F\u7528 AI\uFF09\u3001auto\uFF08\u81EA\u52A8 AI \u89E3\u51B3\uFF09\u3001manual\uFF08\u624B\u52A8\u89E3\u51B3\uFF09",
625
+ allowedValues: ["ask", "auto", "manual"]
626
+ },
627
+ conflictResolveTimeoutMs: {
628
+ defaultValue: 3e5,
629
+ description: "Claude Code \u51B2\u7A81\u89E3\u51B3\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09\uFF0C\u9ED8\u8BA4 300000\uFF085 \u5206\u949F\uFF09"
595
630
  }
596
631
  };
597
632
  function deriveDefaultConfig(definitions) {
package/docs/alias.md CHANGED
@@ -31,7 +31,7 @@ clawt alias remove <alias>
31
31
 
32
32
  **约束规则:**
33
33
 
34
- 1. **别名不能覆盖内置命令名**:别名不能与任何已注册的内置命令同名(动态检测,当前包括 `list`、`create`、`remove`、`run`、`resume`、`validate`、`merge`、`config`、`sync`、`reset`、`status`、`alias`、`projects`、`completion`、`init`)。如果用户尝试设置与内置命令同名的别名,输出错误提示并返回
34
+ 1. **别名不能覆盖内置命令名**:别名不能与任何已注册的内置命令同名(动态检测,当前包括 `list`、`create`、`remove`、`run`、`resume`、`validate`、`cover`、`merge`、`config`、`sync`、`reset`、`status`、`alias`、`projects`、`completion`、`init`、`home`)。如果用户尝试设置与内置命令同名的别名,输出错误提示并返回
35
35
  2. **目标必须是内置命令**:别名的目标(`<command>`)必须是已注册的内置命令名。如果指定了不存在的目标命令,输出错误提示并返回
36
36
  3. **参数透传**:通过别名调用时,所有选项和参数会完全透传给目标命令,行为与直接调用目标命令完全一致
37
37
 
@@ -105,4 +105,10 @@ clawt alias list
105
105
  clawt alias remove l
106
106
  ```
107
107
 
108
+ **实现要点:**
109
+
110
+ - 消息常量定义在 `src/constants/messages/alias.ts`(`ALIAS_MESSAGES`),包括列表为空提示、设置/移除成功、别名不存在、与内置命令冲突、目标命令不存在等消息
111
+ - 别名应用逻辑位于 `src/utils/alias.ts` 的 `applyAliases` 函数:在主入口 `src/index.ts` 中,所有命令注册完成后调用,遍历配置中的 `aliases` 映射,通过 Commander.js 的 `.alias()` 方法为对应命令注册别名。如果目标命令不存在则跳过并输出 warn 级别日志
112
+ - 内置命令冲突检测通过 `getRegisteredCommandNames(program)` 动态获取所有已注册命令名,而非硬编码命令列表
113
+
108
114
  ---
@@ -37,7 +37,7 @@ clawt completion install
37
37
  | `-f` / `--file` 参数之后 | 动态列出匹配的文件和子目录(不限制文件类型,支持子目录递归浏览) |
38
38
  | `config set` / `config get` 之后 | 动态列出所有配置项键名(从 `CONFIG_DEFINITIONS` 获取) |
39
39
  | 输入以 `-` 开头 | 列出当前命令层级的可用选项(short/long) |
40
- | 其他情况 | 列出当前命令层级的可用子命令及别名 |
40
+ | 其他情况 | 列出当前命令层级的可用子命令及别名;若输入为空,同时列出可用选项 |
41
41
 
42
42
  **文件路径补全细节:**
43
43
  - 支持子目录递归浏览(如 `tasks/` 后继续 Tab 可深入子目录)
package/docs/config.md CHANGED
@@ -25,7 +25,7 @@ clawt config reset
25
25
  1. 读取全局配置文件 `~/.clawt/config.json`
26
26
  2. 列出所有配置项供用户选择(`Enquirer.Select`),每项显示:
27
27
  - 配置项名称
28
- - 当前值(布尔值绿色/黄色,字符串青色)
28
+ - 当前值(布尔值绿色/黄色,字符串和数字青色)
29
29
  - 配置项描述(暗淡色 dim)
30
30
  - 对象类型配置项(如 `aliases`)标灰不可选,提示用户通过专用命令管理
31
31
  3. 用户选择某个配置项后,根据值类型自动选择提示策略:
@@ -86,7 +86,8 @@ clawt config reset
86
86
  - 配置项类型定义:`ConfigItemDefinition` 新增可选字段 `allowedValues`(`readonly string[]`),仅对 string 类型有效,用于枚举值校验和交互式 Select 提示
87
87
  - 值解析与提示策略:`src/utils/config-strategy.ts` 中的 `parseConfigValue()`(CLI 字符串解析)和 `promptConfigValue()`(交互式提示),基于类型和 `allowedValues` 自动分发
88
88
  - 交互式配置编辑:`handleInteractiveConfigSet` 调用通用的 `interactiveConfigEditor`(`src/utils/config-strategy.ts`),传入 `CONFIG_DEFINITIONS` 和 `disabledKeys`(对象类型配置项禁用映射),不再在 config 命令中直接构建选择列表和调用 `promptConfigValue`
89
- - `saveConfig(config)`:`src/utils/config.ts` 中新增的通用配置写入函数,将完整配置对象持久化到文件
90
- - `formatConfigValue(value)`:支持 boolean(绿色/黄色)和 string/number(青色)的格式化显示。`undefined` / `null` 值显示为暗淡色的 `(未设置)`。对象类型配置项(如 `aliases`)在交互式列表中通过 `JSON.stringify` 以暗淡色显示
89
+ - `saveConfig(config)`:`src/utils/config.ts` 中的通用配置写入函数,将完整配置对象持久化到文件
90
+ - `formatConfigValue(value)`:支持 boolean(绿色/黄色)和 string/number(青色)的格式化显示。`undefined` / `null` 值显示为暗淡色的 `(未设置)`
91
+ - 对象类型配置项(如 `aliases`)的显示逻辑在 `interactiveConfigEditor` 的列表构建中处理:通过 `JSON.stringify` 以暗淡色显示值,并标记为不可选(disabled),提示用户通过 `clawt alias` 命令管理
91
92
 
92
93
  ---
@@ -20,9 +20,10 @@ clawt cover
20
20
 
21
21
  ##### 步骤 1:前置校验
22
22
 
23
- 1. **主 worktree 校验**(2.1)
24
- 2. **项目级配置校验**(`requireProjectConfig`)
25
- 3. **验证分支校验**:当前分支必须以 `clawt-validate-` 开头,否则报错退出
23
+ 1. **主 worktree 校验**(`requireMainWorktree`)
24
+ 2. **HEAD 校验**(`requireHead`)
25
+ 3. **项目级配置校验**(`requireProjectConfig`)
26
+ 4. **验证分支校验**:当前分支必须以 `clawt-validate-` 开头,否则报错退出
26
27
 
27
28
  ##### 步骤 2:查找目标 worktree
28
29
 
package/docs/create.md CHANGED
@@ -10,20 +10,25 @@ clawt create -b <branchName> [-n <count>]
10
10
 
11
11
  | 参数 | 必填 | 说明 |
12
12
  | ---- | ---- | ----------------------------------------------------- |
13
- | `-b` | 是 | 分支名 |
14
- | `-n` | 否 | 需要创建的 worktree 数量,默认 `1` |
13
+ | `-b, --branch` | 是 | 分支名 |
14
+ | `-n, --number` | 否 | 需要创建的 worktree 数量,默认 `1` |
15
15
 
16
16
  **运行流程:**
17
17
 
18
- 1. **主 worktree 校验** (2.1)
19
- 2. **确保在主工作分支上**(`ensureOnMainWorkBranch`):在创建 worktree 之前,确保当前处于配置的主工作分支(`clawtMainWorkBranch`)上。
18
+ 通过 `runPreChecks(PRE_CHECK_CREATE)` 执行统一前置校验,包含以下检查项:
19
+
20
+ 1. **主 worktree 校验**(`requireMainWorktree`)(2.1)
21
+ 2. **HEAD 存在性校验**(`requireHead`):确保仓库有至少一次 commit
22
+ 3. **确保在主工作分支上**(`ensureOnClawtMainWorkBranch`):在创建 worktree 之前,确保当前处于配置的主工作分支(`clawtMainWorkBranch`)上。
20
23
  - 如果当前分支**是** `clawtMainWorkBranch`,正常继续
21
24
  - 如果当前在**验证分支**(`clawt-validate-` 前缀)上:
22
25
  - 验证分支上的修改视为可丢弃的临时状态
23
26
  - 如果工作区有未提交更改,自动执行 `git reset --hard HEAD && git clean -fd` 清理;若已干净则跳过清理
24
27
  - 然后自动切换到主工作分支,继续创建流程
25
28
  - 如果当前在**其他普通分支**上:
26
- - 如果工作区有未提交的更改,提供交互式选择(避免将修改意外带到主工作分支上):
29
+ - 首先显示警告:`当前分支 <currentBranch> 与配置的主工作分支 <mainBranch> 不一致,如需更新请执行 clawt init`
30
+ - 然后通过 `confirmAction('是否继续执行?')` 让用户确认是否继续;用户拒绝则抛出"已取消操作"退出
31
+ - 用户确认后,如果工作区有未提交的更改,提供交互式选择(避免将修改意外带到主工作分支上):
27
32
  ```
28
33
  ⚠ 当前分支有未提交的更改,请选择处理方式:
29
34
 
@@ -33,16 +38,17 @@ clawt create -b <branchName> [-n <count>]
33
38
  ```
34
39
  - 选择 reset → 执行 `git reset --hard HEAD && git clean -fd`
35
40
  - 选择 stash → 执行 `git add . && git stash push -m "clawt:auto-stash"`
36
- - 选择 exit → 抛出错误退出
37
- - 处理完成后再次校验工作区是否干净,不干净则报错退出
41
+ - 选择 exit → 抛出错误"用户选择退出,请手动处理工作区更改后重试"
42
+ - 处理完成后再次校验工作区是否干净,不干净则报错"工作区仍然不干净,请手动处理"
38
43
  - 执行 `git checkout <clawtMainWorkBranch>`,然后继续创建流程
39
- 3. **创建数量校验**:校验 `-n` 参数必须为正整数,否则报错 `无效的创建数量: "<value>",请输入正整数`
40
- 4. **分支名合法性校验与转换** (2.3)
41
- 5. **分支名存在性校验** (2.4)
44
+ 4. **主分支工作区干净校验**(`requireCleanWorkingDir`):确保主工作分支的工作区和暂存区干净,存在未提交更改时报错"主 worktree 有未提交的更改,请先处理"
45
+ 5. **创建数量校验**:校验 `-n` 参数必须为正整数,否则报错 `无效的创建数量: "<value>",请输入正整数`
46
+ 6. **分支名合法性校验与转换** (2.3)
47
+ 7. **分支名存在性校验** (2.4)
42
48
  - 若 `n = 1`:校验 `branchName`
43
49
  - 若 `n > 1`:校验 `branchName-1` 到 `branchName-n`
44
50
  - 所有分支名在创建任何 worktree **之前**完成全部校验
45
- 6. **批量创建 worktree + 验证分支**
51
+ 8. **批量创建 worktree + 验证分支**
46
52
  - 若 `n = 1`:
47
53
  ```bash
48
54
  git worktree add -b <branchName> ~/.clawt/worktrees/<project>/<branchName>
@@ -58,7 +64,7 @@ clawt create -b <branchName> [-n <count>]
58
64
  git worktree add -b <branchName>-n ~/.clawt/worktrees/<project>/<branchName>-n
59
65
  git branch clawt-validate-<branchName>-n
60
66
  ```
61
- 7. **输出创建日志**
67
+ 9. **输出创建日志**
62
68
 
63
69
  **输出格式:**
64
70
 
@@ -82,4 +88,14 @@ clawt create -b <branchName> [-n <count>]
82
88
  ────────────────────────────────────────
83
89
  ```
84
90
 
91
+ **实现要点:**
92
+
93
+ - 前置校验配置定义在 `src/constants/pre-checks.ts` 的 `PRE_CHECK_CREATE` 常量中
94
+ - 分支名清理逻辑在 `src/utils/branch.ts` 的 `sanitizeBranchName` 中
95
+ - 分支名生成逻辑在 `src/utils/branch.ts` 的 `generateBranchNames` 中
96
+ - worktree 批量创建逻辑在 `src/utils/worktree.ts` 的 `createWorktrees` 中
97
+ - 确保在主工作分支的逻辑在 `src/utils/validate-branch.ts` 的 `ensureOnMainWorkBranch` 中
98
+ - 脏工作区交互处理逻辑在 `src/utils/validate-branch.ts` 的 `handleDirtyWorkingDir` 中
99
+ - 相关消息常量定义在 `src/constants/messages/create.ts` 和 `src/constants/messages/common.ts` 中
100
+
85
101
  ---
package/docs/home.md CHANGED
@@ -16,21 +16,24 @@ clawt home
16
16
 
17
17
  **运行流程:**
18
18
 
19
- 1. **主 worktree 校验** (2.1)
20
- 2. **项目级配置校验**:调用 `requireProjectConfig()` 检查项目是否已初始化
21
- 3. **获取分支信息**:
19
+ 1. **前置校验**:调用 `runPreChecks` 执行统一前置校验:
20
+ - `requireMainWorktree`:校验当前目录是否在主 worktree 根目录 (2.1)
21
+ - `requireHead`:校验 HEAD 是否存在(仓库至少有一次 commit)
22
+ - `requireProjectConfig`:校验项目配置文件是否存在且合法
23
+ - `requireMainBranchExists`:校验配置中的主工作分支在 git 仓库中是否存在
24
+ 2. **获取分支信息**:
22
25
  - 通过 `getMainWorkBranch()` 获取主工作分支名
23
26
  - 通过 `getCurrentBranch()` 获取当前所在分支名
24
- 4. **判断是否需要切换**:
27
+ 3. **判断是否需要切换**:
25
28
  - 当前分支 === 主工作分支 → 输出提示信息,无需切换
26
29
  - 当前分支 !== 主工作分支 → 调用 `ensureOnMainWorkBranch()` 执行切换
27
- 5. **输出结果**
30
+ 4. **输出结果**
28
31
 
29
32
  **输出格式:**
30
33
 
31
34
  ```
32
35
  # 已在主工作分支上
33
- 已在主工作分支 main 上,无需切换
36
+ 已在主工作分支 main 上,无需切换
34
37
 
35
38
  # 切换成功
36
39
  ✓ 已从 clawt-validate-feat-login 切换到主工作分支 main
@@ -48,7 +51,8 @@ clawt home
48
51
  **实现要点:**
49
52
 
50
53
  - 命令注册函数 `registerHomeCommand` 位于 `src/commands/home.ts`
51
- - 依赖 `validateMainWorktree`、`requireProjectConfig`、`ensureOnMainWorkBranch`、`getCurrentBranch`、`getMainWorkBranch` 等工具函数
52
- - `requireProjectConfig()` 为显式调用,因为 home 命令不经过 `ensureOnMainWorkBranch()` 的隐式校验路径(仅在需要切换时才调用 `ensureOnMainWorkBranch()`)
54
+ - 前置校验通过 `runPreChecks` 统一调用,传入 `requireMainWorktree`、`requireHead`、`requireProjectConfig`、`requireMainBranchExists` 四项校验
55
+ - 主逻辑依赖 `ensureOnMainWorkBranch`、`getCurrentBranch`、`getMainWorkBranch`、`guardMainWorkBranchExists` 等工具函数
56
+ - `ensureOnMainWorkBranch()` 仅在需要切换时才调用(当前分支不等于主工作分支时)
53
57
 
54
58
  ---
package/docs/init.md CHANGED
@@ -27,20 +27,24 @@ clawt init show
27
27
  **运行流程(设置模式):**
28
28
 
29
29
  1. **主 worktree 校验** (2.1)
30
- 2. **确定主工作分支名**:
30
+ 2. **加载现有配置**:尝试读取 `~/.clawt/projects/<projectName>/config.json`(可能为 `null`)
31
+ 3. **确定主工作分支名**:
31
32
  - 传了 `-b` → 使用指定的分支名
32
- - 未传 `-b` → 使用当前分支名(`git rev-parse --abbrev-ref HEAD`)
33
- 3. **写入项目级配置**:将 `clawtMainWorkBranch` 写入 `~/.clawt/projects/<projectName>/config.json`
34
- - 配置文件不存在 → 创建
35
- - 配置文件已存在 → 覆盖整个配置文件内容
36
- 4. **输出成功提示**
33
+ - 未传 `-b` → 先验证 HEAD 存在,再使用当前分支名(`git rev-parse --abbrev-ref HEAD`)
34
+ 4. **合并并写入项目级配置**:将 `clawtMainWorkBranch` 合并到现有配置并写入 `~/.clawt/projects/<projectName>/config.json`
35
+ - 配置文件不存在 → 创建新配置
36
+ - 配置文件已存在 → 合并现有配置,仅更新 `clawtMainWorkBranch` 字段(保留其他配置项不变)
37
+ 5. **输出成功提示**:
38
+ - 已有配置 → `✓ 已将主工作分支从 <旧分支> 更新为 <新分支>`
39
+ - 无已有配置 → `✓ 项目初始化成功,主工作分支设置为: <分支名>`
37
40
 
38
41
  **运行流程(show 模式):**
39
42
 
40
43
  1. **主 worktree 校验** (2.1)
41
- 2. **读取项目级配置**:读取 `~/.clawt/projects/<projectName>/config.json`
44
+ 2. **项目配置校验**(`requireProjectConfig`):读取 `~/.clawt/projects/<projectName>/config.json`
42
45
  - 配置不存在 → 抛出错误 `项目尚未初始化,请先执行 clawt init 设置主工作分支`
43
- - 配置存在进入交互式面板
46
+ - 配置缺少 `clawtMainWorkBranch` 字段 抛出错误 `项目配置缺少主工作分支信息,请重新执行 clawt init 设置主工作分支`
47
+ - 配置存在且合法 → 进入交互式面板
44
48
  3. **交互式配置编辑**:调用 `interactiveConfigEditor`(`src/utils/config-strategy.ts`),基于 `PROJECT_CONFIG_DEFINITIONS` 构建配置项列表(详见 [project-config.md](./project-config.md))
45
49
  - 列出所有项目配置项,显示名称、当前值和描述
46
50
  - 用户选择配置项后,根据值类型自动选择输入方式(与全局配置的交互式编辑逻辑一致)
@@ -61,9 +65,12 @@ clawt init show
61
65
 
62
66
  # show 未初始化(抛出错误)
63
67
  项目尚未初始化,请先执行 clawt init 设置主工作分支
68
+
69
+ # show 配置缺少主工作分支字段(抛出错误)
70
+ 项目配置缺少主工作分支信息,请重新执行 clawt init 设置主工作分支
64
71
  ```
65
72
 
66
- **重复执行:** 支持重复执行,后一次覆盖前一次的配置。
73
+ **重复执行:** 支持重复执行,后一次会合并到现有配置中更新 `clawtMainWorkBranch`,不影响其他配置项。
67
74
 
68
75
  **实现要点:**
69
76
 
package/docs/list.md CHANGED
@@ -16,11 +16,10 @@ clawt list [--json]
16
16
 
17
17
  1. **主 worktree 校验** (2.1)
18
18
  2. **获取项目名** (2.2)
19
- 3. 扫描 `~/.clawt/worktrees/<project>/` 目录
20
- 4. 对每个子目录,验证是否为有效的 git worktree(`git worktree list` 交叉验证)
21
- 5. 根据 `--json` 选项决定输出格式:
22
- - 指定 `--json` 以 JSON 格式输出
23
- - 未指定 → 以文本格式输出
19
+ 3. 获取项目的所有 worktree 列表(扫描 `~/.clawt/worktrees/<project>/` 目录,与 `git worktree list` 交叉验证)
20
+ 4. 根据 `--json` 选项决定输出格式:
21
+ - 指定 `--json` → 以 JSON 格式输出(仅包含 path 和 branch)
22
+ - 未指定以文本格式输出(包含变更状态信息)
24
23
 
25
24
  **文本输出格式(默认):**
26
25
 
@@ -30,9 +29,16 @@ clawt list [--json]
30
29
  当前项目: main-project
31
30
 
32
31
  ~/.clawt/worktrees/main-project/feature-scheme-1 [feature-scheme-1]
32
+ 3 个提交 +120 -30 (未提交修改)
33
+
33
34
  ~/.clawt/worktrees/main-project/feature-scheme-2 [feature-scheme-2]
34
- ~/.clawt/worktrees/main-project/feature-scheme-3 [feature-scheme-3]
35
- ~/.clawt/worktrees/main-project/bugfix-login [bugfix-login]
35
+ 1 个提交 +45 -10
36
+
37
+ ~/.clawt/worktrees/main-project/feature-scheme-3 [feature-scheme-3] ← 橙色路径(空闲)
38
+ 0 个提交 无变更
39
+
40
+ ~/.clawt/worktrees/main-project/bugfix-login [bugfix-login]
41
+ 2 个提交 +80 -25
36
42
 
37
43
  共 4 个 worktree
38
44
  ```
package/docs/merge.md CHANGED
@@ -33,26 +33,26 @@ clawt merge [-m <commitMessage>]
33
33
  - 唯一匹配 → 直接使用
34
34
  - 多个匹配 → 通过交互式列表让用户从匹配结果中选择
35
35
  3. **无匹配** → 报错退出,并列出所有可用分支名
36
- 3. **主 worktree 状态检测**
36
+ 4. **主 worktree 状态检测**
37
37
  - 执行 `git status --porcelain`
38
38
  - 如果有更改:
39
39
  - 如果存在该分支的 validate 快照(`~/.clawt/validate-snapshots/<project>/<branchName>.tree`),额外输出警告 `主 worktree 可能存在 validate 残留状态,可先执行 clawt validate -b <branchName> --clean 清理`
40
40
  - 提示 `主 worktree 有未提交的更改,请先处理`,退出
41
41
  - 无更改 → 继续
42
- 4. **Squash 检测与执行(auto-save 临时提交压缩)**
42
+ 5. **Squash 检测与执行(auto-save 临时提交压缩)**
43
43
  - 通过 `git log HEAD..<branchName> --format=%s` 检查目标分支是否存在以 `AUTO_SAVE_COMMIT_MESSAGE`(`chore: auto-save before sync`)为前缀的 commit
44
- - **不存在** → 跳过,进入步骤 5
44
+ - **不存在** → 跳过,进入步骤 6
45
45
  - **存在** → 提示用户是否将所有提交压缩为一个:
46
46
  ```
47
47
  检测到 sync 产生的临时提交,是否将所有提交压缩为一个?
48
48
  压缩后变更将保留在目标worktree的暂存区,需要重新提交(可使用 Claude Code Cli或其他工具生成提交信息)
49
49
  ```
50
- - **用户选择不压缩** → 跳过,进入步骤 5
50
+ - **用户选择不压缩** → 跳过,进入步骤 6
51
51
  - **用户选择压缩** →
52
52
  1. 获取主分支名(从项目级配置 `clawtMainWorkBranch` 获取)
53
53
  2. 计算分叉点:`git merge-base <mainBranch> <branchName>`
54
54
  3. 在目标 worktree 中执行 `git reset --soft <merge-base>`,将所有 commit 撤销到暂存区
55
- 4. 如果用户提供了 `-m` → 直接在目标 worktree 执行 `git commit -m '<commitMessage>'`,输出成功提示,继续步骤 5
55
+ 4. 如果用户提供了 `-m` → 直接在目标 worktree 执行 `git commit -m '<commitMessage>'`,输出成功提示,继续步骤 6
56
56
  5. 如果用户未提供 `-m` → 提示用户前往目标 worktree 自行提交后重新执行 `clawt merge`:
57
57
  ```
58
58
  ✓ 已将所有提交压缩到暂存区
@@ -61,7 +61,7 @@ clawt merge [-m <commitMessage>]
61
61
  提交完成后执行:clawt merge -b <branch>
62
62
  ```
63
63
  **退出流程**
64
- 5. **根据目标 worktree 状态决定是否需要提交**
64
+ 6. **根据目标 worktree 状态决定是否需要提交**
65
65
  - 检测目标 worktree 工作区是否干净(`git status --porcelain`)
66
66
  - **工作区有未提交修改**:
67
67
  - 如果用户未提供 `-m`,提示 `<worktreePath> 有未提交的修改,请通过 -m 参数提供提交信息`(其中 `<worktreePath>` 为目标 worktree 的完整路径),退出
@@ -75,23 +75,23 @@ clawt merge [-m <commitMessage>]
75
75
  - 检查目标分支相对于主分支是否有本地提交(`git log HEAD..<branchName> --oneline`)
76
76
  - 有本地提交 → 跳过提交步骤,直接进入合并
77
77
  - 无本地提交 → 提示 `目标 worktree 没有任何可合并的变更(工作区干净且无本地提交)`,退出
78
- 6. **回到主 worktree 进行合并**
78
+ 7. **回到主 worktree 进行合并**
79
79
  ```bash
80
80
  cd <主 worktree 路径>
81
81
  git merge <branchName>
82
82
  ```
83
- 7. **冲突检测**(双层机制)
83
+ 8. **冲突检测**(双层机制)
84
84
  - **try-catch 层**:`git merge` 抛出异常时,先检查是否有冲突,有冲突则报错退出,否则重新抛出原始异常
85
85
  - **二次确认层**:即使 merge 未抛异常,也再次检查是否有合并冲突
86
86
  - **有冲突** → 提示 `合并存在冲突,请手动处理:\n 解决冲突后执行 git add . && git merge --continue`,退出
87
87
  - **无冲突** → 继续
88
- 8. **推送(受 `autoPullPush` 配置控制)**
88
+ 9. **推送(受 `autoPullPush` 配置控制)**
89
89
  - `autoPullPush` 为 `false` → 输出提示 `已跳过自动 pull/push,请手动执行 git pull && git push`
90
90
  - `autoPullPush` 为 `true` → 执行 `git pull` + `git push`:
91
91
  - `git pull` 失败且有冲突 → 输出警告 `自动 pull 时发生冲突,merge 已完成但远程同步失败`,退出(不再 push)
92
92
  - `git pull` 失败且无冲突 → 抛出错误
93
93
  - `git push` 失败 → 输出警告 `自动 push 失败,merge 和 pull 已完成\n 请手动执行 git push`,退出
94
- 9. **输出成功提示**
94
+ 10. **输出成功提示**
95
95
 
96
96
  ```
97
97
  # 提供了 -m 且已推送时
@@ -111,7 +111,7 @@ clawt merge [-m <commitMessage>]
111
111
  ✓ 分支 feature-scheme-1 已成功合并到当前分支
112
112
  ```
113
113
 
114
- 10. **merge 成功后确认并清理 worktree 和分支(可选)**
114
+ 11. **merge 成功后确认并清理 worktree 和分支(可选)**
115
115
  - 如果配置文件中 `autoDeleteBranch` 为 `true`,自动执行清理
116
116
  - 否则交互式询问用户是否清理
117
117
  - 用户确认后,依次执行:
@@ -129,7 +129,7 @@ clawt merge [-m <commitMessage>]
129
129
  - 输出清理成功提示:`✓ 已清理 worktree 和分支: <branchName>`
130
130
  - 验证分支的删除时机与目标分支保持一致(见 [2.5 验证分支生命周期](#25-验证分支)):用户确认清理 → 同步删除验证分支;用户拒绝清理 → 验证分支也保留
131
131
 
132
- 11. **清理 validate 快照**
132
+ 12. **清理 validate 快照**
133
133
  - merge 成功后,如果存在该分支的 validate 快照(`~/.clawt/validate-snapshots/<project>/<branchName>.tree` 和 `<branchName>.head`),自动删除这些快照文件(merge 成功后快照已无意义)
134
134
 
135
135
  > **注意:** 清理确认和清理操作均在 merge 成功后执行。只有 merge 成功才会询问用户是否清理 worktree 和分支,避免 merge 冲突时用户被提前询问造成困惑。
package/docs/remove.md CHANGED
@@ -24,7 +24,10 @@ clawt remove
24
24
 
25
25
  **运行流程:**
26
26
 
27
- 1. **主 worktree 校验** (2.1)
27
+ 1. **前置校验**:
28
+ - 主 worktree 校验 (2.1)
29
+ - HEAD 存在性校验
30
+ - 项目配置文件校验(确保项目已通过 `clawt init` 初始化)
28
31
  2. **获取项目名** (2.2)
29
32
  3. **确定待移除的 worktree 列表**:
30
33
  - **指定 `--all`** → 选中当前项目所有 worktree(若当前项目无 worktree,则提示并退出)
@@ -39,7 +42,8 @@ clawt remove
39
42
  - 唯一匹配 → 直接使用
40
43
  - 多个匹配 → 通过交互式多选列表让用户从匹配结果中选择
41
44
  3. **无匹配** → 报错退出,并列出所有可用分支名
42
- 4. 列出即将移除的 worktree 及对应分支:
45
+ 4. **当前分支安全检查**:逐个检查待移除的分支,如果该分支或其对应的验证分支(`clawt-validate-<branchName>`)是主 worktree 当前所在分支,则抛出错误并阻止移除。
46
+ 5. 列出即将移除的 worktree 及对应分支:
43
47
 
44
48
  ```
45
49
  即将移除以下 worktree 及本地分支:
@@ -51,29 +55,36 @@ clawt remove
51
55
  是否同时删除对应的本地分支和验证分支?(y/N)
52
56
  ```
53
57
 
54
- 5. 用户确认后(只需确认一次),对每个 worktree 依次执行(单个失败不影响其他):
58
+ 6. **判断是否删除本地分支**:
59
+ - 如果配置文件 `~/.clawt/config.json` 中 `autoDeleteBranch` 为 `true`,则跳过询问,直接删除分支
60
+ - 否则询问用户是否删除,用户拒绝时提示可稍后手动删除
61
+ 7. 对每个 worktree 依次执行(单个失败不影响其他):
55
62
 
56
63
  ```bash
57
- # 确保当前处于主工作分支上(若不在则自动切回)
58
- git checkout <clawtMainWorkBranch>
59
-
60
64
  # 移除 worktree
61
65
  git worktree remove -f <worktree路径>
62
66
 
63
- # 如果用户选择了删除分支
67
+ # 如果用户选择了删除分支(或 autoDeleteBranch 为 true)
64
68
  git branch -D <branchName>
65
69
 
66
- # 无条件删除验证分支和清理快照(不受用户确认控制)
70
+ # 无条件删除验证分支(不受用户确认控制,存在则删除)
67
71
  git branch -D clawt-validate-<branchName>
68
- # 清理该分支对应的 validate 快照
72
+ # 无条件清理该分支对应的 validate 快照
69
73
  ```
70
74
 
71
- 6. 如果配置文件 `~/.clawt/config.json` `autoDeleteBranch` 为 `true`,则跳过询问,直接删除分支。
75
+ 8. 如果使用 `--all` 模式,额外清理整个项目的 validate 快照目录。
76
+
77
+ 9. 移除完成后执行清理:
78
+ - `git worktree prune` 清理已失效的 worktree 引用
79
+ - 如果 `~/.clawt/worktrees/<project>/` 下已无 worktree,则删除该项目目录
72
80
 
73
- 7. 如果使用 `--all` 模式,额外清理整个项目的 validate 快照目录。
81
+ 10. 批量移除时,单个 worktree 移除失败不会中断整个流程,而是收集所有失败项,最后汇总报告并以错误状态退出(抛出 ClawtError)。
74
82
 
75
- 8. 移除完成后,清理空目录(如果 `~/.clawt/worktrees/<project>/` 下已无 worktree,则删除该项目目录)。
83
+ **实现要点:**
76
84
 
77
- 9. 批量移除时,单个 worktree 移除失败不会中断整个流程,而是收集所有失败项,最后汇总报告并以错误状态退出(抛出 ClawtError)。
85
+ - 消息常量定义在 `src/constants/messages/remove.ts`
86
+ - 分支解析逻辑复用公共模块 `resolveTargetWorktrees`(`src/utils/worktree-matcher.ts`)
87
+ - 验证分支删除通过 `deleteValidateBranch`(`src/utils/validate-branch.ts`),内部判断分支是否存在后才执行删除
88
+ - 快照清理通过 `removeSnapshot` 和 `removeProjectSnapshots`(`src/utils/validate-snapshot.ts`)
78
89
 
79
90
  ---
package/docs/reset.md CHANGED
@@ -16,12 +16,14 @@ clawt reset
16
16
 
17
17
  **运行流程:**
18
18
 
19
- 1. **主 worktree 校验** (2.1)
20
- 2. **项目级配置校验**(`requireProjectConfig()`,因 reset 不调用 `ensureOnMainWorkBranch`,需自行校验)
21
- 3. **检测工作区状态**:通过 `git status --porcelain` 检测主 worktree 是否有未提交的更改
19
+ 1. **前置校验**(`runPreChecks`):
20
+ - `requireMainWorktree`:主 worktree 校验 (2.1)
21
+ - `requireHead`:HEAD 存在校验
22
+ - `requireProjectConfig`:项目级配置校验
23
+ 2. **检测工作区状态**:通过 `git status --porcelain` 检测主 worktree 是否有未提交的更改
22
24
  - **工作区干净** → 输出提示 `主 worktree 工作区和暂存区已是干净状态,无需重置`,退出
23
25
  - **工作区不干净** → 继续
24
- 3. **确认破坏性操作**:如果配置项 `confirmDestructiveOps` 为 `true`,提示确认(显示即将执行的危险指令和操作后果),用户取消则退出
26
+ 3. **确认破坏性操作**:如果配置项 `confirmDestructiveOps` 为 `true`,提示确认(显示即将执行的危险指令 `git reset --hard + git clean -fd` 和操作后果 `丢弃所有未提交的更改`),用户取消则输出 `已取消操作` 并退出
25
27
  4. **重置工作区和暂存区**:
26
28
  ```bash
27
29
  git reset --hard HEAD
package/docs/resume.md CHANGED
@@ -22,9 +22,8 @@ clawt resume
22
22
 
23
23
  **运行流程:**
24
24
 
25
- 1. **主 worktree 校验** (2.1)
26
- 2. **Claude Code CLI 校验**:确认 `claude` CLI 可用
27
- 3. **解析目标 worktree**:根据是否传入 `-b` 参数以及 worktree 数量,采用不同的解析策略:
25
+ 1. **前置校验**(`PRE_CHECK_RESUME`):主 worktree 校验 (2.1) + HEAD 存在性校验 + Claude Code CLI 可用性校验
26
+ 2. **解析目标 worktree**:根据是否传入 `-b` 参数以及 worktree 数量,采用不同的解析策略:
28
27
  - **未传 `-b` 参数**:
29
28
  - 获取当前项目所有 worktree
30
29
  - 无可用 worktree → 报错退出
@@ -36,7 +35,7 @@ clawt resume
36
35
  - 唯一匹配 → 直接使用
37
36
  - 多个匹配 → 通过交互式多选列表让用户从匹配结果中选择
38
37
  3. **无匹配** → 报错退出,并列出所有可用分支名
39
- 4. **根据选中数量自动分发**:
38
+ 3. **根据选中数量自动分发**:
40
39
  - **用户未选择任何分支** → 直接退出
41
40
  - **选中 1 个** → 根据全局配置项 `resumeInPlace` 决定打开方式:
42
41
  - `resumeInPlace: true` → 在当前终端就地恢复,通过 `launchInteractiveClaude()` 启动(使用 `spawnSync` + `inherit stdio`)