Browse Source

rename bus

Dax Raad 2 months ago
parent
commit
1e3bdcc71c

+ 43 - 0
packages/opencode/src/bus/bus-event.ts

@@ -0,0 +1,43 @@
+import z from "zod"
+import type { ZodType } from "zod"
+import { Log } from "../util/log"
+
+export namespace BusEvent {
+  const log = Log.create({ service: "event" })
+
+  export type Definition = ReturnType<typeof define>
+
+  const registry = new Map<string, Definition>()
+
+  export function define<Type extends string, Properties extends ZodType>(type: Type, properties: Properties) {
+    const result = {
+      type,
+      properties,
+    }
+    registry.set(type, result)
+    return result
+  }
+
+  export function payloads() {
+    return z
+      .discriminatedUnion(
+        "type",
+        registry
+          .entries()
+          .map(([type, def]) => {
+            return z
+              .object({
+                type: z.literal(type),
+                properties: def.properties,
+              })
+              .meta({
+                ref: "Event" + "." + def.type,
+              })
+          })
+          .toArray() as any,
+      )
+      .meta({
+        ref: "Event",
+      })
+  }
+}

+ 5 - 41
packages/opencode/src/bus/index.ts

@@ -1,7 +1,7 @@
 import z from "zod"
 import z from "zod"
-import type { ZodType } from "zod"
 import { Log } from "../util/log"
 import { Log } from "../util/log"
 import { Instance } from "../project/instance"
 import { Instance } from "../project/instance"
+import { BusEvent } from "./bus-event"
 import { GlobalBus } from "./global"
 import { GlobalBus } from "./global"
 
 
 export namespace Bus {
 export namespace Bus {
@@ -9,10 +9,6 @@ export namespace Bus {
   type Subscription = (event: any) => void
   type Subscription = (event: any) => void
   const disposedEventType = "server.instance.disposed"
   const disposedEventType = "server.instance.disposed"
 
 
-  export type EventDefinition = ReturnType<typeof event>
-
-  const registry = new Map<string, EventDefinition>()
-
   const state = Instance.state(
   const state = Instance.state(
     () => {
     () => {
       const subscriptions = new Map<any, Subscription[]>()
       const subscriptions = new Map<any, Subscription[]>()
@@ -36,46 +32,14 @@ export namespace Bus {
     },
     },
   )
   )
 
 
-  export function event<Type extends string, Properties extends ZodType>(type: Type, properties: Properties) {
-    const result = {
-      type,
-      properties,
-    }
-    registry.set(type, result)
-    return result
-  }
-
-  export const InstanceDisposed = event(
+  export const InstanceDisposed = BusEvent.define(
     disposedEventType,
     disposedEventType,
     z.object({
     z.object({
       directory: z.string(),
       directory: z.string(),
     }),
     }),
   )
   )
 
 
-  export function payloads() {
-    return z
-      .discriminatedUnion(
-        "type",
-        registry
-          .entries()
-          .map(([type, def]) => {
-            return z
-              .object({
-                type: z.literal(type),
-                properties: def.properties,
-              })
-              .meta({
-                ref: "Event" + "." + def.type,
-              })
-          })
-          .toArray() as any,
-      )
-      .meta({
-        ref: "Event",
-      })
-  }
-
-  export async function publish<Definition extends EventDefinition>(
+  export async function publish<Definition extends BusEvent.Definition>(
     def: Definition,
     def: Definition,
     properties: z.output<Definition["properties"]>,
     properties: z.output<Definition["properties"]>,
   ) {
   ) {
@@ -100,14 +64,14 @@ export namespace Bus {
     return Promise.all(pending)
     return Promise.all(pending)
   }
   }
 
 
-  export function subscribe<Definition extends EventDefinition>(
+  export function subscribe<Definition extends BusEvent.Definition>(
     def: Definition,
     def: Definition,
     callback: (event: { type: Definition["type"]; properties: z.infer<Definition["properties"]> }) => void,
     callback: (event: { type: Definition["type"]; properties: z.infer<Definition["properties"]> }) => void,
   ) {
   ) {
     return raw(def.type, callback)
     return raw(def.type, callback)
   }
   }
 
 
-  export function once<Definition extends EventDefinition>(
+  export function once<Definition extends BusEvent.Definition>(
     def: Definition,
     def: Definition,
     callback: (event: {
     callback: (event: {
       type: Definition["type"]
       type: Definition["type"]

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

@@ -1,9 +1,10 @@
+import { BusEvent } from "@/bus/bus-event"
 import { Bus } from "@/bus"
 import { Bus } from "@/bus"
 import z from "zod"
 import z from "zod"
 
 
 export const TuiEvent = {
 export const TuiEvent = {
-  PromptAppend: Bus.event("tui.prompt.append", z.object({ text: z.string() })),
-  CommandExecute: Bus.event(
+  PromptAppend: BusEvent.define("tui.prompt.append", z.object({ text: z.string() })),
+  CommandExecute: BusEvent.define(
     "tui.command.execute",
     "tui.command.execute",
     z.object({
     z.object({
       command: z.union([
       command: z.union([
@@ -27,7 +28,7 @@ export const TuiEvent = {
       ]),
       ]),
     }),
     }),
   ),
   ),
-  ToastShow: Bus.event(
+  ToastShow: BusEvent.define(
     "tui.toast.show",
     "tui.toast.show",
     z.object({
     z.object({
       title: z.string().optional(),
       title: z.string().optional(),

+ 3 - 2
packages/opencode/src/command/index.ts

@@ -1,14 +1,15 @@
+import { Bus } from "@/bus"
+import { BusEvent } from "@/bus/bus-event"
 import z from "zod"
 import z from "zod"
 import { Config } from "../config/config"
 import { Config } from "../config/config"
 import { Instance } from "../project/instance"
 import { Instance } from "../project/instance"
-import { Bus } from "../bus"
 import { Identifier } from "../id/id"
 import { Identifier } from "../id/id"
 import PROMPT_INITIALIZE from "./template/initialize.txt"
 import PROMPT_INITIALIZE from "./template/initialize.txt"
 import PROMPT_REVIEW from "./template/review.txt"
 import PROMPT_REVIEW from "./template/review.txt"
 
 
 export namespace Command {
 export namespace Command {
   export const Event = {
   export const Event = {
-    Executed: Bus.event(
+    Executed: BusEvent.define(
       "command.executed",
       "command.executed",
       z.object({
       z.object({
         name: z.string(),
         name: z.string(),

+ 3 - 2
packages/opencode/src/file/index.ts

@@ -1,5 +1,6 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import z from "zod"
 import z from "zod"
-import { Bus } from "../bus"
 import { $ } from "bun"
 import { $ } from "bun"
 import type { BunFile } from "bun"
 import type { BunFile } from "bun"
 import { formatPatch, structuredPatch } from "diff"
 import { formatPatch, structuredPatch } from "diff"
@@ -111,7 +112,7 @@ export namespace File {
   }
   }
 
 
   export const Event = {
   export const Event = {
-    Edited: Bus.event(
+    Edited: BusEvent.define(
       "file.edited",
       "file.edited",
       z.object({
       z.object({
         file: z.string(),
         file: z.string(),

+ 3 - 2
packages/opencode/src/file/watcher.ts

@@ -1,5 +1,6 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import z from "zod"
 import z from "zod"
-import { Bus } from "../bus"
 import { Instance } from "../project/instance"
 import { Instance } from "../project/instance"
 import { Log } from "../util/log"
 import { Log } from "../util/log"
 import { FileIgnore } from "./ignore"
 import { FileIgnore } from "./ignore"
@@ -16,7 +17,7 @@ export namespace FileWatcher {
   const log = Log.create({ service: "file.watcher" })
   const log = Log.create({ service: "file.watcher" })
 
 
   export const Event = {
   export const Event = {
-    Updated: Bus.event(
+    Updated: BusEvent.define(
       "file.watcher.updated",
       "file.watcher.updated",
       z.object({
       z.object({
         file: z.string(),
         file: z.string(),

+ 3 - 2
packages/opencode/src/ide/index.ts

@@ -1,8 +1,9 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import { spawn } from "bun"
 import { spawn } from "bun"
 import z from "zod"
 import z from "zod"
 import { NamedError } from "@opencode-ai/util/error"
 import { NamedError } from "@opencode-ai/util/error"
 import { Log } from "../util/log"
 import { Log } from "../util/log"
-import { Bus } from "../bus"
 
 
 const SUPPORTED_IDES = [
 const SUPPORTED_IDES = [
   { name: "Windsurf" as const, cmd: "windsurf" },
   { name: "Windsurf" as const, cmd: "windsurf" },
@@ -16,7 +17,7 @@ export namespace Ide {
   const log = Log.create({ service: "ide" })
   const log = Log.create({ service: "ide" })
 
 
   export const Event = {
   export const Event = {
-    Installed: Bus.event(
+    Installed: BusEvent.define(
       "ide.installed",
       "ide.installed",
       z.object({
       z.object({
         ide: z.string(),
         ide: z.string(),

+ 4 - 3
packages/opencode/src/installation/index.ts

@@ -1,8 +1,9 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import path from "path"
 import path from "path"
 import { $ } from "bun"
 import { $ } from "bun"
 import z from "zod"
 import z from "zod"
 import { NamedError } from "@opencode-ai/util/error"
 import { NamedError } from "@opencode-ai/util/error"
-import { Bus } from "../bus"
 import { Log } from "../util/log"
 import { Log } from "../util/log"
 import { iife } from "@/util/iife"
 import { iife } from "@/util/iife"
 
 
@@ -17,13 +18,13 @@ export namespace Installation {
   export type Method = Awaited<ReturnType<typeof method>>
   export type Method = Awaited<ReturnType<typeof method>>
 
 
   export const Event = {
   export const Event = {
-    Updated: Bus.event(
+    Updated: BusEvent.define(
       "installation.updated",
       "installation.updated",
       z.object({
       z.object({
         version: z.string(),
         version: z.string(),
       }),
       }),
     ),
     ),
-    UpdateAvailable: Bus.event(
+    UpdateAvailable: BusEvent.define(
       "installation.update-available",
       "installation.update-available",
       z.object({
       z.object({
         version: z.string(),
         version: z.string(),

+ 3 - 2
packages/opencode/src/lsp/client.ts

@@ -1,9 +1,10 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import path from "path"
 import path from "path"
 import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node"
 import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node"
 import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-types"
 import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-types"
 import { Log } from "../util/log"
 import { Log } from "../util/log"
 import { LANGUAGE_EXTENSIONS } from "./language"
 import { LANGUAGE_EXTENSIONS } from "./language"
-import { Bus } from "../bus"
 import z from "zod"
 import z from "zod"
 import type { LSPServer } from "./server"
 import type { LSPServer } from "./server"
 import { NamedError } from "@opencode-ai/util/error"
 import { NamedError } from "@opencode-ai/util/error"
@@ -25,7 +26,7 @@ export namespace LSPClient {
   )
   )
 
 
   export const Event = {
   export const Event = {
-    Diagnostics: Bus.event(
+    Diagnostics: BusEvent.define(
       "lsp.client.diagnostics",
       "lsp.client.diagnostics",
       z.object({
       z.object({
         serverID: z.string(),
         serverID: z.string(),

+ 3 - 2
packages/opencode/src/lsp/index.ts

@@ -1,3 +1,5 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import { Log } from "../util/log"
 import { Log } from "../util/log"
 import { LSPClient } from "./client"
 import { LSPClient } from "./client"
 import path from "path"
 import path from "path"
@@ -6,13 +8,12 @@ import z from "zod"
 import { Config } from "../config/config"
 import { Config } from "../config/config"
 import { spawn } from "child_process"
 import { spawn } from "child_process"
 import { Instance } from "../project/instance"
 import { Instance } from "../project/instance"
-import { Bus } from "../bus"
 
 
 export namespace LSP {
 export namespace LSP {
   const log = Log.create({ service: "lsp" })
   const log = Log.create({ service: "lsp" })
 
 
   export const Event = {
   export const Event = {
-    Updated: Bus.event("lsp.updated", z.object({})),
+    Updated: BusEvent.define("lsp.updated", z.object({})),
   }
   }
 
 
   export const Range = z
   export const Range = z

+ 4 - 3
packages/opencode/src/permission/index.ts

@@ -1,5 +1,6 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import z from "zod"
 import z from "zod"
-import { Bus } from "../bus"
 import { Log } from "../util/log"
 import { Log } from "../util/log"
 import { Identifier } from "../id/id"
 import { Identifier } from "../id/id"
 import { Plugin } from "../plugin"
 import { Plugin } from "../plugin"
@@ -38,8 +39,8 @@ export namespace Permission {
   export type Info = z.infer<typeof Info>
   export type Info = z.infer<typeof Info>
 
 
   export const Event = {
   export const Event = {
-    Updated: Bus.event("permission.updated", Info),
-    Replied: Bus.event(
+    Updated: BusEvent.define("permission.updated", Info),
+    Replied: BusEvent.define(
       "permission.replied",
       "permission.replied",
       z.object({
       z.object({
         sessionID: z.string(),
         sessionID: z.string(),

+ 49 - 30
packages/opencode/src/project/project.ts

@@ -8,6 +8,8 @@ import { Flag } from "@/flag/flag"
 import { Session } from "../session"
 import { Session } from "../session"
 import { work } from "../util/queue"
 import { work } from "../util/queue"
 import { fn } from "@opencode-ai/util/fn"
 import { fn } from "@opencode-ai/util/fn"
+import { BusEvent } from "@/bus/bus-event"
+import { iife } from "@/util/iife"
 
 
 export namespace Project {
 export namespace Project {
   const log = Log.create({ service: "project" })
   const log = Log.create({ service: "project" })
@@ -30,11 +32,55 @@ export namespace Project {
     })
     })
   export type Info = z.infer<typeof Info>
   export type Info = z.infer<typeof Info>
 
 
+  export const Event = {
+    Updated: BusEvent.define("project.updated", z.object(Info)),
+  }
+
   export async function fromDirectory(directory: string) {
   export async function fromDirectory(directory: string) {
     log.info("fromDirectory", { directory })
     log.info("fromDirectory", { directory })
-    const matches = Filesystem.up({ targets: [".git"], start: directory })
-    const git = await matches.next().then((x) => x.value)
-    await matches.return()
+
+    const { id, worktree } = await iife(async () => {
+      const matches = Filesystem.up({ targets: [".git"], start: directory })
+      const git = await matches.next().then((x) => x.value)
+      await matches.return()
+      if (git) {
+        let worktree = path.dirname(git)
+        let id = await Bun.file(path.join(git, "opencode"))
+          .text()
+          .then((x) => x.trim())
+          .catch(() => {})
+        if (!id) {
+          const roots = await $`git rev-list --max-parents=0 --all`
+            .quiet()
+            .nothrow()
+            .cwd(worktree)
+            .text()
+            .then((x) =>
+              x
+                .split("\n")
+                .filter(Boolean)
+                .map((x) => x.trim())
+                .toSorted(),
+            )
+          id = roots[0]
+          if (id) Bun.file(path.join(git, "opencode")).write(id)
+        }
+        worktree = await $`git rev-parse --show-toplevel`
+          .quiet()
+          .nothrow()
+          .cwd(worktree)
+          .text()
+          .then((x) => path.resolve(worktree, x.trim()))
+        return { id, worktree, vcs: "git" }
+      }
+
+      return {
+        id: "global",
+        worktree: "/",
+        vcs: Info.shape.vcs.parse(Flag.OPENCODE_FAKE_VCS),
+      }
+    })
+
     if (!git) {
     if (!git) {
       const project: Info = {
       const project: Info = {
         id: "global",
         id: "global",
@@ -48,33 +94,6 @@ export namespace Project {
       await Storage.write<Info>(["project", "global"], project)
       await Storage.write<Info>(["project", "global"], project)
       return project
       return project
     }
     }
-    let worktree = path.dirname(git)
-    let id = await Bun.file(path.join(git, "opencode"))
-      .text()
-      .then((x) => x.trim())
-      .catch(() => {})
-    if (!id) {
-      const roots = await $`git rev-list --max-parents=0 --all`
-        .quiet()
-        .nothrow()
-        .cwd(worktree)
-        .text()
-        .then((x) =>
-          x
-            .split("\n")
-            .filter(Boolean)
-            .map((x) => x.trim())
-            .toSorted(),
-        )
-      id = roots[0]
-      if (id) Bun.file(path.join(git, "opencode")).write(id)
-    }
-    worktree = await $`git rev-parse --show-toplevel`
-      .quiet()
-      .nothrow()
-      .cwd(worktree)
-      .text()
-      .then((x) => path.resolve(worktree, x.trim()))
     const projectID = id || "global"
     const projectID = id || "global"
     const existing = id ? await Storage.read<Info>(["project", id]).catch(() => undefined) : undefined
     const existing = id ? await Storage.read<Info>(["project", id]).catch(() => undefined) : undefined
     if (!existing && id) {
     if (!existing && id) {

+ 3 - 2
packages/opencode/src/project/vcs.ts

@@ -1,8 +1,9 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import { $ } from "bun"
 import { $ } from "bun"
 import path from "path"
 import path from "path"
 import z from "zod"
 import z from "zod"
 import { Log } from "@/util/log"
 import { Log } from "@/util/log"
-import { Bus } from "@/bus"
 import { Instance } from "./instance"
 import { Instance } from "./instance"
 import { FileWatcher } from "@/file/watcher"
 import { FileWatcher } from "@/file/watcher"
 
 
@@ -10,7 +11,7 @@ const log = Log.create({ service: "vcs" })
 
 
 export namespace Vcs {
 export namespace Vcs {
   export const Event = {
   export const Event = {
-    BranchUpdated: Bus.event(
+    BranchUpdated: BusEvent.define(
       "vcs.branch.updated",
       "vcs.branch.updated",
       z.object({
       z.object({
         branch: z.string().optional(),
         branch: z.string().optional(),

+ 6 - 5
packages/opencode/src/pty/index.ts

@@ -1,8 +1,9 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import { type IPty } from "bun-pty"
 import { type IPty } from "bun-pty"
 import z from "zod"
 import z from "zod"
 import { Identifier } from "../id/id"
 import { Identifier } from "../id/id"
 import { Log } from "../util/log"
 import { Log } from "../util/log"
-import { Bus } from "../bus"
 import type { WSContext } from "hono/ws"
 import type { WSContext } from "hono/ws"
 import { Instance } from "../project/instance"
 import { Instance } from "../project/instance"
 import { shell } from "@opencode-ai/util/shell"
 import { shell } from "@opencode-ai/util/shell"
@@ -73,10 +74,10 @@ export namespace Pty {
   export type UpdateInput = z.infer<typeof UpdateInput>
   export type UpdateInput = z.infer<typeof UpdateInput>
 
 
   export const Event = {
   export const Event = {
-    Created: Bus.event("pty.created", z.object({ info: Info })),
-    Updated: Bus.event("pty.updated", z.object({ info: Info })),
-    Exited: Bus.event("pty.exited", z.object({ id: Identifier.schema("pty"), exitCode: z.number() })),
-    Deleted: Bus.event("pty.deleted", z.object({ id: Identifier.schema("pty") })),
+    Created: BusEvent.define("pty.created", z.object({ info: Info })),
+    Updated: BusEvent.define("pty.updated", z.object({ info: Info })),
+    Exited: BusEvent.define("pty.exited", z.object({ id: Identifier.schema("pty"), exitCode: z.number() })),
+    Deleted: BusEvent.define("pty.deleted", z.object({ id: Identifier.schema("pty") })),
   }
   }
 
 
   interface ActiveSession {
   interface ActiveSession {

+ 7 - 6
packages/opencode/src/server/server.ts

@@ -1,5 +1,7 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
+import { GlobalBus } from "@/bus/global"
 import { Log } from "../util/log"
 import { Log } from "../util/log"
-import { Bus } from "../bus"
 import { describeRoute, generateSpecs, validator, resolver, openAPIRouteHandler } from "hono-openapi"
 import { describeRoute, generateSpecs, validator, resolver, openAPIRouteHandler } from "hono-openapi"
 import { Hono } from "hono"
 import { Hono } from "hono"
 import { cors } from "hono/cors"
 import { cors } from "hono/cors"
@@ -8,7 +10,7 @@ import { proxy } from "hono/proxy"
 import { Session } from "../session"
 import { Session } from "../session"
 import z from "zod"
 import z from "zod"
 import { Provider } from "../provider/provider"
 import { Provider } from "../provider/provider"
-import { mapValues, pipe } from "remeda"
+import { mapValues } from "remeda"
 import { NamedError } from "@opencode-ai/util/error"
 import { NamedError } from "@opencode-ai/util/error"
 import { ModelsDev } from "../provider/models"
 import { ModelsDev } from "../provider/models"
 import { Ripgrep } from "../file/ripgrep"
 import { Ripgrep } from "../file/ripgrep"
@@ -41,7 +43,6 @@ import type { ContentfulStatusCode } from "hono/utils/http-status"
 import { TuiEvent } from "@/cli/cmd/tui/event"
 import { TuiEvent } from "@/cli/cmd/tui/event"
 import { Snapshot } from "@/snapshot"
 import { Snapshot } from "@/snapshot"
 import { SessionSummary } from "@/session/summary"
 import { SessionSummary } from "@/session/summary"
-import { GlobalBus } from "@/bus/global"
 import { SessionStatus } from "@/session/status"
 import { SessionStatus } from "@/session/status"
 import { upgradeWebSocket, websocket } from "hono/bun"
 import { upgradeWebSocket, websocket } from "hono/bun"
 import { errors } from "./error"
 import { errors } from "./error"
@@ -54,7 +55,7 @@ export namespace Server {
   const log = Log.create({ service: "server" })
   const log = Log.create({ service: "server" })
 
 
   export const Event = {
   export const Event = {
-    Connected: Bus.event("server.connected", z.object({})),
+    Connected: BusEvent.define("server.connected", z.object({})),
   }
   }
 
 
   const app = new Hono()
   const app = new Hono()
@@ -109,7 +110,7 @@ export namespace Server {
                     z
                     z
                       .object({
                       .object({
                         directory: z.string(),
                         directory: z.string(),
-                        payload: Bus.payloads(),
+                        payload: BusEvent.payloads(),
                       })
                       })
                       .meta({
                       .meta({
                         ref: "GlobalEvent",
                         ref: "GlobalEvent",
@@ -2393,7 +2394,7 @@ export namespace Server {
               description: "Event stream",
               description: "Event stream",
               content: {
               content: {
                 "text/event-stream": {
                 "text/event-stream": {
-                  schema: resolver(Bus.payloads()),
+                  schema: resolver(BusEvent.payloads()),
                 },
                 },
               },
               },
             },
             },

+ 3 - 2
packages/opencode/src/session/compaction.ts

@@ -1,3 +1,5 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import { wrapLanguageModel, type ModelMessage } from "ai"
 import { wrapLanguageModel, type ModelMessage } from "ai"
 import { Session } from "."
 import { Session } from "."
 import { Identifier } from "../id/id"
 import { Identifier } from "../id/id"
@@ -5,7 +7,6 @@ import { Instance } from "../project/instance"
 import { Provider } from "../provider/provider"
 import { Provider } from "../provider/provider"
 import { MessageV2 } from "./message-v2"
 import { MessageV2 } from "./message-v2"
 import { SystemPrompt } from "./system"
 import { SystemPrompt } from "./system"
-import { Bus } from "../bus"
 import z from "zod"
 import z from "zod"
 import { SessionPrompt } from "./prompt"
 import { SessionPrompt } from "./prompt"
 import { Flag } from "../flag/flag"
 import { Flag } from "../flag/flag"
@@ -21,7 +22,7 @@ export namespace SessionCompaction {
   const log = Log.create({ service: "session.compaction" })
   const log = Log.create({ service: "session.compaction" })
 
 
   export const Event = {
   export const Event = {
-    Compacted: Bus.event(
+    Compacted: BusEvent.define(
       "session.compacted",
       "session.compacted",
       z.object({
       z.object({
         sessionID: z.string(),
         sessionID: z.string(),

+ 7 - 6
packages/opencode/src/session/index.ts

@@ -1,7 +1,8 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import { Decimal } from "decimal.js"
 import { Decimal } from "decimal.js"
 import z from "zod"
 import z from "zod"
 import { type LanguageModelUsage, type ProviderMetadata } from "ai"
 import { type LanguageModelUsage, type ProviderMetadata } from "ai"
-import { Bus } from "../bus"
 import { Config } from "../config/config"
 import { Config } from "../config/config"
 import { Flag } from "../flag/flag"
 import { Flag } from "../flag/flag"
 import { Identifier } from "../id/id"
 import { Identifier } from "../id/id"
@@ -85,32 +86,32 @@ export namespace Session {
   export type ShareInfo = z.output<typeof ShareInfo>
   export type ShareInfo = z.output<typeof ShareInfo>
 
 
   export const Event = {
   export const Event = {
-    Created: Bus.event(
+    Created: BusEvent.define(
       "session.created",
       "session.created",
       z.object({
       z.object({
         info: Info,
         info: Info,
       }),
       }),
     ),
     ),
-    Updated: Bus.event(
+    Updated: BusEvent.define(
       "session.updated",
       "session.updated",
       z.object({
       z.object({
         info: Info,
         info: Info,
       }),
       }),
     ),
     ),
-    Deleted: Bus.event(
+    Deleted: BusEvent.define(
       "session.deleted",
       "session.deleted",
       z.object({
       z.object({
         info: Info,
         info: Info,
       }),
       }),
     ),
     ),
-    Diff: Bus.event(
+    Diff: BusEvent.define(
       "session.diff",
       "session.diff",
       z.object({
       z.object({
         sessionID: z.string(),
         sessionID: z.string(),
         diff: Snapshot.FileDiff.array(),
         diff: Snapshot.FileDiff.array(),
       }),
       }),
     ),
     ),
-    Error: Bus.event(
+    Error: BusEvent.define(
       "session.error",
       "session.error",
       z.object({
       z.object({
         sessionID: z.string().optional(),
         sessionID: z.string().optional(),

+ 6 - 5
packages/opencode/src/session/message-v2.ts

@@ -1,5 +1,6 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import z from "zod"
 import z from "zod"
-import { Bus } from "../bus"
 import { NamedError } from "@opencode-ai/util/error"
 import { NamedError } from "@opencode-ai/util/error"
 import { Message } from "./message"
 import { Message } from "./message"
 import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessage, type UIMessage } from "ai"
 import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessage, type UIMessage } from "ai"
@@ -375,27 +376,27 @@ export namespace MessageV2 {
   export type Info = z.infer<typeof Info>
   export type Info = z.infer<typeof Info>
 
 
   export const Event = {
   export const Event = {
-    Updated: Bus.event(
+    Updated: BusEvent.define(
       "message.updated",
       "message.updated",
       z.object({
       z.object({
         info: Info,
         info: Info,
       }),
       }),
     ),
     ),
-    Removed: Bus.event(
+    Removed: BusEvent.define(
       "message.removed",
       "message.removed",
       z.object({
       z.object({
         sessionID: z.string(),
         sessionID: z.string(),
         messageID: z.string(),
         messageID: z.string(),
       }),
       }),
     ),
     ),
-    PartUpdated: Bus.event(
+    PartUpdated: BusEvent.define(
       "message.part.updated",
       "message.part.updated",
       z.object({
       z.object({
         part: Part,
         part: Part,
         delta: z.string().optional(),
         delta: z.string().optional(),
       }),
       }),
     ),
     ),
-    PartRemoved: Bus.event(
+    PartRemoved: BusEvent.define(
       "message.part.removed",
       "message.part.removed",
       z.object({
       z.object({
         sessionID: z.string(),
         sessionID: z.string(),

+ 3 - 2
packages/opencode/src/session/status.ts

@@ -1,3 +1,4 @@
+import { BusEvent } from "@/bus/bus-event"
 import { Bus } from "@/bus"
 import { Bus } from "@/bus"
 import { Instance } from "@/project/instance"
 import { Instance } from "@/project/instance"
 import z from "zod"
 import z from "zod"
@@ -24,7 +25,7 @@ export namespace SessionStatus {
   export type Info = z.infer<typeof Info>
   export type Info = z.infer<typeof Info>
 
 
   export const Event = {
   export const Event = {
-    Status: Bus.event(
+    Status: BusEvent.define(
       "session.status",
       "session.status",
       z.object({
       z.object({
         sessionID: z.string(),
         sessionID: z.string(),
@@ -32,7 +33,7 @@ export namespace SessionStatus {
       }),
       }),
     ),
     ),
     // deprecated
     // deprecated
-    Idle: Bus.event(
+    Idle: BusEvent.define(
       "session.idle",
       "session.idle",
       z.object({
       z.object({
         sessionID: z.string(),
         sessionID: z.string(),

+ 3 - 2
packages/opencode/src/session/todo.ts

@@ -1,5 +1,6 @@
+import { BusEvent } from "@/bus/bus-event"
+import { Bus } from "@/bus"
 import z from "zod"
 import z from "zod"
-import { Bus } from "../bus"
 import { Storage } from "../storage/storage"
 import { Storage } from "../storage/storage"
 
 
 export namespace Todo {
 export namespace Todo {
@@ -14,7 +15,7 @@ export namespace Todo {
   export type Info = z.infer<typeof Info>
   export type Info = z.infer<typeof Info>
 
 
   export const Event = {
   export const Event = {
-    Updated: Bus.event(
+    Updated: BusEvent.define(
       "todo.updated",
       "todo.updated",
       z.object({
       z.object({
         sessionID: z.string(),
         sessionID: z.string(),