clawt 2.3.8 → 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 +56 -6
- package/dist/postinstall.js +4 -0
- package/package.json +1 -1
- package/src/commands/remove.ts +9 -0
- package/src/commands/reset.ts +17 -3
- package/src/commands/run.ts +1 -1
- package/src/commands/validate.ts +16 -2
- package/src/constants/config.ts +4 -0
- package/src/constants/messages.ts +3 -1
- 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
|
@@ -100,7 +100,8 @@ var MESSAGES = {
|
|
|
100
100
|
/** sync 冲突 */
|
|
101
101
|
SYNC_CONFLICT: (worktreePath) => `\u5408\u5E76\u5B58\u5728\u51B2\u7A81\uFF0C\u8BF7\u8FDB\u5165\u76EE\u6807 worktree \u624B\u52A8\u89E3\u51B3\uFF1A
|
|
102
102
|
cd ${worktreePath}
|
|
103
|
-
\u89E3\u51B3\u51B2\u7A81\u540E\u6267\u884C git add . && git merge --continue
|
|
103
|
+
\u89E3\u51B3\u51B2\u7A81\u540E\u6267\u884C git add . && git merge --continue
|
|
104
|
+
clawt validate -b <branch> \u9A8C\u8BC1\u53D8\u66F4`,
|
|
104
105
|
/** validate patch apply 失败,提示用户同步主分支 */
|
|
105
106
|
VALIDATE_PATCH_APPLY_FAILED: (branch) => `\u53D8\u66F4\u8FC1\u79FB\u5931\u8D25\uFF1A\u76EE\u6807\u5206\u652F\u4E0E\u4E3B\u5206\u652F\u5DEE\u5F02\u8FC7\u5927
|
|
106
107
|
\u8BF7\u5148\u6267\u884C clawt sync -b ${branch} \u540C\u6B65\u4E3B\u5206\u652F\u540E\u91CD\u8BD5`,
|
|
@@ -113,6 +114,8 @@ var MESSAGES = {
|
|
|
113
114
|
\u8BF7\u5728\u76EE\u6807 worktree \u4E2D\u63D0\u4EA4\u540E\u91CD\u65B0\u6267\u884C merge\uFF1A
|
|
114
115
|
cd ${worktreePath}
|
|
115
116
|
\u63D0\u4EA4\u5B8C\u6210\u540E\u6267\u884C\uFF1Aclawt merge -b ${branch}`,
|
|
117
|
+
/** 用户取消破坏性操作 */
|
|
118
|
+
DESTRUCTIVE_OP_CANCELLED: "\u5DF2\u53D6\u6D88\u64CD\u4F5C",
|
|
116
119
|
/** reset 成功 */
|
|
117
120
|
RESET_SUCCESS: "\u2713 \u4E3B worktree \u5DE5\u4F5C\u533A\u548C\u6682\u5B58\u533A\u5DF2\u91CD\u7F6E",
|
|
118
121
|
/** reset 时工作区和暂存区已干净 */
|
|
@@ -146,6 +149,10 @@ var CONFIG_DEFINITIONS = {
|
|
|
146
149
|
autoPullPush: {
|
|
147
150
|
defaultValue: false,
|
|
148
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"
|
|
149
156
|
}
|
|
150
157
|
};
|
|
151
158
|
function deriveDefaultConfig(definitions) {
|
|
@@ -420,6 +427,10 @@ function confirmAction(question) {
|
|
|
420
427
|
});
|
|
421
428
|
});
|
|
422
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
|
+
}
|
|
423
434
|
function formatWorktreeStatus(status) {
|
|
424
435
|
const parts = [];
|
|
425
436
|
parts.push(chalk.yellow(`${status.commitCount} \u4E2A\u63D0\u4EA4`));
|
|
@@ -666,6 +677,21 @@ function removeSnapshot(projectName, branchName) {
|
|
|
666
677
|
logger.info(`\u5DF2\u5220\u9664 validate \u5FEB\u7167: ${snapshotPath}`);
|
|
667
678
|
}
|
|
668
679
|
}
|
|
680
|
+
function removeProjectSnapshots(projectName) {
|
|
681
|
+
const projectDir = join3(VALIDATE_SNAPSHOTS_DIR, projectName);
|
|
682
|
+
if (!existsSync5(projectDir)) {
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
const files = readdirSync3(projectDir);
|
|
686
|
+
for (const file of files) {
|
|
687
|
+
unlinkSync(join3(projectDir, file));
|
|
688
|
+
}
|
|
689
|
+
try {
|
|
690
|
+
rmdirSync2(projectDir);
|
|
691
|
+
} catch {
|
|
692
|
+
}
|
|
693
|
+
logger.info(`\u5DF2\u5220\u9664\u9879\u76EE ${projectName} \u7684\u6240\u6709 validate \u5FEB\u7167`);
|
|
694
|
+
}
|
|
669
695
|
|
|
670
696
|
// src/commands/list.ts
|
|
671
697
|
import chalk2 from "chalk";
|
|
@@ -773,6 +799,7 @@ async function handleRemove(options) {
|
|
|
773
799
|
if (shouldDeleteBranch) {
|
|
774
800
|
deleteBranch(wt.branch);
|
|
775
801
|
}
|
|
802
|
+
removeSnapshot(projectName, wt.branch);
|
|
776
803
|
printSuccess(MESSAGES.WORKTREE_REMOVED(wt.path));
|
|
777
804
|
} catch (error) {
|
|
778
805
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -780,6 +807,9 @@ async function handleRemove(options) {
|
|
|
780
807
|
failures.push({ path: wt.path, error: errorMessage });
|
|
781
808
|
}
|
|
782
809
|
}
|
|
810
|
+
if (options.all) {
|
|
811
|
+
removeProjectSnapshots(projectName);
|
|
812
|
+
}
|
|
783
813
|
gitWorktreePrune();
|
|
784
814
|
const projectDir = getProjectWorktreeDir();
|
|
785
815
|
removeEmptyDir(projectDir);
|
|
@@ -1062,11 +1092,21 @@ function saveCurrentSnapshotTree(mainWorktreePath, projectName, branchName) {
|
|
|
1062
1092
|
writeSnapshot(projectName, branchName, treeHash);
|
|
1063
1093
|
return treeHash;
|
|
1064
1094
|
}
|
|
1065
|
-
function handleValidateClean(options) {
|
|
1095
|
+
async function handleValidateClean(options) {
|
|
1066
1096
|
validateMainWorktree();
|
|
1067
1097
|
const projectName = getProjectName();
|
|
1068
1098
|
const mainWorktreePath = getGitTopLevel();
|
|
1069
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
|
+
}
|
|
1070
1110
|
if (!isWorkingDirClean(mainWorktreePath)) {
|
|
1071
1111
|
gitResetHard(mainWorktreePath);
|
|
1072
1112
|
gitCleanForce(mainWorktreePath);
|
|
@@ -1099,7 +1139,7 @@ function handleIncrementalValidate(targetWorktreePath, mainWorktreePath, project
|
|
|
1099
1139
|
}
|
|
1100
1140
|
async function handleValidate(options) {
|
|
1101
1141
|
if (options.clean) {
|
|
1102
|
-
handleValidateClean(options);
|
|
1142
|
+
await handleValidateClean(options);
|
|
1103
1143
|
return;
|
|
1104
1144
|
}
|
|
1105
1145
|
validateMainWorktree();
|
|
@@ -1324,15 +1364,25 @@ async function handleSync(options) {
|
|
|
1324
1364
|
|
|
1325
1365
|
// src/commands/reset.ts
|
|
1326
1366
|
function registerResetCommand(program2) {
|
|
1327
|
-
program2.command("reset").description("\u91CD\u7F6E\u4E3B worktree \u5DE5\u4F5C\u533A\u548C\u6682\u5B58\u533A\uFF08\u4FDD\u7559 validate \u5FEB\u7167\uFF09").action(() => {
|
|
1328
|
-
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();
|
|
1329
1369
|
});
|
|
1330
1370
|
}
|
|
1331
|
-
function handleReset() {
|
|
1371
|
+
async function handleReset() {
|
|
1332
1372
|
validateMainWorktree();
|
|
1333
1373
|
const mainWorktreePath = getGitTopLevel();
|
|
1334
1374
|
logger.info("reset \u547D\u4EE4\u6267\u884C");
|
|
1335
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
|
+
}
|
|
1336
1386
|
gitResetHard(mainWorktreePath);
|
|
1337
1387
|
gitCleanForce(mainWorktreePath);
|
|
1338
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/remove.ts
CHANGED
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
printSuccess,
|
|
18
18
|
printError,
|
|
19
19
|
confirmAction,
|
|
20
|
+
removeSnapshot,
|
|
21
|
+
removeProjectSnapshots,
|
|
20
22
|
} from '../utils/index.js';
|
|
21
23
|
|
|
22
24
|
/**
|
|
@@ -100,6 +102,8 @@ async function handleRemove(options: RemoveOptions): Promise<void> {
|
|
|
100
102
|
if (shouldDeleteBranch) {
|
|
101
103
|
deleteBranch(wt.branch);
|
|
102
104
|
}
|
|
105
|
+
// 清理该分支对应的 validate 快照
|
|
106
|
+
removeSnapshot(projectName, wt.branch);
|
|
103
107
|
printSuccess(MESSAGES.WORKTREE_REMOVED(wt.path));
|
|
104
108
|
} catch (error) {
|
|
105
109
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -108,6 +112,11 @@ async function handleRemove(options: RemoveOptions): Promise<void> {
|
|
|
108
112
|
}
|
|
109
113
|
}
|
|
110
114
|
|
|
115
|
+
// --all 模式下清理整个项目的 validate 快照目录
|
|
116
|
+
if (options.all) {
|
|
117
|
+
removeProjectSnapshots(projectName);
|
|
118
|
+
}
|
|
119
|
+
|
|
111
120
|
// 清理 worktree 并清除空目录
|
|
112
121
|
gitWorktreePrune();
|
|
113
122
|
const projectDir = getProjectWorktreeDir();
|
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/run.ts
CHANGED
|
@@ -46,7 +46,7 @@ interface ClaudeTaskHandle {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* 在指定 worktree 中执行 Claude Code
|
|
49
|
+
* 在指定 worktree 中执行 Claude Code 任务,由于是--output-format json形式,所以这里固定claude code cli的启动命令
|
|
50
50
|
* @param {WorktreeInfo} worktree - worktree 信息
|
|
51
51
|
* @param {string} task - 任务描述
|
|
52
52
|
* @returns {ClaudeTaskHandle} 包含子进程引用和结果 Promise
|
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
|
/**
|
|
@@ -86,7 +86,7 @@ export const MESSAGES = {
|
|
|
86
86
|
`✓ 已将 ${mainBranch} 的最新代码同步到 ${targetBranch}`,
|
|
87
87
|
/** sync 冲突 */
|
|
88
88
|
SYNC_CONFLICT: (worktreePath: string) =>
|
|
89
|
-
`合并存在冲突,请进入目标 worktree 手动解决:\n cd ${worktreePath}\n 解决冲突后执行 git add . && git merge --continue
|
|
89
|
+
`合并存在冲突,请进入目标 worktree 手动解决:\n cd ${worktreePath}\n 解决冲突后执行 git add . && git merge --continue\n clawt validate -b <branch> 验证变更`,
|
|
90
90
|
/** validate patch apply 失败,提示用户同步主分支 */
|
|
91
91
|
VALIDATE_PATCH_APPLY_FAILED: (branch: string) =>
|
|
92
92
|
`变更迁移失败:目标分支与主分支差异过大\n 请先执行 clawt sync -b ${branch} 同步主分支后重试`,
|
|
@@ -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';
|