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.
- package/.claude/agent-memory/docs-sync-updater/MEMORY.md +8 -3
- package/README.md +20 -3
- package/dist/index.js +207 -64
- package/dist/postinstall.js +26 -3
- package/docs/spec.md +63 -23
- package/package.json +1 -1
- package/src/commands/config.ts +120 -48
- package/src/constants/config.ts +3 -1
- package/src/constants/index.ts +2 -1
- package/src/constants/messages/config.ts +25 -0
- package/src/constants/messages/index.ts +3 -1
- package/src/types/config.ts +2 -0
- package/src/utils/config-strategy.ts +196 -0
- package/src/utils/config.ts +8 -0
- package/src/utils/index.ts +2 -1
- package/tests/unit/commands/config.test.ts +355 -24
- package/tests/unit/constants/config.test.ts +24 -1
- package/tests/unit/utils/config-strategy.test.ts +217 -0
- package/tests/unit/utils/config.test.ts +13 -1
|
@@ -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,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
|
|
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/
|
|
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 ?
|
|
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(` ${
|
|
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
|
|
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
|
|
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
|
|
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\
|
|
2305
|
-
|
|
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
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
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
|
|
2345
|
-
if (
|
|
2346
|
-
|
|
2445
|
+
async function handleConfigSet(key, value) {
|
|
2446
|
+
if (!key) {
|
|
2447
|
+
await handleInteractiveConfigSet();
|
|
2448
|
+
return;
|
|
2347
2449
|
}
|
|
2348
|
-
if (
|
|
2349
|
-
|
|
2350
|
-
|
|
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
|
-
|
|
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
|
|
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(` ${
|
|
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(` ${
|
|
2553
|
-
printInfo(` \u5206\u652F: ${
|
|
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: ${
|
|
2698
|
+
printInfo(` \u72B6\u6001: ${chalk7.green("\u2713 \u5E72\u51C0")}`);
|
|
2556
2699
|
} else {
|
|
2557
|
-
printInfo(` \u72B6\u6001: ${
|
|
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(` ${
|
|
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(` ${
|
|
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(`${
|
|
2720
|
+
parts.push(`${chalk7.green(`+${wt.insertions}`)} ${chalk7.red(`-${wt.deletions}`)}`);
|
|
2578
2721
|
}
|
|
2579
2722
|
if (wt.commitsAhead > 0) {
|
|
2580
|
-
parts.push(
|
|
2723
|
+
parts.push(chalk7.yellow(`${wt.commitsAhead} \u4E2A\u672C\u5730\u63D0\u4EA4`));
|
|
2581
2724
|
}
|
|
2582
2725
|
if (wt.commitsBehind > 0) {
|
|
2583
|
-
parts.push(
|
|
2726
|
+
parts.push(chalk7.yellow(`\u843D\u540E\u4E3B\u5206\u652F ${wt.commitsBehind} \u4E2A\u63D0\u4EA4`));
|
|
2584
2727
|
} else {
|
|
2585
|
-
parts.push(
|
|
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(` ${
|
|
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
|
|
2739
|
+
return chalk7.green(MESSAGES.STATUS_CHANGE_COMMITTED);
|
|
2597
2740
|
case "uncommitted":
|
|
2598
|
-
return
|
|
2741
|
+
return chalk7.yellow(MESSAGES.STATUS_CHANGE_UNCOMMITTED);
|
|
2599
2742
|
case "conflict":
|
|
2600
|
-
return
|
|
2743
|
+
return chalk7.red(MESSAGES.STATUS_CHANGE_CONFLICT);
|
|
2601
2744
|
case "clean":
|
|
2602
|
-
return
|
|
2745
|
+
return chalk7.gray(MESSAGES.STATUS_CHANGE_CLEAN);
|
|
2603
2746
|
}
|
|
2604
2747
|
}
|
|
2605
2748
|
function printSnapshotsSection(snapshots) {
|
|
2606
|
-
printInfo(` ${
|
|
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 ? "" : ` ${
|
|
2615
|
-
const icon = snap.worktreeExists ?
|
|
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
|
|
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(` ${
|
|
2786
|
+
printInfo(` ${chalk8.bold(alias)} \u2192 ${chalk8.cyan(command)}`);
|
|
2644
2787
|
}
|
|
2645
2788
|
printInfo("");
|
|
2646
2789
|
printSeparator();
|
package/dist/postinstall.js
CHANGED
|
@@ -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
|
|
360
|
+
description: "\u547D\u4EE4\u522B\u540D\u6620\u5C04"
|
|
338
361
|
}
|
|
339
362
|
};
|
|
340
363
|
function deriveDefaultConfig(definitions) {
|