This commit is contained in:
Dax Raad
2026-04-09 14:13:55 -04:00
parent 2b8e2a423d
commit 69b4a2604f
11 changed files with 37 additions and 33 deletions
+5 -7
View File
@@ -398,13 +398,11 @@ export namespace Agent {
}),
)
export const defaultLayer = Layer.suspend(() =>
layer.pipe(
Layer.provide(Provider.defaultLayer),
Layer.provide(Auth.defaultLayer),
Layer.provide(Config.defaultLayer),
Layer.provide(Skill.defaultLayer),
),
export const defaultLayer = layer.pipe(
Layer.provide(Provider.defaultLayer),
Layer.provide(Auth.defaultLayer),
Layer.provide(Config.defaultLayer),
Layer.provide(Skill.defaultLayer),
)
const { runPromise } = makeRuntime(Service, defaultLayer)
+1 -1
View File
@@ -680,7 +680,7 @@ export const RunCommand = cmd({
await bootstrap(process.cwd(), async () => {
const fetchFn = (async (input: RequestInfo | URL, init?: RequestInit) => {
const request = new Request(input, init)
return Server.Default().app.fetch(request)
return (await Server.Default()).app.fetch(request)
}) as typeof globalThis.fetch
const sdk = createOpencodeClient({ baseUrl: "http://opencode.internal", fetch: fetchFn })
await execute(sdk)
+1 -1
View File
@@ -138,7 +138,7 @@ export const rpc = {
headers,
body: input.body,
})
const response = await Server.Default().app.fetch(request)
const response = await (await Server.Default()).app.fetch(request)
const body = await response.text()
return {
status: response.status,
+1 -1
View File
@@ -119,7 +119,7 @@ export namespace Plugin {
Authorization: `Basic ${Buffer.from(`${Flag.OPENCODE_SERVER_USERNAME ?? "opencode"}:${Flag.OPENCODE_SERVER_PASSWORD}`).toString("base64")}`,
}
: undefined,
fetch: async (...args) => Server.Default().app.fetch(...args),
fetch: async (...args) => (await Server.Default()).app.fetch(...args),
})
const cfg = yield* config.get()
const input: PluginInput = {
@@ -24,7 +24,7 @@ import { ProviderRoutes } from "./provider"
import { EventRoutes } from "./event"
import { WorkspaceRouterMiddleware } from "./middleware"
export const InstanceRoutes = (upgrade: UpgradeWebSocket) =>
export const InstanceRoutes = (upgrade: UpgradeWebSocket): Hono =>
new Hono()
.use(WorkspaceRouterMiddleware(upgrade))
.route("/project", ProjectRoutes())
+16 -10
View File
@@ -3,19 +3,12 @@ import { Hono } from "hono"
import { createNodeWebSocket } from "@hono/node-ws"
import { MDNS } from "./mdns"
import { lazy } from "@/util/lazy"
import { AuthMiddleware, CompressionMiddleware, CorsMiddleware, ErrorMiddleware, LoggerMiddleware } from "./middleware"
import { InstanceRoutes } from "./instance"
import { initProjectors } from "./projectors"
import { createAdaptorServer, type ServerType } from "@hono/node-server"
import { ControlPlaneRoutes } from "./control"
import { Log } from "@/util/log"
import { UIRoutes } from "./ui"
// @ts-ignore This global is needed to prevent ai-sdk from logging warnings to stdout https://github.com/vercel/ai/blob/2dc67e0ef538307f21368db32d5a12345d98831b/packages/ai/src/logger/log-warnings.ts#L85
globalThis.AI_SDK_LOG_WARNINGS = false
initProjectors()
export namespace Server {
const log = Log.create({ service: "server" })
@@ -28,7 +21,20 @@ export namespace Server {
export const Default = lazy(() => create({}))
function create(opts: { cors?: string[] }) {
async function create(opts: { cors?: string[] }) {
const [
{ AuthMiddleware, CompressionMiddleware, CorsMiddleware, ErrorMiddleware, LoggerMiddleware },
,
{ ControlPlaneRoutes },
{ InstanceRoutes },
{ UIRoutes },
] = await Promise.all([
import("./middleware"),
import("./projectors"),
import("./control"),
import("./instance"),
import("./ui"),
])
const app = new Hono()
const ws = createNodeWebSocket({ app })
return {
@@ -50,7 +56,7 @@ export namespace Server {
// hono-openapi can see describeRoute metadata (`.route()` wraps
// handlers when the sub-app has a custom errorHandler, which
// strips the metadata symbol).
const { app } = create({})
const { app } = await create({})
const result = await generateSpecs(app, {
documentation: {
info: {
@@ -73,7 +79,7 @@ export namespace Server {
mdnsDomain?: string
cors?: string[]
}): Promise<Listener> {
const built = create(opts)
const built = await create(opts)
const start = (port: number) =>
new Promise<ServerType>((resolve, reject) => {
const server = createAdaptorServer({ fetch: built.app.fetch })
+1 -1
View File
@@ -16,7 +16,7 @@ const DEFAULT_CSP =
const csp = (hash = "") =>
`default-src 'self'; script-src 'self' 'wasm-unsafe-eval'${hash ? ` 'sha256-${hash}'` : ""}; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; media-src 'self' data:; connect-src 'self' data:`
export const UIRoutes = () =>
export const UIRoutes = (): Hono =>
new Hono().all("/*", async (c) => {
const embeddedWebUI = await embeddedUIPromise
const path = c.req.path
@@ -19,7 +19,7 @@ afterEach(async () => {
describe("project.initGit endpoint", () => {
test("initializes git and reloads immediately", async () => {
await using tmp = await tmpdir()
const app = Server.Default().app
const app = (await Server.Default()).app
const seen: { directory?: string; payload: { type: string } }[] = []
const fn = (evt: { directory?: string; payload: { type: string } }) => {
seen.push(evt)
@@ -76,7 +76,7 @@ describe("project.initGit endpoint", () => {
test("does not reload when the project is already git", async () => {
await using tmp = await tmpdir({ git: true })
const app = Server.Default().app
const app = (await Server.Default()).app
const seen: { directory?: string; payload: { type: string } }[] = []
const fn = (evt: { directory?: string; payload: { type: string } }) => {
seen.push(evt)
@@ -43,7 +43,7 @@ describe("session action routes", () => {
fn: async () => {
const session = await Session.create({})
const cancel = spyOn(SessionPrompt, "cancel").mockResolvedValue()
const app = Server.Default().app
const app = (await Server.Default()).app
const res = await app.request(`/session/${session.id}/abort`, {
method: "POST",
@@ -67,7 +67,7 @@ describe("session action routes", () => {
const msg = await user(session.id, "hello")
const busy = spyOn(SessionRunState, "assertNotBusy").mockRejectedValue(new Session.BusyError(session.id))
const remove = spyOn(Session, "removeMessage").mockResolvedValue(msg.id)
const app = Server.Default().app
const app = (await Server.Default()).app
const res = await app.request(`/session/${session.id}/message/${msg.id}`, {
method: "DELETE",
@@ -60,7 +60,7 @@ describe("session messages endpoint", () => {
fn: async () => {
const session = await Session.create({})
const ids = await fill(session.id, 5)
const app = Server.Default().app
const app = (await Server.Default()).app
const a = await app.request(`/session/${session.id}/message?limit=2`)
expect(a.status).toBe(200)
@@ -89,7 +89,7 @@ describe("session messages endpoint", () => {
fn: async () => {
const session = await Session.create({})
const ids = await fill(session.id, 3)
const app = Server.Default().app
const app = (await Server.Default()).app
const res = await app.request(`/session/${session.id}/message`)
expect(res.status).toBe(200)
@@ -109,7 +109,7 @@ describe("session messages endpoint", () => {
directory: tmp.path,
fn: async () => {
const session = await Session.create({})
const app = Server.Default().app
const app = (await Server.Default()).app
const bad = await app.request(`/session/${session.id}/message?limit=2&before=bad`)
expect(bad.status).toBe(400)
@@ -131,7 +131,7 @@ describe("session messages endpoint", () => {
fn: async () => {
const session = await Session.create({})
await fill(session.id, 520)
const app = Server.Default().app
const app = (await Server.Default()).app
const res = await app.request(`/session/${session.id}/message?limit=510`)
expect(res.status).toBe(200)
@@ -21,7 +21,7 @@ describe("tui.selectSession endpoint", () => {
const session = await Session.create({})
// #when
const app = Server.Default().app
const app = (await Server.Default()).app
const response = await app.request("/tui/select-session", {
method: "POST",
headers: { "Content-Type": "application/json" },
@@ -47,7 +47,7 @@ describe("tui.selectSession endpoint", () => {
const nonExistentSessionID = "ses_nonexistent123"
// #when
const app = Server.Default().app
const app = (await Server.Default()).app
const response = await app.request("/tui/select-session", {
method: "POST",
headers: { "Content-Type": "application/json" },
@@ -69,7 +69,7 @@ describe("tui.selectSession endpoint", () => {
const invalidSessionID = "invalid_session_id"
// #when
const app = Server.Default().app
const app = (await Server.Default()).app
const response = await app.request("/tui/select-session", {
method: "POST",
headers: { "Content-Type": "application/json" },