diff --git a/packages/opencode/test/kilocode/server/httpapi-exercise-ready.ts b/packages/opencode/test/kilocode/server/httpapi-exercise-ready.ts new file mode 100644 index 000000000000..a4508bd32d1b --- /dev/null +++ b/packages/opencode/test/kilocode/server/httpapi-exercise-ready.ts @@ -0,0 +1,25 @@ +import { Effect } from "effect" +import { AgentV2 } from "@opencode-ai/core/agent" +import { isRecord } from "../../server/httpapi-exercise/assertions" +import { request } from "../../server/httpapi-exercise/backend" +import { pollWithTimeout } from "../../lib/effect" +import type { ScenarioContext } from "../../server/httpapi-exercise/types" + +export function sessionAfterDefaultAgent(ctx: ScenarioContext, title: string) { + return Effect.gen(function* () { + const session = yield* ctx.session({ title }) + // GET /api/agent and POST /permission share this directory today; a workspace/worktree + // session would boot a different AgentV2 and this wait would not cover it. + yield* pollWithTimeout( + request("GET", { path: "/api/agent", headers: ctx.headers() }).pipe( + Effect.map((result) => { + const body = result.body + if (!isRecord(body) || !Array.isArray(body.data)) return undefined + return body.data.some((item) => isRecord(item) && item.id === AgentV2.defaultID) ? (true as const) : undefined + }), + ), + "default agent never loaded before permission create", + ) + return session + }).pipe(Effect.orDie) +} diff --git a/packages/opencode/test/server/httpapi-exercise/backend.ts b/packages/opencode/test/server/httpapi-exercise/backend.ts index 181fbd261f0f..d484b9727a3b 100644 --- a/packages/opencode/test/server/httpapi-exercise/backend.ts +++ b/packages/opencode/test/server/httpapi-exercise/backend.ts @@ -3,6 +3,7 @@ import { HttpRouter } from "effect/unstable/http" import { parse } from "./assertions" import { runtime, type Runtime } from "./runtime" import type { ActiveScenario, BackendApp, CallResult, CaptureMode, SeededContext } from "./types" +import type { Method, RequestSpec } from "./types" // kilocode_change type CallOptions = { auth?: { @@ -17,6 +18,23 @@ export function call(scenario: ActiveScenario, ctx: SeededContext, opti ) } +// kilocode_change start +export function request(method: Method, spec: RequestSpec) { + return Effect.promise(async () => + capture( + await app(await runtime(), {}).request( + new Request(new URL(spec.path, "http://localhost"), { + method, + headers: spec.body === undefined ? spec.headers : { "content-type": "application/json", ...spec.headers }, + body: spec.body === undefined ? undefined : JSON.stringify(spec.body), + }), + ), + "full", + ), + ) +} +// kilocode_change end + export function callAuthProbe(scenario: ActiveScenario, credentials: "missing" | "valid" = "missing") { return Effect.promise(async () => { const controller = new AbortController() diff --git a/packages/opencode/test/server/httpapi-exercise/index.ts b/packages/opencode/test/server/httpapi-exercise/index.ts index a86c13e090dc..cb1cb26453c2 100644 --- a/packages/opencode/test/server/httpapi-exercise/index.ts +++ b/packages/opencode/test/server/httpapi-exercise/index.ts @@ -37,6 +37,7 @@ import { disposeApps } from "./backend" import { publicApi, runtime } from "./runtime" // kilocode_change import { type Scenario, type Result } from "./types" import { kiloScenarios } from "../../kilocode/server/httpapi-exercise-scenarios" // kilocode_change +import { sessionAfterDefaultAgent } from "../../kilocode/server/httpapi-exercise-ready" // kilocode_change function cursor(input: Record) { return Buffer.from(JSON.stringify(input)).toString("base64url") @@ -872,7 +873,7 @@ const scenarios: Scenario[] = [ }), http.protected .post("/api/session/{sessionID}/permission", "v2.session.permission.create") - .seeded((ctx) => ctx.session({ title: "Permission create owner" })) + .seeded((ctx) => sessionAfterDefaultAgent(ctx, "Permission create owner")) // kilocode_change .at((ctx) => ({ path: route("/api/session/{sessionID}/permission", { sessionID: ctx.state.id }), headers: ctx.headers(), @@ -885,7 +886,7 @@ const scenarios: Scenario[] = [ object(body) object(body.data) check(typeof body.data.id === "string", "permission create should return an ID") - check(body.data.effect === "ask", "permission create should create a pending request") + check(body.data.effect === "ask", `permission create should create a pending request, got ${JSON.stringify(body.data.effect)}`) // kilocode_change }), http.protected .get("/api/session/{sessionID}/permission", "v2.session.permission.list")