@raolin2025/claude-code-node 2.6.15 → 2.6.17

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": "@raolin2025/claude-code-node",
3
- "version": "2.6.15",
3
+ "version": "2.6.17",
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",
@@ -118,7 +118,9 @@ export class TelegramBotClient {
118
118
  const body = {
119
119
  chat_id: chatId,
120
120
  text: text.slice(0, 4096), // Telegram 消息最大 4096 字符
121
- parse_mode: parseMode || 'HTML',
121
+ // parseMode: null 表示降级为纯文本(去掉 parse_mode 字段);
122
+ // 否则默认 HTML,或用显式指定的 parseMode。
123
+ ...(parseMode === null ? {} : { parse_mode: parseMode || 'HTML' }),
122
124
  disable_notification: silent || false,
123
125
  disable_web_page_preview: disableWebPreview ?? true,
124
126
  }
@@ -139,9 +141,9 @@ export class TelegramBotClient {
139
141
  await new Promise(r => setTimeout(r, retryAfter * 1000))
140
142
  return this.sendMessage(chatId, text, options)
141
143
  }
142
- // 400 可能是消息太长或格式问题 — 降级为纯文本
144
+ // 400 可能是消息太长或格式问题 — 降级为纯文本(parseMode: null 去掉 parse_mode)
143
145
  if (data.error_code === 400 && parseMode) {
144
- return this.sendMessage(chatId, text, { ...options, parseMode: undefined })
146
+ return this.sendMessage(chatId, text, { ...options, parseMode: null })
145
147
  }
146
148
  throw new Error(`Telegram API ${data.error_code}: ${data.description?.slice(0, 200) || 'unknown'}`)
147
149
  }
package/src/core/cli.js CHANGED
@@ -599,6 +599,8 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
599
599
  let currentSource = 'cli'
600
600
  // 等待中的 Telegram 权限确认(resolve 回调)— 远程用户回复 y/n/a 时响应
601
601
  let pendingConfirm = null
602
+ // 最近一次 /models 拉取的模型列表(供 /model <编号> 选择)
603
+ let modelList = []
602
604
 
603
605
  // 处理输入行
604
606
  // source: 'cli' 来自终端输入, 'telegram' 来自 Telegram
@@ -634,6 +636,15 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
634
636
  }
635
637
 
636
638
  if (trimmed.startsWith('/')) {
639
+ // 来自 Telegram 的命令:捕获 console 输出并回发到 Telegram
640
+ const isTgCmd = source === 'telegram' && tgListener?.bot
641
+ let tgOut = ''
642
+ const origLog = console.log
643
+ if (isTgCmd) {
644
+ tgOut = ''
645
+ console.log = (...args) => { tgOut += args.map(String).join(' ') + '\n'; origLog(...args) }
646
+ }
647
+ try {
637
648
  const [cmd, ...rest] = trimmed.slice(1).split(' ')
638
649
  switch (cmd) {
639
650
  case 'help':
@@ -646,7 +657,16 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
646
657
  }
647
658
  break
648
659
  case 'model':
649
- if (rest[0]) { engine.config.model = rest.join(' '); console.log(`Model → ${engine.config.model}`) }
660
+ // /model <名字或编号> 支持用 /models 列表里的编号切换
661
+ if (rest[0]) {
662
+ const num = parseInt(rest[0], 10)
663
+ if (!isNaN(num) && modelList.length > 0 && num >= 1 && num <= modelList.length) {
664
+ engine.config.model = modelList[num - 1]
665
+ } else {
666
+ engine.config.model = rest.join(' ')
667
+ }
668
+ console.log(`Model → ${engine.config.model}`)
669
+ }
650
670
  else console.log(`Model: ${engine.config.model}`)
651
671
  break
652
672
  case 'models': {
@@ -668,17 +688,23 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
668
688
  const data = await res.json()
669
689
  const models = data.data || []
670
690
  if (models.length === 0) { console.log('No models returned'); break }
691
+ // 记录模型列表,供 /model <编号> 选择
692
+ modelList = models.map(m => m.id || m)
671
693
  console.log(`\nAvailable models (${models.length}):`)
672
- models.forEach((m, i) => {
673
- const id = m.id || m
694
+ modelList.forEach((id, i) => {
674
695
  console.log(` ${(i + 1).toString().padStart(2)}. ${id}`)
675
696
  })
697
+ // 来自 Telegram:直接列出,不等待 CLI 交互(用 /model 名字或编号 切换)
698
+ if (source === 'telegram') {
699
+ console.log('\nℹ️ 用 /model 名字或编号 切换模型')
700
+ break
701
+ }
676
702
  console.log('\nType a number to select, or model name directly:')
677
703
  const answer = await new Promise(resolve => rl.question('> ', resolve))
678
704
  const num = parseInt(answer, 10)
679
705
  let selected
680
- if (!isNaN(num) && num >= 1 && num <= models.length) {
681
- selected = models[num - 1].id || models[num - 1]
706
+ if (!isNaN(num) && num >= 1 && num <= modelList.length) {
707
+ selected = modelList[num - 1]
682
708
  } else if (answer.trim()) {
683
709
  selected = answer.trim()
684
710
  }
@@ -851,6 +877,13 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
851
877
  default:
852
878
  console.log(`Unknown command: /${cmd}. Type /help for available commands.`)
853
879
  }
880
+ } finally {
881
+ // 恢复 console.log 并把命令输出回发到 Telegram
882
+ if (isTgCmd) {
883
+ console.log = origLog
884
+ if (tgOut.trim()) await sendTelegram(tgOut.trim(), tgChatId || null)
885
+ }
886
+ }
854
887
  showPrompt()
855
888
  return
856
889
  }
@@ -1068,10 +1101,10 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
1068
1101
  tgReplyTarget = msg.replyTo || null
1069
1102
  const text = msg.text || msg.callbackData || ''
1070
1103
  if (!text) return
1071
- // 命令由 listener 内部处理,普通消息转给引擎
1072
- if (!text.startsWith('/')) {
1073
- await processInputLine(text, 'telegram', msg.chatId)
1074
- }
1104
+ // 普通消息和 / 命令都转给引擎(/命令由 processInputLine 处理)
1105
+ // 注意:tg-listener 已内部处理 /ping /status /run 等自己的命令,
1106
+ // 只有未识别的 / 命令(如 /models /stop /resume)才会到达这里。
1107
+ await processInputLine(text, 'telegram', msg.chatId)
1075
1108
  }).catch(e => console.error(`[TG] listener error: ${e.message}`))
1076
1109
  console.log(`✅ Telegram channel ready (bot ${tgToken.slice(0, 12)}...)`)
1077
1110
  } catch (e) {
@@ -1094,9 +1127,9 @@ const systemPrompt = cliArgs.systemPrompt || DEFAULT_SYSTEM_PROMPT
1094
1127
  // 记录全局回复目标,供权限确认 / AI 回复镜像发送到 Telegram 使用
1095
1128
  if (msg.chatId) tgChatId = msg.chatId
1096
1129
  if (msg.replyTo) tgReplyTarget = msg.replyTo
1097
- // 来自外部的消息 → 转发到 REPL 引擎
1130
+ // 来自外部的消息 → 转发到 REPL 引擎(含 / 命令,由 processInputLine 处理)
1098
1131
  const text = msg.text || ''
1099
- if (text && !text.startsWith('/')) {
1132
+ if (text) {
1100
1133
  await processInputLine(text, msg.channel || 'external', msg.chatId)
1101
1134
  }
1102
1135
  },