clawt 3.1.2 → 3.2.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 +3 -3
- package/dist/index.js +291 -229
- package/dist/postinstall.js +33 -1
- package/docs/config.md +2 -1
- package/docs/init.md +16 -7
- package/docs/project-config.md +132 -0
- package/docs/spec.md +32 -22
- package/docs/validate.md +55 -13
- package/package.json +1 -1
- package/src/commands/config.ts +14 -28
- package/src/commands/init.ts +23 -12
- package/src/commands/validate.ts +50 -228
- package/src/constants/index.ts +1 -0
- package/src/constants/messages/init.ts +4 -0
- package/src/constants/messages/validate.ts +3 -0
- package/src/constants/project-config.ts +46 -0
- package/src/types/index.ts +1 -1
- package/src/types/projectConfig.ts +17 -0
- package/src/utils/config-strategy.ts +68 -20
- package/src/utils/index.ts +4 -2
- package/src/utils/project-config.ts +9 -0
- package/src/utils/validate-core.ts +174 -0
- package/src/utils/validate-runner.ts +105 -0
- package/src/utils/validate-snapshot.ts +29 -9
- package/tests/unit/commands/config.test.ts +1 -0
- package/tests/unit/commands/init.test.ts +41 -6
- package/tests/unit/commands/validate.test.ts +96 -243
- package/tests/unit/utils/config-strategy.test.ts +77 -1
- package/tests/unit/utils/project-config.test.ts +32 -0
- package/tests/unit/utils/validate-snapshot.test.ts +8 -3
package/dist/index.js
CHANGED
|
@@ -180,6 +180,8 @@ var VALIDATE_MESSAGES = {
|
|
|
180
180
|
\u6682\u5B58\u533A = \u4E0A\u6B21\u5FEB\u7167\uFF0C\u5DE5\u4F5C\u76EE\u5F55 = \u6700\u65B0\u53D8\u66F4`,
|
|
181
181
|
/** 增量 validate 降级为全量模式提示 */
|
|
182
182
|
INCREMENTAL_VALIDATE_FALLBACK: "\u589E\u91CF\u5BF9\u6BD4\u5931\u8D25\uFF0C\u5DF2\u964D\u7EA7\u4E3A\u5168\u91CF\u6A21\u5F0F",
|
|
183
|
+
/** 增量 validate 检测到目标 worktree 无新变更 */
|
|
184
|
+
INCREMENTAL_VALIDATE_NO_CHANGES: (branch) => `\u5206\u652F ${branch} \u81EA\u4E0A\u6B21 validate \u4EE5\u6765\u6CA1\u6709\u65B0\u7684\u53D8\u66F4\uFF0C\u5DF2\u6062\u590D\u5230\u4E0A\u6B21\u9A8C\u8BC1\u72B6\u6001`,
|
|
183
185
|
/** validate 状态已清理 */
|
|
184
186
|
VALIDATE_CLEANED: (branch) => `\u2713 \u5206\u652F ${branch} \u7684 validate \u72B6\u6001\u5DF2\u6E05\u7406`,
|
|
185
187
|
/** validate patch apply 失败,提示用户同步主分支 */
|
|
@@ -460,7 +462,11 @@ var INIT_MESSAGES = {
|
|
|
460
462
|
/** 项目未初始化(requireProjectConfig 使用) */
|
|
461
463
|
PROJECT_NOT_INITIALIZED: "\u9879\u76EE\u5C1A\u672A\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u6267\u884C clawt init \u8BBE\u7F6E\u4E3B\u5DE5\u4F5C\u5206\u652F",
|
|
462
464
|
/** 项目配置缺少 clawtMainWorkBranch 字段 */
|
|
463
|
-
PROJECT_CONFIG_MISSING_BRANCH: "\u9879\u76EE\u914D\u7F6E\u7F3A\u5C11\u4E3B\u5DE5\u4F5C\u5206\u652F\u4FE1\u606F\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C clawt init \u8BBE\u7F6E\u4E3B\u5DE5\u4F5C\u5206\u652F"
|
|
465
|
+
PROJECT_CONFIG_MISSING_BRANCH: "\u9879\u76EE\u914D\u7F6E\u7F3A\u5C11\u4E3B\u5DE5\u4F5C\u5206\u652F\u4FE1\u606F\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C clawt init \u8BBE\u7F6E\u4E3B\u5DE5\u4F5C\u5206\u652F",
|
|
466
|
+
/** init show 交互式面板选择配置项提示 */
|
|
467
|
+
INIT_SELECT_PROMPT: "\u9009\u62E9\u8981\u4FEE\u6539\u7684\u9879\u76EE\u914D\u7F6E\u9879",
|
|
468
|
+
/** init show 交互式面板配置项修改成功 */
|
|
469
|
+
INIT_SET_SUCCESS: (key, value) => `\u2713 \u9879\u76EE\u914D\u7F6E ${key} \u5DF2\u8BBE\u7F6E\u4E3A ${value}`
|
|
464
470
|
};
|
|
465
471
|
|
|
466
472
|
// src/constants/messages/interactive-panel.ts
|
|
@@ -608,6 +614,32 @@ function deriveConfigDescriptions(definitions) {
|
|
|
608
614
|
var DEFAULT_CONFIG = deriveDefaultConfig(CONFIG_DEFINITIONS);
|
|
609
615
|
var CONFIG_DESCRIPTIONS = deriveConfigDescriptions(CONFIG_DEFINITIONS);
|
|
610
616
|
|
|
617
|
+
// src/constants/project-config.ts
|
|
618
|
+
var PROJECT_CONFIG_DEFINITIONS = {
|
|
619
|
+
clawtMainWorkBranch: {
|
|
620
|
+
defaultValue: "",
|
|
621
|
+
description: "\u4E3B worktree \u7684\u5DE5\u4F5C\u5206\u652F\u540D"
|
|
622
|
+
},
|
|
623
|
+
validateRunCommand: {
|
|
624
|
+
defaultValue: void 0,
|
|
625
|
+
description: "validate \u6210\u529F\u540E\u81EA\u52A8\u6267\u884C\u7684\u547D\u4EE4\uFF08-r \u7684\u9ED8\u8BA4\u503C\uFF09"
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
function deriveDefaultConfig2(definitions) {
|
|
629
|
+
const entries = Object.entries(definitions).map(
|
|
630
|
+
([key, def]) => [key, def.defaultValue]
|
|
631
|
+
);
|
|
632
|
+
return Object.fromEntries(entries);
|
|
633
|
+
}
|
|
634
|
+
function deriveConfigDescriptions2(definitions) {
|
|
635
|
+
const entries = Object.entries(definitions).map(
|
|
636
|
+
([key, def]) => [key, def.description]
|
|
637
|
+
);
|
|
638
|
+
return Object.fromEntries(entries);
|
|
639
|
+
}
|
|
640
|
+
var PROJECT_DEFAULT_CONFIG = deriveDefaultConfig2(PROJECT_CONFIG_DEFINITIONS);
|
|
641
|
+
var PROJECT_CONFIG_DESCRIPTIONS = deriveConfigDescriptions2(PROJECT_CONFIG_DEFINITIONS);
|
|
642
|
+
|
|
611
643
|
// src/constants/git.ts
|
|
612
644
|
var AUTO_SAVE_COMMIT_MESSAGE = "chore: auto-save before sync";
|
|
613
645
|
|
|
@@ -1259,6 +1291,10 @@ function getMainWorkBranch() {
|
|
|
1259
1291
|
const config2 = requireProjectConfig();
|
|
1260
1292
|
return config2.clawtMainWorkBranch;
|
|
1261
1293
|
}
|
|
1294
|
+
function getValidateRunCommand() {
|
|
1295
|
+
const config2 = loadProjectConfig();
|
|
1296
|
+
return config2?.validateRunCommand || void 0;
|
|
1297
|
+
}
|
|
1262
1298
|
|
|
1263
1299
|
// src/utils/validate-branch.ts
|
|
1264
1300
|
function getValidateBranchName(branchName) {
|
|
@@ -1638,6 +1674,9 @@ function getSnapshotPath(projectName, branchName) {
|
|
|
1638
1674
|
function getSnapshotHeadPath(projectName, branchName) {
|
|
1639
1675
|
return join6(VALIDATE_SNAPSHOTS_DIR, projectName, `${branchName}.head`);
|
|
1640
1676
|
}
|
|
1677
|
+
function getSnapshotStagedPath(projectName, branchName) {
|
|
1678
|
+
return join6(VALIDATE_SNAPSHOTS_DIR, projectName, `${branchName}.staged`);
|
|
1679
|
+
}
|
|
1641
1680
|
function hasSnapshot(projectName, branchName) {
|
|
1642
1681
|
return existsSync8(getSnapshotPath(projectName, branchName));
|
|
1643
1682
|
}
|
|
@@ -1650,23 +1689,28 @@ function getSnapshotModifiedTime(projectName, branchName) {
|
|
|
1650
1689
|
function readSnapshot(projectName, branchName) {
|
|
1651
1690
|
const snapshotPath = getSnapshotPath(projectName, branchName);
|
|
1652
1691
|
const headPath = getSnapshotHeadPath(projectName, branchName);
|
|
1692
|
+
const stagedPath = getSnapshotStagedPath(projectName, branchName);
|
|
1653
1693
|
logger.debug(`\u8BFB\u53D6 validate \u5FEB\u7167: ${snapshotPath}`);
|
|
1654
1694
|
const treeHash = existsSync8(snapshotPath) ? readFileSync3(snapshotPath, "utf-8").trim() : "";
|
|
1655
1695
|
const headCommitHash = existsSync8(headPath) ? readFileSync3(headPath, "utf-8").trim() : "";
|
|
1656
|
-
|
|
1696
|
+
const stagedTreeHash = existsSync8(stagedPath) ? readFileSync3(stagedPath, "utf-8").trim() : "";
|
|
1697
|
+
return { treeHash, headCommitHash, stagedTreeHash };
|
|
1657
1698
|
}
|
|
1658
|
-
function writeSnapshot(projectName, branchName, treeHash, headCommitHash) {
|
|
1699
|
+
function writeSnapshot(projectName, branchName, treeHash, headCommitHash, stagedTreeHash = "") {
|
|
1659
1700
|
const snapshotPath = getSnapshotPath(projectName, branchName);
|
|
1660
1701
|
const headPath = getSnapshotHeadPath(projectName, branchName);
|
|
1702
|
+
const stagedPath = getSnapshotStagedPath(projectName, branchName);
|
|
1661
1703
|
const snapshotDir = join6(VALIDATE_SNAPSHOTS_DIR, projectName);
|
|
1662
1704
|
ensureDir(snapshotDir);
|
|
1663
1705
|
writeFileSync3(snapshotPath, treeHash, "utf-8");
|
|
1664
1706
|
writeFileSync3(headPath, headCommitHash, "utf-8");
|
|
1665
|
-
|
|
1707
|
+
writeFileSync3(stagedPath, stagedTreeHash, "utf-8");
|
|
1708
|
+
logger.info(`\u5DF2\u4FDD\u5B58 validate \u5FEB\u7167: ${snapshotPath}, ${headPath}, ${stagedPath}`);
|
|
1666
1709
|
}
|
|
1667
1710
|
function removeSnapshot(projectName, branchName) {
|
|
1668
1711
|
const snapshotPath = getSnapshotPath(projectName, branchName);
|
|
1669
1712
|
const headPath = getSnapshotHeadPath(projectName, branchName);
|
|
1713
|
+
const stagedPath = getSnapshotStagedPath(projectName, branchName);
|
|
1670
1714
|
if (existsSync8(snapshotPath)) {
|
|
1671
1715
|
unlinkSync(snapshotPath);
|
|
1672
1716
|
logger.info(`\u5DF2\u5220\u9664 validate \u5FEB\u7167: ${snapshotPath}`);
|
|
@@ -1675,6 +1719,10 @@ function removeSnapshot(projectName, branchName) {
|
|
|
1675
1719
|
unlinkSync(headPath);
|
|
1676
1720
|
logger.info(`\u5DF2\u5220\u9664 validate \u5FEB\u7167: ${headPath}`);
|
|
1677
1721
|
}
|
|
1722
|
+
if (existsSync8(stagedPath)) {
|
|
1723
|
+
unlinkSync(stagedPath);
|
|
1724
|
+
logger.info(`\u5DF2\u5220\u9664 validate \u5FEB\u7167: ${stagedPath}`);
|
|
1725
|
+
}
|
|
1678
1726
|
}
|
|
1679
1727
|
function getProjectSnapshotBranches(projectName) {
|
|
1680
1728
|
const projectDir = join6(VALIDATE_SNAPSHOTS_DIR, projectName);
|
|
@@ -2717,7 +2765,7 @@ function parseConfigValue(key, rawValue) {
|
|
|
2717
2765
|
}
|
|
2718
2766
|
return { success: true, value: rawValue };
|
|
2719
2767
|
}
|
|
2720
|
-
async function promptConfigValue(key, currentValue) {
|
|
2768
|
+
async function promptConfigValue(key, currentValue, allowedValues) {
|
|
2721
2769
|
const expectedType = typeof currentValue;
|
|
2722
2770
|
if (expectedType === "boolean") {
|
|
2723
2771
|
return promptBooleanValue(key, currentValue);
|
|
@@ -2725,18 +2773,43 @@ async function promptConfigValue(key, currentValue) {
|
|
|
2725
2773
|
if (expectedType === "number") {
|
|
2726
2774
|
return promptNumberValue(key, currentValue);
|
|
2727
2775
|
}
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
return promptEnumValue(key, currentValue, definition.allowedValues);
|
|
2776
|
+
if (allowedValues) {
|
|
2777
|
+
return promptEnumValue(key, currentValue, allowedValues);
|
|
2731
2778
|
}
|
|
2732
2779
|
return promptStringValue(key, currentValue);
|
|
2733
2780
|
}
|
|
2734
2781
|
function formatConfigValue(value) {
|
|
2782
|
+
if (value === void 0 || value === null) {
|
|
2783
|
+
return chalk7.dim("(\u672A\u8BBE\u7F6E)");
|
|
2784
|
+
}
|
|
2735
2785
|
if (typeof value === "boolean") {
|
|
2736
2786
|
return value ? chalk7.green("true") : chalk7.yellow("false");
|
|
2737
2787
|
}
|
|
2738
2788
|
return chalk7.cyan(String(value));
|
|
2739
2789
|
}
|
|
2790
|
+
async function interactiveConfigEditor(config2, definitions, options) {
|
|
2791
|
+
const keys = Object.keys(definitions);
|
|
2792
|
+
const disabledKeys = options?.disabledKeys ?? {};
|
|
2793
|
+
const configRecord = config2;
|
|
2794
|
+
const choices = keys.map((k) => {
|
|
2795
|
+
const isDisabled = k in disabledKeys;
|
|
2796
|
+
const value = configRecord[k];
|
|
2797
|
+
const isObject = typeof value === "object" && value !== null;
|
|
2798
|
+
return {
|
|
2799
|
+
name: k,
|
|
2800
|
+
message: `${k}: ${isObject || isDisabled ? chalk7.dim(isObject ? JSON.stringify(value) : String(value ?? "")) : formatConfigValue(value)} ${chalk7.dim(`\u2014 ${definitions[k].description}`)}`,
|
|
2801
|
+
...isDisabled && { disabled: disabledKeys[k] }
|
|
2802
|
+
};
|
|
2803
|
+
});
|
|
2804
|
+
const selectedKey = await new Enquirer4.Select({
|
|
2805
|
+
message: options?.selectPrompt ?? MESSAGES.CONFIG_SELECT_PROMPT,
|
|
2806
|
+
choices
|
|
2807
|
+
}).run();
|
|
2808
|
+
const currentValue = configRecord[selectedKey];
|
|
2809
|
+
const definition = definitions[selectedKey];
|
|
2810
|
+
const newValue = await promptConfigValue(selectedKey, currentValue, definition.allowedValues);
|
|
2811
|
+
return { key: selectedKey, newValue };
|
|
2812
|
+
}
|
|
2740
2813
|
async function promptBooleanValue(key, currentValue) {
|
|
2741
2814
|
const choices = [
|
|
2742
2815
|
{ name: "true", message: "true" },
|
|
@@ -2774,7 +2847,7 @@ async function promptEnumValue(key, currentValue, allowedValues) {
|
|
|
2774
2847
|
async function promptStringValue(key, currentValue) {
|
|
2775
2848
|
return await new Enquirer4.Input({
|
|
2776
2849
|
message: MESSAGES.CONFIG_INPUT_PROMPT(key),
|
|
2777
|
-
initial: currentValue
|
|
2850
|
+
initial: currentValue || ""
|
|
2778
2851
|
}).run();
|
|
2779
2852
|
}
|
|
2780
2853
|
|
|
@@ -2909,55 +2982,144 @@ async function checkForUpdates(currentVersion) {
|
|
|
2909
2982
|
}
|
|
2910
2983
|
}
|
|
2911
2984
|
|
|
2912
|
-
// src/utils/
|
|
2913
|
-
function
|
|
2914
|
-
|
|
2915
|
-
|
|
2985
|
+
// src/utils/validate-runner.ts
|
|
2986
|
+
function executeSingleCommand(command, mainWorktreePath) {
|
|
2987
|
+
printInfo(MESSAGES.VALIDATE_RUN_START(command));
|
|
2988
|
+
printSeparator();
|
|
2989
|
+
const result = runCommandInherited(command, { cwd: mainWorktreePath });
|
|
2990
|
+
printSeparator();
|
|
2991
|
+
if (result.error) {
|
|
2992
|
+
printError(MESSAGES.VALIDATE_RUN_ERROR(command, result.error.message));
|
|
2993
|
+
return;
|
|
2916
2994
|
}
|
|
2917
|
-
|
|
2918
|
-
|
|
2995
|
+
const exitCode = result.status ?? 1;
|
|
2996
|
+
if (exitCode === 0) {
|
|
2997
|
+
printSuccess(MESSAGES.VALIDATE_RUN_SUCCESS(command));
|
|
2998
|
+
} else {
|
|
2999
|
+
printError(MESSAGES.VALIDATE_RUN_FAILED(command, exitCode));
|
|
2919
3000
|
}
|
|
2920
|
-
|
|
2921
|
-
|
|
3001
|
+
}
|
|
3002
|
+
function reportParallelResults(results) {
|
|
3003
|
+
printSeparator();
|
|
3004
|
+
const successCount = results.filter((r) => r.exitCode === 0 && !r.error).length;
|
|
3005
|
+
const failedCount = results.length - successCount;
|
|
3006
|
+
for (const result of results) {
|
|
3007
|
+
if (result.error) {
|
|
3008
|
+
printError(MESSAGES.VALIDATE_PARALLEL_CMD_ERROR(result.command, result.error));
|
|
3009
|
+
} else if (result.exitCode === 0) {
|
|
3010
|
+
printSuccess(MESSAGES.VALIDATE_PARALLEL_CMD_SUCCESS(result.command));
|
|
3011
|
+
} else {
|
|
3012
|
+
printError(MESSAGES.VALIDATE_PARALLEL_CMD_FAILED(result.command, result.exitCode));
|
|
3013
|
+
}
|
|
2922
3014
|
}
|
|
2923
|
-
if (
|
|
2924
|
-
|
|
3015
|
+
if (failedCount === 0) {
|
|
3016
|
+
printSuccess(MESSAGES.VALIDATE_PARALLEL_RUN_ALL_SUCCESS(results.length));
|
|
3017
|
+
} else {
|
|
3018
|
+
printError(MESSAGES.VALIDATE_PARALLEL_RUN_SUMMARY(successCount, failedCount));
|
|
2925
3019
|
}
|
|
2926
|
-
return String(value);
|
|
2927
3020
|
}
|
|
2928
|
-
function
|
|
2929
|
-
|
|
2930
|
-
|
|
3021
|
+
async function executeParallelCommands(commands, mainWorktreePath) {
|
|
3022
|
+
printInfo(MESSAGES.VALIDATE_PARALLEL_RUN_START(commands.length));
|
|
3023
|
+
for (let i = 0; i < commands.length; i++) {
|
|
3024
|
+
printInfo(MESSAGES.VALIDATE_PARALLEL_CMD_START(i + 1, commands.length, commands[i]));
|
|
2931
3025
|
}
|
|
3026
|
+
printSeparator();
|
|
3027
|
+
const results = await runParallelCommands(commands, { cwd: mainWorktreePath });
|
|
3028
|
+
reportParallelResults(results);
|
|
3029
|
+
}
|
|
3030
|
+
async function executeRunCommand(command, mainWorktreePath) {
|
|
3031
|
+
printInfo("");
|
|
3032
|
+
const commands = parseParallelCommands(command);
|
|
3033
|
+
if (commands.length <= 1) {
|
|
3034
|
+
executeSingleCommand(commands[0] || command, mainWorktreePath);
|
|
3035
|
+
} else {
|
|
3036
|
+
await executeParallelCommands(commands, mainWorktreePath);
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
|
|
3040
|
+
// src/utils/validate-core.ts
|
|
3041
|
+
function migrateChangesViaPatch(targetWorktreePath, mainWorktreePath, branchName, hasUncommitted) {
|
|
3042
|
+
let didTempCommit = false;
|
|
2932
3043
|
try {
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
3044
|
+
if (hasUncommitted) {
|
|
3045
|
+
gitAddAll(targetWorktreePath);
|
|
3046
|
+
gitCommit("clawt:temp-commit-for-validate", targetWorktreePath);
|
|
3047
|
+
didTempCommit = true;
|
|
3048
|
+
}
|
|
3049
|
+
const patch = gitDiffBinaryAgainstBranch(branchName, mainWorktreePath);
|
|
3050
|
+
if (patch.length > 0) {
|
|
3051
|
+
try {
|
|
3052
|
+
gitApplyFromStdin(patch, mainWorktreePath);
|
|
3053
|
+
} catch (error) {
|
|
3054
|
+
logger.warn(`patch apply \u5931\u8D25: ${error}`);
|
|
3055
|
+
printWarning(MESSAGES.VALIDATE_PATCH_APPLY_FAILED(branchName));
|
|
3056
|
+
return { success: false };
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
return { success: true };
|
|
3060
|
+
} finally {
|
|
3061
|
+
if (didTempCommit) {
|
|
3062
|
+
try {
|
|
3063
|
+
gitResetSoft(1, targetWorktreePath);
|
|
3064
|
+
} catch (error) {
|
|
3065
|
+
logger.error(`\u64A4\u9500\u4E34\u65F6 commit \u5931\u8D25: ${error}`);
|
|
3066
|
+
}
|
|
3067
|
+
try {
|
|
3068
|
+
gitRestoreStaged(targetWorktreePath);
|
|
3069
|
+
} catch (error) {
|
|
3070
|
+
logger.error(`\u6062\u590D\u6682\u5B58\u533A\u5931\u8D25: ${error}`);
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
function computeCurrentTreeHash(mainWorktreePath) {
|
|
3076
|
+
gitAddAll(mainWorktreePath);
|
|
3077
|
+
const treeHash = gitWriteTree(mainWorktreePath);
|
|
3078
|
+
gitRestoreStaged(mainWorktreePath);
|
|
3079
|
+
return treeHash;
|
|
3080
|
+
}
|
|
3081
|
+
function saveCurrentSnapshotTree(mainWorktreePath, projectName, branchName, stagedTreeHash = "") {
|
|
3082
|
+
gitAddAll(mainWorktreePath);
|
|
3083
|
+
const treeHash = gitWriteTree(mainWorktreePath);
|
|
3084
|
+
gitRestoreStaged(mainWorktreePath);
|
|
3085
|
+
const headCommitHash = getHeadCommitHash(mainWorktreePath);
|
|
3086
|
+
writeSnapshot(projectName, branchName, treeHash, headCommitHash, stagedTreeHash);
|
|
3087
|
+
return treeHash;
|
|
3088
|
+
}
|
|
3089
|
+
function loadOldSnapshotToStage(oldTreeHash, oldHeadCommitHash, currentHeadCommitHash, mainWorktreePath) {
|
|
3090
|
+
try {
|
|
3091
|
+
if (oldHeadCommitHash && oldHeadCommitHash !== currentHeadCommitHash) {
|
|
3092
|
+
const oldHeadTreeHash = getCommitTreeHash(oldHeadCommitHash, mainWorktreePath);
|
|
3093
|
+
const oldChangePatch = gitDiffTree(oldHeadTreeHash, oldTreeHash, mainWorktreePath);
|
|
3094
|
+
if (oldChangePatch.length > 0 && gitApplyCachedCheck(oldChangePatch, mainWorktreePath)) {
|
|
3095
|
+
gitApplyCachedFromStdin(oldChangePatch, mainWorktreePath);
|
|
3096
|
+
const stagedTreeHash = gitWriteTree(mainWorktreePath);
|
|
3097
|
+
return { success: true, stagedTreeHash };
|
|
3098
|
+
} else if (oldChangePatch.length > 0) {
|
|
3099
|
+
logger.warn("\u65E7\u53D8\u66F4 patch \u4E0E\u5F53\u524D HEAD \u51B2\u7A81\uFF0C\u964D\u7EA7\u4E3A\u5168\u91CF\u6A21\u5F0F");
|
|
3100
|
+
return { success: false, stagedTreeHash: "" };
|
|
3101
|
+
}
|
|
3102
|
+
return { success: true, stagedTreeHash: "" };
|
|
3103
|
+
} else {
|
|
3104
|
+
gitReadTree(oldTreeHash, mainWorktreePath);
|
|
3105
|
+
return { success: true, stagedTreeHash: oldTreeHash };
|
|
2958
3106
|
}
|
|
3107
|
+
} catch (error) {
|
|
3108
|
+
logger.warn(`\u589E\u91CF read-tree \u5931\u8D25: ${error}`);
|
|
3109
|
+
return { success: false, stagedTreeHash: "" };
|
|
2959
3110
|
}
|
|
2960
3111
|
}
|
|
3112
|
+
function switchToValidateBranch(branchName, mainWorktreePath) {
|
|
3113
|
+
const validateBranchName = getValidateBranchName(branchName);
|
|
3114
|
+
if (!checkBranchExists(validateBranchName)) {
|
|
3115
|
+
throw new ClawtError(MESSAGES.VALIDATE_BRANCH_NOT_FOUND(validateBranchName, branchName));
|
|
3116
|
+
}
|
|
3117
|
+
const currentBranch = getCurrentBranch(mainWorktreePath);
|
|
3118
|
+
if (currentBranch !== validateBranchName) {
|
|
3119
|
+
gitCheckout(validateBranchName, mainWorktreePath);
|
|
3120
|
+
}
|
|
3121
|
+
return validateBranchName;
|
|
3122
|
+
}
|
|
2961
3123
|
|
|
2962
3124
|
// src/utils/interactive-panel.ts
|
|
2963
3125
|
import { createInterface as createInterface2 } from "readline";
|
|
@@ -3925,40 +4087,6 @@ function registerValidateCommand(program2) {
|
|
|
3925
4087
|
async function handleDirtyMainWorktree(mainWorktreePath) {
|
|
3926
4088
|
await handleDirtyWorkingDir(mainWorktreePath);
|
|
3927
4089
|
}
|
|
3928
|
-
function migrateChangesViaPatch(targetWorktreePath, mainWorktreePath, branchName, hasUncommitted) {
|
|
3929
|
-
let didTempCommit = false;
|
|
3930
|
-
try {
|
|
3931
|
-
if (hasUncommitted) {
|
|
3932
|
-
gitAddAll(targetWorktreePath);
|
|
3933
|
-
gitCommit("clawt:temp-commit-for-validate", targetWorktreePath);
|
|
3934
|
-
didTempCommit = true;
|
|
3935
|
-
}
|
|
3936
|
-
const patch = gitDiffBinaryAgainstBranch(branchName, mainWorktreePath);
|
|
3937
|
-
if (patch.length > 0) {
|
|
3938
|
-
try {
|
|
3939
|
-
gitApplyFromStdin(patch, mainWorktreePath);
|
|
3940
|
-
} catch (error) {
|
|
3941
|
-
logger.warn(`patch apply \u5931\u8D25: ${error}`);
|
|
3942
|
-
printWarning(MESSAGES.VALIDATE_PATCH_APPLY_FAILED(branchName));
|
|
3943
|
-
return { success: false };
|
|
3944
|
-
}
|
|
3945
|
-
}
|
|
3946
|
-
return { success: true };
|
|
3947
|
-
} finally {
|
|
3948
|
-
if (didTempCommit) {
|
|
3949
|
-
try {
|
|
3950
|
-
gitResetSoft(1, targetWorktreePath);
|
|
3951
|
-
} catch (error) {
|
|
3952
|
-
logger.error(`\u64A4\u9500\u4E34\u65F6 commit \u5931\u8D25: ${error}`);
|
|
3953
|
-
}
|
|
3954
|
-
try {
|
|
3955
|
-
gitRestoreStaged(targetWorktreePath);
|
|
3956
|
-
} catch (error) {
|
|
3957
|
-
logger.error(`\u6062\u590D\u6682\u5B58\u533A\u5931\u8D25: ${error}`);
|
|
3958
|
-
}
|
|
3959
|
-
}
|
|
3960
|
-
}
|
|
3961
|
-
}
|
|
3962
4090
|
async function handlePatchApplyFailure(targetWorktreePath, branchName) {
|
|
3963
4091
|
const confirmed = await confirmAction(MESSAGES.VALIDATE_CONFIRM_AUTO_SYNC(branchName));
|
|
3964
4092
|
if (!confirmed) {
|
|
@@ -3968,14 +4096,6 @@ async function handlePatchApplyFailure(targetWorktreePath, branchName) {
|
|
|
3968
4096
|
printInfo(MESSAGES.VALIDATE_AUTO_SYNC_START(branchName));
|
|
3969
4097
|
const syncResult = await executeSyncForBranch(targetWorktreePath, branchName);
|
|
3970
4098
|
}
|
|
3971
|
-
function saveCurrentSnapshotTree(mainWorktreePath, projectName, branchName) {
|
|
3972
|
-
gitAddAll(mainWorktreePath);
|
|
3973
|
-
const treeHash = gitWriteTree(mainWorktreePath);
|
|
3974
|
-
gitRestoreStaged(mainWorktreePath);
|
|
3975
|
-
const headCommitHash = getHeadCommitHash(mainWorktreePath);
|
|
3976
|
-
writeSnapshot(projectName, branchName, treeHash, headCommitHash);
|
|
3977
|
-
return treeHash;
|
|
3978
|
-
}
|
|
3979
4099
|
async function handleValidateClean(options) {
|
|
3980
4100
|
validateMainWorktree();
|
|
3981
4101
|
requireProjectConfig();
|
|
@@ -4004,11 +4124,7 @@ async function handleValidateClean(options) {
|
|
|
4004
4124
|
printSuccess(MESSAGES.VALIDATE_CLEANED(branchName));
|
|
4005
4125
|
}
|
|
4006
4126
|
async function handleFirstValidate(targetWorktreePath, mainWorktreePath, projectName, branchName, hasUncommitted) {
|
|
4007
|
-
const validateBranchName =
|
|
4008
|
-
if (!checkBranchExists(validateBranchName)) {
|
|
4009
|
-
throw new ClawtError(MESSAGES.VALIDATE_BRANCH_NOT_FOUND(validateBranchName, branchName));
|
|
4010
|
-
}
|
|
4011
|
-
gitCheckout(validateBranchName, mainWorktreePath);
|
|
4127
|
+
const validateBranchName = switchToValidateBranch(branchName, mainWorktreePath);
|
|
4012
4128
|
const result = migrateChangesViaPatch(targetWorktreePath, mainWorktreePath, branchName, hasUncommitted);
|
|
4013
4129
|
if (!result.success) {
|
|
4014
4130
|
await ensureOnMainWorkBranch(mainWorktreePath);
|
|
@@ -4019,102 +4135,48 @@ async function handleFirstValidate(targetWorktreePath, mainWorktreePath, project
|
|
|
4019
4135
|
printSuccess(MESSAGES.VALIDATE_SUCCESS_WITH_BRANCH(branchName, validateBranchName));
|
|
4020
4136
|
}
|
|
4021
4137
|
async function handleIncrementalValidate(targetWorktreePath, mainWorktreePath, projectName, branchName, hasUncommitted) {
|
|
4022
|
-
const { treeHash: oldTreeHash, headCommitHash: oldHeadCommitHash } = readSnapshot(projectName, branchName);
|
|
4138
|
+
const { treeHash: oldTreeHash, headCommitHash: oldHeadCommitHash, stagedTreeHash: oldStagedTreeHash } = readSnapshot(projectName, branchName);
|
|
4023
4139
|
if (!isWorkingDirClean(mainWorktreePath)) {
|
|
4024
4140
|
gitResetHard(mainWorktreePath);
|
|
4025
4141
|
gitCleanForce(mainWorktreePath);
|
|
4026
4142
|
}
|
|
4027
|
-
const validateBranchName =
|
|
4028
|
-
if (!checkBranchExists(validateBranchName)) {
|
|
4029
|
-
throw new ClawtError(MESSAGES.VALIDATE_BRANCH_NOT_FOUND(validateBranchName, branchName));
|
|
4030
|
-
}
|
|
4031
|
-
const currentBranch = getCurrentBranch(mainWorktreePath);
|
|
4032
|
-
if (currentBranch !== validateBranchName) {
|
|
4033
|
-
gitCheckout(validateBranchName, mainWorktreePath);
|
|
4034
|
-
}
|
|
4143
|
+
const validateBranchName = switchToValidateBranch(branchName, mainWorktreePath);
|
|
4035
4144
|
const result = migrateChangesViaPatch(targetWorktreePath, mainWorktreePath, branchName, hasUncommitted);
|
|
4036
4145
|
if (!result.success) {
|
|
4037
4146
|
await ensureOnMainWorkBranch(mainWorktreePath);
|
|
4038
4147
|
await handlePatchApplyFailure(targetWorktreePath, branchName);
|
|
4039
4148
|
return;
|
|
4040
4149
|
}
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
logger.warn("\u65E7\u53D8\u66F4 patch \u4E0E\u5F53\u524D HEAD \u51B2\u7A81\uFF0C\u964D\u7EA7\u4E3A\u5168\u91CF\u6A21\u5F0F");
|
|
4051
|
-
printWarning(MESSAGES.INCREMENTAL_VALIDATE_FALLBACK);
|
|
4052
|
-
printSuccess(MESSAGES.VALIDATE_SUCCESS_WITH_BRANCH(branchName, validateBranchName));
|
|
4053
|
-
return;
|
|
4150
|
+
const newTreeHash = computeCurrentTreeHash(mainWorktreePath);
|
|
4151
|
+
const currentHeadCommitHash = getHeadCommitHash(mainWorktreePath);
|
|
4152
|
+
const hasNewChanges = newTreeHash !== oldTreeHash || oldHeadCommitHash && oldHeadCommitHash !== currentHeadCommitHash;
|
|
4153
|
+
if (!hasNewChanges) {
|
|
4154
|
+
if (oldStagedTreeHash) {
|
|
4155
|
+
try {
|
|
4156
|
+
gitReadTree(oldStagedTreeHash, mainWorktreePath);
|
|
4157
|
+
} catch (error) {
|
|
4158
|
+
logger.warn(`\u6062\u590D\u6682\u5B58\u533A\u5931\u8D25: ${error}`);
|
|
4054
4159
|
}
|
|
4055
|
-
} else {
|
|
4056
|
-
gitReadTree(oldTreeHash, mainWorktreePath);
|
|
4057
4160
|
}
|
|
4058
|
-
|
|
4059
|
-
logger.warn(`\u589E\u91CF read-tree \u5931\u8D25: ${error}`);
|
|
4060
|
-
printWarning(MESSAGES.INCREMENTAL_VALIDATE_FALLBACK);
|
|
4161
|
+
printInfo(MESSAGES.INCREMENTAL_VALIDATE_NO_CHANGES(branchName));
|
|
4061
4162
|
printSuccess(MESSAGES.VALIDATE_SUCCESS_WITH_BRANCH(branchName, validateBranchName));
|
|
4062
4163
|
return;
|
|
4063
4164
|
}
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
const result = runCommandInherited(command, { cwd: mainWorktreePath });
|
|
4070
|
-
printSeparator();
|
|
4071
|
-
if (result.error) {
|
|
4072
|
-
printError(MESSAGES.VALIDATE_RUN_ERROR(command, result.error.message));
|
|
4165
|
+
const stageResult = loadOldSnapshotToStage(oldTreeHash, oldHeadCommitHash, currentHeadCommitHash, mainWorktreePath);
|
|
4166
|
+
if (!stageResult.success) {
|
|
4167
|
+
printWarning(MESSAGES.INCREMENTAL_VALIDATE_FALLBACK);
|
|
4168
|
+
writeSnapshot(projectName, branchName, newTreeHash, currentHeadCommitHash, "");
|
|
4169
|
+
printSuccess(MESSAGES.VALIDATE_SUCCESS_WITH_BRANCH(branchName, validateBranchName));
|
|
4073
4170
|
return;
|
|
4074
4171
|
}
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
printSuccess(MESSAGES.VALIDATE_RUN_SUCCESS(command));
|
|
4078
|
-
} else {
|
|
4079
|
-
printError(MESSAGES.VALIDATE_RUN_FAILED(command, exitCode));
|
|
4080
|
-
}
|
|
4081
|
-
}
|
|
4082
|
-
function reportParallelResults(results) {
|
|
4083
|
-
printSeparator();
|
|
4084
|
-
const successCount = results.filter((r) => r.exitCode === 0 && !r.error).length;
|
|
4085
|
-
const failedCount = results.length - successCount;
|
|
4086
|
-
for (const result of results) {
|
|
4087
|
-
if (result.error) {
|
|
4088
|
-
printError(MESSAGES.VALIDATE_PARALLEL_CMD_ERROR(result.command, result.error));
|
|
4089
|
-
} else if (result.exitCode === 0) {
|
|
4090
|
-
printSuccess(MESSAGES.VALIDATE_PARALLEL_CMD_SUCCESS(result.command));
|
|
4091
|
-
} else {
|
|
4092
|
-
printError(MESSAGES.VALIDATE_PARALLEL_CMD_FAILED(result.command, result.exitCode));
|
|
4093
|
-
}
|
|
4094
|
-
}
|
|
4095
|
-
if (failedCount === 0) {
|
|
4096
|
-
printSuccess(MESSAGES.VALIDATE_PARALLEL_RUN_ALL_SUCCESS(results.length));
|
|
4097
|
-
} else {
|
|
4098
|
-
printError(MESSAGES.VALIDATE_PARALLEL_RUN_SUMMARY(successCount, failedCount));
|
|
4099
|
-
}
|
|
4100
|
-
}
|
|
4101
|
-
async function executeParallelCommands(commands, mainWorktreePath) {
|
|
4102
|
-
printInfo(MESSAGES.VALIDATE_PARALLEL_RUN_START(commands.length));
|
|
4103
|
-
for (let i = 0; i < commands.length; i++) {
|
|
4104
|
-
printInfo(MESSAGES.VALIDATE_PARALLEL_CMD_START(i + 1, commands.length, commands[i]));
|
|
4105
|
-
}
|
|
4106
|
-
printSeparator();
|
|
4107
|
-
const results = await runParallelCommands(commands, { cwd: mainWorktreePath });
|
|
4108
|
-
reportParallelResults(results);
|
|
4172
|
+
writeSnapshot(projectName, branchName, newTreeHash, currentHeadCommitHash, stageResult.stagedTreeHash);
|
|
4173
|
+
printSuccess(MESSAGES.INCREMENTAL_VALIDATE_SUCCESS(branchName));
|
|
4109
4174
|
}
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
if (commands.length <= 1) {
|
|
4114
|
-
executeSingleCommand(commands[0] || command, mainWorktreePath);
|
|
4115
|
-
} else {
|
|
4116
|
-
await executeParallelCommands(commands, mainWorktreePath);
|
|
4175
|
+
function resolveRunCommand(optionRun) {
|
|
4176
|
+
if (optionRun) {
|
|
4177
|
+
return optionRun;
|
|
4117
4178
|
}
|
|
4179
|
+
return getValidateRunCommand();
|
|
4118
4180
|
}
|
|
4119
4181
|
async function handleValidate(options) {
|
|
4120
4182
|
if (options.clean) {
|
|
@@ -4148,8 +4210,9 @@ async function handleValidate(options) {
|
|
|
4148
4210
|
}
|
|
4149
4211
|
await handleFirstValidate(targetWorktreePath, mainWorktreePath, projectName, branchName, hasUncommitted);
|
|
4150
4212
|
}
|
|
4151
|
-
|
|
4152
|
-
|
|
4213
|
+
const runCommand = resolveRunCommand(options.run);
|
|
4214
|
+
if (runCommand) {
|
|
4215
|
+
await executeRunCommand(runCommand, mainWorktreePath);
|
|
4153
4216
|
}
|
|
4154
4217
|
}
|
|
4155
4218
|
|
|
@@ -4274,8 +4337,6 @@ async function handleMerge(options) {
|
|
|
4274
4337
|
}
|
|
4275
4338
|
|
|
4276
4339
|
// src/commands/config.ts
|
|
4277
|
-
import chalk11 from "chalk";
|
|
4278
|
-
import Enquirer5 from "enquirer";
|
|
4279
4340
|
function registerConfigCommand(program2) {
|
|
4280
4341
|
const configCmd = program2.command("config").description("\u4EA4\u4E92\u5F0F\u67E5\u770B\u548C\u4FEE\u6539\u5168\u5C40\u914D\u7F6E").action(async () => {
|
|
4281
4342
|
await handleConfigSet();
|
|
@@ -4329,25 +4390,19 @@ async function handleConfigSet(key, value) {
|
|
|
4329
4390
|
}
|
|
4330
4391
|
async function handleInteractiveConfigSet() {
|
|
4331
4392
|
const config2 = loadConfig();
|
|
4332
|
-
const keys = Object.keys(DEFAULT_CONFIG);
|
|
4333
4393
|
logger.info("config set \u547D\u4EE4\u6267\u884C\uFF0C\u8FDB\u5165\u4EA4\u4E92\u5F0F\u914D\u7F6E");
|
|
4334
|
-
const
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4394
|
+
const disabledKeys = {};
|
|
4395
|
+
for (const k of Object.keys(DEFAULT_CONFIG)) {
|
|
4396
|
+
if (typeof DEFAULT_CONFIG[k] === "object") {
|
|
4397
|
+
disabledKeys[k] = CONFIG_ALIAS_DISABLED_HINT;
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
const { key, newValue } = await interactiveConfigEditor(config2, CONFIG_DEFINITIONS, {
|
|
4401
|
+
disabledKeys
|
|
4341
4402
|
});
|
|
4342
|
-
|
|
4343
|
-
message: MESSAGES.CONFIG_SELECT_PROMPT,
|
|
4344
|
-
choices
|
|
4345
|
-
}).run();
|
|
4346
|
-
const currentValue = config2[selectedKey];
|
|
4347
|
-
const newValue = await promptConfigValue(selectedKey, currentValue);
|
|
4348
|
-
config2[selectedKey] = newValue;
|
|
4403
|
+
config2[key] = newValue;
|
|
4349
4404
|
saveConfig(config2);
|
|
4350
|
-
printSuccess(MESSAGES.CONFIG_SET_SUCCESS(
|
|
4405
|
+
printSuccess(MESSAGES.CONFIG_SET_SUCCESS(key, String(newValue)));
|
|
4351
4406
|
}
|
|
4352
4407
|
function handleConfigGet(key) {
|
|
4353
4408
|
if (!isValidConfigKey(key)) {
|
|
@@ -4391,7 +4446,7 @@ async function handleReset() {
|
|
|
4391
4446
|
}
|
|
4392
4447
|
|
|
4393
4448
|
// src/commands/status.ts
|
|
4394
|
-
import
|
|
4449
|
+
import chalk11 from "chalk";
|
|
4395
4450
|
function registerStatusCommand(program2) {
|
|
4396
4451
|
program2.command("status").description("\u663E\u793A\u9879\u76EE\u5168\u5C40\u72B6\u6001\u603B\u89C8\uFF08\u652F\u6301 --json \u683C\u5F0F\u8F93\u51FA\uFF09").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA").option("-i, --interactive", "\u4EA4\u4E92\u5F0F\u9762\u677F\u6A21\u5F0F").action(async (options) => {
|
|
4397
4452
|
await handleStatus(options);
|
|
@@ -4509,7 +4564,7 @@ function printStatusAsJson(result) {
|
|
|
4509
4564
|
}
|
|
4510
4565
|
function printStatusAsText(result) {
|
|
4511
4566
|
printDoubleSeparator();
|
|
4512
|
-
printInfo(` ${
|
|
4567
|
+
printInfo(` ${chalk11.bold.cyan(MESSAGES.STATUS_TITLE(result.main.projectName))}`);
|
|
4513
4568
|
printDoubleSeparator();
|
|
4514
4569
|
printInfo("");
|
|
4515
4570
|
printMainSection(result.main);
|
|
@@ -4522,17 +4577,17 @@ function printStatusAsText(result) {
|
|
|
4522
4577
|
printDoubleSeparator();
|
|
4523
4578
|
}
|
|
4524
4579
|
function printMainSection(main2) {
|
|
4525
|
-
printInfo(` ${
|
|
4526
|
-
printInfo(` \u5206\u652F: ${
|
|
4580
|
+
printInfo(` ${chalk11.bold("\u25C6")} ${chalk11.bold(MESSAGES.STATUS_MAIN_SECTION)}`);
|
|
4581
|
+
printInfo(` \u5206\u652F: ${chalk11.bold(main2.branch)}`);
|
|
4527
4582
|
if (main2.isClean) {
|
|
4528
|
-
printInfo(` \u72B6\u6001: ${
|
|
4583
|
+
printInfo(` \u72B6\u6001: ${chalk11.green("\u2713 \u5E72\u51C0")}`);
|
|
4529
4584
|
} else {
|
|
4530
|
-
printInfo(` \u72B6\u6001: ${
|
|
4585
|
+
printInfo(` \u72B6\u6001: ${chalk11.yellow("\u2717 \u6709\u672A\u63D0\u4EA4\u4FEE\u6539")}`);
|
|
4531
4586
|
}
|
|
4532
4587
|
printInfo("");
|
|
4533
4588
|
}
|
|
4534
4589
|
function printWorktreesSection(worktrees, total) {
|
|
4535
|
-
printInfo(` ${
|
|
4590
|
+
printInfo(` ${chalk11.bold("\u25C6")} ${chalk11.bold(MESSAGES.STATUS_WORKTREES_SECTION)} (${total} \u4E2A)`);
|
|
4536
4591
|
printInfo("");
|
|
4537
4592
|
if (worktrees.length === 0) {
|
|
4538
4593
|
printInfo(` ${MESSAGES.STATUS_NO_WORKTREES}`);
|
|
@@ -4544,56 +4599,56 @@ function printWorktreesSection(worktrees, total) {
|
|
|
4544
4599
|
}
|
|
4545
4600
|
function printWorktreeItem(wt) {
|
|
4546
4601
|
const statusLabel = formatChangeStatusLabel2(wt.changeStatus);
|
|
4547
|
-
printInfo(` ${
|
|
4602
|
+
printInfo(` ${chalk11.bold("\u25CF")} ${chalk11.bold(wt.branch)} [${statusLabel}]`);
|
|
4548
4603
|
if (wt.insertions > 0 || wt.deletions > 0) {
|
|
4549
|
-
printInfo(` ${
|
|
4604
|
+
printInfo(` ${chalk11.green(`+${wt.insertions}`)} ${chalk11.red(`-${wt.deletions}`)}`);
|
|
4550
4605
|
}
|
|
4551
4606
|
if (wt.commitsAhead > 0) {
|
|
4552
|
-
printInfo(` ${
|
|
4607
|
+
printInfo(` ${chalk11.yellow(`${wt.commitsAhead} \u4E2A\u672C\u5730\u63D0\u4EA4`)}`);
|
|
4553
4608
|
}
|
|
4554
4609
|
if (wt.commitsBehind > 0) {
|
|
4555
|
-
printInfo(` ${
|
|
4610
|
+
printInfo(` ${chalk11.yellow(`\u843D\u540E\u4E3B\u5206\u652F ${wt.commitsBehind} \u4E2A\u63D0\u4EA4`)}`);
|
|
4556
4611
|
} else {
|
|
4557
|
-
printInfo(` ${
|
|
4612
|
+
printInfo(` ${chalk11.green("\u4E0E\u4E3B\u5206\u652F\u540C\u6B65")}`);
|
|
4558
4613
|
}
|
|
4559
4614
|
if (wt.createdAt) {
|
|
4560
4615
|
const relativeTime = formatRelativeTime(wt.createdAt);
|
|
4561
4616
|
if (relativeTime) {
|
|
4562
|
-
printInfo(` ${
|
|
4617
|
+
printInfo(` ${chalk11.gray(MESSAGES.STATUS_CREATED_AT(relativeTime))}`);
|
|
4563
4618
|
}
|
|
4564
4619
|
}
|
|
4565
4620
|
if (wt.snapshotTime) {
|
|
4566
4621
|
const relativeTime = formatRelativeTime(wt.snapshotTime);
|
|
4567
4622
|
if (relativeTime) {
|
|
4568
|
-
printInfo(` ${
|
|
4623
|
+
printInfo(` ${chalk11.green(MESSAGES.STATUS_LAST_VALIDATED(relativeTime))}`);
|
|
4569
4624
|
}
|
|
4570
4625
|
} else {
|
|
4571
|
-
printInfo(` ${
|
|
4626
|
+
printInfo(` ${chalk11.red(MESSAGES.STATUS_NOT_VALIDATED)}`);
|
|
4572
4627
|
}
|
|
4573
4628
|
printInfo("");
|
|
4574
4629
|
}
|
|
4575
4630
|
function formatChangeStatusLabel2(status) {
|
|
4576
4631
|
switch (status) {
|
|
4577
4632
|
case "committed":
|
|
4578
|
-
return
|
|
4633
|
+
return chalk11.green(MESSAGES.STATUS_CHANGE_COMMITTED);
|
|
4579
4634
|
case "uncommitted":
|
|
4580
|
-
return
|
|
4635
|
+
return chalk11.yellow(MESSAGES.STATUS_CHANGE_UNCOMMITTED);
|
|
4581
4636
|
case "conflict":
|
|
4582
|
-
return
|
|
4637
|
+
return chalk11.red(MESSAGES.STATUS_CHANGE_CONFLICT);
|
|
4583
4638
|
case "clean":
|
|
4584
|
-
return
|
|
4639
|
+
return chalk11.gray(MESSAGES.STATUS_CHANGE_CLEAN);
|
|
4585
4640
|
}
|
|
4586
4641
|
}
|
|
4587
4642
|
function printSnapshotsSection(snapshots) {
|
|
4588
|
-
printInfo(` ${
|
|
4643
|
+
printInfo(` ${chalk11.bold("\u25C6")} ${chalk11.bold(MESSAGES.STATUS_SNAPSHOTS_SECTION)} (${snapshots.total} \u4E2A)`);
|
|
4589
4644
|
if (snapshots.orphaned > 0) {
|
|
4590
|
-
printInfo(` ${
|
|
4645
|
+
printInfo(` ${chalk11.yellow(MESSAGES.STATUS_SNAPSHOT_ORPHANED(snapshots.orphaned))}`);
|
|
4591
4646
|
}
|
|
4592
4647
|
printInfo("");
|
|
4593
4648
|
}
|
|
4594
4649
|
|
|
4595
4650
|
// src/commands/alias.ts
|
|
4596
|
-
import
|
|
4651
|
+
import chalk12 from "chalk";
|
|
4597
4652
|
function getRegisteredCommandNames(program2) {
|
|
4598
4653
|
return program2.commands.map((cmd) => cmd.name());
|
|
4599
4654
|
}
|
|
@@ -4614,7 +4669,7 @@ ${MESSAGES.ALIAS_LIST_TITLE}
|
|
|
4614
4669
|
`);
|
|
4615
4670
|
printSeparator();
|
|
4616
4671
|
for (const [alias, command] of entries) {
|
|
4617
|
-
printInfo(` ${
|
|
4672
|
+
printInfo(` ${chalk12.bold(alias)} \u2192 ${chalk12.cyan(command)}`);
|
|
4618
4673
|
}
|
|
4619
4674
|
printInfo("");
|
|
4620
4675
|
printSeparator();
|
|
@@ -4663,7 +4718,7 @@ function registerAliasCommand(program2) {
|
|
|
4663
4718
|
// src/commands/projects.ts
|
|
4664
4719
|
import { existsSync as existsSync10, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
|
|
4665
4720
|
import { join as join8 } from "path";
|
|
4666
|
-
import
|
|
4721
|
+
import chalk13 from "chalk";
|
|
4667
4722
|
function registerProjectsCommand(program2) {
|
|
4668
4723
|
program2.command("projects [name]").description("\u5C55\u793A\u6240\u6709\u9879\u76EE\u7684 worktree \u6982\u89C8\uFF0C\u6216\u67E5\u770B\u6307\u5B9A\u9879\u76EE\u7684 worktree \u8BE6\u60C5").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA").action((name, options) => {
|
|
4669
4724
|
handleProjects({ name, json: options.json });
|
|
@@ -4782,7 +4837,7 @@ function sortByLastActiveTimeDesc(projects) {
|
|
|
4782
4837
|
}
|
|
4783
4838
|
function printProjectsOverviewAsText(result) {
|
|
4784
4839
|
printDoubleSeparator();
|
|
4785
|
-
printInfo(` ${
|
|
4840
|
+
printInfo(` ${chalk13.bold.cyan(MESSAGES.PROJECTS_OVERVIEW_TITLE)}`);
|
|
4786
4841
|
printDoubleSeparator();
|
|
4787
4842
|
printInfo("");
|
|
4788
4843
|
if (result.projects.length === 0) {
|
|
@@ -4796,7 +4851,7 @@ function printProjectsOverviewAsText(result) {
|
|
|
4796
4851
|
}
|
|
4797
4852
|
printSeparator();
|
|
4798
4853
|
printInfo("");
|
|
4799
|
-
printInfo(` \u5171 ${
|
|
4854
|
+
printInfo(` \u5171 ${chalk13.bold(String(result.totalProjects))} \u4E2A\u9879\u76EE ${chalk13.gray(MESSAGES.PROJECTS_TOTAL_DISK_USAGE(formatDiskSize(result.totalDiskUsage)))}`);
|
|
4800
4855
|
printInfo("");
|
|
4801
4856
|
printDoubleSeparator();
|
|
4802
4857
|
}
|
|
@@ -4804,16 +4859,16 @@ function printProjectOverviewItem(project) {
|
|
|
4804
4859
|
const relativeTime = formatRelativeTime(project.lastActiveTime);
|
|
4805
4860
|
const activeLabel = relativeTime ? MESSAGES.PROJECTS_LAST_ACTIVE(relativeTime) : "";
|
|
4806
4861
|
const diskLabel = MESSAGES.PROJECTS_DISK_USAGE(formatDiskSize(project.diskUsage));
|
|
4807
|
-
printInfo(` ${
|
|
4808
|
-
printInfo(` ${MESSAGES.PROJECTS_WORKTREE_COUNT(project.worktreeCount)} ${
|
|
4862
|
+
printInfo(` ${chalk13.bold("\u25CF")} ${chalk13.bold(project.name)}`);
|
|
4863
|
+
printInfo(` ${MESSAGES.PROJECTS_WORKTREE_COUNT(project.worktreeCount)} ${chalk13.gray(activeLabel)} ${chalk13.gray(diskLabel)}`);
|
|
4809
4864
|
printInfo("");
|
|
4810
4865
|
}
|
|
4811
4866
|
function printProjectDetailAsText(result) {
|
|
4812
4867
|
printDoubleSeparator();
|
|
4813
|
-
printInfo(` ${
|
|
4868
|
+
printInfo(` ${chalk13.bold.cyan(MESSAGES.PROJECTS_DETAIL_TITLE(result.name))}`);
|
|
4814
4869
|
printDoubleSeparator();
|
|
4815
4870
|
printInfo("");
|
|
4816
|
-
printInfo(` ${
|
|
4871
|
+
printInfo(` ${chalk13.bold("\u25C6")} ${chalk13.bold(MESSAGES.PROJECTS_PATH(result.projectDir))}`);
|
|
4817
4872
|
printInfo(` ${MESSAGES.PROJECTS_TOTAL_DISK_USAGE(formatDiskSize(result.totalDiskUsage))}`);
|
|
4818
4873
|
printInfo("");
|
|
4819
4874
|
printSeparator();
|
|
@@ -4833,9 +4888,9 @@ function printWorktreeDetailItem(wt) {
|
|
|
4833
4888
|
const relativeTime = formatRelativeTime(wt.lastModifiedTime);
|
|
4834
4889
|
const modifiedLabel = relativeTime ? MESSAGES.PROJECTS_LAST_MODIFIED(relativeTime) : "";
|
|
4835
4890
|
const diskLabel = MESSAGES.PROJECTS_DISK_USAGE(formatDiskSize(wt.diskUsage));
|
|
4836
|
-
printInfo(` ${
|
|
4891
|
+
printInfo(` ${chalk13.bold("\u25CF")} ${chalk13.bold(wt.branch)}`);
|
|
4837
4892
|
printInfo(` ${wt.path}`);
|
|
4838
|
-
printInfo(` ${
|
|
4893
|
+
printInfo(` ${chalk13.gray(modifiedLabel)} ${chalk13.gray(diskLabel)}`);
|
|
4839
4894
|
printInfo("");
|
|
4840
4895
|
}
|
|
4841
4896
|
|
|
@@ -5058,16 +5113,23 @@ function registerInitCommand(program2) {
|
|
|
5058
5113
|
await handleInit(options);
|
|
5059
5114
|
});
|
|
5060
5115
|
initCmd.addCommand(
|
|
5061
|
-
new Cmd("show").description("\
|
|
5062
|
-
handleInitShow();
|
|
5116
|
+
new Cmd("show").description("\u4EA4\u4E92\u5F0F\u67E5\u770B\u548C\u4FEE\u6539\u9879\u76EE\u914D\u7F6E").action(async () => {
|
|
5117
|
+
await handleInitShow();
|
|
5063
5118
|
})
|
|
5064
5119
|
);
|
|
5065
5120
|
}
|
|
5066
|
-
function handleInitShow() {
|
|
5121
|
+
async function handleInitShow() {
|
|
5067
5122
|
validateMainWorktree();
|
|
5068
5123
|
const config2 = requireProjectConfig();
|
|
5069
|
-
|
|
5070
|
-
|
|
5124
|
+
logger.info("init show \u547D\u4EE4\u6267\u884C\uFF0C\u8FDB\u5165\u4EA4\u4E92\u5F0F\u9879\u76EE\u914D\u7F6E");
|
|
5125
|
+
const { key, newValue } = await interactiveConfigEditor(
|
|
5126
|
+
config2,
|
|
5127
|
+
PROJECT_CONFIG_DEFINITIONS,
|
|
5128
|
+
{ selectPrompt: MESSAGES.INIT_SELECT_PROMPT }
|
|
5129
|
+
);
|
|
5130
|
+
const updatedConfig = { ...config2, [key]: newValue };
|
|
5131
|
+
saveProjectConfig(updatedConfig);
|
|
5132
|
+
printSuccess(MESSAGES.INIT_SET_SUCCESS(key, String(newValue)));
|
|
5071
5133
|
}
|
|
5072
5134
|
async function handleInit(options) {
|
|
5073
5135
|
validateMainWorktree();
|