From 89915faf6788c298d82172b6b3622007f87aa8b7 Mon Sep 17 00:00:00 2001 From: Johnny Amancio Date: Wed, 17 Jun 2026 11:48:14 +0200 Subject: [PATCH] feat(vscode): add extension project memory controls --- .changeset/kilo-memory-extension.md | 5 + packages/kilo-vscode/package.json | 11 + packages/kilo-vscode/src/KiloProvider.ts | 73 +++- .../src/agent-manager/AgentManagerProvider.ts | 52 ++- .../kilo-vscode/src/agent-manager/host.ts | 2 + .../src/agent-manager/vscode-host.ts | 2 + packages/kilo-vscode/src/extension.ts | 20 + .../kilo-vscode/src/kilo-provider/memory.ts | 411 ++++++++++++++++++ .../kilo-vscode/tests/setup/vscode-mock.ts | 7 + .../agent-manager-memory-commands.test.ts | 102 +++++ .../unit/kilo-provider-memory-events.test.ts | 187 ++++++++ .../tests/unit/kilo-provider-memory.test.ts | 187 ++++++++ .../tests/unit/memory-command.test.ts | 57 +++ .../agent-manager/AgentManagerApp.tsx | 17 +- packages/kilo-vscode/webview-ui/src/App.tsx | 13 +- .../src/components/chat/AssistantMessage.tsx | 88 ++++ .../src/components/chat/PromptInput.tsx | 70 ++- .../src/components/chat/TaskHeader.tsx | 73 ++++ .../src/components/settings/ContextTab.tsx | 80 +++- .../webview-ui/src/context/memory.tsx | 212 +++++++++ .../kilo-vscode/webview-ui/src/i18n/ar.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/br.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/bs.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/da.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/de.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/en.ts | 40 ++ .../kilo-vscode/webview-ui/src/i18n/es.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/fr.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/it.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/ja.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/ko.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/nl.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/no.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/pl.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/ru.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/th.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/tr.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/uk.ts | 41 ++ .../kilo-vscode/webview-ui/src/i18n/zh.ts | 40 ++ .../kilo-vscode/webview-ui/src/i18n/zht.ts | 40 ++ .../webview-ui/src/stories/StoryProviders.tsx | 41 +- .../webview-ui/src/styles/chat-layout.css | 8 + .../webview-ui/src/styles/task-header.css | 32 ++ .../src/types/messages/extension-messages.ts | 4 + .../webview-ui/src/types/messages/index.ts | 1 + .../webview-ui/src/types/messages/memory.ts | 97 +++++ .../src/types/messages/webview-messages.ts | 5 + .../webview-ui/src/utils/memory-command.ts | 10 + 48 files changed, 2634 insertions(+), 50 deletions(-) create mode 100644 .changeset/kilo-memory-extension.md create mode 100644 packages/kilo-vscode/src/kilo-provider/memory.ts create mode 100644 packages/kilo-vscode/tests/unit/agent-manager-memory-commands.test.ts create mode 100644 packages/kilo-vscode/tests/unit/kilo-provider-memory-events.test.ts create mode 100644 packages/kilo-vscode/tests/unit/kilo-provider-memory.test.ts create mode 100644 packages/kilo-vscode/tests/unit/memory-command.test.ts create mode 100644 packages/kilo-vscode/webview-ui/src/context/memory.tsx create mode 100644 packages/kilo-vscode/webview-ui/src/types/messages/memory.ts create mode 100644 packages/kilo-vscode/webview-ui/src/utils/memory-command.ts diff --git a/.changeset/kilo-memory-extension.md b/.changeset/kilo-memory-extension.md new file mode 100644 index 00000000000..962def361b2 --- /dev/null +++ b/.changeset/kilo-memory-extension.md @@ -0,0 +1,5 @@ +--- +"kilo-code": minor +--- + +Add project memory controls, status, and activity details to the VS Code extension. diff --git a/packages/kilo-vscode/package.json b/packages/kilo-vscode/package.json index 6941d574acd..01bbbb57398 100644 --- a/packages/kilo-vscode/package.json +++ b/packages/kilo-vscode/package.json @@ -195,6 +195,16 @@ "title": "Migrate Settings from Legacy Version", "category": "Kilo Code" }, + { + "command": "kilo-code.new.showMemory", + "title": "Show Memory", + "category": "Kilo Code" + }, + { + "command": "kilo-code.new.toggleMemory", + "title": "Toggle Project Memory", + "category": "Kilo Code" + }, { "command": "kilo-code.new.autocomplete.generateSuggestions", "title": "Generate Suggested Edits", @@ -1082,6 +1092,7 @@ "@kilocode/kilo-gateway": "workspace:*", "@kilocode/kilo-i18n": "workspace:*", "@kilocode/kilo-indexing": "workspace:*", + "@kilocode/kilo-memory": "workspace:*", "@kilocode/kilo-ui": "workspace:*", "@kilocode/sdk": "workspace:*", "@opencode-ai/ui": "workspace:*", diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index b117b8c14ee..a03bcb13fee 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -127,6 +127,7 @@ import { import { fetchAndSendPendingSuggestions } from "./kilo-provider/handlers/suggestion" import { nativeTitle } from "./kilo-provider/native-tab-title" import { parseReview, reviewMetadata, type ReviewMessageData } from "./shared/review-comments" +import { KiloProviderMemory } from "./kilo-provider/memory" import { buildActionContext, @@ -296,6 +297,12 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper private readonly streams = new SessionStreamScheduler((msg) => this.postMessage(msg)) private readonly visibleTaskStreams = new VisibleTaskStreams((id, visible) => this.streams.setVisible(id, visible)) private readonly confirmations = new MessageConfirmation() + private readonly memory = new KiloProviderMemory({ + client: () => this.client ?? undefined, + session: () => this.currentSession ?? undefined, + dir: (sessionID) => this.getProjectDirectory(sessionID) ?? this.getWorkspaceDirectory(sessionID), + post: (message) => this.postMessage(message), + }) private unsubscribeEvent: (() => void) | null = null private unsubscribeState: (() => void) | null = null /** Cached legacy migration data so migrate() doesn't re-read from disk/SecretStorage. */ // legacy-migration @@ -351,7 +358,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper ) { this.projectDirectory = opts.projectDirectory this.slimEditMetadata = opts.slimEditMetadata ?? true - TelemetryProxy.getInstance().setProvider(this) } @@ -776,6 +782,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper return } this.visibleTaskStreams.handle(message) + if (await this.handleMemoryMessage(message)) return switch (message.type) { case "webviewReady": console.log("[Kilo New] KiloProvider: ✅ webviewReady received") @@ -1281,6 +1288,8 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper // Remote status events are global and should always pass through if (event.type === "kilo-sessions.remote-status-changed") return true + if (event.type === "memory.status" || event.type === "memory.updated" || event.type === "memory.error") + return true const sessionId = this.resolveEventSessionId(event) // message.part.* events are always session-scoped; drop if session unknown. @@ -1409,6 +1418,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper this.fetchAndSendConfig(), this.fetchAndSendIndexingStatus(), this.fetchAndSendNotifications(), + this.memory.fetch(), this.seedSessionStatusMap(), ]) this.cachedGitRepo = await hasGit(this.client!, this.getWorkspaceDirectory()) @@ -2069,6 +2079,10 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } } + private async handleMemoryMessage(message: Record): Promise { + return this.memory.handle(message) + } + /** * Fetch backend config and send to webview. */ @@ -3099,6 +3113,38 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper return } + if (event.type === "memory.status" || event.type === "memory.updated" || event.type === "memory.error") { + const props = event.properties as { sessionID?: unknown; detail?: unknown; reason?: unknown } + const eventSessionID = typeof props.sessionID === "string" ? props.sessionID : undefined + const active = this.currentSession?.id + const local = + !directory || sameDirectory(directory, this.getProjectDirectory(active) ?? this.getWorkspaceDirectory(active)) + const tracked = Boolean(eventSessionID && this.trackedSessionIds.has(eventSessionID)) + if (!local && !tracked) return + if (tracked && eventSessionID && directory) this.trackDirectory(eventSessionID, directory) + const targets = new Set() + if (tracked && eventSessionID) targets.add(eventSessionID) + if (local && active) targets.add(active) + if (targets.size === 0 && local) targets.add(undefined) + const detail = + props.detail && typeof props.detail === "object" + ? props.detail + : event.type === "memory.error" && typeof props.reason === "string" + ? { type: "error", message: props.reason, reason: props.reason } + : undefined + for (const sessionID of targets) { + if (detail) { + this.postMessage({ + type: "memoryEvent", + sessionID, + detail, + }) + } + void this.memory.fetch(sessionID, false) + } + return + } + // Drop session events from other projects before any tracking logic. // This must come first: the trackedSessionIds guard below would otherwise // let a foreign session through if it was accidentally tracked. @@ -3281,6 +3327,31 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper this.flushPendingReviewComments() } + public async inspectMemory(sessionID?: string): Promise { + await this.memory.inspect(sessionID ?? this.currentSession?.id) + } + + public async toggleMemory(sessionID?: string): Promise { + if (!this.client) { + void vscode.window.showErrorMessage("Not connected to CLI backend") + return + } + + const sid = sessionID ?? this.currentSession?.id + const directory = this.getProjectDirectory(sid) ?? this.getWorkspaceDirectory(sid) + try { + const { data: status } = await this.client.memory.status({ directory }, { throwOnError: true }) + const operation = status.state.enabled ? "disable" : "enable" + const ok = await this.memory.run({ operation, sessionID: sid }) + if (ok) { + void vscode.window.showInformationMessage(`Project memory ${operation === "enable" ? "enabled" : "disabled"}.`) + } + } catch (error) { + console.error("[Kilo New] KiloProvider: Failed to toggle memory:", error) + void vscode.window.showErrorMessage(getErrorMessage(error) || "Failed to toggle memory") + } + } + private flushPendingReviewComments(): void { if (!this.webview || !this.isWebviewReady || this.pendingReviewComments.length === 0) return diff --git a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts index 72cfd6d4cd1..d619f2108ba 100644 --- a/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts +++ b/packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts @@ -1709,6 +1709,52 @@ export class AgentManagerProvider implements Disposable { return this.panel?.active === true } + private async waitForPanel(panel: PanelContext, promise: Promise): Promise { + const done = promise.then(() => true) + let sub: Disposable | undefined + const disposed = new Promise((resolve) => { + sub = panel.onDidDispose(() => { + sub?.dispose() + resolve(false) + }) + }) + void done.finally(() => sub?.dispose()) + const ok = await Promise.race([done, disposed]) + return ok && this.panel === panel + } + + private waitForPanelReady(panel: PanelContext): Promise { + return this.waitForPanel(panel, panel.waitForReady()) + } + + private waitForPanelActive(panel: PanelContext): Promise { + return this.waitForPanel(panel, panel.waitForActive()) + } + + public async inspectMemory(): Promise { + const panel = this.panel + const sid = this.activeSessionId + if (!panel || !sid) { + this.host.showError("No active Agent Manager session") + return + } + if (!(await this.waitForPanelReady(panel))) return + if (this.activeSessionId !== sid) return + await panel.sessions.inspectMemory(sid) + } + + public async toggleMemory(): Promise { + const panel = this.panel + const sid = this.activeSessionId + if (!panel || !sid) { + this.host.showError("No active Agent Manager session") + return + } + if (!(await this.waitForPanelReady(panel))) return + if (this.activeSessionId !== sid) return + await panel.sessions.toggleMemory(sid) + } + /** Expose worktree session→directory mappings for the auto-approve toggle. */ public getSessionDirectories(): ReadonlyMap { return this.panel?.sessions.getSessionDirectories() ?? new Map() @@ -1762,7 +1808,7 @@ export class AgentManagerProvider implements Disposable { this.openPanel() const panel = this.panel if (!panel) return - await panel.waitForReady() + if (!(await this.waitForPanelReady(panel))) return await this.waitForStateReady("createFromSidebar") await this.onCreateWorktree(baseBranch, branchName) } @@ -1771,8 +1817,8 @@ export class AgentManagerProvider implements Disposable { this.openPanel() const panel = this.panel if (!panel) return - await panel.waitForActive() - await panel.waitForReady() + if (!(await this.waitForPanelActive(panel))) return + if (!(await this.waitForPanelReady(panel))) return await this.waitForStateReady("openAdvancedWorktree") queueMicrotask(() => this.postToWebview({ type: "action", action: "advancedWorktree" })) } diff --git a/packages/kilo-vscode/src/agent-manager/host.ts b/packages/kilo-vscode/src/agent-manager/host.ts index 079b610f590..0cda9986e01 100644 --- a/packages/kilo-vscode/src/agent-manager/host.ts +++ b/packages/kilo-vscode/src/agent-manager/host.ts @@ -44,6 +44,8 @@ export interface SessionProvider { * The callback receives the new session and its directory so the Agent Manager * can route it to the correct worktree instead of LOCAL. */ onFollowupAdopted(cb: (session: Session, directory: string) => void): void + inspectMemory(sessionID?: string): Promise + toggleMemory(sessionID?: string): Promise dispose(): void } diff --git a/packages/kilo-vscode/src/agent-manager/vscode-host.ts b/packages/kilo-vscode/src/agent-manager/vscode-host.ts index 82b381e054c..1424e9d98ac 100644 --- a/packages/kilo-vscode/src/agent-manager/vscode-host.ts +++ b/packages/kilo-vscode/src/agent-manager/vscode-host.ts @@ -116,6 +116,8 @@ export class VscodeHost implements Host { registerSession: (s) => provider.registerSession(s), recoverPendingPrompts: () => provider.recoverPendingPrompts(), onFollowupAdopted: (cb) => provider.onFollowupAdopted(cb), + inspectMemory: (id) => provider.inspectMemory(id), + toggleMemory: (id) => provider.toggleMemory(id), dispose: () => provider.dispose(), } diff --git a/packages/kilo-vscode/src/extension.ts b/packages/kilo-vscode/src/extension.ts index 9d19f9aab36..e1cce754189 100644 --- a/packages/kilo-vscode/src/extension.ts +++ b/packages/kilo-vscode/src/extension.ts @@ -383,6 +383,26 @@ export function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand("kilo-code.new.openIndexingSettings", () => { settingsEditorProvider.openPanel("settings", "indexing") }), + vscode.commands.registerCommand("kilo-code.new.showMemory", async () => { + if (agentManagerProvider.isActive()) { + await agentManagerProvider.inspectMemory() + return + } + const target = activeTabProvider() ?? provider + if (target === provider) await vscode.commands.executeCommand("kilo-code.SidebarProvider.focus") + await target.waitForReady() + await target.inspectMemory() + }), + vscode.commands.registerCommand("kilo-code.new.toggleMemory", async () => { + if (agentManagerProvider.isActive()) { + await agentManagerProvider.toggleMemory() + return + } + const target = activeTabProvider() ?? provider + if (target === provider) await vscode.commands.executeCommand("kilo-code.SidebarProvider.focus") + await target.waitForReady() + await target.toggleMemory() + }), // legacy-migration start vscode.commands.registerCommand("kilo-code.new.openMigrationWizard", () => { provider.postMessage({ type: "migrationState", needed: true }) diff --git a/packages/kilo-vscode/src/kilo-provider/memory.ts b/packages/kilo-vscode/src/kilo-provider/memory.ts new file mode 100644 index 00000000000..ad67ff1de2c --- /dev/null +++ b/packages/kilo-vscode/src/kilo-provider/memory.ts @@ -0,0 +1,411 @@ +import * as vscode from "vscode" +import { + isMemoryOperation, + isMemoryPromptOperation, + type MemoryOperation, + type MemoryPromptOperation, +} from "@kilocode/kilo-memory/commands" +import { MemorySchema } from "@kilocode/kilo-memory/schema" +import type { KiloClient, Session } from "@kilocode/sdk/v2/client" +import { retry } from "../services/cli-backend/retry" +import { getErrorMessage } from "../kilo-provider-utils" + +type MemorySourceFile = MemorySchema.Source +type MemoryApi = KiloClient["memory"] +const CACHE_LIMIT = 8 + +export type KiloProviderMemoryMessage = { + operation: MemoryOperation + sessionID?: string + mode?: "status" | "on" | "off" + confirm?: boolean + text?: string + query?: string + key?: string + file?: MemorySourceFile + section?: string +} + +export type KiloProviderMemoryInput = { + client(): KiloClient | undefined + session(): Session | undefined + dir(sessionID?: string): string + post(message: unknown): void +} + +function file(value: unknown): MemorySourceFile | undefined { + return MemorySchema.source(value) +} + +function operation(value: unknown): MemoryOperation | undefined { + return isMemoryOperation(value) ? value : undefined +} + +function mode(value: unknown) { + if (value === "status" || value === "on" || value === "off") return value + return undefined +} + +function memory(client: KiloClient | undefined): MemoryApi | undefined { + return (client as { memory?: MemoryApi } | undefined)?.memory +} + +function request(input: Record): { value: KiloProviderMemoryMessage } | { error: string } { + const op = operation(input.operation) + if (!op) return { error: "Unknown memory operation" } + const source = file(input.file) + if (input.file !== undefined && !source) return { error: "Invalid memory source file" } + return { + value: { + operation: op, + sessionID: typeof input.sessionID === "string" ? input.sessionID : undefined, + mode: mode(input.mode), + confirm: input.confirm === true, + text: typeof input.text === "string" ? input.text : undefined, + query: typeof input.query === "string" ? input.query : undefined, + key: typeof input.key === "string" ? input.key : undefined, + file: source, + section: typeof input.section === "string" ? input.section : undefined, + }, + } +} + +export class KiloProviderMemory { + private readonly cached = new Map() + private tail = Promise.resolve() + + constructor(private readonly input: KiloProviderMemoryInput) {} + + private cache(dir: string, msg: unknown) { + this.cached.delete(dir) + this.cached.set(dir, msg) + while (this.cached.size > CACHE_LIMIT) { + const key = this.cached.keys().next().value + if (typeof key !== "string") return + this.cached.delete(key) + } + } + + private serial(fn: () => Promise) { + const next = this.tail.then(fn, fn) + this.tail = next.then( + () => undefined, + () => undefined, + ) + return next + } + + async handle(message: Record): Promise { + if (message.type === "requestMemory") { + this.fetch( + typeof message.sessionID === "string" ? message.sessionID : undefined, + message.includeSources === true, + ).catch((err: unknown) => console.error("[Kilo New] fetchAndSendMemory failed:", err)) + return true + } + if (message.type === "memoryInspect") { + await this.inspect(typeof message.sessionID === "string" ? message.sessionID : undefined) + return true + } + if (message.type === "memoryOperation") { + const parsed = request(message) + if ("error" in parsed) { + this.input.post({ + type: "memoryOperationResult", + operation: typeof message.operation === "string" ? message.operation : "unknown", + sessionID: typeof message.sessionID === "string" ? message.sessionID : undefined, + ok: false, + error: parsed.error, + }) + return true + } + await this.run(parsed.value) + return true + } + if (message.type === "memoryPrompt") { + const op = isMemoryPromptOperation(message.operation) ? message.operation : undefined + if (!op) return true + await this.prompt(op, typeof message.sessionID === "string" ? message.sessionID : undefined) + return true + } + return false + } + + fetch(sessionID?: string, includeSources = false): Promise { + return this.serial(() => this.load(sessionID, includeSources)) + } + + private async load(sessionID?: string, includeSources = false): Promise { + const directory = this.input.dir(sessionID ?? this.input.session()?.id) + const client = this.input.client() + if (!client) { + const cached = this.cached.get(directory) + if (cached && typeof cached === "object" && !Array.isArray(cached)) this.input.post({ ...cached, sessionID }) + else this.input.post({ type: "memoryLoaded", sessionID, error: "Not connected to CLI backend" }) + return + } + + const api = memory(client) + if (!api) { + this.input.post({ type: "memoryLoaded", sessionID, error: "Memory unavailable in CLI backend" }) + return + } + + try { + const { data: status } = await retry(() => api.status({ directory }, { throwOnError: true })) + const show = includeSources + ? (await retry(() => api.show({ directory }, { throwOnError: true }))).data + : undefined + const msg = { + type: "memoryLoaded", + sessionID, + status, + ...(show ? { show } : {}), + } + this.cache(directory, msg) + this.input.post(msg) + } catch (err) { + console.error("[Kilo New] KiloProvider: Failed to fetch memory:", err) + this.input.post({ + type: "memoryLoaded", + sessionID, + error: getErrorMessage(err) || "Failed to load memory", + }) + } + } + + async prompt(value: MemoryPromptOperation, sessionID?: string): Promise { + const title = value === "remember" ? "Remember in project memory" : "Forget project memory" + const placeHolder = value === "remember" ? "Project fact, command, or correction" : "Text to remove" + const text = await vscode.window.showInputBox({ title, placeHolder, ignoreFocusOut: true }) + if (!text?.trim()) return + await this.run({ + operation: value, + sessionID, + ...(value === "remember" ? { text: text.trim() } : { query: text.trim() }), + }) + } + + async inspect(sessionID?: string): Promise { + const client = this.input.client() + if (!client) { + this.input.post({ + type: "memoryLoaded", + sessionID, + error: "Not connected to CLI backend", + }) + return + } + + const api = memory(client) + + if (!api) { + this.input.post({ + type: "memoryLoaded", + sessionID, + error: "Memory unavailable in CLI backend", + }) + return + } + + try { + const directory = this.input.dir(sessionID ?? this.input.session()?.id) + const { data: show } = await api.show({ directory }, { throwOnError: true }) + const { data: status } = await api.status({ directory }, { throwOnError: true }) + const current = sessionID ?? this.input.session()?.id + const startup = + current && status.state.stats.lastInjectedSessionID === current ? status.state.stats.lastInjectedTokens : 0 + const content = [ + "# Kilo Memory", + "", + `Root: ${show.root}`, + `Enabled: ${show.state.enabled ? "yes" : "no"}`, + `Auto-save: ${show.state.autoConsolidate ? "on" : "off"}`, + "Startup context: on", + `Stored index tokens: ${status.index.estimatedTokens}`, + `Startup context tokens for this session: ${startup}`, + `Last auto-save model usage: ${status.state.stats.lastConsolidationTokens} tokens`, + "", + "## project.md", + show.sources.project.trim(), + "", + "## environment.md", + show.sources.environment.trim(), + "", + "## corrections.md", + show.sources.corrections.trim(), + "", + "## index.kmem", + show.index.trim(), + "", + "## items", + show.items.trim(), + "", + "## decisions.jsonl", + show.decisions.trim(), + "", + ].join("\n") + await vscode.workspace + .openTextDocument({ content, language: "markdown" }) + .then((doc) => vscode.window.showTextDocument(doc, { preview: true })) + const msg = { + type: "memoryLoaded", + sessionID, + status, + show, + } + this.cache(directory, msg) + this.input.post(msg) + } catch (err) { + console.error("[Kilo New] KiloProvider: Failed to inspect memory:", err) + this.input.post({ + type: "memoryLoaded", + sessionID, + error: getErrorMessage(err) || "Failed to inspect memory", + }) + } + } + + run(message: KiloProviderMemoryMessage): Promise { + return this.serial(() => this.execute(message)) + } + + private async execute(message: KiloProviderMemoryMessage): Promise { + const client = this.input.client() + if (!client) { + this.input.post({ + type: "memoryOperationResult", + operation: message.operation, + sessionID: message.sessionID, + ok: false, + error: "Not connected to CLI backend", + }) + return false + } + + const api = memory(client) + if (!api) { + this.input.post({ + type: "memoryOperationResult", + operation: message.operation, + sessionID: message.sessionID, + ok: false, + error: "Memory unavailable in CLI backend", + }) + return false + } + + try { + const directory = this.input.dir(message.sessionID ?? this.input.session()?.id) + const data = + message.operation === "enable" + ? (await api.enable({ directory }, { throwOnError: true })).data + : message.operation === "disable" + ? (await api.disable({ directory }, { throwOnError: true })).data + : message.operation === "rebuild" + ? (await api.rebuild({ directory }, { throwOnError: true })).data + : message.operation === "purge" + ? await this.purge(api, directory, message) + : message.operation === "auto" + ? await this.auto(api, directory, message) + : message.operation === "remember" + ? await this.remember(api, directory, message) + : message.operation === "correct" + ? await this.correct(api, directory, message) + : await this.forget(api, directory, message) + const refreshed = await Promise.all([ + api.status({ directory }, { throwOnError: true }), + api.show({ directory }, { throwOnError: true }), + ]).catch((err: unknown) => { + console.warn("[Kilo New] Memory changed but refresh failed:", err) + return undefined + }) + const status = refreshed?.[0].data + const show = refreshed?.[1].data + const result = { + type: "memoryOperationResult", + operation: message.operation, + sessionID: message.sessionID, + ok: true, + ...(status ? { status } : {}), + ...(show ? { show } : {}), + result: data, + } + this.input.post(result) + if (status && show) { + const loaded = { + type: "memoryLoaded", + sessionID: message.sessionID, + status, + show, + } + this.cache(directory, loaded) + this.input.post(loaded) + } + return true + } catch (err) { + console.error("[Kilo New] KiloProvider: Failed memory operation:", err) + this.input.post({ + type: "memoryOperationResult", + operation: message.operation, + sessionID: message.sessionID, + ok: false, + error: getErrorMessage(err) || "Memory operation failed", + }) + return false + } + } + + private async remember(api: MemoryApi, directory: string, message: KiloProviderMemoryMessage) { + const text = message.text?.trim() + if (!text) throw new Error("Memory text is required") + return ( + await api.remember( + { + directory, + text, + key: message.key, + file: message.file, + section: message.section, + sessionID: message.sessionID, + }, + { throwOnError: true }, + ) + ).data + } + + private async correct(api: MemoryApi, directory: string, message: KiloProviderMemoryMessage) { + const text = message.text?.trim() + if (!text) throw new Error("Correction text is required") + return ( + await api.correct( + { + directory, + text, + key: message.key, + sessionID: message.sessionID, + }, + { throwOnError: true }, + ) + ).data + } + + private async forget(api: MemoryApi, directory: string, message: KiloProviderMemoryMessage) { + const query = message.query?.trim() + if (!query) throw new Error("Forget query is required") + return (await api.forget({ directory, query, sessionID: message.sessionID }, { throwOnError: true })).data + } + + private async purge(api: MemoryApi, directory: string, message: KiloProviderMemoryMessage) { + if (message.confirm !== true) throw new Error("Memory purge requires confirmation") + return (await api.purge({ directory, confirm: true }, { throwOnError: true })).data + } + + private async auto(api: MemoryApi, directory: string, message: KiloProviderMemoryMessage) { + if (message.mode === "status") return (await api.status({ directory }, { throwOnError: true })).data + if (message.mode === "on" || message.mode === "off") { + return (await api.configure({ directory, autoConsolidate: message.mode === "on" }, { throwOnError: true })).data + } + throw new Error("Auto-save mode is required") + } +} diff --git a/packages/kilo-vscode/tests/setup/vscode-mock.ts b/packages/kilo-vscode/tests/setup/vscode-mock.ts index 799f0bc4a24..8e13f355528 100644 --- a/packages/kilo-vscode/tests/setup/vscode-mock.ts +++ b/packages/kilo-vscode/tests/setup/vscode-mock.ts @@ -49,7 +49,12 @@ const mockVscode = { textDocuments: [] as Array, onDidOpenTextDocument: () => ({ dispose: noop }), onDidChangeTextDocument: () => ({ dispose: noop }), + onDidSaveTextDocument: () => ({ dispose: noop }), onDidCloseTextDocument: () => ({ dispose: noop }), + openTextDocument: async (input: { content?: string; language?: string }) => ({ + getText: () => input.content ?? "", + languageId: input.language ?? "plaintext", + }), getConfiguration: () => ({ get: (_key: string, value?: T) => value, update: async () => {}, @@ -76,6 +81,8 @@ const mockVscode = { visibleTextEditors: [], tabGroups: { all: [] }, showTextDocument: async () => {}, + showInformationMessage: async () => undefined, + showErrorMessage: async () => undefined, showWarningMessage: async () => undefined, createTerminal: () => ({ show: noop, sendText: noop, dispose: noop }), createOutputChannel: () => ({ diff --git a/packages/kilo-vscode/tests/unit/agent-manager-memory-commands.test.ts b/packages/kilo-vscode/tests/unit/agent-manager-memory-commands.test.ts new file mode 100644 index 00000000000..33ed75e6634 --- /dev/null +++ b/packages/kilo-vscode/tests/unit/agent-manager-memory-commands.test.ts @@ -0,0 +1,102 @@ +import { describe, expect, it, mock } from "bun:test" + +const { AgentManagerProvider } = await import("../../src/agent-manager/AgentManagerProvider") + +type Manager = { + host: { showError: (message: string) => void } + panel: + | { + waitForReady: () => Promise + onDidDispose: (cb: () => void) => { dispose: () => void } + sessions: { + inspectMemory: (sessionID?: string) => Promise + toggleMemory: (sessionID?: string) => Promise + } + } + | undefined + activeSessionId: string | undefined + inspectMemory: () => Promise + toggleMemory: () => Promise +} + +function deferred() { + let done: (() => void) | undefined + const promise = new Promise((resolve) => { + done = resolve + }) + return { + promise, + resolve: () => done?.(), + } +} + +function manager() { + const calls: unknown[] = [] + const disposers: Array<() => void> = [] + const item = Object.create(AgentManagerProvider.prototype) as Manager + item.host = { showError: mock((message) => calls.push(["error", message])) } + item.panel = { + waitForReady: mock(async () => calls.push("ready")), + onDidDispose: mock((cb) => { + disposers.push(cb) + return { dispose: mock(() => {}) } + }), + sessions: { + inspectMemory: mock(async (sessionID) => calls.push(["inspect", sessionID])), + toggleMemory: mock(async (sessionID) => calls.push(["toggle", sessionID])), + }, + } + item.activeSessionId = "ses_agent_manager" + return { + item, + calls, + dispose: () => { + for (const cb of disposers) cb() + }, + } +} + +describe("AgentManagerProvider memory commands", () => { + it("routes memory commands to the active Agent Manager session", async () => { + const ctx = manager() + + await ctx.item.inspectMemory() + await ctx.item.toggleMemory() + + expect(ctx.calls).toEqual(["ready", ["inspect", "ses_agent_manager"], "ready", ["toggle", "ses_agent_manager"]]) + }) + + it("does not fall back when Agent Manager has no active session", async () => { + const ctx = manager() + ctx.item.activeSessionId = undefined + + await ctx.item.inspectMemory() + + expect(ctx.calls).toEqual([["error", "No active Agent Manager session"]]) + }) + + it("does not hang when the panel is disposed before it is ready", async () => { + const ctx = manager() + const wait = deferred() + ctx.item.panel!.waitForReady = mock(() => wait.promise) + + const pending = ctx.item.inspectMemory() + ctx.dispose() + await pending + + expect(ctx.calls).toEqual([]) + }) + + it("does not target a stale session after readiness resolves", async () => { + const ctx = manager() + const wait = deferred() + ctx.item.panel!.waitForReady = mock(() => wait.promise) + + const pending = ctx.item.toggleMemory() + ctx.item.activeSessionId = "ses_other" + wait.resolve() + await pending + + expect(ctx.calls).toEqual([]) + }) +}) diff --git a/packages/kilo-vscode/tests/unit/kilo-provider-memory-events.test.ts b/packages/kilo-vscode/tests/unit/kilo-provider-memory-events.test.ts new file mode 100644 index 00000000000..0c3b9919c4b --- /dev/null +++ b/packages/kilo-vscode/tests/unit/kilo-provider-memory-events.test.ts @@ -0,0 +1,187 @@ +import { describe, expect, it } from "bun:test" +import type { KiloClient } from "@kilocode/sdk/v2/client" + +// vscode mock is provided by the shared preload (tests/setup/vscode-mock.ts) +const { KiloProvider } = await import("../../src/KiloProvider") + +type Internals = { + currentSession: { id: string } | null + trackedSessionIds: Set + webview: { postMessage(message: unknown): Promise } | null + handleEvent(event: unknown, directory?: string): void +} + +function status(root: string) { + return { + root: `${root}/.kilo/memory`, + state: { + enabled: true, + autoConsolidate: true, + stats: { + lastInjectedSessionID: "", + lastInjectedTokens: 0, + lastOperationCount: 0, + }, + }, + index: { estimatedTokens: 0 }, + } +} + +function show(root: string) { + return { + root: `${root}/.kilo/memory`, + state: status(root).state, + sources: { project: "", environment: "", corrections: "" }, + index: "", + items: "", + changes: "", + decisions: "", + } +} + +function tick() { + return new Promise((resolve) => setTimeout(resolve, 0)) +} + +describe("KiloProvider memory events", () => { + it("routes tracked background memory events to their session directory", async () => { + const calls: string[] = [] + const posts: unknown[] = [] + const client = { + memory: { + status: async (input: { directory: string }) => { + calls.push(input.directory) + return { data: status(input.directory) } + }, + }, + } as unknown as KiloClient + const provider = new KiloProvider( + {} as never, + { + getClient: () => client, + } as never, + ) + const item = provider as unknown as Internals + item.webview = { postMessage: async (message) => posts.push(message) } + item.currentSession = { id: "ses_active" } + item.trackedSessionIds.add("ses_active") + item.trackedSessionIds.add("ses_bg") + provider.setSessionDirectory("ses_bg", "/worktree") + + item.handleEvent( + { + type: "memory.updated", + properties: { + sessionID: "ses_bg", + detail: { type: "saved", message: "Saved project memory" }, + }, + }, + "/worktree", + ) + await tick() + + expect(posts).toContainEqual({ + type: "memoryEvent", + sessionID: "ses_bg", + detail: { type: "saved", message: "Saved project memory" }, + }) + expect(posts).toContainEqual(expect.objectContaining({ type: "memoryLoaded", sessionID: "ses_bg" })) + expect(posts).not.toContainEqual(expect.objectContaining({ type: "memoryEvent", sessionID: "ses_active" })) + expect(calls).toEqual(["/worktree"]) + }) + + it("also refreshes the active session for same-directory memory events", async () => { + const calls: string[] = [] + const posts: unknown[] = [] + const client = { + memory: { + status: async (input: { directory: string }) => { + calls.push(input.directory) + return { data: status(input.directory) } + }, + }, + } as unknown as KiloClient + const provider = new KiloProvider( + {} as never, + { + getClient: () => client, + } as never, + ) + const item = provider as unknown as Internals + item.webview = { postMessage: async (message) => posts.push(message) } + item.currentSession = { id: "ses_active" } + item.trackedSessionIds.add("ses_active") + item.trackedSessionIds.add("ses_bg") + provider.setSessionDirectory("ses_active", "/repo") + provider.setSessionDirectory("ses_bg", "/repo") + + item.handleEvent( + { + type: "memory.updated", + properties: { + sessionID: "ses_bg", + detail: { type: "saved", message: "Saved project memory" }, + }, + }, + "/repo", + ) + await tick() + await tick() + + expect(posts).toContainEqual({ + type: "memoryEvent", + sessionID: "ses_bg", + detail: { type: "saved", message: "Saved project memory" }, + }) + expect(posts).toContainEqual({ + type: "memoryEvent", + sessionID: "ses_active", + detail: { type: "saved", message: "Saved project memory" }, + }) + expect(posts).toContainEqual(expect.objectContaining({ type: "memoryLoaded", sessionID: "ses_bg" })) + expect(posts).toContainEqual(expect.objectContaining({ type: "memoryLoaded", sessionID: "ses_active" })) + expect(calls).toEqual(["/repo", "/repo"]) + }) + + it("uses the project directory when toggling memory", async () => { + const calls: unknown[] = [] + const client = { + memory: { + status: async (input: { directory: string }) => { + calls.push(["status", input.directory]) + return { data: status(input.directory) } + }, + disable: async (input: { directory: string }) => { + calls.push(["disable", input.directory]) + return { data: { root: `${input.directory}/.kilo/memory`, state: status(input.directory).state } } + }, + show: async (input: { directory: string }) => { + calls.push(["show", input.directory]) + return { data: show(input.directory) } + }, + }, + } as unknown as KiloClient + const posts: unknown[] = [] + const provider = new KiloProvider( + {} as never, + { + getClient: () => client, + } as never, + undefined, + { projectDirectory: "/repo/project" }, + ) + const item = provider as unknown as Internals + item.webview = { postMessage: async (message) => posts.push(message) } + item.currentSession = { id: "ses_active" } + + await provider.toggleMemory("ses_active") + + expect(calls).toEqual([ + ["status", "/repo/project"], + ["disable", "/repo/project"], + ["status", "/repo/project"], + ["show", "/repo/project"], + ]) + expect(posts).toContainEqual(expect.objectContaining({ type: "memoryLoaded", sessionID: "ses_active" })) + }) +}) diff --git a/packages/kilo-vscode/tests/unit/kilo-provider-memory.test.ts b/packages/kilo-vscode/tests/unit/kilo-provider-memory.test.ts new file mode 100644 index 00000000000..2470fc50ac5 --- /dev/null +++ b/packages/kilo-vscode/tests/unit/kilo-provider-memory.test.ts @@ -0,0 +1,187 @@ +import { describe, expect, it } from "bun:test" +import type { KiloClient } from "@kilocode/sdk/v2/client" +import { KiloProviderMemory } from "../../src/kilo-provider/memory" + +function subject(client: KiloClient | undefined) { + const posts: unknown[] = [] + const memory = new KiloProviderMemory({ + client: () => client, + session: () => undefined, + dir: () => "/repo", + post: (message) => posts.push(message), + }) + return { memory, posts } +} + +function status(root: string) { + return { + root: `${root}/.kilo/memory`, + state: { + enabled: true, + autoConsolidate: true, + stats: { + lastInjectedSessionID: "", + lastInjectedTokens: 0, + lastOperationCount: 0, + }, + }, + index: { estimatedTokens: 0 }, + } +} + +function show(root: string) { + return { + root: `${root}/.kilo/memory`, + state: status(root).state, + sources: { project: "", environment: "", corrections: "" }, + index: "", + items: "", + changes: "", + decisions: "", + } +} + +describe("KiloProviderMemory", () => { + it("handles clients without memory endpoints gracefully", async () => { + const item = subject({} as KiloClient) + + await item.memory.fetch("ses_memoryless") + await item.memory.inspect("ses_memoryless") + await item.memory.run({ operation: "enable", sessionID: "ses_memoryless" }) + + expect(item.posts).toEqual([ + { + type: "memoryLoaded", + sessionID: "ses_memoryless", + error: "Memory unavailable in CLI backend", + }, + { + type: "memoryLoaded", + sessionID: "ses_memoryless", + error: "Memory unavailable in CLI backend", + }, + { + type: "memoryOperationResult", + operation: "enable", + sessionID: "ses_memoryless", + ok: false, + error: "Memory unavailable in CLI backend", + }, + ]) + }) + + it("posts a load error when no client or cache exists", async () => { + const item = subject(undefined) + + await item.memory.fetch("ses_disconnected") + + expect(item.posts).toEqual([ + { + type: "memoryLoaded", + sessionID: "ses_disconnected", + error: "Not connected to CLI backend", + }, + ]) + }) + + it("evicts older cached memory payloads", async () => { + let client: KiloClient | undefined + const posts: unknown[] = [] + const item = new KiloProviderMemory({ + client: () => client, + session: () => undefined, + dir: (sid) => `/repo/${sid ?? "current"}`, + post: (message) => posts.push(message), + }) + client = { + memory: { + status: async (input: { directory: string }) => ({ data: status(input.directory) }), + show: async (input: { directory: string }) => ({ data: show(input.directory) }), + }, + } as unknown as KiloClient + + for (let i = 0; i < 9; i++) { + await item.inspect(`ses_${i}`) + } + + posts.length = 0 + client = undefined + await item.fetch("ses_0") + await item.fetch("ses_8") + + expect(posts[0]).toEqual({ + type: "memoryLoaded", + sessionID: "ses_0", + error: "Not connected to CLI backend", + }) + expect(posts[1]).toMatchObject({ + type: "memoryLoaded", + sessionID: "ses_8", + show: { root: "/repo/ses_8/.kilo/memory" }, + }) + }) + + it("does not send ignored placement fields to correction endpoint", async () => { + const calls: unknown[] = [] + const state = status("/repo") + const view = show("/repo") + const item = subject({ + memory: { + correct: async (input: unknown) => { + calls.push(input) + return { data: { operationCount: 1, added: 1, removed: 0, skipped: [], index: { tokens: 0 } } } + }, + status: async () => ({ data: state }), + show: async () => ({ data: view }), + }, + } as unknown as KiloClient) + + await item.memory.run({ + operation: "correct", + sessionID: "ses_correct", + text: "Prefer corrections.", + key: "correction_key", + file: "project.md", + section: "Facts", + }) + + expect(calls).toEqual([ + { + directory: "/repo", + text: "Prefer corrections.", + key: "correction_key", + sessionID: "ses_correct", + }, + ]) + }) + + it("routes auto-save and purge operations with explicit payloads", async () => { + const calls: unknown[] = [] + const state = status("/repo") + const view = show("/repo") + state.state.autoConsolidate = false + const item = subject({ + memory: { + configure: async (input: unknown) => { + calls.push(["configure", input]) + return { data: { root: "/repo/.kilo/memory", state: state.state } } + }, + purge: async (input: unknown) => { + calls.push(["purge", input]) + return { data: { root: "/repo/.kilo/memory", purged: true } } + }, + status: async () => ({ data: state }), + show: async () => ({ data: view }), + }, + } as unknown as KiloClient) + + await item.memory.run({ operation: "auto", mode: "off", sessionID: "ses_memory" }) + await item.memory.run({ operation: "purge", confirm: true, sessionID: "ses_memory" }) + + expect(calls).toEqual([ + ["configure", { directory: "/repo", autoConsolidate: false }], + ["purge", { directory: "/repo", confirm: true }], + ]) + expect(item.posts.filter((post) => (post as { type?: string }).type === "memoryOperationResult")).toHaveLength(2) + }) +}) diff --git a/packages/kilo-vscode/tests/unit/memory-command.test.ts b/packages/kilo-vscode/tests/unit/memory-command.test.ts new file mode 100644 index 00000000000..15201eb41d2 --- /dev/null +++ b/packages/kilo-vscode/tests/unit/memory-command.test.ts @@ -0,0 +1,57 @@ +import { describe, expect, it } from "bun:test" +import { parseMemoryCommand, type ParsedMemoryCommand } from "../../webview-ui/src/utils/memory-command" + +type MemoryOperation = "enable" | "disable" | "rebuild" | "remember" | "correct" | "forget" | "purge" | "auto" +type Case = { + name: string + input: string + result: "none" | "inspect" | "operation" | "usage" + operation?: MemoryOperation + mode?: "status" | "on" | "off" + confirm?: boolean + text?: string + query?: string + reason?: string +} + +const cases = (await Bun.file( + new URL("../../../kilo-memory/test/command-cases.json", import.meta.url), +).json()) as Case[] + +function expected(item: Case): ParsedMemoryCommand | undefined { + if (item.result === "none") return + if (item.result === "inspect") return { kind: "inspect" } + if (item.result === "usage") return { kind: "usage", reason: item.reason ?? "" } + if (!item.operation) throw new Error(`Missing operation for fixture: ${item.name}`) + if (item.operation === "remember" || item.operation === "correct") { + if (!item.text) throw new Error(`Missing text for fixture: ${item.name}`) + return { kind: "operation", operation: item.operation, text: item.text } + } + if (item.operation === "forget") { + if (!item.query) throw new Error(`Missing query for fixture: ${item.name}`) + return { kind: "operation", operation: item.operation, query: item.query } + } + if (item.operation === "auto") { + if (!item.mode) throw new Error(`Missing mode for fixture: ${item.name}`) + return { kind: "operation", operation: item.operation, mode: item.mode } + } + if (item.operation === "purge") { + if (item.confirm !== true) throw new Error(`Missing confirmation for fixture: ${item.name}`) + return { kind: "operation", operation: item.operation, confirm: true } + } + return { kind: "operation", operation: item.operation } +} + +describe("parseMemoryCommand", () => { + it("matches shared command fixtures", () => { + for (const item of cases) { + const parsed = parseMemoryCommand(item.input) + if (item.result === "usage") { + expect(parsed?.kind, item.name).toBe("usage") + expect(parsed && "reason" in parsed ? parsed.reason : "", item.name).toContain(item.reason ?? "") + continue + } + expect(parsed, item.name).toEqual(expected(item)) + } + }) +}) diff --git a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx index f7026acfb25..f357d11205c 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx @@ -80,6 +80,7 @@ import { DisplayProvider } from "../src/context/display" import { KiloEmbeddingModelsProvider } from "../src/context/kilo-embedding-models" import { NotificationsProvider } from "../src/context/notifications" import { FeedbackProvider } from "../src/context/feedback" +import { MemoryProvider } from "../src/context/memory" import { SessionProvider, useSession } from "../src/context/session" import { WorktreeModeProvider } from "../src/context/worktree-mode" import { ChatView } from "../src/components/chat" @@ -3147,13 +3148,15 @@ export const AgentManagerApp: Component = () => { - - - - - - - + + + + + + + + + diff --git a/packages/kilo-vscode/webview-ui/src/App.tsx b/packages/kilo-vscode/webview-ui/src/App.tsx index 26f775a8bf5..70a41905b4d 100644 --- a/packages/kilo-vscode/webview-ui/src/App.tsx +++ b/packages/kilo-vscode/webview-ui/src/App.tsx @@ -19,6 +19,7 @@ import { ConfigProvider } from "./context/config" import { DisplayProvider } from "./context/display" import { WorkStyleProvider } from "./context/work-style" import { IndexingProvider } from "./context/indexing" +import { MemoryProvider } from "./context/memory" import { SessionProvider, useSession } from "./context/session" import { LanguageBridge } from "./context/language-bridge" import { ChatView } from "./components/chat" @@ -378,11 +379,13 @@ const App: Component = () => { - - - - - + + + + + + + diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/AssistantMessage.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/AssistantMessage.tsx index 1b93f888255..651a7717166 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/AssistantMessage.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/AssistantMessage.tsx @@ -11,6 +11,7 @@ import { Component, For, Show, createMemo } from "solid-js" import { Dynamic } from "solid-js/web" import { Part, PART_MAPPING, ToolRegistry } from "@kilocode/kilo-ui/message-part" import type { MessageFeedbackControls } from "@kilocode/kilo-ui/message-part" +import { Tooltip } from "@kilocode/kilo-ui/tooltip" import type { AssistantMessage as SDKAssistantMessage, Part as SDKPart, @@ -22,6 +23,7 @@ import { useSession } from "../../context/session" import { useDisplay } from "../../context/display" import { useConfig } from "../../context/config" import { useLanguage } from "../../context/language" +import { useMemory } from "../../context/memory" import { useServer } from "../../context/server" import { snapshotProgress } from "../../context/session-utils" import { planDisplayPath } from "../../utils/plan-path" @@ -122,6 +124,35 @@ type ToolStateProps = { status?: string } +type MemoryMeta = { + type?: string + tokens?: number + count?: number + files?: string[] + sources?: string[] +} + +function memoryMeta(parts: SDKPart[]) { + for (const part of parts) { + if (part.type !== "text") continue + const meta = (part as SDKPart & { metadata?: { kiloMemory?: unknown } }).metadata?.kiloMemory + if (!meta || typeof meta !== "object") continue + const item = meta as MemoryMeta + const files = Array.isArray(item.files) + ? item.files.filter((file) => typeof file === "string") + : Array.isArray(item.sources) + ? item.sources.filter((source) => typeof source === "string") + : [] + const count = typeof item.count === "number" ? item.count : files.length + const tokens = typeof item.tokens === "number" ? item.tokens : 0 + const type = item.type === "startup" ? "startup" : "recall" + return { type, count, tokens, files } + } + return undefined +} + +type MemoryItem = NonNullable> + function TodoToolCard(props: { part: ToolPart }) { const render = ToolRegistry.render(props.part.tool) const state = () => props.part.state as ToolStateProps @@ -174,6 +205,8 @@ export const AssistantMessage: Component = (props) => { const data = useData() const session = useSession() const display = useDisplay() + const mem = useMemory() + const language = useLanguage() const { config } = useConfig() const open = createMemo(() => config().terminal_command_display !== "collapsed") @@ -182,6 +215,52 @@ export const AssistantMessage: Component = (props) => { if (!stored) return [] return (stored as SDKPart[]).filter((part) => isRenderable(part)) }) + const meta = createMemo(() => memoryMeta(((data.store.part?.[props.message.id] ?? []) as SDKPart[]) ?? [])) + const fmt = (value: number) => value.toLocaleString(language.locale()) + const count = (item: MemoryItem) => fmt(item.count) + const tokens = (item: MemoryItem) => fmt(item.tokens) + const label = (item: MemoryItem) => + item.type === "startup" ? language.t("chat.memory.badge.injected") : language.t("chat.memory.badge.recalled") + const detail = (item: MemoryItem) => + item.type === "startup" + ? language.t("chat.memory.badge.startupCtx") + : language.t("chat.memory.badge.items", { count: count(item) }) + const tip = (item: MemoryItem) => { + const err = mem.error() + if (err) return {err} + const status = mem.status() + if (!status) return {language.t("chat.memory.status.loading")} + const ops = status.state.stats.lastOperationCount + const total = mem.totalTokens().toLocaleString(language.locale()) + return ( +
+
+ {item.type === "startup" + ? language.t("chat.memory.session.tokens", { tokens: tokens(item) }) + : language.t("chat.memory.badge.recalledDetail", { count: count(item), tokens: tokens(item) })} +
+
{language.t("chat.memory.total.tokens", { tokens: total })}
+
+ {!status.state.enabled + ? language.t("chat.memory.project.disabled") + : language.t("chat.memory.project.enabled")} +
+ 0}> +
+ {language.t("chat.memory.savedOperations", { + count: ops.toLocaleString(language.locale()), + })} +
+
+ +
{mem.show()!.changes.split("\n").filter(Boolean).slice(-1)[0]}
+
+ 0}> +
{language.t("chat.memory.badge.files", { files: item.files.join(", ") })}
+
+
+ ) + } return ( <> @@ -276,6 +355,15 @@ export const AssistantMessage: Component = (props) => { ) }} + + {(item) => ( + +
+ {label(item())} · {detail(item())} · {language.t("chat.memory.badge.tokens", { tokens: tokens(item()) })} +
+
+ )} +
) } diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx index d30f37f1b77..88459f321af 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx @@ -48,6 +48,8 @@ import { formatReviewCommentsMarkdown } from "../../utils/review-comment-markdow import { pendingDraftKey, scopeDraftKey, sessionDraftKey } from "../../utils/prompt-drafts" import { ReviewComments } from "./ReviewComments" import { partReview, reviewBody } from "../../../../src/shared/review-comments" +import { parseMemoryCommand } from "../../utils/memory-command" +import { useMemory } from "../../context/memory" // Per-session input text storage (module-level so it survives remounts) const drafts = new Map() @@ -81,6 +83,7 @@ export const PromptInput: Component = (props) => { const provider = useProvider() const language = useLanguage() const vscode = useVSCode() + const projectMemory = useMemory() const sid = () => session.currentSessionID() ?? props.pendingSessionID ?? session.draftSessionID() ?? undefined const ctx = () => { const id = props.boxId @@ -694,9 +697,52 @@ export const PromptInput: Component = (props) => { transcribeAndSend() } + const runMemory = (memory: NonNullable>) => { + if (memory.kind === "usage") { + showToast({ variant: "error", title: language.t("chat.memory.command.failed"), description: memory.reason }) + return false + } + if (isDisabled() || speech.active() || terminal.pending() || git.pending() || props.blocked?.()) return false + const status = projectMemory.status() + if ( + memory.kind === "operation" && + (memory.operation === "remember" || memory.operation === "correct" || memory.operation === "forget") && + status && + !status.state.enabled + ) { + showToast({ variant: "error", title: language.t("chat.memory.project.disabled") }) + return false + } + if (memory.kind === "inspect") vscode.postMessage({ type: "memoryInspect", sessionID: sid() }) + if (memory.kind === "operation") { + vscode.postMessage({ + type: "memoryOperation", + operation: memory.operation, + sessionID: sid(), + ...(memory.operation === "auto" ? { mode: memory.mode } : {}), + ...(memory.operation === "purge" ? { confirm: memory.confirm } : {}), + ...(memory.operation === "remember" || memory.operation === "correct" ? { text: memory.text } : {}), + ...(memory.operation === "forget" ? { query: memory.query } : {}), + }) + } + return true + } + const handleSend = async () => { const draft = text().trim() + const clear = () => { + setText("") + clearReviewComments() + imageAttach.clear() + mention.closeMention() + slash.close() + drafts.delete(draftKey()) + reviewDrafts.delete(draftKey()) + imageDrafts.delete(draftKey()) + if (textareaRef) textareaRef.style.height = "auto" + } + // Detect slash command (hoisted for both client and server command checks). // Prioritize exact name matches over hint/alias matches so that a server // command named e.g. "continue" is not hijacked by a client alias. @@ -708,19 +754,19 @@ export const PromptInput: Component = (props) => { // Client-side slash command — runs locally without a backend round-trip if (matched?.action) { - setText("") - clearReviewComments() - imageAttach.clear() - mention.closeMention() - slash.close() - drafts.delete(draftKey()) - reviewDrafts.delete(draftKey()) - imageDrafts.delete(draftKey()) - if (textareaRef) textareaRef.style.height = "auto" + clear() matched.action() return } + const memory = parseMemoryCommand(draft) + if (memory) { + if (!runMemory(memory)) return + history.append(draft) + clear() + return + } + const imgs = imageAttach.images() const pending = reviewComments() const review = pending.length > 0 ? formatReviewCommentsMarkdown(pending) : "" @@ -780,11 +826,7 @@ export const PromptInput: Component = (props) => { history.append(draft) history.reset() - setText("") - clearReviewComments() - imageAttach.clear() - mention.closeMention() - slash.close() + clear() if (textareaRef) textareaRef.style.height = "auto" } diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/TaskHeader.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/TaskHeader.tsx index d4409d07473..9d5d7ec40b4 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/TaskHeader.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/TaskHeader.tsx @@ -14,6 +14,7 @@ import { Tooltip } from "@kilocode/kilo-ui/tooltip" import { Icon } from "@kilocode/kilo-ui/icon" import { Checkbox } from "@kilocode/kilo-ui/checkbox" import { useSession } from "../../context/session" +import { useMemory } from "../../context/memory" import { calcTokenUsage, collapseCostBreakdown } from "../../context/session-utils" import { useLanguage } from "../../context/language" import { useVSCode } from "../../context/vscode" @@ -29,6 +30,7 @@ interface TaskHeaderProps { export const TaskHeader: Component = (props) => { const session = useSession() + const memory = useMemory() const language = useLanguage() const title = createMemo(() => session.currentSession()?.title ?? language.t("command.session.new")) @@ -84,6 +86,14 @@ export const TaskHeader: Component = (props) => { return String(n) } + const memoryLabel = createMemo(() => { + const status = memory.status() + if (!status) return memory.loading() ? language.t("chat.memory.loading") : undefined + if (!status.state.enabled) return language.t("chat.memory.off") + const count = memory.sessionTokens() + return count > 0 ? language.t("chat.memory.label", { tokens: fmtNum(count) }) : language.t("chat.memory.on") + }) + const vscode = useVSCode() const [expanded, setExpanded] = createSignal(true) @@ -233,6 +243,69 @@ export const TaskHeader: Component = (props) => {
+ +
+ + + {memoryLabel()} + + + + memory.inspect()} + aria-label={language.t("chat.memory.inspect")} + /> + + + memory.remember()} + aria-label={language.t("chat.memory.remember")} + /> + + + memory.forget()} + aria-label={language.t("chat.memory.forget")} + /> + + + memory.rebuild()} + aria-label={language.t("chat.memory.rebuild")} + /> + + + (memory.enabled() ? memory.disable() : memory.enable())} + aria-label={memory.enabled() ? language.t("chat.memory.disable") : language.t("chat.memory.enable")} + /> + + +
+
{(tk) => (
diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/ContextTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/ContextTab.tsx index 878d260e398..e5c779c2971 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/ContextTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/ContextTab.tsx @@ -1,4 +1,4 @@ -import { Component, For, createSignal } from "solid-js" +import { Component, For, Show, createSignal } from "solid-js" import { Switch } from "@kilocode/kilo-ui/switch" import { TextField } from "@kilocode/kilo-ui/text-field" import { Card } from "@kilocode/kilo-ui/card" @@ -7,10 +7,12 @@ import { IconButton } from "@kilocode/kilo-ui/icon-button" import { useConfig } from "../../context/config" import { useLanguage } from "../../context/language" +import { useMemory } from "../../context/memory" import SettingsRow from "./SettingsRow" const ContextTab: Component = () => { const { config, updateConfig } = useConfig() + const memory = useMemory() const language = useLanguage() const [newPattern, setNewPattern] = createSignal("") @@ -50,9 +52,85 @@ const ContextTab: Component = () => { updateConfig({ watcher: { ignore: current } }) } + const memoryStats = () => { + const status = memory.status() + if (!status) return language.t("settings.context.memory.status.notLoaded") + if (!status.state.enabled) return language.t("settings.context.memory.status.disabled") + const tokens = status.index.estimatedTokens.toLocaleString(language.locale()) + const session = memory.sessionTokens().toLocaleString(language.locale()) + const ops = status.state.stats.lastOperationCount.toLocaleString(language.locale()) + return language.t("settings.context.memory.status.enabledTokensOps", { session, tokens, ops }) + } + return (
+

{language.t("settings.context.memory.title")}

+ + + (checked ? memory.enable() : memory.disable())} + hideLabel + disabled={memory.pending()} + > + {language.t("settings.context.memory.project.title")} + + + + memory.auto(checked ? "on" : "off")} + hideLabel + disabled={memory.pending() || !memory.status()} + > + {language.t("settings.context.memory.autoSave.title")} + + + +
+ + memory.rebuild()} + aria-label={language.t("settings.context.memory.rebuild")} + /> +
+
+ + {(err) => ( +
+ {err()} +
+ )} +
+
+ {/* Compaction settings */} +

+ {language.t("settings.context.compaction.title")} +

+ show: Accessor + loading: Accessor + pending: Accessor + error: Accessor + enabled: Accessor + active: Accessor + sessionTokens: Accessor + totalTokens: Accessor + refresh: (includeSources?: boolean) => void + inspect: () => void + enable: () => void + disable: () => void + auto: (mode: "on" | "off") => void + rebuild: () => void + remember: () => void + forget: () => void +} + +const MemoryContext = createContext() + +export const MemoryProvider: ParentComponent = (props) => { + const vscode = useVSCode() + const server = useServer() + const session = useSession() + const language = useLanguage() + const [status, setStatus] = createSignal() + const [show, setShow] = createSignal() + const [loading, setLoading] = createSignal(false) + const [pending, setPending] = createSignal() + const [error, setError] = createSignal() + + const id = () => session.currentSessionID() + const key = (sid?: string) => sid ?? "" + const current = (sid?: string) => { + const active = id() + if (!sid) return true + return active === sid + } + let last = "" + let scope = "" + + const clear = () => { + setStatus(undefined) + setShow(undefined) + setError(undefined) + } + + const refresh = (includeSources = false) => { + if (!server.isConnected()) return + setLoading(true) + setError(undefined) + vscode.postMessage({ type: "requestMemory", sessionID: id(), includeSources }) + } + + const operation = (op: "enable" | "disable" | "rebuild") => { + setPending(key(id())) + setError(undefined) + vscode.postMessage({ type: "memoryOperation", operation: op, sessionID: id() }) + } + + const auto = (mode: "on" | "off") => { + setPending(key(id())) + setError(undefined) + vscode.postMessage({ type: "memoryOperation", operation: "auto", mode, sessionID: id() }) + } + + const prompt = (op: "remember" | "forget") => { + setError(undefined) + vscode.postMessage({ type: "memoryPrompt", operation: op, sessionID: id() }) + } + + const inspect = () => { + setLoading(true) + setError(undefined) + vscode.postMessage({ type: "memoryInspect", sessionID: id() }) + } + + const event = (message: Extract) => { + if (!current(message.sessionID)) return + if (message.detail.type === "skipped") return + if (!message.detail.message) return + const key = `${message.sessionID ?? ""}:${message.detail.type ?? ""}:${message.detail.message}` + if (key === last) return + last = key + showToast({ + ...(message.detail.type === "saved" + ? { variant: "success" as const } + : message.detail.type === "error" + ? { variant: "error" as const } + : {}), + title: message.detail.message, + }) + } + + const loaded = (message: Extract) => { + if (!current(message.sessionID)) return + setLoading(false) + if (message.error) { + setError(message.error) + setStatus(undefined) + setShow(undefined) + return + } + if (message.status) setStatus(message.status) + setShow(message.show) + setError(undefined) + } + + const done = (message: Extract) => { + if (pending() === key(message.sessionID)) setPending(undefined) + if (!current(message.sessionID)) return + setLoading(false) + if (!message.ok) { + const err = message.error ?? language.t("chat.memory.command.failed") + setError(err) + showToast({ variant: "error", title: err }) + return + } + if (message.status) setStatus(message.status) + setShow(message.show) + setError(undefined) + } + + const receive = (message: ExtensionMessage) => { + if (message.type === "memoryEvent") { + event(message) + return + } + if (message.type === "memoryLoaded") { + loaded(message) + return + } + if (message.type === "memoryOperationResult") { + done(message) + return + } + if (message.type === "extensionDataReady" && server.isConnected() && !status()) refresh(false) + } + + const unsubscribe = vscode.onMessage(receive) + + onCleanup(unsubscribe) + + createEffect(() => { + const sid = id() + const dir = server.workspaceDirectory() + const connected = server.isConnected() + const next = `${connected ? "1" : "0"}:${sid ?? ""}:${dir ?? ""}` + if (scope !== next) { + scope = next + clear() + } + if (!connected) { + setLoading(false) + return + } + refresh(false) + }) + + const sessionTokens = (status?: MemoryStatusResponse) => { + const sid = id() + if (!status?.state.enabled) return 0 + if (!sid || status?.state.stats.lastInjectedSessionID !== sid) return 0 + return status.state.stats.lastInjectedTokens + } + + const total = createMemo(() => status()?.index.estimatedTokens ?? 0) + + const sessionTotal = createMemo(() => sessionTokens(status())) + + const value: MemoryContextValue = { + status, + show, + loading, + pending: createMemo(() => pending() === key(id())), + error, + enabled: createMemo(() => status()?.state.enabled ?? false), + active: createMemo(() => Boolean(status()?.state.enabled)), + sessionTokens: sessionTotal, + totalTokens: total, + refresh, + inspect, + enable: () => operation("enable"), + disable: () => operation("disable"), + auto, + rebuild: () => operation("rebuild"), + remember: () => prompt("remember"), + forget: () => prompt("forget"), + } + + return {props.children} +} + +export function useMemory(): MemoryContextValue { + const context = useContext(MemoryContext) + if (!context) { + throw new Error("useMemory must be used within a MemoryProvider") + } + return context +} diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index b0084e40d41..5db1766bd99 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -1446,6 +1446,7 @@ export const dict = { "settings.checkpoints.enable.description": "إنشاء نقاط فحص قبل تحرير الملفات", "settings.context.autoCompaction.title": "ضغط تلقائي", "settings.context.autoCompaction.description": "ضغط السياق تلقائياً قبل أن يصل إلى الحد", + "settings.context.compaction.title": "الضغط", "settings.context.compactionLimit.title": "حد الضغط التلقائي", "settings.context.compactionLimit.description": "اضغط عندما يصل السياق إلى هذه النسبة المئوية من نافذة النموذج. اتركه فارغاً لاستخدام هامش الأمان فقط.", @@ -1454,6 +1455,46 @@ export const dict = { "settings.context.watcherPatterns": "أنماط تجاهل مراقب الملفات", "settings.context.watcherPatterns.description": "أنماط glob للملفات التي يجب على المراقب تجاهلها", + "settings.context.memory.title": "الذاكرة", + "settings.context.memory.project.title": "ذاكرة المشروع", + "settings.context.memory.autoSave.title": "حفظ ذاكرة المشروع تلقائيًا", + "settings.context.memory.autoSave.description": + "حفظ حقائق المشروع الدائمة تلقائيًا من الجولات المكتملة عند تفعيل الذاكرة.", + "settings.context.memory.index.title": "فهرس الذاكرة", + "settings.context.memory.status.notLoaded": "غير محمّلة", + "settings.context.memory.status.disabled": "معطّلة", + "settings.context.memory.status.enabled": "مفعّلة", + "settings.context.memory.status.enabledTokensOps": + "مفعّلة - ~{{session}} رموز سياق بدء التشغيل في هذه الجلسة - ~{{tokens}} رموز في الفهرس المخزّن - آخر عملية {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "فعّل الذاكرة لإنشاء ملفات ذاكرة المشروع.", + "settings.context.memory.inspect": "فحص", + "settings.context.memory.rebuild": "إعادة بناء فهرس الذاكرة", + "chat.memory.loading": "جارٍ تحميل الذاكرة...", + "chat.memory.off": "الذاكرة متوقفة", + "chat.memory.on": "الذاكرة مفعّلة", + "chat.memory.label": "الذاكرة {{tokens}} سياق بدء التشغيل", + "chat.memory.status.loading": "جارٍ تحميل حالة الذاكرة", + "chat.memory.session.tokens": "سياق بدء التشغيل في هذه الجلسة: {{tokens}} رموز", + "chat.memory.total.tokens": "الفهرس المخزّن: {{tokens}} رموز", + "chat.memory.project.enabled": "ذاكرة المشروع مفعّلة", + "chat.memory.project.disabled": "ذاكرة المشروع معطّلة", + "chat.memory.command.failed": "فشل أمر الذاكرة", + "chat.memory.savedOperations": "آخر عملية ذاكرة: {{count}} عمليات", + "chat.memory.inspect": "فحص الذاكرة", + "chat.memory.remember": "تذكّر", + "chat.memory.forget": "انسَ", + "chat.memory.rebuild": "إعادة بناء الفهرس", + "chat.memory.enable": "تفعيل الذاكرة", + "chat.memory.disable": "تعطيل الذاكرة", + "chat.memory.badge.injected": "تم حقن الذاكرة", + "chat.memory.badge.recalled": "تم استدعاء الذاكرة", + "chat.memory.badge.startupCtx": "سياق البدء", + "chat.memory.badge.items": "{{count}} عناصر", + "chat.memory.badge.tokens": "{{tokens}} رموز", + "chat.memory.badge.recalledDetail": "تم استدعاء الذاكرة: {{count}} عناصر - {{tokens}} رموز", + "chat.memory.badge.files": "ملفات الذاكرة: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "استخدام prompt مخصص", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index ae04ef3315f..fee2d8954b3 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -1489,6 +1489,7 @@ export const dict = { "settings.checkpoints.enable.description": "Criar pontos de verificação antes de editar arquivos", "settings.context.autoCompaction.title": "Compactação automática", "settings.context.autoCompaction.description": "Compactar automaticamente o contexto antes que atinja o limite", + "settings.context.compaction.title": "Compactação", "settings.context.compactionLimit.title": "Limite de compactação automática", "settings.context.compactionLimit.description": "Compacte quando o contexto atingir esta porcentagem da janela do modelo. Deixe em branco para usar apenas a margem de segurança.", @@ -1497,6 +1498,46 @@ export const dict = { "settings.context.watcherPatterns": "Padrões de ignorar do observador", "settings.context.watcherPatterns.description": "Padrões glob para arquivos que o observador deve ignorar", + "settings.context.memory.title": "Memória", + "settings.context.memory.project.title": "Memória do projeto", + "settings.context.memory.autoSave.title": "Salvar memória do projeto automaticamente", + "settings.context.memory.autoSave.description": + "Salva automaticamente fatos duradouros do projeto a partir de turnos concluídos quando a memória está ativada.", + "settings.context.memory.index.title": "Índice da memória", + "settings.context.memory.status.notLoaded": "Não carregada", + "settings.context.memory.status.disabled": "Desativada", + "settings.context.memory.status.enabled": "Ativada", + "settings.context.memory.status.enabledTokensOps": + "Ativada - ~{{session}} tokens de contexto inicial nesta sessão - ~{{tokens}} tokens no índice armazenado - última op. {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Ative a memória para criar arquivos de memória do projeto.", + "settings.context.memory.inspect": "Inspecionar", + "settings.context.memory.rebuild": "Reconstruir índice da memória", + "chat.memory.loading": "Memória...", + "chat.memory.off": "Memória desligada", + "chat.memory.on": "Memória ligada", + "chat.memory.label": "Memória {{tokens}} ctx inicial", + "chat.memory.status.loading": "Carregando status da memória", + "chat.memory.session.tokens": "Contexto inicial desta sessão: {{tokens}} tokens", + "chat.memory.total.tokens": "Índice armazenado: {{tokens}} tokens", + "chat.memory.project.enabled": "Memória do projeto ativada", + "chat.memory.project.disabled": "Memória do projeto desativada", + "chat.memory.command.failed": "Comando de memória falhou", + "chat.memory.savedOperations": "Última operação de memória: {{count}} ops", + "chat.memory.inspect": "Inspecionar memória", + "chat.memory.remember": "Lembrar", + "chat.memory.forget": "Esquecer", + "chat.memory.rebuild": "Reconstruir índice", + "chat.memory.enable": "Ativar memória", + "chat.memory.disable": "Desativar memória", + "chat.memory.badge.injected": "Memória injetada", + "chat.memory.badge.recalled": "Memória recuperada", + "chat.memory.badge.startupCtx": "ctx inicial", + "chat.memory.badge.items": "{{count}} itens", + "chat.memory.badge.tokens": "{{tokens}} tokens", + "chat.memory.badge.recalledDetail": "Memória recuperada: {{count}} itens - {{tokens}} tokens", + "chat.memory.badge.files": "Arquivos de memória: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Usar prompt personalizado", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts index b6e5725db7a..5b64350ec4f 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts @@ -1485,6 +1485,7 @@ export const dict = { "settings.checkpoints.enable.description": "Kreiraj kontrolne točke prije uređivanja datoteka", "settings.context.autoCompaction.title": "Automatska kompresija", "settings.context.autoCompaction.description": "Automatski komprimiraj kontekst prije nego dostigne limit", + "settings.context.compaction.title": "Kompresija", "settings.context.compactionLimit.title": "Limit automatske kompresije", "settings.context.compactionLimit.description": "Komprimiraj kada kontekst dostigne ovaj procenat prozora modela. Ostavite prazno da koristite samo sigurnosnu rezervu.", @@ -1493,6 +1494,46 @@ export const dict = { "settings.context.watcherPatterns": "Uzorci ignoriranja za promatrač datoteka", "settings.context.watcherPatterns.description": "Glob uzorci za datoteke koje promatrač treba ignorirati", + "settings.context.memory.title": "Memorija", + "settings.context.memory.project.title": "Memorija projekta", + "settings.context.memory.autoSave.title": "Automatsko spremanje memorije projekta", + "settings.context.memory.autoSave.description": + "Automatski sprema trajne činjenice projekta iz završenih koraka kada je memorija uključena.", + "settings.context.memory.index.title": "Indeks memorije", + "settings.context.memory.status.notLoaded": "Nije učitana", + "settings.context.memory.status.disabled": "Onemogućena", + "settings.context.memory.status.enabled": "Omogućena", + "settings.context.memory.status.enabledTokensOps": + "Omogućena - ~{{session}} tokena početnog konteksta u ovoj sesiji - ~{{tokens}} tokena spremljenog indeksa - zadnja op. {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Omogućite memoriju za kreiranje datoteka memorije projekta.", + "settings.context.memory.inspect": "Pregledaj", + "settings.context.memory.rebuild": "Ponovo izgradi indeks memorije", + "chat.memory.loading": "Memorija...", + "chat.memory.off": "Memorija isključena", + "chat.memory.on": "Memorija uključena", + "chat.memory.label": "Memorija {{tokens}} početni ctx", + "chat.memory.status.loading": "Učitavanje statusa memorije", + "chat.memory.session.tokens": "Početni kontekst ove sesije: {{tokens}} tokena", + "chat.memory.total.tokens": "Spremljeni indeks: {{tokens}} tokena", + "chat.memory.project.enabled": "Memorija projekta omogućena", + "chat.memory.project.disabled": "Memorija projekta onemogućena", + "chat.memory.command.failed": "Komanda memorije nije uspjela", + "chat.memory.savedOperations": "Zadnja operacija memorije: {{count}} op.", + "chat.memory.inspect": "Pregledaj memoriju", + "chat.memory.remember": "Zapamti", + "chat.memory.forget": "Zaboravi", + "chat.memory.rebuild": "Ponovo izgradi indeks", + "chat.memory.enable": "Omogući memoriju", + "chat.memory.disable": "Onemogući memoriju", + "chat.memory.badge.injected": "Memorija ubačena", + "chat.memory.badge.recalled": "Memorija opozvana", + "chat.memory.badge.startupCtx": "početni ctx", + "chat.memory.badge.items": "{{count}} stavki", + "chat.memory.badge.tokens": "{{tokens}} tokena", + "chat.memory.badge.recalledDetail": "Memorija opozvana: {{count}} stavki - {{tokens}} tokena", + "chat.memory.badge.files": "Datoteke memorije: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Koristi prilagođeni prompt", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index 241e3c45116..c34642f1a05 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -1474,6 +1474,7 @@ export const dict = { "settings.checkpoints.enable.description": "Opret kontrolpunkter før filredigeringer", "settings.context.autoCompaction.title": "Automatisk komprimering", "settings.context.autoCompaction.description": "Komprimér automatisk kontekst, før den når grænsen", + "settings.context.compaction.title": "Komprimering", "settings.context.compactionLimit.title": "Grænse for automatisk komprimering", "settings.context.compactionLimit.description": "Komprimér, når konteksten når denne procentdel af modelvinduet. Lad feltet være tomt for kun at bruge sikkerhedsbufferen.", @@ -1482,6 +1483,46 @@ export const dict = { "settings.context.watcherPatterns": "Filvagt-ignormønstre", "settings.context.watcherPatterns.description": "Glob-mønstre for filer, som vagten skal ignorere", + "settings.context.memory.title": "Hukommelse", + "settings.context.memory.project.title": "Projekthukommelse", + "settings.context.memory.autoSave.title": "Gem projekthukommelse automatisk", + "settings.context.memory.autoSave.description": + "Gemmer automatisk varige projektfakta fra afsluttede ture, når hukommelse er aktiveret.", + "settings.context.memory.index.title": "Hukommelsesindeks", + "settings.context.memory.status.notLoaded": "Ikke indlæst", + "settings.context.memory.status.disabled": "Deaktiveret", + "settings.context.memory.status.enabled": "Aktiveret", + "settings.context.memory.status.enabledTokensOps": + "Aktiveret - ~{{session}} opstartstokens i denne session - ~{{tokens}} tokens i gemt indeks - seneste handling {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Aktivér hukommelse for at oprette projektets hukommelsesfiler.", + "settings.context.memory.inspect": "Inspicér", + "settings.context.memory.rebuild": "Genopbyg hukommelsesindeks", + "chat.memory.loading": "Hukommelse...", + "chat.memory.off": "Hukommelse fra", + "chat.memory.on": "Hukommelse til", + "chat.memory.label": "Hukommelse {{tokens}} opstartsctx", + "chat.memory.status.loading": "Indlæser hukommelsesstatus", + "chat.memory.session.tokens": "Opstartskontekst i denne session: {{tokens}} tokens", + "chat.memory.total.tokens": "Gemt indeks: {{tokens}} tokens", + "chat.memory.project.enabled": "Projekthukommelse aktiveret", + "chat.memory.project.disabled": "Projekthukommelse deaktiveret", + "chat.memory.command.failed": "Hukommelseskommando mislykkedes", + "chat.memory.savedOperations": "Seneste hukommelseshandling: {{count}} handlinger", + "chat.memory.inspect": "Inspicér hukommelse", + "chat.memory.remember": "Husk", + "chat.memory.forget": "Glem", + "chat.memory.rebuild": "Genopbyg indeks", + "chat.memory.enable": "Aktivér hukommelse", + "chat.memory.disable": "Deaktivér hukommelse", + "chat.memory.badge.injected": "Hukommelse injiceret", + "chat.memory.badge.recalled": "Hukommelse genkaldt", + "chat.memory.badge.startupCtx": "opstartsctx", + "chat.memory.badge.items": "{{count}} elementer", + "chat.memory.badge.tokens": "{{tokens}} tokens", + "chat.memory.badge.recalledDetail": "Hukommelse genkaldt: {{count}} elementer - {{tokens}} tokens", + "chat.memory.badge.files": "Hukommelsesfiler: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Brug brugerdefineret prompt", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index 04ffc2f2c13..0d5849dfe6c 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -1505,6 +1505,7 @@ export const dict = { "Prüfpunkte vor Dateibearbeitungen erstellen, um vorherige Zustände wiederherstellen zu können", "settings.context.autoCompaction.title": "Automatische Komprimierung", "settings.context.autoCompaction.description": "Kontext automatisch komprimieren, bevor er das Limit erreicht", + "settings.context.compaction.title": "Komprimierung", "settings.context.compactionLimit.title": "Limit für automatische Komprimierung", "settings.context.compactionLimit.description": "Komprimieren, wenn der Kontext diesen Prozentsatz des Modellfensters erreicht. Leer lassen, um nur den Sicherheitspuffer zu verwenden.", @@ -1513,6 +1514,46 @@ export const dict = { "settings.context.watcherPatterns": "Datei-Watcher-Ignorierungsmuster", "settings.context.watcherPatterns.description": "Glob-Muster für Dateien, die der Watcher ignorieren soll", + "settings.context.memory.title": "Speicher", + "settings.context.memory.project.title": "Projektspeicher", + "settings.context.memory.autoSave.title": "Projektspeicher automatisch speichern", + "settings.context.memory.autoSave.description": + "Dauerhafte Projektfakten aus abgeschlossenen Durchläufen automatisch speichern, wenn Speicher aktiviert ist.", + "settings.context.memory.index.title": "Speicherindex", + "settings.context.memory.status.notLoaded": "Nicht geladen", + "settings.context.memory.status.disabled": "Deaktiviert", + "settings.context.memory.status.enabled": "Aktiviert", + "settings.context.memory.status.enabledTokensOps": + "Aktiviert - ~{{session}} Startkontext-Tokens in dieser Sitzung - ~{{tokens}} Tokens im gespeicherten Index - letzte Operation {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Aktivieren Sie den Speicher, um Projektspeicherdateien zu erstellen.", + "settings.context.memory.inspect": "Prüfen", + "settings.context.memory.rebuild": "Speicherindex neu erstellen", + "chat.memory.loading": "Speicher...", + "chat.memory.off": "Speicher aus", + "chat.memory.on": "Speicher an", + "chat.memory.label": "Speicher {{tokens}} Startkontext", + "chat.memory.status.loading": "Speicherstatus wird geladen", + "chat.memory.session.tokens": "Startkontext dieser Sitzung: {{tokens}} Tokens", + "chat.memory.total.tokens": "Gespeicherter Index: {{tokens}} Tokens", + "chat.memory.project.enabled": "Projektspeicher aktiviert", + "chat.memory.project.disabled": "Projektspeicher deaktiviert", + "chat.memory.command.failed": "Speicherbefehl fehlgeschlagen", + "chat.memory.savedOperations": "Letzte Speicheroperation: {{count}} Vorgänge", + "chat.memory.inspect": "Speicher prüfen", + "chat.memory.remember": "Merken", + "chat.memory.forget": "Vergessen", + "chat.memory.rebuild": "Index neu erstellen", + "chat.memory.enable": "Speicher aktivieren", + "chat.memory.disable": "Speicher deaktivieren", + "chat.memory.badge.injected": "Speicher eingefügt", + "chat.memory.badge.recalled": "Speicher abgerufen", + "chat.memory.badge.startupCtx": "Startkontext", + "chat.memory.badge.items": "{{count}} Elemente", + "chat.memory.badge.tokens": "{{tokens}} Tokens", + "chat.memory.badge.recalledDetail": "Speicher abgerufen: {{count}} Elemente - {{tokens}} Tokens", + "chat.memory.badge.files": "Speicherdateien: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Benutzerdefinierten prompt verwenden", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts index affab854d31..24563514998 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts @@ -1460,6 +1460,7 @@ export const dict = { "settings.context.autoCompaction.title": "Auto Compaction", "settings.context.autoCompaction.description": "Automatically compact context before it reaches the limit", + "settings.context.compaction.title": "Compaction", "settings.context.compactionLimit.title": "Auto Compaction Limit", "settings.context.compactionLimit.description": "Compact when context reaches this percentage of the model window. Leave blank to use the safety buffer only.", @@ -1467,6 +1468,45 @@ export const dict = { "settings.context.prune.description": "Remove old tool outputs during compaction", "settings.context.watcherPatterns": "File Watcher Ignore Patterns", "settings.context.watcherPatterns.description": "Glob patterns for files the watcher should ignore", + "settings.context.memory.title": "Memory", + "settings.context.memory.project.title": "Project memory", + "settings.context.memory.autoSave.title": "Auto-save project memory", + "settings.context.memory.autoSave.description": + "Automatically save durable project facts from completed turns when memory is enabled.", + "settings.context.memory.index.title": "Memory index", + "settings.context.memory.status.notLoaded": "Not loaded", + "settings.context.memory.status.disabled": "Disabled", + "settings.context.memory.status.enabled": "Enabled", + "settings.context.memory.status.enabledTokensOps": + "Enabled - ~{{session}} startup tokens this session - ~{{tokens}} stored index tokens - last op {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Enable memory to create project memory files.", + "settings.context.memory.inspect": "Inspect", + "settings.context.memory.rebuild": "Rebuild memory index", + "chat.memory.loading": "Memory...", + "chat.memory.off": "Memory off", + "chat.memory.on": "Memory on", + "chat.memory.label": "Memory {{tokens}} startup ctx", + "chat.memory.status.loading": "Memory status loading", + "chat.memory.session.tokens": "Startup context this session: {{tokens}} tokens", + "chat.memory.total.tokens": "Stored index: {{tokens}} tokens", + "chat.memory.project.enabled": "Project memory enabled", + "chat.memory.project.disabled": "Project memory disabled", + "chat.memory.command.failed": "Memory command failed", + "chat.memory.savedOperations": "Last memory operation: {{count}} ops", + "chat.memory.inspect": "Inspect memory", + "chat.memory.remember": "Remember", + "chat.memory.forget": "Forget", + "chat.memory.rebuild": "Rebuild index", + "chat.memory.enable": "Enable memory", + "chat.memory.disable": "Disable memory", + "chat.memory.badge.injected": "Memory injected", + "chat.memory.badge.recalled": "Memory recalled", + "chat.memory.badge.startupCtx": "startup ctx", + "chat.memory.badge.items": "{{count}} items", + "chat.memory.badge.tokens": "{{tokens}} tokens", + "chat.memory.badge.recalledDetail": "Memory recalled: {{count}} items - {{tokens}} tokens", + "chat.memory.badge.files": "Memory files: {{files}}", "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Use Custom Prompt", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index 68d58c4c587..31983179121 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -1497,6 +1497,7 @@ export const dict = { "settings.checkpoints.enable.description": "Crear puntos de control antes de editar archivos", "settings.context.autoCompaction.title": "Compactación automática", "settings.context.autoCompaction.description": "Compactar automáticamente el contexto antes de que alcance el límite", + "settings.context.compaction.title": "Compactación", "settings.context.compactionLimit.title": "Límite de compactación automática", "settings.context.compactionLimit.description": "Compactar cuando el contexto alcance este porcentaje de la ventana del modelo. Déjalo en blanco para usar solo el búfer de seguridad.", @@ -1505,6 +1506,46 @@ export const dict = { "settings.context.watcherPatterns": "Patrones de ignorar del observador", "settings.context.watcherPatterns.description": "Patrones glob para archivos que el observador debe ignorar", + "settings.context.memory.title": "Memoria", + "settings.context.memory.project.title": "Memoria del proyecto", + "settings.context.memory.autoSave.title": "Guardado automático de memoria del proyecto", + "settings.context.memory.autoSave.description": + "Guardar automáticamente hechos duraderos del proyecto desde turnos completados cuando la memoria está activada.", + "settings.context.memory.index.title": "Índice de memoria", + "settings.context.memory.status.notLoaded": "No cargada", + "settings.context.memory.status.disabled": "Desactivada", + "settings.context.memory.status.enabled": "Activada", + "settings.context.memory.status.enabledTokensOps": + "Activada - ~{{session}} tokens de contexto inicial en esta sesión - ~{{tokens}} tokens del índice almacenado - última op. {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Activa la memoria para crear archivos de memoria del proyecto.", + "settings.context.memory.inspect": "Inspeccionar", + "settings.context.memory.rebuild": "Reconstruir índice de memoria", + "chat.memory.loading": "Memoria...", + "chat.memory.off": "Memoria desactivada", + "chat.memory.on": "Memoria activada", + "chat.memory.label": "Memoria {{tokens}} ctx inicial", + "chat.memory.status.loading": "Cargando estado de la memoria", + "chat.memory.session.tokens": "Contexto inicial de esta sesión: {{tokens}} tokens", + "chat.memory.total.tokens": "Índice almacenado: {{tokens}} tokens", + "chat.memory.project.enabled": "Memoria del proyecto activada", + "chat.memory.project.disabled": "Memoria del proyecto desactivada", + "chat.memory.command.failed": "Error en el comando de memoria", + "chat.memory.savedOperations": "Última operación de memoria: {{count}} ops", + "chat.memory.inspect": "Inspeccionar memoria", + "chat.memory.remember": "Recordar", + "chat.memory.forget": "Olvidar", + "chat.memory.rebuild": "Reconstruir índice", + "chat.memory.enable": "Activar memoria", + "chat.memory.disable": "Desactivar memoria", + "chat.memory.badge.injected": "Memoria inyectada", + "chat.memory.badge.recalled": "Memoria recuperada", + "chat.memory.badge.startupCtx": "ctx inicial", + "chat.memory.badge.items": "{{count}} elementos", + "chat.memory.badge.tokens": "{{tokens}} tokens", + "chat.memory.badge.recalledDetail": "Memoria recuperada: {{count}} elementos - {{tokens}} tokens", + "chat.memory.badge.files": "Archivos de memoria: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Usar prompt personalizado", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index 382d972c4d7..ff2b3068d96 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -1517,6 +1517,7 @@ export const dict = { "settings.context.autoCompaction.title": "Compaction automatique", "settings.context.autoCompaction.description": "Compacter automatiquement le contexte avant qu'il n'atteigne la limite", + "settings.context.compaction.title": "Compactage", "settings.context.compactionLimit.title": "Limite de compactage automatique", "settings.context.compactionLimit.description": "Compacter lorsque le contexte atteint ce pourcentage de la fenêtre du modèle. Laissez vide pour utiliser uniquement la marge de sécurité.", @@ -1525,6 +1526,46 @@ export const dict = { "settings.context.watcherPatterns": "Motifs d'ignorance de l'observateur", "settings.context.watcherPatterns.description": "Motifs glob pour les fichiers que l'observateur doit ignorer", + "settings.context.memory.title": "Mémoire", + "settings.context.memory.project.title": "Mémoire du projet", + "settings.context.memory.autoSave.title": "Enregistrement automatique de la mémoire du projet", + "settings.context.memory.autoSave.description": + "Enregistrer automatiquement les faits durables du projet à partir des tours terminés lorsque la mémoire est activée.", + "settings.context.memory.index.title": "Index de mémoire", + "settings.context.memory.status.notLoaded": "Non chargée", + "settings.context.memory.status.disabled": "Désactivée", + "settings.context.memory.status.enabled": "Activée", + "settings.context.memory.status.enabledTokensOps": + "Activée - ~{{session}} tokens de contexte initial dans cette session - ~{{tokens}} tokens dans l’index stocké - dernière opération {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Activez la mémoire pour créer les fichiers de mémoire du projet.", + "settings.context.memory.inspect": "Inspecter", + "settings.context.memory.rebuild": "Reconstruire l’index de mémoire", + "chat.memory.loading": "Mémoire...", + "chat.memory.off": "Mémoire désactivée", + "chat.memory.on": "Mémoire activée", + "chat.memory.label": "Mémoire {{tokens}} ctx initial", + "chat.memory.status.loading": "Chargement de l’état de la mémoire", + "chat.memory.session.tokens": "Contexte initial de cette session : {{tokens}} tokens", + "chat.memory.total.tokens": "Index stocké : {{tokens}} tokens", + "chat.memory.project.enabled": "Mémoire du projet activée", + "chat.memory.project.disabled": "Mémoire du projet désactivée", + "chat.memory.command.failed": "La commande de mémoire a échoué", + "chat.memory.savedOperations": "Dernière opération de mémoire : {{count}} ops", + "chat.memory.inspect": "Inspecter la mémoire", + "chat.memory.remember": "Mémoriser", + "chat.memory.forget": "Oublier", + "chat.memory.rebuild": "Reconstruire l’index", + "chat.memory.enable": "Activer la mémoire", + "chat.memory.disable": "Désactiver la mémoire", + "chat.memory.badge.injected": "Mémoire injectée", + "chat.memory.badge.recalled": "Mémoire rappelée", + "chat.memory.badge.startupCtx": "ctx initial", + "chat.memory.badge.items": "{{count}} éléments", + "chat.memory.badge.tokens": "{{tokens}} tokens", + "chat.memory.badge.recalledDetail": "Mémoire rappelée : {{count}} éléments - {{tokens}} tokens", + "chat.memory.badge.files": "Fichiers mémoire : {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Utiliser un prompt personnalisé", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/it.ts b/packages/kilo-vscode/webview-ui/src/i18n/it.ts index 4656f1e8950..ff349863ee3 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/it.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/it.ts @@ -1313,10 +1313,51 @@ export const dict = { "Crea checkpoint prima delle modifiche ai file così puoi ripristinare stati precedenti", "settings.context.autoCompaction.title": "Compattazione automatica", "settings.context.autoCompaction.description": "Compatta automaticamente il contesto quando è pieno", + "settings.context.compaction.title": "Compattazione", "settings.context.prune.title": "Riduci output vecchi", "settings.context.prune.description": "Rimuovi output tool vecchi durante la compattazione", "settings.context.watcherPatterns": "Pattern ignore file watcher", "settings.context.watcherPatterns.description": "Pattern glob per file che il watcher deve ignorare", + "settings.context.memory.title": "Memoria", + "settings.context.memory.project.title": "Memoria del progetto", + "settings.context.memory.autoSave.title": "Salvataggio automatico memoria progetto", + "settings.context.memory.autoSave.description": + "Salva automaticamente fatti durevoli del progetto dai turni completati quando la memoria è attiva.", + "settings.context.memory.index.title": "Indice della memoria", + "settings.context.memory.status.notLoaded": "Non caricata", + "settings.context.memory.status.disabled": "Disattivata", + "settings.context.memory.status.enabled": "Attivata", + "settings.context.memory.status.enabledTokensOps": + "Attivata - ~{{session}} token di contesto iniziale in questa sessione - ~{{tokens}} token nell’indice salvato - ultima operazione {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Attiva la memoria per creare i file di memoria del progetto.", + "settings.context.memory.inspect": "Ispeziona", + "settings.context.memory.rebuild": "Ricostruisci indice della memoria", + "chat.memory.loading": "Memoria...", + "chat.memory.off": "Memoria disattivata", + "chat.memory.on": "Memoria attivata", + "chat.memory.label": "Memoria {{tokens}} ctx iniziale", + "chat.memory.status.loading": "Caricamento stato memoria", + "chat.memory.session.tokens": "Contesto iniziale di questa sessione: {{tokens}} token", + "chat.memory.total.tokens": "Indice salvato: {{tokens}} token", + "chat.memory.project.enabled": "Memoria del progetto attivata", + "chat.memory.project.disabled": "Memoria del progetto disattivata", + "chat.memory.command.failed": "Comando memoria non riuscito", + "chat.memory.savedOperations": "Ultima operazione di memoria: {{count}} ops", + "chat.memory.inspect": "Ispeziona memoria", + "chat.memory.remember": "Ricorda", + "chat.memory.forget": "Dimentica", + "chat.memory.rebuild": "Ricostruisci indice", + "chat.memory.enable": "Attiva memoria", + "chat.memory.disable": "Disattiva memoria", + "chat.memory.badge.injected": "Memoria iniettata", + "chat.memory.badge.recalled": "Memoria richiamata", + "chat.memory.badge.startupCtx": "ctx iniziale", + "chat.memory.badge.items": "{{count}} elementi", + "chat.memory.badge.tokens": "{{tokens}} token", + "chat.memory.badge.recalledDetail": "Memoria richiamata: {{count}} elementi - {{tokens}} token", + "chat.memory.badge.files": "File di memoria: {{files}}", + "settings.commitMessage.title": "Messaggio commit", "settings.commitMessage.override.title": "Usa prompt personalizzato", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index 277ea1a10bc..71c0f03f42e 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -1469,6 +1469,7 @@ export const dict = { "settings.checkpoints.enable.description": "ファイル編集前にチェックポイントを作成して以前の状態を復元可能にする", "settings.context.autoCompaction.title": "自動圧縮", "settings.context.autoCompaction.description": "コンテキストが上限に達する前に自動的に圧縮", + "settings.context.compaction.title": "圧縮", "settings.context.compactionLimit.title": "自動圧縮の上限", "settings.context.compactionLimit.description": "コンテキストがモデルウィンドウのこの割合に達したら圧縮します。安全バッファーのみを使用するには空欄のままにしてください。", @@ -1477,6 +1478,46 @@ export const dict = { "settings.context.watcherPatterns": "ファイルウォッチャー無視パターン", "settings.context.watcherPatterns.description": "ウォッチャーが無視すべきファイルのglobパターン", + "settings.context.memory.title": "メモリ", + "settings.context.memory.project.title": "プロジェクトメモリ", + "settings.context.memory.autoSave.title": "プロジェクトメモリを自動保存", + "settings.context.memory.autoSave.description": + "メモリが有効なとき、完了したターンから永続的なプロジェクト情報を自動保存します。", + "settings.context.memory.index.title": "メモリインデックス", + "settings.context.memory.status.notLoaded": "未読み込み", + "settings.context.memory.status.disabled": "無効", + "settings.context.memory.status.enabled": "有効", + "settings.context.memory.status.enabledTokensOps": + "有効 - このセッションの起動コンテキスト ~{{session}} トークン - 保存済みインデックス ~{{tokens}} トークン - 最後の操作 {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "メモリを有効にしてプロジェクトメモリファイルを作成します。", + "settings.context.memory.inspect": "検査", + "settings.context.memory.rebuild": "メモリインデックスを再構築", + "chat.memory.loading": "メモリ...", + "chat.memory.off": "メモリ オフ", + "chat.memory.on": "メモリ オン", + "chat.memory.label": "メモリ {{tokens}} 起動ctx", + "chat.memory.status.loading": "メモリ状態を読み込み中", + "chat.memory.session.tokens": "このセッションの起動コンテキスト: {{tokens}} トークン", + "chat.memory.total.tokens": "保存済みインデックス: {{tokens}} トークン", + "chat.memory.project.enabled": "プロジェクトメモリが有効です", + "chat.memory.project.disabled": "プロジェクトメモリが無効です", + "chat.memory.command.failed": "メモリコマンドに失敗しました", + "chat.memory.savedOperations": "最後のメモリ操作: {{count}} 件", + "chat.memory.inspect": "メモリを検査", + "chat.memory.remember": "記憶", + "chat.memory.forget": "忘れる", + "chat.memory.rebuild": "インデックスを再構築", + "chat.memory.enable": "メモリを有効化", + "chat.memory.disable": "メモリを無効化", + "chat.memory.badge.injected": "メモリを注入しました", + "chat.memory.badge.recalled": "メモリを呼び出しました", + "chat.memory.badge.startupCtx": "起動ctx", + "chat.memory.badge.items": "{{count}} 件", + "chat.memory.badge.tokens": "{{tokens}} トークン", + "chat.memory.badge.recalledDetail": "メモリを呼び出しました: {{count}} 件 - {{tokens}} トークン", + "chat.memory.badge.files": "メモリファイル: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "カスタム prompt を使用", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index fdaf39d51d6..00c69047547 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -1454,6 +1454,7 @@ export const dict = { "settings.checkpoints.enable.description": "파일 편집 전 체크포인트를 생성하여 이전 상태를 복원할 수 있습니다", "settings.context.autoCompaction.title": "자동 압축", "settings.context.autoCompaction.description": "컨텍스트가 한도에 도달하기 전에 자동으로 압축", + "settings.context.compaction.title": "압축", "settings.context.compactionLimit.title": "자동 압축 한도", "settings.context.compactionLimit.description": "컨텍스트가 모델 창의 이 비율에 도달하면 압축합니다. 안전 버퍼만 사용하려면 비워 두세요.", @@ -1462,6 +1463,46 @@ export const dict = { "settings.context.watcherPatterns": "파일 감시자 무시 패턴", "settings.context.watcherPatterns.description": "감시자가 무시해야 할 파일의 글로브 패턴", + "settings.context.memory.title": "메모리", + "settings.context.memory.project.title": "프로젝트 메모리", + "settings.context.memory.autoSave.title": "프로젝트 메모리 자동 저장", + "settings.context.memory.autoSave.description": + "메모리가 활성화되면 완료된 턴에서 지속적인 프로젝트 사실을 자동으로 저장합니다.", + "settings.context.memory.index.title": "메모리 인덱스", + "settings.context.memory.status.notLoaded": "로드되지 않음", + "settings.context.memory.status.disabled": "비활성화됨", + "settings.context.memory.status.enabled": "활성화됨", + "settings.context.memory.status.enabledTokensOps": + "활성화됨 - 이 세션의 시작 컨텍스트 ~{{session}} 토큰 - 저장된 인덱스 ~{{tokens}} 토큰 - 마지막 작업 {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "메모리를 활성화하여 프로젝트 메모리 파일을 만듭니다.", + "settings.context.memory.inspect": "검사", + "settings.context.memory.rebuild": "메모리 인덱스 다시 빌드", + "chat.memory.loading": "메모리...", + "chat.memory.off": "메모리 꺼짐", + "chat.memory.on": "메모리 켜짐", + "chat.memory.label": "메모리 {{tokens}} 시작 ctx", + "chat.memory.status.loading": "메모리 상태 로드 중", + "chat.memory.session.tokens": "이 세션의 시작 컨텍스트: {{tokens}} 토큰", + "chat.memory.total.tokens": "저장된 인덱스: {{tokens}} 토큰", + "chat.memory.project.enabled": "프로젝트 메모리 활성화됨", + "chat.memory.project.disabled": "프로젝트 메모리 비활성화됨", + "chat.memory.command.failed": "메모리 명령 실패", + "chat.memory.savedOperations": "마지막 메모리 작업: {{count}}개 작업", + "chat.memory.inspect": "메모리 검사", + "chat.memory.remember": "기억", + "chat.memory.forget": "잊기", + "chat.memory.rebuild": "인덱스 다시 빌드", + "chat.memory.enable": "메모리 활성화", + "chat.memory.disable": "메모리 비활성화", + "chat.memory.badge.injected": "메모리 주입됨", + "chat.memory.badge.recalled": "메모리 불러옴", + "chat.memory.badge.startupCtx": "시작 ctx", + "chat.memory.badge.items": "{{count}}개 항목", + "chat.memory.badge.tokens": "{{tokens}} 토큰", + "chat.memory.badge.recalledDetail": "메모리 불러옴: {{count}}개 항목 - {{tokens}} 토큰", + "chat.memory.badge.files": "메모리 파일: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "사용자 지정 prompt 사용", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts index 42f413e7f75..f15654c0970 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts @@ -1452,6 +1452,7 @@ export const dict = { "settings.context.autoCompaction.title": "Automatische Compactie", "settings.context.autoCompaction.description": "Context automatisch compacteren voordat deze de limiet bereikt", + "settings.context.compaction.title": "Compactie", "settings.context.compactionLimit.title": "Limiet voor automatisch compacteren", "settings.context.compactionLimit.description": "Compacteer wanneer de context dit percentage van het modelvenster bereikt. Laat leeg om alleen de veiligheidsbuffer te gebruiken.", @@ -1460,6 +1461,46 @@ export const dict = { "settings.context.watcherPatterns": "File Watcher Negeer Patronen", "settings.context.watcherPatterns.description": "Glob-patronen voor bestanden die de watcher moet negeren", + "settings.context.memory.title": "Geheugen", + "settings.context.memory.project.title": "Projectgeheugen", + "settings.context.memory.autoSave.title": "Projectgeheugen automatisch opslaan", + "settings.context.memory.autoSave.description": + "Sla duurzame projectfeiten automatisch op uit voltooide beurten wanneer geheugen is ingeschakeld.", + "settings.context.memory.index.title": "Geheugenindex", + "settings.context.memory.status.notLoaded": "Niet geladen", + "settings.context.memory.status.disabled": "Uitgeschakeld", + "settings.context.memory.status.enabled": "Ingeschakeld", + "settings.context.memory.status.enabledTokensOps": + "Ingeschakeld - ~{{session}} startcontexttokens in deze sessie - ~{{tokens}} tokens in opgeslagen index - laatste bewerking {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Schakel geheugen in om projectgeheugenbestanden te maken.", + "settings.context.memory.inspect": "Inspecteren", + "settings.context.memory.rebuild": "Geheugenindex opnieuw opbouwen", + "chat.memory.loading": "Geheugen...", + "chat.memory.off": "Geheugen uit", + "chat.memory.on": "Geheugen aan", + "chat.memory.label": "Geheugen {{tokens}} startctx", + "chat.memory.status.loading": "Geheugenstatus laden", + "chat.memory.session.tokens": "Startcontext deze sessie: {{tokens}} tokens", + "chat.memory.total.tokens": "Opgeslagen index: {{tokens}} tokens", + "chat.memory.project.enabled": "Projectgeheugen ingeschakeld", + "chat.memory.project.disabled": "Projectgeheugen uitgeschakeld", + "chat.memory.command.failed": "Geheugenopdracht mislukt", + "chat.memory.savedOperations": "Laatste geheugenbewerking: {{count}} bewerkingen", + "chat.memory.inspect": "Geheugen inspecteren", + "chat.memory.remember": "Onthouden", + "chat.memory.forget": "Vergeten", + "chat.memory.rebuild": "Index opnieuw opbouwen", + "chat.memory.enable": "Geheugen inschakelen", + "chat.memory.disable": "Geheugen uitschakelen", + "chat.memory.badge.injected": "Geheugen geïnjecteerd", + "chat.memory.badge.recalled": "Geheugen opgehaald", + "chat.memory.badge.startupCtx": "startctx", + "chat.memory.badge.items": "{{count}} items", + "chat.memory.badge.tokens": "{{tokens}} tokens", + "chat.memory.badge.recalledDetail": "Geheugen opgehaald: {{count}} items - {{tokens}} tokens", + "chat.memory.badge.files": "Geheugenbestanden: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Aangepaste prompt gebruiken", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index 8c5db2c95c9..524c59047f8 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -1472,6 +1472,7 @@ export const dict = { "settings.checkpoints.enable.description": "Opprett kontrollpunkter før filredigeringer", "settings.context.autoCompaction.title": "Automatisk komprimering", "settings.context.autoCompaction.description": "Komprimer automatisk kontekst før den når grensen", + "settings.context.compaction.title": "Komprimering", "settings.context.compactionLimit.title": "Grense for automatisk komprimering", "settings.context.compactionLimit.description": "Komprimer når konteksten når denne prosentandelen av modellvinduet. La stå tomt for å bare bruke sikkerhetsbufferen.", @@ -1480,6 +1481,46 @@ export const dict = { "settings.context.watcherPatterns": "Filvakt-ignormønstre", "settings.context.watcherPatterns.description": "Glob-mønstre for filer som vakten skal ignorere", + "settings.context.memory.title": "Minne", + "settings.context.memory.project.title": "Prosjektminne", + "settings.context.memory.autoSave.title": "Lagre prosjektminne automatisk", + "settings.context.memory.autoSave.description": + "Lagrer varige prosjektfakta automatisk fra fullførte turer når minne er aktivert.", + "settings.context.memory.index.title": "Minneindeks", + "settings.context.memory.status.notLoaded": "Ikke lastet", + "settings.context.memory.status.disabled": "Deaktivert", + "settings.context.memory.status.enabled": "Aktivert", + "settings.context.memory.status.enabledTokensOps": + "Aktivert - ~{{session}} oppstartstokener i denne økten - ~{{tokens}} tokener i lagret indeks - siste operasjon {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Aktiver minne for å opprette prosjektets minnefiler.", + "settings.context.memory.inspect": "Inspiser", + "settings.context.memory.rebuild": "Bygg minneindeks på nytt", + "chat.memory.loading": "Minne...", + "chat.memory.off": "Minne av", + "chat.memory.on": "Minne på", + "chat.memory.label": "Minne {{tokens}} oppstartsctx", + "chat.memory.status.loading": "Laster minnestatus", + "chat.memory.session.tokens": "Oppstartskontekst denne økten: {{tokens}} tokener", + "chat.memory.total.tokens": "Lagret indeks: {{tokens}} tokener", + "chat.memory.project.enabled": "Prosjektminne aktivert", + "chat.memory.project.disabled": "Prosjektminne deaktivert", + "chat.memory.command.failed": "Minnekommando mislyktes", + "chat.memory.savedOperations": "Siste minneoperasjon: {{count}} operasjoner", + "chat.memory.inspect": "Inspiser minne", + "chat.memory.remember": "Husk", + "chat.memory.forget": "Glem", + "chat.memory.rebuild": "Bygg indeks på nytt", + "chat.memory.enable": "Aktiver minne", + "chat.memory.disable": "Deaktiver minne", + "chat.memory.badge.injected": "Minne injisert", + "chat.memory.badge.recalled": "Minne hentet", + "chat.memory.badge.startupCtx": "oppstartsctx", + "chat.memory.badge.items": "{{count}} elementer", + "chat.memory.badge.tokens": "{{tokens}} tokener", + "chat.memory.badge.recalledDetail": "Minne hentet: {{count}} elementer - {{tokens}} tokener", + "chat.memory.badge.files": "Minnefiler: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Bruk egendefinert prompt", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index 367b7e5dbd2..fa6e66275b7 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -1482,6 +1482,7 @@ export const dict = { "settings.checkpoints.enable.description": "Twórz punkty kontrolne przed edycją plików", "settings.context.autoCompaction.title": "Automatyczna kompakcja", "settings.context.autoCompaction.description": "Automatycznie kompaktuj kontekst, zanim osiągnie limit", + "settings.context.compaction.title": "Kompaktowanie", "settings.context.compactionLimit.title": "Limit automatycznego kompaktowania", "settings.context.compactionLimit.description": "Kompaktuj, gdy kontekst osiągnie ten procent okna modelu. Pozostaw puste, aby używać tylko bufora bezpieczeństwa.", @@ -1490,6 +1491,46 @@ export const dict = { "settings.context.watcherPatterns": "Wzorce ignorowania obserwatora plików", "settings.context.watcherPatterns.description": "Wzorce glob dla plików do ignorowania", + "settings.context.memory.title": "Pamięć", + "settings.context.memory.project.title": "Pamięć projektu", + "settings.context.memory.autoSave.title": "Automatycznie zapisuj pamięć projektu", + "settings.context.memory.autoSave.description": + "Automatycznie zapisuje trwałe fakty projektu z zakończonych tur, gdy pamięć jest włączona.", + "settings.context.memory.index.title": "Indeks pamięci", + "settings.context.memory.status.notLoaded": "Nie wczytano", + "settings.context.memory.status.disabled": "Wyłączona", + "settings.context.memory.status.enabled": "Włączona", + "settings.context.memory.status.enabledTokensOps": + "Włączona - ~{{session}} tokenów kontekstu startowego w tej sesji - ~{{tokens}} tokenów w zapisanym indeksie - ostatnia operacja {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Włącz pamięć, aby utworzyć pliki pamięci projektu.", + "settings.context.memory.inspect": "Sprawdź", + "settings.context.memory.rebuild": "Odbuduj indeks pamięci", + "chat.memory.loading": "Pamięć...", + "chat.memory.off": "Pamięć wyłączona", + "chat.memory.on": "Pamięć włączona", + "chat.memory.label": "Pamięć {{tokens}} ctx startowy", + "chat.memory.status.loading": "Ładowanie stanu pamięci", + "chat.memory.session.tokens": "Kontekst startowy tej sesji: {{tokens}} tokenów", + "chat.memory.total.tokens": "Zapisany indeks: {{tokens}} tokenów", + "chat.memory.project.enabled": "Pamięć projektu włączona", + "chat.memory.project.disabled": "Pamięć projektu wyłączona", + "chat.memory.command.failed": "Polecenie pamięci nie powiodło się", + "chat.memory.savedOperations": "Ostatnia operacja pamięci: {{count}} operacji", + "chat.memory.inspect": "Sprawdź pamięć", + "chat.memory.remember": "Zapamiętaj", + "chat.memory.forget": "Zapomnij", + "chat.memory.rebuild": "Odbuduj indeks", + "chat.memory.enable": "Włącz pamięć", + "chat.memory.disable": "Wyłącz pamięć", + "chat.memory.badge.injected": "Pamięć wstrzyknięta", + "chat.memory.badge.recalled": "Pamięć przywołana", + "chat.memory.badge.startupCtx": "ctx startowy", + "chat.memory.badge.items": "{{count}} elementów", + "chat.memory.badge.tokens": "{{tokens}} tokenów", + "chat.memory.badge.recalledDetail": "Pamięć przywołana: {{count}} elementów - {{tokens}} tokenów", + "chat.memory.badge.files": "Pliki pamięci: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Użyj niestandardowego prompt", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index c84a94b0783..46ac8d30a15 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -1482,6 +1482,7 @@ export const dict = { "settings.checkpoints.enable.description": "Создавать контрольные точки перед редактированием файлов", "settings.context.autoCompaction.title": "Автоматическое сжатие", "settings.context.autoCompaction.description": "Автоматически сжимать контекст до достижения лимита", + "settings.context.compaction.title": "Сжатие", "settings.context.compactionLimit.title": "Лимит автоматического сжатия", "settings.context.compactionLimit.description": "Сжимать, когда контекст достигает этого процента окна модели. Оставьте пустым, чтобы использовать только буфер безопасности.", @@ -1490,6 +1491,46 @@ export const dict = { "settings.context.watcherPatterns": "Шаблоны игнорирования наблюдателя файлов", "settings.context.watcherPatterns.description": "Glob-шаблоны для файлов, которые наблюдатель должен игнорировать", + "settings.context.memory.title": "Память", + "settings.context.memory.project.title": "Память проекта", + "settings.context.memory.autoSave.title": "Автосохранение памяти проекта", + "settings.context.memory.autoSave.description": + "Автоматически сохраняет устойчивые факты проекта из завершённых ходов, когда память включена.", + "settings.context.memory.index.title": "Индекс памяти", + "settings.context.memory.status.notLoaded": "Не загружена", + "settings.context.memory.status.disabled": "Отключена", + "settings.context.memory.status.enabled": "Включена", + "settings.context.memory.status.enabledTokensOps": + "Включена - ~{{session}} токенов начального контекста в этой сессии - ~{{tokens}} токенов в сохранённом индексе - последняя операция {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Включите память, чтобы создать файлы памяти проекта.", + "settings.context.memory.inspect": "Проверить", + "settings.context.memory.rebuild": "Перестроить индекс памяти", + "chat.memory.loading": "Память...", + "chat.memory.off": "Память выключена", + "chat.memory.on": "Память включена", + "chat.memory.label": "Память {{tokens}} начальный ctx", + "chat.memory.status.loading": "Загрузка состояния памяти", + "chat.memory.session.tokens": "Начальный контекст этой сессии: {{tokens}} токенов", + "chat.memory.total.tokens": "Сохранённый индекс: {{tokens}} токенов", + "chat.memory.project.enabled": "Память проекта включена", + "chat.memory.project.disabled": "Память проекта отключена", + "chat.memory.command.failed": "Команда памяти не выполнена", + "chat.memory.savedOperations": "Последняя операция памяти: {{count}} операций", + "chat.memory.inspect": "Проверить память", + "chat.memory.remember": "Запомнить", + "chat.memory.forget": "Забыть", + "chat.memory.rebuild": "Перестроить индекс", + "chat.memory.enable": "Включить память", + "chat.memory.disable": "Отключить память", + "chat.memory.badge.injected": "Память внедрена", + "chat.memory.badge.recalled": "Память извлечена", + "chat.memory.badge.startupCtx": "начальный ctx", + "chat.memory.badge.items": "{{count}} элементов", + "chat.memory.badge.tokens": "{{tokens}} токенов", + "chat.memory.badge.recalledDetail": "Память извлечена: {{count}} элементов - {{tokens}} токенов", + "chat.memory.badge.files": "Файлы памяти: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Использовать пользовательский prompt", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index 2646e88a69a..1a1fa3e0051 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -1454,6 +1454,7 @@ export const dict = { "settings.checkpoints.enable.description": "สร้างจุดตรวจก่อนแก้ไขไฟล์", "settings.context.autoCompaction.title": "การบีบอัดอัตโนมัติ", "settings.context.autoCompaction.description": "บีบอัดบริบทอัตโนมัติก่อนถึงขีดจำกัด", + "settings.context.compaction.title": "การบีบอัด", "settings.context.compactionLimit.title": "ขีดจำกัดการบีบอัดอัตโนมัติ", "settings.context.compactionLimit.description": "บีบอัดเมื่อบริบทถึงเปอร์เซ็นต์นี้ของหน้าต่างโมเดล เว้นว่างไว้เพื่อใช้เฉพาะบัฟเฟอร์ความปลอดภัย", @@ -1462,6 +1463,46 @@ export const dict = { "settings.context.watcherPatterns": "รูปแบบการละเว้นตัวเฝ้าดูไฟล์", "settings.context.watcherPatterns.description": "รูปแบบ glob สำหรับไฟล์ที่ตัวเฝ้าดูควรละเว้น", + "settings.context.memory.title": "ความจำ", + "settings.context.memory.project.title": "ความจำของโปรเจกต์", + "settings.context.memory.autoSave.title": "บันทึกความจำของโปรเจกต์อัตโนมัติ", + "settings.context.memory.autoSave.description": + "บันทึกข้อเท็จจริงถาวรของโปรเจกต์จากรอบที่เสร็จแล้วโดยอัตโนมัติเมื่อเปิดใช้ความจำ", + "settings.context.memory.index.title": "ดัชนีความจำ", + "settings.context.memory.status.notLoaded": "ยังไม่ได้โหลด", + "settings.context.memory.status.disabled": "ปิดใช้งาน", + "settings.context.memory.status.enabled": "เปิดใช้งาน", + "settings.context.memory.status.enabledTokensOps": + "เปิดใช้งาน - ~{{session}} โทเค็นบริบทเริ่มต้นในเซสชันนี้ - ~{{tokens}} โทเค็นในดัชนีที่บันทึกไว้ - การทำงานล่าสุด {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "เปิดใช้ความจำเพื่อสร้างไฟล์ความจำของโปรเจกต์", + "settings.context.memory.inspect": "ตรวจสอบ", + "settings.context.memory.rebuild": "สร้างดัชนีความจำใหม่", + "chat.memory.loading": "ความจำ...", + "chat.memory.off": "ปิดความจำ", + "chat.memory.on": "เปิดความจำ", + "chat.memory.label": "ความจำ {{tokens}} ctx เริ่มต้น", + "chat.memory.status.loading": "กำลังโหลดสถานะความจำ", + "chat.memory.session.tokens": "บริบทเริ่มต้นของเซสชันนี้: {{tokens}} โทเค็น", + "chat.memory.total.tokens": "ดัชนีที่บันทึกไว้: {{tokens}} โทเค็น", + "chat.memory.project.enabled": "เปิดใช้ความจำของโปรเจกต์แล้ว", + "chat.memory.project.disabled": "ปิดใช้ความจำของโปรเจกต์แล้ว", + "chat.memory.command.failed": "คำสั่งความจำล้มเหลว", + "chat.memory.savedOperations": "การทำงานความจำล่าสุด: {{count}} รายการ", + "chat.memory.inspect": "ตรวจสอบความจำ", + "chat.memory.remember": "จำ", + "chat.memory.forget": "ลืม", + "chat.memory.rebuild": "สร้างดัชนีใหม่", + "chat.memory.enable": "เปิดใช้ความจำ", + "chat.memory.disable": "ปิดใช้ความจำ", + "chat.memory.badge.injected": "แทรกความจำแล้ว", + "chat.memory.badge.recalled": "เรียกคืนความจำแล้ว", + "chat.memory.badge.startupCtx": "ctx เริ่มต้น", + "chat.memory.badge.items": "{{count}} รายการ", + "chat.memory.badge.tokens": "{{tokens}} โทเค็น", + "chat.memory.badge.recalledDetail": "เรียกคืนความจำแล้ว: {{count}} รายการ - {{tokens}} โทเค็น", + "chat.memory.badge.files": "ไฟล์ความจำ: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "ใช้ prompt แบบกำหนดเอง", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts index b4331e0522d..d9ebfde54b4 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts @@ -1441,6 +1441,7 @@ export const dict = { "settings.context.autoCompaction.title": "Otomatik Sıkıştırma", "settings.context.autoCompaction.description": "Bağlam sınıra ulaşmadan önce otomatik olarak sıkıştır", + "settings.context.compaction.title": "Sıkıştırma", "settings.context.compactionLimit.title": "Otomatik sıkıştırma sınırı", "settings.context.compactionLimit.description": "Bağlam model penceresinin bu yüzdesine ulaştığında sıkıştır. Yalnızca güvenlik tamponunu kullanmak için boş bırakın.", @@ -1449,6 +1450,46 @@ export const dict = { "settings.context.watcherPatterns": "Dosya İzleyici Yok Sayma Kalıpları", "settings.context.watcherPatterns.description": "İzleyicinin yok sayması gereken dosyalar için glob kalıpları", + "settings.context.memory.title": "Bellek", + "settings.context.memory.project.title": "Proje belleği", + "settings.context.memory.autoSave.title": "Proje belleğini otomatik kaydet", + "settings.context.memory.autoSave.description": + "Bellek açıkken tamamlanan turlardan kalıcı proje gerçeklerini otomatik olarak kaydeder.", + "settings.context.memory.index.title": "Bellek indeksi", + "settings.context.memory.status.notLoaded": "Yüklenmedi", + "settings.context.memory.status.disabled": "Devre dışı", + "settings.context.memory.status.enabled": "Etkin", + "settings.context.memory.status.enabledTokensOps": + "Etkin - bu oturumda ~{{session}} başlangıç bağlamı tokenı - depolanan indekste ~{{tokens}} token - son işlem {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Proje belleği dosyalarını oluşturmak için belleği etkinleştirin.", + "settings.context.memory.inspect": "İncele", + "settings.context.memory.rebuild": "Bellek indeksini yeniden oluştur", + "chat.memory.loading": "Bellek...", + "chat.memory.off": "Bellek kapalı", + "chat.memory.on": "Bellek açık", + "chat.memory.label": "Bellek {{tokens}} başlangıç ctx", + "chat.memory.status.loading": "Bellek durumu yükleniyor", + "chat.memory.session.tokens": "Bu oturumdaki başlangıç bağlamı: {{tokens}} token", + "chat.memory.total.tokens": "Depolanan indeks: {{tokens}} token", + "chat.memory.project.enabled": "Proje belleği etkin", + "chat.memory.project.disabled": "Proje belleği devre dışı", + "chat.memory.command.failed": "Bellek komutu başarısız oldu", + "chat.memory.savedOperations": "Son bellek işlemi: {{count}} işlem", + "chat.memory.inspect": "Belleği incele", + "chat.memory.remember": "Hatırla", + "chat.memory.forget": "Unut", + "chat.memory.rebuild": "İndeksi yeniden oluştur", + "chat.memory.enable": "Belleği etkinleştir", + "chat.memory.disable": "Belleği devre dışı bırak", + "chat.memory.badge.injected": "Bellek eklendi", + "chat.memory.badge.recalled": "Bellek geri çağrıldı", + "chat.memory.badge.startupCtx": "başlangıç ctx", + "chat.memory.badge.items": "{{count}} öğe", + "chat.memory.badge.tokens": "{{tokens}} token", + "chat.memory.badge.recalledDetail": "Bellek geri çağrıldı: {{count}} öğe - {{tokens}} token", + "chat.memory.badge.files": "Bellek dosyaları: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Özel prompt Kullan", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts index 31bd1c5a611..9b3d2025675 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts @@ -1439,6 +1439,7 @@ export const dict = { "settings.context.autoCompaction.title": "Автоматичне стиснення", "settings.context.autoCompaction.description": "Автоматично стискати контекст до досягнення ліміту", + "settings.context.compaction.title": "Стискання", "settings.context.compactionLimit.title": "Ліміт автоматичного стискання", "settings.context.compactionLimit.description": "Стискати, коли контекст досягає цього відсотка вікна моделі. Залиште порожнім, щоб використовувати лише буфер безпеки.", @@ -1447,6 +1448,46 @@ export const dict = { "settings.context.watcherPatterns": "Шаблони ігнорування спостерігача файлів", "settings.context.watcherPatterns.description": "Glob-шаблони для файлів, які спостерігач має ігнорувати", + "settings.context.memory.title": "Пам’ять", + "settings.context.memory.project.title": "Пам’ять проєкту", + "settings.context.memory.autoSave.title": "Автозбереження пам’яті проєкту", + "settings.context.memory.autoSave.description": + "Автоматично зберігає сталі факти проєкту із завершених ходів, коли пам’ять увімкнено.", + "settings.context.memory.index.title": "Індекс пам’яті", + "settings.context.memory.status.notLoaded": "Не завантажено", + "settings.context.memory.status.disabled": "Вимкнено", + "settings.context.memory.status.enabled": "Увімкнено", + "settings.context.memory.status.enabledTokensOps": + "Увімкнено - ~{{session}} токенів стартового контексту в цій сесії - ~{{tokens}} токенів у збереженому індексі - остання операція {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "Увімкніть пам’ять, щоб створити файли пам’яті проєкту.", + "settings.context.memory.inspect": "Перевірити", + "settings.context.memory.rebuild": "Перебудувати індекс пам’яті", + "chat.memory.loading": "Пам’ять...", + "chat.memory.off": "Пам’ять вимкнено", + "chat.memory.on": "Пам’ять увімкнено", + "chat.memory.label": "Пам’ять {{tokens}} стартовий ctx", + "chat.memory.status.loading": "Завантаження стану пам’яті", + "chat.memory.session.tokens": "Стартовий контекст цієї сесії: {{tokens}} токенів", + "chat.memory.total.tokens": "Збережений індекс: {{tokens}} токенів", + "chat.memory.project.enabled": "Пам’ять проєкту увімкнено", + "chat.memory.project.disabled": "Пам’ять проєкту вимкнено", + "chat.memory.command.failed": "Команду пам’яті не виконано", + "chat.memory.savedOperations": "Остання операція пам’яті: {{count}} операцій", + "chat.memory.inspect": "Перевірити пам’ять", + "chat.memory.remember": "Запам’ятати", + "chat.memory.forget": "Забути", + "chat.memory.rebuild": "Перебудувати індекс", + "chat.memory.enable": "Увімкнути пам’ять", + "chat.memory.disable": "Вимкнути пам’ять", + "chat.memory.badge.injected": "Пам’ять додано", + "chat.memory.badge.recalled": "Пам’ять відновлено", + "chat.memory.badge.startupCtx": "стартовий ctx", + "chat.memory.badge.items": "{{count}} елементів", + "chat.memory.badge.tokens": "{{tokens}} токенів", + "chat.memory.badge.recalledDetail": "Пам’ять відновлено: {{count}} елементів - {{tokens}} токенів", + "chat.memory.badge.files": "Файли пам’яті: {{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "Використовувати власний prompt", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index c186582fd05..9abe5f3e860 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -1420,6 +1420,7 @@ export const dict = { "settings.checkpoints.enable.description": "在文件编辑前创建检查点,以便恢复之前的状态", "settings.context.autoCompaction.title": "自动压缩", "settings.context.autoCompaction.description": "在上下文达到限制前自动压缩", + "settings.context.compaction.title": "压缩", "settings.context.compactionLimit.title": "自动压缩限制", "settings.context.compactionLimit.description": "当上下文达到模型窗口的此百分比时进行压缩。留空则仅使用安全缓冲区。", "settings.context.prune.title": "修剪旧输出", @@ -1427,6 +1428,45 @@ export const dict = { "settings.context.watcherPatterns": "文件监视器忽略模式", "settings.context.watcherPatterns.description": "监视器应忽略的文件的 glob 模式", + "settings.context.memory.title": "记忆", + "settings.context.memory.project.title": "项目记忆", + "settings.context.memory.autoSave.title": "自动保存项目记忆", + "settings.context.memory.autoSave.description": "启用记忆时,自动从已完成轮次保存持久项目事实。", + "settings.context.memory.index.title": "记忆索引", + "settings.context.memory.status.notLoaded": "未加载", + "settings.context.memory.status.disabled": "已禁用", + "settings.context.memory.status.enabled": "已启用", + "settings.context.memory.status.enabledTokensOps": + "已启用 - 本会话启动上下文约 {{session}} 个 token - 已存储索引约 {{tokens}} 个 token - 上次操作 {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "启用记忆以创建项目记忆文件。", + "settings.context.memory.inspect": "检查", + "settings.context.memory.rebuild": "重建记忆索引", + "chat.memory.loading": "记忆...", + "chat.memory.off": "记忆关闭", + "chat.memory.on": "记忆开启", + "chat.memory.label": "记忆 {{tokens}} 启动 ctx", + "chat.memory.status.loading": "正在加载记忆状态", + "chat.memory.session.tokens": "本会话启动上下文:{{tokens}} 个 token", + "chat.memory.total.tokens": "已存储索引:{{tokens}} 个 token", + "chat.memory.project.enabled": "项目记忆已启用", + "chat.memory.project.disabled": "项目记忆已禁用", + "chat.memory.command.failed": "记忆命令失败", + "chat.memory.savedOperations": "上次记忆操作:{{count}} 次操作", + "chat.memory.inspect": "检查记忆", + "chat.memory.remember": "记住", + "chat.memory.forget": "忘记", + "chat.memory.rebuild": "重建索引", + "chat.memory.enable": "启用记忆", + "chat.memory.disable": "禁用记忆", + "chat.memory.badge.injected": "已注入记忆", + "chat.memory.badge.recalled": "已召回记忆", + "chat.memory.badge.startupCtx": "启动 ctx", + "chat.memory.badge.items": "{{count}} 项", + "chat.memory.badge.tokens": "{{tokens}} 个 token", + "chat.memory.badge.recalledDetail": "已召回记忆:{{count}} 项 - {{tokens}} 个 token", + "chat.memory.badge.files": "记忆文件:{{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "使用自定义 prompt", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index e9d977f7c0c..bfff67aaa55 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -1390,6 +1390,7 @@ export const dict = { "settings.checkpoints.enable.description": "在檔案編輯前建立檢查點,以便恢復之前的狀態", "settings.context.autoCompaction.title": "自動壓縮", "settings.context.autoCompaction.description": "在上下文達到限制前自動壓縮", + "settings.context.compaction.title": "壓縮", "settings.context.compactionLimit.title": "自動壓縮限制", "settings.context.compactionLimit.description": "當上下文達到模型視窗的此百分比時進行壓縮。留空則僅使用安全緩衝區。", "settings.context.prune.title": "修剪舊輸出", @@ -1397,6 +1398,45 @@ export const dict = { "settings.context.watcherPatterns": "檔案監視器忽略模式", "settings.context.watcherPatterns.description": "監視器應忽略的檔案的 glob 模式", + "settings.context.memory.title": "記憶", + "settings.context.memory.project.title": "專案記憶", + "settings.context.memory.autoSave.title": "自動儲存專案記憶", + "settings.context.memory.autoSave.description": "啟用記憶時,自動從已完成回合儲存持久專案事實。", + "settings.context.memory.index.title": "記憶索引", + "settings.context.memory.status.notLoaded": "未載入", + "settings.context.memory.status.disabled": "已停用", + "settings.context.memory.status.enabled": "已啟用", + "settings.context.memory.status.enabledTokensOps": + "已啟用 - 此工作階段啟動內容約 {{session}} 個 token - 已儲存索引約 {{tokens}} 個 token - 上次操作 {{ops}}", + "settings.context.memory.index.path": "{{path}}/index.kmem", + "settings.context.memory.index.enable": "啟用記憶以建立專案記憶檔案。", + "settings.context.memory.inspect": "檢查", + "settings.context.memory.rebuild": "重建記憶索引", + "chat.memory.loading": "記憶...", + "chat.memory.off": "記憶關閉", + "chat.memory.on": "記憶開啟", + "chat.memory.label": "記憶 {{tokens}} 啟動 ctx", + "chat.memory.status.loading": "正在載入記憶狀態", + "chat.memory.session.tokens": "此工作階段啟動內容:{{tokens}} 個 token", + "chat.memory.total.tokens": "已儲存索引:{{tokens}} 個 token", + "chat.memory.project.enabled": "專案記憶已啟用", + "chat.memory.project.disabled": "專案記憶已停用", + "chat.memory.command.failed": "記憶命令失敗", + "chat.memory.savedOperations": "上次記憶操作:{{count}} 次操作", + "chat.memory.inspect": "檢查記憶", + "chat.memory.remember": "記住", + "chat.memory.forget": "忘記", + "chat.memory.rebuild": "重建索引", + "chat.memory.enable": "啟用記憶", + "chat.memory.disable": "停用記憶", + "chat.memory.badge.injected": "已注入記憶", + "chat.memory.badge.recalled": "已召回記憶", + "chat.memory.badge.startupCtx": "啟動 ctx", + "chat.memory.badge.items": "{{count}} 項", + "chat.memory.badge.tokens": "{{tokens}} 個 token", + "chat.memory.badge.recalledDetail": "已召回記憶:{{count}} 項 - {{tokens}} 個 token", + "chat.memory.badge.files": "記憶檔案:{{files}}", + "settings.commitMessage.title": "Commit Message", "settings.commitMessage.override.title": "使用自訂 prompt", "settings.commitMessage.override.description": diff --git a/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx b/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx index 553582c37ca..0dbc62dcb5f 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx @@ -33,6 +33,7 @@ import { NotificationsContext } from "../context/notifications" import { LanguageContext } from "../context/language" import { IndexingProvider } from "../context/indexing" import { KiloEmbeddingModelsProvider } from "../context/kilo-embedding-models" +import { MemoryProvider } from "../context/memory" import { dict as uiEn } from "@kilocode/kilo-ui/i18n/en" import { dict as appEn } from "../i18n/en" import { dict as amEn } from "../../agent-manager/i18n/en" @@ -401,25 +402,27 @@ export const StoryProviders: ParentComponent = (props) => { "en", t }}> - - - - - - - - {props.noPadding ? ( - props.children - ) : ( -
{props.children}
- )} -
-
-
-
-
-
-
+ + + + + + + + + {props.noPadding ? ( + props.children + ) : ( +
{props.children}
+ )} +
+
+
+
+
+
+
+
diff --git a/packages/kilo-vscode/webview-ui/src/styles/chat-layout.css b/packages/kilo-vscode/webview-ui/src/styles/chat-layout.css index 0e625dda4e3..edcc21ab226 100644 --- a/packages/kilo-vscode/webview-ui/src/styles/chat-layout.css +++ b/packages/kilo-vscode/webview-ui/src/styles/chat-layout.css @@ -215,6 +215,14 @@ width: 100%; } +[data-component="assistant-memory-badge"] { + align-self: flex-start; + color: var(--vscode-descriptionForeground); + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + line-height: var(--line-height-normal); +} + .vscode-session-turn-diffs { width: 100%; } diff --git a/packages/kilo-vscode/webview-ui/src/styles/task-header.css b/packages/kilo-vscode/webview-ui/src/styles/task-header.css index d791b23bd16..0bc2f8c525b 100644 --- a/packages/kilo-vscode/webview-ui/src/styles/task-header.css +++ b/packages/kilo-vscode/webview-ui/src/styles/task-header.css @@ -271,6 +271,38 @@ gap: 2px; } +.task-header-memory { + display: flex; + align-items: center; + gap: 6px; + padding: 0 8px; + font-size: var(--kilo-font-size-11); + color: var(--vscode-descriptionForeground); + min-width: 0; +} + +.task-header-memory-status { + display: inline-flex; + align-items: center; + gap: 4px; + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.task-header-memory-status[data-enabled] { + color: var(--vscode-foreground); +} + +.task-header-memory-actions { + display: inline-flex; + align-items: center; + gap: 2px; + flex-shrink: 0; +} + /* Expand toggle */ [data-slot="task-header-expand"] { all: unset; diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts index 95d64f15dcb..dc8f6f598f2 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts @@ -45,6 +45,7 @@ import type { LegacyMigrationSessionProgressMessage, MigrationStateMessage, } from "./migration" +import type { MemoryEventMessage, MemoryLoadedMessage, MemoryOperationResultMessage } from "./memory" // ============================================ // Messages FROM extension TO webview @@ -1108,3 +1109,6 @@ export type ExtensionMessage = | ExtensionDataReadyMessage | TelemetryStateMessage | RemoteStatusMessage + | MemoryLoadedMessage + | MemoryEventMessage + | MemoryOperationResultMessage diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/index.ts b/packages/kilo-vscode/webview-ui/src/types/messages/index.ts index f74b20db685..0a8a6bcfe7f 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages/index.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages/index.ts @@ -13,5 +13,6 @@ export * from "./config" export * from "./profile" export * from "./agent-manager" export * from "./migration" +export * from "./memory" export * from "./extension-messages" export * from "./webview-messages" diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/memory.ts b/packages/kilo-vscode/webview-ui/src/types/messages/memory.ts new file mode 100644 index 00000000000..aa57196a94a --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/types/messages/memory.ts @@ -0,0 +1,97 @@ +import type { + MemoryCorrectResponse, + MemoryConfigureResponse, + MemoryDisableResponse, + MemoryEnableResponse, + MemoryForgetResponse, + MemoryPurgeResponse, + MemoryRememberResponse, + MemoryRebuildResponse, + MemoryShowResponse, + MemoryStatusResponse, +} from "@kilocode/sdk/v2" + +export type MemorySourceFile = "project.md" | "environment.md" | "corrections.md" + +export type MemoryOperation = "enable" | "disable" | "rebuild" | "remember" | "correct" | "forget" | "purge" | "auto" + +export type MemoryResultOperation = MemoryOperation + +export type MemoryPromptOperation = "remember" | "forget" + +export type MemoryOperationResponse = + | MemoryEnableResponse + | MemoryConfigureResponse + | MemoryDisableResponse + | MemoryRebuildResponse + | MemoryRememberResponse + | MemoryCorrectResponse + | MemoryForgetResponse + | MemoryPurgeResponse + +export interface MemoryLoadedMessage { + type: "memoryLoaded" + sessionID?: string + status?: MemoryStatusResponse + show?: MemoryShowResponse + error?: string +} + +export interface MemoryEventDetail { + type?: "saved" | "skipped" | "recalled" | "error" + message?: string + reason?: string + duplicateOf?: string + tokens?: number + operationCount?: number + skippedCount?: number + sources?: string[] + files?: string[] +} + +export interface MemoryEventMessage { + type: "memoryEvent" + sessionID?: string + detail: MemoryEventDetail +} + +export interface MemoryOperationResultMessage { + type: "memoryOperationResult" + operation: MemoryResultOperation + sessionID?: string + ok: boolean + status?: MemoryStatusResponse + show?: MemoryShowResponse + result?: MemoryStatusResponse | MemoryShowResponse | MemoryOperationResponse + error?: string +} + +export interface RequestMemoryMessage { + type: "requestMemory" + sessionID?: string + includeSources?: boolean +} + +export interface MemoryInspectMessage { + type: "memoryInspect" + sessionID?: string +} + +export interface MemoryOperationMessage { + type: "memoryOperation" + operation: MemoryOperation + sessionID?: string + mode?: "status" | "on" | "off" + confirm?: boolean + text?: string + query?: string + key?: string + file?: MemorySourceFile + section?: string +} + +export interface MemoryPromptMessage { + type: "memoryPrompt" + operation: MemoryPromptOperation + sessionID?: string +} diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts index ee7ffcc40c0..cbede3bd39b 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts @@ -14,6 +14,7 @@ import type { SkipLegacyMigrationMessage, StartLegacyMigrationMessage, } from "./migration" +import type { MemoryInspectMessage, MemoryOperationMessage, MemoryPromptMessage, RequestMemoryMessage } from "./memory" // ============================================ // Messages FROM webview TO extension @@ -1261,6 +1262,10 @@ export type WebviewMessage = | SetRemoteEnabledMessage | RequestRemoteStatusMessage | ContinueInWorktreeRequest + | RequestMemoryMessage + | MemoryInspectMessage + | MemoryOperationMessage + | MemoryPromptMessage | CreateSectionRequest | RenameSectionRequest | DeleteSectionRequest diff --git a/packages/kilo-vscode/webview-ui/src/utils/memory-command.ts b/packages/kilo-vscode/webview-ui/src/utils/memory-command.ts new file mode 100644 index 00000000000..7a0972fa1eb --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/utils/memory-command.ts @@ -0,0 +1,10 @@ +import { MEMORY_USAGE, parseMemoryCommand as parse } from "@kilocode/kilo-memory/commands" +import type { ParsedMemoryCommand as SharedMemoryCommand } from "@kilocode/kilo-memory/commands" + +export type ParsedMemoryCommand = SharedMemoryCommand + +export function parseMemoryCommand(input: string): ParsedMemoryCommand | undefined { + const parsed = parse(input) + if (parsed?.kind !== "usage") return parsed + return { ...parsed, reason: `${parsed.reason}\n${MEMORY_USAGE}` } +}