From f560e5bd7af3289200e2d56201901d8faa8b023c Mon Sep 17 00:00:00 2001 From: Imanol Maiztegui Date: Mon, 18 May 2026 14:38:21 +0200 Subject: [PATCH] refactor(kilo-gateway): extract cloud sessions logic and wire up cloud sync endpoints Move inline cloud-sessions fetch logic from Hono route handler into a reusable getCloudSessions function in handlers.ts, and introduce new Effect HttpApi endpoints for fetching and importing individual cloud sessions. - Extract getCloudSessions handler from routes.ts inline implementation - Export fetchCloudSession, fetchCloudSessionForImport, importSessionToDb from kilo-gateway package - Add cloudSession (GET /kilo/cloud/session/:id) endpoint for previewing remote session data - Add cloudSessionImport (POST /kilo/cloud/session/import) endpoint to download and persist cloud sessions locally - Define CloudSession, CloudSessionData, CloudMessage schemas in the kilo-gateway API group - Change claw status error response from 500 InternalServerError to 503 ServiceUnavailable - Register new cloud routes in instance router - Add test coverage for route disambiguation between import and :id paths - Regenerate SDK types and OpenAPI spec --- packages/kilo-gateway/src/index.ts | 2 + packages/kilo-gateway/src/server/handlers.ts | 62 +++ packages/kilo-gateway/src/server/routes.ts | 59 +-- .../server/httpapi/groups/kilo-gateway.ts | 89 ++++ .../server/httpapi/handlers/kilo-gateway.ts | 78 +++- .../src/kilocode/server/httpapi/instance.ts | 3 + .../server/routes/instance/httpapi/public.ts | 1 + .../test/server/httpapi-bridge.test.ts | 13 +- packages/sdk/js/src/v2/gen/sdk.gen.ts | 129 ++++++ packages/sdk/js/src/v2/gen/types.gen.ts | 145 ++++++- packages/sdk/openapi.json | 380 +++++++++++++++++- 11 files changed, 893 insertions(+), 68 deletions(-) diff --git a/packages/kilo-gateway/src/index.ts b/packages/kilo-gateway/src/index.ts index 7767919f67a..1c5fa7108ea 100644 --- a/packages/kilo-gateway/src/index.ts +++ b/packages/kilo-gateway/src/index.ts @@ -48,6 +48,7 @@ export { type OrganizationModeConfig, } from "./api/modes.js" export { fetchKilocodeNotifications, type KilocodeNotification } from "./api/notifications.js" +export { fetchCloudSession, fetchCloudSessionForImport, importSessionToDb } from "./cloud-sessions.js" // ============================================================================ // Server Routes (optional - requires hono and OpenCode dependencies) @@ -59,6 +60,7 @@ export { getOrganizationId, getClawChatCredentials, getClawStatus, + getCloudSessions, getNotifications, getProfile, getToken, diff --git a/packages/kilo-gateway/src/server/handlers.ts b/packages/kilo-gateway/src/server/handlers.ts index 3141178655e..4e3fca63762 100644 --- a/packages/kilo-gateway/src/server/handlers.ts +++ b/packages/kilo-gateway/src/server/handlers.ts @@ -3,6 +3,7 @@ import { fetchKilocodeNotifications } from "../api/notifications.js" import { clearModesCache } from "../api/modes.js" import { HEADER_ORGANIZATIONID, KILO_API_BASE, KILO_CHAT_URL, KILO_EVENT_SERVICE_URL } from "../api/constants.js" import type { KilocodeBalance, KilocodeProfile } from "../types.js" +import { buildKiloHeaders } from "../headers.js" export type KiloAuth = | { type: "api"; key: string } @@ -33,6 +34,12 @@ export interface OrganizationDeps { dispose(): Promise } +export interface CloudSessionsInput { + cursor?: string + limit?: number + gitUrl?: string +} + export class UnauthorizedError extends Error {} export class GatewayError extends Error { @@ -126,3 +133,58 @@ export async function getClawChatCredentials(auth: AuthStore): Promise = {} + if (input.cursor) query.cursor = input.cursor + if (input.limit) query.limit = input.limit + if (input.gitUrl) query.gitUrl = input.gitUrl + + const params = new URLSearchParams({ + batch: "1", + input: JSON.stringify({ "0": query }), + }) + + const response = await fetch(`${KILO_API_BASE}/api/trpc/cliSessionsV2.list?${params.toString()}`, { + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + ...buildKiloHeaders(), + }, + }) + + if (!response.ok) { + const text = await response.text() + console.error("[Kilo Gateway] cloud-sessions: tRPC request failed", { + status: response.status, + body: text.slice(0, 500), + }) + throw new GatewayError(`Cloud sessions fetch failed: ${response.status}`, response.status) + } + + const raw = await response.text() + const json = JSON.parse(raw) + const data = Array.isArray(json) ? json[0]?.result?.data : null + const result = data?.json ?? data + if (!result) return { cliSessions: [], nextCursor: null } + + const cliSessions = (result.cliSessions ?? []).map((item: any) => ({ + session_id: item.session_id, + title: item.title ?? null, + created_at: + typeof item.created_at === "string" + ? item.created_at + : item.created_at + ? new Date(item.created_at).toISOString() + : new Date().toISOString(), + updated_at: + typeof item.updated_at === "string" + ? item.updated_at + : item.updated_at + ? new Date(item.updated_at).toISOString() + : new Date().toISOString(), + version: item.version ?? 0, + })) + + return { cliSessions, nextCursor: result.nextCursor ?? null } +} diff --git a/packages/kilo-gateway/src/server/routes.ts b/packages/kilo-gateway/src/server/routes.ts index fa44b651375..bbf6eb8356e 100644 --- a/packages/kilo-gateway/src/server/routes.ts +++ b/packages/kilo-gateway/src/server/routes.ts @@ -16,6 +16,7 @@ import { UnauthorizedError, getClawChatCredentials, getClawStatus, + getCloudSessions, getNotifications, getProfile, setOrganization, @@ -710,63 +711,9 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { const token = auth.type === "api" ? auth.key : auth.type === "oauth" ? auth.access : undefined if (!token) return c.json({ error: "No valid token found" }, 401) - const { cursor, limit, gitUrl } = c.req.valid("query") - - const input: Record = {} - if (cursor) input.cursor = cursor - if (limit) input.limit = limit - if (gitUrl) input.gitUrl = gitUrl - - const params = new URLSearchParams({ - batch: "1", - input: JSON.stringify({ "0": input }), - }) - - const url = `${KILO_API_BASE}/api/trpc/cliSessionsV2.list?${params.toString()}` - - const response = await fetch(url, { - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - ...buildKiloHeaders(), - }, - }) - - if (!response.ok) { - const text = await response.text() - console.error("[Kilo Gateway] cloud-sessions: tRPC request failed", { - status: response.status, - body: text.slice(0, 500), - }) - return c.json({ error: `Cloud sessions fetch failed: ${response.status}` }, response.status as any) - } - - const raw = await response.text() - const json = JSON.parse(raw) - const data = Array.isArray(json) ? json[0]?.result?.data : null - const result = data?.json ?? data - if (!result) return c.json({ cliSessions: [], nextCursor: null }) - - const sessions = (result.cliSessions ?? []).map((s: any) => ({ - session_id: s.session_id, - title: s.title ?? null, - created_at: - typeof s.created_at === "string" - ? s.created_at - : s.created_at - ? new Date(s.created_at).toISOString() - : new Date().toISOString(), - updated_at: - typeof s.updated_at === "string" - ? s.updated_at - : s.updated_at - ? new Date(s.updated_at).toISOString() - : new Date().toISOString(), - version: s.version ?? 0, - })) - - return c.json({ cliSessions: sessions, nextCursor: result.nextCursor ?? null }) + return c.json(await getCloudSessions(token, c.req.valid("query"))) } catch (err: any) { + if (err instanceof GatewayError) return c.json({ error: err.message }, err.status as any) console.error("[Kilo Gateway] cloud-sessions: unhandled error", err?.message ?? err) return c.json({ error: "Internal error" }, 500) } diff --git a/packages/opencode/src/kilocode/server/httpapi/groups/kilo-gateway.ts b/packages/opencode/src/kilocode/server/httpapi/groups/kilo-gateway.ts index b97a7cf4ef7..9a0a72caffb 100644 --- a/packages/opencode/src/kilocode/server/httpapi/groups/kilo-gateway.ts +++ b/packages/opencode/src/kilocode/server/httpapi/groups/kilo-gateway.ts @@ -86,12 +86,64 @@ export const ClawChatCredentials = Schema.NullOr( }), ) +export const CloudSession = Schema.Struct({ + session_id: Schema.String, + title: Schema.NullOr(Schema.String), + created_at: Schema.String, + updated_at: Schema.String, + version: Schema.Finite, +}) + +export const CloudSessions = Schema.Struct({ + cliSessions: Schema.Array(CloudSession), + nextCursor: Schema.NullOr(Schema.String), +}) + +export const CloudSessionImportBody = Schema.Struct({ + sessionId: Schema.String, +}) + +export const CloudMessage = Schema.Struct({ + info: Schema.Struct({ + id: Schema.String, + sessionID: Schema.String, + role: Schema.Literals(["user", "assistant"]), + time: Schema.Struct({ + created: Schema.Finite, + completed: Schema.optional(Schema.Finite), + }), + }), + parts: Schema.Array( + Schema.Struct({ + id: Schema.String, + sessionID: Schema.String, + messageID: Schema.String, + type: Schema.String, + }), + ), +}) + +export const CloudSessionData = Schema.Struct({ + info: Schema.Struct({ + id: Schema.String, + title: Schema.String, + time: Schema.Struct({ + created: Schema.Finite, + updated: Schema.Finite, + }), + }), + messages: Schema.Array(CloudMessage), +}) + export const KiloGatewayPaths = { profile: `${root}/profile`, notifications: `${root}/notifications`, organization: `${root}/organization`, clawStatus: `${root}/claw/status`, clawChatCredentials: `${root}/claw/chat-credentials`, + cloudSessions: `${root}/cloud-sessions`, + cloudSession: `${root}/cloud/session/:id`, + cloudSessionImport: `${root}/cloud/session/import`, } as const export const KiloGatewayApi = HttpApi.make("kilo") @@ -152,6 +204,43 @@ export const KiloGatewayApi = HttpApi.make("kilo") "event-service both verify it directly with NEXTAUTH_SECRET, so no separate token mint is needed.", }), ), + HttpApiEndpoint.get("cloudSessions", KiloGatewayPaths.cloudSessions, { + query: { + cursor: Schema.optional(Schema.String), + limit: Schema.optional(Schema.String), + gitUrl: Schema.optional(Schema.String), + }, + success: described(CloudSessions, "Cloud sessions list"), + error: [HttpApiError.BadRequest, HttpApiError.Unauthorized], + }).annotateMerge( + OpenApi.annotations({ + identifier: "kilo.cloudSessions", + summary: "Get cloud sessions", + description: "Fetch cloud CLI sessions from Kilo API", + }), + ), + HttpApiEndpoint.get("cloudSession", KiloGatewayPaths.cloudSession, { + params: { id: Schema.String }, + success: described(CloudSessionData, "Cloud session data"), + error: [HttpApiError.Unauthorized, HttpApiError.NotFound], + }).annotateMerge( + OpenApi.annotations({ + identifier: "kilo.cloud.session.get", + summary: "Get cloud session", + description: "Fetch full session data from the Kilo cloud for preview", + }), + ), + HttpApiEndpoint.post("cloudSessionImport", KiloGatewayPaths.cloudSessionImport, { + payload: CloudSessionImportBody, + success: described(CloudSessionData.fields.info, "Imported session info"), + error: [HttpApiError.BadRequest, HttpApiError.Unauthorized, HttpApiError.NotFound], + }).annotateMerge( + OpenApi.annotations({ + identifier: "kilo.cloud.session.import", + summary: "Import session from cloud", + description: "Download a cloud-synced session and write it to local storage with fresh IDs.", + }), + ), ) .annotateMerge( OpenApi.annotations({ diff --git a/packages/opencode/src/kilocode/server/httpapi/handlers/kilo-gateway.ts b/packages/opencode/src/kilocode/server/httpapi/handlers/kilo-gateway.ts index 09dd80451a6..1b600b1a2a7 100644 --- a/packages/opencode/src/kilocode/server/httpapi/handlers/kilo-gateway.ts +++ b/packages/opencode/src/kilocode/server/httpapi/handlers/kilo-gateway.ts @@ -1,4 +1,12 @@ -import { GatewayError, UnauthorizedError, getOrganizationId, getToken } from "@kilocode/kilo-gateway" +import { + GatewayError, + fetchCloudSession, + fetchCloudSessionForImport, + getCloudSessions, + getOrganizationId, + getToken, + importSessionToDb, +} from "@kilocode/kilo-gateway" import { HEADER_ORGANIZATIONID, KILO_API_BASE, @@ -12,9 +20,15 @@ import { import { Effect } from "effect" import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi" import { Auth } from "@/auth" +import { Bus } from "@/bus" +import { Identifier } from "@/id/id" +import { Instance } from "@/project/instance" import { InstanceStore } from "@/project/instance-store" import { ModelCache } from "@/provider/model-cache" import { InstanceHttpApi } from "@/server/routes/instance/httpapi/api" +import { MessageTable, PartTable, SessionTable } from "@/session/session.sql" +import { Session } from "@/session/session" +import { Database } from "@/storage/db" export const kiloGatewayHandlers = HttpApiBuilder.group(InstanceHttpApi, "kilo", (handlers) => Effect.gen(function* () { @@ -85,7 +99,7 @@ export const kiloGatewayHandlers = HttpApiBuilder.group(InstanceHttpApi, "kilo", return response.json() }, catch: (err) => - err instanceof UnauthorizedError + err instanceof GatewayError && err.status === 401 ? new HttpApiError.Unauthorized({}) : new HttpApiError.ServiceUnavailable({}), }) @@ -105,11 +119,71 @@ export const kiloGatewayHandlers = HttpApiBuilder.group(InstanceHttpApi, "kilo", } }) + const cloudSessions = Effect.fn("KiloGatewayHttpApi.cloudSessions")(function* (ctx) { + const info = yield* auth.get("kilo").pipe(Effect.mapError(() => new HttpApiError.BadRequest({}))) + const token = getToken(info) + if (!token) return yield* Effect.fail(new HttpApiError.Unauthorized({})) + + const query = { + ...ctx.query, + limit: ctx.query.limit === undefined ? undefined : Number(ctx.query.limit), + } + + return yield* Effect.tryPromise({ + try: () => getCloudSessions(token, query), + catch: (err) => + err instanceof GatewayError && err.status === 401 + ? new HttpApiError.Unauthorized({}) + : new HttpApiError.BadRequest({}), + }) + }) + + const cloudSession = Effect.fn("KiloGatewayHttpApi.cloudSession")(function* (ctx) { + const info = yield* auth.get("kilo").pipe(Effect.mapError(() => new HttpApiError.Unauthorized({}))) + const token = getToken(info) + if (!token) return yield* Effect.fail(new HttpApiError.Unauthorized({})) + + const result = yield* Effect.promise(() => fetchCloudSession(token, ctx.params.id)) + if (!result.ok && result.status === 404) return yield* Effect.fail(new HttpApiError.NotFound({})) + if (!result.ok) return yield* Effect.fail(new HttpApiError.Unauthorized({})) + return result.data + }) + + const cloudSessionImport = Effect.fn("KiloGatewayHttpApi.cloudSessionImport")(function* (ctx) { + const info = yield* auth.get("kilo").pipe(Effect.mapError(() => new HttpApiError.Unauthorized({}))) + const token = getToken(info) + if (!token) return yield* Effect.fail(new HttpApiError.Unauthorized({})) + + const fetched = yield* Effect.promise(() => fetchCloudSessionForImport(token, ctx.payload.sessionId)) + if (!fetched.ok && fetched.status === 404) return yield* Effect.fail(new HttpApiError.NotFound({})) + if (!fetched.ok) return yield* Effect.fail(new HttpApiError.BadRequest({})) + if (!fetched.data?.info?.id) return yield* Effect.fail(new HttpApiError.BadRequest({})) + + return yield* Effect.try({ + try: () => + importSessionToDb(fetched.data, { + Database, + Instance, + SessionTable, + MessageTable, + PartTable, + SessionToRow: Session.toRow, + Bus, + SessionCreatedEvent: Session.Event.Created, + Identifier, + }), + catch: () => new HttpApiError.BadRequest({}), + }) + }) + return handlers .handle("profile", profile) .handle("notifications", notifications) .handle("organization", organization) .handle("clawStatus", clawStatus) .handle("clawChatCredentials", clawChatCredentials) + .handle("cloudSessions", cloudSessions) + .handle("cloudSession", cloudSession) + .handle("cloudSessionImport", cloudSessionImport) }), ) diff --git a/packages/opencode/src/kilocode/server/httpapi/instance.ts b/packages/opencode/src/kilocode/server/httpapi/instance.ts index e3bb160f073..9c211f3e1a6 100644 --- a/packages/opencode/src/kilocode/server/httpapi/instance.ts +++ b/packages/opencode/src/kilocode/server/httpapi/instance.ts @@ -39,6 +39,9 @@ export function register(app: Hono, handler: Handler, context: Context.Context handler(c.req.raw, context)) app.get(KiloGatewayPaths.clawStatus, (c) => handler(c.req.raw, context)) app.get(KiloGatewayPaths.clawChatCredentials, (c) => handler(c.req.raw, context)) + app.get(KiloGatewayPaths.cloudSessions, (c) => handler(c.req.raw, context)) + app.get(KiloGatewayPaths.cloudSession, (c) => handler(c.req.raw, context)) + app.post(KiloGatewayPaths.cloudSessionImport, (c) => handler(c.req.raw, context)) return app } diff --git a/packages/opencode/src/server/routes/instance/httpapi/public.ts b/packages/opencode/src/server/routes/instance/httpapi/public.ts index c9668336ae9..fdcd84afe4c 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/public.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/public.ts @@ -75,6 +75,7 @@ const QueryNumberParameters = new Set(["start", "cursor", "limit", "method"]) const QueryBooleanParameters = new Set(["roots", "archived"]) const QueryParameterSchemas = { "GET /find/file limit": { type: "integer", minimum: 1, maximum: 200 }, + "GET /kilo/cloud-sessions cursor": { type: "string" }, // kilocode_change "GET /session/{sessionID}/diff messageID": { type: "string", pattern: "^msg.*" }, "GET /session/{sessionID}/message limit": { type: "integer", minimum: 0, maximum: Number.MAX_SAFE_INTEGER }, } satisfies Record diff --git a/packages/opencode/test/server/httpapi-bridge.test.ts b/packages/opencode/test/server/httpapi-bridge.test.ts index a1f70e24fc3..2fd067d1bf9 100644 --- a/packages/opencode/test/server/httpapi-bridge.test.ts +++ b/packages/opencode/test/server/httpapi-bridge.test.ts @@ -4,6 +4,7 @@ import { Instance } from "../../src/project/instance" import { ControlPaths } from "../../src/server/routes/instance/httpapi/groups/control" import { FilePaths } from "../../src/server/routes/instance/httpapi/groups/file" import { GlobalPaths } from "../../src/server/routes/instance/httpapi/groups/global" +import { KiloGatewayPaths } from "../../src/kilocode/server/httpapi/groups/kilo-gateway" import { PublicApi } from "../../src/server/routes/instance/httpapi/public" import { ExperimentalHttpApiServer } from "../../src/server/routes/instance/httpapi/server" import { Server } from "../../src/server/server" @@ -292,10 +293,10 @@ describe("HttpApi server", () => { "POST /kilocode/session-import/session", "POST /kilocode/session-import/message", "POST /kilocode/session-import/part", - "GET /indexing/status", ] expect(kilo.filter((route) => !hono.has(route))).toEqual([]) expect(kilo.filter((route) => !effect.has(route))).toEqual([]) + expect(effect.has("GET /indexing/status")).toBe(true) }) // kilocode_change end @@ -334,6 +335,16 @@ describe("HttpApi server", () => { expect(time?.properties?.archived).toEqual({ type: "number" }) }) + // kilocode_change start - cloud session literal route must not be swallowed by :id. + test("documents cloud session import separately from session id lookup", () => { + const effect = effectOpenApi() + + expect(effect.paths["/kilo/cloud/session/import"]?.post).toBeDefined() + expect(effect.paths["/kilo/cloud/session/{id}"]?.get).toBeDefined() + expect(KiloGatewayPaths.cloudSessionImport).not.toBe(KiloGatewayPaths.cloudSession) + }) + // kilocode_change end + test("documents event routes as server-sent events", () => { const effect = effectOpenApi() diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index 28ff3b9615f..1de79123bbe 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -65,6 +65,12 @@ import type { KiloClawChatCredentialsResponses, KiloClawStatusErrors, KiloClawStatusResponses, + KiloCloudSessionGetErrors, + KiloCloudSessionGetResponses, + KiloCloudSessionImportErrors, + KiloCloudSessionImportResponses, + KiloCloudSessionsErrors, + KiloCloudSessionsResponses, KilocodeHeapSnapshotErrors, KilocodeHeapSnapshotResponses, KilocodeRemoveAgentErrors, @@ -5027,6 +5033,88 @@ export class Claw extends HeyApiClient { } } +export class Session4 extends HeyApiClient { + /** + * Get cloud session + * + * Fetch full session data from the Kilo cloud for preview + */ + public get( + parameters: { + id: string + directory?: string + workspace?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "path", key: "id" }, + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get({ + url: "/kilo/cloud/session/{id}", + ...options, + ...params, + }) + } + + /** + * Import session from cloud + * + * Download a cloud-synced session and write it to local storage with fresh IDs. + */ + public import( + parameters?: { + directory?: string + workspace?: string + sessionId?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + { in: "body", key: "sessionId" }, + ], + }, + ], + ) + return (options?.client ?? this.client).post< + KiloCloudSessionImportResponses, + KiloCloudSessionImportErrors, + ThrowOnError + >({ + url: "/kilo/cloud/session/import", + ...options, + ...params, + headers: { + "Content-Type": "application/json", + ...options?.headers, + ...params.headers, + }, + }) + } +} + +export class Cloud extends HeyApiClient { + private _session?: Session4 + get session(): Session4 { + return (this._session ??= new Session4({ client: this.client })) + } +} + export class Kilo extends HeyApiClient { /** * Get Kilo Gateway profile @@ -5088,6 +5176,42 @@ export class Kilo extends HeyApiClient { }) } + /** + * Get cloud sessions + * + * Fetch cloud CLI sessions from Kilo API + */ + public cloudSessions( + parameters?: { + directory?: string + workspace?: string + cursor?: string + limit?: number + gitUrl?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + { in: "query", key: "cursor" }, + { in: "query", key: "limit" }, + { in: "query", key: "gitUrl" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get({ + url: "/kilo/cloud-sessions", + ...options, + ...params, + }) + } + private _organization?: Organization get organization(): Organization { return (this._organization ??= new Organization({ client: this.client })) @@ -5097,6 +5221,11 @@ export class Kilo extends HeyApiClient { get claw(): Claw { return (this._claw ??= new Claw({ client: this.client })) } + + private _cloud?: Cloud + get cloud(): Cloud { + return (this._cloud ??= new Cloud({ client: this.client })) + } } export class Heap extends HeyApiClient { diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 6619b5c812c..2a00757de5d 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1856,8 +1856,8 @@ export type EffectHttpApiErrorUnauthorized = { _tag: "Unauthorized" } -export type EffectHttpApiErrorInternalServerError = { - _tag: "InternalServerError" +export type EffectHttpApiErrorServiceUnavailable = { + _tag: "ServiceUnavailable" } export type KilocodeSessionImportResult = { @@ -7252,9 +7252,9 @@ export type KiloClawStatusData = { export type KiloClawStatusErrors = { /** - * InternalServerError + * ServiceUnavailable */ - 500: EffectHttpApiErrorInternalServerError + 503: EffectHttpApiErrorServiceUnavailable } export type KiloClawStatusError = KiloClawStatusErrors[keyof KiloClawStatusErrors] @@ -7315,6 +7315,143 @@ export type KiloClawChatCredentialsResponses = { export type KiloClawChatCredentialsResponse = KiloClawChatCredentialsResponses[keyof KiloClawChatCredentialsResponses] +export type KiloCloudSessionsData = { + body?: never + path?: never + query?: { + directory?: string + workspace?: string + cursor?: string + limit?: number + gitUrl?: string + } + url: "/kilo/cloud-sessions" +} + +export type KiloCloudSessionsErrors = { + /** + * Bad request + */ + 400: BadRequestError +} + +export type KiloCloudSessionsError = KiloCloudSessionsErrors[keyof KiloCloudSessionsErrors] + +export type KiloCloudSessionsResponses = { + /** + * Cloud sessions list + */ + 200: { + cliSessions: Array<{ + session_id: string + title: string + created_at: string + updated_at: string + version: number + }> + nextCursor: string + } +} + +export type KiloCloudSessionsResponse = KiloCloudSessionsResponses[keyof KiloCloudSessionsResponses] + +export type KiloCloudSessionGetData = { + body?: never + path: { + id: string + } + query?: { + directory?: string + workspace?: string + } + url: "/kilo/cloud/session/{id}" +} + +export type KiloCloudSessionGetErrors = { + /** + * Not found + */ + 404: NotFoundError +} + +export type KiloCloudSessionGetError = KiloCloudSessionGetErrors[keyof KiloCloudSessionGetErrors] + +export type KiloCloudSessionGetResponses = { + /** + * Cloud session data + */ + 200: { + info: { + id: string + title: string + time: { + created: number + updated: number + } + } + messages: Array<{ + info: { + id: string + sessionID: string + role: "user" | "assistant" + time: { + created: number + completed?: number + } + } + parts: Array<{ + id: string + sessionID: string + messageID: string + type: string + }> + }> + } +} + +export type KiloCloudSessionGetResponse = KiloCloudSessionGetResponses[keyof KiloCloudSessionGetResponses] + +export type KiloCloudSessionImportData = { + body?: { + sessionId: string + } + path?: never + query?: { + directory?: string + workspace?: string + } + url: "/kilo/cloud/session/import" +} + +export type KiloCloudSessionImportErrors = { + /** + * Bad request + */ + 400: BadRequestError + /** + * Not found + */ + 404: NotFoundError +} + +export type KiloCloudSessionImportError = KiloCloudSessionImportErrors[keyof KiloCloudSessionImportErrors] + +export type KiloCloudSessionImportResponses = { + /** + * Imported session info + */ + 200: { + id: string + title: string + time: { + created: number + updated: number + } + } +} + +export type KiloCloudSessionImportResponse = KiloCloudSessionImportResponses[keyof KiloCloudSessionImportResponses] + export type KilocodeHeapSnapshotData = { body?: never path?: never diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index f54f62de1fa..41c446d2567 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -9222,12 +9222,12 @@ } } }, - "500": { - "description": "InternalServerError", + "503": { + "description": "ServiceUnavailable", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/effect_HttpApiError_InternalServerError" + "$ref": "#/components/schemas/effect_HttpApiError_ServiceUnavailable" } } } @@ -9303,6 +9303,376 @@ ] } }, + "/kilo/cloud-sessions": { + "get": { + "tags": ["kilo"], + "operationId": "kilo.cloudSessions", + "parameters": [ + { + "name": "directory", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "workspace", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "cursor", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "number" + }, + "required": false + }, + { + "name": "gitUrl", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Cloud sessions list", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "cliSessions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "session_id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "version": { + "type": "number" + } + }, + "required": ["session_id", "title", "created_at", "updated_at", "version"], + "additionalProperties": false + } + }, + "nextCursor": { + "type": "string" + } + }, + "required": ["cliSessions", "nextCursor"], + "additionalProperties": false, + "description": "Cloud sessions list" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "description": "Fetch cloud CLI sessions from Kilo API", + "summary": "Get cloud sessions", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.kilo.cloudSessions({\n ...\n})" + } + ] + } + }, + "/kilo/cloud/session/{id}": { + "get": { + "tags": ["kilo"], + "operationId": "kilo.cloud.session.get", + "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": "Cloud session data", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "info": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "time": { + "type": "object", + "properties": { + "created": { + "type": "number" + }, + "updated": { + "type": "number" + } + }, + "required": ["created", "updated"], + "additionalProperties": false + } + }, + "required": ["id", "title", "time"], + "additionalProperties": false + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "info": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "role": { + "type": "string", + "enum": ["user", "assistant"] + }, + "time": { + "type": "object", + "properties": { + "created": { + "type": "number" + }, + "completed": { + "type": "number" + } + }, + "required": ["created"], + "additionalProperties": false + } + }, + "required": ["id", "sessionID", "role", "time"], + "additionalProperties": false + }, + "parts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": ["id", "sessionID", "messageID", "type"], + "additionalProperties": false + } + } + }, + "required": ["info", "parts"], + "additionalProperties": false + } + } + }, + "required": ["info", "messages"], + "additionalProperties": false, + "description": "Cloud session data" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "description": "Fetch full session data from the Kilo cloud for preview", + "summary": "Get cloud session", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.kilo.cloud.session.get({\n ...\n})" + } + ] + } + }, + "/kilo/cloud/session/import": { + "post": { + "tags": ["kilo"], + "operationId": "kilo.cloud.session.import", + "parameters": [ + { + "name": "directory", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "workspace", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Imported session info", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "time": { + "type": "object", + "properties": { + "created": { + "type": "number" + }, + "updated": { + "type": "number" + } + }, + "required": ["created", "updated"], + "additionalProperties": false + } + }, + "required": ["id", "title", "time"], + "additionalProperties": false, + "description": "Imported session info" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "description": "Download a cloud-synced session and write it to local storage with fresh IDs.", + "summary": "Import session from cloud", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sessionId": { + "type": "string" + } + }, + "required": ["sessionId"], + "additionalProperties": false + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.kilo.cloud.session.import({\n ...\n})" + } + ] + } + }, "/kilocode/heap/snapshot": { "post": { "tags": ["kilocode"], @@ -16391,12 +16761,12 @@ "required": ["_tag"], "additionalProperties": false }, - "effect_HttpApiError_InternalServerError": { + "effect_HttpApiError_ServiceUnavailable": { "type": "object", "properties": { "_tag": { "type": "string", - "enum": ["InternalServerError"] + "enum": ["ServiceUnavailable"] } }, "required": ["_tag"],