@elizaos/plugin-discord-local 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": [
5
+ "import { execFile } from \"node:child_process\";\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport net from \"node:net\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport {\n ChannelType,\n ContentType,\n createMessageMemory,\n createUniqueUuid,\n type IAgentRuntime,\n logger,\n type Media,\n type Memory,\n type MemoryMetadata,\n type Plugin,\n type Route,\n type RouteRequest,\n type RouteResponse,\n resolveStateDir,\n Service,\n stringToUuid,\n type UUID,\n} from \"@elizaos/core\";\n\nconst execFileAsync = promisify(execFile);\n\nexport const DISCORD_LOCAL_PLUGIN_NAME = \"@elizaos/plugin-discord-local\";\nexport const DISCORD_LOCAL_SERVICE_NAME = \"discord-local\";\nconst DISCORD_OAUTH_TOKEN_URL = \"https://discord.com/api/v10/oauth2/token\";\nconst DISCORD_LOCAL_DEFAULT_SCOPES = [\"rpc\", \"identify\", \"rpc.notifications.read\"] as const;\n\nconst IPC_OP_HANDSHAKE = 0;\nconst IPC_OP_FRAME = 1;\nconst IPC_OP_CLOSE = 2;\nconst IPC_OP_PING = 3;\nconst IPC_OP_PONG = 4;\n\ntype DiscordLocalConfig = {\n enabled: boolean;\n clientId: string;\n clientSecret: string;\n scopes: string[];\n messageChannelIds: string[];\n sendDelayMs: number;\n};\n\ntype DiscordLocalSession = {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n scopes: string[];\n};\n\ntype DiscordLocalUser = {\n id: string;\n username: string;\n global_name?: string | null;\n avatar?: string | null;\n};\n\ntype DiscordLocalChannel = {\n id: string;\n guild_id?: string | null;\n type?: number;\n name?: string | null;\n recipients?: DiscordLocalUser[];\n};\n\ntype DiscordLocalGuild = {\n id: string;\n name: string;\n};\n\ninterface ConnectorSetupService {\n getConfig(): Record<string, unknown>;\n updateConfig(updater: (config: Record<string, unknown>) => void): void;\n registerEscalationChannel(channelName: string): boolean;\n setOwnerContact(update: {\n source: string;\n channelId?: string;\n entityId?: string;\n roomId?: string;\n }): boolean;\n}\n\ninterface ConnectorConfig {\n enabled?: boolean;\n messageChannelIds?: string[];\n [key: string]: unknown;\n}\n\ntype DiscordLocalAttachment = {\n id: string;\n filename?: string;\n url?: string;\n content_type?: string;\n description?: string | null;\n};\n\ntype DiscordLocalMessage = {\n id: string;\n channel_id?: string;\n guild_id?: string | null;\n content?: string;\n author?: DiscordLocalUser | null;\n attachments?: DiscordLocalAttachment[];\n timestamp?: string;\n referenced_message?: DiscordLocalMessage | null;\n message_reference?: {\n message_id?: string;\n channel_id?: string;\n guild_id?: string | null;\n } | null;\n};\n\ntype DiscordLocalNotification = {\n channel_id?: string;\n message?: DiscordLocalMessage | null;\n};\n\ntype DiscordLocalRpcPayload = {\n cmd?: string;\n evt?: string;\n nonce?: string;\n data?: unknown;\n};\n\ntype PendingRpcRequest = {\n resolve: (value: DiscordLocalRpcPayload) => void;\n reject: (error: Error) => void;\n};\n\nfunction parseListSetting(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value\n .map((entry) => (typeof entry === \"string\" ? entry.trim() : \"\"))\n .filter((entry) => entry.length > 0);\n }\n\n if (typeof value === \"string\") {\n return value\n .split(\",\")\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0);\n }\n\n return [];\n}\n\nfunction getDiscordLocalConfig(runtime: IAgentRuntime): DiscordLocalConfig | null {\n const clientId = runtime.getSetting(\"DISCORD_LOCAL_CLIENT_ID\");\n const clientSecret = runtime.getSetting(\"DISCORD_LOCAL_CLIENT_SECRET\");\n const enabledValue = runtime.getSetting(\"DISCORD_LOCAL_ENABLED\");\n\n const enabled =\n enabledValue === undefined ||\n enabledValue === null ||\n (typeof enabledValue === \"string\" && enabledValue.trim() !== \"false\");\n\n if (\n typeof clientId !== \"string\" ||\n clientId.trim().length === 0 ||\n typeof clientSecret !== \"string\" ||\n clientSecret.trim().length === 0\n ) {\n return null;\n }\n\n const rawSendDelayMs = runtime.getSetting(\"DISCORD_LOCAL_SEND_DELAY_MS\");\n const parsedSendDelayMs =\n typeof rawSendDelayMs === \"string\" ? Number.parseInt(rawSendDelayMs, 10) : Number.NaN;\n\n return {\n enabled,\n clientId: clientId.trim(),\n clientSecret: clientSecret.trim(),\n scopes: (() => {\n const parsed = parseListSetting(runtime.getSetting(\"DISCORD_LOCAL_SCOPES\"));\n return parsed.length > 0 ? parsed : [...DISCORD_LOCAL_DEFAULT_SCOPES];\n })(),\n messageChannelIds: parseListSetting(runtime.getSetting(\"DISCORD_LOCAL_MESSAGE_CHANNEL_IDS\")),\n sendDelayMs:\n Number.isFinite(parsedSendDelayMs) && parsedSendDelayMs >= 100 ? parsedSendDelayMs : 900,\n };\n}\n\nfunction resolveSessionPath(): string {\n const dir = path.join(resolveStateDir(), \"discord-local\");\n fs.mkdirSync(dir, { recursive: true });\n return path.join(dir, \"session.json\");\n}\n\nfunction buildDiscordAvatarUrl(user: DiscordLocalUser | null | undefined): string | undefined {\n if (!user?.avatar || !user.id) {\n return undefined;\n }\n return `https://cdn.discordapp.com/avatars/${encodeURIComponent(user.id)}/${encodeURIComponent(user.avatar)}.png?size=128`;\n}\n\nfunction roomTypeForChannel(channelType: number | undefined): ChannelType {\n if (channelType === 1) {\n return ChannelType.DM;\n }\n return ChannelType.GROUP;\n}\n\nfunction worldIdFor(runtime: IAgentRuntime, serverKey: string): UUID {\n return stringToUuid(`discord-local-world:${runtime.agentId}:${serverKey}`) as UUID;\n}\n\nfunction roomIdFor(runtime: IAgentRuntime, channelId: string): UUID {\n return stringToUuid(`discord-local-room:${runtime.agentId}:${channelId}`) as UUID;\n}\n\nfunction entityIdFor(userId: string): UUID {\n return stringToUuid(`discord-local-user:${userId}`) as UUID;\n}\n\nfunction messageIdFor(runtime: IAgentRuntime, channelId: string, messageId: string): UUID {\n return stringToUuid(`discord-local-message:${runtime.agentId}:${channelId}:${messageId}`) as UUID;\n}\n\nfunction outboundMemoryIdFor(runtime: IAgentRuntime, roomId: UUID): UUID {\n return createUniqueUuid(runtime, `discord-local-outbound:${roomId}:${Date.now()}`) as UUID;\n}\n\nfunction getRegisteredSendHandlers(runtime: IAgentRuntime): Map<string, unknown> | null {\n const sendHandlers = (runtime as IAgentRuntime & { sendHandlers?: unknown }).sendHandlers;\n return sendHandlers instanceof Map ? sendHandlers : null;\n}\n\nfunction contentTypeForMime(mimeType: string | undefined): ContentType | undefined {\n const normalized = mimeType?.trim().toLowerCase();\n if (!normalized) {\n return undefined;\n }\n if (normalized.startsWith(\"image/\")) {\n return ContentType.IMAGE;\n }\n if (normalized.startsWith(\"video/\")) {\n return ContentType.VIDEO;\n }\n if (normalized.startsWith(\"audio/\")) {\n return ContentType.AUDIO;\n }\n if (normalized === \"text/uri-list\") {\n return ContentType.LINK;\n }\n return ContentType.DOCUMENT;\n}\n\nfunction describeRpcError(payload: DiscordLocalRpcPayload): string {\n const data =\n payload.data && typeof payload.data === \"object\"\n ? (payload.data as Record<string, unknown>)\n : null;\n const message =\n typeof data?.message === \"string\"\n ? data.message\n : typeof data?.error === \"string\"\n ? data.error\n : payload.cmd\n ? `Discord RPC command ${payload.cmd} failed`\n : \"Discord RPC request failed\";\n const code =\n typeof data?.code === \"number\" || typeof data?.code === \"string\"\n ? ` (${String(data.code)})`\n : \"\";\n return `${message}${code}`;\n}\n\nfunction toAppleScriptStringLiteral(value: string): string {\n return `\"${value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\nfunction buildDiscordSendScript(text: string, delaySeconds: number): string {\n const lines = text.split(/\\r?\\n/);\n const scriptLines = [\n 'tell application \"Discord\" to activate',\n `delay ${delaySeconds.toFixed(2)}`,\n 'tell application \"System Events\"',\n ];\n\n for (const [index, line] of lines.entries()) {\n if (line.length > 0) {\n scriptLines.push(` keystroke ${toAppleScriptStringLiteral(line)}`);\n }\n if (index < lines.length - 1) {\n scriptLines.push(\" key code 36 using shift down\");\n }\n }\n\n scriptLines.push(\" key code 36\");\n scriptLines.push(\"end tell\");\n\n return scriptLines.join(\"\\n\");\n}\n\nasync function openDiscordTarget(channelId: string, guildId?: string | null): Promise<void> {\n const url =\n guildId && guildId.trim().length > 0\n ? `discord://-/channels/${guildId}/${channelId}`\n : `discord://-/channels/@me/${channelId}`;\n await execFileAsync(\"/usr/bin/open\", [url]);\n}\n\nfunction getIpcCandidateDirs(): string[] {\n const candidates = [\n process.env.DISCORD_IPC_DIR,\n process.env.XDG_RUNTIME_DIR,\n process.env.TMPDIR,\n process.env.TMP,\n process.env.TEMP,\n \"/tmp\",\n \"/private/tmp\",\n ].filter((entry): entry is string => typeof entry === \"string\" && entry.trim().length > 0);\n\n return Array.from(new Set(candidates.map((entry) => entry.trim())));\n}\n\nfunction findDiscordIpcPath(): string | null {\n for (const dir of getIpcCandidateDirs()) {\n for (let index = 0; index < 10; index += 1) {\n const candidate = path.join(dir, `discord-ipc-${index}`);\n if (fs.existsSync(candidate)) {\n return candidate;\n }\n }\n }\n\n const macRoot = path.join(os.homedir(), \"Library\", \"Application Support\", \"discord\");\n if (!fs.existsSync(macRoot)) {\n return null;\n }\n\n const stack = [macRoot];\n while (stack.length > 0) {\n const current = stack.pop();\n if (!current) continue;\n\n const entries = fs.readdirSync(current, { withFileTypes: true });\n for (const entry of entries) {\n const candidatePath = path.join(current, entry.name);\n if (entry.isDirectory()) {\n stack.push(candidatePath);\n continue;\n }\n if (entry.isSocket() && /^discord-ipc-\\d+$/.test(entry.name)) {\n return candidatePath;\n }\n }\n }\n\n return null;\n}\n\nexport class DiscordLocalService extends Service {\n static serviceType = DISCORD_LOCAL_SERVICE_NAME;\n capabilityDescription =\n \"The agent can read Discord notifications and channel messages from the local Discord desktop app and send replies through macOS UI automation.\";\n\n private readonly sessionPath = resolveSessionPath();\n private readonly pendingRequests = new Map<string, PendingRpcRequest>();\n private readonly channelCache = new Map<string, DiscordLocalChannel>();\n private readonly guildCache = new Map<string, DiscordLocalGuild>();\n private readonly subscribedChannelIds = new Set<string>();\n private connectorConfig: DiscordLocalConfig | null = null;\n private socket: net.Socket | null = null;\n private connectedIpcPath: string | null = null;\n private readBuffer = Buffer.alloc(0);\n private readyPromise: Promise<void> | null = null;\n private readyResolve: (() => void) | null = null;\n private readyReject: ((error: Error) => void) | null = null;\n private reconnectTimer: NodeJS.Timeout | null = null;\n private session: DiscordLocalSession | null = null;\n private currentUser: DiscordLocalUser | null = null;\n private connected = false;\n private authenticated = false;\n private lastError: string | null = null;\n\n constructor(runtime?: IAgentRuntime) {\n super(runtime);\n if (!runtime) {\n return;\n }\n this.connectorConfig = getDiscordLocalConfig(runtime);\n }\n\n static async start(runtime: IAgentRuntime): Promise<DiscordLocalService> {\n const service = new DiscordLocalService(runtime);\n await service.startService();\n return service;\n }\n\n static registerSendHandlers(runtime: IAgentRuntime, service: DiscordLocalService): void {\n const register = (source: string) => {\n runtime.registerSendHandler(source, async (_runtime, target, content) => {\n const text = typeof content.text === \"string\" ? content.text.trim() : \"\";\n if (!text) {\n return;\n }\n\n const room =\n target.roomId && typeof runtime.getRoom === \"function\"\n ? await runtime.getRoom(target.roomId)\n : null;\n const channelId = String(target.channelId ?? room?.channelId ?? \"\").trim();\n if (!channelId) {\n throw new Error(\"Discord local target is missing a channel ID\");\n }\n\n const channel = await service.getChannel(channelId);\n const guildId =\n channel?.guild_id && channel.guild_id.trim().length > 0 ? channel.guild_id : null;\n await service.sendUiMessage(channelId, guildId, text);\n\n if (!target.roomId) {\n return;\n }\n\n const memory = createMessageMemory({\n id: outboundMemoryIdFor(runtime, target.roomId),\n agentId: runtime.agentId,\n entityId: runtime.agentId,\n roomId: target.roomId,\n content: {\n ...content,\n text,\n source: DISCORD_LOCAL_SERVICE_NAME,\n },\n }) as Memory;\n memory.createdAt = Date.now();\n memory.metadata = {\n ...memory.metadata,\n discordChannelId: channelId,\n ...(guildId ? { discordServerId: guildId } : {}),\n } as MemoryMetadata;\n\n await runtime.createMemory(memory, \"messages\");\n });\n };\n\n register(DISCORD_LOCAL_SERVICE_NAME);\n const sendHandlers = getRegisteredSendHandlers(runtime);\n if (!(sendHandlers instanceof Map) || !sendHandlers.has(\"discord\")) {\n register(\"discord\");\n }\n }\n\n async stop(): Promise<void> {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.connected = false;\n this.authenticated = false;\n this.connectedIpcPath = null;\n this.rejectPendingRequests(new Error(\"Discord local service stopped\"));\n this.socket?.destroy();\n this.socket = null;\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n isAuthenticated(): boolean {\n return this.authenticated;\n }\n\n getStatus() {\n return {\n available: Boolean(this.connectorConfig),\n connected: this.connected,\n authenticated: this.authenticated,\n currentUser: this.currentUser,\n subscribedChannelIds: [...this.subscribedChannelIds],\n configuredChannelIds: this.connectorConfig?.messageChannelIds ?? [],\n scopes: this.session?.scopes ?? this.connectorConfig?.scopes ?? [],\n lastError: this.lastError,\n ipcPath: this.connected ? this.connectedIpcPath : findDiscordIpcPath(),\n };\n }\n\n async authorize(): Promise<ReturnType<DiscordLocalService[\"getStatus\"]>> {\n const config = this.requireConfig();\n await this.ensureRpcConnection();\n const response = await this.sendRpcCommand(\"AUTHORIZE\", {\n client_id: config.clientId,\n scopes: config.scopes,\n });\n\n const code =\n response.data &&\n typeof response.data === \"object\" &&\n typeof (response.data as Record<string, unknown>).code === \"string\"\n ? ((response.data as Record<string, unknown>).code as string)\n : \"\";\n if (!code) {\n throw new Error(\"Discord AUTHORIZE did not return an authorization code\");\n }\n\n await this.exchangeAuthorizationCode(code);\n return this.getStatus();\n }\n\n async disconnectSession(): Promise<void> {\n this.session = null;\n this.currentUser = null;\n this.authenticated = false;\n this.subscribedChannelIds.clear();\n await fsp.rm(this.sessionPath, { force: true });\n await this.stop();\n }\n\n async listGuilds(): Promise<DiscordLocalGuild[]> {\n await this.ensureAuthenticated();\n const response = await this.sendRpcCommand(\"GET_GUILDS\");\n const guilds = Array.isArray(response.data) ? (response.data as DiscordLocalGuild[]) : [];\n for (const guild of guilds) {\n if (guild?.id) {\n this.guildCache.set(guild.id, guild);\n }\n }\n return guilds;\n }\n\n async listChannels(guildId: string): Promise<DiscordLocalChannel[]> {\n await this.ensureAuthenticated();\n const response = await this.sendRpcCommand(\"GET_CHANNELS\", {\n guild_id: guildId,\n });\n const channels = Array.isArray(response.data) ? (response.data as DiscordLocalChannel[]) : [];\n for (const channel of channels) {\n if (channel?.id) {\n this.channelCache.set(channel.id, channel);\n }\n }\n return channels;\n }\n\n async subscribeChannelMessages(channelIds: string[]): Promise<string[]> {\n const config = this.requireConfig();\n await this.ensureAuthenticated();\n const normalized = [...new Set(channelIds.map((entry) => entry.trim()).filter(Boolean))];\n config.messageChannelIds = normalized;\n\n for (const channelId of Array.from(this.subscribedChannelIds)) {\n if (normalized.includes(channelId)) {\n continue;\n }\n await this.sendRpcCommand(\"UNSUBSCRIBE\", { channel_id: channelId }, \"MESSAGE_CREATE\");\n this.subscribedChannelIds.delete(channelId);\n }\n\n for (const channelId of normalized) {\n if (this.subscribedChannelIds.has(channelId)) {\n continue;\n }\n await this.sendRpcCommand(\"SUBSCRIBE\", { channel_id: channelId }, \"MESSAGE_CREATE\");\n this.subscribedChannelIds.add(channelId);\n }\n\n return [...normalized];\n }\n\n async getChannel(channelId: string): Promise<DiscordLocalChannel | null> {\n const cached = this.channelCache.get(channelId);\n if (cached) {\n return cached;\n }\n await this.ensureAuthenticated();\n const response = await this.sendRpcCommand(\"GET_CHANNEL\", {\n channel_id: channelId,\n });\n const channel =\n response.data && typeof response.data === \"object\"\n ? (response.data as DiscordLocalChannel)\n : null;\n if (channel?.id) {\n this.channelCache.set(channel.id, channel);\n }\n return channel;\n }\n\n private requireConfig(): DiscordLocalConfig {\n if (!this.connectorConfig) {\n throw new Error(\"Discord local connector is not configured\");\n }\n if (process.platform !== \"darwin\") {\n throw new Error(\"Discord local connector currently supports macOS only\");\n }\n return this.connectorConfig;\n }\n\n private async startService(): Promise<void> {\n if (!this.connectorConfig?.enabled) {\n return;\n }\n\n this.session = await this.loadSession();\n if (!this.session) {\n return;\n }\n\n try {\n await this.ensureAuthenticated();\n } catch (error) {\n this.lastError = error instanceof Error ? error.message : String(error);\n logger.warn(`[discord-local] Failed to restore Discord local session: ${this.lastError}`);\n }\n }\n\n private async ensureAuthenticated(): Promise<void> {\n this.requireConfig();\n if (!this.session) {\n throw new Error(\"Discord local connector is not authorized\");\n }\n\n await this.ensureRpcConnection();\n\n const expiresAt = this.session.expiresAt ?? 0;\n if (this.session.refreshToken && expiresAt > 0 && Date.now() >= expiresAt - 60_000) {\n await this.refreshAccessToken();\n }\n\n if (this.authenticated) {\n return;\n }\n\n const response = await this.sendRpcCommand(\"AUTHENTICATE\", {\n access_token: this.session.accessToken,\n });\n const rawUser =\n response.data && typeof response.data === \"object\"\n ? ((response.data as Record<string, unknown>).user as DiscordLocalUser | undefined)\n : undefined;\n this.currentUser = rawUser ?? null;\n this.authenticated = true;\n await this.subscribeNotifications();\n await this.subscribeConfiguredChannels();\n }\n\n private async subscribeNotifications(): Promise<void> {\n if (!this.session?.scopes.includes(\"rpc.notifications.read\")) {\n return;\n }\n await this.sendRpcCommand(\"SUBSCRIBE\", {}, \"NOTIFICATION_CREATE\");\n }\n\n private async subscribeConfiguredChannels(): Promise<void> {\n const channelIds = this.connectorConfig?.messageChannelIds ?? [];\n for (const channelId of channelIds) {\n if (this.subscribedChannelIds.has(channelId)) {\n continue;\n }\n await this.sendRpcCommand(\"SUBSCRIBE\", { channel_id: channelId }, \"MESSAGE_CREATE\");\n this.subscribedChannelIds.add(channelId);\n }\n }\n\n private async exchangeAuthorizationCode(code: string): Promise<void> {\n const config = this.requireConfig();\n const body = new URLSearchParams({\n client_id: config.clientId,\n client_secret: config.clientSecret,\n grant_type: \"authorization_code\",\n code,\n });\n\n const response = await fetch(DISCORD_OAUTH_TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n if (!response.ok) {\n throw new Error(`Discord OAuth token exchange failed with ${response.status}`);\n }\n const json = (await response.json()) as Record<string, unknown>;\n await this.storeTokenResponse(json);\n this.authenticated = false;\n await this.ensureAuthenticated();\n }\n\n private async refreshAccessToken(): Promise<void> {\n const config = this.requireConfig();\n if (!this.session?.refreshToken) {\n throw new Error(\"Discord local session cannot be refreshed\");\n }\n\n const body = new URLSearchParams({\n client_id: config.clientId,\n client_secret: config.clientSecret,\n grant_type: \"refresh_token\",\n refresh_token: this.session.refreshToken,\n });\n\n const response = await fetch(DISCORD_OAUTH_TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body,\n });\n if (!response.ok) {\n throw new Error(`Discord OAuth refresh failed with ${response.status}`);\n }\n const json = (await response.json()) as Record<string, unknown>;\n await this.storeTokenResponse(json);\n this.authenticated = false;\n }\n\n private async storeTokenResponse(json: Record<string, unknown>): Promise<void> {\n const accessToken = typeof json.access_token === \"string\" ? json.access_token : \"\";\n if (!accessToken) {\n throw new Error(\"Discord OAuth token response is missing access_token\");\n }\n\n const refreshToken = typeof json.refresh_token === \"string\" ? json.refresh_token : undefined;\n const expiresIn =\n typeof json.expires_in === \"number\"\n ? json.expires_in\n : typeof json.expires_in === \"string\"\n ? Number.parseInt(json.expires_in, 10)\n : 0;\n const scopeString =\n typeof json.scope === \"string\" ? json.scope : (this.connectorConfig?.scopes.join(\" \") ?? \"\");\n\n this.session = {\n accessToken,\n refreshToken,\n expiresAt:\n Number.isFinite(expiresIn) && expiresIn > 0 ? Date.now() + expiresIn * 1000 : undefined,\n scopes: scopeString\n .split(/\\s+/)\n .map((entry) => entry.trim())\n .filter(Boolean),\n };\n await fsp.writeFile(this.sessionPath, JSON.stringify(this.session, null, 2), \"utf8\");\n }\n\n private async loadSession(): Promise<DiscordLocalSession | null> {\n if (!fs.existsSync(this.sessionPath)) {\n return null;\n }\n const raw = await fsp.readFile(this.sessionPath, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<DiscordLocalSession>;\n if (typeof parsed.accessToken !== \"string\" || parsed.accessToken.trim().length === 0) {\n return null;\n }\n return {\n accessToken: parsed.accessToken,\n refreshToken: typeof parsed.refreshToken === \"string\" ? parsed.refreshToken : undefined,\n expiresAt: typeof parsed.expiresAt === \"number\" ? parsed.expiresAt : undefined,\n scopes: Array.isArray(parsed.scopes)\n ? parsed.scopes.filter((entry): entry is string => typeof entry === \"string\")\n : [...DISCORD_LOCAL_DEFAULT_SCOPES],\n };\n }\n\n private async ensureRpcConnection(): Promise<void> {\n const config = this.requireConfig();\n if (this.connected && this.socket && !this.socket.destroyed) {\n return;\n }\n if (this.readyPromise) {\n return this.readyPromise;\n }\n\n const ipcPath = findDiscordIpcPath();\n if (!ipcPath) {\n throw new Error(\"Discord IPC socket not found. Open the Discord desktop app first.\");\n }\n\n this.readyPromise = new Promise<void>((resolve, reject) => {\n this.readyResolve = resolve;\n this.readyReject = reject;\n });\n\n const socket = net.createConnection(ipcPath);\n this.socket = socket;\n this.readBuffer = Buffer.alloc(0);\n\n socket.on(\"connect\", () => {\n this.connectedIpcPath = ipcPath;\n this.writeFrame(IPC_OP_HANDSHAKE, {\n v: 1,\n client_id: config.clientId,\n });\n });\n\n socket.on(\"data\", (chunk: Buffer) => {\n this.handleSocketData(chunk);\n });\n\n socket.on(\"close\", () => {\n const error = new Error(\"Discord local RPC connection closed\");\n this.connected = false;\n this.authenticated = false;\n this.connectedIpcPath = null;\n this.socket = null;\n this.rejectPendingRequests(error);\n this.readyReject?.(error);\n this.readyReject = null;\n this.readyResolve = null;\n this.readyPromise = null;\n if (this.session?.accessToken) {\n this.scheduleReconnect();\n }\n });\n\n socket.on(\"error\", (error) => {\n this.lastError = error.message;\n this.connectedIpcPath = null;\n this.readyReject?.(error);\n this.readyReject = null;\n this.readyResolve = null;\n this.readyPromise = null;\n this.rejectPendingRequests(error);\n });\n\n await this.readyPromise;\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n }\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n void this.ensureAuthenticated().catch((error) => {\n this.lastError = error instanceof Error ? error.message : String(error);\n });\n }, 3_000);\n }\n\n private handleSocketData(chunk: Buffer): void {\n this.readBuffer = Buffer.concat([this.readBuffer, chunk]);\n while (this.readBuffer.length >= 8) {\n const op = this.readBuffer.readInt32LE(0);\n const length = this.readBuffer.readInt32LE(4);\n if (length < 0) {\n logger.warn(\"[discord-local] Discarding malformed IPC frame with negative payload length\");\n this.readBuffer = Buffer.alloc(0);\n return;\n }\n if (this.readBuffer.length < 8 + length) {\n return;\n }\n\n const body = this.readBuffer.subarray(8, 8 + length);\n this.readBuffer = this.readBuffer.subarray(8 + length);\n let payload: DiscordLocalRpcPayload;\n try {\n payload = JSON.parse(body.toString(\"utf8\")) as DiscordLocalRpcPayload;\n } catch {\n logger.warn(\"[discord-local] Discarding malformed IPC frame with invalid JSON payload\");\n continue;\n }\n this.handleRpcPayload(op, payload);\n }\n }\n\n private handleRpcPayload(op: number, payload: DiscordLocalRpcPayload): void {\n if (op === IPC_OP_PING) {\n this.writeFrame(IPC_OP_PONG, payload);\n return;\n }\n\n if (op === IPC_OP_CLOSE) {\n this.lastError = \"Discord local RPC closed the connection\";\n this.socket?.destroy();\n return;\n }\n\n if (payload.nonce) {\n const pending = this.pendingRequests.get(payload.nonce);\n if (pending) {\n this.pendingRequests.delete(payload.nonce);\n if (payload.evt === \"ERROR\") {\n pending.reject(new Error(describeRpcError(payload)));\n } else {\n pending.resolve(payload);\n }\n return;\n }\n }\n\n if (payload.evt === \"READY\") {\n this.connected = true;\n this.readyResolve?.();\n this.readyResolve = null;\n this.readyReject = null;\n this.readyPromise = null;\n return;\n }\n\n if (payload.evt === \"MESSAGE_CREATE\") {\n const data = payload.data as Record<string, unknown> | undefined;\n const channelId = typeof data?.channel_id === \"string\" ? data.channel_id : undefined;\n const message =\n data && typeof data.message === \"object\"\n ? (data.message as DiscordLocalMessage)\n : (payload.data as DiscordLocalMessage | undefined);\n if (channelId && message) {\n void this.ingestMessage(channelId, message);\n }\n return;\n }\n\n if (payload.evt === \"NOTIFICATION_CREATE\") {\n const notification = payload.data as DiscordLocalNotification | undefined;\n const channelId =\n notification?.channel_id ??\n (typeof notification?.message?.channel_id === \"string\"\n ? notification.message.channel_id\n : undefined);\n const message = notification?.message ?? null;\n if (channelId && message) {\n void this.ingestMessage(channelId, message);\n }\n }\n }\n\n private writeFrame(op: number, payload: Record<string, unknown>): void {\n if (!this.socket) {\n throw new Error(\"Discord local RPC socket is not connected\");\n }\n const body = Buffer.from(JSON.stringify(payload), \"utf8\");\n const header = Buffer.alloc(8);\n header.writeInt32LE(op, 0);\n header.writeInt32LE(body.length, 4);\n this.socket.write(Buffer.concat([header, body]));\n }\n\n private async sendRpcCommand(\n cmd: string,\n args: Record<string, unknown> = {},\n evt?: string\n ): Promise<DiscordLocalRpcPayload> {\n await this.ensureRpcConnection();\n const nonce = crypto.randomUUID();\n\n return await new Promise<DiscordLocalRpcPayload>((resolve, reject) => {\n const timeout = setTimeout(() => {\n if (!this.pendingRequests.delete(nonce)) {\n return;\n }\n reject(new Error(`Discord RPC command ${cmd} timed out`));\n }, 20_000);\n this.pendingRequests.set(nonce, {\n resolve: (value) => {\n clearTimeout(timeout);\n resolve(value);\n },\n reject: (error) => {\n clearTimeout(timeout);\n reject(error);\n },\n });\n try {\n this.writeFrame(IPC_OP_FRAME, {\n cmd,\n args,\n ...(evt ? { evt } : {}),\n nonce,\n });\n } catch (error) {\n clearTimeout(timeout);\n this.pendingRequests.delete(nonce);\n reject(error instanceof Error ? error : new Error(String(error)));\n }\n });\n }\n\n private rejectPendingRequests(error: Error): void {\n for (const pending of this.pendingRequests.values()) {\n pending.reject(error);\n }\n this.pendingRequests.clear();\n }\n\n private async ingestMessage(channelId: string, message: DiscordLocalMessage): Promise<void> {\n if (!message.id) {\n return;\n }\n if (message.author?.id && message.author.id === this.currentUser?.id) {\n return;\n }\n\n const memoryId = messageIdFor(this.runtime, channelId, message.id);\n const existing = await this.runtime.getMemoryById(memoryId);\n if (existing) {\n return;\n }\n\n const channel = await this.getChannel(channelId);\n const guildId = channel?.guild_id ?? message.guild_id ?? null;\n const guild = guildId ? (this.guildCache.get(guildId) ?? null) : null;\n const serverKey = guildId ?? `dm:${channelId}`;\n const worldId = worldIdFor(this.runtime, serverKey);\n const roomId = roomIdFor(this.runtime, channelId);\n const entityId = entityIdFor(message.author?.id ?? channelId);\n const roomType = roomTypeForChannel(channel?.type);\n const roomName =\n channel?.name?.trim() ||\n message.author?.global_name ||\n message.author?.username ||\n `Discord ${channelId}`;\n\n // `roomName` is accepted by the local `./eliza` source but not by\n // the npm beta dist-tag of `@elizaos/core`. Cast around the\n // excess-property check so the call works under both resolutions;\n // the runtime itself reads `roomName` in both versions, the type\n // just lags in the published package.\n type EnsureConnectionArg = Parameters<typeof this.runtime.ensureConnection>[0] & {\n roomName?: string;\n };\n await this.runtime.ensureConnection({\n entityId,\n roomId,\n roomName,\n worldId,\n worldName: guild?.name ?? \"Discord Direct Messages\",\n userName: message.author?.username ?? undefined,\n userId: message.author?.id as UUID | undefined,\n name: message.author?.global_name ?? message.author?.username ?? undefined,\n source: DISCORD_LOCAL_SERVICE_NAME,\n type: roomType,\n channelId,\n messageServerId: stringToUuid(`discord-local-server:${serverKey}`) as UUID,\n metadata: {\n discordChannelId: channelId,\n ...(guildId ? { discordServerId: guildId } : {}),\n },\n } as EnsureConnectionArg);\n\n const attachments: Media[] = (message.attachments ?? []).flatMap((attachment) => {\n const url = attachment.url?.trim();\n if (!url) {\n return [];\n }\n return [\n {\n id: attachment.id,\n url,\n title: attachment.filename,\n source: DISCORD_LOCAL_SERVICE_NAME,\n description: attachment.description ?? undefined,\n contentType: contentTypeForMime(attachment.content_type),\n },\n ];\n });\n\n const replyReference =\n message.referenced_message?.id ?? message.message_reference?.message_id ?? undefined;\n const replyChannelId =\n message.referenced_message?.channel_id ?? message.message_reference?.channel_id ?? channelId;\n const inReplyTo =\n typeof replyReference === \"string\" && replyReference.length > 0\n ? messageIdFor(this.runtime, replyChannelId, replyReference)\n : undefined;\n\n const memory = createMessageMemory({\n id: memoryId,\n agentId: this.runtime.agentId,\n entityId,\n roomId,\n content: {\n text: message.content ?? \"\",\n source: DISCORD_LOCAL_SERVICE_NAME,\n ...(attachments.length > 0 ? { attachments } : {}),\n ...(inReplyTo ? { inReplyTo } : {}),\n },\n }) as Memory;\n memory.createdAt = message.timestamp ? Date.parse(message.timestamp) : Date.now();\n memory.metadata = {\n ...memory.metadata,\n source: DISCORD_LOCAL_SERVICE_NAME,\n provider: \"discord\",\n timestamp: memory.createdAt,\n entityName: message.author?.global_name ?? message.author?.username ?? roomName,\n entityUserName: message.author?.username ?? undefined,\n entityAvatarUrl: buildDiscordAvatarUrl(message.author),\n fromId: message.author?.id ?? undefined,\n sourceId: entityId,\n sender: {\n id: message.author?.id ?? undefined,\n name: message.author?.global_name ?? message.author?.username ?? roomName,\n username: message.author?.username ?? undefined,\n },\n [DISCORD_LOCAL_SERVICE_NAME]: {\n id: message.author?.id ?? undefined,\n userId: message.author?.id ?? undefined,\n username: message.author?.username ?? undefined,\n userName: message.author?.username ?? undefined,\n name: message.author?.global_name ?? message.author?.username ?? roomName,\n messageId: message.id,\n channelId,\n guildId: guildId ?? undefined,\n },\n discord: {\n id: message.author?.id ?? undefined,\n userId: message.author?.id ?? undefined,\n username: message.author?.username ?? undefined,\n userName: message.author?.username ?? undefined,\n name: message.author?.global_name ?? message.author?.username ?? roomName,\n messageId: message.id,\n channelId,\n guildId: guildId ?? undefined,\n },\n discordChannelId: channelId,\n discordMessageId: message.id,\n ...(guildId ? { discordServerId: guildId } : {}),\n } as MemoryMetadata;\n\n await this.runtime.createMemory(memory, \"messages\");\n }\n\n private async sendUiMessage(\n channelId: string,\n guildId: string | null,\n text: string\n ): Promise<void> {\n const config = this.requireConfig();\n if (process.platform !== \"darwin\") {\n throw new Error(\"Discord local send automation currently supports macOS only\");\n }\n\n await openDiscordTarget(channelId, guildId);\n const script = buildDiscordSendScript(text, config.sendDelayMs / 1000);\n await execFileAsync(\"/usr/bin/osascript\", [\"-e\", script]);\n }\n}\n\nfunction isConnectorSetupService(service: unknown): service is ConnectorSetupService {\n if (!service || typeof service !== \"object\") {\n return false;\n }\n\n const candidate = service as Record<string, unknown>;\n return (\n typeof candidate.getConfig === \"function\" &&\n typeof candidate.updateConfig === \"function\" &&\n typeof candidate.registerEscalationChannel === \"function\" &&\n typeof candidate.setOwnerContact === \"function\"\n );\n}\n\nfunction getSetupService(runtime: IAgentRuntime): ConnectorSetupService | null {\n const service = runtime.getService(\"connector-setup\");\n return isConnectorSetupService(service) ? service : null;\n}\n\nfunction resolveDiscordLocalService(runtime: IAgentRuntime): DiscordLocalService | null {\n const service = runtime.getService(DISCORD_LOCAL_SERVICE_NAME);\n return service instanceof DiscordLocalService ? service : null;\n}\n\nfunction getConnectorConfig(setupService: ConnectorSetupService): ConnectorConfig {\n const config = setupService.getConfig();\n const connectors =\n (config.connectors as Record<string, ConnectorConfig> | undefined) ??\n ((config as Record<string, unknown>).channels as Record<string, ConnectorConfig> | undefined) ??\n {};\n\n const current = connectors.discordLocal;\n if (current && typeof current === \"object\" && !Array.isArray(current)) {\n return current as ConnectorConfig;\n }\n return {};\n}\n\nasync function handleDiscordLocalStatus(\n _req: RouteRequest,\n res: RouteResponse,\n runtime: IAgentRuntime\n): Promise<void> {\n const service = resolveDiscordLocalService(runtime);\n res.status(200).json(\n service\n ? service.getStatus()\n : {\n available: false,\n connected: false,\n authenticated: false,\n currentUser: null,\n subscribedChannelIds: [],\n configuredChannelIds: [],\n scopes: [],\n lastError: \"discord-local service not registered\",\n ipcPath: null,\n reason: \"discord-local service not registered\",\n }\n );\n}\n\nasync function handleDiscordLocalAuthorize(\n _req: RouteRequest,\n res: RouteResponse,\n runtime: IAgentRuntime\n): Promise<void> {\n const service = resolveDiscordLocalService(runtime);\n if (!service) {\n res.status(503).json({ error: \"discord-local service not registered\" });\n return;\n }\n\n try {\n res.status(200).json(await service.authorize());\n } catch (error) {\n res.status(500).json({\n error: `failed to authorize discord-local: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n\nasync function handleDiscordLocalDisconnect(\n _req: RouteRequest,\n res: RouteResponse,\n runtime: IAgentRuntime\n): Promise<void> {\n const service = resolveDiscordLocalService(runtime);\n if (!service) {\n res.status(503).json({ error: \"discord-local service not registered\" });\n return;\n }\n\n try {\n await service.disconnectSession();\n res.status(200).json({ ok: true });\n } catch (error) {\n res.status(500).json({\n error: `failed to disconnect discord-local: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n\nasync function handleDiscordLocalGuilds(\n _req: RouteRequest,\n res: RouteResponse,\n runtime: IAgentRuntime\n): Promise<void> {\n const service = resolveDiscordLocalService(runtime);\n if (!service) {\n res.status(503).json({ error: \"discord-local service not registered\" });\n return;\n }\n\n try {\n const guilds = await service.listGuilds();\n res.status(200).json({ guilds, count: guilds.length });\n } catch (error) {\n res.status(500).json({\n error: `failed to list discord-local guilds: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n\nasync function handleDiscordLocalChannels(\n req: RouteRequest,\n res: RouteResponse,\n runtime: IAgentRuntime\n): Promise<void> {\n const service = resolveDiscordLocalService(runtime);\n if (!service) {\n res.status(503).json({ error: \"discord-local service not registered\" });\n return;\n }\n\n const url = new URL(req.url ?? \"/api/discord-local/channels\", \"http://localhost\");\n const guildId = url.searchParams.get(\"guildId\")?.trim() ?? \"\";\n if (!guildId) {\n res.status(400).json({ error: \"guildId is required\" });\n return;\n }\n\n try {\n const channels = await service.listChannels(guildId);\n res.status(200).json({ channels, count: channels.length });\n } catch (error) {\n res.status(500).json({\n error: `failed to list discord-local channels: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n\nasync function handleDiscordLocalSubscriptions(\n req: RouteRequest,\n res: RouteResponse,\n runtime: IAgentRuntime\n): Promise<void> {\n const service = resolveDiscordLocalService(runtime);\n if (!service) {\n res.status(503).json({ error: \"discord-local service not registered\" });\n return;\n }\n\n const body = req.body;\n if (!body) {\n res.status(400).json({ error: \"request body is required\" });\n return;\n }\n\n const rawChannelIds = body.channelIds;\n const channelIds = Array.isArray(rawChannelIds)\n ? Array.from(\n new Set(\n rawChannelIds\n .map((entry) => (typeof entry === \"string\" ? entry.trim() : \"\"))\n .filter((entry) => entry.length > 0)\n )\n )\n : [];\n\n try {\n const subscribedChannelIds = await service.subscribeChannelMessages(channelIds);\n\n const setupService = getSetupService(runtime);\n if (setupService) {\n const connectorConfig = getConnectorConfig(setupService);\n setupService.updateConfig((config) => {\n if (!config.connectors) {\n config.connectors = {};\n }\n (config.connectors as Record<string, ConnectorConfig>).discordLocal = {\n ...connectorConfig,\n enabled: connectorConfig.enabled !== false,\n messageChannelIds: subscribedChannelIds,\n };\n });\n\n if (subscribedChannelIds.length > 0) {\n setupService.setOwnerContact({\n source: \"discord\",\n channelId: subscribedChannelIds[0],\n });\n setupService.registerEscalationChannel(\"discord\");\n }\n }\n\n res.status(200).json({ subscribedChannelIds });\n } catch (error) {\n res.status(500).json({\n error: `failed to update discord-local subscriptions: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n\nconst discordLocalSetupRoutes: Route[] = [\n {\n type: \"GET\",\n path: \"/api/discord-local/status\",\n handler: handleDiscordLocalStatus,\n rawPath: true,\n },\n {\n type: \"POST\",\n path: \"/api/discord-local/authorize\",\n handler: handleDiscordLocalAuthorize,\n rawPath: true,\n },\n {\n type: \"POST\",\n path: \"/api/discord-local/disconnect\",\n handler: handleDiscordLocalDisconnect,\n rawPath: true,\n },\n {\n type: \"GET\",\n path: \"/api/discord-local/guilds\",\n handler: handleDiscordLocalGuilds,\n rawPath: true,\n },\n {\n type: \"GET\",\n path: \"/api/discord-local/channels\",\n handler: handleDiscordLocalChannels,\n rawPath: true,\n },\n {\n type: \"POST\",\n path: \"/api/discord-local/subscriptions\",\n handler: handleDiscordLocalSubscriptions,\n rawPath: true,\n },\n];\n\nconst discordLocalPlugin: Plugin = {\n name: DISCORD_LOCAL_PLUGIN_NAME,\n description:\n \"Local Discord desktop integration for Eliza via Discord RPC and macOS UI automation\",\n services: [DiscordLocalService],\n routes: discordLocalSetupRoutes,\n};\n\nexport default discordLocalPlugin;\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "675CB555791E257564756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,86 @@
1
+ import { type IAgentRuntime, type Plugin, Service } from "@elizaos/core";
2
+ export declare const DISCORD_LOCAL_PLUGIN_NAME = "@elizaos/plugin-discord-local";
3
+ export declare const DISCORD_LOCAL_SERVICE_NAME = "discord-local";
4
+ type DiscordLocalUser = {
5
+ id: string;
6
+ username: string;
7
+ global_name?: string | null;
8
+ avatar?: string | null;
9
+ };
10
+ type DiscordLocalChannel = {
11
+ id: string;
12
+ guild_id?: string | null;
13
+ type?: number;
14
+ name?: string | null;
15
+ recipients?: DiscordLocalUser[];
16
+ };
17
+ type DiscordLocalGuild = {
18
+ id: string;
19
+ name: string;
20
+ };
21
+ export declare class DiscordLocalService extends Service {
22
+ static serviceType: string;
23
+ capabilityDescription: string;
24
+ private readonly sessionPath;
25
+ private readonly pendingRequests;
26
+ private readonly channelCache;
27
+ private readonly guildCache;
28
+ private readonly subscribedChannelIds;
29
+ private connectorConfig;
30
+ private socket;
31
+ private connectedIpcPath;
32
+ private readBuffer;
33
+ private readyPromise;
34
+ private readyResolve;
35
+ private readyReject;
36
+ private reconnectTimer;
37
+ private session;
38
+ private currentUser;
39
+ private connected;
40
+ private authenticated;
41
+ private lastError;
42
+ constructor(runtime?: IAgentRuntime);
43
+ static start(runtime: IAgentRuntime): Promise<DiscordLocalService>;
44
+ static registerSendHandlers(runtime: IAgentRuntime, service: DiscordLocalService): void;
45
+ stop(): Promise<void>;
46
+ isConnected(): boolean;
47
+ isAuthenticated(): boolean;
48
+ getStatus(): {
49
+ available: boolean;
50
+ connected: boolean;
51
+ authenticated: boolean;
52
+ currentUser: DiscordLocalUser;
53
+ subscribedChannelIds: string[];
54
+ configuredChannelIds: string[];
55
+ scopes: string[];
56
+ lastError: string;
57
+ ipcPath: string;
58
+ };
59
+ authorize(): Promise<ReturnType<DiscordLocalService["getStatus"]>>;
60
+ disconnectSession(): Promise<void>;
61
+ listGuilds(): Promise<DiscordLocalGuild[]>;
62
+ listChannels(guildId: string): Promise<DiscordLocalChannel[]>;
63
+ subscribeChannelMessages(channelIds: string[]): Promise<string[]>;
64
+ getChannel(channelId: string): Promise<DiscordLocalChannel | null>;
65
+ private requireConfig;
66
+ private startService;
67
+ private ensureAuthenticated;
68
+ private subscribeNotifications;
69
+ private subscribeConfiguredChannels;
70
+ private exchangeAuthorizationCode;
71
+ private refreshAccessToken;
72
+ private storeTokenResponse;
73
+ private loadSession;
74
+ private ensureRpcConnection;
75
+ private scheduleReconnect;
76
+ private handleSocketData;
77
+ private handleRpcPayload;
78
+ private writeFrame;
79
+ private sendRpcCommand;
80
+ private rejectPendingRequests;
81
+ private ingestMessage;
82
+ private sendUiMessage;
83
+ }
84
+ declare const discordLocalPlugin: Plugin;
85
+ export default discordLocalPlugin;
86
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@elizaos/plugin-discord-local",
3
+ "version": "2.0.0-beta.1",
4
+ "description": "Local Discord desktop integration for Eliza via Discord RPC and macOS UI automation",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "types": "dist/src/index.d.ts",
9
+ "packageType": "plugin",
10
+ "platform": "node",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "plugin",
14
+ "elizaos",
15
+ "discord",
16
+ "desktop"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/elizaos/eliza"
21
+ },
22
+ "exports": {
23
+ "./package.json": "./package.json",
24
+ ".": {
25
+ "import": "./dist/index.js",
26
+ "default": "./dist/index.js",
27
+ "types": "./dist/src/index.d.ts"
28
+ }
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "package.json"
33
+ ],
34
+ "elizaos": {
35
+ "plugin": {
36
+ "capabilities": [
37
+ "messaging"
38
+ ]
39
+ }
40
+ },
41
+ "peerDependencies": {
42
+ "@elizaos/core": "2.0.0-beta.1"
43
+ },
44
+ "devDependencies": {
45
+ "@biomejs/biome": "^2.4.14",
46
+ "@types/node": "^25.0.3",
47
+ "typescript": "^6.0.3"
48
+ },
49
+ "scripts": {
50
+ "dev": "bun --hot build.ts",
51
+ "lint": "bunx @biomejs/biome check --write --config-path ./biome.json .",
52
+ "typecheck": "tsc --noEmit -p tsconfig.json",
53
+ "clean": "rm -rf dist .turbo",
54
+ "lint:check": "bunx @biomejs/biome check --config-path ./biome.json .",
55
+ "build": "bun run build.ts",
56
+ "build:ts": "bun run build.ts",
57
+ "format": "bunx @biomejs/biome format --write --config-path ./biome.json .",
58
+ "format:check": "bunx @biomejs/biome format --config-path ./biome.json ."
59
+ },
60
+ "publishConfig": {
61
+ "access": "public"
62
+ }
63
+ }