clawt 3.6.2 → 3.7.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
@@ -1313,6 +1313,20 @@ function gitWorktreePrune(cwd) {
1313
1313
  // src/utils/formatter.ts
1314
1314
  import chalk4 from "chalk";
1315
1315
  import { createInterface } from "readline";
1316
+
1317
+ // src/utils/interactive.ts
1318
+ var nonInteractiveFlag = false;
1319
+ function setNonInteractive(value) {
1320
+ nonInteractiveFlag = value;
1321
+ }
1322
+ function isNonInteractive() {
1323
+ if (nonInteractiveFlag) return true;
1324
+ if (process.env.CI === "true" || process.env.CI === "1") return true;
1325
+ if (process.env.CLAWT_NON_INTERACTIVE === "true" || process.env.CLAWT_NON_INTERACTIVE === "1") return true;
1326
+ return false;
1327
+ }
1328
+
1329
+ // src/utils/formatter.ts
1316
1330
  function printSuccess(message) {
1317
1331
  console.log(chalk4.green(message));
1318
1332
  }
@@ -1334,7 +1348,10 @@ function printSeparator() {
1334
1348
  function printDoubleSeparator() {
1335
1349
  console.log(MESSAGES.DOUBLE_SEPARATOR);
1336
1350
  }
1337
- function confirmAction(question) {
1351
+ function confirmAction(question, nonInteractiveDefault = true) {
1352
+ if (isNonInteractive()) {
1353
+ return Promise.resolve(nonInteractiveDefault);
1354
+ }
1338
1355
  return new Promise((resolve4) => {
1339
1356
  const rl = createInterface({
1340
1357
  input: process.stdin,
@@ -1610,6 +1627,14 @@ async function rebuildValidateBranch(branchName, cwd) {
1610
1627
  logger.info(`\u9A8C\u8BC1\u5206\u652F\u5DF2\u91CD\u5EFA: ${getValidateBranchName(branchName)}`);
1611
1628
  }
1612
1629
  async function handleDirtyWorkingDir(cwd) {
1630
+ if (isNonInteractive()) {
1631
+ gitAddAll(cwd);
1632
+ gitStashPush("clawt:auto-stash", cwd);
1633
+ if (!isWorkingDirClean(cwd)) {
1634
+ throw new ClawtError("\u5DE5\u4F5C\u533A\u4ECD\u7136\u4E0D\u5E72\u51C0\uFF0C\u8BF7\u624B\u52A8\u5904\u7406");
1635
+ }
1636
+ return;
1637
+ }
1613
1638
  printWarning("\u5F53\u524D\u5206\u652F\u6709\u672A\u63D0\u4EA4\u7684\u66F4\u6539\uFF0C\u8BF7\u9009\u62E9\u5904\u7406\u65B9\u5F0F\uFF1A\n");
1614
1639
  const choice = await new Enquirer.Select({
1615
1640
  message: "\u9009\u62E9\u5904\u7406\u65B9\u5F0F",
@@ -1659,7 +1684,7 @@ async function ensureOnMainWorkBranch(cwd) {
1659
1684
  return;
1660
1685
  }
1661
1686
  printWarning(MESSAGES.GUARD_BRANCH_MISMATCH(mainBranch, currentBranch));
1662
- const confirmed = await confirmAction("\u662F\u5426\u7EE7\u7EED\u6267\u884C\uFF1F");
1687
+ const confirmed = isNonInteractive() ? true : await confirmAction("\u662F\u5426\u7EE7\u7EED\u6267\u884C\uFF1F");
1663
1688
  if (!confirmed) {
1664
1689
  throw new ClawtError(MESSAGES.DESTRUCTIVE_OP_CANCELLED);
1665
1690
  }
@@ -2094,6 +2119,9 @@ import { statSync as statSync3 } from "fs";
2094
2119
  // src/utils/ui-prompts.ts
2095
2120
  import Enquirer3 from "enquirer";
2096
2121
  async function promptSelectBranch(worktrees, message) {
2122
+ if (isNonInteractive()) {
2123
+ throw new ClawtError("\u975E\u4EA4\u4E92\u6A21\u5F0F\u4E0B\u65E0\u6CD5\u8FDB\u884C\u5206\u652F\u9009\u62E9\uFF0C\u8BF7\u901A\u8FC7 -b \u53C2\u6570\u7CBE\u786E\u6307\u5B9A\u5206\u652F\u540D");
2124
+ }
2097
2125
  const selectedBranch = await new Enquirer3.Select({
2098
2126
  message,
2099
2127
  choices: worktrees.map((wt) => ({
@@ -2104,6 +2132,9 @@ async function promptSelectBranch(worktrees, message) {
2104
2132
  return worktrees.find((wt) => wt.branch === selectedBranch);
2105
2133
  }
2106
2134
  async function promptMultiSelectBranches(worktrees, message) {
2135
+ if (isNonInteractive()) {
2136
+ throw new ClawtError("\u975E\u4EA4\u4E92\u6A21\u5F0F\u4E0B\u65E0\u6CD5\u8FDB\u884C\u5206\u652F\u591A\u9009\uFF0C\u8BF7\u901A\u8FC7 -b \u53C2\u6570\u7CBE\u786E\u6307\u5B9A\u5206\u652F\u540D");
2137
+ }
2107
2138
  const branchChoices = worktrees.map((wt) => ({
2108
2139
  name: wt.branch,
2109
2140
  message: wt.branch
@@ -2143,6 +2174,9 @@ async function promptMultiSelectBranches(worktrees, message) {
2143
2174
  return worktrees.filter((wt) => selectedBranches.includes(wt.branch));
2144
2175
  }
2145
2176
  async function promptGroupedMultiSelectBranches(worktrees, message) {
2177
+ if (isNonInteractive()) {
2178
+ throw new ClawtError("\u975E\u4EA4\u4E92\u6A21\u5F0F\u4E0B\u65E0\u6CD5\u8FDB\u884C\u5206\u652F\u591A\u9009\uFF0C\u8BF7\u901A\u8FC7 -b \u53C2\u6570\u7CBE\u786E\u6307\u5B9A\u5206\u652F\u540D");
2179
+ }
2146
2180
  const groups = groupWorktreesByDate(worktrees);
2147
2181
  const choices = buildGroupedChoices(groups);
2148
2182
  const groupMembershipMap = buildGroupMembershipMap(groups);
@@ -3150,6 +3184,9 @@ function formatConfigValue(value) {
3150
3184
  return chalk7.cyan(String(value));
3151
3185
  }
3152
3186
  async function interactiveConfigEditor(config2, definitions, options) {
3187
+ if (isNonInteractive()) {
3188
+ throw new ClawtError("\u975E\u4EA4\u4E92\u6A21\u5F0F\u4E0B\u65E0\u6CD5\u4F7F\u7528\u4EA4\u4E92\u5F0F\u914D\u7F6E\u7F16\u8F91\u5668\uFF0C\u8BF7\u4F7F\u7528 clawt config set <key> <value>");
3189
+ }
3153
3190
  const keys = Object.keys(definitions);
3154
3191
  const disabledKeys = options?.disabledKeys ?? {};
3155
3192
  const configRecord = config2;
@@ -4920,7 +4957,7 @@ async function handleSquashIfNeeded(targetWorktreePath, mainWorktreePath, branch
4920
4957
  if (!hasCommitWithMessage(branchName, AUTO_SAVE_COMMIT_MESSAGE, mainWorktreePath)) {
4921
4958
  return false;
4922
4959
  }
4923
- const shouldSquash = await confirmAction(MESSAGES.MERGE_SQUASH_PROMPT);
4960
+ const shouldSquash = await confirmAction(MESSAGES.MERGE_SQUASH_PROMPT, false);
4924
4961
  if (!shouldSquash) {
4925
4962
  return false;
4926
4963
  }
@@ -4942,7 +4979,7 @@ async function shouldCleanupAfterMerge(branchName) {
4942
4979
  printInfo(`\u5DF2\u914D\u7F6E\u81EA\u52A8\u5220\u9664\uFF0Cmerge \u6210\u529F\u540E\u5C06\u81EA\u52A8\u6E05\u7406 worktree \u548C\u5206\u652F: ${branchName}`);
4943
4980
  return true;
4944
4981
  }
4945
- return confirmAction(`\u662F\u5426\u5220\u9664\u5BF9\u5E94\u7684 worktree \u548C\u5206\u652F (${branchName})\uFF1F`);
4982
+ return confirmAction(`\u662F\u5426\u5220\u9664\u5BF9\u5E94\u7684 worktree \u548C\u5206\u652F (${branchName})\uFF1F`, true);
4946
4983
  }
4947
4984
  function cleanupWorktreeAndBranch(worktreePath, branchName) {
4948
4985
  cleanupWorktrees([{ path: worktreePath, branch: branchName }]);
@@ -5914,11 +5951,14 @@ var require2 = createRequire(import.meta.url);
5914
5951
  var { version } = require2("../package.json");
5915
5952
  ensureClawtDirs();
5916
5953
  var program = new Command();
5917
- program.name("clawt").description("\u672C\u5730\u5E76\u884C\u6267\u884C\u591A\u4E2AClaude Code Agent\u4EFB\u52A1\uFF0C\u878D\u5408 Git Worktree \u4E0E Claude Code CLI \u7684\u547D\u4EE4\u884C\u5DE5\u5177").version(version).option("--debug", "\u8F93\u51FA\u8BE6\u7EC6\u8C03\u8BD5\u4FE1\u606F\u5230\u7EC8\u7AEF");
5954
+ program.name("clawt").description("\u672C\u5730\u5E76\u884C\u6267\u884C\u591A\u4E2AClaude Code Agent\u4EFB\u52A1\uFF0C\u878D\u5408 Git Worktree \u4E0E Claude Code CLI \u7684\u547D\u4EE4\u884C\u5DE5\u5177").version(version).option("--debug", "\u8F93\u51FA\u8BE6\u7EC6\u8C03\u8BD5\u4FE1\u606F\u5230\u7EC8\u7AEF").option("-y, --yes", "\u8DF3\u8FC7\u6240\u6709\u4EA4\u4E92\u5F0F\u786E\u8BA4\uFF0C\u9002\u7528\u4E8E\u811A\u672C/CI \u73AF\u5883");
5918
5955
  program.hook("preAction", (thisCommand) => {
5919
5956
  if (thisCommand.opts().debug) {
5920
5957
  enableConsoleTransport();
5921
5958
  }
5959
+ if (thisCommand.opts().yes) {
5960
+ setNonInteractive(true);
5961
+ }
5922
5962
  });
5923
5963
  registerListCommand(program);
5924
5964
  registerCreateCommand(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawt",
3
- "version": "3.6.2",
3
+ "version": "3.7.0",
4
4
  "description": "本地并行执行多个Claude Code Agent任务,融合 Git Worktree 与 Claude Code CLI 的命令行工具",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -82,8 +82,8 @@ async function handleSquashIfNeeded(
82
82
  return false;
83
83
  }
84
84
 
85
- // 提示用户是否压缩
86
- const shouldSquash = await confirmAction(MESSAGES.MERGE_SQUASH_PROMPT);
85
+ // 提示用户是否压缩(非交互模式下默认跳过,保留原始提交)
86
+ const shouldSquash = await confirmAction(MESSAGES.MERGE_SQUASH_PROMPT, false);
87
87
  if (!shouldSquash) {
88
88
  return false;
89
89
  }
@@ -120,7 +120,8 @@ async function shouldCleanupAfterMerge(branchName: string): Promise<boolean> {
120
120
  printInfo(`已配置自动删除,merge 成功后将自动清理 worktree 和分支: ${branchName}`);
121
121
  return true;
122
122
  }
123
- return confirmAction(`是否删除对应的 worktree 和分支 (${branchName})?`);
123
+ // 非交互模式下自动删除
124
+ return confirmAction(`是否删除对应的 worktree 和分支 (${branchName})?`, true);
124
125
  }
125
126
 
126
127
  /**
@@ -100,6 +100,7 @@ async function handleRemove(options: RemoveOptions): Promise<void> {
100
100
  let shouldDeleteBranch = autoDelete;
101
101
 
102
102
  if (!autoDelete) {
103
+ // 非交互模式下默认删除分支(删除 worktree 时分支通常也不再需要)
103
104
  shouldDeleteBranch = await confirmAction(MESSAGES.REMOVE_CONFIRM_DELETE_BRANCHES);
104
105
  if (!shouldDeleteBranch) {
105
106
  printHint(MESSAGES.REMOVE_BRANCHES_KEPT);
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@ import { Command } from 'commander';
3
3
  import { ClawtError } from './errors/index.js';
4
4
  import { logger, enableConsoleTransport } from './logger/index.js';
5
5
  import { EXIT_CODES } from './constants/index.js';
6
- import { printError, ensureClawtDirs, loadConfig, applyAliases, checkForUpdates } from './utils/index.js';
6
+ import { printError, ensureClawtDirs, loadConfig, applyAliases, checkForUpdates, setNonInteractive } from './utils/index.js';
7
7
  import { registerListCommand } from './commands/list.js';
8
8
  import { registerCreateCommand } from './commands/create.js';
9
9
  import { registerRemoveCommand } from './commands/remove.js';
@@ -36,13 +36,18 @@ program
36
36
  .name('clawt')
37
37
  .description('本地并行执行多个Claude Code Agent任务,融合 Git Worktree 与 Claude Code CLI 的命令行工具')
38
38
  .version(version)
39
- .option('--debug', '输出详细调试信息到终端');
39
+ .option('--debug', '输出详细调试信息到终端')
40
+ .option('-y, --yes', '跳过所有交互式确认,适用于脚本/CI 环境');
40
41
 
41
42
  // 在子命令 action 执行前检查 --debug 选项,按需启用控制台日志
42
43
  program.hook('preAction', (thisCommand) => {
43
44
  if (thisCommand.opts().debug) {
44
45
  enableConsoleTransport();
45
46
  }
47
+ // 检测 --yes 选项,启用非交互模式
48
+ if (thisCommand.opts().yes) {
49
+ setNonInteractive(true);
50
+ }
46
51
  });
47
52
 
48
53
  // 注册所有命令
@@ -2,6 +2,8 @@ import chalk from 'chalk';
2
2
  import Enquirer from 'enquirer';
3
3
  import { DEFAULT_CONFIG, CONFIG_DEFINITIONS, MESSAGES } from '../constants/index.js';
4
4
  import type { ClawtConfig } from '../types/index.js';
5
+ import { isNonInteractive } from './interactive.js';
6
+ import { ClawtError } from '../errors/index.js';
5
7
 
6
8
  /**
7
9
  * 校验 key 是否为有效的配置项名称
@@ -132,6 +134,11 @@ export async function interactiveConfigEditor<T extends object>(
132
134
  definitions: Record<string, { description: string; allowedValues?: readonly string[] }>,
133
135
  options?: { selectPrompt?: string; disabledKeys?: Record<string, string> },
134
136
  ): Promise<{ key: keyof T; newValue: unknown }> {
137
+ // 非交互模式下无法进行配置编辑,引导使用 config set 命令
138
+ if (isNonInteractive()) {
139
+ throw new ClawtError('非交互模式下无法使用交互式配置编辑器,请使用 clawt config set <key> <value>');
140
+ }
141
+
135
142
  const keys = Object.keys(definitions);
136
143
  const disabledKeys = options?.disabledKeys ?? {};
137
144
  const configRecord = config as Record<string, unknown>;
@@ -162,7 +162,7 @@ export async function handleMergeConflict(
162
162
  return resolveConflictsWithAI(currentBranch, incomingBranch, cwd);
163
163
  }
164
164
 
165
- // mode === 'ask'
165
+ // mode === 'ask'(非交互模式下默认使用 AI 解决,因为无法手动解决)
166
166
  const shouldUseAI = await confirmAction(MESSAGES.MERGE_CONFLICT_ASK_AI);
167
167
  if (!shouldUseAI) {
168
168
  throw new ClawtError(MESSAGES.MERGE_CONFLICT_MANUAL);
@@ -2,6 +2,7 @@ import chalk from 'chalk';
2
2
  import { MESSAGES } from '../constants/index.js';
3
3
  import { createInterface } from 'node:readline';
4
4
  import type { WorktreeStatus } from '../types/index.js';
5
+ import { isNonInteractive } from './interactive.js';
5
6
 
6
7
  /**
7
8
  * 输出成功信息
@@ -58,11 +59,17 @@ export function printDoubleSeparator(): void {
58
59
  }
59
60
 
60
61
  /**
61
- * 简易 yes/no 确认(非交互式场景使用)
62
+ * 简易 yes/no 确认
63
+ * 非交互模式下根据 nonInteractiveDefault 参数自动返回默认值
62
64
  * @param {string} question - 确认问题
65
+ * @param {boolean} [nonInteractiveDefault=true] - 非交互模式下的默认返回值,true 表示自动确认,false 表示自动拒绝
63
66
  * @returns {Promise<boolean>} 用户是否确认
64
67
  */
65
- export function confirmAction(question: string): Promise<boolean> {
68
+ export function confirmAction(question: string, nonInteractiveDefault: boolean = true): Promise<boolean> {
69
+ // 非交互模式下返回调用方声明的默认值
70
+ if (isNonInteractive()) {
71
+ return Promise.resolve(nonInteractiveDefault);
72
+ }
66
73
  return new Promise((resolve) => {
67
74
  const rl = createInterface({
68
75
  input: process.stdin,
@@ -82,6 +82,7 @@ export { checkForUpdates } from './update-checker.js';
82
82
  export { getProjectConfigPath, loadProjectConfig, saveProjectConfig, requireProjectConfig, getMainWorkBranch, guardMainWorkBranchExists, getValidateRunCommand } from './project-config.js';
83
83
  export { getValidateBranchName, createValidateBranch, deleteValidateBranch, rebuildValidateBranch, ensureOnMainWorkBranch, handleDirtyWorkingDir } from './validate-branch.js';
84
84
  export { safeStringify } from './json.js';
85
+ export { isNonInteractive, setNonInteractive } from './interactive.js';
85
86
  export { executeRunCommand } from './validate-runner.js';
86
87
  export { migrateChangesViaPatch, computeCurrentTreeHash, saveCurrentSnapshotTree, loadOldSnapshotToStage, switchToValidateBranch } from './validate-core.js';
87
88
  export { InteractivePanel } from './interactive-panel.js';
@@ -0,0 +1,27 @@
1
+ /**
2
+ * 非交互模式判断工具
3
+ * 优先级:CLI --yes > 环境变量 CI / CLAWT_NON_INTERACTIVE > 默认交互模式
4
+ */
5
+
6
+ /** 运行时标志,由 --yes 全局选项在 preAction hook 中设置 */
7
+ let nonInteractiveFlag = false;
8
+
9
+ /**
10
+ * 设置非交互模式运行时标志
11
+ * @param {boolean} value - 是否启用非交互模式
12
+ */
13
+ export function setNonInteractive(value: boolean): void {
14
+ nonInteractiveFlag = value;
15
+ }
16
+
17
+ /**
18
+ * 判断当前是否处于非交互模式
19
+ * 检查顺序:运行时标志(--yes)→ CI 环境变量 → CLAWT_NON_INTERACTIVE 环境变量
20
+ * @returns {boolean} 是否为非交互模式
21
+ */
22
+ export function isNonInteractive(): boolean {
23
+ if (nonInteractiveFlag) return true;
24
+ if (process.env.CI === 'true' || process.env.CI === '1') return true;
25
+ if (process.env.CLAWT_NON_INTERACTIVE === 'true' || process.env.CLAWT_NON_INTERACTIVE === '1') return true;
26
+ return false;
27
+ }
@@ -5,6 +5,8 @@ import {
5
5
  } from '../constants/index.js';
6
6
  import type { WorktreeInfo } from '../types/index.js';
7
7
  import { groupWorktreesByDate, buildGroupedChoices, buildGroupMembershipMap } from './worktree-matcher.js';
8
+ import { isNonInteractive } from './interactive.js';
9
+ import { ClawtError } from '../errors/index.js';
8
10
 
9
11
  /** enquirer MultiSelect 选项条目的运行时结构 */
10
12
  export interface MultiSelectChoice {
@@ -41,6 +43,10 @@ export type GroupedChoice = { name: string; message: string } | MultiSelectSepar
41
43
  * @returns {Promise<WorktreeInfo>} 用户选择的 worktree
42
44
  */
43
45
  export async function promptSelectBranch(worktrees: WorktreeInfo[], message: string): Promise<WorktreeInfo> {
46
+ // 非交互模式下无法进行交互选择,要求用户通过 -b 精确指定
47
+ if (isNonInteractive()) {
48
+ throw new ClawtError('非交互模式下无法进行分支选择,请通过 -b 参数精确指定分支名');
49
+ }
44
50
  // @ts-expect-error enquirer 类型声明未导出 Select 类,但运行时存在
45
51
  const selectedBranch: string = await new Enquirer.Select({
46
52
  message,
@@ -62,6 +68,10 @@ export async function promptSelectBranch(worktrees: WorktreeInfo[], message: str
62
68
  * @returns {Promise<WorktreeInfo[]>} 用户选择的 worktree 列表
63
69
  */
64
70
  export async function promptMultiSelectBranches(worktrees: WorktreeInfo[], message: string): Promise<WorktreeInfo[]> {
71
+ // 非交互模式下无法进行交互多选,要求用户通过 -b 精确指定
72
+ if (isNonInteractive()) {
73
+ throw new ClawtError('非交互模式下无法进行分支多选,请通过 -b 参数精确指定分支名');
74
+ }
65
75
  // 构建 choices 列表,顶部插入全选选项
66
76
  const branchChoices = worktrees.map((wt) => ({
67
77
  name: wt.branch,
@@ -131,6 +141,10 @@ export async function promptGroupedMultiSelectBranches(
131
141
  worktrees: WorktreeInfo[],
132
142
  message: string,
133
143
  ): Promise<WorktreeInfo[]> {
144
+ // 非交互模式下无法进行交互多选,要求用户通过 -b 精确指定
145
+ if (isNonInteractive()) {
146
+ throw new ClawtError('非交互模式下无法进行分支多选,请通过 -b 参数精确指定分支名');
147
+ }
134
148
  const groups = groupWorktreesByDate(worktrees);
135
149
  const choices = buildGroupedChoices(groups);
136
150
  const groupMembershipMap = buildGroupMembershipMap(groups);
@@ -5,6 +5,7 @@ import { checkBranchExists, createBranch, deleteBranch, getCurrentBranch, gitChe
5
5
  import { getMainWorkBranch } from './project-config.js';
6
6
  import { printWarning, confirmAction } from './formatter.js';
7
7
  import { ClawtError } from '../errors/index.js';
8
+ import { isNonInteractive } from './interactive.js';
8
9
 
9
10
  /**
10
11
  * 生成验证分支名
@@ -88,6 +89,16 @@ export async function rebuildValidateBranch(branchName: string, cwd?: string): P
88
89
  * @param {string} [cwd] - 工作目录
89
90
  */
90
91
  export async function handleDirtyWorkingDir(cwd?: string): Promise<void> {
92
+ // 非交互模式下默认执行 stash(安全策略,不丢弃代码)
93
+ if (isNonInteractive()) {
94
+ gitAddAll(cwd);
95
+ gitStashPush('clawt:auto-stash', cwd);
96
+ if (!isWorkingDirClean(cwd)) {
97
+ throw new ClawtError('工作区仍然不干净,请手动处理');
98
+ }
99
+ return;
100
+ }
101
+
91
102
  printWarning('当前分支有未提交的更改,请选择处理方式:\n');
92
103
 
93
104
  // @ts-expect-error enquirer 类型声明未导出 Select 类,但运行时存在
@@ -159,7 +170,8 @@ export async function ensureOnMainWorkBranch(cwd?: string): Promise<void> {
159
170
 
160
171
  // 当前在其他分支上,警告并确认后处理脏工作区再切换
161
172
  printWarning(MESSAGES.GUARD_BRANCH_MISMATCH(mainBranch, currentBranch));
162
- const confirmed = await confirmAction('是否继续执行?');
173
+ // 非交互模式下自动确认继续
174
+ const confirmed = isNonInteractive() ? true : await confirmAction('是否继续执行?');
163
175
  if (!confirmed) {
164
176
  throw new ClawtError(MESSAGES.DESTRUCTIVE_OP_CANCELLED);
165
177
  }
@@ -50,6 +50,7 @@ vi.mock('../../../src/utils/index.js', () => ({
50
50
  confirmAction: vi.fn().mockResolvedValue(true),
51
51
  guardMainWorkBranch: vi.fn().mockResolvedValue(undefined),
52
52
  guardMainWorkBranchExists: vi.fn(),
53
+ isNonInteractive: vi.fn().mockReturnValue(false),
53
54
  }));
54
55
 
55
56
  import { registerCoverValidateCommand, extractTargetBranchName, findTargetWorktreePath, computeIncrementalPatch } from '../../../src/commands/cover-validate.js';
@@ -78,6 +78,7 @@ vi.mock('../../../src/utils/index.js', () => ({
78
78
  guardMainWorkBranch: vi.fn().mockResolvedValue(undefined),
79
79
  guardMainWorkBranchExists: vi.fn(),
80
80
  handleMergeConflict: vi.fn(),
81
+ isNonInteractive: vi.fn().mockReturnValue(false),
81
82
  }));
82
83
 
83
84
  import { registerMergeCommand } from '../../../src/commands/merge.js';
@@ -56,6 +56,7 @@ vi.mock('../../../src/utils/index.js', () => ({
56
56
  getCurrentBranch: vi.fn(),
57
57
  guardMainWorkBranch: vi.fn().mockResolvedValue(undefined),
58
58
  guardMainWorkBranchExists: vi.fn(),
59
+ isNonInteractive: vi.fn().mockReturnValue(false),
59
60
  }));
60
61
 
61
62
  import { registerRemoveCommand } from '../../../src/commands/remove.js';