chore: merge dev

This commit is contained in:
Dax Raad
2026-06-04 01:24:55 -04:00
312 changed files with 32760 additions and 4465 deletions
@@ -40,7 +40,15 @@ export function callAuthProbe(scenario: ActiveScenario, credentials: "missing" |
})
}
const appCache: Partial<Record<string, BackendApp>> = {}
type CachedApp = BackendApp & { readonly dispose: () => Promise<void> }
const appCache: Partial<Record<string, CachedApp>> = {}
export async function disposeApps() {
const apps = Object.values(appCache)
for (const key of Object.keys(appCache)) delete appCache[key]
await Promise.all(apps.flatMap((app) => (app === undefined ? [] : [app.dispose()])))
}
function app(modules: Runtime, options: CallOptions) {
const username = options.auth?.username
@@ -48,7 +56,7 @@ function app(modules: Runtime, options: CallOptions) {
const cacheKey = `${username ?? ""}:${password ?? ""}`
if (appCache[cacheKey]) return appCache[cacheKey]
const handler = HttpRouter.toWebHandler(
const web = HttpRouter.toWebHandler(
modules.HttpApiApp.routes.pipe(
Layer.provide(
ConfigProvider.layer(
@@ -57,10 +65,11 @@ function app(modules: Runtime, options: CallOptions) {
),
),
{ disableLogger: true, memoMap: modules.memoMap },
).handler
)
return (appCache[cacheKey] = {
dispose: web.dispose,
request(input: string | URL | Request, init?: RequestInit) {
return handler(
return web.handler(
input instanceof Request ? input : new Request(new URL(input, "http://localhost"), init),
modules.HttpApiApp.context,
)
@@ -33,6 +33,7 @@ import {
import { color, printHeader, printResults } from "./report"
import { coverageResult, parseOptions, routeKey, routeKeys, selectedScenarios } from "./routing"
import { runScenario } from "./runner"
import { disposeApps } from "./backend"
import { runtime } from "./runtime"
import { type Scenario } from "./types"
@@ -656,7 +657,8 @@ const scenarios: Scenario[] = [
.get("/api/provider/{providerID}", "v2.provider.get")
.at((ctx) => ({ path: route("/api/provider/{providerID}", { providerID: "missing" }), headers: ctx.headers() }))
.json(404, object, "status"),
http.protected.get("/api/permission/request", "v2.permission.request.list").json(200, locationData(array)),
http.protected.get("/api/permission/request", "v2.permission.request.list").json(200, array),
http.protected.get("/api/question/request", "v2.question.request.list").json(200, array),
http.protected
.get("/api/session/{sessionID}/permission/request", "v2.session.permission.list")
.seeded((ctx) => ctx.session({ title: "Permission list owner" }))
@@ -677,7 +679,30 @@ const scenarios: Scenario[] = [
body: { reply: "once" },
}))
.json(404, object, "status"),
http.protected.get("/api/permission/saved", "v2.permission.saved.list").json(200, data(array)),
http.protected
.post("/api/session/{sessionID}/question/request/{requestID}/reply", "v2.session.question.reply")
.seeded((ctx) => ctx.session({ title: "Question reply owner" }))
.at((ctx) => ({
path: route("/api/session/{sessionID}/question/request/{requestID}/reply", {
sessionID: ctx.state.id,
requestID: "que_httpapi_missing",
}),
headers: ctx.headers(),
body: { answers: [] },
}))
.json(404, object, "status"),
http.protected
.post("/api/session/{sessionID}/question/request/{requestID}/reject", "v2.session.question.reject")
.seeded((ctx) => ctx.session({ title: "Question reject owner" }))
.at((ctx) => ({
path: route("/api/session/{sessionID}/question/request/{requestID}/reject", {
sessionID: ctx.state.id,
requestID: "que_httpapi_missing",
}),
headers: ctx.headers(),
}))
.json(404, object, "status"),
http.protected.get("/api/permission/saved", "v2.permission.saved.list").json(200, array),
http.protected
.delete("/api/permission/saved/{id}", "v2.permission.saved.remove")
.at((ctx) => ({ path: route("/api/permission/saved/{id}", { id: "psv_httpapi_missing" }), headers: ctx.headers() }))
@@ -1432,7 +1457,7 @@ const llmScenarios = new Set([
])
const main = Effect.gen(function* () {
yield* Effect.addFinalizer(() => cleanupExercisePaths)
yield* Effect.addFinalizer(() => Effect.promise(() => disposeApps()).pipe(Effect.andThen(cleanupExercisePaths)))
const options = parseOptions(Bun.argv.slice(2))
const modules = yield* Effect.promise(() => runtime())
const effectRoutes = routeKeys(OpenApi.fromApi(modules.PublicApi))
@@ -7,11 +7,12 @@ import type { Config } from "../../../src/config/config"
import type { MessageV2 } from "../../../src/session/message-v2"
import { MessageID, PartID } from "../../../src/session/schema"
import { call, callAuthProbe } from "./backend"
import { call, callAuthProbe, disposeApps } from "./backend"
import { original } from "./environment"
import { runtime } from "./runtime"
import type { ActiveScenario, Options, ProjectOptions, Result, Scenario, ScenarioContext, SeededContext } from "./types"
import { ProviderV2 } from "@opencode-ai/core/provider"
import { ModelV2 } from "@opencode-ai/core/model"
export function runScenario(options: Options) {
return (scenario: Scenario) => {
@@ -153,7 +154,7 @@ function withContext<A, E>(
agent: "build",
model: {
providerID: ProviderV2.ID.opencode,
modelID: ProviderV2.ModelID.make("test"),
modelID: ModelV2.ID.make("test"),
},
}
const part: SessionV1.TextPart = {
@@ -259,6 +260,7 @@ const resetState = Effect.promise(async () => {
const modules = await runtime()
Flag.OPENCODE_SERVER_PASSWORD = original.OPENCODE_SERVER_PASSWORD
Flag.OPENCODE_SERVER_USERNAME = original.OPENCODE_SERVER_USERNAME
await disposeApps()
await modules.disposeAllInstances()
await modules.resetDatabase()
await Bun.sleep(25)
@@ -2,7 +2,7 @@ export type Runtime = {
PublicApi: (typeof import("../../../src/server/routes/instance/httpapi/public"))["PublicApi"]
HttpApiApp: (typeof import("../../../src/server/routes/instance/httpapi/server"))["HttpApiApp"]
AppLayer: (typeof import("../../../src/effect/app-runtime"))["AppLayer"]
memoMap: (typeof import("@opencode-ai/core/effect/memo-map"))["memoMap"]
memoMap: import("effect").Layer.MemoMap
InstanceRef: (typeof import("../../../src/effect/instance-ref"))["InstanceRef"]
InstanceStore: (typeof import("../../../src/project/instance-store"))["InstanceStore"]
Session: (typeof import("../../../src/session/session"))["Session"]
@@ -22,7 +22,7 @@ export function runtime() {
const publicApi = await import("../../../src/server/routes/instance/httpapi/public")
const httpApiServer = await import("../../../src/server/routes/instance/httpapi/server")
const appRuntime = await import("../../../src/effect/app-runtime")
const memoMap = await import("@opencode-ai/core/effect/memo-map")
const { Layer } = await import("effect")
const instanceRef = await import("../../../src/effect/instance-ref")
const instanceStore = await import("../../../src/project/instance-store")
const session = await import("../../../src/session/session")
@@ -36,7 +36,7 @@ export function runtime() {
PublicApi: publicApi.PublicApi,
HttpApiApp: httpApiServer.HttpApiApp,
AppLayer: appRuntime.AppLayer,
memoMap: memoMap.memoMap,
memoMap: Layer.makeMemoMapUnsafe(),
InstanceRef: instanceRef.InstanceRef,
InstanceStore: instanceStore.InstanceStore,
Session: session.Session,