diff --git a/packages/core/src/vcs/backends.ts b/packages/core/src/vcs/backends.ts index 80328a0efe..dde3585ff7 100644 --- a/packages/core/src/vcs/backends.ts +++ b/packages/core/src/vcs/backends.ts @@ -3,7 +3,7 @@ export * as VcsBackends from "./backends" import { Vcs } from "@opencode-ai/plugin/v2/effect" import { FileDiff } from "@opencode-ai/schema/file-diff" import { FileStatus } from "@opencode-ai/schema/vcs" -import { Context, Effect, Exit, Layer, Option, Schema } from "effect" +import { Cause, Context, Effect, Exit, Layer, Option, Schema } from "effect" import type { Scope } from "effect" import { ConfigVcs } from "../config/vcs" import { makeLocationNode } from "../effect/app-node" @@ -46,8 +46,12 @@ const layer = Layer.effect( message: `Vcs backend '${backend.type}' is already registered`, }) } - registry.set(backend.type, { backend }) - yield* Effect.addFinalizer(() => Effect.sync(() => registry.delete(backend.type))) + yield* Effect.uninterruptible( + Effect.gen(function* () { + registry.set(backend.type, { backend }) + yield* Effect.addFinalizer(() => Effect.sync(() => registry.delete(backend.type))) + }), + ) }), get: (type) => { const vcs = location.vcsBackend @@ -87,6 +91,7 @@ function sanitize(type: string, operation: string, decode: (input: unknown) = Effect.exit, Effect.flatMap((exit) => { if (Exit.isFailure(exit)) { + if (Cause.hasInterrupts(exit.cause)) return Effect.failCause(exit.cause) return Effect.logWarning("vcs backend failed", { type, operation, cause: exit.cause }).pipe( Effect.as([] as readonly A[]), ) diff --git a/packages/core/test/vcs-backends.test.ts b/packages/core/test/vcs-backends.test.ts index fd9294b28b..a0210ed307 100644 --- a/packages/core/test/vcs-backends.test.ts +++ b/packages/core/test/vcs-backends.test.ts @@ -1,5 +1,5 @@ import { describe, expect } from "bun:test" -import { Effect, Exit, Layer, Scope } from "effect" +import { Cause, Effect, Exit, Fiber, Layer, Scope } from "effect" import { Vcs as PluginVcs } from "@opencode-ai/plugin/v2/effect" import { LayerNode } from "@opencode-ai/core/effect/layer-node" import { Location } from "@opencode-ai/core/location" @@ -116,6 +116,18 @@ describe("VcsBackends", () => { }).pipe(Effect.scoped, provide), ) + it.live("preserves adapter interruption", () => + Effect.gen(function* () { + yield* register(backend({ status: () => Effect.never })) + const vcs = yield* Vcs.Service + const fiber = yield* Effect.forkChild(vcs.status()) + yield* Fiber.interrupt(fiber) + const exit = yield* Fiber.await(fiber) + expect(Exit.isFailure(exit)).toBe(true) + if (Exit.isFailure(exit)) expect(Cause.hasInterrupts(exit.cause)).toBe(true) + }).pipe(Effect.scoped, provide), + ) + it.live("drops rows that fail schema validation", () => Effect.gen(function* () { yield* register(