clawt 2.13.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.
@@ -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 查看和管理全局配置`,包含查看配置和 config reset 子命令两部分(使用 `####` 子标题区分)
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
- ## 命令清单(11 个)
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 reset # 恢复默认配置
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,9 +249,29 @@ 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
- CONFIG_RESET_SUCCESS: "\u2713 \u914D\u7F6E\u5DF2\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C"
255
+ CONFIG_RESET_SUCCESS: "\u2713 \u914D\u7F6E\u5DF2\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C",
256
+ /** 配置项设置成功 */
257
+ CONFIG_SET_SUCCESS: (key, value) => `\u2713 ${key} \u5DF2\u8BBE\u7F6E\u4E3A ${value}`,
258
+ /** 获取配置值显示 */
259
+ CONFIG_GET_VALUE: (key, value) => `${key} = ${value}`,
260
+ /** 无效配置项名称 */
261
+ CONFIG_INVALID_KEY: (key, validKeys) => `\u65E0\u6548\u7684\u914D\u7F6E\u9879: ${key}
262
+ \u53EF\u7528\u7684\u914D\u7F6E\u9879: ${validKeys.join(", ")}`,
263
+ /** 布尔类型值无效 */
264
+ CONFIG_INVALID_BOOLEAN: (key) => `\u914D\u7F6E\u9879 ${key} \u4E3A\u5E03\u5C14\u7C7B\u578B\uFF0C\u4EC5\u63A5\u53D7 true \u6216 false`,
265
+ /** 数字类型值无效 */
266
+ CONFIG_INVALID_NUMBER: (key) => `\u914D\u7F6E\u9879 ${key} \u4E3A\u6570\u5B57\u7C7B\u578B\uFF0C\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57`,
267
+ /** 枚举类型配置项值无效(通用版) */
268
+ CONFIG_INVALID_ENUM: (key, validValues) => `\u914D\u7F6E\u9879 ${key} \u4EC5\u63A5\u53D7\u4EE5\u4E0B\u503C: ${validValues.join(", ")}`,
269
+ /** 交互式选择配置项提示 */
270
+ CONFIG_SELECT_PROMPT: "\u9009\u62E9\u8981\u4FEE\u6539\u7684\u914D\u7F6E\u9879",
271
+ /** 交互式输入新值提示 */
272
+ CONFIG_INPUT_PROMPT: (key) => `\u8F93\u5165 ${key} \u7684\u65B0\u503C`,
273
+ /** 缺少 value 参数提示 */
274
+ CONFIG_MISSING_VALUE: (key) => `\u7F3A\u5C11\u914D\u7F6E\u503C\uFF0C\u7528\u6CD5: clawt config set ${key} <value>`
255
275
  };
256
276
 
257
277
  // src/constants/messages/status.ts
@@ -353,11 +373,12 @@ var CONFIG_DEFINITIONS = {
353
373
  },
354
374
  terminalApp: {
355
375
  defaultValue: "auto",
356
- description: "\u6279\u91CF resume \u4F7F\u7528\u7684\u7EC8\u7AEF\u5E94\u7528\uFF1Aauto\uFF08\u81EA\u52A8\u68C0\u6D4B\uFF09\u3001iterm2\u3001terminal\uFF08macOS\uFF09"
376
+ description: "\u6279\u91CF resume \u4F7F\u7528\u7684\u7EC8\u7AEF\u5E94\u7528\uFF1Aauto\uFF08\u81EA\u52A8\u68C0\u6D4B\uFF09\u3001iterm2\u3001terminal\uFF08macOS\uFF09",
377
+ allowedValues: VALID_TERMINAL_APPS
357
378
  },
358
379
  aliases: {
359
380
  defaultValue: {},
360
- description: "\u547D\u4EE4\u522B\u540D\u6620\u5C04\uFF08\u901A\u8FC7 clawt alias \u547D\u4EE4\u7BA1\u7406\uFF09"
381
+ description: "\u547D\u4EE4\u522B\u540D\u6620\u5C04"
361
382
  }
362
383
  };
363
384
  function deriveDefaultConfig(definitions) {
@@ -936,6 +957,9 @@ function writeConfig(config2) {
936
957
  function writeDefaultConfig() {
937
958
  writeConfig(DEFAULT_CONFIG);
938
959
  }
960
+ function saveConfig(config2) {
961
+ writeFileSync(CONFIG_PATH, JSON.stringify(config2, null, 2), "utf-8");
962
+ }
939
963
  function getConfigValue(key) {
940
964
  const config2 = loadConfig();
941
965
  return config2[key];
@@ -1731,8 +1755,98 @@ function applyAliases(program2, aliases) {
1731
1755
  }
1732
1756
  }
1733
1757
 
1734
- // src/commands/list.ts
1758
+ // src/utils/config-strategy.ts
1735
1759
  import chalk4 from "chalk";
1760
+ import Enquirer3 from "enquirer";
1761
+ function isValidConfigKey(key) {
1762
+ return key in DEFAULT_CONFIG;
1763
+ }
1764
+ function getValidConfigKeys() {
1765
+ return Object.keys(DEFAULT_CONFIG);
1766
+ }
1767
+ function parseConfigValue(key, rawValue) {
1768
+ const expectedType = typeof DEFAULT_CONFIG[key];
1769
+ if (expectedType === "boolean") {
1770
+ if (rawValue === "true") return { success: true, value: true };
1771
+ if (rawValue === "false") return { success: true, value: false };
1772
+ return { success: false, error: MESSAGES.CONFIG_INVALID_BOOLEAN(key) };
1773
+ }
1774
+ if (expectedType === "number") {
1775
+ const num = Number(rawValue);
1776
+ if (Number.isNaN(num)) {
1777
+ return { success: false, error: MESSAGES.CONFIG_INVALID_NUMBER(key) };
1778
+ }
1779
+ return { success: true, value: num };
1780
+ }
1781
+ const definition = CONFIG_DEFINITIONS[key];
1782
+ if (definition.allowedValues && !definition.allowedValues.includes(rawValue)) {
1783
+ return { success: false, error: MESSAGES.CONFIG_INVALID_ENUM(key, definition.allowedValues) };
1784
+ }
1785
+ return { success: true, value: rawValue };
1786
+ }
1787
+ async function promptConfigValue(key, currentValue) {
1788
+ const expectedType = typeof currentValue;
1789
+ if (expectedType === "boolean") {
1790
+ return promptBooleanValue(key, currentValue);
1791
+ }
1792
+ if (expectedType === "number") {
1793
+ return promptNumberValue(key, currentValue);
1794
+ }
1795
+ const definition = CONFIG_DEFINITIONS[key];
1796
+ if (definition.allowedValues) {
1797
+ return promptEnumValue(key, currentValue, definition.allowedValues);
1798
+ }
1799
+ return promptStringValue(key, currentValue);
1800
+ }
1801
+ function formatConfigValue(value) {
1802
+ if (typeof value === "boolean") {
1803
+ return value ? chalk4.green("true") : chalk4.yellow("false");
1804
+ }
1805
+ return chalk4.cyan(String(value));
1806
+ }
1807
+ async function promptBooleanValue(key, currentValue) {
1808
+ const choices = [
1809
+ { name: "true", message: "true" },
1810
+ { name: "false", message: "false" }
1811
+ ];
1812
+ const selected = await new Enquirer3.Select({
1813
+ message: MESSAGES.CONFIG_INPUT_PROMPT(key),
1814
+ choices,
1815
+ initial: currentValue ? 0 : 1
1816
+ }).run();
1817
+ return selected === "true";
1818
+ }
1819
+ async function promptNumberValue(key, currentValue) {
1820
+ const input = await new Enquirer3.Input({
1821
+ message: MESSAGES.CONFIG_INPUT_PROMPT(key),
1822
+ initial: String(currentValue),
1823
+ validate: (val) => {
1824
+ if (Number.isNaN(Number(val))) return "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57";
1825
+ return true;
1826
+ }
1827
+ }).run();
1828
+ return Number(input);
1829
+ }
1830
+ async function promptEnumValue(key, currentValue, allowedValues) {
1831
+ const choices = allowedValues.map((v) => ({
1832
+ name: v,
1833
+ message: v
1834
+ }));
1835
+ return await new Enquirer3.Select({
1836
+ message: MESSAGES.CONFIG_INPUT_PROMPT(key),
1837
+ choices,
1838
+ initial: allowedValues.indexOf(currentValue)
1839
+ }).run();
1840
+ }
1841
+ async function promptStringValue(key, currentValue) {
1842
+ return await new Enquirer3.Input({
1843
+ message: MESSAGES.CONFIG_INPUT_PROMPT(key),
1844
+ initial: currentValue
1845
+ }).run();
1846
+ }
1847
+
1848
+ // src/commands/list.ts
1849
+ import chalk5 from "chalk";
1736
1850
  function registerListCommand(program2) {
1737
1851
  program2.command("list").description("\u5217\u51FA\u5F53\u524D\u9879\u76EE\u6240\u6709 worktree").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA").action((options) => {
1738
1852
  handleList(options);
@@ -1769,12 +1883,12 @@ function printListAsText(projectName, worktrees) {
1769
1883
  for (const wt of worktrees) {
1770
1884
  const status = getWorktreeStatus(wt);
1771
1885
  const isIdle = status ? isWorktreeIdle(status) : false;
1772
- const pathDisplay = isIdle ? chalk4.hex("#FF8C00")(wt.path) : wt.path;
1886
+ const pathDisplay = isIdle ? chalk5.hex("#FF8C00")(wt.path) : wt.path;
1773
1887
  printInfo(` ${pathDisplay} [${wt.branch}]`);
1774
1888
  if (status) {
1775
1889
  printInfo(` ${formatWorktreeStatus(status)}`);
1776
1890
  } else {
1777
- printInfo(` ${chalk4.yellow(MESSAGES.WORKTREE_STATUS_UNAVAILABLE)}`);
1891
+ printInfo(` ${chalk5.yellow(MESSAGES.WORKTREE_STATUS_UNAVAILABLE)}`);
1778
1892
  }
1779
1893
  printInfo("");
1780
1894
  }
@@ -1997,7 +2111,7 @@ async function handleBatchResume(worktrees) {
1997
2111
  }
1998
2112
 
1999
2113
  // src/commands/validate.ts
2000
- import Enquirer3 from "enquirer";
2114
+ import Enquirer4 from "enquirer";
2001
2115
  var VALIDATE_RESOLVE_MESSAGES = {
2002
2116
  noWorktrees: MESSAGES.VALIDATE_NO_WORKTREES,
2003
2117
  selectBranch: MESSAGES.VALIDATE_SELECT_BRANCH,
@@ -2011,7 +2125,7 @@ function registerValidateCommand(program2) {
2011
2125
  }
2012
2126
  async function handleDirtyMainWorktree(mainWorktreePath) {
2013
2127
  printWarning("\u4E3B worktree \u5F53\u524D\u5206\u652F\u6709\u672A\u63D0\u4EA4\u7684\u66F4\u6539\uFF0C\u8BF7\u9009\u62E9\u5904\u7406\u65B9\u5F0F\uFF1A\n");
2014
- const choice = await new Enquirer3.Select({
2128
+ const choice = await new Enquirer4.Select({
2015
2129
  message: "\u9009\u62E9\u5904\u7406\u65B9\u5F0F",
2016
2130
  choices: [
2017
2131
  {
@@ -2299,34 +2413,21 @@ async function handleMerge(options) {
2299
2413
  }
2300
2414
 
2301
2415
  // src/commands/config.ts
2302
- import chalk5 from "chalk";
2416
+ import chalk6 from "chalk";
2417
+ import Enquirer5 from "enquirer";
2303
2418
  function registerConfigCommand(program2) {
2304
- const configCmd = program2.command("config").description("\u67E5\u770B\u548C\u7BA1\u7406\u5168\u5C40\u914D\u7F6E").action(() => {
2305
- handleConfig();
2419
+ const configCmd = program2.command("config").description("\u4EA4\u4E92\u5F0F\u67E5\u770B\u548C\u4FEE\u6539\u5168\u5C40\u914D\u7F6E").action(async () => {
2420
+ await handleConfigSet();
2306
2421
  });
2307
2422
  configCmd.command("reset").description("\u5C06\u914D\u7F6E\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C").action(async () => {
2308
2423
  await handleConfigReset();
2309
2424
  });
2310
- }
2311
- function handleConfig() {
2312
- const config2 = loadConfig();
2313
- logger.info("config \u547D\u4EE4\u6267\u884C\uFF0C\u5C55\u793A\u5168\u5C40\u914D\u7F6E");
2314
- printInfo(`
2315
- ${chalk5.dim("\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84:")} ${CONFIG_PATH}
2316
- `);
2317
- printSeparator();
2318
- const keys = Object.keys(DEFAULT_CONFIG);
2319
- for (let i = 0; i < keys.length; i++) {
2320
- const key = keys[i];
2321
- const value = config2[key];
2322
- const description = CONFIG_DESCRIPTIONS[key];
2323
- const formattedValue = formatConfigValue(value);
2324
- if (i === 0) printInfo("");
2325
- printInfo(` ${chalk5.bold(key)}: ${formattedValue}`);
2326
- printInfo(` ${chalk5.dim(description)}`);
2327
- printInfo("");
2328
- }
2329
- printSeparator();
2425
+ configCmd.command("set [key] [value]").description("\u4FEE\u6539\u914D\u7F6E\u9879\uFF08\u65E0\u53C2\u6570\u8FDB\u5165\u4EA4\u4E92\u5F0F\u914D\u7F6E\uFF09").action(async (key, value) => {
2426
+ await handleConfigSet(key, value);
2427
+ });
2428
+ configCmd.command("get <key>").description("\u83B7\u53D6\u5355\u4E2A\u914D\u7F6E\u9879\u7684\u503C").action((key) => {
2429
+ handleConfigGet(key);
2430
+ });
2330
2431
  }
2331
2432
  async function handleConfigReset() {
2332
2433
  logger.info("config reset \u547D\u4EE4\u6267\u884C\uFF0C\u6062\u590D\u9ED8\u8BA4\u914D\u7F6E");
@@ -2341,19 +2442,61 @@ async function handleConfigReset() {
2341
2442
  writeDefaultConfig();
2342
2443
  printSuccess(MESSAGES.CONFIG_RESET_SUCCESS);
2343
2444
  }
2344
- function formatConfigValue(value) {
2345
- if (typeof value === "boolean") {
2346
- return value ? chalk5.green("true") : chalk5.yellow("false");
2445
+ async function handleConfigSet(key, value) {
2446
+ if (!key) {
2447
+ await handleInteractiveConfigSet();
2448
+ return;
2347
2449
  }
2348
- if (typeof value === "object" && value !== null) {
2349
- const entries = Object.entries(value);
2350
- if (entries.length === 0) {
2351
- return chalk5.dim("(\u65E0)");
2352
- }
2353
- const lines = entries.map(([k, v]) => ` ${chalk5.cyan(k)} \u2192 ${chalk5.cyan(String(v))}`);
2354
- return "\n" + lines.join("\n");
2450
+ if (!isValidConfigKey(key)) {
2451
+ printError(MESSAGES.CONFIG_INVALID_KEY(key, getValidConfigKeys()));
2452
+ return;
2355
2453
  }
2356
- return chalk5.cyan(String(value));
2454
+ if (value === void 0) {
2455
+ printError(MESSAGES.CONFIG_MISSING_VALUE(key));
2456
+ return;
2457
+ }
2458
+ const result = parseConfigValue(key, value);
2459
+ if (!result.success) {
2460
+ printError(result.error);
2461
+ return;
2462
+ }
2463
+ const config2 = loadConfig();
2464
+ config2[key] = result.value;
2465
+ saveConfig(config2);
2466
+ logger.info(`config set \u547D\u4EE4\u6267\u884C\uFF0C\u8BBE\u7F6E ${key} = ${String(result.value)}`);
2467
+ printSuccess(MESSAGES.CONFIG_SET_SUCCESS(key, String(result.value)));
2468
+ }
2469
+ async function handleInteractiveConfigSet() {
2470
+ const config2 = loadConfig();
2471
+ const keys = Object.keys(DEFAULT_CONFIG);
2472
+ logger.info("config set \u547D\u4EE4\u6267\u884C\uFF0C\u8FDB\u5165\u4EA4\u4E92\u5F0F\u914D\u7F6E");
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
+ });
2481
+ const selectedKey = await new Enquirer5.Select({
2482
+ message: MESSAGES.CONFIG_SELECT_PROMPT,
2483
+ choices
2484
+ }).run();
2485
+ const currentValue = config2[selectedKey];
2486
+ const newValue = await promptConfigValue(selectedKey, currentValue);
2487
+ config2[selectedKey] = newValue;
2488
+ saveConfig(config2);
2489
+ printSuccess(MESSAGES.CONFIG_SET_SUCCESS(selectedKey, String(newValue)));
2490
+ }
2491
+ function handleConfigGet(key) {
2492
+ if (!isValidConfigKey(key)) {
2493
+ printError(MESSAGES.CONFIG_INVALID_KEY(key, getValidConfigKeys()));
2494
+ return;
2495
+ }
2496
+ const config2 = loadConfig();
2497
+ const value = config2[key];
2498
+ logger.info(`config get \u547D\u4EE4\u6267\u884C\uFF0C\u83B7\u53D6 ${key} = ${String(value)}`);
2499
+ printInfo(MESSAGES.CONFIG_GET_VALUE(key, String(value)));
2357
2500
  }
2358
2501
 
2359
2502
  // src/commands/sync.ts
@@ -2440,7 +2583,7 @@ async function handleReset() {
2440
2583
  }
2441
2584
 
2442
2585
  // src/commands/status.ts
2443
- import chalk6 from "chalk";
2586
+ import chalk7 from "chalk";
2444
2587
  function registerStatusCommand(program2) {
2445
2588
  program2.command("status").description("\u663E\u793A\u9879\u76EE\u5168\u5C40\u72B6\u6001\u603B\u89C8").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA").action((options) => {
2446
2589
  handleStatus(options);
@@ -2536,7 +2679,7 @@ function printStatusAsJson(result) {
2536
2679
  }
2537
2680
  function printStatusAsText(result) {
2538
2681
  printDoubleSeparator();
2539
- printInfo(` ${chalk6.bold.cyan(MESSAGES.STATUS_TITLE(result.main.projectName))}`);
2682
+ printInfo(` ${chalk7.bold.cyan(MESSAGES.STATUS_TITLE(result.main.projectName))}`);
2540
2683
  printDoubleSeparator();
2541
2684
  printInfo("");
2542
2685
  printMainSection(result.main);
@@ -2549,17 +2692,17 @@ function printStatusAsText(result) {
2549
2692
  printDoubleSeparator();
2550
2693
  }
2551
2694
  function printMainSection(main) {
2552
- printInfo(` ${chalk6.bold("\u25C6")} ${chalk6.bold(MESSAGES.STATUS_MAIN_SECTION)}`);
2553
- printInfo(` \u5206\u652F: ${chalk6.bold(main.branch)}`);
2695
+ printInfo(` ${chalk7.bold("\u25C6")} ${chalk7.bold(MESSAGES.STATUS_MAIN_SECTION)}`);
2696
+ printInfo(` \u5206\u652F: ${chalk7.bold(main.branch)}`);
2554
2697
  if (main.isClean) {
2555
- printInfo(` \u72B6\u6001: ${chalk6.green("\u2713 \u5E72\u51C0")}`);
2698
+ printInfo(` \u72B6\u6001: ${chalk7.green("\u2713 \u5E72\u51C0")}`);
2556
2699
  } else {
2557
- printInfo(` \u72B6\u6001: ${chalk6.yellow("\u2717 \u6709\u672A\u63D0\u4EA4\u4FEE\u6539")}`);
2700
+ printInfo(` \u72B6\u6001: ${chalk7.yellow("\u2717 \u6709\u672A\u63D0\u4EA4\u4FEE\u6539")}`);
2558
2701
  }
2559
2702
  printInfo("");
2560
2703
  }
2561
2704
  function printWorktreesSection(worktrees, total) {
2562
- printInfo(` ${chalk6.bold("\u25C6")} ${chalk6.bold(MESSAGES.STATUS_WORKTREES_SECTION)} (${total} \u4E2A)`);
2705
+ printInfo(` ${chalk7.bold("\u25C6")} ${chalk7.bold(MESSAGES.STATUS_WORKTREES_SECTION)} (${total} \u4E2A)`);
2563
2706
  printInfo("");
2564
2707
  if (worktrees.length === 0) {
2565
2708
  printInfo(` ${MESSAGES.STATUS_NO_WORKTREES}`);
@@ -2571,39 +2714,39 @@ function printWorktreesSection(worktrees, total) {
2571
2714
  }
2572
2715
  function printWorktreeItem(wt) {
2573
2716
  const statusLabel = formatChangeStatusLabel(wt.changeStatus);
2574
- printInfo(` ${chalk6.bold("\u25CF")} ${chalk6.bold(wt.branch)} [${statusLabel}]`);
2717
+ printInfo(` ${chalk7.bold("\u25CF")} ${chalk7.bold(wt.branch)} [${statusLabel}]`);
2575
2718
  const parts = [];
2576
2719
  if (wt.insertions > 0 || wt.deletions > 0) {
2577
- parts.push(`${chalk6.green(`+${wt.insertions}`)} ${chalk6.red(`-${wt.deletions}`)}`);
2720
+ parts.push(`${chalk7.green(`+${wt.insertions}`)} ${chalk7.red(`-${wt.deletions}`)}`);
2578
2721
  }
2579
2722
  if (wt.commitsAhead > 0) {
2580
- parts.push(chalk6.yellow(`${wt.commitsAhead} \u4E2A\u672C\u5730\u63D0\u4EA4`));
2723
+ parts.push(chalk7.yellow(`${wt.commitsAhead} \u4E2A\u672C\u5730\u63D0\u4EA4`));
2581
2724
  }
2582
2725
  if (wt.commitsBehind > 0) {
2583
- parts.push(chalk6.yellow(`\u843D\u540E\u4E3B\u5206\u652F ${wt.commitsBehind} \u4E2A\u63D0\u4EA4`));
2726
+ parts.push(chalk7.yellow(`\u843D\u540E\u4E3B\u5206\u652F ${wt.commitsBehind} \u4E2A\u63D0\u4EA4`));
2584
2727
  } else {
2585
- parts.push(chalk6.green("\u4E0E\u4E3B\u5206\u652F\u540C\u6B65"));
2728
+ parts.push(chalk7.green("\u4E0E\u4E3B\u5206\u652F\u540C\u6B65"));
2586
2729
  }
2587
2730
  printInfo(` ${parts.join(" ")}`);
2588
2731
  if (wt.hasSnapshot) {
2589
- printInfo(` ${chalk6.blue("\u6709 validate \u5FEB\u7167")}`);
2732
+ printInfo(` ${chalk7.blue("\u6709 validate \u5FEB\u7167")}`);
2590
2733
  }
2591
2734
  printInfo("");
2592
2735
  }
2593
2736
  function formatChangeStatusLabel(status) {
2594
2737
  switch (status) {
2595
2738
  case "committed":
2596
- return chalk6.green(MESSAGES.STATUS_CHANGE_COMMITTED);
2739
+ return chalk7.green(MESSAGES.STATUS_CHANGE_COMMITTED);
2597
2740
  case "uncommitted":
2598
- return chalk6.yellow(MESSAGES.STATUS_CHANGE_UNCOMMITTED);
2741
+ return chalk7.yellow(MESSAGES.STATUS_CHANGE_UNCOMMITTED);
2599
2742
  case "conflict":
2600
- return chalk6.red(MESSAGES.STATUS_CHANGE_CONFLICT);
2743
+ return chalk7.red(MESSAGES.STATUS_CHANGE_CONFLICT);
2601
2744
  case "clean":
2602
- return chalk6.gray(MESSAGES.STATUS_CHANGE_CLEAN);
2745
+ return chalk7.gray(MESSAGES.STATUS_CHANGE_CLEAN);
2603
2746
  }
2604
2747
  }
2605
2748
  function printSnapshotsSection(snapshots) {
2606
- printInfo(` ${chalk6.bold("\u25C6")} ${chalk6.bold(MESSAGES.STATUS_SNAPSHOTS_SECTION)} (${snapshots.length} \u4E2A)`);
2749
+ printInfo(` ${chalk7.bold("\u25C6")} ${chalk7.bold(MESSAGES.STATUS_SNAPSHOTS_SECTION)} (${snapshots.length} \u4E2A)`);
2607
2750
  printInfo("");
2608
2751
  if (snapshots.length === 0) {
2609
2752
  printInfo(` ${MESSAGES.STATUS_NO_SNAPSHOTS}`);
@@ -2611,15 +2754,15 @@ function printSnapshotsSection(snapshots) {
2611
2754
  return;
2612
2755
  }
2613
2756
  for (const snap of snapshots) {
2614
- const orphanLabel = snap.worktreeExists ? "" : ` ${chalk6.yellow(MESSAGES.STATUS_SNAPSHOT_ORPHANED)}`;
2615
- const icon = snap.worktreeExists ? chalk6.blue("\u25CF") : chalk6.yellow("\u26A0");
2757
+ const orphanLabel = snap.worktreeExists ? "" : ` ${chalk7.yellow(MESSAGES.STATUS_SNAPSHOT_ORPHANED)}`;
2758
+ const icon = snap.worktreeExists ? chalk7.blue("\u25CF") : chalk7.yellow("\u26A0");
2616
2759
  printInfo(` ${icon} ${snap.branch}${orphanLabel}`);
2617
2760
  }
2618
2761
  printInfo("");
2619
2762
  }
2620
2763
 
2621
2764
  // src/commands/alias.ts
2622
- import chalk7 from "chalk";
2765
+ import chalk8 from "chalk";
2623
2766
  function getRegisteredCommandNames(program2) {
2624
2767
  return program2.commands.map((cmd) => cmd.name());
2625
2768
  }
@@ -2640,7 +2783,7 @@ ${MESSAGES.ALIAS_LIST_TITLE}
2640
2783
  `);
2641
2784
  printSeparator();
2642
2785
  for (const [alias, command] of entries) {
2643
- printInfo(` ${chalk7.bold(alias)} \u2192 ${chalk7.cyan(command)}`);
2786
+ printInfo(` ${chalk8.bold(alias)} \u2192 ${chalk8.cyan(command)}`);
2644
2787
  }
2645
2788
  printInfo("");
2646
2789
  printSeparator();
@@ -243,7 +243,26 @@ var RESET_MESSAGES = {
243
243
  // src/constants/messages/config.ts
244
244
  var CONFIG_CMD_MESSAGES = {
245
245
  /** 配置已恢复为默认值 */
246
- CONFIG_RESET_SUCCESS: "\u2713 \u914D\u7F6E\u5DF2\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C"
246
+ CONFIG_RESET_SUCCESS: "\u2713 \u914D\u7F6E\u5DF2\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C",
247
+ /** 配置项设置成功 */
248
+ CONFIG_SET_SUCCESS: (key, value) => `\u2713 ${key} \u5DF2\u8BBE\u7F6E\u4E3A ${value}`,
249
+ /** 获取配置值显示 */
250
+ CONFIG_GET_VALUE: (key, value) => `${key} = ${value}`,
251
+ /** 无效配置项名称 */
252
+ CONFIG_INVALID_KEY: (key, validKeys) => `\u65E0\u6548\u7684\u914D\u7F6E\u9879: ${key}
253
+ \u53EF\u7528\u7684\u914D\u7F6E\u9879: ${validKeys.join(", ")}`,
254
+ /** 布尔类型值无效 */
255
+ CONFIG_INVALID_BOOLEAN: (key) => `\u914D\u7F6E\u9879 ${key} \u4E3A\u5E03\u5C14\u7C7B\u578B\uFF0C\u4EC5\u63A5\u53D7 true \u6216 false`,
256
+ /** 数字类型值无效 */
257
+ CONFIG_INVALID_NUMBER: (key) => `\u914D\u7F6E\u9879 ${key} \u4E3A\u6570\u5B57\u7C7B\u578B\uFF0C\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57`,
258
+ /** 枚举类型配置项值无效(通用版) */
259
+ CONFIG_INVALID_ENUM: (key, validValues) => `\u914D\u7F6E\u9879 ${key} \u4EC5\u63A5\u53D7\u4EE5\u4E0B\u503C: ${validValues.join(", ")}`,
260
+ /** 交互式选择配置项提示 */
261
+ CONFIG_SELECT_PROMPT: "\u9009\u62E9\u8981\u4FEE\u6539\u7684\u914D\u7F6E\u9879",
262
+ /** 交互式输入新值提示 */
263
+ CONFIG_INPUT_PROMPT: (key) => `\u8F93\u5165 ${key} \u7684\u65B0\u503C`,
264
+ /** 缺少 value 参数提示 */
265
+ CONFIG_MISSING_VALUE: (key) => `\u7F3A\u5C11\u914D\u7F6E\u503C\uFF0C\u7528\u6CD5: clawt config set ${key} <value>`
247
266
  };
248
267
 
249
268
  // src/constants/messages/status.ts
@@ -306,6 +325,9 @@ var MESSAGES = {
306
325
  ...ALIAS_MESSAGES
307
326
  };
308
327
 
328
+ // src/constants/terminal.ts
329
+ var VALID_TERMINAL_APPS = ["auto", "iterm2", "terminal"];
330
+
309
331
  // src/constants/config.ts
310
332
  var CONFIG_DEFINITIONS = {
311
333
  autoDeleteBranch: {
@@ -330,11 +352,12 @@ var CONFIG_DEFINITIONS = {
330
352
  },
331
353
  terminalApp: {
332
354
  defaultValue: "auto",
333
- description: "\u6279\u91CF resume \u4F7F\u7528\u7684\u7EC8\u7AEF\u5E94\u7528\uFF1Aauto\uFF08\u81EA\u52A8\u68C0\u6D4B\uFF09\u3001iterm2\u3001terminal\uFF08macOS\uFF09"
355
+ description: "\u6279\u91CF resume \u4F7F\u7528\u7684\u7EC8\u7AEF\u5E94\u7528\uFF1Aauto\uFF08\u81EA\u52A8\u68C0\u6D4B\uFF09\u3001iterm2\u3001terminal\uFF08macOS\uFF09",
356
+ allowedValues: VALID_TERMINAL_APPS
334
357
  },
335
358
  aliases: {
336
359
  defaultValue: {},
337
- description: "\u547D\u4EE4\u522B\u540D\u6620\u5C04\uFF08\u901A\u8FC7 clawt alias \u547D\u4EE4\u7BA1\u7406\uFF09"
360
+ description: "\u547D\u4EE4\u522B\u540D\u6620\u5C04"
338
361
  }
339
362
  };
340
363
  function deriveDefaultConfig(definitions) {