From 5e3dc8099921952925b6a70853cb06f5e4bebcdc Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 10 Apr 2026 23:52:12 -0400 Subject: [PATCH 1/3] refactor: collapse command facade (#21981) --- packages/opencode/src/command/index.ts | 7 ------- packages/opencode/src/effect/bootstrap-runtime.ts | 9 +++++++++ packages/opencode/src/project/bootstrap.ts | 6 +++--- packages/opencode/src/server/instance.ts | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 packages/opencode/src/effect/bootstrap-runtime.ts diff --git a/packages/opencode/src/command/index.ts b/packages/opencode/src/command/index.ts index 0c5ef67f4d..42f53301b2 100644 --- a/packages/opencode/src/command/index.ts +++ b/packages/opencode/src/command/index.ts @@ -1,6 +1,5 @@ import { BusEvent } from "@/bus/bus-event" import { InstanceState } from "@/effect/instance-state" -import { makeRuntime } from "@/effect/run-service" import type { InstanceContext } from "@/project/instance" import { SessionID, MessageID } from "@/session/schema" import { Effect, Layer, Context } from "effect" @@ -189,10 +188,4 @@ export namespace Command { Layer.provide(MCP.defaultLayer), Layer.provide(Skill.defaultLayer), ) - - const { runPromise } = makeRuntime(Service, defaultLayer) - - export async function list() { - return runPromise((svc) => svc.list()) - } } diff --git a/packages/opencode/src/effect/bootstrap-runtime.ts b/packages/opencode/src/effect/bootstrap-runtime.ts new file mode 100644 index 0000000000..648f2484e6 --- /dev/null +++ b/packages/opencode/src/effect/bootstrap-runtime.ts @@ -0,0 +1,9 @@ +import { Layer, ManagedRuntime } from "effect" +import { memoMap } from "./run-service" + +import { Format } from "@/format" +import { ShareNext } from "@/share/share-next" + +export const BootstrapLayer = Layer.mergeAll(Format.defaultLayer, ShareNext.defaultLayer) + +export const BootstrapRuntime = ManagedRuntime.make(BootstrapLayer, { memoMap }) diff --git a/packages/opencode/src/project/bootstrap.ts b/packages/opencode/src/project/bootstrap.ts index 1340a692ff..9f6f7fa6fa 100644 --- a/packages/opencode/src/project/bootstrap.ts +++ b/packages/opencode/src/project/bootstrap.ts @@ -10,14 +10,14 @@ import { Bus } from "../bus" import { Command } from "../command" import { Instance } from "./instance" import { Log } from "@/util/log" -import { AppRuntime } from "@/effect/app-runtime" +import { BootstrapRuntime } from "@/effect/bootstrap-runtime" import { ShareNext } from "@/share/share-next" export async function InstanceBootstrap() { Log.Default.info("bootstrapping", { directory: Instance.directory }) await Plugin.init() - void AppRuntime.runPromise(ShareNext.Service.use((svc) => svc.init())) - void AppRuntime.runPromise(Format.Service.use((svc) => svc.init())) + void BootstrapRuntime.runPromise(ShareNext.Service.use((svc) => svc.init())) + void BootstrapRuntime.runPromise(Format.Service.use((svc) => svc.init())) await LSP.init() File.init() FileWatcher.init() diff --git a/packages/opencode/src/server/instance.ts b/packages/opencode/src/server/instance.ts index 015d67bfc1..6525d2ded7 100644 --- a/packages/opencode/src/server/instance.ts +++ b/packages/opencode/src/server/instance.ts @@ -191,7 +191,7 @@ export const InstanceRoutes = (upgrade: UpgradeWebSocket, app: Hono = new Hono() }, }), async (c) => { - const commands = await Command.list() + const commands = await AppRuntime.runPromise(Command.Service.use((svc) => svc.list())) return c.json(commands) }, ) From fe4dfb9f6f3051c78599636bcc1dcc036c9ed518 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 10 Apr 2026 23:52:48 -0400 Subject: [PATCH 2/3] refactor(git): remove runtime facade wrappers (#21982) --- packages/opencode/src/cli/cmd/github.ts | 12 ++++++++---- packages/opencode/src/cli/cmd/pr.ts | 25 ++++++++++++++++++------- packages/opencode/src/git/index.ts | 11 ----------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/packages/opencode/src/cli/cmd/github.ts b/packages/opencode/src/cli/cmd/github.ts index 8b693e79ae..28a05512de 100644 --- a/packages/opencode/src/cli/cmd/github.ts +++ b/packages/opencode/src/cli/cmd/github.ts @@ -29,6 +29,7 @@ import { Provider } from "../../provider/provider" import { Bus } from "../../bus" import { MessageV2 } from "../../session/message-v2" import { SessionPrompt } from "@/session/prompt" +import { AppRuntime } from "@/effect/app-runtime" import { Git } from "@/git" import { setTimeout as sleep } from "node:timers/promises" import { Process } from "@/util/process" @@ -258,7 +259,9 @@ export const GithubInstallCommand = cmd({ } // Get repo info - const info = (await Git.run(["remote", "get-url", "origin"], { cwd: Instance.worktree })).text().trim() + const info = await AppRuntime.runPromise( + Git.Service.use((git) => git.run(["remote", "get-url", "origin"], { cwd: Instance.worktree })), + ).then((x) => x.text().trim()) const parsed = parseGitHubRemote(info) if (!parsed) { prompts.log.error(`Could not find git repository. Please run this command from a git repository.`) @@ -497,20 +500,21 @@ export const GithubRunCommand = cmd({ : "issue" : undefined const gitText = async (args: string[]) => { - const result = await Git.run(args, { cwd: Instance.worktree }) + const result = await AppRuntime.runPromise(Git.Service.use((git) => git.run(args, { cwd: Instance.worktree }))) if (result.exitCode !== 0) { throw new Process.RunFailedError(["git", ...args], result.exitCode, result.stdout, result.stderr) } return result.text().trim() } const gitRun = async (args: string[]) => { - const result = await Git.run(args, { cwd: Instance.worktree }) + const result = await AppRuntime.runPromise(Git.Service.use((git) => git.run(args, { cwd: Instance.worktree }))) if (result.exitCode !== 0) { throw new Process.RunFailedError(["git", ...args], result.exitCode, result.stdout, result.stderr) } return result } - const gitStatus = (args: string[]) => Git.run(args, { cwd: Instance.worktree }) + const gitStatus = (args: string[]) => + AppRuntime.runPromise(Git.Service.use((git) => git.run(args, { cwd: Instance.worktree }))) const commitChanges = async (summary: string, actor?: string) => { const args = ["commit", "-m", summary] if (actor) args.push("-m", `Co-authored-by: ${actor} <${actor}@users.noreply.github.com>`) diff --git a/packages/opencode/src/cli/cmd/pr.ts b/packages/opencode/src/cli/cmd/pr.ts index 58d42c6ef0..f392bab4c8 100644 --- a/packages/opencode/src/cli/cmd/pr.ts +++ b/packages/opencode/src/cli/cmd/pr.ts @@ -1,5 +1,6 @@ import { UI } from "../ui" import { cmd } from "./cmd" +import { AppRuntime } from "@/effect/app-runtime" import { Git } from "@/git" import { Instance } from "@/project/instance" import { Process } from "@/util/process" @@ -67,19 +68,29 @@ export const PrCommand = cmd({ const remoteName = forkOwner // Check if remote already exists - const remotes = (await Git.run(["remote"], { cwd: Instance.worktree })).text().trim() + const remotes = await AppRuntime.runPromise( + Git.Service.use((git) => git.run(["remote"], { cwd: Instance.worktree })), + ).then((x) => x.text().trim()) if (!remotes.split("\n").includes(remoteName)) { - await Git.run(["remote", "add", remoteName, `https://github.com/${forkOwner}/${forkName}.git`], { - cwd: Instance.worktree, - }) + await AppRuntime.runPromise( + Git.Service.use((git) => + git.run(["remote", "add", remoteName, `https://github.com/${forkOwner}/${forkName}.git`], { + cwd: Instance.worktree, + }), + ), + ) UI.println(`Added fork remote: ${remoteName}`) } // Set upstream to the fork so pushes go there const headRefName = prInfo.headRefName - await Git.run(["branch", `--set-upstream-to=${remoteName}/${headRefName}`, localBranchName], { - cwd: Instance.worktree, - }) + await AppRuntime.runPromise( + Git.Service.use((git) => + git.run(["branch", `--set-upstream-to=${remoteName}/${headRefName}`, localBranchName], { + cwd: Instance.worktree, + }), + ), + ) } // Check for opencode session link in PR body diff --git a/packages/opencode/src/git/index.ts b/packages/opencode/src/git/index.ts index de84fdd746..ac964ee0a0 100644 --- a/packages/opencode/src/git/index.ts +++ b/packages/opencode/src/git/index.ts @@ -1,7 +1,6 @@ import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner" import { Effect, Layer, Context, Stream } from "effect" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" -import { makeRuntime } from "@/effect/run-service" export namespace Git { const cfg = [ @@ -258,14 +257,4 @@ export namespace Git { ) export const defaultLayer = layer.pipe(Layer.provide(CrossSpawnSpawner.defaultLayer)) - - const { runPromise } = makeRuntime(Service, defaultLayer) - - export async function run(args: string[], opts: Options) { - return runPromise((git) => git.run(args, opts)) - } - - export async function defaultBranch(cwd: string) { - return runPromise((git) => git.defaultBranch(cwd)) - } } From 2e340d976f1d06e803c743e32e0c950f9ba643fb Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Sat, 11 Apr 2026 03:53:48 +0000 Subject: [PATCH 3/3] chore: generate --- packages/sdk/js/src/v2/gen/types.gen.ts | 100 +++++----- packages/sdk/openapi.json | 242 ++++++++++++------------ 2 files changed, 171 insertions(+), 171 deletions(-) diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index ab07077874..7ca6ea05c8 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -316,6 +316,29 @@ export type EventCommandExecuted = { } } +export type EventWorkspaceReady = { + type: "workspace.ready" + properties: { + name: string + } +} + +export type EventWorkspaceFailed = { + type: "workspace.failed" + properties: { + message: string + } +} + +export type EventWorkspaceStatus = { + type: "workspace.status" + properties: { + workspaceID: string + status: "connected" | "connecting" | "disconnected" | "error" + error?: string + } +} + export type QuestionOption = { /** * Display text (1-5 words, concise) @@ -387,29 +410,6 @@ export type EventQuestionRejected = { } } -export type Todo = { - /** - * Brief description of the task - */ - content: string - /** - * Current status of the task: pending, in_progress, completed, cancelled - */ - status: string - /** - * Priority level of the task: high, medium, low - */ - priority: string -} - -export type EventTodoUpdated = { - type: "todo.updated" - properties: { - sessionID: string - todos: Array - } -} - export type SessionStatus = | { type: "idle" @@ -446,6 +446,29 @@ export type EventSessionCompacted = { } } +export type Todo = { + /** + * Brief description of the task + */ + content: string + /** + * Current status of the task: pending, in_progress, completed, cancelled + */ + status: string + /** + * Priority level of the task: high, medium, low + */ + priority: string +} + +export type EventTodoUpdated = { + type: "todo.updated" + properties: { + sessionID: string + todos: Array + } +} + export type EventWorktreeReady = { type: "worktree.ready" properties: { @@ -500,29 +523,6 @@ export type EventPtyDeleted = { } } -export type EventWorkspaceReady = { - type: "workspace.ready" - properties: { - name: string - } -} - -export type EventWorkspaceFailed = { - type: "workspace.failed" - properties: { - message: string - } -} - -export type EventWorkspaceStatus = { - type: "workspace.status" - properties: { - workspaceID: string - status: "connected" | "connecting" | "disconnected" | "error" - error?: string - } -} - export type OutputFormatText = { type: "text" } @@ -995,22 +995,22 @@ export type Event = | EventMcpToolsChanged | EventMcpBrowserOpenFailed | EventCommandExecuted + | EventWorkspaceReady + | EventWorkspaceFailed + | EventWorkspaceStatus | EventQuestionAsked | EventQuestionReplied | EventQuestionRejected - | EventTodoUpdated | EventSessionStatus | EventSessionIdle | EventSessionCompacted + | EventTodoUpdated | EventWorktreeReady | EventWorktreeFailed | EventPtyCreated | EventPtyUpdated | EventPtyExited | EventPtyDeleted - | EventWorkspaceReady - | EventWorkspaceFailed - | EventWorkspaceStatus | EventMessageUpdated | EventMessageRemoved | EventMessagePartUpdated diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 71b17966e3..7bc6392b94 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -7986,6 +7986,71 @@ }, "required": ["type", "properties"] }, + "Event.workspace.ready": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "workspace.ready" + }, + "properties": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": ["name"] + } + }, + "required": ["type", "properties"] + }, + "Event.workspace.failed": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "workspace.failed" + }, + "properties": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": ["message"] + } + }, + "required": ["type", "properties"] + }, + "Event.workspace.status": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "workspace.status" + }, + "properties": { + "type": "object", + "properties": { + "workspaceID": { + "type": "string", + "pattern": "^wrk.*" + }, + "status": { + "type": "string", + "enum": ["connected", "connecting", "disconnected", "error"] + }, + "error": { + "type": "string" + } + }, + "required": ["workspaceID", "status"] + } + }, + "required": ["type", "properties"] + }, "QuestionOption": { "type": "object", "properties": { @@ -8136,50 +8201,6 @@ }, "required": ["type", "properties"] }, - "Todo": { - "type": "object", - "properties": { - "content": { - "description": "Brief description of the task", - "type": "string" - }, - "status": { - "description": "Current status of the task: pending, in_progress, completed, cancelled", - "type": "string" - }, - "priority": { - "description": "Priority level of the task: high, medium, low", - "type": "string" - } - }, - "required": ["content", "status", "priority"] - }, - "Event.todo.updated": { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "todo.updated" - }, - "properties": { - "type": "object", - "properties": { - "sessionID": { - "type": "string", - "pattern": "^ses.*" - }, - "todos": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Todo" - } - } - }, - "required": ["sessionID", "todos"] - } - }, - "required": ["type", "properties"] - }, "SessionStatus": { "anyOf": [ { @@ -8286,6 +8307,50 @@ }, "required": ["type", "properties"] }, + "Todo": { + "type": "object", + "properties": { + "content": { + "description": "Brief description of the task", + "type": "string" + }, + "status": { + "description": "Current status of the task: pending, in_progress, completed, cancelled", + "type": "string" + }, + "priority": { + "description": "Priority level of the task: high, medium, low", + "type": "string" + } + }, + "required": ["content", "status", "priority"] + }, + "Event.todo.updated": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "todo.updated" + }, + "properties": { + "type": "object", + "properties": { + "sessionID": { + "type": "string", + "pattern": "^ses.*" + }, + "todos": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Todo" + } + } + }, + "required": ["sessionID", "todos"] + } + }, + "required": ["type", "properties"] + }, "Event.worktree.ready": { "type": "object", "properties": { @@ -8440,71 +8505,6 @@ }, "required": ["type", "properties"] }, - "Event.workspace.ready": { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "workspace.ready" - }, - "properties": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - }, - "required": ["name"] - } - }, - "required": ["type", "properties"] - }, - "Event.workspace.failed": { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "workspace.failed" - }, - "properties": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - }, - "required": ["message"] - } - }, - "required": ["type", "properties"] - }, - "Event.workspace.status": { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "workspace.status" - }, - "properties": { - "type": "object", - "properties": { - "workspaceID": { - "type": "string", - "pattern": "^wrk.*" - }, - "status": { - "type": "string", - "enum": ["connected", "connecting", "disconnected", "error"] - }, - "error": { - "type": "string" - } - }, - "required": ["workspaceID", "status"] - } - }, - "required": ["type", "properties"] - }, "OutputFormatText": { "type": "object", "properties": { @@ -9937,6 +9937,15 @@ { "$ref": "#/components/schemas/Event.command.executed" }, + { + "$ref": "#/components/schemas/Event.workspace.ready" + }, + { + "$ref": "#/components/schemas/Event.workspace.failed" + }, + { + "$ref": "#/components/schemas/Event.workspace.status" + }, { "$ref": "#/components/schemas/Event.question.asked" }, @@ -9946,9 +9955,6 @@ { "$ref": "#/components/schemas/Event.question.rejected" }, - { - "$ref": "#/components/schemas/Event.todo.updated" - }, { "$ref": "#/components/schemas/Event.session.status" }, @@ -9958,6 +9964,9 @@ { "$ref": "#/components/schemas/Event.session.compacted" }, + { + "$ref": "#/components/schemas/Event.todo.updated" + }, { "$ref": "#/components/schemas/Event.worktree.ready" }, @@ -9976,15 +9985,6 @@ { "$ref": "#/components/schemas/Event.pty.deleted" }, - { - "$ref": "#/components/schemas/Event.workspace.ready" - }, - { - "$ref": "#/components/schemas/Event.workspace.failed" - }, - { - "$ref": "#/components/schemas/Event.workspace.status" - }, { "$ref": "#/components/schemas/Event.message.updated" },