chatccc 0.2.78 → 0.2.80

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatccc",
3
- "version": "0.2.78",
3
+ "version": "0.2.80",
4
4
  "description": "Feishu bot bridge for Claude Code",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -100,6 +100,25 @@ export function pickDisplayChat(sessionId: string): string | undefined {
100
100
  return chats?.has(candidate) ? candidate : undefined;
101
101
  }
102
102
 
103
+ // ---------------------------------------------------------------------------
104
+ // queuePreservedChat: 队列消费时保留 display loop 目标 chat
105
+ // 队列消息来自其他群时,不应把 display loop 重定向到该群
106
+ // ---------------------------------------------------------------------------
107
+
108
+ const queuePreservedChatMap = new Map<string, string>();
109
+
110
+ /** 队列消费前保存当前 display chat,消费完后自动清除(一次性) */
111
+ export function setQueuePreservedChat(sessionId: string, chatId: string): void {
112
+ queuePreservedChatMap.set(sessionId, chatId);
113
+ }
114
+
115
+ /** 获取并清除队列保存的 display chat,没有则返回 undefined */
116
+ export function consumeQueuePreservedChat(sessionId: string): string | undefined {
117
+ const chat = queuePreservedChatMap.get(sessionId);
118
+ queuePreservedChatMap.delete(sessionId);
119
+ return chat;
120
+ }
121
+
103
122
  // ---------------------------------------------------------------------------
104
123
  // displayCards: chatId → 展示卡片状态(display loop 用)
105
124
  // ---------------------------------------------------------------------------
package/src/session.ts CHANGED
@@ -53,6 +53,8 @@ import {
53
53
  dequeueMessage,
54
54
  consumeQueuedMessage,
55
55
  cancelQueuedMessage,
56
+ setQueuePreservedChat,
57
+ consumeQueuePreservedChat,
56
58
  } from "./session-chat-binding.ts";
57
59
 
58
60
  // ---------------------------------------------------------------------------
@@ -680,8 +682,9 @@ export async function runAgentSession(
680
682
  const tid = traceId ?? "";
681
683
 
682
684
  // 记录用户最后发送消息的群(display loop 只推送到该群)
685
+ // 如果是从队列消费且队列消息来自其他群,保留原来的 display chat
683
686
  recordChatPlatform(_chatId, platform);
684
- recordLastActiveChat(sessionId, _chatId);
687
+ recordLastActiveChat(sessionId, consumeQueuePreservedChat(sessionId) ?? _chatId);
685
688
 
686
689
  // 并发检查:同一 session 只能有一个活跃 prompt
687
690
  if (activePrompts.has(sessionId)) {
@@ -858,16 +861,10 @@ export async function runAgentSession(
858
861
  const wasStopped = prompt?.stopped ?? false;
859
862
  activePrompts.delete(sessionId);
860
863
 
861
- // 消费队列中的缓存消息(异步,不阻塞后续清理)
862
- const queued = dequeueMessage(sessionId);
863
- if (queued) {
864
- console.log(`[${ts()}] [QUEUE] Consuming queued message for session ${sessionId}: "${queued.text.slice(0, 50)}"`);
865
- setImmediate(() => {
866
- consumeQueuedMessage(platform, queued);
867
- });
868
- }
869
-
870
- // 写最终状态
864
+ // 先写最终状态(done/stopped),确保 display loop 在下一轮消费前
865
+ // 读到新状态并终结旧卡片。否则 setImmediate 在 CHECK 阶段先于
866
+ // writeFile I/O(POLL 阶段)执行,display loop 会误以为旧轮仍在
867
+ // 运行中并更新旧卡片,而不是新建卡片。
871
868
  const finalStatus = wasStopped ? "stopped" : "done";
872
869
  const finalReply = pickFinalReply(state).trim();
873
870
  await writeStreamState({
@@ -883,6 +880,30 @@ export async function runAgentSession(
883
880
  tool,
884
881
  });
885
882
 
883
+ // 消费队列中的缓存消息(异步,不阻塞后续清理)
884
+ // 用户 /stop 后应丢弃队列消息,避免用户停止后又自动开始新轮
885
+ if (wasStopped) {
886
+ const discarded = dequeueMessage(sessionId);
887
+ if (discarded) {
888
+ console.log(`[${ts()}] [QUEUE] Discarding queued message for stopped session ${sessionId}`);
889
+ }
890
+ } else {
891
+ const queued = dequeueMessage(sessionId);
892
+ if (queued) {
893
+ // 队列消息可能来自其他群,保存当前 display chat 避免 display loop 被
894
+ // 错误重定向(runAgentSession 会 consumeQueuePreservedChat 并在存在时
895
+ // 用保存的 chat 替代 queued.chatId 作为 display 目标)
896
+ const preservedChat = getLastActiveChat(sessionId);
897
+ if (preservedChat && preservedChat !== queued.chatId) {
898
+ setQueuePreservedChat(sessionId, preservedChat);
899
+ }
900
+ console.log(`[${ts()}] [QUEUE] Consuming queued message for session ${sessionId}: "${queued.text.slice(0, 50)}"`);
901
+ setImmediate(() => {
902
+ consumeQueuedMessage(platform, queued);
903
+ });
904
+ }
905
+ }
906
+
886
907
  // display loop 下一轮会读到最终状态并发送消息
887
908
 
888
909
  if (wasStopped) {