import { App } from "@slack/bolt" import { createOpencode } from "@opencode-ai/sdk" const app = new App({ token: process.env.SLACK_BOT_TOKEN, signingSecret: process.env.SLACK_SIGNING_SECRET, socketMode: true, appToken: process.env.SLACK_APP_TOKEN, }) console.log("๐Ÿ”ง Bot configuration:") console.log("- Bot token present:", !!process.env.SLACK_BOT_TOKEN) console.log("- Signing secret present:", !!process.env.SLACK_SIGNING_SECRET) console.log("- App token present:", !!process.env.SLACK_APP_TOKEN) console.log("๐Ÿš€ Starting opencode server...") const opencode = await createOpencode({ port: 0, }) console.log("โœ… Opencode server ready") const sessions = new Map() app.use(async ({ next, context }) => { console.log("๐Ÿ“ก Raw Slack event:", JSON.stringify(context, null, 2)) await next() }) app.message(async ({ message, say }) => { console.log("๐Ÿ“จ Received message event:", JSON.stringify(message, null, 2)) if (message.subtype || !("text" in message) || !message.text) { console.log("โญ๏ธ Skipping message - no text or has subtype") return } console.log("โœ… Processing message:", message.text) const channel = message.channel const thread = (message as any).thread_ts || message.ts const sessionKey = `${channel}-${thread}` let session = sessions.get(sessionKey) if (!session) { console.log("๐Ÿ†• Creating new opencode session...") const { client, server } = opencode const createResult = await client.session.create({ body: { title: `Slack thread ${thread}` }, }) if (createResult.error) { console.error("โŒ Failed to create session:", createResult.error) await say({ text: "Sorry, I had trouble creating a session. Please try again.", thread_ts: thread }) return } console.log("โœ… Created opencode session:", createResult.data.id) session = { client, server, sessionId: createResult.data.id, channel, thread } sessions.set(sessionKey, session) const shareResult = await client.session.share({ path: { id: createResult.data.id } }) if (!shareResult.error && shareResult.data) { const sessionUrl = shareResult.data.share?.url! console.log("๐Ÿ”— Session shared:", sessionUrl) await app.client.chat.postMessage({ channel, thread_ts: thread, text: sessionUrl }) } } console.log("๐Ÿ“ Sending to opencode:", message.text) const result = await session.client.session.prompt({ path: { id: session.sessionId }, body: { parts: [{ type: "text", text: message.text }] }, }) console.log("๐Ÿ“ค Opencode response:", JSON.stringify(result, null, 2)) if (result.error) { console.error("โŒ Failed to send message:", result.error) await say({ text: "Sorry, I had trouble processing your message. Please try again.", thread_ts: thread }) return } const response = result.data const responseText = response.info?.content || response.parts ?.filter((p: any) => p.type === "text") .map((p: any) => p.text) .join("\n") || "I received your message but didn't have a response." console.log("๐Ÿ’ฌ Sending response:", responseText) await say({ text: responseText, thread_ts: thread }) }) app.command("/test", async ({ command, ack, say }) => { await ack() console.log("๐Ÿงช Test command received:", JSON.stringify(command, null, 2)) await say("๐Ÿค– Bot is working! I can hear you loud and clear.") }) await app.start() console.log("โšก๏ธ Slack bot is running!")