diff --git a/packages/client/src/effect/api/api.ts b/packages/client/src/effect/api/api.ts index b05cd55baf1..9bf0a785019 100644 --- a/packages/client/src/effect/api/api.ts +++ b/packages/client/src/effect/api/api.ts @@ -1502,18 +1502,25 @@ export interface ProjectCopyApi { export type Endpoint25_0Input = { readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined } -export type Endpoint25_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray } -export type VcsStatusOperation = (input?: Endpoint25_0Input) => Effect.Effect +export type Endpoint25_0Output = { readonly location: Location.Info; readonly data: Vcs.Info } +export type VcsGetOperation = (input?: Endpoint25_0Input) => Effect.Effect export type Endpoint25_1Input = { readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined +} +export type Endpoint25_1Output = { readonly location: Location.Info; readonly data: ReadonlyArray } +export type VcsStatusOperation = (input?: Endpoint25_1Input) => Effect.Effect + +export type Endpoint25_2Input = { + readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined readonly mode: Vcs.Mode readonly context?: number | undefined } -export type Endpoint25_1Output = { readonly location: Location.Info; readonly data: ReadonlyArray } -export type VcsDiffOperation = (input: Endpoint25_1Input) => Effect.Effect +export type Endpoint25_2Output = { readonly location: Location.Info; readonly data: ReadonlyArray } +export type VcsDiffOperation = (input: Endpoint25_2Input) => Effect.Effect export interface VcsApi { + readonly get: VcsGetOperation readonly status: VcsStatusOperation readonly diff: VcsDiffOperation } diff --git a/packages/client/src/effect/generated/client.ts b/packages/client/src/effect/generated/client.ts index 57f009d3e7e..5f975ee3b32 100644 --- a/packages/client/src/effect/generated/client.ts +++ b/packages/client/src/effect/generated/client.ts @@ -210,6 +210,8 @@ import type { Endpoint25_0Output, Endpoint25_1Input, Endpoint25_1Output, + Endpoint25_2Input, + Endpoint25_2Output, Endpoint26_0Output, Endpoint26_1Input, Endpoint26_1Output, @@ -1182,17 +1184,26 @@ const adaptGroup24 = (raw: RawClient["server.projectCopy"]) => ({ const Endpoint25_0 = (raw: RawClient["server.vcs"]) => (input?: Endpoint25_0Input) => preserveEffect()( + raw["vcs.get"]({ query: { location: input?.["location"] } }).pipe(Effect.mapError(mapClientError)), + ) + +const Endpoint25_1 = (raw: RawClient["server.vcs"]) => (input?: Endpoint25_1Input) => + preserveEffect()( raw["vcs.status"]({ query: { location: input?.["location"] } }).pipe(Effect.mapError(mapClientError)), ) -const Endpoint25_1 = (raw: RawClient["server.vcs"]) => (input: Endpoint25_1Input) => - preserveEffect()( +const Endpoint25_2 = (raw: RawClient["server.vcs"]) => (input: Endpoint25_2Input) => + preserveEffect()( raw["vcs.diff"]({ query: { location: input["location"], mode: input["mode"], context: input["context"] } }).pipe( Effect.mapError(mapClientError), ), ) -const adaptGroup25 = (raw: RawClient["server.vcs"]) => ({ status: Endpoint25_0(raw), diff: Endpoint25_1(raw) }) +const adaptGroup25 = (raw: RawClient["server.vcs"]) => ({ + get: Endpoint25_0(raw), + status: Endpoint25_1(raw), + diff: Endpoint25_2(raw), +}) const Endpoint26_0 = (raw: RawClient["server.debug"]) => () => preserveEffect()(raw["debug.location"]({}).pipe(Effect.mapError(mapClientError))) diff --git a/packages/client/src/promise/generated/client.ts b/packages/client/src/promise/generated/client.ts index 531cbd78de9..4e48ef6450c 100644 --- a/packages/client/src/promise/generated/client.ts +++ b/packages/client/src/promise/generated/client.ts @@ -202,6 +202,8 @@ import type { ProjectCopyRemoveOutput, ProjectCopyRefreshInput, ProjectCopyRefreshOutput, + VcsGetInput, + VcsGetOutput, VcsStatusInput, VcsStatusOutput, VcsDiffInput, @@ -1702,6 +1704,18 @@ export function make(options: ClientOptions) { ), }, vcs: { + get: (input?: VcsGetInput, requestOptions?: RequestOptions) => + request( + { + method: "GET", + path: `/api/vcs`, + query: { location: input?.["location"] }, + successStatus: 200, + declaredStatuses: [401, 400], + empty: false, + }, + requestOptions, + ), status: (input?: VcsStatusInput, requestOptions?: RequestOptions) => request( { diff --git a/packages/client/src/promise/generated/types.ts b/packages/client/src/promise/generated/types.ts index 766e845ffd1..87c8a3105bf 100644 --- a/packages/client/src/promise/generated/types.ts +++ b/packages/client/src/promise/generated/types.ts @@ -530,6 +530,8 @@ export type ReferenceGitSource = { export type ProjectCopyCopy = { directory: string } +export type VcsBranch = { current?: string; default?: string } + export type VcsFileStatus = { file: string additions: number @@ -1745,6 +1747,8 @@ export type SessionStatus2 = { export type ReferenceSource = ReferenceLocalSource | ReferenceGitSource +export type VcsInfo = { branch: VcsBranch } + export type PermissionRuleset = Array export type SessionInfo = { @@ -4902,6 +4906,17 @@ export type ProjectCopyRefreshInput = { export type ProjectCopyRefreshOutput = void +export type VcsGetInput = { + readonly location?: { + readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined + }["location"] +} + +export type VcsGetOutput = { + location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } } + data: VcsInfo +} + export type VcsStatusInput = { readonly location?: { readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined diff --git a/packages/client/test/promise.test.ts b/packages/client/test/promise.test.ts index b38b141cbc5..450ebec5c7f 100644 --- a/packages/client/test/promise.test.ts +++ b/packages/client/test/promise.test.ts @@ -44,7 +44,7 @@ test("exposes every standard HTTP API group", () => { expect(Object.keys(client.integration.command)).toEqual(["connect", "status", "cancel"]) expect(Object.keys(client.websearch)).toEqual(["providers", "query"]) expect(Object.keys(client.file)).toEqual(["read", "list", "find"]) - expect(Object.keys(client.vcs)).toEqual(["status", "diff"]) + expect(Object.keys(client.vcs)).toEqual(["get", "status", "diff"]) expect(Object.keys(client.pty)).toEqual(["list", "create", "get", "update", "remove"]) expect(Object.keys(client.shell)).toEqual(["list", "create", "get", "timeout", "output", "remove"]) expect(Object.keys(client.project)).toEqual(["list", "current", "directories"]) diff --git a/packages/core/src/vcs.ts b/packages/core/src/vcs.ts index 308520bba0c..643c4ae27ab 100644 --- a/packages/core/src/vcs.ts +++ b/packages/core/src/vcs.ts @@ -2,7 +2,7 @@ export * as Vcs from "./vcs" import { Context, Effect, Layer } from "effect" import { FileDiff } from "@opencode-ai/schema/file-diff" -import { FileStatus, Mode } from "@opencode-ai/schema/vcs" +import { FileStatus, Info, Mode } from "@opencode-ai/schema/vcs" import { makeLocationNode } from "@opencode-ai/util/effect/app-node" import { FSUtil } from "@opencode-ai/util/fs-util" import { Location } from "./location" @@ -10,13 +10,14 @@ import { AppProcess } from "@opencode-ai/util/process" import { VcsGit } from "./vcs/git" import { VcsHg } from "./vcs/hg" -export { FileStatus, Mode } +export { FileStatus, Info, Mode } export interface DiffOptions { readonly context?: number } export interface Interface { + readonly info: () => Effect.Effect readonly status: () => Effect.Effect readonly diff: (mode: Mode, options?: DiffOptions) => Effect.Effect } @@ -40,6 +41,10 @@ const layer = Layer.effect( const location = yield* Location.Service const impl = adapter(proc, fs, location) return Service.of({ + info: Effect.fn("Vcs.info")(function* () { + if (!impl) return { branch: {} } + return yield* impl.info() + }), status: Effect.fn("Vcs.status")(function* () { if (!impl) return [] return yield* impl.status() diff --git a/packages/core/src/vcs/git.ts b/packages/core/src/vcs/git.ts index 390348fc4f0..415bbf12873 100644 --- a/packages/core/src/vcs/git.ts +++ b/packages/core/src/vcs/git.ts @@ -3,7 +3,7 @@ export * as VcsGit from "./git" import { Effect } from "effect" import { ChildProcess } from "effect/unstable/process" import { FileDiff } from "@opencode-ai/schema/file-diff" -import { FileStatus, Mode } from "@opencode-ai/schema/vcs" +import { FileStatus, Info, Mode } from "@opencode-ai/schema/vcs" import { AppProcess } from "@opencode-ai/util/process" import type { DiffOptions, Interface } from "../vcs" import { chunksByFile, emptyPatch, MAX_PATCH_BYTES, MAX_TOTAL_PATCH_BYTES, PATCH_CONTEXT_LINES } from "./patch" @@ -20,6 +20,12 @@ export function make(proc: AppProcess.Interface, input: { directory: string; wor const ctx: Ctx = { git: makeGit(proc), directory: input.directory, worktree: input.worktree } return { + info: Effect.fn("VcsGit.info")(function* () { + const [current, root] = yield* Effect.all([ctx.git.branch(ctx.directory), ctx.git.defaultBranch(ctx.directory)], { + concurrency: 2, + }) + return { branch: { current, default: root?.name } } satisfies Info + }), status: Effect.fn("VcsGit.status")(function* () { const git = ctx.git const ref = (yield* git.hasHead(ctx.directory)) ? "HEAD" : undefined diff --git a/packages/core/src/vcs/hg.ts b/packages/core/src/vcs/hg.ts index 10ae0bcbfc8..dad49ac0531 100644 --- a/packages/core/src/vcs/hg.ts +++ b/packages/core/src/vcs/hg.ts @@ -4,7 +4,7 @@ import path from "path" import { Effect } from "effect" import { ChildProcess } from "effect/unstable/process" import { FileDiff } from "@opencode-ai/schema/file-diff" -import { FileStatus, Mode } from "@opencode-ai/schema/vcs" +import { FileStatus, Info, Mode } from "@opencode-ai/schema/vcs" import { FSUtil } from "@opencode-ai/util/fs-util" import { AppProcess } from "@opencode-ai/util/process" import type { DiffOptions, Interface } from "../vcs" @@ -73,6 +73,9 @@ export function make( }) return { + info: Effect.fn("VcsHg.info")(function* () { + return { branch: { current: yield* hg.branch(), default: "default" } } satisfies Info + }), status: Effect.fn("VcsHg.status")(function* () { const [items, batch] = yield* Effect.all( // Zero-context patches are enough to count changed lines. diff --git a/packages/core/test/vcs-hg.test.ts b/packages/core/test/vcs-hg.test.ts index f699eb64575..270b23f113a 100644 --- a/packages/core/test/vcs-hg.test.ts +++ b/packages/core/test/vcs-hg.test.ts @@ -160,6 +160,7 @@ describeHg("Vcs mercurial", () => { await commitAll(directory, "feature change") }) const diff = yield* vcs.diff("branch") + expect(yield* vcs.info()).toEqual({ branch: { current: "feature", default: "default" } }) expect(diff.map((item) => ({ file: item.file, status: item.status }))).toEqual([ { file: "file.txt", status: "modified" }, ]) diff --git a/packages/core/test/vcs.test.ts b/packages/core/test/vcs.test.ts index 822deff75bd..010aaf54412 100644 --- a/packages/core/test/vcs.test.ts +++ b/packages/core/test/vcs.test.ts @@ -53,6 +53,7 @@ describe("Vcs", () => { withTmp((directory) => Effect.gen(function* () { const vcs = yield* Vcs.Service + expect(yield* vcs.info()).toEqual({ branch: {} }) expect(yield* vcs.status()).toEqual([]) expect(yield* vcs.diff("working")).toEqual([]) expect(yield* vcs.diff("branch")).toEqual([]) @@ -163,6 +164,7 @@ describe("Vcs", () => { await commitAll(directory, "feature change") }) const diff = yield* vcs.diff("branch") + expect(yield* vcs.info()).toEqual({ branch: { current: "feature", default: "main" } }) expect(diff.map((item) => ({ file: item.file, status: item.status }))).toEqual([ { file: "file.txt", status: "modified" }, ]) diff --git a/packages/protocol/openapi.json b/packages/protocol/openapi.json index 011fa3d9282..66907577a98 100644 --- a/packages/protocol/openapi.json +++ b/packages/protocol/openapi.json @@ -851,6 +851,16 @@ } ] }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, "agent": { "anyOf": [ { @@ -11301,6 +11311,104 @@ } } }, + "/api/vcs": { + "get": { + "tags": [ + "vcs" + ], + "operationId": "v2.vcs.get", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "anyOf": [ + { + "type": "object", + "properties": { + "directory": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "workspace": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + { + "type": "null" + } + ] + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/Location.Info" + }, + "data": { + "$ref": "#/components/schemas/Vcs.Info" + } + }, + "required": [ + "location", + "data" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + } + }, + "description": "Get current and default branch information for the requested location.", + "summary": "VCS info" + } + }, "/api/vcs/status": { "get": { "tags": [ @@ -12032,11 +12140,15 @@ }, "directory": { "type": "string" + }, + "canonical": { + "type": "string" } }, "required": [ "id", - "directory" + "directory", + "canonical" ], "additionalProperties": false } @@ -12498,7 +12610,6 @@ "cost", "tokens", "time", - "title", "location" ], "additionalProperties": false @@ -13837,6 +13948,15 @@ }, "message": { "type": "string" + }, + "status": { + "type": "integer", + "allOf": [ + { + "minimum": 100, + "maximum": 599 + } + ] } }, "required": [ @@ -20765,7 +20885,7 @@ "id": { "type": "string" }, - "worktree": { + "canonical": { "type": "string" }, "vcs": { @@ -20792,7 +20912,7 @@ }, "required": [ "id", - "worktree", + "canonical", "time", "sandboxes" ], @@ -20806,11 +20926,15 @@ }, "directory": { "type": "string" + }, + "canonical": { + "type": "string" } }, "required": [ "id", - "directory" + "directory", + "canonical" ], "additionalProperties": false }, @@ -22445,7 +22569,6 @@ "slug", "projectID", "directory", - "title", "version", "time" ], @@ -29127,6 +29250,30 @@ ], "additionalProperties": false }, + "Vcs.Branch": { + "type": "object", + "properties": { + "current": { + "type": "string" + }, + "default": { + "type": "string" + } + }, + "additionalProperties": false + }, + "Vcs.Info": { + "type": "object", + "properties": { + "branch": { + "$ref": "#/components/schemas/Vcs.Branch" + } + }, + "required": [ + "branch" + ], + "additionalProperties": false + }, "Vcs.FileStatus": { "type": "object", "properties": { diff --git a/packages/protocol/src/groups/vcs.ts b/packages/protocol/src/groups/vcs.ts index 5c2b85ceb2a..b4b3c3d10a1 100644 --- a/packages/protocol/src/groups/vcs.ts +++ b/packages/protocol/src/groups/vcs.ts @@ -13,6 +13,20 @@ const DiffQuery = Schema.Struct({ }) export const VcsGroup = HttpApiGroup.make("server.vcs") + .add( + HttpApiEndpoint.get("vcs.get", "/api/vcs", { + query: LocationQuery, + success: Location.response(Vcs.Info), + }) + .annotateMerge(locationQueryOpenApi) + .annotateMerge( + OpenApi.annotations({ + identifier: "v2.vcs.get", + summary: "VCS info", + description: "Get current and default branch information for the requested location.", + }), + ), + ) .add( HttpApiEndpoint.get("vcs.status", "/api/vcs/status", { query: LocationQuery, diff --git a/packages/schema/src/vcs.ts b/packages/schema/src/vcs.ts index 08127d8b514..db753ffad89 100644 --- a/packages/schema/src/vcs.ts +++ b/packages/schema/src/vcs.ts @@ -1,7 +1,18 @@ export * as Vcs from "./vcs.js" import { Schema } from "effect" -import { NonNegativeInt } from "./schema.js" +import { NonNegativeInt, optional } from "./schema.js" + +export const Branch = Schema.Struct({ + current: optional(Schema.String), + default: optional(Schema.String), +}).annotate({ identifier: "Vcs.Branch" }) +export interface Branch extends Schema.Schema.Type {} + +export const Info = Schema.Struct({ + branch: Branch, +}).annotate({ identifier: "Vcs.Info" }) +export interface Info extends Schema.Schema.Type {} export const Mode = Schema.Literals(["working", "branch"]).annotate({ identifier: "Vcs.Mode" }) export type Mode = typeof Mode.Type diff --git a/packages/schema/test/contract-hygiene.test.ts b/packages/schema/test/contract-hygiene.test.ts index 74df1ac6270..7ab52ba5492 100644 --- a/packages/schema/test/contract-hygiene.test.ts +++ b/packages/schema/test/contract-hygiene.test.ts @@ -16,6 +16,7 @@ import { FileDiff } from "../src/file-diff.js" import { Money } from "../src/money.js" import { Skill } from "../src/skill.js" import { Shell } from "../src/shell.js" +import { Vcs } from "../src/vcs.js" import { PersistedRevert } from "../src/session-revert.js" import { AbsolutePath, optional } from "../src/schema.js" @@ -134,6 +135,10 @@ describe("contract hygiene", () => { expect(Pty.ID.create()).toStartWith("pty_") }) + test("VCS info omits unavailable branch names", () => { + expect(Schema.encodeSync(Vcs.Info)({ branch: { current: undefined, default: undefined } })).toEqual({ branch: {} }) + }) + test("reusable public identifiers are stable and unique", () => { const identifiers = [ Agent.Color, @@ -166,6 +171,8 @@ describe("contract hygiene", () => { SessionPending.SyntheticData, SessionPending.User, SessionPending.Synthetic, + Vcs.Branch, + Vcs.Info, ].map((schema) => schema.ast.annotations?.identifier) expect(identifiers.every((identifier) => typeof identifier === "string")).toBe(true) diff --git a/packages/server/src/handlers/vcs.ts b/packages/server/src/handlers/vcs.ts index 325eed474a1..70a9aa6b444 100644 --- a/packages/server/src/handlers/vcs.ts +++ b/packages/server/src/handlers/vcs.ts @@ -7,6 +7,14 @@ import { response } from "../location" export const VcsHandler = HttpApiBuilder.group(Api, "server.vcs", (handlers) => Effect.gen(function* () { return handlers + .handle("vcs.get", () => + response( + Effect.gen(function* () { + const vcs = yield* Vcs.Service + return yield* vcs.info() + }), + ), + ) .handle("vcs.status", () => response( Effect.gen(function* () { diff --git a/packages/www/openapi.json b/packages/www/openapi.json index 011fa3d9282..66907577a98 100644 --- a/packages/www/openapi.json +++ b/packages/www/openapi.json @@ -851,6 +851,16 @@ } ] }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, "agent": { "anyOf": [ { @@ -11301,6 +11311,104 @@ } } }, + "/api/vcs": { + "get": { + "tags": [ + "vcs" + ], + "operationId": "v2.vcs.get", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "anyOf": [ + { + "type": "object", + "properties": { + "directory": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "workspace": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + { + "type": "null" + } + ] + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/Location.Info" + }, + "data": { + "$ref": "#/components/schemas/Vcs.Info" + } + }, + "required": [ + "location", + "data" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + } + }, + "description": "Get current and default branch information for the requested location.", + "summary": "VCS info" + } + }, "/api/vcs/status": { "get": { "tags": [ @@ -12032,11 +12140,15 @@ }, "directory": { "type": "string" + }, + "canonical": { + "type": "string" } }, "required": [ "id", - "directory" + "directory", + "canonical" ], "additionalProperties": false } @@ -12498,7 +12610,6 @@ "cost", "tokens", "time", - "title", "location" ], "additionalProperties": false @@ -13837,6 +13948,15 @@ }, "message": { "type": "string" + }, + "status": { + "type": "integer", + "allOf": [ + { + "minimum": 100, + "maximum": 599 + } + ] } }, "required": [ @@ -20765,7 +20885,7 @@ "id": { "type": "string" }, - "worktree": { + "canonical": { "type": "string" }, "vcs": { @@ -20792,7 +20912,7 @@ }, "required": [ "id", - "worktree", + "canonical", "time", "sandboxes" ], @@ -20806,11 +20926,15 @@ }, "directory": { "type": "string" + }, + "canonical": { + "type": "string" } }, "required": [ "id", - "directory" + "directory", + "canonical" ], "additionalProperties": false }, @@ -22445,7 +22569,6 @@ "slug", "projectID", "directory", - "title", "version", "time" ], @@ -29127,6 +29250,30 @@ ], "additionalProperties": false }, + "Vcs.Branch": { + "type": "object", + "properties": { + "current": { + "type": "string" + }, + "default": { + "type": "string" + } + }, + "additionalProperties": false + }, + "Vcs.Info": { + "type": "object", + "properties": { + "branch": { + "$ref": "#/components/schemas/Vcs.Branch" + } + }, + "required": [ + "branch" + ], + "additionalProperties": false + }, "Vcs.FileStatus": { "type": "object", "properties": { diff --git a/packages/www/public/openapi.json b/packages/www/public/openapi.json index 011fa3d9282..66907577a98 100644 --- a/packages/www/public/openapi.json +++ b/packages/www/public/openapi.json @@ -851,6 +851,16 @@ } ] }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, "agent": { "anyOf": [ { @@ -11301,6 +11311,104 @@ } } }, + "/api/vcs": { + "get": { + "tags": [ + "vcs" + ], + "operationId": "v2.vcs.get", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "anyOf": [ + { + "type": "object", + "properties": { + "directory": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "workspace": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + { + "type": "null" + } + ] + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/Location.Info" + }, + "data": { + "$ref": "#/components/schemas/Vcs.Info" + } + }, + "required": [ + "location", + "data" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + } + }, + "description": "Get current and default branch information for the requested location.", + "summary": "VCS info" + } + }, "/api/vcs/status": { "get": { "tags": [ @@ -12032,11 +12140,15 @@ }, "directory": { "type": "string" + }, + "canonical": { + "type": "string" } }, "required": [ "id", - "directory" + "directory", + "canonical" ], "additionalProperties": false } @@ -12498,7 +12610,6 @@ "cost", "tokens", "time", - "title", "location" ], "additionalProperties": false @@ -13837,6 +13948,15 @@ }, "message": { "type": "string" + }, + "status": { + "type": "integer", + "allOf": [ + { + "minimum": 100, + "maximum": 599 + } + ] } }, "required": [ @@ -20765,7 +20885,7 @@ "id": { "type": "string" }, - "worktree": { + "canonical": { "type": "string" }, "vcs": { @@ -20792,7 +20912,7 @@ }, "required": [ "id", - "worktree", + "canonical", "time", "sandboxes" ], @@ -20806,11 +20926,15 @@ }, "directory": { "type": "string" + }, + "canonical": { + "type": "string" } }, "required": [ "id", - "directory" + "directory", + "canonical" ], "additionalProperties": false }, @@ -22445,7 +22569,6 @@ "slug", "projectID", "directory", - "title", "version", "time" ], @@ -29127,6 +29250,30 @@ ], "additionalProperties": false }, + "Vcs.Branch": { + "type": "object", + "properties": { + "current": { + "type": "string" + }, + "default": { + "type": "string" + } + }, + "additionalProperties": false + }, + "Vcs.Info": { + "type": "object", + "properties": { + "branch": { + "$ref": "#/components/schemas/Vcs.Branch" + } + }, + "required": [ + "branch" + ], + "additionalProperties": false + }, "Vcs.FileStatus": { "type": "object", "properties": {