claude-telegram-bot 0.2.3 → 0.2.4

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
@@ -100,7 +100,7 @@ claude-telegram-bot ~/botconfigs/myproj/config.json
100
100
  | `env` | (선택) `claude` 프로세스에 넘길 환경 변수 |
101
101
  | `schedule` | (선택) 정해진 시각에 프롬프트를 실행하는 cron 작업 — [예약 작업](#예약-작업-cron) 참고 |
102
102
 
103
- `state.json`과 첨부 파일(`attachments/`) config 파일과 같은 폴더에 저장됩니다. 그래서 config만 따로 두면 프로젝트끼리 섞이지 않습니다.
103
+ `state`와 첨부 파일은 config 파일 옆 **`.claude-bot/` 숨김 폴더**에 저장됩니다(프로젝트 격리). 구버전에서 올리면 시작 기존 `state.json`·`attachments/`를 `.claude-bot/`로 **자동 이동**합니다(무손실). 로그는 launchd plist가 가리키는 위치 그대로입니다.
104
104
 
105
105
  ## 첫 실행
106
106
 
package/README.md CHANGED
@@ -192,8 +192,10 @@ Edit `config.json`:
192
192
  | `env` | (optional) Extra environment variables passed to the `claude` process |
193
193
  | `schedule` | (optional) Cron jobs that run a prompt on a timer — see [Scheduled tasks](#scheduled-tasks-cron) |
194
194
 
195
- State (`state.json`) and downloaded `attachments/` are written **next to the config file**, so
196
- projects stay isolated.
195
+ State and downloaded attachments live in a hidden **`.claude-bot/`** folder next to the config
196
+ file, so projects stay isolated. Upgrading from an older version **auto-moves** an existing
197
+ `state.json` / `attachments/` into `.claude-bot/` on first start (no data loss). Logs stay wherever
198
+ your launchd plist points them.
197
199
 
198
200
  ### Usage details
199
201
 
package/bot.mjs CHANGED
@@ -14,7 +14,7 @@
14
14
  // 자동 판별하고, cfg.lang 을 주면 그 언어로 고정함. 콘솔/CLI 출력은 영어 단일.
15
15
 
16
16
  import { basename, dirname, join } from "node:path";
17
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
17
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
18
18
 
19
19
  import dns from "node:dns";
20
20
  import { fileURLToPath } from "node:url";
@@ -73,13 +73,33 @@ Requires: the claude CLI installed and authenticated on the host.`);
73
73
  // isolated. Falls back to ./config.json for the single-project setup.
74
74
  const CONFIG_PATH = process.argv[2] || process.env.BOT_CONFIG || join(HERE, "config.json");
75
75
  const DATA_DIR = dirname(CONFIG_PATH);
76
- // state 파일은 config 이름에서 파생 같은 폴더에 여러 페르소나 config 를 둬도 세션이 안 섞임.
77
- // config.jsonstate.json (단일 호환), 외 foo.json foo.state.json.
76
+ // 데이터(state·attachments)는 config 폴더 아래 숨김 폴더 .claude-bot/ 모은다.
77
+ // state 파일명은 config 이름에서 파생 여러 페르소나 config .claude-bot/ 공유해도 안 섞임
78
+ // (config.json → state.json, 그 외 foo.json → foo.state.json).
78
79
  const stateBase = basename(CONFIG_PATH, ".json");
79
- const STATE_PATH = join(
80
- DATA_DIR,
81
- stateBase === "config" ? "state.json" : `${stateBase}.state.json`,
82
- );
80
+ const stateFile = stateBase === "config" ? "state.json" : `${stateBase}.state.json`;
81
+ const BOT_DIR = join(DATA_DIR, ".claude-bot");
82
+ const STATE_PATH = join(BOT_DIR, stateFile);
83
+ const ATTACH_DIR = join(BOT_DIR, "attachments");
84
+ const LEGACY_STATE_PATH = join(DATA_DIR, stateFile); // 구버전(루트 직하) 호환
85
+ const LEGACY_ATTACH_DIR = join(DATA_DIR, "attachments");
86
+
87
+ // 구버전에서 올라온 경우, 루트 직하 데이터를 .claude-bot/ 로 1회 이동(무손실, 실패 시 기존 경로 폴백).
88
+ function migrateData() {
89
+ try {
90
+ mkdirSync(BOT_DIR, { recursive: true });
91
+ if (!existsSync(STATE_PATH) && existsSync(LEGACY_STATE_PATH)) {
92
+ renameSync(LEGACY_STATE_PATH, STATE_PATH);
93
+ console.log(`Migrated state → ${STATE_PATH}`);
94
+ }
95
+ if (!existsSync(ATTACH_DIR) && existsSync(LEGACY_ATTACH_DIR)) {
96
+ renameSync(LEGACY_ATTACH_DIR, ATTACH_DIR);
97
+ console.log(`Migrated attachments → ${ATTACH_DIR}`);
98
+ }
99
+ } catch (e) {
100
+ console.error("Data migration skipped:", e.message);
101
+ }
102
+ }
83
103
 
84
104
  if (!existsSync(CONFIG_PATH)) {
85
105
  console.error(
@@ -224,11 +244,13 @@ const COMMANDS = {
224
244
 
225
245
  // ── 상태 (세션 이어가기용) ────────────────────────────────────────────────
226
246
  function loadState() {
227
- try {
228
- return JSON.parse(readFileSync(STATE_PATH, "utf8"));
229
- } catch {
230
- return {};
247
+ // 새 경로(.claude-bot/) 우선, 없으면 구버전 루트 경로로 폴백(이주 실패 시 안전망).
248
+ for (const p of [STATE_PATH, LEGACY_STATE_PATH]) {
249
+ try {
250
+ return JSON.parse(readFileSync(p, "utf8"));
251
+ } catch {}
231
252
  }
253
+ return {};
232
254
  }
233
255
  function saveState(s) {
234
256
  try {
@@ -237,6 +259,7 @@ function saveState(s) {
237
259
  console.error("Failed to save state", e);
238
260
  }
239
261
  }
262
+ migrateData(); // 루트 직하 → .claude-bot/ 1회 이주(있으면) 후 state 로드
240
263
  let state = loadState(); // { sessionId?, cron?: [{ id, cron, prompt, label? }], restartNotify? }
241
264
 
242
265
  // ── 텔레그램 헬퍼 ─────────────────────────────────────────────────────────
@@ -616,7 +639,7 @@ async function downloadAttachment(att) {
616
639
  const r = await fetch(`https://api.telegram.org/file/bot${cfg.token}/${filePath}`);
617
640
  if (!r.ok) throw new Error(`download failed ${r.status}`);
618
641
  const buf = Buffer.from(await r.arrayBuffer());
619
- const dir = join(DATA_DIR, "attachments");
642
+ const dir = ATTACH_DIR;
620
643
  mkdirSync(dir, { recursive: true });
621
644
  const ext = filePath.includes(".") ? filePath.slice(filePath.lastIndexOf(".")) : "";
622
645
  const name = att.name || `tg-${att.fileId.slice(-10)}${ext}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-telegram-bot",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
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": {