The round-trips non-ASCII output test printed the fixture and exited
immediately. On loaded CI runners bun-pty can observe the child-exit End
message before its reader thread has drained the last output bytes, dropping
the trailing UTF-8 marker and timing the test out.
Keep the child alive after printing (printf ...; sleep 5), matching the
sibling explicit-arguments test, so output is fully consumed before the
process can exit. Also include the received output in the waitForOutput
timeout error to make any future failure self-diagnosing.
* feat: add signal-to-noise controls to grep tool
Add configurable options to reduce noise in grep results:
- context: show N lines before/after each match
- limit: bound maximum matches (default 100) with early termination
- literal: treat pattern as plain text instead of regex
- ignoreCase: case-insensitive matching
These controls help models avoid overwhelming context windows with too
many matches and provide clear guidance when results are truncated.
Implementation preserves upstream ripgrep structure with minimal Kilo
hooks for additive behavior only. Shared-file changes reduced from 183
to 60 lines compared to initial implementation.
* test(core): tolerate PTY event publication race
* fix(cli): count grep matches independently of context
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
Generation was failing. Upstream added a guard in this range that rejects
duplicate session event variants, and Kilo's tool-content codec on the shared
event schema was tripping it, so openapi.json and the SDK were stale and a temp
packages/sdk/js/openapi.json got committed by accident.
Move the codec off the event schema into core/src/kilocode/event-storage.ts,
keyed by event type and applied only at the SQL boundary. Session events are on
the wire now (SessionEvent.Durable backs /api/session/{id}/history), so a
transform there forked the generated API. Shipped readers still parse old rows
and the wire contract goes back to upstream's. Drops the consumer-side
normalizers in the TUI and sync-v2 that existed only to undo the widening.
Also: restore the Kilo HttpApi title and a few branding strings, balance five
kilocode_change markers, drop a duplicate TUI palette entry, and teach
check-model-tool-network about the LayerNode wiring that replaced
Layer.provide(ToolNetwork.httpLayer).
The corrupted-cache recovery in ModelsDev.populate acquired the flock and
fetched unconditionally, while the background refresh fiber runs the same
recovery on layer build. When refresh won the lock race it rewrote a valid
cache file, but populate still fetched again because it never re-read the
cache after acquiring the lock. The result was a duplicated network call,
which the corrupted-cache test catches as calls.length == 2 on slow CI
runners (fast local machines almost always take the single-fetch path).
Re-run loadFromDisk under the flock, mirroring the re-check refresh
already performs, so whichever fiber recovers second reuses the valid
cache instead of refetching.