소스 검색

refactor(effect): prune unused facades (#20748)

Kit Langton 4 달 전
부모
커밋
8942fc21aa

+ 0 - 5
packages/opencode/src/account/index.ts

@@ -417,11 +417,6 @@ export namespace Account {
     return Option.getOrUndefined(await runPromise((service) => service.active()))
   }
 
-  export async function config(accountID: AccountID, orgID: OrgID): Promise<Record<string, unknown> | undefined> {
-    const cfg = await runPromise((service) => service.config(accountID, orgID))
-    return Option.getOrUndefined(cfg)
-  }
-
   export async function token(accountID: AccountID): Promise<AccessToken | undefined> {
     const t = await runPromise((service) => service.token(accountID))
     return Option.getOrUndefined(t)

+ 18 - 18
packages/opencode/src/command/index.ts

@@ -124,20 +124,24 @@ export namespace Command {
             source: "mcp",
             description: prompt.description,
             get template() {
-              return new Promise<string>(async (resolve, reject) => {
-                const template = await MCP.getPrompt(
-                  prompt.client,
-                  prompt.name,
-                  prompt.arguments
-                    ? Object.fromEntries(prompt.arguments.map((argument, i) => [argument.name, `$${i + 1}`]))
-                    : {},
-                ).catch(reject)
-                resolve(
-                  template?.messages
-                    .map((message) => (message.content.type === "text" ? message.content.text : ""))
-                    .join("\n") || "",
-                )
-              })
+              return Effect.runPromise(
+                mcp
+                  .getPrompt(
+                    prompt.client,
+                    prompt.name,
+                    prompt.arguments
+                      ? Object.fromEntries(prompt.arguments.map((argument, i) => [argument.name, `$${i + 1}`]))
+                      : {},
+                  )
+                  .pipe(
+                    Effect.map(
+                      (template) =>
+                        template?.messages
+                          .map((message) => (message.content.type === "text" ? message.content.text : ""))
+                          .join("\n") || "",
+                    ),
+                  ),
+              )
             },
             hints: prompt.arguments?.map((_, i) => `$${i + 1}`) ?? [],
           }
@@ -185,10 +189,6 @@ export namespace Command {
 
   const { runPromise } = makeRuntime(Service, defaultLayer)
 
-  export async function get(name: string) {
-    return runPromise((svc) => svc.get(name))
-  }
-
   export async function list() {
     return runPromise((svc) => svc.list())
   }

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

@@ -341,10 +341,6 @@ export namespace Installation {
 
   const { runPromise } = makeRuntime(Service, defaultLayer)
 
-  export async function info(): Promise<Info> {
-    return runPromise((svc) => svc.info())
-  }
-
   export async function method(): Promise<Method> {
     return runPromise((svc) => svc.method())
   }

+ 0 - 8
packages/opencode/src/mcp/auth.ts

@@ -168,14 +168,6 @@ export namespace McpAuth {
   export const updateCodeVerifier = async (mcpName: string, codeVerifier: string) =>
     runPromise((svc) => svc.updateCodeVerifier(mcpName, codeVerifier))
 
-  export const clearCodeVerifier = async (mcpName: string) => runPromise((svc) => svc.clearCodeVerifier(mcpName))
-
   export const updateOAuthState = async (mcpName: string, oauthState: string) =>
     runPromise((svc) => svc.updateOAuthState(mcpName, oauthState))
-
-  export const getOAuthState = async (mcpName: string) => runPromise((svc) => svc.getOAuthState(mcpName))
-
-  export const clearOAuthState = async (mcpName: string) => runPromise((svc) => svc.clearOAuthState(mcpName))
-
-  export const isTokenExpired = async (mcpName: string) => runPromise((svc) => svc.isTokenExpired(mcpName))
 }

+ 0 - 5
packages/opencode/src/mcp/index.ts

@@ -889,8 +889,6 @@ export namespace MCP {
 
   export const status = async () => runPromise((svc) => svc.status())
 
-  export const clients = async () => runPromise((svc) => svc.clients())
-
   export const tools = async () => runPromise((svc) => svc.tools())
 
   export const prompts = async () => runPromise((svc) => svc.prompts())
@@ -906,9 +904,6 @@ export namespace MCP {
   export const getPrompt = async (clientName: string, name: string, args?: Record<string, string>) =>
     runPromise((svc) => svc.getPrompt(clientName, name, args))
 
-  export const readResource = async (clientName: string, resourceUri: string) =>
-    runPromise((svc) => svc.readResource(clientName, resourceUri))
-
   export const startAuth = async (mcpName: string) => runPromise((svc) => svc.startAuth(mcpName))
 
   export const authenticate = async (mcpName: string) => runPromise((svc) => svc.authenticate(mcpName))

+ 8 - 5
packages/opencode/src/permission/index.ts

@@ -140,6 +140,7 @@ export namespace Permission {
   export const layer = Layer.effect(
     Service,
     Effect.gen(function* () {
+      const bus = yield* Bus.Service
       const state = yield* InstanceState.make<State>(
         Effect.fn("Permission.state")(function* (ctx) {
           const row = Database.use((db) =>
@@ -191,7 +192,7 @@ export namespace Permission {
 
         const deferred = yield* Deferred.make<void, RejectedError | CorrectedError>()
         pending.set(id, { info, deferred })
-        void Bus.publish(Event.Asked, info)
+        yield* bus.publish(Event.Asked, info)
         return yield* Effect.ensuring(
           Deferred.await(deferred),
           Effect.sync(() => {
@@ -206,7 +207,7 @@ export namespace Permission {
         if (!existing) return
 
         pending.delete(input.requestID)
-        void Bus.publish(Event.Replied, {
+        yield* bus.publish(Event.Replied, {
           sessionID: existing.info.sessionID,
           requestID: existing.info.id,
           reply: input.reply,
@@ -221,7 +222,7 @@ export namespace Permission {
           for (const [id, item] of pending.entries()) {
             if (item.info.sessionID !== existing.info.sessionID) continue
             pending.delete(id)
-            void Bus.publish(Event.Replied, {
+            yield* bus.publish(Event.Replied, {
               sessionID: item.info.sessionID,
               requestID: item.info.id,
               reply: "reject",
@@ -249,7 +250,7 @@ export namespace Permission {
           )
           if (!ok) continue
           pending.delete(id)
-          void Bus.publish(Event.Replied, {
+          yield* bus.publish(Event.Replied, {
             sessionID: item.info.sessionID,
             requestID: item.info.id,
             reply: "always",
@@ -306,7 +307,9 @@ export namespace Permission {
     return result
   }
 
-  export const { runPromise } = makeRuntime(Service, layer)
+  export const defaultLayer = layer.pipe(Layer.provide(Bus.layer))
+
+  export const { runPromise } = makeRuntime(Service, defaultLayer)
 
   export async function ask(input: z.infer<typeof AskInput>) {
     return runPromise((s) => s.ask(input))

+ 6 - 6
packages/opencode/src/plugin/index.ts

@@ -74,8 +74,8 @@ export namespace Plugin {
     return result
   }
 
-  function publishPluginError(message: string) {
-    Bus.publish(Session.Event.Error, { error: new NamedError.Unknown({ message }).toObject() })
+  function publishPluginError(bus: Bus.Interface, message: string) {
+    Effect.runFork(bus.publish(Session.Event.Error, { error: new NamedError.Unknown({ message }).toObject() }))
   }
 
   async function applyPlugin(load: PluginLoader.Loaded, input: PluginInput, hooks: Hooks[]) {
@@ -161,24 +161,24 @@ export namespace Plugin {
                   if (stage === "install") {
                     const parsed = parsePluginSpecifier(spec)
                     log.error("failed to install plugin", { pkg: parsed.pkg, version: parsed.version, error: message })
-                    publishPluginError(`Failed to install plugin ${parsed.pkg}@${parsed.version}: ${message}`)
+                    publishPluginError(bus, `Failed to install plugin ${parsed.pkg}@${parsed.version}: ${message}`)
                     return
                   }
 
                   if (stage === "compatibility") {
                     log.warn("plugin incompatible", { path: spec, error: message })
-                    publishPluginError(`Plugin ${spec} skipped: ${message}`)
+                    publishPluginError(bus, `Plugin ${spec} skipped: ${message}`)
                     return
                   }
 
                   if (stage === "entry") {
                     log.error("failed to resolve plugin server entry", { path: spec, error: message })
-                    publishPluginError(`Failed to load plugin ${spec}: ${message}`)
+                    publishPluginError(bus, `Failed to load plugin ${spec}: ${message}`)
                     return
                   }
 
                   log.error("failed to load plugin", { path: spec, target: resolved?.entry, error: message })
-                  publishPluginError(`Failed to load plugin ${spec}: ${message}`)
+                  publishPluginError(bus, `Failed to load plugin ${spec}: ${message}`)
                 },
               },
             }),

+ 89 - 85
packages/opencode/src/pty/index.ts

@@ -118,6 +118,8 @@ export namespace Pty {
   export const layer = Layer.effect(
     Service,
     Effect.gen(function* () {
+      const bus = yield* Bus.Service
+      const plugin = yield* Plugin.Service
       function teardown(session: Active) {
         try {
           session.process.kill()
@@ -157,7 +159,7 @@ export namespace Pty {
         s.sessions.delete(id)
         log.info("removing session", { id })
         teardown(session)
-        void Bus.publish(Event.Deleted, { id: session.info.id })
+        yield* bus.publish(Event.Deleted, { id: session.info.id })
       })
 
       const list = Effect.fn("Pty.list")(function* () {
@@ -172,95 +174,95 @@ export namespace Pty {
 
       const create = Effect.fn("Pty.create")(function* (input: CreateInput) {
         const s = yield* InstanceState.get(state)
-        return yield* Effect.promise(async () => {
-          const id = PtyID.ascending()
-          const command = input.command || Shell.preferred()
-          const args = input.args || []
-          if (Shell.login(command)) {
-            args.push("-l")
-          }
+        const id = PtyID.ascending()
+        const command = input.command || Shell.preferred()
+        const args = input.args || []
+        if (Shell.login(command)) {
+          args.push("-l")
+        }
 
-          const cwd = input.cwd || s.dir
-          const shellEnv = await Plugin.trigger("shell.env", { cwd }, { env: {} })
-          const env = {
-            ...process.env,
-            ...input.env,
-            ...shellEnv.env,
-            TERM: "xterm-256color",
-            OPENCODE_TERMINAL: "1",
-          } as Record<string, string>
-
-          if (process.platform === "win32") {
-            env.LC_ALL = "C.UTF-8"
-            env.LC_CTYPE = "C.UTF-8"
-            env.LANG = "C.UTF-8"
-          }
-          log.info("creating session", { id, cmd: command, args, cwd })
+        const cwd = input.cwd || s.dir
+        const shell = yield* plugin.trigger("shell.env", { cwd }, { env: {} })
+        const env = {
+          ...process.env,
+          ...input.env,
+          ...shell.env,
+          TERM: "xterm-256color",
+          OPENCODE_TERMINAL: "1",
+        } as Record<string, string>
+
+        if (process.platform === "win32") {
+          env.LC_ALL = "C.UTF-8"
+          env.LC_CTYPE = "C.UTF-8"
+          env.LANG = "C.UTF-8"
+        }
+        log.info("creating session", { id, cmd: command, args, cwd })
 
-          const spawn = await pty()
-          const proc = spawn(command, args, {
+        const spawn = yield* Effect.promise(() => pty())
+        const proc = yield* Effect.sync(() =>
+          spawn(command, args, {
             name: "xterm-256color",
             cwd,
             env,
-          })
-
-          const info = {
-            id,
-            title: input.title || `Terminal ${id.slice(-4)}`,
-            command,
-            args,
-            cwd,
-            status: "running",
-            pid: proc.pid,
-          } as const
-          const session: Active = {
-            info,
-            process: proc,
-            buffer: "",
-            bufferCursor: 0,
-            cursor: 0,
-            subscribers: new Map(),
-          }
-          s.sessions.set(id, session)
-          proc.onData(
-            Instance.bind((chunk) => {
-              session.cursor += chunk.length
-
-              for (const [key, ws] of session.subscribers.entries()) {
-                if (ws.readyState !== 1) {
-                  session.subscribers.delete(key)
-                  continue
-                }
-                if (ws.data !== key) {
-                  session.subscribers.delete(key)
-                  continue
-                }
-                try {
-                  ws.send(chunk)
-                } catch {
-                  session.subscribers.delete(key)
-                }
+          }),
+        )
+
+        const info = {
+          id,
+          title: input.title || `Terminal ${id.slice(-4)}`,
+          command,
+          args,
+          cwd,
+          status: "running",
+          pid: proc.pid,
+        } as const
+        const session: Active = {
+          info,
+          process: proc,
+          buffer: "",
+          bufferCursor: 0,
+          cursor: 0,
+          subscribers: new Map(),
+        }
+        s.sessions.set(id, session)
+        proc.onData(
+          Instance.bind((chunk) => {
+            session.cursor += chunk.length
+
+            for (const [key, ws] of session.subscribers.entries()) {
+              if (ws.readyState !== 1) {
+                session.subscribers.delete(key)
+                continue
               }
+              if (ws.data !== key) {
+                session.subscribers.delete(key)
+                continue
+              }
+              try {
+                ws.send(chunk)
+              } catch {
+                session.subscribers.delete(key)
+              }
+            }
 
-              session.buffer += chunk
-              if (session.buffer.length <= BUFFER_LIMIT) return
-              const excess = session.buffer.length - BUFFER_LIMIT
-              session.buffer = session.buffer.slice(excess)
-              session.bufferCursor += excess
-            }),
-          )
-          proc.onExit(
-            Instance.bind(({ exitCode }) => {
-              if (session.info.status === "exited") return
-              log.info("session exited", { id, exitCode })
-              session.info.status = "exited"
-              void Bus.publish(Event.Exited, { id, exitCode })
-              Effect.runFork(remove(id))
-            }),
-          )
-          await Bus.publish(Event.Created, { info })
-          return info
-        })
+            session.buffer += chunk
+            if (session.buffer.length <= BUFFER_LIMIT) return
+            const excess = session.buffer.length - BUFFER_LIMIT
+            session.buffer = session.buffer.slice(excess)
+            session.bufferCursor += excess
+          }),
+        )
+        proc.onExit(
+          Instance.bind(({ exitCode }) => {
+            if (session.info.status === "exited") return
+            log.info("session exited", { id, exitCode })
+            session.info.status = "exited"
+            Effect.runFork(bus.publish(Event.Exited, { id, exitCode }))
+            Effect.runFork(remove(id))
+          }),
+        )
+        yield* bus.publish(Event.Created, { info })
+        return info
       })
 
       const update = Effect.fn("Pty.update")(function* (id: PtyID, input: UpdateInput) {
@@ -273,7 +275,7 @@ export namespace Pty {
         if (input.size) {
           session.process.resize(input.size.cols, input.size.rows)
         }
-        void Bus.publish(Event.Updated, { info: session.info })
+        yield* bus.publish(Event.Updated, { info: session.info })
         return session.info
       })
 
@@ -361,7 +363,9 @@ export namespace Pty {
     }),
   )
 
-  const { runPromise } = makeRuntime(Service, layer)
+  const defaultLayer = layer.pipe(Layer.provide(Bus.layer), Layer.provide(Plugin.defaultLayer))
+
+  const { runPromise } = makeRuntime(Service, defaultLayer)
 
   export async function list() {
     return runPromise((svc) => svc.list())

+ 7 - 4
packages/opencode/src/question/index.ts

@@ -109,6 +109,7 @@ export namespace Question {
   export const layer = Layer.effect(
     Service,
     Effect.gen(function* () {
+      const bus = yield* Bus.Service
       const state = yield* InstanceState.make<State>(
         Effect.fn("Question.state")(function* () {
           const state = {
@@ -145,7 +146,7 @@ export namespace Question {
           tool: input.tool,
         }
         pending.set(id, { info, deferred })
-        Bus.publish(Event.Asked, info)
+        yield* bus.publish(Event.Asked, info)
 
         return yield* Effect.ensuring(
           Deferred.await(deferred),
@@ -164,7 +165,7 @@ export namespace Question {
         }
         pending.delete(input.requestID)
         log.info("replied", { requestID: input.requestID, answers: input.answers })
-        Bus.publish(Event.Replied, {
+        yield* bus.publish(Event.Replied, {
           sessionID: existing.info.sessionID,
           requestID: existing.info.id,
           answers: input.answers,
@@ -181,7 +182,7 @@ export namespace Question {
         }
         pending.delete(requestID)
         log.info("rejected", { requestID })
-        Bus.publish(Event.Rejected, {
+        yield* bus.publish(Event.Rejected, {
           sessionID: existing.info.sessionID,
           requestID: existing.info.id,
         })
@@ -197,7 +198,9 @@ export namespace Question {
     }),
   )
 
-  const { runPromise } = makeRuntime(Service, layer)
+  const defaultLayer = layer.pipe(Layer.provide(Bus.layer))
+
+  const { runPromise } = makeRuntime(Service, defaultLayer)
 
   export async function ask(input: {
     sessionID: SessionID

+ 0 - 8
packages/opencode/src/session/instruction.ts

@@ -248,18 +248,10 @@ export namespace Instruction {
     return runPromise((svc) => svc.systemPaths())
   }
 
-  export async function system() {
-    return runPromise((svc) => svc.system())
-  }
-
   export function loaded(messages: MessageV2.WithParts[]) {
     return extract(messages)
   }
 
-  export async function find(dir: string) {
-    return runPromise((svc) => svc.find(dir))
-  }
-
   export async function resolve(messages: MessageV2.WithParts[], filepath: string, messageID: MessageID) {
     return runPromise((svc) => svc.resolve(messages, filepath, messageID))
   }

+ 1 - 1
packages/opencode/src/session/processor.ts

@@ -512,7 +512,7 @@ export namespace SessionProcessor {
         Layer.provide(Snapshot.defaultLayer),
         Layer.provide(Agent.defaultLayer),
         Layer.provide(LLM.defaultLayer),
-        Layer.provide(Permission.layer),
+        Layer.provide(Permission.defaultLayer),
         Layer.provide(Plugin.defaultLayer),
         Layer.provide(SessionStatus.layer.pipe(Layer.provide(Bus.layer))),
         Layer.provide(Bus.layer),

+ 1 - 1
packages/opencode/src/session/prompt.ts

@@ -1715,7 +1715,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
         Layer.provide(SessionCompaction.defaultLayer),
         Layer.provide(SessionProcessor.defaultLayer),
         Layer.provide(Command.defaultLayer),
-        Layer.provide(Permission.layer),
+        Layer.provide(Permission.defaultLayer),
         Layer.provide(MCP.defaultLayer),
         Layer.provide(LSP.defaultLayer),
         Layer.provide(FileTime.defaultLayer),

+ 0 - 4
packages/opencode/src/session/summary.ts

@@ -174,8 +174,4 @@ export namespace SessionSummary {
   export async function diff(input: z.infer<typeof DiffInput>) {
     return runPromise((svc) => svc.diff(input))
   }
-
-  export async function computeDiff(input: { messages: MessageV2.WithParts[] }) {
-    return runPromise((svc) => svc.computeDiff(input))
-  }
 }

+ 0 - 4
packages/opencode/src/snapshot/index.ts

@@ -545,10 +545,6 @@ export namespace Snapshot {
     return runPromise((svc) => svc.init())
   }
 
-  export async function cleanup() {
-    return runPromise((svc) => svc.cleanup())
-  }
-
   export async function track() {
     return runPromise((svc) => svc.track())
   }

+ 0 - 4
packages/opencode/src/tool/registry.ts

@@ -206,10 +206,6 @@ export namespace ToolRegistry {
 
   const { runPromise } = makeRuntime(Service, defaultLayer)
 
-  export async function register(tool: Tool.Info) {
-    return runPromise((svc) => svc.register(tool))
-  }
-
   export async function ids() {
     return runPromise((svc) => svc.ids())
   }

+ 1 - 1
packages/opencode/test/session/compaction.test.ts

@@ -211,7 +211,7 @@ function liveRuntime(layer: Layer.Layer<LLM.Service>, provider = ProviderTest.fa
       Layer.provide(Session.defaultLayer),
       Layer.provide(Snapshot.defaultLayer),
       Layer.provide(layer),
-      Layer.provide(Permission.layer),
+      Layer.provide(Permission.defaultLayer),
       Layer.provide(Agent.defaultLayer),
       Layer.provide(Plugin.defaultLayer),
       Layer.provide(status),

+ 1 - 1
packages/opencode/test/session/processor-effect.test.ts

@@ -149,7 +149,7 @@ const deps = Layer.mergeAll(
   Session.defaultLayer,
   Snapshot.defaultLayer,
   AgentSvc.defaultLayer,
-  Permission.layer,
+  Permission.defaultLayer,
   Plugin.defaultLayer,
   Config.defaultLayer,
   LLM.defaultLayer,

+ 1 - 1
packages/opencode/test/session/prompt-effect.test.ts

@@ -150,7 +150,7 @@ function makeHttp() {
     LLM.defaultLayer,
     AgentSvc.defaultLayer,
     Command.defaultLayer,
-    Permission.layer,
+    Permission.defaultLayer,
     Plugin.defaultLayer,
     Config.defaultLayer,
     ProviderSvc.defaultLayer,

+ 1 - 1
packages/opencode/test/session/snapshot-tool-race.test.ts

@@ -114,7 +114,7 @@ function makeHttp() {
     LLM.defaultLayer,
     AgentSvc.defaultLayer,
     Command.defaultLayer,
-    Permission.layer,
+    Permission.defaultLayer,
     Plugin.defaultLayer,
     Config.defaultLayer,
     ProviderSvc.defaultLayer,