From dbed38e01583ad75671d034c912c12dc3a2d9608 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 31 Dec 2025 01:48:45 -0500 Subject: [PATCH 01/15] fix: make unknown keybind commands non-fatal with warnings - Change Keybinds schema from .strict() to .passthrough() to allow unknown keys - Add ValidKeybindNames set for validating keybind names - Add Config.Warning schema and Config.warnings() function - Add GET /config/warnings endpoint to fetch warnings - Add warning toast display in TUI when sync completes - Add tests for warning generation with unknown keybind names Fixes #6397 --- packages/opencode/src/cli/cmd/tui/app.tsx | 29 +++++++++ packages/opencode/src/config/config.ts | 42 +++++++++++-- packages/opencode/src/server/server.ts | 22 +++++++ packages/opencode/test/config/config.test.ts | 52 +++++++++++++++ packages/sdk/js/src/v2/gen/sdk.gen.ts | 20 ++++++ packages/sdk/js/src/v2/gen/types.gen.ts | 29 +++++++++ packages/sdk/openapi.json | 66 ++++++++++++++++++++ 7 files changed, 254 insertions(+), 6 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 8b7b68273ac..7f209f0681d 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -584,6 +584,35 @@ function App() { }) }) + // Fetch and display config warnings after sync completes + let warningsShown = false + createEffect( + on( + () => sync.status === "complete", + (isComplete) => { + if (!isComplete || warningsShown) return + warningsShown = true + sdk.client.config + .warnings() + .then((response) => { + const warnings = response.data ?? [] + if (warnings.length > 0) { + const messages = warnings.map((w) => w.message) + toast.show({ + variant: "warning", + title: "Config Warning", + message: messages.join("\n"), + duration: 5000, + }) + } + }) + .catch(() => { + // Silently ignore errors fetching warnings + }) + }, + ), + ) + return ( key !== "leader" && !ValidKeybindNames.has(key), + ) + if (unknownKeybinds.length > 0) { + warnings.push({ + type: "unknown_keybind", + message: `Unknown keybind command(s): ${unknownKeybinds.join(", ")}`, + }) + } + } + return { config: result, directories, + warnings, } }) @@ -581,11 +592,26 @@ export namespace Config { terminal_title_toggle: z.string().optional().default("none").describe("Toggle terminal title"), tips_toggle: z.string().optional().default("h").describe("Toggle tips on home screen"), }) - .strict() + .passthrough() .meta({ ref: "KeybindsConfig", }) + // Set of valid keybind names for validation + export const ValidKeybindNames = new Set(Object.keys(Keybinds.shape).filter((key) => key !== "leader")) + + export const Warning = z + .object({ + type: z.enum(["unknown_keybind"]), + message: z.string(), + }) + .meta({ ref: "ConfigWarning" }) + export type Warning = z.infer + + export const Event = { + Warning: BusEvent.define("config.warning", Warning), + } + export const TUI = z.object({ scroll_speed: z.number().min(0.001).optional().describe("TUI scroll speed"), scroll_acceleration: z @@ -1023,4 +1049,8 @@ export namespace Config { export async function directories() { return state().then((x) => x.directories) } + + export async function warnings() { + return state().then((x) => x.warnings) + } } diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index a8adebd72c5..e8d55947409 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -471,6 +471,28 @@ export namespace Server { return c.json(config) }, ) + .get( + "/config/warnings", + describeRoute({ + summary: "Get configuration warnings", + description: + "Retrieve any warnings generated during configuration loading, such as unknown keybind commands.", + operationId: "config.warnings", + responses: { + 200: { + description: "List of configuration warnings", + content: { + "application/json": { + schema: resolver(Config.Warning.array()), + }, + }, + }, + }, + }), + async (c) => { + return c.json(await Config.warnings()) + }, + ) .get( "/experimental/tool/ids", describeRoute({ diff --git a/packages/opencode/test/config/config.test.ts b/packages/opencode/test/config/config.test.ts index 8871fd50bab..912c097acbb 100644 --- a/packages/opencode/test/config/config.test.ts +++ b/packages/opencode/test/config/config.test.ts @@ -627,3 +627,55 @@ test("compaction config can disable both auto and prune", async () => { }, }) }) + +test("unknown keybind names generate warnings", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + keybinds: { + unknown_command: "ctrl+x", + another_fake_command: "ctrl+y", + }, + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const warnings = await Config.warnings() + expect(warnings.length).toBe(1) + expect(warnings[0].type).toBe("unknown_keybind") + expect(warnings[0].message).toContain("unknown_command") + expect(warnings[0].message).toContain("another_fake_command") + }, + }) +}) + +test("valid keybind names do not generate warnings", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "opencode.json"), + JSON.stringify({ + $schema: "https://opencode.ai/config.json", + keybinds: { + leader: "ctrl+x", + app_exit: "ctrl+q", + session_new: "ctrl+n", + }, + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const warnings = await Config.warnings() + expect(warnings.length).toBe(0) + }, + }) +}) diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index b0610b64bc3..35a85e96d1b 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -16,6 +16,7 @@ import type { ConfigProvidersResponses, ConfigUpdateErrors, ConfigUpdateResponses, + ConfigWarningsResponses, EventSubscribeResponses, EventTuiCommandExecute, EventTuiPromptAppend, @@ -562,6 +563,25 @@ export class Config extends HeyApiClient { }) } + /** + * Get configuration warnings + * + * Retrieve any warnings generated during configuration loading, such as unknown keybind commands. + */ + public warnings( + parameters?: { + directory?: string + }, + options?: Options, + ) { + const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) + return (options?.client ?? this.client).get({ + url: "/config/warnings", + ...options, + ...params, + }) + } + /** * List config providers * diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 58b44fe173d..5cb00bdf23d 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -39,6 +39,16 @@ export type EventProjectUpdated = { properties: Project } +export type ConfigWarning = { + type: "unknown_keybind" + message: string +} + +export type EventConfigWarning = { + type: "config.warning" + properties: ConfigWarning +} + export type EventServerInstanceDisposed = { type: "server.instance.disposed" properties: { @@ -749,6 +759,7 @@ export type Event = | EventInstallationUpdated | EventInstallationUpdateAvailable | EventProjectUpdated + | EventConfigWarning | EventServerInstanceDisposed | EventLspClientDiagnostics | EventLspUpdated @@ -2306,6 +2317,24 @@ export type ConfigUpdateResponses = { export type ConfigUpdateResponse = ConfigUpdateResponses[keyof ConfigUpdateResponses] +export type ConfigWarningsData = { + body?: never + path?: never + query?: { + directory?: string + } + url: "/config/warnings" +} + +export type ConfigWarningsResponses = { + /** + * List of configuration warnings + */ + 200: Array +} + +export type ConfigWarningsResponse = ConfigWarningsResponses[keyof ConfigWarningsResponses] + export type ToolIdsData = { body?: never path?: never diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index db9e5411899..66941aa0fdf 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -678,6 +678,43 @@ ] } }, + "/config/warnings": { + "get": { + "operationId": "config.warnings", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get configuration warnings", + "description": "Retrieve any warnings generated during configuration loading, such as unknown keybind commands.", + "responses": { + "200": { + "description": "List of configuration warnings", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigWarning" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.config.warnings({\n ...\n})" + } + ] + } + }, "/experimental/tool/ids": { "get": { "operationId": "tool.ids", @@ -5149,6 +5186,32 @@ }, "required": ["type", "properties"] }, + "ConfigWarning": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["unknown_keybind"] + }, + "message": { + "type": "string" + } + }, + "required": ["type", "message"] + }, + "Event.config.warning": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "config.warning" + }, + "properties": { + "$ref": "#/components/schemas/ConfigWarning" + } + }, + "required": ["type", "properties"] + }, "Event.server.instance.disposed": { "type": "object", "properties": { @@ -7166,6 +7229,9 @@ { "$ref": "#/components/schemas/Event.project.updated" }, + { + "$ref": "#/components/schemas/Event.config.warning" + }, { "$ref": "#/components/schemas/Event.server.instance.disposed" }, From b29b897ff787380ea5ba7205db810988753fc82b Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 31 Dec 2025 01:55:29 -0500 Subject: [PATCH 02/15] fix: add toast when pressing keybind for unknown command When user presses a key that matches a keybind configured for an unknown command name, show a warning toast with the command name. --- .../cli/cmd/tui/component/dialog-command.tsx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx index d19e93188b2..8f9e4422bc4 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx @@ -11,6 +11,8 @@ import { } from "solid-js" import { useKeyboard } from "@opentui/solid" import { useKeybind } from "@tui/context/keybind" +import { useToast } from "@tui/ui/toast" +import { useSync } from "@tui/context/sync" import type { KeybindsConfig } from "@opencode-ai/sdk/v2" type Context = ReturnType @@ -26,6 +28,8 @@ function init() { const [suspendCount, setSuspendCount] = createSignal(0) const dialog = useDialog() const keybind = useKeybind() + const toast = useToast() + const sync = useSync() const options = createMemo(() => { const all = registrations().flatMap((x) => x()) const suggested = all.filter((x) => x.suggested) @@ -43,6 +47,15 @@ function init() { }) const suspended = () => suspendCount() > 0 + // Get the set of keybind names that have registered commands + const registeredKeybinds = createMemo(() => { + const set = new Set() + for (const option of options()) { + if (option.keybind) set.add(option.keybind) + } + return set + }) + useKeyboard((evt) => { if (suspended()) return if (dialog.stack.length > 0) return @@ -53,6 +66,23 @@ function init() { return } } + + // Check if the pressed key matches an unknown keybind command + const allKeybinds = keybind.all + const registered = registeredKeybinds() + for (const [name, _] of Object.entries(allKeybinds)) { + if (name === "leader") continue + if (registered.has(name)) continue + if (keybind.match(name as keyof typeof sync.data.config.keybinds, evt)) { + evt.preventDefault() + toast.show({ + variant: "warning", + message: `Unknown command: ${name}`, + duration: 3000, + }) + return + } + } }) const result = { From df21fc83662fd54413cefd4ad9984da36ebba498 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 31 Dec 2025 02:01:40 -0500 Subject: [PATCH 03/15] fix: use server-provided unknown keybinds list for toast messages - Fetch unknown keybinds from /config/warnings endpoint instead of iterating all keybinds in config - Add keybinds array field to Warning schema to provide list of unknown keybind names - Fix TypeScript error from passthrough schema by casting value - Regenerate SDK with ConfigWarning.keybinds field --- .../cli/cmd/tui/component/dialog-command.tsx | 47 +++++++++++++------ .../src/cli/cmd/tui/context/keybind.tsx | 2 +- packages/opencode/src/config/config.ts | 2 + packages/sdk/js/src/v2/gen/types.gen.ts | 2 + packages/sdk/openapi.json | 8 +++- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx index 8f9e4422bc4..03a5c535d2b 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx @@ -2,8 +2,10 @@ import { useDialog } from "@tui/ui/dialog" import { DialogSelect, type DialogSelectOption, type DialogSelectRef } from "@tui/ui/dialog-select" import { createContext, + createEffect, createMemo, createSignal, + on, onCleanup, useContext, type Accessor, @@ -13,6 +15,7 @@ import { useKeyboard } from "@opentui/solid" import { useKeybind } from "@tui/context/keybind" import { useToast } from "@tui/ui/toast" import { useSync } from "@tui/context/sync" +import { useSDK } from "@tui/context/sdk" import type { KeybindsConfig } from "@opencode-ai/sdk/v2" type Context = ReturnType @@ -26,10 +29,37 @@ export type CommandOption = DialogSelectOption & { function init() { const [registrations, setRegistrations] = createSignal[]>([]) const [suspendCount, setSuspendCount] = createSignal(0) + const [unknownKeybinds, setUnknownKeybinds] = createSignal([]) const dialog = useDialog() const keybind = useKeybind() const toast = useToast() const sync = useSync() + const sdk = useSDK() + + // Fetch unknown keybinds from warnings when sync completes + let warningsFetched = false + createEffect( + on( + () => sync.status === "complete", + (isComplete) => { + if (!isComplete || warningsFetched) return + warningsFetched = true + sdk.client.config + .warnings() + .then((response) => { + const warnings = response.data ?? [] + for (const warning of warnings) { + if (warning.type === "unknown_keybind" && warning.keybinds) { + setUnknownKeybinds(warning.keybinds) + break + } + } + }) + .catch(() => {}) + }, + ), + ) + const options = createMemo(() => { const all = registrations().flatMap((x) => x()) const suggested = all.filter((x) => x.suggested) @@ -47,15 +77,6 @@ function init() { }) const suspended = () => suspendCount() > 0 - // Get the set of keybind names that have registered commands - const registeredKeybinds = createMemo(() => { - const set = new Set() - for (const option of options()) { - if (option.keybind) set.add(option.keybind) - } - return set - }) - useKeyboard((evt) => { if (suspended()) return if (dialog.stack.length > 0) return @@ -68,12 +89,8 @@ function init() { } // Check if the pressed key matches an unknown keybind command - const allKeybinds = keybind.all - const registered = registeredKeybinds() - for (const [name, _] of Object.entries(allKeybinds)) { - if (name === "leader") continue - if (registered.has(name)) continue - if (keybind.match(name as keyof typeof sync.data.config.keybinds, evt)) { + for (const name of unknownKeybinds()) { + if (keybind.match(name as keyof KeybindsConfig, evt)) { evt.preventDefault() toast.show({ variant: "warning", diff --git a/packages/opencode/src/cli/cmd/tui/context/keybind.tsx b/packages/opencode/src/cli/cmd/tui/context/keybind.tsx index 4c82e594c3e..f09bf50e2d3 100644 --- a/packages/opencode/src/cli/cmd/tui/context/keybind.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/keybind.tsx @@ -15,7 +15,7 @@ export const { use: useKeybind, provider: KeybindProvider } = createSimpleContex const keybinds = createMemo(() => { return pipe( sync.data.config.keybinds ?? {}, - mapValues((value) => Keybind.parse(value)), + mapValues((value) => Keybind.parse(value as string)), ) }) const [store, setStore] = createStore({ diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index a2dd0fdea45..d79318907e9 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -155,6 +155,7 @@ export namespace Config { warnings.push({ type: "unknown_keybind", message: `Unknown keybind command(s): ${unknownKeybinds.join(", ")}`, + keybinds: unknownKeybinds, }) } } @@ -604,6 +605,7 @@ export namespace Config { .object({ type: z.enum(["unknown_keybind"]), message: z.string(), + keybinds: z.array(z.string()).optional(), }) .meta({ ref: "ConfigWarning" }) export type Warning = z.infer diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 5cb00bdf23d..be125bfe08d 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -42,6 +42,7 @@ export type EventProjectUpdated = { export type ConfigWarning = { type: "unknown_keybind" message: string + keybinds?: Array } export type EventConfigWarning = { @@ -1165,6 +1166,7 @@ export type KeybindsConfig = { * Toggle tips on home screen */ tips_toggle?: string + [key: string]: unknown | string | undefined } /** diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 66941aa0fdf..e8307921f83 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -5195,6 +5195,12 @@ }, "message": { "type": "string" + }, + "keybinds": { + "type": "array", + "items": { + "type": "string" + } } }, "required": ["type", "message"] @@ -7822,7 +7828,7 @@ "type": "string" } }, - "additionalProperties": false + "additionalProperties": {} }, "LogLevel": { "description": "Log level", From fbec33ff2c84310d21e06ca40b4c244dc5bd676f Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 31 Dec 2025 02:04:54 -0500 Subject: [PATCH 04/15] fix: use consistent 'Unknown keybind command' message --- packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx index 03a5c535d2b..9dc807aeedc 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx @@ -94,7 +94,7 @@ function init() { evt.preventDefault() toast.show({ variant: "warning", - message: `Unknown command: ${name}`, + message: `Unknown keybind command: ${name}`, duration: 3000, }) return From 71f93916d413a131b6a929331268a75df83a4801 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 31 Dec 2025 02:06:44 -0500 Subject: [PATCH 05/15] fix: use proper pluralization for unknown keybind commands message --- packages/opencode/src/config/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index d79318907e9..0280d7451e8 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -154,7 +154,7 @@ export namespace Config { if (unknownKeybinds.length > 0) { warnings.push({ type: "unknown_keybind", - message: `Unknown keybind command(s): ${unknownKeybinds.join(", ")}`, + message: `Unknown keybind ${unknownKeybinds.length === 1 ? "command" : "commands"}: ${unknownKeybinds.join(", ")}`, keybinds: unknownKeybinds, }) } From 18b74aa1481a20f2ec7889a5599c8183ff16ea6e Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 31 Dec 2025 02:14:47 -0500 Subject: [PATCH 06/15] chore: restore unrelated duplicate block to keep branch tightly scoped --- packages/opencode/src/config/config.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 0280d7451e8..f95875b6fea 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -135,6 +135,11 @@ export namespace Config { result.share = "auto" } + // Handle migration from autoshare to share field + if (result.autoshare === true && !result.share) { + result.share = "auto" + } + if (!result.keybinds) result.keybinds = Info.shape.keybinds.parse({}) // Apply flag overrides for compaction settings From 78984eb1e7c97d2ed4bb2fdecc6c5621e56fbd9f Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 31 Dec 2025 17:09:55 -0500 Subject: [PATCH 07/15] Fix: Implement nonfatal missing keybind commands with pre-processing approach - Pre-process unknown keybinds before Zod validation (keep .strict() schema) - Store unknown keybinds with name+binding in warnings - Update TUI to parse and match unknown keybinds directly - Remove unused BusEvent for warnings - Update tests to verify new warning structure - Regenerate TypeScript SDK (KeybindsConfig without index signature) Resolves #6397 --- .../cli/cmd/tui/component/dialog-command.tsx | 35 ++++-- .../src/cli/cmd/tui/context/keybind.tsx | 2 +- packages/opencode/src/cli/network.ts | 3 +- packages/opencode/src/cli/upgrade.ts | 3 +- packages/opencode/src/config/config.ts | 105 ++++++++++++------ packages/opencode/test/config/config.test.ts | 9 ++ packages/sdk/js/src/v2/gen/types.gen.ts | 22 ++-- 7 files changed, 115 insertions(+), 64 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx index 9dc807aeedc..a58536f8005 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx @@ -16,6 +16,7 @@ import { useKeybind } from "@tui/context/keybind" import { useToast } from "@tui/ui/toast" import { useSync } from "@tui/context/sync" import { useSDK } from "@tui/context/sdk" +import { Keybind } from "@/util/keybind" import type { KeybindsConfig } from "@opencode-ai/sdk/v2" type Context = ReturnType @@ -26,10 +27,15 @@ export type CommandOption = DialogSelectOption & { suggested?: boolean } +type ParsedUnknownKeybind = { + name: string + parsed: Keybind.Info[] +} + function init() { const [registrations, setRegistrations] = createSignal[]>([]) const [suspendCount, setSuspendCount] = createSignal(0) - const [unknownKeybinds, setUnknownKeybinds] = createSignal([]) + const [unknownKeybinds, setUnknownKeybinds] = createSignal([]) const dialog = useDialog() const keybind = useKeybind() const toast = useToast() @@ -50,7 +56,11 @@ function init() { const warnings = response.data ?? [] for (const warning of warnings) { if (warning.type === "unknown_keybind" && warning.keybinds) { - setUnknownKeybinds(warning.keybinds) + const parsed = warning.keybinds.map((kb) => ({ + name: kb.name, + parsed: Keybind.parse(kb.binding), + })) + setUnknownKeybinds(parsed) break } } @@ -89,15 +99,18 @@ function init() { } // Check if the pressed key matches an unknown keybind command - for (const name of unknownKeybinds()) { - if (keybind.match(name as keyof KeybindsConfig, evt)) { - evt.preventDefault() - toast.show({ - variant: "warning", - message: `Unknown keybind command: ${name}`, - duration: 3000, - }) - return + const evtParsed = keybind.parse(evt) + for (const { name, parsed } of unknownKeybinds()) { + for (const binding of parsed) { + if (Keybind.match(binding, evtParsed)) { + evt.preventDefault() + toast.show({ + variant: "warning", + message: `Unknown keybind command: ${name}`, + duration: 3000, + }) + return + } } } }) diff --git a/packages/opencode/src/cli/cmd/tui/context/keybind.tsx b/packages/opencode/src/cli/cmd/tui/context/keybind.tsx index f09bf50e2d3..10766115a8c 100644 --- a/packages/opencode/src/cli/cmd/tui/context/keybind.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/keybind.tsx @@ -15,7 +15,7 @@ export const { use: useKeybind, provider: KeybindProvider } = createSimpleContex const keybinds = createMemo(() => { return pipe( sync.data.config.keybinds ?? {}, - mapValues((value) => Keybind.parse(value as string)), + mapValues((value) => (value ? Keybind.parse(value) : [])), ) }) const [store, setStore] = createStore({ diff --git a/packages/opencode/src/cli/network.ts b/packages/opencode/src/cli/network.ts index fe5731d0713..80027c17679 100644 --- a/packages/opencode/src/cli/network.ts +++ b/packages/opencode/src/cli/network.ts @@ -32,7 +32,8 @@ export function withNetworkOptions(yargs: Argv) { } export async function resolveNetworkOptions(args: NetworkOptions) { - const config = await Config.global() + const globalResult = await Config.global() + const config = globalResult.config const portExplicitlySet = process.argv.includes("--port") const hostnameExplicitlySet = process.argv.includes("--hostname") const mdnsExplicitlySet = process.argv.includes("--mdns") diff --git a/packages/opencode/src/cli/upgrade.ts b/packages/opencode/src/cli/upgrade.ts index 2d46ae39fa2..1105928f1a5 100644 --- a/packages/opencode/src/cli/upgrade.ts +++ b/packages/opencode/src/cli/upgrade.ts @@ -4,7 +4,8 @@ import { Flag } from "@/flag/flag" import { Installation } from "@/installation" export async function upgrade() { - const config = await Config.global() + const globalResult = await Config.global() + const config = globalResult.config const method = await Installation.method() const latest = await Installation.latest(method).catch(() => {}) if (!latest) return diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index fbd4329f61d..d1bf1f26bbb 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -18,7 +18,6 @@ import { LSPServer } from "../lsp/server" import { BunProc } from "@/bun" import { Installation } from "@/installation" import { ConfigMarkdown } from "./markdown" -import { BusEvent } from "../bus/bus-event" export namespace Config { const log = Log.create({ service: "config" }) @@ -36,18 +35,24 @@ export namespace Config { export const state = Instance.state(async () => { const auth = await Auth.all() - let result = await global() + const globalResult = await global() + let result = globalResult.config + const allUnknownKeybinds: Array<{ name: string; binding: string }> = [...globalResult.unknownKeybinds] // Override with custom config if provided if (Flag.OPENCODE_CONFIG) { - result = mergeConfigWithPlugins(result, await loadFile(Flag.OPENCODE_CONFIG)) + const loaded = await loadFile(Flag.OPENCODE_CONFIG) + result = mergeConfigWithPlugins(result, loaded.config) + allUnknownKeybinds.push(...loaded.unknownKeybinds) log.debug("loaded custom config", { path: Flag.OPENCODE_CONFIG }) } for (const file of ["opencode.jsonc", "opencode.json"]) { const found = await Filesystem.findUp(file, Instance.directory, Instance.worktree) for (const resolved of found.toReversed()) { - result = mergeConfigWithPlugins(result, await loadFile(resolved)) + const loaded = await loadFile(resolved) + result = mergeConfigWithPlugins(result, loaded.config) + allUnknownKeybinds.push(...loaded.unknownKeybinds) } } @@ -60,7 +65,9 @@ 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())) as any - result = mergeConfigWithPlugins(result, await load(JSON.stringify(wellknown.config ?? {}), process.cwd())) + const loaded = await load(JSON.stringify(wellknown.config ?? {}), process.cwd()) + result = mergeConfigWithPlugins(result, loaded.config) + allUnknownKeybinds.push(...loaded.unknownKeybinds) } } @@ -96,7 +103,9 @@ export namespace Config { if (dir.endsWith(".opencode") || dir === Flag.OPENCODE_CONFIG_DIR) { for (const file of ["opencode.jsonc", "opencode.json"]) { log.debug(`loading config from ${path.join(dir, file)}`) - result = mergeConfigWithPlugins(result, await loadFile(path.join(dir, file))) + const loaded = await loadFile(path.join(dir, file)) + result = mergeConfigWithPlugins(result, loaded.config) + allUnknownKeybinds.push(...loaded.unknownKeybinds) // to satisfy the type checker result.agent ??= {} result.mode ??= {} @@ -148,19 +157,15 @@ export namespace Config { result.compaction = { ...result.compaction, prune: false } } - // Collect warnings for unknown keybind names + // Generate warnings for unknown keybind names (collected during pre-processing) const warnings: Warning[] = [] - if (result.keybinds) { - const unknownKeybinds = Object.keys(result.keybinds).filter( - (key) => key !== "leader" && !ValidKeybindNames.has(key), - ) - if (unknownKeybinds.length > 0) { - warnings.push({ - type: "unknown_keybind", - message: `Unknown keybind ${unknownKeybinds.length === 1 ? "command" : "commands"}: ${unknownKeybinds.join(", ")}`, - keybinds: unknownKeybinds, - }) - } + if (allUnknownKeybinds.length > 0) { + const names = allUnknownKeybinds.map((kb) => kb.name) + warnings.push({ + type: "unknown_keybind", + message: `Unknown keybind ${names.length === 1 ? "command" : "commands"}: ${names.join(", ")}`, + keybinds: allUnknownKeybinds, + }) } return { @@ -579,7 +584,7 @@ export namespace Config { terminal_title_toggle: z.string().optional().default("none").describe("Toggle terminal title"), tips_toggle: z.string().optional().default("h").describe("Toggle tips on home screen"), }) - .passthrough() + .strict() .meta({ ref: "KeybindsConfig", }) @@ -591,15 +596,18 @@ export namespace Config { .object({ type: z.enum(["unknown_keybind"]), message: z.string(), - keybinds: z.array(z.string()).optional(), + keybinds: z + .array( + z.object({ + name: z.string(), + binding: z.string(), + }), + ) + .optional(), }) .meta({ ref: "ConfigWarning" }) export type Warning = z.infer - export const Event = { - Warning: BusEvent.define("config.warning", Warning), - } - export const TUI = z.object({ scroll_speed: z.number().min(0.001).optional().describe("TUI scroll speed"), scroll_acceleration: z @@ -894,13 +902,18 @@ export namespace Config { export type Info = z.output - export const global = lazy(async () => { - let result: Info = pipe( - {}, - 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"))), - ) + export const global = lazy(async (): Promise => { + const globalUnknownKeybinds: Array<{ name: string; binding: string }> = [] + + const configJson = await loadFile(path.join(Global.Path.config, "config.json")) + const opencodeJson = await loadFile(path.join(Global.Path.config, "opencode.json")) + const opencodeJsonc = await loadFile(path.join(Global.Path.config, "opencode.jsonc")) + + globalUnknownKeybinds.push(...configJson.unknownKeybinds) + globalUnknownKeybinds.push(...opencodeJson.unknownKeybinds) + globalUnknownKeybinds.push(...opencodeJsonc.unknownKeybinds) + + let result: Info = pipe({}, mergeDeep(configJson.config), mergeDeep(opencodeJson.config), mergeDeep(opencodeJsonc.config)) await import(path.join(Global.Path.config, "config"), { with: { @@ -917,10 +930,12 @@ export namespace Config { }) .catch(() => {}) - return result + return { config: result, unknownKeybinds: globalUnknownKeybinds } }) - async function loadFile(filepath: string): Promise { + type LoadResult = { config: Info; unknownKeybinds: Array<{ name: string; binding: string }> } + + async function loadFile(filepath: string): Promise { log.info("loading", { path: filepath }) let text = await Bun.file(filepath) .text() @@ -928,7 +943,7 @@ export namespace Config { if (err.code === "ENOENT") return throw new JsonError({ path: filepath }, { cause: err }) }) - if (!text) return {} + if (!text) return { config: {}, unknownKeybinds: [] } return load(text, filepath) } @@ -998,6 +1013,21 @@ export namespace Config { }) } + // Pre-process keybinds: extract and strip unknown keybind keys before Zod validation + const unknownKeybinds: Array<{ name: string; binding: string }> = [] + if (data && typeof data === "object" && "keybinds" in data && data.keybinds && typeof data.keybinds === "object") { + const keybindsObj = data.keybinds as Record + for (const key of Object.keys(keybindsObj)) { + if (key !== "leader" && !ValidKeybindNames.has(key)) { + const binding = keybindsObj[key] + if (typeof binding === "string") { + unknownKeybinds.push({ name: key, binding }) + } + delete keybindsObj[key] + } + } + } + const parsed = Info.safeParse(data) if (parsed.success) { if (!parsed.data.$schema) { @@ -1013,7 +1043,7 @@ export namespace Config { } catch (err) {} } } - return data + return { config: data, unknownKeybinds } } throw new InvalidError({ @@ -1021,6 +1051,7 @@ export namespace Config { issues: parsed.error.issues, }) } + export const JsonError = NamedError.create( "ConfigJsonError", z.object({ @@ -1053,8 +1084,8 @@ export namespace Config { export async function update(config: Info) { const filepath = path.join(Instance.directory, "config.json") - const existing = await loadFile(filepath) - await Bun.write(filepath, JSON.stringify(mergeDeep(existing, config), null, 2)) + const loaded = await loadFile(filepath) + await Bun.write(filepath, JSON.stringify(mergeDeep(loaded.config, config), null, 2)) await Instance.dispose() } diff --git a/packages/opencode/test/config/config.test.ts b/packages/opencode/test/config/config.test.ts index 912c097acbb..2d35dbbfcfc 100644 --- a/packages/opencode/test/config/config.test.ts +++ b/packages/opencode/test/config/config.test.ts @@ -651,6 +651,15 @@ test("unknown keybind names generate warnings", async () => { expect(warnings[0].type).toBe("unknown_keybind") expect(warnings[0].message).toContain("unknown_command") expect(warnings[0].message).toContain("another_fake_command") + // Verify the keybinds array contains name and binding + expect(warnings[0].keybinds).toBeDefined() + expect(warnings[0].keybinds!.length).toBe(2) + const names = warnings[0].keybinds!.map((kb) => kb.name) + expect(names).toContain("unknown_command") + expect(names).toContain("another_fake_command") + const bindings = warnings[0].keybinds!.map((kb) => kb.binding) + expect(bindings).toContain("ctrl+x") + expect(bindings).toContain("ctrl+y") }, }) }) diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 435ee1e1067..26f893d8082 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -39,17 +39,6 @@ export type EventProjectUpdated = { properties: Project } -export type ConfigWarning = { - type: "unknown_keybind" - message: string - keybinds?: Array -} - -export type EventConfigWarning = { - type: "config.warning" - properties: ConfigWarning -} - export type EventServerInstanceDisposed = { type: "server.instance.disposed" properties: { @@ -760,7 +749,6 @@ export type Event = | EventInstallationUpdated | EventInstallationUpdateAvailable | EventProjectUpdated - | EventConfigWarning | EventServerInstanceDisposed | EventLspClientDiagnostics | EventLspUpdated @@ -1166,7 +1154,6 @@ export type KeybindsConfig = { * Toggle tips on home screen */ tips_toggle?: string - [key: string]: unknown | string | undefined } /** @@ -1675,6 +1662,15 @@ export type Config = { } } +export type ConfigWarning = { + type: "unknown_keybind" + message: string + keybinds?: Array<{ + name: string + binding: string + }> +} + export type ToolIds = Array export type ToolListItem = { From 5d208f14872b4e4faa0bbfd3caaa4d6ac212e49e Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 31 Dec 2025 17:21:15 -0500 Subject: [PATCH 08/15] revert: Remove unnecessary null check in keybind parsing The null check was added during earlier iterations when .passthrough() was used in the keybind schema. With the current pre-processing approach that strips unknown keybinds and maintains .strict(), all keybind values have defaults applied and will never be undefined, making this check unnecessary. --- packages/opencode/src/cli/cmd/tui/context/keybind.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/tui/context/keybind.tsx b/packages/opencode/src/cli/cmd/tui/context/keybind.tsx index 10766115a8c..4c82e594c3e 100644 --- a/packages/opencode/src/cli/cmd/tui/context/keybind.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/keybind.tsx @@ -15,7 +15,7 @@ export const { use: useKeybind, provider: KeybindProvider } = createSimpleContex const keybinds = createMemo(() => { return pipe( sync.data.config.keybinds ?? {}, - mapValues((value) => (value ? Keybind.parse(value) : [])), + mapValues((value) => Keybind.parse(value)), ) }) const [store, setStore] = createStore({ From 3dfd35f8323767eea662433c0c46fdc51013bf52 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 31 Dec 2025 17:27:24 -0500 Subject: [PATCH 09/15] refactor: Simplify Config.global() access to single line --- packages/opencode/src/cli/network.ts | 3 +-- packages/opencode/src/cli/upgrade.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/opencode/src/cli/network.ts b/packages/opencode/src/cli/network.ts index 80027c17679..904d0efc396 100644 --- a/packages/opencode/src/cli/network.ts +++ b/packages/opencode/src/cli/network.ts @@ -32,8 +32,7 @@ export function withNetworkOptions(yargs: Argv) { } export async function resolveNetworkOptions(args: NetworkOptions) { - const globalResult = await Config.global() - const config = globalResult.config + const config = (await Config.global()).config const portExplicitlySet = process.argv.includes("--port") const hostnameExplicitlySet = process.argv.includes("--hostname") const mdnsExplicitlySet = process.argv.includes("--mdns") diff --git a/packages/opencode/src/cli/upgrade.ts b/packages/opencode/src/cli/upgrade.ts index 1105928f1a5..bab062bedb8 100644 --- a/packages/opencode/src/cli/upgrade.ts +++ b/packages/opencode/src/cli/upgrade.ts @@ -4,8 +4,7 @@ import { Flag } from "@/flag/flag" import { Installation } from "@/installation" export async function upgrade() { - const globalResult = await Config.global() - const config = globalResult.config + const config = (await Config.global()).config const method = await Installation.method() const latest = await Installation.latest(method).catch(() => {}) if (!latest) return From 78285aea266d46671b7e15ec9a6a9813fa92d45c Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 31 Dec 2025 17:34:07 -0500 Subject: [PATCH 10/15] chore: remove unused Event.config.warning from openapi schema --- packages/sdk/openapi.json | 1613 +++++++++++++++++++++++++++++-------- 1 file changed, 1297 insertions(+), 316 deletions(-) diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index e09194d2213..81d1910241a 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -27,7 +27,10 @@ "type": "string" } }, - "required": ["healthy", "version"] + "required": [ + "healthy", + "version" + ] } } } @@ -476,7 +479,10 @@ "type": "number" } }, - "required": ["rows", "cols"] + "required": [ + "rows", + "cols" + ] } } } @@ -1091,7 +1097,9 @@ ], "summary": "Get session", "description": "Retrieve detailed information about a specific OpenCode session.", - "tags": ["Session"], + "tags": [ + "Session" + ], "responses": { "200": { "description": "Get session", @@ -1297,7 +1305,9 @@ } ], "summary": "Get session children", - "tags": ["Session"], + "tags": [ + "Session" + ], "description": "Retrieve all child sessions that were forked from the specified parent session.", "responses": { "200": { @@ -1480,7 +1490,11 @@ "pattern": "^msg.*" } }, - "required": ["modelID", "providerID", "messageID"] + "required": [ + "modelID", + "providerID", + "messageID" + ] } } } @@ -1882,7 +1896,10 @@ "type": "boolean" } }, - "required": ["providerID", "modelID"] + "required": [ + "providerID", + "modelID" + ] } } } @@ -1945,7 +1962,10 @@ } } }, - "required": ["info", "parts"] + "required": [ + "info", + "parts" + ] } } } @@ -2019,7 +2039,10 @@ } } }, - "required": ["info", "parts"] + "required": [ + "info", + "parts" + ] } } } @@ -2065,7 +2088,10 @@ "type": "string" } }, - "required": ["providerID", "modelID"] + "required": [ + "providerID", + "modelID" + ] }, "agent": { "type": "string" @@ -2108,7 +2134,9 @@ } } }, - "required": ["parts"] + "required": [ + "parts" + ] } } } @@ -2171,7 +2199,10 @@ } } }, - "required": ["info", "parts"] + "required": [ + "info", + "parts" + ] } } } @@ -2440,7 +2471,10 @@ "type": "string" } }, - "required": ["providerID", "modelID"] + "required": [ + "providerID", + "modelID" + ] }, "agent": { "type": "string" @@ -2483,7 +2517,9 @@ } } }, - "required": ["parts"] + "required": [ + "parts" + ] } } } @@ -2537,7 +2573,10 @@ } } }, - "required": ["info", "parts"] + "required": [ + "info", + "parts" + ] } } } @@ -2589,7 +2628,10 @@ "type": "string" } }, - "required": ["arguments", "command"] + "required": [ + "arguments", + "command" + ] } } } @@ -2676,13 +2718,19 @@ "type": "string" } }, - "required": ["providerID", "modelID"] + "required": [ + "providerID", + "modelID" + ] }, "command": { "type": "string" } }, - "required": ["agent", "command"] + "required": [ + "agent", + "command" + ] } } } @@ -2764,7 +2812,9 @@ "pattern": "^prt.*" } }, - "required": ["messageID"] + "required": [ + "messageID" + ] } } } @@ -2909,10 +2959,16 @@ "properties": { "response": { "type": "string", - "enum": ["once", "always", "reject"] + "enum": [ + "once", + "always", + "reject" + ] } }, - "required": ["response"] + "required": [ + "response" + ] } } } @@ -3037,7 +3093,10 @@ } } }, - "required": ["providers", "default"] + "required": [ + "providers", + "default" + ] } } } @@ -3139,10 +3198,15 @@ "properties": { "field": { "type": "string", - "enum": ["reasoning_content", "reasoning_details"] + "enum": [ + "reasoning_content", + "reasoning_details" + ] } }, - "required": ["field"], + "required": [ + "field" + ], "additionalProperties": false } ] @@ -3178,10 +3242,16 @@ "type": "number" } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] }, "limit": { "type": "object", @@ -3193,7 +3263,10 @@ "type": "number" } }, - "required": ["context", "output"] + "required": [ + "context", + "output" + ] }, "modalities": { "type": "object", @@ -3202,25 +3275,44 @@ "type": "array", "items": { "type": "string", - "enum": ["text", "audio", "image", "video", "pdf"] + "enum": [ + "text", + "audio", + "image", + "video", + "pdf" + ] } }, "output": { "type": "array", "items": { "type": "string", - "enum": ["text", "audio", "image", "video", "pdf"] + "enum": [ + "text", + "audio", + "image", + "video", + "pdf" + ] } } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] }, "experimental": { "type": "boolean" }, "status": { "type": "string", - "enum": ["alpha", "beta", "deprecated"] + "enum": [ + "alpha", + "beta", + "deprecated" + ] }, "options": { "type": "object", @@ -3245,7 +3337,9 @@ "type": "string" } }, - "required": ["npm"] + "required": [ + "npm" + ] }, "variants": { "type": "object", @@ -3275,7 +3369,12 @@ } } }, - "required": ["name", "env", "id", "models"] + "required": [ + "name", + "env", + "id", + "models" + ] } }, "default": { @@ -3294,7 +3393,11 @@ } } }, - "required": ["all", "default", "connected"] + "required": [ + "all", + "default", + "connected" + ] } } } @@ -3407,7 +3510,9 @@ "type": "number" } }, - "required": ["method"] + "required": [ + "method" + ] } } } @@ -3480,7 +3585,9 @@ "type": "string" } }, - "required": ["method"] + "required": [ + "method" + ] } } } @@ -3532,7 +3639,9 @@ "type": "string" } }, - "required": ["text"] + "required": [ + "text" + ] }, "lines": { "type": "object", @@ -3541,7 +3650,9 @@ "type": "string" } }, - "required": ["text"] + "required": [ + "text" + ] }, "line_number": { "type": "number" @@ -3561,7 +3672,9 @@ "type": "string" } }, - "required": ["text"] + "required": [ + "text" + ] }, "start": { "type": "number" @@ -3570,11 +3683,21 @@ "type": "number" } }, - "required": ["match", "start", "end"] + "required": [ + "match", + "start", + "end" + ] } } }, - "required": ["path", "lines", "line_number", "absolute_offset", "submatches"] + "required": [ + "path", + "lines", + "line_number", + "absolute_offset", + "submatches" + ] } } } @@ -3613,7 +3736,10 @@ "name": "dirs", "schema": { "type": "string", - "enum": ["true", "false"] + "enum": [ + "true", + "false" + ] } }, { @@ -3621,7 +3747,10 @@ "name": "type", "schema": { "type": "string", - "enum": ["file", "directory"] + "enum": [ + "file", + "directory" + ] } }, { @@ -3877,7 +4006,12 @@ "level": { "description": "Log level", "type": "string", - "enum": ["debug", "info", "error", "warn"] + "enum": [ + "debug", + "info", + "error", + "warn" + ] }, "message": { "description": "Log message", @@ -3892,7 +4026,11 @@ "additionalProperties": {} } }, - "required": ["service", "level", "message"] + "required": [ + "service", + "level", + "message" + ] } } } @@ -4042,7 +4180,10 @@ ] } }, - "required": ["name", "config"] + "required": [ + "name", + "config" + ] } } } @@ -4090,7 +4231,9 @@ "type": "string" } }, - "required": ["authorizationUrl"] + "required": [ + "authorizationUrl" + ] } } } @@ -4157,7 +4300,9 @@ "const": true } }, - "required": ["success"] + "required": [ + "success" + ] } } } @@ -4246,7 +4391,9 @@ "type": "string" } }, - "required": ["code"] + "required": [ + "code" + ] } } } @@ -4523,7 +4670,9 @@ "type": "string" } }, - "required": ["text"] + "required": [ + "text" + ] } } } @@ -4786,7 +4935,9 @@ "type": "string" } }, - "required": ["command"] + "required": [ + "command" + ] } } } @@ -4839,7 +4990,12 @@ }, "variant": { "type": "string", - "enum": ["info", "success", "warning", "error"] + "enum": [ + "info", + "success", + "warning", + "error" + ] }, "duration": { "description": "Duration in milliseconds", @@ -4847,7 +5003,10 @@ "type": "number" } }, - "required": ["message", "variant"] + "required": [ + "message", + "variant" + ] } } } @@ -4950,7 +5109,10 @@ }, "body": {} }, - "required": ["path", "body"] + "required": [ + "path", + "body" + ] } } } @@ -5117,10 +5279,15 @@ "type": "string" } }, - "required": ["version"] + "required": [ + "version" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.installation.update-available": { "type": "object", @@ -5136,10 +5303,15 @@ "type": "string" } }, - "required": ["version"] + "required": [ + "version" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Project": { "type": "object", @@ -5181,10 +5353,17 @@ "type": "number" } }, - "required": ["created", "updated"] + "required": [ + "created", + "updated" + ] } }, - "required": ["id", "worktree", "time"] + "required": [ + "id", + "worktree", + "time" + ] }, "Event.project.updated": { "type": "object", @@ -5197,39 +5376,10 @@ "$ref": "#/components/schemas/Project" } }, - "required": ["type", "properties"] - }, - "ConfigWarning": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["unknown_keybind"] - }, - "message": { - "type": "string" - }, - "keybinds": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": ["type", "message"] - }, - "Event.config.warning": { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "config.warning" - }, - "properties": { - "$ref": "#/components/schemas/ConfigWarning" - } - }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.server.instance.disposed": { "type": "object", @@ -5245,10 +5395,15 @@ "type": "string" } }, - "required": ["directory"] + "required": [ + "directory" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.lsp.client.diagnostics": { "type": "object", @@ -5267,10 +5422,16 @@ "type": "string" } }, - "required": ["serverID", "path"] + "required": [ + "serverID", + "path" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.lsp.updated": { "type": "object", @@ -5284,7 +5445,10 @@ "properties": {} } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "FileDiff": { "type": "object", @@ -5305,7 +5469,13 @@ "type": "number" } }, - "required": ["file", "before", "after", "additions", "deletions"] + "required": [ + "file", + "before", + "after", + "additions", + "deletions" + ] }, "UserMessage": { "type": "object", @@ -5327,7 +5497,9 @@ "type": "number" } }, - "required": ["created"] + "required": [ + "created" + ] }, "summary": { "type": "object", @@ -5345,7 +5517,9 @@ } } }, - "required": ["diffs"] + "required": [ + "diffs" + ] }, "agent": { "type": "string" @@ -5360,7 +5534,10 @@ "type": "string" } }, - "required": ["providerID", "modelID"] + "required": [ + "providerID", + "modelID" + ] }, "system": { "type": "string" @@ -5378,7 +5555,14 @@ "type": "string" } }, - "required": ["id", "sessionID", "role", "time", "agent", "model"] + "required": [ + "id", + "sessionID", + "role", + "time", + "agent", + "model" + ] }, "ProviderAuthError": { "type": "object", @@ -5397,10 +5581,16 @@ "type": "string" } }, - "required": ["providerID", "message"] + "required": [ + "providerID", + "message" + ] } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "UnknownError": { "type": "object", @@ -5416,10 +5606,15 @@ "type": "string" } }, - "required": ["message"] + "required": [ + "message" + ] } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "MessageOutputLengthError": { "type": "object", @@ -5433,7 +5628,10 @@ "properties": {} } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "MessageAbortedError": { "type": "object", @@ -5449,10 +5647,15 @@ "type": "string" } }, - "required": ["message"] + "required": [ + "message" + ] } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "APIError": { "type": "object", @@ -5495,10 +5698,16 @@ } } }, - "required": ["message", "isRetryable"] + "required": [ + "message", + "isRetryable" + ] } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "AssistantMessage": { "type": "object", @@ -5523,7 +5732,9 @@ "type": "number" } }, - "required": ["created"] + "required": [ + "created" + ] }, "error": { "anyOf": [ @@ -5569,7 +5780,10 @@ "type": "string" } }, - "required": ["cwd", "root"] + "required": [ + "cwd", + "root" + ] }, "summary": { "type": "boolean" @@ -5599,10 +5813,18 @@ "type": "number" } }, - "required": ["read", "write"] + "required": [ + "read", + "write" + ] } }, - "required": ["input", "output", "reasoning", "cache"] + "required": [ + "input", + "output", + "reasoning", + "cache" + ] }, "finish": { "type": "string" @@ -5647,10 +5869,15 @@ "$ref": "#/components/schemas/Message" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.message.removed": { "type": "object", @@ -5669,10 +5896,16 @@ "type": "string" } }, - "required": ["sessionID", "messageID"] + "required": [ + "sessionID", + "messageID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "TextPart": { "type": "object", @@ -5709,7 +5942,9 @@ "type": "number" } }, - "required": ["start"] + "required": [ + "start" + ] }, "metadata": { "type": "object", @@ -5719,7 +5954,13 @@ "additionalProperties": {} } }, - "required": ["id", "sessionID", "messageID", "type", "text"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "text" + ] }, "ReasoningPart": { "type": "object", @@ -5757,10 +5998,19 @@ "type": "number" } }, - "required": ["start"] + "required": [ + "start" + ] } }, - "required": ["id", "sessionID", "messageID", "type", "text", "time"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "text", + "time" + ] }, "FilePartSourceText": { "type": "object", @@ -5779,7 +6029,11 @@ "maximum": 9007199254740991 } }, - "required": ["value", "start", "end"] + "required": [ + "value", + "start", + "end" + ] }, "FileSource": { "type": "object", @@ -5795,7 +6049,11 @@ "type": "string" } }, - "required": ["text", "type", "path"] + "required": [ + "text", + "type", + "path" + ] }, "Range": { "type": "object", @@ -5810,7 +6068,10 @@ "type": "number" } }, - "required": ["line", "character"] + "required": [ + "line", + "character" + ] }, "end": { "type": "object", @@ -5822,10 +6083,16 @@ "type": "number" } }, - "required": ["line", "character"] + "required": [ + "line", + "character" + ] } }, - "required": ["start", "end"] + "required": [ + "start", + "end" + ] }, "SymbolSource": { "type": "object", @@ -5852,7 +6119,14 @@ "maximum": 9007199254740991 } }, - "required": ["text", "type", "path", "range", "name", "kind"] + "required": [ + "text", + "type", + "path", + "range", + "name", + "kind" + ] }, "FilePartSource": { "anyOf": [ @@ -5893,7 +6167,14 @@ "$ref": "#/components/schemas/FilePartSource" } }, - "required": ["id", "sessionID", "messageID", "type", "mime", "url"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "mime", + "url" + ] }, "ToolStatePending": { "type": "object", @@ -5913,7 +6194,11 @@ "type": "string" } }, - "required": ["status", "input", "raw"] + "required": [ + "status", + "input", + "raw" + ] }, "ToolStateRunning": { "type": "object", @@ -5946,10 +6231,16 @@ "type": "number" } }, - "required": ["start"] + "required": [ + "start" + ] } }, - "required": ["status", "input", "time"] + "required": [ + "status", + "input", + "time" + ] }, "ToolStateCompleted": { "type": "object", @@ -5991,7 +6282,10 @@ "type": "number" } }, - "required": ["start", "end"] + "required": [ + "start", + "end" + ] }, "attachments": { "type": "array", @@ -6000,7 +6294,14 @@ } } }, - "required": ["status", "input", "output", "title", "metadata", "time"] + "required": [ + "status", + "input", + "output", + "title", + "metadata", + "time" + ] }, "ToolStateError": { "type": "object", @@ -6036,10 +6337,18 @@ "type": "number" } }, - "required": ["start", "end"] + "required": [ + "start", + "end" + ] } }, - "required": ["status", "input", "error", "time"] + "required": [ + "status", + "input", + "error", + "time" + ] }, "ToolState": { "anyOf": [ @@ -6090,7 +6399,15 @@ "additionalProperties": {} } }, - "required": ["id", "sessionID", "messageID", "type", "callID", "tool", "state"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "callID", + "tool", + "state" + ] }, "StepStartPart": { "type": "object", @@ -6112,7 +6429,12 @@ "type": "string" } }, - "required": ["id", "sessionID", "messageID", "type"] + "required": [ + "id", + "sessionID", + "messageID", + "type" + ] }, "StepFinishPart": { "type": "object", @@ -6161,13 +6483,29 @@ "type": "number" } }, - "required": ["read", "write"] + "required": [ + "read", + "write" + ] } }, - "required": ["input", "output", "reasoning", "cache"] + "required": [ + "input", + "output", + "reasoning", + "cache" + ] } }, - "required": ["id", "sessionID", "messageID", "type", "reason", "cost", "tokens"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "reason", + "cost", + "tokens" + ] }, "SnapshotPart": { "type": "object", @@ -6189,7 +6527,13 @@ "type": "string" } }, - "required": ["id", "sessionID", "messageID", "type", "snapshot"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "snapshot" + ] }, "PatchPart": { "type": "object", @@ -6217,7 +6561,14 @@ } } }, - "required": ["id", "sessionID", "messageID", "type", "hash", "files"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "hash", + "files" + ] }, "AgentPart": { "type": "object", @@ -6255,10 +6606,20 @@ "maximum": 9007199254740991 } }, - "required": ["value", "start", "end"] + "required": [ + "value", + "start", + "end" + ] } }, - "required": ["id", "sessionID", "messageID", "type", "name"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "name" + ] }, "RetryPart": { "type": "object", @@ -6289,10 +6650,20 @@ "type": "number" } }, - "required": ["created"] + "required": [ + "created" + ] } }, - "required": ["id", "sessionID", "messageID", "type", "attempt", "error", "time"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "attempt", + "error", + "time" + ] }, "CompactionPart": { "type": "object", @@ -6314,7 +6685,13 @@ "type": "boolean" } }, - "required": ["id", "sessionID", "messageID", "type", "auto"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "auto" + ] }, "Part": { "anyOf": [ @@ -6350,7 +6727,15 @@ "type": "string" } }, - "required": ["id", "sessionID", "messageID", "type", "prompt", "description", "agent"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "prompt", + "description", + "agent" + ] }, { "$ref": "#/components/schemas/ReasoningPart" @@ -6401,10 +6786,15 @@ "type": "string" } }, - "required": ["part"] + "required": [ + "part" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.message.part.removed": { "type": "object", @@ -6426,10 +6816,17 @@ "type": "string" } }, - "required": ["sessionID", "messageID", "partID"] + "required": [ + "sessionID", + "messageID", + "partID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Permission": { "type": "object", @@ -6479,10 +6876,20 @@ "type": "number" } }, - "required": ["created"] + "required": [ + "created" + ] } }, - "required": ["id", "type", "sessionID", "messageID", "title", "metadata", "time"] + "required": [ + "id", + "type", + "sessionID", + "messageID", + "title", + "metadata", + "time" + ] }, "Event.permission.updated": { "type": "object", @@ -6495,7 +6902,10 @@ "$ref": "#/components/schemas/Permission" } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.permission.replied": { "type": "object", @@ -6517,10 +6927,17 @@ "type": "string" } }, - "required": ["sessionID", "permissionID", "response"] + "required": [ + "sessionID", + "permissionID", + "response" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.file.edited": { "type": "object", @@ -6536,10 +6953,15 @@ "type": "string" } }, - "required": ["file"] + "required": [ + "file" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Todo": { "type": "object", @@ -6561,7 +6983,12 @@ "type": "string" } }, - "required": ["content", "status", "priority", "id"] + "required": [ + "content", + "status", + "priority", + "id" + ] }, "Event.todo.updated": { "type": "object", @@ -6583,10 +7010,16 @@ } } }, - "required": ["sessionID", "todos"] + "required": [ + "sessionID", + "todos" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "SessionStatus": { "anyOf": [ @@ -6598,7 +7031,9 @@ "const": "idle" } }, - "required": ["type"] + "required": [ + "type" + ] }, { "type": "object", @@ -6617,7 +7052,12 @@ "type": "number" } }, - "required": ["type", "attempt", "message", "next"] + "required": [ + "type", + "attempt", + "message", + "next" + ] }, { "type": "object", @@ -6627,7 +7067,9 @@ "const": "busy" } }, - "required": ["type"] + "required": [ + "type" + ] } ] }, @@ -6648,10 +7090,16 @@ "$ref": "#/components/schemas/SessionStatus" } }, - "required": ["sessionID", "status"] + "required": [ + "sessionID", + "status" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.idle": { "type": "object", @@ -6667,10 +7115,15 @@ "type": "string" } }, - "required": ["sessionID"] + "required": [ + "sessionID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.compacted": { "type": "object", @@ -6686,10 +7139,15 @@ "type": "string" } }, - "required": ["sessionID"] + "required": [ + "sessionID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.tui.prompt.append": { "type": "object", @@ -6705,10 +7163,15 @@ "type": "string" } }, - "required": ["text"] + "required": [ + "text" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.tui.command.execute": { "type": "object", @@ -6747,10 +7210,15 @@ ] } }, - "required": ["command"] + "required": [ + "command" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.tui.toast.show": { "type": "object", @@ -6770,7 +7238,12 @@ }, "variant": { "type": "string", - "enum": ["info", "success", "warning", "error"] + "enum": [ + "info", + "success", + "warning", + "error" + ] }, "duration": { "description": "Duration in milliseconds", @@ -6778,10 +7251,16 @@ "type": "number" } }, - "required": ["message", "variant"] + "required": [ + "message", + "variant" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.mcp.tools.changed": { "type": "object", @@ -6797,10 +7276,15 @@ "type": "string" } }, - "required": ["server"] + "required": [ + "server" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.command.executed": { "type": "object", @@ -6827,10 +7311,18 @@ "pattern": "^msg.*" } }, - "required": ["name", "sessionID", "arguments", "messageID"] + "required": [ + "name", + "sessionID", + "arguments", + "messageID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Session": { "type": "object", @@ -6868,7 +7360,11 @@ } } }, - "required": ["additions", "deletions", "files"] + "required": [ + "additions", + "deletions", + "files" + ] }, "share": { "type": "object", @@ -6877,7 +7373,9 @@ "type": "string" } }, - "required": ["url"] + "required": [ + "url" + ] }, "title": { "type": "string" @@ -6901,7 +7399,10 @@ "type": "number" } }, - "required": ["created", "updated"] + "required": [ + "created", + "updated" + ] }, "revert": { "type": "object", @@ -6919,10 +7420,19 @@ "type": "string" } }, - "required": ["messageID"] + "required": [ + "messageID" + ] } }, - "required": ["id", "projectID", "directory", "title", "version", "time"] + "required": [ + "id", + "projectID", + "directory", + "title", + "version", + "time" + ] }, "Event.session.created": { "type": "object", @@ -6938,10 +7448,15 @@ "$ref": "#/components/schemas/Session" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.updated": { "type": "object", @@ -6957,10 +7472,15 @@ "$ref": "#/components/schemas/Session" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.deleted": { "type": "object", @@ -6976,10 +7496,15 @@ "$ref": "#/components/schemas/Session" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.diff": { "type": "object", @@ -7001,10 +7526,16 @@ } } }, - "required": ["sessionID", "diff"] + "required": [ + "sessionID", + "diff" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.error": { "type": "object", @@ -7041,7 +7572,10 @@ } } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.file.watcher.updated": { "type": "object", @@ -7073,10 +7607,16 @@ ] } }, - "required": ["file", "event"] + "required": [ + "file", + "event" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.vcs.branch.updated": { "type": "object", @@ -7094,7 +7634,10 @@ } } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Pty": { "type": "object", @@ -7120,13 +7663,24 @@ }, "status": { "type": "string", - "enum": ["running", "exited"] + "enum": [ + "running", + "exited" + ] }, "pid": { "type": "number" } }, - "required": ["id", "title", "command", "args", "cwd", "status", "pid"] + "required": [ + "id", + "title", + "command", + "args", + "cwd", + "status", + "pid" + ] }, "Event.pty.created": { "type": "object", @@ -7142,10 +7696,15 @@ "$ref": "#/components/schemas/Pty" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.pty.updated": { "type": "object", @@ -7161,10 +7720,15 @@ "$ref": "#/components/schemas/Pty" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.pty.exited": { "type": "object", @@ -7184,10 +7748,16 @@ "type": "number" } }, - "required": ["id", "exitCode"] + "required": [ + "id", + "exitCode" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.pty.deleted": { "type": "object", @@ -7204,10 +7774,15 @@ "pattern": "^pty.*" } }, - "required": ["id"] + "required": [ + "id" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.server.connected": { "type": "object", @@ -7221,7 +7796,10 @@ "properties": {} } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.global.disposed": { "type": "object", @@ -7235,7 +7813,10 @@ "properties": {} } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event": { "anyOf": [ @@ -7248,9 +7829,6 @@ { "$ref": "#/components/schemas/Event.project.updated" }, - { - "$ref": "#/components/schemas/Event.config.warning" - }, { "$ref": "#/components/schemas/Event.server.instance.disposed" }, @@ -7359,7 +7937,10 @@ "$ref": "#/components/schemas/Event" } }, - "required": ["directory", "payload"] + "required": [ + "directory", + "payload" + ] }, "BadRequestError": { "type": "object", @@ -7380,7 +7961,11 @@ "const": false } }, - "required": ["data", "errors", "success"] + "required": [ + "data", + "errors", + "success" + ] }, "NotFoundError": { "type": "object", @@ -7396,10 +7981,15 @@ "type": "string" } }, - "required": ["message"] + "required": [ + "message" + ] } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "KeybindsConfig": { "description": "Custom keybind configurations", @@ -7841,12 +8431,17 @@ "type": "string" } }, - "additionalProperties": {} + "additionalProperties": false }, "LogLevel": { "description": "Log level", "type": "string", - "enum": ["DEBUG", "INFO", "WARN", "ERROR"] + "enum": [ + "DEBUG", + "INFO", + "WARN", + "ERROR" + ] }, "ServerConfig": { "description": "Server configuration for opencode serve and web commands", @@ -7909,7 +8504,11 @@ }, "mode": { "type": "string", - "enum": ["subagent", "primary", "all"] + "enum": [ + "subagent", + "primary", + "all" + ] }, "color": { "description": "Hex color code for the agent (e.g., #FF5733)", @@ -7927,13 +8526,21 @@ "properties": { "edit": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, "bash": { "anyOf": [ { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, { "type": "object", @@ -7942,7 +8549,11 @@ }, "additionalProperties": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] } } ] @@ -7951,7 +8562,11 @@ "anyOf": [ { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, { "type": "object", @@ -7960,22 +8575,38 @@ }, "additionalProperties": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] } } ] }, "webfetch": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, "doom_loop": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, "external_directory": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] } } } @@ -8046,10 +8677,15 @@ "properties": { "field": { "type": "string", - "enum": ["reasoning_content", "reasoning_details"] + "enum": [ + "reasoning_content", + "reasoning_details" + ] } }, - "required": ["field"], + "required": [ + "field" + ], "additionalProperties": false } ] @@ -8085,10 +8721,16 @@ "type": "number" } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] }, "limit": { "type": "object", @@ -8100,7 +8742,10 @@ "type": "number" } }, - "required": ["context", "output"] + "required": [ + "context", + "output" + ] }, "modalities": { "type": "object", @@ -8109,25 +8754,44 @@ "type": "array", "items": { "type": "string", - "enum": ["text", "audio", "image", "video", "pdf"] + "enum": [ + "text", + "audio", + "image", + "video", + "pdf" + ] } }, "output": { "type": "array", "items": { "type": "string", - "enum": ["text", "audio", "image", "video", "pdf"] + "enum": [ + "text", + "audio", + "image", + "video", + "pdf" + ] } } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] }, "experimental": { "type": "boolean" }, "status": { "type": "string", - "enum": ["alpha", "beta", "deprecated"] + "enum": [ + "alpha", + "beta", + "deprecated" + ] }, "options": { "type": "object", @@ -8152,7 +8816,9 @@ "type": "string" } }, - "required": ["npm"] + "required": [ + "npm" + ] }, "variants": { "description": "Variant-specific configuration", @@ -8261,7 +8927,10 @@ "maximum": 9007199254740991 } }, - "required": ["type", "command"], + "required": [ + "type", + "command" + ], "additionalProperties": false }, "McpOAuthConfig": { @@ -8327,13 +8996,19 @@ "maximum": 9007199254740991 } }, - "required": ["type", "url"], + "required": [ + "type", + "url" + ], "additionalProperties": false }, "LayoutConfig": { "description": "@deprecated Always uses stretch layout.", "type": "string", - "enum": ["auto", "stretch"] + "enum": [ + "auto", + "stretch" + ] }, "Config": { "type": "object", @@ -8370,12 +9045,17 @@ "type": "boolean" } }, - "required": ["enabled"] + "required": [ + "enabled" + ] }, "diff_style": { "description": "Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column", "type": "string", - "enum": ["auto", "stacked"] + "enum": [ + "auto", + "stacked" + ] } } }, @@ -8407,7 +9087,9 @@ "type": "boolean" } }, - "required": ["template"] + "required": [ + "template" + ] } }, "watcher": { @@ -8433,7 +9115,11 @@ "share": { "description": "Control sharing behavior:'manual' allows manual sharing via commands, 'auto' enables automatic sharing, 'disabled' disables all sharing", "type": "string", - "enum": ["manual", "auto", "disabled"] + "enum": [ + "manual", + "auto", + "disabled" + ] }, "autoshare": { "description": "@deprecated Use 'share' field instead. Share newly created sessions automatically", @@ -8617,7 +9303,9 @@ "const": true } }, - "required": ["disabled"] + "required": [ + "disabled" + ] }, { "type": "object", @@ -8654,7 +9342,9 @@ "additionalProperties": {} } }, - "required": ["command"] + "required": [ + "command" + ] } ] } @@ -8676,13 +9366,21 @@ "properties": { "edit": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, "bash": { "anyOf": [ { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, { "type": "object", @@ -8691,7 +9389,11 @@ }, "additionalProperties": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] } } ] @@ -8700,7 +9402,11 @@ "anyOf": [ { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, { "type": "object", @@ -8709,22 +9415,38 @@ }, "additionalProperties": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] } } ] }, "webfetch": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, "doom_loop": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, "external_directory": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] } } }, @@ -8791,7 +9513,9 @@ } } }, - "required": ["command"] + "required": [ + "command" + ] } } }, @@ -8816,7 +9540,9 @@ } } }, - "required": ["command"] + "required": [ + "command" + ] } } } @@ -8858,6 +9584,42 @@ }, "additionalProperties": false }, + "ConfigWarning": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "unknown_keybind" + ] + }, + "message": { + "type": "string" + }, + "keybinds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "binding": { + "type": "string" + } + }, + "required": [ + "name", + "binding" + ] + } + } + }, + "required": [ + "type", + "message" + ] + }, "ToolIDs": { "type": "array", "items": { @@ -8875,7 +9637,11 @@ }, "parameters": {} }, - "required": ["id", "description", "parameters"] + "required": [ + "id", + "description", + "parameters" + ] }, "ToolList": { "type": "array", @@ -8902,7 +9668,13 @@ "type": "string" } }, - "required": ["home", "state", "config", "worktree", "directory"] + "required": [ + "home", + "state", + "config", + "worktree", + "directory" + ] }, "VcsInfo": { "type": "object", @@ -8911,7 +9683,9 @@ "type": "string" } }, - "required": ["branch"] + "required": [ + "branch" + ] }, "TextPartInput": { "type": "object", @@ -8942,7 +9716,9 @@ "type": "number" } }, - "required": ["start"] + "required": [ + "start" + ] }, "metadata": { "type": "object", @@ -8952,7 +9728,10 @@ "additionalProperties": {} } }, - "required": ["type", "text"] + "required": [ + "type", + "text" + ] }, "FilePartInput": { "type": "object", @@ -8977,7 +9756,11 @@ "$ref": "#/components/schemas/FilePartSource" } }, - "required": ["type", "mime", "url"] + "required": [ + "type", + "mime", + "url" + ] }, "AgentPartInput": { "type": "object", @@ -9009,10 +9792,17 @@ "maximum": 9007199254740991 } }, - "required": ["value", "start", "end"] + "required": [ + "value", + "start", + "end" + ] } }, - "required": ["type", "name"] + "required": [ + "type", + "name" + ] }, "SubtaskPartInput": { "type": "object", @@ -9037,7 +9827,12 @@ "type": "string" } }, - "required": ["type", "prompt", "description", "agent"] + "required": [ + "type", + "prompt", + "description", + "agent" + ] }, "Command": { "type": "object", @@ -9077,7 +9872,11 @@ } } }, - "required": ["name", "template", "hints"] + "required": [ + "name", + "template", + "hints" + ] }, "Model": { "type": "object", @@ -9101,7 +9900,11 @@ "type": "string" } }, - "required": ["id", "url", "npm"] + "required": [ + "id", + "url", + "npm" + ] }, "name": { "type": "string" @@ -9143,7 +9946,13 @@ "type": "boolean" } }, - "required": ["text", "audio", "image", "video", "pdf"] + "required": [ + "text", + "audio", + "image", + "video", + "pdf" + ] }, "output": { "type": "object", @@ -9164,7 +9973,13 @@ "type": "boolean" } }, - "required": ["text", "audio", "image", "video", "pdf"] + "required": [ + "text", + "audio", + "image", + "video", + "pdf" + ] }, "interleaved": { "anyOf": [ @@ -9176,15 +9991,28 @@ "properties": { "field": { "type": "string", - "enum": ["reasoning_content", "reasoning_details"] + "enum": [ + "reasoning_content", + "reasoning_details" + ] } }, - "required": ["field"] + "required": [ + "field" + ] } ] } }, - "required": ["temperature", "reasoning", "attachment", "toolcall", "input", "output", "interleaved"] + "required": [ + "temperature", + "reasoning", + "attachment", + "toolcall", + "input", + "output", + "interleaved" + ] }, "cost": { "type": "object", @@ -9205,7 +10033,10 @@ "type": "number" } }, - "required": ["read", "write"] + "required": [ + "read", + "write" + ] }, "experimentalOver200K": { "type": "object", @@ -9226,13 +10057,24 @@ "type": "number" } }, - "required": ["read", "write"] + "required": [ + "read", + "write" + ] } }, - "required": ["input", "output", "cache"] + "required": [ + "input", + "output", + "cache" + ] } }, - "required": ["input", "output", "cache"] + "required": [ + "input", + "output", + "cache" + ] }, "limit": { "type": "object", @@ -9244,11 +10086,19 @@ "type": "number" } }, - "required": ["context", "output"] + "required": [ + "context", + "output" + ] }, "status": { "type": "string", - "enum": ["alpha", "beta", "deprecated", "active"] + "enum": [ + "alpha", + "beta", + "deprecated", + "active" + ] }, "options": { "type": "object", @@ -9308,7 +10158,12 @@ }, "source": { "type": "string", - "enum": ["env", "config", "custom", "api"] + "enum": [ + "env", + "config", + "custom", + "api" + ] }, "env": { "type": "array", @@ -9336,7 +10191,14 @@ } } }, - "required": ["id", "name", "source", "env", "options", "models"] + "required": [ + "id", + "name", + "source", + "env", + "options", + "models" + ] }, "ProviderAuthMethod": { "type": "object", @@ -9357,7 +10219,10 @@ "type": "string" } }, - "required": ["type", "label"] + "required": [ + "type", + "label" + ] }, "ProviderAuthAuthorization": { "type": "object", @@ -9381,7 +10246,11 @@ "type": "string" } }, - "required": ["url", "method", "instructions"] + "required": [ + "url", + "method", + "instructions" + ] }, "Symbol": { "type": "object", @@ -9402,10 +10271,17 @@ "$ref": "#/components/schemas/Range" } }, - "required": ["uri", "range"] + "required": [ + "uri", + "range" + ] } }, - "required": ["name", "kind", "location"] + "required": [ + "name", + "kind", + "location" + ] }, "FileNode": { "type": "object", @@ -9421,13 +10297,22 @@ }, "type": { "type": "string", - "enum": ["file", "directory"] + "enum": [ + "file", + "directory" + ] }, "ignored": { "type": "boolean" } }, - "required": ["name", "path", "absolute", "type", "ignored"] + "required": [ + "name", + "path", + "absolute", + "type", + "ignored" + ] }, "FileContent": { "type": "object", @@ -9481,14 +10366,24 @@ } } }, - "required": ["oldStart", "oldLines", "newStart", "newLines", "lines"] + "required": [ + "oldStart", + "oldLines", + "newStart", + "newLines", + "lines" + ] } }, "index": { "type": "string" } }, - "required": ["oldFileName", "newFileName", "hunks"] + "required": [ + "oldFileName", + "newFileName", + "hunks" + ] }, "encoding": { "type": "string", @@ -9498,7 +10393,10 @@ "type": "string" } }, - "required": ["type", "content"] + "required": [ + "type", + "content" + ] }, "File": { "type": "object", @@ -9518,10 +10416,19 @@ }, "status": { "type": "string", - "enum": ["added", "deleted", "modified"] + "enum": [ + "added", + "deleted", + "modified" + ] } }, - "required": ["path", "added", "removed", "status"] + "required": [ + "path", + "added", + "removed", + "status" + ] }, "Agent": { "type": "object", @@ -9534,7 +10441,11 @@ }, "mode": { "type": "string", - "enum": ["subagent", "primary", "all"] + "enum": [ + "subagent", + "primary", + "all" + ] }, "native": { "type": "boolean" @@ -9559,7 +10470,11 @@ "properties": { "edit": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, "bash": { "type": "object", @@ -9568,7 +10483,11 @@ }, "additionalProperties": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] } }, "skill": { @@ -9578,23 +10497,43 @@ }, "additionalProperties": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] } }, "webfetch": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, "doom_loop": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, "external_directory": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] } }, - "required": ["edit", "bash", "skill"] + "required": [ + "edit", + "bash", + "skill" + ] }, "model": { "type": "object", @@ -9606,7 +10545,10 @@ "type": "string" } }, - "required": ["modelID", "providerID"] + "required": [ + "modelID", + "providerID" + ] }, "prompt": { "type": "string" @@ -9633,7 +10575,13 @@ "maximum": 9007199254740991 } }, - "required": ["name", "mode", "permission", "tools", "options"] + "required": [ + "name", + "mode", + "permission", + "tools", + "options" + ] }, "MCPStatusConnected": { "type": "object", @@ -9643,7 +10591,9 @@ "const": "connected" } }, - "required": ["status"] + "required": [ + "status" + ] }, "MCPStatusDisabled": { "type": "object", @@ -9653,7 +10603,9 @@ "const": "disabled" } }, - "required": ["status"] + "required": [ + "status" + ] }, "MCPStatusFailed": { "type": "object", @@ -9666,7 +10618,10 @@ "type": "string" } }, - "required": ["status", "error"] + "required": [ + "status", + "error" + ] }, "MCPStatusNeedsAuth": { "type": "object", @@ -9676,7 +10631,9 @@ "const": "needs_auth" } }, - "required": ["status"] + "required": [ + "status" + ] }, "MCPStatusNeedsClientRegistration": { "type": "object", @@ -9689,7 +10646,10 @@ "type": "string" } }, - "required": ["status", "error"] + "required": [ + "status", + "error" + ] }, "MCPStatus": { "anyOf": [ @@ -9735,7 +10695,12 @@ ] } }, - "required": ["id", "name", "root", "status"] + "required": [ + "id", + "name", + "root", + "status" + ] }, "FormatterStatus": { "type": "object", @@ -9753,7 +10718,11 @@ "type": "boolean" } }, - "required": ["name", "extensions", "enabled"] + "required": [ + "name", + "extensions", + "enabled" + ] }, "OAuth": { "type": "object", @@ -9775,7 +10744,12 @@ "type": "string" } }, - "required": ["type", "refresh", "access", "expires"] + "required": [ + "type", + "refresh", + "access", + "expires" + ] }, "ApiAuth": { "type": "object", @@ -9788,7 +10762,10 @@ "type": "string" } }, - "required": ["type", "key"] + "required": [ + "type", + "key" + ] }, "WellKnownAuth": { "type": "object", @@ -9804,7 +10781,11 @@ "type": "string" } }, - "required": ["type", "key", "token"] + "required": [ + "type", + "key", + "token" + ] }, "Auth": { "anyOf": [ @@ -9821,4 +10802,4 @@ } } } -} +} \ No newline at end of file From 9e4520b309916edf9a7a245ee0b66245fc840e3b Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 31 Dec 2025 19:45:57 -0500 Subject: [PATCH 11/15] refactor: use BusEvent for config warnings instead of API endpoint - Add Config.Event.Warning BusEvent definition - Server sends warning events to clients on SSE connect - TUI subscribes to config.warning events instead of polling API - Remove /config/warnings API endpoint (no longer needed) - Regenerate SDK This fulfills the maintainer's request to use event-based communication for config warnings rather than TUI-side enforcement. --- packages/opencode/src/cli/cmd/tui/app.tsx | 38 ++---- .../cli/cmd/tui/component/dialog-command.tsx | 42 ++---- packages/opencode/src/config/config.ts | 5 + packages/opencode/src/server/server.ts | 34 ++--- packages/sdk/js/src/v2/gen/sdk.gen.ts | 20 --- packages/sdk/js/src/v2/gen/types.gen.ts | 42 ++---- packages/sdk/openapi.json | 128 ++++++++---------- 7 files changed, 108 insertions(+), 201 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 7f209f0681d..3bebb12051a 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -4,6 +4,7 @@ import { TextAttributes } from "@opentui/core" import { RouteProvider, useRoute } from "@tui/context/route" import { Switch, Match, createEffect, untrack, ErrorBoundary, createSignal, onMount, batch, Show, on } from "solid-js" import { Installation } from "@/installation" +import { Config } from "@/config/config" import { Global } from "@/global" import { Flag } from "@/flag/flag" import { DialogProvider, useDialog } from "@tui/ui/dialog" @@ -584,34 +585,15 @@ function App() { }) }) - // Fetch and display config warnings after sync completes - let warningsShown = false - createEffect( - on( - () => sync.status === "complete", - (isComplete) => { - if (!isComplete || warningsShown) return - warningsShown = true - sdk.client.config - .warnings() - .then((response) => { - const warnings = response.data ?? [] - if (warnings.length > 0) { - const messages = warnings.map((w) => w.message) - toast.show({ - variant: "warning", - title: "Config Warning", - message: messages.join("\n"), - duration: 5000, - }) - } - }) - .catch(() => { - // Silently ignore errors fetching warnings - }) - }, - ), - ) + // Subscribe to config warning events + sdk.event.on(Config.Event.Warning.type, (evt) => { + toast.show({ + variant: "warning", + title: "Config Warning", + message: evt.properties.message, + duration: 5000, + }) + }) return ( @@ -39,36 +37,18 @@ function init() { const dialog = useDialog() const keybind = useKeybind() const toast = useToast() - const sync = useSync() const sdk = useSDK() - // Fetch unknown keybinds from warnings when sync completes - let warningsFetched = false - createEffect( - on( - () => sync.status === "complete", - (isComplete) => { - if (!isComplete || warningsFetched) return - warningsFetched = true - sdk.client.config - .warnings() - .then((response) => { - const warnings = response.data ?? [] - for (const warning of warnings) { - if (warning.type === "unknown_keybind" && warning.keybinds) { - const parsed = warning.keybinds.map((kb) => ({ - name: kb.name, - parsed: Keybind.parse(kb.binding), - })) - setUnknownKeybinds(parsed) - break - } - } - }) - .catch(() => {}) - }, - ), - ) + // Subscribe to config warning events to get unknown keybinds + sdk.event.on(Config.Event.Warning.type, (evt) => { + if (evt.properties.type === "unknown_keybind" && evt.properties.keybinds) { + const parsed = evt.properties.keybinds.map((kb) => ({ + name: kb.name, + parsed: Keybind.parse(kb.binding), + })) + setUnknownKeybinds(parsed) + } + }) const options = createMemo(() => { const all = registrations().flatMap((x) => x()) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index d1bf1f26bbb..5f4dd88f8f1 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -1,3 +1,4 @@ +import { BusEvent } from "../bus/bus-event" import { Log } from "../util/log" import path from "path" import { pathToFileURL } from "url" @@ -608,6 +609,10 @@ export namespace Config { .meta({ ref: "ConfigWarning" }) export type Warning = z.infer + export const Event = { + Warning: BusEvent.define("config.warning", Warning), + } + export const TUI = z.object({ scroll_speed: z.number().min(0.001).optional().describe("TUI scroll speed"), scroll_acceleration: z diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index a87de2081df..2df211c68f2 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -475,28 +475,6 @@ export namespace Server { return c.json(config) }, ) - .get( - "/config/warnings", - describeRoute({ - summary: "Get configuration warnings", - description: - "Retrieve any warnings generated during configuration loading, such as unknown keybind commands.", - operationId: "config.warnings", - responses: { - 200: { - description: "List of configuration warnings", - content: { - "application/json": { - schema: resolver(Config.Warning.array()), - }, - }, - }, - }, - }), - async (c) => { - return c.json(await Config.warnings()) - }, - ) .get( "/experimental/tool/ids", describeRoute({ @@ -2648,6 +2626,18 @@ export namespace Server { properties: {}, }), }) + + // Send config warnings to newly connected client + const warnings = await Config.warnings() + for (const warning of warnings) { + stream.writeSSE({ + data: JSON.stringify({ + type: Config.Event.Warning.type, + properties: warning, + }), + }) + } + const unsub = Bus.subscribeAll(async (event) => { await stream.writeSSE({ data: JSON.stringify(event), diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index 35a85e96d1b..b0610b64bc3 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -16,7 +16,6 @@ import type { ConfigProvidersResponses, ConfigUpdateErrors, ConfigUpdateResponses, - ConfigWarningsResponses, EventSubscribeResponses, EventTuiCommandExecute, EventTuiPromptAppend, @@ -563,25 +562,6 @@ export class Config extends HeyApiClient { }) } - /** - * Get configuration warnings - * - * Retrieve any warnings generated during configuration loading, such as unknown keybind commands. - */ - public warnings( - parameters?: { - directory?: string - }, - options?: Options, - ) { - const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "directory" }] }]) - return (options?.client ?? this.client).get({ - url: "/config/warnings", - ...options, - ...params, - }) - } - /** * List config providers * diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 26f893d8082..3b14045719e 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -39,6 +39,20 @@ export type EventProjectUpdated = { properties: Project } +export type ConfigWarning = { + type: "unknown_keybind" + message: string + keybinds?: Array<{ + name: string + binding: string + }> +} + +export type EventConfigWarning = { + type: "config.warning" + properties: ConfigWarning +} + export type EventServerInstanceDisposed = { type: "server.instance.disposed" properties: { @@ -749,6 +763,7 @@ export type Event = | EventInstallationUpdated | EventInstallationUpdateAvailable | EventProjectUpdated + | EventConfigWarning | EventServerInstanceDisposed | EventLspClientDiagnostics | EventLspUpdated @@ -1662,15 +1677,6 @@ export type Config = { } } -export type ConfigWarning = { - type: "unknown_keybind" - message: string - keybinds?: Array<{ - name: string - binding: string - }> -} - export type ToolIds = Array export type ToolListItem = { @@ -2334,24 +2340,6 @@ export type ConfigUpdateResponses = { export type ConfigUpdateResponse = ConfigUpdateResponses[keyof ConfigUpdateResponses] -export type ConfigWarningsData = { - body?: never - path?: never - query?: { - directory?: string - } - url: "/config/warnings" -} - -export type ConfigWarningsResponses = { - /** - * List of configuration warnings - */ - 200: Array -} - -export type ConfigWarningsResponse = ConfigWarningsResponses[keyof ConfigWarningsResponses] - export type ToolIdsData = { body?: never path?: never diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 81d1910241a..b900190ed0d 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -684,43 +684,6 @@ ] } }, - "/config/warnings": { - "get": { - "operationId": "config.warnings", - "parameters": [ - { - "in": "query", - "name": "directory", - "schema": { - "type": "string" - } - } - ], - "summary": "Get configuration warnings", - "description": "Retrieve any warnings generated during configuration loading, such as unknown keybind commands.", - "responses": { - "200": { - "description": "List of configuration warnings", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ConfigWarning" - } - } - } - } - } - }, - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.config.warnings({\n ...\n})" - } - ] - } - }, "/experimental/tool/ids": { "get": { "operationId": "tool.ids", @@ -5381,6 +5344,58 @@ "properties" ] }, + "ConfigWarning": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "unknown_keybind" + ] + }, + "message": { + "type": "string" + }, + "keybinds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "binding": { + "type": "string" + } + }, + "required": [ + "name", + "binding" + ] + } + } + }, + "required": [ + "type", + "message" + ] + }, + "Event.config.warning": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "config.warning" + }, + "properties": { + "$ref": "#/components/schemas/ConfigWarning" + } + }, + "required": [ + "type", + "properties" + ] + }, "Event.server.instance.disposed": { "type": "object", "properties": { @@ -7829,6 +7844,9 @@ { "$ref": "#/components/schemas/Event.project.updated" }, + { + "$ref": "#/components/schemas/Event.config.warning" + }, { "$ref": "#/components/schemas/Event.server.instance.disposed" }, @@ -9584,42 +9602,6 @@ }, "additionalProperties": false }, - "ConfigWarning": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "unknown_keybind" - ] - }, - "message": { - "type": "string" - }, - "keybinds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "binding": { - "type": "string" - } - }, - "required": [ - "name", - "binding" - ] - } - } - }, - "required": [ - "type", - "message" - ] - }, "ToolIDs": { "type": "array", "items": { From 97099fce555fb74ad829f4b13edbc25ba684d4d0 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Thu, 1 Jan 2026 18:31:26 -0500 Subject: [PATCH 12/15] revert: remove unnecessary formatting changes from openapi.json --- packages/sdk/openapi.json | 1595 +++++++------------------------------ 1 file changed, 280 insertions(+), 1315 deletions(-) diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index b900190ed0d..973c217fd18 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -27,10 +27,7 @@ "type": "string" } }, - "required": [ - "healthy", - "version" - ] + "required": ["healthy", "version"] } } } @@ -479,10 +476,7 @@ "type": "number" } }, - "required": [ - "rows", - "cols" - ] + "required": ["rows", "cols"] } } } @@ -1060,9 +1054,7 @@ ], "summary": "Get session", "description": "Retrieve detailed information about a specific OpenCode session.", - "tags": [ - "Session" - ], + "tags": ["Session"], "responses": { "200": { "description": "Get session", @@ -1268,9 +1260,7 @@ } ], "summary": "Get session children", - "tags": [ - "Session" - ], + "tags": ["Session"], "description": "Retrieve all child sessions that were forked from the specified parent session.", "responses": { "200": { @@ -1453,11 +1443,7 @@ "pattern": "^msg.*" } }, - "required": [ - "modelID", - "providerID", - "messageID" - ] + "required": ["modelID", "providerID", "messageID"] } } } @@ -1859,10 +1845,7 @@ "type": "boolean" } }, - "required": [ - "providerID", - "modelID" - ] + "required": ["providerID", "modelID"] } } } @@ -1925,10 +1908,7 @@ } } }, - "required": [ - "info", - "parts" - ] + "required": ["info", "parts"] } } } @@ -2002,10 +1982,7 @@ } } }, - "required": [ - "info", - "parts" - ] + "required": ["info", "parts"] } } } @@ -2051,10 +2028,7 @@ "type": "string" } }, - "required": [ - "providerID", - "modelID" - ] + "required": ["providerID", "modelID"] }, "agent": { "type": "string" @@ -2097,9 +2071,7 @@ } } }, - "required": [ - "parts" - ] + "required": ["parts"] } } } @@ -2162,10 +2134,7 @@ } } }, - "required": [ - "info", - "parts" - ] + "required": ["info", "parts"] } } } @@ -2434,10 +2403,7 @@ "type": "string" } }, - "required": [ - "providerID", - "modelID" - ] + "required": ["providerID", "modelID"] }, "agent": { "type": "string" @@ -2480,9 +2446,7 @@ } } }, - "required": [ - "parts" - ] + "required": ["parts"] } } } @@ -2536,10 +2500,7 @@ } } }, - "required": [ - "info", - "parts" - ] + "required": ["info", "parts"] } } } @@ -2591,10 +2552,7 @@ "type": "string" } }, - "required": [ - "arguments", - "command" - ] + "required": ["arguments", "command"] } } } @@ -2681,19 +2639,13 @@ "type": "string" } }, - "required": [ - "providerID", - "modelID" - ] + "required": ["providerID", "modelID"] }, "command": { "type": "string" } }, - "required": [ - "agent", - "command" - ] + "required": ["agent", "command"] } } } @@ -2775,9 +2727,7 @@ "pattern": "^prt.*" } }, - "required": [ - "messageID" - ] + "required": ["messageID"] } } } @@ -2922,16 +2872,10 @@ "properties": { "response": { "type": "string", - "enum": [ - "once", - "always", - "reject" - ] + "enum": ["once", "always", "reject"] } }, - "required": [ - "response" - ] + "required": ["response"] } } } @@ -3056,10 +3000,7 @@ } } }, - "required": [ - "providers", - "default" - ] + "required": ["providers", "default"] } } } @@ -3161,15 +3102,10 @@ "properties": { "field": { "type": "string", - "enum": [ - "reasoning_content", - "reasoning_details" - ] + "enum": ["reasoning_content", "reasoning_details"] } }, - "required": [ - "field" - ], + "required": ["field"], "additionalProperties": false } ] @@ -3205,16 +3141,10 @@ "type": "number" } }, - "required": [ - "input", - "output" - ] + "required": ["input", "output"] } }, - "required": [ - "input", - "output" - ] + "required": ["input", "output"] }, "limit": { "type": "object", @@ -3226,10 +3156,7 @@ "type": "number" } }, - "required": [ - "context", - "output" - ] + "required": ["context", "output"] }, "modalities": { "type": "object", @@ -3238,44 +3165,25 @@ "type": "array", "items": { "type": "string", - "enum": [ - "text", - "audio", - "image", - "video", - "pdf" - ] + "enum": ["text", "audio", "image", "video", "pdf"] } }, "output": { "type": "array", "items": { "type": "string", - "enum": [ - "text", - "audio", - "image", - "video", - "pdf" - ] + "enum": ["text", "audio", "image", "video", "pdf"] } } }, - "required": [ - "input", - "output" - ] + "required": ["input", "output"] }, "experimental": { "type": "boolean" }, "status": { "type": "string", - "enum": [ - "alpha", - "beta", - "deprecated" - ] + "enum": ["alpha", "beta", "deprecated"] }, "options": { "type": "object", @@ -3300,9 +3208,7 @@ "type": "string" } }, - "required": [ - "npm" - ] + "required": ["npm"] }, "variants": { "type": "object", @@ -3332,12 +3238,7 @@ } } }, - "required": [ - "name", - "env", - "id", - "models" - ] + "required": ["name", "env", "id", "models"] } }, "default": { @@ -3356,11 +3257,7 @@ } } }, - "required": [ - "all", - "default", - "connected" - ] + "required": ["all", "default", "connected"] } } } @@ -3473,9 +3370,7 @@ "type": "number" } }, - "required": [ - "method" - ] + "required": ["method"] } } } @@ -3548,9 +3443,7 @@ "type": "string" } }, - "required": [ - "method" - ] + "required": ["method"] } } } @@ -3602,9 +3495,7 @@ "type": "string" } }, - "required": [ - "text" - ] + "required": ["text"] }, "lines": { "type": "object", @@ -3613,9 +3504,7 @@ "type": "string" } }, - "required": [ - "text" - ] + "required": ["text"] }, "line_number": { "type": "number" @@ -3635,9 +3524,7 @@ "type": "string" } }, - "required": [ - "text" - ] + "required": ["text"] }, "start": { "type": "number" @@ -3646,21 +3533,11 @@ "type": "number" } }, - "required": [ - "match", - "start", - "end" - ] + "required": ["match", "start", "end"] } } }, - "required": [ - "path", - "lines", - "line_number", - "absolute_offset", - "submatches" - ] + "required": ["path", "lines", "line_number", "absolute_offset", "submatches"] } } } @@ -3699,10 +3576,7 @@ "name": "dirs", "schema": { "type": "string", - "enum": [ - "true", - "false" - ] + "enum": ["true", "false"] } }, { @@ -3710,10 +3584,7 @@ "name": "type", "schema": { "type": "string", - "enum": [ - "file", - "directory" - ] + "enum": ["file", "directory"] } }, { @@ -3969,12 +3840,7 @@ "level": { "description": "Log level", "type": "string", - "enum": [ - "debug", - "info", - "error", - "warn" - ] + "enum": ["debug", "info", "error", "warn"] }, "message": { "description": "Log message", @@ -3989,11 +3855,7 @@ "additionalProperties": {} } }, - "required": [ - "service", - "level", - "message" - ] + "required": ["service", "level", "message"] } } } @@ -4143,10 +4005,7 @@ ] } }, - "required": [ - "name", - "config" - ] + "required": ["name", "config"] } } } @@ -4194,9 +4053,7 @@ "type": "string" } }, - "required": [ - "authorizationUrl" - ] + "required": ["authorizationUrl"] } } } @@ -4263,9 +4120,7 @@ "const": true } }, - "required": [ - "success" - ] + "required": ["success"] } } } @@ -4354,9 +4209,7 @@ "type": "string" } }, - "required": [ - "code" - ] + "required": ["code"] } } } @@ -4633,9 +4486,7 @@ "type": "string" } }, - "required": [ - "text" - ] + "required": ["text"] } } } @@ -4898,9 +4749,7 @@ "type": "string" } }, - "required": [ - "command" - ] + "required": ["command"] } } } @@ -4953,12 +4802,7 @@ }, "variant": { "type": "string", - "enum": [ - "info", - "success", - "warning", - "error" - ] + "enum": ["info", "success", "warning", "error"] }, "duration": { "description": "Duration in milliseconds", @@ -4966,10 +4810,7 @@ "type": "number" } }, - "required": [ - "message", - "variant" - ] + "required": ["message", "variant"] } } } @@ -5072,10 +4913,7 @@ }, "body": {} }, - "required": [ - "path", - "body" - ] + "required": ["path", "body"] } } } @@ -5242,15 +5080,10 @@ "type": "string" } }, - "required": [ - "version" - ] + "required": ["version"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.installation.update-available": { "type": "object", @@ -5266,15 +5099,10 @@ "type": "string" } }, - "required": [ - "version" - ] + "required": ["version"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Project": { "type": "object", @@ -5316,17 +5144,10 @@ "type": "number" } }, - "required": [ - "created", - "updated" - ] + "required": ["created", "updated"] } }, - "required": [ - "id", - "worktree", - "time" - ] + "required": ["id", "worktree", "time"] }, "Event.project.updated": { "type": "object", @@ -5339,62 +5160,7 @@ "$ref": "#/components/schemas/Project" } }, - "required": [ - "type", - "properties" - ] - }, - "ConfigWarning": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "unknown_keybind" - ] - }, - "message": { - "type": "string" - }, - "keybinds": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "binding": { - "type": "string" - } - }, - "required": [ - "name", - "binding" - ] - } - } - }, - "required": [ - "type", - "message" - ] - }, - "Event.config.warning": { - "type": "object", - "properties": { - "type": { - "type": "string", - "const": "config.warning" - }, - "properties": { - "$ref": "#/components/schemas/ConfigWarning" - } - }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.server.instance.disposed": { "type": "object", @@ -5410,15 +5176,10 @@ "type": "string" } }, - "required": [ - "directory" - ] + "required": ["directory"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.lsp.client.diagnostics": { "type": "object", @@ -5437,16 +5198,10 @@ "type": "string" } }, - "required": [ - "serverID", - "path" - ] + "required": ["serverID", "path"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.lsp.updated": { "type": "object", @@ -5460,10 +5215,7 @@ "properties": {} } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "FileDiff": { "type": "object", @@ -5484,13 +5236,7 @@ "type": "number" } }, - "required": [ - "file", - "before", - "after", - "additions", - "deletions" - ] + "required": ["file", "before", "after", "additions", "deletions"] }, "UserMessage": { "type": "object", @@ -5512,9 +5258,7 @@ "type": "number" } }, - "required": [ - "created" - ] + "required": ["created"] }, "summary": { "type": "object", @@ -5532,9 +5276,7 @@ } } }, - "required": [ - "diffs" - ] + "required": ["diffs"] }, "agent": { "type": "string" @@ -5549,10 +5291,7 @@ "type": "string" } }, - "required": [ - "providerID", - "modelID" - ] + "required": ["providerID", "modelID"] }, "system": { "type": "string" @@ -5570,14 +5309,7 @@ "type": "string" } }, - "required": [ - "id", - "sessionID", - "role", - "time", - "agent", - "model" - ] + "required": ["id", "sessionID", "role", "time", "agent", "model"] }, "ProviderAuthError": { "type": "object", @@ -5596,16 +5328,10 @@ "type": "string" } }, - "required": [ - "providerID", - "message" - ] + "required": ["providerID", "message"] } }, - "required": [ - "name", - "data" - ] + "required": ["name", "data"] }, "UnknownError": { "type": "object", @@ -5621,15 +5347,10 @@ "type": "string" } }, - "required": [ - "message" - ] + "required": ["message"] } }, - "required": [ - "name", - "data" - ] + "required": ["name", "data"] }, "MessageOutputLengthError": { "type": "object", @@ -5643,10 +5364,7 @@ "properties": {} } }, - "required": [ - "name", - "data" - ] + "required": ["name", "data"] }, "MessageAbortedError": { "type": "object", @@ -5662,15 +5380,10 @@ "type": "string" } }, - "required": [ - "message" - ] + "required": ["message"] } }, - "required": [ - "name", - "data" - ] + "required": ["name", "data"] }, "APIError": { "type": "object", @@ -5713,16 +5426,10 @@ } } }, - "required": [ - "message", - "isRetryable" - ] + "required": ["message", "isRetryable"] } }, - "required": [ - "name", - "data" - ] + "required": ["name", "data"] }, "AssistantMessage": { "type": "object", @@ -5747,9 +5454,7 @@ "type": "number" } }, - "required": [ - "created" - ] + "required": ["created"] }, "error": { "anyOf": [ @@ -5795,10 +5500,7 @@ "type": "string" } }, - "required": [ - "cwd", - "root" - ] + "required": ["cwd", "root"] }, "summary": { "type": "boolean" @@ -5828,18 +5530,10 @@ "type": "number" } }, - "required": [ - "read", - "write" - ] + "required": ["read", "write"] } }, - "required": [ - "input", - "output", - "reasoning", - "cache" - ] + "required": ["input", "output", "reasoning", "cache"] }, "finish": { "type": "string" @@ -5884,15 +5578,10 @@ "$ref": "#/components/schemas/Message" } }, - "required": [ - "info" - ] + "required": ["info"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.message.removed": { "type": "object", @@ -5911,16 +5600,10 @@ "type": "string" } }, - "required": [ - "sessionID", - "messageID" - ] + "required": ["sessionID", "messageID"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "TextPart": { "type": "object", @@ -5957,9 +5640,7 @@ "type": "number" } }, - "required": [ - "start" - ] + "required": ["start"] }, "metadata": { "type": "object", @@ -5969,13 +5650,7 @@ "additionalProperties": {} } }, - "required": [ - "id", - "sessionID", - "messageID", - "type", - "text" - ] + "required": ["id", "sessionID", "messageID", "type", "text"] }, "ReasoningPart": { "type": "object", @@ -6013,19 +5688,10 @@ "type": "number" } }, - "required": [ - "start" - ] + "required": ["start"] } }, - "required": [ - "id", - "sessionID", - "messageID", - "type", - "text", - "time" - ] + "required": ["id", "sessionID", "messageID", "type", "text", "time"] }, "FilePartSourceText": { "type": "object", @@ -6044,11 +5710,7 @@ "maximum": 9007199254740991 } }, - "required": [ - "value", - "start", - "end" - ] + "required": ["value", "start", "end"] }, "FileSource": { "type": "object", @@ -6064,11 +5726,7 @@ "type": "string" } }, - "required": [ - "text", - "type", - "path" - ] + "required": ["text", "type", "path"] }, "Range": { "type": "object", @@ -6083,10 +5741,7 @@ "type": "number" } }, - "required": [ - "line", - "character" - ] + "required": ["line", "character"] }, "end": { "type": "object", @@ -6098,16 +5753,10 @@ "type": "number" } }, - "required": [ - "line", - "character" - ] + "required": ["line", "character"] } }, - "required": [ - "start", - "end" - ] + "required": ["start", "end"] }, "SymbolSource": { "type": "object", @@ -6134,14 +5783,7 @@ "maximum": 9007199254740991 } }, - "required": [ - "text", - "type", - "path", - "range", - "name", - "kind" - ] + "required": ["text", "type", "path", "range", "name", "kind"] }, "FilePartSource": { "anyOf": [ @@ -6182,14 +5824,7 @@ "$ref": "#/components/schemas/FilePartSource" } }, - "required": [ - "id", - "sessionID", - "messageID", - "type", - "mime", - "url" - ] + "required": ["id", "sessionID", "messageID", "type", "mime", "url"] }, "ToolStatePending": { "type": "object", @@ -6209,11 +5844,7 @@ "type": "string" } }, - "required": [ - "status", - "input", - "raw" - ] + "required": ["status", "input", "raw"] }, "ToolStateRunning": { "type": "object", @@ -6246,16 +5877,10 @@ "type": "number" } }, - "required": [ - "start" - ] + "required": ["start"] } }, - "required": [ - "status", - "input", - "time" - ] + "required": ["status", "input", "time"] }, "ToolStateCompleted": { "type": "object", @@ -6297,10 +5922,7 @@ "type": "number" } }, - "required": [ - "start", - "end" - ] + "required": ["start", "end"] }, "attachments": { "type": "array", @@ -6309,14 +5931,7 @@ } } }, - "required": [ - "status", - "input", - "output", - "title", - "metadata", - "time" - ] + "required": ["status", "input", "output", "title", "metadata", "time"] }, "ToolStateError": { "type": "object", @@ -6352,18 +5967,10 @@ "type": "number" } }, - "required": [ - "start", - "end" - ] + "required": ["start", "end"] } }, - "required": [ - "status", - "input", - "error", - "time" - ] + "required": ["status", "input", "error", "time"] }, "ToolState": { "anyOf": [ @@ -6414,15 +6021,7 @@ "additionalProperties": {} } }, - "required": [ - "id", - "sessionID", - "messageID", - "type", - "callID", - "tool", - "state" - ] + "required": ["id", "sessionID", "messageID", "type", "callID", "tool", "state"] }, "StepStartPart": { "type": "object", @@ -6444,12 +6043,7 @@ "type": "string" } }, - "required": [ - "id", - "sessionID", - "messageID", - "type" - ] + "required": ["id", "sessionID", "messageID", "type"] }, "StepFinishPart": { "type": "object", @@ -6498,29 +6092,13 @@ "type": "number" } }, - "required": [ - "read", - "write" - ] + "required": ["read", "write"] } }, - "required": [ - "input", - "output", - "reasoning", - "cache" - ] + "required": ["input", "output", "reasoning", "cache"] } }, - "required": [ - "id", - "sessionID", - "messageID", - "type", - "reason", - "cost", - "tokens" - ] + "required": ["id", "sessionID", "messageID", "type", "reason", "cost", "tokens"] }, "SnapshotPart": { "type": "object", @@ -6542,13 +6120,7 @@ "type": "string" } }, - "required": [ - "id", - "sessionID", - "messageID", - "type", - "snapshot" - ] + "required": ["id", "sessionID", "messageID", "type", "snapshot"] }, "PatchPart": { "type": "object", @@ -6576,14 +6148,7 @@ } } }, - "required": [ - "id", - "sessionID", - "messageID", - "type", - "hash", - "files" - ] + "required": ["id", "sessionID", "messageID", "type", "hash", "files"] }, "AgentPart": { "type": "object", @@ -6621,20 +6186,10 @@ "maximum": 9007199254740991 } }, - "required": [ - "value", - "start", - "end" - ] + "required": ["value", "start", "end"] } }, - "required": [ - "id", - "sessionID", - "messageID", - "type", - "name" - ] + "required": ["id", "sessionID", "messageID", "type", "name"] }, "RetryPart": { "type": "object", @@ -6665,20 +6220,10 @@ "type": "number" } }, - "required": [ - "created" - ] + "required": ["created"] } }, - "required": [ - "id", - "sessionID", - "messageID", - "type", - "attempt", - "error", - "time" - ] + "required": ["id", "sessionID", "messageID", "type", "attempt", "error", "time"] }, "CompactionPart": { "type": "object", @@ -6700,13 +6245,7 @@ "type": "boolean" } }, - "required": [ - "id", - "sessionID", - "messageID", - "type", - "auto" - ] + "required": ["id", "sessionID", "messageID", "type", "auto"] }, "Part": { "anyOf": [ @@ -6742,15 +6281,7 @@ "type": "string" } }, - "required": [ - "id", - "sessionID", - "messageID", - "type", - "prompt", - "description", - "agent" - ] + "required": ["id", "sessionID", "messageID", "type", "prompt", "description", "agent"] }, { "$ref": "#/components/schemas/ReasoningPart" @@ -6801,15 +6332,10 @@ "type": "string" } }, - "required": [ - "part" - ] + "required": ["part"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.message.part.removed": { "type": "object", @@ -6831,17 +6357,10 @@ "type": "string" } }, - "required": [ - "sessionID", - "messageID", - "partID" - ] + "required": ["sessionID", "messageID", "partID"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Permission": { "type": "object", @@ -6891,20 +6410,10 @@ "type": "number" } }, - "required": [ - "created" - ] + "required": ["created"] } }, - "required": [ - "id", - "type", - "sessionID", - "messageID", - "title", - "metadata", - "time" - ] + "required": ["id", "type", "sessionID", "messageID", "title", "metadata", "time"] }, "Event.permission.updated": { "type": "object", @@ -6917,10 +6426,7 @@ "$ref": "#/components/schemas/Permission" } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.permission.replied": { "type": "object", @@ -6942,17 +6448,10 @@ "type": "string" } }, - "required": [ - "sessionID", - "permissionID", - "response" - ] + "required": ["sessionID", "permissionID", "response"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.file.edited": { "type": "object", @@ -6968,15 +6467,10 @@ "type": "string" } }, - "required": [ - "file" - ] + "required": ["file"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Todo": { "type": "object", @@ -6998,12 +6492,7 @@ "type": "string" } }, - "required": [ - "content", - "status", - "priority", - "id" - ] + "required": ["content", "status", "priority", "id"] }, "Event.todo.updated": { "type": "object", @@ -7025,16 +6514,10 @@ } } }, - "required": [ - "sessionID", - "todos" - ] + "required": ["sessionID", "todos"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "SessionStatus": { "anyOf": [ @@ -7046,9 +6529,7 @@ "const": "idle" } }, - "required": [ - "type" - ] + "required": ["type"] }, { "type": "object", @@ -7067,12 +6548,7 @@ "type": "number" } }, - "required": [ - "type", - "attempt", - "message", - "next" - ] + "required": ["type", "attempt", "message", "next"] }, { "type": "object", @@ -7082,9 +6558,7 @@ "const": "busy" } }, - "required": [ - "type" - ] + "required": ["type"] } ] }, @@ -7105,16 +6579,10 @@ "$ref": "#/components/schemas/SessionStatus" } }, - "required": [ - "sessionID", - "status" - ] + "required": ["sessionID", "status"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.session.idle": { "type": "object", @@ -7130,15 +6598,10 @@ "type": "string" } }, - "required": [ - "sessionID" - ] + "required": ["sessionID"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.session.compacted": { "type": "object", @@ -7154,15 +6617,10 @@ "type": "string" } }, - "required": [ - "sessionID" - ] + "required": ["sessionID"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.tui.prompt.append": { "type": "object", @@ -7178,15 +6636,10 @@ "type": "string" } }, - "required": [ - "text" - ] + "required": ["text"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.tui.command.execute": { "type": "object", @@ -7225,15 +6678,10 @@ ] } }, - "required": [ - "command" - ] + "required": ["command"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.tui.toast.show": { "type": "object", @@ -7253,12 +6701,7 @@ }, "variant": { "type": "string", - "enum": [ - "info", - "success", - "warning", - "error" - ] + "enum": ["info", "success", "warning", "error"] }, "duration": { "description": "Duration in milliseconds", @@ -7266,16 +6709,10 @@ "type": "number" } }, - "required": [ - "message", - "variant" - ] + "required": ["message", "variant"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.mcp.tools.changed": { "type": "object", @@ -7291,15 +6728,10 @@ "type": "string" } }, - "required": [ - "server" - ] + "required": ["server"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.command.executed": { "type": "object", @@ -7326,18 +6758,10 @@ "pattern": "^msg.*" } }, - "required": [ - "name", - "sessionID", - "arguments", - "messageID" - ] + "required": ["name", "sessionID", "arguments", "messageID"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Session": { "type": "object", @@ -7375,11 +6799,7 @@ } } }, - "required": [ - "additions", - "deletions", - "files" - ] + "required": ["additions", "deletions", "files"] }, "share": { "type": "object", @@ -7388,9 +6808,7 @@ "type": "string" } }, - "required": [ - "url" - ] + "required": ["url"] }, "title": { "type": "string" @@ -7414,10 +6832,7 @@ "type": "number" } }, - "required": [ - "created", - "updated" - ] + "required": ["created", "updated"] }, "revert": { "type": "object", @@ -7435,19 +6850,10 @@ "type": "string" } }, - "required": [ - "messageID" - ] + "required": ["messageID"] } }, - "required": [ - "id", - "projectID", - "directory", - "title", - "version", - "time" - ] + "required": ["id", "projectID", "directory", "title", "version", "time"] }, "Event.session.created": { "type": "object", @@ -7463,15 +6869,10 @@ "$ref": "#/components/schemas/Session" } }, - "required": [ - "info" - ] + "required": ["info"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.session.updated": { "type": "object", @@ -7487,15 +6888,10 @@ "$ref": "#/components/schemas/Session" } }, - "required": [ - "info" - ] + "required": ["info"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.session.deleted": { "type": "object", @@ -7511,15 +6907,10 @@ "$ref": "#/components/schemas/Session" } }, - "required": [ - "info" - ] + "required": ["info"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.session.diff": { "type": "object", @@ -7541,16 +6932,10 @@ } } }, - "required": [ - "sessionID", - "diff" - ] + "required": ["sessionID", "diff"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.session.error": { "type": "object", @@ -7587,10 +6972,7 @@ } } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.file.watcher.updated": { "type": "object", @@ -7622,16 +7004,10 @@ ] } }, - "required": [ - "file", - "event" - ] + "required": ["file", "event"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.vcs.branch.updated": { "type": "object", @@ -7649,10 +7025,7 @@ } } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Pty": { "type": "object", @@ -7678,24 +7051,13 @@ }, "status": { "type": "string", - "enum": [ - "running", - "exited" - ] + "enum": ["running", "exited"] }, "pid": { "type": "number" } }, - "required": [ - "id", - "title", - "command", - "args", - "cwd", - "status", - "pid" - ] + "required": ["id", "title", "command", "args", "cwd", "status", "pid"] }, "Event.pty.created": { "type": "object", @@ -7711,15 +7073,10 @@ "$ref": "#/components/schemas/Pty" } }, - "required": [ - "info" - ] + "required": ["info"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.pty.updated": { "type": "object", @@ -7735,15 +7092,10 @@ "$ref": "#/components/schemas/Pty" } }, - "required": [ - "info" - ] + "required": ["info"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.pty.exited": { "type": "object", @@ -7763,16 +7115,10 @@ "type": "number" } }, - "required": [ - "id", - "exitCode" - ] + "required": ["id", "exitCode"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.pty.deleted": { "type": "object", @@ -7789,15 +7135,10 @@ "pattern": "^pty.*" } }, - "required": [ - "id" - ] + "required": ["id"] } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.server.connected": { "type": "object", @@ -7811,10 +7152,7 @@ "properties": {} } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event.global.disposed": { "type": "object", @@ -7828,10 +7166,7 @@ "properties": {} } }, - "required": [ - "type", - "properties" - ] + "required": ["type", "properties"] }, "Event": { "anyOf": [ @@ -7844,9 +7179,6 @@ { "$ref": "#/components/schemas/Event.project.updated" }, - { - "$ref": "#/components/schemas/Event.config.warning" - }, { "$ref": "#/components/schemas/Event.server.instance.disposed" }, @@ -7955,10 +7287,7 @@ "$ref": "#/components/schemas/Event" } }, - "required": [ - "directory", - "payload" - ] + "required": ["directory", "payload"] }, "BadRequestError": { "type": "object", @@ -7979,11 +7308,7 @@ "const": false } }, - "required": [ - "data", - "errors", - "success" - ] + "required": ["data", "errors", "success"] }, "NotFoundError": { "type": "object", @@ -7999,15 +7324,10 @@ "type": "string" } }, - "required": [ - "message" - ] + "required": ["message"] } }, - "required": [ - "name", - "data" - ] + "required": ["name", "data"] }, "KeybindsConfig": { "description": "Custom keybind configurations", @@ -8454,12 +7774,7 @@ "LogLevel": { "description": "Log level", "type": "string", - "enum": [ - "DEBUG", - "INFO", - "WARN", - "ERROR" - ] + "enum": ["DEBUG", "INFO", "WARN", "ERROR"] }, "ServerConfig": { "description": "Server configuration for opencode serve and web commands", @@ -8522,11 +7837,7 @@ }, "mode": { "type": "string", - "enum": [ - "subagent", - "primary", - "all" - ] + "enum": ["subagent", "primary", "all"] }, "color": { "description": "Hex color code for the agent (e.g., #FF5733)", @@ -8544,21 +7855,13 @@ "properties": { "edit": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, "bash": { "anyOf": [ { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, { "type": "object", @@ -8567,11 +7870,7 @@ }, "additionalProperties": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] } } ] @@ -8580,11 +7879,7 @@ "anyOf": [ { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, { "type": "object", @@ -8593,38 +7888,22 @@ }, "additionalProperties": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] } } ] }, "webfetch": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, "doom_loop": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, "external_directory": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] } } } @@ -8695,15 +7974,10 @@ "properties": { "field": { "type": "string", - "enum": [ - "reasoning_content", - "reasoning_details" - ] + "enum": ["reasoning_content", "reasoning_details"] } }, - "required": [ - "field" - ], + "required": ["field"], "additionalProperties": false } ] @@ -8739,16 +8013,10 @@ "type": "number" } }, - "required": [ - "input", - "output" - ] + "required": ["input", "output"] } }, - "required": [ - "input", - "output" - ] + "required": ["input", "output"] }, "limit": { "type": "object", @@ -8760,10 +8028,7 @@ "type": "number" } }, - "required": [ - "context", - "output" - ] + "required": ["context", "output"] }, "modalities": { "type": "object", @@ -8772,44 +8037,25 @@ "type": "array", "items": { "type": "string", - "enum": [ - "text", - "audio", - "image", - "video", - "pdf" - ] + "enum": ["text", "audio", "image", "video", "pdf"] } }, "output": { "type": "array", "items": { "type": "string", - "enum": [ - "text", - "audio", - "image", - "video", - "pdf" - ] + "enum": ["text", "audio", "image", "video", "pdf"] } } }, - "required": [ - "input", - "output" - ] + "required": ["input", "output"] }, "experimental": { "type": "boolean" }, "status": { "type": "string", - "enum": [ - "alpha", - "beta", - "deprecated" - ] + "enum": ["alpha", "beta", "deprecated"] }, "options": { "type": "object", @@ -8834,9 +8080,7 @@ "type": "string" } }, - "required": [ - "npm" - ] + "required": ["npm"] }, "variants": { "description": "Variant-specific configuration", @@ -8945,10 +8189,7 @@ "maximum": 9007199254740991 } }, - "required": [ - "type", - "command" - ], + "required": ["type", "command"], "additionalProperties": false }, "McpOAuthConfig": { @@ -9014,19 +8255,13 @@ "maximum": 9007199254740991 } }, - "required": [ - "type", - "url" - ], + "required": ["type", "url"], "additionalProperties": false }, "LayoutConfig": { "description": "@deprecated Always uses stretch layout.", "type": "string", - "enum": [ - "auto", - "stretch" - ] + "enum": ["auto", "stretch"] }, "Config": { "type": "object", @@ -9063,17 +8298,12 @@ "type": "boolean" } }, - "required": [ - "enabled" - ] + "required": ["enabled"] }, "diff_style": { "description": "Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column", "type": "string", - "enum": [ - "auto", - "stacked" - ] + "enum": ["auto", "stacked"] } } }, @@ -9105,9 +8335,7 @@ "type": "boolean" } }, - "required": [ - "template" - ] + "required": ["template"] } }, "watcher": { @@ -9133,11 +8361,7 @@ "share": { "description": "Control sharing behavior:'manual' allows manual sharing via commands, 'auto' enables automatic sharing, 'disabled' disables all sharing", "type": "string", - "enum": [ - "manual", - "auto", - "disabled" - ] + "enum": ["manual", "auto", "disabled"] }, "autoshare": { "description": "@deprecated Use 'share' field instead. Share newly created sessions automatically", @@ -9321,9 +8545,7 @@ "const": true } }, - "required": [ - "disabled" - ] + "required": ["disabled"] }, { "type": "object", @@ -9360,9 +8582,7 @@ "additionalProperties": {} } }, - "required": [ - "command" - ] + "required": ["command"] } ] } @@ -9384,21 +8604,13 @@ "properties": { "edit": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, "bash": { "anyOf": [ { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, { "type": "object", @@ -9407,11 +8619,7 @@ }, "additionalProperties": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] } } ] @@ -9420,11 +8628,7 @@ "anyOf": [ { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, { "type": "object", @@ -9433,38 +8637,22 @@ }, "additionalProperties": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] } } ] }, "webfetch": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, "doom_loop": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, "external_directory": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] } } }, @@ -9531,9 +8719,7 @@ } } }, - "required": [ - "command" - ] + "required": ["command"] } } }, @@ -9558,9 +8744,7 @@ } } }, - "required": [ - "command" - ] + "required": ["command"] } } } @@ -9619,11 +8803,7 @@ }, "parameters": {} }, - "required": [ - "id", - "description", - "parameters" - ] + "required": ["id", "description", "parameters"] }, "ToolList": { "type": "array", @@ -9650,13 +8830,7 @@ "type": "string" } }, - "required": [ - "home", - "state", - "config", - "worktree", - "directory" - ] + "required": ["home", "state", "config", "worktree", "directory"] }, "VcsInfo": { "type": "object", @@ -9665,9 +8839,7 @@ "type": "string" } }, - "required": [ - "branch" - ] + "required": ["branch"] }, "TextPartInput": { "type": "object", @@ -9698,9 +8870,7 @@ "type": "number" } }, - "required": [ - "start" - ] + "required": ["start"] }, "metadata": { "type": "object", @@ -9710,10 +8880,7 @@ "additionalProperties": {} } }, - "required": [ - "type", - "text" - ] + "required": ["type", "text"] }, "FilePartInput": { "type": "object", @@ -9738,11 +8905,7 @@ "$ref": "#/components/schemas/FilePartSource" } }, - "required": [ - "type", - "mime", - "url" - ] + "required": ["type", "mime", "url"] }, "AgentPartInput": { "type": "object", @@ -9774,17 +8937,10 @@ "maximum": 9007199254740991 } }, - "required": [ - "value", - "start", - "end" - ] + "required": ["value", "start", "end"] } }, - "required": [ - "type", - "name" - ] + "required": ["type", "name"] }, "SubtaskPartInput": { "type": "object", @@ -9809,12 +8965,7 @@ "type": "string" } }, - "required": [ - "type", - "prompt", - "description", - "agent" - ] + "required": ["type", "prompt", "description", "agent"] }, "Command": { "type": "object", @@ -9854,11 +9005,7 @@ } } }, - "required": [ - "name", - "template", - "hints" - ] + "required": ["name", "template", "hints"] }, "Model": { "type": "object", @@ -9882,11 +9029,7 @@ "type": "string" } }, - "required": [ - "id", - "url", - "npm" - ] + "required": ["id", "url", "npm"] }, "name": { "type": "string" @@ -9928,13 +9071,7 @@ "type": "boolean" } }, - "required": [ - "text", - "audio", - "image", - "video", - "pdf" - ] + "required": ["text", "audio", "image", "video", "pdf"] }, "output": { "type": "object", @@ -9955,13 +9092,7 @@ "type": "boolean" } }, - "required": [ - "text", - "audio", - "image", - "video", - "pdf" - ] + "required": ["text", "audio", "image", "video", "pdf"] }, "interleaved": { "anyOf": [ @@ -9973,28 +9104,15 @@ "properties": { "field": { "type": "string", - "enum": [ - "reasoning_content", - "reasoning_details" - ] + "enum": ["reasoning_content", "reasoning_details"] } }, - "required": [ - "field" - ] + "required": ["field"] } ] } }, - "required": [ - "temperature", - "reasoning", - "attachment", - "toolcall", - "input", - "output", - "interleaved" - ] + "required": ["temperature", "reasoning", "attachment", "toolcall", "input", "output", "interleaved"] }, "cost": { "type": "object", @@ -10015,10 +9133,7 @@ "type": "number" } }, - "required": [ - "read", - "write" - ] + "required": ["read", "write"] }, "experimentalOver200K": { "type": "object", @@ -10039,24 +9154,13 @@ "type": "number" } }, - "required": [ - "read", - "write" - ] + "required": ["read", "write"] } }, - "required": [ - "input", - "output", - "cache" - ] + "required": ["input", "output", "cache"] } }, - "required": [ - "input", - "output", - "cache" - ] + "required": ["input", "output", "cache"] }, "limit": { "type": "object", @@ -10068,19 +9172,11 @@ "type": "number" } }, - "required": [ - "context", - "output" - ] + "required": ["context", "output"] }, "status": { "type": "string", - "enum": [ - "alpha", - "beta", - "deprecated", - "active" - ] + "enum": ["alpha", "beta", "deprecated", "active"] }, "options": { "type": "object", @@ -10140,12 +9236,7 @@ }, "source": { "type": "string", - "enum": [ - "env", - "config", - "custom", - "api" - ] + "enum": ["env", "config", "custom", "api"] }, "env": { "type": "array", @@ -10173,14 +9264,7 @@ } } }, - "required": [ - "id", - "name", - "source", - "env", - "options", - "models" - ] + "required": ["id", "name", "source", "env", "options", "models"] }, "ProviderAuthMethod": { "type": "object", @@ -10201,10 +9285,7 @@ "type": "string" } }, - "required": [ - "type", - "label" - ] + "required": ["type", "label"] }, "ProviderAuthAuthorization": { "type": "object", @@ -10228,11 +9309,7 @@ "type": "string" } }, - "required": [ - "url", - "method", - "instructions" - ] + "required": ["url", "method", "instructions"] }, "Symbol": { "type": "object", @@ -10253,17 +9330,10 @@ "$ref": "#/components/schemas/Range" } }, - "required": [ - "uri", - "range" - ] + "required": ["uri", "range"] } }, - "required": [ - "name", - "kind", - "location" - ] + "required": ["name", "kind", "location"] }, "FileNode": { "type": "object", @@ -10279,22 +9349,13 @@ }, "type": { "type": "string", - "enum": [ - "file", - "directory" - ] + "enum": ["file", "directory"] }, "ignored": { "type": "boolean" } }, - "required": [ - "name", - "path", - "absolute", - "type", - "ignored" - ] + "required": ["name", "path", "absolute", "type", "ignored"] }, "FileContent": { "type": "object", @@ -10348,24 +9409,14 @@ } } }, - "required": [ - "oldStart", - "oldLines", - "newStart", - "newLines", - "lines" - ] + "required": ["oldStart", "oldLines", "newStart", "newLines", "lines"] } }, "index": { "type": "string" } }, - "required": [ - "oldFileName", - "newFileName", - "hunks" - ] + "required": ["oldFileName", "newFileName", "hunks"] }, "encoding": { "type": "string", @@ -10375,10 +9426,7 @@ "type": "string" } }, - "required": [ - "type", - "content" - ] + "required": ["type", "content"] }, "File": { "type": "object", @@ -10398,19 +9446,10 @@ }, "status": { "type": "string", - "enum": [ - "added", - "deleted", - "modified" - ] + "enum": ["added", "deleted", "modified"] } }, - "required": [ - "path", - "added", - "removed", - "status" - ] + "required": ["path", "added", "removed", "status"] }, "Agent": { "type": "object", @@ -10423,11 +9462,7 @@ }, "mode": { "type": "string", - "enum": [ - "subagent", - "primary", - "all" - ] + "enum": ["subagent", "primary", "all"] }, "native": { "type": "boolean" @@ -10452,11 +9487,7 @@ "properties": { "edit": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, "bash": { "type": "object", @@ -10465,11 +9496,7 @@ }, "additionalProperties": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] } }, "skill": { @@ -10479,43 +9506,23 @@ }, "additionalProperties": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] } }, "webfetch": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, "doom_loop": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] }, "external_directory": { "type": "string", - "enum": [ - "ask", - "allow", - "deny" - ] + "enum": ["ask", "allow", "deny"] } }, - "required": [ - "edit", - "bash", - "skill" - ] + "required": ["edit", "bash", "skill"] }, "model": { "type": "object", @@ -10527,10 +9534,7 @@ "type": "string" } }, - "required": [ - "modelID", - "providerID" - ] + "required": ["modelID", "providerID"] }, "prompt": { "type": "string" @@ -10557,13 +9561,7 @@ "maximum": 9007199254740991 } }, - "required": [ - "name", - "mode", - "permission", - "tools", - "options" - ] + "required": ["name", "mode", "permission", "tools", "options"] }, "MCPStatusConnected": { "type": "object", @@ -10573,9 +9571,7 @@ "const": "connected" } }, - "required": [ - "status" - ] + "required": ["status"] }, "MCPStatusDisabled": { "type": "object", @@ -10585,9 +9581,7 @@ "const": "disabled" } }, - "required": [ - "status" - ] + "required": ["status"] }, "MCPStatusFailed": { "type": "object", @@ -10600,10 +9594,7 @@ "type": "string" } }, - "required": [ - "status", - "error" - ] + "required": ["status", "error"] }, "MCPStatusNeedsAuth": { "type": "object", @@ -10613,9 +9604,7 @@ "const": "needs_auth" } }, - "required": [ - "status" - ] + "required": ["status"] }, "MCPStatusNeedsClientRegistration": { "type": "object", @@ -10628,10 +9617,7 @@ "type": "string" } }, - "required": [ - "status", - "error" - ] + "required": ["status", "error"] }, "MCPStatus": { "anyOf": [ @@ -10677,12 +9663,7 @@ ] } }, - "required": [ - "id", - "name", - "root", - "status" - ] + "required": ["id", "name", "root", "status"] }, "FormatterStatus": { "type": "object", @@ -10700,11 +9681,7 @@ "type": "boolean" } }, - "required": [ - "name", - "extensions", - "enabled" - ] + "required": ["name", "extensions", "enabled"] }, "OAuth": { "type": "object", @@ -10726,12 +9703,7 @@ "type": "string" } }, - "required": [ - "type", - "refresh", - "access", - "expires" - ] + "required": ["type", "refresh", "access", "expires"] }, "ApiAuth": { "type": "object", @@ -10744,10 +9716,7 @@ "type": "string" } }, - "required": [ - "type", - "key" - ] + "required": ["type", "key"] }, "WellKnownAuth": { "type": "object", @@ -10763,11 +9732,7 @@ "type": "string" } }, - "required": [ - "type", - "key", - "token" - ] + "required": ["type", "key", "token"] }, "Auth": { "anyOf": [ @@ -10784,4 +9749,4 @@ } } } -} \ No newline at end of file +} From 557390a23ba7bf158bcaf8421b93db3b229e141c Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Thu, 1 Jan 2026 18:37:42 -0500 Subject: [PATCH 13/15] fix: add ConfigWarning schema to openapi.json for SDK compatibility --- packages/sdk/openapi.json | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 973c217fd18..044548dcc09 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -5162,6 +5162,47 @@ }, "required": ["type", "properties"] }, + "ConfigWarning": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["unknown_keybind"] + }, + "message": { + "type": "string" + }, + "keybinds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "binding": { + "type": "string" + } + }, + "required": ["name", "binding"] + } + } + }, + "required": ["type", "message"] + }, + "Event.config.warning": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "config.warning" + }, + "properties": { + "$ref": "#/components/schemas/ConfigWarning" + } + }, + "required": ["type", "properties"] + }, "Event.server.instance.disposed": { "type": "object", "properties": { @@ -7179,6 +7220,9 @@ { "$ref": "#/components/schemas/Event.project.updated" }, + { + "$ref": "#/components/schemas/Event.config.warning" + }, { "$ref": "#/components/schemas/Event.server.instance.disposed" }, From 9fba8a100d39e9cce9d2c5ced87c4af4ecf6907c Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 7 Jan 2026 19:13:42 -0500 Subject: [PATCH 14/15] Remove duplicate code in config.ts --- packages/opencode/src/config/config.ts | 41 ++------------------------ 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 3592d396b18..df4192f2453 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -91,31 +91,10 @@ export const state = Instance.state(async () => { log.debug("loaded custom config from OPENCODE_CONFIG_CONTENT") } - // Load remote/well-known config first as the base layer (lowest precedence) - // This allows organizations to provide default configs that users can override - let result: Info = {} - for (const [key, value] of Object.entries(auth)) { - if (value.type === "wellknown") { - process.env[value.key] = value.token - log.debug("fetching remote config", { url: `${key}/.well-known/opencode` }) - const response = await fetch(`${key}/.well-known/opencode`) - if (!response.ok) { - throw new Error(`failed to fetch remote config from ${key}: ${response.status}`) - } - const wellknown = (await response.json()) as any - const remoteConfig = wellknown.config ?? {} - // Add $schema to prevent load() from trying to write back to a non-existent file - if (!remoteConfig.$schema) remoteConfig.$schema = "https://opencode.ai/config.json" - result = mergeConfigConcatArrays( - result, - await load(JSON.stringify(remoteConfig), `${key}/.well-known/opencode`), - ) - log.debug("loaded remote config from well-known", { url: key }) - } - } - // Global user config overrides remote config - result = mergeConfigConcatArrays(result, await global()) + const globalResult = await global() + result = mergeConfigConcatArrays(result, globalResult.config) + allUnknownKeybinds.push(...globalResult.unknownKeybinds) // Custom config path overrides global if (Flag.OPENCODE_CONFIG) { @@ -140,20 +119,6 @@ export const state = Instance.state(async () => { result = mergeConfigConcatArrays(result, JSON.parse(Flag.OPENCODE_CONFIG_CONTENT)) log.debug("loaded custom config from OPENCODE_CONFIG_CONTENT") } - -<<<<<<< HEAD - for (const [key, value] of Object.entries(auth)) { - if (value.type === "wellknown") { - process.env[value.key] = value.token - const wellknown = (await fetch(`${key}/.well-known/opencode`).then((x) => x.json())) as any - const loaded = await load(JSON.stringify(wellknown.config ?? {}), process.cwd()) - result = mergeConfigConcatArrays(result, loaded.config) - allUnknownKeybinds.push(...loaded.unknownKeybinds) - } - } - -======= ->>>>>>> dev result.agent = result.agent || {} result.mode = result.mode || {} result.plugin = result.plugin || [] From 7cd5bd09b70007fa4381f27910443e4e1adf1bfb Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Wed, 7 Jan 2026 19:17:12 -0500 Subject: [PATCH 15/15] Remove duplicate config loading code --- packages/opencode/src/config/config.ts | 29 -------------------------- 1 file changed, 29 deletions(-) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index df4192f2453..53590a94d9d 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -85,35 +85,6 @@ export const state = Instance.state(async () => { } } - // Inline config content has highest precedence - if (Flag.OPENCODE_CONFIG_CONTENT) { - result = mergeConfigConcatArrays(result, JSON.parse(Flag.OPENCODE_CONFIG_CONTENT)) - log.debug("loaded custom config from OPENCODE_CONFIG_CONTENT") - } - - // Global user config overrides remote config - const globalResult = await global() - result = mergeConfigConcatArrays(result, globalResult.config) - allUnknownKeybinds.push(...globalResult.unknownKeybinds) - - // Custom config path overrides global - if (Flag.OPENCODE_CONFIG) { - const loaded = await loadFile(Flag.OPENCODE_CONFIG) - result = mergeConfigConcatArrays(result, loaded.config) - allUnknownKeybinds.push(...loaded.unknownKeybinds) - log.debug("loaded custom config", { path: Flag.OPENCODE_CONFIG }) - } - - // Project config has highest precedence (overrides global and remote) - for (const file of ["opencode.jsonc", "opencode.json"]) { - const found = await Filesystem.findUp(file, Instance.directory, Instance.worktree) - for (const resolved of found.toReversed()) { - const loaded = await loadFile(resolved) - result = mergeConfigConcatArrays(result, loaded.config) - allUnknownKeybinds.push(...loaded.unknownKeybinds) - } - } - // Inline config content has highest precedence if (Flag.OPENCODE_CONFIG_CONTENT) { result = mergeConfigConcatArrays(result, JSON.parse(Flag.OPENCODE_CONFIG_CONTENT))