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
This commit is contained in:
Imanol Maiztegui
2026-05-18 14:38:21 +02:00
parent 580a94aaaf
commit f560e5bd7a
11 changed files with 893 additions and 68 deletions
+2
View File
@@ -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,
@@ -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<void>
}
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<ClawChatC
eventServiceUrl: KILO_EVENT_SERVICE_URL,
}
}
export async function getCloudSessions(token: string, input: CloudSessionsInput) {
const query: Record<string, unknown> = {}
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 }
}
+3 -56
View File
@@ -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<string, unknown> = {}
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)
}
@@ -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({
@@ -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)
}),
)
@@ -39,6 +39,9 @@ export function register(app: Hono, handler: Handler, context: Context.Context<u
app.post(KiloGatewayPaths.organization, (c) => 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
}
@@ -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<string, OpenApiSchema>
@@ -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()
+129
View File
@@ -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<ThrowOnError extends boolean = false>(
parameters: {
id: string
directory?: string
workspace?: string
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams(
[parameters],
[
{
args: [
{ in: "path", key: "id" },
{ in: "query", key: "directory" },
{ in: "query", key: "workspace" },
],
},
],
)
return (options?.client ?? this.client).get<KiloCloudSessionGetResponses, KiloCloudSessionGetErrors, ThrowOnError>({
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<ThrowOnError extends boolean = false>(
parameters?: {
directory?: string
workspace?: string
sessionId?: string
},
options?: Options<never, ThrowOnError>,
) {
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<ThrowOnError extends boolean = false>(
parameters?: {
directory?: string
workspace?: string
cursor?: string
limit?: number
gitUrl?: string
},
options?: Options<never, ThrowOnError>,
) {
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<KiloCloudSessionsResponses, KiloCloudSessionsErrors, ThrowOnError>({
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 {
+141 -4
View File
@@ -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
+375 -5
View File
@@ -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"],