Compare commits

..

1 Commits

Author SHA1 Message Date
Aiden Cline 31d25c8f08 fix(opencode): flush embedded server telemetry 2026-07-30 22:16:45 +00:00
4 changed files with 22 additions and 31 deletions
+5 -7
View File
@@ -123,16 +123,14 @@ async function toolError(part: ToolPart) {
}
}
async function embeddedServer() {
async function embeddedServer(auth?: string) {
const { Server } = await import("@/server/server")
const server = Server.Default().app
const server = Server.Default()
const fetch = (async (input: RequestInfo | URL, init?: RequestInit) => {
const request = new Request(input, init)
const headers = new Headers(request.headers)
const { ServerAuth } = await import("@/server/auth")
const auth = ServerAuth.header()
if (auth) headers.set("Authorization", auth)
return server.fetch(new Request(request, { headers }))
return server.app.fetch(new Request(request, { headers }))
}) as typeof globalThis.fetch
return { fetch, dispose: server.dispose }
}
@@ -916,7 +914,7 @@ export const RunCommand = effectCmd({
if (interactive && !args.attach && !args.session && !args.continue) {
const model = pick(args.model)
const { runInteractiveLocalMode } = await import("./run/runtime")
const server = await embeddedServer()
const server = await embeddedServer(ServerAuth.header())
try {
return await runInteractiveLocalMode({
@@ -949,7 +947,7 @@ export const RunCommand = effectCmd({
return await execute(sdk)
}
const server = await embeddedServer()
const server = await embeddedServer(ServerAuth.header())
try {
const sdk = createOpencodeClient({
baseUrl: "http://opencode.internal",
+15 -21
View File
@@ -60,8 +60,6 @@ interface EffectCmdOpts<Args, A> {
*
* Errors propagate to the existing top-level handler in `src/index.ts`; use
* `fail("...")` for user-visible domain failures (clean exit, formatted message).
* The AppRuntime is disposed after the command finishes so its scoped resources
* are released without making the CLI entrypoint import the full application graph.
*
* Handlers are typically `Effect.fn("Cli.<name>")(function*(args) { ... })`,
* which adds a named tracing span per CLI invocation. Once all commands use
@@ -76,27 +74,23 @@ export const effectCmd = <Args, A>(opts: EffectCmdOpts<Args, A>) =>
builder: opts.builder as never,
async handler(rawArgs) {
const { AppRuntime } = await import("@/effect/app-runtime")
// yargs typing wraps Args in ArgumentsCamelCase<WithDoubleDash<...>>; cast at the boundary.
const args = rawArgs as unknown as WithDoubleDash<Args>
const useInstance = typeof opts.instance === "function" ? opts.instance(args) : opts.instance !== false
if (!useInstance) {
await AppRuntime.runPromise(opts.handler(args))
return
}
const { InstanceStore } = await import("@/project/instance-store")
const { InstanceRef } = await import("@/effect/instance-ref")
const directory = opts.directory?.(args) ?? process.cwd()
const { store, ctx } = await AppRuntime.runPromise(
InstanceStore.Service.use((store) => store.load({ directory }).pipe(Effect.map((ctx) => ({ store, ctx })))),
)
try {
// yargs typing wraps Args in ArgumentsCamelCase<WithDoubleDash<...>>; cast at the boundary.
const args = rawArgs as unknown as WithDoubleDash<Args>
const useInstance = typeof opts.instance === "function" ? opts.instance(args) : opts.instance !== false
if (!useInstance) {
await AppRuntime.runPromise(opts.handler(args))
return
}
const { InstanceStore } = await import("@/project/instance-store")
const { InstanceRef } = await import("@/effect/instance-ref")
const directory = opts.directory?.(args) ?? process.cwd()
const { store, ctx } = await AppRuntime.runPromise(
InstanceStore.Service.use((store) => store.load({ directory }).pipe(Effect.map((ctx) => ({ store, ctx })))),
)
try {
await AppRuntime.runPromise(opts.handler(args).pipe(Effect.provideService(InstanceRef, ctx)))
} finally {
await AppRuntime.runPromise(store.dispose(ctx))
}
await AppRuntime.runPromise(opts.handler(args).pipe(Effect.provideService(InstanceRef, ctx)))
} finally {
await AppRuntime.dispose().catch(() => {})
await AppRuntime.runPromise(store.dispose(ctx))
}
},
})
+1
View File
@@ -72,6 +72,7 @@ export const rpc = {
async shutdown() {
await InstanceRuntime.disposeAllInstances()
if (server) await server.stop(true)
if (Server.Default.loaded()) await Server.Default().dispose()
process.off("unhandledRejection", onUnhandledRejection)
process.off("uncaughtException", onUncaughtException)
},
+1 -3
View File
@@ -27,7 +27,6 @@ export type Listener = {
type ServerApp = {
fetch(request: Request): Response | Promise<Response>
request(input: string | URL | Request, init?: RequestInit): Response | Promise<Response>
dispose(): Promise<void>
}
type ListenOptions = CorsOptions & {
@@ -61,9 +60,8 @@ export const Default = lazy(() => {
request(input, init) {
return app.fetch(input instanceof Request ? input : new Request(new URL(input, "http://localhost"), init))
},
dispose: web.dispose,
}
return { app }
return { app, dispose: web.dispose }
})
export async function openapi() {