|
|
@@ -0,0 +1,496 @@
|
|
|
+import type { ServerApi } from "./server"
|
|
|
+import type { ServerProtocol } from "./server-protocol"
|
|
|
+import type { OpencodeClient, Session } from "@opencode-ai/sdk/v2/client"
|
|
|
+import type {
|
|
|
+ Project,
|
|
|
+ ProjectCurrent,
|
|
|
+ SessionApi,
|
|
|
+ SessionCommandInput,
|
|
|
+ SessionCommandOutput,
|
|
|
+ SessionCompactInput,
|
|
|
+ SessionCompactOutput,
|
|
|
+ SessionInfo,
|
|
|
+ SessionPromptInput,
|
|
|
+ SessionPromptOutput,
|
|
|
+ SessionShellInput,
|
|
|
+ SessionShellOutput,
|
|
|
+} from "@opencode-ai/client/promise"
|
|
|
+
|
|
|
+type LegacyClient = OpencodeClient
|
|
|
+type LegacyFor = (directory?: string) => LegacyClient
|
|
|
+type CompatibleSessionApi = Omit<
|
|
|
+ SessionApi,
|
|
|
+ "prompt" | "command" | "shell" | "compact" | "rename" | "archive" | "remove"
|
|
|
+> & {
|
|
|
+ prompt: (input: SessionPromptInput & LegacyPrompt) => Promise<SessionPromptOutput>
|
|
|
+ command: (input: SessionCommandInput) => Promise<SessionCommandOutput>
|
|
|
+ shell: (input: SessionShellInput & LegacyPrompt) => Promise<SessionShellOutput>
|
|
|
+ compact: (input: SessionCompactInput & { model?: LegacyPrompt["model"] }) => Promise<SessionCompactOutput>
|
|
|
+ rename: (input: Parameters<SessionApi["rename"]>[0] & LegacyLocation) => ReturnType<SessionApi["rename"]>
|
|
|
+ archive: (input: Parameters<SessionApi["archive"]>[0] & LegacyLocation) => ReturnType<SessionApi["archive"]>
|
|
|
+ remove: (input: Parameters<SessionApi["remove"]>[0] & LegacyLocation) => ReturnType<SessionApi["remove"]>
|
|
|
+}
|
|
|
+export type CompatibleApi = Omit<ServerApi, "session"> & { readonly session: CompatibleSessionApi }
|
|
|
+type LegacyPrompt = {
|
|
|
+ agent?: string
|
|
|
+ model?: { providerID: string; modelID: string }
|
|
|
+ variant?: string
|
|
|
+}
|
|
|
+type LegacyLocation = { directory?: string }
|
|
|
+
|
|
|
+function mime(uri: string) {
|
|
|
+ const match = /^data:([^;,]+)/.exec(uri)
|
|
|
+ return match?.[1] ?? "application/octet-stream"
|
|
|
+}
|
|
|
+
|
|
|
+function sessionInfo(session: Session): SessionInfo {
|
|
|
+ return {
|
|
|
+ id: session.id,
|
|
|
+ parentID: session.parentID,
|
|
|
+ projectID: session.projectID,
|
|
|
+ agent: session.agent,
|
|
|
+ model: session.model && {
|
|
|
+ id: session.model.id,
|
|
|
+ providerID: session.model.providerID,
|
|
|
+ variant: session.model.variant,
|
|
|
+ },
|
|
|
+ cost: session.cost ?? 0,
|
|
|
+ tokens: session.tokens ?? { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
|
|
+ time: session.time,
|
|
|
+ title: session.title,
|
|
|
+ location: { directory: session.directory, workspaceID: session.workspaceID },
|
|
|
+ subpath: session.path,
|
|
|
+ revert: session.revert && {
|
|
|
+ messageID: session.revert.messageID,
|
|
|
+ partID: session.revert.partID,
|
|
|
+ snapshot: session.revert.snapshot,
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export function createCompatibleApi(input: {
|
|
|
+ protocol: Promise<ServerProtocol>
|
|
|
+ current: ServerApi
|
|
|
+ legacy: LegacyFor
|
|
|
+ directory?: string
|
|
|
+}): CompatibleApi {
|
|
|
+ const directory = (location?: { directory?: string }) => location?.directory ?? input.directory
|
|
|
+ const legacy = (location?: { directory?: string }) => input.legacy(directory(location))
|
|
|
+ const isV1 = () => input.protocol.then((protocol) => protocol === "v1")
|
|
|
+ const located = <T>(data: T, value?: { directory?: string }) => ({
|
|
|
+ location: {
|
|
|
+ directory: directory(value) ?? "",
|
|
|
+ project: { id: "", directory: directory(value) ?? "" },
|
|
|
+ },
|
|
|
+ data,
|
|
|
+ })
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...input.current,
|
|
|
+ session: {
|
|
|
+ ...input.current.session,
|
|
|
+ async list(
|
|
|
+ value?: Parameters<ServerApi["session"]["list"]>[0],
|
|
|
+ options?: Parameters<ServerApi["session"]["list"]>[1],
|
|
|
+ ) {
|
|
|
+ if (!(await isV1())) return input.current.session.list(value, options)
|
|
|
+ if (!value?.directory && value?.search !== undefined) {
|
|
|
+ const result = await legacy().experimental.session.list(
|
|
|
+ {
|
|
|
+ roots: value.parentID === null ? true : undefined,
|
|
|
+ search: value.search,
|
|
|
+ limit: value.limit,
|
|
|
+ },
|
|
|
+ options,
|
|
|
+ )
|
|
|
+ return { data: (result.data ?? []).map(sessionInfo), cursor: {} }
|
|
|
+ }
|
|
|
+ const result = await legacy({ directory: value?.directory }).session.list({
|
|
|
+ directory: value?.directory,
|
|
|
+ roots: value?.parentID === null ? true : undefined,
|
|
|
+ search: value?.search,
|
|
|
+ limit: value?.limit,
|
|
|
+ })
|
|
|
+ return { data: (result.data ?? []).map(sessionInfo), cursor: {} }
|
|
|
+ },
|
|
|
+ async create(value?: Parameters<ServerApi["session"]["create"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.session.create(value)
|
|
|
+ const result = await legacy(value?.location ?? undefined).session.create({
|
|
|
+ directory: directory(value?.location ?? undefined),
|
|
|
+ })
|
|
|
+ if (!result.data) throw new Error("Failed to create session")
|
|
|
+ return sessionInfo(result.data)
|
|
|
+ },
|
|
|
+ async get(value: Parameters<ServerApi["session"]["get"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.session.get(value)
|
|
|
+ const result = await legacy().session.get(value)
|
|
|
+ if (!result.data) throw new Error(`Session not found: ${value.sessionID}`)
|
|
|
+ return sessionInfo(result.data)
|
|
|
+ },
|
|
|
+ async active() {
|
|
|
+ if (!(await isV1())) return input.current.session.active()
|
|
|
+ const result = await legacy().session.status()
|
|
|
+ return Object.fromEntries(
|
|
|
+ Object.entries(result.data ?? {}).flatMap(([sessionID, status]) =>
|
|
|
+ status.type === "idle" ? [] : [[sessionID, { type: "running" as const }]],
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ },
|
|
|
+ async rename(value: Parameters<ServerApi["session"]["rename"]>[0] & LegacyLocation) {
|
|
|
+ if (!(await isV1())) return input.current.session.rename(value)
|
|
|
+ await legacy(value).session.update({ sessionID: value.sessionID, title: value.title })
|
|
|
+ },
|
|
|
+ async archive(value: Parameters<ServerApi["session"]["archive"]>[0] & LegacyLocation) {
|
|
|
+ if (!(await isV1())) return input.current.session.archive(value)
|
|
|
+ await legacy(value).session.update({ sessionID: value.sessionID, time: { archived: Date.now() } })
|
|
|
+ },
|
|
|
+ async remove(value: Parameters<ServerApi["session"]["remove"]>[0] & LegacyLocation) {
|
|
|
+ if (!(await isV1())) return input.current.session.remove(value)
|
|
|
+ await legacy(value).session.delete(value)
|
|
|
+ },
|
|
|
+ async fork(value: Parameters<ServerApi["session"]["fork"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.session.fork(value)
|
|
|
+ const result = await legacy().session.fork(value)
|
|
|
+ if (!result.data) throw new Error("Failed to fork session")
|
|
|
+ return sessionInfo(result.data)
|
|
|
+ },
|
|
|
+ async interrupt(value: Parameters<ServerApi["session"]["interrupt"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.session.interrupt(value)
|
|
|
+ await legacy().session.abort(value)
|
|
|
+ },
|
|
|
+ async prompt(value: SessionPromptInput & LegacyPrompt) {
|
|
|
+ if (!(await isV1())) return input.current.session.prompt(value)
|
|
|
+ await legacy().session.promptAsync({
|
|
|
+ sessionID: value.sessionID,
|
|
|
+ messageID: value.id ?? undefined,
|
|
|
+ agent: value.agent,
|
|
|
+ model: value.model,
|
|
|
+ variant: value.variant,
|
|
|
+ parts: [
|
|
|
+ { type: "text", text: value.text },
|
|
|
+ ...(value.files ?? []).map((file) => ({
|
|
|
+ type: "file" as const,
|
|
|
+ mime: mime(file.uri),
|
|
|
+ url: file.uri,
|
|
|
+ filename: file.name,
|
|
|
+ })),
|
|
|
+ ...(value.agents ?? []).map((agent) => ({
|
|
|
+ type: "agent" as const,
|
|
|
+ name: agent.name,
|
|
|
+ source: agent.mention
|
|
|
+ ? { value: agent.mention.text, start: agent.mention.start, end: agent.mention.end }
|
|
|
+ : undefined,
|
|
|
+ })),
|
|
|
+ ],
|
|
|
+ })
|
|
|
+ return {
|
|
|
+ admittedSeq: 0,
|
|
|
+ id: value.id ?? "",
|
|
|
+ sessionID: value.sessionID,
|
|
|
+ timeCreated: Date.now(),
|
|
|
+ type: "user",
|
|
|
+ data: { text: value.text },
|
|
|
+ delivery: value.delivery ?? "steer",
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async command(value: SessionCommandInput) {
|
|
|
+ if (!(await isV1())) return input.current.session.command(value)
|
|
|
+ await legacy().session.command({
|
|
|
+ sessionID: value.sessionID,
|
|
|
+ messageID: value.id ?? undefined,
|
|
|
+ command: value.command,
|
|
|
+ arguments: value.arguments ?? "",
|
|
|
+ agent: value.agent ?? undefined,
|
|
|
+ model: value.model ? `${value.model.providerID}/${value.model.id}` : undefined,
|
|
|
+ variant: value.model?.variant,
|
|
|
+ parts: value.files?.map((file) => ({
|
|
|
+ type: "file" as const,
|
|
|
+ mime: mime(file.uri),
|
|
|
+ url: file.uri,
|
|
|
+ filename: file.name,
|
|
|
+ })),
|
|
|
+ })
|
|
|
+ return {
|
|
|
+ admittedSeq: 0,
|
|
|
+ id: value.id ?? "",
|
|
|
+ sessionID: value.sessionID,
|
|
|
+ timeCreated: Date.now(),
|
|
|
+ type: "user",
|
|
|
+ data: { text: `/${value.command} ${value.arguments ?? ""}`.trim() },
|
|
|
+ delivery: value.delivery ?? "steer",
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async shell(value: SessionShellInput & LegacyPrompt) {
|
|
|
+ if (!(await isV1())) return input.current.session.shell(value)
|
|
|
+ await legacy().session.shell({
|
|
|
+ sessionID: value.sessionID,
|
|
|
+ command: value.command,
|
|
|
+ agent: value.agent,
|
|
|
+ model: value.model,
|
|
|
+ })
|
|
|
+ },
|
|
|
+ compact: async (value: SessionCompactInput & { model?: LegacyPrompt["model"] }) => {
|
|
|
+ if (!(await isV1())) return input.current.session.compact(value)
|
|
|
+ if (!value.model) throw new Error("A model is required to compact a V1 session")
|
|
|
+ await legacy().session.summarize({
|
|
|
+ sessionID: value.sessionID,
|
|
|
+ providerID: value.model.providerID,
|
|
|
+ modelID: value.model.modelID,
|
|
|
+ })
|
|
|
+ return {
|
|
|
+ admittedSeq: 0,
|
|
|
+ id: value.id ?? "",
|
|
|
+ sessionID: value.sessionID,
|
|
|
+ timeCreated: Date.now(),
|
|
|
+ type: "compaction",
|
|
|
+ }
|
|
|
+ },
|
|
|
+ revert: {
|
|
|
+ stage: async (value: Parameters<ServerApi["session"]["revert"]["stage"]>[0]) => {
|
|
|
+ if (!(await isV1())) return input.current.session.revert.stage(value)
|
|
|
+ await legacy().session.revert(value)
|
|
|
+ return { messageID: value.messageID }
|
|
|
+ },
|
|
|
+ clear: async (value: Parameters<ServerApi["session"]["revert"]["clear"]>[0]) => {
|
|
|
+ if (!(await isV1())) return input.current.session.revert.clear(value)
|
|
|
+ await legacy().session.unrevert(value)
|
|
|
+ },
|
|
|
+ commit: input.current.session.revert.commit,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ project: {
|
|
|
+ ...input.current.project,
|
|
|
+ async list() {
|
|
|
+ if (!(await isV1())) return input.current.project.list()
|
|
|
+ return ((await legacy().project.list()).data ?? []) as Project[]
|
|
|
+ },
|
|
|
+ async current(value?: Parameters<ServerApi["project"]["current"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.project.current(value)
|
|
|
+ const result = await legacy(value?.location).project.current()
|
|
|
+ if (!result.data) throw new Error("Project not found")
|
|
|
+ return { id: result.data.id, directory: result.data.worktree } satisfies ProjectCurrent
|
|
|
+ },
|
|
|
+ async update(value: Parameters<ServerApi["project"]["update"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.project.update(value)
|
|
|
+ const project = (await legacy().project.list()).data?.find((item) => item.id === value.projectID)
|
|
|
+ const result = await legacy({ directory: project?.worktree }).project.update({
|
|
|
+ ...value,
|
|
|
+ directory: project?.worktree,
|
|
|
+ })
|
|
|
+ if (!result.data) throw new Error(`Project not found: ${value.projectID}`)
|
|
|
+ return result.data as Project
|
|
|
+ },
|
|
|
+ async directories(value: Parameters<ServerApi["project"]["directories"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.project.directories(value)
|
|
|
+ const result = await legacy(value.location).worktree.list()
|
|
|
+ return (result.data ?? []).map((item) => ({ directory: item }))
|
|
|
+ },
|
|
|
+ },
|
|
|
+ path: {
|
|
|
+ ...input.current.path,
|
|
|
+ async get(value?: Parameters<ServerApi["path"]["get"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.path.get(value)
|
|
|
+ const result = await legacy(value?.location).path.get()
|
|
|
+ if (!result.data) throw new Error("Path unavailable")
|
|
|
+ return result.data
|
|
|
+ },
|
|
|
+ },
|
|
|
+ vcs: {
|
|
|
+ ...input.current.vcs,
|
|
|
+ async get(value?: Parameters<ServerApi["vcs"]["get"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.vcs.get(value)
|
|
|
+ const result = await legacy(value?.location).vcs.get()
|
|
|
+ return located({ branch: result.data?.branch, defaultBranch: undefined }, value?.location)
|
|
|
+ },
|
|
|
+ async status(value?: Parameters<ServerApi["vcs"]["status"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.vcs.status(value)
|
|
|
+ const result = await legacy(value?.location).vcs.status()
|
|
|
+ return located(result.data ?? [], value?.location)
|
|
|
+ },
|
|
|
+ async diff(value: Parameters<ServerApi["vcs"]["diff"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.vcs.diff(value)
|
|
|
+ const result = await legacy(value.location).vcs.diff({
|
|
|
+ mode: value.mode === "working" ? "git" : value.mode,
|
|
|
+ context: value.context,
|
|
|
+ })
|
|
|
+ return located(
|
|
|
+ (result.data ?? []).map((file) => ({
|
|
|
+ file: file.file,
|
|
|
+ patch: file.patch ?? "",
|
|
|
+ additions: file.additions,
|
|
|
+ deletions: file.deletions,
|
|
|
+ status: file.status ?? "modified",
|
|
|
+ })),
|
|
|
+ value.location,
|
|
|
+ )
|
|
|
+ },
|
|
|
+ },
|
|
|
+ file: {
|
|
|
+ ...input.current.file,
|
|
|
+ async list(value?: Parameters<ServerApi["file"]["list"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.file.list(value)
|
|
|
+ const result = await legacy(value?.location).file.list({ path: value?.path ?? "" })
|
|
|
+ return located(result.data ?? [], value?.location)
|
|
|
+ },
|
|
|
+ async find(value: Parameters<ServerApi["file"]["find"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.file.find(value)
|
|
|
+ const result = await legacy(value.location).find.files({
|
|
|
+ query: value.query,
|
|
|
+ type: value.type,
|
|
|
+ limit: value.limit,
|
|
|
+ })
|
|
|
+ return located(
|
|
|
+ (result.data ?? []).map((path) => ({ path, type: value.type ?? "file" })),
|
|
|
+ value.location,
|
|
|
+ )
|
|
|
+ },
|
|
|
+ },
|
|
|
+ integration: {
|
|
|
+ ...input.current.integration,
|
|
|
+ async get(value: Parameters<ServerApi["integration"]["get"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.integration.get(value)
|
|
|
+ const methods = ((await legacy(value.location).provider.auth()).data?.[value.integrationID] ?? []).map(
|
|
|
+ (method, index) =>
|
|
|
+ method.type === "api"
|
|
|
+ ? { type: "key" as const, label: method.label }
|
|
|
+ : { type: "oauth" as const, id: String(index), label: method.label, prompts: method.prompts },
|
|
|
+ )
|
|
|
+ return located(
|
|
|
+ {
|
|
|
+ id: value.integrationID,
|
|
|
+ name: value.integrationID,
|
|
|
+ methods,
|
|
|
+ connections: [],
|
|
|
+ },
|
|
|
+ value.location,
|
|
|
+ )
|
|
|
+ },
|
|
|
+ connect: {
|
|
|
+ ...input.current.integration.connect,
|
|
|
+ key: async (value: Parameters<ServerApi["integration"]["connect"]["key"]>[0]) => {
|
|
|
+ if (!(await isV1())) return input.current.integration.connect.key(value)
|
|
|
+ await legacy(value.location).auth.set({
|
|
|
+ providerID: value.integrationID,
|
|
|
+ auth: { type: "api", key: value.key },
|
|
|
+ })
|
|
|
+ },
|
|
|
+ },
|
|
|
+ oauth: {
|
|
|
+ ...input.current.integration.oauth,
|
|
|
+ connect: async (value: Parameters<ServerApi["integration"]["oauth"]["connect"]>[0]) => {
|
|
|
+ if (!(await isV1())) return input.current.integration.oauth.connect(value)
|
|
|
+ const method = Number(value.methodID)
|
|
|
+ const result = await legacy(value.location).provider.oauth.authorize(
|
|
|
+ { providerID: value.integrationID, method, inputs: value.inputs },
|
|
|
+ { throwOnError: true },
|
|
|
+ )
|
|
|
+ if (!result.data) throw new Error("Failed to start OAuth authorization")
|
|
|
+ return located(
|
|
|
+ {
|
|
|
+ attemptID: `${value.integrationID}:${method}`,
|
|
|
+ url: result.data.url,
|
|
|
+ instructions: result.data.instructions,
|
|
|
+ mode: result.data.method,
|
|
|
+ time: { created: Date.now(), expires: Date.now() + 10 * 60 * 1000 },
|
|
|
+ },
|
|
|
+ value.location,
|
|
|
+ )
|
|
|
+ },
|
|
|
+ complete: async (value: Parameters<ServerApi["integration"]["oauth"]["complete"]>[0]) => {
|
|
|
+ if (!(await isV1())) return input.current.integration.oauth.complete(value)
|
|
|
+ const method = Number(value.attemptID.split(":").at(-1))
|
|
|
+ await legacy(value.location).provider.oauth.callback(
|
|
|
+ { providerID: value.integrationID, method, code: value.code },
|
|
|
+ { throwOnError: true },
|
|
|
+ )
|
|
|
+ },
|
|
|
+ status: async (value: Parameters<ServerApi["integration"]["oauth"]["status"]>[0]) => {
|
|
|
+ if (!(await isV1())) return input.current.integration.oauth.status(value)
|
|
|
+ const method = Number(value.attemptID.split(":").at(-1))
|
|
|
+ await legacy(value.location).provider.oauth.callback(
|
|
|
+ { providerID: value.integrationID, method },
|
|
|
+ { throwOnError: true },
|
|
|
+ )
|
|
|
+ return located(
|
|
|
+ { status: "complete" as const, time: { created: Date.now(), expires: Date.now() } },
|
|
|
+ value.location,
|
|
|
+ )
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ pty: {
|
|
|
+ ...input.current.pty,
|
|
|
+ async shells(value?: Parameters<ServerApi["pty"]["shells"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.pty.shells(value)
|
|
|
+ return located((await legacy(value?.location).pty.shells()).data ?? [], value?.location)
|
|
|
+ },
|
|
|
+ async list(value?: Parameters<ServerApi["pty"]["list"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.pty.list(value)
|
|
|
+ return located((await legacy(value?.location).pty.list()).data ?? [], value?.location)
|
|
|
+ },
|
|
|
+ async create(value?: Parameters<ServerApi["pty"]["create"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.pty.create(value)
|
|
|
+ const result = await legacy(value?.location).pty.create({
|
|
|
+ command: value?.command,
|
|
|
+ args: value?.args ? [...value.args] : undefined,
|
|
|
+ cwd: value?.cwd,
|
|
|
+ title: value?.title,
|
|
|
+ env: value?.env,
|
|
|
+ })
|
|
|
+ if (!result.data) throw new Error("Failed to create terminal")
|
|
|
+ return located(result.data, value?.location)
|
|
|
+ },
|
|
|
+ async get(value: Parameters<ServerApi["pty"]["get"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.pty.get(value)
|
|
|
+ const result = await legacy(value.location).pty.get({ ptyID: value.ptyID })
|
|
|
+ if (!result.data) throw new Error(`Terminal not found: ${value.ptyID}`)
|
|
|
+ return located(result.data, value.location)
|
|
|
+ },
|
|
|
+ async update(value: Parameters<ServerApi["pty"]["update"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.pty.update(value)
|
|
|
+ const result = await legacy(value.location).pty.update({
|
|
|
+ ptyID: value.ptyID,
|
|
|
+ title: value.title,
|
|
|
+ size: value.size,
|
|
|
+ })
|
|
|
+ if (!result.data) throw new Error(`Terminal not found: ${value.ptyID}`)
|
|
|
+ return located(result.data, value.location)
|
|
|
+ },
|
|
|
+ async remove(value: Parameters<ServerApi["pty"]["remove"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.pty.remove(value)
|
|
|
+ await legacy(value.location).pty.remove({ ptyID: value.ptyID })
|
|
|
+ },
|
|
|
+ async connectToken(value: Parameters<ServerApi["pty"]["connectToken"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.pty.connectToken(value)
|
|
|
+ const result = await legacy(value.location).pty.connectToken({ ptyID: value.ptyID })
|
|
|
+ if (!result.data) throw new Error(`Failed to connect terminal: ${value.ptyID}`)
|
|
|
+ return located(result.data, value.location)
|
|
|
+ },
|
|
|
+ },
|
|
|
+ permission: {
|
|
|
+ ...input.current.permission,
|
|
|
+ async reply(value: Parameters<ServerApi["permission"]["reply"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.permission.reply(value)
|
|
|
+ await legacy().permission.respond({
|
|
|
+ sessionID: value.sessionID,
|
|
|
+ permissionID: value.requestID,
|
|
|
+ response: value.reply,
|
|
|
+ })
|
|
|
+ },
|
|
|
+ },
|
|
|
+ question: {
|
|
|
+ ...input.current.question,
|
|
|
+ async reply(value: Parameters<ServerApi["question"]["reply"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.question.reply(value)
|
|
|
+ await legacy().question.reply({
|
|
|
+ requestID: value.requestID,
|
|
|
+ answers: value.answers.map((answer) => [...answer]),
|
|
|
+ })
|
|
|
+ },
|
|
|
+ async reject(value: Parameters<ServerApi["question"]["reject"]>[0]) {
|
|
|
+ if (!(await isV1())) return input.current.question.reject(value)
|
|
|
+ await legacy().question.reject({ requestID: value.requestID })
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|