mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-28 19:11:03 +08:00
feat: promote Kilo mobile app to Cloud Agent users
Show a dismissible in-app notice pointing Cloud Agent (/remote) users at the Kilo mobile app, in both the VS Code extension and the CLI. - CLI: Notices.markCloudAgentUsed() (src/kilocode/notices.ts) persists a machine-global flag under Global.Path.state/notices.json when enableRemote() succeeds (src/kilo-sessions/kilo-sessions.ts). A new local kilo serve endpoint (kilocode.mobileAppNotice / kilocode.dismissMobileAppNotice) exposes/gates this flag for any client. The TUI session route shows the existing DialogRetryAction dialog and persists dismissal via the endpoint. - VS Code: fetchAndSendNotifications() merges a locally-constructed notification into the existing KiloNotifications banner when the local kilo serve reports show=true, reusing the existing kilo.dismissedNotificationIds globalState dismiss flow and also propagating dismissal back to the CLI-side flag. - Regenerated the SDK for the new kilocode.mobileAppNotice / dismissMobileAppNotice endpoints.
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"kilo-code": minor
|
||||
"@kilocode/cli": minor
|
||||
---
|
||||
|
||||
Show a dismissible notice promoting the Kilo mobile app to users who have previously used Cloud Agents (the `/remote` command in the CLI). The notice links to the mobile app announcement and stays hidden for everyone else, and once dismissed it never shows again.
|
||||
@@ -33,6 +33,29 @@ export interface NotificationsContext {
|
||||
notify: (id: string) => void
|
||||
}
|
||||
|
||||
const MOBILE_APP_NOTICE_ID = "mobile-app-promo"
|
||||
const MOBILE_APP_NOTICE_URL = "https://blog.kilo.ai/p/kilo-app-for-ios-and-android-is-live"
|
||||
|
||||
/**
|
||||
* Purely local (non-server-fetched) notice promoting the Kilo mobile app. Gated by the
|
||||
* local `kilo serve` instance's `kilocode.mobileAppNotice()` endpoint, which is only true
|
||||
* for users who have previously enabled a Cloud Agent / remote session relay from the CLI
|
||||
* (see `Notices.markCloudAgentUsed()` in `packages/opencode/src/kilocode/notices.ts`).
|
||||
* Dismissal reuses the existing `kilo.dismissedNotificationIds` globalState flow below.
|
||||
*/
|
||||
async function localNotifications(client: KiloClient): Promise<NotificationItem[]> {
|
||||
const res = await client.kilocode.mobileAppNotice().catch(() => null)
|
||||
if (!res?.data?.show) return []
|
||||
return [
|
||||
{
|
||||
id: MOBILE_APP_NOTICE_ID,
|
||||
title: "Kilo Mobile App",
|
||||
message: "Continue your /remote sessions in the Kilo mobile app.",
|
||||
action: { actionText: "Open", actionURL: MOBILE_APP_NOTICE_URL },
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
export async function fetchAndSendNotifications(ctx: NotificationsContext): Promise<void> {
|
||||
if (!ctx.client) {
|
||||
const cached = ctx.cached()
|
||||
@@ -48,8 +71,11 @@ export async function fetchAndSendNotifications(ctx: NotificationsContext): Prom
|
||||
}
|
||||
|
||||
try {
|
||||
const { data: all } = await retry(() => ctx.client!.kilo.notifications(undefined, { throwOnError: true }))
|
||||
const notifications = all.filter((n) => !n.showIn || n.showIn.includes("extension"))
|
||||
const [{ data: all }, local] = await Promise.all([
|
||||
retry(() => ctx.client!.kilo.notifications(undefined, { throwOnError: true })),
|
||||
localNotifications(ctx.client),
|
||||
])
|
||||
const notifications = [...local, ...all.filter((n) => !n.showIn || n.showIn.includes("extension"))]
|
||||
const existing = ctx.context?.globalState.get<string[]>(KEY, []) ?? []
|
||||
const active = new Set(notifications.map((n) => n.id))
|
||||
const dismissedIds = notifications.length > 0 ? existing.filter((id) => active.has(id)) : existing
|
||||
@@ -67,6 +93,10 @@ export async function dismissNotification(ctx: NotificationsContext, id: string)
|
||||
const existing = ctx.context.globalState.get<string[]>(KEY, [])
|
||||
if (!existing.includes(id)) await ctx.context.globalState.update(KEY, [...existing, id])
|
||||
|
||||
// Also persist dismissal on the local kilo serve instance so the CLI/TUI (which shares
|
||||
// the same machine-global notice flag) stops showing it too.
|
||||
if (id === MOBILE_APP_NOTICE_ID) await ctx.client?.kilocode.dismissMobileAppNotice().catch(() => undefined)
|
||||
|
||||
const cached = ctx.cached()
|
||||
if (cached && !cached.dismissedIds.includes(id)) {
|
||||
ctx.set({
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import { describe, expect, it } from "bun:test"
|
||||
import {
|
||||
dismissNotification,
|
||||
fetchAndSendNotifications,
|
||||
type NotificationsContext,
|
||||
} from "../../src/kilo-provider/notifications"
|
||||
|
||||
function makeContext(input: { show: boolean; initialDismissed?: string[] }) {
|
||||
const flag = new Map<string, unknown>(
|
||||
input.initialDismissed ? [["kilo.dismissedNotificationIds", input.initialDismissed]] : [],
|
||||
)
|
||||
let dismissMobileAppNoticeCalls = 0
|
||||
let cached: NotificationsContext["cached"] extends () => infer R ? R : never = null
|
||||
const posted: unknown[] = []
|
||||
|
||||
const client = {
|
||||
kilo: {
|
||||
notifications: async () => ({ data: [] }),
|
||||
},
|
||||
kilocode: {
|
||||
mobileAppNotice: async () => ({ data: { show: input.show } }),
|
||||
dismissMobileAppNotice: async () => {
|
||||
dismissMobileAppNoticeCalls++
|
||||
return { data: true }
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const ctx: NotificationsContext = {
|
||||
context: {
|
||||
globalState: {
|
||||
get: <T>(key: string, fallback?: T) => (flag.has(key) ? (flag.get(key) as T) : fallback),
|
||||
update: async (key: string, value: unknown) => {
|
||||
flag.set(key, value)
|
||||
},
|
||||
},
|
||||
} as any,
|
||||
client: client as any,
|
||||
cached: () => cached,
|
||||
set: (message) => {
|
||||
cached = message
|
||||
},
|
||||
post: (message) => {
|
||||
posted.push(message)
|
||||
},
|
||||
notify: () => {},
|
||||
}
|
||||
|
||||
return { ctx, flag, posted, dismissMobileAppNoticeCallCount: () => dismissMobileAppNoticeCalls }
|
||||
}
|
||||
|
||||
describe("mobile app promo notice", () => {
|
||||
it("is included when the local kilo serve reports Cloud Agent usage", async () => {
|
||||
const { ctx, posted } = makeContext({ show: true })
|
||||
|
||||
await fetchAndSendNotifications(ctx)
|
||||
|
||||
const message = posted[0] as { notifications: { id: string }[] }
|
||||
expect(message.notifications.some((n) => n.id === "mobile-app-promo")).toBe(true)
|
||||
})
|
||||
|
||||
it("is omitted for users who have never used a Cloud Agent / remote session", async () => {
|
||||
const { ctx, posted } = makeContext({ show: false })
|
||||
|
||||
await fetchAndSendNotifications(ctx)
|
||||
|
||||
const message = posted[0] as { notifications: { id: string }[] }
|
||||
expect(message.notifications.some((n) => n.id === "mobile-app-promo")).toBe(false)
|
||||
})
|
||||
|
||||
it("persists dismissal in globalState and propagates it to the local kilo serve instance", async () => {
|
||||
const { ctx, flag, dismissMobileAppNoticeCallCount } = makeContext({ show: true })
|
||||
|
||||
await fetchAndSendNotifications(ctx)
|
||||
await dismissNotification(ctx, "mobile-app-promo")
|
||||
|
||||
expect(flag.get("kilo.dismissedNotificationIds")).toContain("mobile-app-promo")
|
||||
expect(dismissMobileAppNoticeCallCount()).toBe(1)
|
||||
})
|
||||
|
||||
it("keeps the notice dismissed across subsequent fetches even though the server still reports show=true", async () => {
|
||||
const { ctx, posted } = makeContext({ show: true, initialDismissed: ["mobile-app-promo"] })
|
||||
|
||||
await fetchAndSendNotifications(ctx)
|
||||
|
||||
const message = posted[0] as { notifications: { id: string }[]; dismissedIds: string[] }
|
||||
expect(message.notifications.some((n) => n.id === "mobile-app-promo")).toBe(true)
|
||||
expect(message.dismissedIds).toContain("mobile-app-promo")
|
||||
})
|
||||
})
|
||||
@@ -116,6 +116,7 @@ import { getScrollAcceleration } from "../../util/scroll"
|
||||
import { collapseToolOutput } from "../../util/collapse-tool-output"
|
||||
import { TuiPluginRuntime } from "@/cli/cmd/tui/plugin/runtime"
|
||||
import { DialogRetryAction } from "../../component/dialog-retry-action"
|
||||
import { useMobileAppNotice } from "@/kilocode/cli/cmd/tui/routes/session/mobile-app-notice" // kilocode_change
|
||||
import { SessionRetry } from "@/session/retry"
|
||||
import { getRevertDiffFiles } from "../../util/revert-diff"
|
||||
import { KILO_BASE_MODE, useBindings, useCommandShortcut, useOpencodeKeymap } from "../../keymap"
|
||||
@@ -460,6 +461,8 @@ export function Session() {
|
||||
return exit.message.set(banner(title, session()?.id, UI.Style.TEXT_DIM, UI.Style.TEXT_NORMAL))
|
||||
})
|
||||
|
||||
useMobileAppNotice({ sdk, dialog })
|
||||
|
||||
const [exitPress, setExitPress] = createSignal(0)
|
||||
useBindings(() => ({
|
||||
enabled: Boolean(session()?.parentID),
|
||||
|
||||
@@ -25,6 +25,7 @@ import { Vcs } from "@/project/vcs"
|
||||
import simpleGit from "simple-git"
|
||||
import { RemoteWS } from "@/kilo-sessions/remote-ws"
|
||||
import { RemoteSender } from "@/kilo-sessions/remote-sender"
|
||||
import { Notices } from "@/kilocode/notices" // kilocode_change
|
||||
import { SessionStatus } from "@/session/status"
|
||||
import { Telemetry } from "@kilocode/kilo-telemetry"
|
||||
import { Question } from "@/question"
|
||||
@@ -465,6 +466,9 @@ export namespace KiloSessions {
|
||||
remote = { conn, sender }
|
||||
log.info("remote connection enabled", { connected: conn.connected })
|
||||
Telemetry.trackRemoteConnectionOpened()
|
||||
// kilocode_change start - mark Cloud Agent (remote) usage so cross-surface promo notices can target these users
|
||||
void Notices.markCloudAgentUsed().catch((err) => log.warn("failed to persist cloud agent usage", { error: String(err) }))
|
||||
// kilocode_change end
|
||||
void Bus.publish(Instance.current, Event.RemoteStatusChanged, { enabled: true, connected: conn.connected })
|
||||
})()
|
||||
.catch((err) => {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// kilocode_change - new file
|
||||
/**
|
||||
* "Continue your /remote sessions in the Kilo mobile app" promo notice.
|
||||
*
|
||||
* Only shown to users who have previously enabled a Cloud Agent / remote session relay
|
||||
* (`Notices.markCloudAgentUsed()` in `@/kilocode/notices`, set from `enableRemote()` in
|
||||
* `src/kilo-sessions/kilo-sessions.ts`). Persists until the user explicitly dismisses it
|
||||
* via the "don't show again" action.
|
||||
*/
|
||||
import { onMount } from "solid-js"
|
||||
import type { useDialog } from "@tui/ui/dialog"
|
||||
import { DialogRetryAction } from "@tui/component/dialog-retry-action"
|
||||
|
||||
export const MOBILE_APP_NOTICE_URL = "https://blog.kilo.ai/p/kilo-app-for-ios-and-android-is-live"
|
||||
|
||||
// Loosely typed to avoid coupling this module to the exact generated SDK client shape.
|
||||
type SDKLike = {
|
||||
client: {
|
||||
kilocode: {
|
||||
mobileAppNotice: (...args: any[]) => Promise<{ data?: { show: boolean } }>
|
||||
dismissMobileAppNotice: (...args: any[]) => Promise<unknown>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function useMobileAppNotice(deps: { sdk: SDKLike; dialog: ReturnType<typeof useDialog> }) {
|
||||
onMount(() => {
|
||||
void (async () => {
|
||||
if (deps.dialog.stack.length > 0) return
|
||||
const res = await deps.sdk.client.kilocode.mobileAppNotice().catch(() => null)
|
||||
if (!res?.data?.show) return
|
||||
if (deps.dialog.stack.length > 0) return
|
||||
|
||||
const dontShowAgain = await DialogRetryAction.show(deps.dialog, {
|
||||
title: "Kilo Mobile App",
|
||||
message: "Continue your /remote sessions in the Kilo mobile app.",
|
||||
label: "Open",
|
||||
link: MOBILE_APP_NOTICE_URL,
|
||||
})
|
||||
if (dontShowAgain) await deps.sdk.client.kilocode.dismissMobileAppNotice().catch(() => undefined)
|
||||
})()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Persisted, machine-global "notice" flags shared by every Kilo surface (TUI, VS Code
|
||||
* extension, etc.) that talks to a local `kilo serve` instance.
|
||||
*
|
||||
* Backed by a small JSON file under `Global.Path.state` so it survives across CLI
|
||||
* invocations and is visible to the VS Code extension's embedded `kilo serve` process,
|
||||
* without requiring a database or per-project scoping.
|
||||
*/
|
||||
import path from "path"
|
||||
import { Global } from "@opencode-ai/core/global"
|
||||
import { Flock } from "@opencode-ai/core/util/flock"
|
||||
import { Filesystem } from "@/util/filesystem"
|
||||
|
||||
const CLOUD_AGENT_USED = "cloud_agent_used"
|
||||
const MOBILE_APP_NOTICE_DISMISSED = "mobile_app_notice_dismissed"
|
||||
|
||||
export namespace Notices {
|
||||
const filePath = path.join(Global.Path.state, "notices.json")
|
||||
const lock = `kilo-notices:${filePath}`
|
||||
|
||||
async function read(): Promise<Record<string, boolean | undefined>> {
|
||||
return Filesystem.readJson<Record<string, boolean | undefined>>(filePath).catch(() => ({}))
|
||||
}
|
||||
|
||||
async function update(patch: Record<string, boolean>): Promise<void> {
|
||||
await Flock.withLock(lock, async () => {
|
||||
const current = await read()
|
||||
await Filesystem.writeJson(filePath, { ...current, ...patch })
|
||||
})
|
||||
}
|
||||
|
||||
/** Record that the user has enabled a remote/Cloud Agent session relay at least once. */
|
||||
export async function markCloudAgentUsed(): Promise<void> {
|
||||
const current = await read()
|
||||
if (current[CLOUD_AGENT_USED]) return
|
||||
await update({ [CLOUD_AGENT_USED]: true })
|
||||
}
|
||||
|
||||
/** Whether the "continue in the Kilo mobile app" notice should be shown. */
|
||||
export async function shouldShowMobileAppNotice(): Promise<boolean> {
|
||||
const current = await read()
|
||||
return !!current[CLOUD_AGENT_USED] && !current[MOBILE_APP_NOTICE_DISMISSED]
|
||||
}
|
||||
|
||||
export async function dismissMobileAppNotice(): Promise<void> {
|
||||
await update({ [MOBILE_APP_NOTICE_DISMISSED]: true })
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,10 @@ export const RemoveSkillPayload = Schema.Struct({
|
||||
location: Schema.String,
|
||||
})
|
||||
|
||||
export const MobileAppNotice = Schema.Struct({
|
||||
show: Schema.Boolean,
|
||||
})
|
||||
|
||||
export const RemoveAgentPayload = Schema.Struct({
|
||||
name: Schema.String,
|
||||
})
|
||||
@@ -45,6 +49,8 @@ export const KilocodePaths = {
|
||||
notebookReply: `${root}/notebook/:requestID/reply`,
|
||||
notebookReject: `${root}/notebook/:requestID/reject`,
|
||||
sessionModelUsage: `/session/:sessionID/model-usage`,
|
||||
mobileAppNotice: `${root}/notice/mobile-app`,
|
||||
dismissMobileAppNotice: `${root}/notice/mobile-app/dismiss`,
|
||||
} as const
|
||||
|
||||
export const KilocodeApi = HttpApi.make("kilocode")
|
||||
@@ -145,6 +151,27 @@ export const KilocodeApi = HttpApi.make("kilocode")
|
||||
description: "Get token usage and direct cost by model for the complete top-level session tree.",
|
||||
}),
|
||||
),
|
||||
HttpApiEndpoint.get("mobileAppNotice", KilocodePaths.mobileAppNotice, {
|
||||
query: WorkspaceRoutingQuery,
|
||||
success: described(MobileAppNotice, "Mobile app notice visibility"),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "kilocode.mobileAppNotice",
|
||||
summary: "Get mobile app notice visibility",
|
||||
description:
|
||||
"Whether to show the 'continue your /remote sessions in the Kilo mobile app' notice. Only true for users who have previously used a Cloud Agent / remote session relay and have not dismissed the notice.",
|
||||
}),
|
||||
),
|
||||
HttpApiEndpoint.post("dismissMobileAppNotice", KilocodePaths.dismissMobileAppNotice, {
|
||||
query: WorkspaceRoutingQuery,
|
||||
success: described(Schema.Boolean, "Notice dismissed"),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "kilocode.dismissMobileAppNotice",
|
||||
summary: "Dismiss mobile app notice",
|
||||
description: "Permanently dismiss the Kilo mobile app promo notice for this machine.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
|
||||
@@ -4,10 +4,12 @@ import * as KiloAgent from "@/kilocode/agent"
|
||||
import * as KiloSkill from "@/kilocode/skill-remove"
|
||||
import { Agent } from "@/agent/agent"
|
||||
import { Config } from "@/config/config"
|
||||
import { EffectBridge } from "@/effect/bridge"
|
||||
import { InstanceState } from "@/effect/instance-state"
|
||||
import { HeapSnapshot } from "@/kilocode/cli/heap-snapshot"
|
||||
import type { RequestID as NotebookRequestID } from "@/kilocode/notebook/protocol"
|
||||
import { Notebook } from "@/kilocode/notebook/service"
|
||||
import { Notices } from "@/kilocode/notices"
|
||||
import { ModelUsage } from "@/kilocode/session/model-usage"
|
||||
import { InstanceStore } from "@/project/instance-store"
|
||||
import { InstanceHttpApi } from "@/server/routes/instance/httpapi/api"
|
||||
@@ -98,6 +100,16 @@ export const kilocodeHandlers = HttpApiBuilder.group(InstanceHttpApi, "kilocode"
|
||||
return usage
|
||||
})
|
||||
|
||||
const mobileAppNotice = Effect.fn("KilocodeHttpApi.mobileAppNotice")(function* () {
|
||||
const show = yield* EffectBridge.fromPromise(() => Notices.shouldShowMobileAppNotice())
|
||||
return { show }
|
||||
})
|
||||
|
||||
const dismissMobileAppNotice = Effect.fn("KilocodeHttpApi.dismissMobileAppNotice")(function* () {
|
||||
yield* EffectBridge.fromPromise(() => Notices.dismissMobileAppNotice())
|
||||
return true
|
||||
})
|
||||
|
||||
return handlers
|
||||
.handle("heapSnapshot", heapSnapshot)
|
||||
.handle("agentRequirements", agentRequirements)
|
||||
@@ -107,5 +119,7 @@ export const kilocodeHandlers = HttpApiBuilder.group(InstanceHttpApi, "kilocode"
|
||||
.handle("notebookReply", notebookReply)
|
||||
.handle("notebookReject", notebookReject)
|
||||
.handle("sessionModelUsage", sessionModelUsage)
|
||||
.handle("mobileAppNotice", mobileAppNotice)
|
||||
.handle("dismissMobileAppNotice", dismissMobileAppNotice)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { afterEach, beforeEach, describe, expect, test } from "bun:test"
|
||||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
import { Global } from "@opencode-ai/core/global"
|
||||
import { Notices } from "../../src/kilocode/notices"
|
||||
|
||||
const noticesPath = path.join(Global.Path.state, "notices.json")
|
||||
|
||||
beforeEach(async () => {
|
||||
await fs.rm(noticesPath, { force: true }).catch(() => {})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(noticesPath, { force: true }).catch(() => {})
|
||||
})
|
||||
|
||||
describe("Notices (mobile app promo targeting)", () => {
|
||||
test("does not show the notice for users who have never used a Cloud Agent / remote session", async () => {
|
||||
expect(await Notices.shouldShowMobileAppNotice()).toBe(false)
|
||||
})
|
||||
|
||||
test("shows the notice once a Cloud Agent / remote session has been used", async () => {
|
||||
await Notices.markCloudAgentUsed()
|
||||
expect(await Notices.shouldShowMobileAppNotice()).toBe(true)
|
||||
})
|
||||
|
||||
test("persists dismissal so the notice never shows again, even across separate reads", async () => {
|
||||
await Notices.markCloudAgentUsed()
|
||||
expect(await Notices.shouldShowMobileAppNotice()).toBe(true)
|
||||
|
||||
await Notices.dismissMobileAppNotice()
|
||||
expect(await Notices.shouldShowMobileAppNotice()).toBe(false)
|
||||
|
||||
// Simulate re-marking cloud agent usage (e.g. re-enabling /remote) — must stay dismissed.
|
||||
await Notices.markCloudAgentUsed()
|
||||
expect(await Notices.shouldShowMobileAppNotice()).toBe(false)
|
||||
})
|
||||
|
||||
test("is idempotent when Cloud Agent usage is marked more than once", async () => {
|
||||
await Notices.markCloudAgentUsed()
|
||||
await Notices.markCloudAgentUsed()
|
||||
const raw = JSON.parse(await fs.readFile(noticesPath, "utf-8"))
|
||||
expect(raw.cloud_agent_used).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -160,8 +160,12 @@ import type {
|
||||
KiloCloudSessionsResponses,
|
||||
KilocodeAgentRequirementsErrors,
|
||||
KilocodeAgentRequirementsResponses,
|
||||
KilocodeDismissMobileAppNoticeErrors,
|
||||
KilocodeDismissMobileAppNoticeResponses,
|
||||
KilocodeHeapSnapshotErrors,
|
||||
KilocodeHeapSnapshotResponses,
|
||||
KilocodeMobileAppNoticeErrors,
|
||||
KilocodeMobileAppNoticeResponses,
|
||||
KilocodeNotebookListErrors,
|
||||
KilocodeNotebookListResponses,
|
||||
KilocodeNotebookRejectErrors,
|
||||
@@ -7846,6 +7850,74 @@ export class Kilocode extends HeyApiClient {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mobile app notice visibility
|
||||
*
|
||||
* Whether to show the 'continue your /remote sessions in the Kilo mobile app' notice. Only true for users who have previously used a Cloud Agent / remote session relay and have not dismissed the notice.
|
||||
*/
|
||||
public mobileAppNotice<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
directory?: string
|
||||
workspace?: string
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
const params = buildClientParams(
|
||||
[parameters],
|
||||
[
|
||||
{
|
||||
args: [
|
||||
{ in: "query", key: "directory" },
|
||||
{ in: "query", key: "workspace" },
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
return (options?.client ?? this.client).get<
|
||||
KilocodeMobileAppNoticeResponses,
|
||||
KilocodeMobileAppNoticeErrors,
|
||||
ThrowOnError
|
||||
>({
|
||||
url: "/kilocode/notice/mobile-app",
|
||||
...options,
|
||||
...params,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss mobile app notice
|
||||
*
|
||||
* Permanently dismiss the Kilo mobile app promo notice for this machine.
|
||||
*/
|
||||
public dismissMobileAppNotice<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
directory?: string
|
||||
workspace?: string
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
const params = buildClientParams(
|
||||
[parameters],
|
||||
[
|
||||
{
|
||||
args: [
|
||||
{ in: "query", key: "directory" },
|
||||
{ in: "query", key: "workspace" },
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
return (options?.client ?? this.client).post<
|
||||
KilocodeDismissMobileAppNoticeResponses,
|
||||
KilocodeDismissMobileAppNoticeErrors,
|
||||
ThrowOnError
|
||||
>({
|
||||
url: "/kilocode/notice/mobile-app/dismiss",
|
||||
...options,
|
||||
...params,
|
||||
})
|
||||
}
|
||||
|
||||
private _heap?: Heap
|
||||
get heap(): Heap {
|
||||
return (this._heap ??= new Heap({ client: this.client }))
|
||||
|
||||
@@ -5,20 +5,10 @@ export type ClientOptions = {
|
||||
}
|
||||
|
||||
export type Event =
|
||||
| EventServerInstanceDisposed
|
||||
| EventServerConnected
|
||||
| EventGlobalDisposed
|
||||
| EventGlobalConfigUpdated
|
||||
| EventTuiPromptAppend
|
||||
| EventTuiCommandExecute
|
||||
| EventTuiToastShow1
|
||||
| EventTuiSessionSelect
|
||||
| EventSandboxStatusChanged
|
||||
| EventKilocodeAgentManagerStart
|
||||
| EventKilocodeNotebookRequested
|
||||
| EventKilocodeNotebookCancelled
|
||||
| EventIndexingStatus
|
||||
| EventIndexingWarning
|
||||
| EventServerInstanceDisposed
|
||||
| EventFileEdited
|
||||
| EventFileWatcherUpdated
|
||||
| EventQuestionAsked
|
||||
@@ -26,6 +16,10 @@ export type Event =
|
||||
| EventQuestionRejected
|
||||
| EventLspClientDiagnostics
|
||||
| EventLspUpdated
|
||||
| EventTuiPromptAppend
|
||||
| EventTuiCommandExecute
|
||||
| EventTuiToastShow1
|
||||
| EventTuiSessionSelect
|
||||
| EventMcpToolsChanged
|
||||
| EventMcpBrowserOpenFailed
|
||||
| EventSessionNetworkAsked
|
||||
@@ -42,6 +36,7 @@ export type Event =
|
||||
| EventInteractiveTerminalDeleted
|
||||
| EventSessionTurnOpen
|
||||
| EventSessionTurnClose
|
||||
| EventSandboxStatusChanged
|
||||
| EventSessionDiff
|
||||
| EventSessionError
|
||||
| EventTodoUpdated
|
||||
@@ -55,6 +50,9 @@ export type Event =
|
||||
| EventCommandExecuted
|
||||
| EventProjectUpdated
|
||||
| EventSessionCompacted
|
||||
| EventKilocodeAgentManagerStart
|
||||
| EventKilocodeNotebookRequested
|
||||
| EventKilocodeNotebookCancelled
|
||||
| EventVcsBranchUpdated
|
||||
| EventKiloSessionsRemoteStatusChanged
|
||||
| EventWorkspaceReady
|
||||
@@ -99,9 +97,11 @@ export type Event =
|
||||
| EventSessionNextCompactionStarted
|
||||
| EventSessionNextCompactionDelta
|
||||
| EventSessionNextCompactionEnded
|
||||
| EventIndexingStatus
|
||||
| EventIndexingWarning
|
||||
| EventModelsDevRefreshed
|
||||
| EventPluginAdded
|
||||
| EventCatalogModelUpdated
|
||||
| EventModelsDevRefreshed
|
||||
| EventAccountAdded
|
||||
| EventAccountRemoved
|
||||
| EventAccountSwitched
|
||||
@@ -142,137 +142,6 @@ export type InvalidRequestError = {
|
||||
field?: string
|
||||
}
|
||||
|
||||
export type EventTuiPromptAppend = {
|
||||
id: string
|
||||
type: "tui.prompt.append"
|
||||
properties: {
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type EventTuiCommandExecute = {
|
||||
id: string
|
||||
type: "tui.command.execute"
|
||||
properties: {
|
||||
command:
|
||||
| "session.list"
|
||||
| "session.new"
|
||||
| "session.share"
|
||||
| "session.interrupt"
|
||||
| "session.compact"
|
||||
| "session.page.up"
|
||||
| "session.page.down"
|
||||
| "session.line.up"
|
||||
| "session.line.down"
|
||||
| "session.half.page.up"
|
||||
| "session.half.page.down"
|
||||
| "session.first"
|
||||
| "session.last"
|
||||
| "prompt.clear"
|
||||
| "prompt.submit"
|
||||
| "agent.cycle"
|
||||
| string
|
||||
}
|
||||
}
|
||||
|
||||
export type EventTuiToastShow = {
|
||||
id: string
|
||||
type: "tui.toast.show"
|
||||
properties: {
|
||||
title?: string
|
||||
message: string
|
||||
variant: "info" | "success" | "warning" | "error"
|
||||
duration?: number
|
||||
}
|
||||
}
|
||||
|
||||
export type EventTuiSessionSelect = {
|
||||
id: string
|
||||
type: "tui.session.select"
|
||||
properties: {
|
||||
/**
|
||||
* Session ID to navigate to
|
||||
*/
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type NotebookRequestId = string
|
||||
|
||||
export type NotebookReadRequest = {
|
||||
id: NotebookRequestId
|
||||
sessionID: string
|
||||
path: string
|
||||
operation: "read"
|
||||
includeOutputs: boolean
|
||||
}
|
||||
|
||||
export type NotebookEditRequest = {
|
||||
id: NotebookRequestId
|
||||
sessionID: string
|
||||
path: string
|
||||
operation: "edit"
|
||||
/**
|
||||
* Opaque notebook content revision; pass it back unchanged and do not parse or increment it
|
||||
*/
|
||||
expectedRevision?: string
|
||||
/**
|
||||
* Zero-based cell index
|
||||
*/
|
||||
index: number
|
||||
edit:
|
||||
| {
|
||||
action: "insert"
|
||||
kind: "code" | "markdown"
|
||||
language?: string
|
||||
source: string
|
||||
}
|
||||
| {
|
||||
action: "replace"
|
||||
kind: "code" | "markdown"
|
||||
language?: string
|
||||
source: string
|
||||
}
|
||||
| {
|
||||
action: "delete"
|
||||
}
|
||||
| {
|
||||
action: "create"
|
||||
}
|
||||
}
|
||||
|
||||
export type NotebookExecuteRequest = {
|
||||
id: NotebookRequestId
|
||||
sessionID: string
|
||||
path: string
|
||||
operation: "execute"
|
||||
/**
|
||||
* Opaque notebook content revision; pass it back unchanged and do not parse or increment it
|
||||
*/
|
||||
expectedRevision: string
|
||||
/**
|
||||
* Zero-based cell index
|
||||
*/
|
||||
index: number
|
||||
}
|
||||
|
||||
export type NotebookRequest = NotebookReadRequest | NotebookEditRequest | NotebookExecuteRequest
|
||||
|
||||
export type IndexingStatusState = "Disabled" | "In Progress" | "Complete" | "Error" | "Standby"
|
||||
|
||||
export type IndexingStatus = {
|
||||
state: IndexingStatusState
|
||||
message: string
|
||||
processedFiles: number
|
||||
totalFiles: number
|
||||
percent: number
|
||||
}
|
||||
|
||||
export type IndexingWarning = {
|
||||
code: "qdrant.version-incompatible" | "qdrant.version-unavailable"
|
||||
message: string
|
||||
}
|
||||
|
||||
export type QuestionOption = {
|
||||
/**
|
||||
* Display text (1-5 words, concise)
|
||||
@@ -335,6 +204,61 @@ export type QuestionRejected = {
|
||||
requestID: string
|
||||
}
|
||||
|
||||
export type EventTuiPromptAppend = {
|
||||
id: string
|
||||
type: "tui.prompt.append"
|
||||
properties: {
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
export type EventTuiCommandExecute = {
|
||||
id: string
|
||||
type: "tui.command.execute"
|
||||
properties: {
|
||||
command:
|
||||
| "session.list"
|
||||
| "session.new"
|
||||
| "session.share"
|
||||
| "session.interrupt"
|
||||
| "session.compact"
|
||||
| "session.page.up"
|
||||
| "session.page.down"
|
||||
| "session.line.up"
|
||||
| "session.line.down"
|
||||
| "session.half.page.up"
|
||||
| "session.half.page.down"
|
||||
| "session.first"
|
||||
| "session.last"
|
||||
| "prompt.clear"
|
||||
| "prompt.submit"
|
||||
| "agent.cycle"
|
||||
| string
|
||||
}
|
||||
}
|
||||
|
||||
export type EventTuiToastShow = {
|
||||
id: string
|
||||
type: "tui.toast.show"
|
||||
properties: {
|
||||
title?: string
|
||||
message: string
|
||||
variant: "info" | "success" | "warning" | "error"
|
||||
duration?: number
|
||||
}
|
||||
}
|
||||
|
||||
export type EventTuiSessionSelect = {
|
||||
id: string
|
||||
type: "tui.session.select"
|
||||
properties: {
|
||||
/**
|
||||
* Session ID to navigate to
|
||||
*/
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionNetworkWait = {
|
||||
id: string
|
||||
sessionID: string
|
||||
@@ -584,6 +508,67 @@ export type Project = {
|
||||
sandboxes: Array<string>
|
||||
}
|
||||
|
||||
export type NotebookRequestId = string
|
||||
|
||||
export type NotebookReadRequest = {
|
||||
id: NotebookRequestId
|
||||
sessionID: string
|
||||
path: string
|
||||
operation: "read"
|
||||
includeOutputs: boolean
|
||||
}
|
||||
|
||||
export type NotebookEditRequest = {
|
||||
id: NotebookRequestId
|
||||
sessionID: string
|
||||
path: string
|
||||
operation: "edit"
|
||||
/**
|
||||
* Opaque notebook content revision; pass it back unchanged and do not parse or increment it
|
||||
*/
|
||||
expectedRevision?: string
|
||||
/**
|
||||
* Zero-based cell index
|
||||
*/
|
||||
index: number
|
||||
edit:
|
||||
| {
|
||||
action: "insert"
|
||||
kind: "code" | "markdown"
|
||||
language?: string
|
||||
source: string
|
||||
}
|
||||
| {
|
||||
action: "replace"
|
||||
kind: "code" | "markdown"
|
||||
language?: string
|
||||
source: string
|
||||
}
|
||||
| {
|
||||
action: "delete"
|
||||
}
|
||||
| {
|
||||
action: "create"
|
||||
}
|
||||
}
|
||||
|
||||
export type NotebookExecuteRequest = {
|
||||
id: NotebookRequestId
|
||||
sessionID: string
|
||||
path: string
|
||||
operation: "execute"
|
||||
/**
|
||||
* Opaque notebook content revision; pass it back unchanged and do not parse or increment it
|
||||
*/
|
||||
expectedRevision: string
|
||||
/**
|
||||
* Zero-based cell index
|
||||
*/
|
||||
index: number
|
||||
}
|
||||
|
||||
export type NotebookRequest = NotebookReadRequest | NotebookEditRequest | NotebookExecuteRequest
|
||||
|
||||
export type Pty = {
|
||||
id: string
|
||||
title: string
|
||||
@@ -1030,25 +1015,30 @@ export type Prompt = {
|
||||
references?: Array<PromptReferenceAttachment>
|
||||
}
|
||||
|
||||
export type IndexingStatusState = "Disabled" | "In Progress" | "Complete" | "Error" | "Standby"
|
||||
|
||||
export type IndexingStatus = {
|
||||
state: IndexingStatusState
|
||||
message: string
|
||||
processedFiles: number
|
||||
totalFiles: number
|
||||
percent: number
|
||||
}
|
||||
|
||||
export type IndexingWarning = {
|
||||
code: "qdrant.version-incompatible" | "qdrant.version-unavailable"
|
||||
message: string
|
||||
}
|
||||
|
||||
export type GlobalEvent = {
|
||||
directory: string
|
||||
project?: string
|
||||
workspace?: string
|
||||
payload:
|
||||
| EventServerInstanceDisposed
|
||||
| EventServerConnected
|
||||
| EventGlobalDisposed
|
||||
| EventGlobalConfigUpdated
|
||||
| EventTuiPromptAppend
|
||||
| EventTuiCommandExecute
|
||||
| EventTuiToastShow
|
||||
| EventTuiSessionSelect
|
||||
| EventSandboxStatusChanged
|
||||
| EventKilocodeAgentManagerStart
|
||||
| EventKilocodeNotebookRequested
|
||||
| EventKilocodeNotebookCancelled
|
||||
| EventIndexingStatus
|
||||
| EventIndexingWarning
|
||||
| EventServerInstanceDisposed
|
||||
| EventFileEdited
|
||||
| EventFileWatcherUpdated
|
||||
| EventQuestionAsked
|
||||
@@ -1056,6 +1046,10 @@ export type GlobalEvent = {
|
||||
| EventQuestionRejected
|
||||
| EventLspClientDiagnostics
|
||||
| EventLspUpdated
|
||||
| EventTuiPromptAppend
|
||||
| EventTuiCommandExecute
|
||||
| EventTuiToastShow
|
||||
| EventTuiSessionSelect
|
||||
| EventMcpToolsChanged
|
||||
| EventMcpBrowserOpenFailed
|
||||
| EventSessionNetworkAsked
|
||||
@@ -1072,6 +1066,7 @@ export type GlobalEvent = {
|
||||
| EventInteractiveTerminalDeleted
|
||||
| EventSessionTurnOpen
|
||||
| EventSessionTurnClose
|
||||
| EventSandboxStatusChanged
|
||||
| EventSessionDiff
|
||||
| EventSessionError
|
||||
| EventTodoUpdated
|
||||
@@ -1085,6 +1080,9 @@ export type GlobalEvent = {
|
||||
| EventCommandExecuted
|
||||
| EventProjectUpdated
|
||||
| EventSessionCompacted
|
||||
| EventKilocodeAgentManagerStart
|
||||
| EventKilocodeNotebookRequested
|
||||
| EventKilocodeNotebookCancelled
|
||||
| EventVcsBranchUpdated
|
||||
| EventKiloSessionsRemoteStatusChanged
|
||||
| EventWorkspaceReady
|
||||
@@ -1129,9 +1127,11 @@ export type GlobalEvent = {
|
||||
| EventSessionNextCompactionStarted
|
||||
| EventSessionNextCompactionDelta
|
||||
| EventSessionNextCompactionEnded
|
||||
| EventIndexingStatus
|
||||
| EventIndexingWarning
|
||||
| EventModelsDevRefreshed
|
||||
| EventPluginAdded
|
||||
| EventCatalogModelUpdated
|
||||
| EventModelsDevRefreshed
|
||||
| EventAccountAdded
|
||||
| EventAccountRemoved
|
||||
| EventAccountSwitched
|
||||
@@ -3338,6 +3338,14 @@ export type SyncEventSessionNextCompactionEnded = {
|
||||
}
|
||||
}
|
||||
|
||||
export type EventServerInstanceDisposed = {
|
||||
id: string
|
||||
type: "server.instance.disposed"
|
||||
properties: {
|
||||
directory: string
|
||||
}
|
||||
}
|
||||
|
||||
export type EventServerConnected = {
|
||||
id: string
|
||||
type: "server.connected"
|
||||
@@ -3362,78 +3370,6 @@ export type EventGlobalConfigUpdated = {
|
||||
}
|
||||
}
|
||||
|
||||
export type EventSandboxStatusChanged = {
|
||||
id: string
|
||||
type: "sandbox.status.changed"
|
||||
properties: {
|
||||
sessionID: string
|
||||
directory: string
|
||||
enabled: boolean
|
||||
available: boolean
|
||||
reason?: string
|
||||
version: number
|
||||
}
|
||||
}
|
||||
|
||||
export type EventKilocodeAgentManagerStart = {
|
||||
id: string
|
||||
type: "kilocode.agent_manager.start"
|
||||
properties: {
|
||||
requestID: string
|
||||
sessionID: string
|
||||
mode: "worktree" | "local"
|
||||
versions?: boolean
|
||||
tasks: Array<{
|
||||
prompt?: string
|
||||
name?: string
|
||||
branchName?: string
|
||||
model?: {
|
||||
providerID: string
|
||||
modelID: string
|
||||
}
|
||||
variant?: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export type EventKilocodeNotebookRequested = {
|
||||
id: string
|
||||
type: "kilocode.notebook.requested"
|
||||
properties: NotebookRequest
|
||||
}
|
||||
|
||||
export type EventKilocodeNotebookCancelled = {
|
||||
id: string
|
||||
type: "kilocode.notebook.cancelled"
|
||||
properties: {
|
||||
requestID: NotebookRequestId
|
||||
sessionID: string
|
||||
reason: "cancelled" | "disposed" | "timeout"
|
||||
}
|
||||
}
|
||||
|
||||
export type EventIndexingStatus = {
|
||||
id: string
|
||||
type: "indexing.status"
|
||||
properties: {
|
||||
status: IndexingStatus
|
||||
}
|
||||
}
|
||||
|
||||
export type EventIndexingWarning = {
|
||||
id: string
|
||||
type: "indexing.warning"
|
||||
properties: IndexingWarning
|
||||
}
|
||||
|
||||
export type EventServerInstanceDisposed = {
|
||||
id: string
|
||||
type: "server.instance.disposed"
|
||||
properties: {
|
||||
directory: string
|
||||
}
|
||||
}
|
||||
|
||||
export type EventFileEdited = {
|
||||
id: string
|
||||
type: "file.edited"
|
||||
@@ -3630,6 +3566,19 @@ export type EventSessionTurnClose = {
|
||||
}
|
||||
}
|
||||
|
||||
export type EventSandboxStatusChanged = {
|
||||
id: string
|
||||
type: "sandbox.status.changed"
|
||||
properties: {
|
||||
sessionID: string
|
||||
directory: string
|
||||
enabled: boolean
|
||||
available: boolean
|
||||
reason?: string
|
||||
version: number
|
||||
}
|
||||
}
|
||||
|
||||
export type EventSessionDiff = {
|
||||
id: string
|
||||
type: "session.diff"
|
||||
@@ -3759,6 +3708,43 @@ export type EventSessionCompacted = {
|
||||
}
|
||||
}
|
||||
|
||||
export type EventKilocodeAgentManagerStart = {
|
||||
id: string
|
||||
type: "kilocode.agent_manager.start"
|
||||
properties: {
|
||||
requestID: string
|
||||
sessionID: string
|
||||
mode: "worktree" | "local"
|
||||
versions?: boolean
|
||||
tasks: Array<{
|
||||
prompt?: string
|
||||
name?: string
|
||||
branchName?: string
|
||||
model?: {
|
||||
providerID: string
|
||||
modelID: string
|
||||
}
|
||||
variant?: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export type EventKilocodeNotebookRequested = {
|
||||
id: string
|
||||
type: "kilocode.notebook.requested"
|
||||
properties: NotebookRequest
|
||||
}
|
||||
|
||||
export type EventKilocodeNotebookCancelled = {
|
||||
id: string
|
||||
type: "kilocode.notebook.cancelled"
|
||||
properties: {
|
||||
requestID: NotebookRequestId
|
||||
sessionID: string
|
||||
reason: "cancelled" | "disposed" | "timeout"
|
||||
}
|
||||
}
|
||||
|
||||
export type EventVcsBranchUpdated = {
|
||||
id: string
|
||||
type: "vcs.branch.updated"
|
||||
@@ -4297,6 +4283,28 @@ export type EventSessionNextCompactionEnded = {
|
||||
}
|
||||
}
|
||||
|
||||
export type EventIndexingStatus = {
|
||||
id: string
|
||||
type: "indexing.status"
|
||||
properties: {
|
||||
status: IndexingStatus
|
||||
}
|
||||
}
|
||||
|
||||
export type EventIndexingWarning = {
|
||||
id: string
|
||||
type: "indexing.warning"
|
||||
properties: IndexingWarning
|
||||
}
|
||||
|
||||
export type EventModelsDevRefreshed = {
|
||||
id: string
|
||||
type: "models-dev.refreshed"
|
||||
properties: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type EventPluginAdded = {
|
||||
id: string
|
||||
type: "plugin.added"
|
||||
@@ -4411,14 +4419,6 @@ export type EventCatalogModelUpdated = {
|
||||
}
|
||||
}
|
||||
|
||||
export type EventModelsDevRefreshed = {
|
||||
id: string
|
||||
type: "models-dev.refreshed"
|
||||
properties: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
export type AccountV2oAuthCredential = {
|
||||
type: "oauth"
|
||||
refresh: string
|
||||
@@ -11337,6 +11337,66 @@ export type KilocodeSessionModelUsageResponses = {
|
||||
export type KilocodeSessionModelUsageResponse =
|
||||
KilocodeSessionModelUsageResponses[keyof KilocodeSessionModelUsageResponses]
|
||||
|
||||
export type KilocodeMobileAppNoticeData = {
|
||||
body?: never
|
||||
path?: never
|
||||
query?: {
|
||||
directory?: string
|
||||
workspace?: string
|
||||
}
|
||||
url: "/kilocode/notice/mobile-app"
|
||||
}
|
||||
|
||||
export type KilocodeMobileAppNoticeErrors = {
|
||||
/**
|
||||
* Bad request
|
||||
*/
|
||||
400: BadRequestError
|
||||
}
|
||||
|
||||
export type KilocodeMobileAppNoticeError = KilocodeMobileAppNoticeErrors[keyof KilocodeMobileAppNoticeErrors]
|
||||
|
||||
export type KilocodeMobileAppNoticeResponses = {
|
||||
/**
|
||||
* Mobile app notice visibility
|
||||
*/
|
||||
200: {
|
||||
show: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export type KilocodeMobileAppNoticeResponse = KilocodeMobileAppNoticeResponses[keyof KilocodeMobileAppNoticeResponses]
|
||||
|
||||
export type KilocodeDismissMobileAppNoticeData = {
|
||||
body?: never
|
||||
path?: never
|
||||
query?: {
|
||||
directory?: string
|
||||
workspace?: string
|
||||
}
|
||||
url: "/kilocode/notice/mobile-app/dismiss"
|
||||
}
|
||||
|
||||
export type KilocodeDismissMobileAppNoticeErrors = {
|
||||
/**
|
||||
* Bad request
|
||||
*/
|
||||
400: BadRequestError
|
||||
}
|
||||
|
||||
export type KilocodeDismissMobileAppNoticeError =
|
||||
KilocodeDismissMobileAppNoticeErrors[keyof KilocodeDismissMobileAppNoticeErrors]
|
||||
|
||||
export type KilocodeDismissMobileAppNoticeResponses = {
|
||||
/**
|
||||
* Notice dismissed
|
||||
*/
|
||||
200: boolean
|
||||
}
|
||||
|
||||
export type KilocodeDismissMobileAppNoticeResponse =
|
||||
KilocodeDismissMobileAppNoticeResponses[keyof KilocodeDismissMobileAppNoticeResponses]
|
||||
|
||||
export type AnacondaDesktopStatusData = {
|
||||
body?: never
|
||||
path?: never
|
||||
|
||||
+958
-698
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user