docs: add design spec, implementation plan, test plan; update gitignore

This commit is contained in:
neken
2026-04-10 17:55:43 +05:00
parent 8bccf6ce88
commit 6afb703a85
4 changed files with 1364 additions and 0 deletions
@@ -0,0 +1,196 @@
# 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 <path или name>` | Создать новую сессию для проекта |
| `/stop` | Остановить текущую активную сессию |
| `/stop <name>` | Остановить конкретную сессию |
| `/stopall` | Остановить все сессии |
| `/switch <name>` | Переключиться на другую активную сессию |
| `/sessions` | Список активных сессий с inline-кнопками для переключения |
| `/status` | Статус текущей сессии (idle/busy, проект, cwd) |
### Управление проектами (закладки)
| Команда | Описание |
|---------|----------|
| `/save <name> <path>` | Сохранить закладку проекта |
| `/remove <name>` | Удалить закладку |
| `/projects` | Список закладок с inline-кнопками для запуска |
### Прочее
| Команда | Описание |
|---------|----------|
| `/help` | Справка по командам |
### Обычные сообщения
Текст без `/` отправляется как промпт в текущую активную сессию.
### Inline-кнопки
- `/sessions` — кнопки с именами сессий для быстрого переключения
- `/projects` — кнопки "Запустить <name>" для быстрого старта сессии
### Обработка ошибок
- Сообщение без активной сессии → "Нет активной сессии. Используй /start"
- Сообщение пока сессия busy → "Сессия занята, дождись ответа"
- `/start` с уже существующим именем → предложить `/switch`
## Модель данных
Состояние хранится в `~/.claude-telegram-bot/state.json`:
```typescript
interface AppState {
// Закладки проектов
projects: Record<string, string>; // name → absolute path
// Активные сессии
sessions: Record<string, { // name → session info
sessionId: string; // ID из Claude Agent SDK
cwd: string; // рабочая директория
status: "idle" | "busy";
}>;
// Какая сессия сейчас принимает сообщения
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=<API ключ Anthropic>
```
## Структура проекта
```
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 по завершении