Skip to content

Commit 7d91d3b

Browse files
authored
Normalize instance lifecycle wiring (#25501)
1 parent a646406 commit 7d91d3b

71 files changed

Lines changed: 852 additions & 936 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/opencode/src/cli/bootstrap.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { Instance } from "../project/instance"
22
import { InstanceRuntime } from "../project/instance-runtime"
3+
import { WithInstance } from "../project/with-instance"
34

45
export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
5-
return Instance.provide({
6+
return WithInstance.provide({
67
directory,
78
fn: async () => {
89
try {

packages/opencode/src/cli/cmd/agent.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import fs from "fs/promises"
1010
import { Filesystem } from "@/util/filesystem"
1111
import matter from "gray-matter"
1212
import { Instance } from "../../project/instance"
13+
import { WithInstance } from "../../project/with-instance"
1314
import { EOL } from "os"
1415
import type { Argv } from "yargs"
1516

@@ -61,7 +62,7 @@ const AgentCreateCommand = cmd({
6162
describe: "model to use in the format of provider/model",
6263
}),
6364
async handler(args) {
64-
await Instance.provide({
65+
await WithInstance.provide({
6566
directory: process.cwd(),
6667
async fn() {
6768
const cliPath = args.path
@@ -236,7 +237,7 @@ const AgentListCommand = cmd({
236237
command: "list",
237238
describe: "list all available agents",
238239
async handler() {
239-
await Instance.provide({
240+
await WithInstance.provide({
240241
directory: process.cwd(),
241242
async fn() {
242243
const agents = await AppRuntime.runPromise(Agent.Service.use((svc) => svc.list()))

packages/opencode/src/cli/cmd/github.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { UI } from "../ui"
2020
import { cmd } from "./cmd"
2121
import { ModelsDev } from "@/provider/models"
2222
import { Instance } from "@/project/instance"
23+
import { WithInstance } from "@/project/with-instance"
2324
import { bootstrap } from "../bootstrap"
2425
import { SessionShare } from "@/share/session"
2526
import { Session } from "@/session/session"
@@ -203,7 +204,7 @@ export const GithubInstallCommand = cmd({
203204
command: "install",
204205
describe: "install the GitHub agent",
205206
async handler() {
206-
await Instance.provide({
207+
await WithInstance.provide({
207208
directory: process.cwd(),
208209
async fn() {
209210
{

packages/opencode/src/cli/cmd/mcp.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { McpOAuthProvider } from "../../mcp/oauth-provider"
1010
import { Config } from "@/config/config"
1111
import { ConfigMCP } from "../../config/mcp"
1212
import { Instance } from "../../project/instance"
13+
import { WithInstance } from "../../project/with-instance"
1314
import { Installation } from "../../installation"
1415
import { InstallationVersion } from "@opencode-ai/core/installation/version"
1516
import path from "path"
@@ -114,7 +115,7 @@ export const McpListCommand = cmd({
114115
aliases: ["ls"],
115116
describe: "list MCP servers and their status",
116117
async handler() {
117-
await Instance.provide({
118+
await WithInstance.provide({
118119
directory: process.cwd(),
119120
async fn() {
120121
UI.empty()
@@ -186,7 +187,7 @@ export const McpAuthCommand = cmd({
186187
})
187188
.command(McpAuthListCommand),
188189
async handler(args) {
189-
await Instance.provide({
190+
await WithInstance.provide({
190191
directory: process.cwd(),
191192
async fn() {
192193
UI.empty()
@@ -318,7 +319,7 @@ export const McpAuthListCommand = cmd({
318319
aliases: ["ls"],
319320
describe: "list OAuth-capable MCP servers and their auth status",
320321
async handler() {
321-
await Instance.provide({
322+
await WithInstance.provide({
322323
directory: process.cwd(),
323324
async fn() {
324325
UI.empty()
@@ -357,7 +358,7 @@ export const McpLogoutCommand = cmd({
357358
type: "string",
358359
}),
359360
async handler(args) {
360-
await Instance.provide({
361+
await WithInstance.provide({
361362
directory: process.cwd(),
362363
async fn() {
363364
UI.empty()
@@ -448,7 +449,7 @@ export const McpAddCommand = cmd({
448449
command: "add",
449450
describe: "add an MCP server",
450451
async handler() {
451-
await Instance.provide({
452+
await WithInstance.provide({
452453
directory: process.cwd(),
453454
async fn() {
454455
UI.empty()
@@ -618,7 +619,7 @@ export const McpDebugCommand = cmd({
618619
demandOption: true,
619620
}),
620621
async handler(args) {
621-
await Instance.provide({
622+
await WithInstance.provide({
622623
directory: process.cwd(),
623624
async fn() {
624625
UI.empty()

packages/opencode/src/cli/cmd/providers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import os from "os"
1313
import { Config } from "@/config/config"
1414
import { Global } from "@opencode-ai/core/global"
1515
import { Plugin } from "../../plugin"
16-
import { Instance } from "../../project/instance"
16+
import { WithInstance } from "../../project/with-instance"
1717
import type { Hooks } from "@opencode-ai/plugin"
1818
import { Process } from "@/util/process"
1919
import { text } from "node:stream/consumers"
@@ -303,7 +303,7 @@ export const ProvidersLoginCommand = cmd({
303303
type: "string",
304304
}),
305305
async handler(args) {
306-
await Instance.provide({
306+
await WithInstance.provide({
307307
directory: process.cwd(),
308308
async fn() {
309309
UI.empty()

packages/opencode/src/cli/cmd/tui/plugin/runtime.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { TuiConfig } from "@/cli/cmd/tui/config/tui"
1616
import * as Log from "@opencode-ai/core/util/log"
1717
import { errorData, errorMessage } from "@/util/error"
1818
import { isRecord } from "@/util/record"
19-
import { Instance } from "@/project/instance"
19+
import { WithInstance } from "@/project/with-instance"
2020
import {
2121
readPackageThemes,
2222
readPluginId,
@@ -790,7 +790,7 @@ async function addPluginBySpec(state: RuntimeState | undefined, raw: string) {
790790
state.pending.delete(spec)
791791
return true
792792
}
793-
const ready = await Instance.provide({
793+
const ready = await WithInstance.provide({
794794
directory: state.directory,
795795
fn: () => resolveExternalPlugins([cfg], () => TuiConfig.waitForDependencies()),
796796
}).catch((error) => {
@@ -986,7 +986,7 @@ async function load(input: { api: Api; config: TuiConfig.Info }) {
986986
}
987987
runtime = next
988988
try {
989-
await Instance.provide({
989+
await WithInstance.provide({
990990
directory: cwd,
991991
fn: async () => {
992992
const records = Flag.OPENCODE_PURE ? [] : (config.plugin_origins ?? [])

packages/opencode/src/cli/cmd/tui/worker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { Installation } from "@/installation"
22
import { Server } from "@/server/server"
33
import * as Log from "@opencode-ai/core/util/log"
4-
import { Instance } from "@/project/instance"
54
import { InstanceRuntime } from "@/project/instance-runtime"
5+
import { WithInstance } from "@/project/with-instance"
66
import { Rpc } from "@/util/rpc"
77
import { upgrade } from "@/cli/upgrade"
88
import { Config } from "@/config/config"
@@ -77,7 +77,7 @@ export const rpc = {
7777
return { url: server.url.toString() }
7878
},
7979
async checkUpgrade(input: { directory: string }) {
80-
await Instance.provide({
80+
await WithInstance.provide({
8181
directory: input.directory,
8282
fn: async () => {
8383
await upgrade().catch(() => {})

packages/opencode/src/effect/app-runtime.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import { Command } from "@/command"
4040
import { Truncate } from "@/tool/truncate"
4141
import { ToolRegistry } from "@/tool/registry"
4242
import { Format } from "@/format"
43-
import { InstanceRuntime } from "@/project/instance-runtime"
43+
import { InstanceLayer } from "@/project/instance-layer"
4444
import { Project } from "@/project/project"
4545
import { Vcs } from "@/project/vcs"
4646
import { Workspace } from "@/control-plane/workspace"
@@ -93,17 +93,16 @@ export const AppLayer = Layer.mergeAll(
9393
Truncate.defaultLayer,
9494
ToolRegistry.defaultLayer,
9595
Format.defaultLayer,
96-
InstanceRuntime.layer,
9796
Project.defaultLayer,
9897
Vcs.defaultLayer,
9998
Workspace.defaultLayer,
100-
Worktree.defaultLayer,
99+
Worktree.appLayer,
101100
Pty.defaultLayer,
102101
Installation.defaultLayer,
103102
ShareNext.defaultLayer,
104103
SessionShare.defaultLayer,
105104
SyncEvent.defaultLayer,
106-
).pipe(Layer.provideMerge(Observability.layer))
105+
).pipe(Layer.provideMerge(InstanceLayer.layer), Layer.provideMerge(Observability.layer))
107106

108107
const rt = ManagedRuntime.make(AppLayer, { memoMap })
109108
type Runtime = Pick<typeof rt, "runSync" | "runPromise" | "runPromiseExit" | "runFork" | "runCallback" | "dispose">
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Effect, Layer } from "effect"
2+
import { InstanceStore } from "./instance-store"
3+
4+
export const layer = Layer.unwrap(
5+
Effect.promise(async () => {
6+
const { InstanceBootstrap } = await import("./bootstrap")
7+
return InstanceStore.defaultLayer.pipe(Layer.provide(InstanceBootstrap.defaultLayer))
8+
}),
9+
)
10+
11+
export * as InstanceLayer from "./instance-layer"
Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,16 @@
1-
import { makeRuntime } from "@/effect/run-service"
1+
import { AppRuntime } from "@/effect/app-runtime"
22
import { type InstanceContext } from "./instance-context"
33
import { InstanceStore, type LoadInput } from "./instance-store"
4-
import { Effect, Layer } from "effect"
54

6-
// Production InstanceStore wiring plus a bridge for Promise/ALS callers that
7-
// cannot yet yield InstanceStore.Service. This keeps InstanceStore itself
8-
// low-level while still giving legacy Hono and CLI paths the production
9-
// bootstrap implementation. Delete the Promise helpers once those callers are
10-
// migrated to Effect boundaries that provide InstanceStore directly.
11-
// Keep the bootstrap implementation import lazy: Instance is imported broadly,
12-
// and importing the app bootstrap graph at module load can trigger ESM cycles.
13-
export const layer = Layer.unwrap(
14-
Effect.promise(async () => {
15-
const { InstanceBootstrap } = await import("./bootstrap")
16-
return InstanceStore.defaultLayer.pipe(Layer.provide(InstanceBootstrap.defaultLayer))
17-
}),
18-
)
5+
// Bridge for Promise/ALS callers that cannot yet yield InstanceStore.Service.
6+
// Delete this module once those callers are migrated to Effect boundaries that
7+
// provide InstanceStore directly.
198

20-
const runtime = makeRuntime(InstanceStore.Service, layer)
21-
22-
export const load = (input: LoadInput) => runtime.runPromise((store) => store.load(input))
23-
export const disposeInstance = (ctx: InstanceContext) => runtime.runPromise((store) => store.dispose(ctx))
24-
export const disposeAllInstances = () => runtime.runPromise((store) => store.disposeAll())
25-
export const reloadInstance = (input: LoadInput) => runtime.runPromise((store) => store.reload(input))
9+
export const load = (input: LoadInput) => AppRuntime.runPromise(InstanceStore.Service.use((store) => store.load(input)))
10+
export const disposeInstance = (ctx: InstanceContext) =>
11+
AppRuntime.runPromise(InstanceStore.Service.use((store) => store.dispose(ctx)))
12+
export const disposeAllInstances = () => AppRuntime.runPromise(InstanceStore.Service.use((store) => store.disposeAll()))
13+
export const reloadInstance = (input: LoadInput) =>
14+
AppRuntime.runPromise(InstanceStore.Service.use((store) => store.reload(input)))
2615

2716
export * as InstanceRuntime from "./instance-runtime"

0 commit comments

Comments
 (0)