The New Worktree dialog renders model, reasoning-variant, and mode pickers
inline (portal=false) so clicks aren't swallowed by the modal overlay. The
CSS overflow escape hatch that lets an open popover break out of the dialog's
scroll containers keyed only on model-selector-popover, so the variant and
mode dropdowns added later were clipped by .am-nv-dialog-content and the
prompt container.
Generalize the :has() rules to any popover-content inside the dialog. Popover
content unmounts on close, so the override only applies while a dropdown is open.
Add a visual-regression story (NewWorktreeDialog with the variant dropdown
open) that reproduces the clipping without the fix and covers all inline
pickers going forward.
* 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
@smithy/util-buffer-from >=4.3.0 became a re-export shim of @smithy/core/serde.
Under the browser build condition, @smithy/core's serde exposes fromArrayBuffer
as Symbol.for("node-only"), so @smithy/util-utf8's toUtf8 throws inside the
Bedrock event-stream decoder, whose catch { break } silently ends the stream.
Every Bedrock request completed with empty output on HTTP 200.
Pin to 4.2.2 (last self-contained 4.x) so fromArrayBuffer stays a real function.
Agent prompts substitute with missing:"empty", which swallowed every file read error — including a deliberate out-of-scope scope block — so an escaping {file:} was silently emptied and never warned, contradicting the agent.ts catch narrative. Tag security blocks as ConfigVariableGuard.BlockedError (out-of-scope, fd swap, /proc) and, in substitute(), always reject those regardless of missing:"empty"; genuine missing/IO errors are still emptied. Now an out-of-scope {file:} in an agent prompt rejects, hits the agent catch, and records a warning. Adds guard/substitute tests for the block-under-missing:empty, missing-is-emptied, and BlockedError classification cases.
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.
The message said file references are 'not allowed in project config', but in-root file references ARE allowed when a fileScope is supplied (the normal project path). This branch only fires when no scope was provided, so reword it to reflect that specific case and update the comment.
ConfigAgent.load() awaited ConfigVariable.substitute without a catch, so a throw (untrusted {env:} or out-of-scope {file:} in a project agent prompt) propagated through Effect.promise and failed the whole config load. Catch it, record a warning, and skip only the offending agent — mirroring the existing frontmatter-parse handling and the project config-file loops. Scope stays JSON-config-loading; the markdown substitution path (KilocodeMarkdown.substitute) remains the separate follow-up in #11889.
The read is fd-pinned, but on non-Linux the scope check realpath'd the caller's path independently of the fd, so an attacker could swap the path between open and check to validate an in-root inode while the fd pointed elsewhere. fstat the open fd and compare dev/ino against the resolved path; reject if they differ, so the inode we validate is the inode we read.
In-root absolute paths are intentionally allowed; only references that leave the root (absolute paths outside it, ../ traversal, symlinks) are rejected. Fix the docs wording and add a regression test for the in-root absolute case.
KilocodeConfigOverlay.load() propagated InvalidError from untrusted {env:}/out-of-scope {file:} substitutions through Promise.all, breaking the whole /config/overlay instead of skipping the offending file. Skip failed files (log + return {}) so the settings overlay still shows remaining config, matching the main config loader's degrade-gracefully behavior.
On non-Linux, read() validated the target via realpath but re-read by path, letting an attacker swap the file between the check and the read. Read through the already-open FileHandle (file.readFile) on every platform so the validated inode is the one read. Drops the now-unused load callback.