claude-telegram-bot 0.3.15 → 0.3.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/README.ko.md CHANGED
@@ -6,6 +6,8 @@
6
6
  [![npm downloads](https://img.shields.io/npm/dm/claude-telegram-bot.svg)](https://www.npmjs.com/package/claude-telegram-bot)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
 
9
+ 텔레그램으로 Claude Code를 — 어디서든, 어떤 기기에서도.
10
+
9
11
  텔레그램으로 메시지를 보내면, 집이나 서버에 켜둔 Claude Code가 작업하고 결과를 다시 텔레그램으로 돌려주는 봇입니다.
10
12
 
11
13
  ```
package/README.md CHANGED
@@ -6,6 +6,8 @@
6
6
  [![npm downloads](https://img.shields.io/npm/dm/claude-telegram-bot.svg)](https://www.npmjs.com/package/claude-telegram-bot)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
 
9
+ Use Claude Code from Telegram — run it anywhere, from any device.
10
+
9
11
  **A zero-dependency, single-file, daemonized Claude Code bot — no Bun, no Python, no open session.**
10
12
 
11
13
  A tiny bridge that takes your Telegram messages, runs `claude -p` (Claude Code headless mode)
package/bot.mjs CHANGED
@@ -114,6 +114,11 @@ if (!existsSync(CONFIG_PATH)) {
114
114
  const cfg = JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
115
115
  console.log({ ...cfg, token: cfg.token ? "<redacted>" : "(none)" });
116
116
  const TG = `https://api.telegram.org/bot${cfg.token}`;
117
+ // allowedChatId 는 문자열 또는 배열 모두 허용 (하위 호환)
118
+ const allowedIds = []
119
+ .concat(cfg.allowedChatId)
120
+ .filter(Boolean)
121
+ .map(String);
117
122
 
118
123
  // ── i18n (영어 기본 + 한국어) ─────────────────────────────────────────────
119
124
  // cfg.lang 를 "en"/"ko" 로 주면 그 언어로 고정. 비우면 메시지의 from.language_code 로
@@ -354,7 +359,7 @@ function isNewer(latest, current) {
354
359
  }
355
360
 
356
361
  async function checkForUpdate() {
357
- if (!cfg.allowedChatId) return;
362
+ if (!allowedIds.length) return;
358
363
  const now = Date.now();
359
364
  if (state.lastVersionCheck && now - state.lastVersionCheck < VERSION_CHECK_INTERVAL) return;
360
365
  const latest = await fetchLatestVersion();
@@ -364,9 +369,10 @@ async function checkForUpdate() {
364
369
  if (state.notifiedVersion === latest) return; // 이미 알린 버전
365
370
  state.notifiedVersion = latest;
366
371
  saveState(state);
367
- await send(cfg.allowedChatId,
368
- `✨ 업데이트가 있습니다: ${VERSION} → ${latest}\n\`npm i -g claude-telegram-bot\` 후 /restart`
369
- ).catch(() => {});
372
+ for (const id of allowedIds)
373
+ await send(id,
374
+ `✨ 업데이트가 있습니다: ${VERSION} → ${latest}\n\`npm i -g claude-telegram-bot\` 후 /restart`
375
+ ).catch(() => {});
370
376
  }
371
377
 
372
378
  // ── 퍼시스턴트 메모리 ─────────────────────────────────────────────────────
@@ -553,9 +559,9 @@ function runClaude(prompt, sessionId, opts = {}) {
553
559
  : null;
554
560
  // opts.injectMemory: 퍼시스턴트 메모리를 시스템 프롬프트에 주입 (/new 로 초기화해도 유지)
555
561
  const mem = opts.injectMemory ? loadMemory() : "";
556
- const memoryBlock = mem ? `## Persistent memory (survives /new)\n${mem}` : null;
557
- // 페르소나(cfg.persona) + 간결 지침 + 모델 힌트 + 메모리를 함께 주입
558
- const appendSys = [cfg.persona, brevity, modelHint, memoryBlock].filter(Boolean).join("\n\n");
562
+ // 메모리는 persona보다 앞에 배치하고 헤더를 강화 persona가 덮어쓰는 방지
563
+ const memoryBlock = mem ? `## RULES (must follow before anything else)\n${mem}` : null;
564
+ const appendSys = [memoryBlock, cfg.persona, brevity, modelHint].filter(Boolean).join("\n\n");
559
565
  if (appendSys) args.push("--append-system-prompt", appendSys);
560
566
  if (model) args.push("--model", model);
561
567
  if (sessionId) args.push("--resume", sessionId);
@@ -680,9 +686,9 @@ async function runScheduled(job) {
680
686
  const footer = res.ok
681
687
  ? `\n\n— ⏰ ${label} · ${secs}s${res.cost ? ` · $${res.cost.toFixed(4)}` : ""}`
682
688
  : `\n\n— ⏰ ${label}`;
683
- await send(cfg.allowedChatId, (res.ok ? res.text : `⚠️ ${res.text}`) + footer);
689
+ for (const id of allowedIds) await send(id, (res.ok ? res.text : `⚠️ ${res.text}`) + footer);
684
690
  } catch (e) {
685
- await send(cfg.allowedChatId, t(BOT_LANG, "scheduledError", e.message));
691
+ for (const id of allowedIds) await send(id, t(BOT_LANG, "scheduledError", e.message));
686
692
  } finally {
687
693
  busy = false;
688
694
  }
@@ -691,7 +697,7 @@ async function runScheduled(job) {
691
697
  function startScheduler() {
692
698
  // allowedChatId 없으면 결과를 보낼 곳이 없으니 비활성화. /cron add 로 나중에 작업이
693
699
  // 늘 수 있으므로, schedule 이 지금 비어 있어도 인터벌은 항상 돌린다(없으면 no-op).
694
- if (!cfg.allowedChatId) {
700
+ if (!allowedIds.length) {
695
701
  console.warn("allowedChatId missing → scheduler disabled");
696
702
  return;
697
703
  }
@@ -848,11 +854,11 @@ async function handle(msg) {
848
854
  if (!text && !attachment && !msg._mediaGroup?.length) return;
849
855
 
850
856
  // 화이트리스트
851
- if (!cfg.allowedChatId) {
857
+ if (!allowedIds.length) {
852
858
  await send(chatId, t(l, "needChatId", chatId));
853
859
  return;
854
860
  }
855
- if (String(chatId) !== String(cfg.allowedChatId)) {
861
+ if (!allowedIds.includes(String(chatId))) {
856
862
  console.warn(`Ignoring unauthorized chatId ${chatId}`);
857
863
  return;
858
864
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-telegram-bot",
3
- "version": "0.3.15",
3
+ "version": "0.3.17",
4
4
  "description": "Drive Claude Code from Telegram — messages run headless `claude -p` in a project dir and replies come back to the chat. Zero dependencies.",
5
5
  "type": "module",
6
6
  "bin": {