diff --git a/packages/opencode/src/account/index.ts b/packages/opencode/src/account/index.ts
index 753b80c5f1..22341f481a 100644
--- a/packages/opencode/src/account/index.ts
+++ b/packages/opencode/src/account/index.ts
@@ -1,34 +1,26 @@
-import { Effect, Option } from "effect"
-
-import { Account as S, type AccountError, type AccessToken, AccountID, Info as Model, OrgID } from "./effect"
+import { Option } from "effect"
+import { run } from "@/effect/run"
+import { type AccessToken, AccountID, Info as Model, OrgID } from "./effect"
export { AccessToken, AccountID, OrgID } from "./effect"
-import { runtime } from "@/effect/runtime"
-
-function runSync(f: (service: S.Interface) => Effect.Effect) {
- return runtime.runSync(S.Service.use(f))
-}
-
-function runPromise(f: (service: S.Interface) => Effect.Effect) {
- return runtime.runPromise(S.Service.use(f))
-}
+const svc = () => import("./effect").then((m) => m.Account.Service)
export namespace Account {
export const Info = Model
export type Info = Model
- export function active(): Info | undefined {
- return Option.getOrUndefined(runSync((service) => service.active()))
+ export async function active(): Promise {
+ return Option.getOrUndefined(await run((await svc()).use((s) => s.active())))
}
export async function config(accountID: AccountID, orgID: OrgID): Promise | undefined> {
- const config = await runPromise((service) => service.config(accountID, orgID))
+ const config = await run((await svc()).use((s) => s.config(accountID, orgID)))
return Option.getOrUndefined(config)
}
export async function token(accountID: AccountID): Promise {
- const token = await runPromise((service) => service.token(accountID))
+ const token = await run((await svc()).use((s) => s.token(accountID)))
return Option.getOrUndefined(token)
}
}
diff --git a/packages/opencode/src/auth/index.ts b/packages/opencode/src/auth/index.ts
index 411d9dccc0..b8fb00243a 100644
--- a/packages/opencode/src/auth/index.ts
+++ b/packages/opencode/src/auth/index.ts
@@ -1,13 +1,9 @@
-import { Effect } from "effect"
import z from "zod"
-import { runtime } from "@/effect/runtime"
-import * as S from "./effect"
+import { run } from "@/effect/run"
export { OAUTH_DUMMY_KEY } from "./effect"
-function runPromise(f: (service: S.Auth.Interface) => Effect.Effect) {
- return runtime.runPromise(S.Auth.Service.use(f))
-}
+const svc = () => import("./effect").then((m) => m.Auth.Service)
export namespace Auth {
export const Oauth = z
@@ -40,18 +36,18 @@ export namespace Auth {
export type Info = z.infer
export async function get(providerID: string) {
- return runPromise((service) => service.get(providerID))
+ return run((await svc()).use((s) => s.get(providerID)))
}
export async function all(): Promise> {
- return runPromise((service) => service.all())
+ return run((await svc()).use((s) => s.all()))
}
export async function set(key: string, info: Info) {
- return runPromise((service) => service.set(key, info))
+ return run((await svc()).use((s) => s.set(key, info)))
}
export async function remove(key: string) {
- return runPromise((service) => service.remove(key))
+ return run((await svc()).use((s) => s.remove(key)))
}
}
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index 47afdfd7d0..09fbcfe19a 100644
--- a/packages/opencode/src/config/config.ts
+++ b/packages/opencode/src/config/config.ts
@@ -11,7 +11,6 @@ import fs from "fs/promises"
import { lazy } from "../util/lazy"
import { NamedError } from "@opencode-ai/util/error"
import { Flag } from "../flag/flag"
-import { Auth } from "../auth"
import { Env } from "../env"
import {
type ParseError as JsoncParseError,
@@ -33,12 +32,14 @@ import { Glob } from "../util/glob"
import { PackageRegistry } from "@/bun/registry"
import { proxied } from "@/util/proxied"
import { iife } from "@/util/iife"
-import { Account } from "@/account"
import { ConfigPaths } from "./paths"
import { Filesystem } from "@/util/filesystem"
import { Process } from "@/util/process"
import { Lock } from "@/util/lock"
+const auth = lazy(() => import("../auth").then((x) => x.Auth))
+const account = lazy(() => import("@/account").then((x) => x.Account))
+
export namespace Config {
const ModelId = z.string().meta({ $ref: "https://models.dev/model-schema.json#/$defs/Model" })
@@ -76,7 +77,7 @@ export namespace Config {
}
export const state = Instance.state(async () => {
- const auth = await Auth.all()
+ const entries = await (await auth()).all()
// Config loading order (low -> high precedence): https://opencode.ai/docs/config#precedence-order
// 1) Remote .well-known/opencode (org defaults)
@@ -87,7 +88,7 @@ export namespace Config {
// 6) Inline config (OPENCODE_CONFIG_CONTENT)
// Managed config directory is enterprise-only and always overrides everything above.
let result: Info = {}
- for (const [key, value] of Object.entries(auth)) {
+ for (const [key, value] of Object.entries(entries)) {
if (value.type === "wellknown") {
const url = key.replace(/\/+$/, "")
process.env[value.key] = value.token
@@ -177,13 +178,11 @@ export namespace Config {
log.debug("loaded custom config from OPENCODE_CONFIG_CONTENT")
}
- const active = Account.active()
+ const acct = await account()
+ const active = await acct.active()
if (active?.active_org_id) {
try {
- const [config, token] = await Promise.all([
- Account.config(active.id, active.active_org_id),
- Account.token(active.id),
- ])
+ const [config, token] = await Promise.all([acct.config(active.id, active.active_org_id), acct.token(active.id)])
if (token) {
process.env["OPENCODE_CONSOLE_TOKEN"] = token
Env.set("OPENCODE_CONSOLE_TOKEN", token)
diff --git a/packages/opencode/src/effect/run.ts b/packages/opencode/src/effect/run.ts
new file mode 100644
index 0000000000..3f843a1856
--- /dev/null
+++ b/packages/opencode/src/effect/run.ts
@@ -0,0 +1,21 @@
+import type { Effect } from "effect"
+
+/**
+ * Lazy wrappers that defer the import of @/effect/runtime to call time.
+ *
+ * Adapter modules must not eagerly import @/effect/runtime — or even
+ * their own service modules — because bun's bundler can evaluate them
+ * before their dependencies have finished initializing.
+ */
+
+/** For global services (Auth, Account, etc.) */
+export async function run(effect: Effect.Effect): Promise {
+ const { runtime } = await import("@/effect/runtime")
+ return runtime.runPromise(effect)
+}
+
+/** For instance-scoped services (Skill, Snapshot, Question, etc.) */
+export async function runInstance(effect: Effect.Effect): Promise {
+ const { runPromiseInstance } = await import("@/effect/runtime")
+ return runPromiseInstance(effect)
+}
diff --git a/packages/opencode/src/effect/runtime.ts b/packages/opencode/src/effect/runtime.ts
index e6f1f32626..c1d60d48d0 100644
--- a/packages/opencode/src/effect/runtime.ts
+++ b/packages/opencode/src/effect/runtime.ts
@@ -9,7 +9,7 @@ import { Instance } from "@/project/instance"
export const runtime = ManagedRuntime.make(
Layer.mergeAll(
- Account.defaultLayer, //
+ Account.defaultLayer,
Installation.defaultLayer,
Truncate.defaultLayer,
Instances.layer,
diff --git a/packages/opencode/src/file/index.ts b/packages/opencode/src/file/index.ts
index 35a5b5e204..f97fef5f3c 100644
--- a/packages/opencode/src/file/index.ts
+++ b/packages/opencode/src/file/index.ts
@@ -1,40 +1,37 @@
-import { runPromiseInstance } from "@/effect/runtime"
+import { runInstance } from "@/effect/run"
import { File as S } from "./service"
+const svc = () => import("./service").then((m) => m.File.Service)
+
export namespace File {
export const Info = S.Info
export type Info = S.Info
-
export const Node = S.Node
export type Node = S.Node
-
export const Content = S.Content
export type Content = S.Content
-
export const Event = S.Event
-
export type Interface = S.Interface
-
export const Service = S.Service
export const layer = S.layer
- export function init() {
- return runPromiseInstance(S.Service.use((svc) => svc.init()))
+ export async function init() {
+ return runInstance((await svc()).use((s) => s.init()))
}
export async function status() {
- return runPromiseInstance(S.Service.use((svc) => svc.status()))
+ return runInstance((await svc()).use((s) => s.status()))
}
export async function read(file: string): Promise {
- return runPromiseInstance(S.Service.use((svc) => svc.read(file)))
+ return runInstance((await svc()).use((s) => s.read(file)))
}
export async function list(dir?: string) {
- return runPromiseInstance(S.Service.use((svc) => svc.list(dir)))
+ return runInstance((await svc()).use((s) => s.list(dir)))
}
export async function search(input: { query: string; limit?: number; dirs?: boolean; type?: "file" | "directory" }) {
- return runPromiseInstance(S.Service.use((svc) => svc.search(input)))
+ return runInstance((await svc()).use((s) => s.search(input)))
}
}
diff --git a/packages/opencode/src/file/time.ts b/packages/opencode/src/file/time.ts
index b6d572fe8b..45fc9dd22f 100644
--- a/packages/opencode/src/file/time.ts
+++ b/packages/opencode/src/file/time.ts
@@ -1,28 +1,28 @@
-import { runPromiseInstance } from "@/effect/runtime"
+import { runInstance } from "@/effect/run"
import type { SessionID } from "@/session/schema"
import { FileTime as S } from "./time-service"
+const svc = () => import("./time-service").then((m) => m.FileTime.Service)
+
export namespace FileTime {
export type Stamp = S.Stamp
-
export type Interface = S.Interface
-
export const Service = S.Service
export const layer = S.layer
- export function read(sessionID: SessionID, file: string) {
- return runPromiseInstance(S.Service.use((s) => s.read(sessionID, file)))
+ export async function read(sessionID: SessionID, file: string) {
+ return runInstance((await svc()).use((s) => s.read(sessionID, file)))
}
- export function get(sessionID: SessionID, file: string) {
- return runPromiseInstance(S.Service.use((s) => s.get(sessionID, file)))
+ export async function get(sessionID: SessionID, file: string) {
+ return runInstance((await svc()).use((s) => s.get(sessionID, file)))
}
export async function assert(sessionID: SessionID, filepath: string) {
- return runPromiseInstance(S.Service.use((s) => s.assert(sessionID, filepath)))
+ return runInstance((await svc()).use((s) => s.assert(sessionID, filepath)))
}
export async function withLock(filepath: string, fn: () => Promise): Promise {
- return runPromiseInstance(S.Service.use((s) => s.withLock(filepath, fn)))
+ return runInstance((await svc()).use((s) => s.withLock(filepath, fn)))
}
}
diff --git a/packages/opencode/src/format/index.ts b/packages/opencode/src/format/index.ts
index e4381c69b2..33e3e53082 100644
--- a/packages/opencode/src/format/index.ts
+++ b/packages/opencode/src/format/index.ts
@@ -1,16 +1,9 @@
-import { runPromiseInstance } from "@/effect/runtime"
-import { Format as S } from "./service"
+import { runInstance } from "@/effect/run"
+
+const svc = () => import("./service").then((m) => m.Format.Service)
export namespace Format {
- export const Status = S.Status
- export type Status = S.Status
-
- export type Interface = S.Interface
-
- export const Service = S.Service
- export const layer = S.layer
-
export async function status() {
- return runPromiseInstance(S.Service.use((s) => s.status()))
+ return runInstance((await svc()).use((s) => s.status()))
}
}
diff --git a/packages/opencode/src/permission/index.ts b/packages/opencode/src/permission/index.ts
index 01ac768971..8229be5e13 100644
--- a/packages/opencode/src/permission/index.ts
+++ b/packages/opencode/src/permission/index.ts
@@ -1,52 +1,43 @@
-import { runPromiseInstance } from "@/effect/runtime"
-import { fn } from "@/util/fn"
-import z from "zod"
+import { runInstance } from "@/effect/run"
import { Permission as S } from "./service"
+const svc = () => import("./service").then((m) => m.Permission.Service)
+
export namespace PermissionNext {
export const Action = S.Action
export type Action = S.Action
-
export const Rule = S.Rule
export type Rule = S.Rule
-
- export const Ruleset = S.Ruleset
export type Ruleset = S.Ruleset
-
export const Request = S.Request
export type Request = S.Request
-
export const Reply = S.Reply
export type Reply = S.Reply
-
export const Approval = S.Approval
- export type Approval = z.infer
-
export const Event = S.Event
-
export const RejectedError = S.RejectedError
export const CorrectedError = S.CorrectedError
export const DeniedError = S.DeniedError
export type Error = S.Error
-
export const AskInput = S.AskInput
export const ReplyInput = S.ReplyInput
-
export type Interface = S.Interface
-
export const Service = S.Service
export const layer = S.layer
-
export const evaluate = S.evaluate
export const fromConfig = S.fromConfig
export const merge = S.merge
export const disabled = S.disabled
- export const ask = fn(S.AskInput, async (input) => runPromiseInstance(S.Service.use((s) => s.ask(input))))
+ export async function ask(input: S.AskInput) {
+ return runInstance((await svc()).use((s) => s.ask(input)))
+ }
- export const reply = fn(S.ReplyInput, async (input) => runPromiseInstance(S.Service.use((s) => s.reply(input))))
+ export async function reply(input: S.ReplyInput) {
+ return runInstance((await svc()).use((s) => s.reply(input)))
+ }
export async function list() {
- return runPromiseInstance(S.Service.use((s) => s.list()))
+ return runInstance((await svc()).use((s) => s.list()))
}
}
diff --git a/packages/opencode/src/permission/service.ts b/packages/opencode/src/permission/service.ts
index 08475520b2..0bbacf1932 100644
--- a/packages/opencode/src/permission/service.ts
+++ b/packages/opencode/src/permission/service.ts
@@ -105,16 +105,18 @@ export namespace Permission {
export const AskInput = Request.partial({ id: true }).extend({
ruleset: Ruleset,
})
+ export type AskInput = z.infer
export const ReplyInput = z.object({
requestID: PermissionID.zod,
reply: Reply,
message: z.string().optional(),
})
+ export type ReplyInput = z.infer
export interface Interface {
- readonly ask: (input: z.infer) => Effect.Effect
- readonly reply: (input: z.infer) => Effect.Effect
+ readonly ask: (input: AskInput) => Effect.Effect
+ readonly reply: (input: ReplyInput) => Effect.Effect
readonly list: () => Effect.Effect
}
@@ -140,7 +142,7 @@ export namespace Permission {
const pending = new Map()
const approved: Ruleset = row?.data ?? []
- const ask = Effect.fn("Permission.ask")(function* (input: z.infer) {
+ const ask = Effect.fn("Permission.ask")(function* (input: AskInput) {
const { ruleset, ...request } = input
let needsAsk = false
@@ -176,7 +178,7 @@ export namespace Permission {
)
})
- const reply = Effect.fn("Permission.reply")(function* (input: z.infer) {
+ const reply = Effect.fn("Permission.reply")(function* (input: ReplyInput) {
const existing = pending.get(input.requestID)
if (!existing) return
diff --git a/packages/opencode/src/provider/auth.ts b/packages/opencode/src/provider/auth.ts
index 8ede977a59..4e026a7dc0 100644
--- a/packages/opencode/src/provider/auth.ts
+++ b/packages/opencode/src/provider/auth.ts
@@ -1,30 +1,28 @@
-import { runPromiseInstance } from "@/effect/runtime"
+import { runInstance } from "@/effect/run"
import { fn } from "@/util/fn"
import { ProviderID } from "./schema"
import z from "zod"
import { ProviderAuth as S } from "./auth-service"
+const svc = () => import("./auth-service").then((m) => m.ProviderAuth.Service)
+
export namespace ProviderAuth {
export const Method = S.Method
export type Method = S.Method
-
export const Authorization = S.Authorization
export type Authorization = S.Authorization
-
export const OauthMissing = S.OauthMissing
export const OauthCodeMissing = S.OauthCodeMissing
export const OauthCallbackFailed = S.OauthCallbackFailed
export const ValidationFailed = S.ValidationFailed
export type Error = S.Error
-
export type Interface = S.Interface
-
export const Service = S.Service
export const layer = S.layer
export const defaultLayer = S.defaultLayer
export async function methods() {
- return runPromiseInstance(S.Service.use((svc) => svc.methods()))
+ return runInstance((await svc()).use((s) => s.methods()))
}
export const authorize = fn(
@@ -34,7 +32,7 @@ export namespace ProviderAuth {
inputs: z.record(z.string(), z.string()).optional(),
}),
async (input): Promise =>
- runPromiseInstance(S.Service.use((svc) => svc.authorize(input))),
+ runInstance((await svc()).use((s) => s.authorize(input))),
)
export const callback = fn(
@@ -43,6 +41,6 @@ export namespace ProviderAuth {
method: z.number(),
code: z.string().optional(),
}),
- async (input) => runPromiseInstance(S.Service.use((svc) => svc.callback(input))),
+ async (input) => runInstance((await svc()).use((s) => s.callback(input))),
)
}
diff --git a/packages/opencode/src/question/index.ts b/packages/opencode/src/question/index.ts
index de00951908..57b6494240 100644
--- a/packages/opencode/src/question/index.ts
+++ b/packages/opencode/src/question/index.ts
@@ -1,29 +1,24 @@
-import { runPromiseInstance } from "@/effect/runtime"
+import { runInstance } from "@/effect/run"
import type { MessageID, SessionID } from "@/session/schema"
import type { QuestionID } from "./schema"
import { Question as S } from "./service"
-export namespace Question {
- export const Option = S.Option
- export type Option = S.Option
+const svc = () => import("./service").then((m) => m.Question.Service)
+export namespace Question {
export const Info = S.Info
export type Info = S.Info
-
export const Request = S.Request
export type Request = S.Request
-
export const Answer = S.Answer
export type Answer = S.Answer
-
export const Reply = S.Reply
export type Reply = S.Reply
-
+ export const Option = S.Option
+ export type Option = S.Option
export const Event = S.Event
export const RejectedError = S.RejectedError
-
export type Interface = S.Interface
-
export const Service = S.Service
export const layer = S.layer
@@ -32,18 +27,18 @@ export namespace Question {
questions: Info[]
tool?: { messageID: MessageID; callID: string }
}): Promise {
- return runPromiseInstance(S.Service.use((s) => s.ask(input)))
+ return runInstance((await svc()).use((s) => s.ask(input)))
}
export async function reply(input: { requestID: QuestionID; answers: Answer[] }) {
- return runPromiseInstance(S.Service.use((s) => s.reply(input)))
+ return runInstance((await svc()).use((s) => s.reply(input)))
}
export async function reject(requestID: QuestionID) {
- return runPromiseInstance(S.Service.use((s) => s.reject(requestID)))
+ return runInstance((await svc()).use((s) => s.reject(requestID)))
}
export async function list() {
- return runPromiseInstance(S.Service.use((s) => s.list()))
+ return runInstance((await svc()).use((s) => s.list()))
}
}
diff --git a/packages/opencode/src/server/routes/file.ts b/packages/opencode/src/server/routes/file.ts
index 60789ef4b7..66d67e61ef 100644
--- a/packages/opencode/src/server/routes/file.ts
+++ b/packages/opencode/src/server/routes/file.ts
@@ -1,7 +1,8 @@
import { Hono } from "hono"
import { describeRoute, validator, resolver } from "hono-openapi"
import z from "zod"
-import { File } from "../../file"
+import { File } from "../../file/service"
+import { File as FileApi } from "../../file"
import { Ripgrep } from "../../file/ripgrep"
import { LSP } from "../../lsp"
import { Instance } from "../../project/instance"
@@ -73,7 +74,7 @@ export const FileRoutes = lazy(() =>
const dirs = c.req.valid("query").dirs
const type = c.req.valid("query").type
const limit = c.req.valid("query").limit
- const results = await File.search({
+ const results = await FileApi.search({
query,
limit: limit ?? 10,
dirs: dirs !== "false",
@@ -139,7 +140,7 @@ export const FileRoutes = lazy(() =>
),
async (c) => {
const path = c.req.valid("query").path
- const content = await File.list(path)
+ const content = await FileApi.list(path)
return c.json(content)
},
)
@@ -168,7 +169,7 @@ export const FileRoutes = lazy(() =>
),
async (c) => {
const path = c.req.valid("query").path
- const content = await File.read(path)
+ const content = await FileApi.read(path)
return c.json(content)
},
)
@@ -190,7 +191,7 @@ export const FileRoutes = lazy(() =>
},
}),
async (c) => {
- const content = await File.status()
+ const content = await FileApi.status()
return c.json(content)
},
),
diff --git a/packages/opencode/src/server/routes/permission.ts b/packages/opencode/src/server/routes/permission.ts
index cc6c26d435..bf340042bd 100644
--- a/packages/opencode/src/server/routes/permission.ts
+++ b/packages/opencode/src/server/routes/permission.ts
@@ -1,6 +1,7 @@
import { Hono } from "hono"
import { describeRoute, validator, resolver } from "hono-openapi"
import z from "zod"
+import { Permission } from "@/permission/service"
import { PermissionNext } from "@/permission"
import { PermissionID } from "@/permission/schema"
import { errors } from "../error"
@@ -32,7 +33,7 @@ export const PermissionRoutes = lazy(() =>
requestID: PermissionID.zod,
}),
),
- validator("json", z.object({ reply: PermissionNext.Reply, message: z.string().optional() })),
+ validator("json", z.object({ reply: Permission.Reply, message: z.string().optional() })),
async (c) => {
const params = c.req.valid("param")
const json = c.req.valid("json")
@@ -55,7 +56,7 @@ export const PermissionRoutes = lazy(() =>
description: "List of pending permissions",
content: {
"application/json": {
- schema: resolver(PermissionNext.Request.array()),
+ schema: resolver(Permission.Request.array()),
},
},
},
diff --git a/packages/opencode/src/server/routes/provider.ts b/packages/opencode/src/server/routes/provider.ts
index 64fe34f450..4495451d28 100644
--- a/packages/opencode/src/server/routes/provider.ts
+++ b/packages/opencode/src/server/routes/provider.ts
@@ -4,7 +4,8 @@ import z from "zod"
import { Config } from "../../config/config"
import { Provider } from "../../provider/provider"
import { ModelsDev } from "../../provider/models"
-import { ProviderAuth } from "../../provider/auth"
+import { ProviderAuth } from "../../provider/auth-service"
+import { ProviderAuth as ProviderAuthApi } from "../../provider/auth"
import { ProviderID } from "../../provider/schema"
import { mapValues } from "remeda"
import { errors } from "../error"
@@ -81,7 +82,7 @@ export const ProviderRoutes = lazy(() =>
},
}),
async (c) => {
- return c.json(await ProviderAuth.methods())
+ return c.json(await ProviderAuthApi.methods())
},
)
.post(
@@ -118,7 +119,7 @@ export const ProviderRoutes = lazy(() =>
async (c) => {
const providerID = c.req.valid("param").providerID
const { method, inputs } = c.req.valid("json")
- const result = await ProviderAuth.authorize({
+ const result = await ProviderAuthApi.authorize({
providerID,
method,
inputs,
@@ -160,7 +161,7 @@ export const ProviderRoutes = lazy(() =>
async (c) => {
const providerID = c.req.valid("param").providerID
const { method, code } = c.req.valid("json")
- await ProviderAuth.callback({
+ await ProviderAuthApi.callback({
providerID,
method,
code,
diff --git a/packages/opencode/src/server/routes/question.ts b/packages/opencode/src/server/routes/question.ts
index 3fff895fa6..357e51a396 100644
--- a/packages/opencode/src/server/routes/question.ts
+++ b/packages/opencode/src/server/routes/question.ts
@@ -2,7 +2,8 @@ import { Hono } from "hono"
import { describeRoute, validator } from "hono-openapi"
import { resolver } from "hono-openapi"
import { QuestionID } from "@/question/schema"
-import { Question } from "../../question"
+import { Question } from "../../question/service"
+import { Question as QuestionApi } from "../../question"
import z from "zod"
import { errors } from "../error"
import { lazy } from "../../util/lazy"
@@ -27,7 +28,7 @@ export const QuestionRoutes = lazy(() =>
},
}),
async (c) => {
- const questions = await Question.list()
+ const questions = await QuestionApi.list()
return c.json(questions)
},
)
@@ -59,7 +60,7 @@ export const QuestionRoutes = lazy(() =>
async (c) => {
const params = c.req.valid("param")
const json = c.req.valid("json")
- await Question.reply({
+ await QuestionApi.reply({
requestID: params.requestID,
answers: json.answers,
})
@@ -92,7 +93,7 @@ export const QuestionRoutes = lazy(() =>
),
async (c) => {
const params = c.req.valid("param")
- await Question.reject(params.requestID)
+ await QuestionApi.reject(params.requestID)
return c.json(true)
},
),
diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts
index a68becb1fb..07425c7762 100644
--- a/packages/opencode/src/server/server.ts
+++ b/packages/opencode/src/server/server.ts
@@ -8,13 +8,15 @@ import z from "zod"
import { Provider } from "../provider/provider"
import { NamedError } from "@opencode-ai/util/error"
import { LSP } from "../lsp"
+import { Format as FormatService } from "../format/service"
import { Format } from "../format"
import { TuiRoutes } from "./routes/tui"
import { Instance } from "../project/instance"
import { Vcs } from "../project/vcs"
import { runPromiseInstance } from "@/effect/runtime"
import { Agent } from "../agent/agent"
-import { Skill } from "../skill/skill"
+import { Skill as SkillService } from "../skill/service"
+import { Skill } from "../skill"
import { Auth } from "../auth"
import { Flag } from "../flag/flag"
import { Command } from "../command"
@@ -444,7 +446,7 @@ export namespace Server {
description: "List of skills",
content: {
"application/json": {
- schema: resolver(Skill.Info.array()),
+ schema: resolver(SkillService.Info.array()),
},
},
},
@@ -487,7 +489,7 @@ export namespace Server {
description: "Formatter status",
content: {
"application/json": {
- schema: resolver(Format.Status.array()),
+ schema: resolver(FormatService.Status.array()),
},
},
},
diff --git a/packages/opencode/src/share/share-next.ts b/packages/opencode/src/share/share-next.ts
index e911656c90..e331e8fc6a 100644
--- a/packages/opencode/src/share/share-next.ts
+++ b/packages/opencode/src/share/share-next.ts
@@ -45,7 +45,7 @@ export namespace ShareNext {
}> {
const headers: Record = {}
- const active = Account.active()
+ const active = await Account.active()
if (!active?.active_org_id) {
const baseUrl = await Config.get().then((x) => x.enterprise?.url ?? "https://opncd.ai")
return { headers, api: legacyApi, baseUrl }
diff --git a/packages/opencode/src/skill/index.ts b/packages/opencode/src/skill/index.ts
index 67bef3bd38..8dcf5d8044 100644
--- a/packages/opencode/src/skill/index.ts
+++ b/packages/opencode/src/skill/index.ts
@@ -1 +1,30 @@
-export * from "./skill"
+import type { Agent } from "@/agent/agent"
+import { runInstance } from "@/effect/run"
+
+const svc = () => import("./service").then((m) => m.Skill.Service)
+const mod = () => import("./service").then((m) => m.Skill)
+
+export namespace Skill {
+ export type Info = import("./service").Skill.Info
+ export type Interface = import("./service").Skill.Interface
+
+ export async function get(name: string) {
+ return runInstance((await svc()).use((s) => s.get(name)))
+ }
+
+ export async function all() {
+ return runInstance((await svc()).use((s) => s.all()))
+ }
+
+ export async function dirs() {
+ return runInstance((await svc()).use((s) => s.dirs()))
+ }
+
+ export async function available(agent?: Agent.Info) {
+ return runInstance((await svc()).use((s) => s.available(agent)))
+ }
+
+ export async function fmt(list: Info[], opts: { verbose: boolean }) {
+ return (await mod()).fmt(list, opts)
+ }
+}
diff --git a/packages/opencode/src/skill/skill.ts b/packages/opencode/src/skill/skill.ts
deleted file mode 100644
index ed3e0a4b75..0000000000
--- a/packages/opencode/src/skill/skill.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { runPromiseInstance } from "@/effect/runtime"
-import type { Agent } from "@/agent/agent"
-import { Skill as S } from "./service"
-
-export namespace Skill {
- export const Info = S.Info
- export type Info = S.Info
-
- export const InvalidError = S.InvalidError
- export const NameMismatchError = S.NameMismatchError
-
- export type Interface = S.Interface
-
- export const Service = S.Service
- export const layer = S.layer
- export const defaultLayer = S.defaultLayer
-
- export const fmt = S.fmt
-
- export async function get(name: string) {
- return runPromiseInstance(S.Service.use((skill) => skill.get(name)))
- }
-
- export async function all() {
- return runPromiseInstance(S.Service.use((skill) => skill.all()))
- }
-
- export async function dirs() {
- return runPromiseInstance(S.Service.use((skill) => skill.dirs()))
- }
-
- export async function available(agent?: Agent.Info) {
- return runPromiseInstance(S.Service.use((skill) => skill.available(agent)))
- }
-}
diff --git a/packages/opencode/src/snapshot/index.ts b/packages/opencode/src/snapshot/index.ts
index 4f845ca2de..b955c0d8d0 100644
--- a/packages/opencode/src/snapshot/index.ts
+++ b/packages/opencode/src/snapshot/index.ts
@@ -1,44 +1,43 @@
-import { runPromiseInstance } from "@/effect/runtime"
+import { runInstance } from "@/effect/run"
import { Snapshot as S } from "./service"
+const svc = () => import("./service").then((m) => m.Snapshot.Service)
+
export namespace Snapshot {
export const Patch = S.Patch
export type Patch = S.Patch
-
export const FileDiff = S.FileDiff
export type FileDiff = S.FileDiff
-
export type Interface = S.Interface
-
export const Service = S.Service
export const layer = S.layer
export const defaultLayer = S.defaultLayer
export async function cleanup() {
- return runPromiseInstance(S.Service.use((svc) => svc.cleanup()))
+ return runInstance((await svc()).use((s) => s.cleanup()))
}
export async function track() {
- return runPromiseInstance(S.Service.use((svc) => svc.track()))
+ return runInstance((await svc()).use((s) => s.track()))
}
export async function patch(hash: string) {
- return runPromiseInstance(S.Service.use((svc) => svc.patch(hash)))
+ return runInstance((await svc()).use((s) => s.patch(hash)))
}
export async function restore(snapshot: string) {
- return runPromiseInstance(S.Service.use((svc) => svc.restore(snapshot)))
+ return runInstance((await svc()).use((s) => s.restore(snapshot)))
}
export async function revert(patches: Patch[]) {
- return runPromiseInstance(S.Service.use((svc) => svc.revert(patches)))
+ return runInstance((await svc()).use((s) => s.revert(patches)))
}
export async function diff(hash: string) {
- return runPromiseInstance(S.Service.use((svc) => svc.diff(hash)))
+ return runInstance((await svc()).use((s) => s.diff(hash)))
}
export async function diffFull(from: string, to: string) {
- return runPromiseInstance(S.Service.use((svc) => svc.diffFull(from, to)))
+ return runInstance((await svc()).use((s) => s.diffFull(from, to)))
}
}
diff --git a/packages/opencode/test/share/share-next.test.ts b/packages/opencode/test/share/share-next.test.ts
index 5be5d02450..fc8d511509 100644
--- a/packages/opencode/test/share/share-next.test.ts
+++ b/packages/opencode/test/share/share-next.test.ts
@@ -7,7 +7,7 @@ test("ShareNext.request uses legacy share API without active org account", async
const originalActive = Account.active
const originalConfigGet = Config.get
- Account.active = mock(() => undefined)
+ Account.active = mock(async () => undefined)
Config.get = mock(async () => ({ enterprise: { url: "https://legacy-share.example.com" } }))
try {
@@ -29,7 +29,7 @@ test("ShareNext.request uses org share API with auth headers when account is act
const originalActive = Account.active
const originalToken = Account.token
- Account.active = mock(() => ({
+ Account.active = mock(async () => ({
id: AccountID.make("account-1"),
email: "user@example.com",
url: "https://control.example.com",
@@ -59,7 +59,7 @@ test("ShareNext.request fails when org account has no token", async () => {
const originalActive = Account.active
const originalToken = Account.token
- Account.active = mock(() => ({
+ Account.active = mock(async () => ({
id: AccountID.make("account-1"),
email: "user@example.com",
url: "https://control.example.com",