# Master Test Plan — Claude Telegram Bot Compiled from per-block test plans produced during implementation. --- ## Block 1: Project Scaffolding - [ ] 1.1: `git log --oneline` shows initial commit - [ ] 1.2: `bun run src/index.ts` starts without errors (with valid .env) - [ ] 1.3: `.env` is NOT tracked by git - [ ] 1.4: `git show --stat HEAD~8` shows exactly: .gitignore, bun.lock, package.json, src/index.ts, tsconfig.json - [ ] 1.5: `node_modules/` exists with dependencies installed ## Block 2: State Store (`src/state/store.ts`) - [ ] 2.1: `new Store()` returns default state `{ projects: {}, sessions: {}, activeSession: null }` when no state file exists - [ ] 2.2: `store.save()` creates `~/.claude-telegram-bot/state.json` with valid JSON - [ ] 2.3: Save then load round-trips correctly — write state, create new Store, verify data matches - [ ] 2.4: `save()` auto-creates `~/.claude-telegram-bot/` directory if missing - [ ] 2.5: TypeScript rejects invalid `SessionInfo.status` values (only "idle" | "busy") ## Block 3: Session Manager (`src/services/session-manager.ts`) - [ ] 3.1: `activeSession` returns `null` when no session started - [ ] 3.2: `createSession` sets session data, marks as active, and persists - [ ] 3.3: `stopSession` removes session, reassigns active to remaining (or null) - [ ] 3.4: `stopSession` returns `false` for unknown session name - [ ] 3.5: `stopAll` clears all sessions, sets activeSession to null, returns count - [ ] 3.6: `switchSession` updates activeSession and returns true for valid name - [ ] 3.7: `switchSession` returns false for unknown name - [ ] 3.8: `setStatus` updates only status field, no-ops for unknown session - [ ] 3.9: `resolveProjectPath` returns bookmarked path when name matches a project - [ ] 3.10: `resolveProjectPath` extracts basename from path for non-bookmarked input - [ ] 3.11: `generateName` appends `-2`, `-3` on name conflicts - [ ] 3.12: `saveProject` / `removeProject` CRUD works correctly - [ ] 3.13: Every mutating method calls `store.save()` exactly once ## Block 4: Claude Service (`src/services/claude.ts`) - [ ] 4.1: `createSession` returns non-empty `sessionId` with valid prompt and cwd - [ ] 4.2: `createSession` returns non-empty `result` string - [ ] 4.3: `sendMessage` with valid sessionId resumes context and returns result - [ ] 4.4: Session context is preserved — sendMessage result reflects prior conversation - [ ] 4.5: Invalid sessionId in `sendMessage` throws or returns empty string gracefully - [ ] 4.6: `cwd` is respected — Claude tools resolve paths relative to it - [ ] 4.7: Multi-message stream handled — only final result captured ## Block 5: Telegram Utilities (`src/utils/telegram.ts`) - [ ] 5.1: Short message (<=4096 chars) returns single-element array - [ ] 5.2: Exactly 4096 chars returns single-element array (boundary) - [ ] 5.3: Long message with `\n\n` splits at paragraph boundary - [ ] 5.4: Long message with only `\n` splits at line boundary - [ ] 5.5: Long message with no whitespace hard-splits at 4096 - [ ] 5.6: All chunks are <= 4096 characters - [ ] 5.7: No data loss — concatenated chunks reconstruct original content - [ ] 5.8: `escapeMarkdown` returns input unchanged ## Block 6: Command Handlers (`src/handlers/commands.ts`) - [ ] 6.1: `/start` without argument shows usage - [ ] 6.2: `/start ` with existing session name suggests `/switch` - [ ] 6.3: `/start ` creates Claude session, registers in manager, replies with result - [ ] 6.4: `/stop` with no active session replies "Nothing to stop" - [ ] 6.5: `/stop ` removes session, shows next active if any - [ ] 6.6: `/stop ` for unknown session replies "not found" - [ ] 6.7: `/stopall` stops all, reports count - [ ] 6.8: `/switch` without argument shows usage - [ ] 6.9: `/switch ` switches and confirms - [ ] 6.10: `/switch ` for unknown session shows error + hint - [ ] 6.11: `/sessions` with no sessions replies "No active sessions" - [ ] 6.12: `/sessions` lists sessions with `►` marker and inline keyboard - [ ] 6.13: `/status` with no session replies "No active session" - [ ] 6.14: `/status` shows name, path, status - [ ] 6.15: `/save` with <2 args shows usage - [ ] 6.16: `/save ` saves and confirms - [ ] 6.17: `/remove ` removes or says "not found" - [ ] 6.18: `/projects` shows list with inline "Start" buttons - [ ] 6.19: `/help` shows full command reference ## Block 7: Message Handler (`src/handlers/message.ts`) - [ ] 7.1: Non-text message ignored silently - [ ] 7.2: Text with no active session shows "No active session" message - [ ] 7.3: Text when session busy shows "Session is busy" message - [ ] 7.4: Status set to "busy" before Claude call, "idle" after (including on error) - [ ] 7.5: Typing indicator sent before Claude call - [ ] 7.6: Response split into chunks and sent sequentially - [ ] 7.7: Empty Claude response sends "(empty response)" - [ ] 7.8: Claude error caught, error message sent, status reset to idle ## Block 8: Bot Setup (`src/bot.ts`) - [ ] 8.1: `createBot` returns Bot instance without errors - [ ] 8.2: Non-owner messages silently dropped by middleware - [ ] 8.3: Owner messages reach handlers - [ ] 8.4: `switch:` callback switches session and confirms - [ ] 8.5: `start:` callback for unknown project answers "not found" - [ ] 8.6: `start:` callback for existing session switches instead of creating - [ ] 8.7: `start:` callback for new project creates session via Claude - [ ] 8.8: Claude error in `start:` callback sends error message - [ ] 8.9: All imports are static, `createBot` is synchronous ## Block 9: Entry Point (`src/index.ts`) - [ ] 9.1: Missing TELEGRAM_BOT_TOKEN throws with clear message - [ ] 9.2: Missing TELEGRAM_OWNER_ID throws with clear message - [ ] 9.3: Missing ANTHROPIC_API_KEY throws with clear message - [ ] 9.4: All vars present — bot starts, logs "Bot started successfully" - [ ] 9.5: TELEGRAM_OWNER_ID converted to number - [ ] 9.6: SIGINT triggers graceful shutdown with "Shutting down..." log - [ ] 9.7: `.env` file loaded by dotenv/config --- ## Integration / Smoke Test - [ ] E2E-1: `/help` — shows command list - [ ] E2E-2: `/start /d/claude_telegram_bot` — creates session, Claude responds - [ ] E2E-3: `What files are in this directory?` — Claude lists project files - [ ] E2E-4: `/status` — shows session name, path, idle status - [ ] E2E-5: `/sessions` — shows list with inline button - [ ] E2E-6: Click inline button — switches session - [ ] E2E-7: `/save mybot /d/claude_telegram_bot` — saves bookmark - [ ] E2E-8: `/projects` — shows bookmark with "Start" button - [ ] E2E-9: `/stop` — stops session - [ ] E2E-10: `/sessions` — shows "No active sessions" - [ ] E2E-11: Send text without session — shows "No active session" error - [ ] E2E-12: Message from non-owner — silently ignored