Download packages/protocol/src/groups/pty.ts from SaylorTwift/opencode: direct link, hf CLI and curl.
- Browser
- Download file 5.09 kB
-
https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/protocol/src/groups/pty.ts
- Command line
-
hf download hf://SaylorTwift/opencode/packages/protocol/src/groups/pty.ts
-
curl -L -o pty.ts https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/protocol/src/groups/pty.ts
5.09 kB
| import { Pty } from "@opencode-ai/schema/pty" | |
| import { PtyTicket } from "@opencode-ai/schema/pty-ticket" | |
| import { Location } from "@opencode-ai/schema/location" | |
| import { Schema } from "effect" | |
| import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" | |
| import { ForbiddenError, PtyNotFoundError } from "../errors" | |
| import { LocationQuery, locationQueryOpenApi } from "./location" | |
| export const PTY_CONNECT_TICKET_QUERY = "ticket" | |
| export const PTY_CONNECT_TOKEN_HEADER = "x-opencode-ticket" | |
| export const PTY_CONNECT_TOKEN_HEADER_VALUE = "1" | |
| const PTY_CONNECT_PATH = /^\/api\/pty\/[^/]+\/connect$/ | |
| // Authorization middleware skips credential checks when this matches; the PTY connect handler | |
| // is then responsible for consuming and validating the ticket. | |
| export function hasPtyConnectTicketURL(url: URL) { | |
| return PTY_CONNECT_PATH.test(url.pathname) && !!url.searchParams.get(PTY_CONNECT_TICKET_QUERY) | |
| } | |
| export const PtyGroup = HttpApiGroup.make("server.pty") | |
| .add( | |
| HttpApiEndpoint.get("pty.list", "/api/pty", { | |
| query: LocationQuery, | |
| success: Location.response(Schema.Array(Pty.Info)), | |
| }) | |
| .annotateMerge(locationQueryOpenApi) | |
| .annotateMerge( | |
| OpenApi.annotations({ | |
| identifier: "v2.pty.list", | |
| summary: "List PTY sessions", | |
| description: "List PTY sessions for a location, including exited sessions retained until removal.", | |
| }), | |
| ), | |
| ) | |
| .add( | |
| HttpApiEndpoint.post("pty.create", "/api/pty", { | |
| query: LocationQuery, | |
| payload: Pty.CreateInput, | |
| success: Location.response(Pty.Info), | |
| }) | |
| .annotateMerge(locationQueryOpenApi) | |
| .annotateMerge( | |
| OpenApi.annotations({ | |
| identifier: "v2.pty.create", | |
| summary: "Create PTY session", | |
| description: "Create a pseudo-terminal session for a location.", | |
| }), | |
| ), | |
| ) | |
| .add( | |
| HttpApiEndpoint.get("pty.get", "/api/pty/:ptyID", { | |
| params: { ptyID: Pty.ID }, | |
| query: LocationQuery, | |
| success: Location.response(Pty.Info), | |
| error: PtyNotFoundError, | |
| }) | |
| .annotateMerge(locationQueryOpenApi) | |
| .annotateMerge( | |
| OpenApi.annotations({ | |
| identifier: "v2.pty.get", | |
| summary: "Get PTY session", | |
| description: "Get one PTY session, including its exit code once exited.", | |
| }), | |
| ), | |
| ) | |
| .add( | |
| HttpApiEndpoint.put("pty.update", "/api/pty/:ptyID", { | |
| params: { ptyID: Pty.ID }, | |
| query: LocationQuery, | |
| payload: Pty.UpdateInput, | |
| success: Location.response(Pty.Info), | |
| error: PtyNotFoundError, | |
| }) | |
| .annotateMerge(locationQueryOpenApi) | |
| .annotateMerge( | |
| OpenApi.annotations({ | |
| identifier: "v2.pty.update", | |
| summary: "Update PTY session", | |
| description: "Update the title or viewport size of one PTY session.", | |
| }), | |
| ), | |
| ) | |
| .add( | |
| HttpApiEndpoint.delete("pty.remove", "/api/pty/:ptyID", { | |
| params: { ptyID: Pty.ID }, | |
| query: LocationQuery, | |
| success: HttpApiSchema.NoContent, | |
| error: PtyNotFoundError, | |
| }) | |
| .annotateMerge(locationQueryOpenApi) | |
| .annotateMerge( | |
| OpenApi.annotations({ | |
| identifier: "v2.pty.remove", | |
| summary: "Remove PTY session", | |
| description: "Terminate and remove one PTY session.", | |
| }), | |
| ), | |
| ) | |
| .add( | |
| HttpApiEndpoint.post("pty.connectToken", "/api/pty/:ptyID/connect-token", { | |
| params: { ptyID: Pty.ID }, | |
| query: LocationQuery, | |
| success: Location.response(PtyTicket.ConnectToken), | |
| error: [ForbiddenError, PtyNotFoundError], | |
| }) | |
| .annotateMerge(locationQueryOpenApi) | |
| .annotateMerge( | |
| OpenApi.annotations({ | |
| identifier: "v2.pty.connectToken", | |
| summary: "Create PTY WebSocket token", | |
| description: "Create a short-lived single-use ticket for opening a PTY WebSocket connection.", | |
| }), | |
| ), | |
| ) | |
| .add( | |
| // Query fields are decoded in the raw handler after the existence check so a missing | |
| // session responds with an empty 404 before any upgrade work. | |
| HttpApiEndpoint.get("pty.connect", "/api/pty/:ptyID/connect", { | |
| params: { ptyID: Pty.ID }, | |
| success: Schema.Boolean, | |
| error: [ForbiddenError, PtyNotFoundError], | |
| }).annotateMerge( | |
| OpenApi.annotations({ | |
| identifier: "v2.pty.connect", | |
| summary: "Connect to PTY session", | |
| description: "Establish a WebSocket connection streaming PTY output and accepting terminal input.", | |
| transform: (operation) => ({ | |
| ...operation, | |
| "x-websocket": true, | |
| parameters: [ | |
| ...(operation.parameters ?? []), | |
| ...["location[directory]", "location[workspace]", "cursor", PTY_CONNECT_TICKET_QUERY].map((name) => ({ | |
| in: "query", | |
| name, | |
| schema: { type: "string" }, | |
| })), | |
| ], | |
| }), | |
| }), | |
| ), | |
| ) | |
| .annotateMerge(OpenApi.annotations({ title: "pty", description: "Experimental location-scoped PTY routes." })) | |