chore(client): regenerate PTY API

This commit is contained in:
Brendan Allan 2026-07-23 12:05:05 +08:00
commit 704e9ff3fb
No known key found for this signature in database
GPG key ID: 41E835AEA046A32E
5 changed files with 185 additions and 61 deletions

View file

@ -820,55 +820,71 @@ export interface EventApi<E = never> {
readonly subscribe: EventSubscribeOperation<E>
}
type Endpoint20_0Request = Parameters<RawClient["server.pty"]["pty.list"]>[0]
type Endpoint20_0Request = Parameters<RawClient["server.pty"]["pty.shells"]>[0]
export type Endpoint20_0Input = { readonly location?: Endpoint20_0Request["query"]["location"] }
export type Endpoint20_0Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.list"]>>
export type PtyListOperation<E = never> = (input?: Endpoint20_0Input) => Effect.Effect<Endpoint20_0Output, E>
export type Endpoint20_0Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.shells"]>>
export type PtyShellsOperation<E = never> = (input?: Endpoint20_0Input) => Effect.Effect<Endpoint20_0Output, E>
type Endpoint20_1Request = Parameters<RawClient["server.pty"]["pty.create"]>[0]
export type Endpoint20_1Input = {
readonly location?: Endpoint20_1Request["query"]["location"]
readonly command?: Endpoint20_1Request["payload"]["command"]
readonly args?: Endpoint20_1Request["payload"]["args"]
readonly cwd?: Endpoint20_1Request["payload"]["cwd"]
readonly title?: Endpoint20_1Request["payload"]["title"]
readonly env?: Endpoint20_1Request["payload"]["env"]
}
export type Endpoint20_1Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.create"]>>
export type PtyCreateOperation<E = never> = (input?: Endpoint20_1Input) => Effect.Effect<Endpoint20_1Output, E>
type Endpoint20_1Request = Parameters<RawClient["server.pty"]["pty.list"]>[0]
export type Endpoint20_1Input = { readonly location?: Endpoint20_1Request["query"]["location"] }
export type Endpoint20_1Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.list"]>>
export type PtyListOperation<E = never> = (input?: Endpoint20_1Input) => Effect.Effect<Endpoint20_1Output, E>
type Endpoint20_2Request = Parameters<RawClient["server.pty"]["pty.get"]>[0]
type Endpoint20_2Request = Parameters<RawClient["server.pty"]["pty.create"]>[0]
export type Endpoint20_2Input = {
readonly ptyID: Endpoint20_2Request["params"]["ptyID"]
readonly location?: Endpoint20_2Request["query"]["location"]
readonly command?: Endpoint20_2Request["payload"]["command"]
readonly args?: Endpoint20_2Request["payload"]["args"]
readonly cwd?: Endpoint20_2Request["payload"]["cwd"]
readonly title?: Endpoint20_2Request["payload"]["title"]
readonly env?: Endpoint20_2Request["payload"]["env"]
}
export type Endpoint20_2Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.get"]>>
export type PtyGetOperation<E = never> = (input: Endpoint20_2Input) => Effect.Effect<Endpoint20_2Output, E>
export type Endpoint20_2Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.create"]>>
export type PtyCreateOperation<E = never> = (input?: Endpoint20_2Input) => Effect.Effect<Endpoint20_2Output, E>
type Endpoint20_3Request = Parameters<RawClient["server.pty"]["pty.update"]>[0]
type Endpoint20_3Request = Parameters<RawClient["server.pty"]["pty.get"]>[0]
export type Endpoint20_3Input = {
readonly ptyID: Endpoint20_3Request["params"]["ptyID"]
readonly location?: Endpoint20_3Request["query"]["location"]
readonly title?: Endpoint20_3Request["payload"]["title"]
readonly size?: Endpoint20_3Request["payload"]["size"]
}
export type Endpoint20_3Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.update"]>>
export type PtyUpdateOperation<E = never> = (input: Endpoint20_3Input) => Effect.Effect<Endpoint20_3Output, E>
export type Endpoint20_3Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.get"]>>
export type PtyGetOperation<E = never> = (input: Endpoint20_3Input) => Effect.Effect<Endpoint20_3Output, E>
type Endpoint20_4Request = Parameters<RawClient["server.pty"]["pty.remove"]>[0]
type Endpoint20_4Request = Parameters<RawClient["server.pty"]["pty.update"]>[0]
export type Endpoint20_4Input = {
readonly ptyID: Endpoint20_4Request["params"]["ptyID"]
readonly location?: Endpoint20_4Request["query"]["location"]
readonly title?: Endpoint20_4Request["payload"]["title"]
readonly size?: Endpoint20_4Request["payload"]["size"]
}
export type Endpoint20_4Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.remove"]>>
export type PtyRemoveOperation<E = never> = (input: Endpoint20_4Input) => Effect.Effect<Endpoint20_4Output, E>
export type Endpoint20_4Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.update"]>>
export type PtyUpdateOperation<E = never> = (input: Endpoint20_4Input) => Effect.Effect<Endpoint20_4Output, E>
type Endpoint20_5Request = Parameters<RawClient["server.pty"]["pty.remove"]>[0]
export type Endpoint20_5Input = {
readonly ptyID: Endpoint20_5Request["params"]["ptyID"]
readonly location?: Endpoint20_5Request["query"]["location"]
}
export type Endpoint20_5Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.remove"]>>
export type PtyRemoveOperation<E = never> = (input: Endpoint20_5Input) => Effect.Effect<Endpoint20_5Output, E>
type Endpoint20_6Request = Parameters<RawClient["server.pty"]["pty.connectToken"]>[0]
export type Endpoint20_6Input = {
readonly ptyID: Endpoint20_6Request["params"]["ptyID"]
readonly location?: Endpoint20_6Request["query"]["location"]
readonly "x-opencode-ticket"?: Endpoint20_6Request["headers"]["x-opencode-ticket"]
}
export type Endpoint20_6Output = EffectValue<ReturnType<RawClient["server.pty"]["pty.connectToken"]>>
export type PtyConnectTokenOperation<E = never> = (input: Endpoint20_6Input) => Effect.Effect<Endpoint20_6Output, E>
export interface PtyApi<E = never> {
readonly shells: PtyShellsOperation<E>
readonly list: PtyListOperation<E>
readonly create: PtyCreateOperation<E>
readonly get: PtyGetOperation<E>
readonly update: PtyUpdateOperation<E>
readonly remove: PtyRemoveOperation<E>
readonly connectToken: PtyConnectTokenOperation<E>
}
type Endpoint21_0Request = Parameters<RawClient["server.shell"]["shell.list"]>[0]

View file

@ -977,21 +977,26 @@ const Endpoint19_0 = (raw: RawClient["server.event"]) => () =>
const adaptGroup19 = (raw: RawClient["server.event"]) => ({ subscribe: Endpoint19_0(raw) })
type Endpoint20_0Request = Parameters<RawClient["server.pty"]["pty.list"]>[0]
type Endpoint20_0Request = Parameters<RawClient["server.pty"]["pty.shells"]>[0]
type Endpoint20_0Input = { readonly location?: Endpoint20_0Request["query"]["location"] }
const Endpoint20_0 = (raw: RawClient["server.pty"]) => (input?: Endpoint20_0Input) =>
raw["pty.shells"]({ query: { location: input?.["location"] } }).pipe(Effect.mapError(mapClientError))
type Endpoint20_1Request = Parameters<RawClient["server.pty"]["pty.list"]>[0]
type Endpoint20_1Input = { readonly location?: Endpoint20_1Request["query"]["location"] }
const Endpoint20_1 = (raw: RawClient["server.pty"]) => (input?: Endpoint20_1Input) =>
raw["pty.list"]({ query: { location: input?.["location"] } }).pipe(Effect.mapError(mapClientError))
type Endpoint20_1Request = Parameters<RawClient["server.pty"]["pty.create"]>[0]
type Endpoint20_1Input = {
readonly location?: Endpoint20_1Request["query"]["location"]
readonly command?: Endpoint20_1Request["payload"]["command"]
readonly args?: Endpoint20_1Request["payload"]["args"]
readonly cwd?: Endpoint20_1Request["payload"]["cwd"]
readonly title?: Endpoint20_1Request["payload"]["title"]
readonly env?: Endpoint20_1Request["payload"]["env"]
type Endpoint20_2Request = Parameters<RawClient["server.pty"]["pty.create"]>[0]
type Endpoint20_2Input = {
readonly location?: Endpoint20_2Request["query"]["location"]
readonly command?: Endpoint20_2Request["payload"]["command"]
readonly args?: Endpoint20_2Request["payload"]["args"]
readonly cwd?: Endpoint20_2Request["payload"]["cwd"]
readonly title?: Endpoint20_2Request["payload"]["title"]
readonly env?: Endpoint20_2Request["payload"]["env"]
}
const Endpoint20_1 = (raw: RawClient["server.pty"]) => (input?: Endpoint20_1Input) =>
const Endpoint20_2 = (raw: RawClient["server.pty"]) => (input?: Endpoint20_2Input) =>
raw["pty.create"]({
query: { location: input?.["location"] },
payload: {
@ -1003,46 +1008,61 @@ const Endpoint20_1 = (raw: RawClient["server.pty"]) => (input?: Endpoint20_1Inpu
},
}).pipe(Effect.mapError(mapClientError))
type Endpoint20_2Request = Parameters<RawClient["server.pty"]["pty.get"]>[0]
type Endpoint20_2Input = {
readonly ptyID: Endpoint20_2Request["params"]["ptyID"]
readonly location?: Endpoint20_2Request["query"]["location"]
type Endpoint20_3Request = Parameters<RawClient["server.pty"]["pty.get"]>[0]
type Endpoint20_3Input = {
readonly ptyID: Endpoint20_3Request["params"]["ptyID"]
readonly location?: Endpoint20_3Request["query"]["location"]
}
const Endpoint20_2 = (raw: RawClient["server.pty"]) => (input: Endpoint20_2Input) =>
const Endpoint20_3 = (raw: RawClient["server.pty"]) => (input: Endpoint20_3Input) =>
raw["pty.get"]({ params: { ptyID: input["ptyID"] }, query: { location: input["location"] } }).pipe(
Effect.mapError(mapClientError),
)
type Endpoint20_3Request = Parameters<RawClient["server.pty"]["pty.update"]>[0]
type Endpoint20_3Input = {
readonly ptyID: Endpoint20_3Request["params"]["ptyID"]
readonly location?: Endpoint20_3Request["query"]["location"]
readonly title?: Endpoint20_3Request["payload"]["title"]
readonly size?: Endpoint20_3Request["payload"]["size"]
type Endpoint20_4Request = Parameters<RawClient["server.pty"]["pty.update"]>[0]
type Endpoint20_4Input = {
readonly ptyID: Endpoint20_4Request["params"]["ptyID"]
readonly location?: Endpoint20_4Request["query"]["location"]
readonly title?: Endpoint20_4Request["payload"]["title"]
readonly size?: Endpoint20_4Request["payload"]["size"]
}
const Endpoint20_3 = (raw: RawClient["server.pty"]) => (input: Endpoint20_3Input) =>
const Endpoint20_4 = (raw: RawClient["server.pty"]) => (input: Endpoint20_4Input) =>
raw["pty.update"]({
params: { ptyID: input["ptyID"] },
query: { location: input["location"] },
payload: { title: input["title"], size: input["size"] },
}).pipe(Effect.mapError(mapClientError))
type Endpoint20_4Request = Parameters<RawClient["server.pty"]["pty.remove"]>[0]
type Endpoint20_4Input = {
readonly ptyID: Endpoint20_4Request["params"]["ptyID"]
readonly location?: Endpoint20_4Request["query"]["location"]
type Endpoint20_5Request = Parameters<RawClient["server.pty"]["pty.remove"]>[0]
type Endpoint20_5Input = {
readonly ptyID: Endpoint20_5Request["params"]["ptyID"]
readonly location?: Endpoint20_5Request["query"]["location"]
}
const Endpoint20_4 = (raw: RawClient["server.pty"]) => (input: Endpoint20_4Input) =>
const Endpoint20_5 = (raw: RawClient["server.pty"]) => (input: Endpoint20_5Input) =>
raw["pty.remove"]({ params: { ptyID: input["ptyID"] }, query: { location: input["location"] } }).pipe(
Effect.mapError(mapClientError),
)
type Endpoint20_6Request = Parameters<RawClient["server.pty"]["pty.connectToken"]>[0]
type Endpoint20_6Input = {
readonly ptyID: Endpoint20_6Request["params"]["ptyID"]
readonly location?: Endpoint20_6Request["query"]["location"]
readonly "x-opencode-ticket"?: Endpoint20_6Request["headers"]["x-opencode-ticket"]
}
const Endpoint20_6 = (raw: RawClient["server.pty"]) => (input: Endpoint20_6Input) =>
raw["pty.connectToken"]({
params: { ptyID: input["ptyID"] },
query: { location: input["location"] },
headers: { "x-opencode-ticket": input["x-opencode-ticket"] },
}).pipe(Effect.mapError(mapClientError))
const adaptGroup20 = (raw: RawClient["server.pty"]) => ({
list: Endpoint20_0(raw),
create: Endpoint20_1(raw),
get: Endpoint20_2(raw),
update: Endpoint20_3(raw),
remove: Endpoint20_4(raw),
shells: Endpoint20_0(raw),
list: Endpoint20_1(raw),
create: Endpoint20_2(raw),
get: Endpoint20_3(raw),
update: Endpoint20_4(raw),
remove: Endpoint20_5(raw),
connectToken: Endpoint20_6(raw),
})
type Endpoint21_0Request = Parameters<RawClient["server.shell"]["shell.list"]>[0]

View file

@ -162,6 +162,8 @@ import type {
SkillListInput,
SkillListOutput,
EventSubscribeOutput,
PtyShellsInput,
PtyShellsOutput,
PtyListInput,
PtyListOutput,
PtyCreateInput,
@ -172,6 +174,8 @@ import type {
PtyUpdateOutput,
PtyRemoveInput,
PtyRemoveOutput,
PtyConnectTokenInput,
PtyConnectTokenOutput,
ShellListInput,
ShellListOutput,
ShellCreateInput,
@ -1430,6 +1434,18 @@ export function make(options: ClientOptions) {
),
},
pty: {
shells: (input?: PtyShellsInput, requestOptions?: RequestOptions) =>
request<PtyShellsOutput>(
{
method: "GET",
path: `/api/pty/shells`,
query: { location: input?.["location"] },
successStatus: 200,
declaredStatuses: [401, 400],
empty: false,
},
requestOptions,
),
list: (input?: PtyListInput, requestOptions?: RequestOptions) =>
request<PtyListOutput>(
{
@ -1498,6 +1514,19 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
connectToken: (input: PtyConnectTokenInput, requestOptions?: RequestOptions) =>
request<PtyConnectTokenOutput>(
{
method: "POST",
path: `/api/pty/${encodeURIComponent(input.ptyID)}/connect-token`,
query: { location: input["location"] },
headers: { "x-opencode-ticket": input["x-opencode-ticket"] },
successStatus: 200,
declaredStatuses: [403, 404, 401, 400],
empty: false,
},
requestOptions,
),
},
shell: {
list: (input?: ShellListInput, requestOptions?: RequestOptions) =>

View file

@ -501,6 +501,10 @@ export type QuestionTool = { messageID: string; callID: string }
export type QuestionAnswer = Array<string>
export type PtyShell = { path: string; name: string; acceptable: boolean }
export type PtyTicketConnectToken = { ticket: string; expires_in: number }
export type ShellInfo1 = {
id: string
status: "running" | "exited" | "timeout" | "killed"
@ -2530,6 +2534,10 @@ export type PtyNotFoundError = { readonly _tag: "PtyNotFoundError"; readonly pty
export const isPtyNotFoundError = (value: unknown): value is PtyNotFoundError =>
typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "PtyNotFoundError"
export type ForbiddenError = { readonly _tag: "ForbiddenError"; readonly message: string }
export const isForbiddenError = (value: unknown): value is ForbiddenError =>
typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ForbiddenError"
export type ShellNotFoundError = { readonly _tag: "ShellNotFoundError"; readonly id: string; readonly message: string }
export const isShellNotFoundError = (value: unknown): value is ShellNotFoundError =>
typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ShellNotFoundError"
@ -4649,6 +4657,17 @@ export type SkillListOutput = {
export type EventSubscribeOutput = V2Event
export type PtyShellsInput = {
readonly location?: {
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
}["location"]
}
export type PtyShellsOutput = {
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
data: Array<PtyShell>
}
export type PtyListInput = {
readonly location?: {
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
@ -4744,6 +4763,19 @@ export type PtyRemoveInput = {
export type PtyRemoveOutput = void
export type PtyConnectTokenInput = {
readonly ptyID: { readonly ptyID: string }["ptyID"]
readonly location?: {
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
}["location"]
readonly "x-opencode-ticket"?: { readonly "x-opencode-ticket"?: string | undefined }["x-opencode-ticket"]
}
export type PtyConnectTokenOutput = {
location: { directory: string; workspaceID?: string; project: { id: string; directory: string } }
data: PtyTicketConnectToken
}
export type ShellListInput = {
readonly location?: {
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined

View file

@ -44,11 +44,38 @@ test("exposes every standard HTTP API group", () => {
expect(Object.keys(client.integration.command)).toEqual(["connect", "status", "cancel"])
expect(Object.keys(client.file)).toEqual(["read", "list", "find"])
expect(Object.keys(client.vcs)).toEqual(["status", "diff"])
expect(Object.keys(client.pty)).toEqual(["list", "create", "get", "update", "remove"])
expect(Object.keys(client.pty)).toEqual(["shells", "list", "create", "get", "update", "remove", "connectToken"])
expect(Object.keys(client.shell)).toEqual(["list", "create", "get", "timeout", "output", "remove"])
expect(Object.keys(client.project)).toEqual(["list", "current", "directories"])
})
test("PTY connect token sends the required browser header", async () => {
let request: Request | undefined
const client = OpenCode.make({
baseUrl: "http://localhost:3000",
fetch: async (input, init) => {
request = input instanceof Request ? input : new Request(input, init)
return Response.json({
location: { directory: "/tmp/project", project: { id: "proj_test", directory: "/tmp/project" } },
data: { ticket: "ticket", expires_in: 60 },
})
},
})
const result = await client.pty.connectToken({
ptyID: "pty_test",
location: { directory: "/tmp/project" },
"x-opencode-ticket": "1",
})
expect(result.data.ticket).toBe("ticket")
expect(request?.method).toBe("POST")
expect(request?.headers.get("x-opencode-ticket")).toBe("1")
expect(request?.url).toBe(
"http://localhost:3000/api/pty/pty_test/connect-token?location%5Bdirectory%5D=%2Ftmp%2Fproject",
)
})
test("server.get uses the public HTTP contract", async () => {
let request: Request | undefined
const client = OpenCode.make({