|
@@ -0,0 +1,105 @@
|
|
|
|
|
+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<string, { client: any; server: any; sessionId: string; channel: string; thread: string }>()
|
|
|
|
|
+
|
|
|
|
|
+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!")
|