The Google AI Studio API keys page (aistudio.google.com/api-keys)
redirects to Google account sign-in for unauthenticated requests, so
lychee sees a 302 and fails the link check. The URL is correct and is
the one Google's own Gemini API key documentation links to, so exclude
it from the link checker like the already-excluded console.cloud.google.com.
The hardcoded team list in packages/script/src/index.ts (Script.team)
and its duplicate in script/changelog-github.cjs had drifted apart and
both included accounts no longer in the Kilo-Org. This list is consumed
by script/raw-changelog.ts to strip 'Thanks @user!' attribution for
internal members, so stale entries let departed contributors keep
receiving credit while active ones still get thanked.
Reconcile both copies against the live org-member and repo-collaborator
rosters: remove departed humans, add missing active accounts, keep all
bot/CI accounts, and alphabetize for parity between the two files.
McpTool's formattedOutput() only fences output when it parses as JSON;
non-JSON output (the common case for a tool returning prose or
markdown) is fed straight into the real Markdown renderer, which does
parse [label](url) into a link, hiding the URL half. toolText() was
treating all non-bash tool output the same as bash's (never stripped),
which reintroduced the exact mismatch this PR fixes for JSON-shaped
output on plain-text results. Now mirrors McpTool's own JSON.parse-or-
fallback branching: JSON output stays raw (rendered fenced, literal),
non-JSON output gets the same link stripping as text/reasoning chunks.
(cherry picked from commit e33a1a7ebc)
WARNING: stripMarkdownLinkUrls was applied to tool/bash chunks too.
Bash output is rendered via escapeHtml + syntax highlighting -- never
through Markdown -- and the generic/MCP fallback renderer wraps its
output in a fenced code block before it ever reaches Markdown. Both
show link-like `[x](y)` text literally, so stripping it searched text
that no longer matched what's on screen (e.g. a shell command that
echoes/cats a markdown link, or JSON with bracket+paren sequences).
Stripping is now only applied to text/reasoning chunks, which do go
through the real Markdown renderer.
Reverted the auto-load-history cap/opt-in from the previous commit: a
partial match count while some history remains unsearched can actively
mislead a user into the wrong conclusion, which outweighs the cost of
loading a long session's full history. Search now simply auto-loads
the entire session before reporting a final count/"No results", same
as originally requested. Revisit with a cap or lazy/incremental search
strategy in a follow-up PR if this proves too slow/expensive in
practice on very long sessions.
(cherry picked from commit f0ff4d3066)
User messages render via UserMessageDisplay/HighlightedText
(message-part.tsx), which never parses markdown at all -- [label](url)
always shows literally, brackets and all, unlike assistant text/
reasoning/tool content which goes through the real Markdown renderer.
Stripping link URLs there collapsed two genuinely visible literal
occurrences into one. Stripping now only applies to non-user rows.
(cherry picked from commit 097124d7ed)
High: visible tool content (e.g. a todowrite checklist) could be
highlighted in the DOM while the counter still reported "No results"
and navigation was disabled. toolText() previously only indexed
state.title for non-bash tools, independently of what
transcript-search-highlight.ts actually scans in the DOM. Rewrote it
to recursively collect every string leaf from state.input/state.metadata
plus state.output for any tool, so matching and highlighting draw from
one canonical, much more comprehensive notion of "the tool's text"
instead of two divergent ones. read/glob/grep/list remain excluded --
kilo-ui's context-tool-results.tsx confirmed they never render raw
input/output text, even expanded, so including it there would
reintroduce the same class of mismatch for those tools.
High: search only covered the initially-loaded message page (80
messages), silently missing older history in long sessions. MessageList
now auto-requests older pages (session.loadOlderMessages()) while a
search is active with a non-empty query, looping via reactivity on
hasOlderMessages()/loadingOlderMessages() until history is exhausted.
A new searchingHistory state surfaces this to the widget, which shows
"Searching earlier messages..." and withholds a final "No results"
until the whole session has actually been searched (a live match count
still updates progressively as pages load).
Medium: whole-word matching used plain \b, which only treats ASCII
letters/digits/underscore as word characters and silently breaks for
Cyrillic, Arabic, CJK, and similar text. Replaced with Unicode-aware
boundary lookarounds using \p{L}/\p{M}/\p{N} property escapes, with the
`u` flag applied to every compiled pattern.
New chat.search.searchingHistory i18n key added across all 20 locales.
(cherry picked from commit 47d4ebd73b)
errorText() previously only matched ErrorDisplay.tsx's default card body
(unwrapped error.data.message). It now mirrors the component's full
Switch/Match classification (parseAssistantError/parseProviderAuthError,
isUnauthorizedPaidModelError/isUnauthorizedPromotionLimitError, and the
same canAuth() gate used to decide whether the provider-auth prompt or
the default card renders), so search text matches whichever variant is
actually shown: paid-model, promotion-limit, provider-auth (including
the ChatGPT oauth copy), or the default unwrapped message.
(cherry picked from commit 7e9a984f08)
- Wrap StoryProviders in TranscriptSearchProvider - fixes the failing
Visual Regression check (5 stories threw because TaskHeader/MessageList
call useTranscriptSearch() unconditionally with no fallback context).
- Reset the whole search widget when the current session changes so
stale query/matches don't linger across a session switch.
- Search error rows via the same unwrapped error.data.message shown by
ErrorDisplay, instead of the internal, never-rendered error.name.
- Reorder bash tool search text to description -> command -> output,
matching the actual DOM order in shell-rolling-results.tsx, so
occurrence numbering lines up with what gets highlighted.
- Surface invalid regular expressions explicitly instead of leaving them
indistinguishable from "no matches".
- Track both legs of the chained highlight rAF so cleanup can cancel
either one, preventing a stray callback from touching state after
unmount.
- Widen Escape/Enter handling to the whole search widget, not just the
text input.
- Add an aria-label to the search input and type the search provider's
children as ParentComponent instead of any.
New chat.search.invalidRegex i18n key added across all 20 locales.
(cherry picked from commit 64dd8e3a2b)
Add a search widget to the VS Code sidebar and editor-tab chat header.
Clicking the header search icon opens an inline, VS Code-style find bar
with match case, whole word, and regular expression options. Matches are
highlighted across the transcript via the CSS Custom Highlight API, and
next/previous controls step through each occurrence, recentering only
when a match drifts near the viewport edge.
All user-facing strings are localized across the 20 supported locales.
(cherry picked from commit 3f8b4443c3)
The hardcoded team list in packages/script/src/index.ts (Script.team)
and its duplicate in script/changelog-github.cjs had drifted apart and
both included accounts no longer in the Kilo-Org. This list is consumed
by script/raw-changelog.ts to strip 'Thanks @user!' attribution for
internal members, so stale entries let departed contributors keep
receiving credit while active ones still get thanked.
Reconcile both copies against the live org-member and repo-collaborator
rosters: remove departed humans, add missing active accounts, keep all
bot/CI accounts, and alphabetize for parity between the two files.
* fix(cli): resolve latest CLI release when install script hits non-CLI tag
The GitHub releases/latest endpoint can point to non-CLI releases
(e.g., jetbrains/v7.0.4), whose tag prefix doesn't match the existing
version regex. Query the paginated releases endpoint, pick the first
tag starting with 'v', and use that version for both display and the
download URL instead of trusting releases/latest.
Closes#12125
* fix(cli): select stable installer release
---------
Co-authored-by: marius-kilocode <marius@kilocode.ai>
Move the five legacy-migration webview message cases out of the large
onDidReceiveMessage switch into an early-return handler, matching the
existing routeEarlyMessage/handleMemoryMessage pattern. The switch's
async arrow function exceeded the complexity cap of 150 after the
recent main merge; extracting these cases lowers it below the cap.
On Windows the spawned `kilo serve` process could outlive the IDE and then
block the next IDE launch (a surviving child inherits IDE handles). The
app-close teardown also deadlocked: closeForShutdown() closed the CLI's
streams before killing it, and on Windows closing a process stream while a
reader thread is mid-read hangs until the process dies — so IDE shutdown
blocked, the JVM stayed alive, the kill-on-close job never fired, and the
CLI lingered until killed by hand (which is what unblocked restart).
- Bind the CLI tree to the IDE via a Windows Job Object with
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, so the OS terminates the tree when
the IDE exits for any reason (clean exit, halt(), crash, force-kill).
- Reorder app-close teardown to kill first, then close streams
(shutdownTree), removing the deadlock. Order is regression-tested.
- Map the Job Object kernel32 functions directly (the IDE's bundled JNA
omits them) using only the platform's core JNA; JNA is not bundled to
avoid a jnidispatch collision. Guard on JnaLoader.isLoaded() before any
Native access and release handles via try/finally ownership.
- Best-effort / Windows-only: assign() returns null off-Windows, without
JNA, on non-64-bit, or on any native failure, so callers keep the
existing process-tree kill. No CLI changes.
Adds diagnostics on the setup/app-close paths, a Windows-gated integration
test, and ordering regression tests.
Known limitation: kill-on-close also terminates `persistent=true`
background processes on Windows; full support needs a coordinated CLI
breakaway change (CREATE_BREAKAWAY_FROM_JOB + JOB_OBJECT_LIMIT_BREAKAWAY_OK).
The process-tree kill test flaked on Linux CI ("child still alive"): a
SIGKILLed orphan reparents to init and lingers as an unreaped zombie that
ProcessHandle still reports alive (onExit never fires for a non-child), so the
kill worked but was unobservable. The test now treats a zombie ('Z' in /proc)
or already-reaped process as exited, with an isAlive fallback off Linux.
Also simplify confirmKilled to wait only on the tracked parent (our real
child, reliably reaped) and report descendants best-effort, so wait=true
shutdown no longer blocks on an orphan exit it cannot observe.
Locks in the disposal terminal-state guarantee (R5): after dispose(), a late SSE onClosed/onFailure with a stale source must not resurrect the connection or schedule a reconnect. Deterministic — drives the listener directly, no sleeps.
Address review: guarding TurnOpen/TurnClose/status with revertOp dropped
the transitions entirely, so a turn that started just before a rollback
could leave the prompt idle while the server turn was still active. Record
the underlying turn/status transition in revertDeferred while the revert is
held and reconcile it when the operation releases: an aborted turn releases
to Idle, a still-active turn releases back to Busy/Retry/Offline. Failed
reverts still surface the error explicitly.
Confirm process-tree exit after SIGKILL on the non-Windows kill path, and
escalate SIGTERM to SIGKILL on the shutdown-hook (no-wait) path so a
SIGTERM-ignoring tree is not orphaned on JVM exit. Deflake the process-tree
kill test by capturing both children deterministically and add coverage for
the no-wait escalation.
Make JetBrains IDE app-close teardown non-blocking: send SIGTERM and return,
letting the JVM shutdown hook confirm exit, so quitting the IDE no longer
stalls the EDT for up to several seconds. Stop plugin-unload teardown from
waiting on the lifecycle mutex behind an in-flight download.
Add a parent-death watchdog to `kilo serve`: the VS Code extension and
JetBrains plugin pass their PID via KILO_PARENT_PID and the server exits when
that process disappears, covering hard client kills where no signal or
shutdown hook runs.