@raolin2025/claude-code-node 2.7.4 → 2.7.6

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/core/cli.js +33 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raolin2025/claude-code-node",
3
- "version": "2.7.4",
3
+ "version": "2.7.6",
4
4
  "description": "Node.js AI Code Agent CLI - Zero dependencies, pure JavaScript, security hardened, multi-channel notifications, Telegram & QQ Bot remote programming, rich media upload, multi-account management",
5
5
  "type": "module",
6
6
  "main": "src/core/index.js",
package/src/core/cli.js CHANGED
@@ -590,6 +590,8 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
590
590
  let pendingConfirm = null
591
591
  // 等待中的 Telegram AskUserQuestion 回答(resolve 回调)— 远程用户回复任意文本时响应
592
592
  let pendingAskUser = null
593
+ // 取消当前等待中的 AskUserQuestion(用户 /stop 时调用,resolve 为取消标记,避免死锁)
594
+ let cancelAskUser = null
593
595
  // 最近一次 /models 拉取的模型列表(供 /model <编号> 选择)
594
596
  let modelList = []
595
597
  // /models 从 Telegram 发出后,等待用户回复编号/名字来选择模型
@@ -613,7 +615,8 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
613
615
  if (source === 'telegram' && pendingAskUser && !trimmed.startsWith('/')) {
614
616
  const ask = pendingAskUser
615
617
  pendingAskUser = null
616
- ask(trimmed)
618
+ cancelAskUser = null
619
+ ask.fn(trimmed)
617
620
  return
618
621
  }
619
622
  if (source === 'telegram' && pendingConfirm && !trimmed.startsWith('/')) {
@@ -808,7 +811,14 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
808
811
  console.log('Conversation cleared')
809
812
  break
810
813
  case 'stop':
811
- // 停止当前正在运行的 AI 工作(如卡死 / 长时间无响应时)
814
+ // 停止当前正在运行的 AI 工作(如卡死 / 长时间无响应时)。
815
+ // 若正在等待 AskUserQuestion 回答,先取消提问(resolve 取消标记),避免引擎挂起。
816
+ if (pendingAskUser) {
817
+ const cancel = cancelAskUser
818
+ pendingAskUser = null
819
+ cancelAskUser = null
820
+ if (cancel) cancel()
821
+ }
812
822
  if (engine.state.isRunning) {
813
823
  engine.abort()
814
824
  console.log('⏹️ 已发送停止信号,正在中止当前工作...')
@@ -1008,7 +1018,10 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
1008
1018
  // 让远程用户看到 AI 正在工作,而不是"以为没回应"。
1009
1019
  // 采用节流 + 编辑同一消息的方式,避免刷屏和触发速率限制。
1010
1020
  // ============================================================
1011
- const tgThinking = { buffer: '', timer: null, target: null, lastMsgId: null, flushing: false, typingTimer: null }
1021
+ const tgThinking = { buffer: '', timer: null, target: null, lastMsgId: null, flushing: false, typingTimer: null, lastResetAt: 0 }
1022
+ // 周期性重置"🧠 思考中…"消息,避免它无限膨胀成一个无法判断是否仍在工作的静态块。
1023
+ // 每隔 RESET_MS 就删掉旧消息、发一条新的,让用户每隔几秒看到一次明确的活动信号。
1024
+ const TG_THINKING_RESET_MS = 5000
1012
1025
 
1013
1026
  // Telegram 的 typing 提示约 5 秒后自动消失。若 cc-node 处理耗时较长
1014
1027
  //(如执行工具、读取文件、多轮思考),单次 sendChatAction 撑不住整个周期,
@@ -1036,6 +1049,7 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
1036
1049
  tgThinking.buffer = ''
1037
1050
  tgThinking.lastMsgId = null
1038
1051
  tgThinking.flushing = false
1052
+ tgThinking.lastResetAt = Date.now()
1039
1053
  // 先发送 typing 动作,让 Telegram 立即显示"正在输入",并启动心跳保持持续显示
1040
1054
  if (tgListener?.bot && tgThinking.target) {
1041
1055
  tgListener.bot.sendChatAction(tgThinking.target, 'typing').catch(() => {})
@@ -1062,6 +1076,14 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
1062
1076
  const target = tgThinking.target
1063
1077
  const body = `🧠 思考中…\n\n${tgThinking.buffer.slice(-3500)}`
1064
1078
  try {
1079
+ // 周期性重置:若已有一条消息且距上次重置超过阈值,删除旧消息并发新消息,
1080
+ // 让用户每隔几秒看到"🧠 思考中…"重新出现,明确 AI 仍在工作(而非已卡死/完成)。
1081
+ const needReset = tgThinking.lastMsgId && (Date.now() - tgThinking.lastResetAt) >= TG_THINKING_RESET_MS
1082
+ if (needReset) {
1083
+ tgListener.bot.deleteMessage(target, tgThinking.lastMsgId).catch(() => {})
1084
+ tgThinking.lastMsgId = null
1085
+ tgThinking.lastResetAt = Date.now()
1086
+ }
1065
1087
  if (tgThinking.lastMsgId) {
1066
1088
  await tgListener.bot.editMessage(target, tgThinking.lastMsgId, body, { parseMode: 'HTML' })
1067
1089
  } else {
@@ -1140,17 +1162,16 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
1140
1162
  // - CLI 本地模式:走本地终端交互(inputCtrl.ask)
1141
1163
  engine.config.onAskUser = (question) => {
1142
1164
  if (currentSource === 'telegram' && tgListener?.bot) {
1143
- const promptText = `❓ ${question}\n\n请直接回复你的回答。`
1165
+ const promptText = `❓ ${question}\n\n请直接回复你的回答。\n(发 /stop 可取消本次提问)`
1144
1166
  sendTelegram(promptText, null).catch(() => {})
1145
1167
  return new Promise((resolve) => {
1146
- // 60 秒内未回复则自动跳过,避免远程提问永久挂起阻塞引擎
1147
- const timer = setTimeout(() => {
1148
- if (pendingAskUser === resolve) pendingAskUser = null
1149
- resolve('(用户未在 60 秒内回答)')
1150
- }, 60000)
1151
- pendingAskUser = (val) => {
1152
- clearTimeout(timer)
1153
- resolve(val)
1168
+ // 一直等待用户回答——不设超时自行结束(超时会吞掉迟到回答,违背"等待回答"语义)。
1169
+ // 用户回复任意文本即作为回答;用户 /stop 则通过 cancelAskUser 取消(resolve 取消标记,避免死锁)。
1170
+ pendingAskUser = { fn: (val) => resolve(val) }
1171
+ cancelAskUser = () => {
1172
+ if (pendingAskUser) pendingAskUser = null
1173
+ cancelAskUser = null
1174
+ resolve('(提问已取消)')
1154
1175
  }
1155
1176
  })
1156
1177
  }