import { Command } from 'commander' import { handleError } from '@/shared/utils/error-handler' import { formatOutput } from '@/shared/utils/output' import { DiscordBotCredentialManager } from '../credential-manager' import type { BotOption } from './shared' import { getClient } from './shared' interface SnapshotOption extends BotOption { channelsOnly?: boolean usersOnly?: boolean full?: boolean limit?: number } interface SnapshotResult { server_id?: string channels?: Array<{ id: string name: string type?: number messages?: Array<{ id: string author: string content: string timestamp: string }> }> users?: Array<{ id: string username: string global_name: string | null }> hint?: string error?: string } export async function snapshotAction(options: SnapshotOption): Promise { try { const serverId = options.server || (await (options._credManager ?? new DiscordBotCredentialManager()).getCurrentServer()) if (!serverId) { return { error: 'No server set. Run "server switch " first.' } } const client = await getClient(options) const isFull = options.full || options.channelsOnly || options.usersOnly if (isFull) { const limit = options.limit ?? 5 if (options.usersOnly) { const users = await client.listUsers(serverId) return { server_id: serverId, users: users.map((u) => ({ id: u.id, username: u.username, global_name: u.global_name ?? null, })), } } const allChannels = await client.listChannels(serverId) const textChannels = allChannels.filter((ch) => ch.type === 0) if (options.channelsOnly) { return { server_id: serverId, channels: textChannels.map((ch) => ({ id: ch.id, name: ch.name, type: ch.type, })), } } const channelsWithMessages = await Promise.all( textChannels.map(async (ch) => { const messages = await client.getMessages(ch.id, limit) return { id: ch.id, name: ch.name, messages: messages.map((msg) => ({ id: msg.id, author: msg.author.username, content: msg.content, timestamp: msg.timestamp, })), } }), ) return { server_id: serverId, channels: channelsWithMessages, } } const allChannels = await client.listChannels(serverId) const textChannels = allChannels.filter((ch) => ch.type === 0) return { server_id: serverId, channels: textChannels.map((ch) => ({ id: ch.id, name: ch.name })), hint: "Use 'message list ' for messages, 'channel info ' for channel details, 'user list' for members.", } } catch (error) { return { error: (error as Error).message } } } export const snapshotCommand = new Command('snapshot') .description('Server overview for AI agents (brief by default, use --full for comprehensive data)') .option('--full', 'Include messages and members (verbose)') .option('--channels-only', 'List channels only, skip messages') .option('--users-only', 'List users only') .option('--limit ', 'Messages per channel with --full (default: 5)', '5') .option('--server ', 'Use specific server') .option('--bot ', 'Use specific bot') .option('--pretty', 'Pretty print JSON output') .action(async (options) => { try { const result = await snapshotAction({ ...options, full: options.full, limit: parseInt(options.limit, 10), }) console.log(formatOutput(result, options.pretty)) } catch (error) { handleError(error as Error) } })