# Telegram Bot для управления сессиями Claude Code ## Обзор Персональный Telegram-бот для управления сессиями Claude Code, запущенными на локальном сервере. Позволяет создавать, останавливать, переключать сессии для разных проектов и вести полноценный диалог с Claude через Telegram. ## Решения - **Подход:** Claude Agent SDK (`@anthropic-ai/claude-agent-sdk`) — программный контроль сессий из одного процесса - **Пользователь:** один (персональный бот) - **Взаимодействие:** полноценный чат — сообщения в Telegram отправляются как промпты в активную сессию - **Управление проектами:** быстрый старт по пути + именованные закладки - **Мультисессия:** одна активная сессия получает сообщения, переключение через `/switch` или inline-кнопки - **Вывод:** только финальный результат (без стриминга промежуточных шагов) ## Архитектура ``` ┌─────────────┐ Telegram Bot API ┌──────────────────────┐ │ Telegram │◄───────────────────────►│ Bot Server │ │ (владелец) │ │ (Bun + TypeScript) │ └─────────────┘ │ │ │ ┌────────────────┐ │ │ │ Session Manager │ │ │ │ - activeSession│ │ │ │ - sessions map │ │ │ │ - projects map │ │ │ └───────┬────────┘ │ │ │ │ │ ┌───────▼────────┐ │ │ │ Claude Agent SDK│ │ │ │ query({ │ │ │ │ prompt, │ │ │ │ cwd, │ │ │ │ resume, │ │ │ │ allowedTools │ │ │ │ }) │ │ │ └────────────────┘ │ └──────────────────────┘ │ ┌──────────▼──────────┐ │ Файловая система │ │ сервера (проекты) │ └─────────────────────┘ ``` **Три компонента:** 1. **Telegram Bot** (grammy) — принимает сообщения, отправляет ответы, inline-кнопки 2. **Session Manager** — CRUD сессий, переключение, закладки проектов, персистентность 3. **Claude Agent SDK** — выполнение запросов, управление session ID, resume **Стек:** TypeScript, Bun, grammy, @anthropic-ai/claude-agent-sdk ## Команды бота ### Управление сессиями | Команда | Описание | |---------|----------| | `/start ` | Создать новую сессию для проекта | | `/stop` | Остановить текущую активную сессию | | `/stop ` | Остановить конкретную сессию | | `/stopall` | Остановить все сессии | | `/switch ` | Переключиться на другую активную сессию | | `/sessions` | Список активных сессий с inline-кнопками для переключения | | `/status` | Статус текущей сессии (idle/busy, проект, cwd) | ### Управление проектами (закладки) | Команда | Описание | |---------|----------| | `/save ` | Сохранить закладку проекта | | `/remove ` | Удалить закладку | | `/projects` | Список закладок с inline-кнопками для запуска | ### Прочее | Команда | Описание | |---------|----------| | `/help` | Справка по командам | ### Обычные сообщения Текст без `/` отправляется как промпт в текущую активную сессию. ### Inline-кнопки - `/sessions` — кнопки с именами сессий для быстрого переключения - `/projects` — кнопки "Запустить " для быстрого старта сессии ### Обработка ошибок - Сообщение без активной сессии → "Нет активной сессии. Используй /start" - Сообщение пока сессия busy → "Сессия занята, дождись ответа" - `/start` с уже существующим именем → предложить `/switch` ## Модель данных Состояние хранится в `~/.claude-telegram-bot/state.json`: ```typescript interface AppState { // Закладки проектов projects: Record; // name → absolute path // Активные сессии sessions: Record; // Какая сессия сейчас принимает сообщения activeSession: string | null; // name из sessions } ``` **Персистентность:** - Записывается при каждом изменении - При старте бота загружается из файла - `sessions` при рестарте: sessionId сохраняются, при следующем сообщении пробуем resume — если не удаётся, сообщаем пользователю - `projects` переживают перезапуск полностью **Именование сессий:** - `/start /d/my-project` → имя из последнего сегмента пути: `my-project` - `/start mybot` (закладка) → имя = имя закладки - Конфликт имён → суффикс: `my-project-2` ## Обработка сообщений ``` Telegram сообщение │ ├─ начинается с "/" → парсинг команды → выполнение │ └─ обычный текст → отправка в активную сессию: 1. Проверить activeSession != null 2. Проверить session.status === "idle" 3. Поставить status = "busy" 4. Отправить typing индикатор 5. query({ prompt: text, resume: sessionId }) 6. Собрать финальный ResultMessage 7. Отправить ответ (разбить на чанки если > 4096 символов) 8. Поставить status = "idle" При ошибке → сообщение об ошибке, вернуть status = "idle" ``` **Разбивка длинных ответов:** - Лимит Telegram — 4096 символов - Разбиваем по границам `\n\n`, затем `\n` - Markdown-форматирование в каждом чанке ## Безопасность - **Allowlist по chat_id** — бот отвечает только владельцу (TELEGRAM_OWNER_ID), остальных игнорирует - **Permissions для Claude Agent SDK** — `permissionMode: "bypassPermissions"` (персональный бот, интерактивный approval нецелесообразен) - **Без валидации путей** — единственный пользователь, ограничение файловой системы не нужно ## Конфигурация Файл `.env`: ``` TELEGRAM_BOT_TOKEN=<токен от BotFather> TELEGRAM_OWNER_ID=<твой Telegram user ID> ANTHROPIC_API_KEY= ``` ## Структура проекта ``` claude-telegram-bot/ ├── src/ │ ├── index.ts # Точка входа │ ├── bot.ts # grammy Bot, middleware owner check, хендлеры │ ├── handlers/ │ │ ├── commands.ts # Хендлеры команд │ │ └── message.ts # Текстовые сообщения → Claude │ ├── services/ │ │ ├── session-manager.ts # CRUD сессий, переключение │ │ └── claude.ts # Обёртка Claude Agent SDK │ ├── state/ │ │ └── store.ts # Загрузка/сохранение state.json │ └── utils/ │ └── telegram.ts # Разбивка сообщений, форматирование ├── .env ├── package.json ├── tsconfig.json └── README.md ``` ## Git - Репозиторий: `http://localhost:3000/admin/claude-telegram-bot` - Инициализация git при создании проекта, push в remote по завершении