From cf27a733971ebde73d3c986dfc8ace0336b0234b Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 10 Apr 2026 19:46:52 -0400 Subject: [PATCH] feat: add AppRuntime for unified service composition (#21953) --- packages/opencode/src/bus/index.ts | 2 + packages/opencode/src/effect/app-runtime.ts | 100 ++++++++++++++++++++ packages/opencode/src/mcp/auth.ts | 2 +- packages/opencode/src/project/vcs.ts | 2 +- packages/opencode/src/pty/index.ts | 2 +- packages/opencode/src/session/prompt.ts | 2 +- packages/opencode/src/worktree/index.ts | 2 +- 7 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 packages/opencode/src/effect/app-runtime.ts diff --git a/packages/opencode/src/bus/index.ts b/packages/opencode/src/bus/index.ts index 6db4eb04fc..87b08d6101 100644 --- a/packages/opencode/src/bus/index.ts +++ b/packages/opencode/src/bus/index.ts @@ -169,6 +169,8 @@ export namespace Bus { }), ) + export const defaultLayer = layer + const { runPromise, runSync } = makeRuntime(Service, layer) // runSync is safe here because the subscribe chain (InstanceState.get, PubSub.subscribe, diff --git a/packages/opencode/src/effect/app-runtime.ts b/packages/opencode/src/effect/app-runtime.ts new file mode 100644 index 0000000000..674ca1a2ac --- /dev/null +++ b/packages/opencode/src/effect/app-runtime.ts @@ -0,0 +1,100 @@ +import { Layer, ManagedRuntime } from "effect" +import { memoMap } from "./run-service" +import { Observability } from "./oltp" + +import { AppFileSystem } from "@/filesystem" +import { Bus } from "@/bus" +import { Auth } from "@/auth" +import { Account } from "@/account" +import { Config } from "@/config/config" +import { Git } from "@/git" +import { Ripgrep } from "@/file/ripgrep" +import { FileTime } from "@/file/time" +import { File } from "@/file" +import { FileWatcher } from "@/file/watcher" +import { Storage } from "@/storage/storage" +import { Snapshot } from "@/snapshot" +import { Plugin } from "@/plugin" +import { Provider } from "@/provider/provider" +import { ProviderAuth } from "@/provider/auth" +import { Agent } from "@/agent/agent" +import { Skill } from "@/skill" +import { Discovery } from "@/skill/discovery" +import { Question } from "@/question" +import { Permission } from "@/permission" +import { Todo } from "@/session/todo" +import { Session } from "@/session" +import { SessionStatus } from "@/session/status" +import { SessionRunState } from "@/session/run-state" +import { SessionProcessor } from "@/session/processor" +import { SessionCompaction } from "@/session/compaction" +import { SessionRevert } from "@/session/revert" +import { SessionSummary } from "@/session/summary" +import { SessionPrompt } from "@/session/prompt" +import { Instruction } from "@/session/instruction" +import { LLM } from "@/session/llm" +import { LSP } from "@/lsp" +import { MCP } from "@/mcp" +import { McpAuth } from "@/mcp/auth" +import { Command } from "@/command" +import { Truncate } from "@/tool/truncate" +import { ToolRegistry } from "@/tool/registry" +import { Format } from "@/format" +import { Project } from "@/project/project" +import { Vcs } from "@/project/vcs" +import { Worktree } from "@/worktree" +import { Pty } from "@/pty" +import { Installation } from "@/installation" +import { ShareNext } from "@/share/share-next" +import { SessionShare } from "@/share/session" + +export const AppLayer = Layer.mergeAll( + Observability.layer, + AppFileSystem.defaultLayer, + Bus.defaultLayer, + Auth.defaultLayer, + Account.defaultLayer, + Config.defaultLayer, + Git.defaultLayer, + Ripgrep.defaultLayer, + FileTime.defaultLayer, + File.defaultLayer, + FileWatcher.defaultLayer, + Storage.defaultLayer, + Snapshot.defaultLayer, + Plugin.defaultLayer, + Provider.defaultLayer, + ProviderAuth.defaultLayer, + Agent.defaultLayer, + Skill.defaultLayer, + Discovery.defaultLayer, + Question.defaultLayer, + Permission.defaultLayer, + Todo.defaultLayer, + Session.defaultLayer, + SessionStatus.defaultLayer, + SessionRunState.defaultLayer, + SessionProcessor.defaultLayer, + SessionCompaction.defaultLayer, + SessionRevert.defaultLayer, + SessionSummary.defaultLayer, + SessionPrompt.defaultLayer, + Instruction.defaultLayer, + LLM.defaultLayer, + LSP.defaultLayer, + MCP.defaultLayer, + McpAuth.defaultLayer, + Command.defaultLayer, + Truncate.defaultLayer, + ToolRegistry.defaultLayer, + Format.defaultLayer, + Project.defaultLayer, + Vcs.defaultLayer, + Worktree.defaultLayer, + Pty.defaultLayer, + Installation.defaultLayer, + ShareNext.defaultLayer, + SessionShare.defaultLayer, +) + +export const AppRuntime = ManagedRuntime.make(AppLayer, { memoMap }) diff --git a/packages/opencode/src/mcp/auth.ts b/packages/opencode/src/mcp/auth.ts index 773ca0a6f5..e9c3db8a94 100644 --- a/packages/opencode/src/mcp/auth.ts +++ b/packages/opencode/src/mcp/auth.ts @@ -141,7 +141,7 @@ export namespace McpAuth { }), ) - const defaultLayer = layer.pipe(Layer.provide(AppFileSystem.defaultLayer)) + export const defaultLayer = layer.pipe(Layer.provide(AppFileSystem.defaultLayer)) const { runPromise } = makeRuntime(Service, defaultLayer) diff --git a/packages/opencode/src/project/vcs.ts b/packages/opencode/src/project/vcs.ts index d31dff6a97..0e430d41b9 100644 --- a/packages/opencode/src/project/vcs.ts +++ b/packages/opencode/src/project/vcs.ts @@ -226,7 +226,7 @@ export namespace Vcs { }), ) - const defaultLayer = layer.pipe( + export const defaultLayer = layer.pipe( Layer.provide(Git.defaultLayer), Layer.provide(AppFileSystem.defaultLayer), Layer.provide(Bus.layer), diff --git a/packages/opencode/src/pty/index.ts b/packages/opencode/src/pty/index.ts index 7695b9ce6a..ff44de73b5 100644 --- a/packages/opencode/src/pty/index.ts +++ b/packages/opencode/src/pty/index.ts @@ -359,7 +359,7 @@ export namespace Pty { }), ) - const defaultLayer = layer.pipe(Layer.provide(Bus.layer), Layer.provide(Plugin.defaultLayer)) + export const defaultLayer = layer.pipe(Layer.provide(Bus.layer), Layer.provide(Plugin.defaultLayer)) const { runPromise } = makeRuntime(Service, defaultLayer) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 66740cd401..fe54a25abb 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -1672,7 +1672,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the }), ) - const defaultLayer = Layer.suspend(() => + export const defaultLayer = Layer.suspend(() => layer.pipe( Layer.provide(SessionRunState.defaultLayer), Layer.provide(SessionStatus.defaultLayer), diff --git a/packages/opencode/src/worktree/index.ts b/packages/opencode/src/worktree/index.ts index e0e7dab4c1..dc15483008 100644 --- a/packages/opencode/src/worktree/index.ts +++ b/packages/opencode/src/worktree/index.ts @@ -590,7 +590,7 @@ export namespace Worktree { }), ) - const defaultLayer = layer.pipe( + export const defaultLayer = layer.pipe( Layer.provide(Git.defaultLayer), Layer.provide(CrossSpawnSpawner.defaultLayer), Layer.provide(Project.defaultLayer),