clawt 3.9.9 → 3.9.10

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
@@ -704,6 +704,7 @@ var VALID_TERMINAL_APPS = ["auto", "iterm2", "terminal", "cmux"];
704
704
  var ITERM2_APP_PATH = "/Applications/iTerm.app";
705
705
 
706
706
  // src/constants/config.ts
707
+ var APPEND_SYSTEM_PROMPT = "Currently, you are in the git worktree directory.";
707
708
  var CLAUDE_CODE_ENTRYPOINT_VALUE = "cli";
708
709
  var CONFIG_DEFINITIONS = {
709
710
  autoDeleteBranch: {
@@ -2299,7 +2300,9 @@ function launchInteractiveClaude(worktree, options = {}) {
2299
2300
  const parts = commandStr.split(/\s+/).filter(Boolean);
2300
2301
  const cmd = parts[0];
2301
2302
  const args = [
2302
- ...parts.slice(1)
2303
+ ...parts.slice(1),
2304
+ "--append-system-prompt",
2305
+ APPEND_SYSTEM_PROMPT
2303
2306
  ];
2304
2307
  const hasPreviousSession = options.autoContinue === true && hasClaudeSessionHistory(worktree.path);
2305
2308
  if (hasPreviousSession) {
@@ -2329,9 +2332,11 @@ function escapeShellSingleQuote(str) {
2329
2332
  }
2330
2333
  function buildClaudeCommand(worktree, hasPreviousSession) {
2331
2334
  const commandStr = resolveClaudeCodeCommand();
2335
+ const systemPrompt = APPEND_SYSTEM_PROMPT;
2332
2336
  const escapedPath = escapeShellSingleQuote(worktree.path);
2337
+ const escapedPrompt = escapeShellSingleQuote(systemPrompt);
2333
2338
  const continueFlag = hasPreviousSession ? " --continue" : "";
2334
- return `cd '${escapedPath}' && ${commandStr}${continueFlag}`;
2339
+ return `cd '${escapedPath}' && ${commandStr} --append-system-prompt '${escapedPrompt}'${continueFlag}`;
2335
2340
  }
2336
2341
  function launchInteractiveClaudeInNewTerminal(worktree, hasPreviousSession) {
2337
2342
  const command = buildClaudeCommand(worktree, hasPreviousSession);
@@ -3107,7 +3112,8 @@ function parseStreamEvent(event) {
3107
3112
 
3108
3113
  // src/utils/task-executor.ts
3109
3114
  function executeClaudeTask(worktree, task, onActivity, continueSession) {
3110
- const args = ["-p", task, "--output-format", "stream-json", "--verbose", "--permission-mode", "bypassPermissions"];
3115
+ const systemPrompt = APPEND_SYSTEM_PROMPT;
3116
+ const args = ["-p", task, "--output-format", "stream-json", "--verbose", "--permission-mode", "bypassPermissions", "--append-system-prompt", systemPrompt];
3111
3117
  if (continueSession) {
3112
3118
  args.push("--continue");
3113
3119
  }
@@ -4,7 +4,7 @@
4
4
 
5
5
  postCreate hook 是在 worktree 创建完成后自动执行的钩子命令,可用于执行任意初始化操作(如安装依赖、生成配置文件、编译资源等)。`create` 和 `run` 命令在创建 worktree 之后,会尝试解析并执行 postCreate hook。
6
6
 
7
- hook 以 **fire-and-forget** 模式后台异步并行执行,不阻塞主流程(不 await)。执行结果仅写入日志,不影响后续 Claude Code 的启动。
7
+ hook 以 **fire-and-forget** 模式后台异步并行执行,不阻塞主流程(不 await)。执行结果仅写入日志,不影响后续 Claude Code 的启动或系统提示。
8
8
 
9
9
  #### 配置方式
10
10
 
@@ -100,6 +100,10 @@ clawt run -b feat --no-post-create
100
100
  - **结果汇总**:后台执行完毕后通过 `.then()` 回调写入日志汇总(成功数 + 失败数)
101
101
  - **返回值**:`runPostCreateHooks()` 返回 `void`——以 fire-and-forget 模式后台执行,不等待结果
102
102
 
103
+ #### 系统提示
104
+
105
+ Claude Code 启动时统一使用 `APPEND_SYSTEM_PROMPT` 常量(定义在 `src/constants/config.ts`)作为 `--append-system-prompt` 参数值,内容为通用的 worktree 目录提示,不因 hook 执行结果而变化。
106
+
103
107
  #### 相关类型定义
104
108
 
105
109
  类型定义位于 `src/types/postCreateHook.ts`:
package/docs/run.md CHANGED
@@ -86,8 +86,9 @@ clawt run -b <branchName>
86
86
  5. 通过公共函数 `executeBatchTasks`(`src/utils/task-executor.ts`)启动批量任务执行,该函数负责进度面板渲染、SIGINT 中断处理、并发控制和汇总输出。对每个 worktree 并行启动 Claude Code CLI:
87
87
  ```bash
88
88
  cd ~/.clawt/worktrees/<project>/<branchName>-<i>
89
- claude -p "<tasks[i]>" --output-format stream-json --verbose --permission-mode bypassPermissions
89
+ claude -p "<tasks[i]>" --output-format stream-json --verbose --permission-mode bypassPermissions --append-system-prompt "<系统提示>"
90
90
  ```
91
+ 其中 `--append-system-prompt` 使用统一的 `APPEND_SYSTEM_PROMPT` 常量(定义在 `src/constants/config.ts`)。
91
92
  子进程通过 `spawnProcess()`(`src/utils/shell.ts`)启动,会自动注入环境变量 `CLAUDE_CODE_ENTRYPOINT="cli"`(通过 `getEnvWithoutNestedSessionFlag()` 函数),使会话支持通过 `--continue` 恢复。
92
93
  使用 `stream-json` 格式可实时获取 Claude Code 的流式事件(工具调用、文本输出、最终结果),用于在进度面板中显示每个任务的实时活动描述和结果预览。流式事件解析由 `src/utils/stream-parser.ts` 负责。
93
94
  6. 进入**事件监听通知**阶段(见 [5.3](#53-任务完成通知机制))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawt",
3
- "version": "3.9.9",
3
+ "version": "3.9.10",
4
4
  "description": "本地并行执行多个Claude Code Agent任务,融合 Git Worktree 与 Claude Code CLI 的命令行工具",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,10 @@
1
1
  import type { ClawtConfig, ConfigDefinitions } from '../types/index.js';
2
2
  import { VALID_TERMINAL_APPS } from './terminal.js';
3
3
 
4
+ /** Claude Code 系统约束提示 */
5
+ export const APPEND_SYSTEM_PROMPT =
6
+ 'Currently, you are in the git worktree directory.';
7
+
4
8
  /**
5
9
  * 通过 clawt 启动的 Claude Code 非交互式会话(claude -p)的 entrypoint 标识
6
10
  * 设置为 'cli' 使 claude -p 启动的会话可以通过 --continue 恢复
@@ -5,7 +5,7 @@ export { CONFIG_ALIAS_DISABLED_HINT } from './messages/index.js';
5
5
  export { UPDATE_MESSAGES, UPDATE_COMMANDS } from './messages/update.js';
6
6
  export { EXIT_CODES } from './exitCodes.js';
7
7
  export { ENABLE_BRACKETED_PASTE, DISABLE_BRACKETED_PASTE, PASTE_THRESHOLD_MS, VALID_TERMINAL_APPS, ITERM2_APP_PATH } from './terminal.js';
8
- export { DEFAULT_CONFIG, CONFIG_DESCRIPTIONS, CONFIG_DEFINITIONS, CLAUDE_CODE_ENTRYPOINT_VALUE } from './config.js';
8
+ export { DEFAULT_CONFIG, CONFIG_DESCRIPTIONS, CONFIG_DEFINITIONS, APPEND_SYSTEM_PROMPT, CLAUDE_CODE_ENTRYPOINT_VALUE } from './config.js';
9
9
  export { PROJECT_CONFIG_DEFINITIONS, PROJECT_DEFAULT_CONFIG, PROJECT_CONFIG_DESCRIPTIONS } from './project-config.js';
10
10
  export { AUTO_SAVE_COMMIT_MESSAGE_PREFIX } from './git.js';
11
11
  export { DEBUG_LOG_PREFIX, DEBUG_TIMESTAMP_FORMAT } from './logger.js';
@@ -2,7 +2,7 @@ import { spawnSync } from 'node:child_process';
2
2
  import { existsSync, readdirSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { ClawtError } from '../errors/index.js';
5
- import { CLAUDE_PROJECTS_DIR } from '../constants/index.js';
5
+ import { APPEND_SYSTEM_PROMPT, CLAUDE_PROJECTS_DIR } from '../constants/index.js';
6
6
  import { resolveClaudeCodeCommand } from './project-config.js';
7
7
  import { printInfo, printWarning } from './formatter.js';
8
8
  import { openCommandInNewTerminalTab } from './terminal.js';
@@ -56,6 +56,8 @@ export function launchInteractiveClaude(worktree: WorktreeInfo, options: LaunchC
56
56
  const cmd = parts[0];
57
57
  const args = [
58
58
  ...parts.slice(1),
59
+ '--append-system-prompt',
60
+ APPEND_SYSTEM_PROMPT,
59
61
  ];
60
62
 
61
63
  // 仅在启用 autoContinue 时检测历史会话并追加 --continue
@@ -99,18 +101,20 @@ function escapeShellSingleQuote(str: string): string {
99
101
 
100
102
  /**
101
103
  * 构建在指定 worktree 中启动 Claude Code 的完整 shell 命令
102
- * 生成格式:cd <path> && <claudeCommand> [--continue]
104
+ * 生成格式:cd <path> && <claudeCommand> --append-system-prompt '...' [--continue]
103
105
  * @param {WorktreeInfo} worktree - worktree 信息
104
106
  * @param {boolean} hasPreviousSession - 是否存在历史会话(由调用方预计算,避免重复 I/O)
105
107
  * @returns {string} 完整的 shell 命令字符串
106
108
  */
107
109
  export function buildClaudeCommand(worktree: WorktreeInfo, hasPreviousSession: boolean): string {
108
110
  const commandStr = resolveClaudeCodeCommand();
111
+ const systemPrompt = APPEND_SYSTEM_PROMPT;
109
112
 
110
113
  const escapedPath = escapeShellSingleQuote(worktree.path);
114
+ const escapedPrompt = escapeShellSingleQuote(systemPrompt);
111
115
  const continueFlag = hasPreviousSession ? ' --continue' : '';
112
116
 
113
- return `cd '${escapedPath}' && ${commandStr}${continueFlag}`;
117
+ return `cd '${escapedPath}' && ${commandStr} --append-system-prompt '${escapedPrompt}'${continueFlag}`;
114
118
  }
115
119
 
116
120
  /**
@@ -5,6 +5,7 @@ import type { ClaudeCodeResult, TaskResult, TaskSummary, WorktreeInfo } from '..
5
5
  import { spawnProcess, killAllChildProcesses } from './shell.js';
6
6
  import { cleanupWorktrees } from './worktree.js';
7
7
  import { getConfigValue } from './config.js';
8
+ import { APPEND_SYSTEM_PROMPT } from '../constants/index.js';
8
9
  import { printSuccess, printWarning, printInfo, printDoubleSeparator, confirmAction } from './formatter.js';
9
10
  import { ProgressRenderer } from './progress.js';
10
11
  import { createLineBuffer, parseStreamLine, parseStreamEvent, truncateText } from './stream-parser.js';
@@ -34,8 +35,11 @@ type ActivityCallback = (activityText: string) => void;
34
35
  * @returns {ClaudeTaskHandle} 包含子进程引用和结果 Promise
35
36
  */
36
37
  function executeClaudeTask(worktree: WorktreeInfo, task: string, onActivity?: ActivityCallback, continueSession?: boolean): ClaudeTaskHandle {
38
+ // 使用统一的系统提示常量
39
+ const systemPrompt = APPEND_SYSTEM_PROMPT;
40
+
37
41
  // 旧版使用 --output-format json,现改为 stream-json --verbose 以支持实时活动信息
38
- const args = ['-p', task, '--output-format', 'stream-json', '--verbose', '--permission-mode', 'bypassPermissions'];
42
+ const args = ['-p', task, '--output-format', 'stream-json', '--verbose', '--permission-mode', 'bypassPermissions', '--append-system-prompt', systemPrompt];
39
43
 
40
44
  // 追问模式:追加 --continue 继续该目录下最新会话
41
45
  if (continueSession) {
@@ -33,6 +33,7 @@ import { launchInteractiveClaude, hasClaudeSessionHistory, buildClaudeCommand }
33
33
  import { getConfigValue } from '../../../src/utils/config.js';
34
34
  import { printInfo, printWarning } from '../../../src/utils/formatter.js';
35
35
  import { ClawtError } from '../../../src/errors/index.js';
36
+ import { APPEND_SYSTEM_PROMPT } from '../../../src/constants/config.js';
36
37
  import { createWorktreeInfo } from '../../helpers/fixtures.js';
37
38
 
38
39
  const mockedSpawnSync = vi.mocked(spawnSync);
@@ -103,7 +104,7 @@ describe('launchInteractiveClaude', () => {
103
104
  expect(mockedGetConfigValue).toHaveBeenCalledWith('claudeCodeCommand');
104
105
  expect(mockedSpawnSync).toHaveBeenCalledWith(
105
106
  'claude',
106
- expect.any(Array),
107
+ expect.arrayContaining(['--append-system-prompt']),
107
108
  expect.objectContaining({
108
109
  cwd: '/tmp/test-worktree',
109
110
  stdio: 'inherit',
@@ -147,7 +148,7 @@ describe('launchInteractiveClaude', () => {
147
148
 
148
149
  expect(mockedSpawnSync).toHaveBeenCalledWith(
149
150
  'npx',
150
- expect.arrayContaining(['claude']),
151
+ expect.arrayContaining(['claude', '--append-system-prompt']),
151
152
  expect.any(Object),
152
153
  );
153
154
  });
@@ -284,7 +285,7 @@ describe('launchInteractiveClaude', () => {
284
285
  expect(callArgs).not.toContain('--continue');
285
286
  });
286
287
 
287
- it('不包含 --append-system-prompt 参数', () => {
288
+ it('固定使用 APPEND_SYSTEM_PROMPT 作为系统提示', () => {
288
289
  mockedGetConfigValue.mockReturnValue('claude');
289
290
  mockedExistsSync.mockReturnValue(false);
290
291
  mockedSpawnSync.mockReturnValue({
@@ -300,7 +301,8 @@ describe('launchInteractiveClaude', () => {
300
301
  launchInteractiveClaude(worktree);
301
302
 
302
303
  const callArgs = mockedSpawnSync.mock.calls[0][1] as string[];
303
- expect(callArgs).not.toContain('--append-system-prompt');
304
+ const promptIndex = callArgs.indexOf('--append-system-prompt');
305
+ expect(callArgs[promptIndex + 1]).toBe(APPEND_SYSTEM_PROMPT);
304
306
  });
305
307
  });
306
308
 
@@ -317,6 +319,7 @@ describe('buildClaudeCommand', () => {
317
319
 
318
320
  expect(cmd).toContain("cd '/tmp/test-worktree'");
319
321
  expect(cmd).toContain('claude');
322
+ expect(cmd).toContain('--append-system-prompt');
320
323
  });
321
324
 
322
325
  it('hasPreviousSession 为 true 时包含 --continue', () => {
@@ -335,12 +338,12 @@ describe('buildClaudeCommand', () => {
335
338
  expect(cmd).not.toContain('--continue');
336
339
  });
337
340
 
338
- it('不包含 --append-system-prompt 参数', () => {
341
+ it('固定使用 APPEND_SYSTEM_PROMPT 作为系统提示', () => {
339
342
  mockedGetConfigValue.mockReturnValue('claude');
340
343
 
341
344
  const cmd = buildClaudeCommand(worktree, false);
342
345
 
343
- expect(cmd).not.toContain('--append-system-prompt');
346
+ expect(cmd).toContain(APPEND_SYSTEM_PROMPT);
344
347
  });
345
348
 
346
349
  it('路径中的单引号被正确转义', () => {