diff --git a/packages/kilo-console/src/routes/projects/terminal/GhosttyTerminal.tsx b/packages/kilo-console/src/routes/projects/terminal/GhosttyTerminal.tsx
index c1df440817..187c21c0f1 100644
--- a/packages/kilo-console/src/routes/projects/terminal/GhosttyTerminal.tsx
+++ b/packages/kilo-console/src/routes/projects/terminal/GhosttyTerminal.tsx
@@ -70,12 +70,44 @@ function rect(view: View, x: number, y: number, w: number, h: number) {
view.ctx.fillRect(left, top, right - left, bottom - top)
}
+function sextant(view: View, mask: number, x: number, y: number, w: number, h: number) {
+ const sw = w / 2
+ const sh = h / 3
+
+ for (const n of [1, 2, 3, 4, 5, 6]) {
+ if (!(mask & (1 << (n - 1)))) continue
+ const dx = n % 2 === 1 ? 0 : sw
+ const dy = Math.floor((n - 1) / 2) * sh
+ rect(view, x + dx, y + dy, sw, sh)
+ }
+}
+
function fill(view: View, cp: number, x: number, y: number, w: number, h: number) {
const ew = w / 8
const eh = h / 8
const hw = w / 2
const hh = h / 2
+ if (cp === 0x1fb01) {
+ sextant(view, 0b000010, x, y, w, h)
+ return true
+ }
+
+ if (cp === 0x1fb0f) {
+ sextant(view, 0b010000, x, y, w, h)
+ return true
+ }
+
+ if (cp === 0x1fb2c) {
+ sextant(view, 0b101111, x, y, w, h)
+ return true
+ }
+
+ if (cp === 0x1fb3a) {
+ sextant(view, 0b111101, x, y, w, h)
+ return true
+ }
+
if (cp >= 0x2581 && cp <= 0x2587) {
const n = cp - 0x2580
rect(view, x, y + h - eh * n, w, eh * n)
@@ -187,9 +219,11 @@ function patch(renderer: Terminal["renderer"]) {
view.renderCellText = (cell, x, y, over) => {
if (
!(cell.flags & CellFlags.INVISIBLE) &&
- cell.grapheme_len === 0 &&
- cell.codepoint >= 0x2580 &&
- cell.codepoint <= 0x259f
+ ((cell.codepoint >= 0x2580 && cell.codepoint <= 0x259f) ||
+ cell.codepoint === 0x1fb01 ||
+ cell.codepoint === 0x1fb0f ||
+ cell.codepoint === 0x1fb2c ||
+ cell.codepoint === 0x1fb3a)
) {
const w = view.metrics.width * cell.width
const h = view.metrics.height
@@ -244,7 +278,8 @@ export function GhosttyTerminal(props: { query: Query; pty: string; active?: boo
cols: 100,
rows: 30,
cursorBlink: true,
- fontFamily: "'FiraCode Nerd Font', 'FiraCode Nerd Font Mono', 'Fira Code', Menlo, Monaco, 'Courier New', monospace",
+ fontFamily:
+ "'FiraCode Nerd Font', 'FiraCode Nerd Font Mono', 'Fira Code', Menlo, Monaco, 'Courier New', monospace",
fontSize: Math.max(14, px(host, "--font-size-base", 14)),
scrollback: 5000,
theme: theme(host),
@@ -323,9 +358,7 @@ export function GhosttyTerminal(props: { query: Query; pty: string; active?: boo
return (
-
- {(msg) => {msg()}
}
-
+
{(msg) => {msg()}
}
)
}
diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts
index 5d45570b4a..996ac084e9 100644
--- a/packages/opencode/src/cli/cmd/tui/thread.ts
+++ b/packages/opencode/src/cli/cmd/tui/thread.ts
@@ -89,7 +89,7 @@ export function resolveThreadDirectory(project?: string, envPWD = process.env.PW
const root = envPWD && Filesystem.resolve(envPWD) === real ? Filesystem.resolve(envPWD) : real
// kilocode_change end
if (project) return Filesystem.resolve(path.isAbsolute(project) ? project : path.join(root, project))
- return real
+ return real // kilocode_change
}
export const TuiThreadCommand = cmd({
@@ -363,7 +363,7 @@ export const TuiThreadCommand = cmd({
try {
await validateSession({
- url: transport.url,
+ url: transport.url, // kilocode_change
sessionID: args.session,
directory: cwd,
fetch: transport.fetch,
@@ -398,9 +398,8 @@ export const TuiThreadCommand = cmd({
}
// kilocode_change end
- await start({
- // kilocode_change
- url: transport.url,
+ await start({ // kilocode_change
+ url: transport.url, // kilocode_change
async onSnapshot() {
const tui = writeHeapSnapshot("tui.heapsnapshot")
const server = await client.call("snapshot", undefined)
diff --git a/packages/opencode/src/config/mcp.ts b/packages/opencode/src/config/mcp.ts
index f72b7c0ab4..3f7d2f4657 100644
--- a/packages/opencode/src/config/mcp.ts
+++ b/packages/opencode/src/config/mcp.ts
@@ -31,8 +31,14 @@ const LocalInput = Schema.Struct({
})
const normalizeLocal = (input: Schema.Schema.Type): Schema.Schema.Type => {
- const { env, environment, ...rest } = input
- return { ...rest, environment: environment ?? env }
+ const env = input.environment ?? input.env
+ return {
+ type: input.type,
+ command: input.command,
+ ...(env === undefined ? {} : { environment: env }),
+ ...("enabled" in input ? { enabled: input.enabled } : {}),
+ ...("timeout" in input ? { timeout: input.timeout } : {}),
+ }
}
export const Local = LocalInput.pipe(
diff --git a/packages/opencode/src/kilocode/server/httpapi/groups/agent-builder.ts b/packages/opencode/src/kilocode/server/httpapi/groups/agent-builder.ts
new file mode 100644
index 0000000000..bc2c9ad258
--- /dev/null
+++ b/packages/opencode/src/kilocode/server/httpapi/groups/agent-builder.ts
@@ -0,0 +1,77 @@
+import { Authorization } from "@/server/routes/instance/httpapi/middleware/authorization"
+import { InstanceContextMiddleware } from "@/server/routes/instance/httpapi/middleware/instance-context"
+import { WorkspaceRoutingMiddleware } from "@/server/routes/instance/httpapi/middleware/workspace-routing"
+import { described } from "@/server/routes/instance/httpapi/groups/metadata"
+import { Schema } from "effect"
+import { HttpApi, HttpApiEndpoint, HttpApiError, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
+
+const Scope = Schema.Literals(["global", "project"])
+const Mode = Schema.Literals(["primary", "subagent", "all"])
+export const AgentBuilderID = Schema.String
+const Body = {
+ scope: Schema.optional(Scope),
+ description: Schema.optional(Schema.String),
+ mode: Schema.optional(Mode),
+ model: Schema.optional(Schema.String),
+ color: Schema.optional(Schema.String),
+ steps: Schema.optional(Schema.Number),
+ tools: Schema.optional(Schema.Array(Schema.String)),
+ permission: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
+ prompt: Schema.String,
+}
+
+export const AgentBuilderInput = Schema.Struct({ id: AgentBuilderID, ...Body })
+export const AgentBuilderSaveInput = Schema.Struct({ id: Schema.optional(AgentBuilderID), ...Body })
+export const AgentBuilderOutput = Schema.Struct({
+ id: AgentBuilderID,
+ scope: Scope,
+ path: Schema.String,
+ markdown: Schema.String,
+})
+
+export const AgentBuilderPaths = {
+ preview: "/agent-builder/preview",
+ save: "/agent-builder/:id",
+} as const
+
+export const AgentBuilderApi = HttpApi.make("agent-builder")
+ .add(
+ HttpApiGroup.make("agent-builder")
+ .add(
+ HttpApiEndpoint.post("preview", AgentBuilderPaths.preview, {
+ payload: AgentBuilderInput,
+ success: described(AgentBuilderOutput, "Agent markdown preview"),
+ error: HttpApiError.BadRequest,
+ }).annotateMerge(
+ OpenApi.annotations({
+ identifier: "agentBuilder.preview",
+ summary: "Preview agent markdown",
+ description:
+ "Validate an agent builder payload and return the canonical agent markdown without writing it.",
+ }),
+ ),
+ HttpApiEndpoint.put("save", AgentBuilderPaths.save, {
+ params: { id: AgentBuilderID },
+ payload: AgentBuilderSaveInput,
+ success: described(AgentBuilderOutput, "Saved agent markdown"),
+ error: HttpApiError.BadRequest,
+ }).annotateMerge(
+ OpenApi.annotations({
+ identifier: "agentBuilder.save",
+ summary: "Save agent markdown",
+ description: "Save an agent builder payload as a canonical agent markdown file.",
+ }),
+ ),
+ )
+ .annotateMerge(OpenApi.annotations({ title: "agent-builder", description: "Kilo agent builder routes." }))
+ .middleware(InstanceContextMiddleware)
+ .middleware(WorkspaceRoutingMiddleware)
+ .middleware(Authorization),
+ )
+ .annotateMerge(
+ OpenApi.annotations({
+ title: "kilo HttpApi",
+ version: "0.0.1",
+ description: "Kilo HttpApi surface.",
+ }),
+ )
diff --git a/packages/opencode/src/kilocode/server/httpapi/groups/config-console.ts b/packages/opencode/src/kilocode/server/httpapi/groups/config-console.ts
new file mode 100644
index 0000000000..0aa0d759c2
--- /dev/null
+++ b/packages/opencode/src/kilocode/server/httpapi/groups/config-console.ts
@@ -0,0 +1,188 @@
+import { Config } from "@/config/config"
+import { ConfigPlugin } from "@/config/plugin"
+import { Authorization } from "@/server/routes/instance/httpapi/middleware/authorization"
+import { InstanceContextMiddleware } from "@/server/routes/instance/httpapi/middleware/instance-context"
+import { WorkspaceRoutingMiddleware } from "@/server/routes/instance/httpapi/middleware/workspace-routing"
+import { described } from "@/server/routes/instance/httpapi/groups/metadata"
+import { Schema } from "effect"
+import { HttpApi, HttpApiEndpoint, HttpApiError, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
+
+const Scope = Schema.Literals(["global", "project"])
+const Origin = Schema.Literals(["project", "global", "system", "default"])
+const UnknownRecord = Schema.Record(Schema.String, Schema.Unknown)
+const ModelRef = Schema.Struct({ providerID: Schema.String, modelID: Schema.String })
+const Resolved = Schema.Struct({
+ key: Schema.String,
+ path: Schema.Array(Schema.String),
+ value: Schema.optional(Schema.Unknown),
+ global: Schema.optional(Schema.Unknown),
+ local: Schema.optional(Schema.Unknown),
+ source: Origin,
+ inherited: Schema.Boolean,
+ overridden: Schema.Boolean,
+ editable: Schema.Boolean,
+ reason: Schema.optional(Schema.String),
+})
+const Source = Schema.Struct({
+ order: Schema.Number,
+ kind: Schema.String,
+ scope: Schema.String,
+ label: Schema.String,
+ source: Schema.String,
+ path: Schema.optional(Schema.String),
+ exists: Schema.Boolean,
+ editable: Schema.Boolean,
+ reason: Schema.optional(Schema.String),
+})
+
+export const ConfigOverlayQuery = Schema.Struct({ scope: Schema.optional(Scope) })
+export const ConfigOverlayPatch = Schema.Struct({
+ scope: Schema.optional(Scope),
+ set: Schema.optional(UnknownRecord),
+ unset: Schema.optional(Schema.Array(Schema.Array(Schema.String))),
+})
+export const ConfigOverlayResponse = Schema.Struct({
+ scope: Scope,
+ effective: Config.Info,
+ global: Config.Info,
+ project: Config.Info,
+ sources: Schema.Array(Source),
+ targets: Schema.Struct({
+ global: Schema.optional(Schema.String),
+ project: Schema.optional(Schema.String),
+ active: Schema.optional(Schema.String),
+ }),
+ fields: Schema.Record(Schema.String, Resolved),
+ collections: Schema.Record(Schema.String, Schema.Array(Resolved)),
+}).annotate({ identifier: "ConfigOverlayResponse" })
+export const ConfigSourcesResponse = Schema.Struct({ sources: Schema.Array(Source) }).annotate({
+ identifier: "ConfigSourcesResponse",
+})
+export const ConfigModelStatePatch = Schema.Struct({ favorite: Schema.optional(Schema.Array(ModelRef)) })
+export const ConfigModelStateResponse = Schema.Struct({
+ model: Schema.Record(Schema.String, ModelRef),
+ recent: Schema.Array(ModelRef),
+ favorite: Schema.Array(ModelRef),
+ variant: Schema.Record(Schema.String, Schema.String),
+}).annotate({ identifier: "ConfigModelStateResponse" })
+
+export const TuiConfigQuery = Schema.Struct({ scope: Schema.optional(Scope) })
+const TuiConfigShape = {
+ $schema: Schema.optional(Schema.String),
+ theme: Schema.optional(Schema.String),
+ keybinds: Schema.optional(Schema.Record(Schema.String, Schema.UndefinedOr(Schema.String))),
+ plugin: Schema.optional(Schema.Array(ConfigPlugin.Spec)),
+ plugin_enabled: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)),
+ scroll_speed: Schema.optional(Schema.Number),
+ scroll_acceleration: Schema.optional(Schema.Struct({ enabled: Schema.Boolean })),
+ diff_style: Schema.optional(Schema.Literals(["auto", "stacked"])),
+ mouse: Schema.optional(Schema.Boolean),
+}
+export const TuiConfigResponse = Schema.Struct(TuiConfigShape).annotate({ identifier: "TuiConfigGetResponse" })
+export const TuiConfigPatch = Schema.Struct(TuiConfigShape)
+
+export const ConfigConsolePaths = {
+ sources: "/config/sources",
+ effective: "/config/effective",
+ overlay: "/config/overlay",
+ modelState: "/config/model-state",
+ tuiConfig: "/tui/config",
+} as const
+
+export const ConfigConsoleApi = HttpApi.make("config-console")
+ .add(
+ HttpApiGroup.make("config-console")
+ .add(
+ HttpApiEndpoint.get("overlay", ConfigConsolePaths.overlay, {
+ query: ConfigOverlayQuery,
+ success: described(ConfigOverlayResponse, "Resolved config overlay"),
+ }).annotateMerge(
+ OpenApi.annotations({
+ identifier: "config.overlay",
+ summary: "Get config overlay",
+ description:
+ "Resolve global, project, and effective config values with source metadata for inheritance-aware settings UI.",
+ }),
+ ),
+ HttpApiEndpoint.get("sources", ConfigConsolePaths.sources, {
+ success: described(ConfigSourcesResponse, "Config source inventory"),
+ }).annotateMerge(
+ OpenApi.annotations({
+ identifier: "config.sources",
+ summary: "List config sources",
+ description: "List config source metadata in load order without exposing config contents or secrets.",
+ }),
+ ),
+ HttpApiEndpoint.get("effective", ConfigConsolePaths.effective, {
+ success: described(Config.Info, "Effective config info"),
+ }).annotateMerge(
+ OpenApi.annotations({
+ identifier: "config.effective",
+ summary: "Get effective configuration",
+ description: "Retrieve effective config for the current instance directory.",
+ }),
+ ),
+ HttpApiEndpoint.patch("overlayUpdate", ConfigConsolePaths.overlay, {
+ payload: ConfigOverlayPatch,
+ success: described(Config.Info, "Effective configuration after patch"),
+ }).annotateMerge(
+ OpenApi.annotations({
+ identifier: "config.overlayUpdate",
+ summary: "Patch config overlay",
+ description:
+ "Apply a minimal global or project config patch, including unset paths for reverting local overrides.",
+ }),
+ ),
+ HttpApiEndpoint.get("modelState", ConfigConsolePaths.modelState, {
+ success: described(ConfigModelStateResponse, "Model state"),
+ }).annotateMerge(
+ OpenApi.annotations({
+ identifier: "config.modelState",
+ summary: "Get model state",
+ description: "Retrieve TUI-compatible recent and favorite model selections.",
+ }),
+ ),
+ HttpApiEndpoint.patch("modelStateUpdate", ConfigConsolePaths.modelState, {
+ payload: ConfigModelStatePatch,
+ success: described(ConfigModelStateResponse, "Updated model state"),
+ }).annotateMerge(
+ OpenApi.annotations({
+ identifier: "config.modelStateUpdate",
+ summary: "Update model state",
+ description: "Patch TUI-compatible model selections shared with Kilo Console.",
+ }),
+ ),
+ HttpApiEndpoint.get("tuiConfigGet", ConfigConsolePaths.tuiConfig, {
+ success: described(TuiConfigResponse, "Effective TUI configuration"),
+ }).annotateMerge(
+ OpenApi.annotations({
+ identifier: "tui.config.get",
+ summary: "Get TUI configuration",
+ description: "Retrieve the effective TUI configuration for the current instance directory.",
+ }),
+ ),
+ HttpApiEndpoint.patch("tuiConfigUpdate", ConfigConsolePaths.tuiConfig, {
+ query: TuiConfigQuery,
+ payload: TuiConfigPatch,
+ success: described(TuiConfigResponse, "Effective TUI configuration after the update"),
+ error: HttpApiError.BadRequest,
+ }).annotateMerge(
+ OpenApi.annotations({
+ identifier: "tui.config.update",
+ summary: "Update TUI configuration",
+ description: "Patch global or project TUI configuration and return the effective TUI configuration.",
+ }),
+ ),
+ )
+ .annotateMerge(OpenApi.annotations({ title: "config-console", description: "Kilo Console config routes." }))
+ .middleware(InstanceContextMiddleware)
+ .middleware(WorkspaceRoutingMiddleware)
+ .middleware(Authorization),
+ )
+ .annotateMerge(
+ OpenApi.annotations({
+ title: "kilo HttpApi",
+ version: "0.0.1",
+ description: "Kilo HttpApi surface.",
+ }),
+ )
diff --git a/packages/opencode/src/kilocode/server/httpapi/handlers/agent-builder.ts b/packages/opencode/src/kilocode/server/httpapi/handlers/agent-builder.ts
new file mode 100644
index 0000000000..71a062bba3
--- /dev/null
+++ b/packages/opencode/src/kilocode/server/httpapi/handlers/agent-builder.ts
@@ -0,0 +1,43 @@
+import * as InstanceState from "@/effect/instance-state"
+import { AgentBuilder } from "@/kilocode/agent/builder"
+import { InstanceStore } from "@/project/instance-store"
+import { InstanceHttpApi } from "@/server/routes/instance/httpapi/api"
+import { Effect } from "effect"
+import { HttpApiBuilder } from "effect/unstable/httpapi"
+import { AgentBuilderID, AgentBuilderInput, AgentBuilderSaveInput } from "../groups/agent-builder"
+
+export const agentBuilderHandlers = HttpApiBuilder.group(InstanceHttpApi, "agent-builder", (handlers) =>
+ Effect.gen(function* () {
+ const store = yield* InstanceStore.Service
+
+ const preview = Effect.fn("AgentBuilderHttpApi.preview")(function* (ctx: {
+ payload: typeof AgentBuilderInput.Type
+ }) {
+ const instance = yield* InstanceState.context
+ return yield* Effect.promise(() => AgentBuilder.preview(instance, normalize(ctx.payload)))
+ })
+
+ const save = Effect.fn("AgentBuilderHttpApi.save")(function* (ctx: {
+ params: { id: typeof AgentBuilderID.Type }
+ payload: typeof AgentBuilderSaveInput.Type
+ }) {
+ const instance = yield* InstanceState.context
+ const input = normalize({ ...ctx.payload, id: ctx.params.id })
+ const output = yield* Effect.promise(() => AgentBuilder.save(instance, input))
+ yield* store.dispose(instance)
+ return output
+ })
+
+ return handlers.handle("preview", preview).handle("save", save)
+ }),
+)
+
+function normalize(input: typeof AgentBuilderInput.Type): AgentBuilder.Input {
+ return {
+ ...input,
+ scope: input.scope ?? "project",
+ mode: input.mode ?? "primary",
+ prompt: input.prompt.trim(),
+ tools: input.tools ? [...input.tools] : undefined,
+ }
+}
diff --git a/packages/opencode/src/kilocode/server/httpapi/handlers/config-console.ts b/packages/opencode/src/kilocode/server/httpapi/handlers/config-console.ts
new file mode 100644
index 0000000000..2fe2b20c24
--- /dev/null
+++ b/packages/opencode/src/kilocode/server/httpapi/handlers/config-console.ts
@@ -0,0 +1,153 @@
+import { Account } from "@/account/account"
+import { Auth } from "@/auth"
+import { Config } from "@/config/config"
+import * as InstanceState from "@/effect/instance-state"
+import { KilocodeConfigOverlay } from "@/kilocode/config/overlay"
+import { KilocodeConfigSources } from "@/kilocode/config/sources"
+import { KilocodeModelState } from "@/kilocode/config/model-state"
+import { KilocodeTuiConfig } from "@/kilocode/tui/config"
+import { InstanceHttpApi } from "@/server/routes/instance/httpapi/api"
+import { Effect, Option } from "effect"
+import { HttpApiBuilder } from "effect/unstable/httpapi"
+import {
+ ConfigModelStatePatch,
+ ConfigOverlayPatch,
+ ConfigOverlayQuery,
+ TuiConfigPatch,
+ TuiConfigQuery,
+} from "../groups/config-console"
+
+export const configConsoleHandlers = HttpApiBuilder.group(InstanceHttpApi, "config-console", (handlers) =>
+ Effect.gen(function* () {
+ const config = yield* Config.Service
+ const auth = yield* Auth.Service
+ const account = yield* Account.Service
+
+ const overlay = Effect.fn("ConfigConsoleHttpApi.overlay")(function* (ctx: {
+ query: typeof ConfigOverlayQuery.Type
+ }) {
+ const instance = yield* InstanceState.context
+ const all = yield* auth.all().pipe(Effect.orElseSucceed(() => ({})))
+ const active = yield* account.active().pipe(
+ Effect.map(Option.getOrUndefined),
+ Effect.orElseSucceed(() => undefined),
+ )
+ const [base, global, sources] = yield* Effect.all(
+ [
+ config.get(),
+ config.getGlobal(),
+ Effect.promise(() =>
+ KilocodeConfigSources.list({
+ directory: instance.directory,
+ worktree: instance.worktree,
+ auth: all,
+ account: active,
+ }),
+ ),
+ ],
+ { concurrency: 3 },
+ )
+ return yield* Effect.promise(() =>
+ KilocodeConfigOverlay.resolve({
+ directory: instance.directory,
+ worktree: instance.worktree,
+ scope: ctx.query.scope ?? "project",
+ effective: base,
+ global,
+ sources: sources.sources,
+ }),
+ )
+ })
+
+ const overlayUpdate = Effect.fn("ConfigConsoleHttpApi.overlayUpdate")(function* (ctx: {
+ payload: typeof ConfigOverlayPatch.Type
+ }) {
+ const body = {
+ ...ctx.payload,
+ scope: ctx.payload.scope ?? "project",
+ set: ctx.payload.set ? { ...ctx.payload.set } : undefined,
+ unset: ctx.payload.unset?.map((item) => [...item]),
+ }
+ const patch = KilocodeConfigOverlay.patch(body)
+ if (Object.keys(patch).length === 0) {
+ if (body.scope === "global") return yield* config.getGlobal()
+ return yield* config.get()
+ }
+ if (body.scope === "global") return (yield* config.updateGlobal(patch)).info
+ yield* config.update(patch)
+ return yield* config.get()
+ })
+
+ const sources = Effect.fn("ConfigConsoleHttpApi.sources")(function* () {
+ const instance = yield* InstanceState.context
+ const all = yield* auth.all().pipe(Effect.orElseSucceed(() => ({})))
+ const active = yield* account.active().pipe(
+ Effect.map(Option.getOrUndefined),
+ Effect.orElseSucceed(() => undefined),
+ )
+ return yield* Effect.promise(() =>
+ KilocodeConfigSources.list({
+ directory: instance.directory,
+ worktree: instance.worktree,
+ auth: all,
+ account: active,
+ }),
+ )
+ })
+
+ const effective = Effect.fn("ConfigConsoleHttpApi.effective")(function* () {
+ return yield* config.get()
+ })
+
+ const modelState = Effect.fn("ConfigConsoleHttpApi.modelState")(function* () {
+ return yield* Effect.promise(() => KilocodeModelState.get())
+ })
+
+ const modelStateUpdate = Effect.fn("ConfigConsoleHttpApi.modelStateUpdate")(function* (ctx: {
+ payload: typeof ConfigModelStatePatch.Type
+ }) {
+ return yield* Effect.promise(() =>
+ KilocodeModelState.update({ favorite: ctx.payload.favorite?.map((item) => ({ ...item })) }),
+ )
+ })
+
+ const tuiConfigGet = Effect.fn("ConfigConsoleHttpApi.tuiConfigGet")(function* () {
+ const instance = yield* InstanceState.context
+ return yield* Effect.promise(() => KilocodeTuiConfig.get({ directory: instance.directory }))
+ })
+
+ const tuiConfigUpdate = Effect.fn("ConfigConsoleHttpApi.tuiConfigUpdate")(function* (ctx: {
+ query: typeof TuiConfigQuery.Type
+ payload: typeof TuiConfigPatch.Type
+ }) {
+ const instance = yield* InstanceState.context
+ const patch = {
+ ...ctx.payload,
+ keybinds: ctx.payload.keybinds ? { ...ctx.payload.keybinds } : undefined,
+ plugin: ctx.payload.plugin?.map((item) => {
+ if (!Array.isArray(item)) return item
+ return [item[0], { ...item[1] }] as [string, { readonly [x: string]: unknown }]
+ }),
+ plugin_enabled: ctx.payload.plugin_enabled ? { ...ctx.payload.plugin_enabled } : undefined,
+ }
+ return yield* Effect.promise(() =>
+ KilocodeTuiConfig.update({
+ directory: instance.directory,
+ worktree: instance.worktree,
+ scope: ctx.query.scope ?? "project",
+ patch,
+ }),
+ )
+ })
+
+ return handlers
+ .handle("overlay", overlay)
+ .handle("overlayUpdate", overlayUpdate)
+ .handle("sources", sources)
+ .handle("effective", effective)
+ .handle("modelState", modelState)
+ .handle("modelStateUpdate", modelStateUpdate)
+ .handle("tuiConfigGet", tuiConfigGet)
+ .handle("tuiConfigUpdate", tuiConfigUpdate)
+ }),
+)
diff --git a/packages/opencode/src/kilocode/server/httpapi/instance.ts b/packages/opencode/src/kilocode/server/httpapi/instance.ts
index 2e823ed1e4..5d9f3eddfe 100644
--- a/packages/opencode/src/kilocode/server/httpapi/instance.ts
+++ b/packages/opencode/src/kilocode/server/httpapi/instance.ts
@@ -1,6 +1,8 @@
import type { Context } from "effect"
import type { Hono } from "hono"
+import { AgentBuilderPaths } from "./groups/agent-builder"
import { BackgroundProcessPaths } from "./groups/background-process"
+import { ConfigConsolePaths } from "./groups/config-console"
import { IndexingPaths } from "./groups/indexing"
import { KiloGatewayPaths } from "./groups/kilo-gateway"
import { KilocodePaths } from "./groups/kilocode"
@@ -13,12 +15,22 @@ import { TelemetryPaths } from "./groups/telemetry"
type Handler = (request: Request, context: Context.Context) => Promise
export function register(app: Hono, handler: Handler, context: Context.Context) {
+ app.post(AgentBuilderPaths.preview, (c) => handler(c.req.raw, context))
+ app.put(AgentBuilderPaths.save, (c) => handler(c.req.raw, context))
app.get(BackgroundProcessPaths.list, (c) => handler(c.req.raw, context))
app.get(BackgroundProcessPaths.get, (c) => handler(c.req.raw, context))
app.get(BackgroundProcessPaths.logs, (c) => handler(c.req.raw, context))
app.post(BackgroundProcessPaths.stop, (c) => handler(c.req.raw, context))
app.post(BackgroundProcessPaths.restart, (c) => handler(c.req.raw, context))
app.post(BackgroundProcessPaths.stopSession, (c) => handler(c.req.raw, context))
+ app.get(ConfigConsolePaths.sources, (c) => handler(c.req.raw, context))
+ app.get(ConfigConsolePaths.effective, (c) => handler(c.req.raw, context))
+ app.get(ConfigConsolePaths.overlay, (c) => handler(c.req.raw, context))
+ app.patch(ConfigConsolePaths.overlay, (c) => handler(c.req.raw, context))
+ app.get(ConfigConsolePaths.modelState, (c) => handler(c.req.raw, context))
+ app.patch(ConfigConsolePaths.modelState, (c) => handler(c.req.raw, context))
+ app.get(ConfigConsolePaths.tuiConfig, (c) => handler(c.req.raw, context))
+ app.patch(ConfigConsolePaths.tuiConfig, (c) => handler(c.req.raw, context))
app.post("/permission/allow-everything", (c) => handler(c.req.raw, context))
app.post("/enhance-prompt", (c) => handler(c.req.raw, context))
app.post("/commit-message", (c) => handler(c.req.raw, context))
diff --git a/packages/opencode/src/kilocode/server/httpapi/public.ts b/packages/opencode/src/kilocode/server/httpapi/public.ts
index bd3fdd7f6d..739e23f9c3 100644
--- a/packages/opencode/src/kilocode/server/httpapi/public.ts
+++ b/packages/opencode/src/kilocode/server/httpapi/public.ts
@@ -12,21 +12,18 @@ type Response = {
description?: string
}
+type Operation = {
+ requestBody?: {
+ content?: Record
+ }
+ responses?: Record
+}
+
type Spec = {
components?: {
schemas?: Record
}
- paths?: Record<
- string,
- {
- post?: {
- requestBody?: {
- content?: Record
- }
- responses?: Record
- }
- }
- >
+ paths?: Record>>
}
export function matchLegacyKiloOpenApi(input: Record) {
@@ -40,6 +37,14 @@ export function matchLegacyKiloOpenApi(input: Record) {
if (provider?.additionalProperties && typeof provider.additionalProperties === "object")
provider.additionalProperties = nullable(provider.additionalProperties)
+ const pty = spec.components?.schemas?.Pty?.properties
+ if (pty?.sessionID) pty.sessionID = nullable(pty.sessionID)
+
+ const update = spec.paths?.["/pty/{ptyID}"]?.put?.requestBody?.content?.["application/json"]?.schema
+ const name = update?.$ref?.replace("#/components/schemas/", "")
+ const fields = name ? spec.components?.schemas?.[name]?.properties : update?.properties
+ if (fields?.sessionID) fields.sessionID = nullable(fields.sessionID)
+
const fim = spec.paths?.["/kilo/fim"]?.post?.responses
if (!fim) return
fim["200"] = {
diff --git a/packages/opencode/src/kilocode/server/httpapi/server.ts b/packages/opencode/src/kilocode/server/httpapi/server.ts
index f82f17fe98..e8e1e97879 100644
--- a/packages/opencode/src/kilocode/server/httpapi/server.ts
+++ b/packages/opencode/src/kilocode/server/httpapi/server.ts
@@ -1,7 +1,9 @@
import { Layer } from "effect"
+import { agentBuilderHandlers } from "./handlers/agent-builder"
import { backgroundProcessHandlers } from "./handlers/background-process"
import { commitMessageHandlers } from "./handlers/commit-message"
+import { configConsoleHandlers } from "./handlers/config-console"
import { enhancePromptHandlers } from "./handlers/enhance-prompt"
import { indexingHandlers } from "./handlers/indexing"
import { kiloGatewayHandlers } from "./handlers/kilo-gateway"
@@ -13,8 +15,10 @@ import { suggestionHandlers } from "./handlers/suggestion"
import { telemetryHandlers } from "./handlers/telemetry"
export const provide = Layer.provide([
+ agentBuilderHandlers,
backgroundProcessHandlers,
commitMessageHandlers,
+ configConsoleHandlers,
enhancePromptHandlers,
indexingHandlers,
kiloGatewayHandlers,
diff --git a/packages/opencode/src/kilocode/server/routes/agent-builder.ts b/packages/opencode/src/kilocode/server/routes/agent-builder.ts
index 6d08a14947..8d30155309 100644
--- a/packages/opencode/src/kilocode/server/routes/agent-builder.ts
+++ b/packages/opencode/src/kilocode/server/routes/agent-builder.ts
@@ -1,6 +1,7 @@
import { Hono } from "hono"
import { describeRoute, resolver, validator } from "hono-openapi"
import { AgentBuilder } from "@/kilocode/agent/builder"
+import { AppRuntime } from "@/effect/app-runtime"
import { Instance } from "@/project/instance"
import { InstanceStore } from "@/project/instance-store"
import { errors } from "@/server/error"
@@ -53,7 +54,7 @@ export const AgentBuilderRoutes = lazy(() =>
const body = c.req.valid("json")
const input = AgentBuilder.Input.parse({ ...body, id: c.req.valid("param").id })
const output = await AgentBuilder.save(context(), input)
- await InstanceStore.disposeInstance(Instance.current)
+ await AppRuntime.runPromise(InstanceStore.Service.use((svc) => svc.dispose(Instance.current)))
return c.json(output)
},
),
diff --git a/packages/opencode/src/pty/index.ts b/packages/opencode/src/pty/index.ts
index f8b57d898e..7bc2588a2e 100644
--- a/packages/opencode/src/pty/index.ts
+++ b/packages/opencode/src/pty/index.ts
@@ -185,7 +185,7 @@ export const layer = Layer.effect(
const id = PtyID.ascending()
// kilocode_change end
const resolved = KiloPtySelfCommand.resolve(input) // kilocode_change
- const command = resolved.command || Shell.preferred(cfg.shell)
+ const command = resolved.command || Shell.preferred(cfg.shell) // kilocode_change
const args = resolved.args || [] // kilocode_change
if (Shell.login(command)) {
args.push("-l") // kilocode_change
diff --git a/packages/opencode/src/server/routes/instance/httpapi/api.ts b/packages/opencode/src/server/routes/instance/httpapi/api.ts
index 1121970da6..19c03eb052 100644
--- a/packages/opencode/src/server/routes/instance/httpapi/api.ts
+++ b/packages/opencode/src/server/routes/instance/httpapi/api.ts
@@ -21,8 +21,10 @@ import { TuiApi } from "./groups/tui"
import { WorkspaceApi } from "./groups/workspace"
import { V2Api } from "./groups/v2"
// kilocode_change start - Kilo HttpApi groups
+import { AgentBuilderApi } from "@/kilocode/server/httpapi/groups/agent-builder"
import { CommitMessageApi } from "@/kilocode/server/httpapi/groups/commit-message"
import { BackgroundProcessApi } from "@/kilocode/server/httpapi/groups/background-process"
+import { ConfigConsoleApi } from "@/kilocode/server/httpapi/groups/config-console"
import { EnhancePromptApi } from "@/kilocode/server/httpapi/groups/enhance-prompt"
import { IndexingApi } from "@/kilocode/server/httpapi/groups/indexing"
import { KiloGatewayApi } from "@/kilocode/server/httpapi/groups/kilo-gateway"
@@ -58,8 +60,10 @@ export const InstanceHttpApi = HttpApi.make("opencode-instance")
.addHttpApi(TuiApi)
.addHttpApi(WorkspaceApi)
// kilocode_change start - Kilo HttpApi groups
+ .addHttpApi(AgentBuilderApi)
.addHttpApi(BackgroundProcessApi)
.addHttpApi(CommitMessageApi)
+ .addHttpApi(ConfigConsoleApi)
.addHttpApi(EnhancePromptApi)
.addHttpApi(IndexingApi)
.addHttpApi(KiloGatewayApi)
diff --git a/packages/opencode/test/cli/tui/thread.test.ts b/packages/opencode/test/cli/tui/thread.test.ts
index a03f73ef0b..e951c3f603 100644
--- a/packages/opencode/test/cli/tui/thread.test.ts
+++ b/packages/opencode/test/cli/tui/thread.test.ts
@@ -26,6 +26,7 @@ describe("tui thread", () => {
await check(".")
})
+ // kilocode_change start
test("ignores stale PWD after cwd is changed by a process wrapper", async () => {
await using root = await tmpdir()
const pkg = path.join(root.path, "packages", "opencode")
@@ -33,4 +34,5 @@ describe("tui thread", () => {
expect(resolveThreadDirectory(".", root.path, pkg)).toBe(pkg)
})
+ // kilocode_change end
})
diff --git a/packages/opencode/test/kilocode/server/config-overlay.test.ts b/packages/opencode/test/kilocode/server/config-overlay.test.ts
index 65e9f1d941..7e739e29e5 100644
--- a/packages/opencode/test/kilocode/server/config-overlay.test.ts
+++ b/packages/opencode/test/kilocode/server/config-overlay.test.ts
@@ -20,7 +20,7 @@ type Overlay = {
afterEach(async () => {
;(Global.Path as { config: string }).config = original
- await AppRuntime.runPromise(Config.Service.use((svc) => svc.invalidate(true)))
+ await AppRuntime.runPromise(Config.Service.use((svc) => svc.invalidate()))
await disposeAllInstances()
await resetDatabase()
})
@@ -45,7 +45,7 @@ async function config(dir: string, value: unknown) {
}
async function invalidate() {
- await AppRuntime.runPromise(Config.Service.use((svc) => svc.invalidate(true)))
+ await AppRuntime.runPromise(Config.Service.use((svc) => svc.invalidate()))
}
describe("config overlay routes", () => {
diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts
index b6495fd866..e7df7015c6 100644
--- a/packages/sdk/js/src/v2/gen/sdk.gen.ts
+++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts
@@ -3,6 +3,10 @@
import { client } from "./client.gen.js"
import { buildClientParams, type Client, type Options as Options2, type TDataShape } from "./client/index.js"
import type {
+ AgentBuilderPreviewErrors,
+ AgentBuilderPreviewResponses,
+ AgentBuilderSaveErrors,
+ AgentBuilderSaveResponses,
AgentPartInput,
AppAgentsResponses,
AppLogErrors,
@@ -26,9 +30,15 @@ import type {
CommandListResponses,
CommitMessageGenerateErrors,
CommitMessageGenerateResponses,
- Config as Config3,
+ Config as Config4,
+ ConfigEffectiveResponses,
ConfigGetResponses,
+ ConfigModelStateResponses,
+ ConfigModelStateUpdateResponses,
+ ConfigOverlayResponses,
+ ConfigOverlayUpdateResponses,
ConfigProvidersResponses,
+ ConfigSourcesResponses,
ConfigUpdateErrors,
ConfigUpdateResponses,
ConfigWarningsResponses,
@@ -254,6 +264,9 @@ import type {
TuiAppendPromptErrors,
TuiAppendPromptResponses,
TuiClearPromptResponses,
+ TuiConfigGetResponses,
+ TuiConfigUpdateErrors,
+ TuiConfigUpdateResponses,
TuiControlNextResponses,
TuiControlResponseResponses,
TuiExecuteCommandErrors,
@@ -526,7 +539,7 @@ export class Config extends HeyApiClient {
*/
public update(
parameters?: {
- config?: Config3
+ config?: Config4
},
options?: Options,
) {
@@ -683,7 +696,7 @@ export class Config2 extends HeyApiClient {
parameters?: {
directory?: string
workspace?: string
- config?: Config3
+ config?: Config4
},
options?: Options,
) {
@@ -770,6 +783,211 @@ export class Config2 extends HeyApiClient {
...params,
})
}
+
+ /**
+ * Get config overlay
+ *
+ * Resolve global, project, and effective config values with source metadata for inheritance-aware settings UI.
+ */
+ public overlay(
+ parameters?: {
+ directory?: string
+ workspace?: string
+ scope?: "global" | "project"
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ { in: "query", key: "directory" },
+ { in: "query", key: "workspace" },
+ { in: "query", key: "scope" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).get({
+ url: "/config/overlay",
+ ...options,
+ ...params,
+ })
+ }
+
+ /**
+ * Patch config overlay
+ *
+ * Apply a minimal global or project config patch, including unset paths for reverting local overrides.
+ */
+ public overlayUpdate(
+ parameters?: {
+ directory?: string
+ workspace?: string
+ scope?: "global" | "project"
+ set?: {
+ [key: string]: unknown
+ }
+ unset?: Array>
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ { in: "query", key: "directory" },
+ { in: "query", key: "workspace" },
+ { in: "body", key: "scope" },
+ { in: "body", key: "set" },
+ { in: "body", key: "unset" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).patch({
+ url: "/config/overlay",
+ ...options,
+ ...params,
+ headers: {
+ "Content-Type": "application/json",
+ ...options?.headers,
+ ...params.headers,
+ },
+ })
+ }
+
+ /**
+ * List config sources
+ *
+ * List config source metadata in load order without exposing config contents or secrets.
+ */
+ public sources(
+ parameters?: {
+ directory?: string
+ workspace?: string
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ { in: "query", key: "directory" },
+ { in: "query", key: "workspace" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).get({
+ url: "/config/sources",
+ ...options,
+ ...params,
+ })
+ }
+
+ /**
+ * Get effective configuration
+ *
+ * Retrieve effective config for the current instance directory.
+ */
+ public effective(
+ parameters?: {
+ directory?: string
+ workspace?: string
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ { in: "query", key: "directory" },
+ { in: "query", key: "workspace" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).get({
+ url: "/config/effective",
+ ...options,
+ ...params,
+ })
+ }
+
+ /**
+ * Get model state
+ *
+ * Retrieve TUI-compatible recent and favorite model selections.
+ */
+ public modelState(
+ parameters?: {
+ directory?: string
+ workspace?: string
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ { in: "query", key: "directory" },
+ { in: "query", key: "workspace" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).get({
+ url: "/config/model-state",
+ ...options,
+ ...params,
+ })
+ }
+
+ /**
+ * Update model state
+ *
+ * Patch TUI-compatible model selections shared with Kilo Console.
+ */
+ public modelStateUpdate(
+ parameters?: {
+ directory?: string
+ workspace?: string
+ favorite?: Array<{
+ providerID: string
+ modelID: string
+ }>
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ { in: "query", key: "directory" },
+ { in: "query", key: "workspace" },
+ { in: "body", key: "favorite" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).patch({
+ url: "/config/model-state",
+ ...options,
+ ...params,
+ headers: {
+ "Content-Type": "application/json",
+ ...options?.headers,
+ ...params.headers,
+ },
+ })
+ }
}
export class Console extends HeyApiClient {
@@ -2639,7 +2857,7 @@ export class Pty extends HeyApiClient {
directory?: string
workspace?: string
title?: string
- sessionID?: string
+ sessionID?: string | null
size?: {
rows: number
cols: number
@@ -4748,6 +4966,107 @@ export class Control extends HeyApiClient {
}
}
+export class Config3 extends HeyApiClient {
+ /**
+ * Get TUI configuration
+ *
+ * Retrieve the effective TUI configuration for the current instance directory.
+ */
+ public get(
+ parameters?: {
+ directory?: string
+ workspace?: string
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ { in: "query", key: "directory" },
+ { in: "query", key: "workspace" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).get({
+ url: "/tui/config",
+ ...options,
+ ...params,
+ })
+ }
+
+ /**
+ * Update TUI configuration
+ *
+ * Patch global or project TUI configuration and return the effective TUI configuration.
+ */
+ public update(
+ parameters?: {
+ directory?: string
+ workspace?: string
+ scope?: "global" | "project"
+ $schema?: string
+ theme?: string
+ keybinds?: {
+ [key: string]: string
+ }
+ plugin?: Array<
+ | string
+ | [
+ string,
+ {
+ [key: string]: unknown
+ },
+ ]
+ >
+ plugin_enabled?: {
+ [key: string]: boolean
+ }
+ scroll_speed?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
+ scroll_acceleration?: {
+ enabled: boolean
+ }
+ diff_style?: "auto" | "stacked"
+ mouse?: boolean
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ { in: "query", key: "directory" },
+ { in: "query", key: "workspace" },
+ { in: "query", key: "scope" },
+ { in: "body", key: "$schema" },
+ { in: "body", key: "theme" },
+ { in: "body", key: "keybinds" },
+ { in: "body", key: "plugin" },
+ { in: "body", key: "plugin_enabled" },
+ { in: "body", key: "scroll_speed" },
+ { in: "body", key: "scroll_acceleration" },
+ { in: "body", key: "diff_style" },
+ { in: "body", key: "mouse" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).patch({
+ url: "/tui/config",
+ ...options,
+ ...params,
+ headers: {
+ "Content-Type": "application/json",
+ ...options?.headers,
+ ...params.headers,
+ },
+ })
+ }
+}
+
export class Tui extends HeyApiClient {
/**
* Append TUI prompt
@@ -5124,6 +5443,139 @@ export class Tui extends HeyApiClient {
get control(): Control {
return (this._control ??= new Control({ client: this.client }))
}
+
+ private _config?: Config3
+ get config(): Config3 {
+ return (this._config ??= new Config3({ client: this.client }))
+ }
+}
+
+export class AgentBuilder extends HeyApiClient {
+ /**
+ * Preview agent markdown
+ *
+ * Validate an agent builder payload and return the canonical agent markdown without writing it.
+ */
+ public preview(
+ parameters?: {
+ directory?: string
+ workspace?: string
+ id?: string
+ scope?: "global" | "project"
+ description?: string
+ mode?: "primary" | "subagent" | "all"
+ model?: string
+ color?: string
+ steps?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
+ tools?: Array
+ permission?: {
+ [key: string]: unknown
+ }
+ prompt?: string
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ { in: "query", key: "directory" },
+ { in: "query", key: "workspace" },
+ { in: "body", key: "id" },
+ { in: "body", key: "scope" },
+ { in: "body", key: "description" },
+ { in: "body", key: "mode" },
+ { in: "body", key: "model" },
+ { in: "body", key: "color" },
+ { in: "body", key: "steps" },
+ { in: "body", key: "tools" },
+ { in: "body", key: "permission" },
+ { in: "body", key: "prompt" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).post(
+ {
+ url: "/agent-builder/preview",
+ ...options,
+ ...params,
+ headers: {
+ "Content-Type": "application/json",
+ ...options?.headers,
+ ...params.headers,
+ },
+ },
+ )
+ }
+
+ /**
+ * Save agent markdown
+ *
+ * Save an agent builder payload as a canonical agent markdown file.
+ */
+ public save(
+ parameters: {
+ path_id: string
+ directory?: string
+ workspace?: string
+ body_id?: string
+ scope?: "global" | "project"
+ description?: string
+ mode?: "primary" | "subagent" | "all"
+ model?: string
+ color?: string
+ steps?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
+ tools?: Array
+ permission?: {
+ [key: string]: unknown
+ }
+ prompt?: string
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ {
+ in: "path",
+ key: "path_id",
+ map: "id",
+ },
+ { in: "query", key: "directory" },
+ { in: "query", key: "workspace" },
+ {
+ in: "body",
+ key: "body_id",
+ map: "id",
+ },
+ { in: "body", key: "scope" },
+ { in: "body", key: "description" },
+ { in: "body", key: "mode" },
+ { in: "body", key: "model" },
+ { in: "body", key: "color" },
+ { in: "body", key: "steps" },
+ { in: "body", key: "tools" },
+ { in: "body", key: "permission" },
+ { in: "body", key: "prompt" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).put({
+ url: "/agent-builder/{id}",
+ ...options,
+ ...params,
+ headers: {
+ "Content-Type": "application/json",
+ ...options?.headers,
+ ...params.headers,
+ },
+ })
+ }
}
export class BackgroundProcess extends HeyApiClient {
@@ -6974,6 +7426,11 @@ export class KiloClient extends HeyApiClient {
return (this._tui ??= new Tui({ client: this.client }))
}
+ private _agentBuilder?: AgentBuilder
+ get agentBuilder(): AgentBuilder {
+ return (this._agentBuilder ??= new AgentBuilder({ client: this.client }))
+ }
+
private _backgroundProcess?: BackgroundProcess
get backgroundProcess(): BackgroundProcess {
return (this._backgroundProcess ??= new BackgroundProcess({ client: this.client }))
diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts
index c06af10487..6e67012518 100644
--- a/packages/sdk/js/src/v2/gen/types.gen.ts
+++ b/packages/sdk/js/src/v2/gen/types.gen.ts
@@ -438,7 +438,7 @@ export type Pty = {
cwd: string
status: "running" | "exited"
pid: number
- sessionID?: string
+ sessionID?: string | null
}
export type OutputFormatText = {
@@ -1985,6 +1985,117 @@ export type BackgroundProcessLogs = {
output: string
}
+export type ConfigOverlayResponse = {
+ scope: "global" | "project"
+ effective: Config
+ global: Config
+ project: Config
+ sources: Array<{
+ order: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
+ kind: string
+ scope: string
+ label: string
+ source: string
+ path?: string
+ exists: boolean
+ editable: boolean
+ reason?: string
+ }>
+ targets: {
+ global?: string
+ project?: string
+ active?: string
+ }
+ fields: {
+ [key: string]: {
+ key: string
+ path: Array
+ value?: unknown
+ global?: unknown
+ local?: unknown
+ source: "project" | "global" | "system" | "default"
+ inherited: boolean
+ overridden: boolean
+ editable: boolean
+ reason?: string
+ }
+ }
+ collections: {
+ [key: string]: Array<{
+ key: string
+ path: Array
+ value?: unknown
+ global?: unknown
+ local?: unknown
+ source: "project" | "global" | "system" | "default"
+ inherited: boolean
+ overridden: boolean
+ editable: boolean
+ reason?: string
+ }>
+ }
+}
+
+export type ConfigSourcesResponse = {
+ sources: Array<{
+ order: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
+ kind: string
+ scope: string
+ label: string
+ source: string
+ path?: string
+ exists: boolean
+ editable: boolean
+ reason?: string
+ }>
+}
+
+export type ConfigModelStateResponse = {
+ model: {
+ [key: string]: {
+ providerID: string
+ modelID: string
+ }
+ }
+ recent: Array<{
+ providerID: string
+ modelID: string
+ }>
+ favorite: Array<{
+ providerID: string
+ modelID: string
+ }>
+ variant: {
+ [key: string]: string
+ }
+}
+
+export type TuiConfigGetResponse = {
+ $schema?: string
+ theme?: string
+ keybinds?: {
+ [key: string]: string
+ }
+ plugin?: Array<
+ | string
+ | [
+ string,
+ {
+ [key: string]: unknown
+ },
+ ]
+ >
+ plugin_enabled?: {
+ [key: string]: boolean
+ }
+ scroll_speed?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
+ scroll_acceleration?: {
+ enabled: boolean
+ }
+ diff_style?: "auto" | "stacked"
+ mouse?: boolean
+}
+
export type EffectHttpApiErrorUnauthorized = {
_tag: "Unauthorized"
}
@@ -5211,7 +5322,7 @@ export type PtyGetResponse = PtyGetResponses[keyof PtyGetResponses]
export type PtyUpdateData = {
body?: {
title?: string
- sessionID?: string
+ sessionID?: string | null
size?: {
rows: number
cols: number
@@ -7395,6 +7506,100 @@ export type ExperimentalWorkspaceWarpResponses = {
export type ExperimentalWorkspaceWarpResponse =
ExperimentalWorkspaceWarpResponses[keyof ExperimentalWorkspaceWarpResponses]
+export type AgentBuilderPreviewData = {
+ body?: {
+ id: string
+ scope?: "global" | "project"
+ description?: string
+ mode?: "primary" | "subagent" | "all"
+ model?: string
+ color?: string
+ steps?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
+ tools?: Array
+ permission?: {
+ [key: string]: unknown
+ }
+ prompt: string
+ }
+ path?: never
+ query?: {
+ directory?: string
+ workspace?: string
+ }
+ url: "/agent-builder/preview"
+}
+
+export type AgentBuilderPreviewErrors = {
+ /**
+ * Bad request
+ */
+ 400: BadRequestError
+}
+
+export type AgentBuilderPreviewError = AgentBuilderPreviewErrors[keyof AgentBuilderPreviewErrors]
+
+export type AgentBuilderPreviewResponses = {
+ /**
+ * Agent markdown preview
+ */
+ 200: {
+ id: string
+ scope: "global" | "project"
+ path: string
+ markdown: string
+ }
+}
+
+export type AgentBuilderPreviewResponse = AgentBuilderPreviewResponses[keyof AgentBuilderPreviewResponses]
+
+export type AgentBuilderSaveData = {
+ body?: {
+ id?: string
+ scope?: "global" | "project"
+ description?: string
+ mode?: "primary" | "subagent" | "all"
+ model?: string
+ color?: string
+ steps?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
+ tools?: Array
+ permission?: {
+ [key: string]: unknown
+ }
+ prompt: string
+ }
+ path: {
+ id: string
+ }
+ query?: {
+ directory?: string
+ workspace?: string
+ }
+ url: "/agent-builder/{id}"
+}
+
+export type AgentBuilderSaveErrors = {
+ /**
+ * Bad request
+ */
+ 400: BadRequestError
+}
+
+export type AgentBuilderSaveError = AgentBuilderSaveErrors[keyof AgentBuilderSaveErrors]
+
+export type AgentBuilderSaveResponses = {
+ /**
+ * Saved agent markdown
+ */
+ 200: {
+ id: string
+ scope: "global" | "project"
+ path: string
+ markdown: string
+ }
+}
+
+export type AgentBuilderSaveResponse = AgentBuilderSaveResponses[keyof AgentBuilderSaveResponses]
+
export type BackgroundProcessListData = {
body?: never
path?: never
@@ -7594,6 +7799,204 @@ export type CommitMessageGenerateResponses = {
export type CommitMessageGenerateResponse = CommitMessageGenerateResponses[keyof CommitMessageGenerateResponses]
+export type ConfigOverlayData = {
+ body?: never
+ path?: never
+ query?: {
+ directory?: string
+ workspace?: string
+ scope?: "global" | "project"
+ }
+ url: "/config/overlay"
+}
+
+export type ConfigOverlayResponses = {
+ /**
+ * Resolved config overlay
+ */
+ 200: ConfigOverlayResponse
+}
+
+export type ConfigOverlayResponse2 = ConfigOverlayResponses[keyof ConfigOverlayResponses]
+
+export type ConfigOverlayUpdateData = {
+ body?: {
+ scope?: "global" | "project"
+ set?: {
+ [key: string]: unknown
+ }
+ unset?: Array>
+ }
+ path?: never
+ query?: {
+ directory?: string
+ workspace?: string
+ }
+ url: "/config/overlay"
+}
+
+export type ConfigOverlayUpdateResponses = {
+ /**
+ * Effective configuration after patch
+ */
+ 200: Config
+}
+
+export type ConfigOverlayUpdateResponse = ConfigOverlayUpdateResponses[keyof ConfigOverlayUpdateResponses]
+
+export type ConfigSourcesData = {
+ body?: never
+ path?: never
+ query?: {
+ directory?: string
+ workspace?: string
+ }
+ url: "/config/sources"
+}
+
+export type ConfigSourcesResponses = {
+ /**
+ * Config source inventory
+ */
+ 200: ConfigSourcesResponse
+}
+
+export type ConfigSourcesResponse2 = ConfigSourcesResponses[keyof ConfigSourcesResponses]
+
+export type ConfigEffectiveData = {
+ body?: never
+ path?: never
+ query?: {
+ directory?: string
+ workspace?: string
+ }
+ url: "/config/effective"
+}
+
+export type ConfigEffectiveResponses = {
+ /**
+ * Effective config info
+ */
+ 200: Config
+}
+
+export type ConfigEffectiveResponse = ConfigEffectiveResponses[keyof ConfigEffectiveResponses]
+
+export type ConfigModelStateData = {
+ body?: never
+ path?: never
+ query?: {
+ directory?: string
+ workspace?: string
+ }
+ url: "/config/model-state"
+}
+
+export type ConfigModelStateResponses = {
+ /**
+ * Model state
+ */
+ 200: ConfigModelStateResponse
+}
+
+export type ConfigModelStateResponse2 = ConfigModelStateResponses[keyof ConfigModelStateResponses]
+
+export type ConfigModelStateUpdateData = {
+ body?: {
+ favorite?: Array<{
+ providerID: string
+ modelID: string
+ }>
+ }
+ path?: never
+ query?: {
+ directory?: string
+ workspace?: string
+ }
+ url: "/config/model-state"
+}
+
+export type ConfigModelStateUpdateResponses = {
+ /**
+ * Updated model state
+ */
+ 200: ConfigModelStateResponse
+}
+
+export type ConfigModelStateUpdateResponse = ConfigModelStateUpdateResponses[keyof ConfigModelStateUpdateResponses]
+
+export type TuiConfigGetData = {
+ body?: never
+ path?: never
+ query?: {
+ directory?: string
+ workspace?: string
+ }
+ url: "/tui/config"
+}
+
+export type TuiConfigGetResponses = {
+ /**
+ * Effective TUI configuration
+ */
+ 200: TuiConfigGetResponse
+}
+
+export type TuiConfigGetResponse2 = TuiConfigGetResponses[keyof TuiConfigGetResponses]
+
+export type TuiConfigUpdateData = {
+ body?: {
+ $schema?: string
+ theme?: string
+ keybinds?: {
+ [key: string]: string
+ }
+ plugin?: Array<
+ | string
+ | [
+ string,
+ {
+ [key: string]: unknown
+ },
+ ]
+ >
+ plugin_enabled?: {
+ [key: string]: boolean
+ }
+ scroll_speed?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
+ scroll_acceleration?: {
+ enabled: boolean
+ }
+ diff_style?: "auto" | "stacked"
+ mouse?: boolean
+ }
+ path?: never
+ query?: {
+ directory?: string
+ workspace?: string
+ scope?: "global" | "project"
+ }
+ url: "/tui/config"
+}
+
+export type TuiConfigUpdateErrors = {
+ /**
+ * Bad request
+ */
+ 400: BadRequestError
+}
+
+export type TuiConfigUpdateError = TuiConfigUpdateErrors[keyof TuiConfigUpdateErrors]
+
+export type TuiConfigUpdateResponses = {
+ /**
+ * Effective TUI configuration after the update
+ */
+ 200: TuiConfigGetResponse
+}
+
+export type TuiConfigUpdateResponse = TuiConfigUpdateResponses[keyof TuiConfigUpdateResponses]
+
export type EnhancePromptEnhanceData = {
body?: {
/**
diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json
index e3b359d979..1e51549ed4 100644
--- a/packages/sdk/openapi.json
+++ b/packages/sdk/openapi.json
@@ -3773,7 +3773,14 @@
"type": "string"
},
"sessionID": {
- "type": "string"
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ]
},
"size": {
"type": "object",
@@ -9205,6 +9212,294 @@
]
}
},
+ "/agent-builder/preview": {
+ "post": {
+ "tags": ["agent-builder"],
+ "operationId": "agentBuilder.preview",
+ "parameters": [
+ {
+ "name": "directory",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Agent markdown preview",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string",
+ "enum": ["global", "project"]
+ },
+ "path": {
+ "type": "string"
+ },
+ "markdown": {
+ "type": "string"
+ }
+ },
+ "required": ["id", "scope", "path", "markdown"],
+ "additionalProperties": false,
+ "description": "Agent markdown preview"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Validate an agent builder payload and return the canonical agent markdown without writing it.",
+ "summary": "Preview agent markdown",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string",
+ "enum": ["global", "project"]
+ },
+ "description": {
+ "type": "string"
+ },
+ "mode": {
+ "type": "string",
+ "enum": ["primary", "subagent", "all"]
+ },
+ "model": {
+ "type": "string"
+ },
+ "color": {
+ "type": "string"
+ },
+ "steps": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "tools": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "permission": {
+ "type": "object"
+ },
+ "prompt": {
+ "type": "string"
+ }
+ },
+ "required": ["id", "prompt"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.agentBuilder.preview({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/agent-builder/{id}": {
+ "put": {
+ "tags": ["agent-builder"],
+ "operationId": "agentBuilder.save",
+ "parameters": [
+ {
+ "name": "directory",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "id",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Saved agent markdown",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string",
+ "enum": ["global", "project"]
+ },
+ "path": {
+ "type": "string"
+ },
+ "markdown": {
+ "type": "string"
+ }
+ },
+ "required": ["id", "scope", "path", "markdown"],
+ "additionalProperties": false,
+ "description": "Saved agent markdown"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Save an agent builder payload as a canonical agent markdown file.",
+ "summary": "Save agent markdown",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string",
+ "enum": ["global", "project"]
+ },
+ "description": {
+ "type": "string"
+ },
+ "mode": {
+ "type": "string",
+ "enum": ["primary", "subagent", "all"]
+ },
+ "model": {
+ "type": "string"
+ },
+ "color": {
+ "type": "string"
+ },
+ "steps": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "tools": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "permission": {
+ "type": "object"
+ },
+ "prompt": {
+ "type": "string"
+ }
+ },
+ "required": ["prompt"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.agentBuilder.save({\n ...\n})"
+ }
+ ]
+ }
+ },
"/background-process": {
"get": {
"tags": ["background-process"],
@@ -9647,6 +9942,529 @@
]
}
},
+ "/config/overlay": {
+ "get": {
+ "tags": ["config-console"],
+ "operationId": "config.overlay",
+ "parameters": [
+ {
+ "name": "directory",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "scope",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "enum": ["global", "project"]
+ },
+ "required": false
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Resolved config overlay",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConfigOverlayResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "Resolve global, project, and effective config values with source metadata for inheritance-aware settings UI.",
+ "summary": "Get config overlay",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.config.overlay({\n ...\n})"
+ }
+ ]
+ },
+ "patch": {
+ "tags": ["config-console"],
+ "operationId": "config.overlayUpdate",
+ "parameters": [
+ {
+ "name": "directory",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Effective configuration after patch",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Config"
+ }
+ }
+ }
+ }
+ },
+ "description": "Apply a minimal global or project config patch, including unset paths for reverting local overrides.",
+ "summary": "Patch config overlay",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "scope": {
+ "type": "string",
+ "enum": ["global", "project"]
+ },
+ "set": {
+ "type": "object"
+ },
+ "unset": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.config.overlayUpdate({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/config/sources": {
+ "get": {
+ "tags": ["config-console"],
+ "operationId": "config.sources",
+ "parameters": [
+ {
+ "name": "directory",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Config source inventory",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConfigSourcesResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "List config source metadata in load order without exposing config contents or secrets.",
+ "summary": "List config sources",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.config.sources({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/config/effective": {
+ "get": {
+ "tags": ["config-console"],
+ "operationId": "config.effective",
+ "parameters": [
+ {
+ "name": "directory",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Effective config info",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Config"
+ }
+ }
+ }
+ }
+ },
+ "description": "Retrieve effective config for the current instance directory.",
+ "summary": "Get effective configuration",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.config.effective({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/config/model-state": {
+ "get": {
+ "tags": ["config-console"],
+ "operationId": "config.modelState",
+ "parameters": [
+ {
+ "name": "directory",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Model state",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConfigModelStateResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "Retrieve TUI-compatible recent and favorite model selections.",
+ "summary": "Get model state",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.config.modelState({\n ...\n})"
+ }
+ ]
+ },
+ "patch": {
+ "tags": ["config-console"],
+ "operationId": "config.modelStateUpdate",
+ "parameters": [
+ {
+ "name": "directory",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Updated model state",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConfigModelStateResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "Patch TUI-compatible model selections shared with Kilo Console.",
+ "summary": "Update model state",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "favorite": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "providerID": {
+ "type": "string"
+ },
+ "modelID": {
+ "type": "string"
+ }
+ },
+ "required": ["providerID", "modelID"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.config.modelStateUpdate({\n ...\n})"
+ }
+ ]
+ }
+ },
+ "/tui/config": {
+ "get": {
+ "tags": ["config-console"],
+ "operationId": "tui.config.get",
+ "parameters": [
+ {
+ "name": "directory",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Effective TUI configuration",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TuiConfigGetResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "Retrieve the effective TUI configuration for the current instance directory.",
+ "summary": "Get TUI configuration",
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.tui.config.get({\n ...\n})"
+ }
+ ]
+ },
+ "patch": {
+ "tags": ["config-console"],
+ "operationId": "tui.config.update",
+ "parameters": [
+ {
+ "name": "directory",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "workspace",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "scope",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "enum": ["global", "project"]
+ },
+ "required": false
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Effective TUI configuration after the update",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TuiConfigGetResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad request",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestError"
+ }
+ }
+ }
+ }
+ },
+ "description": "Patch global or project TUI configuration and return the effective TUI configuration.",
+ "summary": "Update TUI configuration",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "$schema": {
+ "type": "string"
+ },
+ "theme": {
+ "type": "string"
+ },
+ "keybinds": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "plugin": {
+ "type": "array",
+ "items": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "prefixItems": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "object"
+ }
+ ],
+ "maxItems": 2,
+ "minItems": 2
+ }
+ ]
+ }
+ },
+ "plugin_enabled": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "boolean"
+ }
+ },
+ "scroll_speed": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "scroll_acceleration": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ }
+ },
+ "required": ["enabled"],
+ "additionalProperties": false
+ },
+ "diff_style": {
+ "type": "string",
+ "enum": ["auto", "stacked"]
+ },
+ "mouse": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "x-codeSamples": [
+ {
+ "lang": "js",
+ "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.tui.config.update({\n ...\n})"
+ }
+ ]
+ }
+ },
"/enhance-prompt": {
"post": {
"tags": ["enhance-prompt"],
@@ -14074,7 +14892,14 @@
"exclusiveMinimum": 0
},
"sessionID": {
- "type": "string"
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ]
}
},
"required": ["id", "title", "command", "args", "cwd", "status", "pid"],
@@ -18604,6 +19429,389 @@
"required": ["id", "sessionID", "output"],
"additionalProperties": false
},
+ "ConfigOverlayResponse": {
+ "type": "object",
+ "properties": {
+ "scope": {
+ "type": "string",
+ "enum": ["global", "project"]
+ },
+ "effective": {
+ "$ref": "#/components/schemas/Config"
+ },
+ "global": {
+ "$ref": "#/components/schemas/Config"
+ },
+ "project": {
+ "$ref": "#/components/schemas/Config"
+ },
+ "sources": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "order": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "kind": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "label": {
+ "type": "string"
+ },
+ "source": {
+ "type": "string"
+ },
+ "path": {
+ "type": "string"
+ },
+ "exists": {
+ "type": "boolean"
+ },
+ "editable": {
+ "type": "boolean"
+ },
+ "reason": {
+ "type": "string"
+ }
+ },
+ "required": ["order", "kind", "scope", "label", "source", "exists", "editable"],
+ "additionalProperties": false
+ }
+ },
+ "targets": {
+ "type": "object",
+ "properties": {
+ "global": {
+ "type": "string"
+ },
+ "project": {
+ "type": "string"
+ },
+ "active": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "fields": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string"
+ },
+ "path": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "value": {},
+ "global": {},
+ "local": {},
+ "source": {
+ "type": "string",
+ "enum": ["project", "global", "system", "default"]
+ },
+ "inherited": {
+ "type": "boolean"
+ },
+ "overridden": {
+ "type": "boolean"
+ },
+ "editable": {
+ "type": "boolean"
+ },
+ "reason": {
+ "type": "string"
+ }
+ },
+ "required": ["key", "path", "source", "inherited", "overridden", "editable"],
+ "additionalProperties": false
+ }
+ },
+ "collections": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string"
+ },
+ "path": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "value": {},
+ "global": {},
+ "local": {},
+ "source": {
+ "type": "string",
+ "enum": ["project", "global", "system", "default"]
+ },
+ "inherited": {
+ "type": "boolean"
+ },
+ "overridden": {
+ "type": "boolean"
+ },
+ "editable": {
+ "type": "boolean"
+ },
+ "reason": {
+ "type": "string"
+ }
+ },
+ "required": ["key", "path", "source", "inherited", "overridden", "editable"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "required": ["scope", "effective", "global", "project", "sources", "targets", "fields", "collections"],
+ "additionalProperties": false
+ },
+ "ConfigSourcesResponse": {
+ "type": "object",
+ "properties": {
+ "sources": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "order": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "kind": {
+ "type": "string"
+ },
+ "scope": {
+ "type": "string"
+ },
+ "label": {
+ "type": "string"
+ },
+ "source": {
+ "type": "string"
+ },
+ "path": {
+ "type": "string"
+ },
+ "exists": {
+ "type": "boolean"
+ },
+ "editable": {
+ "type": "boolean"
+ },
+ "reason": {
+ "type": "string"
+ }
+ },
+ "required": ["order", "kind", "scope", "label", "source", "exists", "editable"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": ["sources"],
+ "additionalProperties": false
+ },
+ "ConfigModelStateResponse": {
+ "type": "object",
+ "properties": {
+ "model": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "providerID": {
+ "type": "string"
+ },
+ "modelID": {
+ "type": "string"
+ }
+ },
+ "required": ["providerID", "modelID"],
+ "additionalProperties": false
+ }
+ },
+ "recent": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "providerID": {
+ "type": "string"
+ },
+ "modelID": {
+ "type": "string"
+ }
+ },
+ "required": ["providerID", "modelID"],
+ "additionalProperties": false
+ }
+ },
+ "favorite": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "providerID": {
+ "type": "string"
+ },
+ "modelID": {
+ "type": "string"
+ }
+ },
+ "required": ["providerID", "modelID"],
+ "additionalProperties": false
+ }
+ },
+ "variant": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ },
+ "required": ["model", "recent", "favorite", "variant"],
+ "additionalProperties": false
+ },
+ "TuiConfigGetResponse": {
+ "type": "object",
+ "properties": {
+ "$schema": {
+ "type": "string"
+ },
+ "theme": {
+ "type": "string"
+ },
+ "keybinds": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "plugin": {
+ "type": "array",
+ "items": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "prefixItems": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "object"
+ }
+ ],
+ "maxItems": 2,
+ "minItems": 2
+ }
+ ]
+ }
+ },
+ "plugin_enabled": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "boolean"
+ }
+ },
+ "scroll_speed": {
+ "anyOf": [
+ {
+ "type": "number"
+ },
+ {
+ "type": "string",
+ "enum": ["NaN"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["-Infinity"]
+ },
+ {
+ "type": "string",
+ "enum": ["Infinity", "-Infinity", "NaN"]
+ }
+ ]
+ },
+ "scroll_acceleration": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ }
+ },
+ "required": ["enabled"],
+ "additionalProperties": false
+ },
+ "diff_style": {
+ "type": "string",
+ "enum": ["auto", "stacked"]
+ },
+ "mouse": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ },
"effect_HttpApiError_Unauthorized": {
"type": "object",
"properties": {
@@ -23767,6 +24975,10 @@
"name": "workspace",
"description": "Experimental HttpApi workspace routes."
},
+ {
+ "name": "agent-builder",
+ "description": "Kilo agent builder routes."
+ },
{
"name": "background-process",
"description": "Kilo background process routes."
@@ -23775,6 +24987,10 @@
"name": "commit-message",
"description": "Kilo commit message routes."
},
+ {
+ "name": "config-console",
+ "description": "Kilo Console config routes."
+ },
{
"name": "enhance-prompt",
"description": "Kilo enhance prompt routes."