my harness for niri
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

reply_to in ingress event

+64 -1
+64 -1
src/triggers/discord.ts
··· 1 1 import type { UserMessage } from "../types.js" 2 + import { getDb } from "../db.js" 2 3 3 4 function asIsoTimestamp(value: unknown, fallback: string): string { 4 5 if (typeof value !== "string" && typeof value !== "number") return fallback ··· 6 7 return Number.isNaN(parsed.getTime()) ? fallback : parsed.toISOString() 7 8 } 8 9 10 + function asRecord(value: unknown): Record<string, unknown> | null { 11 + return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : null 12 + } 13 + 14 + function asString(value: unknown): string | null { 15 + if (typeof value === "string") { 16 + const trimmed = value.trim() 17 + return trimmed.length > 0 ? trimmed : null 18 + } 19 + if (typeof value === "number" && Number.isFinite(value)) return String(value) 20 + return null 21 + } 22 + 23 + function referencedMessageId(message: Record<string, unknown>, body: Record<string, unknown>): string | null { 24 + const reference = 25 + asRecord(message.message_reference) ?? 26 + asRecord(body.message_reference) ?? 27 + asRecord(message.reference) ?? 28 + asRecord(body.reference) 29 + return asString(reference?.message_id) ?? asString(reference?.messageId) ?? asString(reference?.id) 30 + } 31 + 32 + function embeddedReferencedMessage( 33 + message: Record<string, unknown>, 34 + body: Record<string, unknown>, 35 + ): { message_id: string; author_username: string | null; content: string } | null { 36 + const referenced = asRecord(message.referenced_message) ?? asRecord(body.referenced_message) 37 + if (!referenced) return null 38 + 39 + const messageId = asString(referenced.id) 40 + if (!messageId) return null 41 + 42 + const author = asRecord(referenced.author) 43 + return { 44 + message_id: messageId, 45 + author_username: asString(author?.global_name) ?? asString(author?.username), 46 + content: String(referenced.content ?? ""), 47 + } 48 + } 49 + 50 + function replyContextLine(message: Record<string, unknown>, body: Record<string, unknown>): string | null { 51 + const refId = referencedMessageId(message, body) 52 + if (!refId) return null 53 + 54 + const db = getDb() 55 + const stored = db 56 + .prepare( 57 + `select message_id, author_username, content 58 + from discord_messages 59 + where message_id = ?`, 60 + ) 61 + .get(refId) as { message_id: string; author_username: string | null; content: string } | undefined 62 + const reply = stored ?? embeddedReferencedMessage(message, body) ?? { 63 + message_id: refId, 64 + author_username: null, 65 + content: "", 66 + } 67 + const author = reply.author_username ? `@${reply.author_username}` : "unknown" 68 + return `reply_to: ${author} msg/${reply.message_id}: ${JSON.stringify(reply.content)}` 69 + } 70 + 9 71 export function fromDiscord(body: unknown): UserMessage { 10 72 const b = body as Record<string, unknown> 11 73 const message = (typeof b.message === "object" && b.message ··· 45 107 const action = isDm 46 108 ? "This is a direct message. Reply if it needs a response." 47 109 : "This is a server channel message, not a DM. You may choose not to reply; only respond if useful." 110 + const replyLine = replyContextLine(message, b) 48 111 49 112 return { 50 113 source: "discord", 51 114 triggeredAt, 52 - content: `${header} @${authorName}\ncontext: ${location}\nmessage_id: ${messageId}\ntimestamp: ${timestamp}\naction: ${action}\n\n${content}`, 115 + content: `${header} @${authorName}\ncontext: ${location}\nmessage_id: ${messageId}\ntimestamp: ${timestamp}${replyLine ? `\n${replyLine}` : ""}\naction: ${action}\n\n${content}`, 53 116 raw: body, 54 117 } 55 118 }