chatccc 0.2.199 → 0.2.200

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.
Files changed (90) hide show
  1. package/README.md +1 -1
  2. package/agent-prompts/claude_specific.md +45 -45
  3. package/agent-prompts/codex_specific.md +2 -2
  4. package/agent-prompts/cursor_specific.md +13 -13
  5. package/bin/cccagent.mjs +17 -17
  6. package/config.sample.json +27 -27
  7. package/im-skills/feishu-skill/receive-send-file.md +63 -63
  8. package/im-skills/feishu-skill/receive-send-image.md +24 -24
  9. package/im-skills/feishu-skill/skill.md +3 -3
  10. package/im-skills/wechat-file-skill/receive-send-file.md +38 -38
  11. package/im-skills/wechat-file-skill/send-file.mjs +83 -83
  12. package/im-skills/wechat-file-skill/skill.md +10 -10
  13. package/im-skills/wechat-image-skill/skill.md +10 -10
  14. package/im-skills/wechat-video-skill/receive-send-video.md +38 -38
  15. package/im-skills/wechat-video-skill/send-video.mjs +79 -79
  16. package/im-skills/wechat-video-skill/skill.md +10 -10
  17. package/package.json +1 -1
  18. package/scripts/postinstall-sharp-check.mjs +58 -58
  19. package/src/__tests__/agent-delegate-task-rpc.test.ts +165 -165
  20. package/src/__tests__/agent-reload-config-rpc.test.ts +99 -99
  21. package/src/__tests__/builtin-chat-session.test.ts +277 -277
  22. package/src/__tests__/builtin-cli-json.test.ts +39 -39
  23. package/src/__tests__/builtin-config.test.ts +33 -33
  24. package/src/__tests__/builtin-context.test.ts +163 -163
  25. package/src/__tests__/builtin-file-tools.test.ts +224 -224
  26. package/src/__tests__/builtin-session-select.test.ts +116 -116
  27. package/src/__tests__/builtin-sigint.test.ts +56 -56
  28. package/src/__tests__/card-plain-text.test.ts +5 -5
  29. package/src/__tests__/cardkit.test.ts +60 -60
  30. package/src/__tests__/cards.test.ts +109 -109
  31. package/src/__tests__/ccc-adapter.test.ts +114 -114
  32. package/src/__tests__/chatgpt-subscription-rpc.test.ts +89 -89
  33. package/src/__tests__/chatgpt-subscription.test.ts +135 -135
  34. package/src/__tests__/chrome-devtools-guard.test.ts +165 -165
  35. package/src/__tests__/claude-adapter.test.ts +592 -592
  36. package/src/__tests__/claude-raw-stream-log.test.ts +87 -87
  37. package/src/__tests__/codex-raw-stream-log.test.ts +163 -163
  38. package/src/__tests__/codex-reset-actions.test.ts +146 -146
  39. package/src/__tests__/config-reload.test.ts +10 -10
  40. package/src/__tests__/config-sample.test.ts +18 -18
  41. package/src/__tests__/feishu-api.test.ts +60 -60
  42. package/src/__tests__/feishu-avatar.test.ts +87 -45
  43. package/src/__tests__/feishu-platform.test.ts +22 -22
  44. package/src/__tests__/format-message.test.ts +47 -47
  45. package/src/__tests__/jsonl-stream.test.ts +79 -79
  46. package/src/__tests__/orchestrator.test.ts +227 -202
  47. package/src/__tests__/privacy.test.ts +198 -198
  48. package/src/__tests__/raw-stream-log.test.ts +106 -106
  49. package/src/__tests__/session.test.ts +40 -40
  50. package/src/__tests__/shared-prefix.test.ts +36 -36
  51. package/src/__tests__/sim-platform.test.ts +12 -12
  52. package/src/__tests__/stream-state.test.ts +42 -42
  53. package/src/__tests__/web-ui.test.ts +209 -209
  54. package/src/adapters/ccc-adapter.ts +121 -121
  55. package/src/adapters/claude-adapter.ts +603 -603
  56. package/src/adapters/claude-session-meta-store.ts +120 -120
  57. package/src/adapters/codex-adapter.ts +380 -380
  58. package/src/adapters/jsonl-stream.ts +157 -157
  59. package/src/adapters/raw-stream-log.ts +124 -124
  60. package/src/adapters/resource-monitor.ts +140 -140
  61. package/src/agent-delegate-task-rpc.ts +153 -153
  62. package/src/agent-delegate-task.ts +81 -81
  63. package/src/agent-reload-config-rpc.ts +34 -34
  64. package/src/agent-stop-stuck.ts +129 -129
  65. package/src/builtin/cli.ts +473 -473
  66. package/src/builtin/context.ts +323 -323
  67. package/src/builtin/file-tools.ts +1072 -1072
  68. package/src/builtin/index.ts +404 -404
  69. package/src/builtin/session-select.ts +48 -48
  70. package/src/builtin/sigint.ts +50 -50
  71. package/src/cards.ts +195 -195
  72. package/src/chatgpt-subscription-rpc.ts +27 -27
  73. package/src/chatgpt-subscription.ts +299 -299
  74. package/src/chrome-devtools-guard.ts +318 -318
  75. package/src/codex-reset-actions.ts +184 -184
  76. package/src/config.ts +125 -125
  77. package/src/feishu-api.ts +86 -63
  78. package/src/feishu-platform.ts +20 -20
  79. package/src/format-message.ts +293 -293
  80. package/src/litellm-proxy.ts +374 -374
  81. package/src/orchestrator.ts +183 -183
  82. package/src/privacy.ts +118 -118
  83. package/src/runtime-reload.ts +34 -34
  84. package/src/session-chat-binding.ts +6 -6
  85. package/src/session-name.ts +8 -8
  86. package/src/session.ts +141 -141
  87. package/src/shared-prefix.ts +29 -29
  88. package/src/sim-platform.ts +20 -20
  89. package/src/turn-cards.ts +117 -117
  90. package/src/web-ui.ts +205 -205
@@ -22,24 +22,24 @@ import {
22
22
  PROJECT_ROOT,
23
23
  anthropicConfigDisplay,
24
24
  config,
25
- fileLog,
26
- getAllEffortsForTool,
27
- getAllModelsForTool,
28
- getDefaultEffortForTool,
29
- getDefaultCwd,
25
+ fileLog,
26
+ getAllEffortsForTool,
27
+ getAllModelsForTool,
28
+ getDefaultEffortForTool,
29
+ getDefaultCwd,
30
30
  setDefaultCwd,
31
31
  getRecentDirs,
32
32
  addRecentDir,
33
33
  resolveDefaultAgentTool,
34
- sessionPrefixForTool,
35
- toolDisplayName,
36
- ts,
37
- type AgentTool,
38
- } from "./config.ts";
34
+ sessionPrefixForTool,
35
+ toolDisplayName,
36
+ ts,
37
+ type AgentTool,
38
+ } from "./config.ts";
39
39
  import {
40
- buildHelpCard,
41
- buildEffortCard,
42
- buildModelCard,
40
+ buildHelpCard,
41
+ buildEffortCard,
42
+ buildModelCard,
43
43
  buildStatusCard,
44
44
  buildCdContent,
45
45
  buildCdCard,
@@ -54,21 +54,21 @@ import {
54
54
  runGitCommand,
55
55
  } from "./git-command.ts";
56
56
  import {
57
- clearSessionModelOverride,
58
- clearSessionEffortOverride,
57
+ clearSessionModelOverride,
58
+ clearSessionEffortOverride,
59
59
  getSessionStatus,
60
60
  getAllSessionsStatus,
61
61
  initClaudeSession,
62
62
  lastMsgTimestamps,
63
63
  resumeAndPrompt,
64
64
  sessionInfoMap,
65
- setSessionModelOverride,
66
- setSessionEffortOverride,
65
+ setSessionModelOverride,
66
+ setSessionEffortOverride,
67
67
  switchChatBinding,
68
68
  recordSessionRegistry,
69
69
  getAdapterForTool,
70
- getEffectiveModelForTool,
71
- getEffectiveEffortForTool,
70
+ getEffectiveModelForTool,
71
+ getEffectiveEffortForTool,
72
72
  stopSession,
73
73
  loadSessionRegistryForBinding,
74
74
  removeSessionRegistryRecord,
@@ -87,11 +87,11 @@ import {
87
87
  import { getCodexUsageSummary, getTenantAccessToken, sendPostMessage } from "./feishu-platform.ts";
88
88
  import { getCursorUsageSummary, type CursorUsageSummary } from "./cursor-usage.ts";
89
89
  import { getChatGptSubscriptionStatus, type ChatGptSubscriptionResult } from "./chatgpt-subscription.ts";
90
- import { delegateAgentTask } from "./agent-delegate-task.ts";
91
- import { applySharedPrefix } from "./shared-prefix.ts";
92
- import { cwdDisplayName, sessionChatName } from "./session-name.ts";
93
- import { reloadRuntimeConfig } from "./runtime-reload.ts";
94
- export { type PlatformAdapter } from "./platform-adapter.ts";
90
+ import { delegateAgentTask } from "./agent-delegate-task.ts";
91
+ import { applySharedPrefix } from "./shared-prefix.ts";
92
+ import { cwdDisplayName, sessionChatName } from "./session-name.ts";
93
+ import { reloadRuntimeConfig } from "./runtime-reload.ts";
94
+ export { type PlatformAdapter } from "./platform-adapter.ts";
95
95
  import type { ChatAvatarUsageHints, PlatformAdapter } from "./platform-adapter.ts";
96
96
  import type { CodexUsageSummary } from "./feishu-api.ts";
97
97
 
@@ -135,7 +135,7 @@ function formatCodexUsageSummary(usage: CodexUsageSummary, chatGptSubscription:
135
135
  return `(约 ${parts.join("")}后)`;
136
136
  };
137
137
 
138
- const formatResetTime = (balance: CodexUsageSummary["fiveHour"]) => {
138
+ const formatResetTime = (balance: NonNullable<CodexUsageSummary["fiveHour"]>) => {
139
139
  if (balance.resetAtEpochSeconds === null) return "暂无数据";
140
140
  const date = new Date(balance.resetAtEpochSeconds * 1000);
141
141
  const pad = (value: number) => String(value).padStart(2, "0");
@@ -263,8 +263,8 @@ function formatCodexUsageSummary(usage: CodexUsageSummary, chatGptSubscription:
263
263
  formatChatGptSubscriptionFailure(),
264
264
  formatResetCredits(),
265
265
  "",
266
- formatWindow("5h", usage.fiveHour),
267
- formatWindow("", usage.weekly),
266
+ usage.fiveHour ? formatWindow("5h", usage.fiveHour) : "",
267
+ usage.weekly ? formatWindow("7天", usage.weekly) : "",
268
268
  ].filter((line, index, arr) => line !== "" || (index > 0 && arr[index - 1] !== "")).join("\n");
269
269
  }
270
270
 
@@ -325,7 +325,7 @@ function formatCursorUsageSummary(usage: CursorUsageSummary): string {
325
325
  }
326
326
 
327
327
  function usageHelpLine(tool: string): string {
328
- if (tool === "codex") return "\n发送 **/usage** 查看 Codex 5h/周用量,以及查询/使用主动重置卡。";
328
+ if (tool === "codex") return "\n发送 **/usage** 查看 Codex 实际存在的 5h/7天用量窗口,以及查询/使用主动重置卡。";
329
329
  if (tool === "cursor") return "\n发送 **/usage** 查看 Cursor 用量。";
330
330
  return "";
331
331
  }
@@ -545,31 +545,31 @@ export async function handleCommand(
545
545
  text = sharedPrefix.body;
546
546
  const textLower = text.toLowerCase();
547
547
  const isCommandText = !sharedPrefix.matched && textLower.startsWith("/");
548
- recordChatPlatform(chatId, platform);
549
- await cleanupNonWechatP2pBinding(platform, chatId, chatType, tid);
550
-
551
- if (isCommandText && textLower === "/reload") {
552
- logTrace(tid, "BRANCH", { cmd: "/reload" });
553
- try {
554
- const result = await reloadRuntimeConfig("chat-command");
555
- await platform.sendText(
556
- chatId,
557
- [
558
- "配置已重新加载。",
559
- `默认 Agent: ${toolDisplayName(result.defaultAgent)}`,
560
- `配置文件: ${result.configPath}`,
561
- "后续新会话会使用最新配置;正在生成的会话不会被中断。",
562
- ].join("\n"),
563
- ).catch(() => {});
564
- logTrace(tid, "DONE", { outcome: "reload", defaultAgent: result.defaultAgent });
565
- } catch (err) {
566
- await platform.sendText(chatId, `配置重载失败:${(err as Error).message}`).catch(() => {});
567
- logTrace(tid, "DONE", { outcome: "reload_fail", error: (err as Error).message });
568
- }
569
- return;
570
- }
571
-
572
- if (isCommandText && textLower === "/restart") {
548
+ recordChatPlatform(chatId, platform);
549
+ await cleanupNonWechatP2pBinding(platform, chatId, chatType, tid);
550
+
551
+ if (isCommandText && textLower === "/reload") {
552
+ logTrace(tid, "BRANCH", { cmd: "/reload" });
553
+ try {
554
+ const result = await reloadRuntimeConfig("chat-command");
555
+ await platform.sendText(
556
+ chatId,
557
+ [
558
+ "配置已重新加载。",
559
+ `默认 Agent: ${toolDisplayName(result.defaultAgent)}`,
560
+ `配置文件: ${result.configPath}`,
561
+ "后续新会话会使用最新配置;正在生成的会话不会被中断。",
562
+ ].join("\n"),
563
+ ).catch(() => {});
564
+ logTrace(tid, "DONE", { outcome: "reload", defaultAgent: result.defaultAgent });
565
+ } catch (err) {
566
+ await platform.sendText(chatId, `配置重载失败:${(err as Error).message}`).catch(() => {});
567
+ logTrace(tid, "DONE", { outcome: "reload_fail", error: (err as Error).message });
568
+ }
569
+ return;
570
+ }
571
+
572
+ if (isCommandText && textLower === "/restart") {
573
573
  logTrace(tid, "BRANCH", { cmd: "/restart" });
574
574
  await platform.sendText(chatId, "重启中...请几秒后发消息唤醒我").catch(() => {});
575
575
  logTrace(tid, "DONE", { outcome: "restart" });
@@ -763,7 +763,7 @@ export async function handleCommand(
763
763
  const toolArg = text.slice(5).trim().toLowerCase();
764
764
  const tool = toolArg || resolveDefaultAgentTool();
765
765
  logTrace(tid, "BRANCH", { cmd: "/new", tool });
766
- const validTools = ["claude", "cursor", "codex", "ccc"];
766
+ const validTools = ["claude", "cursor", "codex", "ccc"];
767
767
  if (!validTools.includes(tool)) {
768
768
  logTrace(tid, "DONE", { outcome: "new_invalid_tool", tool });
769
769
  await platform.sendCard(
@@ -1555,96 +1555,96 @@ export async function handleCommand(
1555
1555
  }
1556
1556
 
1557
1557
  // /git <args>:在「当前会话工作目录」执行 git 命令
1558
- if (isCommandText && textLower === "/effort clear") {
1559
- logTrace(tid, "BRANCH", { cmd: "/effort clear", sessionId, tool: descriptionTool });
1560
- const efforts = getAllEffortsForTool(descriptionTool as AgentTool);
1561
- const toolLabel = toolDisplayName(descriptionTool);
1562
- if (efforts.length === 0) {
1563
- const msg = `当前 ${toolLabel} 不支持 effort 切换。`;
1564
- await (platform.kind === "wechat"
1565
- ? platform.sendText(chatId, msg)
1566
- : platform.sendCard(chatId, "Effort 切换", msg, "red")
1567
- ).catch(() => {});
1568
- logTrace(tid, "DONE", { outcome: "effort_unsupported", tool: descriptionTool });
1569
- return;
1570
- }
1571
-
1572
- clearSessionEffortOverride(sessionId);
1573
- const defaultEffort = getDefaultEffortForTool(descriptionTool as AgentTool);
1574
- const msg = `已清除当前 ${toolLabel} 会话的 effort 覆盖,恢复使用: \`${defaultEffort || "(未指定)"}\``;
1575
- await (platform.kind === "wechat"
1576
- ? platform.sendText(chatId, msg)
1577
- : platform.sendCard(chatId, "Effort 切换", msg, "green")
1578
- ).catch(() => {});
1579
- logTrace(tid, "DONE", { outcome: "effort_cleared", sessionId, tool: descriptionTool });
1580
- return;
1581
- }
1582
-
1583
- if (isCommandText && textLower.startsWith("/effort ")) {
1584
- const effortArg = text.slice(8).trim();
1585
- if (!effortArg) return;
1586
- logTrace(tid, "BRANCH", { cmd: "/effort", arg: effortArg, sessionId, tool: descriptionTool });
1587
-
1588
- const efforts = getAllEffortsForTool(descriptionTool as AgentTool);
1589
- const toolLabel = toolDisplayName(descriptionTool);
1590
- if (efforts.length === 0) {
1591
- const msg = `当前 ${toolLabel} 不支持 effort 切换。`;
1592
- await (platform.kind === "wechat"
1593
- ? platform.sendText(chatId, msg)
1594
- : platform.sendCard(chatId, "Effort 切换", msg, "red")
1595
- ).catch(() => {});
1596
- logTrace(tid, "DONE", { outcome: "effort_unsupported", tool: descriptionTool });
1597
- return;
1598
- }
1599
-
1600
- const target = findModelMatch(effortArg, efforts);
1601
- if (!target) {
1602
- const msg = `未找到匹配 "${effortArg}" 的 effort。当前 ${toolLabel} 可选 effort:\n${efforts.map(e => ` \`${e}\``).join("\n")}`;
1603
- await (platform.kind === "wechat"
1604
- ? platform.sendText(chatId, msg)
1605
- : platform.sendCard(chatId, "Effort 切换", msg, "red")
1606
- ).catch(() => {});
1607
- logTrace(tid, "DONE", { outcome: "effort_not_found", arg: effortArg, tool: descriptionTool });
1608
- return;
1609
- }
1610
-
1611
- setSessionEffortOverride(sessionId, target);
1612
- const msg = `已切换当前 ${toolLabel} 会话 effort 为: \`${target}\``;
1613
- await (platform.kind === "wechat"
1614
- ? platform.sendText(chatId, msg)
1615
- : platform.sendCard(chatId, "Effort 切换", msg, "green")
1616
- ).catch(() => {});
1617
- logTrace(tid, "DONE", { outcome: "effort_switched", arg: effortArg, target, sessionId, tool: descriptionTool });
1618
- return;
1619
- }
1620
-
1621
- if (isCommandText && textLower === "/effort") {
1622
- logTrace(tid, "BRANCH", { cmd: "/effort", sessionId, tool: descriptionTool });
1623
- const efforts = getAllEffortsForTool(descriptionTool as AgentTool);
1624
- const currentEffort = getEffectiveEffortForTool(descriptionTool, sessionId);
1625
- const toolLabel = toolDisplayName(descriptionTool);
1626
-
1627
- if (efforts.length === 0) {
1628
- const msg = `当前 ${toolLabel} 不支持 effort 切换。`;
1629
- await (platform.kind === "wechat"
1630
- ? platform.sendText(chatId, msg)
1631
- : platform.sendCard(chatId, "Effort 切换", msg, "red")
1632
- ).catch(() => {});
1633
- } else if (platform.kind === "wechat") {
1634
- const lines = [currentEffort ? `当前 effort (${toolLabel}): ${currentEffort}` : `当前 effort (${toolLabel}): 未指定`];
1635
- lines.push("", "可切换 effort:");
1636
- for (const e of efforts) lines.push(` ${e}`);
1637
- lines.push("", "输入 /effort <effort> 切换 effort");
1638
- await platform.sendText(chatId, lines.join("\n")).catch(() => {});
1639
- } else {
1640
- const card = buildEffortCard(currentEffort, efforts, descriptionTool);
1641
- await platform.sendRawCard(chatId, card);
1642
- }
1643
- logTrace(tid, "DONE", { outcome: "effort_query", tool: descriptionTool });
1644
- return;
1645
- }
1646
-
1647
- if (isCommandText && (textLower.startsWith("/git ") || textLower === "/git")) {
1558
+ if (isCommandText && textLower === "/effort clear") {
1559
+ logTrace(tid, "BRANCH", { cmd: "/effort clear", sessionId, tool: descriptionTool });
1560
+ const efforts = getAllEffortsForTool(descriptionTool as AgentTool);
1561
+ const toolLabel = toolDisplayName(descriptionTool);
1562
+ if (efforts.length === 0) {
1563
+ const msg = `当前 ${toolLabel} 不支持 effort 切换。`;
1564
+ await (platform.kind === "wechat"
1565
+ ? platform.sendText(chatId, msg)
1566
+ : platform.sendCard(chatId, "Effort 切换", msg, "red")
1567
+ ).catch(() => {});
1568
+ logTrace(tid, "DONE", { outcome: "effort_unsupported", tool: descriptionTool });
1569
+ return;
1570
+ }
1571
+
1572
+ clearSessionEffortOverride(sessionId);
1573
+ const defaultEffort = getDefaultEffortForTool(descriptionTool as AgentTool);
1574
+ const msg = `已清除当前 ${toolLabel} 会话的 effort 覆盖,恢复使用: \`${defaultEffort || "(未指定)"}\``;
1575
+ await (platform.kind === "wechat"
1576
+ ? platform.sendText(chatId, msg)
1577
+ : platform.sendCard(chatId, "Effort 切换", msg, "green")
1578
+ ).catch(() => {});
1579
+ logTrace(tid, "DONE", { outcome: "effort_cleared", sessionId, tool: descriptionTool });
1580
+ return;
1581
+ }
1582
+
1583
+ if (isCommandText && textLower.startsWith("/effort ")) {
1584
+ const effortArg = text.slice(8).trim();
1585
+ if (!effortArg) return;
1586
+ logTrace(tid, "BRANCH", { cmd: "/effort", arg: effortArg, sessionId, tool: descriptionTool });
1587
+
1588
+ const efforts = getAllEffortsForTool(descriptionTool as AgentTool);
1589
+ const toolLabel = toolDisplayName(descriptionTool);
1590
+ if (efforts.length === 0) {
1591
+ const msg = `当前 ${toolLabel} 不支持 effort 切换。`;
1592
+ await (platform.kind === "wechat"
1593
+ ? platform.sendText(chatId, msg)
1594
+ : platform.sendCard(chatId, "Effort 切换", msg, "red")
1595
+ ).catch(() => {});
1596
+ logTrace(tid, "DONE", { outcome: "effort_unsupported", tool: descriptionTool });
1597
+ return;
1598
+ }
1599
+
1600
+ const target = findModelMatch(effortArg, efforts);
1601
+ if (!target) {
1602
+ const msg = `未找到匹配 "${effortArg}" 的 effort。当前 ${toolLabel} 可选 effort:\n${efforts.map(e => ` \`${e}\``).join("\n")}`;
1603
+ await (platform.kind === "wechat"
1604
+ ? platform.sendText(chatId, msg)
1605
+ : platform.sendCard(chatId, "Effort 切换", msg, "red")
1606
+ ).catch(() => {});
1607
+ logTrace(tid, "DONE", { outcome: "effort_not_found", arg: effortArg, tool: descriptionTool });
1608
+ return;
1609
+ }
1610
+
1611
+ setSessionEffortOverride(sessionId, target);
1612
+ const msg = `已切换当前 ${toolLabel} 会话 effort 为: \`${target}\``;
1613
+ await (platform.kind === "wechat"
1614
+ ? platform.sendText(chatId, msg)
1615
+ : platform.sendCard(chatId, "Effort 切换", msg, "green")
1616
+ ).catch(() => {});
1617
+ logTrace(tid, "DONE", { outcome: "effort_switched", arg: effortArg, target, sessionId, tool: descriptionTool });
1618
+ return;
1619
+ }
1620
+
1621
+ if (isCommandText && textLower === "/effort") {
1622
+ logTrace(tid, "BRANCH", { cmd: "/effort", sessionId, tool: descriptionTool });
1623
+ const efforts = getAllEffortsForTool(descriptionTool as AgentTool);
1624
+ const currentEffort = getEffectiveEffortForTool(descriptionTool, sessionId);
1625
+ const toolLabel = toolDisplayName(descriptionTool);
1626
+
1627
+ if (efforts.length === 0) {
1628
+ const msg = `当前 ${toolLabel} 不支持 effort 切换。`;
1629
+ await (platform.kind === "wechat"
1630
+ ? platform.sendText(chatId, msg)
1631
+ : platform.sendCard(chatId, "Effort 切换", msg, "red")
1632
+ ).catch(() => {});
1633
+ } else if (platform.kind === "wechat") {
1634
+ const lines = [currentEffort ? `当前 effort (${toolLabel}): ${currentEffort}` : `当前 effort (${toolLabel}): 未指定`];
1635
+ lines.push("", "可切换 effort:");
1636
+ for (const e of efforts) lines.push(` ${e}`);
1637
+ lines.push("", "输入 /effort <effort> 切换 effort");
1638
+ await platform.sendText(chatId, lines.join("\n")).catch(() => {});
1639
+ } else {
1640
+ const card = buildEffortCard(currentEffort, efforts, descriptionTool);
1641
+ await platform.sendRawCard(chatId, card);
1642
+ }
1643
+ logTrace(tid, "DONE", { outcome: "effort_query", tool: descriptionTool });
1644
+ return;
1645
+ }
1646
+
1647
+ if (isCommandText && (textLower.startsWith("/git ") || textLower === "/git")) {
1648
1648
  const args = text === "/git" ? "" : text.slice(5).trim();
1649
1649
  logTrace(tid, "BRANCH", { cmd: "/git", args: args || "(none)" });
1650
1650
  if (!args) {
@@ -1802,45 +1802,45 @@ export async function handleCommand(
1802
1802
  }
1803
1803
 
1804
1804
  // 无会话上下文 → /sessions 仍是有效指令,不触发飞书私聊自动建群。
1805
- if (isCommandText && textLower === "/effort") {
1806
- const defaultTool = resolveDefaultAgentTool();
1807
- const efforts = getAllEffortsForTool(defaultTool);
1808
- const currentEffort = getDefaultEffortForTool(defaultTool);
1809
- const toolLabel = toolDisplayName(defaultTool);
1810
-
1811
- if (efforts.length === 0) {
1812
- const msg = `当前默认 agent (${toolLabel}) 不支持 effort 切换。`;
1813
- await (platform.kind === "wechat"
1814
- ? platform.sendText(chatId, msg)
1815
- : platform.sendCard(chatId, "Effort 切换", msg, "red")
1816
- ).catch(() => {});
1817
- } else if (platform.kind === "wechat") {
1818
- const lines = [currentEffort ? `当前默认 effort (${toolLabel}): ${currentEffort}` : `当前默认 effort (${toolLabel}): 未指定`];
1819
- lines.push("", "可切换 effort:");
1820
- for (const e of efforts) lines.push(` ${e}`);
1821
- lines.push("", "在会话中输入 /effort <effort> 切换 effort");
1822
- await platform.sendText(chatId, lines.join("\n")).catch(() => {});
1823
- } else {
1824
- const card = buildEffortCard(currentEffort, efforts, defaultTool);
1825
- await platform.sendRawCard(chatId, card);
1826
- }
1827
- logTrace(tid, "DONE", { outcome: "effort_query", defaultTool });
1828
- return;
1829
- }
1830
-
1831
- if (isCommandText && textLower.startsWith("/effort ")) {
1832
- const defaultTool = resolveDefaultAgentTool();
1833
- const toolLabel = toolDisplayName(defaultTool);
1834
- const msg = `当前没有绑定会话。请先进入 Claude/Codex 会话,再输入 /effort <effort> 切换当前会话的 effort。当前默认 agent: ${toolLabel}`;
1835
- await (platform.kind === "wechat"
1836
- ? platform.sendText(chatId, msg)
1837
- : platform.sendCard(chatId, "Effort 切换", msg, "yellow")
1838
- ).catch(() => {});
1839
- logTrace(tid, "DONE", { outcome: "effort_no_session", defaultTool });
1840
- return;
1841
- }
1842
-
1843
- if (isCommandText && textLower === "/sessions") {
1805
+ if (isCommandText && textLower === "/effort") {
1806
+ const defaultTool = resolveDefaultAgentTool();
1807
+ const efforts = getAllEffortsForTool(defaultTool);
1808
+ const currentEffort = getDefaultEffortForTool(defaultTool);
1809
+ const toolLabel = toolDisplayName(defaultTool);
1810
+
1811
+ if (efforts.length === 0) {
1812
+ const msg = `当前默认 agent (${toolLabel}) 不支持 effort 切换。`;
1813
+ await (platform.kind === "wechat"
1814
+ ? platform.sendText(chatId, msg)
1815
+ : platform.sendCard(chatId, "Effort 切换", msg, "red")
1816
+ ).catch(() => {});
1817
+ } else if (platform.kind === "wechat") {
1818
+ const lines = [currentEffort ? `当前默认 effort (${toolLabel}): ${currentEffort}` : `当前默认 effort (${toolLabel}): 未指定`];
1819
+ lines.push("", "可切换 effort:");
1820
+ for (const e of efforts) lines.push(` ${e}`);
1821
+ lines.push("", "在会话中输入 /effort <effort> 切换 effort");
1822
+ await platform.sendText(chatId, lines.join("\n")).catch(() => {});
1823
+ } else {
1824
+ const card = buildEffortCard(currentEffort, efforts, defaultTool);
1825
+ await platform.sendRawCard(chatId, card);
1826
+ }
1827
+ logTrace(tid, "DONE", { outcome: "effort_query", defaultTool });
1828
+ return;
1829
+ }
1830
+
1831
+ if (isCommandText && textLower.startsWith("/effort ")) {
1832
+ const defaultTool = resolveDefaultAgentTool();
1833
+ const toolLabel = toolDisplayName(defaultTool);
1834
+ const msg = `当前没有绑定会话。请先进入 Claude/Codex 会话,再输入 /effort <effort> 切换当前会话的 effort。当前默认 agent: ${toolLabel}`;
1835
+ await (platform.kind === "wechat"
1836
+ ? platform.sendText(chatId, msg)
1837
+ : platform.sendCard(chatId, "Effort 切换", msg, "yellow")
1838
+ ).catch(() => {});
1839
+ logTrace(tid, "DONE", { outcome: "effort_no_session", defaultTool });
1840
+ return;
1841
+ }
1842
+
1843
+ if (isCommandText && textLower === "/sessions") {
1844
1844
  logTrace(tid, "BRANCH", { cmd: "/sessions", scope: "global" });
1845
1845
  const allSessions = await getAllSessionsStatus();
1846
1846
  const now = Date.now();