claude-telegram-bot 0.3.17 → 0.3.19

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/bot.mjs +31 -4
  2. package/package.json +1 -1
package/bot.mjs CHANGED
@@ -134,6 +134,7 @@ const STR = {
134
134
  `${cfg.name || "Claude Code Telegram bot"}\n\n` +
135
135
  "• Just send a message and Claude works in the project.\n" +
136
136
  "• /new — reset conversation context (new session)\n" +
137
+ "• /compact — compress context to free up space (keeps the session)\n" +
137
138
  "• /stop — stop the current task · /stop --reset to also roll back the session\n" +
138
139
  "• /cron — list tasks · /cron add <natural language> to add · /cron rm <id> to remove\n" +
139
140
  "• /remember <text> — save to persistent memory (survives /new)\n" +
@@ -145,6 +146,9 @@ const STR = {
145
146
  "• /id — show this chat ID\n" +
146
147
  `\nWorking dir: ${cfg.projectDir}\nPermission mode: ${cfg.permissionMode}`,
147
148
  newSession: "🆕 Started a new conversation (previous context cleared).",
149
+ compactOk: "🗜️ Context compacted. The conversation continues with a summary.",
150
+ compactFail: (m) => `⚠️ Compact failed: ${m}`,
151
+ compactNoSession: "No active session to compact. Just send a message to start one.",
148
152
  busy: "⏳ A previous task is still running. Please try again when it finishes.",
149
153
  queued: (n) => `⏳ Queued (#${n}). Will run when the current task finishes.`,
150
154
  stopOk: "🛑 Task stopped.",
@@ -203,12 +207,14 @@ const STR = {
203
207
  reserveRm: "🚫 Scheduled retry canceled.",
204
208
  reserveNone: "No retry is scheduled.",
205
209
  reserveNoLimit: "No recent usage limit error. Send a message first.",
210
+ contextTooLong: "⚠️ Prompt is too long. Use `/compact` to compress context, or `/new` to start fresh.",
206
211
  },
207
212
  ko: {
208
213
  help: () =>
209
214
  `${cfg.name || "Claude Code 텔레그램 봇"}\n\n` +
210
215
  "• 그냥 메시지를 보내면 Claude가 프로젝트에서 작업합니다.\n" +
211
216
  "• /new — 대화 맥락 초기화 (새 세션)\n" +
217
+ "• /compact — 컨텍스트 압축 (세션 유지, 공간 확보)\n" +
212
218
  "• /stop — 진행 중인 작업 중단 · /stop --reset 으로 세션도 되돌리기\n" +
213
219
  "• /cron — 예약 작업 보기 · /cron add <자연어>로 추가 · /cron rm <번호>로 삭제\n" +
214
220
  "• /remember <내용> — 퍼시스턴트 메모리에 저장 (/new 로 초기화해도 유지)\n" +
@@ -277,6 +283,10 @@ const STR = {
277
283
  reserveRm: "🚫 예약된 재시도를 취소했습니다.",
278
284
  reserveNone: "예약된 재시도가 없습니다.",
279
285
  reserveNoLimit: "최근 한도 초과 에러가 없습니다. 먼저 메시지를 보내주세요.",
286
+ compactOk: "🗜️ 컨텍스트를 압축했습니다. 대화가 요약본으로 이어집니다.",
287
+ compactFail: (m) => `⚠️ compact 실패: ${m}`,
288
+ compactNoSession: "압축할 활성 세션이 없습니다. 메시지를 보내 세션을 시작하세요.",
289
+ contextTooLong: "⚠️ 프롬프트가 너무 깁니다. `/compact` 로 컨텍스트를 압축하거나 `/new` 로 새 세션을 시작하세요.",
280
290
  },
281
291
  };
282
292
  const t = (l, key, ...a) => {
@@ -291,6 +301,7 @@ const MODEL_SUGGESTIONS = ["fable", "opus", "sonnet", "haiku"];
291
301
  const COMMANDS = {
292
302
  en: [
293
303
  { command: "new", description: "Reset context (new session)" },
304
+ { command: "compact", description: "Compress context to free up space (keeps session)" },
294
305
  { command: "stop", description: "Stop the current task (--reset to roll back session)" },
295
306
  { command: "remember", description: "Save to persistent memory (survives /new)" },
296
307
  { command: "memory", description: "View or clear persistent memory" },
@@ -304,6 +315,7 @@ const COMMANDS = {
304
315
  ],
305
316
  ko: [
306
317
  { command: "new", description: "대화 맥락 초기화 (새 세션)" },
318
+ { command: "compact", description: "컨텍스트 압축 (세션 유지, 공간 확보)" },
307
319
  { command: "stop", description: "작업 중단 (--reset 으로 세션 되돌리기)" },
308
320
  { command: "remember", description: "퍼시스턴트 메모리에 저장 (/new 후에도 유지)" },
309
321
  { command: "memory", description: "메모리 보기·삭제" },
@@ -533,8 +545,8 @@ function classifyClaudeError(raw, code) {
533
545
  return "⏱️ 요청이 너무 많습니다. 잠시 후 다시 시도해주세요.";
534
546
  if (t.includes("overloaded") || code === 529)
535
547
  return "🔄 Claude 서버가 일시적으로 과부하 상태입니다. 잠시 후 다시 시도해주세요.";
536
- if (t.includes("context") && (t.includes("length") || t.includes("limit") || t.includes("window")))
537
- return "📏 대화 맥락이 너무 길어졌습니다. `/new` 로 새 세션을 시작해주세요.";
548
+ if (t.includes("prompt is too long") || (t.includes("context") && (t.includes("length") || t.includes("limit") || t.includes("window"))))
549
+ return "contextTooLong";
538
550
  return `Execution error (exit ${code}):\n${raw}`;
539
551
  }
540
552
 
@@ -828,7 +840,7 @@ async function downloadAttachment(att) {
828
840
  const dir = ATTACH_DIR;
829
841
  mkdirSync(dir, { recursive: true });
830
842
  const ext = filePath.includes(".") ? filePath.slice(filePath.lastIndexOf(".")) : "";
831
- const name = att.name || `tg-${att.fileId.slice(-10)}${ext}`;
843
+ const name = att.name || `tg-${Date.now()}-${att.fileId.slice(-6)}${ext}`;
832
844
  const dest = join(dir, name);
833
845
  writeFileSync(dest, buf);
834
846
  return { dest, name };
@@ -932,6 +944,20 @@ async function handle(msg) {
932
944
  });
933
945
  return;
934
946
  }
947
+ if (text === "/compact") {
948
+ if (!state.sessionId) { await send(chatId, t(l, "compactNoSession")); return; }
949
+ try {
950
+ const res = await runClaude("/compact", state.sessionId);
951
+ if (res.ok !== false) {
952
+ await send(chatId, t(l, "compactOk"));
953
+ } else {
954
+ await send(chatId, t(l, "compactFail", res.text));
955
+ }
956
+ } catch (e) {
957
+ await send(chatId, t(l, "compactFail", e.message));
958
+ }
959
+ return;
960
+ }
935
961
  if (text === "/new") {
936
962
  state.sessionId = undefined;
937
963
  saveState(state);
@@ -1054,7 +1080,8 @@ async function handle(msg) {
1054
1080
  // 레이트 리밋이고 리셋 시간을 알면 /reserve 힌트 추가
1055
1081
  const hint = res.resetAt ? t(l, "reserveHint") : "";
1056
1082
  rateLimitState = res.resetAt ? { prompt, resetAt: res.resetAt } : null;
1057
- if (!stopping) await send(chatId, `⚠️ ${res.text}${hint}`);
1083
+ const errMsg = res.text === "contextTooLong" ? t(l, "contextTooLong") : `⚠️ ${res.text}${hint}`;
1084
+ if (!stopping) await send(chatId, errMsg);
1058
1085
  } else {
1059
1086
  rateLimitState = null;
1060
1087
  const footer = `\n\n— ${secs}s${res.cost ? ` · $${res.cost.toFixed(4)}` : ""}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-telegram-bot",
3
- "version": "0.3.17",
3
+ "version": "0.3.19",
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": {