feat(plugin): bound vcs adapter diffs

This commit is contained in:
Shoubhit Dash
2026-07-06 18:21:43 +05:30
parent 10a71bae4a
commit ceb5f3554e
4 changed files with 40 additions and 5 deletions
+5 -1
View File
@@ -10,6 +10,7 @@ import { AppProcess } from "./process"
import { VcsBackends } from "./vcs/backends"
import { VcsGit } from "./vcs/git"
import { VcsHg } from "./vcs/hg"
import { MAX_TOTAL_PATCH_BYTES, PATCH_CONTEXT_LINES } from "./vcs/patch"
export { FileStatus, Mode }
@@ -60,7 +61,10 @@ const layer = Layer.effect(
diff: Effect.fn("Vcs.diff")(function* (mode: Mode, options?: DiffOptions) {
const impl = yield* adapter()
if (!impl) return []
return yield* impl.diff(mode, options)
return yield* impl.diff(mode, {
context: options?.context ?? PATCH_CONTEXT_LINES,
maxOutputBytes: MAX_TOTAL_PATCH_BYTES,
})
}),
})
}),
+12
View File
@@ -81,10 +81,22 @@ function guard(type: string, make: () => Vcs.Adapter): Vcs.Adapter {
adapter.pipe(
Effect.flatMap((impl) => impl.diff(mode, options)),
sanitize(type, "diff", decodeDiff),
Effect.map((rows) => boundDiff(rows, options.maxOutputBytes)),
),
}
}
function boundDiff(rows: readonly FileDiff.Info[], maxOutputBytes: number) {
let total = 0
return rows.map((row) => {
if (row.patch === undefined) return row
const bytes = Buffer.byteLength(row.patch)
if (total + bytes > maxOutputBytes) return { ...row, patch: undefined }
total += bytes
return row
})
}
function sanitize<A>(type: string, operation: string, decode: (input: unknown) => Option.Option<readonly A[]>) {
return <E, R>(effect: Effect.Effect<readonly A[], E, R>) =>
effect.pipe(
+17
View File
@@ -53,6 +53,23 @@ describe("VcsBackends", () => {
}).pipe(Effect.scoped, provide),
)
it.live("passes normalized options and bounds plugin diffs", () =>
Effect.gen(function* () {
let received: Parameters<PluginVcs.Adapter["diff"]>[1] | undefined
yield* register(
backend({
diff: (_mode, options) => {
received = options
return Effect.succeed([{ ...diff[0], patch: "x".repeat(options.maxOutputBytes + 1) }])
},
}),
)
const vcs = yield* Vcs.Service
expect(yield* vcs.diff("working", { context: 3 })).toEqual([{ ...diff[0], patch: undefined }])
expect(received).toEqual({ context: 3, maxOutputBytes: 10_000_000 })
}).pipe(Effect.scoped, provide),
)
it.live("passes the location scope to the adapter factory", () =>
Effect.gen(function* () {
let scope: PluginVcs.AdapterScope | undefined
+6 -4
View File
@@ -15,12 +15,14 @@ export interface AdapterScope {
readonly store: string
}
export interface DiffOptions {
readonly context: number
readonly maxOutputBytes: number
}
export interface Adapter {
readonly status: () => Effect.Effect<readonly FileStatus[]>
readonly diff: (
mode: Mode,
options?: { readonly context?: number },
) => Effect.Effect<readonly FileDiff.Info[]>
readonly diff: (mode: Mode, options: DiffOptions) => Effect.Effect<readonly FileDiff.Info[]>
}
export interface Backend {