clawt 2.3.9 → 2.4.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/dist/index.js +35 -5
- package/dist/postinstall.js +4 -0
- package/package.json +1 -1
- package/src/commands/reset.ts +17 -3
- package/src/commands/validate.ts +16 -2
- package/src/constants/config.ts +4 -0
- package/src/constants/messages.ts +2 -0
- package/src/types/config.ts +2 -0
- package/src/utils/formatter.ts +11 -0
- package/src/utils/index.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -114,6 +114,8 @@ var MESSAGES = {
|
|
|
114
114
|
\u8BF7\u5728\u76EE\u6807 worktree \u4E2D\u63D0\u4EA4\u540E\u91CD\u65B0\u6267\u884C merge\uFF1A
|
|
115
115
|
cd ${worktreePath}
|
|
116
116
|
\u63D0\u4EA4\u5B8C\u6210\u540E\u6267\u884C\uFF1Aclawt merge -b ${branch}`,
|
|
117
|
+
/** 用户取消破坏性操作 */
|
|
118
|
+
DESTRUCTIVE_OP_CANCELLED: "\u5DF2\u53D6\u6D88\u64CD\u4F5C",
|
|
117
119
|
/** reset 成功 */
|
|
118
120
|
RESET_SUCCESS: "\u2713 \u4E3B worktree \u5DE5\u4F5C\u533A\u548C\u6682\u5B58\u533A\u5DF2\u91CD\u7F6E",
|
|
119
121
|
/** reset 时工作区和暂存区已干净 */
|
|
@@ -147,6 +149,10 @@ var CONFIG_DEFINITIONS = {
|
|
|
147
149
|
autoPullPush: {
|
|
148
150
|
defaultValue: false,
|
|
149
151
|
description: "merge \u6210\u529F\u540E\u662F\u5426\u81EA\u52A8\u6267\u884C git pull \u548C git push"
|
|
152
|
+
},
|
|
153
|
+
confirmDestructiveOps: {
|
|
154
|
+
defaultValue: true,
|
|
155
|
+
description: "\u6267\u884C\u7834\u574F\u6027\u64CD\u4F5C\uFF08reset\u3001validate --clean\uFF09\u524D\u662F\u5426\u63D0\u793A\u786E\u8BA4"
|
|
150
156
|
}
|
|
151
157
|
};
|
|
152
158
|
function deriveDefaultConfig(definitions) {
|
|
@@ -421,6 +427,10 @@ function confirmAction(question) {
|
|
|
421
427
|
});
|
|
422
428
|
});
|
|
423
429
|
}
|
|
430
|
+
function confirmDestructiveAction(dangerousCommand, description) {
|
|
431
|
+
printWarning(`\u5373\u5C06\u6267\u884C ${chalk.red.bold(dangerousCommand)}\uFF0C${description}`);
|
|
432
|
+
return confirmAction("\u662F\u5426\u7EE7\u7EED\uFF1F");
|
|
433
|
+
}
|
|
424
434
|
function formatWorktreeStatus(status) {
|
|
425
435
|
const parts = [];
|
|
426
436
|
parts.push(chalk.yellow(`${status.commitCount} \u4E2A\u63D0\u4EA4`));
|
|
@@ -1082,11 +1092,21 @@ function saveCurrentSnapshotTree(mainWorktreePath, projectName, branchName) {
|
|
|
1082
1092
|
writeSnapshot(projectName, branchName, treeHash);
|
|
1083
1093
|
return treeHash;
|
|
1084
1094
|
}
|
|
1085
|
-
function handleValidateClean(options) {
|
|
1095
|
+
async function handleValidateClean(options) {
|
|
1086
1096
|
validateMainWorktree();
|
|
1087
1097
|
const projectName = getProjectName();
|
|
1088
1098
|
const mainWorktreePath = getGitTopLevel();
|
|
1089
1099
|
logger.info(`validate --clean \u6267\u884C\uFF0C\u5206\u652F: ${options.branch}`);
|
|
1100
|
+
if (getConfigValue("confirmDestructiveOps")) {
|
|
1101
|
+
const confirmed = await confirmDestructiveAction(
|
|
1102
|
+
"git reset --hard + git clean -fd",
|
|
1103
|
+
`\u91CD\u7F6E\u4E3B worktree \u5E76\u5220\u9664\u5206\u652F ${options.branch} \u7684 validate \u5FEB\u7167`
|
|
1104
|
+
);
|
|
1105
|
+
if (!confirmed) {
|
|
1106
|
+
printInfo(MESSAGES.DESTRUCTIVE_OP_CANCELLED);
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1090
1110
|
if (!isWorkingDirClean(mainWorktreePath)) {
|
|
1091
1111
|
gitResetHard(mainWorktreePath);
|
|
1092
1112
|
gitCleanForce(mainWorktreePath);
|
|
@@ -1119,7 +1139,7 @@ function handleIncrementalValidate(targetWorktreePath, mainWorktreePath, project
|
|
|
1119
1139
|
}
|
|
1120
1140
|
async function handleValidate(options) {
|
|
1121
1141
|
if (options.clean) {
|
|
1122
|
-
handleValidateClean(options);
|
|
1142
|
+
await handleValidateClean(options);
|
|
1123
1143
|
return;
|
|
1124
1144
|
}
|
|
1125
1145
|
validateMainWorktree();
|
|
@@ -1344,15 +1364,25 @@ async function handleSync(options) {
|
|
|
1344
1364
|
|
|
1345
1365
|
// src/commands/reset.ts
|
|
1346
1366
|
function registerResetCommand(program2) {
|
|
1347
|
-
program2.command("reset").description("\u91CD\u7F6E\u4E3B worktree \u5DE5\u4F5C\u533A\u548C\u6682\u5B58\u533A\uFF08\u4FDD\u7559 validate \u5FEB\u7167\uFF09").action(() => {
|
|
1348
|
-
handleReset();
|
|
1367
|
+
program2.command("reset").description("\u91CD\u7F6E\u4E3B worktree \u5DE5\u4F5C\u533A\u548C\u6682\u5B58\u533A\uFF08\u4FDD\u7559 validate \u5FEB\u7167\uFF09").action(async () => {
|
|
1368
|
+
await handleReset();
|
|
1349
1369
|
});
|
|
1350
1370
|
}
|
|
1351
|
-
function handleReset() {
|
|
1371
|
+
async function handleReset() {
|
|
1352
1372
|
validateMainWorktree();
|
|
1353
1373
|
const mainWorktreePath = getGitTopLevel();
|
|
1354
1374
|
logger.info("reset \u547D\u4EE4\u6267\u884C");
|
|
1355
1375
|
if (!isWorkingDirClean(mainWorktreePath)) {
|
|
1376
|
+
if (getConfigValue("confirmDestructiveOps")) {
|
|
1377
|
+
const confirmed = await confirmDestructiveAction(
|
|
1378
|
+
"git reset --hard + git clean -fd",
|
|
1379
|
+
"\u4E22\u5F03\u6240\u6709\u672A\u63D0\u4EA4\u7684\u66F4\u6539"
|
|
1380
|
+
);
|
|
1381
|
+
if (!confirmed) {
|
|
1382
|
+
printInfo(MESSAGES.DESTRUCTIVE_OP_CANCELLED);
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1356
1386
|
gitResetHard(mainWorktreePath);
|
|
1357
1387
|
gitCleanForce(mainWorktreePath);
|
|
1358
1388
|
printSuccess(MESSAGES.RESET_SUCCESS);
|
package/dist/postinstall.js
CHANGED
|
@@ -23,6 +23,10 @@ var CONFIG_DEFINITIONS = {
|
|
|
23
23
|
autoPullPush: {
|
|
24
24
|
defaultValue: false,
|
|
25
25
|
description: "merge \u6210\u529F\u540E\u662F\u5426\u81EA\u52A8\u6267\u884C git pull \u548C git push"
|
|
26
|
+
},
|
|
27
|
+
confirmDestructiveOps: {
|
|
28
|
+
defaultValue: true,
|
|
29
|
+
description: "\u6267\u884C\u7834\u574F\u6027\u64CD\u4F5C\uFF08reset\u3001validate --clean\uFF09\u524D\u662F\u5426\u63D0\u793A\u786E\u8BA4"
|
|
26
30
|
}
|
|
27
31
|
};
|
|
28
32
|
function deriveDefaultConfig(definitions) {
|
package/package.json
CHANGED
package/src/commands/reset.ts
CHANGED
|
@@ -4,9 +4,11 @@ import { MESSAGES } from '../constants/index.js';
|
|
|
4
4
|
import {
|
|
5
5
|
validateMainWorktree,
|
|
6
6
|
getGitTopLevel,
|
|
7
|
+
getConfigValue,
|
|
7
8
|
isWorkingDirClean,
|
|
8
9
|
gitResetHard,
|
|
9
10
|
gitCleanForce,
|
|
11
|
+
confirmDestructiveAction,
|
|
10
12
|
printSuccess,
|
|
11
13
|
printInfo,
|
|
12
14
|
} from '../utils/index.js';
|
|
@@ -19,20 +21,32 @@ export function registerResetCommand(program: Command): void {
|
|
|
19
21
|
program
|
|
20
22
|
.command('reset')
|
|
21
23
|
.description('重置主 worktree 工作区和暂存区(保留 validate 快照)')
|
|
22
|
-
.action(() => {
|
|
23
|
-
handleReset();
|
|
24
|
+
.action(async () => {
|
|
25
|
+
await handleReset();
|
|
24
26
|
});
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
/**
|
|
28
30
|
* 执行 reset 命令:重置主 worktree 工作区和暂存区
|
|
29
31
|
*/
|
|
30
|
-
function handleReset(): void {
|
|
32
|
+
async function handleReset(): Promise<void> {
|
|
31
33
|
validateMainWorktree();
|
|
32
34
|
const mainWorktreePath = getGitTopLevel();
|
|
33
35
|
logger.info('reset 命令执行');
|
|
34
36
|
|
|
35
37
|
if (!isWorkingDirClean(mainWorktreePath)) {
|
|
38
|
+
// 根据配置决定是否需要确认
|
|
39
|
+
if (getConfigValue('confirmDestructiveOps')) {
|
|
40
|
+
const confirmed = await confirmDestructiveAction(
|
|
41
|
+
'git reset --hard + git clean -fd',
|
|
42
|
+
'丢弃所有未提交的更改',
|
|
43
|
+
);
|
|
44
|
+
if (!confirmed) {
|
|
45
|
+
printInfo(MESSAGES.DESTRUCTIVE_OP_CANCELLED);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
36
50
|
gitResetHard(mainWorktreePath);
|
|
37
51
|
gitCleanForce(mainWorktreePath);
|
|
38
52
|
printSuccess(MESSAGES.RESET_SUCCESS);
|
package/src/commands/validate.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
getProjectName,
|
|
12
12
|
getGitTopLevel,
|
|
13
13
|
getProjectWorktreeDir,
|
|
14
|
+
getConfigValue,
|
|
14
15
|
isWorkingDirClean,
|
|
15
16
|
gitAddAll,
|
|
16
17
|
gitCommit,
|
|
@@ -28,6 +29,7 @@ import {
|
|
|
28
29
|
readSnapshotTreeHash,
|
|
29
30
|
writeSnapshot,
|
|
30
31
|
removeSnapshot,
|
|
32
|
+
confirmDestructiveAction,
|
|
31
33
|
printSuccess,
|
|
32
34
|
printWarning,
|
|
33
35
|
printInfo,
|
|
@@ -163,7 +165,7 @@ function saveCurrentSnapshotTree(mainWorktreePath: string, projectName: string,
|
|
|
163
165
|
* 处理 --clean 选项:清理 validate 状态
|
|
164
166
|
* @param {ValidateOptions} options - 命令选项
|
|
165
167
|
*/
|
|
166
|
-
function handleValidateClean(options: ValidateOptions): void {
|
|
168
|
+
async function handleValidateClean(options: ValidateOptions): Promise<void> {
|
|
167
169
|
validateMainWorktree();
|
|
168
170
|
|
|
169
171
|
const projectName = getProjectName();
|
|
@@ -171,6 +173,18 @@ function handleValidateClean(options: ValidateOptions): void {
|
|
|
171
173
|
|
|
172
174
|
logger.info(`validate --clean 执行,分支: ${options.branch}`);
|
|
173
175
|
|
|
176
|
+
// 根据配置决定是否需要确认
|
|
177
|
+
if (getConfigValue('confirmDestructiveOps')) {
|
|
178
|
+
const confirmed = await confirmDestructiveAction(
|
|
179
|
+
'git reset --hard + git clean -fd',
|
|
180
|
+
`重置主 worktree 并删除分支 ${options.branch} 的 validate 快照`,
|
|
181
|
+
);
|
|
182
|
+
if (!confirmed) {
|
|
183
|
+
printInfo(MESSAGES.DESTRUCTIVE_OP_CANCELLED);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
174
188
|
// 清空主 worktree
|
|
175
189
|
if (!isWorkingDirClean(mainWorktreePath)) {
|
|
176
190
|
gitResetHard(mainWorktreePath);
|
|
@@ -250,7 +264,7 @@ function handleIncrementalValidate(targetWorktreePath: string, mainWorktreePath:
|
|
|
250
264
|
async function handleValidate(options: ValidateOptions): Promise<void> {
|
|
251
265
|
// 处理 --clean 选项
|
|
252
266
|
if (options.clean) {
|
|
253
|
-
handleValidateClean(options);
|
|
267
|
+
await handleValidateClean(options);
|
|
254
268
|
return;
|
|
255
269
|
}
|
|
256
270
|
|
package/src/constants/config.ts
CHANGED
|
@@ -21,6 +21,10 @@ export const CONFIG_DEFINITIONS: ConfigDefinitions = {
|
|
|
21
21
|
defaultValue: false,
|
|
22
22
|
description: 'merge 成功后是否自动执行 git pull 和 git push',
|
|
23
23
|
},
|
|
24
|
+
confirmDestructiveOps: {
|
|
25
|
+
defaultValue: true,
|
|
26
|
+
description: '执行破坏性操作(reset、validate --clean)前是否提示确认',
|
|
27
|
+
},
|
|
24
28
|
};
|
|
25
29
|
|
|
26
30
|
/**
|
|
@@ -98,6 +98,8 @@ export const MESSAGES = {
|
|
|
98
98
|
/** squash 完成但未提供 -m,提示用户自行提交 */
|
|
99
99
|
MERGE_SQUASH_PENDING: (worktreePath: string, branch: string) =>
|
|
100
100
|
`✓ 已将所有提交压缩到暂存区\n 请在目标 worktree 中提交后重新执行 merge:\n cd ${worktreePath}\n 提交完成后执行:clawt merge -b ${branch}`,
|
|
101
|
+
/** 用户取消破坏性操作 */
|
|
102
|
+
DESTRUCTIVE_OP_CANCELLED: '已取消操作',
|
|
101
103
|
/** reset 成功 */
|
|
102
104
|
RESET_SUCCESS: '✓ 主 worktree 工作区和暂存区已重置',
|
|
103
105
|
/** reset 时工作区和暂存区已干净 */
|
package/src/types/config.ts
CHANGED
package/src/utils/formatter.ts
CHANGED
|
@@ -67,6 +67,17 @@ export function confirmAction(question: string): Promise<boolean> {
|
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* 破坏性操作确认:先输出带高亮危险指令的警告,再等待用户确认
|
|
72
|
+
* @param {string} dangerousCommand - 即将执行的危险指令(会用红色加粗高亮)
|
|
73
|
+
* @param {string} description - 操作后果描述
|
|
74
|
+
* @returns {Promise<boolean>} 用户是否确认
|
|
75
|
+
*/
|
|
76
|
+
export function confirmDestructiveAction(dangerousCommand: string, description: string): Promise<boolean> {
|
|
77
|
+
printWarning(`即将执行 ${chalk.red.bold(dangerousCommand)},${description}`);
|
|
78
|
+
return confirmAction('是否继续?');
|
|
79
|
+
}
|
|
80
|
+
|
|
70
81
|
/**
|
|
71
82
|
* 将 WorktreeStatus 格式化为带颜色的字符串
|
|
72
83
|
* @param {WorktreeStatus} status - worktree 变更统计信息
|
package/src/utils/index.ts
CHANGED
|
@@ -45,7 +45,7 @@ export { sanitizeBranchName, generateBranchNames, validateBranchesNotExist } fro
|
|
|
45
45
|
export { validateMainWorktree, validateGitInstalled, validateClaudeCodeInstalled } from './validation.js';
|
|
46
46
|
export { createWorktrees, getProjectWorktrees, getProjectWorktreeDir, cleanupWorktrees, getWorktreeStatus } from './worktree.js';
|
|
47
47
|
export { loadConfig, getConfigValue, ensureClawtDirs } from './config.js';
|
|
48
|
-
export { printSuccess, printError, printWarning, printInfo, printSeparator, printDoubleSeparator, confirmAction, formatWorktreeStatus } from './formatter.js';
|
|
48
|
+
export { printSuccess, printError, printWarning, printInfo, printSeparator, printDoubleSeparator, confirmAction, confirmDestructiveAction, formatWorktreeStatus } from './formatter.js';
|
|
49
49
|
export { ensureDir, removeEmptyDir } from './fs.js';
|
|
50
50
|
export { multilineInput } from './prompt.js';
|
|
51
51
|
export { launchInteractiveClaude } from './claude.js';
|