fix(vcs): accept explicit Git init provider

This commit is contained in:
Brendonovich
2026-09-29 06:28:15 +00:00
parent 81c967c4e1
commit cb7f6b7ba4
8 changed files with 46 additions and 7 deletions
@@ -63,5 +63,6 @@ for (const view of ["desktop", "mobile"] as const) {
await test.info().attach("review-after-git", { body: await panel.screenshot(), contentType: "image/png" })
expect(requests).toHaveLength(1)
expect(new URL(requests[0]!).searchParams.get("location[directory]")).toBe(directory)
expect(new URL(requests[0]!).searchParams.get("provider")).toBe("git")
})
}
+1 -1
View File
@@ -171,7 +171,7 @@ export function createSessionReview(input: {
if (!sessionID) return
setState("initializingGit", true)
void server.api.vcs
.init({ location: { directory } })
.init({ location: { directory }, provider: "git" })
.then(async () => {
data.project.invalidate()
data.session.invalidate(sessionID)
+4 -1
View File
@@ -2223,7 +2223,10 @@ export interface WorktreeApi<E = never> {
readonly refresh: WorktreeRefreshOperation<E>
}
export type VcsInitInput = { readonly location?: { readonly directory?: string | undefined } | undefined }
export type VcsInitInput = {
readonly location?: { readonly directory?: string | undefined } | undefined
readonly provider?: "git" | undefined
}
export type VcsInitOutput = void
export type VcsInitOperation<E = never> = (input?: VcsInitInput) => Effect.Effect<VcsInitOutput, E>
@@ -1454,7 +1454,9 @@ const adaptGroupWorktree = (raw: RawClient["server.worktree"]) => ({
const EndpointVcsInit = (raw: RawClient["server.vcs"]) => (input?: VcsInitInput) =>
preserveEffect<VcsInitOutput>()(
raw["vcs.init"]({ query: { location: input?.["location"] } }).pipe(Effect.mapError(mapClientError)),
raw["vcs.init"]({ query: { location: input?.["location"], provider: input?.["provider"] } }).pipe(
Effect.mapError(mapClientError),
),
)
const EndpointVcsGet = (raw: RawClient["server.vcs"]) => (input?: VcsGetInput) =>
@@ -2019,7 +2019,7 @@ export function make(options: ClientOptions) {
{
method: "POST",
path: `/api/vcs/init`,
query: { location: input?.["location"] },
query: { location: input?.["location"], provider: input?.["provider"] },
successStatus: 204,
declaredStatuses: [400, 401, 409, 503],
empty: true,
@@ -6250,7 +6250,14 @@ export type WorktreeRefreshInput = { readonly projectID: { readonly projectID: s
export type WorktreeRefreshOutput = void
export type VcsInitInput = {
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
readonly location?: {
readonly location?: { readonly directory?: string | undefined } | undefined
readonly provider?: "git" | undefined
}["location"]
readonly provider?: {
readonly location?: { readonly directory?: string | undefined } | undefined
readonly provider?: "git" | undefined
}["provider"]
}
export type VcsInitOutput = void
+8 -2
View File
@@ -7,6 +7,11 @@ import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/un
import { LocationQuery, locationQueryOpenApi } from "./location.js"
import { ConflictError, InvalidRequestError, ServiceUnavailableError } from "../errors.js"
const InitQuery = Schema.Struct({
...LocationQuery.fields,
provider: Schema.optional(Schema.Literal("git")),
})
const BranchesQuery = Schema.Struct({
...LocationQuery.fields,
search: Schema.optional(Schema.String),
@@ -23,7 +28,7 @@ const DiffQuery = Schema.Struct({
export const VcsGroup = HttpApiGroup.make("server.vcs")
.add(
HttpApiEndpoint.post("vcs.init", "/api/vcs/init", {
query: LocationQuery,
query: InitQuery,
success: HttpApiSchema.NoContent,
error: [ConflictError, InvalidRequestError, ServiceUnavailableError],
})
@@ -32,7 +37,8 @@ export const VcsGroup = HttpApiGroup.make("server.vcs")
OpenApi.annotations({
identifier: "vcs.init",
summary: "Initialize Git repository",
description: "Initialize Git in a markerless project's directory and refresh its location services.",
description:
"Initialize the selected repository type in a markerless project's directory and refresh its location services. Only git is supported; omitting provider defaults to git.",
}),
),
)
+20
View File
@@ -80,6 +80,26 @@ it.live(
15_000,
)
it.live(
"accepts an explicit Git provider and rejects unsupported providers without initializing",
() =>
Effect.gen(function* () {
const tmp = yield* Effect.acquireDisposable(Effect.promise(() => tmpdir("opencode-vcs-provider-")))
const server = yield* startServer(path.join(tmp.path, "config"))
const url = new URL("/api/vcs/init", server.base)
url.searchParams.set("location[directory]", tmp.path)
url.searchParams.set("provider", "hg")
const unsupported = yield* Effect.promise(() => fetch(url, { method: "POST", headers: server.headers }))
expect(unsupported.status).toBe(400)
expect(yield* Effect.promise(() => Bun.file(path.join(tmp.path, ".git", "HEAD")).exists())).toBe(false)
url.searchParams.set("provider", "git")
const initialized = yield* Effect.promise(() => fetch(url, { method: "POST", headers: server.headers }))
expect(initialized.status).toBe(204)
expect(yield* Effect.promise(() => Bun.file(path.join(tmp.path, ".git", "HEAD")).exists())).toBe(true)
}),
15_000,
)
it.live(
"serves lazy review bases, committed diffs, and unavailable-base errors",
() =>