claude-telegram-bot 0.4.0 → 0.4.1
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/CHANGELOG.md +6 -0
- package/README.ko.md +3 -3
- package/README.md +3 -3
- package/bot.mjs +25 -14
- package/ctb.mjs +3 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.1] - 2026-07-10
|
|
4
|
+
### Changed
|
|
5
|
+
- `ctb`의 provider 결정 우선순위(`--provider` → `config.provider` → `claude`)를 도움말에 명시했다.
|
|
6
|
+
- `/model` 상태·설정 안내를 provider별로 분리했다. Claude에서는 모델 별칭을 제안하고, Codex에서는
|
|
7
|
+
Claude 별칭을 노출하지 않고 전체 Codex 모델 ID와 `codexModel`/CLI 기본값 사용법을 안내한다.
|
|
8
|
+
|
|
3
9
|
## [0.4.0] - 2026-07-10
|
|
4
10
|
### Added
|
|
5
11
|
- `config.json`의 `provider`로 Claude 또는 Codex를 텔레그램 봇의 메인 실행자로 선택할 수 있다.
|
package/README.ko.md
CHANGED
|
@@ -137,7 +137,7 @@ CLI를 업데이트한 뒤에는 무인 실행에 맡기기 전에 `/testfallbac
|
|
|
137
137
|
| `commands` | (선택) 쉘 스크립트를 실행하는 커스텀 `/명령어` — [커스텀 명령어](#커스텀-명령어) 참고 |
|
|
138
138
|
| `codexFallback` | (선택) `true`로 설정하면 Claude 레이트 리밋·크레딧 부족 시 Codex를 우선 폴백으로 사용 |
|
|
139
139
|
| `codexBin` | (선택) `codex` 실행 파일 경로. 기본값은 `PATH`의 `"codex"`이며 launchd에서는 절대경로 권장 |
|
|
140
|
-
| `codexModel` | (선택) Codex에 `--model`로 넘길
|
|
140
|
+
| `codexModel` | (선택) Codex에 `--model`로 넘길 모델. Codex 활성 상태에서 `/model <전체-ID>`로 변경 가능 |
|
|
141
141
|
| `codexSandbox` | (선택) 첫 `codex exec` 세션의 샌드박스 (기본값: `"workspace-write"`) |
|
|
142
142
|
| `codexTimeout` | (선택) Codex 응답을 기다리는 최대 시간(ms). 실패하면 reserve/Ollama로 넘어감 (기본값: `600000`) |
|
|
143
143
|
| `ollamaFallback` | (선택) `true`로 설정하면 Claude 레이트 리밋·크레딧 부족 시 로컬 Ollama를 보조 폴백으로 사용 |
|
|
@@ -176,7 +176,7 @@ Claude는 `state.sessionId`, Codex는 `state.codexSessionId`를 읽어 `codex re
|
|
|
176
176
|
| 명령어 | 기능 |
|
|
177
177
|
|---|---|
|
|
178
178
|
| `/provider [claude\|codex\|default]` | 텔레그램 봇 provider 확인·전환 |
|
|
179
|
-
| `/model [이름\|default]` | 활성 provider 모델
|
|
179
|
+
| `/model [이름\|default]` | 활성 provider 모델 확인·전환, provider별 안내 표시 |
|
|
180
180
|
| `/new` | 활성 provider의 대화 세션 초기화 |
|
|
181
181
|
| `/plan <요청>` | 계획 작성 후 승인 대기 (Claude 전용) |
|
|
182
182
|
| `/compact` | 현재 컨텍스트 압축 (Claude 전용) |
|
|
@@ -197,7 +197,7 @@ Claude는 `state.sessionId`, Codex는 `state.codexSessionId`를 읽어 `codex re
|
|
|
197
197
|
|
|
198
198
|
- **세션 유지** — Claude와 Codex의 세션 ID를 따로 저장합니다. `/provider`로 전환해도 각각의 맥락이 유지되며 `/new`는 활성 provider 세션만 초기화합니다.
|
|
199
199
|
- **메시지 큐** — 작업 중에 새 메시지가 오면 버리지 않고 큐에 쌓아둡니다. 작업이 끝나면 대기 중인 메시지를 모두 하나의 프롬프트로 합쳐서 처리합니다(예: "A 해줘" → "아니다 B 해줘"를 한 번에 처리). `/stop`으로 실행 중인 작업과 큐를 동시에 취소할 수 있습니다.
|
|
200
|
-
- **모델
|
|
200
|
+
- **모델 설정** — `/model`은 활성 provider를 따르며 Claude와 Codex override를 별도로 저장합니다. Claude에서는 `haiku`, `sonnet`, `opus`, `fable` 별칭을 안내하고, Codex에서는 Claude 별칭 대신 전체 Codex 모델 ID 입력을 안내합니다. `/model default`는 활성 provider의 override만 해제합니다.
|
|
201
201
|
- **한도 초과 큐** — Claude Max / API 레이트 리밋 에러에 리셋 시간이 포함되면, 먼저 활성화된 폴백을 시도합니다. 폴백이 없거나 모두 실패할 때만 해당 메시지를 큐에 넣고 리셋 시각에 재시도합니다 — 작업 중 큐와 같은 방식입니다. 한도가 걸린 동안 추가로 보내는 메시지도 자동으로 큐에 쌓입니다. `/reserve`로 대기 현황과 리셋 시각 확인, `/reserve rm`으로 큐 전체 취소.
|
|
202
202
|
- **Codex 폴백** — `"codexFallback": true`로 설정하면 Claude 레이트 리밋·크레딧 부족 시 `codex exec`가 대신 실행됩니다. Codex는 `state.codexSessionId`에 별도 세션을 저장하고 `codex exec resume <id>`로 이어가지만, Claude 세션과 Codex 세션은 서로 호환되지 않습니다. 대신 성공한 Codex 폴백마다 `.claude-bot/codex-handoff.md`에 요약을 남기고, 이후 Claude 호출 때 최근 handoff 내용을 맥락으로 주입합니다.
|
|
203
203
|
- **실행 중 provider 전환** — `/provider`로 확인하고, `/provider claude` 또는 `/provider codex`로 봇 state override를 저장할 수 있습니다. `/provider default`는 config 값으로 되돌립니다.
|
package/README.md
CHANGED
|
@@ -186,7 +186,7 @@ Core commands:
|
|
|
186
186
|
| Command | Purpose |
|
|
187
187
|
|---|---|
|
|
188
188
|
| `/provider [claude\|codex\|default]` | View or switch the Telegram bot's provider override |
|
|
189
|
-
| `/model [name\|default]` | View or switch the active provider's model |
|
|
189
|
+
| `/model [name\|default]` | View or switch the active provider's model; suggestions are provider-specific |
|
|
190
190
|
| `/new` | Reset the active provider's conversation session |
|
|
191
191
|
| `/plan <request>` | Produce a plan and wait for approval (Claude only) |
|
|
192
192
|
| `/compact` | Compact the current context (Claude only) |
|
|
@@ -264,7 +264,7 @@ Edit `mybot.json`:
|
|
|
264
264
|
| `commands` | (optional) Custom `/commands` that run shell scripts — see [Custom commands](#custom-commands) |
|
|
265
265
|
| `codexFallback` | (optional) `true` to enable Codex as the preferred fallback when Claude is rate-limited or out of credits |
|
|
266
266
|
| `codexBin` | (optional) Path to the `codex` binary. Defaults to `"codex"` on `PATH`; use an absolute path for launchd |
|
|
267
|
-
| `codexModel` | (optional) Codex model
|
|
267
|
+
| `codexModel` | (optional) Codex model passed with `--model`; override while Codex is active with `/model <full-id>` |
|
|
268
268
|
| `codexSandbox` | (optional) Codex sandbox for a new `codex exec` session (default: `"workspace-write"`) |
|
|
269
269
|
| `codexTimeout` | (optional) Milliseconds to wait for Codex before falling back to reserve/Ollama (default: `600000`) |
|
|
270
270
|
| `ollamaFallback` | (optional) `true` to enable Ollama as a secondary fallback when Claude is rate-limited or out of credits |
|
|
@@ -309,7 +309,7 @@ your launchd plist points them.
|
|
|
309
309
|
- **Sessions**: Claude and Codex keep separate session IDs, so switching providers preserves both
|
|
310
310
|
conversations. `/new` resets only the active provider's session.
|
|
311
311
|
- **Message queue**: if you send a message while a task is running, it is queued (not dropped). When the task finishes, all queued messages are merged into a single prompt so Claude can resolve corrections and follow-ups in one pass (e.g. "do X" then "never mind, do Y" → handled together). Use `/stop` to cancel the running task and discard the queue.
|
|
312
|
-
- **
|
|
312
|
+
- **Models**: `/model` follows the active provider and stores separate Claude/Codex overrides. Claude shows the `haiku`, `sonnet`, `opus`, and `fable` aliases; Codex asks for a full Codex model ID instead of displaying Claude aliases. `/model default` clears only the active provider's override.
|
|
313
313
|
- **Usage-limit queue**: when a Claude Max / API rate-limit error includes a reset time, the bot first tries enabled fallbacks. If no fallback is enabled or every fallback fails, the triggering message is queued and retried at that time — just like messages queued while Claude is busy. Any additional messages you send during the limit window are also added to the queue. Use `/reserve` to check queue status and reset time, `/reserve rm` to cancel and clear the queue.
|
|
314
314
|
- **Codex fallback**: set `"codexFallback": true` to run `codex exec` when Claude is rate-limited or out of credits. Codex keeps its own session in `state.codexSessionId` using `codex exec resume <id>`, but Claude and Codex sessions are not interoperable. Each successful Codex fallback appends a summary to `.claude-bot/codex-handoff.md`, and future Claude calls receive the recent handoff notes as context.
|
|
315
315
|
- **Runtime provider switching**: use `/provider` to view the active provider, `/provider claude` or `/provider codex` to store a bot-state override, and `/provider default` to return to the config value. Each provider's session is preserved separately.
|
package/bot.mjs
CHANGED
|
@@ -217,12 +217,16 @@ const STR = {
|
|
|
217
217
|
`• Scheduled jobs: ${i.jobs}\n` +
|
|
218
218
|
`• Project: ${i.projectDir}\n` +
|
|
219
219
|
`• Permission: ${i.permissionMode}`,
|
|
220
|
-
|
|
221
|
-
`🧠
|
|
220
|
+
claudeModelStatus: (cur, list) =>
|
|
221
|
+
`🧠 Claude model: ${cur}\n` +
|
|
222
222
|
`Switch: ${list.map((x) => `/model ${x}`).join(" · ")} (or a full model id)\n` +
|
|
223
223
|
`/model default — clear the override`,
|
|
224
|
-
|
|
225
|
-
|
|
224
|
+
codexModelStatus: (cur) =>
|
|
225
|
+
`🧠 Codex model: ${cur}\n` +
|
|
226
|
+
"Set: `/model <full-codex-model-id>`\n" +
|
|
227
|
+
`/model default — clear the override and use codexModel/CLI default`,
|
|
228
|
+
modelSet: (provider, m) => `🧠 ${provider} model set to: ${m}`,
|
|
229
|
+
modelReset: (provider, def) => `🧠 ${provider} model reset to default (${def}).`,
|
|
226
230
|
providerStatus: (cur, def) => `🤖 Provider: ${cur}${cur === def ? " (config default)" : ` (config default: ${def})`}\nSwitch: /provider claude · /provider codex · /provider default`,
|
|
227
231
|
providerSet: (provider) => `🤖 Default provider set to ${provider}. Existing Claude and Codex sessions are preserved separately.`,
|
|
228
232
|
providerReset: (provider) => `🤖 Provider reset to the config default (${provider}).`,
|
|
@@ -312,12 +316,16 @@ const STR = {
|
|
|
312
316
|
`• 예약 작업: ${i.jobs}개\n` +
|
|
313
317
|
`• 작업 폴더: ${i.projectDir}\n` +
|
|
314
318
|
`• 권한 모드: ${i.permissionMode}`,
|
|
315
|
-
|
|
316
|
-
`🧠 현재 모델: ${cur}\n` +
|
|
319
|
+
claudeModelStatus: (cur, list) =>
|
|
320
|
+
`🧠 현재 Claude 모델: ${cur}\n` +
|
|
317
321
|
`전환: ${list.map((x) => `/model ${x}`).join(" · ")} (또는 전체 모델 ID)\n` +
|
|
318
322
|
`/model default — 오버라이드 해제`,
|
|
319
|
-
|
|
320
|
-
|
|
323
|
+
codexModelStatus: (cur) =>
|
|
324
|
+
`🧠 현재 Codex 모델: ${cur}\n` +
|
|
325
|
+
"설정: `/model <Codex 전체 모델 ID>`\n" +
|
|
326
|
+
`/model default — 오버라이드를 해제하고 codexModel/CLI 기본값 사용`,
|
|
327
|
+
modelSet: (provider, m) => `🧠 ${provider} 모델을 ${m}(으)로 설정했습니다.`,
|
|
328
|
+
modelReset: (provider, def) => `🧠 ${provider} 모델을 기본값(${def})으로 되돌렸습니다.`,
|
|
321
329
|
providerStatus: (cur, def) => `🤖 현재 provider: ${cur}${cur === def ? " (config 기본값)" : ` (config 기본값: ${def})`}\n전환: /provider claude · /provider codex · /provider default`,
|
|
322
330
|
providerSet: (provider) => `🤖 기본 provider를 ${provider}(으)로 변경했습니다. Claude와 Codex의 기존 세션은 각각 유지됩니다.`,
|
|
323
331
|
providerReset: (provider) => `🤖 provider를 config 기본값(${provider})으로 되돌렸습니다.`,
|
|
@@ -365,7 +373,7 @@ const t = (l, key, ...a) => {
|
|
|
365
373
|
};
|
|
366
374
|
|
|
367
375
|
// /model 에서 보여줄 추천 별칭(claude CLI 가 별칭·전체 모델 ID 모두 허용).
|
|
368
|
-
const
|
|
376
|
+
const CLAUDE_MODEL_SUGGESTIONS = ["fable", "opus", "sonnet", "haiku"];
|
|
369
377
|
|
|
370
378
|
// /(슬래시) 자동완성 메뉴용 명령 목록 (언어별). setMyCommands 로 등록.
|
|
371
379
|
const COMMANDS = {
|
|
@@ -1488,22 +1496,25 @@ async function handle(msg) {
|
|
|
1488
1496
|
}
|
|
1489
1497
|
if (text === "/model" || text.startsWith("/model ")) {
|
|
1490
1498
|
const arg = text.slice(6).trim();
|
|
1491
|
-
const
|
|
1492
|
-
const
|
|
1499
|
+
const provider = currentProvider();
|
|
1500
|
+
const modelStateKey = provider === "codex" ? "codexModel" : "model";
|
|
1501
|
+
const configuredModel = provider === "codex" ? cfg.codexModel : cfg.model;
|
|
1493
1502
|
if (!arg) {
|
|
1494
1503
|
const cur = state[modelStateKey] || configuredModel || (l === "ko" ? "(기본값)" : "(default)");
|
|
1495
|
-
await send(chatId,
|
|
1504
|
+
await send(chatId, provider === "codex"
|
|
1505
|
+
? t(l, "codexModelStatus", cur)
|
|
1506
|
+
: t(l, "claudeModelStatus", cur, CLAUDE_MODEL_SUGGESTIONS));
|
|
1496
1507
|
return;
|
|
1497
1508
|
}
|
|
1498
1509
|
if (arg === "default" || arg === "reset") {
|
|
1499
1510
|
state[modelStateKey] = undefined;
|
|
1500
1511
|
saveState(state);
|
|
1501
|
-
await send(chatId, t(l, "modelReset", configuredModel || (l === "ko" ? "기본값" : "default")));
|
|
1512
|
+
await send(chatId, t(l, "modelReset", provider, configuredModel || (l === "ko" ? "기본값" : "default")));
|
|
1502
1513
|
return;
|
|
1503
1514
|
}
|
|
1504
1515
|
state[modelStateKey] = arg;
|
|
1505
1516
|
saveState(state);
|
|
1506
|
-
await send(chatId, t(l, "modelSet", arg));
|
|
1517
|
+
await send(chatId, t(l, "modelSet", provider, arg));
|
|
1507
1518
|
return;
|
|
1508
1519
|
}
|
|
1509
1520
|
if (text === "/autocompact" || text.startsWith("/autocompact ")) {
|
package/ctb.mjs
CHANGED
|
@@ -74,9 +74,10 @@ async function main() {
|
|
|
74
74
|
` ctb --help | --version\n\n` +
|
|
75
75
|
`config.json defaults to $BOT_CONFIG or the package's own config.json.\n` +
|
|
76
76
|
`A bare name like "planner.json" resolves relative to the package directory.\n\n` +
|
|
77
|
+
`Provider precedence: --provider flag → config.provider → claude.\n\n` +
|
|
77
78
|
`Examples:\n` +
|
|
78
|
-
` ctb Interactive
|
|
79
|
-
` ctb -p "what did we do?" Headless
|
|
79
|
+
` ctb Interactive configured provider, continuing its session\n` +
|
|
80
|
+
` ctb -p "what did we do?" Headless configured provider with session context\n` +
|
|
80
81
|
` ctb planner.json Resume planner persona session interactively\n` +
|
|
81
82
|
` ctb planner.json -p "..." Headless with planner session\n` +
|
|
82
83
|
` ctb planner.json --provider codex Interactive Codex with its Telegram session\n` +
|
package/package.json
CHANGED