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/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
- return { treeHash, headCommitHash };
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
- logger.info(`\u5DF2\u4FDD\u5B58 validate \u5FEB\u7167: ${snapshotPath}, ${headPath}`);
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
- const definition = CONFIG_DEFINITIONS[key];
2729
- if (definition.allowedValues) {
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/json.ts
2913
- function primitiveToString(value) {
2914
- if (value === void 0) {
2915
- return "undefined";
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
- if (value === null) {
2918
- return "null";
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
- if (typeof value === "symbol") {
2921
- return value.toString();
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 (typeof value === "function") {
2924
- return `[Function: ${value.name || "anonymous"}]`;
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 safeStringify(value, indent = 2) {
2929
- if (value === null || typeof value !== "object") {
2930
- return primitiveToString(value);
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
- const seen = /* @__PURE__ */ new WeakSet();
2934
- return JSON.stringify(
2935
- value,
2936
- (_key, val) => {
2937
- if (typeof val === "bigint") {
2938
- return val.toString();
2939
- }
2940
- if (typeof val === "undefined" || typeof val === "function" || typeof val === "symbol") {
2941
- return primitiveToString(val);
2942
- }
2943
- if (typeof val === "object" && val !== null) {
2944
- if (seen.has(val)) {
2945
- return "[Circular]";
2946
- }
2947
- seen.add(val);
2948
- }
2949
- return val;
2950
- },
2951
- indent
2952
- );
2953
- } catch {
2954
- try {
2955
- return JSON.stringify(String(value), null, indent);
2956
- } catch {
2957
- return "[Unserializable]";
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 = getValidateBranchName(branchName);
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 = getValidateBranchName(branchName);
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
- saveCurrentSnapshotTree(mainWorktreePath, projectName, branchName);
4042
- try {
4043
- const currentHeadCommitHash = getHeadCommitHash(mainWorktreePath);
4044
- if (oldHeadCommitHash && oldHeadCommitHash !== currentHeadCommitHash) {
4045
- const oldHeadTreeHash = getCommitTreeHash(oldHeadCommitHash, mainWorktreePath);
4046
- const oldChangePatch = gitDiffTree(oldHeadTreeHash, oldTreeHash, mainWorktreePath);
4047
- if (oldChangePatch.length > 0 && gitApplyCachedCheck(oldChangePatch, mainWorktreePath)) {
4048
- gitApplyCachedFromStdin(oldChangePatch, mainWorktreePath);
4049
- } else if (oldChangePatch.length > 0) {
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
- } catch (error) {
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
- printSuccess(MESSAGES.INCREMENTAL_VALIDATE_SUCCESS(branchName));
4065
- }
4066
- function executeSingleCommand(command, mainWorktreePath) {
4067
- printInfo(MESSAGES.VALIDATE_RUN_START(command));
4068
- printSeparator();
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
- const exitCode = result.status ?? 1;
4076
- if (exitCode === 0) {
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
- async function executeRunCommand(command, mainWorktreePath) {
4111
- printInfo("");
4112
- const commands = parseParallelCommands(command);
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
- if (options.run) {
4152
- await executeRunCommand(options.run, mainWorktreePath);
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 choices = keys.map((k) => {
4335
- const isObject = typeof DEFAULT_CONFIG[k] === "object";
4336
- return {
4337
- name: k,
4338
- message: `${k}: ${isObject ? chalk11.dim(JSON.stringify(config2[k])) : formatConfigValue(config2[k])} ${chalk11.dim(`\u2014 ${CONFIG_DESCRIPTIONS[k]}`)}`,
4339
- ...isObject && { disabled: CONFIG_ALIAS_DISABLED_HINT }
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
- const selectedKey = await new Enquirer5.Select({
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(selectedKey, String(newValue)));
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 chalk12 from "chalk";
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(` ${chalk12.bold.cyan(MESSAGES.STATUS_TITLE(result.main.projectName))}`);
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(` ${chalk12.bold("\u25C6")} ${chalk12.bold(MESSAGES.STATUS_MAIN_SECTION)}`);
4526
- printInfo(` \u5206\u652F: ${chalk12.bold(main2.branch)}`);
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: ${chalk12.green("\u2713 \u5E72\u51C0")}`);
4583
+ printInfo(` \u72B6\u6001: ${chalk11.green("\u2713 \u5E72\u51C0")}`);
4529
4584
  } else {
4530
- printInfo(` \u72B6\u6001: ${chalk12.yellow("\u2717 \u6709\u672A\u63D0\u4EA4\u4FEE\u6539")}`);
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(` ${chalk12.bold("\u25C6")} ${chalk12.bold(MESSAGES.STATUS_WORKTREES_SECTION)} (${total} \u4E2A)`);
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(` ${chalk12.bold("\u25CF")} ${chalk12.bold(wt.branch)} [${statusLabel}]`);
4602
+ printInfo(` ${chalk11.bold("\u25CF")} ${chalk11.bold(wt.branch)} [${statusLabel}]`);
4548
4603
  if (wt.insertions > 0 || wt.deletions > 0) {
4549
- printInfo(` ${chalk12.green(`+${wt.insertions}`)} ${chalk12.red(`-${wt.deletions}`)}`);
4604
+ printInfo(` ${chalk11.green(`+${wt.insertions}`)} ${chalk11.red(`-${wt.deletions}`)}`);
4550
4605
  }
4551
4606
  if (wt.commitsAhead > 0) {
4552
- printInfo(` ${chalk12.yellow(`${wt.commitsAhead} \u4E2A\u672C\u5730\u63D0\u4EA4`)}`);
4607
+ printInfo(` ${chalk11.yellow(`${wt.commitsAhead} \u4E2A\u672C\u5730\u63D0\u4EA4`)}`);
4553
4608
  }
4554
4609
  if (wt.commitsBehind > 0) {
4555
- printInfo(` ${chalk12.yellow(`\u843D\u540E\u4E3B\u5206\u652F ${wt.commitsBehind} \u4E2A\u63D0\u4EA4`)}`);
4610
+ printInfo(` ${chalk11.yellow(`\u843D\u540E\u4E3B\u5206\u652F ${wt.commitsBehind} \u4E2A\u63D0\u4EA4`)}`);
4556
4611
  } else {
4557
- printInfo(` ${chalk12.green("\u4E0E\u4E3B\u5206\u652F\u540C\u6B65")}`);
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(` ${chalk12.gray(MESSAGES.STATUS_CREATED_AT(relativeTime))}`);
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(` ${chalk12.green(MESSAGES.STATUS_LAST_VALIDATED(relativeTime))}`);
4623
+ printInfo(` ${chalk11.green(MESSAGES.STATUS_LAST_VALIDATED(relativeTime))}`);
4569
4624
  }
4570
4625
  } else {
4571
- printInfo(` ${chalk12.red(MESSAGES.STATUS_NOT_VALIDATED)}`);
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 chalk12.green(MESSAGES.STATUS_CHANGE_COMMITTED);
4633
+ return chalk11.green(MESSAGES.STATUS_CHANGE_COMMITTED);
4579
4634
  case "uncommitted":
4580
- return chalk12.yellow(MESSAGES.STATUS_CHANGE_UNCOMMITTED);
4635
+ return chalk11.yellow(MESSAGES.STATUS_CHANGE_UNCOMMITTED);
4581
4636
  case "conflict":
4582
- return chalk12.red(MESSAGES.STATUS_CHANGE_CONFLICT);
4637
+ return chalk11.red(MESSAGES.STATUS_CHANGE_CONFLICT);
4583
4638
  case "clean":
4584
- return chalk12.gray(MESSAGES.STATUS_CHANGE_CLEAN);
4639
+ return chalk11.gray(MESSAGES.STATUS_CHANGE_CLEAN);
4585
4640
  }
4586
4641
  }
4587
4642
  function printSnapshotsSection(snapshots) {
4588
- printInfo(` ${chalk12.bold("\u25C6")} ${chalk12.bold(MESSAGES.STATUS_SNAPSHOTS_SECTION)} (${snapshots.total} \u4E2A)`);
4643
+ printInfo(` ${chalk11.bold("\u25C6")} ${chalk11.bold(MESSAGES.STATUS_SNAPSHOTS_SECTION)} (${snapshots.total} \u4E2A)`);
4589
4644
  if (snapshots.orphaned > 0) {
4590
- printInfo(` ${chalk12.yellow(MESSAGES.STATUS_SNAPSHOT_ORPHANED(snapshots.orphaned))}`);
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 chalk13 from "chalk";
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(` ${chalk13.bold(alias)} \u2192 ${chalk13.cyan(command)}`);
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 chalk14 from "chalk";
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(` ${chalk14.bold.cyan(MESSAGES.PROJECTS_OVERVIEW_TITLE)}`);
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 ${chalk14.bold(String(result.totalProjects))} \u4E2A\u9879\u76EE ${chalk14.gray(MESSAGES.PROJECTS_TOTAL_DISK_USAGE(formatDiskSize(result.totalDiskUsage)))}`);
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(` ${chalk14.bold("\u25CF")} ${chalk14.bold(project.name)}`);
4808
- printInfo(` ${MESSAGES.PROJECTS_WORKTREE_COUNT(project.worktreeCount)} ${chalk14.gray(activeLabel)} ${chalk14.gray(diskLabel)}`);
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(` ${chalk14.bold.cyan(MESSAGES.PROJECTS_DETAIL_TITLE(result.name))}`);
4868
+ printInfo(` ${chalk13.bold.cyan(MESSAGES.PROJECTS_DETAIL_TITLE(result.name))}`);
4814
4869
  printDoubleSeparator();
4815
4870
  printInfo("");
4816
- printInfo(` ${chalk14.bold("\u25C6")} ${chalk14.bold(MESSAGES.PROJECTS_PATH(result.projectDir))}`);
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(` ${chalk14.bold("\u25CF")} ${chalk14.bold(wt.branch)}`);
4891
+ printInfo(` ${chalk13.bold("\u25CF")} ${chalk13.bold(wt.branch)}`);
4837
4892
  printInfo(` ${wt.path}`);
4838
- printInfo(` ${chalk14.gray(modifiedLabel)} ${chalk14.gray(diskLabel)}`);
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("\u5C55\u793A\u5F53\u524D\u9879\u76EE\u7684 init \u914D\u7F6E").action(() => {
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
- const configJson = safeStringify(config2);
5070
- printInfo(MESSAGES.INIT_SHOW(configJson));
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();