chatccc 0.2.103 → 0.2.106

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/src/cards.ts CHANGED
@@ -131,7 +131,6 @@ export function buildHelpCard(
131
131
  "发送 **/new cursor** 创建新 Cursor 会话",
132
132
  "发送 **/new codex** 创建新 Codex 会话",
133
133
  "发送 **/newh** 重置当前会话(沿用当前工作目录,不切换)",
134
- "发送 **/claude** 查看或切换 Claude API 模式(官方/第三方)",
135
134
  ].join("\n");
136
135
  return JSON.stringify({
137
136
  config: { wide_screen_mode: true },
@@ -463,33 +462,3 @@ export function buildModelCard(
463
462
  });
464
463
  }
465
464
 
466
- /** Claude API 模式切换卡片(/claude 命令) */
467
- export function buildClaudeCard(
468
- currentMode: "official" | "thirdparty",
469
- missingFields: string[],
470
- ): string {
471
- const modeLabel = currentMode === "thirdparty" ? "第三方 API(自定义网关)" : "官方 API(Anthropic 直连)";
472
- const modeDesc = currentMode === "thirdparty"
473
- ? "使用第三方兼容网关,需配置 API Key 和 Base URL。"
474
- : "直连 Anthropic 官方 API,使用系统环境变量中的 ANTHROPIC_API_KEY。";
475
- const lines = [`**当前模式:** ${modeLabel}`, "", modeDesc];
476
-
477
- if (missingFields.length > 0) {
478
- lines.push("", `**切换失败:** 以下必填项未配置: ${missingFields.map(f => `\`${f}\``).join(", ")}`);
479
- }
480
-
481
- const buttons: ButtonDef[] = [
482
- { text: "/claude official", value: JSON.stringify({ cmd: "/claude official" }), type: currentMode === "official" ? "default" : "primary" },
483
- { text: "/claude 3rd", value: JSON.stringify({ cmd: "/claude 3rd" }), type: currentMode === "thirdparty" ? "default" : "primary" },
484
- ];
485
-
486
- return JSON.stringify({
487
- config: { wide_screen_mode: true },
488
- header: { template: "blue", title: { content: "Claude API 模式", tag: "plain_text" } },
489
- elements: [
490
- { tag: "div", text: { tag: "lark_md", content: lines.join("\n") } },
491
- { tag: "hr" },
492
- buildButtons(buttons),
493
- ],
494
- });
495
- }
package/src/config.ts CHANGED
@@ -65,10 +65,10 @@ export interface ClaudeConfig {
65
65
  model: string;
66
66
  subagentModel: string;
67
67
  effort: string;
68
+ /** Anthropic API Key(选填,留空则使用 Claude CLI 默认认证) */
68
69
  apiKey: string;
70
+ /** Anthropic 兼容 API Base URL(选填,留空则使用默认端点) */
69
71
  baseUrl: string;
70
- /** 是否使用第三方 API(非 Anthropic 官方);为 true 时 baseUrl 必须配置 */
71
- useThirdPartyApi: boolean;
72
72
  }
73
73
 
74
74
  export interface CursorConfig {
@@ -324,7 +324,7 @@ function loadConfig(): AppConfig {
324
324
  port: 18080,
325
325
  gitTimeoutSeconds: 180,
326
326
  allowInterrupt: false,
327
- claude: { enabled: false, defaultAgent: true, model: "", subagentModel: "", effort: "", apiKey: "", baseUrl: "", useThirdPartyApi: false },
327
+ claude: { enabled: false, defaultAgent: true, model: "", subagentModel: "", effort: "", apiKey: "", baseUrl: "" },
328
328
  cursor: { enabled: false, defaultAgent: false, path: "", model: "claude-opus-4-7-max" },
329
329
  codex: { enabled: false, defaultAgent: false, path: "", model: "", effort: "" },
330
330
  };
@@ -466,9 +466,8 @@ function loadConfig(): AppConfig {
466
466
  model: normalizeOptionalConfigField(claude.model, { label: "claude.model" }),
467
467
  subagentModel: normalizeOptionalConfigField(claude.subagentModel, { label: "claude.subagentModel" }),
468
468
  effort: normalizeOptionalConfigField(claude.effort, { label: "claude.effort" }),
469
- apiKey: claude.apiKey ?? "",
470
- baseUrl: claude.baseUrl ?? "",
471
- useThirdPartyApi: typeof claude.useThirdPartyApi === "boolean" ? claude.useThirdPartyApi : false,
469
+ apiKey: normalizeOptionalConfigField(claude.apiKey, { label: "claude.apiKey" }),
470
+ baseUrl: normalizeOptionalConfigField(claude.baseUrl, { label: "claude.baseUrl" }),
472
471
  },
473
472
  cursor: {
474
473
  enabled: cursorEnabled,
@@ -496,12 +495,6 @@ function loadConfig(): AppConfig {
496
495
  */
497
496
  export const config: AppConfig = loadConfig();
498
497
 
499
- // 注:历史上这里曾把 config.claude.apiKey / baseUrl 写入 process.env 以便
500
- // @anthropic-ai/claude-agent-sdk 子进程读取,但这会污染主进程的环境变量。
501
- // 现在改为:在 ClaudeAdapter 构造时把这两个值传进去,由 adapter 在调用 SDK
502
- // 时通过 SDK 的 `Options.env` 字段(仅作用于子进程)传递,主进程 env 保持
503
- // 干净。详见 src/adapters/claude-adapter.ts buildSdkEnv()。
504
-
505
498
  // ---------------------------------------------------------------------------
506
499
  // Re-exported config values
507
500
  // ---------------------------------------------------------------------------
@@ -528,12 +521,8 @@ export const LOCAL_RELAY_URL = `ws://127.0.0.1:${CHATCCC_PORT}`;
528
521
  export let CLAUDE_MODEL = config.claude.model;
529
522
  export let CLAUDE_SUBAGENT_MODEL = config.claude.subagentModel;
530
523
  export let CLAUDE_EFFORT = config.claude.effort;
531
- /** Anthropic 兼容网关的 API key(仅经 SDK 子进程 env 传递,从不写入主进程 process.env) */
532
524
  export let CLAUDE_API_KEY = config.claude.apiKey;
533
- /** Anthropic 兼容网关的 base URL(仅经 SDK 子进程 env 传递,从不写入主进程 process.env) */
534
525
  export let CLAUDE_BASE_URL = config.claude.baseUrl;
535
- /** 是否使用第三方 API(非 Anthropic 官方) */
536
- export let CLAUDE_USE_THIRD_PARTY_API = config.claude.useThirdPartyApi;
537
526
 
538
527
  /** 返回当前生效的 Claude 模型(per-session 覆盖由 session.ts 管理,此处仅返回全局配置) */
539
528
  export function getEffectiveClaudeModel(): string {
@@ -613,7 +602,6 @@ export function applyLoadedConfig(next: AppConfig): void {
613
602
  CLAUDE_EFFORT = next.claude.effort;
614
603
  CLAUDE_API_KEY = next.claude.apiKey;
615
604
  CLAUDE_BASE_URL = next.claude.baseUrl;
616
- CLAUDE_USE_THIRD_PARTY_API = next.claude.useThirdPartyApi;
617
605
  GIT_TIMEOUT_SECONDS = next.gitTimeoutSeconds;
618
606
  GIT_TIMEOUT_MS = GIT_TIMEOUT_SECONDS * 1000;
619
607
  ALLOW_INTERRUPT = next.allowInterrupt;
@@ -16,9 +16,6 @@ import {
16
16
  CLAUDE_EFFORT,
17
17
  CLAUDE_MODEL,
18
18
  CLAUDE_SUBAGENT_MODEL,
19
- CLAUDE_API_KEY,
20
- CLAUDE_BASE_URL,
21
- CLAUDE_USE_THIRD_PARTY_API,
22
19
  CONFIG_FILE,
23
20
  GIT_TIMEOUT_MS,
24
21
  PROJECT_ROOT,
@@ -46,7 +43,6 @@ import {
46
43
  buildSessionsCard,
47
44
  buildQueuedCard,
48
45
  buildQueueFullCard,
49
- buildClaudeCard,
50
46
  } from "./cards.ts";
51
47
  import {
52
48
  formatGitResult,
@@ -390,7 +386,6 @@ export async function handleCommand(
390
386
  `**工作目录:** \`${cwd}\`\n\n` +
391
387
  `直接在这里发消息即可与 ${toolLabel} 对话。\n\n` +
392
388
  `发送 **/cd** 切换新建会话的默认目录。\n` +
393
- `发送 **/claude** 查看或切换 Claude API 模式(官方/第三方)。\n` +
394
389
  `发送 **/model** 查看或切换当前会话的模型。\n` +
395
390
  `发送 **/new** 创建新会话,**/newh** 重置当前会话(沿用工作目录)。\n` +
396
391
  `发送 **/sessions** 查看所有会话状态。\n` +
@@ -1086,72 +1081,6 @@ export async function handleCommand(
1086
1081
  return;
1087
1082
  }
1088
1083
 
1089
- // /claude — 查看/切换 Claude API 模式(官方 vs 第三方)
1090
- if (textLower === "/claude" || textLower === "/claude official" || textLower === "/claude 3rd") {
1091
- logTrace(tid, "BRANCH", { cmd: "/claude", arg: text.slice(8).trim() || "(none)" });
1092
-
1093
- if (textLower === "/claude official") {
1094
- // 切换到官方模式:设置 useThirdPartyApi=false,清空 apiKey 和 baseUrl
1095
- try {
1096
- const raw = readFileSync(CONFIG_FILE, "utf-8");
1097
- const cfg = JSON.parse(raw);
1098
- cfg.claude = cfg.claude || {};
1099
- cfg.claude.useThirdPartyApi = false;
1100
- cfg.claude.apiKey = "";
1101
- cfg.claude.baseUrl = "";
1102
- writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
1103
- reloadConfigFromDisk();
1104
- logTrace(tid, "DONE", { outcome: "claude_official" });
1105
- const card = buildClaudeCard("official", []);
1106
- await platform.sendRawCard(chatId, card);
1107
- } catch (err) {
1108
- logTrace(tid, "DONE", { outcome: "claude_official_fail", error: (err as Error).message });
1109
- await platform.sendText(chatId, `切换失败: ${(err as Error).message}`).catch(() => {});
1110
- }
1111
- return;
1112
- }
1113
-
1114
- if (textLower === "/claude 3rd") {
1115
- // 切换到第三方模式:检查 apiKey 和 baseUrl 是否已配置
1116
- const missing: string[] = [];
1117
- if (!CLAUDE_API_KEY.trim()) missing.push("API Key");
1118
- if (!CLAUDE_BASE_URL.trim()) missing.push("Base URL");
1119
-
1120
- if (missing.length > 0) {
1121
- logTrace(tid, "DONE", { outcome: "claude_3rd_missing", missing });
1122
- const card = buildClaudeCard(
1123
- CLAUDE_USE_THIRD_PARTY_API ? "thirdparty" : "official",
1124
- missing,
1125
- );
1126
- await platform.sendRawCard(chatId, card);
1127
- return;
1128
- }
1129
-
1130
- try {
1131
- const raw = readFileSync(CONFIG_FILE, "utf-8");
1132
- const cfg = JSON.parse(raw);
1133
- cfg.claude = cfg.claude || {};
1134
- cfg.claude.useThirdPartyApi = true;
1135
- writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
1136
- reloadConfigFromDisk();
1137
- logTrace(tid, "DONE", { outcome: "claude_3rd" });
1138
- const card = buildClaudeCard("thirdparty", []);
1139
- await platform.sendRawCard(chatId, card);
1140
- } catch (err) {
1141
- logTrace(tid, "DONE", { outcome: "claude_3rd_fail", error: (err as Error).message });
1142
- await platform.sendText(chatId, `切换失败: ${(err as Error).message}`).catch(() => {});
1143
- }
1144
- return;
1145
- }
1146
-
1147
- // /claude — 显示当前模式和切换按钮
1148
- const currentMode: "official" | "thirdparty" = CLAUDE_USE_THIRD_PARTY_API ? "thirdparty" : "official";
1149
- const card = buildClaudeCard(currentMode, []);
1150
- await platform.sendRawCard(chatId, card);
1151
- logTrace(tid, "DONE", { outcome: "claude_query", mode: currentMode });
1152
- return;
1153
- }
1154
-
1155
1084
  // /git <args>:在「当前会话工作目录」执行 git 命令
1156
1085
  if (textLower.startsWith("/git ") || textLower === "/git") {
1157
1086
  const args = text === "/git" ? "" : text.slice(5).trim();
@@ -1283,69 +1212,6 @@ export async function handleCommand(
1283
1212
  return;
1284
1213
  }
1285
1214
 
1286
- // 无会话上下文 → 检查是否是 /claude 查询
1287
- if (textLower === "/claude" || textLower === "/claude official" || textLower === "/claude 3rd") {
1288
- logTrace(tid, "BRANCH", { cmd: "/claude", arg: text.slice(8).trim() || "(none)", noSession: true });
1289
-
1290
- if (textLower === "/claude official") {
1291
- try {
1292
- const raw = readFileSync(CONFIG_FILE, "utf-8");
1293
- const cfg = JSON.parse(raw);
1294
- cfg.claude = cfg.claude || {};
1295
- cfg.claude.useThirdPartyApi = false;
1296
- cfg.claude.apiKey = "";
1297
- cfg.claude.baseUrl = "";
1298
- writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
1299
- reloadConfigFromDisk();
1300
- logTrace(tid, "DONE", { outcome: "claude_official" });
1301
- const card = buildClaudeCard("official", []);
1302
- await platform.sendRawCard(chatId, card);
1303
- } catch (err) {
1304
- logTrace(tid, "DONE", { outcome: "claude_official_fail", error: (err as Error).message });
1305
- await platform.sendText(chatId, `切换失败: ${(err as Error).message}`).catch(() => {});
1306
- }
1307
- return;
1308
- }
1309
-
1310
- if (textLower === "/claude 3rd") {
1311
- const missing: string[] = [];
1312
- if (!CLAUDE_API_KEY.trim()) missing.push("API Key");
1313
- if (!CLAUDE_BASE_URL.trim()) missing.push("Base URL");
1314
-
1315
- if (missing.length > 0) {
1316
- logTrace(tid, "DONE", { outcome: "claude_3rd_missing", missing });
1317
- const card = buildClaudeCard(
1318
- CLAUDE_USE_THIRD_PARTY_API ? "thirdparty" : "official",
1319
- missing,
1320
- );
1321
- await platform.sendRawCard(chatId, card);
1322
- return;
1323
- }
1324
-
1325
- try {
1326
- const raw = readFileSync(CONFIG_FILE, "utf-8");
1327
- const cfg = JSON.parse(raw);
1328
- cfg.claude = cfg.claude || {};
1329
- cfg.claude.useThirdPartyApi = true;
1330
- writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
1331
- reloadConfigFromDisk();
1332
- logTrace(tid, "DONE", { outcome: "claude_3rd" });
1333
- const card = buildClaudeCard("thirdparty", []);
1334
- await platform.sendRawCard(chatId, card);
1335
- } catch (err) {
1336
- logTrace(tid, "DONE", { outcome: "claude_3rd_fail", error: (err as Error).message });
1337
- await platform.sendText(chatId, `切换失败: ${(err as Error).message}`).catch(() => {});
1338
- }
1339
- return;
1340
- }
1341
-
1342
- const currentMode: "official" | "thirdparty" = CLAUDE_USE_THIRD_PARTY_API ? "thirdparty" : "official";
1343
- const card = buildClaudeCard(currentMode, []);
1344
- await platform.sendRawCard(chatId, card);
1345
- logTrace(tid, "DONE", { outcome: "claude_query", mode: currentMode });
1346
- return;
1347
- }
1348
-
1349
1215
  // 无会话上下文 → 检查是否是 /model 查询
1350
1216
  if (textLower === "/model") {
1351
1217
  const defaultTool = resolveDefaultAgentTool();
package/src/session.ts CHANGED
@@ -363,9 +363,9 @@ export function getAdapterForTool(tool: string, sessionId?: string): ToolAdapter
363
363
  model: effectiveModel,
364
364
  subagentModel: CLAUDE_SUBAGENT_MODEL,
365
365
  effort: CLAUDE_EFFORT,
366
- isEmpty: isAnthropicConfigEmpty,
367
366
  apiKey: CLAUDE_API_KEY,
368
367
  baseUrl: CLAUDE_BASE_URL,
368
+ isEmpty: isAnthropicConfigEmpty,
369
369
  });
370
370
  }
371
371
  adapterCache.set(cacheKey, adapter);