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 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);
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawt",
3
- "version": "2.3.9",
3
+ "version": "2.4.0",
4
4
  "description": "本地并行执行多个Claude Code Agent任务,融合 Git Worktree 与 Claude Code CLI 的命令行工具",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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);
@@ -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
 
@@ -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 时工作区和暂存区已干净 */
@@ -6,6 +6,8 @@ export interface ClawtConfig {
6
6
  claudeCodeCommand: string;
7
7
  /** merge 成功后是否自动执行 git pull 和 git push */
8
8
  autoPullPush: boolean;
9
+ /** 执行破坏性操作(reset、validate --clean)前是否提示确认 */
10
+ confirmDestructiveOps: boolean;
9
11
  }
10
12
 
11
13
  /** 单个配置项的完整定义(默认值 + 描述) */
@@ -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 变更统计信息
@@ -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';