| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- /**
- * OpenCode SDK client instance
- * Configured to connect to the OpenCode server at the default location.
- *
- * When `window.__OPENCODE_SERVER_URL__` is set (e.g. injected by the VS Code
- * gui-only plugin), all API requests target that absolute URL. When absent,
- * relative URLs are used — identical to the original behaviour.
- */
- import { createOpencodeClient, type Provider } from "@opencode-ai/sdk/client"
- export const serverBase: string =
- ((globalThis as any).__OPENCODE_SERVER_URL__ as string | undefined)?.replace(/\/$/, "") || ""
- const baseClient = createOpencodeClient({ baseUrl: serverBase || "/" })
- interface ProvidersResponse {
- providers: Provider[]
- default: Record<string, string>
- }
- interface ModelEntry {
- providerID: string
- modelID: string
- }
- interface ModelPreferences {
- recent: ModelEntry[]
- favorite: ModelEntry[]
- variant?: Record<string, string>
- }
- interface PathResponse {
- state: string
- config: string
- worktree: string
- directory: string
- }
- /**
- * Extended SDK client with state management methods
- * TODO: Remove once SDK is regenerated with Stainless
- */
- export const sdk = {
- ...baseClient,
- session: Object.assign(baseClient.session, {
- retry: async (options: { path: { sessionID: string } }) => {
- try {
- const response = await fetch(`${serverBase}/app/api/session/${options.path.sessionID}/retry`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- })
- if (!response.ok) {
- return { error: { message: "Failed to retry session" }, data: null }
- }
- const data = await response.json()
- return { data, error: null }
- } catch (error) {
- return {
- error: { message: error instanceof Error ? error.message : "Unknown error" },
- data: null,
- }
- }
- },
- }) as (typeof baseClient.session) & {
- retry: (options: { path: { sessionID: string } }) => Promise<any>
- },
- config: {
- get: baseClient.config.get.bind(baseClient.config),
- update: baseClient.config.update.bind(baseClient.config),
- providers: baseClient.config.providers.bind(baseClient.config),
- allProviders: async () => {
- try {
- const response = await fetch(`${serverBase}/app/api/config/providers`, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- })
- if (!response.ok) {
- return { error: { message: "Failed to load providers" }, data: null as ProvidersResponse | null }
- }
- const data = (await response.json()) as ProvidersResponse
- return { data, error: null as { message: string } | null }
- } catch (error) {
- return {
- error: { message: error instanceof Error ? error.message : "Unknown error" },
- data: null as ProvidersResponse | null,
- }
- }
- },
- },
- path: {
- get: async () => {
- try {
- const response = await fetch(`${serverBase}/path`, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- })
- if (!response.ok) {
- return {
- error: { message: "Failed to fetch path" },
- data: null as PathResponse | null,
- }
- }
- const data = (await response.json()) as PathResponse
- return { data, error: null as { message: string } | null }
- } catch (error) {
- return {
- error: { message: error instanceof Error ? error.message : "Unknown error" },
- data: null as PathResponse | null,
- }
- }
- },
- },
- auth: {
- set: async (provider: string, value: any) => {
- const res = await fetch(`${serverBase}/app/api/auth/set`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ provider, value }),
- })
- if (!res.ok) throw new Error(await res.text())
- },
- list: async () => {
- const res = await fetch(`${serverBase}/app/api/auth/list`)
- return res.json() as Promise<Record<string, any>>
- },
- remove: async (provider: string) => {
- await fetch(`${serverBase}/app/api/auth/remove`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ provider }),
- })
- },
- methods: async (provider: string) => {
- const res = await fetch(`${serverBase}/app/api/auth/methods?provider=${provider}`)
- return res.json() as Promise<
- Array<{
- label: string
- type: "oauth" | "api"
- prompts?: any[]
- }>
- >
- },
- start: async (provider: string, methodIndex: number, inputs: any) => {
- const res = await fetch(`${serverBase}/app/api/auth/login/start`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ provider, methodIndex, inputs }),
- })
- if (!res.ok) throw new Error(await res.text())
- return res.json() as Promise<{ id: string; url?: string; method: "auto" | "code"; instructions?: string }>
- },
- submit: async (id: string, code: string) => {
- const res = await fetch(`${serverBase}/app/api/auth/login/submit`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ id, code }),
- })
- if (!res.ok) throw new Error(await res.text())
- return res.json() as Promise<boolean>
- },
- status: async (id: string) => {
- const res = await fetch(`${serverBase}/app/api/auth/login/status/${id}`)
- return res.json() as Promise<{ status: "pending" | "success" | "failed"; result?: any }>
- },
- },
- permissions: {
- respond: async (options: {
- path: { requestID: string }
- body: { reply: "once" | "always" | "reject"; message?: string }
- }) => {
- const response = await fetch(`${serverBase}/permission/${options.path.requestID}/reply`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(options.body),
- })
- if (!response.ok) {
- return { error: { message: "Failed to respond to permission" }, data: null }
- }
- const data = await response.json()
- return { data, error: null }
- },
- },
- question: {
- reply: async (options: { requestID: string; answers: Array<Array<string>> }) => {
- const response = await fetch(`${serverBase}/question/${options.requestID}/reply`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ answers: options.answers }),
- })
- if (!response.ok) {
- return { error: { message: "Failed to reply to question" }, data: null }
- }
- const data = await response.json()
- return { data, error: null }
- },
- reject: async (options: { requestID: string }) => {
- const response = await fetch(`${serverBase}/question/${options.requestID}/reject`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- })
- if (!response.ok) {
- return { error: { message: "Failed to reject question" }, data: null }
- }
- const data = await response.json()
- return { data, error: null }
- },
- },
- model: {
- get: async () => {
- try {
- const response = await fetch(`${serverBase}/app/api/model`, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- })
- if (!response.ok) {
- return { error: { message: "Failed to fetch model preferences" }, data: null as ModelPreferences | null }
- }
- const data = (await response.json()) as ModelPreferences
- return { data, error: null as { message: string } | null }
- } catch (error) {
- return { error: { message: error instanceof Error ? error.message : "Unknown error" }, data: null as ModelPreferences | null }
- }
- },
- update: async (options: { body: Partial<ModelPreferences> }) => {
- try {
- const response = await fetch(`${serverBase}/app/api/model`, {
- method: "PATCH",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(options.body),
- })
- if (!response.ok) {
- return { error: { message: "Failed to update model preferences" }, data: null as ModelPreferences | null }
- }
- const data = (await response.json()) as ModelPreferences
- return { data, error: null as { message: string } | null }
- } catch (error) {
- return { error: { message: error instanceof Error ? error.message : "Unknown error" }, data: null as ModelPreferences | null }
- }
- },
- },
- kv: {
- get: async () => {
- try {
- const response = await fetch(`${serverBase}/app/api/kv`, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- })
- if (!response.ok) {
- return { error: { message: "Failed to fetch kv" }, data: null as Record<string, any> | null }
- }
- const data = (await response.json()) as Record<string, any>
- return { data, error: null as { message: string } | null }
- } catch (error) {
- return { error: { message: error instanceof Error ? error.message : "Unknown error" }, data: null as Record<string, any> | null }
- }
- },
- update: async (options: { body: Record<string, any> }) => {
- try {
- const response = await fetch(`${serverBase}/app/api/kv`, {
- method: "PATCH",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(options.body),
- })
- if (!response.ok) {
- return { error: { message: "Failed to update kv" }, data: null as Record<string, any> | null }
- }
- const data = (await response.json()) as Record<string, any>
- return { data, error: null as { message: string } | null }
- } catch (error) {
- return { error: { message: error instanceof Error ? error.message : "Unknown error" }, data: null as Record<string, any> | null }
- }
- },
- },
- }
|