Commit Graph
1630 Commits
Author SHA1 Message Date
Marius 00ec003c11 perf(streaming): four fixes that unfreeze long-session streaming (#9341)
* perf(vscode): stop O(N) reactive cascade on every streaming token

The webview DataBridge wrapped the whole session Data shape in a
`createMemo`, whose body walked `store.parts[msg.id]` for every message
in the session family. Any single part mutation — i.e. every token
delta — invalidated the memo, produced a fresh POJO, and invalidated
every downstream consumer (including O(N) scans inside each mounted
SessionTurn). On a 200-message session a Chrome CPU profile showed
three back-to-back 440ms main-thread blocks per SSE batch, ~46% of
the time in Solid reactive runtime alone.

Expose `data` as a plain object with reactive getters over
`session.allMessages`/`allParts`/`allStatusMap` so consumers reading
`data.store.part[Y]` subscribe to only that key. Removes the now-unused
`familyData` helper and its interface/mock entries.

* perf(ui): drop TextShimmer JS timer — CSS-only animation

A createEffect inside TextShimmer ran clearTimeout + setTimeout on every
`active` prop change to gate the sweep animation via a `data-run`
attribute. During LLM token streaming in long sessions, `active` props
(bound to `pending()` / `running()` accessors) thrashed as tools
started/finished across many shimmer instances. CPU profile of a 7s
streaming window showed ~2,500 timer operations — 16% of the blocked
main-thread time.

Remove the effect and drive the animation purely from the `data-active`
attribute. The opacity transition on the shimmer char (220ms) already
handles the fade, so visual behavior is unchanged. Adds one static
regression guard and one runtime perf assertion (with happy-dom) that
toggling the prop 1000 times results in zero timer calls.

* perf(kilo-ui): skip layout reads in GrowBox watch-mode ResizeObserver

The GrowBox component wraps each assistant part and, when watch=true
(which is set on the currently-streaming text part), runs a
ResizeObserver that called body.getBoundingClientRect() via
targetHeight() on every body-size change. During streaming this fires
at ~60Hz and each call forces a synchronous layout. CPU profile of a
7s streaming window showed 1,362 gBCR samples (~9% of blocked
main-thread time) all attributable to this path.

Reuse the browser's pre-measured contentBoxSize / contentRect from the
observer entries — no extra layout read. Also skip sub-pixel updates
(<2px) that the spring absorbs imperceptibly anyway, cutting per-token
spring work when tokens add tiny height deltas.

* perf(ui): coalesce markdown parse to one per animation frame

During LLM token streaming, the Markdown render effect ran
temp.innerHTML = content + morphdom on every content update. SSE
tokens arrive at 60–200Hz and each delta reparsed the entire
accumulated HTML. CPU profile of a 7s streaming window showed 2,940
ParseHTML events totaling ~619ms (~46% of blocked main-thread time).

Queue the latest content in a component-scoped pending variable and
run the morphdom pass inside requestAnimationFrame. K rapid updates
before the frame fires now collapse to one parse. The onCleanup
handler cancels any queued frame so it doesn't touch an unmounted
DOM. Fast-path is preserved untouched so non-streaming first paint
stays synchronous.

* chore(changeset): consolidate streaming-perf changesets into one

Per-commit changesets produced four nearly-identical release-note
entries. The user-visible change is a single perceptual improvement —
streaming is smooth in long sessions — so roll them up into one
feature-oriented entry.

* test(vscode): consolidate streaming perf tests + wire into CI

Replace three synthetic reactivity tests with a single end-to-end
streaming perf benchmark that:
- Renders the real TextShimmer component and asserts zero setTimeout/
  clearTimeout calls during a 100-toggle burst (TextShimmer fix).
- Asserts per-key Solid reactivity: 100 text deltas on one message
  must re-run only that message's consumer, not O(N) consumers
  (DataBridge cascade fix).
- Uses only count-based assertions against deterministic APIs
  (setTimeout/clearTimeout/innerHTML setter) — no wall-clock
  thresholds, so it doesn't flake under CI load.

Also wire `bun run test:webview-reactivity` into the test-vscode
workflow so the benchmark runs on every PR that touches
packages/kilo-vscode, packages/ui, or packages/kilo-ui. Without this
wiring the perf regression guard would have shipped dormant.

* test(vscode): declare @happy-dom/global-registrator as devDep

The streaming-perf benchmark imports @happy-dom/global-registrator to
get a DOM for mounting the real TextShimmer component. It resolved
locally through workspace hoisting but CI's clean install didn't have
it. Make the dependency explicit.

* test(vscode): import TextShimmer via package export so JSX resolves

Using the deep relative path (../../../ui/src/components/text-shimmer)
made Bun's test transpiler apply kilo-vscode's tsconfig — which has no
`jsxImportSource` — so the .tsx file was compiled with the default
React runtime, producing "React is not defined" in CI.

Resolving through the package export (@opencode-ai/ui/text-shimmer)
picks up packages/ui/tsconfig.json which sets
`jsxImportSource: solid-js`. Works consistently across Linux/macOS/
Windows CI without needing bunfig-level JSX overrides.

* test(vscode): address bot review — add runtime coverage for Markdown + GrowBox, drop empty smoke test

Two kilo-code-bot findings on the streaming perf bench:

1. The 'benchmark completes quickly' smoke test timed an empty block,
   so `elapsed` was always near zero and the assertion never fired.
   Drop it — the real benchmarks below already complete in ~90ms.

2. The original file installed spy counters for innerHTML writes and
   getBoundingClientRect but never asserted against them, leaving
   Markdown rAF coalescing and GrowBox layout-read regressions silently
   uncaught.

Add two runtime mirrors:
- Markdown rAF pattern: 100 async content updates coalesce to <20 parses
  (would be exactly 100 pre-fix).
- GrowBox ResizeObserver pattern: 100 synthetic resize callbacks using
  contentBoxSize/contentRect trigger zero getBoundingClientRect calls
  (would be exactly 100 pre-fix).

Source-level regression guards in tests/unit/markdown-raf-coalesce.test.ts
and tests/unit/growbox-no-layout-thrash.test.ts cover the actual
component code. The runtime tests here prove the patterns the guards
require actually deliver the perf property at runtime.

Benchmark runs in ~90ms, 5 consecutive local runs all green.

* test(vscode): drop unstable TextShimmer runtime mount from streaming perf bench

The benchmark tried to mount the real @opencode-ai/ui TextShimmer to
assert zero setTimeout/clearTimeout calls. That required Bun's test
runner to transpile text-shimmer.tsx with Solid's JSX runtime, which
depends on tsconfig resolution walking up to packages/ui/tsconfig.json.
In CI (fresh workspace, different node_modules layout) this resolution
was unstable and kept falling back to React JSX ("React is not
defined").

Keep the three runtime patterns that don't need JSX transpilation
(DataBridge cascade, Markdown rAF coalescing, GrowBox contentRect),
plus the source-level regression guard at
tests/unit/textshimmer-no-timer.test.ts which asserts text-shimmer.tsx
contains no setTimeout/clearTimeout/createEffect/data-run. Together
these cover all four fixes without CI flakiness.

5 consecutive local runs pass in ~80ms.

* test(vscode): remove streaming perf tests

Static source-parsing guards and pattern-mirror runtime tests didn't
actually exercise the fixed component code — a regression in the real
code could have left them green. Remove them along with the
test:webview-reactivity script, the workflow step, the
@happy-dom/global-registrator devDep, and the tests/webview-reactivity
directory. The four perf fixes stand on their own; adding dubious
guards was worse than adding none.

* test(vscode): restore static perf-regression guards wired to real source

Restore four guards that each parse the actual fixed component source
and fail loudly if the fix pattern is removed:

- databridge-shape.test.ts     reads webview-ui/src/App.tsx, asserts
                               `data` is not wrapped in createMemo
- textshimmer-no-timer.test.ts reads ui/src/components/text-shimmer.tsx
                               + .css, asserts no setTimeout/
                               clearTimeout/createEffect, animation
                               gated on data-active
- markdown-raf-coalesce.test.ts reads ui/src/components/markdown.tsx,
                                asserts the render createEffect uses
                                requestAnimationFrame + cancelAnimationFrame
- growbox-no-layout-thrash.test.ts reads kilo-ui/src/components/grow-box.tsx,
                                   asserts the ResizeObserver callback
                                   does not call gBCR, uses contentRect/
                                   contentBoxSize, and has the sub-pixel
                                   delta guard

Verified by mutation: each guard fails when its fix pattern is removed
from the real source file and passes again once restored. Runs as part
of the existing test:unit script (no extra CI wiring).
2026-04-23 10:40:15 +02:00
Mark IJbema b24c144198 fix(ui): prevent single-dollar math fallback 2026-04-22 18:00:05 +02:00
kiloconnect[bot] 62f374e628 fix(ui): disable single-dollar LaTeX math to preserve currency symbols
Single $ delimiters in agent responses (e.g. $93K, $307K) were being
interpreted as inline LaTeX math by marked-katex-extension, garbling
dollar amounts. Override the inlineKatex tokenizer to never match and
remove the regex-based single-dollar rendering in renderMathInText.
Display math ($$...$$) is preserved.
2026-04-22 15:40:09 +00:00
Imanol Maiztegui 5149d3edcb Merge branch 'main' into imanolmaiztegui/kilo-opencode-v1.4.7 2026-04-22 15:55:07 +02:00
kilo-maintainer[bot] eb7bd75d6d release: v7.2.20 2026-04-22 12:30:54 +00:00
kilo-maintainer[bot] 475f836904 release: v7.2.19 2026-04-22 11:42:59 +00:00
kilo-maintainer[bot] fe76dffa50 release: v7.2.18 2026-04-22 10:51:47 +00:00
Imanol Maiztegui 87c2b560d1 Merge branch 'main' into imanolmaiztegui/kilo-opencode-v1.4.7 2026-04-22 09:44:37 +02:00
Imanol Maiztegui 094ebe7e74 build(deps): consolidate @opencode-ai/util and @opencode-ai/server into @opencode-ai/shared
Remove the standalone `packages/util` and `packages/server` workspace
packages, migrating all imports across app, kilo-ui, opencode, and ui
to use `@opencode-ai/shared/util/*` paths instead. Also fix the
VITE_KILO_CHANNEL env variable name in the type declaration and add a
null guard in the titlebar channel badge rendering.
2026-04-21 18:33:48 +02:00
Imanol Maiztegui d5357f3961 resolve merge conflicts 2026-04-21 18:03:34 +02:00
kilo-maintainer[bot] ba98c5c402 release: v7.2.17 2026-04-21 14:28:13 +00:00
Imanol Maiztegui bf6f499b24 refactor: kilo compat for v1.4.7 2026-04-20 13:49:07 +02:00
Imanol Maiztegui aa4deb520c resolve merge conflicts 2026-04-20 11:04:03 +02:00
Imanol Maiztegui c4a516f3cf refactor: kilo compat for v1.4.6 2026-04-20 10:45:43 +02:00
Imanol Maiztegui 5a2789167f Merge branch 'main' into johnnyamancio/kilo-opencode-v1.4.4 2026-04-17 22:35:10 +02:00
kilo-maintainer[bot] 024ad48c50 release: v7.2.14 2026-04-17 18:09:17 +00:00
Mariusandgithub-actions[bot] eac2dbafa0 perf(vscode): paginated message loading with virtualized scroll (#8911)
* perf(vscode): paginated message loading with virtualized scroll

Reimplement session message loading with cursor-based pagination and
virtual list rendering to reduce initial load time and memory for long
sessions.

* chore: update kilo-vscode visual regression baselines

* fix(vscode): update VscodeSessionTurn props in storybook

* chore: update kilo-vscode visual regression baselines

* perf(vscode): skip reconcile on session switch, lazy part hydration, fast markdown render

Skip SolidJS reconcile() for replace-mode message loads — direct array
assignment avoids expensive O(n) diffing and proxy creation for 80+
messages on every session switch.

Defer part hydration until the virtualizer renders each turn, reducing
reactive store writes by 85% on initial load. Double-rAF scroll
restoration avoids forced layout reflow mid-paint.

Extract markdown fast-path render into packages/ui/src/kilocode/ to
minimize shared file changes.

* fix(vscode): keep lazy part hydration correct in stories

* fix(vscode): resolve state-risk regressions in message pagination

Five correctness issues surfaced during review of the paginated-message-
loading stack, plus the follow-through performance tuning needed to keep
session switching near-instant:

- focus-mode selection re-enters the server for the tail (new "reconcile"
  load mode) so SSE drops self-heal on the next session switch instead of
  stranding the webview on a stale snapshot. Throttled to 1s to avoid
  stacking up fetches on rapid tab switching, and early-outs in the
  webview when the server tail matches local state.
- cursor pagination falls back to a client-synthesized `{id,time}` cursor
  when a proxy or older binary strips the X-Next-Cursor header, so "load
  earlier" keeps working.
- in-flight loadMessages results for a session deleted mid-fetch are
  dropped instead of resurrecting a ghost entry in the webview store.
- sub-agent viewer now loads the full transcript via `limit: 0` instead
  of silently truncating to MESSAGE_PAGE_LIMIT (it has no "load earlier"
  UI to recover from the cap).
- stashed message parts are now cleared on messageRemoved. Extracted the
  stash-access helpers into a PartStash class so every lifecycle event
  coordinates store + stash cleanup in one place.

Also restores the two-pass markdown rendering intended by PR #7102 — an
upstream merge silently re-added marked-shiki, which made Shiki run
synchronously during parse and froze the main thread for up to 1.3s on
session switches with many code blocks. Code blocks render as plain
<pre><code> first and deferredHighlight() upgrades them after paint.

Regression tests cover all five state risks (fetchMessagePage cursor
fallback, KiloProvider focus reconcile, ghost session on prepend,
sub-agent full load, focus-mode throttle, PartStash leak on
messageRemoved).

* chore(vscode): restore unrelated doc comments in KiloProvider

PR review: the previous fix commit trimmed four unrelated doc comments
(loadMessagesAbort, handleSyncSession JSDoc, "inherit parent directory"
comment, handleDeleteSession JSDoc) to squeeze under the 3350-line
max-lines cap. Restoring them — the cap is hit exactly at 3350 and the
PR surface stays focused on the state-risk fixes.

* chore: update kilo-vscode visual regression baselines

* refactor: simplify pagination helpers without behavior change

- fetchMessagePage: drop the conditional spread for `limit`/`before` — the
  server schema accepts `limit: 0` the same as omitted (`z.coerce.number()
  .int().min(0).optional()`), so always passing the values directly works.
  Inline the `oldest` temp and drop `?? undefined` (`headers.get()` returns
  `null | string` which `??` handles identically downstream).
- handleLoadMessages: inline the single-use `focus` boolean, fold the
  `mode === "replace"` refresh call into the `if (abort)` block since
  they're gated by the same condition.
- sameReconcileShape: destructure `c`/`n` once per iteration instead of
  accessing `current[i]!` / `incoming[i]!` three times each.

All 1815 tests pass, typecheck + lint clean.

* docs: clarify intent of helpers flagged in PR review

- commands.ts: comment explains the in-flight dedup pattern and why the
  identity check in the `finally` guards against clear-then-restart races.
- sessionsForWorktree: comment notes the oldest-first sort is the canonical
  order before applyTabOrder, and why both the worktree label and the tab
  bar must agree on "which session is first".

No behavior change — both helpers already did this; now the intent is on
the page for future readers.

* chore: address PR #8911 review feedback from chrarnoldus

- Rewrite changeset as user-facing imperative summary (per AGENTS.md
  guidance: changesets appear in release notes; keep concise and feature-
  oriented, not implementation details).
- Drop redundant `kilocode_change - new file` marker on
  packages/ui/src/kilocode/markdown-fast-path.ts — the kilocode/ directory
  already signals the file is a Kilo addition; markers aren't needed in
  paths containing "kilocode".

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-17 16:47:45 +02:00
MariusandSylwester Liljegren 9749cc178d feat(kilo-ui): enhance MCP tool display with input/output sections and improved styling (#9123)
* feat(kilo-ui): enhance MCP tool display with input/output sections and improved styling

- Add subtitle and args display to MCP tool triggers for better context
- Separate input and output sections with labels and dividers
- Format input and output as JSON with proper syntax highlighting
- Reposition copy button tooltip to prevent clipping in tool output
- Add styling for MCP section labels and tool dividers

* feat(kilo-ui): i18n for MCP input/output labels

* chore: add changeset

---------

Co-authored-by: Sylwester Liljegren <sylwester.liljegren@softronic.se>
2026-04-17 13:24:35 +02:00
Johnny Amancio 0c3e31f6d2 Merge remote-tracking branch 'origin/main' into johnnyamancio/kilo-opencode-v1.4.4 2026-04-17 12:23:18 +02:00
kilo-maintainer[bot] 76f5d5dc08 release: v7.2.12 2026-04-17 09:30:38 +00:00
opencode 9f201d6370 release: v1.4.7 2026-04-16 21:54:54 +00:00
Johnny Amancio 689f810705 Merge remote-tracking branch 'origin/main' into johnnyamancio/kilo-opencode-v1.4.4 2026-04-16 20:30:42 +02:00
kilo-maintainer[bot] f3708c55fb release: v7.2.11 2026-04-16 17:40:26 +00:00
Marius d73e848cf1 fix(ui): restore localized revert tooltips (#9031)
* fix(ui): restore localized revert tooltips

* fix(ui): use existing revert tooltip key

* fix(ui): restore revert to here wording
2026-04-16 12:20:42 +02:00
Kit Langton 9f4b73b6a3 fix: clean up final 16 no-unused-vars warnings (#22751) 2026-04-16 03:54:21 +00:00
Kit Langton 8aa0f9fe95 feat: enable type-aware no-base-to-string rule, fix 56 violations (#22750) 2026-04-16 03:50:47 +00:00
opencode-agent[bot] 0beaf04df5 chore: generate 2026-04-16 03:28:30 +00:00
Kit Langton 80f1f1b5b8 feat: enable type-aware no-floating-promises rule, fix all 177 violations (#22741) 2026-04-15 23:27:32 -04:00
Kit Langton 34213d4446 fix: delete 9 dead functions with zero callers (#22697) 2026-04-16 02:01:02 +00:00
Kit Langton f7d4665e40 fix: resolve oxlint warnings — suppress false positives, remove unused imports (#22687) 2026-04-15 21:33:54 -04:00
Kit Langton 3d6f90cb53 feat: add oxlint with correctness defaults (#22682) 2026-04-15 20:45:19 -04:00
e16589f8b5 tweak(ui): session spacing (#20839)
Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
Co-authored-by: Brendan Allan <brendonovich@outlook.com>
2026-04-15 18:58:05 -04:00
Johnny Amancio 87aaac92cb Merge remote-tracking branch 'origin/main' into johnnyamancio/kilo-opencode-v1.4.4 2026-04-15 23:07:46 +02:00
Johnny Amancio 915f12c7e2 resolve merge conflicts 2026-04-15 22:51:15 +02:00
kilo-maintainer[bot] 3f68303a0a release: v7.2.10 2026-04-15 20:10:59 +00:00
kilo-maintainer[bot] 114f9a2db2 release: v7.2.9 2026-04-15 19:47:08 +00:00
kilo-maintainer[bot] 41ffb3a3aa release: v7.2.8 2026-04-15 19:11:48 +00:00
kilo-maintainer[bot] a476e19a88 release: v7.2.7 2026-04-15 17:05:20 +00:00
Dax be9432a893 shared package (#22626) 2026-04-15 14:26:20 +00:00
Johnny Amancio beb9b3b076 refactor: kilo compat for v1.4.4 2026-04-15 11:30:02 +02:00
Marius b9ecdb16a6 fix(ui): use LTR isolate instead of LTR embedding for directory paths in diff headers (#8959)
The trailing / in directory paths was visually disappearing in diff
viewer headers because CSS direction:rtl interacted poorly with the
weaker LRE/PDF bidi embedding characters (\u202A/\u202C). Replace with
LRI/PDI isolate characters (\u2066/\u2069) which fully prevent the
surrounding RTL context from reordering boundary characters like /.
2026-04-15 08:58:38 +00:00
Brendan Allan c98f616385 ui: update accordion styles and session review component (#22582) 2026-04-15 07:29:36 +00:00
Brendan Allan 5069cd9798 fix(ui): disable accordion items for binary files and improve disabled state styling (#22577) 2026-04-15 07:26:34 +00:00
opencode 7659321990 release: v1.4.6 2026-04-15 07:26:23 +00:00
Brendan Allan 8d89c3417b fix: prevent tooltip reopen on trigger click (#22571) 2026-04-15 06:03:29 +00:00
opencode dfc72838d7 release: v1.4.5 2026-04-15 04:25:18 +00:00
opencode bddf830083 release: v1.4.4 2026-04-15 00:03:43 +00:00
Catriel Müller 51983b1e95 refactor: regenerate sdk 2026-04-14 17:09:24 -03:00
Catriel Müller 1c67e0fe71 resolve merge conflicts 2026-04-14 17:05:48 -03:00
Catriel Müller c9e0060e2a refactor: kilo compat for v1.4.3 2026-04-14 14:46:57 -03:00