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 +9 -3
- package/docs/post-create-hook.md +5 -1
- package/docs/run.md +2 -1
- package/package.json +1 -1
- package/src/constants/config.ts +4 -0
- package/src/constants/index.ts +1 -1
- package/src/utils/claude.ts +7 -3
- package/src/utils/task-executor.ts +5 -1
- package/tests/unit/utils/claude.test.ts +9 -6
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
|
|
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
|
}
|
package/docs/post-create-hook.md
CHANGED
|
@@ -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
package/src/constants/config.ts
CHANGED
|
@@ -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 恢复
|
package/src/constants/index.ts
CHANGED
|
@@ -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';
|
package/src/utils/claude.ts
CHANGED
|
@@ -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.
|
|
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('
|
|
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
|
-
|
|
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('
|
|
341
|
+
it('固定使用 APPEND_SYSTEM_PROMPT 作为系统提示', () => {
|
|
339
342
|
mockedGetConfigValue.mockReturnValue('claude');
|
|
340
343
|
|
|
341
344
|
const cmd = buildClaudeCommand(worktree, false);
|
|
342
345
|
|
|
343
|
-
expect(cmd).
|
|
346
|
+
expect(cmd).toContain(APPEND_SYSTEM_PROMPT);
|
|
344
347
|
});
|
|
345
348
|
|
|
346
349
|
it('路径中的单引号被正确转义', () => {
|