Jelajahi Sumber

fix: preserve bus instance context (#28051)

Dax 3 bulan lalu
induk
melakukan
23b594de6e

+ 4 - 1
packages/opencode/src/bus/index.ts

@@ -6,6 +6,8 @@ import { GlobalBus } from "./global"
 import { InstanceState } from "@/effect/instance-state"
 import { makeRuntime } from "@/effect/run-service"
 import { Identifier } from "@/id/id"
+import type { InstanceContext } from "@/project/instance-context"
+import { InstanceRef } from "@/effect/instance-ref"
 
 const log = Log.create({ service: "bus" })
 
@@ -185,11 +187,12 @@ export function createID() {
 }
 
 export async function publish<D extends BusEvent.Definition>(
+  ctx: InstanceContext,
   def: D,
   properties: BusProperties<D>,
   options?: { id?: string },
 ) {
-  return runPromise((svc) => svc.publish(def, properties, options))
+  return runPromise((svc) => svc.publish(def, properties, options).pipe(Effect.provideService(InstanceRef, ctx)))
 }
 
 export function subscribe<D extends BusEvent.Definition>(def: D, callback: (event: Payload<D>) => unknown) {

+ 1 - 0
packages/opencode/src/cli/cmd/tui/app.tsx

@@ -859,6 +859,7 @@ function App(props: { onSnapshot?: () => Promise<string[]> }) {
   })
 
   event.on("installation.update-available", async (evt) => {
+    console.log("installation.update-available", evt)
     const version = evt.properties.version
 
     const skipped = kv.get("skipped_version")

+ 24 - 4
packages/opencode/src/cli/upgrade.ts

@@ -1,9 +1,9 @@
-import { Bus } from "@/bus"
 import { Config } from "@/config/config"
 import { AppRuntime } from "@/effect/app-runtime"
 import { Flag } from "@opencode-ai/core/flag/flag"
 import { Installation } from "@/installation"
 import { InstallationVersion } from "@opencode-ai/core/installation/version"
+import { GlobalBus } from "@/bus/global"
 
 export async function upgrade() {
   const config = await AppRuntime.runPromise(Config.Service.use((cfg) => cfg.getGlobal()))
@@ -13,7 +13,13 @@ export async function upgrade() {
   if (!latest) return
 
   if (Flag.OPENCODE_ALWAYS_NOTIFY_UPDATE) {
-    await Bus.publish(Installation.Event.UpdateAvailable, { version: latest })
+    GlobalBus.emit("event", {
+      directory: "global",
+      payload: {
+        type: Installation.Event.UpdateAvailable.type,
+        properties: { version: latest },
+      },
+    })
     return
   }
 
@@ -22,12 +28,26 @@ export async function upgrade() {
   const kind = Installation.getReleaseType(InstallationVersion, latest)
 
   if (config.autoupdate === "notify" || kind !== "patch") {
-    await Bus.publish(Installation.Event.UpdateAvailable, { version: latest })
+    GlobalBus.emit("event", {
+      directory: "global",
+      payload: {
+        type: Installation.Event.UpdateAvailable.type,
+        properties: { version: latest },
+      },
+    })
     return
   }
 
   if (method === "unknown") return
   await Installation.upgrade(method, latest)
-    .then(() => Bus.publish(Installation.Event.Updated, { version: latest }))
+    .then(() =>
+      GlobalBus.emit("event", {
+        directory: "global",
+        payload: {
+          type: Installation.Event.Updated.type,
+          properties: { version: latest },
+        },
+      }),
+    )
     .catch(() => {})
 }

+ 2 - 14
packages/opencode/src/config/agent.ts

@@ -1,10 +1,8 @@
 export * as ConfigAgent from "./agent"
 
 import { Exit, Schema, SchemaGetter } from "effect"
-import { Bus } from "@/bus"
 import { PositiveInt } from "@opencode-ai/core/schema"
 import * as Log from "@opencode-ai/core/util/log"
-import { NamedError } from "@opencode-ai/core/util/error"
 import { Glob } from "@opencode-ai/core/util/glob"
 import { configEntryNameFromPath } from "./entry-name"
 import * as ConfigMarkdown from "./markdown"
@@ -112,12 +110,7 @@ export async function load(dir: string) {
     dot: true,
     symlink: true,
   })) {
-    const md = await ConfigMarkdown.parse(item).catch(async (err) => {
-      const message = ConfigMarkdown.FrontmatterError.isInstance(err)
-        ? err.data.message
-        : `Failed to parse agent ${item}`
-      const { Session } = await import("@/session/session")
-      void Bus.publish(Session.Event.Error, { error: new NamedError.Unknown({ message }).toObject() })
+    const md = await ConfigMarkdown.parse(item).catch((err) => {
       log.error("failed to load agent", { agent: item, err })
       return undefined
     })
@@ -144,12 +137,7 @@ export async function loadMode(dir: string) {
     dot: true,
     symlink: true,
   })) {
-    const md = await ConfigMarkdown.parse(item).catch(async (err) => {
-      const message = ConfigMarkdown.FrontmatterError.isInstance(err)
-        ? err.data.message
-        : `Failed to parse mode ${item}`
-      const { Session } = await import("@/session/session")
-      void Bus.publish(Session.Event.Error, { error: new NamedError.Unknown({ message }).toObject() })
+    const md = await ConfigMarkdown.parse(item).catch((err) => {
       log.error("failed to load mode", { mode: item, err })
       return undefined
     })

+ 1 - 8
packages/opencode/src/config/command.ts

@@ -2,9 +2,7 @@ export * as ConfigCommand from "./command"
 
 import * as Log from "@opencode-ai/core/util/log"
 import { Cause, Exit, Schema } from "effect"
-import { NamedError } from "@opencode-ai/core/util/error"
 import { Glob } from "@opencode-ai/core/util/glob"
-import { Bus } from "@/bus"
 import { configEntryNameFromPath } from "./entry-name"
 import { InvalidError } from "./error"
 import * as ConfigMarkdown from "./markdown"
@@ -32,12 +30,7 @@ export async function load(dir: string) {
     dot: true,
     symlink: true,
   })) {
-    const md = await ConfigMarkdown.parse(item).catch(async (err) => {
-      const message = ConfigMarkdown.FrontmatterError.isInstance(err)
-        ? err.data.message
-        : `Failed to parse command ${item}`
-      const { Session } = await import("@/session/session")
-      void Bus.publish(Session.Event.Error, { error: new NamedError.Unknown({ message }).toObject() })
+    const md = await ConfigMarkdown.parse(item).catch((err) => {
       log.error("failed to load command", { command: item, err })
       return undefined
     })

+ 4 - 4
packages/opencode/src/file/watcher.ts

@@ -96,11 +96,11 @@ export const layer = Layer.effect(
           )
 
           const cb: ParcelWatcher.SubscribeCallback = bridge.bind((err, evts) => {
-            if (err) return
+            // if (err) return
             for (const evt of evts) {
-              if (evt.type === "create") void Bus.publish(Event.Updated, { file: evt.path, event: "add" })
-              if (evt.type === "update") void Bus.publish(Event.Updated, { file: evt.path, event: "change" })
-              if (evt.type === "delete") void Bus.publish(Event.Updated, { file: evt.path, event: "unlink" })
+              if (evt.type === "create") void Bus.publish(ctx, Event.Updated, { file: evt.path, event: "add" })
+              if (evt.type === "update") void Bus.publish(ctx, Event.Updated, { file: evt.path, event: "change" })
+              if (evt.type === "delete") void Bus.publish(ctx, Event.Updated, { file: evt.path, event: "unlink" })
             }
           })
 

+ 1 - 6
packages/opencode/src/lsp/lsp.ts

@@ -13,11 +13,8 @@ import { InstanceState } from "@/effect/instance-state"
 import { containsPath } from "@/project/instance-context"
 import { NonNegativeInt } from "@opencode-ai/core/schema"
 import { RuntimeFlags } from "@/effect/runtime-flags"
-import { InstanceRef } from "@/effect/instance-ref"
-import { makeRuntime } from "@/effect/run-service"
 
 const log = Log.create({ service: "lsp" })
-const busRuntime = makeRuntime(Bus.Service, Bus.layer)
 
 export const Event = {
   Updated: BusEvent.define("lsp.updated", Schema.Struct({})),
@@ -294,9 +291,7 @@ export const layer = Layer.effect(
           if (!client) continue
 
           result.push(client)
-          void busRuntime.runPromise((bus) =>
-            bus.publish(Event.Updated, {}).pipe(Effect.provideService(InstanceRef, ctx)),
-          )
+          await Bus.publish(ctx, Event.Updated, {})
         }
 
         return result

+ 0 - 12
packages/opencode/src/session/compaction.ts

@@ -16,10 +16,8 @@ import { Effect, Layer, Context, Schema } from "effect"
 import * as DateTime from "effect/DateTime"
 import { InstanceState } from "@/effect/instance-state"
 import { isOverflow as overflow, usable } from "./overflow"
-import { makeRuntime } from "@/effect/run-service"
 import { serviceUse } from "@/effect/service-use"
 import { RuntimeFlags } from "@/effect/runtime-flags"
-import { EventV2 } from "@opencode-ai/core/event"
 import { EventV2Bridge } from "@/event-v2-bridge"
 import { SessionEvent } from "@opencode-ai/core/session-event"
 
@@ -638,14 +636,4 @@ export const defaultLayer = Layer.suspend(() =>
   ),
 )
 
-const { runPromise } = makeRuntime(Service, defaultLayer)
-
-export async function isOverflow(input: { tokens: MessageV2.Assistant["tokens"]; model: Provider.Model }) {
-  return runPromise((svc) => svc.isOverflow(input))
-}
-
-export async function prune(input: { sessionID: SessionID }) {
-  return runPromise((svc) => svc.prune(input))
-}
-
 export * as SessionCompaction from "./compaction"