chatccc 0.2.286 → 0.2.288

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.
@@ -29,7 +29,7 @@ function compressWechatDisplayText(text) {
29
29
  }
30
30
  import { readStreamState, writeStreamState, createEmptyStreamState, isFinalReplySentForTurn, markFinalReplySent, } from "./stream-state.js";
31
31
  import { addCardToTurn, finalizeTurnCards, markCardDone } from "./turn-cards.js";
32
- import { bindChatToSession, unbindChatFromSession, getChatsForSession, activePrompts, displayCards, unifiedDisplayLoopHandle, setUnifiedDisplayLoopHandle, rebuildSessionChatsFromRegistry, recordLastActiveChat, getLastActiveChat, pickDisplayChat, dequeueMessage, consumeQueuedMessage, cancelQueuedMessage, setQueuePreservedChat, consumeQueuePreservedChat, markSessionFinalizing, clearSessionFinalizing, reserveAutoRecovery, consumeAutoRecoveryReservation, cancelAutoRecoveryReservation, hasAutoRecoveryReservation, } from "./session-chat-binding.js";
32
+ import { bindChatToSession, unbindChatFromSession, getChatsForSession, activePrompts, displayCards, unifiedDisplayLoopHandle, setUnifiedDisplayLoopHandle, rebuildSessionChatsFromRegistry, recordLastActiveChat, getLastActiveChat, pickDisplayChat, dequeueMessage, consumeQueuedMessage, cancelQueuedMessage, shiftInjection, unshiftInjection, drainRemainingInjections, clearInjections, setQueuePreservedChat, consumeQueuePreservedChat, markSessionFinalizing, clearSessionFinalizing, reserveAutoRecovery, consumeAutoRecoveryReservation, cancelAutoRecoveryReservation, hasAutoRecoveryReservation, } from "./session-chat-binding.js";
33
33
  async function sendFinalReplyTextOnce(platform, chatId, sessionId, turnCount, text) {
34
34
  const sent = await platform.sendText(chatId, text).then((ok) => ok !== false).catch(() => false);
35
35
  if (sent)
@@ -827,6 +827,10 @@ export function accumulateBlockContent(block, state, toolCallMap) {
827
827
  }
828
828
  case "agent_status":
829
829
  break;
830
+ case "input_injected":
831
+ // 协作式让位:显示一条轻量注入标记(仅过程展示,不进入最终回复)。
832
+ state.accumulatedContent += `\n\n↳ 已注入新消息:${block.text}\n`;
833
+ break;
830
834
  }
831
835
  }
832
836
  export async function switchChatBinding(args) {
@@ -1283,6 +1287,8 @@ export async function runAgentSession(sessionId, userText, platform, _chatId, ms
1283
1287
  }
1284
1288
  }
1285
1289
  try {
1290
+ // 供 onInjectionRejected 退回的“最后一条已取出但未成功注入”的消息
1291
+ let lastShiftedInjection = null;
1286
1292
  for await (const unifiedMsg of adapter.prompt(sessionId, userTextWithCapabilities, cwd, controller.signal, {
1287
1293
  onProcessStart: (processInfo) => {
1288
1294
  startPromptProcessMonitor(sessionId, processInfo);
@@ -1299,6 +1305,24 @@ export async function runAgentSession(sessionId, userText, platform, _chatId, ms
1299
1305
  if (prompt)
1300
1306
  prompt.closeSession = closeSession;
1301
1307
  },
1308
+ // ccc 内核与 codex app-server 支持协作式让位:同步从注入队列取队首文本,
1309
+ // 供适配器在每个 model step 边界吸收。其他 adapter 忽略该字段。
1310
+ drainInput: tool === "ccc" || tool === "codex" ? () => {
1311
+ const injected = shiftInjection(sessionId);
1312
+ if (!injected)
1313
+ return undefined;
1314
+ lastShiftedInjection = injected;
1315
+ // 与首次消息保持一致的结构化包装;imSkillsPrompt 已在首次消息中,
1316
+ // 此处不重复注入,避免多轮注入导致上下文膨胀。
1317
+ return `[User message]\n${injected.text}\n[/User message]`;
1318
+ } : undefined,
1319
+ // 注入未被当前 turn 吸收(如 turn 恰好已结束)时,退回队列头部,避免丢消息。
1320
+ onInjectionRejected: tool === "ccc" || tool === "codex" ? () => {
1321
+ if (lastShiftedInjection) {
1322
+ unshiftInjection(sessionId, lastShiftedInjection);
1323
+ lastShiftedInjection = null;
1324
+ }
1325
+ } : undefined,
1302
1326
  })) {
1303
1327
  if (unifiedMsg.isFinalResponse) {
1304
1328
  const prompt = activePrompts.get(sessionId);
@@ -1630,11 +1654,20 @@ export async function runAgentSession(sessionId, userText, platform, _chatId, ms
1630
1654
  if (discarded) {
1631
1655
  console.log(`[${ts()}] [QUEUE] Discarding queued message for stopped session ${sessionId}`);
1632
1656
  }
1657
+ const discardedInjections = drainRemainingInjections(sessionId);
1658
+ if (discardedInjections.length > 0) {
1659
+ console.log(`[${ts()}] [INJECT] Discarding ${discardedInjections.length} pending injection(s) for stopped session ${sessionId}`);
1660
+ }
1633
1661
  }
1634
1662
  else if (!shouldScheduleAutoRecovery) {
1635
1663
  // 第一次 response-stall 后保留普通缓存;恢复轮结束后由恢复轮的
1636
1664
  // finally 再消费,顺序固定为“自动恢复 → 用户缓存”。
1637
1665
  queuedForConsumption = dequeueMessage(sessionId);
1666
+ // ccc/codex 注入队列剩余(turn 期间未注入完,如 non-streaming 或收尾窗口到达)
1667
+ // 取第一条转普通消费,其余留待下一轮结束后继续消费。
1668
+ if (!queuedForConsumption) {
1669
+ queuedForConsumption = shiftInjection(sessionId);
1670
+ }
1638
1671
  }
1639
1672
  if (queuedForConsumption) {
1640
1673
  const queued = queuedForConsumption;
@@ -2043,6 +2076,7 @@ export function stopSession(sessionId) {
2043
2076
  if (!prompt) {
2044
2077
  if (cancelledRecovery) {
2045
2078
  cancelQueuedMessage(sessionId);
2079
+ clearInjections(sessionId);
2046
2080
  console.log(`[${ts()}] [STOP] Reserved automatic recovery for ${sessionId} cancelled`);
2047
2081
  return true;
2048
2082
  }
@@ -2054,6 +2088,7 @@ export function stopSession(sessionId) {
2054
2088
  clearPromptAvatarRefreshTimer(sessionId);
2055
2089
  clearPromptFinalResponseCloseTimer(sessionId);
2056
2090
  cancelQueuedMessage(sessionId);
2091
+ clearInjections(sessionId);
2057
2092
  // 先发起整棵进程树清理,再触发 close/abort。Windows 上 CLI 由
2058
2093
  // cmd.exe → node → 实际二进制组成;若先 process.kill(cmd.exe),taskkill
2059
2094
  // 随后便无法从已消失的根 PID 找到后代,正是幽灵 Codex/Cursor 的来源。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatccc",
3
- "version": "0.2.286",
3
+ "version": "0.2.288",
4
4
  "description": "Feishu bot bridge for Claude Code",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",