Dax Raad 8 månader sedan
förälder
incheckning
ca031278ca
38 ändrade filer med 2784 tillägg och 2500 borttagningar
  1. 13 0
      bun.lock
  2. 1 11
      opencode.json
  3. 1 1
      packages/function/package.json
  4. 2 1
      packages/opencode/package.json
  5. 2 0
      packages/opencode/src/cli/bootstrap.ts
  6. 28 16
      packages/opencode/src/config/config.ts
  7. 14 1
      packages/opencode/src/permission/index.ts
  8. 85 0
      packages/opencode/src/plugin/index.ts
  9. 18 14
      packages/opencode/src/provider/provider.ts
  10. 3 2
      packages/opencode/src/server/server.ts
  11. 46 5
      packages/opencode/src/session/index.ts
  12. 5 1
      packages/opencode/tsconfig.json
  13. 1 0
      packages/plugin/.gitignore
  14. 21 0
      packages/plugin/package.json
  15. 18 0
      packages/plugin/script/publish.ts
  16. 7 0
      packages/plugin/src/example.ts
  17. 56 0
      packages/plugin/src/index.ts
  18. 16 0
      packages/plugin/tsconfig.json
  19. 8 2
      packages/sdk/js/package.json
  20. 1 0
      packages/sdk/js/script/generate.ts
  21. 0 7
      packages/sdk/js/script/publish.ts
  22. 10 6
      packages/sdk/js/src/gen/client.gen.ts
  23. 72 82
      packages/sdk/js/src/gen/client/client.ts
  24. 7 11
      packages/sdk/js/src/gen/client/index.ts
  25. 67 98
      packages/sdk/js/src/gen/client/types.ts
  26. 156 200
      packages/sdk/js/src/gen/client/utils.ts
  27. 13 14
      packages/sdk/js/src/gen/core/auth.ts
  28. 34 52
      packages/sdk/js/src/gen/core/bodySerializer.ts
  29. 56 65
      packages/sdk/js/src/gen/core/params.ts
  30. 80 94
      packages/sdk/js/src/gen/core/pathSerializer.ts
  31. 28 57
      packages/sdk/js/src/gen/core/types.ts
  32. 474 397
      packages/sdk/js/src/gen/sdk.gen.ts
  33. 1408 1357
      packages/sdk/js/src/gen/types.gen.ts
  34. 1 0
      packages/sdk/js/src/index.ts
  35. 6 1
      packages/sdk/js/tsconfig.json
  36. 1 1
      packages/web/package.json
  37. 24 3
      script/publish.ts
  38. 1 1
      sdks/vscode/package.json

+ 13 - 0
bun.lock

@@ -38,6 +38,7 @@
         "@octokit/graphql": "9.0.1",
         "@octokit/rest": "22.0.0",
         "@openauthjs/openauth": "0.4.3",
+        "@opencode-ai/plugin": "workspace:*",
         "@standard-schema/spec": "1.0.0",
         "@zip.js/zip.js": "2.7.62",
         "ai": "catalog:",
@@ -74,6 +75,16 @@
         "zod-to-json-schema": "3.24.5",
       },
     },
+    "packages/plugin": {
+      "name": "@opencode-ai/plugin",
+      "version": "0.0.0",
+      "devDependencies": {
+        "@hey-api/openapi-ts": "0.80.1",
+        "@opencode-ai/sdk": "workspace:*",
+        "@tsconfig/node22": "catalog:",
+        "typescript": "catalog:",
+      },
+    },
     "packages/sdk/js": {
       "name": "@opencode-ai/sdk",
       "version": "0.0.0",
@@ -416,6 +427,8 @@
 
     "@openauthjs/openauth": ["@openauthjs/[email protected]", "", { "dependencies": { "@standard-schema/spec": "1.0.0-beta.3", "aws4fetch": "1.0.20", "jose": "5.9.6" }, "peerDependencies": { "arctic": "^2.2.2", "hono": "^4.0.0" } }, "sha512-RlnjqvHzqcbFVymEwhlUEuac4utA5h4nhSK/i2szZuQmxTIqbGUxZ+nM+avM+VV4Ing+/ZaNLKILoXS3yrkOOw=="],
 
+    "@opencode-ai/plugin": ["@opencode-ai/plugin@workspace:packages/plugin"],
+
     "@opencode-ai/sdk": ["@opencode-ai/sdk@workspace:packages/sdk/js"],
 
     "@opencode/function": ["@opencode/function@workspace:packages/function"],

+ 1 - 11
opencode.json

@@ -1,16 +1,6 @@
 {
   "$schema": "https://opencode.ai/config.json",
-  "provider": {
-    "cerebras": {
-      "options": {
-        "apiKey": "csk-m33xrvt43whkypn8r4ph9xc8fenhx2f68c3pj22ext45v5k9"
-      },
-      "npm": "@ai-sdk/cerebras",
-      "models": {
-        "qwen-3-coder-480b": {}
-      }
-    }
-  },
+  "plugin": ["./packages/plugin/src/example.ts"],
   "mcp": {
     "context7": {
       "type": "remote",

+ 1 - 1
packages/function/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@opencode/function",
-  "version": "0.0.1",
+  "version": "0.0.0-202508022246",
   "$schema": "https://json.schemastore.org/package.json",
   "private": true,
   "type": "module",

+ 2 - 1
packages/opencode/package.json

@@ -1,6 +1,6 @@
 {
   "$schema": "https://json.schemastore.org/package.json",
-  "version": "0.0.0",
+  "version": "0.0.0-202508022246",
   "name": "opencode",
   "type": "module",
   "private": true,
@@ -36,6 +36,7 @@
     "@octokit/graphql": "9.0.1",
     "@octokit/rest": "22.0.0",
     "@openauthjs/openauth": "0.4.3",
+    "@opencode-ai/plugin": "workspace:*",
     "@standard-schema/spec": "1.0.0",
     "@zip.js/zip.js": "2.7.62",
     "ai": "catalog:",

+ 2 - 0
packages/opencode/src/cli/bootstrap.ts

@@ -2,6 +2,7 @@ import { App } from "../app/app"
 import { ConfigHooks } from "../config/hooks"
 import { Format } from "../format"
 import { LSP } from "../lsp"
+import { Plugin } from "../plugin"
 import { Share } from "../share/share"
 import { Snapshot } from "../snapshot"
 
@@ -9,6 +10,7 @@ export async function bootstrap<T>(input: App.Input, cb: (app: App.Info) => Prom
   return App.provide(input, async (app) => {
     Share.init()
     Format.init()
+    Plugin.init()
     ConfigHooks.init()
     LSP.init()
     Snapshot.init()

+ 28 - 16
packages/opencode/src/config/config.ts

@@ -23,13 +23,13 @@ export namespace Config {
     for (const file of ["opencode.jsonc", "opencode.json"]) {
       const found = await Filesystem.findUp(file, app.path.cwd, app.path.root)
       for (const resolved of found.toReversed()) {
-        result = mergeDeep(result, await load(resolved))
+        result = mergeDeep(result, await loadFile(resolved))
       }
     }
 
     // Override with custom config if provided
     if (Flag.OPENCODE_CONFIG) {
-      result = mergeDeep(result, await load(Flag.OPENCODE_CONFIG))
+      result = mergeDeep(result, await loadFile(Flag.OPENCODE_CONFIG))
       log.debug("loaded custom config", { path: Flag.OPENCODE_CONFIG })
     }
 
@@ -37,7 +37,7 @@ export namespace Config {
       if (value.type === "wellknown") {
         process.env[value.key] = value.token
         const wellknown = await fetch(`${key}/.well-known/opencode`).then((x) => x.json())
-        result = mergeDeep(result, await loadRaw(JSON.stringify(wellknown.config ?? {}), process.cwd()))
+        result = mergeDeep(result, await load(JSON.stringify(wellknown.config ?? {}), process.cwd()))
       }
     }
 
@@ -223,6 +223,7 @@ export namespace Config {
       $schema: z.string().optional().describe("JSON schema reference for configuration validation"),
       theme: z.string().optional().describe("Theme name to use for the interface"),
       keybinds: Keybinds.optional().describe("Custom keybind configurations"),
+      plugin: z.string().array().optional(),
       share: z
         .enum(["manual", "auto", "disabled"])
         .optional()
@@ -352,9 +353,9 @@ export namespace Config {
   export const global = lazy(async () => {
     let result: Info = pipe(
       {},
-      mergeDeep(await load(path.join(Global.Path.config, "config.json"))),
-      mergeDeep(await load(path.join(Global.Path.config, "opencode.json"))),
-      mergeDeep(await load(path.join(Global.Path.config, "opencode.jsonc"))),
+      mergeDeep(await loadFile(path.join(Global.Path.config, "config.json"))),
+      mergeDeep(await loadFile(path.join(Global.Path.config, "opencode.json"))),
+      mergeDeep(await loadFile(path.join(Global.Path.config, "opencode.jsonc"))),
     )
 
     await import(path.join(Global.Path.config, "config"), {
@@ -375,25 +376,26 @@ export namespace Config {
     return result
   })
 
-  async function load(configPath: string): Promise<Info> {
-    let text = await Bun.file(configPath)
+  async function loadFile(filepath: string): Promise<Info> {
+    log.info("loading", { path: filepath })
+    let text = await Bun.file(filepath)
       .text()
       .catch((err) => {
         if (err.code === "ENOENT") return
-        throw new JsonError({ path: configPath }, { cause: err })
+        throw new JsonError({ path: filepath }, { cause: err })
       })
     if (!text) return {}
-    return loadRaw(text, configPath)
+    return load(text, filepath)
   }
 
-  async function loadRaw(text: string, configPath: string) {
+  async function load(text: string, filepath: string) {
     text = text.replace(/\{env:([^}]+)\}/g, (_, varName) => {
       return process.env[varName] || ""
     })
 
     const fileMatches = text.match(/\{file:[^}]+\}/g)
     if (fileMatches) {
-      const configDir = path.dirname(configPath)
+      const configDir = path.dirname(filepath)
       const lines = text.split("\n")
 
       for (const match of fileMatches) {
@@ -428,7 +430,7 @@ export namespace Config {
         .join("\n")
 
       throw new JsonError({
-        path: configPath,
+        path: filepath,
         message: `\n--- JSONC Input ---\n${text}\n--- Errors ---\n${errorDetails}\n--- End ---`,
       })
     }
@@ -437,11 +439,21 @@ export namespace Config {
     if (parsed.success) {
       if (!parsed.data.$schema) {
         parsed.data.$schema = "https://opencode.ai/config.json"
-        await Bun.write(configPath, JSON.stringify(parsed.data, null, 2))
+        await Bun.write(filepath, JSON.stringify(parsed.data, null, 2))
       }
-      return parsed.data
+      const data = parsed.data
+      if (data.plugin) {
+        for (let i = 0; i < data.plugin?.length; i++) {
+          const plugin = data.plugin[i]
+          if (typeof plugin === "string") {
+            data.plugin[i] = path.resolve(path.dirname(filepath), plugin)
+          }
+        }
+      }
+      return data
     }
-    throw new InvalidError({ path: configPath, issues: parsed.error.issues })
+
+    throw new InvalidError({ path: filepath, issues: parsed.error.issues })
   }
   export const JsonError = NamedError.create(
     "ConfigJsonError",

+ 14 - 1
packages/opencode/src/permission/index.ts

@@ -3,6 +3,7 @@ import { z } from "zod"
 import { Bus } from "../bus"
 import { Log } from "../util/log"
 import { Identifier } from "../id/id"
+import { Plugin } from "../plugin"
 
 export namespace Permission {
   const log = Log.create({ service: "permission" })
@@ -67,7 +68,7 @@ export namespace Permission {
     },
   )
 
-  export function ask(input: {
+  export async function ask(input: {
     type: Info["type"]
     title: Info["title"]
     pattern?: Info["pattern"]
@@ -95,6 +96,18 @@ export namespace Permission {
         created: Date.now(),
       },
     }
+
+    switch (
+      await Plugin.trigger("permission.ask", info, {
+        status: "ask",
+      }).then((x) => x.status)
+    ) {
+      case "deny":
+        throw new RejectedError(info.sessionID, info.id, info.callID)
+      case "allow":
+        return
+    }
+
     pending[input.sessionID] = pending[input.sessionID] || {}
     return new Promise<void>((resolve, reject) => {
       pending[input.sessionID][info.id] = {

+ 85 - 0
packages/opencode/src/plugin/index.ts

@@ -0,0 +1,85 @@
+import type { Hooks, Plugin as PluginInstance } from "@opencode-ai/plugin"
+import { App } from "../app/app"
+import { Config } from "../config/config"
+import { Bus } from "../bus"
+import { Log } from "../util/log"
+import { createOpencodeClient } from "@opencode-ai/sdk"
+import { Server } from "../server/server"
+import { pathOr } from "remeda"
+
+export namespace Plugin {
+  const log = Log.create({ service: "plugin" })
+
+  const state = App.state("plugin", async (app) => {
+    const client = createOpencodeClient({
+      baseUrl: "http://localhost:4096",
+      fetch: async (...args) => Server.app().fetch(...args),
+    })
+    const config = await Config.get()
+    const hooks = []
+    for (const plugin of config.plugin ?? []) {
+      log.info("loading plugin", { path: plugin })
+      const mod = await import(plugin)
+      for (const [_name, fn] of Object.entries<PluginInstance>(mod)) {
+        const init = await fn({
+          client,
+          app,
+          $: Bun.$,
+        })
+        hooks.push(init)
+      }
+    }
+
+    return {
+      hooks,
+    }
+  })
+
+  type Path<T, Prefix extends string = ""> = T extends object
+    ? {
+        [K in keyof T]: K extends string
+          ? T[K] extends Function | undefined
+            ? `${Prefix}${K}`
+            : Path<T[K], `${Prefix}${K}.`>
+          : never
+      }[keyof T]
+    : never
+
+  export type FunctionFromKey<T, P extends Path<T>> = P extends `${infer K}.${infer R}`
+    ? K extends keyof T
+      ? R extends Path<T[K]>
+        ? FunctionFromKey<T[K], R>
+        : never
+      : never
+    : P extends keyof T
+      ? T[P]
+      : never
+
+  export async function trigger<
+    Name extends Path<Required<Hooks>>,
+    Input = Parameters<FunctionFromKey<Required<Hooks>, Name>>[0],
+    Output = Parameters<FunctionFromKey<Required<Hooks>, Name>>[1],
+  >(fn: Name, input: Input, output: Output): Promise<Output> {
+    if (!fn) return output
+    const path = fn.split(".")
+    for (const hook of await state().then((x) => x.hooks)) {
+      // @ts-expect-error
+      const fn = pathOr(hook, path, undefined)
+      if (!fn) continue
+      // @ts-expect-error
+      await fn(input, output)
+    }
+    return output
+  }
+
+  export function init() {
+    Bus.subscribeAll(async (input) => {
+      const hooks = await state().then((x) => x.hooks)
+      for (const hook of hooks) {
+        hook["event"]?.({
+          event: input,
+        })
+      }
+    })
+  }
+}

+ 18 - 14
packages/opencode/src/provider/provider.ts

@@ -97,7 +97,7 @@ export namespace Provider {
                     Array.isArray(msg.content) && msg.content.some((part: any) => part.type === "image_url"),
                 )
               }
-            } catch { }
+            } catch {}
             const headers: Record<string, string> = {
               ...init.headers,
               ...copilot.HEADERS,
@@ -283,26 +283,26 @@ export namespace Provider {
           cost:
             !model.cost && !existing?.cost
               ? {
-                input: 0,
-                output: 0,
-                cache_read: 0,
-                cache_write: 0,
-              }
+                  input: 0,
+                  output: 0,
+                  cache_read: 0,
+                  cache_write: 0,
+                }
               : {
-                cache_read: 0,
-                cache_write: 0,
-                ...existing?.cost,
-                ...model.cost,
-              },
+                  cache_read: 0,
+                  cache_write: 0,
+                  ...existing?.cost,
+                  ...model.cost,
+                },
           options: {
             ...existing?.options,
             ...model.options,
           },
           limit: model.limit ??
             existing?.limit ?? {
-            context: 0,
-            output: 0,
-          },
+              context: 0,
+              output: 0,
+            },
         }
         parsed.models[modelID] = parsedModel
       }
@@ -386,6 +386,10 @@ export namespace Provider {
     })
   }
 
+  export async function getProvider(providerID: string) {
+    return state().then((s) => s.providers[providerID])
+  }
+
   export async function getModel(providerID: string, modelID: string) {
     const key = `${providerID}/${modelID}`
     const s = await state()

+ 3 - 2
packages/opencode/src/server/server.ts

@@ -19,6 +19,7 @@ import { MessageV2 } from "../session/message-v2"
 import { Mode } from "../session/mode"
 import { callTui, TuiRoute } from "./tui"
 import { Permission } from "../permission"
+import { lazy } from "../util/lazy"
 
 const ERRORS = {
   400: {
@@ -48,7 +49,7 @@ export namespace Server {
     Connected: Bus.event("server.connected", z.object({})),
   }
 
-  function app() {
+  export const app = lazy(() => {
     const app = new Hono()
 
     const result = app
@@ -1022,7 +1023,7 @@ export namespace Server {
       .route("/tui/control", TuiRoute)
 
     return result
-  }
+  })
 
   export async function openapi() {
     const a = app()

+ 46 - 5
packages/opencode/src/session/index.ts

@@ -41,6 +41,7 @@ import { LSP } from "../lsp"
 import { ReadTool } from "../tool/read"
 import { mergeDeep, pipe, splitWhen } from "remeda"
 import { ToolRegistry } from "../tool/registry"
+import { Plugin } from "../plugin"
 
 export namespace Session {
   const log = Log.create({ service: "session" })
@@ -571,7 +572,14 @@ export namespace Session {
         text: PROMPT_PLAN,
         synthetic: true,
       })
-
+    await Plugin.trigger(
+      "chat.message",
+      {},
+      {
+        message: userMsg,
+        parts: userParts,
+      },
+    )
     await updateMessage(userMsg)
     for (const part of userParts) {
       await updatePart(part)
@@ -716,6 +724,17 @@ export namespace Session {
         description: item.description,
         inputSchema: item.parameters as ZodSchema,
         async execute(args, options) {
+          await Plugin.trigger(
+            "tool.execute.before",
+            {
+              tool: item.id,
+              sessionID: input.sessionID,
+              callID: options.toolCallId,
+            },
+            {
+              args,
+            },
+          )
           await processor.track(options.toolCallId)
           const result = await item.execute(args, {
             sessionID: input.sessionID,
@@ -740,6 +759,15 @@ export namespace Session {
               }
             },
           })
+          await Plugin.trigger(
+            "tool.execute.after",
+            {
+              tool: item.id,
+              sessionID: input.sessionID,
+              callID: options.toolCallId,
+            },
+            result,
+          )
           return result
         },
         toModelOutput(result) {
@@ -776,6 +804,21 @@ export namespace Session {
       tools[key] = item
     }
 
+    const params = {
+      temperature: model.info.temperature
+        ? (mode.temperature ?? ProviderTransform.temperature(input.providerID, input.modelID))
+        : undefined,
+      topP: mode.topP ?? ProviderTransform.topP(input.providerID, input.modelID),
+    }
+    await Plugin.trigger(
+      "chat.params",
+      {
+        model: model.info,
+        provider: await Provider.getProvider(input.providerID),
+        message: userMsg,
+      },
+      params,
+    )
     const stream = streamText({
       onError(e) {
         log.error("streamText error", {
@@ -835,6 +878,8 @@ export namespace Session {
       providerOptions: {
         [input.providerID]: model.info.options,
       },
+      temperature: params.temperature,
+      topP: params.topP,
       messages: [
         ...system.map(
           (x): ModelMessage => ({
@@ -844,10 +889,6 @@ export namespace Session {
         ),
         ...MessageV2.toModelMessage(msgs),
       ],
-      temperature: model.info.temperature
-        ? (mode.temperature ?? ProviderTransform.temperature(input.providerID, input.modelID))
-        : undefined,
-      topP: mode.topP ?? ProviderTransform.topP(input.providerID, input.modelID),
       tools: model.info.tool_call === false ? undefined : tools,
       model: wrapLanguageModel({
         model: model.language,

+ 5 - 1
packages/opencode/tsconfig.json

@@ -1,5 +1,9 @@
 {
   "$schema": "https://json.schemastore.org/tsconfig",
   "extends": "@tsconfig/bun/tsconfig.json",
-  "compilerOptions": {}
+  "compilerOptions": {
+    "customConditions": [
+      "development"
+    ]
+  }
 }

+ 1 - 0
packages/plugin/.gitignore

@@ -0,0 +1 @@
+dist

+ 21 - 0
packages/plugin/package.json

@@ -0,0 +1,21 @@
+{
+  "$schema": "https://json.schemastore.org/package.json",
+  "name": "@opencode-ai/plugin",
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "typecheck": "tsc --noEmit"
+  },
+  "exports": {
+    ".": "./src/index.ts"
+  },
+  "files": [
+    "dist"
+  ],
+  "devDependencies": {
+    "typescript": "catalog:",
+    "@hey-api/openapi-ts": "0.80.1",
+    "@tsconfig/node22": "catalog:",
+    "@opencode-ai/sdk": "workspace:*"
+  }
+}

+ 18 - 0
packages/plugin/script/publish.ts

@@ -0,0 +1,18 @@
+#!/usr/bin/env bun
+
+const dir = new URL("..", import.meta.url).pathname
+process.chdir(dir)
+
+import { $ } from "bun"
+
+const snapshot = process.env["OPENCODE_SNAPSHOT"] === "true"
+
+await $`bun tsc`
+
+if (snapshot) {
+  await $`bun publish --tag snapshot --access public`
+  await $`git checkout package.json`
+}
+if (!snapshot) {
+  await $`bun publish --access public`
+}

+ 7 - 0
packages/plugin/src/example.ts

@@ -0,0 +1,7 @@
+import { Plugin } from "./index"
+
+export const ExamplePlugin: Plugin = async ({ app, client }) => {
+  return {
+    permission: {},
+  }
+}

+ 56 - 0
packages/plugin/src/index.ts

@@ -0,0 +1,56 @@
+import type { Event, createOpencodeClient, App, Model, Provider, Permission, UserMessage, Part } from "@opencode-ai/sdk"
+import { $ } from "bun"
+
+export type PluginInput = {
+  client: ReturnType<typeof createOpencodeClient>
+  app: App
+  $: $
+}
+export type Plugin = (input: PluginInput) => Promise<Hooks>
+
+export interface Hooks {
+  event?: (input: { event: Event }) => Promise<void>
+  chat?: {
+    /**
+     * Called when a new message is received
+     */
+    message?: (input: {}, output: { message: UserMessage; parts: Part[] }) => Promise<void>
+    /**
+     * Modify parameters sent to LLM
+     */
+    params?: (
+      input: { model: Model; provider: Provider; message: UserMessage },
+      output: { temperature: number; topP: number },
+    ) => Promise<void>
+  }
+  permission?: {
+    /**
+     * Called when a permission is asked
+     */
+    ask?: (input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise<void>
+  }
+  tool?: {
+    execute?: {
+      /**
+       * Called before a tool is executed
+       */
+      before?: (
+        input: { tool: string; sessionID: string; callID: string },
+        output: {
+          args: any
+        },
+      ) => Promise<void>
+      /**
+       * Called after a tool is executed
+       */
+      after?: (
+        input: { tool: string; sessionID: string; callID: string },
+        output: {
+          title: string
+          output: string
+          metadata: any
+        },
+      ) => Promise<void>
+    }
+  }
+}

+ 16 - 0
packages/plugin/tsconfig.json

@@ -0,0 +1,16 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig.json",
+  "extends": "@tsconfig/node22/tsconfig.json",
+  "compilerOptions": {
+    "outDir": "dist",
+    "module": "preserve",
+    "declaration": true,
+    "moduleResolution": "bundler",
+    "customConditions": [
+      "development"
+    ]
+  },
+  "include": [
+    "src"
+  ]
+}

+ 8 - 2
packages/sdk/js/package.json

@@ -1,10 +1,16 @@
 {
   "$schema": "https://json.schemastore.org/package.json",
   "name": "@opencode-ai/sdk",
-  "version": "0.0.0",
+  "version": "0.0.0-202508022246",
   "type": "module",
+  "scripts": {
+    "typecheck": "tsc --noEmit"
+  },
   "exports": {
-    ".": "./dist/index.js"
+    ".": {
+      "development": "./src/index.ts",
+      "import": "./dist/index.js"
+    }
   },
   "files": [
     "dist"

+ 1 - 0
packages/sdk/js/script/generate.ts

@@ -36,6 +36,7 @@ await createClient({
     },
   ],
 })
+await $`bun prettier --write src/gen`
 
 await $`rm -rf dist`
 await $`bun tsc`

+ 0 - 7
packages/sdk/js/script/publish.ts

@@ -5,20 +5,13 @@ process.chdir(dir)
 
 import { $ } from "bun"
 
-const version = process.env["OPENCODE_VERSION"]
-if (!version) {
-  throw new Error("OPENCODE_VERSION is required")
-}
-
 await import("./generate")
 
 const snapshot = process.env["OPENCODE_SNAPSHOT"] === "true"
 
-await $`bun pm version --allow-same-version --no-git-tag-version ${version}`
 if (snapshot) {
   await $`bun publish --tag snapshot`
 }
 if (!snapshot) {
   await $`bun publish`
 }
-await $`bun pm version 0.0.0 --no-git-tag-version`

+ 10 - 6
packages/sdk/js/src/gen/client.gen.ts

@@ -1,7 +1,7 @@
 // This file is auto-generated by @hey-api/openapi-ts
 
-import type { ClientOptions } from './types.gen';
-import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from './client';
+import type { ClientOptions } from "./types.gen"
+import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from "./client"
 
 /**
  * The `createClientConfig()` function will be called on client initialization
@@ -11,8 +11,12 @@ import { type Config, type ClientOptions as DefaultClientOptions, createClient,
  * `setConfig()`. This is useful for example if you're using Next.js
  * to ensure your client always has the correct values.
  */
-export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (override?: Config<DefaultClientOptions & T>) => Config<Required<DefaultClientOptions> & T>;
+export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (
+  override?: Config<DefaultClientOptions & T>,
+) => Config<Required<DefaultClientOptions> & T>
 
-export const client = createClient(createConfig<ClientOptions>({
-    baseUrl: 'http://localhost:4096'
-}));
+export const client = createClient(
+  createConfig<ClientOptions>({
+    baseUrl: "http://localhost:4096",
+  }),
+)

+ 72 - 82
packages/sdk/js/src/gen/client/client.ts

@@ -1,4 +1,4 @@
-import type { Client, Config, RequestOptions } from './types';
+import type { Client, Config, RequestOptions } from "./types"
 import {
   buildUrl,
   createConfig,
@@ -7,189 +7,179 @@ import {
   mergeConfigs,
   mergeHeaders,
   setAuthParams,
-} from './utils';
+} from "./utils"
 
-type ReqInit = Omit<RequestInit, 'body' | 'headers'> & {
-  body?: any;
-  headers: ReturnType<typeof mergeHeaders>;
-};
+type ReqInit = Omit<RequestInit, "body" | "headers"> & {
+  body?: any
+  headers: ReturnType<typeof mergeHeaders>
+}
 
 export const createClient = (config: Config = {}): Client => {
-  let _config = mergeConfigs(createConfig(), config);
+  let _config = mergeConfigs(createConfig(), config)
 
-  const getConfig = (): Config => ({ ..._config });
+  const getConfig = (): Config => ({ ..._config })
 
   const setConfig = (config: Config): Config => {
-    _config = mergeConfigs(_config, config);
-    return getConfig();
-  };
-
-  const interceptors = createInterceptors<
-    Request,
-    Response,
-    unknown,
-    RequestOptions
-  >();
-
-  const request: Client['request'] = async (options) => {
+    _config = mergeConfigs(_config, config)
+    return getConfig()
+  }
+
+  const interceptors = createInterceptors<Request, Response, unknown, RequestOptions>()
+
+  const request: Client["request"] = async (options) => {
     const opts = {
       ..._config,
       ...options,
       fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
       headers: mergeHeaders(_config.headers, options.headers),
-    };
+    }
 
     if (opts.security) {
       await setAuthParams({
         ...opts,
         security: opts.security,
-      });
+      })
     }
 
     if (opts.requestValidator) {
-      await opts.requestValidator(opts);
+      await opts.requestValidator(opts)
     }
 
     if (opts.body && opts.bodySerializer) {
-      opts.body = opts.bodySerializer(opts.body);
+      opts.body = opts.bodySerializer(opts.body)
     }
 
     // remove Content-Type header if body is empty to avoid sending invalid requests
-    if (opts.body === undefined || opts.body === '') {
-      opts.headers.delete('Content-Type');
+    if (opts.body === undefined || opts.body === "") {
+      opts.headers.delete("Content-Type")
     }
 
-    const url = buildUrl(opts);
+    const url = buildUrl(opts)
     const requestInit: ReqInit = {
-      redirect: 'follow',
+      redirect: "follow",
       ...opts,
-    };
+    }
 
-    let request = new Request(url, requestInit);
+    let request = new Request(url, requestInit)
 
     for (const fn of interceptors.request._fns) {
       if (fn) {
-        request = await fn(request, opts);
+        request = await fn(request, opts)
       }
     }
 
     // fetch must be assigned here, otherwise it would throw the error:
     // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
-    const _fetch = opts.fetch!;
-    let response = await _fetch(request);
+    const _fetch = opts.fetch!
+    let response = await _fetch(request)
 
     for (const fn of interceptors.response._fns) {
       if (fn) {
-        response = await fn(response, request, opts);
+        response = await fn(response, request, opts)
       }
     }
 
     const result = {
       request,
       response,
-    };
+    }
 
     if (response.ok) {
-      if (
-        response.status === 204 ||
-        response.headers.get('Content-Length') === '0'
-      ) {
-        return opts.responseStyle === 'data'
+      if (response.status === 204 || response.headers.get("Content-Length") === "0") {
+        return opts.responseStyle === "data"
           ? {}
           : {
               data: {},
               ...result,
-            };
+            }
       }
 
       const parseAs =
-        (opts.parseAs === 'auto'
-          ? getParseAs(response.headers.get('Content-Type'))
-          : opts.parseAs) ?? 'json';
+        (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json"
 
-      let data: any;
+      let data: any
       switch (parseAs) {
-        case 'arrayBuffer':
-        case 'blob':
-        case 'formData':
-        case 'json':
-        case 'text':
-          data = await response[parseAs]();
-          break;
-        case 'stream':
-          return opts.responseStyle === 'data'
+        case "arrayBuffer":
+        case "blob":
+        case "formData":
+        case "json":
+        case "text":
+          data = await response[parseAs]()
+          break
+        case "stream":
+          return opts.responseStyle === "data"
             ? response.body
             : {
                 data: response.body,
                 ...result,
-              };
+              }
       }
 
-      if (parseAs === 'json') {
+      if (parseAs === "json") {
         if (opts.responseValidator) {
-          await opts.responseValidator(data);
+          await opts.responseValidator(data)
         }
 
         if (opts.responseTransformer) {
-          data = await opts.responseTransformer(data);
+          data = await opts.responseTransformer(data)
         }
       }
 
-      return opts.responseStyle === 'data'
+      return opts.responseStyle === "data"
         ? data
         : {
             data,
             ...result,
-          };
+          }
     }
 
-    const textError = await response.text();
-    let jsonError: unknown;
+    const textError = await response.text()
+    let jsonError: unknown
 
     try {
-      jsonError = JSON.parse(textError);
+      jsonError = JSON.parse(textError)
     } catch {
       // noop
     }
 
-    const error = jsonError ?? textError;
-    let finalError = error;
+    const error = jsonError ?? textError
+    let finalError = error
 
     for (const fn of interceptors.error._fns) {
       if (fn) {
-        finalError = (await fn(error, response, request, opts)) as string;
+        finalError = (await fn(error, response, request, opts)) as string
       }
     }
 
-    finalError = finalError || ({} as string);
+    finalError = finalError || ({} as string)
 
     if (opts.throwOnError) {
-      throw finalError;
+      throw finalError
     }
 
     // TODO: we probably want to return error and improve types
-    return opts.responseStyle === 'data'
+    return opts.responseStyle === "data"
       ? undefined
       : {
           error: finalError,
           ...result,
-        };
-  };
+        }
+  }
 
   return {
     buildUrl,
-    connect: (options) => request({ ...options, method: 'CONNECT' }),
-    delete: (options) => request({ ...options, method: 'DELETE' }),
-    get: (options) => request({ ...options, method: 'GET' }),
+    connect: (options) => request({ ...options, method: "CONNECT" }),
+    delete: (options) => request({ ...options, method: "DELETE" }),
+    get: (options) => request({ ...options, method: "GET" }),
     getConfig,
-    head: (options) => request({ ...options, method: 'HEAD' }),
+    head: (options) => request({ ...options, method: "HEAD" }),
     interceptors,
-    options: (options) => request({ ...options, method: 'OPTIONS' }),
-    patch: (options) => request({ ...options, method: 'PATCH' }),
-    post: (options) => request({ ...options, method: 'POST' }),
-    put: (options) => request({ ...options, method: 'PUT' }),
+    options: (options) => request({ ...options, method: "OPTIONS" }),
+    patch: (options) => request({ ...options, method: "PATCH" }),
+    post: (options) => request({ ...options, method: "POST" }),
+    put: (options) => request({ ...options, method: "PUT" }),
     request,
     setConfig,
-    trace: (options) => request({ ...options, method: 'TRACE' }),
-  };
-};
+    trace: (options) => request({ ...options, method: "TRACE" }),
+  }
+}

+ 7 - 11
packages/sdk/js/src/gen/client/index.ts

@@ -1,12 +1,8 @@
-export type { Auth } from '../core/auth';
-export type { QuerySerializerOptions } from '../core/bodySerializer';
-export {
-  formDataBodySerializer,
-  jsonBodySerializer,
-  urlSearchParamsBodySerializer,
-} from '../core/bodySerializer';
-export { buildClientParams } from '../core/params';
-export { createClient } from './client';
+export type { Auth } from "../core/auth"
+export type { QuerySerializerOptions } from "../core/bodySerializer"
+export { formDataBodySerializer, jsonBodySerializer, urlSearchParamsBodySerializer } from "../core/bodySerializer"
+export { buildClientParams } from "../core/params"
+export { createClient } from "./client"
 export type {
   Client,
   ClientOptions,
@@ -18,5 +14,5 @@ export type {
   RequestResult,
   ResponseStyle,
   TDataShape,
-} from './types';
-export { createConfig, mergeHeaders } from './utils';
+} from "./types"
+export { createConfig, mergeHeaders } from "./utils"

+ 67 - 98
packages/sdk/js/src/gen/client/types.ts

@@ -1,33 +1,30 @@
-import type { Auth } from '../core/auth';
-import type {
-  Client as CoreClient,
-  Config as CoreConfig,
-} from '../core/types';
-import type { Middleware } from './utils';
+import type { Auth } from "../core/auth"
+import type { Client as CoreClient, Config as CoreConfig } from "../core/types"
+import type { Middleware } from "./utils"
 
-export type ResponseStyle = 'data' | 'fields';
+export type ResponseStyle = "data" | "fields"
 
 export interface Config<T extends ClientOptions = ClientOptions>
-  extends Omit<RequestInit, 'body' | 'headers' | 'method'>,
+  extends Omit<RequestInit, "body" | "headers" | "method">,
     CoreConfig {
   /**
    * Base URL for all requests made by this client.
    */
-  baseUrl?: T['baseUrl'];
+  baseUrl?: T["baseUrl"]
   /**
    * Fetch API implementation. You can use this option to provide a custom
    * fetch instance.
    *
    * @default globalThis.fetch
    */
-  fetch?: (request: Request) => ReturnType<typeof fetch>;
+  fetch?: (request: Request) => ReturnType<typeof fetch>
   /**
    * Please don't use the Fetch client for Next.js applications. The `next`
    * options won't have any effect.
    *
    * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead.
    */
-  next?: never;
+  next?: never
   /**
    * Return the response data parsed in a specified format. By default, `auto`
    * will infer the appropriate method from the `Content-Type` response header.
@@ -36,135 +33,118 @@ export interface Config<T extends ClientOptions = ClientOptions>
    *
    * @default 'auto'
    */
-  parseAs?:
-    | 'arrayBuffer'
-    | 'auto'
-    | 'blob'
-    | 'formData'
-    | 'json'
-    | 'stream'
-    | 'text';
+  parseAs?: "arrayBuffer" | "auto" | "blob" | "formData" | "json" | "stream" | "text"
   /**
    * Should we return only data or multiple fields (data, error, response, etc.)?
    *
    * @default 'fields'
    */
-  responseStyle?: ResponseStyle;
+  responseStyle?: ResponseStyle
   /**
    * Throw an error instead of returning it in the response?
    *
    * @default false
    */
-  throwOnError?: T['throwOnError'];
+  throwOnError?: T["throwOnError"]
 }
 
 export interface RequestOptions<
-  TResponseStyle extends ResponseStyle = 'fields',
+  TResponseStyle extends ResponseStyle = "fields",
   ThrowOnError extends boolean = boolean,
   Url extends string = string,
 > extends Config<{
-    responseStyle: TResponseStyle;
-    throwOnError: ThrowOnError;
+    responseStyle: TResponseStyle
+    throwOnError: ThrowOnError
   }> {
   /**
    * Any body that you want to add to your request.
    *
    * {@link https://developer.mozilla.org/docs/Web/API/fetch#body}
    */
-  body?: unknown;
-  path?: Record<string, unknown>;
-  query?: Record<string, unknown>;
+  body?: unknown
+  path?: Record<string, unknown>
+  query?: Record<string, unknown>
   /**
    * Security mechanism(s) to use for the request.
    */
-  security?: ReadonlyArray<Auth>;
-  url: Url;
+  security?: ReadonlyArray<Auth>
+  url: Url
 }
 
 export type RequestResult<
   TData = unknown,
   TError = unknown,
   ThrowOnError extends boolean = boolean,
-  TResponseStyle extends ResponseStyle = 'fields',
+  TResponseStyle extends ResponseStyle = "fields",
 > = ThrowOnError extends true
   ? Promise<
-      TResponseStyle extends 'data'
+      TResponseStyle extends "data"
         ? TData extends Record<string, unknown>
           ? TData[keyof TData]
           : TData
         : {
-            data: TData extends Record<string, unknown>
-              ? TData[keyof TData]
-              : TData;
-            request: Request;
-            response: Response;
+            data: TData extends Record<string, unknown> ? TData[keyof TData] : TData
+            request: Request
+            response: Response
           }
     >
   : Promise<
-      TResponseStyle extends 'data'
-        ?
-            | (TData extends Record<string, unknown>
-                ? TData[keyof TData]
-                : TData)
-            | undefined
+      TResponseStyle extends "data"
+        ? (TData extends Record<string, unknown> ? TData[keyof TData] : TData) | undefined
         : (
             | {
-                data: TData extends Record<string, unknown>
-                  ? TData[keyof TData]
-                  : TData;
-                error: undefined;
+                data: TData extends Record<string, unknown> ? TData[keyof TData] : TData
+                error: undefined
               }
             | {
-                data: undefined;
-                error: TError extends Record<string, unknown>
-                  ? TError[keyof TError]
-                  : TError;
+                data: undefined
+                error: TError extends Record<string, unknown> ? TError[keyof TError] : TError
               }
           ) & {
-            request: Request;
-            response: Response;
+            request: Request
+            response: Response
           }
-    >;
+    >
 
 export interface ClientOptions {
-  baseUrl?: string;
-  responseStyle?: ResponseStyle;
-  throwOnError?: boolean;
+  baseUrl?: string
+  responseStyle?: ResponseStyle
+  throwOnError?: boolean
 }
 
 type MethodFn = <
   TData = unknown,
   TError = unknown,
   ThrowOnError extends boolean = false,
-  TResponseStyle extends ResponseStyle = 'fields',
+  TResponseStyle extends ResponseStyle = "fields",
 >(
-  options: Omit<RequestOptions<TResponseStyle, ThrowOnError>, 'method'>,
-) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
+  options: Omit<RequestOptions<TResponseStyle, ThrowOnError>, "method">,
+) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>
 
 type RequestFn = <
   TData = unknown,
   TError = unknown,
   ThrowOnError extends boolean = false,
-  TResponseStyle extends ResponseStyle = 'fields',
+  TResponseStyle extends ResponseStyle = "fields",
 >(
-  options: Omit<RequestOptions<TResponseStyle, ThrowOnError>, 'method'> &
-    Pick<Required<RequestOptions<TResponseStyle, ThrowOnError>>, 'method'>,
-) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
+  options: Omit<RequestOptions<TResponseStyle, ThrowOnError>, "method"> &
+    Pick<Required<RequestOptions<TResponseStyle, ThrowOnError>>, "method">,
+) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>
 
 type BuildUrlFn = <
   TData extends {
-    body?: unknown;
-    path?: Record<string, unknown>;
-    query?: Record<string, unknown>;
-    url: string;
+    body?: unknown
+    path?: Record<string, unknown>
+    query?: Record<string, unknown>
+    url: string
   },
 >(
-  options: Pick<TData, 'url'> & Options<TData>,
-) => string;
+  options: Pick<TData, "url"> & Options<TData>,
+) => string
 
 export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn> & {
-  interceptors: Middleware<Request, Response, unknown, RequestOptions>;
-};
+  interceptors: Middleware<Request, Response, unknown, RequestOptions>
+}
 
 /**
  * The `createClientConfig()` function will be called on client initialization
@@ -176,47 +156,36 @@ export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn> & {
  */
 export type CreateClientConfig<T extends ClientOptions = ClientOptions> = (
   override?: Config<ClientOptions & T>,
-) => Config<Required<ClientOptions> & T>;
+) => Config<Required<ClientOptions> & T>
 
 export interface TDataShape {
-  body?: unknown;
-  headers?: unknown;
-  path?: unknown;
-  query?: unknown;
-  url: string;
+  body?: unknown
+  headers?: unknown
+  path?: unknown
+  query?: unknown
+  url: string
 }
 
-type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>;
+type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>
 
 export type Options<
   TData extends TDataShape = TDataShape,
   ThrowOnError extends boolean = boolean,
-  TResponseStyle extends ResponseStyle = 'fields',
-> = OmitKeys<
-  RequestOptions<TResponseStyle, ThrowOnError>,
-  'body' | 'path' | 'query' | 'url'
-> &
-  Omit<TData, 'url'>;
+  TResponseStyle extends ResponseStyle = "fields",
+> = OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, "body" | "path" | "query" | "url"> & Omit<TData, "url">
 
 export type OptionsLegacyParser<
   TData = unknown,
   ThrowOnError extends boolean = boolean,
-  TResponseStyle extends ResponseStyle = 'fields',
+  TResponseStyle extends ResponseStyle = "fields",
 > = TData extends { body?: any }
   ? TData extends { headers?: any }
-    ? OmitKeys<
-        RequestOptions<TResponseStyle, ThrowOnError>,
-        'body' | 'headers' | 'url'
-      > &
-        TData
-    : OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, 'body' | 'url'> &
+    ? OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, "body" | "headers" | "url"> & TData
+    : OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, "body" | "url"> &
         TData &
-        Pick<RequestOptions<TResponseStyle, ThrowOnError>, 'headers'>
+        Pick<RequestOptions<TResponseStyle, ThrowOnError>, "headers">
   : TData extends { headers?: any }
-    ? OmitKeys<
-        RequestOptions<TResponseStyle, ThrowOnError>,
-        'headers' | 'url'
-      > &
+    ? OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, "headers" | "url"> &
         TData &
-        Pick<RequestOptions<TResponseStyle, ThrowOnError>, 'body'>
-    : OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, 'url'> & TData;
+        Pick<RequestOptions<TResponseStyle, ThrowOnError>, "body">
+    : OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, "url"> & TData

+ 156 - 200
packages/sdk/js/src/gen/client/utils.ts

@@ -1,64 +1,54 @@
-import { getAuthToken } from '../core/auth';
-import type {
-  QuerySerializer,
-  QuerySerializerOptions,
-} from '../core/bodySerializer';
-import { jsonBodySerializer } from '../core/bodySerializer';
-import {
-  serializeArrayParam,
-  serializeObjectParam,
-  serializePrimitiveParam,
-} from '../core/pathSerializer';
-import type { Client, ClientOptions, Config, RequestOptions } from './types';
+import { getAuthToken } from "../core/auth"
+import type { QuerySerializer, QuerySerializerOptions } from "../core/bodySerializer"
+import { jsonBodySerializer } from "../core/bodySerializer"
+import { serializeArrayParam, serializeObjectParam, serializePrimitiveParam } from "../core/pathSerializer"
+import type { Client, ClientOptions, Config, RequestOptions } from "./types"
 
 interface PathSerializer {
-  path: Record<string, unknown>;
-  url: string;
+  path: Record<string, unknown>
+  url: string
 }
 
-const PATH_PARAM_RE = /\{[^{}]+\}/g;
+const PATH_PARAM_RE = /\{[^{}]+\}/g
 
-type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited';
-type MatrixStyle = 'label' | 'matrix' | 'simple';
-type ArraySeparatorStyle = ArrayStyle | MatrixStyle;
+type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"
+type MatrixStyle = "label" | "matrix" | "simple"
+type ArraySeparatorStyle = ArrayStyle | MatrixStyle
 
 const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => {
-  let url = _url;
-  const matches = _url.match(PATH_PARAM_RE);
+  let url = _url
+  const matches = _url.match(PATH_PARAM_RE)
   if (matches) {
     for (const match of matches) {
-      let explode = false;
-      let name = match.substring(1, match.length - 1);
-      let style: ArraySeparatorStyle = 'simple';
+      let explode = false
+      let name = match.substring(1, match.length - 1)
+      let style: ArraySeparatorStyle = "simple"
 
-      if (name.endsWith('*')) {
-        explode = true;
-        name = name.substring(0, name.length - 1);
+      if (name.endsWith("*")) {
+        explode = true
+        name = name.substring(0, name.length - 1)
       }
 
-      if (name.startsWith('.')) {
-        name = name.substring(1);
-        style = 'label';
-      } else if (name.startsWith(';')) {
-        name = name.substring(1);
-        style = 'matrix';
+      if (name.startsWith(".")) {
+        name = name.substring(1)
+        style = "label"
+      } else if (name.startsWith(";")) {
+        name = name.substring(1)
+        style = "matrix"
       }
 
-      const value = path[name];
+      const value = path[name]
 
       if (value === undefined || value === null) {
-        continue;
+        continue
       }
 
       if (Array.isArray(value)) {
-        url = url.replace(
-          match,
-          serializeArrayParam({ explode, name, style, value }),
-        );
-        continue;
+        url = url.replace(match, serializeArrayParam({ explode, name, style, value }))
+        continue
       }
 
-      if (typeof value === 'object') {
+      if (typeof value === "object") {
         url = url.replace(
           match,
           serializeObjectParam({
@@ -68,43 +58,37 @@ const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => {
             value: value as Record<string, unknown>,
             valueOnly: true,
           }),
-        );
-        continue;
+        )
+        continue
       }
 
-      if (style === 'matrix') {
+      if (style === "matrix") {
         url = url.replace(
           match,
           `;${serializePrimitiveParam({
             name,
             value: value as string,
           })}`,
-        );
-        continue;
+        )
+        continue
       }
 
-      const replaceValue = encodeURIComponent(
-        style === 'label' ? `.${value as string}` : (value as string),
-      );
-      url = url.replace(match, replaceValue);
+      const replaceValue = encodeURIComponent(style === "label" ? `.${value as string}` : (value as string))
+      url = url.replace(match, replaceValue)
     }
   }
-  return url;
-};
-
-export const createQuerySerializer = <T = unknown>({
-  allowReserved,
-  array,
-  object,
-}: QuerySerializerOptions = {}) => {
+  return url
+}
+
+export const createQuerySerializer = <T = unknown>({ allowReserved, array, object }: QuerySerializerOptions = {}) => {
   const querySerializer = (queryParams: T) => {
-    const search: string[] = [];
-    if (queryParams && typeof queryParams === 'object') {
+    const search: string[] = []
+    if (queryParams && typeof queryParams === "object") {
       for (const name in queryParams) {
-        const value = queryParams[name];
+        const value = queryParams[name]
 
         if (value === undefined || value === null) {
-          continue;
+          continue
         }
 
         if (Array.isArray(value)) {
@@ -112,129 +96,120 @@ export const createQuerySerializer = <T = unknown>({
             allowReserved,
             explode: true,
             name,
-            style: 'form',
+            style: "form",
             value,
             ...array,
-          });
-          if (serializedArray) search.push(serializedArray);
-        } else if (typeof value === 'object') {
+          })
+          if (serializedArray) search.push(serializedArray)
+        } else if (typeof value === "object") {
           const serializedObject = serializeObjectParam({
             allowReserved,
             explode: true,
             name,
-            style: 'deepObject',
+            style: "deepObject",
             value: value as Record<string, unknown>,
             ...object,
-          });
-          if (serializedObject) search.push(serializedObject);
+          })
+          if (serializedObject) search.push(serializedObject)
         } else {
           const serializedPrimitive = serializePrimitiveParam({
             allowReserved,
             name,
             value: value as string,
-          });
-          if (serializedPrimitive) search.push(serializedPrimitive);
+          })
+          if (serializedPrimitive) search.push(serializedPrimitive)
         }
       }
     }
-    return search.join('&');
-  };
-  return querySerializer;
-};
+    return search.join("&")
+  }
+  return querySerializer
+}
 
 /**
  * Infers parseAs value from provided Content-Type header.
  */
-export const getParseAs = (
-  contentType: string | null,
-): Exclude<Config['parseAs'], 'auto'> => {
+export const getParseAs = (contentType: string | null): Exclude<Config["parseAs"], "auto"> => {
   if (!contentType) {
     // If no Content-Type header is provided, the best we can do is return the raw response body,
     // which is effectively the same as the 'stream' option.
-    return 'stream';
+    return "stream"
   }
 
-  const cleanContent = contentType.split(';')[0]?.trim();
+  const cleanContent = contentType.split(";")[0]?.trim()
 
   if (!cleanContent) {
-    return;
+    return
   }
 
-  if (
-    cleanContent.startsWith('application/json') ||
-    cleanContent.endsWith('+json')
-  ) {
-    return 'json';
+  if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
+    return "json"
   }
 
-  if (cleanContent === 'multipart/form-data') {
-    return 'formData';
+  if (cleanContent === "multipart/form-data") {
+    return "formData"
   }
 
-  if (
-    ['application/', 'audio/', 'image/', 'video/'].some((type) =>
-      cleanContent.startsWith(type),
-    )
-  ) {
-    return 'blob';
+  if (["application/", "audio/", "image/", "video/"].some((type) => cleanContent.startsWith(type))) {
+    return "blob"
   }
 
-  if (cleanContent.startsWith('text/')) {
-    return 'text';
+  if (cleanContent.startsWith("text/")) {
+    return "text"
   }
 
-  return;
-};
+  return
+}
 
 export const setAuthParams = async ({
   security,
   ...options
-}: Pick<Required<RequestOptions>, 'security'> &
-  Pick<RequestOptions, 'auth' | 'query'> & {
-    headers: Headers;
+}: Pick<Required<RequestOptions>, "security"> &
+  Pick<RequestOptions, "auth" | "query"> & {
+    headers: Headers
   }) => {
   for (const auth of security) {
-    const token = await getAuthToken(auth, options.auth);
+    const token = await getAuthToken(auth, options.auth)
 
     if (!token) {
-      continue;
+      continue
     }
 
-    const name = auth.name ?? 'Authorization';
+    const name = auth.name ?? "Authorization"
 
     switch (auth.in) {
-      case 'query':
+      case "query":
         if (!options.query) {
-          options.query = {};
+          options.query = {}
         }
-        options.query[name] = token;
-        break;
-      case 'cookie':
-        options.headers.append('Cookie', `${name}=${token}`);
-        break;
-      case 'header':
+        options.query[name] = token
+        break
+      case "cookie":
+        options.headers.append("Cookie", `${name}=${token}`)
+        break
+      case "header":
       default:
-        options.headers.set(name, token);
-        break;
+        options.headers.set(name, token)
+        break
     }
 
-    return;
+    return
   }
-};
+}
 
-export const buildUrl: Client['buildUrl'] = (options) => {
+export const buildUrl: Client["buildUrl"] = (options) => {
   const url = getUrl({
     baseUrl: options.baseUrl as string,
     path: options.path,
     query: options.query,
     querySerializer:
-      typeof options.querySerializer === 'function'
+      typeof options.querySerializer === "function"
         ? options.querySerializer
         : createQuerySerializer(options.querySerializer),
     url: options.url,
-  });
-  return url;
-};
+  })
+  return url
+}
 
 export const getUrl = ({
   baseUrl,
@@ -243,144 +218,125 @@ export const getUrl = ({
   querySerializer,
   url: _url,
 }: {
-  baseUrl?: string;
-  path?: Record<string, unknown>;
-  query?: Record<string, unknown>;
-  querySerializer: QuerySerializer;
-  url: string;
+  baseUrl?: string
+  path?: Record<string, unknown>
+  query?: Record<string, unknown>
+  querySerializer: QuerySerializer
+  url: string
 }) => {
-  const pathUrl = _url.startsWith('/') ? _url : `/${_url}`;
-  let url = (baseUrl ?? '') + pathUrl;
+  const pathUrl = _url.startsWith("/") ? _url : `/${_url}`
+  let url = (baseUrl ?? "") + pathUrl
   if (path) {
-    url = defaultPathSerializer({ path, url });
+    url = defaultPathSerializer({ path, url })
   }
-  let search = query ? querySerializer(query) : '';
-  if (search.startsWith('?')) {
-    search = search.substring(1);
+  let search = query ? querySerializer(query) : ""
+  if (search.startsWith("?")) {
+    search = search.substring(1)
   }
   if (search) {
-    url += `?${search}`;
+    url += `?${search}`
   }
-  return url;
-};
+  return url
+}
 
 export const mergeConfigs = (a: Config, b: Config): Config => {
-  const config = { ...a, ...b };
-  if (config.baseUrl?.endsWith('/')) {
-    config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
+  const config = { ...a, ...b }
+  if (config.baseUrl?.endsWith("/")) {
+    config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1)
   }
-  config.headers = mergeHeaders(a.headers, b.headers);
-  return config;
-};
-
-export const mergeHeaders = (
-  ...headers: Array<Required<Config>['headers'] | undefined>
-): Headers => {
-  const mergedHeaders = new Headers();
+  config.headers = mergeHeaders(a.headers, b.headers)
+  return config
+}
+
+export const mergeHeaders = (...headers: Array<Required<Config>["headers"] | undefined>): Headers => {
+  const mergedHeaders = new Headers()
   for (const header of headers) {
-    if (!header || typeof header !== 'object') {
-      continue;
+    if (!header || typeof header !== "object") {
+      continue
     }
 
-    const iterator =
-      header instanceof Headers ? header.entries() : Object.entries(header);
+    const iterator = header instanceof Headers ? header.entries() : Object.entries(header)
 
     for (const [key, value] of iterator) {
       if (value === null) {
-        mergedHeaders.delete(key);
+        mergedHeaders.delete(key)
       } else if (Array.isArray(value)) {
         for (const v of value) {
-          mergedHeaders.append(key, v as string);
+          mergedHeaders.append(key, v as string)
         }
       } else if (value !== undefined) {
         // assume object headers are meant to be JSON stringified, i.e. their
         // content value in OpenAPI specification is 'application/json'
-        mergedHeaders.set(
-          key,
-          typeof value === 'object' ? JSON.stringify(value) : (value as string),
-        );
+        mergedHeaders.set(key, typeof value === "object" ? JSON.stringify(value) : (value as string))
       }
     }
   }
-  return mergedHeaders;
-};
+  return mergedHeaders
+}
 
 type ErrInterceptor<Err, Res, Req, Options> = (
   error: Err,
   response: Res,
   request: Req,
   options: Options,
-) => Err | Promise<Err>;
+) => Err | Promise<Err>
 
-type ReqInterceptor<Req, Options> = (
-  request: Req,
-  options: Options,
-) => Req | Promise<Req>;
+type ReqInterceptor<Req, Options> = (request: Req, options: Options) => Req | Promise<Req>
 
-type ResInterceptor<Res, Req, Options> = (
-  response: Res,
-  request: Req,
-  options: Options,
-) => Res | Promise<Res>;
+type ResInterceptor<Res, Req, Options> = (response: Res, request: Req, options: Options) => Res | Promise<Res>
 
 class Interceptors<Interceptor> {
-  _fns: (Interceptor | null)[];
+  _fns: (Interceptor | null)[]
 
   constructor() {
-    this._fns = [];
+    this._fns = []
   }
 
   clear() {
-    this._fns = [];
+    this._fns = []
   }
 
   getInterceptorIndex(id: number | Interceptor): number {
-    if (typeof id === 'number') {
-      return this._fns[id] ? id : -1;
+    if (typeof id === "number") {
+      return this._fns[id] ? id : -1
     } else {
-      return this._fns.indexOf(id);
+      return this._fns.indexOf(id)
     }
   }
   exists(id: number | Interceptor) {
-    const index = this.getInterceptorIndex(id);
-    return !!this._fns[index];
+    const index = this.getInterceptorIndex(id)
+    return !!this._fns[index]
   }
 
   eject(id: number | Interceptor) {
-    const index = this.getInterceptorIndex(id);
+    const index = this.getInterceptorIndex(id)
     if (this._fns[index]) {
-      this._fns[index] = null;
+      this._fns[index] = null
     }
   }
 
   update(id: number | Interceptor, fn: Interceptor) {
-    const index = this.getInterceptorIndex(id);
+    const index = this.getInterceptorIndex(id)
     if (this._fns[index]) {
-      this._fns[index] = fn;
-      return id;
+      this._fns[index] = fn
+      return id
     } else {
-      return false;
+      return false
     }
   }
 
   use(fn: Interceptor) {
-    this._fns = [...this._fns, fn];
-    return this._fns.length - 1;
+    this._fns = [...this._fns, fn]
+    return this._fns.length - 1
   }
 }
 
 // `createInterceptors()` response, meant for external use as it does not
 // expose internals
 export interface Middleware<Req, Res, Err, Options> {
-  error: Pick<
-    Interceptors<ErrInterceptor<Err, Res, Req, Options>>,
-    'eject' | 'use'
-  >;
-  request: Pick<Interceptors<ReqInterceptor<Req, Options>>, 'eject' | 'use'>;
-  response: Pick<
-    Interceptors<ResInterceptor<Res, Req, Options>>,
-    'eject' | 'use'
-  >;
+  error: Pick<Interceptors<ErrInterceptor<Err, Res, Req, Options>>, "eject" | "use">
+  request: Pick<Interceptors<ReqInterceptor<Req, Options>>, "eject" | "use">
+  response: Pick<Interceptors<ResInterceptor<Res, Req, Options>>, "eject" | "use">
 }
 
 // do not add `Middleware` as return type so we can use _fns internally
@@ -388,30 +344,30 @@ export const createInterceptors = <Req, Res, Err, Options>() => ({
   error: new Interceptors<ErrInterceptor<Err, Res, Req, Options>>(),
   request: new Interceptors<ReqInterceptor<Req, Options>>(),
   response: new Interceptors<ResInterceptor<Res, Req, Options>>(),
-});
+})
 
 const defaultQuerySerializer = createQuerySerializer({
   allowReserved: false,
   array: {
     explode: true,
-    style: 'form',
+    style: "form",
   },
   object: {
     explode: true,
-    style: 'deepObject',
+    style: "deepObject",
   },
-});
+})
 
 const defaultHeaders = {
-  'Content-Type': 'application/json',
-};
+  "Content-Type": "application/json",
+}
 
 export const createConfig = <T extends ClientOptions = ClientOptions>(
   override: Config<Omit<ClientOptions, keyof T> & T> = {},
 ): Config<Omit<ClientOptions, keyof T> & T> => ({
   ...jsonBodySerializer,
   headers: defaultHeaders,
-  parseAs: 'auto',
+  parseAs: "auto",
   querySerializer: defaultQuerySerializer,
   ...override,
-});
+})

+ 13 - 14
packages/sdk/js/src/gen/core/auth.ts

@@ -1,4 +1,4 @@
-export type AuthToken = string | undefined;
+export type AuthToken = string | undefined
 
 export interface Auth {
   /**
@@ -6,35 +6,34 @@ export interface Auth {
    *
    * @default 'header'
    */
-  in?: 'header' | 'query' | 'cookie';
+  in?: "header" | "query" | "cookie"
   /**
    * Header or query parameter name.
    *
    * @default 'Authorization'
    */
-  name?: string;
-  scheme?: 'basic' | 'bearer';
-  type: 'apiKey' | 'http';
+  name?: string
+  scheme?: "basic" | "bearer"
+  type: "apiKey" | "http"
 }
 
 export const getAuthToken = async (
   auth: Auth,
   callback: ((auth: Auth) => Promise<AuthToken> | AuthToken) | AuthToken,
 ): Promise<string | undefined> => {
-  const token =
-    typeof callback === 'function' ? await callback(auth) : callback;
+  const token = typeof callback === "function" ? await callback(auth) : callback
 
   if (!token) {
-    return;
+    return
   }
 
-  if (auth.scheme === 'bearer') {
-    return `Bearer ${token}`;
+  if (auth.scheme === "bearer") {
+    return `Bearer ${token}`
   }
 
-  if (auth.scheme === 'basic') {
-    return `Basic ${btoa(token)}`;
+  if (auth.scheme === "basic") {
+    return `Basic ${btoa(token)}`
   }
 
-  return token;
-};
+  return token
+}

+ 34 - 52
packages/sdk/js/src/gen/core/bodySerializer.ts

@@ -1,88 +1,70 @@
-import type {
-  ArrayStyle,
-  ObjectStyle,
-  SerializerOptions,
-} from './pathSerializer';
+import type { ArrayStyle, ObjectStyle, SerializerOptions } from "./pathSerializer"
 
-export type QuerySerializer = (query: Record<string, unknown>) => string;
+export type QuerySerializer = (query: Record<string, unknown>) => string
 
-export type BodySerializer = (body: any) => any;
+export type BodySerializer = (body: any) => any
 
 export interface QuerySerializerOptions {
-  allowReserved?: boolean;
-  array?: SerializerOptions<ArrayStyle>;
-  object?: SerializerOptions<ObjectStyle>;
+  allowReserved?: boolean
+  array?: SerializerOptions<ArrayStyle>
+  object?: SerializerOptions<ObjectStyle>
 }
 
-const serializeFormDataPair = (
-  data: FormData,
-  key: string,
-  value: unknown,
-): void => {
-  if (typeof value === 'string' || value instanceof Blob) {
-    data.append(key, value);
+const serializeFormDataPair = (data: FormData, key: string, value: unknown): void => {
+  if (typeof value === "string" || value instanceof Blob) {
+    data.append(key, value)
   } else {
-    data.append(key, JSON.stringify(value));
+    data.append(key, JSON.stringify(value))
   }
-};
+}
 
-const serializeUrlSearchParamsPair = (
-  data: URLSearchParams,
-  key: string,
-  value: unknown,
-): void => {
-  if (typeof value === 'string') {
-    data.append(key, value);
+const serializeUrlSearchParamsPair = (data: URLSearchParams, key: string, value: unknown): void => {
+  if (typeof value === "string") {
+    data.append(key, value)
   } else {
-    data.append(key, JSON.stringify(value));
+    data.append(key, JSON.stringify(value))
   }
-};
+}
 
 export const formDataBodySerializer = {
-  bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(
-    body: T,
-  ): FormData => {
-    const data = new FormData();
+  bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(body: T): FormData => {
+    const data = new FormData()
 
     Object.entries(body).forEach(([key, value]) => {
       if (value === undefined || value === null) {
-        return;
+        return
       }
       if (Array.isArray(value)) {
-        value.forEach((v) => serializeFormDataPair(data, key, v));
+        value.forEach((v) => serializeFormDataPair(data, key, v))
       } else {
-        serializeFormDataPair(data, key, value);
+        serializeFormDataPair(data, key, value)
       }
-    });
+    })
 
-    return data;
+    return data
   },
-};
+}
 
 export const jsonBodySerializer = {
   bodySerializer: <T>(body: T): string =>
-    JSON.stringify(body, (_key, value) =>
-      typeof value === 'bigint' ? value.toString() : value,
-    ),
-};
+    JSON.stringify(body, (_key, value) => (typeof value === "bigint" ? value.toString() : value)),
+}
 
 export const urlSearchParamsBodySerializer = {
-  bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(
-    body: T,
-  ): string => {
-    const data = new URLSearchParams();
+  bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(body: T): string => {
+    const data = new URLSearchParams()
 
     Object.entries(body).forEach(([key, value]) => {
       if (value === undefined || value === null) {
-        return;
+        return
       }
       if (Array.isArray(value)) {
-        value.forEach((v) => serializeUrlSearchParamsPair(data, key, v));
+        value.forEach((v) => serializeUrlSearchParamsPair(data, key, v))
       } else {
-        serializeUrlSearchParamsPair(data, key, value);
+        serializeUrlSearchParamsPair(data, key, value)
       }
-    });
+    })
 
-    return data.toString();
+    return data.toString()
   },
-};
+}

+ 56 - 65
packages/sdk/js/src/gen/core/params.ts

@@ -1,142 +1,133 @@
-type Slot = 'body' | 'headers' | 'path' | 'query';
+type Slot = "body" | "headers" | "path" | "query"
 
 export type Field =
   | {
-      in: Exclude<Slot, 'body'>;
+      in: Exclude<Slot, "body">
       /**
        * Field name. This is the name we want the user to see and use.
        */
-      key: string;
+      key: string
       /**
        * Field mapped name. This is the name we want to use in the request.
        * If omitted, we use the same value as `key`.
        */
-      map?: string;
+      map?: string
     }
   | {
-      in: Extract<Slot, 'body'>;
+      in: Extract<Slot, "body">
       /**
        * Key isn't required for bodies.
        */
-      key?: string;
-      map?: string;
-    };
+      key?: string
+      map?: string
+    }
 
 export interface Fields {
-  allowExtra?: Partial<Record<Slot, boolean>>;
-  args?: ReadonlyArray<Field>;
+  allowExtra?: Partial<Record<Slot, boolean>>
+  args?: ReadonlyArray<Field>
 }
 
-export type FieldsConfig = ReadonlyArray<Field | Fields>;
+export type FieldsConfig = ReadonlyArray<Field | Fields>
 
 const extraPrefixesMap: Record<string, Slot> = {
-  $body_: 'body',
-  $headers_: 'headers',
-  $path_: 'path',
-  $query_: 'query',
-};
-const extraPrefixes = Object.entries(extraPrefixesMap);
+  $body_: "body",
+  $headers_: "headers",
+  $path_: "path",
+  $query_: "query",
+}
+const extraPrefixes = Object.entries(extraPrefixesMap)
 
 type KeyMap = Map<
   string,
   {
-    in: Slot;
-    map?: string;
+    in: Slot
+    map?: string
   }
->;
+>
 
 const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => {
   if (!map) {
-    map = new Map();
+    map = new Map()
   }
 
   for (const config of fields) {
-    if ('in' in config) {
+    if ("in" in config) {
       if (config.key) {
         map.set(config.key, {
           in: config.in,
           map: config.map,
-        });
+        })
       }
     } else if (config.args) {
-      buildKeyMap(config.args, map);
+      buildKeyMap(config.args, map)
     }
   }
 
-  return map;
-};
+  return map
+}
 
 interface Params {
-  body: unknown;
-  headers: Record<string, unknown>;
-  path: Record<string, unknown>;
-  query: Record<string, unknown>;
+  body: unknown
+  headers: Record<string, unknown>
+  path: Record<string, unknown>
+  query: Record<string, unknown>
 }
 
 const stripEmptySlots = (params: Params) => {
   for (const [slot, value] of Object.entries(params)) {
-    if (value && typeof value === 'object' && !Object.keys(value).length) {
-      delete params[slot as Slot];
+    if (value && typeof value === "object" && !Object.keys(value).length) {
+      delete params[slot as Slot]
     }
   }
-};
+}
 
-export const buildClientParams = (
-  args: ReadonlyArray<unknown>,
-  fields: FieldsConfig,
-) => {
+export const buildClientParams = (args: ReadonlyArray<unknown>, fields: FieldsConfig) => {
   const params: Params = {
     body: {},
     headers: {},
     path: {},
     query: {},
-  };
+  }
 
-  const map = buildKeyMap(fields);
+  const map = buildKeyMap(fields)
 
-  let config: FieldsConfig[number] | undefined;
+  let config: FieldsConfig[number] | undefined
 
   for (const [index, arg] of args.entries()) {
     if (fields[index]) {
-      config = fields[index];
+      config = fields[index]
     }
 
     if (!config) {
-      continue;
+      continue
     }
 
-    if ('in' in config) {
+    if ("in" in config) {
       if (config.key) {
-        const field = map.get(config.key)!;
-        const name = field.map || config.key;
-        (params[field.in] as Record<string, unknown>)[name] = arg;
+        const field = map.get(config.key)!
+        const name = field.map || config.key
+        ;(params[field.in] as Record<string, unknown>)[name] = arg
       } else {
-        params.body = arg;
+        params.body = arg
       }
     } else {
       for (const [key, value] of Object.entries(arg ?? {})) {
-        const field = map.get(key);
+        const field = map.get(key)
 
         if (field) {
-          const name = field.map || key;
-          (params[field.in] as Record<string, unknown>)[name] = value;
+          const name = field.map || key
+          ;(params[field.in] as Record<string, unknown>)[name] = value
         } else {
-          const extra = extraPrefixes.find(([prefix]) =>
-            key.startsWith(prefix),
-          );
+          const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix))
 
           if (extra) {
-            const [prefix, slot] = extra;
-            (params[slot] as Record<string, unknown>)[
-              key.slice(prefix.length)
-            ] = value;
+            const [prefix, slot] = extra
+            ;(params[slot] as Record<string, unknown>)[key.slice(prefix.length)] = value
           } else {
-            for (const [slot, allowed] of Object.entries(
-              config.allowExtra ?? {},
-            )) {
+            for (const [slot, allowed] of Object.entries(config.allowExtra ?? {})) {
               if (allowed) {
-                (params[slot as Slot] as Record<string, unknown>)[key] = value;
-                break;
+                ;(params[slot as Slot] as Record<string, unknown>)[key] = value
+                break
               }
             }
           }
@@ -145,7 +136,7 @@ export const buildClientParams = (
     }
   }
 
-  stripEmptySlots(params);
+  stripEmptySlots(params)
 
-  return params;
-};
+  return params
+}

+ 80 - 94
packages/sdk/js/src/gen/core/pathSerializer.ts

@@ -1,68 +1,66 @@
-interface SerializeOptions<T>
-  extends SerializePrimitiveOptions,
-    SerializerOptions<T> {}
+interface SerializeOptions<T> extends SerializePrimitiveOptions, SerializerOptions<T> {}
 
 interface SerializePrimitiveOptions {
-  allowReserved?: boolean;
-  name: string;
+  allowReserved?: boolean
+  name: string
 }
 
 export interface SerializerOptions<T> {
   /**
    * @default true
    */
-  explode: boolean;
-  style: T;
+  explode: boolean
+  style: T
 }
 
-export type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited';
-export type ArraySeparatorStyle = ArrayStyle | MatrixStyle;
-type MatrixStyle = 'label' | 'matrix' | 'simple';
-export type ObjectStyle = 'form' | 'deepObject';
-type ObjectSeparatorStyle = ObjectStyle | MatrixStyle;
+export type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"
+export type ArraySeparatorStyle = ArrayStyle | MatrixStyle
+type MatrixStyle = "label" | "matrix" | "simple"
+export type ObjectStyle = "form" | "deepObject"
+type ObjectSeparatorStyle = ObjectStyle | MatrixStyle
 
 interface SerializePrimitiveParam extends SerializePrimitiveOptions {
-  value: string;
+  value: string
 }
 
 export const separatorArrayExplode = (style: ArraySeparatorStyle) => {
   switch (style) {
-    case 'label':
-      return '.';
-    case 'matrix':
-      return ';';
-    case 'simple':
-      return ',';
+    case "label":
+      return "."
+    case "matrix":
+      return ";"
+    case "simple":
+      return ","
     default:
-      return '&';
+      return "&"
   }
-};
+}
 
 export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => {
   switch (style) {
-    case 'form':
-      return ',';
-    case 'pipeDelimited':
-      return '|';
-    case 'spaceDelimited':
-      return '%20';
+    case "form":
+      return ","
+    case "pipeDelimited":
+      return "|"
+    case "spaceDelimited":
+      return "%20"
     default:
-      return ',';
+      return ","
   }
-};
+}
 
 export const separatorObjectExplode = (style: ObjectSeparatorStyle) => {
   switch (style) {
-    case 'label':
-      return '.';
-    case 'matrix':
-      return ';';
-    case 'simple':
-      return ',';
+    case "label":
+      return "."
+    case "matrix":
+      return ";"
+    case "simple":
+      return ","
     default:
-      return '&';
+      return "&"
   }
-};
+}
 
 export const serializeArrayParam = ({
   allowReserved,
@@ -71,60 +69,54 @@ export const serializeArrayParam = ({
   style,
   value,
 }: SerializeOptions<ArraySeparatorStyle> & {
-  value: unknown[];
+  value: unknown[]
 }) => {
   if (!explode) {
-    const joinedValues = (
-      allowReserved ? value : value.map((v) => encodeURIComponent(v as string))
-    ).join(separatorArrayNoExplode(style));
+    const joinedValues = (allowReserved ? value : value.map((v) => encodeURIComponent(v as string))).join(
+      separatorArrayNoExplode(style),
+    )
     switch (style) {
-      case 'label':
-        return `.${joinedValues}`;
-      case 'matrix':
-        return `;${name}=${joinedValues}`;
-      case 'simple':
-        return joinedValues;
+      case "label":
+        return `.${joinedValues}`
+      case "matrix":
+        return `;${name}=${joinedValues}`
+      case "simple":
+        return joinedValues
       default:
-        return `${name}=${joinedValues}`;
+        return `${name}=${joinedValues}`
     }
   }
 
-  const separator = separatorArrayExplode(style);
+  const separator = separatorArrayExplode(style)
   const joinedValues = value
     .map((v) => {
-      if (style === 'label' || style === 'simple') {
-        return allowReserved ? v : encodeURIComponent(v as string);
+      if (style === "label" || style === "simple") {
+        return allowReserved ? v : encodeURIComponent(v as string)
       }
 
       return serializePrimitiveParam({
         allowReserved,
         name,
         value: v as string,
-      });
+      })
     })
-    .join(separator);
-  return style === 'label' || style === 'matrix'
-    ? separator + joinedValues
-    : joinedValues;
-};
+    .join(separator)
+  return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues
+}
 
-export const serializePrimitiveParam = ({
-  allowReserved,
-  name,
-  value,
-}: SerializePrimitiveParam) => {
+export const serializePrimitiveParam = ({ allowReserved, name, value }: SerializePrimitiveParam) => {
   if (value === undefined || value === null) {
-    return '';
+    return ""
   }
 
-  if (typeof value === 'object') {
+  if (typeof value === "object") {
     throw new Error(
-      'Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.',
-    );
+      "Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.",
+    )
   }
 
-  return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
-};
+  return `${name}=${allowReserved ? value : encodeURIComponent(value)}`
+}
 
 export const serializeObjectParam = ({
   allowReserved,
@@ -134,46 +126,40 @@ export const serializeObjectParam = ({
   value,
   valueOnly,
 }: SerializeOptions<ObjectSeparatorStyle> & {
-  value: Record<string, unknown> | Date;
-  valueOnly?: boolean;
+  value: Record<string, unknown> | Date
+  valueOnly?: boolean
 }) => {
   if (value instanceof Date) {
-    return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
+    return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`
   }
 
-  if (style !== 'deepObject' && !explode) {
-    let values: string[] = [];
+  if (style !== "deepObject" && !explode) {
+    let values: string[] = []
     Object.entries(value).forEach(([key, v]) => {
-      values = [
-        ...values,
-        key,
-        allowReserved ? (v as string) : encodeURIComponent(v as string),
-      ];
-    });
-    const joinedValues = values.join(',');
+      values = [...values, key, allowReserved ? (v as string) : encodeURIComponent(v as string)]
+    })
+    const joinedValues = values.join(",")
     switch (style) {
-      case 'form':
-        return `${name}=${joinedValues}`;
-      case 'label':
-        return `.${joinedValues}`;
-      case 'matrix':
-        return `;${name}=${joinedValues}`;
+      case "form":
+        return `${name}=${joinedValues}`
+      case "label":
+        return `.${joinedValues}`
+      case "matrix":
+        return `;${name}=${joinedValues}`
       default:
-        return joinedValues;
+        return joinedValues
     }
   }
 
-  const separator = separatorObjectExplode(style);
+  const separator = separatorObjectExplode(style)
   const joinedValues = Object.entries(value)
     .map(([key, v]) =>
       serializePrimitiveParam({
         allowReserved,
-        name: style === 'deepObject' ? `${name}[${key}]` : key,
+        name: style === "deepObject" ? `${name}[${key}]` : key,
         value: v as string,
       }),
     )
-    .join(separator);
-  return style === 'label' || style === 'matrix'
-    ? separator + joinedValues
-    : joinedValues;
-};
+    .join(separator)
+  return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues
+}

+ 28 - 57
packages/sdk/js/src/gen/core/types.ts

@@ -1,32 +1,23 @@
-import type { Auth, AuthToken } from './auth';
-import type {
-  BodySerializer,
-  QuerySerializer,
-  QuerySerializerOptions,
-} from './bodySerializer';
+import type { Auth, AuthToken } from "./auth"
+import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from "./bodySerializer"
 
-export interface Client<
-  RequestFn = never,
-  Config = unknown,
-  MethodFn = never,
-  BuildUrlFn = never,
-> {
+export interface Client<RequestFn = never, Config = unknown, MethodFn = never, BuildUrlFn = never> {
   /**
    * Returns the final request URL.
    */
-  buildUrl: BuildUrlFn;
-  connect: MethodFn;
-  delete: MethodFn;
-  get: MethodFn;
-  getConfig: () => Config;
-  head: MethodFn;
-  options: MethodFn;
-  patch: MethodFn;
-  post: MethodFn;
-  put: MethodFn;
-  request: RequestFn;
-  setConfig: (config: Config) => Config;
-  trace: MethodFn;
+  buildUrl: BuildUrlFn
+  connect: MethodFn
+  delete: MethodFn
+  get: MethodFn
+  getConfig: () => Config
+  head: MethodFn
+  options: MethodFn
+  patch: MethodFn
+  post: MethodFn
+  put: MethodFn
+  request: RequestFn
+  setConfig: (config: Config) => Config
+  trace: MethodFn
 }
 
 export interface Config {
@@ -34,12 +25,12 @@ export interface Config {
    * Auth token or a function returning auth token. The resolved value will be
    * added to the request payload as defined by its `security` array.
    */
-  auth?: ((auth: Auth) => Promise<AuthToken> | AuthToken) | AuthToken;
+  auth?: ((auth: Auth) => Promise<AuthToken> | AuthToken) | AuthToken
   /**
    * A function for serializing request body parameter. By default,
    * {@link JSON.stringify()} will be used.
    */
-  bodySerializer?: BodySerializer | null;
+  bodySerializer?: BodySerializer | null
   /**
    * An object containing any HTTP headers that you want to pre-populate your
    * `Headers` object with.
@@ -47,32 +38,14 @@ export interface Config {
    * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more}
    */
   headers?:
-    | RequestInit['headers']
-    | Record<
-        string,
-        | string
-        | number
-        | boolean
-        | (string | number | boolean)[]
-        | null
-        | undefined
-        | unknown
-      >;
+    | RequestInit["headers"]
+    | Record<string, string | number | boolean | (string | number | boolean)[] | null | undefined | unknown>
   /**
    * The request method.
    *
    * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more}
    */
-  method?:
-    | 'CONNECT'
-    | 'DELETE'
-    | 'GET'
-    | 'HEAD'
-    | 'OPTIONS'
-    | 'PATCH'
-    | 'POST'
-    | 'PUT'
-    | 'TRACE';
+  method?: "CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE"
   /**
    * A function for serializing request query parameters. By default, arrays
    * will be exploded in form style, objects will be exploded in deepObject
@@ -83,24 +56,24 @@ export interface Config {
    *
    * {@link https://swagger.io/docs/specification/serialization/#query View examples}
    */
-  querySerializer?: QuerySerializer | QuerySerializerOptions;
+  querySerializer?: QuerySerializer | QuerySerializerOptions
   /**
    * A function validating request data. This is useful if you want to ensure
    * the request conforms to the desired shape, so it can be safely sent to
    * the server.
    */
-  requestValidator?: (data: unknown) => Promise<unknown>;
+  requestValidator?: (data: unknown) => Promise<unknown>
   /**
    * A function transforming response data before it's returned. This is useful
    * for post-processing data, e.g. converting ISO strings into Date objects.
    */
-  responseTransformer?: (data: unknown) => Promise<unknown>;
+  responseTransformer?: (data: unknown) => Promise<unknown>
   /**
    * A function validating response data. This is useful if you want to ensure
    * the response conforms to the desired shape, so it can be safely passed to
    * the transformers and returned to the user.
    */
-  responseValidator?: (data: unknown) => Promise<unknown>;
+  responseValidator?: (data: unknown) => Promise<unknown>
 }
 
 type IsExactlyNeverOrNeverUndefined<T> = [T] extends [never]
@@ -109,10 +82,8 @@ type IsExactlyNeverOrNeverUndefined<T> = [T] extends [never]
     ? [undefined] extends [T]
       ? false
       : true
-    : false;
+    : false
 
 export type OmitNever<T extends Record<string, unknown>> = {
-  [K in keyof T as IsExactlyNeverOrNeverUndefined<T[K]> extends true
-    ? never
-    : K]: T[K];
-};
+  [K in keyof T as IsExactlyNeverOrNeverUndefined<T[K]> extends true ? never : K]: T[K]
+}

+ 474 - 397
packages/sdk/js/src/gen/sdk.gen.ts

@@ -1,426 +1,503 @@
 // This file is auto-generated by @hey-api/openapi-ts
 
-import type { Options as ClientOptions, TDataShape, Client } from './client';
-import type { EventSubscribeData, EventSubscribeResponses, AppGetData, AppGetResponses, AppInitData, AppInitResponses, ConfigGetData, ConfigGetResponses, SessionListData, SessionListResponses, SessionCreateData, SessionCreateResponses, SessionCreateErrors, SessionDeleteData, SessionDeleteResponses, SessionInitData, SessionInitResponses, SessionAbortData, SessionAbortResponses, SessionUnshareData, SessionUnshareResponses, SessionShareData, SessionShareResponses, SessionSummarizeData, SessionSummarizeResponses, SessionMessagesData, SessionMessagesResponses, SessionChatData, SessionChatResponses, SessionMessageData, SessionMessageResponses, SessionRevertData, SessionRevertResponses, SessionUnrevertData, SessionUnrevertResponses, PostSessionByIdPermissionsByPermissionIdData, PostSessionByIdPermissionsByPermissionIdResponses, ConfigProvidersData, ConfigProvidersResponses, FindTextData, FindTextResponses, FindFilesData, FindFilesResponses, FindSymbolsData, FindSymbolsResponses, FileReadData, FileReadResponses, FileStatusData, FileStatusResponses, AppLogData, AppLogResponses, AppModesData, AppModesResponses, TuiAppendPromptData, TuiAppendPromptResponses, TuiOpenHelpData, TuiOpenHelpResponses, TuiOpenSessionsData, TuiOpenSessionsResponses, TuiOpenThemesData, TuiOpenThemesResponses, TuiOpenModelsData, TuiOpenModelsResponses, TuiSubmitPromptData, TuiSubmitPromptResponses, TuiClearPromptData, TuiClearPromptResponses, TuiExecuteCommandData, TuiExecuteCommandResponses } from './types.gen';
-import { client as _heyApiClient } from './client.gen';
-
-export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
-    /**
-     * You can provide a client instance returned by `createClient()` instead of
-     * individual options. This might be also useful if you want to implement a
-     * custom client.
-     */
-    client?: Client;
-    /**
-     * You can pass arbitrary values through the `meta` object. This can be
-     * used to access values that aren't defined as part of the SDK function.
-     */
-    meta?: Record<string, unknown>;
-};
+import type { Options as ClientOptions, TDataShape, Client } from "./client"
+import type {
+  EventSubscribeData,
+  EventSubscribeResponses,
+  AppGetData,
+  AppGetResponses,
+  AppInitData,
+  AppInitResponses,
+  ConfigGetData,
+  ConfigGetResponses,
+  SessionListData,
+  SessionListResponses,
+  SessionCreateData,
+  SessionCreateResponses,
+  SessionCreateErrors,
+  SessionDeleteData,
+  SessionDeleteResponses,
+  SessionInitData,
+  SessionInitResponses,
+  SessionAbortData,
+  SessionAbortResponses,
+  SessionUnshareData,
+  SessionUnshareResponses,
+  SessionShareData,
+  SessionShareResponses,
+  SessionSummarizeData,
+  SessionSummarizeResponses,
+  SessionMessagesData,
+  SessionMessagesResponses,
+  SessionChatData,
+  SessionChatResponses,
+  SessionMessageData,
+  SessionMessageResponses,
+  SessionRevertData,
+  SessionRevertResponses,
+  SessionUnrevertData,
+  SessionUnrevertResponses,
+  PostSessionByIdPermissionsByPermissionIdData,
+  PostSessionByIdPermissionsByPermissionIdResponses,
+  ConfigProvidersData,
+  ConfigProvidersResponses,
+  FindTextData,
+  FindTextResponses,
+  FindFilesData,
+  FindFilesResponses,
+  FindSymbolsData,
+  FindSymbolsResponses,
+  FileReadData,
+  FileReadResponses,
+  FileStatusData,
+  FileStatusResponses,
+  AppLogData,
+  AppLogResponses,
+  AppModesData,
+  AppModesResponses,
+  TuiAppendPromptData,
+  TuiAppendPromptResponses,
+  TuiOpenHelpData,
+  TuiOpenHelpResponses,
+  TuiOpenSessionsData,
+  TuiOpenSessionsResponses,
+  TuiOpenThemesData,
+  TuiOpenThemesResponses,
+  TuiOpenModelsData,
+  TuiOpenModelsResponses,
+  TuiSubmitPromptData,
+  TuiSubmitPromptResponses,
+  TuiClearPromptData,
+  TuiClearPromptResponses,
+  TuiExecuteCommandData,
+  TuiExecuteCommandResponses,
+} from "./types.gen"
+import { client as _heyApiClient } from "./client.gen"
+
+export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<
+  TData,
+  ThrowOnError
+> & {
+  /**
+   * You can provide a client instance returned by `createClient()` instead of
+   * individual options. This might be also useful if you want to implement a
+   * custom client.
+   */
+  client?: Client
+  /**
+   * You can pass arbitrary values through the `meta` object. This can be
+   * used to access values that aren't defined as part of the SDK function.
+   */
+  meta?: Record<string, unknown>
+}
 
 class _HeyApiClient {
-    protected _client: Client = _heyApiClient;
-    
-    constructor(args?: {
-        client?: Client;
-    }) {
-        if (args?.client) {
-            this._client = args.client;
-        }
+  protected _client: Client = _heyApiClient
+
+  constructor(args?: { client?: Client }) {
+    if (args?.client) {
+      this._client = args.client
     }
+  }
 }
 
 class Event extends _HeyApiClient {
-    /**
-     * Get events
-     */
-    public subscribe<ThrowOnError extends boolean = false>(options?: Options<EventSubscribeData, ThrowOnError>) {
-        return (options?.client ?? this._client).get<EventSubscribeResponses, unknown, ThrowOnError>({
-            url: '/event',
-            ...options
-        });
-    }
+  /**
+   * Get events
+   */
+  public subscribe<ThrowOnError extends boolean = false>(options?: Options<EventSubscribeData, ThrowOnError>) {
+    return (options?.client ?? this._client).get<EventSubscribeResponses, unknown, ThrowOnError>({
+      url: "/event",
+      ...options,
+    })
+  }
 }
 
 class App extends _HeyApiClient {
-    /**
-     * Get app info
-     */
-    public get<ThrowOnError extends boolean = false>(options?: Options<AppGetData, ThrowOnError>) {
-        return (options?.client ?? this._client).get<AppGetResponses, unknown, ThrowOnError>({
-            url: '/app',
-            ...options
-        });
-    }
-    
-    /**
-     * Initialize the app
-     */
-    public init<ThrowOnError extends boolean = false>(options?: Options<AppInitData, ThrowOnError>) {
-        return (options?.client ?? this._client).post<AppInitResponses, unknown, ThrowOnError>({
-            url: '/app/init',
-            ...options
-        });
-    }
-    
-    /**
-     * Write a log entry to the server logs
-     */
-    public log<ThrowOnError extends boolean = false>(options?: Options<AppLogData, ThrowOnError>) {
-        return (options?.client ?? this._client).post<AppLogResponses, unknown, ThrowOnError>({
-            url: '/log',
-            ...options,
-            headers: {
-                'Content-Type': 'application/json',
-                ...options?.headers
-            }
-        });
-    }
-    
-    /**
-     * List all modes
-     */
-    public modes<ThrowOnError extends boolean = false>(options?: Options<AppModesData, ThrowOnError>) {
-        return (options?.client ?? this._client).get<AppModesResponses, unknown, ThrowOnError>({
-            url: '/mode',
-            ...options
-        });
-    }
+  /**
+   * Get app info
+   */
+  public get<ThrowOnError extends boolean = false>(options?: Options<AppGetData, ThrowOnError>) {
+    return (options?.client ?? this._client).get<AppGetResponses, unknown, ThrowOnError>({
+      url: "/app",
+      ...options,
+    })
+  }
+
+  /**
+   * Initialize the app
+   */
+  public init<ThrowOnError extends boolean = false>(options?: Options<AppInitData, ThrowOnError>) {
+    return (options?.client ?? this._client).post<AppInitResponses, unknown, ThrowOnError>({
+      url: "/app/init",
+      ...options,
+    })
+  }
+
+  /**
+   * Write a log entry to the server logs
+   */
+  public log<ThrowOnError extends boolean = false>(options?: Options<AppLogData, ThrowOnError>) {
+    return (options?.client ?? this._client).post<AppLogResponses, unknown, ThrowOnError>({
+      url: "/log",
+      ...options,
+      headers: {
+        "Content-Type": "application/json",
+        ...options?.headers,
+      },
+    })
+  }
+
+  /**
+   * List all modes
+   */
+  public modes<ThrowOnError extends boolean = false>(options?: Options<AppModesData, ThrowOnError>) {
+    return (options?.client ?? this._client).get<AppModesResponses, unknown, ThrowOnError>({
+      url: "/mode",
+      ...options,
+    })
+  }
 }
 
 class Config extends _HeyApiClient {
-    /**
-     * Get config info
-     */
-    public get<ThrowOnError extends boolean = false>(options?: Options<ConfigGetData, ThrowOnError>) {
-        return (options?.client ?? this._client).get<ConfigGetResponses, unknown, ThrowOnError>({
-            url: '/config',
-            ...options
-        });
-    }
-    
-    /**
-     * List all providers
-     */
-    public providers<ThrowOnError extends boolean = false>(options?: Options<ConfigProvidersData, ThrowOnError>) {
-        return (options?.client ?? this._client).get<ConfigProvidersResponses, unknown, ThrowOnError>({
-            url: '/config/providers',
-            ...options
-        });
-    }
+  /**
+   * Get config info
+   */
+  public get<ThrowOnError extends boolean = false>(options?: Options<ConfigGetData, ThrowOnError>) {
+    return (options?.client ?? this._client).get<ConfigGetResponses, unknown, ThrowOnError>({
+      url: "/config",
+      ...options,
+    })
+  }
+
+  /**
+   * List all providers
+   */
+  public providers<ThrowOnError extends boolean = false>(options?: Options<ConfigProvidersData, ThrowOnError>) {
+    return (options?.client ?? this._client).get<ConfigProvidersResponses, unknown, ThrowOnError>({
+      url: "/config/providers",
+      ...options,
+    })
+  }
 }
 
 class Session extends _HeyApiClient {
-    /**
-     * List all sessions
-     */
-    public list<ThrowOnError extends boolean = false>(options?: Options<SessionListData, ThrowOnError>) {
-        return (options?.client ?? this._client).get<SessionListResponses, unknown, ThrowOnError>({
-            url: '/session',
-            ...options
-        });
-    }
-    
-    /**
-     * Create a new session
-     */
-    public create<ThrowOnError extends boolean = false>(options?: Options<SessionCreateData, ThrowOnError>) {
-        return (options?.client ?? this._client).post<SessionCreateResponses, SessionCreateErrors, ThrowOnError>({
-            url: '/session',
-            ...options
-        });
-    }
-    
-    /**
-     * Delete a session and all its data
-     */
-    public delete<ThrowOnError extends boolean = false>(options: Options<SessionDeleteData, ThrowOnError>) {
-        return (options.client ?? this._client).delete<SessionDeleteResponses, unknown, ThrowOnError>({
-            url: '/session/{id}',
-            ...options
-        });
-    }
-    
-    /**
-     * Analyze the app and create an AGENTS.md file
-     */
-    public init<ThrowOnError extends boolean = false>(options: Options<SessionInitData, ThrowOnError>) {
-        return (options.client ?? this._client).post<SessionInitResponses, unknown, ThrowOnError>({
-            url: '/session/{id}/init',
-            ...options,
-            headers: {
-                'Content-Type': 'application/json',
-                ...options.headers
-            }
-        });
-    }
-    
-    /**
-     * Abort a session
-     */
-    public abort<ThrowOnError extends boolean = false>(options: Options<SessionAbortData, ThrowOnError>) {
-        return (options.client ?? this._client).post<SessionAbortResponses, unknown, ThrowOnError>({
-            url: '/session/{id}/abort',
-            ...options
-        });
-    }
-    
-    /**
-     * Unshare the session
-     */
-    public unshare<ThrowOnError extends boolean = false>(options: Options<SessionUnshareData, ThrowOnError>) {
-        return (options.client ?? this._client).delete<SessionUnshareResponses, unknown, ThrowOnError>({
-            url: '/session/{id}/share',
-            ...options
-        });
-    }
-    
-    /**
-     * Share a session
-     */
-    public share<ThrowOnError extends boolean = false>(options: Options<SessionShareData, ThrowOnError>) {
-        return (options.client ?? this._client).post<SessionShareResponses, unknown, ThrowOnError>({
-            url: '/session/{id}/share',
-            ...options
-        });
-    }
-    
-    /**
-     * Summarize the session
-     */
-    public summarize<ThrowOnError extends boolean = false>(options: Options<SessionSummarizeData, ThrowOnError>) {
-        return (options.client ?? this._client).post<SessionSummarizeResponses, unknown, ThrowOnError>({
-            url: '/session/{id}/summarize',
-            ...options,
-            headers: {
-                'Content-Type': 'application/json',
-                ...options.headers
-            }
-        });
-    }
-    
-    /**
-     * List messages for a session
-     */
-    public messages<ThrowOnError extends boolean = false>(options: Options<SessionMessagesData, ThrowOnError>) {
-        return (options.client ?? this._client).get<SessionMessagesResponses, unknown, ThrowOnError>({
-            url: '/session/{id}/message',
-            ...options
-        });
-    }
-    
-    /**
-     * Create and send a new message to a session
-     */
-    public chat<ThrowOnError extends boolean = false>(options: Options<SessionChatData, ThrowOnError>) {
-        return (options.client ?? this._client).post<SessionChatResponses, unknown, ThrowOnError>({
-            url: '/session/{id}/message',
-            ...options,
-            headers: {
-                'Content-Type': 'application/json',
-                ...options.headers
-            }
-        });
-    }
-    
-    /**
-     * Get a message from a session
-     */
-    public message<ThrowOnError extends boolean = false>(options: Options<SessionMessageData, ThrowOnError>) {
-        return (options.client ?? this._client).get<SessionMessageResponses, unknown, ThrowOnError>({
-            url: '/session/{id}/message/{messageID}',
-            ...options
-        });
-    }
-    
-    /**
-     * Revert a message
-     */
-    public revert<ThrowOnError extends boolean = false>(options: Options<SessionRevertData, ThrowOnError>) {
-        return (options.client ?? this._client).post<SessionRevertResponses, unknown, ThrowOnError>({
-            url: '/session/{id}/revert',
-            ...options,
-            headers: {
-                'Content-Type': 'application/json',
-                ...options.headers
-            }
-        });
-    }
-    
-    /**
-     * Restore all reverted messages
-     */
-    public unrevert<ThrowOnError extends boolean = false>(options: Options<SessionUnrevertData, ThrowOnError>) {
-        return (options.client ?? this._client).post<SessionUnrevertResponses, unknown, ThrowOnError>({
-            url: '/session/{id}/unrevert',
-            ...options
-        });
-    }
+  /**
+   * List all sessions
+   */
+  public list<ThrowOnError extends boolean = false>(options?: Options<SessionListData, ThrowOnError>) {
+    return (options?.client ?? this._client).get<SessionListResponses, unknown, ThrowOnError>({
+      url: "/session",
+      ...options,
+    })
+  }
+
+  /**
+   * Create a new session
+   */
+  public create<ThrowOnError extends boolean = false>(options?: Options<SessionCreateData, ThrowOnError>) {
+    return (options?.client ?? this._client).post<SessionCreateResponses, SessionCreateErrors, ThrowOnError>({
+      url: "/session",
+      ...options,
+    })
+  }
+
+  /**
+   * Delete a session and all its data
+   */
+  public delete<ThrowOnError extends boolean = false>(options: Options<SessionDeleteData, ThrowOnError>) {
+    return (options.client ?? this._client).delete<SessionDeleteResponses, unknown, ThrowOnError>({
+      url: "/session/{id}",
+      ...options,
+    })
+  }
+
+  /**
+   * Analyze the app and create an AGENTS.md file
+   */
+  public init<ThrowOnError extends boolean = false>(options: Options<SessionInitData, ThrowOnError>) {
+    return (options.client ?? this._client).post<SessionInitResponses, unknown, ThrowOnError>({
+      url: "/session/{id}/init",
+      ...options,
+      headers: {
+        "Content-Type": "application/json",
+        ...options.headers,
+      },
+    })
+  }
+
+  /**
+   * Abort a session
+   */
+  public abort<ThrowOnError extends boolean = false>(options: Options<SessionAbortData, ThrowOnError>) {
+    return (options.client ?? this._client).post<SessionAbortResponses, unknown, ThrowOnError>({
+      url: "/session/{id}/abort",
+      ...options,
+    })
+  }
+
+  /**
+   * Unshare the session
+   */
+  public unshare<ThrowOnError extends boolean = false>(options: Options<SessionUnshareData, ThrowOnError>) {
+    return (options.client ?? this._client).delete<SessionUnshareResponses, unknown, ThrowOnError>({
+      url: "/session/{id}/share",
+      ...options,
+    })
+  }
+
+  /**
+   * Share a session
+   */
+  public share<ThrowOnError extends boolean = false>(options: Options<SessionShareData, ThrowOnError>) {
+    return (options.client ?? this._client).post<SessionShareResponses, unknown, ThrowOnError>({
+      url: "/session/{id}/share",
+      ...options,
+    })
+  }
+
+  /**
+   * Summarize the session
+   */
+  public summarize<ThrowOnError extends boolean = false>(options: Options<SessionSummarizeData, ThrowOnError>) {
+    return (options.client ?? this._client).post<SessionSummarizeResponses, unknown, ThrowOnError>({
+      url: "/session/{id}/summarize",
+      ...options,
+      headers: {
+        "Content-Type": "application/json",
+        ...options.headers,
+      },
+    })
+  }
+
+  /**
+   * List messages for a session
+   */
+  public messages<ThrowOnError extends boolean = false>(options: Options<SessionMessagesData, ThrowOnError>) {
+    return (options.client ?? this._client).get<SessionMessagesResponses, unknown, ThrowOnError>({
+      url: "/session/{id}/message",
+      ...options,
+    })
+  }
+
+  /**
+   * Create and send a new message to a session
+   */
+  public chat<ThrowOnError extends boolean = false>(options: Options<SessionChatData, ThrowOnError>) {
+    return (options.client ?? this._client).post<SessionChatResponses, unknown, ThrowOnError>({
+      url: "/session/{id}/message",
+      ...options,
+      headers: {
+        "Content-Type": "application/json",
+        ...options.headers,
+      },
+    })
+  }
+
+  /**
+   * Get a message from a session
+   */
+  public message<ThrowOnError extends boolean = false>(options: Options<SessionMessageData, ThrowOnError>) {
+    return (options.client ?? this._client).get<SessionMessageResponses, unknown, ThrowOnError>({
+      url: "/session/{id}/message/{messageID}",
+      ...options,
+    })
+  }
+
+  /**
+   * Revert a message
+   */
+  public revert<ThrowOnError extends boolean = false>(options: Options<SessionRevertData, ThrowOnError>) {
+    return (options.client ?? this._client).post<SessionRevertResponses, unknown, ThrowOnError>({
+      url: "/session/{id}/revert",
+      ...options,
+      headers: {
+        "Content-Type": "application/json",
+        ...options.headers,
+      },
+    })
+  }
+
+  /**
+   * Restore all reverted messages
+   */
+  public unrevert<ThrowOnError extends boolean = false>(options: Options<SessionUnrevertData, ThrowOnError>) {
+    return (options.client ?? this._client).post<SessionUnrevertResponses, unknown, ThrowOnError>({
+      url: "/session/{id}/unrevert",
+      ...options,
+    })
+  }
 }
 
 class Find extends _HeyApiClient {
-    /**
-     * Find text in files
-     */
-    public text<ThrowOnError extends boolean = false>(options: Options<FindTextData, ThrowOnError>) {
-        return (options.client ?? this._client).get<FindTextResponses, unknown, ThrowOnError>({
-            url: '/find',
-            ...options
-        });
-    }
-    
-    /**
-     * Find files
-     */
-    public files<ThrowOnError extends boolean = false>(options: Options<FindFilesData, ThrowOnError>) {
-        return (options.client ?? this._client).get<FindFilesResponses, unknown, ThrowOnError>({
-            url: '/find/file',
-            ...options
-        });
-    }
-    
-    /**
-     * Find workspace symbols
-     */
-    public symbols<ThrowOnError extends boolean = false>(options: Options<FindSymbolsData, ThrowOnError>) {
-        return (options.client ?? this._client).get<FindSymbolsResponses, unknown, ThrowOnError>({
-            url: '/find/symbol',
-            ...options
-        });
-    }
+  /**
+   * Find text in files
+   */
+  public text<ThrowOnError extends boolean = false>(options: Options<FindTextData, ThrowOnError>) {
+    return (options.client ?? this._client).get<FindTextResponses, unknown, ThrowOnError>({
+      url: "/find",
+      ...options,
+    })
+  }
+
+  /**
+   * Find files
+   */
+  public files<ThrowOnError extends boolean = false>(options: Options<FindFilesData, ThrowOnError>) {
+    return (options.client ?? this._client).get<FindFilesResponses, unknown, ThrowOnError>({
+      url: "/find/file",
+      ...options,
+    })
+  }
+
+  /**
+   * Find workspace symbols
+   */
+  public symbols<ThrowOnError extends boolean = false>(options: Options<FindSymbolsData, ThrowOnError>) {
+    return (options.client ?? this._client).get<FindSymbolsResponses, unknown, ThrowOnError>({
+      url: "/find/symbol",
+      ...options,
+    })
+  }
 }
 
 class File extends _HeyApiClient {
-    /**
-     * Read a file
-     */
-    public read<ThrowOnError extends boolean = false>(options: Options<FileReadData, ThrowOnError>) {
-        return (options.client ?? this._client).get<FileReadResponses, unknown, ThrowOnError>({
-            url: '/file',
-            ...options
-        });
-    }
-    
-    /**
-     * Get file status
-     */
-    public status<ThrowOnError extends boolean = false>(options?: Options<FileStatusData, ThrowOnError>) {
-        return (options?.client ?? this._client).get<FileStatusResponses, unknown, ThrowOnError>({
-            url: '/file/status',
-            ...options
-        });
-    }
+  /**
+   * Read a file
+   */
+  public read<ThrowOnError extends boolean = false>(options: Options<FileReadData, ThrowOnError>) {
+    return (options.client ?? this._client).get<FileReadResponses, unknown, ThrowOnError>({
+      url: "/file",
+      ...options,
+    })
+  }
+
+  /**
+   * Get file status
+   */
+  public status<ThrowOnError extends boolean = false>(options?: Options<FileStatusData, ThrowOnError>) {
+    return (options?.client ?? this._client).get<FileStatusResponses, unknown, ThrowOnError>({
+      url: "/file/status",
+      ...options,
+    })
+  }
 }
 
 class Tui extends _HeyApiClient {
-    /**
-     * Append prompt to the TUI
-     */
-    public appendPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiAppendPromptData, ThrowOnError>) {
-        return (options?.client ?? this._client).post<TuiAppendPromptResponses, unknown, ThrowOnError>({
-            url: '/tui/append-prompt',
-            ...options,
-            headers: {
-                'Content-Type': 'application/json',
-                ...options?.headers
-            }
-        });
-    }
-    
-    /**
-     * Open the help dialog
-     */
-    public openHelp<ThrowOnError extends boolean = false>(options?: Options<TuiOpenHelpData, ThrowOnError>) {
-        return (options?.client ?? this._client).post<TuiOpenHelpResponses, unknown, ThrowOnError>({
-            url: '/tui/open-help',
-            ...options
-        });
-    }
-    
-    /**
-     * Open the session dialog
-     */
-    public openSessions<ThrowOnError extends boolean = false>(options?: Options<TuiOpenSessionsData, ThrowOnError>) {
-        return (options?.client ?? this._client).post<TuiOpenSessionsResponses, unknown, ThrowOnError>({
-            url: '/tui/open-sessions',
-            ...options
-        });
-    }
-    
-    /**
-     * Open the theme dialog
-     */
-    public openThemes<ThrowOnError extends boolean = false>(options?: Options<TuiOpenThemesData, ThrowOnError>) {
-        return (options?.client ?? this._client).post<TuiOpenThemesResponses, unknown, ThrowOnError>({
-            url: '/tui/open-themes',
-            ...options
-        });
-    }
-    
-    /**
-     * Open the model dialog
-     */
-    public openModels<ThrowOnError extends boolean = false>(options?: Options<TuiOpenModelsData, ThrowOnError>) {
-        return (options?.client ?? this._client).post<TuiOpenModelsResponses, unknown, ThrowOnError>({
-            url: '/tui/open-models',
-            ...options
-        });
-    }
-    
-    /**
-     * Submit the prompt
-     */
-    public submitPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiSubmitPromptData, ThrowOnError>) {
-        return (options?.client ?? this._client).post<TuiSubmitPromptResponses, unknown, ThrowOnError>({
-            url: '/tui/submit-prompt',
-            ...options
-        });
-    }
-    
-    /**
-     * Clear the prompt
-     */
-    public clearPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiClearPromptData, ThrowOnError>) {
-        return (options?.client ?? this._client).post<TuiClearPromptResponses, unknown, ThrowOnError>({
-            url: '/tui/clear-prompt',
-            ...options
-        });
-    }
-    
-    /**
-     * Execute a TUI command (e.g. switch_mode)
-     */
-    public executeCommand<ThrowOnError extends boolean = false>(options?: Options<TuiExecuteCommandData, ThrowOnError>) {
-        return (options?.client ?? this._client).post<TuiExecuteCommandResponses, unknown, ThrowOnError>({
-            url: '/tui/execute-command',
-            ...options,
-            headers: {
-                'Content-Type': 'application/json',
-                ...options?.headers
-            }
-        });
-    }
+  /**
+   * Append prompt to the TUI
+   */
+  public appendPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiAppendPromptData, ThrowOnError>) {
+    return (options?.client ?? this._client).post<TuiAppendPromptResponses, unknown, ThrowOnError>({
+      url: "/tui/append-prompt",
+      ...options,
+      headers: {
+        "Content-Type": "application/json",
+        ...options?.headers,
+      },
+    })
+  }
+
+  /**
+   * Open the help dialog
+   */
+  public openHelp<ThrowOnError extends boolean = false>(options?: Options<TuiOpenHelpData, ThrowOnError>) {
+    return (options?.client ?? this._client).post<TuiOpenHelpResponses, unknown, ThrowOnError>({
+      url: "/tui/open-help",
+      ...options,
+    })
+  }
+
+  /**
+   * Open the session dialog
+   */
+  public openSessions<ThrowOnError extends boolean = false>(options?: Options<TuiOpenSessionsData, ThrowOnError>) {
+    return (options?.client ?? this._client).post<TuiOpenSessionsResponses, unknown, ThrowOnError>({
+      url: "/tui/open-sessions",
+      ...options,
+    })
+  }
+
+  /**
+   * Open the theme dialog
+   */
+  public openThemes<ThrowOnError extends boolean = false>(options?: Options<TuiOpenThemesData, ThrowOnError>) {
+    return (options?.client ?? this._client).post<TuiOpenThemesResponses, unknown, ThrowOnError>({
+      url: "/tui/open-themes",
+      ...options,
+    })
+  }
+
+  /**
+   * Open the model dialog
+   */
+  public openModels<ThrowOnError extends boolean = false>(options?: Options<TuiOpenModelsData, ThrowOnError>) {
+    return (options?.client ?? this._client).post<TuiOpenModelsResponses, unknown, ThrowOnError>({
+      url: "/tui/open-models",
+      ...options,
+    })
+  }
+
+  /**
+   * Submit the prompt
+   */
+  public submitPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiSubmitPromptData, ThrowOnError>) {
+    return (options?.client ?? this._client).post<TuiSubmitPromptResponses, unknown, ThrowOnError>({
+      url: "/tui/submit-prompt",
+      ...options,
+    })
+  }
+
+  /**
+   * Clear the prompt
+   */
+  public clearPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiClearPromptData, ThrowOnError>) {
+    return (options?.client ?? this._client).post<TuiClearPromptResponses, unknown, ThrowOnError>({
+      url: "/tui/clear-prompt",
+      ...options,
+    })
+  }
+
+  /**
+   * Execute a TUI command (e.g. switch_mode)
+   */
+  public executeCommand<ThrowOnError extends boolean = false>(options?: Options<TuiExecuteCommandData, ThrowOnError>) {
+    return (options?.client ?? this._client).post<TuiExecuteCommandResponses, unknown, ThrowOnError>({
+      url: "/tui/execute-command",
+      ...options,
+      headers: {
+        "Content-Type": "application/json",
+        ...options?.headers,
+      },
+    })
+  }
 }
 
 export class OpencodeClient extends _HeyApiClient {
-    /**
-     * Respond to a permission request
-     */
-    public postSessionByIdPermissionsByPermissionId<ThrowOnError extends boolean = false>(options: Options<PostSessionByIdPermissionsByPermissionIdData, ThrowOnError>) {
-        return (options.client ?? this._client).post<PostSessionByIdPermissionsByPermissionIdResponses, unknown, ThrowOnError>({
-            url: '/session/{id}/permissions/{permissionID}',
-            ...options,
-            headers: {
-                'Content-Type': 'application/json',
-                ...options.headers
-            }
-        });
-    }
-    event = new Event({ client: this._client });
-    app = new App({ client: this._client });
-    config = new Config({ client: this._client });
-    session = new Session({ client: this._client });
-    find = new Find({ client: this._client });
-    file = new File({ client: this._client });
-    tui = new Tui({ client: this._client });
-}
+  /**
+   * Respond to a permission request
+   */
+  public postSessionByIdPermissionsByPermissionId<ThrowOnError extends boolean = false>(
+    options: Options<PostSessionByIdPermissionsByPermissionIdData, ThrowOnError>,
+  ) {
+    return (options.client ?? this._client).post<
+      PostSessionByIdPermissionsByPermissionIdResponses,
+      unknown,
+      ThrowOnError
+    >({
+      url: "/session/{id}/permissions/{permissionID}",
+      ...options,
+      headers: {
+        "Content-Type": "application/json",
+        ...options.headers,
+      },
+    })
+  }
+  event = new Event({ client: this._client })
+  app = new App({ client: this._client })
+  config = new Config({ client: this._client })
+  session = new Session({ client: this._client })
+  find = new Find({ client: this._client })
+  file = new File({ client: this._client })
+  tui = new Tui({ client: this._client })
+}

+ 1408 - 1357
packages/sdk/js/src/gen/types.gen.ts

@@ -1,1639 +1,1690 @@
 // This file is auto-generated by @hey-api/openapi-ts
 
-export type Event = ({
-    type: 'installation.updated';
-} & EventInstallationUpdated) | ({
-    type: 'lsp.client.diagnostics';
-} & EventLspClientDiagnostics) | ({
-    type: 'message.updated';
-} & EventMessageUpdated) | ({
-    type: 'message.removed';
-} & EventMessageRemoved) | ({
-    type: 'message.part.updated';
-} & EventMessagePartUpdated) | ({
-    type: 'message.part.removed';
-} & EventMessagePartRemoved) | ({
-    type: 'storage.write';
-} & EventStorageWrite) | ({
-    type: 'permission.updated';
-} & EventPermissionUpdated) | ({
-    type: 'permission.replied';
-} & EventPermissionReplied) | ({
-    type: 'file.edited';
-} & EventFileEdited) | ({
-    type: 'session.updated';
-} & EventSessionUpdated) | ({
-    type: 'session.deleted';
-} & EventSessionDeleted) | ({
-    type: 'session.idle';
-} & EventSessionIdle) | ({
-    type: 'session.error';
-} & EventSessionError) | ({
-    type: 'server.connected';
-} & EventServerConnected) | ({
-    type: 'file.watcher.updated';
-} & EventFileWatcherUpdated) | ({
-    type: 'ide.installed';
-} & EventIdeInstalled);
+export type Event =
+  | ({
+      type: "installation.updated"
+    } & EventInstallationUpdated)
+  | ({
+      type: "lsp.client.diagnostics"
+    } & EventLspClientDiagnostics)
+  | ({
+      type: "message.updated"
+    } & EventMessageUpdated)
+  | ({
+      type: "message.removed"
+    } & EventMessageRemoved)
+  | ({
+      type: "message.part.updated"
+    } & EventMessagePartUpdated)
+  | ({
+      type: "message.part.removed"
+    } & EventMessagePartRemoved)
+  | ({
+      type: "storage.write"
+    } & EventStorageWrite)
+  | ({
+      type: "file.edited"
+    } & EventFileEdited)
+  | ({
+      type: "server.connected"
+    } & EventServerConnected)
+  | ({
+      type: "permission.updated"
+    } & EventPermissionUpdated)
+  | ({
+      type: "permission.replied"
+    } & EventPermissionReplied)
+  | ({
+      type: "session.updated"
+    } & EventSessionUpdated)
+  | ({
+      type: "session.deleted"
+    } & EventSessionDeleted)
+  | ({
+      type: "session.idle"
+    } & EventSessionIdle)
+  | ({
+      type: "session.error"
+    } & EventSessionError)
+  | ({
+      type: "file.watcher.updated"
+    } & EventFileWatcherUpdated)
+  | ({
+      type: "ide.installed"
+    } & EventIdeInstalled)
 
 export type EventInstallationUpdated = {
-    type: string;
-    properties: {
-        version: string;
-    };
-};
+  type: string
+  properties: {
+    version: string
+  }
+}
 
 export type EventLspClientDiagnostics = {
-    type: string;
-    properties: {
-        serverID: string;
-        path: string;
-    };
-};
+  type: string
+  properties: {
+    serverID: string
+    path: string
+  }
+}
 
 export type EventMessageUpdated = {
-    type: string;
-    properties: {
-        info: Message;
-    };
-};
-
-export type Message = ({
-    role: 'user';
-} & UserMessage) | ({
-    role: 'assistant';
-} & AssistantMessage);
+  type: string
+  properties: {
+    info: Message
+  }
+}
+
+export type Message =
+  | ({
+      role: "user"
+    } & UserMessage)
+  | ({
+      role: "assistant"
+    } & AssistantMessage)
 
 export type UserMessage = {
-    id: string;
-    sessionID: string;
-    role: string;
-    time: {
-        created: number;
-    };
-};
+  id: string
+  sessionID: string
+  role: string
+  time: {
+    created: number
+  }
+}
 
 export type AssistantMessage = {
-    id: string;
-    sessionID: string;
-    role: string;
-    time: {
-        created: number;
-        completed?: number;
-    };
-    error?: ({
-        name: 'ProviderAuthError';
-    } & ProviderAuthError) | ({
-        name: 'UnknownError';
-    } & UnknownError) | ({
-        name: 'MessageOutputLengthError';
-    } & MessageOutputLengthError) | ({
-        name: 'MessageAbortedError';
-    } & MessageAbortedError);
-    system: Array<string>;
-    modelID: string;
-    providerID: string;
-    mode: string;
-    path: {
-        cwd: string;
-        root: string;
-    };
-    summary?: boolean;
-    cost: number;
-    tokens: {
-        input: number;
-        output: number;
-        reasoning: number;
-        cache: {
-            read: number;
-            write: number;
-        };
-    };
-};
+  id: string
+  sessionID: string
+  role: string
+  time: {
+    created: number
+    completed?: number
+  }
+  error?:
+    | ({
+        name: "ProviderAuthError"
+      } & ProviderAuthError)
+    | ({
+        name: "UnknownError"
+      } & UnknownError)
+    | ({
+        name: "MessageOutputLengthError"
+      } & MessageOutputLengthError)
+    | ({
+        name: "MessageAbortedError"
+      } & MessageAbortedError)
+  system: Array<string>
+  modelID: string
+  providerID: string
+  mode: string
+  path: {
+    cwd: string
+    root: string
+  }
+  summary?: boolean
+  cost: number
+  tokens: {
+    input: number
+    output: number
+    reasoning: number
+    cache: {
+      read: number
+      write: number
+    }
+  }
+}
 
 export type ProviderAuthError = {
-    name: string;
-    data: {
-        providerID: string;
-        message: string;
-    };
-};
+  name: string
+  data: {
+    providerID: string
+    message: string
+  }
+}
 
 export type UnknownError = {
-    name: string;
-    data: {
-        message: string;
-    };
-};
+  name: string
+  data: {
+    message: string
+  }
+}
 
 export type MessageOutputLengthError = {
-    name: string;
-    data: {
-        [key: string]: unknown;
-    };
-};
+  name: string
+  data: {
+    [key: string]: unknown
+  }
+}
 
 export type MessageAbortedError = {
-    name: string;
-    data: {
-        [key: string]: unknown;
-    };
-};
+  name: string
+  data: {
+    [key: string]: unknown
+  }
+}
 
 export type EventMessageRemoved = {
-    type: string;
-    properties: {
-        sessionID: string;
-        messageID: string;
-    };
-};
+  type: string
+  properties: {
+    sessionID: string
+    messageID: string
+  }
+}
 
 export type EventMessagePartUpdated = {
-    type: string;
-    properties: {
-        part: Part;
-    };
-};
-
-export type Part = ({
-    type: 'text';
-} & TextPart) | ({
-    type: 'file';
-} & FilePart) | ({
-    type: 'tool';
-} & ToolPart) | ({
-    type: 'step-start';
-} & StepStartPart) | ({
-    type: 'step-finish';
-} & StepFinishPart) | ({
-    type: 'snapshot';
-} & SnapshotPart) | ({
-    type: 'patch';
-} & PatchPart);
+  type: string
+  properties: {
+    part: Part
+  }
+}
+
+export type Part =
+  | ({
+      type: "text"
+    } & TextPart)
+  | ({
+      type: "file"
+    } & FilePart)
+  | ({
+      type: "tool"
+    } & ToolPart)
+  | ({
+      type: "step-start"
+    } & StepStartPart)
+  | ({
+      type: "step-finish"
+    } & StepFinishPart)
+  | ({
+      type: "snapshot"
+    } & SnapshotPart)
+  | ({
+      type: "patch"
+    } & PatchPart)
 
 export type TextPart = {
-    id: string;
-    sessionID: string;
-    messageID: string;
-    type: string;
-    text: string;
-    synthetic?: boolean;
-    time?: {
-        start: number;
-        end?: number;
-    };
-};
+  id: string
+  sessionID: string
+  messageID: string
+  type: string
+  text: string
+  synthetic?: boolean
+  time?: {
+    start: number
+    end?: number
+  }
+}
 
 export type FilePart = {
-    id: string;
-    sessionID: string;
-    messageID: string;
-    type: string;
-    mime: string;
-    filename?: string;
-    url: string;
-    source?: FilePartSource;
-};
-
-export type FilePartSource = ({
-    type: 'file';
-} & FileSource) | ({
-    type: 'symbol';
-} & SymbolSource);
+  id: string
+  sessionID: string
+  messageID: string
+  type: string
+  mime: string
+  filename?: string
+  url: string
+  source?: FilePartSource
+}
+
+export type FilePartSource =
+  | ({
+      type: "file"
+    } & FileSource)
+  | ({
+      type: "symbol"
+    } & SymbolSource)
 
 export type FileSource = {
-    text: FilePartSourceText;
-    type: string;
-    path: string;
-};
+  text: FilePartSourceText
+  type: string
+  path: string
+}
 
 export type FilePartSourceText = {
-    value: string;
-    start: number;
-    end: number;
-};
+  value: string
+  start: number
+  end: number
+}
 
 export type SymbolSource = {
-    text: FilePartSourceText;
-    type: string;
-    path: string;
-    range: Range;
-    name: string;
-    kind: number;
-};
+  text: FilePartSourceText
+  type: string
+  path: string
+  range: Range
+  name: string
+  kind: number
+}
 
 export type Range = {
-    start: {
-        line: number;
-        character: number;
-    };
-    end: {
-        line: number;
-        character: number;
-    };
-};
+  start: {
+    line: number
+    character: number
+  }
+  end: {
+    line: number
+    character: number
+  }
+}
 
 export type ToolPart = {
-    id: string;
-    sessionID: string;
-    messageID: string;
-    type: string;
-    callID: string;
-    tool: string;
-    state: ToolState;
-};
-
-export type ToolState = ({
-    status: 'pending';
-} & ToolStatePending) | ({
-    status: 'running';
-} & ToolStateRunning) | ({
-    status: 'completed';
-} & ToolStateCompleted) | ({
-    status: 'error';
-} & ToolStateError);
+  id: string
+  sessionID: string
+  messageID: string
+  type: string
+  callID: string
+  tool: string
+  state: ToolState
+}
+
+export type ToolState =
+  | ({
+      status: "pending"
+    } & ToolStatePending)
+  | ({
+      status: "running"
+    } & ToolStateRunning)
+  | ({
+      status: "completed"
+    } & ToolStateCompleted)
+  | ({
+      status: "error"
+    } & ToolStateError)
 
 export type ToolStatePending = {
-    status: string;
-};
+  status: string
+}
 
 export type ToolStateRunning = {
-    status: string;
-    input?: unknown;
-    title?: string;
-    metadata?: {
-        [key: string]: unknown;
-    };
-    time: {
-        start: number;
-    };
-};
+  status: string
+  input?: unknown
+  title?: string
+  metadata?: {
+    [key: string]: unknown
+  }
+  time: {
+    start: number
+  }
+}
 
 export type ToolStateCompleted = {
-    status: string;
-    input: {
-        [key: string]: unknown;
-    };
-    output: string;
-    title: string;
-    metadata: {
-        [key: string]: unknown;
-    };
-    time: {
-        start: number;
-        end: number;
-    };
-};
+  status: string
+  input: {
+    [key: string]: unknown
+  }
+  output: string
+  title: string
+  metadata: {
+    [key: string]: unknown
+  }
+  time: {
+    start: number
+    end: number
+  }
+}
 
 export type ToolStateError = {
-    status: string;
-    input: {
-        [key: string]: unknown;
-    };
-    error: string;
-    time: {
-        start: number;
-        end: number;
-    };
-};
+  status: string
+  input: {
+    [key: string]: unknown
+  }
+  error: string
+  time: {
+    start: number
+    end: number
+  }
+}
 
 export type StepStartPart = {
-    id: string;
-    sessionID: string;
-    messageID: string;
-    type: string;
-};
+  id: string
+  sessionID: string
+  messageID: string
+  type: string
+}
 
 export type StepFinishPart = {
-    id: string;
-    sessionID: string;
-    messageID: string;
-    type: string;
-    cost: number;
-    tokens: {
-        input: number;
-        output: number;
-        reasoning: number;
-        cache: {
-            read: number;
-            write: number;
-        };
-    };
-};
+  id: string
+  sessionID: string
+  messageID: string
+  type: string
+  cost: number
+  tokens: {
+    input: number
+    output: number
+    reasoning: number
+    cache: {
+      read: number
+      write: number
+    }
+  }
+}
 
 export type SnapshotPart = {
-    id: string;
-    sessionID: string;
-    messageID: string;
-    type: string;
-    snapshot: string;
-};
+  id: string
+  sessionID: string
+  messageID: string
+  type: string
+  snapshot: string
+}
 
 export type PatchPart = {
-    id: string;
-    sessionID: string;
-    messageID: string;
-    type: string;
-    hash: string;
-    files: Array<string>;
-};
+  id: string
+  sessionID: string
+  messageID: string
+  type: string
+  hash: string
+  files: Array<string>
+}
 
 export type EventMessagePartRemoved = {
-    type: string;
-    properties: {
-        sessionID: string;
-        messageID: string;
-        partID: string;
-    };
-};
+  type: string
+  properties: {
+    sessionID: string
+    messageID: string
+    partID: string
+  }
+}
 
 export type EventStorageWrite = {
-    type: string;
-    properties: {
-        key: string;
-        content?: unknown;
-    };
-};
+  type: string
+  properties: {
+    key: string
+    content?: unknown
+  }
+}
+
+export type EventFileEdited = {
+  type: string
+  properties: {
+    file: string
+  }
+}
+
+export type EventServerConnected = {
+  type: string
+  properties: {
+    [key: string]: unknown
+  }
+}
 
 export type EventPermissionUpdated = {
-    type: string;
-    properties: Permission;
-};
+  type: string
+  properties: Permission
+}
 
 export type Permission = {
-    id: string;
-    type: string;
-    pattern?: string;
-    sessionID: string;
-    messageID: string;
-    callID?: string;
-    title: string;
-    metadata: {
-        [key: string]: unknown;
-    };
-    time: {
-        created: number;
-    };
-};
+  id: string
+  type: string
+  pattern?: string
+  sessionID: string
+  messageID: string
+  callID?: string
+  title: string
+  metadata: {
+    [key: string]: unknown
+  }
+  time: {
+    created: number
+  }
+}
 
 export type EventPermissionReplied = {
-    type: string;
-    properties: {
-        sessionID: string;
-        permissionID: string;
-        response: string;
-    };
-};
-
-export type EventFileEdited = {
-    type: string;
-    properties: {
-        file: string;
-    };
-};
+  type: string
+  properties: {
+    sessionID: string
+    permissionID: string
+    response: string
+  }
+}
 
 export type EventSessionUpdated = {
-    type: string;
-    properties: {
-        info: Session;
-    };
-};
+  type: string
+  properties: {
+    info: Session
+  }
+}
 
 export type Session = {
-    id: string;
-    parentID?: string;
-    share?: {
-        url: string;
-    };
-    title: string;
-    version: string;
-    time: {
-        created: number;
-        updated: number;
-    };
-    revert?: {
-        messageID: string;
-        partID?: string;
-        snapshot?: string;
-        diff?: string;
-    };
-};
+  id: string
+  parentID?: string
+  share?: {
+    url: string
+  }
+  title: string
+  version: string
+  time: {
+    created: number
+    updated: number
+  }
+  revert?: {
+    messageID: string
+    partID?: string
+    snapshot?: string
+    diff?: string
+  }
+}
 
 export type EventSessionDeleted = {
-    type: string;
-    properties: {
-        info: Session;
-    };
-};
+  type: string
+  properties: {
+    info: Session
+  }
+}
 
 export type EventSessionIdle = {
-    type: string;
-    properties: {
-        sessionID: string;
-    };
-};
+  type: string
+  properties: {
+    sessionID: string
+  }
+}
 
 export type EventSessionError = {
-    type: string;
-    properties: {
-        sessionID?: string;
-        error?: ({
-            name: 'ProviderAuthError';
-        } & ProviderAuthError) | ({
-            name: 'UnknownError';
-        } & UnknownError) | ({
-            name: 'MessageOutputLengthError';
-        } & MessageOutputLengthError) | ({
-            name: 'MessageAbortedError';
-        } & MessageAbortedError);
-    };
-};
-
-export type EventServerConnected = {
-    type: string;
-    properties: {
-        [key: string]: unknown;
-    };
-};
+  type: string
+  properties: {
+    sessionID?: string
+    error?:
+      | ({
+          name: "ProviderAuthError"
+        } & ProviderAuthError)
+      | ({
+          name: "UnknownError"
+        } & UnknownError)
+      | ({
+          name: "MessageOutputLengthError"
+        } & MessageOutputLengthError)
+      | ({
+          name: "MessageAbortedError"
+        } & MessageAbortedError)
+  }
+}
 
 export type EventFileWatcherUpdated = {
-    type: string;
-    properties: {
-        file: string;
-        event: string;
-    };
-};
+  type: string
+  properties: {
+    file: string
+    event: string
+  }
+}
 
 export type EventIdeInstalled = {
-    type: string;
-    properties: {
-        ide: string;
-    };
-};
+  type: string
+  properties: {
+    ide: string
+  }
+}
 
 export type App = {
-    hostname: string;
-    git: boolean;
-    path: {
-        config: string;
-        data: string;
-        root: string;
-        cwd: string;
-        state: string;
-    };
-    time: {
-        initialized?: number;
-    };
-};
+  hostname: string
+  git: boolean
+  path: {
+    config: string
+    data: string
+    root: string
+    cwd: string
+    state: string
+  }
+  time: {
+    initialized?: number
+  }
+}
 
 export type Config = {
-    /**
-     * JSON schema reference for configuration validation
-     */
-    $schema?: string;
-    /**
-     * Theme name to use for the interface
-     */
-    theme?: string;
-    keybinds?: KeybindsConfig;
-    /**
-     * Control sharing behavior:'manual' allows manual sharing via commands, 'auto' enables automatic sharing, 'disabled' disables all sharing
-     */
-    share?: 'manual' | 'auto' | 'disabled';
-    /**
-     * @deprecated Use 'share' field instead. Share newly created sessions automatically
-     */
-    autoshare?: boolean;
-    /**
-     * Automatically update to the latest version
-     */
-    autoupdate?: boolean;
-    /**
-     * Disable providers that are loaded automatically
-     */
-    disabled_providers?: Array<string>;
-    /**
-     * Model to use in the format of provider/model, eg anthropic/claude-2
-     */
-    model?: string;
-    /**
-     * Small model to use for tasks like summarization and title generation in the format of provider/model
-     */
-    small_model?: string;
-    /**
-     * Custom username to display in conversations instead of system username
-     */
-    username?: string;
-    /**
-     * Modes configuration, see https://opencode.ai/docs/modes
-     */
-    mode?: {
-        build?: ModeConfig;
-        plan?: ModeConfig;
-        [key: string]: ModeConfig | undefined;
-    };
-    /**
-     * Modes configuration, see https://opencode.ai/docs/modes
-     */
-    agent?: {
-        general?: AgentConfig;
-        [key: string]: AgentConfig | undefined;
-    };
-    /**
-     * Custom provider configurations and model overrides
-     */
-    provider?: {
-        [key: string]: {
-            api?: string;
-            name?: string;
-            env?: Array<string>;
-            id?: string;
-            npm?: string;
-            models: {
-                [key: string]: {
-                    id?: string;
-                    name?: string;
-                    release_date?: string;
-                    attachment?: boolean;
-                    reasoning?: boolean;
-                    temperature?: boolean;
-                    tool_call?: boolean;
-                    cost?: {
-                        input: number;
-                        output: number;
-                        cache_read?: number;
-                        cache_write?: number;
-                    };
-                    limit?: {
-                        context: number;
-                        output: number;
-                    };
-                    options?: {
-                        [key: string]: unknown;
-                    };
-                };
-            };
-            options?: {
-                apiKey?: string;
-                baseURL?: string;
-                [key: string]: unknown | string | undefined;
-            };
-        };
-    };
-    /**
-     * MCP (Model Context Protocol) server configurations
-     */
-    mcp?: {
-        [key: string]: ({
-            type: 'local';
-        } & McpLocalConfig) | ({
-            type: 'remote';
-        } & McpRemoteConfig);
-    };
-    formatter?: {
-        [key: string]: {
-            disabled?: boolean;
-            command?: Array<string>;
-            environment?: {
-                [key: string]: string;
-            };
-            extensions?: Array<string>;
-        };
-    };
-    lsp?: {
+  /**
+   * JSON schema reference for configuration validation
+   */
+  $schema?: string
+  /**
+   * Theme name to use for the interface
+   */
+  theme?: string
+  keybinds?: KeybindsConfig
+  plugin?: Array<string>
+  /**
+   * Control sharing behavior:'manual' allows manual sharing via commands, 'auto' enables automatic sharing, 'disabled' disables all sharing
+   */
+  share?: "manual" | "auto" | "disabled"
+  /**
+   * @deprecated Use 'share' field instead. Share newly created sessions automatically
+   */
+  autoshare?: boolean
+  /**
+   * Automatically update to the latest version
+   */
+  autoupdate?: boolean
+  /**
+   * Disable providers that are loaded automatically
+   */
+  disabled_providers?: Array<string>
+  /**
+   * Model to use in the format of provider/model, eg anthropic/claude-2
+   */
+  model?: string
+  /**
+   * Small model to use for tasks like summarization and title generation in the format of provider/model
+   */
+  small_model?: string
+  /**
+   * Custom username to display in conversations instead of system username
+   */
+  username?: string
+  /**
+   * Modes configuration, see https://opencode.ai/docs/modes
+   */
+  mode?: {
+    build?: ModeConfig
+    plan?: ModeConfig
+    [key: string]: ModeConfig | undefined
+  }
+  /**
+   * Modes configuration, see https://opencode.ai/docs/modes
+   */
+  agent?: {
+    general?: AgentConfig
+    [key: string]: AgentConfig | undefined
+  }
+  /**
+   * Custom provider configurations and model overrides
+   */
+  provider?: {
+    [key: string]: {
+      api?: string
+      name?: string
+      env?: Array<string>
+      id?: string
+      npm?: string
+      models: {
         [key: string]: {
-            disabled: boolean;
-        } | {
-            command: Array<string>;
-            extensions?: Array<string>;
-            disabled?: boolean;
-            env?: {
-                [key: string]: string;
-            };
-            initialization?: {
-                [key: string]: unknown;
-            };
-        };
-    };
-    /**
-     * Additional instruction files or patterns to include
-     */
-    instructions?: Array<string>;
-    layout?: LayoutConfig;
-    permission?: {
-        edit?: string;
-        bash?: string | {
-            [key: string]: string;
-        };
-    };
-    experimental?: {
-        hook?: {
-            file_edited?: {
-                [key: string]: Array<{
-                    command: Array<string>;
-                    environment?: {
-                        [key: string]: string;
-                    };
-                }>;
-            };
-            session_completed?: Array<{
-                command: Array<string>;
-                environment?: {
-                    [key: string]: string;
-                };
-            }>;
-        };
-    };
-};
+          id?: string
+          name?: string
+          release_date?: string
+          attachment?: boolean
+          reasoning?: boolean
+          temperature?: boolean
+          tool_call?: boolean
+          cost?: {
+            input: number
+            output: number
+            cache_read?: number
+            cache_write?: number
+          }
+          limit?: {
+            context: number
+            output: number
+          }
+          options?: {
+            [key: string]: unknown
+          }
+        }
+      }
+      options?: {
+        apiKey?: string
+        baseURL?: string
+        [key: string]: unknown | string | undefined
+      }
+    }
+  }
+  /**
+   * MCP (Model Context Protocol) server configurations
+   */
+  mcp?: {
+    [key: string]:
+      | ({
+          type: "local"
+        } & McpLocalConfig)
+      | ({
+          type: "remote"
+        } & McpRemoteConfig)
+  }
+  formatter?: {
+    [key: string]: {
+      disabled?: boolean
+      command?: Array<string>
+      environment?: {
+        [key: string]: string
+      }
+      extensions?: Array<string>
+    }
+  }
+  lsp?: {
+    [key: string]:
+      | {
+          disabled: boolean
+        }
+      | {
+          command: Array<string>
+          extensions?: Array<string>
+          disabled?: boolean
+          env?: {
+            [key: string]: string
+          }
+          initialization?: {
+            [key: string]: unknown
+          }
+        }
+  }
+  /**
+   * Additional instruction files or patterns to include
+   */
+  instructions?: Array<string>
+  layout?: LayoutConfig
+  permission?: {
+    edit?: string
+    bash?:
+      | string
+      | {
+          [key: string]: string
+        }
+  }
+  experimental?: {
+    hook?: {
+      file_edited?: {
+        [key: string]: Array<{
+          command: Array<string>
+          environment?: {
+            [key: string]: string
+          }
+        }>
+      }
+      session_completed?: Array<{
+        command: Array<string>
+        environment?: {
+          [key: string]: string
+        }
+      }>
+    }
+  }
+}
 
 export type KeybindsConfig = {
-    /**
-     * Leader key for keybind combinations
-     */
-    leader: string;
-    /**
-     * Show help dialog
-     */
-    app_help: string;
-    /**
-     * Next mode
-     */
-    switch_mode: string;
-    /**
-     * Previous Mode
-     */
-    switch_mode_reverse: string;
-    /**
-     * Open external editor
-     */
-    editor_open: string;
-    /**
-     * Export session to editor
-     */
-    session_export: string;
-    /**
-     * Create a new session
-     */
-    session_new: string;
-    /**
-     * List all sessions
-     */
-    session_list: string;
-    /**
-     * Share current session
-     */
-    session_share: string;
-    /**
-     * Unshare current session
-     */
-    session_unshare: string;
-    /**
-     * Interrupt current session
-     */
-    session_interrupt: string;
-    /**
-     * Compact the session
-     */
-    session_compact: string;
-    /**
-     * Toggle tool details
-     */
-    tool_details: string;
-    /**
-     * List available models
-     */
-    model_list: string;
-    /**
-     * List available themes
-     */
-    theme_list: string;
-    /**
-     * List files
-     */
-    file_list: string;
-    /**
-     * Close file
-     */
-    file_close: string;
-    /**
-     * Search file
-     */
-    file_search: string;
-    /**
-     * Split/unified diff
-     */
-    file_diff_toggle: string;
-    /**
-     * Create/update AGENTS.md
-     */
-    project_init: string;
-    /**
-     * Clear input field
-     */
-    input_clear: string;
-    /**
-     * Paste from clipboard
-     */
-    input_paste: string;
-    /**
-     * Submit input
-     */
-    input_submit: string;
-    /**
-     * Insert newline in input
-     */
-    input_newline: string;
-    /**
-     * Scroll messages up by one page
-     */
-    messages_page_up: string;
-    /**
-     * Scroll messages down by one page
-     */
-    messages_page_down: string;
-    /**
-     * Scroll messages up by half page
-     */
-    messages_half_page_up: string;
-    /**
-     * Scroll messages down by half page
-     */
-    messages_half_page_down: string;
-    /**
-     * Navigate to previous message
-     */
-    messages_previous: string;
-    /**
-     * Navigate to next message
-     */
-    messages_next: string;
-    /**
-     * Navigate to first message
-     */
-    messages_first: string;
-    /**
-     * Navigate to last message
-     */
-    messages_last: string;
-    /**
-     * Toggle layout
-     */
-    messages_layout_toggle: string;
-    /**
-     * Copy message
-     */
-    messages_copy: string;
-    /**
-     * @deprecated use messages_undo. Revert message
-     */
-    messages_revert: string;
-    /**
-     * Undo message
-     */
-    messages_undo: string;
-    /**
-     * Redo message
-     */
-    messages_redo: string;
-    /**
-     * Exit the application
-     */
-    app_exit: string;
-};
+  /**
+   * Leader key for keybind combinations
+   */
+  leader: string
+  /**
+   * Show help dialog
+   */
+  app_help: string
+  /**
+   * Next mode
+   */
+  switch_mode: string
+  /**
+   * Previous Mode
+   */
+  switch_mode_reverse: string
+  /**
+   * Open external editor
+   */
+  editor_open: string
+  /**
+   * Export session to editor
+   */
+  session_export: string
+  /**
+   * Create a new session
+   */
+  session_new: string
+  /**
+   * List all sessions
+   */
+  session_list: string
+  /**
+   * Share current session
+   */
+  session_share: string
+  /**
+   * Unshare current session
+   */
+  session_unshare: string
+  /**
+   * Interrupt current session
+   */
+  session_interrupt: string
+  /**
+   * Compact the session
+   */
+  session_compact: string
+  /**
+   * Toggle tool details
+   */
+  tool_details: string
+  /**
+   * List available models
+   */
+  model_list: string
+  /**
+   * List available themes
+   */
+  theme_list: string
+  /**
+   * List files
+   */
+  file_list: string
+  /**
+   * Close file
+   */
+  file_close: string
+  /**
+   * Search file
+   */
+  file_search: string
+  /**
+   * Split/unified diff
+   */
+  file_diff_toggle: string
+  /**
+   * Create/update AGENTS.md
+   */
+  project_init: string
+  /**
+   * Clear input field
+   */
+  input_clear: string
+  /**
+   * Paste from clipboard
+   */
+  input_paste: string
+  /**
+   * Submit input
+   */
+  input_submit: string
+  /**
+   * Insert newline in input
+   */
+  input_newline: string
+  /**
+   * Scroll messages up by one page
+   */
+  messages_page_up: string
+  /**
+   * Scroll messages down by one page
+   */
+  messages_page_down: string
+  /**
+   * Scroll messages up by half page
+   */
+  messages_half_page_up: string
+  /**
+   * Scroll messages down by half page
+   */
+  messages_half_page_down: string
+  /**
+   * Navigate to previous message
+   */
+  messages_previous: string
+  /**
+   * Navigate to next message
+   */
+  messages_next: string
+  /**
+   * Navigate to first message
+   */
+  messages_first: string
+  /**
+   * Navigate to last message
+   */
+  messages_last: string
+  /**
+   * Toggle layout
+   */
+  messages_layout_toggle: string
+  /**
+   * Copy message
+   */
+  messages_copy: string
+  /**
+   * @deprecated use messages_undo. Revert message
+   */
+  messages_revert: string
+  /**
+   * Undo message
+   */
+  messages_undo: string
+  /**
+   * Redo message
+   */
+  messages_redo: string
+  /**
+   * Exit the application
+   */
+  app_exit: string
+}
 
 export type ModeConfig = {
-    model?: string;
-    temperature?: number;
-    top_p?: number;
-    prompt?: string;
-    tools?: {
-        [key: string]: boolean;
-    };
-    disable?: boolean;
-};
+  model?: string
+  temperature?: number
+  top_p?: number
+  prompt?: string
+  tools?: {
+    [key: string]: boolean
+  }
+  disable?: boolean
+}
 
 export type AgentConfig = ModeConfig & {
-    description: string;
-};
+  description: string
+}
 
 export type Provider = {
-    api?: string;
-    name: string;
-    env: Array<string>;
-    id: string;
-    npm?: string;
-    models: {
-        [key: string]: Model;
-    };
-};
+  api?: string
+  name: string
+  env: Array<string>
+  id: string
+  npm?: string
+  models: {
+    [key: string]: Model
+  }
+}
 
 export type Model = {
-    id: string;
-    name: string;
-    release_date: string;
-    attachment: boolean;
-    reasoning: boolean;
-    temperature: boolean;
-    tool_call: boolean;
-    cost: {
-        input: number;
-        output: number;
-        cache_read?: number;
-        cache_write?: number;
-    };
-    limit: {
-        context: number;
-        output: number;
-    };
-    options: {
-        [key: string]: unknown;
-    };
-};
+  id: string
+  name: string
+  release_date: string
+  attachment: boolean
+  reasoning: boolean
+  temperature: boolean
+  tool_call: boolean
+  cost: {
+    input: number
+    output: number
+    cache_read?: number
+    cache_write?: number
+  }
+  limit: {
+    context: number
+    output: number
+  }
+  options: {
+    [key: string]: unknown
+  }
+}
 
 export type McpLocalConfig = {
-    /**
-     * Type of MCP server connection
-     */
-    type: string;
-    /**
-     * Command and arguments to run the MCP server
-     */
-    command: Array<string>;
-    /**
-     * Environment variables to set when running the MCP server
-     */
-    environment?: {
-        [key: string]: string;
-    };
-    /**
-     * Enable or disable the MCP server on startup
-     */
-    enabled?: boolean;
-};
+  /**
+   * Type of MCP server connection
+   */
+  type: string
+  /**
+   * Command and arguments to run the MCP server
+   */
+  command: Array<string>
+  /**
+   * Environment variables to set when running the MCP server
+   */
+  environment?: {
+    [key: string]: string
+  }
+  /**
+   * Enable or disable the MCP server on startup
+   */
+  enabled?: boolean
+}
 
 export type McpRemoteConfig = {
-    /**
-     * Type of MCP server connection
-     */
-    type: string;
-    /**
-     * URL of the remote MCP server
-     */
-    url: string;
-    /**
-     * Enable or disable the MCP server on startup
-     */
-    enabled?: boolean;
-    /**
-     * Headers to send with the request
-     */
-    headers?: {
-        [key: string]: string;
-    };
-};
-
-export type LayoutConfig = 'auto' | 'stretch';
+  /**
+   * Type of MCP server connection
+   */
+  type: string
+  /**
+   * URL of the remote MCP server
+   */
+  url: string
+  /**
+   * Enable or disable the MCP server on startup
+   */
+  enabled?: boolean
+  /**
+   * Headers to send with the request
+   */
+  headers?: {
+    [key: string]: string
+  }
+}
+
+export type LayoutConfig = "auto" | "stretch"
 
 export type _Error = {
-    data: {
-        [key: string]: unknown;
-    };
-};
+  data: {
+    [key: string]: unknown
+  }
+}
 
 export type TextPartInput = {
-    id?: string;
-    type: string;
-    text: string;
-    synthetic?: boolean;
-    time?: {
-        start: number;
-        end?: number;
-    };
-};
+  id?: string
+  type: string
+  text: string
+  synthetic?: boolean
+  time?: {
+    start: number
+    end?: number
+  }
+}
 
 export type FilePartInput = {
-    id?: string;
-    type: string;
-    mime: string;
-    filename?: string;
-    url: string;
-    source?: FilePartSource;
-};
+  id?: string
+  type: string
+  mime: string
+  filename?: string
+  url: string
+  source?: FilePartSource
+}
 
 export type Symbol = {
-    name: string;
-    kind: number;
-    location: {
-        uri: string;
-        range: Range;
-    };
-};
+  name: string
+  kind: number
+  location: {
+    uri: string
+    range: Range
+  }
+}
 
 export type File = {
-    path: string;
-    added: number;
-    removed: number;
-    status: 'added' | 'deleted' | 'modified';
-};
+  path: string
+  added: number
+  removed: number
+  status: "added" | "deleted" | "modified"
+}
 
 export type Mode = {
-    name: string;
-    temperature?: number;
-    topP?: number;
-    model?: {
-        modelID: string;
-        providerID: string;
-    };
-    prompt?: string;
-    tools: {
-        [key: string]: boolean;
-    };
-};
+  name: string
+  temperature?: number
+  topP?: number
+  model?: {
+    modelID: string
+    providerID: string
+  }
+  prompt?: string
+  tools: {
+    [key: string]: boolean
+  }
+}
 
 export type EventSubscribeData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/event';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/event"
+}
 
 export type EventSubscribeResponses = {
-    /**
-     * Event stream
-     */
-    200: Event;
-};
+  /**
+   * Event stream
+   */
+  200: Event
+}
 
-export type EventSubscribeResponse = EventSubscribeResponses[keyof EventSubscribeResponses];
+export type EventSubscribeResponse = EventSubscribeResponses[keyof EventSubscribeResponses]
 
 export type AppGetData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/app';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/app"
+}
 
 export type AppGetResponses = {
-    /**
-     * 200
-     */
-    200: App;
-};
+  /**
+   * 200
+   */
+  200: App
+}
 
-export type AppGetResponse = AppGetResponses[keyof AppGetResponses];
+export type AppGetResponse = AppGetResponses[keyof AppGetResponses]
 
 export type AppInitData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/app/init';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/app/init"
+}
 
 export type AppInitResponses = {
-    /**
-     * Initialize the app
-     */
-    200: boolean;
-};
+  /**
+   * Initialize the app
+   */
+  200: boolean
+}
 
-export type AppInitResponse = AppInitResponses[keyof AppInitResponses];
+export type AppInitResponse = AppInitResponses[keyof AppInitResponses]
 
 export type ConfigGetData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/config';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/config"
+}
 
 export type ConfigGetResponses = {
-    /**
-     * Get config info
-     */
-    200: Config;
-};
+  /**
+   * Get config info
+   */
+  200: Config
+}
 
-export type ConfigGetResponse = ConfigGetResponses[keyof ConfigGetResponses];
+export type ConfigGetResponse = ConfigGetResponses[keyof ConfigGetResponses]
 
 export type SessionListData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/session';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/session"
+}
 
 export type SessionListResponses = {
-    /**
-     * List of sessions
-     */
-    200: Array<Session>;
-};
+  /**
+   * List of sessions
+   */
+  200: Array<Session>
+}
 
-export type SessionListResponse = SessionListResponses[keyof SessionListResponses];
+export type SessionListResponse = SessionListResponses[keyof SessionListResponses]
 
 export type SessionCreateData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/session';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/session"
+}
 
 export type SessionCreateErrors = {
-    /**
-     * Bad request
-     */
-    400: _Error;
-};
+  /**
+   * Bad request
+   */
+  400: _Error
+}
 
-export type SessionCreateError = SessionCreateErrors[keyof SessionCreateErrors];
+export type SessionCreateError = SessionCreateErrors[keyof SessionCreateErrors]
 
 export type SessionCreateResponses = {
-    /**
-     * Successfully created session
-     */
-    200: Session;
-};
+  /**
+   * Successfully created session
+   */
+  200: Session
+}
 
-export type SessionCreateResponse = SessionCreateResponses[keyof SessionCreateResponses];
+export type SessionCreateResponse = SessionCreateResponses[keyof SessionCreateResponses]
 
 export type SessionDeleteData = {
-    body?: never;
-    path: {
-        id: string;
-    };
-    query?: never;
-    url: '/session/{id}';
-};
+  body?: never
+  path: {
+    id: string
+  }
+  query?: never
+  url: "/session/{id}"
+}
 
 export type SessionDeleteResponses = {
-    /**
-     * Successfully deleted session
-     */
-    200: boolean;
-};
+  /**
+   * Successfully deleted session
+   */
+  200: boolean
+}
 
-export type SessionDeleteResponse = SessionDeleteResponses[keyof SessionDeleteResponses];
+export type SessionDeleteResponse = SessionDeleteResponses[keyof SessionDeleteResponses]
 
 export type SessionInitData = {
-    body?: {
-        messageID: string;
-        providerID: string;
-        modelID: string;
-    };
-    path: {
-        /**
-         * Session ID
-         */
-        id: string;
-    };
-    query?: never;
-    url: '/session/{id}/init';
-};
-
-export type SessionInitResponses = {
+  body?: {
+    messageID: string
+    providerID: string
+    modelID: string
+  }
+  path: {
     /**
-     * 200
+     * Session ID
      */
-    200: boolean;
-};
+    id: string
+  }
+  query?: never
+  url: "/session/{id}/init"
+}
+
+export type SessionInitResponses = {
+  /**
+   * 200
+   */
+  200: boolean
+}
 
-export type SessionInitResponse = SessionInitResponses[keyof SessionInitResponses];
+export type SessionInitResponse = SessionInitResponses[keyof SessionInitResponses]
 
 export type SessionAbortData = {
-    body?: never;
-    path: {
-        id: string;
-    };
-    query?: never;
-    url: '/session/{id}/abort';
-};
+  body?: never
+  path: {
+    id: string
+  }
+  query?: never
+  url: "/session/{id}/abort"
+}
 
 export type SessionAbortResponses = {
-    /**
-     * Aborted session
-     */
-    200: boolean;
-};
+  /**
+   * Aborted session
+   */
+  200: boolean
+}
 
-export type SessionAbortResponse = SessionAbortResponses[keyof SessionAbortResponses];
+export type SessionAbortResponse = SessionAbortResponses[keyof SessionAbortResponses]
 
 export type SessionUnshareData = {
-    body?: never;
-    path: {
-        id: string;
-    };
-    query?: never;
-    url: '/session/{id}/share';
-};
+  body?: never
+  path: {
+    id: string
+  }
+  query?: never
+  url: "/session/{id}/share"
+}
 
 export type SessionUnshareResponses = {
-    /**
-     * Successfully unshared session
-     */
-    200: Session;
-};
+  /**
+   * Successfully unshared session
+   */
+  200: Session
+}
 
-export type SessionUnshareResponse = SessionUnshareResponses[keyof SessionUnshareResponses];
+export type SessionUnshareResponse = SessionUnshareResponses[keyof SessionUnshareResponses]
 
 export type SessionShareData = {
-    body?: never;
-    path: {
-        id: string;
-    };
-    query?: never;
-    url: '/session/{id}/share';
-};
+  body?: never
+  path: {
+    id: string
+  }
+  query?: never
+  url: "/session/{id}/share"
+}
 
 export type SessionShareResponses = {
-    /**
-     * Successfully shared session
-     */
-    200: Session;
-};
+  /**
+   * Successfully shared session
+   */
+  200: Session
+}
 
-export type SessionShareResponse = SessionShareResponses[keyof SessionShareResponses];
+export type SessionShareResponse = SessionShareResponses[keyof SessionShareResponses]
 
 export type SessionSummarizeData = {
-    body?: {
-        providerID: string;
-        modelID: string;
-    };
-    path: {
-        /**
-         * Session ID
-         */
-        id: string;
-    };
-    query?: never;
-    url: '/session/{id}/summarize';
-};
-
-export type SessionSummarizeResponses = {
+  body?: {
+    providerID: string
+    modelID: string
+  }
+  path: {
     /**
-     * Summarized session
+     * Session ID
      */
-    200: boolean;
-};
+    id: string
+  }
+  query?: never
+  url: "/session/{id}/summarize"
+}
 
-export type SessionSummarizeResponse = SessionSummarizeResponses[keyof SessionSummarizeResponses];
+export type SessionSummarizeResponses = {
+  /**
+   * Summarized session
+   */
+  200: boolean
+}
 
-export type SessionMessagesData = {
-    body?: never;
-    path: {
-        /**
-         * Session ID
-         */
-        id: string;
-    };
-    query?: never;
-    url: '/session/{id}/message';
-};
+export type SessionSummarizeResponse = SessionSummarizeResponses[keyof SessionSummarizeResponses]
 
-export type SessionMessagesResponses = {
+export type SessionMessagesData = {
+  body?: never
+  path: {
     /**
-     * List of messages
+     * Session ID
      */
-    200: Array<{
-        info: Message;
-        parts: Array<Part>;
-    }>;
-};
+    id: string
+  }
+  query?: never
+  url: "/session/{id}/message"
+}
+
+export type SessionMessagesResponses = {
+  /**
+   * List of messages
+   */
+  200: Array<{
+    info: Message
+    parts: Array<Part>
+  }>
+}
 
-export type SessionMessagesResponse = SessionMessagesResponses[keyof SessionMessagesResponses];
+export type SessionMessagesResponse = SessionMessagesResponses[keyof SessionMessagesResponses]
 
 export type SessionChatData = {
-    body?: {
-        messageID?: string;
-        providerID: string;
-        modelID: string;
-        mode?: string;
-        system?: string;
-        tools?: {
-            [key: string]: boolean;
-        };
-        parts: Array<({
-            type: 'text';
-        } & TextPartInput) | ({
-            type: 'file';
-        } & FilePartInput)>;
-    };
-    path: {
-        /**
-         * Session ID
-         */
-        id: string;
-    };
-    query?: never;
-    url: '/session/{id}/message';
-};
+  body?: {
+    messageID?: string
+    providerID: string
+    modelID: string
+    mode?: string
+    system?: string
+    tools?: {
+      [key: string]: boolean
+    }
+    parts: Array<
+      | ({
+          type: "text"
+        } & TextPartInput)
+      | ({
+          type: "file"
+        } & FilePartInput)
+    >
+  }
+  path: {
+    /**
+     * Session ID
+     */
+    id: string
+  }
+  query?: never
+  url: "/session/{id}/message"
+}
 
 export type SessionChatResponses = {
-    /**
-     * Created message
-     */
-    200: AssistantMessage;
-};
+  /**
+   * Created message
+   */
+  200: AssistantMessage
+}
 
-export type SessionChatResponse = SessionChatResponses[keyof SessionChatResponses];
+export type SessionChatResponse = SessionChatResponses[keyof SessionChatResponses]
 
 export type SessionMessageData = {
-    body?: never;
-    path: {
-        /**
-         * Session ID
-         */
-        id: string;
-        /**
-         * Message ID
-         */
-        messageID: string;
-    };
-    query?: never;
-    url: '/session/{id}/message/{messageID}';
-};
-
-export type SessionMessageResponses = {
+  body?: never
+  path: {
     /**
-     * Message
+     * Session ID
      */
-    200: {
-        info: Message;
-        parts: Array<Part>;
-    };
-};
+    id: string
+    /**
+     * Message ID
+     */
+    messageID: string
+  }
+  query?: never
+  url: "/session/{id}/message/{messageID}"
+}
+
+export type SessionMessageResponses = {
+  /**
+   * Message
+   */
+  200: {
+    info: Message
+    parts: Array<Part>
+  }
+}
 
-export type SessionMessageResponse = SessionMessageResponses[keyof SessionMessageResponses];
+export type SessionMessageResponse = SessionMessageResponses[keyof SessionMessageResponses]
 
 export type SessionRevertData = {
-    body?: {
-        messageID: string;
-        partID?: string;
-    };
-    path: {
-        id: string;
-    };
-    query?: never;
-    url: '/session/{id}/revert';
-};
+  body?: {
+    messageID: string
+    partID?: string
+  }
+  path: {
+    id: string
+  }
+  query?: never
+  url: "/session/{id}/revert"
+}
 
 export type SessionRevertResponses = {
-    /**
-     * Updated session
-     */
-    200: Session;
-};
+  /**
+   * Updated session
+   */
+  200: Session
+}
 
-export type SessionRevertResponse = SessionRevertResponses[keyof SessionRevertResponses];
+export type SessionRevertResponse = SessionRevertResponses[keyof SessionRevertResponses]
 
 export type SessionUnrevertData = {
-    body?: never;
-    path: {
-        id: string;
-    };
-    query?: never;
-    url: '/session/{id}/unrevert';
-};
+  body?: never
+  path: {
+    id: string
+  }
+  query?: never
+  url: "/session/{id}/unrevert"
+}
 
 export type SessionUnrevertResponses = {
-    /**
-     * Updated session
-     */
-    200: Session;
-};
+  /**
+   * Updated session
+   */
+  200: Session
+}
 
-export type SessionUnrevertResponse = SessionUnrevertResponses[keyof SessionUnrevertResponses];
+export type SessionUnrevertResponse = SessionUnrevertResponses[keyof SessionUnrevertResponses]
 
 export type PostSessionByIdPermissionsByPermissionIdData = {
-    body?: {
-        response: 'once' | 'always' | 'reject';
-    };
-    path: {
-        id: string;
-        permissionID: string;
-    };
-    query?: never;
-    url: '/session/{id}/permissions/{permissionID}';
-};
+  body?: {
+    response: "once" | "always" | "reject"
+  }
+  path: {
+    id: string
+    permissionID: string
+  }
+  query?: never
+  url: "/session/{id}/permissions/{permissionID}"
+}
 
 export type PostSessionByIdPermissionsByPermissionIdResponses = {
-    /**
-     * Permission processed successfully
-     */
-    200: boolean;
-};
+  /**
+   * Permission processed successfully
+   */
+  200: boolean
+}
 
-export type PostSessionByIdPermissionsByPermissionIdResponse = PostSessionByIdPermissionsByPermissionIdResponses[keyof PostSessionByIdPermissionsByPermissionIdResponses];
+export type PostSessionByIdPermissionsByPermissionIdResponse =
+  PostSessionByIdPermissionsByPermissionIdResponses[keyof PostSessionByIdPermissionsByPermissionIdResponses]
 
 export type ConfigProvidersData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/config/providers';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/config/providers"
+}
 
 export type ConfigProvidersResponses = {
-    /**
-     * List of providers
-     */
-    200: {
-        providers: Array<Provider>;
-        default: {
-            [key: string]: string;
-        };
-    };
-};
-
-export type ConfigProvidersResponse = ConfigProvidersResponses[keyof ConfigProvidersResponses];
+  /**
+   * List of providers
+   */
+  200: {
+    providers: Array<Provider>
+    default: {
+      [key: string]: string
+    }
+  }
+}
+
+export type ConfigProvidersResponse = ConfigProvidersResponses[keyof ConfigProvidersResponses]
 
 export type FindTextData = {
-    body?: never;
-    path?: never;
-    query: {
-        pattern: string;
-    };
-    url: '/find';
-};
+  body?: never
+  path?: never
+  query: {
+    pattern: string
+  }
+  url: "/find"
+}
 
 export type FindTextResponses = {
-    /**
-     * Matches
-     */
-    200: Array<{
-        path: {
-            text: string;
-        };
-        lines: {
-            text: string;
-        };
-        line_number: number;
-        absolute_offset: number;
-        submatches: Array<{
-            match: {
-                text: string;
-            };
-            start: number;
-            end: number;
-        }>;
-    }>;
-};
-
-export type FindTextResponse = FindTextResponses[keyof FindTextResponses];
+  /**
+   * Matches
+   */
+  200: Array<{
+    path: {
+      text: string
+    }
+    lines: {
+      text: string
+    }
+    line_number: number
+    absolute_offset: number
+    submatches: Array<{
+      match: {
+        text: string
+      }
+      start: number
+      end: number
+    }>
+  }>
+}
+
+export type FindTextResponse = FindTextResponses[keyof FindTextResponses]
 
 export type FindFilesData = {
-    body?: never;
-    path?: never;
-    query: {
-        query: string;
-    };
-    url: '/find/file';
-};
+  body?: never
+  path?: never
+  query: {
+    query: string
+  }
+  url: "/find/file"
+}
 
 export type FindFilesResponses = {
-    /**
-     * File paths
-     */
-    200: Array<string>;
-};
+  /**
+   * File paths
+   */
+  200: Array<string>
+}
 
-export type FindFilesResponse = FindFilesResponses[keyof FindFilesResponses];
+export type FindFilesResponse = FindFilesResponses[keyof FindFilesResponses]
 
 export type FindSymbolsData = {
-    body?: never;
-    path?: never;
-    query: {
-        query: string;
-    };
-    url: '/find/symbol';
-};
+  body?: never
+  path?: never
+  query: {
+    query: string
+  }
+  url: "/find/symbol"
+}
 
 export type FindSymbolsResponses = {
-    /**
-     * Symbols
-     */
-    200: Array<Symbol>;
-};
+  /**
+   * Symbols
+   */
+  200: Array<Symbol>
+}
 
-export type FindSymbolsResponse = FindSymbolsResponses[keyof FindSymbolsResponses];
+export type FindSymbolsResponse = FindSymbolsResponses[keyof FindSymbolsResponses]
 
 export type FileReadData = {
-    body?: never;
-    path?: never;
-    query: {
-        path: string;
-    };
-    url: '/file';
-};
+  body?: never
+  path?: never
+  query: {
+    path: string
+  }
+  url: "/file"
+}
 
 export type FileReadResponses = {
-    /**
-     * File content
-     */
-    200: {
-        type: 'raw' | 'patch';
-        content: string;
-    };
-};
+  /**
+   * File content
+   */
+  200: {
+    type: "raw" | "patch"
+    content: string
+  }
+}
 
-export type FileReadResponse = FileReadResponses[keyof FileReadResponses];
+export type FileReadResponse = FileReadResponses[keyof FileReadResponses]
 
 export type FileStatusData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/file/status';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/file/status"
+}
 
 export type FileStatusResponses = {
-    /**
-     * File status
-     */
-    200: Array<File>;
-};
+  /**
+   * File status
+   */
+  200: Array<File>
+}
 
-export type FileStatusResponse = FileStatusResponses[keyof FileStatusResponses];
+export type FileStatusResponse = FileStatusResponses[keyof FileStatusResponses]
 
 export type AppLogData = {
-    body?: {
-        /**
-         * Service name for the log entry
-         */
-        service: string;
-        /**
-         * Log level
-         */
-        level: 'debug' | 'info' | 'error' | 'warn';
-        /**
-         * Log message
-         */
-        message: string;
-        /**
-         * Additional metadata for the log entry
-         */
-        extra?: {
-            [key: string]: unknown;
-        };
-    };
-    path?: never;
-    query?: never;
-    url: '/log';
-};
-
-export type AppLogResponses = {
+  body?: {
+    /**
+     * Service name for the log entry
+     */
+    service: string
+    /**
+     * Log level
+     */
+    level: "debug" | "info" | "error" | "warn"
     /**
-     * Log entry written successfully
+     * Log message
      */
-    200: boolean;
-};
+    message: string
+    /**
+     * Additional metadata for the log entry
+     */
+    extra?: {
+      [key: string]: unknown
+    }
+  }
+  path?: never
+  query?: never
+  url: "/log"
+}
+
+export type AppLogResponses = {
+  /**
+   * Log entry written successfully
+   */
+  200: boolean
+}
 
-export type AppLogResponse = AppLogResponses[keyof AppLogResponses];
+export type AppLogResponse = AppLogResponses[keyof AppLogResponses]
 
 export type AppModesData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/mode';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/mode"
+}
 
 export type AppModesResponses = {
-    /**
-     * List of modes
-     */
-    200: Array<Mode>;
-};
+  /**
+   * List of modes
+   */
+  200: Array<Mode>
+}
 
-export type AppModesResponse = AppModesResponses[keyof AppModesResponses];
+export type AppModesResponse = AppModesResponses[keyof AppModesResponses]
 
 export type TuiAppendPromptData = {
-    body?: {
-        text: string;
-    };
-    path?: never;
-    query?: never;
-    url: '/tui/append-prompt';
-};
+  body?: {
+    text: string
+  }
+  path?: never
+  query?: never
+  url: "/tui/append-prompt"
+}
 
 export type TuiAppendPromptResponses = {
-    /**
-     * Prompt processed successfully
-     */
-    200: boolean;
-};
+  /**
+   * Prompt processed successfully
+   */
+  200: boolean
+}
 
-export type TuiAppendPromptResponse = TuiAppendPromptResponses[keyof TuiAppendPromptResponses];
+export type TuiAppendPromptResponse = TuiAppendPromptResponses[keyof TuiAppendPromptResponses]
 
 export type TuiOpenHelpData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/tui/open-help';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/tui/open-help"
+}
 
 export type TuiOpenHelpResponses = {
-    /**
-     * Help dialog opened successfully
-     */
-    200: boolean;
-};
+  /**
+   * Help dialog opened successfully
+   */
+  200: boolean
+}
 
-export type TuiOpenHelpResponse = TuiOpenHelpResponses[keyof TuiOpenHelpResponses];
+export type TuiOpenHelpResponse = TuiOpenHelpResponses[keyof TuiOpenHelpResponses]
 
 export type TuiOpenSessionsData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/tui/open-sessions';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/tui/open-sessions"
+}
 
 export type TuiOpenSessionsResponses = {
-    /**
-     * Session dialog opened successfully
-     */
-    200: boolean;
-};
+  /**
+   * Session dialog opened successfully
+   */
+  200: boolean
+}
 
-export type TuiOpenSessionsResponse = TuiOpenSessionsResponses[keyof TuiOpenSessionsResponses];
+export type TuiOpenSessionsResponse = TuiOpenSessionsResponses[keyof TuiOpenSessionsResponses]
 
 export type TuiOpenThemesData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/tui/open-themes';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/tui/open-themes"
+}
 
 export type TuiOpenThemesResponses = {
-    /**
-     * Theme dialog opened successfully
-     */
-    200: boolean;
-};
+  /**
+   * Theme dialog opened successfully
+   */
+  200: boolean
+}
 
-export type TuiOpenThemesResponse = TuiOpenThemesResponses[keyof TuiOpenThemesResponses];
+export type TuiOpenThemesResponse = TuiOpenThemesResponses[keyof TuiOpenThemesResponses]
 
 export type TuiOpenModelsData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/tui/open-models';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/tui/open-models"
+}
 
 export type TuiOpenModelsResponses = {
-    /**
-     * Model dialog opened successfully
-     */
-    200: boolean;
-};
+  /**
+   * Model dialog opened successfully
+   */
+  200: boolean
+}
 
-export type TuiOpenModelsResponse = TuiOpenModelsResponses[keyof TuiOpenModelsResponses];
+export type TuiOpenModelsResponse = TuiOpenModelsResponses[keyof TuiOpenModelsResponses]
 
 export type TuiSubmitPromptData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/tui/submit-prompt';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/tui/submit-prompt"
+}
 
 export type TuiSubmitPromptResponses = {
-    /**
-     * Prompt submitted successfully
-     */
-    200: boolean;
-};
+  /**
+   * Prompt submitted successfully
+   */
+  200: boolean
+}
 
-export type TuiSubmitPromptResponse = TuiSubmitPromptResponses[keyof TuiSubmitPromptResponses];
+export type TuiSubmitPromptResponse = TuiSubmitPromptResponses[keyof TuiSubmitPromptResponses]
 
 export type TuiClearPromptData = {
-    body?: never;
-    path?: never;
-    query?: never;
-    url: '/tui/clear-prompt';
-};
+  body?: never
+  path?: never
+  query?: never
+  url: "/tui/clear-prompt"
+}
 
 export type TuiClearPromptResponses = {
-    /**
-     * Prompt cleared successfully
-     */
-    200: boolean;
-};
+  /**
+   * Prompt cleared successfully
+   */
+  200: boolean
+}
 
-export type TuiClearPromptResponse = TuiClearPromptResponses[keyof TuiClearPromptResponses];
+export type TuiClearPromptResponse = TuiClearPromptResponses[keyof TuiClearPromptResponses]
 
 export type TuiExecuteCommandData = {
-    body?: {
-        command: string;
-    };
-    path?: never;
-    query?: never;
-    url: '/tui/execute-command';
-};
+  body?: {
+    command: string
+  }
+  path?: never
+  query?: never
+  url: "/tui/execute-command"
+}
 
 export type TuiExecuteCommandResponses = {
-    /**
-     * Command executed successfully
-     */
-    200: boolean;
-};
+  /**
+   * Command executed successfully
+   */
+  200: boolean
+}
 
-export type TuiExecuteCommandResponse = TuiExecuteCommandResponses[keyof TuiExecuteCommandResponses];
+export type TuiExecuteCommandResponse = TuiExecuteCommandResponses[keyof TuiExecuteCommandResponses]
 
 export type ClientOptions = {
-    baseUrl: `${string}://${string}` | (string & {});
-};
+  baseUrl: `${string}://${string}` | (string & {})
+}

+ 1 - 0
packages/sdk/js/src/index.ts

@@ -1,6 +1,7 @@
 import { createClient } from "./gen/client/client"
 import { type Config } from "./gen/client/types"
 import { OpencodeClient } from "./gen/sdk.gen"
+export * from "./gen/types.gen"
 
 export function createOpencodeClient(config?: Config) {
   const client = createClient(config)

+ 6 - 1
packages/sdk/js/tsconfig.json

@@ -5,7 +5,12 @@
     "outDir": "dist",
     "module": "preserve",
     "declaration": true,
-    "moduleResolution": "bundler"
+    "moduleResolution": "bundler",
+    "lib": [
+      "es2022",
+      "dom",
+      "dom.iterable"
+    ]
   },
   "include": [
     "src"

+ 1 - 1
packages/web/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@opencode/web",
   "type": "module",
-  "version": "0.0.1",
+  "version": "0.0.0-202508022246",
   "scripts": {
     "dev": "astro dev",
     "dev:remote": "sst shell --stage=dev --target=Web astro dev",

+ 24 - 3
script/publish.ts

@@ -11,18 +11,39 @@ if (!version) {
 }
 process.env["OPENCODE_VERSION"] = version
 
-await import(`../packages/opencode/script/publish.ts`)
+const pkgjsons = await Array.fromAsync(
+  new Bun.Glob("**/package.json").scan({
+    absolute: true,
+  }),
+)
+
+const tree = await $`git add . && git write-tree`.text().then((x) => x.trim())
+for await (const file of new Bun.Glob("**/package.json").scan({
+  absolute: true,
+})) {
+  let pkg = await Bun.file(file).text()
+  pkg = pkg.replaceAll(/"version": "[^"]+"/g, `"version": "${version}"`)
+  await Bun.file(file).write(pkg)
+}
+
+// await import(`../packages/opencode/script/publish.ts`)
 await import(`../packages/sdk/js/script/publish.ts`)
+await import(`../packages/plugin/script/publish.ts`)
 // await import(`../packages/sdk/stainless/generate.ts`)
 
 if (!snapshot) {
   await $`git commit -am "release: v${version}"`
   await $`git tag v${version}`
-  await $`git push origin HEAD --tags`
+  await $`git push origin HEAD --tags --no-verify`
 }
 if (snapshot) {
   await $`git commit --allow-empty -m "Snapshot release v${version}"`
   await $`git tag v${version}`
-  await $`git push origin v${version}`
+  await $`git push origin v${version} --no-verify`
   await $`git reset --soft HEAD~1`
+  for await (const file of new Bun.Glob("**/package.json").scan({
+    absolute: true,
+  })) {
+    $`await git checkout ${tree} ${file}`
+  }
 }

+ 1 - 1
sdks/vscode/package.json

@@ -2,7 +2,7 @@
   "name": "opencode",
   "displayName": "opencode",
   "description": "opencode for VS Code",
-  "version": "0.0.0",
+  "version": "0.0.0-202508022246",
   "publisher": "sst-dev",
   "repository": {
     "type": "git",