Skip to content

Commit 722b1e2

Browse files
Apply PR #22753: core: move plugin intialisation to config layer override
2 parents e80ce4c + f280e7e commit 722b1e2

File tree

5 files changed

+45
-19
lines changed

5 files changed

+45
-19
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { Log } from "../../util"
1515
import { Global } from "../../global"
1616
// dynamic import: static `import * as` of CJS package triggers Bun bundler splitting bug
1717
import type * as QRCodeType from "qrcode"
18+
import { bootstrap } from "../bootstrap"
1819

1920
const log = Log.create({ service: "serve" })
2021

@@ -217,7 +218,7 @@ export const ServeCommand = cmd({
217218
}),
218219
describe: "starts a headless opencode server",
219220
handler: async (args) => {
220-
const opts = await resolveNetworkOptions(args)
221+
const network = await resolveNetworkOptions(args)
221222
const relayURL = (
222223
args["relay-url"] ??
223224
process.env.OPENCODE_EXPERIMENTAL_PUSH_RELAY_URL ??
@@ -233,7 +234,7 @@ export const ServeCommand = cmd({
233234
.split(",")
234235
.map((item) => item.trim())
235236
.filter(Boolean)
236-
const tailscaleAdvertiseHost = readTailscaleAdvertiseHost(opts.hostname)
237+
const tailscaleAdvertiseHost = readTailscaleAdvertiseHost(network.hostname)
237238
const advertiseHosts = [
238239
...new Set([
239240
...advertiseHostsFromArg,
@@ -247,7 +248,7 @@ export const ServeCommand = cmd({
247248
const connectQR = Boolean(args["connect-qr"])
248249

249250
if (connectQR) {
250-
const pairHosts = hosts(opts.hostname, opts.port > 0 ? opts.port : 4096, advertiseHosts, false)
251+
const pairHosts = hosts(network.hostname, network.port > 0 ? network.port : 4096, advertiseHosts, false)
251252
if (!pairHosts.length) {
252253
console.log("connect qr mode requires at least one valid advertised host")
253254
return
@@ -270,6 +271,7 @@ export const ServeCommand = cmd({
270271
console.log("Warning: OPENCODE_SERVER_PASSWORD is not set; server is unsecured.")
271272
}
272273

274+
const opts = await bootstrap(process.cwd(), () => resolveNetworkOptions(args))
273275
const server = await Server.listen(opts)
274276
console.log(`opencode server listening on http://${server.hostname}:${server.port}`)
275277

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { UI } from "@/cli/ui"
88
import { Log } from "@/util"
99
import { errorMessage } from "@/util/error"
1010
import { withTimeout } from "@/util/timeout"
11+
import { Instance } from "@/project/instance"
1112
import { withNetworkOptions, resolveNetworkOptionsNoConfig } from "@/cli/network"
1213
import { Filesystem } from "@/util"
1314
import type { GlobalEvent } from "@opencode-ai/sdk/v2"
@@ -181,7 +182,11 @@ export const TuiThreadCommand = cmd({
181182
const prompt = await input(args.prompt)
182183
const config = await TuiConfig.get()
183184

184-
const network = resolveNetworkOptionsNoConfig(args)
185+
const network = await Instance.provide({
186+
directory: cwd,
187+
fn: () => resolveNetworkOptionsNoConfig(args),
188+
})
189+
185190
const external =
186191
process.argv.includes("--port") ||
187192
process.argv.includes("--hostname") ||

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { withNetworkOptions, resolveNetworkOptions } from "../network"
55
import { Flag } from "../../flag/flag"
66
import open from "open"
77
import { networkInterfaces } from "os"
8+
import { bootstrap } from "../bootstrap"
89

910
function getNetworkIPs() {
1011
const nets = networkInterfaces()
@@ -36,7 +37,7 @@ export const WebCommand = cmd({
3637
if (!Flag.OPENCODE_SERVER_PASSWORD) {
3738
UI.println(UI.Style.TEXT_WARNING_BOLD + "! OPENCODE_SERVER_PASSWORD is not set; server is unsecured.")
3839
}
39-
const opts = await resolveNetworkOptions(args)
40+
const opts = await bootstrap(process.cwd(), () => resolveNetworkOptions(args))
4041
const server = await Server.listen(opts)
4142
UI.empty()
4243
UI.println(UI.logo(" "))

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,34 @@ import { Pty } from "@/pty"
4646
import { Installation } from "@/installation"
4747
import { ShareNext } from "@/share"
4848
import { SessionShare } from "@/share"
49+
import * as Effect from "effect/Effect"
4950
import { Npm } from "@/npm"
5051
import { memoMap } from "./memo-map"
5152

53+
// Adjusts the default Config layer to ensure that plugins are always initialised before
54+
// any other layers read the current config
55+
const ConfigWithPluginPriority = Layer.effect(
56+
Config.Service,
57+
Effect.gen(function* () {
58+
const config = yield* Config.Service
59+
const plugin = yield* Plugin.Service
60+
61+
return {
62+
...config,
63+
get: () => Effect.andThen(plugin.init(), config.get),
64+
getGlobal: () => Effect.andThen(plugin.init(), config.getGlobal),
65+
getConsoleState: () => Effect.andThen(plugin.init(), config.getConsoleState),
66+
}
67+
}),
68+
).pipe(Layer.provide(Layer.merge(Plugin.defaultLayer, Config.defaultLayer)))
69+
5270
export const AppLayer = Layer.mergeAll(
5371
Npm.defaultLayer,
5472
AppFileSystem.defaultLayer,
5573
Bus.defaultLayer,
5674
Auth.defaultLayer,
5775
Account.defaultLayer,
58-
Config.defaultLayer,
76+
ConfigWithPluginPriority,
5977
Git.defaultLayer,
6078
Ripgrep.defaultLayer,
6179
File.defaultLayer,

packages/opencode/src/project/bootstrap.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Plugin } from "../plugin"
21
import { Format } from "../format"
32
import { LSP } from "../lsp"
43
import { File } from "../file"
@@ -8,6 +7,7 @@ import * as Vcs from "./vcs"
87
import { Bus } from "../bus"
98
import { Command } from "../command"
109
import { Instance } from "./instance"
10+
import { Plugin } from "../plugin"
1111
import { Log } from "@/util"
1212
import { FileWatcher } from "@/file/watcher"
1313
import { ShareNext } from "@/share"
@@ -16,20 +16,20 @@ import { Config } from "@/config"
1616

1717
export const InstanceBootstrap = Effect.gen(function* () {
1818
Log.Default.info("bootstrapping", { directory: Instance.directory })
19-
// everything depends on config so eager load it for nice traces
20-
yield* Config.Service.use((svc) => svc.get())
21-
// Plugin can mutate config so it has to be initialized before anything else.
22-
yield* Plugin.Service.use((svc) => svc.init())
2319
yield* Effect.all(
2420
[
25-
LSP.Service,
26-
ShareNext.Service,
27-
Format.Service,
28-
File.Service,
29-
FileWatcher.Service,
30-
Vcs.Service,
31-
Snapshot.Service,
32-
].map((s) => Effect.forkDetach(s.use((i) => i.init()))),
21+
Config.Service.use((i) => i.get()),
22+
...[
23+
Plugin.Service,
24+
LSP.Service,
25+
ShareNext.Service,
26+
Format.Service,
27+
File.Service,
28+
FileWatcher.Service,
29+
Vcs.Service,
30+
Snapshot.Service,
31+
].map((s) => s.use((i) => i.init())),
32+
].map((e) => Effect.forkDetach(e)),
3333
).pipe(Effect.withSpan("InstanceBootstrap.init"))
3434

3535
yield* Bus.Service.use((svc) =>

0 commit comments

Comments
 (0)