chatccc 0.2.139 → 0.2.140
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/agent-prompts/claude_specific.md +0 -10
- package/agent-prompts/codex_specific.md +0 -1
- package/agent-prompts/cursor_specific.md +0 -1
- package/package.json +1 -1
- package/src/__tests__/claude-adapter.test.ts +31 -1
- package/src/adapters/claude-adapter.ts +62 -12
- package/src/orchestrator.ts +8 -10
- package/src/session.ts +9 -3
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
# Claude-Specific Injection Prompt
|
|
2
|
-
|
|
3
|
-
Use this prompt as the Claude Agent SDK injection prompt for this project.
|
|
4
|
-
|
|
5
|
-
Project workspace:
|
|
6
|
-
|
|
7
|
-
```text
|
|
8
|
-
f:\users\weizhangjian\feishuclauderprivate
|
|
9
|
-
```
|
|
10
|
-
|
|
11
1
|
## Repeated Successful Command Guard
|
|
12
2
|
|
|
13
3
|
When working in this project through Claude Agent SDK, repeated successful shell commands are a completion signal, not a reason to keep using tools.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
如果计划写好了等待你的审阅,将计划文件通过当前聊天软件发给用户
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
如果计划写好了等待你的审阅,将计划文件通过当前聊天软件发给用户
|
package/package.json
CHANGED
|
@@ -467,7 +467,37 @@ describe("buildClaudePromptText", () => {
|
|
|
467
467
|
|
|
468
468
|
describe("buildSdkEnv", () => {
|
|
469
469
|
it("returns undefined when no SDK env override is configured", () => {
|
|
470
|
-
|
|
470
|
+
const originalPath = process.env.PATH;
|
|
471
|
+
try {
|
|
472
|
+
process.env.PATH = process.platform === "win32"
|
|
473
|
+
? "C:\\Program Files\\Git\\usr\\bin;C:\\Windows\\System32"
|
|
474
|
+
: "/usr/bin:/bin";
|
|
475
|
+
expect(buildSdkEnv("", " ", undefined)).toBeUndefined();
|
|
476
|
+
} finally {
|
|
477
|
+
process.env.PATH = originalPath;
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
it("prefers Git Bash before WindowsApps for Claude SDK subprocesses on Windows", () => {
|
|
482
|
+
if (process.platform !== "win32") return;
|
|
483
|
+
const originalPath = process.env.PATH;
|
|
484
|
+
try {
|
|
485
|
+
process.env.PATH = [
|
|
486
|
+
"C:\\Users\\weizhangjian\\AppData\\Local\\Microsoft\\WindowsApps",
|
|
487
|
+
"C:\\Program Files\\Git\\usr\\bin",
|
|
488
|
+
"%PATH%",
|
|
489
|
+
"C:\\Windows\\System32",
|
|
490
|
+
].join(";");
|
|
491
|
+
|
|
492
|
+
const env = buildSdkEnv("", "", "");
|
|
493
|
+
|
|
494
|
+
expect(env).toBeDefined();
|
|
495
|
+
const parts = env!.PATH!.split(";");
|
|
496
|
+
expect(parts[0]).toBe("C:\\Program Files\\Git\\usr\\bin");
|
|
497
|
+
expect(parts).not.toContain("%PATH%");
|
|
498
|
+
} finally {
|
|
499
|
+
process.env.PATH = originalPath;
|
|
500
|
+
}
|
|
471
501
|
});
|
|
472
502
|
|
|
473
503
|
it("sets requested SDK env overrides and removes conflicting Claude auth/model vars", () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
3
|
+
import { delimiter, dirname, join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
|
|
6
6
|
import {
|
|
@@ -82,23 +82,73 @@ export function buildSdkEnv(
|
|
|
82
82
|
const apiKeyTrim = (apiKey ?? "").trim();
|
|
83
83
|
const baseUrlTrim = (baseUrl ?? "").trim();
|
|
84
84
|
|
|
85
|
-
if (!subagentModelTrim && !apiKeyTrim && !baseUrlTrim) return undefined;
|
|
86
|
-
|
|
87
85
|
const env: Record<string, string | undefined> = { ...process.env };
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
86
|
+
let mutated = preferGitBashOnWindows(env);
|
|
87
|
+
|
|
88
|
+
if (subagentModelTrim || apiKeyTrim || baseUrlTrim) {
|
|
89
|
+
delete env.ANTHROPIC_AUTH_TOKEN;
|
|
90
|
+
delete env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
91
|
+
delete env.ANTHROPIC_MODEL;
|
|
92
|
+
delete env.ANTHROPIC_DEFAULT_OPUS_MODEL;
|
|
93
|
+
delete env.ANTHROPIC_DEFAULT_SONNET_MODEL;
|
|
94
|
+
delete env.ANTHROPIC_DEFAULT_HAIKU_MODEL;
|
|
95
|
+
delete env.CLAUDE_CODE_EFFORT_LEVEL;
|
|
96
|
+
delete env.CLAUDE_CODE_SUBAGENT_MODEL;
|
|
97
|
+
mutated = true;
|
|
98
|
+
}
|
|
96
99
|
|
|
97
100
|
if (subagentModelTrim) env.CLAUDE_CODE_SUBAGENT_MODEL = subagentModelTrim;
|
|
98
101
|
if (apiKeyTrim) env.ANTHROPIC_API_KEY = apiKeyTrim;
|
|
99
102
|
if (baseUrlTrim) env.ANTHROPIC_BASE_URL = baseUrlTrim;
|
|
100
103
|
|
|
101
|
-
return env;
|
|
104
|
+
return mutated ? env : undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function preferGitBashOnWindows(env: Record<string, string | undefined>): boolean {
|
|
108
|
+
if (process.platform !== "win32") return false;
|
|
109
|
+
|
|
110
|
+
const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") ?? "PATH";
|
|
111
|
+
const rawPath = env[pathKey];
|
|
112
|
+
if (!rawPath) return false;
|
|
113
|
+
|
|
114
|
+
const parts = rawPath.split(delimiter).filter((part) => part && part !== "%PATH%");
|
|
115
|
+
const preferred = findPreferredGitBashPath(parts);
|
|
116
|
+
if (!preferred) {
|
|
117
|
+
const nextPath = parts.join(delimiter);
|
|
118
|
+
if (nextPath !== rawPath) {
|
|
119
|
+
env[pathKey] = nextPath;
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const preferredLower = preferred.toLowerCase();
|
|
126
|
+
const reordered = [
|
|
127
|
+
preferred,
|
|
128
|
+
...parts.filter((part) => part.toLowerCase() !== preferredLower),
|
|
129
|
+
];
|
|
130
|
+
const nextPath = reordered.join(delimiter);
|
|
131
|
+
if (nextPath === rawPath) return false;
|
|
132
|
+
env[pathKey] = nextPath;
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function findPreferredGitBashPath(pathParts: string[]): string | undefined {
|
|
137
|
+
const programFilesGit = join(
|
|
138
|
+
process.env.ProgramFiles ?? "C:\\Program Files",
|
|
139
|
+
"Git",
|
|
140
|
+
"usr",
|
|
141
|
+
"bin",
|
|
142
|
+
);
|
|
143
|
+
if (existsSync(join(programFilesGit, "bash.exe"))) return programFilesGit;
|
|
144
|
+
|
|
145
|
+
return pathParts.find((part) => {
|
|
146
|
+
if (!/(\\|\/)(Git)(\\|\/)usr(\\|\/)bin$/i.test(part) &&
|
|
147
|
+
!/(\\|\/)Fork(\\|\/)gitInstance(\\|\/)[^\\/]+(\\|\/)bin$/i.test(part)) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
return existsSync(join(part, "bash.exe"));
|
|
151
|
+
});
|
|
102
152
|
}
|
|
103
153
|
|
|
104
154
|
function readMcpServersConfig(): Record<string, unknown> | undefined {
|
package/src/orchestrator.ts
CHANGED
|
@@ -1235,11 +1235,10 @@ export async function handleCommand(
|
|
|
1235
1235
|
text,
|
|
1236
1236
|
platform,
|
|
1237
1237
|
chatId,
|
|
1238
|
-
msgTimestamp,
|
|
1239
|
-
descriptionTool,
|
|
1240
|
-
tid,
|
|
1241
|
-
|
|
1242
|
-
);
|
|
1238
|
+
msgTimestamp,
|
|
1239
|
+
descriptionTool,
|
|
1240
|
+
tid,
|
|
1241
|
+
);
|
|
1243
1242
|
logTrace(tid, "DONE", { outcome: "resume_done", sessionId });
|
|
1244
1243
|
console.log(`[${ts()}] [RESUME] Session ${sessionId} done`);
|
|
1245
1244
|
} catch (err) {
|
|
@@ -1435,11 +1434,10 @@ export async function handleCommand(
|
|
|
1435
1434
|
text,
|
|
1436
1435
|
platform,
|
|
1437
1436
|
newChatId,
|
|
1438
|
-
msgTimestamp,
|
|
1439
|
-
tool,
|
|
1440
|
-
tid,
|
|
1441
|
-
|
|
1442
|
-
);
|
|
1437
|
+
msgTimestamp,
|
|
1438
|
+
tool,
|
|
1439
|
+
tid,
|
|
1440
|
+
);
|
|
1443
1441
|
console.log(`[${ts()}] [AUTO-P2P 5/5] First prompt sent → OK`);
|
|
1444
1442
|
logTrace(tid, "DONE", { outcome: "auto_new_p2p_prompt_done", newChatId, sessionId, tool });
|
|
1445
1443
|
} catch (err) {
|
package/src/session.ts
CHANGED
|
@@ -1013,7 +1013,9 @@ export async function runAgentSession(
|
|
|
1013
1013
|
const { title: headerTitle, template: headerTemplate } = formatTerminalHeader(prevState.status);
|
|
1014
1014
|
const cardContent = truncateContent(prevState.accumulatedContent + prevState.finalReply) || " ";
|
|
1015
1015
|
const doneCard = buildProgressCard(cardContent, { showStop: false, headerTitle, headerTemplate });
|
|
1016
|
-
await pp.cardUpdate(display.cardId, doneCard, nextSeq).catch(
|
|
1016
|
+
await pp.cardUpdate(display.cardId, doneCard, nextSeq).catch(err => {
|
|
1017
|
+
console.error(`[${ts()}] [DISPLAY] prevState final cardUpdate failed: ${(err as Error).message}`);
|
|
1018
|
+
});
|
|
1017
1019
|
// cardUpdate IO 期间统一 loop 可能也已处理此 display → 删前检查引用
|
|
1018
1020
|
const stillOursAfterUpdate = displayCards.get(displayChatId) === display;
|
|
1019
1021
|
displayCards.delete(displayChatId);
|
|
@@ -1344,7 +1346,9 @@ export function startUnifiedDisplayLoop(): void {
|
|
|
1344
1346
|
const { title: headerTitle, template: headerTemplate } = formatTerminalHeader(state.status);
|
|
1345
1347
|
const cardContent = truncateContent(state.accumulatedContent + state.finalReply) || " ";
|
|
1346
1348
|
const doneCard = buildProgressCard(cardContent, { showStop: false, headerTitle, headerTemplate });
|
|
1347
|
-
await p.cardUpdate(display.cardId, doneCard, nextSeq).catch(
|
|
1349
|
+
await p.cardUpdate(display.cardId, doneCard, nextSeq).catch(err => {
|
|
1350
|
+
console.error(`[${ts()}] [DISPLAY] terminal cardUpdate failed: ${(err as Error).message}`);
|
|
1351
|
+
});
|
|
1348
1352
|
|
|
1349
1353
|
// 若 session 仍在 activePrompts 中,说明 runAgentSession 的 finally
|
|
1350
1354
|
// 还没执行,当前 stream state 可能是 stopSession fire-and-forget
|
|
@@ -1419,7 +1423,9 @@ export function startUnifiedDisplayLoop(): void {
|
|
|
1419
1423
|
const oldSeqBase = display.sequence;
|
|
1420
1424
|
const oldContent = state.accumulatedContent + state.finalReply;
|
|
1421
1425
|
const oldCard = buildProgressCard(truncateContent(oldContent) || " ", { showStop: false, headerTitle: "生成中(上轮)" });
|
|
1422
|
-
await p.cardUpdate(display.cardId, oldCard, oldSeqBase + 1).catch(
|
|
1426
|
+
await p.cardUpdate(display.cardId, oldCard, oldSeqBase + 1).catch(err => {
|
|
1427
|
+
console.error(`[${ts()}] [DISPLAY] rotation old cardUpdate failed: ${(err as Error).message}`);
|
|
1428
|
+
});
|
|
1423
1429
|
markCardDone(sessionId, display.turnCount, display.cardId).catch(() => {});
|
|
1424
1430
|
const newCardId = await p.cardCreate(buildProgressCard(
|
|
1425
1431
|
"",
|