clawt 2.14.0 → 2.14.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.
- package/.claude/agent-memory/docs-sync-updater/MEMORY.md +8 -3
- package/README.md +20 -3
- package/dist/index.js +10 -5
- package/dist/postinstall.js +1 -1
- package/docs/spec.md +63 -23
- package/package.json +1 -1
- package/src/commands/config.ts +10 -5
- package/src/constants/config.ts +1 -1
- package/src/constants/index.ts +1 -0
- package/src/constants/messages/config.ts +3 -0
- package/src/constants/messages/index.ts +3 -1
- package/tests/unit/commands/config.test.ts +34 -3
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
- 命令流程在 `5. 需求场景详细设计` 下,每个命令一个子章节(5.1-5.14)
|
|
8
8
|
- run 命令对应 `5.2 批量创建 Worktree + 执行 Claude Code 任务`,流程按步骤编号描述
|
|
9
9
|
- merge 命令对应 `5.6 合并验证过的分支`,-b 可选,支持模糊匹配(与 resume/validate 共享匹配逻辑),流程按步骤编号描述
|
|
10
|
-
- config 命令对应 `5.10
|
|
10
|
+
- config 命令对应 `5.10 交互式查看和修改全局配置`,包含四个子章节:交互式修改(config / config set 无参数)、直接设置(config set key value)、获取(config get)、恢复默认(config reset),使用 `####` 子标题区分
|
|
11
11
|
- resume 命令对应 `5.11 在已有 Worktree 中恢复会话`,统一使用多选交互(resolveTargetWorktrees),选 1 个当前终端恢复,选多个在独立终端 Tab 批量恢复(-b 可选)
|
|
12
12
|
- validate 命令对应 `5.4 在主 Worktree 验证其他分支`,-b 可选,支持模糊匹配(与 resume 共享匹配逻辑)
|
|
13
13
|
- sync 命令对应 `5.12 将主分支代码同步到目标 Worktree`,-b 可选,支持模糊匹配(与 resume/validate/merge 共享匹配逻辑)
|
|
@@ -72,9 +72,9 @@ run 命令有两种模式(自 claudeCodeCommand 特性后):
|
|
|
72
72
|
- `formatDuration` 从 `src/utils/progress.ts` 移至 `src/utils/formatter.ts`
|
|
73
73
|
- 进度面板每个任务行末尾显示 worktree 路径(终端可点击跳转)
|
|
74
74
|
|
|
75
|
-
## 命令清单(
|
|
75
|
+
## 命令清单(12 个)
|
|
76
76
|
|
|
77
|
-
`create`、`run`、`resume`、`list`、`remove`、`validate`、`merge`、`config`、`sync`、`reset`、`status`
|
|
77
|
+
`create`、`run`、`resume`、`list`、`remove`、`validate`、`merge`、`config`、`sync`、`reset`、`status`、`alias`
|
|
78
78
|
|
|
79
79
|
Notes:
|
|
80
80
|
- resume 和 run(交互式模式)共用 `launchInteractiveClaude()`,该函数从 run.ts 提取到 src/utils/claude.ts
|
|
@@ -91,6 +91,11 @@ Notes:
|
|
|
91
91
|
- `promptMultiSelectBranches` 支持「全选」选项(顶部 [select-all]),通过扩展 MultiSelect 覆写 space() 实现全选 toggle
|
|
92
92
|
- `SELECT_ALL_NAME` 和 `SELECT_ALL_LABEL` 常量定义在 `src/constants/prompt.ts`
|
|
93
93
|
- `VALID_TERMINAL_APPS` 和 `ITERM2_APP_PATH` 常量定义在 `src/constants/terminal.ts`
|
|
94
|
+
- config 交互式修改:对象类型配置项(如 `aliases`)在 Enquirer.Select 列表中标灰不可选(`disabled: CONFIG_ALIAS_DISABLED_HINT`),提示用户通过专用命令管理
|
|
95
|
+
- `CONFIG_ALIAS_DISABLED_HINT` 常量定义在 `src/constants/messages/config.ts`,通过 `src/constants/messages/index.ts` 和 `src/constants/index.ts` 导出
|
|
96
|
+
- `parseConfigValue()` 和 `promptConfigValue()` 在 `src/utils/config-strategy.ts`,基于配置项类型和 `allowedValues` 自动分发值解析/提示策略
|
|
97
|
+
- `saveConfig()` 在 `src/utils/config.ts`,通用配置写入函数
|
|
98
|
+
- `ConfigItemDefinition` 支持可选 `allowedValues` 字段(`readonly string[]`),用于 string 类型枚举校验
|
|
94
99
|
|
|
95
100
|
## validate 快照机制
|
|
96
101
|
|
package/README.md
CHANGED
|
@@ -143,11 +143,28 @@ clawt status --json # JSON 格式
|
|
|
143
143
|
clawt reset
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
### `clawt config` —
|
|
146
|
+
### `clawt config` — 交互式查看和修改配置
|
|
147
147
|
|
|
148
148
|
```bash
|
|
149
|
-
clawt config
|
|
150
|
-
clawt config
|
|
149
|
+
clawt config # 交互式修改配置(选择配置项并修改值)
|
|
150
|
+
clawt config set <key> <value> # 直接设置某个配置项
|
|
151
|
+
clawt config get <key> # 获取某个配置项的值
|
|
152
|
+
clawt config reset # 恢复默认配置
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**使用示例:**
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# 交互式修改(列出所有配置项,方向键选择,根据类型自动提示)
|
|
159
|
+
clawt config
|
|
160
|
+
|
|
161
|
+
# 直接设置
|
|
162
|
+
clawt config set autoDeleteBranch true
|
|
163
|
+
clawt config set maxConcurrency 4
|
|
164
|
+
clawt config set terminalApp iterm2
|
|
165
|
+
|
|
166
|
+
# 查看某项配置
|
|
167
|
+
clawt config get maxConcurrency
|
|
151
168
|
```
|
|
152
169
|
|
|
153
170
|
### `clawt alias` — 管理命令别名
|
package/dist/index.js
CHANGED
|
@@ -249,6 +249,7 @@ var RESET_MESSAGES = {
|
|
|
249
249
|
};
|
|
250
250
|
|
|
251
251
|
// src/constants/messages/config.ts
|
|
252
|
+
var CONFIG_ALIAS_DISABLED_HINT = "(\u901A\u8FC7 clawt alias \u547D\u4EE4\u7BA1\u7406)";
|
|
252
253
|
var CONFIG_CMD_MESSAGES = {
|
|
253
254
|
/** 配置已恢复为默认值 */
|
|
254
255
|
CONFIG_RESET_SUCCESS: "\u2713 \u914D\u7F6E\u5DF2\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C",
|
|
@@ -377,7 +378,7 @@ var CONFIG_DEFINITIONS = {
|
|
|
377
378
|
},
|
|
378
379
|
aliases: {
|
|
379
380
|
defaultValue: {},
|
|
380
|
-
description: "\u547D\u4EE4\u522B\u540D\u6620\u5C04
|
|
381
|
+
description: "\u547D\u4EE4\u522B\u540D\u6620\u5C04"
|
|
381
382
|
}
|
|
382
383
|
};
|
|
383
384
|
function deriveDefaultConfig(definitions) {
|
|
@@ -2469,10 +2470,14 @@ async function handleInteractiveConfigSet() {
|
|
|
2469
2470
|
const config2 = loadConfig();
|
|
2470
2471
|
const keys = Object.keys(DEFAULT_CONFIG);
|
|
2471
2472
|
logger.info("config set \u547D\u4EE4\u6267\u884C\uFF0C\u8FDB\u5165\u4EA4\u4E92\u5F0F\u914D\u7F6E");
|
|
2472
|
-
const choices = keys.map((k) =>
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2473
|
+
const choices = keys.map((k) => {
|
|
2474
|
+
const isObject = typeof DEFAULT_CONFIG[k] === "object";
|
|
2475
|
+
return {
|
|
2476
|
+
name: k,
|
|
2477
|
+
message: `${k}: ${isObject ? chalk6.dim(JSON.stringify(config2[k])) : formatConfigValue(config2[k])} ${chalk6.dim(`\u2014 ${CONFIG_DESCRIPTIONS[k]}`)}`,
|
|
2478
|
+
...isObject && { disabled: CONFIG_ALIAS_DISABLED_HINT }
|
|
2479
|
+
};
|
|
2480
|
+
});
|
|
2476
2481
|
const selectedKey = await new Enquirer5.Select({
|
|
2477
2482
|
message: MESSAGES.CONFIG_SELECT_PROMPT,
|
|
2478
2483
|
choices
|
package/dist/postinstall.js
CHANGED
|
@@ -357,7 +357,7 @@ var CONFIG_DEFINITIONS = {
|
|
|
357
357
|
},
|
|
358
358
|
aliases: {
|
|
359
359
|
defaultValue: {},
|
|
360
|
-
description: "\u547D\u4EE4\u522B\u540D\u6620\u5C04
|
|
360
|
+
description: "\u547D\u4EE4\u522B\u540D\u6620\u5C04"
|
|
361
361
|
}
|
|
362
362
|
};
|
|
363
363
|
function deriveDefaultConfig(definitions) {
|
package/docs/spec.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
- [5.7 默认配置文件](#57-默认配置文件)
|
|
22
22
|
- [5.8 获取当前项目所有 Worktree](#58-获取当前项目所有-worktree)
|
|
23
23
|
- [5.9 日志系统](#59-日志系统)
|
|
24
|
-
- [5.10
|
|
24
|
+
- [5.10 交互式查看和修改全局配置](#510-交互式查看和修改全局配置)
|
|
25
25
|
- [5.11 在已有 Worktree 中恢复会话](#511-在已有-worktree-中恢复会话)
|
|
26
26
|
- [5.12 将主分支代码同步到目标 Worktree](#512-将主分支代码同步到目标-worktree)
|
|
27
27
|
- [5.13 重置主 Worktree 工作区和暂存区](#513-重置主-worktree-工作区和暂存区)
|
|
@@ -174,7 +174,9 @@ git show-ref --verify refs/heads/<branchName> 2>/dev/null
|
|
|
174
174
|
| `clawt merge` | 合并某个已验证的 worktree 分支到主 worktree | 5.6 |
|
|
175
175
|
| `clawt remove` | 移除 worktree(支持模糊匹配/多选/全部) | 5.5 |
|
|
176
176
|
| `clawt list` | 列出当前项目所有 worktree(支持 `--json` 格式输出) | 5.8 |
|
|
177
|
-
| `clawt config` |
|
|
177
|
+
| `clawt config` | 交互式查看和修改全局配置(等同于 `config set`) | 5.10 |
|
|
178
|
+
| `clawt config set` | 修改配置项(无参数进入交互式,有参数直接设置) | 5.10 |
|
|
179
|
+
| `clawt config get` | 获取单个配置项的值 | 5.10 |
|
|
178
180
|
| `clawt config reset` | 将配置恢复为默认值 | 5.10 |
|
|
179
181
|
| `clawt resume` | 在已有 worktree 中恢复 Claude Code 会话(支持多选批量恢复) | 5.11 |
|
|
180
182
|
| `clawt sync` | 将主分支最新代码同步到目标 worktree | 5.12 |
|
|
@@ -1000,51 +1002,82 @@ clawt validate -b feature-scheme --debug
|
|
|
1000
1002
|
|
|
1001
1003
|
---
|
|
1002
1004
|
|
|
1003
|
-
### 5.10
|
|
1005
|
+
### 5.10 交互式查看和修改全局配置
|
|
1004
1006
|
|
|
1005
1007
|
**命令:**
|
|
1006
1008
|
|
|
1007
1009
|
```bash
|
|
1008
|
-
#
|
|
1010
|
+
# 交互式修改配置(等同于 config set 无参数)
|
|
1009
1011
|
clawt config
|
|
1010
1012
|
|
|
1013
|
+
# 修改配置项(无参数进入交互式,有参数直接设置)
|
|
1014
|
+
clawt config set [key] [value]
|
|
1015
|
+
|
|
1016
|
+
# 获取单个配置项的值
|
|
1017
|
+
clawt config get <key>
|
|
1018
|
+
|
|
1011
1019
|
# 将配置恢复为默认值
|
|
1012
1020
|
clawt config reset
|
|
1013
1021
|
```
|
|
1014
1022
|
|
|
1015
|
-
####
|
|
1023
|
+
#### 交互式修改配置(`config` / `config set`)
|
|
1024
|
+
|
|
1025
|
+
直接执行 `clawt config` 或 `clawt config set`(不带参数)进入交互式配置修改模式。
|
|
1016
1026
|
|
|
1017
1027
|
**运行流程:**
|
|
1018
1028
|
|
|
1019
1029
|
1. 读取全局配置文件 `~/.clawt/config.json`
|
|
1020
|
-
2.
|
|
1021
|
-
-
|
|
1030
|
+
2. 列出所有配置项供用户选择(`Enquirer.Select`),每项显示:
|
|
1031
|
+
- 配置项名称
|
|
1022
1032
|
- 当前值(布尔值绿色/黄色,字符串青色)
|
|
1023
1033
|
- 配置项描述(灰色)
|
|
1024
|
-
|
|
1034
|
+
- 对象类型配置项(如 `aliases`)标灰不可选,提示用户通过专用命令管理
|
|
1035
|
+
3. 用户选择某个配置项后,根据值类型自动选择提示策略:
|
|
1036
|
+
- **boolean 类型** → `Select`(true / false)
|
|
1037
|
+
- **number 类型** → `Input`(带数字校验)
|
|
1038
|
+
- **string 类型 + 有 `allowedValues`** → `Select`(枚举列表)
|
|
1039
|
+
- **string 类型 + 无 `allowedValues`** → `Input`(自由输入)
|
|
1040
|
+
4. 将修改后的配置持久化到配置文件
|
|
1041
|
+
5. 输出成功提示:`✓ <key> 已设置为 <value>`
|
|
1025
1042
|
|
|
1026
|
-
|
|
1043
|
+
#### 直接设置配置项(`config set <key> <value>`)
|
|
1027
1044
|
|
|
1028
|
-
|
|
1029
|
-
配置文件路径: ~/.clawt/config.json
|
|
1030
|
-
────────────────────────────────────────
|
|
1031
|
-
autoDeleteBranch: false
|
|
1032
|
-
移除 worktree 时是否自动删除对应本地分支
|
|
1045
|
+
当带参数执行 `clawt config set <key> <value>` 时,直接修改指定配置项。
|
|
1033
1046
|
|
|
1034
|
-
|
|
1035
|
-
Claude Code CLI 启动指令
|
|
1047
|
+
**参数:**
|
|
1036
1048
|
|
|
1037
|
-
|
|
1038
|
-
|
|
1049
|
+
| 参数 | 必填 | 说明 |
|
|
1050
|
+
| ---- | ---- | ---- |
|
|
1051
|
+
| `key` | 否 | 配置项名称(不传则进入交互式模式) |
|
|
1052
|
+
| `value` | 否 | 配置值(传了 `key` 时必填) |
|
|
1039
1053
|
|
|
1040
|
-
|
|
1041
|
-
执行破坏性操作(reset、validate --clean)前是否提示确认
|
|
1054
|
+
**运行流程:**
|
|
1042
1055
|
|
|
1043
|
-
|
|
1056
|
+
1. 校验 `key` 是否为有效的配置项名称(基于 `DEFAULT_CONFIG` 的键列表),无效则输出错误及可用配置项列表
|
|
1057
|
+
2. 校验 `value` 是否缺失,缺失则提示用法:`clawt config set <key> <value>`
|
|
1058
|
+
3. 根据目标配置项的类型解析并校验值:
|
|
1059
|
+
- **boolean** → 仅接受 `true` 或 `false`
|
|
1060
|
+
- **number** → `Number()` 解析,`NaN` 报错
|
|
1061
|
+
- **string + 有 `allowedValues`** → 校验值是否在枚举列表中
|
|
1062
|
+
- **string + 无 `allowedValues`** → 无额外校验
|
|
1063
|
+
4. 加载配置、修改目标项、持久化
|
|
1064
|
+
5. 输出成功提示:`✓ <key> 已设置为 <value>`
|
|
1044
1065
|
|
|
1045
|
-
|
|
1066
|
+
#### 获取单个配置项(`config get <key>`)
|
|
1046
1067
|
|
|
1047
|
-
|
|
1068
|
+
**参数:**
|
|
1069
|
+
|
|
1070
|
+
| 参数 | 必填 | 说明 |
|
|
1071
|
+
| ---- | ---- | ---- |
|
|
1072
|
+
| `key` | 是 | 配置项名称 |
|
|
1073
|
+
|
|
1074
|
+
**运行流程:**
|
|
1075
|
+
|
|
1076
|
+
1. 校验 `key` 是否为有效的配置项名称,无效则输出错误及可用配置项列表
|
|
1077
|
+
2. 读取配置文件,获取目标配置项的值
|
|
1078
|
+
3. 输出:`<key> = <value>`
|
|
1079
|
+
|
|
1080
|
+
#### 恢复默认配置(`config reset`)
|
|
1048
1081
|
|
|
1049
1082
|
**运行流程:**
|
|
1050
1083
|
|
|
@@ -1052,6 +1085,13 @@ clawt config reset
|
|
|
1052
1085
|
2. 将默认配置写入 `~/.clawt/config.json`(覆盖现有配置文件)
|
|
1053
1086
|
3. 输出成功提示:`✓ 配置已恢复为默认值`
|
|
1054
1087
|
|
|
1088
|
+
**实现要点:**
|
|
1089
|
+
|
|
1090
|
+
- 配置项类型定义:`ConfigItemDefinition` 新增可选字段 `allowedValues`(`readonly string[]`),仅对 string 类型有效,用于枚举值校验和交互式 Select 提示
|
|
1091
|
+
- 值解析与提示策略:`src/utils/config-strategy.ts` 中的 `parseConfigValue()`(CLI 字符串解析)和 `promptConfigValue()`(交互式提示),基于类型和 `allowedValues` 自动分发
|
|
1092
|
+
- `saveConfig(config)`:`src/utils/config.ts` 中新增的通用配置写入函数,将完整配置对象持久化到文件
|
|
1093
|
+
- `formatConfigValue(value)`:支持 boolean、string、number、对象类型(如 `aliases`,按键值对逐行展示)的格式化显示
|
|
1094
|
+
|
|
1055
1095
|
---
|
|
1056
1096
|
|
|
1057
1097
|
### 5.11 在已有 Worktree 中恢复会话
|
package/package.json
CHANGED
package/src/commands/config.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import Enquirer from 'enquirer';
|
|
4
|
-
import { DEFAULT_CONFIG, CONFIG_DESCRIPTIONS, MESSAGES } from '../constants/index.js';
|
|
4
|
+
import { DEFAULT_CONFIG, CONFIG_DESCRIPTIONS, MESSAGES, CONFIG_ALIAS_DISABLED_HINT } from '../constants/index.js';
|
|
5
5
|
import { logger } from '../logger/index.js';
|
|
6
6
|
import {
|
|
7
7
|
loadConfig,
|
|
@@ -123,10 +123,15 @@ async function handleInteractiveConfigSet(): Promise<void> {
|
|
|
123
123
|
logger.info('config set 命令执行,进入交互式配置');
|
|
124
124
|
|
|
125
125
|
// 构建选择列表,显示配置项名称、当前值和描述
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
// 对象类型配置项(如 aliases)标灰不可选,提示用户通过专用命令管理
|
|
127
|
+
const choices = keys.map((k) => {
|
|
128
|
+
const isObject = typeof DEFAULT_CONFIG[k] === 'object';
|
|
129
|
+
return {
|
|
130
|
+
name: k,
|
|
131
|
+
message: `${k}: ${isObject ? chalk.dim(JSON.stringify(config[k])) : formatConfigValue(config[k])} ${chalk.dim(`— ${CONFIG_DESCRIPTIONS[k]}`)}`,
|
|
132
|
+
...(isObject && { disabled: CONFIG_ALIAS_DISABLED_HINT }),
|
|
133
|
+
};
|
|
134
|
+
});
|
|
130
135
|
|
|
131
136
|
// @ts-expect-error enquirer 类型声明未导出 Select 类,但运行时存在
|
|
132
137
|
const selectedKey: keyof ClawtConfig = await new Enquirer.Select({
|
package/src/constants/config.ts
CHANGED
package/src/constants/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { CLAWT_HOME, CONFIG_PATH, LOGS_DIR, WORKTREES_DIR, VALIDATE_SNAPSHOTS_DIR, CLAUDE_PROJECTS_DIR } from './paths.js';
|
|
2
2
|
export { INVALID_BRANCH_CHARS } from './branch.js';
|
|
3
3
|
export { MESSAGES } from './messages/index.js';
|
|
4
|
+
export { CONFIG_ALIAS_DISABLED_HINT } from './messages/index.js';
|
|
4
5
|
export { EXIT_CODES } from './exitCodes.js';
|
|
5
6
|
export { ENABLE_BRACKETED_PASTE, DISABLE_BRACKETED_PASTE, PASTE_THRESHOLD_MS, VALID_TERMINAL_APPS, ITERM2_APP_PATH } from './terminal.js';
|
|
6
7
|
export { DEFAULT_CONFIG, CONFIG_DESCRIPTIONS, CONFIG_DEFINITIONS, APPEND_SYSTEM_PROMPT } from './config.js';
|
|
@@ -7,7 +7,9 @@ import { SYNC_MESSAGES } from './sync.js';
|
|
|
7
7
|
import { RESUME_MESSAGES } from './resume.js';
|
|
8
8
|
import { REMOVE_MESSAGES } from './remove.js';
|
|
9
9
|
import { RESET_MESSAGES } from './reset.js';
|
|
10
|
-
import { CONFIG_CMD_MESSAGES } from './config.js';
|
|
10
|
+
import { CONFIG_CMD_MESSAGES, CONFIG_ALIAS_DISABLED_HINT } from './config.js';
|
|
11
|
+
|
|
12
|
+
export { CONFIG_ALIAS_DISABLED_HINT };
|
|
11
13
|
import { STATUS_MESSAGES } from './status.js';
|
|
12
14
|
import { ALIAS_MESSAGES } from './alias.js';
|
|
13
15
|
|
|
@@ -2,15 +2,17 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
|
|
4
4
|
// mock enquirer(必须在所有 import 之前)
|
|
5
|
-
const { mockSelectRun, mockInputRun } = vi.hoisted(() => {
|
|
5
|
+
const { mockSelectRun, mockInputRun, mockSelectConstructorArgs } = vi.hoisted(() => {
|
|
6
6
|
const mockSelectRun = vi.fn();
|
|
7
7
|
const mockInputRun = vi.fn();
|
|
8
|
-
|
|
8
|
+
/** 用于捕获 Select 构造时传入的参数 */
|
|
9
|
+
const mockSelectConstructorArgs: unknown[] = [];
|
|
10
|
+
return { mockSelectRun, mockInputRun, mockSelectConstructorArgs };
|
|
9
11
|
});
|
|
10
12
|
|
|
11
13
|
vi.mock('enquirer', () => ({
|
|
12
14
|
default: {
|
|
13
|
-
Select: function MockSelect() { return { run: mockSelectRun }; },
|
|
15
|
+
Select: function MockSelect(opts: unknown) { mockSelectConstructorArgs.push(opts); return { run: mockSelectRun }; },
|
|
14
16
|
Input: function MockInput() { return { run: mockInputRun }; },
|
|
15
17
|
},
|
|
16
18
|
}));
|
|
@@ -48,6 +50,7 @@ vi.mock('../../../src/constants/index.js', () => ({
|
|
|
48
50
|
confirmDestructiveOps: true,
|
|
49
51
|
maxConcurrency: 0,
|
|
50
52
|
terminalApp: 'auto',
|
|
53
|
+
aliases: {},
|
|
51
54
|
},
|
|
52
55
|
CONFIG_DESCRIPTIONS: {
|
|
53
56
|
autoDeleteBranch: '自动删除分支',
|
|
@@ -56,6 +59,7 @@ vi.mock('../../../src/constants/index.js', () => ({
|
|
|
56
59
|
confirmDestructiveOps: '破坏性操作确认',
|
|
57
60
|
maxConcurrency: '最大并发数',
|
|
58
61
|
terminalApp: '终端应用',
|
|
62
|
+
aliases: '命令别名映射',
|
|
59
63
|
},
|
|
60
64
|
CONFIG_DEFINITIONS: {
|
|
61
65
|
autoDeleteBranch: { defaultValue: false, description: '自动删除分支' },
|
|
@@ -64,7 +68,9 @@ vi.mock('../../../src/constants/index.js', () => ({
|
|
|
64
68
|
confirmDestructiveOps: { defaultValue: true, description: '破坏性操作确认' },
|
|
65
69
|
maxConcurrency: { defaultValue: 0, description: '最大并发数' },
|
|
66
70
|
terminalApp: { defaultValue: 'auto', description: '终端应用', allowedValues: ['auto', 'iterm2', 'terminal'] },
|
|
71
|
+
aliases: { defaultValue: {}, description: '命令别名映射' },
|
|
67
72
|
},
|
|
73
|
+
CONFIG_ALIAS_DISABLED_HINT: '(通过 clawt alias 命令管理)',
|
|
68
74
|
MESSAGES: {
|
|
69
75
|
CONFIG_RESET_SUCCESS: '配置已恢复为默认值',
|
|
70
76
|
DESTRUCTIVE_OP_CANCELLED: '已取消操作',
|
|
@@ -104,6 +110,7 @@ function createMockConfig() {
|
|
|
104
110
|
confirmDestructiveOps: true,
|
|
105
111
|
maxConcurrency: 0,
|
|
106
112
|
terminalApp: 'auto',
|
|
113
|
+
aliases: {},
|
|
107
114
|
};
|
|
108
115
|
}
|
|
109
116
|
|
|
@@ -117,6 +124,7 @@ beforeEach(() => {
|
|
|
117
124
|
mockedConfirmDestructiveAction.mockReset();
|
|
118
125
|
mockSelectRun.mockReset();
|
|
119
126
|
mockInputRun.mockReset();
|
|
127
|
+
mockSelectConstructorArgs.length = 0;
|
|
120
128
|
});
|
|
121
129
|
|
|
122
130
|
describe('registerConfigCommand', () => {
|
|
@@ -374,6 +382,29 @@ describe('handleConfigSet — 交互模式', () => {
|
|
|
374
382
|
);
|
|
375
383
|
expect(mockedPrintSuccess).toHaveBeenCalled();
|
|
376
384
|
});
|
|
385
|
+
|
|
386
|
+
it('aliases 选项带 disabled 属性且不可选', async () => {
|
|
387
|
+
mockedLoadConfig.mockReturnValue(createMockConfig());
|
|
388
|
+
// 选择一个普通配置项完成交互流程
|
|
389
|
+
mockSelectRun.mockResolvedValueOnce('autoDeleteBranch');
|
|
390
|
+
mockSelectRun.mockResolvedValueOnce('true');
|
|
391
|
+
|
|
392
|
+
const program = new Command();
|
|
393
|
+
program.exitOverride();
|
|
394
|
+
registerConfigCommand(program);
|
|
395
|
+
await program.parseAsync(['config', 'set'], { from: 'user' });
|
|
396
|
+
|
|
397
|
+
// 捕获第一次 Select 构造参数(配置项选择列表)
|
|
398
|
+
const selectOpts = mockSelectConstructorArgs[0] as { choices: Array<{ name: string; disabled?: string }> };
|
|
399
|
+
const aliasesChoice = selectOpts.choices.find((c) => c.name === 'aliases');
|
|
400
|
+
expect(aliasesChoice).toBeDefined();
|
|
401
|
+
expect(aliasesChoice!.disabled).toBe('(通过 clawt alias 命令管理)');
|
|
402
|
+
|
|
403
|
+
// 普通配置项不应有 disabled 属性
|
|
404
|
+
const normalChoice = selectOpts.choices.find((c) => c.name === 'autoDeleteBranch');
|
|
405
|
+
expect(normalChoice).toBeDefined();
|
|
406
|
+
expect(normalChoice!.disabled).toBeUndefined();
|
|
407
|
+
});
|
|
377
408
|
});
|
|
378
409
|
|
|
379
410
|
describe('handleConfigGet', () => {
|