Explorar el Código

refactor(server): replace Bun serve with Hono node adapters

Dax Raad hace 1 mes
padre
commit
406d216cd2

+ 2 - 0
packages/opencode/package.json

@@ -88,6 +88,8 @@
     "@gitlab/gitlab-ai-provider": "3.6.0",
     "@gitlab/opencode-gitlab-auth": "1.3.3",
     "@hono/standard-validator": "0.1.5",
+    "@hono/node-server": "1.19.11",
+    "@hono/node-ws": "1.3.0",
     "@hono/zod-validator": "catalog:",
     "@modelcontextprotocol/sdk": "1.25.2",
     "@npmcli/arborist": "9.4.0",

+ 1 - 1
packages/opencode/src/cli/cmd/acp.ts

@@ -23,7 +23,7 @@ export const AcpCommand = cmd({
     process.env.OPENCODE_CLIENT = "acp"
     await bootstrap(process.cwd(), async () => {
       const opts = await resolveNetworkOptions(args)
-      const server = Server.listen(opts)
+      const server = await Server.listen(opts)
 
       const sdk = createOpencodeClient({
         baseUrl: `http://${server.hostname}:${server.port}`,

+ 1 - 1
packages/opencode/src/cli/cmd/serve.ts

@@ -15,7 +15,7 @@ export const ServeCommand = cmd({
       console.log("Warning: OPENCODE_SERVER_PASSWORD is not set; server is unsecured.")
     }
     const opts = await resolveNetworkOptions(args)
-    const server = Server.listen(opts)
+    const server = await Server.listen(opts)
     console.log(`opencode server listening on http://${server.hostname}:${server.port}`)
 
     await new Promise(() => {})

+ 3 - 4
packages/opencode/src/cli/cmd/tui/worker.ts

@@ -8,7 +8,6 @@ import { upgrade } from "@/cli/upgrade"
 import { Config } from "@/config/config"
 import { GlobalBus } from "@/bus/global"
 import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2"
-import type { BunWebSocketData } from "hono/bun"
 import { Flag } from "@/flag/flag"
 import { setTimeout as sleep } from "node:timers/promises"
 
@@ -38,7 +37,7 @@ GlobalBus.on("event", (event) => {
   Rpc.emit("global.event", event)
 })
 
-let server: Bun.Server<BunWebSocketData> | undefined
+let server: Awaited<ReturnType<typeof Server.listen>> | undefined
 
 const eventStream = {
   abort: undefined as AbortController | undefined,
@@ -120,7 +119,7 @@ export const rpc = {
   },
   async server(input: { port: number; hostname: string; mdns?: boolean; cors?: string[] }) {
     if (server) await server.stop(true)
-    server = Server.listen(input)
+    server = await Server.listen(input)
     return { url: server.url.toString() }
   },
   async checkUpgrade(input: { directory: string }) {
@@ -143,7 +142,7 @@ export const rpc = {
     Log.Default.info("worker shutting down")
     if (eventStream.abort) eventStream.abort.abort()
     await Instance.disposeAll()
-    if (server) server.stop(true)
+    if (server) await server.stop(true)
   },
 }
 

+ 1 - 1
packages/opencode/src/cli/cmd/web.ts

@@ -37,7 +37,7 @@ export const WebCommand = cmd({
       UI.println(UI.Style.TEXT_WARNING_BOLD + "!  " + "OPENCODE_SERVER_PASSWORD is not set; server is unsecured.")
     }
     const opts = await resolveNetworkOptions(args)
-    const server = Server.listen(opts)
+    const server = await Server.listen(opts)
     UI.empty()
     UI.println(UI.logo("  "))
     UI.empty()

+ 15 - 16
packages/opencode/src/pty/index.ts

@@ -23,6 +23,8 @@ export namespace Pty {
     close: (code?: number, reason?: string) => void
   }
 
+  const key = (ws: Socket) => (ws.data && typeof ws.data === "object" ? ws.data : ws)
+
   // WebSocket control frame: 0x00 + UTF-8 JSON.
   const meta = (cursor: number) => {
     const json = JSON.stringify({ cursor })
@@ -97,9 +99,9 @@ export namespace Pty {
         try {
           session.process.kill()
         } catch {}
-        for (const [key, ws] of session.subscribers.entries()) {
+        for (const [id, ws] of session.subscribers.entries()) {
           try {
-            if (ws.data === key) ws.close()
+            if (key(ws) === id) ws.close()
           } catch {
             // ignore
           }
@@ -170,21 +172,21 @@ export namespace Pty {
     ptyProcess.onData((chunk) => {
       session.cursor += chunk.length
 
-      for (const [key, ws] of session.subscribers.entries()) {
+      for (const [id, ws] of session.subscribers.entries()) {
         if (ws.readyState !== 1) {
-          session.subscribers.delete(key)
+          session.subscribers.delete(id)
           continue
         }
 
-        if (ws.data !== key) {
-          session.subscribers.delete(key)
+        if (key(ws) !== id) {
+          session.subscribers.delete(id)
           continue
         }
 
         try {
           ws.send(chunk)
         } catch {
-          session.subscribers.delete(key)
+          session.subscribers.delete(id)
         }
       }
 
@@ -226,9 +228,9 @@ export namespace Pty {
     try {
       session.process.kill()
     } catch {}
-    for (const [key, ws] of session.subscribers.entries()) {
+    for (const [id, ws] of session.subscribers.entries()) {
       try {
-        if (ws.data === key) ws.close()
+        if (key(ws) === id) ws.close()
       } catch {
         // ignore
       }
@@ -259,16 +261,13 @@ export namespace Pty {
     }
     log.info("client connected to session", { id })
 
-    // Use ws.data as the unique key for this connection lifecycle.
-    // If ws.data is undefined, fallback to ws object.
-    const connectionKey = ws.data && typeof ws.data === "object" ? ws.data : ws
+    const sub = key(ws)
 
-    // Optionally cleanup if the key somehow exists
-    session.subscribers.delete(connectionKey)
-    session.subscribers.set(connectionKey, ws)
+    session.subscribers.delete(sub)
+    session.subscribers.set(sub, ws)
 
     const cleanup = () => {
-      session.subscribers.delete(connectionKey)
+      session.subscribers.delete(sub)
     }
 
     const start = session.bufferCursor

+ 5 - 6
packages/opencode/src/server/routes/pty.ts

@@ -1,14 +1,13 @@
 import { Hono } from "hono"
 import { describeRoute, validator, resolver } from "hono-openapi"
-import { upgradeWebSocket } from "hono/bun"
+import type { UpgradeWebSocket } from "hono/ws"
 import z from "zod"
 import { Pty } from "@/pty"
 import { NotFoundError } from "../../storage/db"
 import { errors } from "../error"
-import { lazy } from "../../util/lazy"
 
-export const PtyRoutes = lazy(() =>
-  new Hono()
+export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) {
+  return new Hono()
     .get(
       "/",
       describeRoute({
@@ -196,5 +195,5 @@ export const PtyRoutes = lazy(() =>
           },
         }
       }),
-    ),
-)
+    )
+}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 458 - 449
packages/opencode/src/server/server.ts


Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio