feat: add all command handlers with inline keyboards
This commit is contained in:
@@ -0,0 +1,175 @@
|
|||||||
|
import { type Context, InlineKeyboard } from "grammy";
|
||||||
|
import { SessionManager } from "../services/session-manager.js";
|
||||||
|
import { ClaudeService } from "../services/claude.js";
|
||||||
|
|
||||||
|
export function registerCommands(
|
||||||
|
manager: SessionManager,
|
||||||
|
claude: ClaudeService,
|
||||||
|
onCommand: Record<string, (ctx: Context) => Promise<void>>,
|
||||||
|
): void {
|
||||||
|
onCommand["start"] = async (ctx) => {
|
||||||
|
const arg = ctx.match as string;
|
||||||
|
if (!arg) {
|
||||||
|
await ctx.reply("Usage: /start <path or project name>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolved = manager.resolveProjectPath(arg);
|
||||||
|
if (!resolved) {
|
||||||
|
await ctx.reply("Could not resolve project path.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (manager.getAllSessions()[resolved.name]) {
|
||||||
|
await ctx.reply(
|
||||||
|
`Session "${resolved.name}" already exists. Use /switch ${resolved.name}`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onCommand["stop"] = async (ctx) => {
|
||||||
|
const arg = ctx.match as string;
|
||||||
|
const name = arg || manager.activeSession;
|
||||||
|
if (!name) {
|
||||||
|
await ctx.reply("No active session. Nothing to stop.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (manager.stopSession(name)) {
|
||||||
|
const active = manager.activeSession;
|
||||||
|
let msg = `Session "${name}" stopped.`;
|
||||||
|
if (active) msg += ` Switched to "${active}".`;
|
||||||
|
await ctx.reply(msg);
|
||||||
|
} else {
|
||||||
|
await ctx.reply(`Session "${name}" not found.`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onCommand["stopall"] = async (ctx) => {
|
||||||
|
const count = manager.stopAll();
|
||||||
|
await ctx.reply(`Stopped ${count} session(s).`);
|
||||||
|
};
|
||||||
|
|
||||||
|
onCommand["switch"] = async (ctx) => {
|
||||||
|
const arg = ctx.match as string;
|
||||||
|
if (!arg) {
|
||||||
|
await ctx.reply("Usage: /switch <session name>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (manager.switchSession(arg)) {
|
||||||
|
await ctx.reply(`Switched to "${arg}".`);
|
||||||
|
} else {
|
||||||
|
await ctx.reply(`Session "${arg}" not found. Use /sessions to see active sessions.`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onCommand["sessions"] = async (ctx) => {
|
||||||
|
const sessions = manager.getAllSessions();
|
||||||
|
const names = Object.keys(sessions);
|
||||||
|
if (names.length === 0) {
|
||||||
|
await ctx.reply("No active sessions.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const active = manager.activeSession;
|
||||||
|
const lines = names.map((name) => {
|
||||||
|
const s = sessions[name];
|
||||||
|
const marker = name === active ? "►" : " ";
|
||||||
|
return `${marker} ${name} — ${s.cwd} (${s.status})`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const keyboard = new InlineKeyboard();
|
||||||
|
for (const name of names) {
|
||||||
|
keyboard.text(name, `switch:${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.reply(lines.join("\n"), { reply_markup: keyboard });
|
||||||
|
};
|
||||||
|
|
||||||
|
onCommand["status"] = async (ctx) => {
|
||||||
|
const info = manager.activeSessionInfo;
|
||||||
|
if (!info) {
|
||||||
|
await ctx.reply("No active session.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const name = manager.activeSession!;
|
||||||
|
await ctx.reply(
|
||||||
|
`Session: ${name}\nPath: ${info.cwd}\nStatus: ${info.status}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
onCommand["save"] = async (ctx) => {
|
||||||
|
const arg = ctx.match as string;
|
||||||
|
const parts = arg.split(/\s+/, 2);
|
||||||
|
if (parts.length < 2) {
|
||||||
|
await ctx.reply("Usage: /save <name> <path>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
manager.saveProject(parts[0], parts[1]);
|
||||||
|
await ctx.reply(`Project "${parts[0]}" saved → ${parts[1]}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
onCommand["remove"] = async (ctx) => {
|
||||||
|
const arg = ctx.match as string;
|
||||||
|
if (!arg) {
|
||||||
|
await ctx.reply("Usage: /remove <name>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (manager.removeProject(arg)) {
|
||||||
|
await ctx.reply(`Project "${arg}" removed.`);
|
||||||
|
} else {
|
||||||
|
await ctx.reply(`Project "${arg}" not found.`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onCommand["projects"] = async (ctx) => {
|
||||||
|
const projects = manager.getProjects();
|
||||||
|
const names = Object.keys(projects);
|
||||||
|
if (names.length === 0) {
|
||||||
|
await ctx.reply("No saved projects.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lines = names.map((n) => `${n} — ${projects[n]}`);
|
||||||
|
const keyboard = new InlineKeyboard();
|
||||||
|
for (const name of names) {
|
||||||
|
keyboard.text(`Start ${name}`, `start:${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.reply(lines.join("\n"), { reply_markup: keyboard });
|
||||||
|
};
|
||||||
|
|
||||||
|
onCommand["help"] = async (ctx) => {
|
||||||
|
await ctx.reply(
|
||||||
|
[
|
||||||
|
"Session commands:",
|
||||||
|
" /start <path|name> — start new session",
|
||||||
|
" /stop [name] — stop session",
|
||||||
|
" /stopall — stop all sessions",
|
||||||
|
" /switch <name> — switch active session",
|
||||||
|
" /sessions — list sessions",
|
||||||
|
" /status — current session info",
|
||||||
|
"",
|
||||||
|
"Project bookmarks:",
|
||||||
|
" /save <name> <path> — save bookmark",
|
||||||
|
" /remove <name> — remove bookmark",
|
||||||
|
" /projects — list bookmarks",
|
||||||
|
"",
|
||||||
|
"Any other text is sent to the active session.",
|
||||||
|
].join("\n"),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user