* fix(tui): order live transcript by message created time so wrapped ids stay visible
* test(tui): cover window eviction and versioned sync channel for wrapped ids
* fix(tui): keep Kilo Gateway models visible in the model picker
Selecting a model removed it from its provider section, so a recently
used Kilo sonnet vanished from "Recommended"/"Kilo Gateway" and only
survived under "Recent". Search also keyed off title and section header
only, so filtering by `kilo` never matched titles like "Anthropic Claude
Sonnet 4.5" grouped under "Recommended".
Recents now stay in their provider section (favorites are still deduped
into their own section) and search additionally keys off the provider
name, provider id, and model id, matching the VS Code selector.
Option building moves to kilocode/model-picker.ts so the grouping and
search rules are unit testable.
* chore: add changeset for TUI gateway picker
* fix(tui): identify the selected picker row by reference
Keeping recents in their provider section means a model can legitimately
appear twice in the list (once under "Recent", once under its provider or
"Recommended" section). DialogSelect resolved the selected row by value
equality, so both copies lit up as active whenever either was selected —
visible on every picker open, since the current model is usually a recent
— and hovering the provider-section copy warped selection and scroll to
the "Recent" copy instead.
Match the selected row by object reference instead. Rows are always
distinct objects, so this is a strict refinement for every other dialog;
`current` still uses value equality, which is correct — both rows really
are the current model.
The /privacy command wrote only to global config but read the effective
config, so a project-level privacy_mode could shadow the global toggle
and the UI would not change even though the command reported success.
Since privacy mode is a personal preference, persist and read it only
from the global config.
The sidebar footer used tone() for both the bullet and masked balance,
so the bullet color still revealed whether the balance was low. Use
theme().textMuted for both while masked, retaining tone() only when
privacy mode is off.
* feat(tui): expand a collapsed paste on a second identical paste
* chore: retrigger review
* chore(tui): add paste expansion changeset
* fix(cli): target paste changeset
* fix(tui): refresh autocomplete after expanding a paste
Call auto()?.onInput on the expand-placeholder path so open autocomplete
matches onContentChange when a second identical paste expands text.
The note was appended after the tool's own output (or, in an interim
revert, on its own line above it), which either looked like part of
the output or was visually noisier than desired. Render it inline on
the header/title line instead, matching the existing RoutedModelMeta
badge convention (' · note'), so it reads unambiguously as metadata
about the call rather than output.
Restore packages/ui/src/components/markdown.css. Upstream moved markdown
styling into the new session-ui package and deleted this file, but Kilo still
ships packages/ui's markdown component to the VS Code webview, so the rules
went missing while their consumer stayed. The copy button lost
position: absolute and opacity: 0, so it rendered below every code block
instead of in its corner, and showed the copy and check icons at once because
nothing hid the check state.
The palette showed "Enable auto-approve permissions" next to "Enable
auto-approve mode", which reads as the same command twice. They are not: one
lasts for the TUI run and is what --auto and --yolo seed, the other saves a
rule to global config. Both now say which they are and carry a desc, which
the palette already renders. The saved one is enforced server side, so its
desc says it covers every client. No behaviour change, and the command names
are untouched so the slash aliases still work.
Tests no longer depend on the developer's credential store. Credential
imports Global.data/auth.json on startup, and the catalog, plugin and
models-dev layers built Credential.node without overriding Global, so results
changed depending on whether the machine was logged in. They now use a temp
data directory, as the integration suite already did. That suite in turn set
KILO_AUTH_CONTENT at module scope; bun shares one process across test files,
so it leaked into credential.test.ts, whose auth.json cases then read "{}"
and found no credentials. Scoped with beforeAll/afterAll.
macOS-only failures, all merge gaps in Kilo tests:
- sandbox/state.test.ts runs a script in a subprocess; the LayerNode
migration put AppNodeBuilder.build in it without adding the import
- sandbox/session-tools.test.ts mocked MCP without clients(), which
upstream's resource tools now call
- sandbox/session.test.ts built SessionV2 without binding SessionExecution
Generated files: schema.gen.ts was formatted by an older prettier than the
one main's dependency bump resolves, so the generator no longer reproduced it
and the migration check called the schema stale. packages/client was missing
Pty.sessionID and the compaction include field. Both regenerated.
Also corrected the listener comment: it claimed application services still
come from AppRuntime, but the SessionV2 and MoveSession builds sit inside
KiloListener's Layer.fresh boundary and self-provide their subtrees, which is
deliberate since both bind this listener's own LocationServiceMap.
- tool-input delta/end no longer recreate a settled call as a pending part
- outputTokenMax is back in overflow accounting, with RuntimeFlags rewired
- MCP server instructions reach the system prompt again (sys.mcp call site)
- session revert decodes stored messages through the Kilo normalize boundary
- shell tool titles runs with the model description and keeps it in metadata
- subdirectory snapshots drop newly ignored files: the ignore check and the
index removal ran from the instance dir, but candidates are worktree
relative
- customize-opencode builtin stays unregistered after the boot.ts rename
- --auto is interpreted in one place; the flag beside it now covers only
--yolo and --dangerously-skip-permissions
- --cloud-fork works again, validateSession had landed before the import
- TUI block tool skips the empty title row, opencode catalog gate reads
credentials per reload, TUI worker logs crashes, Snowflake OAuth uses the
Kilo page, annotations guard covers the shared packages
- tests: startRun spawned without the solid preload so every run under it
died on the JSX runtime; two upstream tests get a permission fixture since
headless auto-rejects bash; one expected a single error record where Kilo
emits two, as it did before this merge
- changeset for the range, help snapshot, llmgateway indentation
Ports the auto-approval provenance explanation already shown in
kilo-ui/vscode to the TUI. Adds a Kilo-owned tool-approval.tsx with a
plain-text description helper (describeApproval) and a shared
ApprovalNote row component, then wires a single call into InlineTool/
InlineToolRow (Shell, Read, Grep, Glob, WebFetch, etc.) and BlockTool
(Write, Edit, ApplyPatch, Task), showing a muted line under completed/
failed tool calls.
Todo writes are excluded via a hideApproval prop, mirroring the
kilo-ui behavior that treats them as orchestration rather than an
auditable action.