import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { Type } from "typebox"; import { randomUUID } from "node:crypto"; import { appendMessage, validateChannelName } from "./transport.ts"; import type { SubscriptionMode, InboxMessage } from "./types.ts"; export function createIdentity(inboxName: string): string { const shortId = randomUUID().slice(0, 6); return `${inboxName}/${shortId}`; } export function registerInboxTools( pi: ExtensionAPI, getInboxName: () => string, getDataDir: () => string, getSubscriptions: () => string[], getIdentity: () => string, advanceCursor: (snapshots: { channel: string; messages: InboxMessage[] }[]) => void, getSubscriptionMode: (channel: string) => SubscriptionMode | undefined, ) { pi.registerTool({ name: "inbox_post", label: "Inbox Post", description: "Post a message to an inbox channel.", promptSnippet: "Post a message to an inbox channel", promptGuidelines: [ "Use inbox_post to send a message to an inbox channel you are subscribed to.", "Keep messages concise and focused.", ], parameters: Type.Object({ channel: Type.String({ description: "The channel to post to" }), message: Type.String({ description: "The message content" }), }), async execute(_toolCallId, params) { const channelError = validateChannelName(params.channel); if (channelError) { return { content: [{ type: "text" as const, text: channelError }], details: undefined, }; } const subs = getSubscriptions(); if (!subs.includes(params.channel)) { const list = subs.length > 0 ? subs.join(", ") : "none"; return { content: [{ type: "text" as const, text: `Cannot post to "${params.channel}" — you are only subscribed to: ${list}` }], details: undefined, }; } const mode = getSubscriptionMode(params.channel); if (mode === "ro") { return { content: [{ type: "text" as const, text: `Cannot post to "${params.channel}" — subscription is read-only (use :rw to re-subscribe)` }], details: undefined, }; } const dataDir = getDataDir(); const identity = getIdentity(); const msg: InboxMessage = { id: randomUUID(), from: identity, content: params.message, ts: Date.now(), }; appendMessage(dataDir, getInboxName(), params.channel, msg); advanceCursor([{ channel: params.channel, messages: [msg] }]); return { content: [{ type: "text" as const, text: `Posted to "${params.channel}": ${params.message.slice(0, 100)}` }], details: undefined, }; }, }); }