chatccc 0.2.66 → 0.2.67

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.
@@ -1,11 +1,11 @@
1
- ---
2
- name: wechat-image-skill
3
- description: WeChat iLink local skills for sending and receiving images.
4
- ---
5
-
6
- Current working directory: {{cwd}}
7
-
8
- WeChat images are handled through the iLink SDK. The local server does NOT have HTTP RPC endpoints for WeChat; use the helper scripts below instead.
9
-
10
- - **Receive images**: Images sent to the bot are automatically downloaded to `~/.chatccc/images/downloads/` with the filename prefix `wx_`. The message text will include the local path as `[图片] <absolute path>` — read `{{im_skills_cache_dir}}/wechat-image-skill/receive-send-image.md`
1
+ ---
2
+ name: wechat-image-skill
3
+ description: WeChat iLink local skills for sending and receiving images.
4
+ ---
5
+
6
+ Current working directory: {{cwd}}
7
+
8
+ WeChat images are handled through the iLink SDK. The local server does NOT have HTTP RPC endpoints for WeChat; use the helper scripts below instead.
9
+
10
+ - **Receive images**: Images sent to the bot are automatically downloaded to `~/.chatccc/images/downloads/` with the filename prefix `wx_`. The message text will include the local path as `[图片] <absolute path>` — read `{{im_skills_cache_dir}}/wechat-image-skill/receive-send-image.md`
11
11
  - **Send images**: Use the send-image helper script — read `{{im_skills_cache_dir}}/wechat-image-skill/receive-send-image.md`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatccc",
3
- "version": "0.2.66",
3
+ "version": "0.2.67",
4
4
  "description": "Feishu bot bridge for Claude Code",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
package/src/im-skills.ts CHANGED
@@ -70,6 +70,37 @@ export async function buildImSkillsPrompt(input: BuildImSkillsPromptInput): Prom
70
70
  .join("\n\n");
71
71
  }
72
72
 
73
+ // ---------------------------------------------------------------------------
74
+ // 会话级缓存:相同 session_id + cwd 的渲染结果完全相同,避免每轮重复读文件+渲染
75
+ // ---------------------------------------------------------------------------
76
+
77
+ const promptCache = new Map<string, string>();
78
+
79
+ function promptCacheKey(input: BuildImSkillsPromptInput): string {
80
+ const names = input.enabledSkillNames
81
+ ? [...input.enabledSkillNames].sort().join(",")
82
+ : "*";
83
+ const { session_id, cwd } = input.variables;
84
+ return `${input.skillsDir ?? DEFAULT_IM_SKILLS_DIR}|${names}|${session_id}|${cwd}`;
85
+ }
86
+
87
+ /** 带会话级缓存的 buildImSkillsPrompt。同 session + 同 cwd 时直接返回缓存的渲染结果。 */
88
+ export async function buildImSkillsPromptCached(input: BuildImSkillsPromptInput): Promise<string> {
89
+ const key = promptCacheKey(input);
90
+ const cached = promptCache.get(key);
91
+ if (cached !== undefined) return cached;
92
+ const result = await buildImSkillsPrompt(input);
93
+ promptCache.set(key, result);
94
+ return result;
95
+ }
96
+
97
+ /** 清除指定会话的缓存(如 /cd 后 cwd 变了,旧 key 不再需要) */
98
+ export function clearImSkillsPromptCache(sessionId: string): void {
99
+ for (const key of promptCache.keys()) {
100
+ if (key.includes(`|${sessionId}|`)) promptCache.delete(key);
101
+ }
102
+ }
103
+
73
104
  /**
74
105
  * 渲染技能目录下的子文档(skill.md 除外)并写入 outputDir。
75
106
  * 返回写入的文件路径列表。通常在会话初始化时调用,写入的文档供 Agent 按需读取。
@@ -21,6 +21,7 @@ import {
21
21
  setDefaultCwd,
22
22
  getRecentDirs,
23
23
  addRecentDir,
24
+ resolveDefaultAgentTool,
24
25
  sessionPrefixForTool,
25
26
  toolDisplayName,
26
27
  ts,
@@ -240,7 +241,7 @@ export async function handleCommand(
240
241
 
241
242
  if (textLower === "/new" || textLower.startsWith("/new ")) {
242
243
  const toolArg = text.slice(5).trim().toLowerCase();
243
- const tool = toolArg || "claude";
244
+ const tool = toolArg || resolveDefaultAgentTool();
244
245
  logTrace(tid, "BRANCH", { cmd: "/new", tool });
245
246
  const validTools = ["claude", "cursor", "codex"];
246
247
  if (!validTools.includes(tool)) {
@@ -643,7 +644,7 @@ export async function handleCommand(
643
644
  model: s.model,
644
645
  tool: s.tool,
645
646
  }));
646
- const card = buildSessionsCard(cardData);
647
+ const card = buildSessionsCard(cardData, { defaultToolLabel: toolDisplayName(resolveDefaultAgentTool()) });
647
648
  const ok = await platform.sendRawCard(chatId, card);
648
649
  console.log(
649
650
  `[${ts()}] [SESSIONS] card sent, ok=${ok}, count=${cardData.length}`,
@@ -1032,7 +1033,7 @@ export async function handleCommand(
1032
1033
 
1033
1034
  // 无会话上下文 → help card
1034
1035
  logTrace(tid, "SEND", { method: "help_card", chatId });
1035
- const card = buildHelpCard(text);
1036
+ const card = buildHelpCard(text, { defaultToolLabel: toolDisplayName(resolveDefaultAgentTool()) });
1036
1037
  const ok = await platform.sendRawCard(chatId, card);
1037
1038
  if (!ok) {
1038
1039
  console.error(`[${ts()}] [SEND] help_card FAIL: chatId=${chatId}`);
package/src/session.ts CHANGED
@@ -28,7 +28,7 @@ import type { ToolAdapter } from "./adapters/adapter-interface.ts";
28
28
  import { createClaudeAdapter } from "./adapters/claude-adapter.ts";
29
29
  import { createCursorAdapter } from "./adapters/cursor-adapter.ts";
30
30
  import { createCodexAdapter } from "./adapters/codex-adapter.ts";
31
- import { buildImSkillsPrompt, exportSkillSubDocs } from "./im-skills.ts";
31
+ import { buildImSkillsPromptCached, exportSkillSubDocs, clearImSkillsPromptCache } from "./im-skills.ts";
32
32
  import type { PlatformAdapter } from "./platform-adapter.ts";
33
33
 
34
34
  // 微信显示循环压缩:头5 + ... + 尾5,避免在最后一步 sendText 中压缩指令回复
@@ -734,7 +734,7 @@ export async function runAgentSession(
734
734
  wechat_send_video_script: join(wechatVideoSkillDir, "send-video.mjs"),
735
735
  };
736
736
  const enabledSkillNames = imSkillNamesForPlatform(platform);
737
- var imSkillsPrompt = await buildImSkillsPrompt({ variables: skillVariables, enabledSkillNames });
737
+ var imSkillsPrompt = await buildImSkillsPromptCached({ variables: skillVariables, enabledSkillNames });
738
738
  await exportSkillSubDocs({ variables: skillVariables, enabledSkillNames }, imSkillsCacheDir);
739
739
  var userTextWithCapabilities = [
740
740
  ...(imSkillsPrompt ? [imSkillsPrompt, ""] : []),