feat: add bot setup with owner middleware, commands, callbacks
This commit is contained in:
+74
@@ -0,0 +1,74 @@
|
|||||||
|
import { Bot, type Context } from "grammy";
|
||||||
|
import { Store } from "./state/store.js";
|
||||||
|
import { SessionManager } from "./services/session-manager.js";
|
||||||
|
import { ClaudeService } from "./services/claude.js";
|
||||||
|
import { registerCommands } from "./handlers/commands.js";
|
||||||
|
import { createMessageHandler } from "./handlers/message.js";
|
||||||
|
|
||||||
|
export function createBot(token: string, ownerId: number): Bot {
|
||||||
|
const bot = new Bot(token);
|
||||||
|
|
||||||
|
// Owner-only middleware
|
||||||
|
bot.use(async (ctx, next) => {
|
||||||
|
if (ctx.from?.id !== ownerId) return;
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
const store = new Store();
|
||||||
|
const manager = new SessionManager(store);
|
||||||
|
const claude = new ClaudeService();
|
||||||
|
|
||||||
|
// Register command handlers
|
||||||
|
const commands: Record<string, (ctx: Context) => Promise<void>> = {};
|
||||||
|
registerCommands(manager, claude, commands);
|
||||||
|
|
||||||
|
for (const [name, handler] of Object.entries(commands)) {
|
||||||
|
bot.command(name, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback queries for inline buttons
|
||||||
|
bot.on("callback_query:data", async (ctx) => {
|
||||||
|
const data = ctx.callbackQuery.data;
|
||||||
|
|
||||||
|
if (data.startsWith("switch:")) {
|
||||||
|
const name = data.slice("switch:".length);
|
||||||
|
if (manager.switchSession(name)) {
|
||||||
|
await ctx.answerCallbackQuery({ text: `Switched to "${name}"` });
|
||||||
|
await ctx.reply(`Switched to "${name}".`);
|
||||||
|
} else {
|
||||||
|
await ctx.answerCallbackQuery({ text: `Session "${name}" not found` });
|
||||||
|
}
|
||||||
|
} else if (data.startsWith("start:")) {
|
||||||
|
const name = data.slice("start:".length);
|
||||||
|
const resolved = manager.resolveProjectPath(name);
|
||||||
|
if (!resolved) {
|
||||||
|
await ctx.answerCallbackQuery({ text: "Project not found" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (manager.getAllSessions()[resolved.name]) {
|
||||||
|
manager.switchSession(resolved.name);
|
||||||
|
await ctx.answerCallbackQuery({ text: `Switched to "${resolved.name}"` });
|
||||||
|
await ctx.reply(`Session "${resolved.name}" already exists. Switched to it.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await ctx.answerCallbackQuery({ text: `Starting "${resolved.name}"...` });
|
||||||
|
await ctx.reply(`Starting session "${resolved.name}" in ${resolved.path}...`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { sessionId, result } = await claude.createSession(
|
||||||
|
"You are now connected via Telegram. Briefly confirm you're ready and state the project directory.",
|
||||||
|
resolved.path,
|
||||||
|
);
|
||||||
|
manager.createSession(resolved.name, resolved.path, sessionId);
|
||||||
|
await ctx.reply(`Session "${resolved.name}" created.\n\n${result}`);
|
||||||
|
} catch (err) {
|
||||||
|
await ctx.reply(`Failed to create session: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Plain text messages
|
||||||
|
bot.on("message:text", createMessageHandler(manager, claude));
|
||||||
|
|
||||||
|
return bot;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user