* feat(memory): opt-in project memory — capture, recall, CLI + TUI integration
Add project memory: the standalone @kilocode/kilo-memory effect layer plus the
opencode CLI/server/TUI integration. Memory is disabled by default, so it is a
no-op until enabled (no behavior change when off).
Capture (turn-close consolidation): per-op parse salvage, secret redaction that
skips the offending op instead of aborting the batch, supersede-only auto-updates
(never model-driven deletes), correction-aware echo handling, non-LLM fallback
digests on interrupted/error turns, a shared interval throttle with idle-flush.
Recall + injection: keyword tokenizer with camelCase/compound splitting, light
stemming, and an English-first stopword filter (Unicode-aware; non-English falls
back to plain token-overlap), a live relevance floor, a budget-reserved startup
index, a session-digest catalog, and per-session prompt-cache pinning of the
injected memory block.
Surfaces: kilo_memory_save / kilo_memory_recall tools, the memory HTTP API
(contract schemas live in the package), and a status-focused TUI sidebar showing
auto-save, loaded context, and active recall, plus the /memory dialog.
* fix(memory): address PR review feedback
- C1: bump @kilocode/kilo-memory in the changeset
- C2: redact secrets before they hit the audit log (skip + salvage paths);
redact before truncating in salvageTyped so a secret straddling the
500-char cap can't leak an unmatched fragment; opText -> salvageText
- C3: de-abbreviate savedOperations, "changes" wording, ops.ts -> operations.ts
- C4: log.warn on the remaining silent-catch fallbacks (turn diff, memory
context injection, tool-visibility check)
- C5: relocate memory storage from ~/.kilo to Global.Path.data, delete the
now-dead needsDependencyInstall guard, add /memory status (root path) and
/memory edit ($VISUAL/$EDITOR + auto-rebuild)
- C6: replace the hardcoded English stopword list with corpus-derived
ubiquitous-term filtering (df across the user's own entries) and the
English suffix stemmer with suffix-tolerant term matching, so recall
noise-filtering works in any language
- C8: delete the CORRECTION_INTENT English regex; echo turns now run typed
capture (digest stays echo-gated), bounded by the interval throttle, with
the typed prompt as the language-agnostic content filter
- C9: exclude generated paths (dist/build/coverage/*.gen.*/*.map/snapshots)
from the durable-diff churn fallback so generated churn can't burn a
consolidation call
- C11: fix duplicated assert in httpapi-memory test; assert the error body
- kilo-code-bot batch: clause-boundary regex fix, byte-safe catalog
truncation, max-length guards on remember/correct/forget payloads (text,
query, key, sessionID), trim consistency in reconcile, param-shadowing
rename, missing doc entry for kilo_memory_recall, dead-code removal,
dialog UI fixes, memoryEnabledCache eviction bound, dedicated Configure
schema, recall permission renderer, covered-session pointer cap, redact
chat transcript before the consolidation model call, split configProtected
metadata from disableAlways so memory-save prompts don't show config-file
copy, drop unused MemoryService.layer provide from tool registry
- redact colon-separated low-entropy secrets too (password: hunterx),
accepting the prose false-positive tradeoff (secret: enabled) in favor of
not missing a real secret
- rename lastConsolidatedAt -> lastTypedConsolidationAt to make its narrow
scope (typed-consolidation throttle clock) explicit; regen openapi/SDK
- drop now-dead home/config fields from MemoryPaths.Host after the data-dir
relocation; add Process.splitCommand for quoted $EDITOR/$VISUAL paths with
spaces, used by /memory edit and the pre-existing Editor.open utility
* refactor(memory): shared client helpers, capture hardening, /memory UX rework
- extract client-side derivations into kilo-memory so both frontends share
one implementation: MemoryDecisions.summarize (decision-log summary),
MemoryAutosaveStatus.summarize (autosave-status semantics), and
MemoryMarkerMeta (marker wire contract encode/decode)
- match exact-key upserts via the canonical stored id (slugged key,
normalized section) so a re-emitted spaced/uppercase key updates the
entry instead of falling to fuzzy dedupe
- salvageTyped throws on valid JSON without an operations array so the
caller's fallback path records a parse error instead of a silent
zero-op success
- rename memory tool metadata files -> sources (stripPartMetadata rewrites
tool-part metadata.files assuming apply_patch records, mangling string[])
- read state instead of status for tool enabled checks; dedupe TUI helpers
(errorMessage, shared route(), Locale.number, relativeTime)
- /memory UX: bare /memory opens a help modal driven by a structured
command catalog in kilo-memory; /memory on|off become the canonical
toggle verbs (enable/disable kept as quiet aliases); /memory status opens
a clean overview dialog (root path, autosave, startup context, source
counts, index size) instead of a toast; /memory show is the single full
audit view (inspect removed)
* feat(cli): remote model catalog and WebSocket reconnection fixes
* fix(cli): preserve provider default semantics under truncation and deflake reconnect test
* fix(cli): omit provider default when per-provider truncation removes preferred model
* refactor(cli): simplify remote model catalog by removing size limits
* refactor(cli): strip remote model catalog to sanitize-and-shape only
* fix(cli): cap remote model catalog at MAX_MODELS
* fix(cli): preserve model metadata and enforce remote catalog limits
* fix(cli): omit currentModel and defaultModel when truncation drops them
* fix(cli): keep stable connection identity across reconnects
* feat(cli): include protocol version in remote session heartbeat
Wire fetchKilocodeNotifications up to the shared header helpers
(getDefaultHeaders + buildKiloHeaders) so notification requests carry
User-Agent, X-KILOCODE-EDITORNAME, and org headers instead of only
Authorization/Content-Type. Also set KILOCODE_VERSION to the extension
version when spawning kilo serve so the extension version flows into the
User-Agent, letting the backend discriminate on extension version.
Hit-testing for inline action cells (Connect/OAuth/Disconnect/Enable)
re-derived cell rectangles by hand, ignoring the horizontal insets the
platform SelectablePanel adds in the New UI. The click target was offset
from the drawn button, so only a small strip responded to clicks.
Read the rectangles back from the actual rendered component tree instead,
giving one source of geometry shared by the provider, agent, and MCP
settings lists.
Render markdown tables in their own horizontal scroll block, mirroring
the code-block pattern, so a wide table shrinks to the panel width and
scrolls horizontally instead of stretching the message and cropping
content. Derive the pane height from the rendered view's preferred size
so the table is not clipped vertically.
Move the vim modal editing engine and prompt integration out of shared
upstream files and into src/kilocode/ mirrors per the Fork Isolation Rule:
- src/kilocode/cli/cmd/tui/component/prompt/vim.ts (engine, moved)
- src/kilocode/cli/cmd/tui/component/prompt/index.tsx (new mirror with
useVim, VimModeIndicator, vimToggleCommand)
- test/kilocode/cli/cmd/tui/prompt/vim.test.ts (moved)
The shared prompt/index.tsx now calls into the mirror behind minimal
kilocode_change markers instead of inlining ~200 lines of vim logic.
* fix(vscode): include kilo-sandbox-mutation-worker.js in extension bundle
The release build script (packages/kilo-vscode/script/build.ts) was
missing the copyKiloSandboxWorker call, causing the sandbox mutation
worker file to be absent from .vsix packages. All sandbox-enclosed file
operations (write, copy, rename, chmod, etc.) would fail with a
"Module not found" error because the kilo binary could not spawn the
required worker process.
Closes#11925
* chore(vscode): fix import formatting
---------
Co-authored-by: marius-kilocode <marius@kilocode.ai>
The reasoning-variant and mode pickers in the New Worktree dialog portaled
their popover content to <body>, where the dialog's full-screen modal overlay
(z-index 50, pointer-events auto) intercepted pointer events before the
option onClick fired. Selecting a variant dismissed the popover via the
overlay without applying the choice, so the trigger label reverted to the
previous value.
The model picker already avoided this with portal={false} (09f0156bfc).
Forward the same portal prop through ThinkingSelectorBase and
ModeSwitcherBase and pass portal={false} from NewWorktreeDialog so all
three pickers render inline within the dialog content, above the overlay.
Reproduced live in the isolated VS Code self-test: before the fix a real
pointer click on a variant option timed out with 'dialog-overlay ...
intercepts pointer events' and the label stayed unchanged; after the fix
the popover nests inside [dialog] and clicking a variant applies in both
directions with no console errors.