clawt 2.12.1 → 2.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -150,6 +150,33 @@ clawt config # 查看当前配置
150
150
  clawt config reset # 恢复默认配置
151
151
  ```
152
152
 
153
+ ### `clawt alias` — 管理命令别名
154
+
155
+ ```bash
156
+ clawt alias # 列出所有命令别名
157
+ clawt alias list # 列出所有命令别名
158
+ clawt alias set <alias> <command> # 设置命令别名
159
+ clawt alias remove <alias> # 移除命令别名
160
+ ```
161
+
162
+ **使用示例:**
163
+
164
+ ```bash
165
+ # 设置别名
166
+ clawt alias set l list
167
+ clawt alias set r run
168
+ clawt alias set v validate
169
+
170
+ # 使用别名(等同于对应的完整命令)
171
+ clawt l # 等同于 clawt list
172
+ clawt r task.md # 等同于 clawt run task.md
173
+
174
+ # 移除别名
175
+ clawt alias remove l
176
+ ```
177
+
178
+ > **约束:** 别名不能覆盖内置命令名,目标必须是已注册的内置命令。别名的选项和参数会完全透传给目标命令。
179
+
153
180
  ## 配置
154
181
 
155
182
  配置文件位于 `~/.clawt/config.json`,安装后自动生成:
@@ -162,6 +189,7 @@ clawt config reset # 恢复默认配置
162
189
  | `confirmDestructiveOps` | `true` | 破坏性操作前确认 |
163
190
  | `maxConcurrency` | `0` | run 命令最大并发数,`0` 为不限制 |
164
191
  | `terminalApp` | `"auto"` | 批量 resume 使用的终端:`auto` / `iterm2` / `terminal` |
192
+ | `aliases` | `{}` | 命令别名映射(如 `{"l": "list", "r": "run"}`) |
165
193
 
166
194
  ## 全局选项
167
195
 
package/dist/index.js CHANGED
@@ -251,7 +251,26 @@ var RESET_MESSAGES = {
251
251
  // src/constants/messages/config.ts
252
252
  var CONFIG_CMD_MESSAGES = {
253
253
  /** 配置已恢复为默认值 */
254
- CONFIG_RESET_SUCCESS: "\u2713 \u914D\u7F6E\u5DF2\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C"
254
+ CONFIG_RESET_SUCCESS: "\u2713 \u914D\u7F6E\u5DF2\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C",
255
+ /** 配置项设置成功 */
256
+ CONFIG_SET_SUCCESS: (key, value) => `\u2713 ${key} \u5DF2\u8BBE\u7F6E\u4E3A ${value}`,
257
+ /** 获取配置值显示 */
258
+ CONFIG_GET_VALUE: (key, value) => `${key} = ${value}`,
259
+ /** 无效配置项名称 */
260
+ CONFIG_INVALID_KEY: (key, validKeys) => `\u65E0\u6548\u7684\u914D\u7F6E\u9879: ${key}
261
+ \u53EF\u7528\u7684\u914D\u7F6E\u9879: ${validKeys.join(", ")}`,
262
+ /** 布尔类型值无效 */
263
+ CONFIG_INVALID_BOOLEAN: (key) => `\u914D\u7F6E\u9879 ${key} \u4E3A\u5E03\u5C14\u7C7B\u578B\uFF0C\u4EC5\u63A5\u53D7 true \u6216 false`,
264
+ /** 数字类型值无效 */
265
+ CONFIG_INVALID_NUMBER: (key) => `\u914D\u7F6E\u9879 ${key} \u4E3A\u6570\u5B57\u7C7B\u578B\uFF0C\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57`,
266
+ /** 枚举类型配置项值无效(通用版) */
267
+ CONFIG_INVALID_ENUM: (key, validValues) => `\u914D\u7F6E\u9879 ${key} \u4EC5\u63A5\u53D7\u4EE5\u4E0B\u503C: ${validValues.join(", ")}`,
268
+ /** 交互式选择配置项提示 */
269
+ CONFIG_SELECT_PROMPT: "\u9009\u62E9\u8981\u4FEE\u6539\u7684\u914D\u7F6E\u9879",
270
+ /** 交互式输入新值提示 */
271
+ CONFIG_INPUT_PROMPT: (key) => `\u8F93\u5165 ${key} \u7684\u65B0\u503C`,
272
+ /** 缺少 value 参数提示 */
273
+ CONFIG_MISSING_VALUE: (key) => `\u7F3A\u5C11\u914D\u7F6E\u503C\uFF0C\u7528\u6CD5: clawt config set ${key} <value>`
255
274
  };
256
275
 
257
276
  // src/constants/messages/status.ts
@@ -280,6 +299,24 @@ var STATUS_MESSAGES = {
280
299
  STATUS_SNAPSHOT_ORPHANED: "(\u5BF9\u5E94 worktree \u5DF2\u4E0D\u5B58\u5728)"
281
300
  };
282
301
 
302
+ // src/constants/messages/alias.ts
303
+ var ALIAS_MESSAGES = {
304
+ /** 别名列表为空 */
305
+ ALIAS_LIST_EMPTY: "(\u65E0\u522B\u540D)",
306
+ /** 别名设置成功 */
307
+ ALIAS_SET_SUCCESS: (alias, command) => `\u2713 \u5DF2\u8BBE\u7F6E\u522B\u540D: ${alias} \u2192 ${command}`,
308
+ /** 别名移除成功 */
309
+ ALIAS_REMOVE_SUCCESS: (alias) => `\u2713 \u5DF2\u79FB\u9664\u522B\u540D: ${alias}`,
310
+ /** 别名不存在 */
311
+ ALIAS_NOT_FOUND: (alias) => `\u522B\u540D "${alias}" \u4E0D\u5B58\u5728`,
312
+ /** 别名与内置命令冲突 */
313
+ ALIAS_CONFLICTS_BUILTIN: (alias) => `\u522B\u540D "${alias}" \u4E0E\u5185\u7F6E\u547D\u4EE4\u51B2\u7A81\uFF0C\u4E0D\u5141\u8BB8\u8986\u76D6\u5185\u7F6E\u547D\u4EE4`,
314
+ /** 目标命令不存在 */
315
+ ALIAS_TARGET_NOT_FOUND: (command) => `\u76EE\u6807\u547D\u4EE4 "${command}" \u4E0D\u5B58\u5728\uFF0C\u8BF7\u6307\u5B9A\u5DF2\u6CE8\u518C\u7684\u5185\u7F6E\u547D\u4EE4\u540D`,
316
+ /** 别名列表标题 */
317
+ ALIAS_LIST_TITLE: "\u5F53\u524D\u522B\u540D\u5217\u8868\uFF1A"
318
+ };
319
+
283
320
  // src/constants/messages/index.ts
284
321
  var MESSAGES = {
285
322
  ...COMMON_MESSAGES,
@@ -292,7 +329,8 @@ var MESSAGES = {
292
329
  ...REMOVE_MESSAGES,
293
330
  ...RESET_MESSAGES,
294
331
  ...CONFIG_CMD_MESSAGES,
295
- ...STATUS_MESSAGES
332
+ ...STATUS_MESSAGES,
333
+ ...ALIAS_MESSAGES
296
334
  };
297
335
 
298
336
  // src/constants/exitCodes.ts
@@ -334,7 +372,12 @@ var CONFIG_DEFINITIONS = {
334
372
  },
335
373
  terminalApp: {
336
374
  defaultValue: "auto",
337
- description: "\u6279\u91CF resume \u4F7F\u7528\u7684\u7EC8\u7AEF\u5E94\u7528\uFF1Aauto\uFF08\u81EA\u52A8\u68C0\u6D4B\uFF09\u3001iterm2\u3001terminal\uFF08macOS\uFF09"
375
+ description: "\u6279\u91CF resume \u4F7F\u7528\u7684\u7EC8\u7AEF\u5E94\u7528\uFF1Aauto\uFF08\u81EA\u52A8\u68C0\u6D4B\uFF09\u3001iterm2\u3001terminal\uFF08macOS\uFF09",
376
+ allowedValues: VALID_TERMINAL_APPS
377
+ },
378
+ aliases: {
379
+ defaultValue: {},
380
+ description: "\u547D\u4EE4\u522B\u540D\u6620\u5C04\uFF08\u901A\u8FC7 clawt alias \u547D\u4EE4\u7BA1\u7406\uFF09"
338
381
  }
339
382
  };
340
383
  function deriveDefaultConfig(definitions) {
@@ -907,12 +950,18 @@ function loadConfig() {
907
950
  return { ...DEFAULT_CONFIG };
908
951
  }
909
952
  }
953
+ function writeConfig(config2) {
954
+ writeFileSync(CONFIG_PATH, JSON.stringify(config2, null, 2), "utf-8");
955
+ }
910
956
  function writeDefaultConfig() {
911
- writeFileSync(CONFIG_PATH, JSON.stringify(DEFAULT_CONFIG, null, 2), "utf-8");
957
+ writeConfig(DEFAULT_CONFIG);
958
+ }
959
+ function saveConfig(config2) {
960
+ writeFileSync(CONFIG_PATH, JSON.stringify(config2, null, 2), "utf-8");
912
961
  }
913
962
  function getConfigValue(key) {
914
- const config = loadConfig();
915
- return config[key];
963
+ const config2 = loadConfig();
964
+ return config2[key];
916
965
  }
917
966
  function ensureClawtDirs() {
918
967
  ensureDir(CLAWT_HOME);
@@ -1692,8 +1741,111 @@ async function executeBatchTasks(worktrees, tasks, concurrency) {
1692
1741
  printTaskSummary(summary);
1693
1742
  }
1694
1743
 
1695
- // src/commands/list.ts
1744
+ // src/utils/alias.ts
1745
+ function applyAliases(program2, aliases) {
1746
+ for (const [alias, commandName] of Object.entries(aliases)) {
1747
+ const targetCmd = program2.commands.find((cmd) => cmd.name() === commandName);
1748
+ if (targetCmd) {
1749
+ targetCmd.alias(alias);
1750
+ logger.debug(`\u5DF2\u6CE8\u518C\u522B\u540D: ${alias} \u2192 ${commandName}`);
1751
+ } else {
1752
+ logger.warn(`\u522B\u540D "${alias}" \u7684\u76EE\u6807\u547D\u4EE4 "${commandName}" \u4E0D\u5B58\u5728\uFF0C\u5DF2\u8DF3\u8FC7`);
1753
+ }
1754
+ }
1755
+ }
1756
+
1757
+ // src/utils/config-strategy.ts
1696
1758
  import chalk4 from "chalk";
1759
+ import Enquirer3 from "enquirer";
1760
+ function isValidConfigKey(key) {
1761
+ return key in DEFAULT_CONFIG;
1762
+ }
1763
+ function getValidConfigKeys() {
1764
+ return Object.keys(DEFAULT_CONFIG);
1765
+ }
1766
+ function parseConfigValue(key, rawValue) {
1767
+ const expectedType = typeof DEFAULT_CONFIG[key];
1768
+ if (expectedType === "boolean") {
1769
+ if (rawValue === "true") return { success: true, value: true };
1770
+ if (rawValue === "false") return { success: true, value: false };
1771
+ return { success: false, error: MESSAGES.CONFIG_INVALID_BOOLEAN(key) };
1772
+ }
1773
+ if (expectedType === "number") {
1774
+ const num = Number(rawValue);
1775
+ if (Number.isNaN(num)) {
1776
+ return { success: false, error: MESSAGES.CONFIG_INVALID_NUMBER(key) };
1777
+ }
1778
+ return { success: true, value: num };
1779
+ }
1780
+ const definition = CONFIG_DEFINITIONS[key];
1781
+ if (definition.allowedValues && !definition.allowedValues.includes(rawValue)) {
1782
+ return { success: false, error: MESSAGES.CONFIG_INVALID_ENUM(key, definition.allowedValues) };
1783
+ }
1784
+ return { success: true, value: rawValue };
1785
+ }
1786
+ async function promptConfigValue(key, currentValue) {
1787
+ const expectedType = typeof currentValue;
1788
+ if (expectedType === "boolean") {
1789
+ return promptBooleanValue(key, currentValue);
1790
+ }
1791
+ if (expectedType === "number") {
1792
+ return promptNumberValue(key, currentValue);
1793
+ }
1794
+ const definition = CONFIG_DEFINITIONS[key];
1795
+ if (definition.allowedValues) {
1796
+ return promptEnumValue(key, currentValue, definition.allowedValues);
1797
+ }
1798
+ return promptStringValue(key, currentValue);
1799
+ }
1800
+ function formatConfigValue(value) {
1801
+ if (typeof value === "boolean") {
1802
+ return value ? chalk4.green("true") : chalk4.yellow("false");
1803
+ }
1804
+ return chalk4.cyan(String(value));
1805
+ }
1806
+ async function promptBooleanValue(key, currentValue) {
1807
+ const choices = [
1808
+ { name: "true", message: "true" },
1809
+ { name: "false", message: "false" }
1810
+ ];
1811
+ const selected = await new Enquirer3.Select({
1812
+ message: MESSAGES.CONFIG_INPUT_PROMPT(key),
1813
+ choices,
1814
+ initial: currentValue ? 0 : 1
1815
+ }).run();
1816
+ return selected === "true";
1817
+ }
1818
+ async function promptNumberValue(key, currentValue) {
1819
+ const input = await new Enquirer3.Input({
1820
+ message: MESSAGES.CONFIG_INPUT_PROMPT(key),
1821
+ initial: String(currentValue),
1822
+ validate: (val) => {
1823
+ if (Number.isNaN(Number(val))) return "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57";
1824
+ return true;
1825
+ }
1826
+ }).run();
1827
+ return Number(input);
1828
+ }
1829
+ async function promptEnumValue(key, currentValue, allowedValues) {
1830
+ const choices = allowedValues.map((v) => ({
1831
+ name: v,
1832
+ message: v
1833
+ }));
1834
+ return await new Enquirer3.Select({
1835
+ message: MESSAGES.CONFIG_INPUT_PROMPT(key),
1836
+ choices,
1837
+ initial: allowedValues.indexOf(currentValue)
1838
+ }).run();
1839
+ }
1840
+ async function promptStringValue(key, currentValue) {
1841
+ return await new Enquirer3.Input({
1842
+ message: MESSAGES.CONFIG_INPUT_PROMPT(key),
1843
+ initial: currentValue
1844
+ }).run();
1845
+ }
1846
+
1847
+ // src/commands/list.ts
1848
+ import chalk5 from "chalk";
1697
1849
  function registerListCommand(program2) {
1698
1850
  program2.command("list").description("\u5217\u51FA\u5F53\u524D\u9879\u76EE\u6240\u6709 worktree").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA").action((options) => {
1699
1851
  handleList(options);
@@ -1730,12 +1882,12 @@ function printListAsText(projectName, worktrees) {
1730
1882
  for (const wt of worktrees) {
1731
1883
  const status = getWorktreeStatus(wt);
1732
1884
  const isIdle = status ? isWorktreeIdle(status) : false;
1733
- const pathDisplay = isIdle ? chalk4.hex("#FF8C00")(wt.path) : wt.path;
1885
+ const pathDisplay = isIdle ? chalk5.hex("#FF8C00")(wt.path) : wt.path;
1734
1886
  printInfo(` ${pathDisplay} [${wt.branch}]`);
1735
1887
  if (status) {
1736
1888
  printInfo(` ${formatWorktreeStatus(status)}`);
1737
1889
  } else {
1738
- printInfo(` ${chalk4.yellow(MESSAGES.WORKTREE_STATUS_UNAVAILABLE)}`);
1890
+ printInfo(` ${chalk5.yellow(MESSAGES.WORKTREE_STATUS_UNAVAILABLE)}`);
1739
1891
  }
1740
1892
  printInfo("");
1741
1893
  }
@@ -1958,7 +2110,7 @@ async function handleBatchResume(worktrees) {
1958
2110
  }
1959
2111
 
1960
2112
  // src/commands/validate.ts
1961
- import Enquirer3 from "enquirer";
2113
+ import Enquirer4 from "enquirer";
1962
2114
  var VALIDATE_RESOLVE_MESSAGES = {
1963
2115
  noWorktrees: MESSAGES.VALIDATE_NO_WORKTREES,
1964
2116
  selectBranch: MESSAGES.VALIDATE_SELECT_BRANCH,
@@ -1972,7 +2124,7 @@ function registerValidateCommand(program2) {
1972
2124
  }
1973
2125
  async function handleDirtyMainWorktree(mainWorktreePath) {
1974
2126
  printWarning("\u4E3B worktree \u5F53\u524D\u5206\u652F\u6709\u672A\u63D0\u4EA4\u7684\u66F4\u6539\uFF0C\u8BF7\u9009\u62E9\u5904\u7406\u65B9\u5F0F\uFF1A\n");
1975
- const choice = await new Enquirer3.Select({
2127
+ const choice = await new Enquirer4.Select({
1976
2128
  message: "\u9009\u62E9\u5904\u7406\u65B9\u5F0F",
1977
2129
  choices: [
1978
2130
  {
@@ -2260,34 +2412,21 @@ async function handleMerge(options) {
2260
2412
  }
2261
2413
 
2262
2414
  // src/commands/config.ts
2263
- import chalk5 from "chalk";
2415
+ import chalk6 from "chalk";
2416
+ import Enquirer5 from "enquirer";
2264
2417
  function registerConfigCommand(program2) {
2265
- const configCmd = program2.command("config").description("\u67E5\u770B\u548C\u7BA1\u7406\u5168\u5C40\u914D\u7F6E").action(() => {
2266
- handleConfig();
2418
+ const configCmd = program2.command("config").description("\u4EA4\u4E92\u5F0F\u67E5\u770B\u548C\u4FEE\u6539\u5168\u5C40\u914D\u7F6E").action(async () => {
2419
+ await handleConfigSet();
2267
2420
  });
2268
2421
  configCmd.command("reset").description("\u5C06\u914D\u7F6E\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C").action(async () => {
2269
2422
  await handleConfigReset();
2270
2423
  });
2271
- }
2272
- function handleConfig() {
2273
- const config = loadConfig();
2274
- logger.info("config \u547D\u4EE4\u6267\u884C\uFF0C\u5C55\u793A\u5168\u5C40\u914D\u7F6E");
2275
- printInfo(`
2276
- ${chalk5.dim("\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84:")} ${CONFIG_PATH}
2277
- `);
2278
- printSeparator();
2279
- const keys = Object.keys(DEFAULT_CONFIG);
2280
- for (let i = 0; i < keys.length; i++) {
2281
- const key = keys[i];
2282
- const value = config[key];
2283
- const description = CONFIG_DESCRIPTIONS[key];
2284
- const formattedValue = formatConfigValue(value);
2285
- if (i === 0) printInfo("");
2286
- printInfo(` ${chalk5.bold(key)}: ${formattedValue}`);
2287
- printInfo(` ${chalk5.dim(description)}`);
2288
- printInfo("");
2289
- }
2290
- printSeparator();
2424
+ 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) => {
2425
+ await handleConfigSet(key, value);
2426
+ });
2427
+ configCmd.command("get <key>").description("\u83B7\u53D6\u5355\u4E2A\u914D\u7F6E\u9879\u7684\u503C").action((key) => {
2428
+ handleConfigGet(key);
2429
+ });
2291
2430
  }
2292
2431
  async function handleConfigReset() {
2293
2432
  logger.info("config reset \u547D\u4EE4\u6267\u884C\uFF0C\u6062\u590D\u9ED8\u8BA4\u914D\u7F6E");
@@ -2302,11 +2441,57 @@ async function handleConfigReset() {
2302
2441
  writeDefaultConfig();
2303
2442
  printSuccess(MESSAGES.CONFIG_RESET_SUCCESS);
2304
2443
  }
2305
- function formatConfigValue(value) {
2306
- if (typeof value === "boolean") {
2307
- return value ? chalk5.green("true") : chalk5.yellow("false");
2444
+ async function handleConfigSet(key, value) {
2445
+ if (!key) {
2446
+ await handleInteractiveConfigSet();
2447
+ return;
2448
+ }
2449
+ if (!isValidConfigKey(key)) {
2450
+ printError(MESSAGES.CONFIG_INVALID_KEY(key, getValidConfigKeys()));
2451
+ return;
2308
2452
  }
2309
- return chalk5.cyan(String(value));
2453
+ if (value === void 0) {
2454
+ printError(MESSAGES.CONFIG_MISSING_VALUE(key));
2455
+ return;
2456
+ }
2457
+ const result = parseConfigValue(key, value);
2458
+ if (!result.success) {
2459
+ printError(result.error);
2460
+ return;
2461
+ }
2462
+ const config2 = loadConfig();
2463
+ config2[key] = result.value;
2464
+ saveConfig(config2);
2465
+ logger.info(`config set \u547D\u4EE4\u6267\u884C\uFF0C\u8BBE\u7F6E ${key} = ${String(result.value)}`);
2466
+ printSuccess(MESSAGES.CONFIG_SET_SUCCESS(key, String(result.value)));
2467
+ }
2468
+ async function handleInteractiveConfigSet() {
2469
+ const config2 = loadConfig();
2470
+ const keys = Object.keys(DEFAULT_CONFIG);
2471
+ logger.info("config set \u547D\u4EE4\u6267\u884C\uFF0C\u8FDB\u5165\u4EA4\u4E92\u5F0F\u914D\u7F6E");
2472
+ const choices = keys.map((k) => ({
2473
+ name: k,
2474
+ message: `${k}: ${formatConfigValue(config2[k])} ${chalk6.dim(`\u2014 ${CONFIG_DESCRIPTIONS[k]}`)}`
2475
+ }));
2476
+ const selectedKey = await new Enquirer5.Select({
2477
+ message: MESSAGES.CONFIG_SELECT_PROMPT,
2478
+ choices
2479
+ }).run();
2480
+ const currentValue = config2[selectedKey];
2481
+ const newValue = await promptConfigValue(selectedKey, currentValue);
2482
+ config2[selectedKey] = newValue;
2483
+ saveConfig(config2);
2484
+ printSuccess(MESSAGES.CONFIG_SET_SUCCESS(selectedKey, String(newValue)));
2485
+ }
2486
+ function handleConfigGet(key) {
2487
+ if (!isValidConfigKey(key)) {
2488
+ printError(MESSAGES.CONFIG_INVALID_KEY(key, getValidConfigKeys()));
2489
+ return;
2490
+ }
2491
+ const config2 = loadConfig();
2492
+ const value = config2[key];
2493
+ logger.info(`config get \u547D\u4EE4\u6267\u884C\uFF0C\u83B7\u53D6 ${key} = ${String(value)}`);
2494
+ printInfo(MESSAGES.CONFIG_GET_VALUE(key, String(value)));
2310
2495
  }
2311
2496
 
2312
2497
  // src/commands/sync.ts
@@ -2393,7 +2578,7 @@ async function handleReset() {
2393
2578
  }
2394
2579
 
2395
2580
  // src/commands/status.ts
2396
- import chalk6 from "chalk";
2581
+ import chalk7 from "chalk";
2397
2582
  function registerStatusCommand(program2) {
2398
2583
  program2.command("status").description("\u663E\u793A\u9879\u76EE\u5168\u5C40\u72B6\u6001\u603B\u89C8").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA").action((options) => {
2399
2584
  handleStatus(options);
@@ -2489,7 +2674,7 @@ function printStatusAsJson(result) {
2489
2674
  }
2490
2675
  function printStatusAsText(result) {
2491
2676
  printDoubleSeparator();
2492
- printInfo(` ${chalk6.bold.cyan(MESSAGES.STATUS_TITLE(result.main.projectName))}`);
2677
+ printInfo(` ${chalk7.bold.cyan(MESSAGES.STATUS_TITLE(result.main.projectName))}`);
2493
2678
  printDoubleSeparator();
2494
2679
  printInfo("");
2495
2680
  printMainSection(result.main);
@@ -2502,17 +2687,17 @@ function printStatusAsText(result) {
2502
2687
  printDoubleSeparator();
2503
2688
  }
2504
2689
  function printMainSection(main) {
2505
- printInfo(` ${chalk6.bold("\u25C6")} ${chalk6.bold(MESSAGES.STATUS_MAIN_SECTION)}`);
2506
- printInfo(` \u5206\u652F: ${chalk6.bold(main.branch)}`);
2690
+ printInfo(` ${chalk7.bold("\u25C6")} ${chalk7.bold(MESSAGES.STATUS_MAIN_SECTION)}`);
2691
+ printInfo(` \u5206\u652F: ${chalk7.bold(main.branch)}`);
2507
2692
  if (main.isClean) {
2508
- printInfo(` \u72B6\u6001: ${chalk6.green("\u2713 \u5E72\u51C0")}`);
2693
+ printInfo(` \u72B6\u6001: ${chalk7.green("\u2713 \u5E72\u51C0")}`);
2509
2694
  } else {
2510
- printInfo(` \u72B6\u6001: ${chalk6.yellow("\u2717 \u6709\u672A\u63D0\u4EA4\u4FEE\u6539")}`);
2695
+ printInfo(` \u72B6\u6001: ${chalk7.yellow("\u2717 \u6709\u672A\u63D0\u4EA4\u4FEE\u6539")}`);
2511
2696
  }
2512
2697
  printInfo("");
2513
2698
  }
2514
2699
  function printWorktreesSection(worktrees, total) {
2515
- printInfo(` ${chalk6.bold("\u25C6")} ${chalk6.bold(MESSAGES.STATUS_WORKTREES_SECTION)} (${total} \u4E2A)`);
2700
+ printInfo(` ${chalk7.bold("\u25C6")} ${chalk7.bold(MESSAGES.STATUS_WORKTREES_SECTION)} (${total} \u4E2A)`);
2516
2701
  printInfo("");
2517
2702
  if (worktrees.length === 0) {
2518
2703
  printInfo(` ${MESSAGES.STATUS_NO_WORKTREES}`);
@@ -2524,39 +2709,39 @@ function printWorktreesSection(worktrees, total) {
2524
2709
  }
2525
2710
  function printWorktreeItem(wt) {
2526
2711
  const statusLabel = formatChangeStatusLabel(wt.changeStatus);
2527
- printInfo(` ${chalk6.bold("\u25CF")} ${chalk6.bold(wt.branch)} [${statusLabel}]`);
2712
+ printInfo(` ${chalk7.bold("\u25CF")} ${chalk7.bold(wt.branch)} [${statusLabel}]`);
2528
2713
  const parts = [];
2529
2714
  if (wt.insertions > 0 || wt.deletions > 0) {
2530
- parts.push(`${chalk6.green(`+${wt.insertions}`)} ${chalk6.red(`-${wt.deletions}`)}`);
2715
+ parts.push(`${chalk7.green(`+${wt.insertions}`)} ${chalk7.red(`-${wt.deletions}`)}`);
2531
2716
  }
2532
2717
  if (wt.commitsAhead > 0) {
2533
- parts.push(chalk6.yellow(`${wt.commitsAhead} \u4E2A\u672C\u5730\u63D0\u4EA4`));
2718
+ parts.push(chalk7.yellow(`${wt.commitsAhead} \u4E2A\u672C\u5730\u63D0\u4EA4`));
2534
2719
  }
2535
2720
  if (wt.commitsBehind > 0) {
2536
- parts.push(chalk6.yellow(`\u843D\u540E\u4E3B\u5206\u652F ${wt.commitsBehind} \u4E2A\u63D0\u4EA4`));
2721
+ parts.push(chalk7.yellow(`\u843D\u540E\u4E3B\u5206\u652F ${wt.commitsBehind} \u4E2A\u63D0\u4EA4`));
2537
2722
  } else {
2538
- parts.push(chalk6.green("\u4E0E\u4E3B\u5206\u652F\u540C\u6B65"));
2723
+ parts.push(chalk7.green("\u4E0E\u4E3B\u5206\u652F\u540C\u6B65"));
2539
2724
  }
2540
2725
  printInfo(` ${parts.join(" ")}`);
2541
2726
  if (wt.hasSnapshot) {
2542
- printInfo(` ${chalk6.blue("\u6709 validate \u5FEB\u7167")}`);
2727
+ printInfo(` ${chalk7.blue("\u6709 validate \u5FEB\u7167")}`);
2543
2728
  }
2544
2729
  printInfo("");
2545
2730
  }
2546
2731
  function formatChangeStatusLabel(status) {
2547
2732
  switch (status) {
2548
2733
  case "committed":
2549
- return chalk6.green(MESSAGES.STATUS_CHANGE_COMMITTED);
2734
+ return chalk7.green(MESSAGES.STATUS_CHANGE_COMMITTED);
2550
2735
  case "uncommitted":
2551
- return chalk6.yellow(MESSAGES.STATUS_CHANGE_UNCOMMITTED);
2736
+ return chalk7.yellow(MESSAGES.STATUS_CHANGE_UNCOMMITTED);
2552
2737
  case "conflict":
2553
- return chalk6.red(MESSAGES.STATUS_CHANGE_CONFLICT);
2738
+ return chalk7.red(MESSAGES.STATUS_CHANGE_CONFLICT);
2554
2739
  case "clean":
2555
- return chalk6.gray(MESSAGES.STATUS_CHANGE_CLEAN);
2740
+ return chalk7.gray(MESSAGES.STATUS_CHANGE_CLEAN);
2556
2741
  }
2557
2742
  }
2558
2743
  function printSnapshotsSection(snapshots) {
2559
- printInfo(` ${chalk6.bold("\u25C6")} ${chalk6.bold(MESSAGES.STATUS_SNAPSHOTS_SECTION)} (${snapshots.length} \u4E2A)`);
2744
+ printInfo(` ${chalk7.bold("\u25C6")} ${chalk7.bold(MESSAGES.STATUS_SNAPSHOTS_SECTION)} (${snapshots.length} \u4E2A)`);
2560
2745
  printInfo("");
2561
2746
  if (snapshots.length === 0) {
2562
2747
  printInfo(` ${MESSAGES.STATUS_NO_SNAPSHOTS}`);
@@ -2564,13 +2749,81 @@ function printSnapshotsSection(snapshots) {
2564
2749
  return;
2565
2750
  }
2566
2751
  for (const snap of snapshots) {
2567
- const orphanLabel = snap.worktreeExists ? "" : ` ${chalk6.yellow(MESSAGES.STATUS_SNAPSHOT_ORPHANED)}`;
2568
- const icon = snap.worktreeExists ? chalk6.blue("\u25CF") : chalk6.yellow("\u26A0");
2752
+ const orphanLabel = snap.worktreeExists ? "" : ` ${chalk7.yellow(MESSAGES.STATUS_SNAPSHOT_ORPHANED)}`;
2753
+ const icon = snap.worktreeExists ? chalk7.blue("\u25CF") : chalk7.yellow("\u26A0");
2569
2754
  printInfo(` ${icon} ${snap.branch}${orphanLabel}`);
2570
2755
  }
2571
2756
  printInfo("");
2572
2757
  }
2573
2758
 
2759
+ // src/commands/alias.ts
2760
+ import chalk8 from "chalk";
2761
+ function getRegisteredCommandNames(program2) {
2762
+ return program2.commands.map((cmd) => cmd.name());
2763
+ }
2764
+ function isBuiltinCommand(program2, alias) {
2765
+ return getRegisteredCommandNames(program2).includes(alias);
2766
+ }
2767
+ function handleAliasList() {
2768
+ const config2 = loadConfig();
2769
+ const { aliases } = config2;
2770
+ const entries = Object.entries(aliases);
2771
+ logger.debug("alias list \u547D\u4EE4\u6267\u884C\uFF0C\u5C55\u793A\u522B\u540D\u5217\u8868");
2772
+ if (entries.length === 0) {
2773
+ printInfo(MESSAGES.ALIAS_LIST_EMPTY);
2774
+ return;
2775
+ }
2776
+ printInfo(`
2777
+ ${MESSAGES.ALIAS_LIST_TITLE}
2778
+ `);
2779
+ printSeparator();
2780
+ for (const [alias, command] of entries) {
2781
+ printInfo(` ${chalk8.bold(alias)} \u2192 ${chalk8.cyan(command)}`);
2782
+ }
2783
+ printInfo("");
2784
+ printSeparator();
2785
+ }
2786
+ function handleAliasSet(program2, alias, command) {
2787
+ logger.debug(`alias set \u547D\u4EE4\u6267\u884C\uFF0C\u522B\u540D: ${alias}\uFF0C\u76EE\u6807: ${command}`);
2788
+ if (isBuiltinCommand(program2, alias)) {
2789
+ printError(MESSAGES.ALIAS_CONFLICTS_BUILTIN(alias));
2790
+ return;
2791
+ }
2792
+ if (!isBuiltinCommand(program2, command)) {
2793
+ printError(MESSAGES.ALIAS_TARGET_NOT_FOUND(command));
2794
+ return;
2795
+ }
2796
+ const config2 = loadConfig();
2797
+ config2.aliases[alias] = command;
2798
+ writeConfig(config2);
2799
+ printSuccess(MESSAGES.ALIAS_SET_SUCCESS(alias, command));
2800
+ }
2801
+ function handleAliasRemove(alias) {
2802
+ logger.debug(`alias remove \u547D\u4EE4\u6267\u884C\uFF0C\u522B\u540D: ${alias}`);
2803
+ const config2 = loadConfig();
2804
+ if (!(alias in config2.aliases)) {
2805
+ printError(MESSAGES.ALIAS_NOT_FOUND(alias));
2806
+ return;
2807
+ }
2808
+ delete config2.aliases[alias];
2809
+ writeConfig(config2);
2810
+ printSuccess(MESSAGES.ALIAS_REMOVE_SUCCESS(alias));
2811
+ }
2812
+ function registerAliasCommand(program2) {
2813
+ const aliasCmd = program2.command("alias").description("\u7BA1\u7406\u547D\u4EE4\u522B\u540D").action(() => {
2814
+ handleAliasList();
2815
+ });
2816
+ aliasCmd.command("list").description("\u5217\u51FA\u6240\u6709\u522B\u540D").action(() => {
2817
+ handleAliasList();
2818
+ });
2819
+ aliasCmd.command("set <alias> <command>").description("\u8BBE\u7F6E\u547D\u4EE4\u522B\u540D").action((alias, command) => {
2820
+ handleAliasSet(program2, alias, command);
2821
+ });
2822
+ aliasCmd.command("remove <alias>").description("\u79FB\u9664\u547D\u4EE4\u522B\u540D").action((alias) => {
2823
+ handleAliasRemove(alias);
2824
+ });
2825
+ }
2826
+
2574
2827
  // src/index.ts
2575
2828
  var require2 = createRequire(import.meta.url);
2576
2829
  var { version } = require2("../package.json");
@@ -2593,6 +2846,9 @@ registerConfigCommand(program);
2593
2846
  registerSyncCommand(program);
2594
2847
  registerResetCommand(program);
2595
2848
  registerStatusCommand(program);
2849
+ registerAliasCommand(program);
2850
+ var config = loadConfig();
2851
+ applyAliases(program, config.aliases);
2596
2852
  process.on("uncaughtException", (error) => {
2597
2853
  if (error instanceof ClawtError) {
2598
2854
  printError(error.message);
@@ -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
@@ -272,6 +291,24 @@ var STATUS_MESSAGES = {
272
291
  STATUS_SNAPSHOT_ORPHANED: "(\u5BF9\u5E94 worktree \u5DF2\u4E0D\u5B58\u5728)"
273
292
  };
274
293
 
294
+ // src/constants/messages/alias.ts
295
+ var ALIAS_MESSAGES = {
296
+ /** 别名列表为空 */
297
+ ALIAS_LIST_EMPTY: "(\u65E0\u522B\u540D)",
298
+ /** 别名设置成功 */
299
+ ALIAS_SET_SUCCESS: (alias, command) => `\u2713 \u5DF2\u8BBE\u7F6E\u522B\u540D: ${alias} \u2192 ${command}`,
300
+ /** 别名移除成功 */
301
+ ALIAS_REMOVE_SUCCESS: (alias) => `\u2713 \u5DF2\u79FB\u9664\u522B\u540D: ${alias}`,
302
+ /** 别名不存在 */
303
+ ALIAS_NOT_FOUND: (alias) => `\u522B\u540D "${alias}" \u4E0D\u5B58\u5728`,
304
+ /** 别名与内置命令冲突 */
305
+ ALIAS_CONFLICTS_BUILTIN: (alias) => `\u522B\u540D "${alias}" \u4E0E\u5185\u7F6E\u547D\u4EE4\u51B2\u7A81\uFF0C\u4E0D\u5141\u8BB8\u8986\u76D6\u5185\u7F6E\u547D\u4EE4`,
306
+ /** 目标命令不存在 */
307
+ ALIAS_TARGET_NOT_FOUND: (command) => `\u76EE\u6807\u547D\u4EE4 "${command}" \u4E0D\u5B58\u5728\uFF0C\u8BF7\u6307\u5B9A\u5DF2\u6CE8\u518C\u7684\u5185\u7F6E\u547D\u4EE4\u540D`,
308
+ /** 别名列表标题 */
309
+ ALIAS_LIST_TITLE: "\u5F53\u524D\u522B\u540D\u5217\u8868\uFF1A"
310
+ };
311
+
275
312
  // src/constants/messages/index.ts
276
313
  var MESSAGES = {
277
314
  ...COMMON_MESSAGES,
@@ -284,9 +321,13 @@ var MESSAGES = {
284
321
  ...REMOVE_MESSAGES,
285
322
  ...RESET_MESSAGES,
286
323
  ...CONFIG_CMD_MESSAGES,
287
- ...STATUS_MESSAGES
324
+ ...STATUS_MESSAGES,
325
+ ...ALIAS_MESSAGES
288
326
  };
289
327
 
328
+ // src/constants/terminal.ts
329
+ var VALID_TERMINAL_APPS = ["auto", "iterm2", "terminal"];
330
+
290
331
  // src/constants/config.ts
291
332
  var CONFIG_DEFINITIONS = {
292
333
  autoDeleteBranch: {
@@ -311,7 +352,12 @@ var CONFIG_DEFINITIONS = {
311
352
  },
312
353
  terminalApp: {
313
354
  defaultValue: "auto",
314
- 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
357
+ },
358
+ aliases: {
359
+ defaultValue: {},
360
+ description: "\u547D\u4EE4\u522B\u540D\u6620\u5C04\uFF08\u901A\u8FC7 clawt alias \u547D\u4EE4\u7BA1\u7406\uFF09"
315
361
  }
316
362
  };
317
363
  function deriveDefaultConfig(definitions) {